18 #ifndef NANOVDB_IO_H_HAS_BEEN_INCLUDED 19 #define NANOVDB_IO_H_HAS_BEEN_INCLUDED 21 #include "../NanoVDB.h" 31 #ifdef NANOVDB_USE_ZIP 34 #ifdef NANOVDB_USE_BLOSC 41 #if defined(major) || defined(minor) 68 static const char * LUT[] = {
"NONE",
"ZIP",
"BLOSC" ,
"END" };
69 return LUT[
static_cast<int>(codec)];
78 template<
typename BufferT>
81 template<
typename BufferT>
98 return (((val) >> 56) & 0x00000000000000FF) | (((val) >> 40) & 0x000000000000FF00) |
99 (((val) >> 24) & 0x0000000000FF0000) | (((val) >> 8) & 0x00000000FF000000) |
100 (((val) << 8) & 0x000000FF00000000) | (((val) << 24) & 0x0000FF0000000000) |
101 (((val) << 40) & 0x00FF000000000000) | (((val) << 56) & 0xFF00000000000000);
153 uint32_t nodeCount[4];
154 uint32_t tileCount[3];
162 static_assert(
sizeof(
MetaData) == 176,
"Unexpected sizeof(MetaData)");
164 void read(std::istream& is);
165 void write(std::ostream& os)
const;
167 template<
typename ValueT>
175 static_assert(
sizeof(
Header) == 16u,
"Unexpected sizeof(Header)");
177 std::vector<GridMetaData>
meta;
183 template<
typename BufferT>
185 bool read(std::istream& is);
186 void write(std::ostream& os)
const;
191 template<
typename BufferT>
197 template<
typename BufferT>
201 template<
typename BufferT =
HostBuffer,
template<
typename...>
class VecT = std::vector>
207 template<
typename BufferT =
HostBuffer,
template<
typename...>
class VecT = std::vector>
213 template<
typename BufferT = HostBuffer>
219 template<
typename BufferT = HostBuffer>
225 template<
typename BufferT = HostBuffer>
226 GridHandle<BufferT> readGrid(
const std::string& fileName,
const std::string& gridName,
int verbose = 0,
const BufferT& buffer = BufferT());
229 template<
typename BufferT = HostBuffer>
233 template<
typename BufferT =
HostBuffer,
template<
typename...>
class VecT = std::vector>
234 VecT<GridHandle<BufferT>>
readGrids(
const std::string& fileName,
int verbose = 0,
const BufferT& buffer = BufferT());
237 template<
typename BufferT =
HostBuffer,
template<
typename...>
class VecT = std::vector>
238 VecT<GridHandle<BufferT>>
readGrids(std::istream& is,
const BufferT& buffer = BufferT());
241 bool hasGrid(
const std::string& fileName,
const std::string& gridName);
244 bool hasGrid(std::istream& is,
const std::string& gridName);
254 template<
typename BufferT>
257 const char* data =
reinterpret_cast<const char*
>(handle.
data());
262 #ifdef NANOVDB_USE_ZIP 263 uLongf size = compressBound(residual);
264 std::unique_ptr<Bytef[]> tmp(
new Bytef[size]);
265 const int status = compress(tmp.get(), &size,
reinterpret_cast<const Bytef*
>(data), residual);
267 std::runtime_error(
"Internal write error in ZIP");
269 std::cerr <<
"\nWarning: Unexpected ZIP compression from " << residual <<
" to " << size <<
" bytes\n";
271 os.write(reinterpret_cast<const char*>(&outBytes),
sizeof(
fileSize_t));
272 os.write(reinterpret_cast<const char*>(tmp.get()), outBytes);
275 throw std::runtime_error(
"ZIP compression codec was disabled during build");
280 #ifdef NANOVDB_USE_BLOSC 283 std::unique_ptr<char[]> tmp(
new char[size]);
284 const int count = blosc_compress_ctx(9, 1,
sizeof(
float), chunk, data, tmp.get(), size, BLOSC_LZ4_COMPNAME, 1 << 18, 1);
286 std::runtime_error(
"Internal write error in BLOSC");
288 os.write(reinterpret_cast<const char*>(&outBytes),
sizeof(
fileSize_t));
289 os.write(reinterpret_cast<const char*>(tmp.get()), outBytes);
293 }
while (residual > 0);
295 throw std::runtime_error(
"BLOSC compression codec was disabled during build");
300 os.write(data, residual);
304 throw std::runtime_error(
"Failed to write Tree to file");
309 template<
typename BufferT>
312 char* data =
reinterpret_cast<char*
>(handle.
buffer().data());
318 #ifdef NANOVDB_USE_ZIP 320 is.read(reinterpret_cast<char*>(&size),
sizeof(
fileSize_t));
321 std::unique_ptr<Bytef[]> tmp(
new Bytef[size]);
322 is.read(reinterpret_cast<char*>(tmp.get()), size);
323 uLongf numBytes = residual;
324 int status = uncompress(reinterpret_cast<Bytef*>(data), &numBytes, tmp.get(),
static_cast<uLongf
>(size));
326 std::runtime_error(
"Internal read error in ZIP");
328 throw std::runtime_error(
"UNZIP failed on byte size");
330 throw std::runtime_error(
"ZIP compression codec was disabled during build");
335 #ifdef NANOVDB_USE_BLOSC 338 is.read(reinterpret_cast<char*>(&size),
sizeof(
fileSize_t));
339 std::unique_ptr<char[]> tmp(
new char[size]);
340 is.read(reinterpret_cast<char*>(tmp.get()), size);
342 const int count = blosc_decompress_ctx(tmp.get(), data, size_t(chunk), 1);
344 std::runtime_error(
"Internal read error in BLOSC");
345 if (count !=
int(chunk))
346 throw std::runtime_error(
"BLOSC failed on byte size");
347 data += size_t(chunk);
349 }
while (residual > 0);
351 throw std::runtime_error(
"BLOSC compression codec was disabled during build");
356 is.read(data, residual);
359 throw std::runtime_error(
"Failed to read Tree from file");
365 template<
typename ValueT>
385 nameSize =
static_cast<uint32_t
>(gridName.size() + 1);
386 const uint32_t* ptr =
reinterpret_cast<const TreeData<3>*
>(&grid.tree())->mNodeCount;
387 for (
int i = 0; i < 3; ++i) {
391 for (
int i = 0; i < 3; ++i) {
398 os.write(reinterpret_cast<const char*>(
this),
sizeof(
MetaData));
399 os.write(gridName.c_str(),
nameSize);
401 throw std::runtime_error(
"Failed writing GridMetaData");
407 is.read(reinterpret_cast<char*>(
this),
sizeof(
MetaData));
408 std::unique_ptr<char[]> tmp(
new char[
nameSize]);
409 is.read(reinterpret_cast<char*>(tmp.get()), nameSize);
410 gridName.assign(tmp.get());
412 throw std::runtime_error(
"Failed reading GridMetaData");
420 uint64_t sum =
sizeof(
Header);
421 for (
auto& m : meta) {
427 template<
typename BufferT>
430 if (
auto* grid = h.template grid<float>()) {
431 meta.emplace_back(h.
size(), header.codec, *grid);
432 }
else if (
auto* grid = h.template grid<Vec3f>()) {
433 meta.emplace_back(h.
size(), header.codec, *grid);
434 }
else if (
auto* grid = h.template grid<double>()) {
435 meta.emplace_back(h.
size(), header.codec, *grid);
436 }
else if (
auto* grid = h.template grid<int32_t>()) {
437 meta.emplace_back(h.
size(), header.codec, *grid);
438 }
else if (
auto* grid = h.template grid<uint32_t>()) {
439 meta.emplace_back(h.
size(), header.codec, *grid);
440 }
else if (
auto* grid = h.template grid<int64_t>()) {
441 meta.emplace_back(h.
size(), header.codec, *grid);
442 }
else if (
auto* grid = h.template grid<int16_t>()) {
443 meta.emplace_back(h.
size(), header.codec, *grid);
444 }
else if (
auto* grid = h.template grid<Vec3d>()) {
445 meta.emplace_back(h.
size(), header.codec, *grid);
446 }
else if (
auto* grid = h.template grid<ValueMask>()) {
447 meta.emplace_back(h.
size(), header.codec, *grid);
448 }
else if (
auto* grid = h.template grid<bool>()) {
449 meta.emplace_back(h.
size(), header.codec, *grid);
450 }
else if (
auto* grid = h.template grid<Rgba8>()) {
451 meta.emplace_back(h.
size(), header.codec, *grid);
452 }
else if (
auto* grid = h.template grid<Fp4>()) {
453 meta.emplace_back(h.
size(), header.codec, *grid);
454 }
else if (
auto* grid = h.template grid<Fp8>()) {
455 meta.emplace_back(h.
size(), header.codec, *grid);
456 }
else if (
auto* grid = h.template grid<Fp16>()) {
457 meta.emplace_back(h.
size(), header.codec, *grid);
458 }
else if (
auto* grid = h.template grid<FpN>()) {
459 meta.emplace_back(h.
size(), header.codec, *grid);
460 }
else if (
auto* grid = h.template grid<Vec4f>()) {
461 meta.emplace_back(h.
size(), header.codec, *grid);
462 }
else if (
auto* grid = h.template grid<Vec4d>()) {
463 meta.emplace_back(h.
size(), header.codec, *grid);
465 throw std::runtime_error(
"nanovdb::io::Segment::add Cannot write grid of unknown type to file");
467 header.gridCount += 1;
472 if (header.gridCount == 0) {
473 throw std::runtime_error(
"Segment contains no grids");
474 }
else if (!os.write(reinterpret_cast<const char*>(&header),
sizeof(
Header))) {
475 throw std::runtime_error(
"Failed to write Header of Segment");
477 for (
auto& m : meta) {
484 is.read(reinterpret_cast<char*>(&header),
sizeof(
Header));
491 throw std::runtime_error(
"This nvdb file has reversed endianness");
492 throw std::runtime_error(
"Magic number error: This is not a valid nvdb file");
494 std::stringstream ss;
496 ss <<
"The file contains an older version of NanoVDB: " << std::string(header.version.c_str()) <<
"!\n\t" 500 <<
"Recommendation: Re-compile this tool against the newer version: " << header.version.getMajor() <<
".X of NanoVDB";
502 throw std::runtime_error(
"An unrecoverable error in nanovdb::Segment::read:\n\tIncompatible file format: " + ss.str());
504 meta.resize(header.gridCount);
505 for (
auto& m : meta) {
507 m.version = header.version;
514 template<
typename BufferT>
517 std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
519 throw std::runtime_error(
"Unable to open file named \"" + fileName +
"\" for output");
521 writeGrid<BufferT>(os, handle,
codec);
523 std::cout <<
"Wrote nanovdb::Grid to file named \"" << fileName <<
"\"" << std::endl;
527 template<
typename BufferT>
532 const uint64_t headerSize = s.
memUsage();
533 std::streamoff seek = headerSize;
534 os.seekp(seek, std::ios_base::cur);
536 seek += s.
meta[0].fileSize;
537 os.seekp(-seek, std::ios_base::cur);
539 os.seekp(seek - headerSize, std::ios_base::cur);
542 template<
typename BufferT,
template<
typename...>
class VecT>
545 std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
547 throw std::runtime_error(
"Unable to open file named \"" + fileName +
"\" for output");
549 writeGrids<BufferT, VecT>(os, handles,
codec);
551 std::cout <<
"Wrote " << handles.size() <<
" nanovdb::Grid(s) to file named \"" << fileName <<
"\"" << std::endl;
555 template<
typename BufferT,
template<
typename...>
class VecT>
559 for (
auto& h : handles) {
562 const uint64_t headerSize = s.
memUsage();
563 std::streamoff seek = headerSize;
564 os.seekp(seek, std::ios_base::cur);
565 for (
size_t i = 0; i < handles.size(); ++i) {
567 seek += s.
meta[i].fileSize;
569 os.seekp(-seek, std::ios_base::cur);
571 os.seekp(seek - headerSize, std::ios_base::cur);
575 template<
typename BufferT>
578 std::ifstream is(fileName, std::ios::in | std::ios::binary);
580 throw std::runtime_error(
"Unable to open file named \"" + fileName +
"\" for input");
582 auto handle = readGrid<BufferT>(is, n, buffer);
584 std::cout <<
"Read NanoGrid # " << n <<
" from the file named \"" << fileName <<
"\"" << std::endl;
589 template<
typename BufferT>
593 uint64_t counter = 0;
595 std::streamoff seek = 0;
596 for (
auto& m : s.
meta) {
599 is.seekg(seek, std::ios_base::cur);
607 is.seekg(seek, std::ios_base::cur);
609 throw std::runtime_error(
"Grid index exceeds grid count in file");
613 template<
typename BufferT>
616 std::ifstream is(fileName, std::ios::in | std::ios::binary);
618 throw std::runtime_error(
"Unable to open file named \"" + fileName +
"\" for input");
620 auto handle = readGrid<BufferT>(is,
gridName, buffer);
623 std::cout <<
"Read NanoGrid named \"" << gridName <<
"\" from the file named \"" << fileName <<
"\"" << std::endl;
625 std::cout <<
"File named \"" << fileName <<
"\" does not contain a grid named \"" + gridName +
"\"" << std::endl;
631 template<
typename BufferT>
637 std::streamoff seek = 0;
638 for (
auto& m : s.
meta) {
639 if (m.nameKey == key && m.gridName == gridName) {
641 is.seekg(seek, std::ios_base::cur);
648 is.seekg(seek, std::ios_base::cur);
654 template<
typename BufferT,
template<
typename...>
class VecT>
655 VecT<GridHandle<BufferT>>
readGrids(
const std::string& fileName,
int verbose,
const BufferT& buffer)
657 std::ifstream is(fileName, std::ios::in | std::ios::binary);
659 throw std::runtime_error(
"Unable to open file named \"" + fileName +
"\" for input");
661 auto handles = readGrids<BufferT, VecT>(is, buffer);
663 std::cout <<
"Read " << handles.size() <<
" NanoGrid(s) from the file named \"" << fileName <<
"\"" << std::endl;
668 template<
typename BufferT,
template<
typename...>
class VecT>
669 VecT<GridHandle<BufferT>>
readGrids(std::istream& is,
const BufferT& buffer)
671 VecT<GridHandle<BufferT>> handles;
673 while (seg.
read(is)) {
674 for (
auto& m : seg.
meta) {
677 handles.push_back(std::move(handle));
685 std::ifstream is(fileName, std::ios::in | std::ios::binary);
687 throw std::runtime_error(
"Unable to open file named \"" + fileName +
"\" for input");
694 std::vector<GridMetaData> meta;
696 while (seg.
read(is)) {
697 std::streamoff seek = 0;
698 for (
auto& m : seg.
meta) {
702 is.seekg(seek, std::ios_base::cur);
707 inline bool hasGrid(
const std::string& fileName,
const std::string& gridName)
709 std::ifstream is(fileName, std::ios::in | std::ios::binary);
711 throw std::runtime_error(
"Unable to open file named \"" + fileName +
"\" for input");
716 inline bool hasGrid(std::istream& is,
const std::string& gridName)
721 std::streamoff seek = 0;
722 for (
auto& m : s.
meta) {
723 if (m.nameKey == key && m.gridName == gridName) {
728 is.seekg(seek, std::ios_base::cur);
739 for (
auto* str = reinterpret_cast<const unsigned char*>(cstr); *str; ++str) {
740 uint64_t overflow = hash >> (64 - 8);
742 hash += *str + overflow;
750 #endif // NANOVDB_IO_H_HAS_BEEN_INCLUDED
const BBox< Vec3R > & worldBBox() const
Computes a AABB of active values in world space.
Definition: NanoVDB.h:2405
uint64_t reverseEndianness(uint64_t val)
Return a uint64_t with its bytes reversed so we can check for endianness.
Definition: IO.h:96
std::vector< GridMetaData > readGridMetaData(const std::string &fileName)
Reads and returns a vector of meta data for all the grids found in the specified file.
Definition: IO.h:683
Highest level of the data structure. Contains a tree and a world->index transform (that currently onl...
Definition: NanoVDB.h:2307
GridClass
Classes (defined in OpenVDB) that are currently supported by NanoVDB.
Definition: NanoVDB.h:253
bool hasGrid(const std::string &fileName, const std::string &gridName)
Return true if the file contains a grid with the specified name.
Definition: IO.h:707
Defines two classes, a GridRegister the defines the value type (e.g. Double, Float etc) of a NanoVDB ...
std::vector< GridMetaData > meta
Definition: IO.h:177
const TreeT & tree() const
Return a const reference to the tree.
Definition: NanoVDB.h:2344
Segment(Codec c=Codec::NONE)
Definition: IO.h:178
Bit-compacted representation of all three version numbers.
Definition: NanoVDB.h:540
uint64_t activeVoxelCount() const
Return the total number of active voxels in this tree.
Definition: NanoVDB.h:2414
uint64_t fileSize_t
Definition: IO.h:53
uint64_t stringHash(const char *cstr)
Standard hash function to use on strings; std::hash may vary by platform/implementation and is know t...
Definition: IO.h:733
static fileSize_t write(std::ostream &os, const GridHandle< BufferT > &handle, Codec codec)
This class serves to manage a raw memory buffer of a NanoVDB Grid.
Definition: GridHandle.h:70
BufferT & buffer()
Return a reference to the buffer.
Definition: GridHandle.h:107
Definition: NanoVDB.h:184
Header header
Definition: IO.h:175
static void read(std::istream &is, GridHandle< BufferT > &handle, Codec codec)
#define NANOVDB_MAJOR_VERSION_NUMBER
Definition: NanoVDB.h:104
uint8_t * data() override
Returns a non-const pointer to the data.
Definition: GridHandle.h:115
Definition: NanoVDB.h:1524
#define NANOVDB_MAGIC_NUMBER
Definition: NanoVDB.h:102
void writeGrid(const std::string &fileName, const GridHandle< BufferT > &handle, Codec codec=Codec::NONE, int verbose=0)
Write a single grid to file (over-writing existing content of the file)
Definition: IO.h:515
const GridType & gridType() const
Definition: NanoVDB.h:2418
This is a buffer that contains a shared or private pool to either externally or internally managed ho...
Definition: HostBuffer.h:109
uint64_t memUsage() const
Definition: IO.h:418
__hostdev__ uint32_t hash(uint32_t x)
Definition: common.h:13
VecT< GridHandle< BufferT > > readGrids(const std::string &fileName, int verbose=0, const BufferT &buffer=BufferT())
Read all the grids in the file.
Definition: IO.h:655
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:216
const Vec3R & voxelSize() const
Return a const reference to the size of a voxel in world units.
Definition: NanoVDB.h:2353
const GridClass & gridClass() const
Definition: NanoVDB.h:2419
Codec
Optional compression codecs.
Definition: IO.h:61
Definition: NanoVDB.h:2500
bool read(std::istream &is)
Definition: IO.h:482
uint64_t size() const override
Returns the size in bytes of the raw memory buffer managed by this GridHandle's allocator.
Definition: GridHandle.h:123
#define __hostdev__
Definition: NanoVDB.h:168
GridHandle< BufferT > readGrid(const std::string &fileName, uint64_t n=0, int verbose=0, const BufferT &buffer=BufferT())
Read the n'th grid from file (defaults to first grid)
Definition: IO.h:576
void add(const GridHandle< BufferT > &h)
Definition: IO.h:428
void write(std::ostream &os) const
Definition: IO.h:470
void writeGrids(const std::string &fileName, const VecT< GridHandle< BufferT >> &handles, Codec codec=Codec::NONE, int verbose=0)
Write multiple grids to file (over-writing existing content of the file)
Definition: IO.h:543
const char * toStr(Codec codec)
Definition: IO.h:66
static constexpr fileSize_t MAX_SIZE
Definition: IO.h:76