33#ifndef NANOVDB_IO_H_HAS_BEEN_INCLUDED
34#define NANOVDB_IO_H_HAS_BEEN_INCLUDED
50#ifdef NANOVDB_USE_BLOSC
57#if defined(major) || defined(minor)
71template<
typename BufferT>
77template<
typename BufferT = HostBuffer,
template<
typename...>
class VecT = std::vector>
78void writeGrids(
const std::string& fileName,
const VecT<GridHandle<BufferT>>& handles,
Codec codec =
Codec::NONE,
int verbose = 0);
92template<
typename BufferT = HostBuffer>
93GridHandle<BufferT>
readGrid(
const std::string& fileName,
int n = 0,
int verbose = 0,
const BufferT& buffer = BufferT());
103template<
typename BufferT = HostBuffer>
104GridHandle<BufferT>
readGrid(
const std::string& fileName,
const std::string& gridName,
int verbose = 0,
const BufferT& buffer = BufferT());
115template<
typename BufferT = HostBuffer,
template<
typename...>
class VecT = std::vector>
116VecT<GridHandle<BufferT>>
readGrids(
const std::string& fileName,
int verbose = 0,
const BufferT& buffer = BufferT());
130static constexpr fileSize_t MAX_SIZE = 1UL << 30;
132template<
typename BufferT>
135template<
typename BufferT>
136static void read(std::istream& is, BufferT& buffer,
Codec codec);
138static void read(std::istream& is,
char* data,
fileSize_t size,
Codec codec);
152 return (((val) >> 56) & 0x00000000000000FF) | (((val) >> 40) & 0x000000000000FF00) |
153 (((val) >> 24) & 0x0000000000FF0000) | (((val) >> 8) & 0x00000000FF000000) |
154 (((val) << 8) & 0x000000FF00000000) | (((val) << 24) & 0x0000FF0000000000) |
155 (((val) << 40) & 0x00FF000000000000) | (((val) << 56) & 0xFF00000000000000);
167 static_assert(
sizeof(
FileMetaData) == 176,
"Unexpected sizeof(FileMetaData)");
169 void read(std::istream& is);
170 void write(std::ostream& os)
const;
183 static_assert(
sizeof(
FileHeader) == 16u,
"Unexpected sizeof(FileHeader)");
185 std::vector<FileGridMetaData>
meta;
187#ifdef NANOVDB_USE_NEW_MAGIC_NUMBERS
195 template<
typename BufferT>
196 void add(
const GridHandle<BufferT>& h);
197 bool read(std::istream& is);
198 void write(std::ostream& os)
const;
203bool hasGrid(
const std::string& fileName,
const std::string& gridName);
206bool hasGrid(std::istream& is,
const std::string& gridName);
218template<
typename BufferT>
219fileSize_t Internal::write(std::ostream& os,
const GridHandle<BufferT>& handle,
Codec codec,
unsigned int n)
221 const char* data =
reinterpret_cast<const char*
>(handle.gridData(n));
222 fileSize_t total = 0, residual = handle.gridSize(n);
226#ifdef NANOVDB_USE_ZIP
227 uLongf size = compressBound(
static_cast<uLongf
>(residual));
228 std::unique_ptr<Bytef[]> tmp(
new Bytef[size]);
229 const int status = compress(tmp.get(), &size,
reinterpret_cast<const Bytef*
>(data),
static_cast<uLongf
>(residual));
230 if (status != Z_OK)
throw std::runtime_error(
"Internal write error in ZIP");
231 if (size > residual) std::cerr <<
"\nWarning: Unexpected ZIP compression from " << residual <<
" to " << size <<
" bytes\n";
233 os.write(
reinterpret_cast<const char*
>(&outBytes),
sizeof(
fileSize_t));
234 os.write(
reinterpret_cast<const char*
>(tmp.get()), outBytes);
237 throw std::runtime_error(
"ZIP compression codec was disabled during build");
242#ifdef NANOVDB_USE_BLOSC
244 fileSize_t chunk = residual < MAX_SIZE ? residual : MAX_SIZE, size = chunk + BLOSC_MAX_OVERHEAD;
245 std::unique_ptr<char[]> tmp(
new char[size]);
246 const int count = blosc_compress_ctx(9, 1,
sizeof(
float), chunk, data, tmp.get(), size, BLOSC_LZ4_COMPNAME, 1 << 18, 1);
247 if (count <= 0)
throw std::runtime_error(
"Internal write error in BLOSC");
249 os.write(
reinterpret_cast<const char*
>(&outBytes),
sizeof(
fileSize_t));
250 os.write(
reinterpret_cast<const char*
>(tmp.get()), outBytes);
254 }
while (residual > 0);
256 throw std::runtime_error(
"BLOSC compression codec was disabled during build");
261 os.write(data, residual);
264 if (!os)
throw std::runtime_error(
"Failed to write Tree to file");
268template<
typename BufferT>
269void Internal::read(std::istream& is, BufferT& buffer,
Codec codec)
271 Internal::read(is,
reinterpret_cast<char*
>(buffer.data()), buffer.size(), codec);
279void Internal::read(std::istream& is,
char* data,
fileSize_t residual,
Codec codec)
284#ifdef NANOVDB_USE_ZIP
286 is.read(
reinterpret_cast<char*
>(&size),
sizeof(
fileSize_t));
287 std::unique_ptr<Bytef[]> tmp(
new Bytef[size]);
288 is.read(
reinterpret_cast<char*
>(tmp.get()), size);
289 uLongf numBytes =
static_cast<uLongf
>(residual);
290 int status = uncompress(
reinterpret_cast<Bytef*
>(data), &numBytes, tmp.get(),
static_cast<uLongf
>(size));
291 if (status != Z_OK)
throw std::runtime_error(
"Internal read error in ZIP");
292 if (
fileSize_t(numBytes) != residual)
throw std::runtime_error(
"UNZIP failed on byte size");
294 throw std::runtime_error(
"ZIP compression codec was disabled during build");
299#ifdef NANOVDB_USE_BLOSC
302 is.read(
reinterpret_cast<char*
>(&size),
sizeof(
fileSize_t));
303 std::unique_ptr<char[]> tmp(
new char[size]);
304 is.read(
reinterpret_cast<char*
>(tmp.get()), size);
305 const fileSize_t chunk = residual < MAX_SIZE ? residual : MAX_SIZE;
306 const int count = blosc_decompress_ctx(tmp.get(), data,
size_t(chunk), 1);
307 if (count < 1)
throw std::runtime_error(
"Internal read error in BLOSC");
308 if (count !=
int(chunk))
throw std::runtime_error(
"BLOSC failed on byte size");
309 data += size_t(chunk);
311 }
while (residual > 0);
313 throw std::runtime_error(
"BLOSC compression codec was disabled during build");
318 is.read(data, residual);
320 if (!is)
throw std::runtime_error(
"Failed to read Tree from file");
340 uint16_t(gridData.mBlindMetadataCount),
342 , gridName(gridData.gridName())
344 NANOVDB_ASSERT(gridData.mBlindMetadataCount <= uint32_t(1 << 16));
345 auto &treeData = *
reinterpret_cast<const TreeData*
>(gridData.treePtr());
346 nameKey = stringHash(gridName);
347 voxelCount = treeData.mVoxelCount;
348 nameSize =
static_cast<uint32_t
>(gridName.size() + 1);
349 for (
int i = 0; i < 3; ++i) {
350 FileMetaData::nodeCount[i] = treeData.mNodeCount[i];
351 FileMetaData::tileCount[i] = treeData.mTileCount[i];
357 os.write(
reinterpret_cast<const char*
>(
this),
sizeof(
FileMetaData));
359 if (!os)
throw std::runtime_error(
"Failed writing FileGridMetaData");
364 is.read(
reinterpret_cast<char*
>(
this),
sizeof(
FileMetaData));
365 std::unique_ptr<char[]> tmp(
new char[
nameSize]);
366 is.read(
reinterpret_cast<char*
>(tmp.get()),
nameSize);
368 if (!is)
throw std::runtime_error(
"Failed reading FileGridMetaData");
376 for (
auto& m :
meta) sum += m.memUsage();
380template<
typename BufferT>
383 for (uint32_t i = 0; i < h.
gridCount(); ++i) {
385 if (!gridData)
throw std::runtime_error(
"Segment::add: GridHandle does not contain grid #" + std::to_string(i));
393 if (
header.gridCount == 0) {
394 throw std::runtime_error(
"Segment contains no grids");
395 }
else if (!os.write(
reinterpret_cast<const char*
>(&
header),
sizeof(
FileHeader))) {
396 throw std::runtime_error(
"Failed to write FileHeader of Segment");
398 for (
auto& m :
meta) m.write(os);
405 is.clear(std::ios_base::eofbit);
413 throw std::runtime_error(
"This nvdb file has reversed endianness");
416 throw std::runtime_error(
"Expected a NanoVDB file, but read an OpenVDB file!");
418 throw std::runtime_error(
"Expected a NanoVDB file, but read a raw NanoVDB grid!");
420 throw std::runtime_error(
"Expected a NanoVDB file, but read a file of unknown type!");
423 }
else if ( !
header.version.isCompatible()) {
424 std::stringstream ss;
426 is.read(
reinterpret_cast<char*
>(&v),
sizeof(
Version));
428 ss <<
"This file looks like it contains a raw grid buffer and not a standard file with meta data";
431 ss <<
"The file contains an older version of NanoVDB: " << std::string(
toStr(str,
header.version)) <<
"!\n\t"
435 <<
"Recommendation: Re-compile this tool against the newer version: " <<
header.version.getMajor() <<
".X of NanoVDB";
437 throw std::runtime_error(
"An unrecoverable error in nanovdb::Segment::read:\n\tIncompatible file format: " + ss.str());
440 for (
auto& m :
meta) {
442 m.version =
header.version;
449template<
typename BufferT>
454 const auto start = os.tellp();
456 for (uint32_t i = 0; i < handle.
gridCount(); ++i) {
457 seg.
meta[i].fileSize = Internal::write(os, handle, codec, i);
461 os.seekp(0, std::ios_base::end);
464template<
typename BufferT>
467 std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
469 throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for output");
473 std::cout <<
"Wrote nanovdb::Grid to file named \"" << fileName <<
"\"" << std::endl;
479template<
typename BufferT =
HostBuffer,
template<
typename...>
class VecT = std::vector>
482 for (
auto& h : handles)
writeGrid(os, h, codec);
485template<
typename BufferT,
template<
typename...>
class VecT>
488 std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
489 if (!os.is_open())
throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for output");
491 if (verbose) std::cout <<
"Wrote " << handles.size() <<
" nanovdb::Grid(s) to file named \"" << fileName <<
"\"" << std::endl;
496template<
typename BufferT>
502 handle.
read(is, pool);
503 }
catch(
const std::logic_error&) {
505 uint64_t bufferSize = 0u;
506 uint32_t gridCount = 0u, gridIndex = 0u;
507 const auto start = is.tellg();
508 while (seg.
read(is)) {
509 std::streamoff skipSize = 0;
510 for (
auto& m : seg.
meta) {
512 bufferSize += m.gridSize;
513 skipSize += m.fileSize;
515 is.seekg(skipSize, std::ios_base::cur);
517 auto buffer = BufferT::create(bufferSize, &pool);
518 char *ptr = (
char*)buffer.data();
520 while (seg.
read(is)) {
521 for (
auto& m : seg.
meta) {
522 Internal::read(is, ptr, m.gridSize, seg.
header.
codec);
531 handle.
read(is, uint32_t(n), pool);
533 }
catch(
const std::logic_error&) {
536 while (seg.
read(is)) {
537 std::streamoff seek = 0;
538 for (
auto& m : seg.
meta) {
539 if (++counter == n) {
540 auto buffer = BufferT::create(m.gridSize, &pool);
548 is.seekg(seek, std::ios_base::cur);
550 if (n != counter)
throw std::runtime_error(
"stream does not contain a #" + std::to_string(n) +
" grid");
557template<
typename BufferT>
560 std::ifstream is(fileName, std::ios::in | std::ios::binary);
561 if (!is.is_open())
throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for input");
565 std::cout <<
"Read all NanoGrids from the file named \"" << fileName <<
"\"" << std::endl;
567 std::cout <<
"Read NanoGrid # " << n <<
" from the file named \"" << fileName <<
"\"" << std::endl;
580template<
typename BufferT>
585 handle.
read(is, gridName, pool);
587 }
catch(
const std::logic_error&) {
590 while (seg.
read(is)) {
591 std::streamoff seek = 0;
592 for (
auto& m : seg.
meta) {
593 if ((m.nameKey == 0u || m.nameKey == key) && m.gridName == gridName) {
594 auto buffer = BufferT::create(m.gridSize, &pool);
595 is.seekg(seek, std::ios_base::cur);
603 is.seekg(seek, std::ios_base::cur);
606 throw std::runtime_error(
"Grid name '" + gridName +
"' not found in file");
610template<
typename BufferT>
613 std::ifstream is(fileName, std::ios::in | std::ios::binary);
614 if (!is.is_open())
throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for input");
618 std::cout <<
"Read NanoGrid named \"" << gridName <<
"\" from the file named \"" << fileName <<
"\"" << std::endl;
620 std::cout <<
"File named \"" << fileName <<
"\" does not contain a grid named \"" + gridName +
"\"" << std::endl;
628template<
typename BufferT =
HostBuffer,
template<
typename...>
class VecT = std::vector>
629VecT<GridHandle<BufferT>>
readGrids(std::istream& is,
const BufferT& pool = BufferT())
631 VecT<GridHandle<BufferT>> handles;
634 handle.
read(is, pool);
635 handles.push_back(std::move(handle));
636 }
catch(
const std::logic_error&) {
638 while (seg.
read(is)) {
639 uint64_t bufferSize = 0;
640 for (
auto& m : seg.
meta) bufferSize += m.gridSize;
641 auto buffer = BufferT::create(bufferSize, &pool);
642 uint64_t bufferOffset = 0;
645 Internal::read(is, (
char*)data, seg.
meta[i].gridSize, seg.
header.
codec);
647 bufferOffset += seg.
meta[i].gridSize;
649 handles.emplace_back(std::move(buffer));
656template<
typename BufferT,
template<
typename...>
class VecT>
657VecT<GridHandle<BufferT>>
readGrids(
const std::string& fileName,
int verbose,
const BufferT& buffer)
659 std::ifstream is(fileName, std::ios::in | std::ios::binary);
660 if (!is.is_open())
throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for input");
662 if (verbose) std::cout <<
"Read " << handles.size() <<
" NanoGrid(s) from the file named \"" << fileName <<
"\"" << std::endl;
670 std::ifstream is(fileName, std::ios::in | std::ios::binary);
671 if (!is.is_open())
throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for input");
678 std::vector<FileGridMetaData> meta;
683 meta = std::move(seg.
meta);
684 }
catch(
const std::logic_error&) {
685 while (seg.
read(is)) {
686 std::streamoff skip = 0;
687 for (
auto& m : seg.
meta) {
691 is.seekg(skip, std::ios_base::cur);
699inline bool hasGrid(
const std::string& fileName,
const std::string& gridName)
701 std::ifstream is(fileName, std::ios::in | std::ios::binary);
702 if (!is.is_open())
throw std::ios_base::failure(
"Unable to open file named \"" + fileName +
"\" for input");
706inline bool hasGrid(std::istream& is,
const std::string& gridName)
710 while (seg.
read(is)) {
711 std::streamoff seek = 0;
712 for (
auto& m : seg.
meta) {
713 if (m.nameKey == key && m.gridName == gridName)
return true;
716 is.seekg(seek, std::ios_base::cur);
727 for (
auto* str =
reinterpret_cast<const unsigned char*
>(c_str); *str; ++str) {
728 uint64_t overflow =
hash >> (64 - 8);
730 hash += *str + overflow;
746 os <<
"(" << b[0][0] <<
"," << b[0][1] <<
"," << b[0][2] <<
") -> "
747 <<
"(" << b[1][0] <<
"," << b[1][1] <<
"," << b[1][2] <<
")";
754 os <<
"(" << b[0][0] <<
"," << b[0][1] <<
"," << b[0][2] <<
") -> "
755 <<
"(" << b[1][0] <<
"," << b[1][1] <<
"," << b[1][2] <<
")";
762 os <<
"(" << ijk[0] <<
"," << ijk[1] <<
"," << ijk[2] <<
")";
770 os <<
"(" << v[0] <<
"," << v[1] <<
"," << v[2] <<
")";
778 os <<
"(" << v[0] <<
"," << v[1] <<
"," << v[2] <<
"," << v[3] <<
")";
Defines GridHandle, which manages a memory buffer containing one or more NanoVDB grids: host-resident...
Implements a light-weight self-contained VDB data-structure in a single file! In other words,...
#define NANOVDB_MAGIC_FILE
Definition NanoVDB.h:141
#define NANOVDB_MAJOR_VERSION_NUMBER
Definition NanoVDB.h:146
#define NANOVDB_MAGIC_NUMB
Definition NanoVDB.h:139
This class serves to manage a buffer containing one or more NanoVDB Grids.
Definition GridHandle.h:109
const GridData * gridData(uint32_t n=0) const
Access to the GridData of the n'th grid in the current handle.
Definition GridHandle.h:481
uint64_t gridSize(uint32_t n=0) const
Return the grid size of the n'th grid in this GridHandle.
Definition GridHandle.h:348
uint32_t gridCount() const
Return the total number of grids contained in this buffer.
Definition GridHandle.h:343
void * data()
Returns a pointer to the host data; not available for a single-space device buffer,...
Definition GridHandle.h:225
void read(std::istream &is, const BufferT &pool=BufferT())
Read an entire raw grid buffer from an input stream.
Definition GridHandle.h:560
This is a buffer that contains a shared or private pool to either externally or internally managed ho...
Definition HostBuffer.h:181
Bit-compacted representation of all three version numbers.
Definition NanoVDB.h:730
uint32_t getMajor() const
Definition NanoVDB.h:757
Signed (i, j, k) 32-bit integer coordinate class, similar to openvdb::math::Coord.
Definition Math.h:346
A simple vector class with three components, similar to openvdb::math::Vec3.
Definition Math.h:1362
A simple vector class with four components, similar to openvdb::math::Vec4.
Definition Math.h:1560
__hostdev__ uint32_t hash(uint32_t x)
Definition common.h:16
std::ostream & operator<<(std::ostream &os, const nanovdb::math::BBox< nanovdb::math::Vec3< T > > &b)
Definition IO.h:744
Definition NanoVDB.h:6011
VecT< GridHandle< BufferT > > readGrids(const std::string &fileName, int verbose=0, const BufferT &buffer=BufferT())
Read all the grids in the file and return them as a vector of multiple GridHandles,...
Definition IO.h:657
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:486
uint64_t fileSize_t
Definition IO.h:123
std::vector< FileGridMetaData > 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:668
uint64_t stringHash(const char *cstr)
Internal functions for compressed read/write of a NanoVDB GridHandle into a stream.
Definition IO.h:723
uint64_t reverseEndianness(uint64_t val)
Return a uint64_t with its bytes reversed so we can check for endianness.
Definition IO.h:150
void writeGrid(const std::string &fileName, const GridHandle< BufferT > &handle, io::Codec codec=io::Codec::NONE, int verbose=0)
Write a single grid to file (over-writing existing content of the file)
Definition IO.h:465
GridHandle< BufferT > readGrid(const std::string &fileName, int n=0, int verbose=0, const BufferT &buffer=BufferT())
Read and return one or all grids from a file into a single GridHandle.
Definition IO.h:558
Codec
Define compression codecs.
Definition NanoVDB.h:6019
@ ZIP
Definition NanoVDB.h:6020
@ BLOSC
Definition NanoVDB.h:6021
@ NONE
Definition NanoVDB.h:6019
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:699
static DstT * PtrAdd(void *p, int64_t offset)
Adds a byte offset to a non-const pointer to produce another non-const pointer.
Definition Util.h:524
Defines a simple memory pool used to call cub functions that use dynamic temporary storage.
Definition GridHandle.h:31
MagicType toMagic(uint64_t magic)
maps 64 bits of magic number to enum
Definition NanoVDB.h:366
MagicType
Enums used to identify magic numbers recognized by NanoVDB.
Definition NanoVDB.h:357
@ OpenVDB
Definition NanoVDB.h:358
@ NanoGrid
Definition NanoVDB.h:360
@ NanoVDB
Definition NanoVDB.h:359
@ NanoFile
Definition NanoVDB.h:361
char * toStr(char *dst, GridType gridType)
Maps a GridType to a c-string.
Definition NanoVDB.h:253
math::BBox< Coord > CoordBBox
Definition Math.h:2241
#define NANOVDB_ASSERT(x)
Definition Util.h:53
Struct with all the member data of the Grid (useful during serialization of an openvdb grid)
Definition NanoVDB.h:1977
This class defines all the data stored in segment of a file.
Definition IO.h:181
bool read(std::istream &is)
Definition IO.h:401
void add(const GridHandle< BufferT > &h)
Definition IO.h:381
void write(std::ostream &os) const
Definition IO.h:391
std::vector< FileGridMetaData > meta
Definition IO.h:185
uint64_t memUsage() const
Definition IO.h:373
Segment(Codec c=Codec::NONE)
Definition IO.h:186
FileHeader header
Definition IO.h:184