OpenVDB  12.0.1
NanoVDB.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: Apache-2.0
3 
4 /*!
5  \file nanovdb/NanoVDB.h
6 
7  \author Ken Museth
8 
9  \date January 8, 2020
10 
11  \brief Implements a light-weight self-contained VDB data-structure in a
12  single file! In other words, this is a significantly watered-down
13  version of the OpenVDB implementation, with few dependencies - so
14  a one-stop-shop for a minimalistic VDB data structure that run on
15  most platforms!
16 
17  \note It is important to note that NanoVDB (by design) is a read-only
18  sparse GPU (and CPU) friendly data structure intended for applications
19  like rendering and collision detection. As such it obviously lacks
20  a lot of the functionality and features of OpenVDB grids. NanoVDB
21  is essentially a compact linearized (or serialized) representation of
22  an OpenVDB tree with getValue methods only. For best performance use
23  the ReadAccessor::getValue method as opposed to the Tree::getValue
24  method. Note that since a ReadAccessor caches previous access patterns
25  it is by design not thread-safe, so use one instantiation per thread
26  (it is very light-weight). Also, it is not safe to copy accessors between
27  the GPU and CPU! In fact, client code should only interface
28  with the API of the Grid class (all other nodes of the NanoVDB data
29  structure can safely be ignored by most client codes)!
30 
31 
32  \warning NanoVDB grids can only be constructed via tools like createNanoGrid
33  or the GridBuilder. This explains why none of the grid nodes defined below
34  have public constructors or destructors.
35 
36  \details Please see the following paper for more details on the data structure:
37  K. Museth, “VDB: High-Resolution Sparse Volumes with Dynamic Topology”,
38  ACM Transactions on Graphics 32(3), 2013, which can be found here:
39  http://www.museth.org/Ken/Publications_files/Museth_TOG13.pdf
40 
41  NanoVDB was first published there: https://dl.acm.org/doi/fullHtml/10.1145/3450623.3464653
42 
43 
44  Overview: This file implements the following fundamental class that when combined
45  forms the backbone of the VDB tree data structure:
46 
47  Coord- a signed integer coordinate
48  Vec3 - a 3D vector
49  Vec4 - a 4D vector
50  BBox - a bounding box
51  Mask - a bitmask essential to the non-root tree nodes
52  Map - an affine coordinate transformation
53  Grid - contains a Tree and a map for world<->index transformations. Use
54  this class as the main API with client code!
55  Tree - contains a RootNode and getValue methods that should only be used for debugging
56  RootNode - the top-level node of the VDB data structure
57  InternalNode - the internal nodes of the VDB data structure
58  LeafNode - the lowest level tree nodes that encode voxel values and state
59  ReadAccessor - implements accelerated random access operations
60 
61  Semantics: A VDB data structure encodes values and (binary) states associated with
62  signed integer coordinates. Values encoded at the leaf node level are
63  denoted voxel values, and values associated with other tree nodes are referred
64  to as tile values, which by design cover a larger coordinate index domain.
65 
66 
67  Memory layout:
68 
69  It's important to emphasize that all the grid data (defined below) are explicitly 32 byte
70  aligned, which implies that any memory buffer that contains a NanoVDB grid must also be at
71  32 byte aligned. That is, the memory address of the beginning of a buffer (see ascii diagram below)
72  must be divisible by 32, i.e. uintptr_t(&buffer)%32 == 0! If this is not the case, the C++ standard
73  says the behaviour is undefined! Normally this is not a concerns on GPUs, because they use 256 byte
74  aligned allocations, but the same cannot be said about the CPU.
75 
76  GridData is always at the very beginning of the buffer immediately followed by TreeData!
77  The remaining nodes and blind-data are allowed to be scattered throughout the buffer,
78  though in practice they are arranged as:
79 
80  GridData: 672 bytes (e.g. magic, checksum, major, flags, index, count, size, name, map, world bbox, voxel size, class, type, offset, count)
81 
82  TreeData: 64 bytes (node counts and byte offsets)
83 
84  ... optional padding ...
85 
86  RootData: size depends on ValueType (index bbox, voxel count, tile count, min/max/avg/standard deviation)
87 
88  Array of: RootData::Tile
89 
90  ... optional padding ...
91 
92  Array of: Upper InternalNodes of size 32^3: bbox, two bit masks, 32768 tile values, and min/max/avg/standard deviation values
93 
94  ... optional padding ...
95 
96  Array of: Lower InternalNodes of size 16^3: bbox, two bit masks, 4096 tile values, and min/max/avg/standard deviation values
97 
98  ... optional padding ...
99 
100  Array of: LeafNodes of size 8^3: bbox, bit masks, 512 voxel values, and min/max/avg/standard deviation values
101 
102 
103  Notation: "]---[" implies it has optional padding, and "][" implies zero padding
104 
105  [GridData(672B)][TreeData(64B)]---[RootData][N x Root::Tile]---[InternalData<5>]---[InternalData<4>]---[LeafData<3>]---[BLINDMETA...]---[BLIND0]---[BLIND1]---etc.
106  ^ ^ ^ ^ ^ ^
107  | | | | | |
108  +-- Start of 32B aligned buffer | | | | +-- Node0::DataType* leafData
109  GridType::DataType* gridData | | | |
110  | | | +-- Node1::DataType* lowerData
111  RootType::DataType* rootData --+ | |
112  | +-- Node2::DataType* upperData
113  |
114  +-- RootType::DataType::Tile* tile
115 
116 */
117 
118 #ifndef NANOVDB_NANOVDB_H_HAS_BEEN_INCLUDED
119 #define NANOVDB_NANOVDB_H_HAS_BEEN_INCLUDED
120 
121 // The following two header files are the only mandatory dependencies
122 #include <nanovdb/util/Util.h>// for __hostdev__ and lots of other utility functions
123 #include <nanovdb/math/Math.h>// for Coord, BBox, Vec3, Vec4 etc
124 
125 // Do not change this value! 32 byte alignment is fixed in NanoVDB
126 #define NANOVDB_DATA_ALIGNMENT 32
127 
128 // NANOVDB_MAGIC_NUMB is currently used for both grids and files (starting with v32.6.0)
129 // NANOVDB_MAGIC_GRID will soon be used exclusively for grids (serialized to a single buffer)
130 // NANOVDB_MAGIC_FILE will soon be used exclusively for files
131 // NANOVDB_MAGIC_NODE will soon be used exclusively for NodeManager
132 // NANOVDB_MAGIC_FRAG will soon be used exclusively for a fragmented grid, i.e. a grid that is not serialized
133 // | : 0 in 30 corresponds to 0 in NanoVDB0
134 #define NANOVDB_MAGIC_NUMB 0x304244566f6e614eUL // "NanoVDB0" in hex - little endian (uint64_t)
135 #define NANOVDB_MAGIC_GRID 0x314244566f6e614eUL // "NanoVDB1" in hex - little endian (uint64_t)
136 #define NANOVDB_MAGIC_FILE 0x324244566f6e614eUL // "NanoVDB2" in hex - little endian (uint64_t)
137 #define NANOVDB_MAGIC_NODE 0x334244566f6e614eUL // "NanoVDB3" in hex - little endian (uint64_t)
138 #define NANOVDB_MAGIC_FRAG 0x344244566f6e614eUL // "NanoVDB4" in hex - little endian (uint64_t)
139 #define NANOVDB_MAGIC_MASK 0x00FFFFFFFFFFFFFFUL // use this mask to remove the number
140 
141 //#define NANOVDB_MAGIC_NUMBER 0x304244566f6e614eUL
142 //#define NANOVDB_USE_NEW_MAGIC_NUMBERS// used to enable use of the new magic numbers described above
143 
144 #define NANOVDB_MAJOR_VERSION_NUMBER 32 // reflects changes to the ABI and hence also the file format
145 #define NANOVDB_MINOR_VERSION_NUMBER 7 // reflects changes to the API but not ABI
146 #define NANOVDB_PATCH_VERSION_NUMBER 0 // reflects changes that does not affect the ABI or API
147 
148 #define TBB_SUPPRESS_DEPRECATED_MESSAGES 1
149 
150 // This replaces a Coord key at the root level with a single uint64_t
151 #define NANOVDB_USE_SINGLE_ROOT_KEY
152 
153 // This replaces three levels of Coord keys in the ReadAccessor with one Coord
154 //#define NANOVDB_USE_SINGLE_ACCESSOR_KEY
155 
156 // Use this to switch between std::ofstream or FILE implementations
157 //#define NANOVDB_USE_IOSTREAMS
158 
159 // Use this to switch between old and new accessor methods
160 #define NANOVDB_NEW_ACCESSOR_METHODS
161 
162 #define NANOVDB_FPN_BRANCHLESS
163 
164 #if !defined(NANOVDB_ALIGN)
165 #define NANOVDB_ALIGN(n) alignas(n)
166 #endif // !defined(NANOVDB_ALIGN)
167 
168 namespace nanovdb {// =================================================================
169 
170 // --------------------------> Build types <------------------------------------
171 
172 /// @brief Dummy type for a voxel whose value equals an offset into an external value array
173 class ValueIndex{};
174 
175 /// @brief Dummy type for a voxel whose value equals an offset into an external value array of active values
176 class ValueOnIndex{};
177 
178 /// @brief Like @c ValueIndex but with a mutable mask
180 
181 /// @brief Like @c ValueOnIndex but with a mutable mask
183 
184 /// @brief Dummy type for a voxel whose value equals its binary active state
185 class ValueMask{};
186 
187 /// @brief Dummy type for a 16 bit floating point values (placeholder for IEEE 754 Half)
188 class Half{};
189 
190 /// @brief Dummy type for a 4bit quantization of float point values
191 class Fp4{};
192 
193 /// @brief Dummy type for a 8bit quantization of float point values
194 class Fp8{};
195 
196 /// @brief Dummy type for a 16bit quantization of float point values
197 class Fp16{};
198 
199 /// @brief Dummy type for a variable bit quantization of floating point values
200 class FpN{};
201 
202 /// @brief Dummy type for indexing points into voxels
203 class Point{};
204 
205 // --------------------------> GridType <------------------------------------
206 
207 /// @brief return the number of characters (including null termination) required to convert enum type to a string
208 template <class EnumT>
209 __hostdev__ inline constexpr uint32_t strlen(){return (uint32_t)EnumT::StrLen - (uint32_t)EnumT::End;}
210 
211 /// @brief List of types that are currently supported by NanoVDB
212 ///
213 /// @note To expand on this list do:
214 /// 1) Add the new type between Unknown and End in the enum below
215 /// 2) Add the new type to OpenToNanoVDB::processGrid that maps OpenVDB types to GridType
216 /// 3) Verify that the ConvertTrait in NanoToOpenVDB.h works correctly with the new type
217 /// 4) Add the new type to toGridType (defined below) that maps NanoVDB types to GridType
218 /// 5) Add the new type to toStr (defined below)
219 enum class GridType : uint32_t { Unknown = 0, // unknown value type - should rarely be used
220  Float = 1, // single precision floating point value
221  Double = 2, // double precision floating point value
222  Int16 = 3, // half precision signed integer value
223  Int32 = 4, // single precision signed integer value
224  Int64 = 5, // double precision signed integer value
225  Vec3f = 6, // single precision floating 3D vector
226  Vec3d = 7, // double precision floating 3D vector
227  Mask = 8, // no value, just the active state
228  Half = 9, // half precision floating point value (placeholder for IEEE 754 Half)
229  UInt32 = 10, // single precision unsigned integer value
230  Boolean = 11, // boolean value, encoded in bit array
231  RGBA8 = 12, // RGBA packed into 32bit word in reverse-order, i.e. R is lowest byte.
232  Fp4 = 13, // 4bit quantization of floating point value
233  Fp8 = 14, // 8bit quantization of floating point value
234  Fp16 = 15, // 16bit quantization of floating point value
235  FpN = 16, // variable bit quantization of floating point value
236  Vec4f = 17, // single precision floating 4D vector
237  Vec4d = 18, // double precision floating 4D vector
238  Index = 19, // index into an external array of active and inactive values
239  OnIndex = 20, // index into an external array of active values
240  IndexMask = 21, // like Index but with a mutable mask
241  OnIndexMask = 22, // like OnIndex but with a mutable mask
242  PointIndex = 23, // voxels encode indices to co-located points
243  Vec3u8 = 24, // 8bit quantization of floating point 3D vector (only as blind data)
244  Vec3u16 = 25, // 16bit quantization of floating point 3D vector (only as blind data)
245  UInt8 = 26, // 8 bit unsigned integer values (eg 0 -> 255 gray scale)
246  End = 27,// total number of types in this enum (excluding StrLen since it's not a type)
247  StrLen = End + 12};// this entry is used to determine the minimum size of c-string
248 
249 /// @brief Maps a GridType to a c-string
250 /// @param dst destination string of size 12 or larger
251 /// @param gridType GridType enum to be mapped to a string
252 /// @return Retuns a c-string used to describe a GridType
253 __hostdev__ inline char* toStr(char *dst, GridType gridType)
254 {
255  switch (gridType){
256  case GridType::Unknown: return util::strcpy(dst, "?");
257  case GridType::Float: return util::strcpy(dst, "float");
258  case GridType::Double: return util::strcpy(dst, "double");
259  case GridType::Int16: return util::strcpy(dst, "int16");
260  case GridType::Int32: return util::strcpy(dst, "int32");
261  case GridType::Int64: return util::strcpy(dst, "int64");
262  case GridType::Vec3f: return util::strcpy(dst, "Vec3f");
263  case GridType::Vec3d: return util::strcpy(dst, "Vec3d");
264  case GridType::Mask: return util::strcpy(dst, "Mask");
265  case GridType::Half: return util::strcpy(dst, "Half");
266  case GridType::UInt32: return util::strcpy(dst, "uint32");
267  case GridType::Boolean: return util::strcpy(dst, "bool");
268  case GridType::RGBA8: return util::strcpy(dst, "RGBA8");
269  case GridType::Fp4: return util::strcpy(dst, "Float4");
270  case GridType::Fp8: return util::strcpy(dst, "Float8");
271  case GridType::Fp16: return util::strcpy(dst, "Float16");
272  case GridType::FpN: return util::strcpy(dst, "FloatN");
273  case GridType::Vec4f: return util::strcpy(dst, "Vec4f");
274  case GridType::Vec4d: return util::strcpy(dst, "Vec4d");
275  case GridType::Index: return util::strcpy(dst, "Index");
276  case GridType::OnIndex: return util::strcpy(dst, "OnIndex");
277  case GridType::IndexMask: return util::strcpy(dst, "IndexMask");
278  case GridType::OnIndexMask: return util::strcpy(dst, "OnIndexMask");
279  case GridType::PointIndex: return util::strcpy(dst, "PointIndex");
280  case GridType::Vec3u8: return util::strcpy(dst, "Vec3u8");
281  case GridType::Vec3u16: return util::strcpy(dst, "Vec3u16");
282  case GridType::UInt8: return util::strcpy(dst, "uint8");
283  default: return util::strcpy(dst, "End");
284  }
285 }
286 
287 // --------------------------> GridClass <------------------------------------
288 
289 /// @brief Classes (superset of OpenVDB) that are currently supported by NanoVDB
290 enum class GridClass : uint32_t { Unknown = 0,
291  LevelSet = 1, // narrow band level set, e.g. SDF
292  FogVolume = 2, // fog volume, e.g. density
293  Staggered = 3, // staggered MAC grid, e.g. velocity
294  PointIndex = 4, // point index grid
295  PointData = 5, // point data grid
296  Topology = 6, // grid with active states only (no values)
297  VoxelVolume = 7, // volume of geometric cubes, e.g. colors cubes in Minecraft
298  IndexGrid = 8, // grid whose values are offsets, e.g. into an external array
299  TensorGrid = 9, // Index grid for indexing learnable tensor features
300  End = 10,// total number of types in this enum (excluding StrLen since it's not a type)
301  StrLen = End + 7};// this entry is used to determine the minimum size of c-string
302 
303 
304 /// @brief Retuns a c-string used to describe a GridClass
305 /// @param dst destination string of size 7 or larger
306 /// @param gridClass GridClass enum to be converted to a string
307 __hostdev__ inline char* toStr(char *dst, GridClass gridClass)
308 {
309  switch (gridClass){
310  case GridClass::Unknown: return util::strcpy(dst, "?");
311  case GridClass::LevelSet: return util::strcpy(dst, "SDF");
312  case GridClass::FogVolume: return util::strcpy(dst, "FOG");
313  case GridClass::Staggered: return util::strcpy(dst, "MAC");
314  case GridClass::PointIndex: return util::strcpy(dst, "PNTIDX");
315  case GridClass::PointData: return util::strcpy(dst, "PNTDAT");
316  case GridClass::Topology: return util::strcpy(dst, "TOPO");
317  case GridClass::VoxelVolume: return util::strcpy(dst, "VOX");
318  case GridClass::IndexGrid: return util::strcpy(dst, "INDEX");
319  case GridClass::TensorGrid: return util::strcpy(dst, "TENSOR");
320  default: return util::strcpy(dst, "END");
321  }
322 }
323 
324 // --------------------------> GridFlags <------------------------------------
325 
326 /// @brief Grid flags which indicate what extra information is present in the grid buffer.
327 enum class GridFlags : uint32_t {
328  HasLongGridName = 1 << 0, // grid name is longer than 256 characters
329  HasBBox = 1 << 1, // nodes contain bounding-boxes of active values
330  HasMinMax = 1 << 2, // nodes contain min/max of active values
331  HasAverage = 1 << 3, // nodes contain averages of active values
332  HasStdDeviation = 1 << 4, // nodes contain standard deviations of active values
333  IsBreadthFirst = 1 << 5, // nodes are typically arranged breadth-first in memory
334  End = 1 << 6, // use End - 1 as a mask for the 5 lower bit flags
335  StrLen = End + 23,// this entry is used to determine the minimum size of c-string
336 };
337 
338 /// @brief Retuns a c-string used to describe a GridFlags
339 /// @param dst destination string of size 23 or larger
340 /// @param gridFlags GridFlags enum to be converted to a string
341 __hostdev__ inline const char* toStr(char *dst, GridFlags gridFlags)
342 {
343  switch (gridFlags){
344  case GridFlags::HasLongGridName: return util::strcpy(dst, "has long grid name");
345  case GridFlags::HasBBox: return util::strcpy(dst, "has bbox");
346  case GridFlags::HasMinMax: return util::strcpy(dst, "has min/max");
347  case GridFlags::HasAverage: return util::strcpy(dst, "has average");
348  case GridFlags::HasStdDeviation: return util::strcpy(dst, "has standard deviation");
349  case GridFlags::IsBreadthFirst: return util::strcpy(dst, "is breadth-first");
350  default: return util::strcpy(dst, "end");
351  }
352 }
353 
354 // --------------------------> MagicType <------------------------------------
355 
356 /// @brief Enums used to identify magic numbers recognized by NanoVDB
357 enum class MagicType : uint32_t { Unknown = 0,// first 64 bits are neither of the cases below
358  OpenVDB = 1,// first 32 bits = 0x56444220UL
359  NanoVDB = 2,// first 64 bits = NANOVDB_MAGIC_NUMB
360  NanoGrid = 3,// first 64 bits = NANOVDB_MAGIC_GRID
361  NanoFile = 4,// first 64 bits = NANOVDB_MAGIC_FILE
362  NanoNode = 5,// first 64 bits = NANOVDB_MAGIC_NODE
363  NanoFrag = 6,// first 64 bits = NANOVDB_MAGIC_FRAG
364  End = 7,
365  StrLen = End + 25};// this entry is used to determine the minimum size of c-string
366 
367 /// @brief maps 64 bits of magic number to enum
368 __hostdev__ inline MagicType toMagic(uint64_t magic)
369 {
370  switch (magic){
376  default: return (magic & ~uint32_t(0)) == 0x56444220UL ? MagicType::OpenVDB : MagicType::Unknown;
377  }
378 }
379 
380 /// @brief print 64-bit magic number to string
381 /// @param dst destination string of size 25 or larger
382 /// @param magic 64 bit magic number to be printed
383 /// @return return destination string @c dst
384 __hostdev__ inline char* toStr(char *dst, MagicType magic)
385 {
386  switch (magic){
387  case MagicType::Unknown: return util::strcpy(dst, "unknown");
388  case MagicType::NanoVDB: return util::strcpy(dst, "nanovdb");
389  case MagicType::NanoGrid: return util::strcpy(dst, "nanovdb::Grid");
390  case MagicType::NanoFile: return util::strcpy(dst, "nanovdb::File");
391  case MagicType::NanoNode: return util::strcpy(dst, "nanovdb::NodeManager");
392  case MagicType::NanoFrag: return util::strcpy(dst, "fragmented nanovdb::Grid");
393  case MagicType::OpenVDB: return util::strcpy(dst, "openvdb");
394  default: return util::strcpy(dst, "end");
395  }
396 }
397 
398 // --------------------------> PointType enums <------------------------------------
399 
400 // Define the type used when the points are encoded as blind data in the output grid
401 enum class PointType : uint32_t { Disable = 0,// no point information e.g. when BuildT != Point
402  PointID = 1,// linear index of type uint32_t to points
403  World64 = 2,// Vec3d in world space
404  World32 = 3,// Vec3f in world space
405  Grid64 = 4,// Vec3d in grid space
406  Grid32 = 5,// Vec3f in grid space
407  Voxel32 = 6,// Vec3f in voxel space
408  Voxel16 = 7,// Vec3u16 in voxel space
409  Voxel8 = 8,// Vec3u8 in voxel space
410  Default = 9,// output matches input, i.e. Vec3d or Vec3f in world space
411  End =10 };
412 
413 // --------------------------> GridBlindData enums <------------------------------------
414 
415 /// @brief Blind-data Classes that are currently supported by NanoVDB
416 enum class GridBlindDataClass : uint32_t { Unknown = 0,
417  IndexArray = 1,
418  AttributeArray = 2,
419  GridName = 3,
420  ChannelArray = 4,
421  End = 5 };
422 
423 /// @brief Blind-data Semantics that are currently understood by NanoVDB
424 enum class GridBlindDataSemantic : uint32_t { Unknown = 0,
425  PointPosition = 1, // 3D coordinates in an unknown space
426  PointColor = 2,
427  PointNormal = 3,
428  PointRadius = 4,
429  PointVelocity = 5,
430  PointId = 6,
431  WorldCoords = 7, // 3D coordinates in world space, e.g. (0.056, 0.8, 1,8)
432  GridCoords = 8, // 3D coordinates in grid space, e.g. (1.2, 4.0, 5.7), aka index-space
433  VoxelCoords = 9, // 3D coordinates in voxel space, e.g. (0.2, 0.0, 0.7)
434  End = 10 };
435 
436 // --------------------------> BuildTraits <------------------------------------
437 
438 /// @brief Define static boolean tests for template build types
439 template<typename T>
441 {
442  // check if T is an index type
445  static constexpr bool is_offindex = util::is_same<T, ValueIndex, ValueIndexMask>::value;
446  static constexpr bool is_indexmask = util::is_same<T, ValueIndexMask, ValueOnIndexMask>::value;
447  // check if T is a compressed float type with fixed bit precision
448  static constexpr bool is_FpX = util::is_same<T, Fp4, Fp8, Fp16>::value;
449  // check if T is a compressed float type with fixed or variable bit precision
450  static constexpr bool is_Fp = util::is_same<T, Fp4, Fp8, Fp16, FpN>::value;
451  // check if T is a POD float type, i.e float or double
452  static constexpr bool is_float = util::is_floating_point<T>::value;
453  // check if T is a template specialization of LeafData<T>, i.e. has T mValues[512]
454  static constexpr bool is_special = is_index || is_Fp || util::is_same<T, Point, bool, ValueMask>::value;
455 }; // BuildTraits
456 
457 // --------------------------> BuildToValueMap <------------------------------------
458 
459 /// @brief Maps one type (e.g. the build types above) to other (actual) types
460 template<typename T>
462 {
463  using Type = T;
464  using type = T;
465 };
466 
467 template<>
469 {
470  using Type = uint64_t;
471  using type = uint64_t;
472 };
473 
474 template<>
476 {
477  using Type = uint64_t;
478  using type = uint64_t;
479 };
480 
481 template<>
483 {
484  using Type = uint64_t;
485  using type = uint64_t;
486 };
487 
488 template<>
490 {
491  using Type = uint64_t;
492  using type = uint64_t;
493 };
494 
495 template<>
497 {
498  using Type = bool;
499  using type = bool;
500 };
501 
502 template<>
504 {
505  using Type = float;
506  using type = float;
507 };
508 
509 template<>
511 {
512  using Type = float;
513  using type = float;
514 };
515 
516 template<>
518 {
519  using Type = float;
520  using type = float;
521 };
522 
523 template<>
525 {
526  using Type = float;
527  using type = float;
528 };
529 
530 template<>
532 {
533  using Type = float;
534  using type = float;
535 };
536 
537 template<>
539 {
540  using Type = uint64_t;
541  using type = uint64_t;
542 };
543 
544 // --------------------------> utility functions related to alignment <------------------------------------
545 
546 /// @brief return true if the specified pointer is 32 byte aligned
547 __hostdev__ inline static bool isAligned(const void* p){return uint64_t(p) % NANOVDB_DATA_ALIGNMENT == 0;}
548 
549 /// @brief return the smallest number of bytes that when added to the specified pointer results in a 32 byte aligned pointer.
550 __hostdev__ inline static uint64_t alignmentPadding(const void* p)
551 {
552  NANOVDB_ASSERT(p);
554 }
555 
556 /// @brief offset the specified pointer so it is 32 byte aligned. Works with both const and non-const pointers.
557 template <typename T>
558 __hostdev__ inline static T* alignPtr(T* p){return util::PtrAdd<T>(p, alignmentPadding(p));}
559 
560 // --------------------------> isFloatingPoint(GridType) <------------------------------------
561 
562 /// @brief return true if the GridType maps to a floating point type
563 __hostdev__ inline bool isFloatingPoint(GridType gridType)
564 {
565  return gridType == GridType::Float ||
566  gridType == GridType::Double ||
567  gridType == GridType::Half ||
568  gridType == GridType::Fp4 ||
569  gridType == GridType::Fp8 ||
570  gridType == GridType::Fp16 ||
571  gridType == GridType::FpN;
572 }
573 
574 // --------------------------> isFloatingPointVector(GridType) <------------------------------------
575 
576 /// @brief return true if the GridType maps to a floating point vec3.
578 {
579  return gridType == GridType::Vec3f ||
580  gridType == GridType::Vec3d ||
581  gridType == GridType::Vec4f ||
582  gridType == GridType::Vec4d;
583 }
584 
585 // --------------------------> isInteger(GridType) <------------------------------------
586 
587 /// @brief Return true if the GridType maps to a POD integer type.
588 /// @details These types are used to associate a voxel with a POD integer type
589 __hostdev__ inline bool isInteger(GridType gridType)
590 {
591  return gridType == GridType::Int16 ||
592  gridType == GridType::Int32 ||
593  gridType == GridType::Int64 ||
594  gridType == GridType::UInt32||
595  gridType == GridType::UInt8;
596 }
597 
598 // --------------------------> isIndex(GridType) <------------------------------------
599 
600 /// @brief Return true if the GridType maps to a special index type (not a POD integer type).
601 /// @details These types are used to index from a voxel into an external array of values, e.g. sidecar or blind data.
602 __hostdev__ inline bool isIndex(GridType gridType)
603 {
604  return gridType == GridType::Index ||// index both active and inactive values
605  gridType == GridType::OnIndex ||// index active values only
606  gridType == GridType::IndexMask ||// as Index, but with an additional mask
607  gridType == GridType::OnIndexMask;// as OnIndex, but with an additional mask
608 }
609 
610 // --------------------------> isValue(GridType, GridClass) <------------------------------------
611 
612 /// @brief return true if the combination of GridType and GridClass is valid.
613 __hostdev__ inline bool isValid(GridType gridType, GridClass gridClass)
614 {
615  if (gridClass == GridClass::LevelSet || gridClass == GridClass::FogVolume) {
616  return isFloatingPoint(gridType);
617  } else if (gridClass == GridClass::Staggered) {
618  return isFloatingPointVector(gridType);
619  } else if (gridClass == GridClass::PointIndex || gridClass == GridClass::PointData) {
620  return gridType == GridType::PointIndex || gridType == GridType::UInt32;
621  } else if (gridClass == GridClass::Topology) {
622  return gridType == GridType::Mask;
623  } else if (gridClass == GridClass::IndexGrid) {
624  return isIndex(gridType);
625  } else if (gridClass == GridClass::VoxelVolume) {
626  return gridType == GridType::RGBA8 || gridType == GridType::Float ||
627  gridType == GridType::Double || gridType == GridType::Vec3f ||
628  gridType == GridType::Vec3d || gridType == GridType::UInt32 ||
629  gridType == GridType::UInt8;
630  }
631  return gridClass < GridClass::End && gridType < GridType::End; // any valid combination
632 }
633 
634 // --------------------------> validation of blind data meta data <------------------------------------
635 
636 /// @brief return true if the combination of GridBlindDataClass, GridBlindDataSemantic and GridType is valid.
637 __hostdev__ inline bool isValid(const GridBlindDataClass& blindClass,
638  const GridBlindDataSemantic& blindSemantics,
639  const GridType& blindType)
640 {
641  bool test = false;
642  switch (blindClass) {
644  test = (blindSemantics == GridBlindDataSemantic::Unknown ||
645  blindSemantics == GridBlindDataSemantic::PointId) &&
646  isInteger(blindType);
647  break;
649  if (blindSemantics == GridBlindDataSemantic::PointPosition ||
650  blindSemantics == GridBlindDataSemantic::WorldCoords) {
651  test = blindType == GridType::Vec3f || blindType == GridType::Vec3d;
652  } else if (blindSemantics == GridBlindDataSemantic::GridCoords) {
653  test = blindType == GridType::Vec3f;
654  } else if (blindSemantics == GridBlindDataSemantic::VoxelCoords) {
655  test = blindType == GridType::Vec3f || blindType == GridType::Vec3u8 || blindType == GridType::Vec3u16;
656  } else {
657  test = blindSemantics != GridBlindDataSemantic::PointId;
658  }
659  break;
661  test = blindSemantics == GridBlindDataSemantic::Unknown && blindType == GridType::Unknown;
662  break;
663  default: // captures blindClass == Unknown and ChannelArray
664  test = blindClass < GridBlindDataClass::End &&
665  blindSemantics < GridBlindDataSemantic::End &&
666  blindType < GridType::End; // any valid combination
667  break;
668  }
669  //if (!test) printf("Invalid combination: GridBlindDataClass=%u, GridBlindDataSemantic=%u, GridType=%u\n",(uint32_t)blindClass, (uint32_t)blindSemantics, (uint32_t)blindType);
670  return test;
671 }
672 
673 // ----------------------------> Version class <-------------------------------------
674 
675 /// @brief Bit-compacted representation of all three version numbers
676 ///
677 /// @details major is the top 11 bits, minor is the 11 middle bits and patch is the lower 10 bits
678 class Version
679 {
680  uint32_t mData; // 11 + 11 + 10 bit packing of major + minor + patch
681 public:
682  static constexpr uint32_t End = 0, StrLen = 8;// for strlen<Version>()
683  /// @brief Default constructor
685  : mData(uint32_t(NANOVDB_MAJOR_VERSION_NUMBER) << 21 |
686  uint32_t(NANOVDB_MINOR_VERSION_NUMBER) << 10 |
688  {
689  }
690  /// @brief Constructor from a raw uint32_t data representation
691  __hostdev__ Version(uint32_t data) : mData(data) {}
692  /// @brief Constructor from major.minor.patch version numbers
693  __hostdev__ Version(uint32_t major, uint32_t minor, uint32_t patch)
694  : mData(major << 21 | minor << 10 | patch)
695  {
696  NANOVDB_ASSERT(major < (1u << 11)); // max value of major is 2047
697  NANOVDB_ASSERT(minor < (1u << 11)); // max value of minor is 2047
698  NANOVDB_ASSERT(patch < (1u << 10)); // max value of patch is 1023
699  }
700  __hostdev__ bool operator==(const Version& rhs) const { return mData == rhs.mData; }
701  __hostdev__ bool operator<( const Version& rhs) const { return mData < rhs.mData; }
702  __hostdev__ bool operator<=(const Version& rhs) const { return mData <= rhs.mData; }
703  __hostdev__ bool operator>( const Version& rhs) const { return mData > rhs.mData; }
704  __hostdev__ bool operator>=(const Version& rhs) const { return mData >= rhs.mData; }
705  __hostdev__ uint32_t id() const { return mData; }
706  __hostdev__ uint32_t getMajor() const { return (mData >> 21) & ((1u << 11) - 1); }
707  __hostdev__ uint32_t getMinor() const { return (mData >> 10) & ((1u << 11) - 1); }
708  __hostdev__ uint32_t getPatch() const { return mData & ((1u << 10) - 1); }
709  __hostdev__ bool isCompatible() const { return this->getMajor() == uint32_t(NANOVDB_MAJOR_VERSION_NUMBER); }
710  /// @brief Returns the difference between major version of this instance and NANOVDB_MAJOR_VERSION_NUMBER
711  /// @return return 0 if the major version equals NANOVDB_MAJOR_VERSION_NUMBER, else a negative age if this
712  /// instance has a smaller major verion (is older), and a positive age if it is newer, i.e. larger.
713  __hostdev__ int age() const {return int(this->getMajor()) - int(NANOVDB_MAJOR_VERSION_NUMBER);}
714 }; // Version
715 
716 /// @brief print the verion number to a c-string
717 /// @param dst destination string of size 8 or more
718 /// @param v version to be printed
719 /// @return returns destination string @c dst
720 __hostdev__ inline char* toStr(char *dst, const Version &v)
721 {
722  return util::sprint(dst, v.getMajor(), ".",v.getMinor(), ".",v.getPatch());
723 }
724 
725 // ----------------------------> TensorTraits <--------------------------------------
726 
727 template<typename T, int Rank = (util::is_specialization<T, math::Vec3>::value || util::is_specialization<T, math::Vec4>::value || util::is_same<T, math::Rgba8>::value) ? 1 : 0>
729 
730 template<typename T>
731 struct TensorTraits<T, 0>
732 {
733  static const int Rank = 0; // i.e. scalar
734  static const bool IsScalar = true;
735  static const bool IsVector = false;
736  static const int Size = 1;
737  using ElementType = T;
738  static T scalar(const T& s) { return s; }
739 };
740 
741 template<typename T>
742 struct TensorTraits<T, 1>
743 {
744  static const int Rank = 1; // i.e. vector
745  static const bool IsScalar = false;
746  static const bool IsVector = true;
747  static const int Size = T::SIZE;
748  using ElementType = typename T::ValueType;
749  static ElementType scalar(const T& v) { return v.length(); }
750 };
751 
752 // ----------------------------> FloatTraits <--------------------------------------
753 
754 template<typename T, int = sizeof(typename TensorTraits<T>::ElementType)>
756 {
757  using FloatType = float;
758 };
759 
760 template<typename T>
761 struct FloatTraits<T, 8>
762 {
763  using FloatType = double;
764 };
765 
766 template<>
767 struct FloatTraits<bool, 1>
768 {
769  using FloatType = bool;
770 };
771 
772 template<>
773 struct FloatTraits<ValueIndex, 1> // size of empty class in C++ is 1 byte and not 0 byte
774 {
775  using FloatType = uint64_t;
776 };
777 
778 template<>
779 struct FloatTraits<ValueIndexMask, 1> // size of empty class in C++ is 1 byte and not 0 byte
780 {
781  using FloatType = uint64_t;
782 };
783 
784 template<>
785 struct FloatTraits<ValueOnIndex, 1> // size of empty class in C++ is 1 byte and not 0 byte
786 {
787  using FloatType = uint64_t;
788 };
789 
790 template<>
791 struct FloatTraits<ValueOnIndexMask, 1> // size of empty class in C++ is 1 byte and not 0 byte
792 {
793  using FloatType = uint64_t;
794 };
795 
796 template<>
797 struct FloatTraits<ValueMask, 1> // size of empty class in C++ is 1 byte and not 0 byte
798 {
799  using FloatType = bool;
800 };
801 
802 template<>
803 struct FloatTraits<Point, 1> // size of empty class in C++ is 1 byte and not 0 byte
804 {
805  using FloatType = double;
806 };
807 
808 // ----------------------------> mapping BuildType -> GridType <--------------------------------------
809 
810 /// @brief Maps from a templated build type to a GridType enum
811 template<typename BuildT>
813 {
814  if constexpr(util::is_same<BuildT, float>::value) { // resolved at compile-time
815  return GridType::Float;
816  } else if constexpr(util::is_same<BuildT, double>::value) {
817  return GridType::Double;
818  } else if constexpr(util::is_same<BuildT, int16_t>::value) {
819  return GridType::Int16;
820  } else if constexpr(util::is_same<BuildT, int32_t>::value) {
821  return GridType::Int32;
822  } else if constexpr(util::is_same<BuildT, int64_t>::value) {
823  return GridType::Int64;
824  } else if constexpr(util::is_same<BuildT, Vec3f>::value) {
825  return GridType::Vec3f;
826  } else if constexpr(util::is_same<BuildT, Vec3d>::value) {
827  return GridType::Vec3d;
828  } else if constexpr(util::is_same<BuildT, uint32_t>::value) {
829  return GridType::UInt32;
830  } else if constexpr(util::is_same<BuildT, ValueMask>::value) {
831  return GridType::Mask;
832  } else if constexpr(util::is_same<BuildT, Half>::value) {
833  return GridType::Half;
834  } else if constexpr(util::is_same<BuildT, ValueIndex>::value) {
835  return GridType::Index;
836  } else if constexpr(util::is_same<BuildT, ValueOnIndex>::value) {
837  return GridType::OnIndex;
838  } else if constexpr(util::is_same<BuildT, ValueIndexMask>::value) {
839  return GridType::IndexMask;
841  return GridType::OnIndexMask;
842  } else if constexpr(util::is_same<BuildT, bool>::value) {
843  return GridType::Boolean;
844  } else if constexpr(util::is_same<BuildT, math::Rgba8>::value) {
845  return GridType::RGBA8;
846  } else if constexpr(util::is_same<BuildT, Fp4>::value) {
847  return GridType::Fp4;
848  } else if constexpr(util::is_same<BuildT, Fp8>::value) {
849  return GridType::Fp8;
850  } else if constexpr(util::is_same<BuildT, Fp16>::value) {
851  return GridType::Fp16;
852  } else if constexpr(util::is_same<BuildT, FpN>::value) {
853  return GridType::FpN;
854  } else if constexpr(util::is_same<BuildT, Vec4f>::value) {
855  return GridType::Vec4f;
856  } else if constexpr(util::is_same<BuildT, Vec4d>::value) {
857  return GridType::Vec4d;
858  } else if constexpr(util::is_same<BuildT, Point>::value) {
859  return GridType::PointIndex;
860  } else if constexpr(util::is_same<BuildT, Vec3u8>::value) {
861  return GridType::Vec3u8;
862  } else if constexpr(util::is_same<BuildT, Vec3u16>::value) {
863  return GridType::Vec3u16;
864  } else if constexpr(util::is_same<BuildT, uint8_t>::value) {
865  return GridType::UInt8;
866  }
867  return GridType::Unknown;
868 }// toGridType
869 
870 template<typename BuildT>
871 [[deprecated("Use toGridType<T>() instead.")]]
872 __hostdev__ inline GridType mapToGridType(){return toGridType<BuildT>();}
873 
874 // ----------------------------> mapping BuildType -> GridClass <--------------------------------------
875 
876 /// @brief Maps from a templated build type to a GridClass enum
877 template<typename BuildT>
879 {
881  return GridClass::Topology;
882  } else if constexpr(BuildTraits<BuildT>::is_index) {
883  return GridClass::IndexGrid;
884  } else if constexpr(util::is_same<BuildT, math::Rgba8>::value) {
885  return GridClass::VoxelVolume;
886  } else if constexpr(util::is_same<BuildT, Point>::value) {
887  return GridClass::PointIndex;
888  }
889  return defaultClass;
890 }
891 
892 template<typename BuildT>
893 [[deprecated("Use toGridClass<T>() instead.")]]
895 {
896  return toGridClass<BuildT>();
897 }
898 
899 // ----------------------------> BitFlags <--------------------------------------
900 
901 template<int N>
902 struct BitArray;
903 template<>
904 struct BitArray<8>
905 {
906  uint8_t mFlags{0};
907 };
908 template<>
909 struct BitArray<16>
910 {
911  uint16_t mFlags{0};
912 };
913 template<>
914 struct BitArray<32>
915 {
916  uint32_t mFlags{0};
917 };
918 template<>
919 struct BitArray<64>
920 {
921  uint64_t mFlags{0};
922 };
923 
924 template<int N>
925 class BitFlags : public BitArray<N>
926 {
927 protected:
928  using BitArray<N>::mFlags;
929 
930 public:
931  using Type = decltype(mFlags);
932  BitFlags() {}
933  BitFlags(Type mask) : BitArray<N>{mask} {}
934  BitFlags(std::initializer_list<uint8_t> list)
935  {
936  for (auto bit : list) mFlags |= static_cast<Type>(1 << bit);
937  }
938  template<typename MaskT>
939  BitFlags(std::initializer_list<MaskT> list)
940  {
941  for (auto mask : list) mFlags |= static_cast<Type>(mask);
942  }
943  __hostdev__ Type data() const { return mFlags; }
944  __hostdev__ Type& data() { return mFlags; }
945  __hostdev__ void initBit(std::initializer_list<uint8_t> list)
946  {
947  mFlags = 0u;
948  for (auto bit : list) mFlags |= static_cast<Type>(1 << bit);
949  }
950  template<typename MaskT>
951  __hostdev__ void initMask(std::initializer_list<MaskT> list)
952  {
953  mFlags = 0u;
954  for (auto mask : list) mFlags |= static_cast<Type>(mask);
955  }
956  //__hostdev__ Type& data() { return mFlags; }
957  //__hostdev__ Type data() const { return mFlags; }
958  __hostdev__ Type getFlags() const { return mFlags & (static_cast<Type>(GridFlags::End) - 1u); } // mask out everything except relevant bits
959 
960  __hostdev__ void setOn() { mFlags = ~Type(0u); }
961  __hostdev__ void setOff() { mFlags = Type(0u); }
962 
963  __hostdev__ void setBitOn(uint8_t bit) { mFlags |= static_cast<Type>(1 << bit); }
964  __hostdev__ void setBitOff(uint8_t bit) { mFlags &= ~static_cast<Type>(1 << bit); }
965 
966  __hostdev__ void setBitOn(std::initializer_list<uint8_t> list)
967  {
968  for (auto bit : list) mFlags |= static_cast<Type>(1 << bit);
969  }
970  __hostdev__ void setBitOff(std::initializer_list<uint8_t> list)
971  {
972  for (auto bit : list) mFlags &= ~static_cast<Type>(1 << bit);
973  }
974 
975  template<typename MaskT>
976  __hostdev__ void setMaskOn(MaskT mask) { mFlags |= static_cast<Type>(mask); }
977  template<typename MaskT>
978  __hostdev__ void setMaskOff(MaskT mask) { mFlags &= ~static_cast<Type>(mask); }
979 
980  template<typename MaskT>
981  __hostdev__ void setMaskOn(std::initializer_list<MaskT> list)
982  {
983  for (auto mask : list) mFlags |= static_cast<Type>(mask);
984  }
985  template<typename MaskT>
986  __hostdev__ void setMaskOff(std::initializer_list<MaskT> list)
987  {
988  for (auto mask : list) mFlags &= ~static_cast<Type>(mask);
989  }
990 
991  __hostdev__ void setBit(uint8_t bit, bool on) { on ? this->setBitOn(bit) : this->setBitOff(bit); }
992  template<typename MaskT>
993  __hostdev__ void setMask(MaskT mask, bool on) { on ? this->setMaskOn(mask) : this->setMaskOff(mask); }
994 
995  __hostdev__ bool isOn() const { return mFlags == ~Type(0u); }
996  __hostdev__ bool isOff() const { return mFlags == Type(0u); }
997  __hostdev__ bool isBitOn(uint8_t bit) const { return 0 != (mFlags & static_cast<Type>(1 << bit)); }
998  __hostdev__ bool isBitOff(uint8_t bit) const { return 0 == (mFlags & static_cast<Type>(1 << bit)); }
999  template<typename MaskT>
1000  __hostdev__ bool isMaskOn(MaskT mask) const { return 0 != (mFlags & static_cast<Type>(mask)); }
1001  template<typename MaskT>
1002  __hostdev__ bool isMaskOff(MaskT mask) const { return 0 == (mFlags & static_cast<Type>(mask)); }
1003  /// @brief return true if any of the masks in the list are on
1004  template<typename MaskT>
1005  __hostdev__ bool isMaskOn(std::initializer_list<MaskT> list) const
1006  {
1007  for (auto mask : list) {
1008  if (0 != (mFlags & static_cast<Type>(mask))) return true;
1009  }
1010  return false;
1011  }
1012  /// @brief return true if any of the masks in the list are off
1013  template<typename MaskT>
1014  __hostdev__ bool isMaskOff(std::initializer_list<MaskT> list) const
1015  {
1016  for (auto mask : list) {
1017  if (0 == (mFlags & static_cast<Type>(mask))) return true;
1018  }
1019  return false;
1020  }
1021  /// @brief required for backwards compatibility
1022  __hostdev__ BitFlags& operator=(Type n)
1023  {
1024  mFlags = n;
1025  return *this;
1026  }
1027 }; // BitFlags<N>
1028 
1029 // ----------------------------> Mask <--------------------------------------
1030 
1031 /// @brief Bit-mask to encode active states and facilitate sequential iterators
1032 /// and a fast codec for I/O compression.
1033 template<uint32_t LOG2DIM>
1034 class Mask
1035 {
1036 public:
1037  static constexpr uint32_t SIZE = 1U << (3 * LOG2DIM); // Number of bits in mask
1038  static constexpr uint32_t WORD_COUNT = SIZE >> 6; // Number of 64 bit words
1039 
1040  /// @brief Return the memory footprint in bytes of this Mask
1041  __hostdev__ static size_t memUsage() { return sizeof(Mask); }
1042 
1043  /// @brief Return the number of bits available in this Mask
1044  __hostdev__ static uint32_t bitCount() { return SIZE; }
1045 
1046  /// @brief Return the number of machine words used by this Mask
1047  __hostdev__ static uint32_t wordCount() { return WORD_COUNT; }
1048 
1049  /// @brief Return the total number of set bits in this Mask
1050  __hostdev__ uint32_t countOn() const
1051  {
1052  uint32_t sum = 0;
1053  for (const uint64_t *w = mWords, *q = w + WORD_COUNT; w != q; ++w)
1054  sum += util::countOn(*w);
1055  return sum;
1056  }
1057 
1058  /// @brief Return the number of lower set bits in mask up to but excluding the i'th bit
1059  inline __hostdev__ uint32_t countOn(uint32_t i) const
1060  {
1061  uint32_t n = i >> 6, sum = util::countOn(mWords[n] & ((uint64_t(1) << (i & 63u)) - 1u));
1062  for (const uint64_t* w = mWords; n--; ++w)
1063  sum += util::countOn(*w);
1064  return sum;
1065  }
1066 
1067  template<bool On>
1068  class Iterator
1069  {
1070  public:
1072  : mPos(Mask::SIZE)
1073  , mParent(nullptr)
1074  {
1075  }
1076  __hostdev__ Iterator(uint32_t pos, const Mask* parent)
1077  : mPos(pos)
1078  , mParent(parent)
1079  {
1080  }
1081  Iterator& operator=(const Iterator&) = default;
1082  __hostdev__ uint32_t operator*() const { return mPos; }
1083  __hostdev__ uint32_t pos() const { return mPos; }
1084  __hostdev__ operator bool() const { return mPos != Mask::SIZE; }
1086  {
1087  mPos = mParent->findNext<On>(mPos + 1);
1088  return *this;
1089  }
1091  {
1092  auto tmp = *this;
1093  ++(*this);
1094  return tmp;
1095  }
1096 
1097  private:
1098  uint32_t mPos;
1099  const Mask* mParent;
1100  }; // Member class Iterator
1101 
1103  {
1104  public:
1106  : mPos(pos)
1107  {
1108  }
1109  DenseIterator& operator=(const DenseIterator&) = default;
1110  __hostdev__ uint32_t operator*() const { return mPos; }
1111  __hostdev__ uint32_t pos() const { return mPos; }
1112  __hostdev__ operator bool() const { return mPos != Mask::SIZE; }
1114  {
1115  ++mPos;
1116  return *this;
1117  }
1119  {
1120  auto tmp = *this;
1121  ++mPos;
1122  return tmp;
1123  }
1124 
1125  private:
1126  uint32_t mPos;
1127  }; // Member class DenseIterator
1128 
1131 
1132  __hostdev__ OnIterator beginOn() const { return OnIterator(this->findFirst<true>(), this); }
1133 
1134  __hostdev__ OffIterator beginOff() const { return OffIterator(this->findFirst<false>(), this); }
1135 
1137 
1138  /// @brief Initialize all bits to zero.
1140  {
1141  for (uint32_t i = 0; i < WORD_COUNT; ++i)
1142  mWords[i] = 0;
1143  }
1145  {
1146  const uint64_t v = on ? ~uint64_t(0) : uint64_t(0);
1147  for (uint32_t i = 0; i < WORD_COUNT; ++i)
1148  mWords[i] = v;
1149  }
1150 
1151  /// @brief Copy constructor
1152  __hostdev__ Mask(const Mask& other)
1153  {
1154  for (uint32_t i = 0; i < WORD_COUNT; ++i)
1155  mWords[i] = other.mWords[i];
1156  }
1157 
1158  /// @brief Return a pointer to the list of words of the bit mask
1159  __hostdev__ uint64_t* words() { return mWords; }
1160  __hostdev__ const uint64_t* words() const { return mWords; }
1161 
1162  template<typename WordT>
1163  __hostdev__ WordT getWord(uint32_t n) const
1164  {
1166  NANOVDB_ASSERT(n*8*sizeof(WordT) < WORD_COUNT);
1167  return reinterpret_cast<WordT*>(mWords)[n];
1168  }
1169  template<typename WordT>
1170  __hostdev__ void setWord(WordT w, uint32_t n)
1171  {
1173  NANOVDB_ASSERT(n*8*sizeof(WordT) < WORD_COUNT);
1174  reinterpret_cast<WordT*>(mWords)[n] = w;
1175  }
1176 
1177  /// @brief Assignment operator that works with openvdb::util::NodeMask
1178  template<typename MaskT = Mask>
1180  {
1181  static_assert(sizeof(Mask) == sizeof(MaskT), "Mismatching sizeof");
1182  static_assert(WORD_COUNT == MaskT::WORD_COUNT, "Mismatching word count");
1183  static_assert(LOG2DIM == MaskT::LOG2DIM, "Mismatching LOG2DIM");
1184  auto* src = reinterpret_cast<const uint64_t*>(&other);
1185  for (uint64_t *dst = mWords, *end = dst + WORD_COUNT; dst != end; ++dst)
1186  *dst = *src++;
1187  return *this;
1188  }
1189 
1190  //__hostdev__ Mask& operator=(const Mask& other){return *util::memcpy(this, &other);}
1191  Mask& operator=(const Mask&) = default;
1192 
1193  __hostdev__ bool operator==(const Mask& other) const
1194  {
1195  for (uint32_t i = 0; i < WORD_COUNT; ++i) {
1196  if (mWords[i] != other.mWords[i])
1197  return false;
1198  }
1199  return true;
1200  }
1201 
1202  __hostdev__ bool operator!=(const Mask& other) const { return !((*this) == other); }
1203 
1204  /// @brief Return true if the given bit is set.
1205  __hostdev__ bool isOn(uint32_t n) const { return 0 != (mWords[n >> 6] & (uint64_t(1) << (n & 63))); }
1206 
1207  /// @brief Return true if the given bit is NOT set.
1208  __hostdev__ bool isOff(uint32_t n) const { return 0 == (mWords[n >> 6] & (uint64_t(1) << (n & 63))); }
1209 
1210  /// @brief Return true if all the bits are set in this Mask.
1211  __hostdev__ bool isOn() const
1212  {
1213  for (uint32_t i = 0; i < WORD_COUNT; ++i)
1214  if (mWords[i] != ~uint64_t(0))
1215  return false;
1216  return true;
1217  }
1218 
1219  /// @brief Return true if none of the bits are set in this Mask.
1220  __hostdev__ bool isOff() const
1221  {
1222  for (uint32_t i = 0; i < WORD_COUNT; ++i)
1223  if (mWords[i] != uint64_t(0))
1224  return false;
1225  return true;
1226  }
1227 
1228  /// @brief Set the specified bit on.
1229  __hostdev__ void setOn(uint32_t n) { mWords[n >> 6] |= uint64_t(1) << (n & 63); }
1230  /// @brief Set the specified bit off.
1231  __hostdev__ void setOff(uint32_t n) { mWords[n >> 6] &= ~(uint64_t(1) << (n & 63)); }
1232 
1233 #if defined(__CUDACC__) // the following functions only run on the GPU!
1234  __device__ inline void setOnAtomic(uint32_t n)
1235  {
1236  atomicOr(reinterpret_cast<unsigned long long int*>(this) + (n >> 6), 1ull << (n & 63));
1237  }
1238  __device__ inline void setOffAtomic(uint32_t n)
1239  {
1240  atomicAnd(reinterpret_cast<unsigned long long int*>(this) + (n >> 6), ~(1ull << (n & 63)));
1241  }
1242  __device__ inline void setAtomic(uint32_t n, bool on)
1243  {
1244  on ? this->setOnAtomic(n) : this->setOffAtomic(n);
1245  }
1246 /*
1247  template<typename WordT>
1248  __device__ inline void setWordAtomic(WordT w, uint32_t n)
1249  {
1250  static_assert(util::is_same<WordT, uint8_t, uint16_t, uint32_t, uint64_t>::value);
1251  NANOVDB_ASSERT(n*8*sizeof(WordT) < WORD_COUNT);
1252  if constexpr(util::is_same<WordT,uint8_t>::value) {
1253  mask <<= x;
1254  } else if constexpr(util::is_same<WordT,uint16_t>::value) {
1255  unsigned int mask = w;
1256  if (n >> 1) mask <<= 16;
1257  atomicOr(reinterpret_cast<unsigned int*>(this) + n, mask);
1258  } else if constexpr(util::is_same<WordT,uint32_t>::value) {
1259  atomicOr(reinterpret_cast<unsigned int*>(this) + n, w);
1260  } else {
1261  atomicOr(reinterpret_cast<unsigned long long int*>(this) + n, w);
1262  }
1263  }
1264 */
1265 #endif
1266  /// @brief Set the specified bit on or off.
1267  __hostdev__ void set(uint32_t n, bool on)
1268  {
1269 #if 1 // switch between branchless
1270  auto& word = mWords[n >> 6];
1271  n &= 63;
1272  word &= ~(uint64_t(1) << n);
1273  word |= uint64_t(on) << n;
1274 #else
1275  on ? this->setOn(n) : this->setOff(n);
1276 #endif
1277  }
1278 
1279  /// @brief Set all bits on
1281  {
1282  for (uint32_t i = 0; i < WORD_COUNT; ++i)mWords[i] = ~uint64_t(0);
1283  }
1284 
1285  /// @brief Set all bits off
1287  {
1288  for (uint32_t i = 0; i < WORD_COUNT; ++i) mWords[i] = uint64_t(0);
1289  }
1290 
1291  /// @brief Set all bits off
1292  __hostdev__ void set(bool on)
1293  {
1294  const uint64_t v = on ? ~uint64_t(0) : uint64_t(0);
1295  for (uint32_t i = 0; i < WORD_COUNT; ++i) mWords[i] = v;
1296  }
1297  /// brief Toggle the state of all bits in the mask
1299  {
1300  uint32_t n = WORD_COUNT;
1301  for (auto* w = mWords; n--; ++w) *w = ~*w;
1302  }
1303  __hostdev__ void toggle(uint32_t n) { mWords[n >> 6] ^= uint64_t(1) << (n & 63); }
1304 
1305  /// @brief Bitwise intersection
1307  {
1308  uint64_t* w1 = mWords;
1309  const uint64_t* w2 = other.mWords;
1310  for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 &= *w2;
1311  return *this;
1312  }
1313  /// @brief Bitwise union
1315  {
1316  uint64_t* w1 = mWords;
1317  const uint64_t* w2 = other.mWords;
1318  for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 |= *w2;
1319  return *this;
1320  }
1321  /// @brief Bitwise difference
1323  {
1324  uint64_t* w1 = mWords;
1325  const uint64_t* w2 = other.mWords;
1326  for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 &= ~*w2;
1327  return *this;
1328  }
1329  /// @brief Bitwise XOR
1331  {
1332  uint64_t* w1 = mWords;
1333  const uint64_t* w2 = other.mWords;
1334  for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 ^= *w2;
1335  return *this;
1336  }
1337 
1339  template<bool ON>
1340  __hostdev__ uint32_t findFirst() const
1341  {
1342  uint32_t n = 0u;
1343  const uint64_t* w = mWords;
1344  for (; n < WORD_COUNT && !(ON ? *w : ~*w); ++w, ++n);
1345  return n < WORD_COUNT ? (n << 6) + util::findLowestOn(ON ? *w : ~*w) : SIZE;
1346  }
1347 
1349  template<bool ON>
1350  __hostdev__ uint32_t findNext(uint32_t start) const
1351  {
1352  uint32_t n = start >> 6; // initiate
1353  if (n >= WORD_COUNT) return SIZE; // check for out of bounds
1354  uint32_t m = start & 63u;
1355  uint64_t b = ON ? mWords[n] : ~mWords[n];
1356  if (b & (uint64_t(1u) << m)) return start; // simple case: start is on/off
1357  b &= ~uint64_t(0u) << m; // mask out lower bits
1358  while (!b && ++n < WORD_COUNT) b = ON ? mWords[n] : ~mWords[n]; // find next non-zero word
1359  return b ? (n << 6) + util::findLowestOn(b) : SIZE; // catch last word=0
1360  }
1361 
1363  template<bool ON>
1364  __hostdev__ uint32_t findPrev(uint32_t start) const
1365  {
1366  uint32_t n = start >> 6; // initiate
1367  if (n >= WORD_COUNT) return SIZE; // check for out of bounds
1368  uint32_t m = start & 63u;
1369  uint64_t b = ON ? mWords[n] : ~mWords[n];
1370  if (b & (uint64_t(1u) << m)) return start; // simple case: start is on/off
1371  b &= (uint64_t(1u) << m) - 1u; // mask out higher bits
1372  while (!b && n) b = ON ? mWords[--n] : ~mWords[--n]; // find previous non-zero word
1373  return b ? (n << 6) + util::findHighestOn(b) : SIZE; // catch first word=0
1374  }
1375 
1376 private:
1377  uint64_t mWords[WORD_COUNT];
1378 }; // Mask class
1379 
1380 // ----------------------------> Map <--------------------------------------
1381 
1382 /// @brief Defines an affine transform and its inverse represented as a 3x3 matrix and a vec3 translation
1383 struct Map
1384 { // 264B (not 32B aligned!)
1385  float mMatF[9]; // 9*4B <- 3x3 matrix
1386  float mInvMatF[9]; // 9*4B <- 3x3 matrix
1387  float mVecF[3]; // 3*4B <- translation
1388  float mTaperF; // 4B, placeholder for taper value
1389  double mMatD[9]; // 9*8B <- 3x3 matrix
1390  double mInvMatD[9]; // 9*8B <- 3x3 matrix
1391  double mVecD[3]; // 3*8B <- translation
1392  double mTaperD; // 8B, placeholder for taper value
1393 
1394  /// @brief Default constructor for the identity map
1396  : mMatF{ 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}
1397  , mInvMatF{1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}
1398  , mVecF{0.0f, 0.0f, 0.0f}
1399  , mTaperF{1.0f}
1400  , mMatD{ 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}
1401  , mInvMatD{1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}
1402  , mVecD{0.0, 0.0, 0.0}
1403  , mTaperD{1.0}
1404  {
1405  }
1406  __hostdev__ Map(double s, const Vec3d& t = Vec3d(0.0, 0.0, 0.0))
1407  : mMatF{float(s), 0.0f, 0.0f, 0.0f, float(s), 0.0f, 0.0f, 0.0f, float(s)}
1408  , mInvMatF{1.0f / float(s), 0.0f, 0.0f, 0.0f, 1.0f / float(s), 0.0f, 0.0f, 0.0f, 1.0f / float(s)}
1409  , mVecF{float(t[0]), float(t[1]), float(t[2])}
1410  , mTaperF{1.0f}
1411  , mMatD{s, 0.0, 0.0, 0.0, s, 0.0, 0.0, 0.0, s}
1412  , mInvMatD{1.0 / s, 0.0, 0.0, 0.0, 1.0 / s, 0.0, 0.0, 0.0, 1.0 / s}
1413  , mVecD{t[0], t[1], t[2]}
1414  , mTaperD{1.0}
1415  {
1416  }
1417 
1418  /// @brief Initialize the member data from 3x3 or 4x4 matrices
1419  /// @note This is not _hostdev__ since then MatT=openvdb::Mat4d will produce warnings
1420  template<typename MatT, typename Vec3T>
1421  void set(const MatT& mat, const MatT& invMat, const Vec3T& translate, double taper = 1.0);
1422 
1423  /// @brief Initialize the member data from 4x4 matrices
1424  /// @note The last (4th) row of invMat is actually ignored.
1425  /// This is not _hostdev__ since then Mat4T=openvdb::Mat4d will produce warnings
1426  template<typename Mat4T>
1427  void set(const Mat4T& mat, const Mat4T& invMat, double taper = 1.0) { this->set(mat, invMat, mat[3], taper); }
1428 
1429  template<typename Vec3T>
1430  void set(double scale, const Vec3T& translation, double taper = 1.0);
1431 
1432  /// @brief Apply the forward affine transformation to a vector using 64bit floating point arithmetics.
1433  /// @note Typically this operation is used for the scale, rotation and translation of index -> world mapping
1434  /// @tparam Vec3T Template type of the 3D vector to be mapped
1435  /// @param ijk 3D vector to be mapped - typically floating point index coordinates
1436  /// @return Forward mapping for affine transformation, i.e. (mat x ijk) + translation
1437  template<typename Vec3T>
1438  __hostdev__ Vec3T applyMap(const Vec3T& ijk) const { return math::matMult(mMatD, mVecD, ijk); }
1439 
1440  /// @brief Apply the forward affine transformation to a vector using 32bit floating point arithmetics.
1441  /// @note Typically this operation is used for the scale, rotation and translation of index -> world mapping
1442  /// @tparam Vec3T Template type of the 3D vector to be mapped
1443  /// @param ijk 3D vector to be mapped - typically floating point index coordinates
1444  /// @return Forward mapping for affine transformation, i.e. (mat x ijk) + translation
1445  template<typename Vec3T>
1446  __hostdev__ Vec3T applyMapF(const Vec3T& ijk) const { return math::matMult(mMatF, mVecF, ijk); }
1447 
1448  /// @brief Apply the linear forward 3x3 transformation to an input 3d vector using 64bit floating point arithmetics,
1449  /// e.g. scale and rotation WITHOUT translation.
1450  /// @note Typically this operation is used for scale and rotation from index -> world mapping
1451  /// @tparam Vec3T Template type of the 3D vector to be mapped
1452  /// @param ijk 3D vector to be mapped - typically floating point index coordinates
1453  /// @return linear forward 3x3 mapping of the input vector
1454  template<typename Vec3T>
1455  __hostdev__ Vec3T applyJacobian(const Vec3T& ijk) const { return math::matMult(mMatD, ijk); }
1456 
1457  /// @brief Apply the linear forward 3x3 transformation to an input 3d vector using 32bit floating point arithmetics,
1458  /// e.g. scale and rotation WITHOUT translation.
1459  /// @note Typically this operation is used for scale and rotation from index -> world mapping
1460  /// @tparam Vec3T Template type of the 3D vector to be mapped
1461  /// @param ijk 3D vector to be mapped - typically floating point index coordinates
1462  /// @return linear forward 3x3 mapping of the input vector
1463  template<typename Vec3T>
1464  __hostdev__ Vec3T applyJacobianF(const Vec3T& ijk) const { return math::matMult(mMatF, ijk); }
1465 
1466  /// @brief Apply the inverse affine mapping to a vector using 64bit floating point arithmetics.
1467  /// @note Typically this operation is used for the world -> index mapping
1468  /// @tparam Vec3T Template type of the 3D vector to be mapped
1469  /// @param xyz 3D vector to be mapped - typically floating point world coordinates
1470  /// @return Inverse affine mapping of the input @c xyz i.e. (xyz - translation) x mat^-1
1471  template<typename Vec3T>
1472  __hostdev__ Vec3T applyInverseMap(const Vec3T& xyz) const
1473  {
1474  return math::matMult(mInvMatD, Vec3T(xyz[0] - mVecD[0], xyz[1] - mVecD[1], xyz[2] - mVecD[2]));
1475  }
1476 
1477  /// @brief Apply the inverse affine mapping to a vector using 32bit floating point arithmetics.
1478  /// @note Typically this operation is used for the world -> index mapping
1479  /// @tparam Vec3T Template type of the 3D vector to be mapped
1480  /// @param xyz 3D vector to be mapped - typically floating point world coordinates
1481  /// @return Inverse affine mapping of the input @c xyz i.e. (xyz - translation) x mat^-1
1482  template<typename Vec3T>
1483  __hostdev__ Vec3T applyInverseMapF(const Vec3T& xyz) const
1484  {
1485  return math::matMult(mInvMatF, Vec3T(xyz[0] - mVecF[0], xyz[1] - mVecF[1], xyz[2] - mVecF[2]));
1486  }
1487 
1488  /// @brief Apply the linear inverse 3x3 transformation to an input 3d vector using 64bit floating point arithmetics,
1489  /// e.g. inverse scale and inverse rotation WITHOUT translation.
1490  /// @note Typically this operation is used for scale and rotation from world -> index mapping
1491  /// @tparam Vec3T Template type of the 3D vector to be mapped
1492  /// @param ijk 3D vector to be mapped - typically floating point index coordinates
1493  /// @return linear inverse 3x3 mapping of the input vector i.e. xyz x mat^-1
1494  template<typename Vec3T>
1495  __hostdev__ Vec3T applyInverseJacobian(const Vec3T& xyz) const { return math::matMult(mInvMatD, xyz); }
1496 
1497  /// @brief Apply the linear inverse 3x3 transformation to an input 3d vector using 32bit floating point arithmetics,
1498  /// e.g. inverse scale and inverse rotation WITHOUT translation.
1499  /// @note Typically this operation is used for scale and rotation from world -> index mapping
1500  /// @tparam Vec3T Template type of the 3D vector to be mapped
1501  /// @param ijk 3D vector to be mapped - typically floating point index coordinates
1502  /// @return linear inverse 3x3 mapping of the input vector i.e. xyz x mat^-1
1503  template<typename Vec3T>
1504  __hostdev__ Vec3T applyInverseJacobianF(const Vec3T& xyz) const { return math::matMult(mInvMatF, xyz); }
1505 
1506  /// @brief Apply the transposed inverse 3x3 transformation to an input 3d vector using 64bit floating point arithmetics,
1507  /// e.g. inverse scale and inverse rotation WITHOUT translation.
1508  /// @note Typically this operation is used for scale and rotation from world -> index mapping
1509  /// @tparam Vec3T Template type of the 3D vector to be mapped
1510  /// @param ijk 3D vector to be mapped - typically floating point index coordinates
1511  /// @return linear inverse 3x3 mapping of the input vector i.e. xyz x mat^-1
1512  template<typename Vec3T>
1513  __hostdev__ Vec3T applyIJT(const Vec3T& xyz) const { return math::matMultT(mInvMatD, xyz); }
1514  template<typename Vec3T>
1515  __hostdev__ Vec3T applyIJTF(const Vec3T& xyz) const { return math::matMultT(mInvMatF, xyz); }
1516 
1517  /// @brief Return a voxels size in each coordinate direction, measured at the origin
1518  __hostdev__ Vec3d getVoxelSize() const { return this->applyMap(Vec3d(1)) - this->applyMap(Vec3d(0)); }
1519 }; // Map
1520 
1521 template<typename MatT, typename Vec3T>
1522 inline void Map::set(const MatT& mat, const MatT& invMat, const Vec3T& translate, double taper)
1523 {
1524  float * mf = mMatF, *vf = mVecF, *mif = mInvMatF;
1525  double *md = mMatD, *vd = mVecD, *mid = mInvMatD;
1526  mTaperF = static_cast<float>(taper);
1527  mTaperD = taper;
1528  for (int i = 0; i < 3; ++i) {
1529  *vd++ = translate[i]; //translation
1530  *vf++ = static_cast<float>(translate[i]); //translation
1531  for (int j = 0; j < 3; ++j) {
1532  *md++ = mat[j][i]; //transposed
1533  *mid++ = invMat[j][i];
1534  *mf++ = static_cast<float>(mat[j][i]); //transposed
1535  *mif++ = static_cast<float>(invMat[j][i]);
1536  }
1537  }
1538 }
1539 
1540 template<typename Vec3T>
1541 inline void Map::set(double dx, const Vec3T& trans, double taper)
1542 {
1543  NANOVDB_ASSERT(dx > 0.0);
1544  const double mat[3][3] = { {dx, 0.0, 0.0}, // row 0
1545  {0.0, dx, 0.0}, // row 1
1546  {0.0, 0.0, dx} }; // row 2
1547  const double idx = 1.0 / dx;
1548  const double invMat[3][3] = { {idx, 0.0, 0.0}, // row 0
1549  {0.0, idx, 0.0}, // row 1
1550  {0.0, 0.0, idx} }; // row 2
1551  this->set(mat, invMat, trans, taper);
1552 }
1553 
1554 // ----------------------------> GridBlindMetaData <--------------------------------------
1555 
1556 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridBlindMetaData
1557 { // 288 bytes
1558  static const int MaxNameSize = 256; // due to NULL termination the maximum length is one less!
1559  int64_t mDataOffset; // byte offset to the blind data, relative to this GridBlindMetaData.
1560  uint64_t mValueCount; // number of blind values, e.g. point count
1561  uint32_t mValueSize;// byte size of each value, e.g. 4 if mDataType=Float and 1 if mDataType=Unknown since that amounts to char
1562  GridBlindDataSemantic mSemantic; // semantic meaning of the data.
1564  GridType mDataType; // 4 bytes
1565  char mName[MaxNameSize]; // note this includes the NULL termination
1566  // no padding required for 32 byte alignment
1567 
1568  // disallow copy-construction since methods like blindData and getBlindData uses the this pointer!
1569  GridBlindMetaData(const GridBlindMetaData&) = delete;
1570 
1571  // disallow copy-assignment since methods like blindData and getBlindData uses the this pointer!
1572  const GridBlindMetaData& operator=(const GridBlindMetaData&) = delete;
1573 
1574  __hostdev__ void setBlindData(void* blindData) { mDataOffset = util::PtrDiff(blindData, this); }
1575 
1576  // unsafe
1577  __hostdev__ const void* blindData() const {return util::PtrAdd(this, mDataOffset);}
1578 
1579  /// @brief Get a const pointer to the blind data represented by this meta data
1580  /// @tparam BlindDataT Expected value type of the blind data.
1581  /// @return Returns NULL if mGridType!=toGridType<BlindDataT>(), else a const point of type BlindDataT.
1582  /// @note Use mDataType=Unknown if BlindDataT is a custom data type unknown to NanoVDB.
1583  template<typename BlindDataT>
1584  __hostdev__ const BlindDataT* getBlindData() const
1585  {
1586  //if (mDataType != toGridType<BlindDataT>()) printf("getBlindData mismatch\n");
1587  return mDataType == toGridType<BlindDataT>() ? util::PtrAdd<BlindDataT>(this, mDataOffset) : nullptr;
1588  }
1589 
1590  /// @brief return true if this meta data has a valid combination of semantic, class and value tags
1591  __hostdev__ bool isValid() const
1592  {
1593  auto check = [&]()->bool{
1594  switch (mDataType){
1595  case GridType::Unknown: return mValueSize==1u;// i.e. we encode data as mValueCount chars
1596  case GridType::Float: return mValueSize==4u;
1597  case GridType::Double: return mValueSize==8u;
1598  case GridType::Int16: return mValueSize==2u;
1599  case GridType::Int32: return mValueSize==4u;
1600  case GridType::Int64: return mValueSize==8u;
1601  case GridType::Vec3f: return mValueSize==12u;
1602  case GridType::Vec3d: return mValueSize==24u;
1603  case GridType::Half: return mValueSize==2u;
1604  case GridType::RGBA8: return mValueSize==4u;
1605  case GridType::Fp8: return mValueSize==1u;
1606  case GridType::Fp16: return mValueSize==2u;
1607  case GridType::Vec4f: return mValueSize==16u;
1608  case GridType::Vec4d: return mValueSize==32u;
1609  case GridType::Vec3u8: return mValueSize==3u;
1610  case GridType::Vec3u16: return mValueSize==6u;
1611  default: return true;}// all other combinations are valid
1612  };
1613  return nanovdb::isValid(mDataClass, mSemantic, mDataType) && check();
1614  }
1615 
1616  /// @brief return size in bytes of the blind data represented by this blind meta data
1617  /// @note This size includes possible padding for 32 byte alignment. The actual amount
1618  /// of bind data is mValueCount * mValueSize
1619  __hostdev__ uint64_t blindDataSize() const
1620  {
1621  return math::AlignUp<NANOVDB_DATA_ALIGNMENT>(mValueCount * mValueSize);
1622  }
1623 }; // GridBlindMetaData
1624 
1625 // ----------------------------> NodeTrait <--------------------------------------
1626 
1627 /// @brief Struct to derive node type from its level in a given
1628 /// grid, tree or root while preserving constness
1629 template<typename GridOrTreeOrRootT, int LEVEL>
1630 struct NodeTrait;
1631 
1632 // Partial template specialization of above Node struct
1633 template<typename GridOrTreeOrRootT>
1634 struct NodeTrait<GridOrTreeOrRootT, 0>
1635 {
1636  static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported");
1637  using Type = typename GridOrTreeOrRootT::LeafNodeType;
1638  using type = typename GridOrTreeOrRootT::LeafNodeType;
1639 };
1640 template<typename GridOrTreeOrRootT>
1641 struct NodeTrait<const GridOrTreeOrRootT, 0>
1642 {
1643  static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported");
1644  using Type = const typename GridOrTreeOrRootT::LeafNodeType;
1645  using type = const typename GridOrTreeOrRootT::LeafNodeType;
1646 };
1647 
1648 template<typename GridOrTreeOrRootT>
1649 struct NodeTrait<GridOrTreeOrRootT, 1>
1650 {
1651  static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported");
1652  using Type = typename GridOrTreeOrRootT::RootNodeType::ChildNodeType::ChildNodeType;
1653  using type = typename GridOrTreeOrRootT::RootNodeType::ChildNodeType::ChildNodeType;
1654 };
1655 template<typename GridOrTreeOrRootT>
1656 struct NodeTrait<const GridOrTreeOrRootT, 1>
1657 {
1658  static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported");
1659  using Type = const typename GridOrTreeOrRootT::RootNodeType::ChildNodeType::ChildNodeType;
1660  using type = const typename GridOrTreeOrRootT::RootNodeType::ChildNodeType::ChildNodeType;
1661 };
1662 template<typename GridOrTreeOrRootT>
1663 struct NodeTrait<GridOrTreeOrRootT, 2>
1664 {
1665  static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported");
1666  using Type = typename GridOrTreeOrRootT::RootNodeType::ChildNodeType;
1667  using type = typename GridOrTreeOrRootT::RootNodeType::ChildNodeType;
1668 };
1669 template<typename GridOrTreeOrRootT>
1670 struct NodeTrait<const GridOrTreeOrRootT, 2>
1671 {
1672  static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported");
1673  using Type = const typename GridOrTreeOrRootT::RootNodeType::ChildNodeType;
1674  using type = const typename GridOrTreeOrRootT::RootNodeType::ChildNodeType;
1675 };
1676 template<typename GridOrTreeOrRootT>
1677 struct NodeTrait<GridOrTreeOrRootT, 3>
1678 {
1679  static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported");
1680  using Type = typename GridOrTreeOrRootT::RootNodeType;
1681  using type = typename GridOrTreeOrRootT::RootNodeType;
1682 };
1683 
1684 template<typename GridOrTreeOrRootT>
1685 struct NodeTrait<const GridOrTreeOrRootT, 3>
1686 {
1687  static_assert(GridOrTreeOrRootT::RootNodeType::LEVEL == 3, "Tree depth is not supported");
1688  using Type = const typename GridOrTreeOrRootT::RootNodeType;
1689  using type = const typename GridOrTreeOrRootT::RootNodeType;
1690 };
1691 
1692 // ----------------------------> Froward decelerations of random access methods <--------------------------------------
1693 
1694 template<typename BuildT>
1695 struct GetValue;
1696 template<typename BuildT>
1697 struct SetValue;
1698 template<typename BuildT>
1699 struct SetVoxel;
1700 template<typename BuildT>
1701 struct GetState;
1702 template<typename BuildT>
1703 struct GetDim;
1704 template<typename BuildT>
1705 struct GetLeaf;
1706 template<typename BuildT>
1707 struct ProbeValue;
1708 template<typename BuildT>
1710 
1711 // ----------------------------> CheckMode <----------------------------------
1712 
1713 /// @brief List of different modes for computing for a checksum
1714 enum class CheckMode : uint32_t { Disable = 0, // no computation
1715  Empty = 0,
1716  Half = 1,
1717  Partial = 1, // fast but approximate
1718  Default = 1, // defaults to Partial
1719  Full = 2, // slow but accurate
1720  End = 3, // marks the end of the enum list
1721  StrLen = 9 + End};
1722 
1723 /// @brief Prints CheckMode enum to a c-string
1724 /// @param dst Destination c-string
1725 /// @param mode CheckMode enum to be converted to string
1726 /// @return destinations string @c dst
1727 __hostdev__ inline char* toStr(char *dst, CheckMode mode)
1728 {
1729  switch (mode){
1730  case CheckMode::Half: return util::strcpy(dst, "half");
1731  case CheckMode::Full: return util::strcpy(dst, "full");
1732  default: return util::strcpy(dst, "disabled");
1733  }
1734 }
1735 
1736 // ----------------------------> Checksum <----------------------------------
1737 
1738 /// @brief Class that encapsulates two CRC32 checksums, one for the Grid, Tree and Root node meta data
1739 /// and one for the remaining grid nodes.
1741 {
1742  /// Three types of checksums:
1743  /// 1) Empty: all 64 bits are on (used to signify a disabled or undefined checksum)
1744  /// 2) Half: Upper 32 bits are on and not all of lower 32 bits are on (lower 32 bits checksum head of grid)
1745  /// 3) Full: Not all of the 64 bits are one (lower 32 bits checksum head of grid and upper 32 bits checksum tail of grid)
1746  union { uint32_t mCRC32[2]; uint64_t mCRC64; };// mCRC32[0] is checksum of Grid, Tree and Root, and mCRC32[1] is checksum of nodes
1747 
1748 public:
1749 
1750  static constexpr uint32_t EMPTY32 = ~uint32_t{0};
1751  static constexpr uint64_t EMPTY64 = ~uint64_t(0);
1752 
1753  /// @brief default constructor initiates checksum to EMPTY
1754  __hostdev__ Checksum() : mCRC64{EMPTY64} {}
1755 
1756  /// @brief Constructor that allows the two 32bit checksums to be initiated explicitly
1757  /// @param head Initial 32bit CRC checksum of grid, tree and root data
1758  /// @param tail Initial 32bit CRC checksum of all the nodes and blind data
1759  __hostdev__ Checksum(uint32_t head, uint32_t tail) : mCRC32{head, tail} {}
1760 
1761  /// @brief
1762  /// @param checksum
1763  /// @param mode
1764  __hostdev__ Checksum(uint64_t checksum, CheckMode mode = CheckMode::Full) : mCRC64{mode == CheckMode::Disable ? EMPTY64 : checksum}
1765  {
1766  if (mode == CheckMode::Partial) mCRC32[1] = EMPTY32;
1767  }
1768 
1769  /// @brief return the 64 bit checksum of this instance
1770  [[deprecated("Use Checksum::data instead.")]]
1771  __hostdev__ uint64_t checksum() const { return mCRC64; }
1772  [[deprecated("Use Checksum::head and Ckecksum::tail instead.")]]
1773  __hostdev__ uint32_t& checksum(int i) {NANOVDB_ASSERT(i==0 || i==1); return mCRC32[i]; }
1774  [[deprecated("Use Checksum::head and Ckecksum::tail instead.")]]
1775  __hostdev__ uint32_t checksum(int i) const {NANOVDB_ASSERT(i==0 || i==1); return mCRC32[i]; }
1776 
1777  __hostdev__ uint64_t full() const { return mCRC64; }
1778  __hostdev__ uint64_t& full() { return mCRC64; }
1779  __hostdev__ uint32_t head() const { return mCRC32[0]; }
1780  __hostdev__ uint32_t& head() { return mCRC32[0]; }
1781  __hostdev__ uint32_t tail() const { return mCRC32[1]; }
1782  __hostdev__ uint32_t& tail() { return mCRC32[1]; }
1783 
1784  /// @brief return true if the 64 bit checksum is partial, i.e. of head only
1785  [[deprecated("Use Checksum::isHalf instead.")]]
1786  __hostdev__ bool isPartial() const { return mCRC32[0] != EMPTY32 && mCRC32[1] == EMPTY32; }
1787  __hostdev__ bool isHalf() const { return mCRC32[0] != EMPTY32 && mCRC32[1] == EMPTY32; }
1788 
1789  /// @brief return true if the 64 bit checksum is fill, i.e. of both had and nodes
1790  __hostdev__ bool isFull() const { return mCRC64 != EMPTY64 && mCRC32[1] != EMPTY32; }
1791 
1792  /// @brief return true if the 64 bit checksum is disables (unset)
1793  __hostdev__ bool isEmpty() const { return mCRC64 == EMPTY64; }
1794 
1795  __hostdev__ void disable() { mCRC64 = EMPTY64; }
1796 
1797  /// @brief return the mode of the 64 bit checksum
1799  {
1800  return mCRC64 == EMPTY64 ? CheckMode::Disable :
1801  mCRC32[1] == EMPTY32 ? CheckMode::Partial : CheckMode::Full;
1802  }
1803 
1804  /// @brief return true if the checksums are identical
1805  /// @param rhs other Checksum
1806  __hostdev__ bool operator==(const Checksum &rhs) const {return mCRC64 == rhs.mCRC64;}
1807 
1808  /// @brief return true if the checksums are not identical
1809  /// @param rhs other Checksum
1810  __hostdev__ bool operator!=(const Checksum &rhs) const {return mCRC64 != rhs.mCRC64;}
1811 };// Checksum
1812 
1813 /// @brief Maps 64 bit checksum to CheckMode enum
1814 /// @param checksum 64 bit checksum with two CRC32 codes
1815 /// @return CheckMode enum
1816 __hostdev__ inline CheckMode toCheckMode(const Checksum &checksum){return checksum.mode();}
1817 
1818 // ----------------------------> Grid <--------------------------------------
1819 
1820 /*
1821  The following class and comment is for internal use only
1822 
1823  Memory layout:
1824 
1825  Grid -> 39 x double (world bbox and affine transformation)
1826  Tree -> Root 3 x ValueType + int32_t + N x Tiles (background,min,max,tileCount + tileCount x Tiles)
1827 
1828  N2 upper InternalNodes each with 2 bit masks, N2 tiles, and min/max values
1829 
1830  N1 lower InternalNodes each with 2 bit masks, N1 tiles, and min/max values
1831 
1832  N0 LeafNodes each with a bit mask, N0 ValueTypes and min/max
1833 
1834  Example layout: ("---" implies it has a custom offset, "..." implies zero or more)
1835  [GridData][TreeData]---[RootData][ROOT TILES...]---[InternalData<5>]---[InternalData<4>]---[LeafData<3>]---[BLINDMETA...]---[BLIND0]---[BLIND1]---etc.
1836 */
1837 
1838 /// @brief Struct with all the member data of the Grid (useful during serialization of an openvdb grid)
1839 ///
1840 /// @note The transform is assumed to be affine (so linear) and have uniform scale! So frustum transforms
1841 /// and non-uniform scaling are not supported (primarily because they complicate ray-tracing in index space)
1842 ///
1843 /// @note No client code should (or can) interface with this struct so it can safely be ignored!
1844 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData
1845 { // sizeof(GridData) = 672B
1846  static const int MaxNameSize = 256; // due to NULL termination the maximum length is one less
1847  uint64_t mMagic; // 8B (0) magic to validate it is valid grid data.
1848  Checksum mChecksum; // 8B (8). Checksum of grid buffer.
1849  Version mVersion; // 4B (16) major, minor, and patch version numbers
1850  BitFlags<32> mFlags; // 4B (20). flags for grid.
1851  uint32_t mGridIndex; // 4B (24). Index of this grid in the buffer
1852  uint32_t mGridCount; // 4B (28). Total number of grids in the buffer
1853  uint64_t mGridSize; // 8B (32). byte count of this entire grid occupied in the buffer.
1854  char mGridName[MaxNameSize]; // 256B (40)
1855  Map mMap; // 264B (296). affine transformation between index and world space in both single and double precision
1856  Vec3dBBox mWorldBBox; // 48B (560). floating-point AABB of active values in WORLD SPACE (2 x 3 doubles)
1857  Vec3d mVoxelSize; // 24B (608). size of a voxel in world units
1858  GridClass mGridClass; // 4B (632).
1859  GridType mGridType; // 4B (636).
1860  int64_t mBlindMetadataOffset; // 8B (640). offset to beginning of GridBlindMetaData structures that follow this grid.
1861  uint32_t mBlindMetadataCount; // 4B (648). count of GridBlindMetaData structures that follow this grid.
1862  uint32_t mData0; // 4B (652) unused
1863  uint64_t mData1; // 8B (656) is use for the total number of values indexed by an IndexGrid
1864  uint64_t mData2; // 8B (664) padding to 32 B alignment
1865  /// @brief Use this method to initiate most member data
1866  GridData& operator=(const GridData&) = default;
1867  //__hostdev__ GridData& operator=(const GridData& other){return *util::memcpy(this, &other);}
1868  __hostdev__ void init(std::initializer_list<GridFlags> list = {GridFlags::IsBreadthFirst},
1869  uint64_t gridSize = 0u,
1870  const Map& map = Map(),
1871  GridType gridType = GridType::Unknown,
1872  GridClass gridClass = GridClass::Unknown)
1873  {
1874 #ifdef NANOVDB_USE_NEW_MAGIC_NUMBERS
1875  mMagic = NANOVDB_MAGIC_GRID;
1876 #else
1877  mMagic = NANOVDB_MAGIC_NUMB;
1878 #endif
1879  mChecksum.disable();// all 64 bits ON means checksum is disabled
1880  mVersion = Version();
1881  mFlags.initMask(list);
1882  mGridIndex = 0u;
1883  mGridCount = 1u;
1884  mGridSize = gridSize;
1885  mGridName[0] = '\0';
1886  mMap = map;
1887  mWorldBBox = Vec3dBBox();// invalid bbox
1888  mVoxelSize = map.getVoxelSize();
1889  mGridClass = gridClass;
1890  mGridType = gridType;
1891  mBlindMetadataOffset = mGridSize; // i.e. no blind data
1892  mBlindMetadataCount = 0u; // i.e. no blind data
1893  mData0 = 0u; // zero padding
1894  mData1 = 0u; // only used for index and point grids
1895  mData2 = NANOVDB_MAGIC_GRID; // since version 32.6.0 (will change in the future)
1896  }
1897  /// @brief return true if the magic number and the version are both valid
1898  __hostdev__ bool isValid() const {
1899  // Before v32.6.0: toMagic(mMagic) = MagicType::NanoVDB and mData2 was undefined
1900  // For v32.6.0: toMagic(mMagic) = MagicType::NanoVDB and toMagic(mData2) = MagicType::NanoGrid
1901  // After v32.7.X: toMagic(mMagic) = MagicType::NanoGrid and mData2 will again be undefined
1902  const MagicType magic = toMagic(mMagic);
1903  if (magic == MagicType::NanoGrid || toMagic(mData2) == MagicType::NanoGrid) return true;
1904  bool test = magic == MagicType::NanoVDB;// could be GridData or io::FileHeader
1905  if (test) test = mVersion.isCompatible();
1906  if (test) test = mGridCount > 0u && mGridIndex < mGridCount;
1907  if (test) test = mGridClass < GridClass::End && mGridType < GridType::End;
1908  return test;
1909  }
1910  // Set and unset various bit flags
1911  __hostdev__ void setMinMaxOn(bool on = true) { mFlags.setMask(GridFlags::HasMinMax, on); }
1912  __hostdev__ void setBBoxOn(bool on = true) { mFlags.setMask(GridFlags::HasBBox, on); }
1913  __hostdev__ void setLongGridNameOn(bool on = true) { mFlags.setMask(GridFlags::HasLongGridName, on); }
1914  __hostdev__ void setAverageOn(bool on = true) { mFlags.setMask(GridFlags::HasAverage, on); }
1915  __hostdev__ void setStdDeviationOn(bool on = true) { mFlags.setMask(GridFlags::HasStdDeviation, on); }
1916  __hostdev__ bool setGridName(const char* src)
1917  {
1918  const bool success = (util::strncpy(mGridName, src, MaxNameSize)[MaxNameSize-1] == '\0');
1919  if (!success) mGridName[MaxNameSize-1] = '\0';
1920  return success; // returns true if input grid name is NOT longer than MaxNameSize characters
1921  }
1922  // Affine transformations based on double precision
1923  template<typename Vec3T>
1924  __hostdev__ Vec3T applyMap(const Vec3T& xyz) const { return mMap.applyMap(xyz); } // Pos: index -> world
1925  template<typename Vec3T>
1926  __hostdev__ Vec3T applyInverseMap(const Vec3T& xyz) const { return mMap.applyInverseMap(xyz); } // Pos: world -> index
1927  template<typename Vec3T>
1928  __hostdev__ Vec3T applyJacobian(const Vec3T& xyz) const { return mMap.applyJacobian(xyz); } // Dir: index -> world
1929  template<typename Vec3T>
1930  __hostdev__ Vec3T applyInverseJacobian(const Vec3T& xyz) const { return mMap.applyInverseJacobian(xyz); } // Dir: world -> index
1931  template<typename Vec3T>
1932  __hostdev__ Vec3T applyIJT(const Vec3T& xyz) const { return mMap.applyIJT(xyz); }
1933  // Affine transformations based on single precision
1934  template<typename Vec3T>
1935  __hostdev__ Vec3T applyMapF(const Vec3T& xyz) const { return mMap.applyMapF(xyz); } // Pos: index -> world
1936  template<typename Vec3T>
1937  __hostdev__ Vec3T applyInverseMapF(const Vec3T& xyz) const { return mMap.applyInverseMapF(xyz); } // Pos: world -> index
1938  template<typename Vec3T>
1939  __hostdev__ Vec3T applyJacobianF(const Vec3T& xyz) const { return mMap.applyJacobianF(xyz); } // Dir: index -> world
1940  template<typename Vec3T>
1941  __hostdev__ Vec3T applyInverseJacobianF(const Vec3T& xyz) const { return mMap.applyInverseJacobianF(xyz); } // Dir: world -> index
1942  template<typename Vec3T>
1943  __hostdev__ Vec3T applyIJTF(const Vec3T& xyz) const { return mMap.applyIJTF(xyz); }
1944 
1945  // @brief Return a non-const void pointer to the tree
1946  __hostdev__ void* treePtr() { return this + 1; }// TreeData is always right after GridData
1947 
1948  // @brief Return a const void pointer to the tree
1949  __hostdev__ const void* treePtr() const { return this + 1; }// TreeData is always right after GridData
1950 
1951  /// @brief Return a non-const void pointer to the first node at @c LEVEL
1952  /// @tparam LEVEL Level of the node. LEVEL 0 means leaf node and LEVEL 3 means root node
1953  template <uint32_t LEVEL>
1954  __hostdev__ const void* nodePtr() const
1955  {
1956  static_assert(LEVEL >= 0 && LEVEL <= 3, "invalid LEVEL template parameter");
1957  const void *treeData = this + 1;// TreeData is always right after GridData
1958  const uint64_t nodeOffset = *util::PtrAdd<uint64_t>(treeData, 8*LEVEL);// skip LEVEL uint64_t
1959  return nodeOffset ? util::PtrAdd(treeData, nodeOffset) : nullptr;
1960  }
1961 
1962  /// @brief Return a non-const void pointer to the first node at @c LEVEL
1963  /// @tparam LEVEL of the node. LEVEL 0 means leaf node and LEVEL 3 means root node
1964  /// @warning If not nodes exist at @c LEVEL NULL is returned
1965  template <uint32_t LEVEL>
1967  {
1968  static_assert(LEVEL >= 0 && LEVEL <= 3, "invalid LEVEL template parameter");
1969  void *treeData = this + 1;// TreeData is always right after GridData
1970  const uint64_t nodeOffset = *util::PtrAdd<uint64_t>(treeData, 8*LEVEL);// skip LEVEL uint64_t
1971  return nodeOffset ? util::PtrAdd(treeData, nodeOffset) : nullptr;
1972  }
1973 
1974  /// @brief Return number of nodes at @c LEVEL
1975  /// @tparam Level of the node. LEVEL 0 means leaf node and LEVEL 2 means upper node
1976  template <uint32_t LEVEL>
1977  __hostdev__ uint32_t nodeCount() const
1978  {
1979  static_assert(LEVEL >= 0 && LEVEL < 3, "invalid LEVEL template parameter");
1980  return *util::PtrAdd<uint32_t>(this + 1, 4*(8 + LEVEL));// TreeData is always right after GridData
1981  }
1982 
1983  /// @brief Returns a const reference to the blindMetaData at the specified linear offset.
1984  ///
1985  /// @warning The linear offset is assumed to be in the valid range
1987  {
1988  NANOVDB_ASSERT(n < mBlindMetadataCount);
1989  return util::PtrAdd<GridBlindMetaData>(this, mBlindMetadataOffset) + n;
1990  }
1991 
1992  __hostdev__ const char* gridName() const
1993  {
1994  if (mFlags.isMaskOn(GridFlags::HasLongGridName)) {// search for first blind meta data that contains a name
1995  NANOVDB_ASSERT(mBlindMetadataCount > 0);
1996  for (uint32_t i = 0; i < mBlindMetadataCount; ++i) {
1997  const auto* metaData = this->blindMetaData(i);// EXTREMELY important to be a pointer
1998  if (metaData->mDataClass == GridBlindDataClass::GridName) {
1999  NANOVDB_ASSERT(metaData->mDataType == GridType::Unknown);
2000  return metaData->template getBlindData<const char>();
2001  }
2002  }
2003  NANOVDB_ASSERT(false); // should never hit this!
2004  }
2005  return mGridName;
2006  }
2007 
2008  /// @brief Return memory usage in bytes for this class only.
2009  __hostdev__ static uint64_t memUsage() { return sizeof(GridData); }
2010 
2011  /// @brief return AABB of active values in world space
2012  __hostdev__ const Vec3dBBox& worldBBox() const { return mWorldBBox; }
2013 
2014  /// @brief return AABB of active values in index space
2015  __hostdev__ const CoordBBox& indexBBox() const {return *(const CoordBBox*)(this->nodePtr<3>());}
2016 
2017  /// @brief return the root table has size
2018  __hostdev__ uint32_t rootTableSize() const
2019  {
2020  const void *root = this->nodePtr<3>();
2021  return root ? *util::PtrAdd<uint32_t>(root, sizeof(CoordBBox)) : 0u;
2022  }
2023 
2024  /// @brief test if the grid is empty, e.i the root table has size 0
2025  /// @return true if this grid contains not data whatsoever
2026  __hostdev__ bool isEmpty() const {return this->rootTableSize() == 0u;}
2027 
2028  /// @brief return true if RootData follows TreeData in memory without any extra padding
2029  /// @details TreeData is always following right after GridData, but the same might not be true for RootData
2030  __hostdev__ bool isRootConnected() const { return *(const uint64_t*)((const char*)(this + 1) + 24) == 64u;}
2031 }; // GridData
2032 
2033 // Forward declaration of accelerated random access class
2034 template<typename BuildT, int LEVEL0 = -1, int LEVEL1 = -1, int LEVEL2 = -1>
2036 
2037 template<typename BuildT>
2039 
2040 /// @brief Highest level of the data structure. Contains a tree and a world->index
2041 /// transform (that currently only supports uniform scaling and translation).
2042 ///
2043 /// @note This the API of this class to interface with client code
2044 template<typename TreeT>
2045 class Grid : public GridData
2046 {
2047 public:
2048  using TreeType = TreeT;
2049  using RootType = typename TreeT::RootType;
2051  using UpperNodeType = typename RootNodeType::ChildNodeType;
2052  using LowerNodeType = typename UpperNodeType::ChildNodeType;
2053  using LeafNodeType = typename RootType::LeafNodeType;
2055  using ValueType = typename TreeT::ValueType;
2056  using BuildType = typename TreeT::BuildType; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool
2057  using CoordType = typename TreeT::CoordType;
2059 
2060  /// @brief Disallow constructions, copy and assignment
2061  ///
2062  /// @note Only a Serializer, defined elsewhere, can instantiate this class
2063  Grid(const Grid&) = delete;
2064  Grid& operator=(const Grid&) = delete;
2065  ~Grid() = delete;
2066 
2067  __hostdev__ Version version() const { return DataType::mVersion; }
2068 
2069  __hostdev__ DataType* data() { return reinterpret_cast<DataType*>(this); }
2070 
2071  __hostdev__ const DataType* data() const { return reinterpret_cast<const DataType*>(this); }
2072 
2073  /// @brief Return memory usage in bytes for this class only.
2074  //__hostdev__ static uint64_t memUsage() { return sizeof(GridData); }
2075 
2076  /// @brief Return the memory footprint of the entire grid, i.e. including all nodes and blind data
2077  __hostdev__ uint64_t gridSize() const { return DataType::mGridSize; }
2078 
2079  /// @brief Return index of this grid in the buffer
2080  __hostdev__ uint32_t gridIndex() const { return DataType::mGridIndex; }
2081 
2082  /// @brief Return total number of grids in the buffer
2083  __hostdev__ uint32_t gridCount() const { return DataType::mGridCount; }
2084 
2085  /// @brief @brief Return the total number of values indexed by this IndexGrid
2086  ///
2087  /// @note This method is only defined for IndexGrid = NanoGrid<ValueIndex || ValueOnIndex || ValueIndexMask || ValueOnIndexMask>
2088  template<typename T = BuildType>
2089  __hostdev__ typename util::enable_if<BuildTraits<T>::is_index, const uint64_t&>::type
2090  valueCount() const { return DataType::mData1; }
2091 
2092  /// @brief @brief Return the total number of points indexed by this PointGrid
2093  ///
2094  /// @note This method is only defined for PointGrid = NanoGrid<Point>
2095  template<typename T = BuildType>
2096  __hostdev__ typename util::enable_if<util::is_same<T, Point>::value, const uint64_t&>::type
2097  pointCount() const { return DataType::mData1; }
2098 
2099  /// @brief Return a const reference to the tree
2100  __hostdev__ const TreeT& tree() const { return *reinterpret_cast<const TreeT*>(this->treePtr()); }
2101 
2102  /// @brief Return a non-const reference to the tree
2103  __hostdev__ TreeT& tree() { return *reinterpret_cast<TreeT*>(this->treePtr()); }
2104 
2105  /// @brief Return a new instance of a ReadAccessor used to access values in this grid
2106  __hostdev__ AccessorType getAccessor() const { return AccessorType(this->tree().root()); }
2107 
2108  /// @brief Return a const reference to the size of a voxel in world units
2109  __hostdev__ const Vec3d& voxelSize() const { return DataType::mVoxelSize; }
2110 
2111  /// @brief Return a const reference to the Map for this grid
2112  __hostdev__ const Map& map() const { return DataType::mMap; }
2113 
2114  /// @brief world to index space transformation
2115  template<typename Vec3T>
2116  __hostdev__ Vec3T worldToIndex(const Vec3T& xyz) const { return this->applyInverseMap(xyz); }
2117 
2118  /// @brief index to world space transformation
2119  template<typename Vec3T>
2120  __hostdev__ Vec3T indexToWorld(const Vec3T& xyz) const { return this->applyMap(xyz); }
2121 
2122  /// @brief transformation from index space direction to world space direction
2123  /// @warning assumes dir to be normalized
2124  template<typename Vec3T>
2125  __hostdev__ Vec3T indexToWorldDir(const Vec3T& dir) const { return this->applyJacobian(dir); }
2126 
2127  /// @brief transformation from world space direction to index space direction
2128  /// @warning assumes dir to be normalized
2129  template<typename Vec3T>
2130  __hostdev__ Vec3T worldToIndexDir(const Vec3T& dir) const { return this->applyInverseJacobian(dir); }
2131 
2132  /// @brief transform the gradient from index space to world space.
2133  /// @details Applies the inverse jacobian transform map.
2134  template<typename Vec3T>
2135  __hostdev__ Vec3T indexToWorldGrad(const Vec3T& grad) const { return this->applyIJT(grad); }
2136 
2137  /// @brief world to index space transformation
2138  template<typename Vec3T>
2139  __hostdev__ Vec3T worldToIndexF(const Vec3T& xyz) const { return this->applyInverseMapF(xyz); }
2140 
2141  /// @brief index to world space transformation
2142  template<typename Vec3T>
2143  __hostdev__ Vec3T indexToWorldF(const Vec3T& xyz) const { return this->applyMapF(xyz); }
2144 
2145  /// @brief transformation from index space direction to world space direction
2146  /// @warning assumes dir to be normalized
2147  template<typename Vec3T>
2148  __hostdev__ Vec3T indexToWorldDirF(const Vec3T& dir) const { return this->applyJacobianF(dir); }
2149 
2150  /// @brief transformation from world space direction to index space direction
2151  /// @warning assumes dir to be normalized
2152  template<typename Vec3T>
2153  __hostdev__ Vec3T worldToIndexDirF(const Vec3T& dir) const { return this->applyInverseJacobianF(dir); }
2154 
2155  /// @brief Transforms the gradient from index space to world space.
2156  /// @details Applies the inverse jacobian transform map.
2157  template<typename Vec3T>
2158  __hostdev__ Vec3T indexToWorldGradF(const Vec3T& grad) const { return DataType::applyIJTF(grad); }
2159 
2160  /// @brief Computes a AABB of active values in world space
2161  //__hostdev__ const Vec3dBBox& worldBBox() const { return DataType::mWorldBBox; }
2162 
2163  /// @brief Computes a AABB of active values in index space
2164  ///
2165  /// @note This method is returning a floating point bounding box and not a CoordBBox. This makes
2166  /// it more useful for clipping rays.
2167  //__hostdev__ const BBox<CoordType>& indexBBox() const { return this->tree().bbox(); }
2168 
2169  /// @brief Return the total number of active voxels in this tree.
2170  __hostdev__ uint64_t activeVoxelCount() const { return this->tree().activeVoxelCount(); }
2171 
2172  /// @brief Methods related to the classification of this grid
2173  __hostdev__ bool isValid() const { return DataType::isValid(); }
2174  __hostdev__ const GridType& gridType() const { return DataType::mGridType; }
2175  __hostdev__ const GridClass& gridClass() const { return DataType::mGridClass; }
2176  __hostdev__ bool isLevelSet() const { return DataType::mGridClass == GridClass::LevelSet; }
2177  __hostdev__ bool isFogVolume() const { return DataType::mGridClass == GridClass::FogVolume; }
2178  __hostdev__ bool isStaggered() const { return DataType::mGridClass == GridClass::Staggered; }
2179  __hostdev__ bool isPointIndex() const { return DataType::mGridClass == GridClass::PointIndex; }
2180  __hostdev__ bool isGridIndex() const { return DataType::mGridClass == GridClass::IndexGrid; }
2181  __hostdev__ bool isPointData() const { return DataType::mGridClass == GridClass::PointData; }
2182  __hostdev__ bool isMask() const { return DataType::mGridClass == GridClass::Topology; }
2183  __hostdev__ bool isUnknown() const { return DataType::mGridClass == GridClass::Unknown; }
2184  __hostdev__ bool hasMinMax() const { return DataType::mFlags.isMaskOn(GridFlags::HasMinMax); }
2185  __hostdev__ bool hasBBox() const { return DataType::mFlags.isMaskOn(GridFlags::HasBBox); }
2186  __hostdev__ bool hasLongGridName() const { return DataType::mFlags.isMaskOn(GridFlags::HasLongGridName); }
2187  __hostdev__ bool hasAverage() const { return DataType::mFlags.isMaskOn(GridFlags::HasAverage); }
2188  __hostdev__ bool hasStdDeviation() const { return DataType::mFlags.isMaskOn(GridFlags::HasStdDeviation); }
2189  __hostdev__ bool isBreadthFirst() const { return DataType::mFlags.isMaskOn(GridFlags::IsBreadthFirst); }
2190 
2191  /// @brief return true if the specified node type is layed out breadth-first in memory and has a fixed size.
2192  /// This allows for sequential access to the nodes.
2193  template<typename NodeT>
2194  __hostdev__ bool isSequential() const { return NodeT::FIXED_SIZE && this->isBreadthFirst(); }
2195 
2196  /// @brief return true if the specified node level is layed out breadth-first in memory and has a fixed size.
2197  /// This allows for sequential access to the nodes.
2198  template<int LEVEL>
2199  __hostdev__ bool isSequential() const { return NodeTrait<TreeT, LEVEL>::type::FIXED_SIZE && this->isBreadthFirst(); }
2200 
2201  /// @brief return true if nodes at all levels can safely be accessed with simple linear offsets
2202  __hostdev__ bool isSequential() const { return UpperNodeType::FIXED_SIZE && LowerNodeType::FIXED_SIZE && LeafNodeType::FIXED_SIZE && this->isBreadthFirst(); }
2203 
2204  /// @brief Return a c-string with the name of this grid
2205  __hostdev__ const char* gridName() const { return DataType::gridName(); }
2206 
2207  /// @brief Return a c-string with the name of this grid, truncated to 255 characters
2208  __hostdev__ const char* shortGridName() const { return DataType::mGridName; }
2209 
2210  /// @brief Return checksum of the grid buffer.
2211  __hostdev__ const Checksum& checksum() const { return DataType::mChecksum; }
2212 
2213  /// @brief Return true if this grid is empty, i.e. contains no values or nodes.
2214  //__hostdev__ bool isEmpty() const { return this->tree().isEmpty(); }
2215 
2216  /// @brief Return the count of blind-data encoded in this grid
2217  __hostdev__ uint32_t blindDataCount() const { return DataType::mBlindMetadataCount; }
2218 
2219  /// @brief Return the index of the first blind data with specified name if found, otherwise -1.
2220  __hostdev__ int findBlindData(const char* name) const;
2221 
2222  /// @brief Return the index of the first blind data with specified semantic if found, otherwise -1.
2223  __hostdev__ int findBlindDataForSemantic(GridBlindDataSemantic semantic) const;
2224 
2225  /// @brief Returns a const pointer to the blindData at the specified linear offset.
2226  ///
2227  /// @warning Pointer might be NULL and the linear offset is assumed to be in the valid range
2228  // this method is deprecated !!!!
2229  [[deprecated("Use Grid::getBlindData<T>() instead.")]]
2230  __hostdev__ const void* blindData(uint32_t n) const
2231  {
2232  printf("\nnanovdb::Grid::blindData is unsafe and hence deprecated! Please use nanovdb::Grid::getBlindData instead.\n\n");
2233  NANOVDB_ASSERT(n < DataType::mBlindMetadataCount);
2234  return this->blindMetaData(n).blindData();
2235  }
2236 
2237  template <typename BlindDataT>
2238  __hostdev__ const BlindDataT* getBlindData(uint32_t n) const
2239  {
2240  if (n >= DataType::mBlindMetadataCount) return nullptr;// index is out of bounds
2241  return this->blindMetaData(n).template getBlindData<BlindDataT>();// NULL if mismatching BlindDataT
2242  }
2243 
2244  template <typename BlindDataT>
2245  __hostdev__ BlindDataT* getBlindData(uint32_t n)
2246  {
2247  if (n >= DataType::mBlindMetadataCount) return nullptr;// index is out of bounds
2248  return const_cast<BlindDataT*>(this->blindMetaData(n).template getBlindData<BlindDataT>());// NULL if mismatching BlindDataT
2249  }
2250 
2251  __hostdev__ const GridBlindMetaData& blindMetaData(uint32_t n) const { return *DataType::blindMetaData(n); }
2252 
2253 private:
2254  static_assert(sizeof(GridData) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(GridData) is misaligned");
2255 }; // Class Grid
2256 
2257 template<typename TreeT>
2259 {
2260  for (uint32_t i = 0, n = this->blindDataCount(); i < n; ++i) {
2261  if (this->blindMetaData(i).mSemantic == semantic)
2262  return int(i);
2263  }
2264  return -1;
2265 }
2266 
2267 template<typename TreeT>
2268 __hostdev__ int Grid<TreeT>::findBlindData(const char* name) const
2269 {
2270  auto test = [&](int n) {
2271  const char* str = this->blindMetaData(n).mName;
2272  for (int i = 0; i < GridBlindMetaData::MaxNameSize; ++i) {
2273  if (name[i] != str[i])
2274  return false;
2275  if (name[i] == '\0' && str[i] == '\0')
2276  return true;
2277  }
2278  return true; // all len characters matched
2279  };
2280  for (int i = 0, n = this->blindDataCount(); i < n; ++i)
2281  if (test(i))
2282  return i;
2283  return -1;
2284 }
2285 
2286 // ----------------------------> Tree <--------------------------------------
2287 
2288 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) TreeData
2289 { // sizeof(TreeData) == 64B
2290  int64_t mNodeOffset[4];// 32B, byte offset from this tree to first leaf, lower, upper and root node. If mNodeCount[N]=0 => mNodeOffset[N]==mNodeOffset[N+1]
2291  uint32_t mNodeCount[3]; // 12B, total number of nodes of type: leaf, lower internal, upper internal
2292  uint32_t mTileCount[3]; // 12B, total number of active tile values at the lower internal, upper internal and root node levels
2293  uint64_t mVoxelCount; // 8B, total number of active voxels in the root and all its child nodes.
2294  // No padding since it's always 32B aligned
2295  //__hostdev__ TreeData& operator=(const TreeData& other){return *util::memcpy(this, &other);}
2296  TreeData& operator=(const TreeData&) = default;
2297  __hostdev__ void setRoot(const void* root) {
2298  NANOVDB_ASSERT(root);
2299  mNodeOffset[3] = util::PtrDiff(root, this);
2300  }
2301 
2302  /// @brief Get a non-const void pointer to the root node (never NULL)
2303  __hostdev__ void* getRoot() { return util::PtrAdd(this, mNodeOffset[3]); }
2304 
2305  /// @brief Get a const void pointer to the root node (never NULL)
2306  __hostdev__ const void* getRoot() const { return util::PtrAdd(this, mNodeOffset[3]); }
2307 
2308  template<typename NodeT>
2309  __hostdev__ void setFirstNode(const NodeT* node) {mNodeOffset[NodeT::LEVEL] = (node ? util::PtrDiff(node, this) : 0);}
2310 
2311  /// @brief Return true if the root is empty, i.e. has not child nodes or constant tiles
2312  __hostdev__ bool isEmpty() const {return mNodeOffset[3] ? *util::PtrAdd<uint32_t>(this, mNodeOffset[3] + sizeof(CoordBBox)) == 0 : true;}
2313 
2314  /// @brief Return the index bounding box of all the active values in this tree, i.e. in all nodes of the tree
2315  __hostdev__ CoordBBox bbox() const {return mNodeOffset[3] ? *util::PtrAdd<CoordBBox>(this, mNodeOffset[3]) : CoordBBox();}
2316 
2317  /// @brief return true if RootData is layout out immediately after TreeData in memory
2318  __hostdev__ bool isRootNext() const {return mNodeOffset[3] ? mNodeOffset[3] == sizeof(TreeData) : false; }
2319 };// TreeData
2320 
2321 // ----------------------------> GridTree <--------------------------------------
2322 
2323 /// @brief defines a tree type from a grid type while preserving constness
2324 template<typename GridT>
2325 struct GridTree
2326 {
2327  using Type = typename GridT::TreeType;
2328  using type = typename GridT::TreeType;
2329 };
2330 template<typename GridT>
2331 struct GridTree<const GridT>
2332 {
2333  using Type = const typename GridT::TreeType;
2334  using type = const typename GridT::TreeType;
2335 };
2336 
2337 // ----------------------------> Tree <--------------------------------------
2338 
2339 /// @brief VDB Tree, which is a thin wrapper around a RootNode.
2340 template<typename RootT>
2341 class Tree : public TreeData
2342 {
2343  static_assert(RootT::LEVEL == 3, "Tree depth is not supported");
2344  static_assert(RootT::ChildNodeType::LOG2DIM == 5, "Tree configuration is not supported");
2345  static_assert(RootT::ChildNodeType::ChildNodeType::LOG2DIM == 4, "Tree configuration is not supported");
2346  static_assert(RootT::LeafNodeType::LOG2DIM == 3, "Tree configuration is not supported");
2347 
2348 public:
2350  using RootType = RootT;
2351  using RootNodeType = RootT;
2352  using UpperNodeType = typename RootNodeType::ChildNodeType;
2353  using LowerNodeType = typename UpperNodeType::ChildNodeType;
2354  using LeafNodeType = typename RootType::LeafNodeType;
2355  using ValueType = typename RootT::ValueType;
2356  using BuildType = typename RootT::BuildType; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool
2357  using CoordType = typename RootT::CoordType;
2359 
2360  using Node3 = RootT;
2361  using Node2 = typename RootT::ChildNodeType;
2362  using Node1 = typename Node2::ChildNodeType;
2364 
2365  /// @brief This class cannot be constructed or deleted
2366  Tree() = delete;
2367  Tree(const Tree&) = delete;
2368  Tree& operator=(const Tree&) = delete;
2369  ~Tree() = delete;
2370 
2371  __hostdev__ DataType* data() { return reinterpret_cast<DataType*>(this); }
2372 
2373  __hostdev__ const DataType* data() const { return reinterpret_cast<const DataType*>(this); }
2374 
2375  /// @brief return memory usage in bytes for the class
2376  __hostdev__ static uint64_t memUsage() { return sizeof(DataType); }
2377 
2378  __hostdev__ RootT& root() {return *reinterpret_cast<RootT*>(DataType::getRoot());}
2379 
2380  __hostdev__ const RootT& root() const {return *reinterpret_cast<const RootT*>(DataType::getRoot());}
2381 
2382  __hostdev__ AccessorType getAccessor() const { return AccessorType(this->root()); }
2383 
2384  /// @brief Return the value of the given voxel (regardless of state or location in the tree.)
2385  __hostdev__ ValueType getValue(const CoordType& ijk) const { return this->root().getValue(ijk); }
2386  __hostdev__ ValueType getValue(int i, int j, int k) const { return this->root().getValue(CoordType(i, j, k)); }
2387 
2388  /// @brief Return the active state of the given voxel (regardless of state or location in the tree.)
2389  __hostdev__ bool isActive(const CoordType& ijk) const { return this->root().isActive(ijk); }
2390 
2391  /// @brief Return true if this tree is empty, i.e. contains no values or nodes
2392  //__hostdev__ bool isEmpty() const { return this->root().isEmpty(); }
2393 
2394  /// @brief Combines the previous two methods in a single call
2395  __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->root().probeValue(ijk, v); }
2396 
2397  /// @brief Return a const reference to the background value.
2398  __hostdev__ const ValueType& background() const { return this->root().background(); }
2399 
2400  /// @brief Sets the extrema values of all the active values in this tree, i.e. in all nodes of the tree
2401  __hostdev__ void extrema(ValueType& min, ValueType& max) const;
2402 
2403  /// @brief Return a const reference to the index bounding box of all the active values in this tree, i.e. in all nodes of the tree
2404  //__hostdev__ const BBox<CoordType>& bbox() const { return this->root().bbox(); }
2405 
2406  /// @brief Return the total number of active voxels in this tree.
2407  __hostdev__ uint64_t activeVoxelCount() const { return DataType::mVoxelCount; }
2408 
2409  /// @brief Return the total number of active tiles at the specified level of the tree.
2410  ///
2411  /// @details level = 1,2,3 corresponds to active tile count in lower internal nodes, upper
2412  /// internal nodes, and the root level. Note active values at the leaf level are
2413  /// referred to as active voxels (see activeVoxelCount defined above).
2414  __hostdev__ const uint32_t& activeTileCount(uint32_t level) const
2415  {
2416  NANOVDB_ASSERT(level > 0 && level <= 3); // 1, 2, or 3
2417  return DataType::mTileCount[level - 1];
2418  }
2419 
2420  template<typename NodeT>
2421  __hostdev__ uint32_t nodeCount() const
2422  {
2423  static_assert(NodeT::LEVEL < 3, "Invalid NodeT");
2424  return DataType::mNodeCount[NodeT::LEVEL];
2425  }
2426 
2427  __hostdev__ uint32_t nodeCount(int level) const
2428  {
2429  NANOVDB_ASSERT(level < 3);
2430  return DataType::mNodeCount[level];
2431  }
2432 
2433  __hostdev__ uint32_t totalNodeCount() const
2434  {
2435  return DataType::mNodeCount[0] + DataType::mNodeCount[1] + DataType::mNodeCount[2];
2436  }
2437 
2438  /// @brief return a pointer to the first node of the specified type
2439  ///
2440  /// @warning Note it may return NULL if no nodes exist
2441  template<typename NodeT>
2443  {
2444  const int64_t nodeOffset = DataType::mNodeOffset[NodeT::LEVEL];
2445  return nodeOffset ? util::PtrAdd<NodeT>(this, nodeOffset) : nullptr;
2446  }
2447 
2448  /// @brief return a const pointer to the first node of the specified type
2449  ///
2450  /// @warning Note it may return NULL if no nodes exist
2451  template<typename NodeT>
2452  __hostdev__ const NodeT* getFirstNode() const
2453  {
2454  const int64_t nodeOffset = DataType::mNodeOffset[NodeT::LEVEL];
2455  return nodeOffset ? util::PtrAdd<NodeT>(this, nodeOffset) : nullptr;
2456  }
2457 
2458  /// @brief return a pointer to the first node at the specified level
2459  ///
2460  /// @warning Note it may return NULL if no nodes exist
2461  template<int LEVEL>
2463  {
2464  return this->template getFirstNode<typename NodeTrait<RootT, LEVEL>::type>();
2465  }
2466 
2467  /// @brief return a const pointer to the first node of the specified level
2468  ///
2469  /// @warning Note it may return NULL if no nodes exist
2470  template<int LEVEL>
2472  {
2473  return this->template getFirstNode<typename NodeTrait<RootT, LEVEL>::type>();
2474  }
2475 
2476  /// @brief Template specializations of getFirstNode
2477  __hostdev__ LeafNodeType* getFirstLeaf() { return this->getFirstNode<LeafNodeType>(); }
2478  __hostdev__ const LeafNodeType* getFirstLeaf() const { return this->getFirstNode<LeafNodeType>(); }
2479  __hostdev__ typename NodeTrait<RootT, 1>::type* getFirstLower() { return this->getFirstNode<1>(); }
2480  __hostdev__ const typename NodeTrait<RootT, 1>::type* getFirstLower() const { return this->getFirstNode<1>(); }
2481  __hostdev__ typename NodeTrait<RootT, 2>::type* getFirstUpper() { return this->getFirstNode<2>(); }
2482  __hostdev__ const typename NodeTrait<RootT, 2>::type* getFirstUpper() const { return this->getFirstNode<2>(); }
2483 
2484  template<typename OpT, typename... ArgsT>
2485  __hostdev__ auto get(const CoordType& ijk, ArgsT&&... args) const
2486  {
2487  return this->root().template get<OpT>(ijk, args...);
2488  }
2489 
2490  template<typename OpT, typename... ArgsT>
2491  __hostdev__ auto set(const CoordType& ijk, ArgsT&&... args)
2492  {
2493  return this->root().template set<OpT>(ijk, args...);
2494  }
2495 
2496 private:
2497  static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(TreeData) is misaligned");
2498 
2499 }; // Tree class
2500 
2501 template<typename RootT>
2503 {
2504  min = this->root().minimum();
2505  max = this->root().maximum();
2506 }
2507 
2508 // --------------------------> RootData <------------------------------------
2509 
2510 /// @brief Struct with all the member data of the RootNode (useful during serialization of an openvdb RootNode)
2511 ///
2512 /// @note No client code should (or can) interface with this struct so it can safely be ignored!
2513 template<typename ChildT>
2514 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) RootData
2515 {
2516  using ValueT = typename ChildT::ValueType;
2517  using BuildT = typename ChildT::BuildType; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool
2518  using CoordT = typename ChildT::CoordType;
2519  using StatsT = typename ChildT::FloatType;
2520  static constexpr bool FIXED_SIZE = false;
2521 
2522  /// @brief Return a key based on the coordinates of a voxel
2523 #ifdef NANOVDB_USE_SINGLE_ROOT_KEY
2524  using KeyT = uint64_t;
2525  template<typename CoordType>
2526  __hostdev__ static KeyT CoordToKey(const CoordType& ijk)
2527  {
2528  static_assert(sizeof(CoordT) == sizeof(CoordType), "Mismatching sizeof");
2529  static_assert(32 - ChildT::TOTAL <= 21, "Cannot use 64 bit root keys");
2530  return (KeyT(uint32_t(ijk[2]) >> ChildT::TOTAL)) | // z is the lower 21 bits
2531  (KeyT(uint32_t(ijk[1]) >> ChildT::TOTAL) << 21) | // y is the middle 21 bits
2532  (KeyT(uint32_t(ijk[0]) >> ChildT::TOTAL) << 42); // x is the upper 21 bits
2533  }
2534  __hostdev__ static CoordT KeyToCoord(const KeyT& key)
2535  {
2536  static constexpr uint64_t MASK = (1u << 21) - 1; // used to mask out 21 lower bits
2537  return CoordT(((key >> 42) & MASK) << ChildT::TOTAL, // x are the upper 21 bits
2538  ((key >> 21) & MASK) << ChildT::TOTAL, // y are the middle 21 bits
2539  (key & MASK) << ChildT::TOTAL); // z are the lower 21 bits
2540  }
2541 #else
2542  using KeyT = CoordT;
2543  __hostdev__ static KeyT CoordToKey(const CoordT& ijk) { return ijk & ~ChildT::MASK; }
2544  __hostdev__ static CoordT KeyToCoord(const KeyT& key) { return key; }
2545 #endif
2546  math::BBox<CoordT> mBBox; // 24B. AABB of active values in index space.
2547  uint32_t mTableSize; // 4B. number of tiles and child pointers in the root node
2548 
2549  ValueT mBackground; // background value, i.e. value of any unset voxel
2550  ValueT mMinimum; // typically 4B, minimum of all the active values
2551  ValueT mMaximum; // typically 4B, maximum of all the active values
2552  StatsT mAverage; // typically 4B, average of all the active values in this node and its child nodes
2553  StatsT mStdDevi; // typically 4B, standard deviation of all the active values in this node and its child nodes
2554 
2555  /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment
2556  ///
2557  /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members.
2558  __hostdev__ static constexpr uint32_t padding()
2559  {
2560  return sizeof(RootData) - (24 + 4 + 3 * sizeof(ValueT) + 2 * sizeof(StatsT));
2561  }
2562 
2563  struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) Tile
2564  {
2565  template<typename CoordType>
2566  __hostdev__ void setChild(const CoordType& k, const void* ptr, const RootData* data)
2567  {
2568  key = CoordToKey(k);
2569  state = false;
2570  child = util::PtrDiff(ptr, data);
2571  }
2572  template<typename CoordType, typename ValueType>
2573  __hostdev__ void setValue(const CoordType& k, bool s, const ValueType& v)
2574  {
2575  key = CoordToKey(k);
2576  state = s;
2577  value = v;
2578  child = 0;
2579  }
2580  __hostdev__ bool isChild() const { return child != 0; }
2581  __hostdev__ bool isValue() const { return child == 0; }
2582  __hostdev__ bool isActive() const { return child == 0 && state; }
2583  __hostdev__ CoordT origin() const { return KeyToCoord(key); }
2584  KeyT key; // NANOVDB_USE_SINGLE_ROOT_KEY ? 8B : 12B
2585  int64_t child; // 8B. signed byte offset from this node to the child node. 0 means it is a constant tile, so use value.
2586  uint32_t state; // 4B. state of tile value
2587  ValueT value; // value of tile (i.e. no child node)
2588  }; // Tile
2589 
2590  /// @brief Returns a non-const reference to the tile at the specified linear offset.
2591  ///
2592  /// @warning The linear offset is assumed to be in the valid range
2593  __hostdev__ const Tile* tile(uint32_t n) const
2594  {
2595  NANOVDB_ASSERT(n < mTableSize);
2596  return reinterpret_cast<const Tile*>(this + 1) + n;
2597  }
2598  __hostdev__ Tile* tile(uint32_t n)
2599  {
2600  NANOVDB_ASSERT(n < mTableSize);
2601  return reinterpret_cast<Tile*>(this + 1) + n;
2602  }
2603 
2605  {
2606 #if 1 // switch between linear and binary seach
2607  const auto key = CoordToKey(ijk);
2608  for (Tile *p = reinterpret_cast<Tile*>(this + 1), *q = p + mTableSize; p < q; ++p)
2609  if (p->key == key)
2610  return p;
2611  return nullptr;
2612 #else // do not enable binary search if tiles are not guaranteed to be sorted!!!!!!
2613  int32_t low = 0, high = mTableSize; // low is inclusive and high is exclusive
2614  while (low != high) {
2615  int mid = low + ((high - low) >> 1);
2616  const Tile* tile = &tiles[mid];
2617  if (tile->key == key) {
2618  return tile;
2619  } else if (tile->key < key) {
2620  low = mid + 1;
2621  } else {
2622  high = mid;
2623  }
2624  }
2625  return nullptr;
2626 #endif
2627  }
2628 
2629  __hostdev__ inline const Tile* probeTile(const CoordT& ijk) const
2630  {
2631  return const_cast<RootData*>(this)->probeTile(ijk);
2632  }
2633 
2634  /// @brief Returns a const reference to the child node in the specified tile.
2635  ///
2636  /// @warning A child node is assumed to exist in the specified tile
2637  __hostdev__ ChildT* getChild(const Tile* tile)
2638  {
2639  NANOVDB_ASSERT(tile->child);
2640  return util::PtrAdd<ChildT>(this, tile->child);
2641  }
2642  __hostdev__ const ChildT* getChild(const Tile* tile) const
2643  {
2644  NANOVDB_ASSERT(tile->child);
2645  return util::PtrAdd<ChildT>(this, tile->child);
2646  }
2647 
2648  __hostdev__ const ValueT& getMin() const { return mMinimum; }
2649  __hostdev__ const ValueT& getMax() const { return mMaximum; }
2650  __hostdev__ const StatsT& average() const { return mAverage; }
2651  __hostdev__ const StatsT& stdDeviation() const { return mStdDevi; }
2652 
2653  __hostdev__ void setMin(const ValueT& v) { mMinimum = v; }
2654  __hostdev__ void setMax(const ValueT& v) { mMaximum = v; }
2655  __hostdev__ void setAvg(const StatsT& v) { mAverage = v; }
2656  __hostdev__ void setDev(const StatsT& v) { mStdDevi = v; }
2657 
2658  /// @brief This class cannot be constructed or deleted
2659  RootData() = delete;
2660  RootData(const RootData&) = delete;
2661  RootData& operator=(const RootData&) = delete;
2662  ~RootData() = delete;
2663 }; // RootData
2664 
2665 // --------------------------> RootNode <------------------------------------
2666 
2667 /// @brief Top-most node of the VDB tree structure.
2668 template<typename ChildT>
2669 class RootNode : public RootData<ChildT>
2670 {
2671 public:
2673  using ChildNodeType = ChildT;
2674  using RootType = RootNode<ChildT>; // this allows RootNode to behave like a Tree
2676  using UpperNodeType = ChildT;
2677  using LowerNodeType = typename UpperNodeType::ChildNodeType;
2678  using LeafNodeType = typename ChildT::LeafNodeType;
2679  using ValueType = typename DataType::ValueT;
2680  using FloatType = typename DataType::StatsT;
2681  using BuildType = typename DataType::BuildT; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool
2682 
2683  using CoordType = typename ChildT::CoordType;
2684  using BBoxType = math::BBox<CoordType>;
2686  using Tile = typename DataType::Tile;
2687  static constexpr bool FIXED_SIZE = DataType::FIXED_SIZE;
2688 
2689  static constexpr uint32_t LEVEL = 1 + ChildT::LEVEL; // level 0 = leaf
2690 
2691  template<typename RootT>
2692  class BaseIter
2693  {
2694  protected:
2698  uint32_t mPos, mSize;
2699  __hostdev__ BaseIter(DataT* data = nullptr, uint32_t n = 0)
2700  : mData(data)
2701  , mPos(0)
2702  , mSize(n)
2703  {
2704  }
2705 
2706  public:
2707  __hostdev__ operator bool() const { return mPos < mSize; }
2708  __hostdev__ uint32_t pos() const { return mPos; }
2709  __hostdev__ void next() { ++mPos; }
2710  __hostdev__ TileT* tile() const { return mData->tile(mPos); }
2712  {
2713  NANOVDB_ASSERT(*this);
2714  return this->tile()->origin();
2715  }
2717  {
2718  NANOVDB_ASSERT(*this);
2719  return this->tile()->origin();
2720  }
2721  }; // Member class BaseIter
2722 
2723  template<typename RootT>
2724  class ChildIter : public BaseIter<RootT>
2725  {
2726  static_assert(util::is_same<typename util::remove_const<RootT>::type, RootNode>::value, "Invalid RootT");
2727  using BaseT = BaseIter<RootT>;
2728  using NodeT = typename util::match_const<ChildT, RootT>::type;
2729 
2730  public:
2732  : BaseT()
2733  {
2734  }
2735  __hostdev__ ChildIter(RootT* parent)
2736  : BaseT(parent->data(), parent->tileCount())
2737  {
2738  NANOVDB_ASSERT(BaseT::mData);
2739  while (*this && !this->tile()->isChild())
2740  this->next();
2741  }
2742  __hostdev__ NodeT& operator*() const
2743  {
2744  NANOVDB_ASSERT(*this);
2745  return *BaseT::mData->getChild(this->tile());
2746  }
2747  __hostdev__ NodeT* operator->() const
2748  {
2749  NANOVDB_ASSERT(*this);
2750  return BaseT::mData->getChild(this->tile());
2751  }
2753  {
2754  NANOVDB_ASSERT(BaseT::mData);
2755  this->next();
2756  while (*this && this->tile()->isValue())
2757  this->next();
2758  return *this;
2759  }
2761  {
2762  auto tmp = *this;
2763  ++(*this);
2764  return tmp;
2765  }
2766  }; // Member class ChildIter
2767 
2770 
2773 
2774  template<typename RootT>
2775  class ValueIter : public BaseIter<RootT>
2776  {
2777  using BaseT = BaseIter<RootT>;
2778 
2779  public:
2781  : BaseT()
2782  {
2783  }
2784  __hostdev__ ValueIter(RootT* parent)
2785  : BaseT(parent->data(), parent->tileCount())
2786  {
2787  NANOVDB_ASSERT(BaseT::mData);
2788  while (*this && this->tile()->isChild())
2789  this->next();
2790  }
2792  {
2793  NANOVDB_ASSERT(*this);
2794  return this->tile()->value;
2795  }
2796  __hostdev__ bool isActive() const
2797  {
2798  NANOVDB_ASSERT(*this);
2799  return this->tile()->state;
2800  }
2802  {
2803  NANOVDB_ASSERT(BaseT::mData);
2804  this->next();
2805  while (*this && this->tile()->isChild())
2806  this->next();
2807  return *this;
2808  }
2810  {
2811  auto tmp = *this;
2812  ++(*this);
2813  return tmp;
2814  }
2815  }; // Member class ValueIter
2816 
2819 
2822 
2823  template<typename RootT>
2824  class ValueOnIter : public BaseIter<RootT>
2825  {
2826  using BaseT = BaseIter<RootT>;
2827 
2828  public:
2830  : BaseT()
2831  {
2832  }
2833  __hostdev__ ValueOnIter(RootT* parent)
2834  : BaseT(parent->data(), parent->tileCount())
2835  {
2836  NANOVDB_ASSERT(BaseT::mData);
2837  while (*this && !this->tile()->isActive())
2838  ++BaseT::mPos;
2839  }
2841  {
2842  NANOVDB_ASSERT(*this);
2843  return this->tile()->value;
2844  }
2846  {
2847  NANOVDB_ASSERT(BaseT::mData);
2848  this->next();
2849  while (*this && !this->tile()->isActive())
2850  this->next();
2851  return *this;
2852  }
2854  {
2855  auto tmp = *this;
2856  ++(*this);
2857  return tmp;
2858  }
2859  }; // Member class ValueOnIter
2860 
2863 
2866 
2867  template<typename RootT>
2868  class DenseIter : public BaseIter<RootT>
2869  {
2870  using BaseT = BaseIter<RootT>;
2871  using NodeT = typename util::match_const<ChildT, RootT>::type;
2872 
2873  public:
2875  : BaseT()
2876  {
2877  }
2878  __hostdev__ DenseIter(RootT* parent)
2879  : BaseT(parent->data(), parent->tileCount())
2880  {
2881  NANOVDB_ASSERT(BaseT::mData);
2882  }
2883  __hostdev__ NodeT* probeChild(ValueType& value) const
2884  {
2885  NANOVDB_ASSERT(*this);
2886  NodeT* child = nullptr;
2887  auto* t = this->tile();
2888  if (t->isChild()) {
2889  child = BaseT::mData->getChild(t);
2890  } else {
2891  value = t->value;
2892  }
2893  return child;
2894  }
2895  __hostdev__ bool isValueOn() const
2896  {
2897  NANOVDB_ASSERT(*this);
2898  return this->tile()->state;
2899  }
2901  {
2902  NANOVDB_ASSERT(BaseT::mData);
2903  this->next();
2904  return *this;
2905  }
2907  {
2908  auto tmp = *this;
2909  ++(*this);
2910  return tmp;
2911  }
2912  }; // Member class DenseIter
2913 
2916 
2920 
2921  /// @brief This class cannot be constructed or deleted
2922  RootNode() = delete;
2923  RootNode(const RootNode&) = delete;
2924  RootNode& operator=(const RootNode&) = delete;
2925  ~RootNode() = delete;
2926 
2928 
2929  __hostdev__ DataType* data() { return reinterpret_cast<DataType*>(this); }
2930 
2931  __hostdev__ const DataType* data() const { return reinterpret_cast<const DataType*>(this); }
2932 
2933  /// @brief Return a const reference to the index bounding box of all the active values in this tree, i.e. in all nodes of the tree
2934  __hostdev__ const BBoxType& bbox() const { return DataType::mBBox; }
2935 
2936  /// @brief Return the total number of active voxels in the root and all its child nodes.
2937 
2938  /// @brief Return a const reference to the background value, i.e. the value associated with
2939  /// any coordinate location that has not been set explicitly.
2940  __hostdev__ const ValueType& background() const { return DataType::mBackground; }
2941 
2942  /// @brief Return the number of tiles encoded in this root node
2943  __hostdev__ const uint32_t& tileCount() const { return DataType::mTableSize; }
2944  __hostdev__ const uint32_t& getTableSize() const { return DataType::mTableSize; }
2945 
2946  /// @brief Return a const reference to the minimum active value encoded in this root node and any of its child nodes
2947  __hostdev__ const ValueType& minimum() const { return DataType::mMinimum; }
2948 
2949  /// @brief Return a const reference to the maximum active value encoded in this root node and any of its child nodes
2950  __hostdev__ const ValueType& maximum() const { return DataType::mMaximum; }
2951 
2952  /// @brief Return a const reference to the average of all the active values encoded in this root node and any of its child nodes
2953  __hostdev__ const FloatType& average() const { return DataType::mAverage; }
2954 
2955  /// @brief Return the variance of all the active values encoded in this root node and any of its child nodes
2956  __hostdev__ FloatType variance() const { return math::Pow2(DataType::mStdDevi); }
2957 
2958  /// @brief Return a const reference to the standard deviation of all the active values encoded in this root node and any of its child nodes
2959  __hostdev__ const FloatType& stdDeviation() const { return DataType::mStdDevi; }
2960 
2961  /// @brief Return the expected memory footprint in bytes with the specified number of tiles
2962  __hostdev__ static uint64_t memUsage(uint32_t tableSize) { return sizeof(RootNode) + tableSize * sizeof(Tile); }
2963 
2964  /// @brief Return the actual memory footprint of this root node
2965  __hostdev__ uint64_t memUsage() const { return sizeof(RootNode) + DataType::mTableSize * sizeof(Tile); }
2966 
2967  /// @brief Return true if this RootNode is empty, i.e. contains no values or nodes
2968  __hostdev__ bool isEmpty() const { return DataType::mTableSize == uint32_t(0); }
2969 
2970 #ifdef NANOVDB_NEW_ACCESSOR_METHODS
2971  /// @brief Return the value of the given voxel
2972  __hostdev__ ValueType getValue(const CoordType& ijk) const { return this->template get<GetValue<BuildType>>(ijk); }
2973  __hostdev__ ValueType getValue(int i, int j, int k) const { return this->template get<GetValue<BuildType>>(CoordType(i, j, k)); }
2974  __hostdev__ bool isActive(const CoordType& ijk) const { return this->template get<GetState<BuildType>>(ijk); }
2975  /// @brief return the state and updates the value of the specified voxel
2976  __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->template get<ProbeValue<BuildType>>(ijk, v); }
2977  __hostdev__ const LeafNodeType* probeLeaf(const CoordType& ijk) const { return this->template get<GetLeaf<BuildType>>(ijk); }
2978 #else // NANOVDB_NEW_ACCESSOR_METHODS
2979 
2980  /// @brief Return the value of the given voxel
2981  __hostdev__ ValueType getValue(const CoordType& ijk) const
2982  {
2983  if (const Tile* tile = DataType::probeTile(ijk)) {
2984  return tile->isChild() ? this->getChild(tile)->getValue(ijk) : tile->value;
2985  }
2986  return DataType::mBackground;
2987  }
2988  __hostdev__ ValueType getValue(int i, int j, int k) const { return this->getValue(CoordType(i, j, k)); }
2989 
2990  __hostdev__ bool isActive(const CoordType& ijk) const
2991  {
2992  if (const Tile* tile = DataType::probeTile(ijk)) {
2993  return tile->isChild() ? this->getChild(tile)->isActive(ijk) : tile->state;
2994  }
2995  return false;
2996  }
2997 
2998  __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const
2999  {
3000  if (const Tile* tile = DataType::probeTile(ijk)) {
3001  if (tile->isChild()) {
3002  const auto* child = this->getChild(tile);
3003  return child->probeValue(ijk, v);
3004  }
3005  v = tile->value;
3006  return tile->state;
3007  }
3008  v = DataType::mBackground;
3009  return false;
3010  }
3011 
3012  __hostdev__ const LeafNodeType* probeLeaf(const CoordType& ijk) const
3013  {
3014  const Tile* tile = DataType::probeTile(ijk);
3015  if (tile && tile->isChild()) {
3016  const auto* child = this->getChild(tile);
3017  return child->probeLeaf(ijk);
3018  }
3019  return nullptr;
3020  }
3021 
3022 #endif // NANOVDB_NEW_ACCESSOR_METHODS
3023 
3025  {
3026  const Tile* tile = DataType::probeTile(ijk);
3027  return tile && tile->isChild() ? this->getChild(tile) : nullptr;
3028  }
3029 
3031  {
3032  const Tile* tile = DataType::probeTile(ijk);
3033  return tile && tile->isChild() ? this->getChild(tile) : nullptr;
3034  }
3035 
3036  template<typename OpT, typename... ArgsT>
3037  __hostdev__ auto get(const CoordType& ijk, ArgsT&&... args) const
3038  {
3039  if (const Tile* tile = this->probeTile(ijk)) {
3040  if (tile->isChild())
3041  return this->getChild(tile)->template get<OpT>(ijk, args...);
3042  return OpT::get(*tile, args...);
3043  }
3044  return OpT::get(*this, args...);
3045  }
3046 
3047  template<typename OpT, typename... ArgsT>
3048  // __hostdev__ auto // occasionally fails with NVCC
3049  __hostdev__ decltype(OpT::set(util::declval<Tile&>(), util::declval<ArgsT>()...))
3050  set(const CoordType& ijk, ArgsT&&... args)
3051  {
3052  if (Tile* tile = DataType::probeTile(ijk)) {
3053  if (tile->isChild())
3054  return this->getChild(tile)->template set<OpT>(ijk, args...);
3055  return OpT::set(*tile, args...);
3056  }
3057  return OpT::set(*this, args...);
3058  }
3059 
3060 private:
3061  static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(RootData) is misaligned");
3062  static_assert(sizeof(typename DataType::Tile) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(RootData::Tile) is misaligned");
3063 
3064  template<typename, int, int, int>
3065  friend class ReadAccessor;
3066 
3067  template<typename>
3068  friend class Tree;
3069 #ifndef NANOVDB_NEW_ACCESSOR_METHODS
3070  /// @brief Private method to return node information and update a ReadAccessor
3071  template<typename AccT>
3072  __hostdev__ typename AccT::NodeInfo getNodeInfoAndCache(const CoordType& ijk, const AccT& acc) const
3073  {
3074  using NodeInfoT = typename AccT::NodeInfo;
3075  if (const Tile* tile = this->probeTile(ijk)) {
3076  if (tile->isChild()) {
3077  const auto* child = this->getChild(tile);
3078  acc.insert(ijk, child);
3079  return child->getNodeInfoAndCache(ijk, acc);
3080  }
3081  return NodeInfoT{LEVEL, ChildT::dim(), tile->value, tile->value, tile->value, 0, tile->origin(), tile->origin() + CoordType(ChildT::DIM)};
3082  }
3083  return NodeInfoT{LEVEL, ChildT::dim(), this->minimum(), this->maximum(), this->average(), this->stdDeviation(), this->bbox()[0], this->bbox()[1]};
3084  }
3085 
3086  /// @brief Private method to return a voxel value and update a ReadAccessor
3087  template<typename AccT>
3088  __hostdev__ ValueType getValueAndCache(const CoordType& ijk, const AccT& acc) const
3089  {
3090  if (const Tile* tile = this->probeTile(ijk)) {
3091  if (tile->isChild()) {
3092  const auto* child = this->getChild(tile);
3093  acc.insert(ijk, child);
3094  return child->getValueAndCache(ijk, acc);
3095  }
3096  return tile->value;
3097  }
3098  return DataType::mBackground;
3099  }
3100 
3101  template<typename AccT>
3102  __hostdev__ bool isActiveAndCache(const CoordType& ijk, const AccT& acc) const
3103  {
3104  const Tile* tile = this->probeTile(ijk);
3105  if (tile && tile->isChild()) {
3106  const auto* child = this->getChild(tile);
3107  acc.insert(ijk, child);
3108  return child->isActiveAndCache(ijk, acc);
3109  }
3110  return false;
3111  }
3112 
3113  template<typename AccT>
3114  __hostdev__ bool probeValueAndCache(const CoordType& ijk, ValueType& v, const AccT& acc) const
3115  {
3116  if (const Tile* tile = this->probeTile(ijk)) {
3117  if (tile->isChild()) {
3118  const auto* child = this->getChild(tile);
3119  acc.insert(ijk, child);
3120  return child->probeValueAndCache(ijk, v, acc);
3121  }
3122  v = tile->value;
3123  return tile->state;
3124  }
3125  v = DataType::mBackground;
3126  return false;
3127  }
3128 
3129  template<typename AccT>
3130  __hostdev__ const LeafNodeType* probeLeafAndCache(const CoordType& ijk, const AccT& acc) const
3131  {
3132  const Tile* tile = this->probeTile(ijk);
3133  if (tile && tile->isChild()) {
3134  const auto* child = this->getChild(tile);
3135  acc.insert(ijk, child);
3136  return child->probeLeafAndCache(ijk, acc);
3137  }
3138  return nullptr;
3139  }
3140 #endif // NANOVDB_NEW_ACCESSOR_METHODS
3141 
3142  template<typename RayT, typename AccT>
3143  __hostdev__ uint32_t getDimAndCache(const CoordType& ijk, const RayT& ray, const AccT& acc) const
3144  {
3145  if (const Tile* tile = this->probeTile(ijk)) {
3146  if (tile->isChild()) {
3147  const auto* child = this->getChild(tile);
3148  acc.insert(ijk, child);
3149  return child->getDimAndCache(ijk, ray, acc);
3150  }
3151  return 1 << ChildT::TOTAL; //tile value
3152  }
3153  return ChildNodeType::dim(); // background
3154  }
3155 
3156  template<typename OpT, typename AccT, typename... ArgsT>
3157  //__hostdev__ decltype(OpT::get(util::declval<const Tile&>(), util::declval<ArgsT>()...))
3158  __hostdev__ auto
3159  getAndCache(const CoordType& ijk, const AccT& acc, ArgsT&&... args) const
3160  {
3161  if (const Tile* tile = this->probeTile(ijk)) {
3162  if (tile->isChild()) {
3163  const ChildT* child = this->getChild(tile);
3164  acc.insert(ijk, child);
3165  return child->template getAndCache<OpT>(ijk, acc, args...);
3166  }
3167  return OpT::get(*tile, args...);
3168  }
3169  return OpT::get(*this, args...);
3170  }
3171 
3172  template<typename OpT, typename AccT, typename... ArgsT>
3173  // __hostdev__ auto // occasionally fails with NVCC
3174  __hostdev__ decltype(OpT::set(util::declval<Tile&>(), util::declval<ArgsT>()...))
3175  setAndCache(const CoordType& ijk, const AccT& acc, ArgsT&&... args)
3176  {
3177  if (Tile* tile = DataType::probeTile(ijk)) {
3178  if (tile->isChild()) {
3179  ChildT* child = this->getChild(tile);
3180  acc.insert(ijk, child);
3181  return child->template setAndCache<OpT>(ijk, acc, args...);
3182  }
3183  return OpT::set(*tile, args...);
3184  }
3185  return OpT::set(*this, args...);
3186  }
3187 
3188 }; // RootNode class
3189 
3190 // After the RootNode the memory layout is assumed to be the sorted Tiles
3191 
3192 // --------------------------> InternalNode <------------------------------------
3193 
3194 /// @brief Struct with all the member data of the InternalNode (useful during serialization of an openvdb InternalNode)
3195 ///
3196 /// @note No client code should (or can) interface with this struct so it can safely be ignored!
3197 template<typename ChildT, uint32_t LOG2DIM>
3198 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) InternalData
3199 {
3200  using ValueT = typename ChildT::ValueType;
3201  using BuildT = typename ChildT::BuildType; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool
3202  using StatsT = typename ChildT::FloatType;
3203  using CoordT = typename ChildT::CoordType;
3204  using MaskT = typename ChildT::template MaskType<LOG2DIM>;
3205  static constexpr bool FIXED_SIZE = true;
3206 
3207  union Tile
3208  {
3210  int64_t child; //signed 64 bit byte offset relative to this InternalData, i.e. child-pointer = Tile::child + this
3211  /// @brief This class cannot be constructed or deleted
3212  Tile() = delete;
3213  Tile(const Tile&) = delete;
3214  Tile& operator=(const Tile&) = delete;
3215  ~Tile() = delete;
3216  };
3217 
3218  math::BBox<CoordT> mBBox; // 24B. node bounding box. |
3219  uint64_t mFlags; // 8B. node flags. | 32B aligned
3220  MaskT mValueMask; // LOG2DIM(5): 4096B, LOG2DIM(4): 512B | 32B aligned
3221  MaskT mChildMask; // LOG2DIM(5): 4096B, LOG2DIM(4): 512B | 32B aligned
3222 
3223  ValueT mMinimum; // typically 4B
3224  ValueT mMaximum; // typically 4B
3225  StatsT mAverage; // typically 4B, average of all the active values in this node and its child nodes
3226  StatsT mStdDevi; // typically 4B, standard deviation of all the active values in this node and its child nodes
3227  // possible padding, e.g. 28 byte padding when ValueType = bool
3228 
3229  /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment
3230  ///
3231  /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members.
3232  __hostdev__ static constexpr uint32_t padding()
3233  {
3234  return sizeof(InternalData) - (24u + 8u + 2 * (sizeof(MaskT) + sizeof(ValueT) + sizeof(StatsT)) + (1u << (3 * LOG2DIM)) * (sizeof(ValueT) > 8u ? sizeof(ValueT) : 8u));
3235  }
3236  alignas(32) Tile mTable[1u << (3 * LOG2DIM)]; // sizeof(ValueT) x (16*16*16 or 32*32*32)
3237 
3238  __hostdev__ static uint64_t memUsage() { return sizeof(InternalData); }
3239 
3240  __hostdev__ void setChild(uint32_t n, const void* ptr)
3241  {
3242  NANOVDB_ASSERT(mChildMask.isOn(n));
3243  mTable[n].child = util::PtrDiff(ptr, this);
3244  }
3245 
3246  template<typename ValueT>
3247  __hostdev__ void setValue(uint32_t n, const ValueT& v)
3248  {
3249  NANOVDB_ASSERT(!mChildMask.isOn(n));
3250  mTable[n].value = v;
3251  }
3252 
3253  /// @brief Returns a pointer to the child node at the specifed linear offset.
3254  __hostdev__ ChildT* getChild(uint32_t n)
3255  {
3256  NANOVDB_ASSERT(mChildMask.isOn(n));
3257  return util::PtrAdd<ChildT>(this, mTable[n].child);
3258  }
3259  __hostdev__ const ChildT* getChild(uint32_t n) const
3260  {
3261  NANOVDB_ASSERT(mChildMask.isOn(n));
3262  return util::PtrAdd<ChildT>(this, mTable[n].child);
3263  }
3264 
3265  __hostdev__ ValueT getValue(uint32_t n) const
3266  {
3267  NANOVDB_ASSERT(mChildMask.isOff(n));
3268  return mTable[n].value;
3269  }
3270 
3271  __hostdev__ bool isActive(uint32_t n) const
3272  {
3273  NANOVDB_ASSERT(mChildMask.isOff(n));
3274  return mValueMask.isOn(n);
3275  }
3276 
3277  __hostdev__ bool isChild(uint32_t n) const { return mChildMask.isOn(n); }
3278 
3279  template<typename T>
3280  __hostdev__ void setOrigin(const T& ijk) { mBBox[0] = ijk; }
3281 
3282  __hostdev__ const ValueT& getMin() const { return mMinimum; }
3283  __hostdev__ const ValueT& getMax() const { return mMaximum; }
3284  __hostdev__ const StatsT& average() const { return mAverage; }
3285  __hostdev__ const StatsT& stdDeviation() const { return mStdDevi; }
3286 
3287 #if defined(__GNUC__) && !defined(__APPLE__) && !defined(__llvm__)
3288 #pragma GCC diagnostic push
3289 #pragma GCC diagnostic ignored "-Wstringop-overflow"
3290 #endif
3291  __hostdev__ void setMin(const ValueT& v) { mMinimum = v; }
3292  __hostdev__ void setMax(const ValueT& v) { mMaximum = v; }
3293  __hostdev__ void setAvg(const StatsT& v) { mAverage = v; }
3294  __hostdev__ void setDev(const StatsT& v) { mStdDevi = v; }
3295 #if defined(__GNUC__) && !defined(__APPLE__) && !defined(__llvm__)
3296 #pragma GCC diagnostic pop
3297 #endif
3298 
3299  /// @brief This class cannot be constructed or deleted
3300  InternalData() = delete;
3301  InternalData(const InternalData&) = delete;
3302  InternalData& operator=(const InternalData&) = delete;
3303  ~InternalData() = delete;
3304 }; // InternalData
3305 
3306 /// @brief Internal nodes of a VDB tree
3307 template<typename ChildT, uint32_t Log2Dim = ChildT::LOG2DIM + 1>
3308 class InternalNode : public InternalData<ChildT, Log2Dim>
3309 {
3310 public:
3312  using ValueType = typename DataType::ValueT;
3313  using FloatType = typename DataType::StatsT;
3314  using BuildType = typename DataType::BuildT; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool
3315  using LeafNodeType = typename ChildT::LeafNodeType;
3316  using ChildNodeType = ChildT;
3317  using CoordType = typename ChildT::CoordType;
3318  static constexpr bool FIXED_SIZE = DataType::FIXED_SIZE;
3319  template<uint32_t LOG2>
3320  using MaskType = typename ChildT::template MaskType<LOG2>;
3321  template<bool On>
3322  using MaskIterT = typename Mask<Log2Dim>::template Iterator<On>;
3323 
3324  static constexpr uint32_t LOG2DIM = Log2Dim;
3325  static constexpr uint32_t TOTAL = LOG2DIM + ChildT::TOTAL; // dimension in index space
3326  static constexpr uint32_t DIM = 1u << TOTAL; // number of voxels along each axis of this node
3327  static constexpr uint32_t SIZE = 1u << (3 * LOG2DIM); // number of tile values (or child pointers)
3328  static constexpr uint32_t MASK = (1u << TOTAL) - 1u;
3329  static constexpr uint32_t LEVEL = 1 + ChildT::LEVEL; // level 0 = leaf
3330  static constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node
3331 
3332  /// @brief Visits child nodes of this node only
3333  template <typename ParentT>
3334  class ChildIter : public MaskIterT<true>
3335  {
3336  static_assert(util::is_same<typename util::remove_const<ParentT>::type, InternalNode>::value, "Invalid ParentT");
3337  using BaseT = MaskIterT<true>;
3338  using NodeT = typename util::match_const<ChildT, ParentT>::type;
3339  ParentT* mParent;
3340 
3341  public:
3343  : BaseT()
3344  , mParent(nullptr)
3345  {
3346  }
3347  __hostdev__ ChildIter(ParentT* parent)
3348  : BaseT(parent->mChildMask.beginOn())
3349  , mParent(parent)
3350  {
3351  }
3352  ChildIter& operator=(const ChildIter&) = default;
3353  __hostdev__ NodeT& operator*() const
3354  {
3355  NANOVDB_ASSERT(*this);
3356  return *mParent->getChild(BaseT::pos());
3357  }
3358  __hostdev__ NodeT* operator->() const
3359  {
3360  NANOVDB_ASSERT(*this);
3361  return mParent->getChild(BaseT::pos());
3362  }
3364  {
3365  NANOVDB_ASSERT(*this);
3366  return (*this)->origin();
3367  }
3368  __hostdev__ CoordType getCoord() const {return this->getOrigin();}
3369  }; // Member class ChildIter
3370 
3373 
3376 
3377  /// @brief Visits all tile values in this node, i.e. both inactive and active tiles
3378  class ValueIterator : public MaskIterT<false>
3379  {
3380  using BaseT = MaskIterT<false>;
3381  const InternalNode* mParent;
3382 
3383  public:
3385  : BaseT()
3386  , mParent(nullptr)
3387  {
3388  }
3390  : BaseT(parent->data()->mChildMask.beginOff())
3391  , mParent(parent)
3392  {
3393  }
3394  ValueIterator& operator=(const ValueIterator&) = default;
3396  {
3397  NANOVDB_ASSERT(*this);
3398  return mParent->data()->getValue(BaseT::pos());
3399  }
3401  {
3402  NANOVDB_ASSERT(*this);
3403  return mParent->offsetToGlobalCoord(BaseT::pos());
3404  }
3405  __hostdev__ CoordType getCoord() const {return this->getOrigin();}
3406  __hostdev__ bool isActive() const
3407  {
3408  NANOVDB_ASSERT(*this);
3409  return mParent->data()->isActive(BaseT::mPos);
3410  }
3411  }; // Member class ValueIterator
3412 
3415 
3416  /// @brief Visits active tile values of this node only
3417  class ValueOnIterator : public MaskIterT<true>
3418  {
3419  using BaseT = MaskIterT<true>;
3420  const InternalNode* mParent;
3421 
3422  public:
3424  : BaseT()
3425  , mParent(nullptr)
3426  {
3427  }
3429  : BaseT(parent->data()->mValueMask.beginOn())
3430  , mParent(parent)
3431  {
3432  }
3433  ValueOnIterator& operator=(const ValueOnIterator&) = default;
3435  {
3436  NANOVDB_ASSERT(*this);
3437  return mParent->data()->getValue(BaseT::pos());
3438  }
3440  {
3441  NANOVDB_ASSERT(*this);
3442  return mParent->offsetToGlobalCoord(BaseT::pos());
3443  }
3444  __hostdev__ CoordType getCoord() const {return this->getOrigin();}
3445  }; // Member class ValueOnIterator
3446 
3449 
3450  /// @brief Visits all tile values and child nodes of this node
3451  class DenseIterator : public Mask<Log2Dim>::DenseIterator
3452  {
3453  using BaseT = typename Mask<Log2Dim>::DenseIterator;
3454  const DataType* mParent;
3455 
3456  public:
3458  : BaseT()
3459  , mParent(nullptr)
3460  {
3461  }
3463  : BaseT(0)
3464  , mParent(parent->data())
3465  {
3466  }
3467  DenseIterator& operator=(const DenseIterator&) = default;
3468  __hostdev__ const ChildT* probeChild(ValueType& value) const
3469  {
3470  NANOVDB_ASSERT(mParent && bool(*this));
3471  const ChildT* child = nullptr;
3472  if (mParent->mChildMask.isOn(BaseT::pos())) {
3473  child = mParent->getChild(BaseT::pos());
3474  } else {
3475  value = mParent->getValue(BaseT::pos());
3476  }
3477  return child;
3478  }
3479  __hostdev__ bool isValueOn() const
3480  {
3481  NANOVDB_ASSERT(mParent && bool(*this));
3482  return mParent->isActive(BaseT::pos());
3483  }
3485  {
3486  NANOVDB_ASSERT(mParent && bool(*this));
3487  return mParent->offsetToGlobalCoord(BaseT::pos());
3488  }
3489  __hostdev__ CoordType getCoord() const {return this->getOrigin();}
3490  }; // Member class DenseIterator
3491 
3493  __hostdev__ DenseIterator cbeginChildAll() const { return DenseIterator(this); } // matches openvdb
3494 
3495  /// @brief This class cannot be constructed or deleted
3496  InternalNode() = delete;
3497  InternalNode(const InternalNode&) = delete;
3498  InternalNode& operator=(const InternalNode&) = delete;
3499  ~InternalNode() = delete;
3500 
3501  __hostdev__ DataType* data() { return reinterpret_cast<DataType*>(this); }
3502 
3503  __hostdev__ const DataType* data() const { return reinterpret_cast<const DataType*>(this); }
3504 
3505  /// @brief Return the dimension, in voxel units, of this internal node (typically 8*16 or 8*16*32)
3506  __hostdev__ static uint32_t dim() { return 1u << TOTAL; }
3507 
3508  /// @brief Return memory usage in bytes for the class
3509  __hostdev__ static size_t memUsage() { return DataType::memUsage(); }
3510 
3511  /// @brief Return a const reference to the bit mask of active voxels in this internal node
3512  __hostdev__ const MaskType<LOG2DIM>& valueMask() const { return DataType::mValueMask; }
3513  __hostdev__ const MaskType<LOG2DIM>& getValueMask() const { return DataType::mValueMask; }
3514 
3515  /// @brief Return a const reference to the bit mask of child nodes in this internal node
3516  __hostdev__ const MaskType<LOG2DIM>& childMask() const { return DataType::mChildMask; }
3517  __hostdev__ const MaskType<LOG2DIM>& getChildMask() const { return DataType::mChildMask; }
3518 
3519  /// @brief Return the origin in index space of this leaf node
3520  __hostdev__ CoordType origin() const { return DataType::mBBox.min() & ~MASK; }
3521 
3522  /// @brief Return a const reference to the minimum active value encoded in this internal node and any of its child nodes
3523  __hostdev__ const ValueType& minimum() const { return this->getMin(); }
3524 
3525  /// @brief Return a const reference to the maximum active value encoded in this internal node and any of its child nodes
3526  __hostdev__ const ValueType& maximum() const { return this->getMax(); }
3527 
3528  /// @brief Return a const reference to the average of all the active values encoded in this internal node and any of its child nodes
3529  __hostdev__ const FloatType& average() const { return DataType::mAverage; }
3530 
3531  /// @brief Return the variance of all the active values encoded in this internal node and any of its child nodes
3532  __hostdev__ FloatType variance() const { return DataType::mStdDevi * DataType::mStdDevi; }
3533 
3534  /// @brief Return a const reference to the standard deviation of all the active values encoded in this internal node and any of its child nodes
3535  __hostdev__ const FloatType& stdDeviation() const { return DataType::mStdDevi; }
3536 
3537  /// @brief Return a const reference to the bounding box in index space of active values in this internal node and any of its child nodes
3538  __hostdev__ const math::BBox<CoordType>& bbox() const { return DataType::mBBox; }
3539 
3540  /// @brief If the first entry in this node's table is a tile, return the tile's value.
3541  /// Otherwise, return the result of calling getFirstValue() on the child.
3543  {
3544  return DataType::mChildMask.isOn(0) ? this->getChild(0)->getFirstValue() : DataType::getValue(0);
3545  }
3546 
3547  /// @brief If the last entry in this node's table is a tile, return the tile's value.
3548  /// Otherwise, return the result of calling getLastValue() on the child.
3550  {
3551  return DataType::mChildMask.isOn(SIZE - 1) ? this->getChild(SIZE - 1)->getLastValue() : DataType::getValue(SIZE - 1);
3552  }
3553 
3554 #ifdef NANOVDB_NEW_ACCESSOR_METHODS
3555  /// @brief Return the value of the given voxel
3556  __hostdev__ ValueType getValue(const CoordType& ijk) const { return this->template get<GetValue<BuildType>>(ijk); }
3557  __hostdev__ bool isActive(const CoordType& ijk) const { return this->template get<GetState<BuildType>>(ijk); }
3558  /// @brief return the state and updates the value of the specified voxel
3559  __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->template get<ProbeValue<BuildType>>(ijk, v); }
3560  __hostdev__ const LeafNodeType* probeLeaf(const CoordType& ijk) const { return this->template get<GetLeaf<BuildType>>(ijk); }
3561 #else // NANOVDB_NEW_ACCESSOR_METHODS
3562  __hostdev__ ValueType getValue(const CoordType& ijk) const
3563  {
3564  const uint32_t n = CoordToOffset(ijk);
3565  return DataType::mChildMask.isOn(n) ? this->getChild(n)->getValue(ijk) : DataType::getValue(n);
3566  }
3567  __hostdev__ bool isActive(const CoordType& ijk) const
3568  {
3569  const uint32_t n = CoordToOffset(ijk);
3570  return DataType::mChildMask.isOn(n) ? this->getChild(n)->isActive(ijk) : DataType::isActive(n);
3571  }
3572  __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const
3573  {
3574  const uint32_t n = CoordToOffset(ijk);
3575  if (DataType::mChildMask.isOn(n))
3576  return this->getChild(n)->probeValue(ijk, v);
3577  v = DataType::getValue(n);
3578  return DataType::isActive(n);
3579  }
3580  __hostdev__ const LeafNodeType* probeLeaf(const CoordType& ijk) const
3581  {
3582  const uint32_t n = CoordToOffset(ijk);
3583  if (DataType::mChildMask.isOn(n))
3584  return this->getChild(n)->probeLeaf(ijk);
3585  return nullptr;
3586  }
3587 
3588 #endif // NANOVDB_NEW_ACCESSOR_METHODS
3589 
3591  {
3592  const uint32_t n = CoordToOffset(ijk);
3593  return DataType::mChildMask.isOn(n) ? this->getChild(n) : nullptr;
3594  }
3596  {
3597  const uint32_t n = CoordToOffset(ijk);
3598  return DataType::mChildMask.isOn(n) ? this->getChild(n) : nullptr;
3599  }
3600 
3601  /// @brief Return the linear offset corresponding to the given coordinate
3602  __hostdev__ static uint32_t CoordToOffset(const CoordType& ijk)
3603  {
3604  return (((ijk[0] & MASK) >> ChildT::TOTAL) << (2 * LOG2DIM)) | // note, we're using bitwise OR instead of +
3605  (((ijk[1] & MASK) >> ChildT::TOTAL) << (LOG2DIM)) |
3606  ((ijk[2] & MASK) >> ChildT::TOTAL);
3607  }
3608 
3609  /// @return the local coordinate of the n'th tile or child node
3610  __hostdev__ static Coord OffsetToLocalCoord(uint32_t n)
3611  {
3612  NANOVDB_ASSERT(n < SIZE);
3613  const uint32_t m = n & ((1 << 2 * LOG2DIM) - 1);
3614  return Coord(n >> 2 * LOG2DIM, m >> LOG2DIM, m & ((1 << LOG2DIM) - 1));
3615  }
3616 
3617  /// @brief modifies local coordinates to global coordinates of a tile or child node
3618  __hostdev__ void localToGlobalCoord(Coord& ijk) const
3619  {
3620  ijk <<= ChildT::TOTAL;
3621  ijk += this->origin();
3622  }
3623 
3624  __hostdev__ Coord offsetToGlobalCoord(uint32_t n) const
3625  {
3626  Coord ijk = InternalNode::OffsetToLocalCoord(n);
3627  this->localToGlobalCoord(ijk);
3628  return ijk;
3629  }
3630 
3631  /// @brief Return true if this node or any of its child nodes contain active values
3632  __hostdev__ bool isActive() const { return DataType::mFlags & uint32_t(2); }
3633 
3634  template<typename OpT, typename... ArgsT>
3635  __hostdev__ auto get(const CoordType& ijk, ArgsT&&... args) const
3636  {
3637  const uint32_t n = CoordToOffset(ijk);
3638  if (this->isChild(n))
3639  return this->getChild(n)->template get<OpT>(ijk, args...);
3640  return OpT::get(*this, n, args...);
3641  }
3642 
3643  template<typename OpT, typename... ArgsT>
3644  //__hostdev__ auto // occasionally fails with NVCC
3645  __hostdev__ decltype(OpT::set(util::declval<InternalNode&>(), util::declval<uint32_t>(), util::declval<ArgsT>()...))
3646  set(const CoordType& ijk, ArgsT&&... args)
3647  {
3648  const uint32_t n = CoordToOffset(ijk);
3649  if (this->isChild(n))
3650  return this->getChild(n)->template set<OpT>(ijk, args...);
3651  return OpT::set(*this, n, args...);
3652  }
3653 
3654 private:
3655  static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(InternalData) is misaligned");
3656 
3657  template<typename, int, int, int>
3658  friend class ReadAccessor;
3659 
3660  template<typename>
3661  friend class RootNode;
3662  template<typename, uint32_t>
3663  friend class InternalNode;
3664 
3665 #ifndef NANOVDB_NEW_ACCESSOR_METHODS
3666  /// @brief Private read access method used by the ReadAccessor
3667  template<typename AccT>
3668  __hostdev__ ValueType getValueAndCache(const CoordType& ijk, const AccT& acc) const
3669  {
3670  const uint32_t n = CoordToOffset(ijk);
3671  if (DataType::mChildMask.isOff(n))
3672  return DataType::getValue(n);
3673  const ChildT* child = this->getChild(n);
3674  acc.insert(ijk, child);
3675  return child->getValueAndCache(ijk, acc);
3676  }
3677  template<typename AccT>
3678  __hostdev__ bool isActiveAndCache(const CoordType& ijk, const AccT& acc) const
3679  {
3680  const uint32_t n = CoordToOffset(ijk);
3681  if (DataType::mChildMask.isOff(n))
3682  return DataType::isActive(n);
3683  const ChildT* child = this->getChild(n);
3684  acc.insert(ijk, child);
3685  return child->isActiveAndCache(ijk, acc);
3686  }
3687  template<typename AccT>
3688  __hostdev__ bool probeValueAndCache(const CoordType& ijk, ValueType& v, const AccT& acc) const
3689  {
3690  const uint32_t n = CoordToOffset(ijk);
3691  if (DataType::mChildMask.isOff(n)) {
3692  v = DataType::getValue(n);
3693  return DataType::isActive(n);
3694  }
3695  const ChildT* child = this->getChild(n);
3696  acc.insert(ijk, child);
3697  return child->probeValueAndCache(ijk, v, acc);
3698  }
3699  template<typename AccT>
3700  __hostdev__ const LeafNodeType* probeLeafAndCache(const CoordType& ijk, const AccT& acc) const
3701  {
3702  const uint32_t n = CoordToOffset(ijk);
3703  if (DataType::mChildMask.isOff(n))
3704  return nullptr;
3705  const ChildT* child = this->getChild(n);
3706  acc.insert(ijk, child);
3707  return child->probeLeafAndCache(ijk, acc);
3708  }
3709  template<typename AccT>
3710  __hostdev__ typename AccT::NodeInfo getNodeInfoAndCache(const CoordType& ijk, const AccT& acc) const
3711  {
3712  using NodeInfoT = typename AccT::NodeInfo;
3713  const uint32_t n = CoordToOffset(ijk);
3714  if (DataType::mChildMask.isOff(n)) {
3715  return NodeInfoT{LEVEL, this->dim(), this->minimum(), this->maximum(), this->average(), this->stdDeviation(), this->bbox()[0], this->bbox()[1]};
3716  }
3717  const ChildT* child = this->getChild(n);
3718  acc.insert(ijk, child);
3719  return child->getNodeInfoAndCache(ijk, acc);
3720  }
3721 #endif // NANOVDB_NEW_ACCESSOR_METHODS
3722 
3723  template<typename RayT, typename AccT>
3724  __hostdev__ uint32_t getDimAndCache(const CoordType& ijk, const RayT& ray, const AccT& acc) const
3725  {
3726  if (DataType::mFlags & uint32_t(1u))
3727  return this->dim(); // skip this node if the 1st bit is set
3728  //if (!ray.intersects( this->bbox() )) return 1<<TOTAL;
3729 
3730  const uint32_t n = CoordToOffset(ijk);
3731  if (DataType::mChildMask.isOn(n)) {
3732  const ChildT* child = this->getChild(n);
3733  acc.insert(ijk, child);
3734  return child->getDimAndCache(ijk, ray, acc);
3735  }
3736  return ChildNodeType::dim(); // tile value
3737  }
3738 
3739  template<typename OpT, typename AccT, typename... ArgsT>
3740  __hostdev__ auto
3741  //__hostdev__ decltype(OpT::get(util::declval<const InternalNode&>(), util::declval<uint32_t>(), util::declval<ArgsT>()...))
3742  getAndCache(const CoordType& ijk, const AccT& acc, ArgsT&&... args) const
3743  {
3744  const uint32_t n = CoordToOffset(ijk);
3745  if (DataType::mChildMask.isOff(n))
3746  return OpT::get(*this, n, args...);
3747  const ChildT* child = this->getChild(n);
3748  acc.insert(ijk, child);
3749  return child->template getAndCache<OpT>(ijk, acc, args...);
3750  }
3751 
3752  template<typename OpT, typename AccT, typename... ArgsT>
3753  //__hostdev__ auto // occasionally fails with NVCC
3754  __hostdev__ decltype(OpT::set(util::declval<InternalNode&>(), util::declval<uint32_t>(), util::declval<ArgsT>()...))
3755  setAndCache(const CoordType& ijk, const AccT& acc, ArgsT&&... args)
3756  {
3757  const uint32_t n = CoordToOffset(ijk);
3758  if (DataType::mChildMask.isOff(n))
3759  return OpT::set(*this, n, args...);
3760  ChildT* child = this->getChild(n);
3761  acc.insert(ijk, child);
3762  return child->template setAndCache<OpT>(ijk, acc, args...);
3763  }
3764 
3765 }; // InternalNode class
3766 
3767 // --------------------------> LeafData<T> <------------------------------------
3768 
3769 /// @brief Stuct with all the member data of the LeafNode (useful during serialization of an openvdb LeafNode)
3770 ///
3771 /// @note No client code should (or can) interface with this struct so it can safely be ignored!
3772 template<typename ValueT, typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
3773 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData
3774 {
3775  static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof");
3776  static_assert(sizeof(MaskT<LOG2DIM>) == sizeof(Mask<LOG2DIM>), "Mismatching sizeof");
3777  using ValueType = ValueT;
3778  using BuildType = ValueT;
3780  using ArrayType = ValueT; // type used for the internal mValue array
3781  static constexpr bool FIXED_SIZE = true;
3782 
3783  CoordT mBBoxMin; // 12B.
3784  uint8_t mBBoxDif[3]; // 3B.
3785  uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: has stats, bits5,6,7: bit-width for FpN
3786  MaskT<LOG2DIM> mValueMask; // LOG2DIM(3): 64B.
3787 
3788  ValueType mMinimum; // typically 4B
3789  ValueType mMaximum; // typically 4B
3790  FloatType mAverage; // typically 4B, average of all the active values in this node and its child nodes
3791  FloatType mStdDevi; // typically 4B, standard deviation of all the active values in this node and its child nodes
3792  alignas(32) ValueType mValues[1u << 3 * LOG2DIM];
3793 
3794  /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment
3795  ///
3796  /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members.
3797  __hostdev__ static constexpr uint32_t padding()
3798  {
3799  return sizeof(LeafData) - (12 + 3 + 1 + sizeof(MaskT<LOG2DIM>) + 2 * (sizeof(ValueT) + sizeof(FloatType)) + (1u << (3 * LOG2DIM)) * sizeof(ValueT));
3800  }
3801  __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); }
3802 
3803  __hostdev__ static bool hasStats() { return true; }
3804 
3805  __hostdev__ ValueType getValue(uint32_t i) const { return mValues[i]; }
3806  __hostdev__ void setValueOnly(uint32_t offset, const ValueType& value) { mValues[offset] = value; }
3807  __hostdev__ void setValue(uint32_t offset, const ValueType& value)
3808  {
3809  mValueMask.setOn(offset);
3810  mValues[offset] = value;
3811  }
3812  __hostdev__ void setOn(uint32_t offset) { mValueMask.setOn(offset); }
3813 
3814  __hostdev__ ValueType getMin() const { return mMinimum; }
3815  __hostdev__ ValueType getMax() const { return mMaximum; }
3816  __hostdev__ FloatType getAvg() const { return mAverage; }
3817  __hostdev__ FloatType getDev() const { return mStdDevi; }
3818 
3819  __hostdev__ void setMin(const ValueType& v) { mMinimum = v; }
3820  __hostdev__ void setMax(const ValueType& v) { mMaximum = v; }
3821  __hostdev__ void setAvg(const FloatType& v) { mAverage = v; }
3822  __hostdev__ void setDev(const FloatType& v) { mStdDevi = v; }
3823 
3824  template<typename T>
3825  __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; }
3826 
3827  __hostdev__ void fill(const ValueType& v)
3828  {
3829  for (auto *p = mValues, *q = p + 512; p != q; ++p)
3830  *p = v;
3831  }
3832 
3833  /// @brief This class cannot be constructed or deleted
3834  LeafData() = delete;
3835  LeafData(const LeafData&) = delete;
3836  LeafData& operator=(const LeafData&) = delete;
3837  ~LeafData() = delete;
3838 }; // LeafData<ValueT>
3839 
3840 // --------------------------> LeafFnBase <------------------------------------
3841 
3842 /// @brief Base-class for quantized float leaf nodes
3843 template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
3844 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafFnBase
3845 {
3846  static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof");
3847  static_assert(sizeof(MaskT<LOG2DIM>) == sizeof(Mask<LOG2DIM>), "Mismatching sizeof");
3848  using ValueType = float;
3849  using FloatType = float;
3850 
3851  CoordT mBBoxMin; // 12B.
3852  uint8_t mBBoxDif[3]; // 3B.
3853  uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: has stats, bits5,6,7: bit-width for FpN
3854  MaskT<LOG2DIM> mValueMask; // LOG2DIM(3): 64B.
3855 
3856  float mMinimum; // 4B - minimum of ALL values in this node
3857  float mQuantum; // = (max - min)/15 4B
3858  uint16_t mMin, mMax, mAvg, mDev; // quantized representations of statistics of active values
3859  // no padding since it's always 32B aligned
3860  __hostdev__ static uint64_t memUsage() { return sizeof(LeafFnBase); }
3861 
3862  __hostdev__ static bool hasStats() { return true; }
3863 
3864  /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment
3865  ///
3866  /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members.
3867  __hostdev__ static constexpr uint32_t padding()
3868  {
3869  return sizeof(LeafFnBase) - (12 + 3 + 1 + sizeof(MaskT<LOG2DIM>) + 2 * 4 + 4 * 2);
3870  }
3871  __hostdev__ void init(float min, float max, uint8_t bitWidth)
3872  {
3873  mMinimum = min;
3874  mQuantum = (max - min) / float((1 << bitWidth) - 1);
3875  }
3876 
3877  __hostdev__ void setOn(uint32_t offset) { mValueMask.setOn(offset); }
3878 
3879  /// @brief return the quantized minimum of the active values in this node
3880  __hostdev__ float getMin() const { return mMin * mQuantum + mMinimum; }
3881 
3882  /// @brief return the quantized maximum of the active values in this node
3883  __hostdev__ float getMax() const { return mMax * mQuantum + mMinimum; }
3884 
3885  /// @brief return the quantized average of the active values in this node
3886  __hostdev__ float getAvg() const { return mAvg * mQuantum + mMinimum; }
3887  /// @brief return the quantized standard deviation of the active values in this node
3888 
3889  /// @note 0 <= StdDev <= max-min or 0 <= StdDev/(max-min) <= 1
3890  __hostdev__ float getDev() const { return mDev * mQuantum; }
3891 
3892  /// @note min <= X <= max or 0 <= (X-min)/(min-max) <= 1
3893  __hostdev__ void setMin(float min) { mMin = uint16_t((min - mMinimum) / mQuantum + 0.5f); }
3894 
3895  /// @note min <= X <= max or 0 <= (X-min)/(min-max) <= 1
3896  __hostdev__ void setMax(float max) { mMax = uint16_t((max - mMinimum) / mQuantum + 0.5f); }
3897 
3898  /// @note min <= avg <= max or 0 <= (avg-min)/(min-max) <= 1
3899  __hostdev__ void setAvg(float avg) { mAvg = uint16_t((avg - mMinimum) / mQuantum + 0.5f); }
3900 
3901  /// @note 0 <= StdDev <= max-min or 0 <= StdDev/(max-min) <= 1
3902  __hostdev__ void setDev(float dev) { mDev = uint16_t(dev / mQuantum + 0.5f); }
3903 
3904  template<typename T>
3905  __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; }
3906 }; // LeafFnBase
3907 
3908 // --------------------------> LeafData<Fp4> <------------------------------------
3909 
3910 /// @brief Stuct with all the member data of the LeafNode (useful during serialization of an openvdb LeafNode)
3911 ///
3912 /// @note No client code should (or can) interface with this struct so it can safely be ignored!
3913 template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
3914 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<Fp4, CoordT, MaskT, LOG2DIM>
3915  : public LeafFnBase<CoordT, MaskT, LOG2DIM>
3916 {
3918  using BuildType = Fp4;
3919  using ArrayType = uint8_t; // type used for the internal mValue array
3920  static constexpr bool FIXED_SIZE = true;
3921  alignas(32) uint8_t mCode[1u << (3 * LOG2DIM - 1)]; // LeafFnBase is 32B aligned and so is mCode
3922 
3923  __hostdev__ static constexpr uint64_t memUsage() { return sizeof(LeafData); }
3924  __hostdev__ static constexpr uint32_t padding()
3925  {
3926  static_assert(BaseT::padding() == 0, "expected no padding in LeafFnBase");
3927  return sizeof(LeafData) - sizeof(BaseT) - (1u << (3 * LOG2DIM - 1));
3928  }
3929 
3930  __hostdev__ static constexpr uint8_t bitWidth() { return 4u; }
3931  __hostdev__ float getValue(uint32_t i) const
3932  {
3933 #if 0
3934  const uint8_t c = mCode[i>>1];
3935  return ( (i&1) ? c >> 4 : c & uint8_t(15) )*BaseT::mQuantum + BaseT::mMinimum;
3936 #else
3937  return ((mCode[i >> 1] >> ((i & 1) << 2)) & uint8_t(15)) * BaseT::mQuantum + BaseT::mMinimum;
3938 #endif
3939  }
3940 
3941  /// @brief This class cannot be constructed or deleted
3942  LeafData() = delete;
3943  LeafData(const LeafData&) = delete;
3944  LeafData& operator=(const LeafData&) = delete;
3945  ~LeafData() = delete;
3946 }; // LeafData<Fp4>
3947 
3948 // --------------------------> LeafBase<Fp8> <------------------------------------
3949 
3950 template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
3951 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<Fp8, CoordT, MaskT, LOG2DIM>
3952  : public LeafFnBase<CoordT, MaskT, LOG2DIM>
3953 {
3955  using BuildType = Fp8;
3956  using ArrayType = uint8_t; // type used for the internal mValue array
3957  static constexpr bool FIXED_SIZE = true;
3958  alignas(32) uint8_t mCode[1u << 3 * LOG2DIM];
3959  __hostdev__ static constexpr int64_t memUsage() { return sizeof(LeafData); }
3960  __hostdev__ static constexpr uint32_t padding()
3961  {
3962  static_assert(BaseT::padding() == 0, "expected no padding in LeafFnBase");
3963  return sizeof(LeafData) - sizeof(BaseT) - (1u << 3 * LOG2DIM);
3964  }
3965 
3966  __hostdev__ static constexpr uint8_t bitWidth() { return 8u; }
3967  __hostdev__ float getValue(uint32_t i) const
3968  {
3969  return mCode[i] * BaseT::mQuantum + BaseT::mMinimum; // code * (max-min)/255 + min
3970  }
3971  /// @brief This class cannot be constructed or deleted
3972  LeafData() = delete;
3973  LeafData(const LeafData&) = delete;
3974  LeafData& operator=(const LeafData&) = delete;
3975  ~LeafData() = delete;
3976 }; // LeafData<Fp8>
3977 
3978 // --------------------------> LeafData<Fp16> <------------------------------------
3979 
3980 template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
3981 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<Fp16, CoordT, MaskT, LOG2DIM>
3982  : public LeafFnBase<CoordT, MaskT, LOG2DIM>
3983 {
3985  using BuildType = Fp16;
3986  using ArrayType = uint16_t; // type used for the internal mValue array
3987  static constexpr bool FIXED_SIZE = true;
3988  alignas(32) uint16_t mCode[1u << 3 * LOG2DIM];
3989 
3990  __hostdev__ static constexpr uint64_t memUsage() { return sizeof(LeafData); }
3991  __hostdev__ static constexpr uint32_t padding()
3992  {
3993  static_assert(BaseT::padding() == 0, "expected no padding in LeafFnBase");
3994  return sizeof(LeafData) - sizeof(BaseT) - 2 * (1u << 3 * LOG2DIM);
3995  }
3996 
3997  __hostdev__ static constexpr uint8_t bitWidth() { return 16u; }
3998  __hostdev__ float getValue(uint32_t i) const
3999  {
4000  return mCode[i] * BaseT::mQuantum + BaseT::mMinimum; // code * (max-min)/65535 + min
4001  }
4002 
4003  /// @brief This class cannot be constructed or deleted
4004  LeafData() = delete;
4005  LeafData(const LeafData&) = delete;
4006  LeafData& operator=(const LeafData&) = delete;
4007  ~LeafData() = delete;
4008 }; // LeafData<Fp16>
4009 
4010 // --------------------------> LeafData<FpN> <------------------------------------
4011 
4012 template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
4013 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<FpN, CoordT, MaskT, LOG2DIM>
4014  : public LeafFnBase<CoordT, MaskT, LOG2DIM>
4015 { // this class has no additional data members, however every instance is immediately followed by
4016  // bitWidth*64 bytes. Since its base class is 32B aligned so are the bitWidth*64 bytes
4018  using BuildType = FpN;
4019  static constexpr bool FIXED_SIZE = false;
4020  __hostdev__ static constexpr uint32_t padding()
4021  {
4022  static_assert(BaseT::padding() == 0, "expected no padding in LeafFnBase");
4023  return 0;
4024  }
4025 
4026  __hostdev__ uint8_t bitWidth() const { return 1 << (BaseT::mFlags >> 5); } // 4,8,16,32 = 2^(2,3,4,5)
4027  __hostdev__ size_t memUsage() const { return sizeof(*this) + this->bitWidth() * 64; }
4028  __hostdev__ static size_t memUsage(uint32_t bitWidth) { return 96u + bitWidth * 64; }
4029  __hostdev__ float getValue(uint32_t i) const
4030  {
4031 #ifdef NANOVDB_FPN_BRANCHLESS // faster
4032  const int b = BaseT::mFlags >> 5; // b = 0, 1, 2, 3, 4 corresponding to 1, 2, 4, 8, 16 bits
4033 #if 0 // use LUT
4034  uint16_t code = reinterpret_cast<const uint16_t*>(this + 1)[i >> (4 - b)];
4035  const static uint8_t shift[5] = {15, 7, 3, 1, 0};
4036  const static uint16_t mask[5] = {1, 3, 15, 255, 65535};
4037  code >>= (i & shift[b]) << b;
4038  code &= mask[b];
4039 #else // no LUT
4040  uint32_t code = reinterpret_cast<const uint32_t*>(this + 1)[i >> (5 - b)];
4041  code >>= (i & ((32 >> b) - 1)) << b;
4042  code &= (1 << (1 << b)) - 1;
4043 #endif
4044 #else // use branched version (slow)
4045  float code;
4046  auto* values = reinterpret_cast<const uint8_t*>(this + 1);
4047  switch (BaseT::mFlags >> 5) {
4048  case 0u: // 1 bit float
4049  code = float((values[i >> 3] >> (i & 7)) & uint8_t(1));
4050  break;
4051  case 1u: // 2 bits float
4052  code = float((values[i >> 2] >> ((i & 3) << 1)) & uint8_t(3));
4053  break;
4054  case 2u: // 4 bits float
4055  code = float((values[i >> 1] >> ((i & 1) << 2)) & uint8_t(15));
4056  break;
4057  case 3u: // 8 bits float
4058  code = float(values[i]);
4059  break;
4060  default: // 16 bits float
4061  code = float(reinterpret_cast<const uint16_t*>(values)[i]);
4062  }
4063 #endif
4064  return float(code) * BaseT::mQuantum + BaseT::mMinimum; // code * (max-min)/UNITS + min
4065  }
4066 
4067  /// @brief This class cannot be constructed or deleted
4068  LeafData() = delete;
4069  LeafData(const LeafData&) = delete;
4070  LeafData& operator=(const LeafData&) = delete;
4071  ~LeafData() = delete;
4072 }; // LeafData<FpN>
4073 
4074 // --------------------------> LeafData<bool> <------------------------------------
4075 
4076 // Partial template specialization of LeafData with bool
4077 template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
4078 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<bool, CoordT, MaskT, LOG2DIM>
4079 {
4080  static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof");
4081  static_assert(sizeof(MaskT<LOG2DIM>) == sizeof(Mask<LOG2DIM>), "Mismatching sizeof");
4082  using ValueType = bool;
4083  using BuildType = bool;
4084  using FloatType = bool; // dummy value type
4085  using ArrayType = MaskT<LOG2DIM>; // type used for the internal mValue array
4086  static constexpr bool FIXED_SIZE = true;
4087 
4088  CoordT mBBoxMin; // 12B.
4089  uint8_t mBBoxDif[3]; // 3B.
4090  uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: has stats, bits5,6,7: bit-width for FpN
4091  MaskT<LOG2DIM> mValueMask; // LOG2DIM(3): 64B.
4092  MaskT<LOG2DIM> mValues; // LOG2DIM(3): 64B.
4093  uint64_t mPadding[2]; // 16B padding to 32B alignment
4094 
4095  __hostdev__ static constexpr uint32_t padding() { return sizeof(LeafData) - 12u - 3u - 1u - 2 * sizeof(MaskT<LOG2DIM>) - 16u; }
4096  __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); }
4097  __hostdev__ static bool hasStats() { return false; }
4098  __hostdev__ bool getValue(uint32_t i) const { return mValues.isOn(i); }
4099  __hostdev__ bool getMin() const { return false; } // dummy
4100  __hostdev__ bool getMax() const { return false; } // dummy
4101  __hostdev__ bool getAvg() const { return false; } // dummy
4102  __hostdev__ bool getDev() const { return false; } // dummy
4103  __hostdev__ void setValue(uint32_t offset, bool v)
4104  {
4105  mValueMask.setOn(offset);
4106  mValues.set(offset, v);
4107  }
4108  __hostdev__ void setOn(uint32_t offset) { mValueMask.setOn(offset); }
4109  __hostdev__ void setMin(const bool&) {} // no-op
4110  __hostdev__ void setMax(const bool&) {} // no-op
4111  __hostdev__ void setAvg(const bool&) {} // no-op
4112  __hostdev__ void setDev(const bool&) {} // no-op
4113 
4114  template<typename T>
4115  __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; }
4116 
4117  /// @brief This class cannot be constructed or deleted
4118  LeafData() = delete;
4119  LeafData(const LeafData&) = delete;
4120  LeafData& operator=(const LeafData&) = delete;
4121  ~LeafData() = delete;
4122 }; // LeafData<bool>
4123 
4124 // --------------------------> LeafData<ValueMask> <------------------------------------
4125 
4126 // Partial template specialization of LeafData with ValueMask
4127 template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
4128 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<ValueMask, CoordT, MaskT, LOG2DIM>
4129 {
4130  static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof");
4131  static_assert(sizeof(MaskT<LOG2DIM>) == sizeof(Mask<LOG2DIM>), "Mismatching sizeof");
4132  using ValueType = bool;
4134  using FloatType = bool; // dummy value type
4135  using ArrayType = void; // type used for the internal mValue array - void means missing
4136  static constexpr bool FIXED_SIZE = true;
4137 
4138  CoordT mBBoxMin; // 12B.
4139  uint8_t mBBoxDif[3]; // 3B.
4140  uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: has stats, bits5,6,7: bit-width for FpN
4141  MaskT<LOG2DIM> mValueMask; // LOG2DIM(3): 64B.
4142  uint64_t mPadding[2]; // 16B padding to 32B alignment
4143 
4144  __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); }
4145  __hostdev__ static bool hasStats() { return false; }
4146  __hostdev__ static constexpr uint32_t padding()
4147  {
4148  return sizeof(LeafData) - (12u + 3u + 1u + sizeof(MaskT<LOG2DIM>) + 2 * 8u);
4149  }
4150 
4151  __hostdev__ bool getValue(uint32_t i) const { return mValueMask.isOn(i); }
4152  __hostdev__ bool getMin() const { return false; } // dummy
4153  __hostdev__ bool getMax() const { return false; } // dummy
4154  __hostdev__ bool getAvg() const { return false; } // dummy
4155  __hostdev__ bool getDev() const { return false; } // dummy
4156  __hostdev__ void setValue(uint32_t offset, bool) { mValueMask.setOn(offset); }
4157  __hostdev__ void setOn(uint32_t offset) { mValueMask.setOn(offset); }
4158  __hostdev__ void setMin(const ValueType&) {} // no-op
4159  __hostdev__ void setMax(const ValueType&) {} // no-op
4160  __hostdev__ void setAvg(const FloatType&) {} // no-op
4161  __hostdev__ void setDev(const FloatType&) {} // no-op
4162 
4163  template<typename T>
4164  __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; }
4165 
4166  /// @brief This class cannot be constructed or deleted
4167  LeafData() = delete;
4168  LeafData(const LeafData&) = delete;
4169  LeafData& operator=(const LeafData&) = delete;
4170  ~LeafData() = delete;
4171 }; // LeafData<ValueMask>
4172 
4173 // --------------------------> LeafIndexBase <------------------------------------
4174 
4175 // Partial template specialization of LeafData with ValueIndex
4176 template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
4177 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafIndexBase
4178 {
4179  static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof");
4180  static_assert(sizeof(MaskT<LOG2DIM>) == sizeof(Mask<LOG2DIM>), "Mismatching sizeof");
4181  using ValueType = uint64_t;
4182  using FloatType = uint64_t;
4183  using ArrayType = void; // type used for the internal mValue array - void means missing
4184  static constexpr bool FIXED_SIZE = true;
4185 
4186  CoordT mBBoxMin; // 12B.
4187  uint8_t mBBoxDif[3]; // 3B.
4188  uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: has stats, bits5,6,7: bit-width for FpN
4189  MaskT<LOG2DIM> mValueMask; // LOG2DIM(3): 64B.
4190  uint64_t mOffset, mPrefixSum; // 8B offset to first value in this leaf node and 9-bit prefix sum
4191  __hostdev__ static constexpr uint32_t padding()
4192  {
4193  return sizeof(LeafIndexBase) - (12u + 3u + 1u + sizeof(MaskT<LOG2DIM>) + 2 * 8u);
4194  }
4195  __hostdev__ static uint64_t memUsage() { return sizeof(LeafIndexBase); }
4196  __hostdev__ bool hasStats() const { return mFlags & (uint8_t(1) << 4); }
4197  // return the offset to the first value indexed by this leaf node
4198  __hostdev__ const uint64_t& firstOffset() const { return mOffset; }
4199  __hostdev__ void setMin(const ValueType&) {} // no-op
4200  __hostdev__ void setMax(const ValueType&) {} // no-op
4201  __hostdev__ void setAvg(const FloatType&) {} // no-op
4202  __hostdev__ void setDev(const FloatType&) {} // no-op
4203  __hostdev__ void setOn(uint32_t offset) { mValueMask.setOn(offset); }
4204  template<typename T>
4205  __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; }
4206 
4207 protected:
4208  /// @brief This class should be used as an abstract class and only constructed or deleted via child classes
4209  LeafIndexBase() = default;
4210  LeafIndexBase(const LeafIndexBase&) = default;
4211  LeafIndexBase& operator=(const LeafIndexBase&) = default;
4212  ~LeafIndexBase() = default;
4213 }; // LeafIndexBase
4214 
4215 // --------------------------> LeafData<ValueIndex> <------------------------------------
4216 
4217 // Partial template specialization of LeafData with ValueIndex
4218 template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
4219 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<ValueIndex, CoordT, MaskT, LOG2DIM>
4220  : public LeafIndexBase<CoordT, MaskT, LOG2DIM>
4221 {
4224  // return the total number of values indexed by this leaf node, excluding the optional 4 stats
4225  __hostdev__ static uint32_t valueCount() { return uint32_t(512); } // 8^3 = 2^9
4226  // return the offset to the last value indexed by this leaf node (disregarding optional stats)
4227  __hostdev__ uint64_t lastOffset() const { return BaseT::mOffset + 511u; } // 2^9 - 1
4228  // if stats are available, they are always placed after the last voxel value in this leaf node
4229  __hostdev__ uint64_t getMin() const { return this->hasStats() ? BaseT::mOffset + 512u : 0u; }
4230  __hostdev__ uint64_t getMax() const { return this->hasStats() ? BaseT::mOffset + 513u : 0u; }
4231  __hostdev__ uint64_t getAvg() const { return this->hasStats() ? BaseT::mOffset + 514u : 0u; }
4232  __hostdev__ uint64_t getDev() const { return this->hasStats() ? BaseT::mOffset + 515u : 0u; }
4233  __hostdev__ uint64_t getValue(uint32_t i) const { return BaseT::mOffset + i; } // dense leaf node with active and inactive voxels
4234 }; // LeafData<ValueIndex>
4235 
4236 // --------------------------> LeafData<ValueOnIndex> <------------------------------------
4237 
4238 template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
4239 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<ValueOnIndex, CoordT, MaskT, LOG2DIM>
4240  : public LeafIndexBase<CoordT, MaskT, LOG2DIM>
4241 {
4244  __hostdev__ uint32_t valueCount() const
4245  {
4246  return util::countOn(BaseT::mValueMask.words()[7]) + (BaseT::mPrefixSum >> 54u & 511u); // last 9 bits of mPrefixSum do not account for the last word in mValueMask
4247  }
4248  __hostdev__ uint64_t lastOffset() const { return BaseT::mOffset + this->valueCount() - 1u; }
4249  __hostdev__ uint64_t getMin() const { return this->hasStats() ? this->lastOffset() + 1u : 0u; }
4250  __hostdev__ uint64_t getMax() const { return this->hasStats() ? this->lastOffset() + 2u : 0u; }
4251  __hostdev__ uint64_t getAvg() const { return this->hasStats() ? this->lastOffset() + 3u : 0u; }
4252  __hostdev__ uint64_t getDev() const { return this->hasStats() ? this->lastOffset() + 4u : 0u; }
4253  __hostdev__ uint64_t getValue(uint32_t i) const
4254  {
4255  //return mValueMask.isOn(i) ? mOffset + mValueMask.countOn(i) : 0u;// for debugging
4256  uint32_t n = i >> 6;
4257  const uint64_t w = BaseT::mValueMask.words()[n], mask = uint64_t(1) << (i & 63u);
4258  if (!(w & mask)) return uint64_t(0); // if i'th value is inactive return offset to background value
4259  uint64_t sum = BaseT::mOffset + util::countOn(w & (mask - 1u));
4260  if (n--) sum += BaseT::mPrefixSum >> (9u * n) & 511u;
4261  return sum;
4262  }
4263 }; // LeafData<ValueOnIndex>
4264 
4265 // --------------------------> LeafData<ValueIndexMask> <------------------------------------
4266 
4267 template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
4268 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<ValueIndexMask, CoordT, MaskT, LOG2DIM>
4269  : public LeafData<ValueIndex, CoordT, MaskT, LOG2DIM>
4270 {
4272  MaskT<LOG2DIM> mMask;
4273  __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); }
4274  __hostdev__ bool isMaskOn(uint32_t offset) const { return mMask.isOn(offset); }
4275  __hostdev__ void setMask(uint32_t offset, bool v) { mMask.set(offset, v); }
4276 }; // LeafData<ValueIndexMask>
4277 
4278 template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
4279 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<ValueOnIndexMask, CoordT, MaskT, LOG2DIM>
4280  : public LeafData<ValueOnIndex, CoordT, MaskT, LOG2DIM>
4281 {
4283  MaskT<LOG2DIM> mMask;
4284  __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); }
4285  __hostdev__ bool isMaskOn(uint32_t offset) const { return mMask.isOn(offset); }
4286  __hostdev__ void setMask(uint32_t offset, bool v) { mMask.set(offset, v); }
4287 }; // LeafData<ValueOnIndexMask>
4288 
4289 // --------------------------> LeafData<Point> <------------------------------------
4290 
4291 template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
4292 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<Point, CoordT, MaskT, LOG2DIM>
4293 {
4294  static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof");
4295  static_assert(sizeof(MaskT<LOG2DIM>) == sizeof(Mask<LOG2DIM>), "Mismatching sizeof");
4296  using ValueType = uint64_t;
4297  using BuildType = Point;
4299  using ArrayType = uint16_t; // type used for the internal mValue array
4300  static constexpr bool FIXED_SIZE = true;
4301 
4302  CoordT mBBoxMin; // 12B.
4303  uint8_t mBBoxDif[3]; // 3B.
4304  uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: has stats, bits5,6,7: bit-width for FpN
4305  MaskT<LOG2DIM> mValueMask; // LOG2DIM(3): 64B.
4306 
4307  uint64_t mOffset; // 8B
4308  uint64_t mPointCount; // 8B
4309  alignas(32) uint16_t mValues[1u << 3 * LOG2DIM]; // 1KB
4310  // no padding
4311 
4312  /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment
4313  ///
4314  /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members.
4315  __hostdev__ static constexpr uint32_t padding()
4316  {
4317  return sizeof(LeafData) - (12u + 3u + 1u + sizeof(MaskT<LOG2DIM>) + 2 * 8u + (1u << 3 * LOG2DIM) * 2u);
4318  }
4319  __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); }
4320 
4321  __hostdev__ uint64_t offset() const { return mOffset; }
4322  __hostdev__ uint64_t pointCount() const { return mPointCount; }
4323  __hostdev__ uint64_t first(uint32_t i) const { return i ? uint64_t(mValues[i - 1u]) + mOffset : mOffset; }
4324  __hostdev__ uint64_t last(uint32_t i) const { return uint64_t(mValues[i]) + mOffset; }
4325  __hostdev__ uint64_t getValue(uint32_t i) const { return uint64_t(mValues[i]); }
4326  __hostdev__ void setValueOnly(uint32_t offset, uint16_t value) { mValues[offset] = value; }
4327  __hostdev__ void setValue(uint32_t offset, uint16_t value)
4328  {
4329  mValueMask.setOn(offset);
4330  mValues[offset] = value;
4331  }
4332  __hostdev__ void setOn(uint32_t offset) { mValueMask.setOn(offset); }
4333 
4334  __hostdev__ ValueType getMin() const { return mOffset; }
4335  __hostdev__ ValueType getMax() const { return mPointCount; }
4336  __hostdev__ FloatType getAvg() const { return 0.0f; }
4337  __hostdev__ FloatType getDev() const { return 0.0f; }
4338 
4339  __hostdev__ void setMin(const ValueType&) {}
4340  __hostdev__ void setMax(const ValueType&) {}
4341  __hostdev__ void setAvg(const FloatType&) {}
4342  __hostdev__ void setDev(const FloatType&) {}
4343 
4344  template<typename T>
4345  __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; }
4346 
4347  /// @brief This class cannot be constructed or deleted
4348  LeafData() = delete;
4349  LeafData(const LeafData&) = delete;
4350  LeafData& operator=(const LeafData&) = delete;
4351  ~LeafData() = delete;
4352 }; // LeafData<Point>
4353 
4354 // --------------------------> LeafNode<T> <------------------------------------
4355 
4356 /// @brief Leaf nodes of the VDB tree. (defaults to 8x8x8 = 512 voxels)
4357 template<typename BuildT,
4358  typename CoordT = Coord,
4359  template<uint32_t> class MaskT = Mask,
4360  uint32_t Log2Dim = 3>
4361 class LeafNode : public LeafData<BuildT, CoordT, MaskT, Log2Dim>
4362 {
4363 public:
4365  {
4366  static constexpr uint32_t TOTAL = 0;
4367  static constexpr uint32_t DIM = 1;
4368  __hostdev__ static uint32_t dim() { return 1u; }
4369  }; // Voxel
4372  using ValueType = typename DataType::ValueType;
4373  using FloatType = typename DataType::FloatType;
4374  using BuildType = typename DataType::BuildType;
4375  using CoordType = CoordT;
4376  static constexpr bool FIXED_SIZE = DataType::FIXED_SIZE;
4377  template<uint32_t LOG2>
4378  using MaskType = MaskT<LOG2>;
4379  template<bool ON>
4380  using MaskIterT = typename Mask<Log2Dim>::template Iterator<ON>;
4381 
4382  /// @brief Visits all active values in a leaf node
4383  class ValueOnIterator : public MaskIterT<true>
4384  {
4385  using BaseT = MaskIterT<true>;
4386  const LeafNode* mParent;
4387 
4388  public:
4390  : BaseT()
4391  , mParent(nullptr)
4392  {
4393  }
4395  : BaseT(parent->data()->mValueMask.beginOn())
4396  , mParent(parent)
4397  {
4398  }
4399  ValueOnIterator& operator=(const ValueOnIterator&) = default;
4401  {
4402  NANOVDB_ASSERT(*this);
4403  return mParent->getValue(BaseT::pos());
4404  }
4405  __hostdev__ CoordT getCoord() const
4406  {
4407  NANOVDB_ASSERT(*this);
4408  return mParent->offsetToGlobalCoord(BaseT::pos());
4409  }
4410  }; // Member class ValueOnIterator
4411 
4412  __hostdev__ ValueOnIterator beginValueOn() const { return ValueOnIterator(this); }
4413  __hostdev__ ValueOnIterator cbeginValueOn() const { return ValueOnIterator(this); }
4414 
4415  /// @brief Visits all inactive values in a leaf node
4416  class ValueOffIterator : public MaskIterT<false>
4417  {
4418  using BaseT = MaskIterT<false>;
4419  const LeafNode* mParent;
4420 
4421  public:
4423  : BaseT()
4424  , mParent(nullptr)
4425  {
4426  }
4428  : BaseT(parent->data()->mValueMask.beginOff())
4429  , mParent(parent)
4430  {
4431  }
4432  ValueOffIterator& operator=(const ValueOffIterator&) = default;
4434  {
4435  NANOVDB_ASSERT(*this);
4436  return mParent->getValue(BaseT::pos());
4437  }
4438  __hostdev__ CoordT getCoord() const
4439  {
4440  NANOVDB_ASSERT(*this);
4441  return mParent->offsetToGlobalCoord(BaseT::pos());
4442  }
4443  }; // Member class ValueOffIterator
4444 
4445  __hostdev__ ValueOffIterator beginValueOff() const { return ValueOffIterator(this); }
4446  __hostdev__ ValueOffIterator cbeginValueOff() const { return ValueOffIterator(this); }
4447 
4448  /// @brief Visits all values in a leaf node, i.e. both active and inactive values
4450  {
4451  const LeafNode* mParent;
4452  uint32_t mPos;
4453 
4454  public:
4456  : mParent(nullptr)
4457  , mPos(1u << 3 * Log2Dim)
4458  {
4459  }
4461  : mParent(parent)
4462  , mPos(0)
4463  {
4464  NANOVDB_ASSERT(parent);
4465  }
4466  ValueIterator& operator=(const ValueIterator&) = default;
4468  {
4469  NANOVDB_ASSERT(*this);
4470  return mParent->getValue(mPos);
4471  }
4472  __hostdev__ CoordT getCoord() const
4473  {
4474  NANOVDB_ASSERT(*this);
4475  return mParent->offsetToGlobalCoord(mPos);
4476  }
4477  __hostdev__ bool isActive() const
4478  {
4479  NANOVDB_ASSERT(*this);
4480  return mParent->isActive(mPos);
4481  }
4482  __hostdev__ operator bool() const { return mPos < (1u << 3 * Log2Dim); }
4484  {
4485  ++mPos;
4486  return *this;
4487  }
4489  {
4490  auto tmp = *this;
4491  ++(*this);
4492  return tmp;
4493  }
4494  }; // Member class ValueIterator
4495 
4496  __hostdev__ ValueIterator beginValue() const { return ValueIterator(this); }
4497  __hostdev__ ValueIterator cbeginValueAll() const { return ValueIterator(this); }
4498 
4499  static_assert(util::is_same<ValueType, typename BuildToValueMap<BuildType>::Type>::value, "Mismatching BuildType");
4500  static constexpr uint32_t LOG2DIM = Log2Dim;
4501  static constexpr uint32_t TOTAL = LOG2DIM; // needed by parent nodes
4502  static constexpr uint32_t DIM = 1u << TOTAL; // number of voxels along each axis of this node
4503  static constexpr uint32_t SIZE = 1u << 3 * LOG2DIM; // total number of voxels represented by this node
4504  static constexpr uint32_t MASK = (1u << LOG2DIM) - 1u; // mask for bit operations
4505  static constexpr uint32_t LEVEL = 0; // level 0 = leaf
4506  static constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node
4507 
4508  __hostdev__ DataType* data() { return reinterpret_cast<DataType*>(this); }
4509 
4510  __hostdev__ const DataType* data() const { return reinterpret_cast<const DataType*>(this); }
4511 
4512  /// @brief Return a const reference to the bit mask of active voxels in this leaf node
4513  __hostdev__ const MaskType<LOG2DIM>& valueMask() const { return DataType::mValueMask; }
4514  __hostdev__ const MaskType<LOG2DIM>& getValueMask() const { return DataType::mValueMask; }
4515 
4516  /// @brief Return a const reference to the minimum active value encoded in this leaf node
4517  __hostdev__ ValueType minimum() const { return DataType::getMin(); }
4518 
4519  /// @brief Return a const reference to the maximum active value encoded in this leaf node
4520  __hostdev__ ValueType maximum() const { return DataType::getMax(); }
4521 
4522  /// @brief Return a const reference to the average of all the active values encoded in this leaf node
4523  __hostdev__ FloatType average() const { return DataType::getAvg(); }
4524 
4525  /// @brief Return the variance of all the active values encoded in this leaf node
4526  __hostdev__ FloatType variance() const { return Pow2(DataType::getDev()); }
4527 
4528  /// @brief Return a const reference to the standard deviation of all the active values encoded in this leaf node
4529  __hostdev__ FloatType stdDeviation() const { return DataType::getDev(); }
4530 
4531  __hostdev__ uint8_t flags() const { return DataType::mFlags; }
4532 
4533  /// @brief Return the origin in index space of this leaf node
4534  __hostdev__ CoordT origin() const { return DataType::mBBoxMin & ~MASK; }
4535 
4536  /// @brief Compute the local coordinates from a linear offset
4537  /// @param n Linear offset into this nodes dense table
4538  /// @return Local (vs global) 3D coordinates
4539  __hostdev__ static CoordT OffsetToLocalCoord(uint32_t n)
4540  {
4541  NANOVDB_ASSERT(n < SIZE);
4542  const uint32_t m = n & ((1 << 2 * LOG2DIM) - 1);
4543  return CoordT(n >> 2 * LOG2DIM, m >> LOG2DIM, m & MASK);
4544  }
4545 
4546  /// @brief Converts (in place) a local index coordinate to a global index coordinate
4547  __hostdev__ void localToGlobalCoord(Coord& ijk) const { ijk += this->origin(); }
4548 
4549  __hostdev__ CoordT offsetToGlobalCoord(uint32_t n) const
4550  {
4551  return OffsetToLocalCoord(n) + this->origin();
4552  }
4553 
4554  /// @brief Return the dimension, in index space, of this leaf node (typically 8 as for openvdb leaf nodes!)
4555  __hostdev__ static uint32_t dim() { return 1u << LOG2DIM; }
4556 
4557  /// @brief Return the bounding box in index space of active values in this leaf node
4558  __hostdev__ math::BBox<CoordT> bbox() const
4559  {
4560  math::BBox<CoordT> bbox(DataType::mBBoxMin, DataType::mBBoxMin);
4561  if (this->hasBBox()) {
4562  bbox.max()[0] += DataType::mBBoxDif[0];
4563  bbox.max()[1] += DataType::mBBoxDif[1];
4564  bbox.max()[2] += DataType::mBBoxDif[2];
4565  } else { // very rare case
4566  bbox = math::BBox<CoordT>(); // invalid
4567  }
4568  return bbox;
4569  }
4570 
4571  /// @brief Return the total number of voxels (e.g. values) encoded in this leaf node
4572  __hostdev__ static uint32_t voxelCount() { return 1u << (3 * LOG2DIM); }
4573 
4574  __hostdev__ static uint32_t padding() { return DataType::padding(); }
4575 
4576  /// @brief return memory usage in bytes for the leaf node
4577  __hostdev__ uint64_t memUsage() const { return DataType::memUsage(); }
4578 
4579  /// @brief This class cannot be constructed or deleted
4580  LeafNode() = delete;
4581  LeafNode(const LeafNode&) = delete;
4582  LeafNode& operator=(const LeafNode&) = delete;
4583  ~LeafNode() = delete;
4584 
4585  /// @brief Return the voxel value at the given offset.
4586  __hostdev__ ValueType getValue(uint32_t offset) const { return DataType::getValue(offset); }
4587 
4588  /// @brief Return the voxel value at the given coordinate.
4589  __hostdev__ ValueType getValue(const CoordT& ijk) const { return DataType::getValue(CoordToOffset(ijk)); }
4590 
4591  /// @brief Return the first value in this leaf node.
4592  __hostdev__ ValueType getFirstValue() const { return this->getValue(0); }
4593  /// @brief Return the last value in this leaf node.
4594  __hostdev__ ValueType getLastValue() const { return this->getValue(SIZE - 1); }
4595 
4596  /// @brief Sets the value at the specified location and activate its state.
4597  ///
4598  /// @note This is safe since it does not change the topology of the tree (unlike setValue methods on the other nodes)
4599  __hostdev__ void setValue(const CoordT& ijk, const ValueType& v) { DataType::setValue(CoordToOffset(ijk), v); }
4600 
4601  /// @brief Sets the value at the specified location but leaves its state unchanged.
4602  ///
4603  /// @note This is safe since it does not change the topology of the tree (unlike setValue methods on the other nodes)
4604  __hostdev__ void setValueOnly(uint32_t offset, const ValueType& v) { DataType::setValueOnly(offset, v); }
4605  __hostdev__ void setValueOnly(const CoordT& ijk, const ValueType& v) { DataType::setValueOnly(CoordToOffset(ijk), v); }
4606 
4607  /// @brief Return @c true if the voxel value at the given coordinate is active.
4608  __hostdev__ bool isActive(const CoordT& ijk) const { return DataType::mValueMask.isOn(CoordToOffset(ijk)); }
4609  __hostdev__ bool isActive(uint32_t n) const { return DataType::mValueMask.isOn(n); }
4610 
4611  /// @brief Return @c true if any of the voxel value are active in this leaf node.
4612  __hostdev__ bool isActive() const
4613  {
4614  //NANOVDB_ASSERT( bool(DataType::mFlags & uint8_t(2)) != DataType::mValueMask.isOff() );
4615  //return DataType::mFlags & uint8_t(2);
4616  return !DataType::mValueMask.isOff();
4617  }
4618 
4619  __hostdev__ bool hasBBox() const { return DataType::mFlags & uint8_t(2); }
4620 
4621  /// @brief Return @c true if the voxel value at the given coordinate is active and updates @c v with the value.
4622  __hostdev__ bool probeValue(const CoordT& ijk, ValueType& v) const
4623  {
4624  const uint32_t n = CoordToOffset(ijk);
4625  v = DataType::getValue(n);
4626  return DataType::mValueMask.isOn(n);
4627  }
4628 
4629  __hostdev__ const LeafNode* probeLeaf(const CoordT&) const { return this; }
4630 
4631  /// @brief Return the linear offset corresponding to the given coordinate
4632  __hostdev__ static uint32_t CoordToOffset(const CoordT& ijk)
4633  {
4634  return ((ijk[0] & MASK) << (2 * LOG2DIM)) | ((ijk[1] & MASK) << LOG2DIM) | (ijk[2] & MASK);
4635  }
4636 
4637  /// @brief Updates the local bounding box of active voxels in this node. Return true if bbox was updated.
4638  ///
4639  /// @warning It assumes that the origin and value mask have already been set.
4640  ///
4641  /// @details This method is based on few (intrinsic) bit operations and hence is relatively fast.
4642  /// However, it should only only be called if either the value mask has changed or if the
4643  /// active bounding box is still undefined. e.g. during construction of this node.
4644  __hostdev__ bool updateBBox();
4645 
4646  template<typename OpT, typename... ArgsT>
4647  __hostdev__ auto get(const CoordType& ijk, ArgsT&&... args) const
4648  {
4649  return OpT::get(*this, CoordToOffset(ijk), args...);
4650  }
4651 
4652  template<typename OpT, typename... ArgsT>
4653  __hostdev__ auto get(const uint32_t n, ArgsT&&... args) const
4654  {
4655  return OpT::get(*this, n, args...);
4656  }
4657 
4658  template<typename OpT, typename... ArgsT>
4659  __hostdev__ auto set(const CoordType& ijk, ArgsT&&... args)
4660  {
4661  return OpT::set(*this, CoordToOffset(ijk), args...);
4662  }
4663 
4664  template<typename OpT, typename... ArgsT>
4665  __hostdev__ auto set(const uint32_t n, ArgsT&&... args)
4666  {
4667  return OpT::set(*this, n, args...);
4668  }
4669 
4670 private:
4671  static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(LeafData) is misaligned");
4672 
4673  template<typename, int, int, int>
4674  friend class ReadAccessor;
4675 
4676  template<typename>
4677  friend class RootNode;
4678  template<typename, uint32_t>
4679  friend class InternalNode;
4680 
4681 #ifndef NANOVDB_NEW_ACCESSOR_METHODS
4682  /// @brief Private method to return a voxel value and update a (dummy) ReadAccessor
4683  template<typename AccT>
4684  __hostdev__ ValueType getValueAndCache(const CoordT& ijk, const AccT&) const { return this->getValue(ijk); }
4685 
4686  /// @brief Return the node information.
4687  template<typename AccT>
4688  __hostdev__ typename AccT::NodeInfo getNodeInfoAndCache(const CoordType& /*ijk*/, const AccT& /*acc*/) const
4689  {
4690  using NodeInfoT = typename AccT::NodeInfo;
4691  return NodeInfoT{LEVEL, this->dim(), this->minimum(), this->maximum(), this->average(), this->stdDeviation(), this->bbox()[0], this->bbox()[1]};
4692  }
4693 
4694  template<typename AccT>
4695  __hostdev__ bool isActiveAndCache(const CoordT& ijk, const AccT&) const { return this->isActive(ijk); }
4696 
4697  template<typename AccT>
4698  __hostdev__ bool probeValueAndCache(const CoordT& ijk, ValueType& v, const AccT&) const { return this->probeValue(ijk, v); }
4699 
4700  template<typename AccT>
4701  __hostdev__ const LeafNode* probeLeafAndCache(const CoordT&, const AccT&) const { return this; }
4702 #endif
4703 
4704  template<typename RayT, typename AccT>
4705  __hostdev__ uint32_t getDimAndCache(const CoordT&, const RayT& /*ray*/, const AccT&) const
4706  {
4707  if (DataType::mFlags & uint8_t(1u))
4708  return this->dim(); // skip this node if the 1st bit is set
4709 
4710  //if (!ray.intersects( this->bbox() )) return 1 << LOG2DIM;
4711  return ChildNodeType::dim();
4712  }
4713 
4714  template<typename OpT, typename AccT, typename... ArgsT>
4715  __hostdev__ auto
4716  //__hostdev__ decltype(OpT::get(util::declval<const LeafNode&>(), util::declval<uint32_t>(), util::declval<ArgsT>()...))
4717  getAndCache(const CoordType& ijk, const AccT&, ArgsT&&... args) const
4718  {
4719  return OpT::get(*this, CoordToOffset(ijk), args...);
4720  }
4721 
4722  template<typename OpT, typename AccT, typename... ArgsT>
4723  //__hostdev__ auto // occasionally fails with NVCC
4724  __hostdev__ decltype(OpT::set(util::declval<LeafNode&>(), util::declval<uint32_t>(), util::declval<ArgsT>()...))
4725  setAndCache(const CoordType& ijk, const AccT&, ArgsT&&... args)
4726  {
4727  return OpT::set(*this, CoordToOffset(ijk), args...);
4728  }
4729 
4730 }; // LeafNode class
4731 
4732 // --------------------------> LeafNode<T>::updateBBox <------------------------------------
4733 
4734 template<typename ValueT, typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
4736 {
4737  static_assert(LOG2DIM == 3, "LeafNode::updateBBox: only supports LOGDIM = 3!");
4738  if (DataType::mValueMask.isOff()) {
4739  DataType::mFlags &= ~uint8_t(2); // set 2nd bit off, which indicates that this nodes has no bbox
4740  return false;
4741  }
4742  auto update = [&](uint32_t min, uint32_t max, int axis) {
4743  NANOVDB_ASSERT(min <= max && max < 8);
4744  DataType::mBBoxMin[axis] = (DataType::mBBoxMin[axis] & ~MASK) + int(min);
4745  DataType::mBBoxDif[axis] = uint8_t(max - min);
4746  };
4747  uint64_t *w = DataType::mValueMask.words(), word64 = *w;
4748  uint32_t Xmin = word64 ? 0u : 8u, Xmax = Xmin;
4749  for (int i = 1; i < 8; ++i) { // last loop over 8 64 bit words
4750  if (w[i]) { // skip if word has no set bits
4751  word64 |= w[i]; // union 8 x 64 bits words into one 64 bit word
4752  if (Xmin == 8)
4753  Xmin = i; // only set once
4754  Xmax = i;
4755  }
4756  }
4757  NANOVDB_ASSERT(word64);
4758  update(Xmin, Xmax, 0);
4759  update(util::findLowestOn(word64) >> 3, util::findHighestOn(word64) >> 3, 1);
4760  const uint32_t *p = reinterpret_cast<const uint32_t*>(&word64), word32 = p[0] | p[1];
4761  const uint16_t *q = reinterpret_cast<const uint16_t*>(&word32), word16 = q[0] | q[1];
4762  const uint8_t *b = reinterpret_cast<const uint8_t*>(&word16), byte = b[0] | b[1];
4763  NANOVDB_ASSERT(byte);
4764  update(util::findLowestOn(static_cast<uint32_t>(byte)), util::findHighestOn(static_cast<uint32_t>(byte)), 2);
4765  DataType::mFlags |= uint8_t(2); // set 2nd bit on, which indicates that this nodes has a bbox
4766  return true;
4767 } // LeafNode::updateBBox
4768 
4769 // --------------------------> Template specializations and traits <------------------------------------
4770 
4771 /// @brief Template specializations to the default configuration used in OpenVDB:
4772 /// Root -> 32^3 -> 16^3 -> 8^3
4773 template<typename BuildT>
4775 template<typename BuildT>
4777 template<typename BuildT>
4779 template<typename BuildT>
4781 template<typename BuildT>
4783 template<typename BuildT>
4785 
4786 /// @brief Trait to map from LEVEL to node type
4787 template<typename BuildT, int LEVEL>
4788 struct NanoNode;
4789 
4790 // Partial template specialization of above Node struct
4791 template<typename BuildT>
4792 struct NanoNode<BuildT, 0>
4793 {
4796 };
4797 template<typename BuildT>
4798 struct NanoNode<BuildT, 1>
4799 {
4802 };
4803 template<typename BuildT>
4804 struct NanoNode<BuildT, 2>
4805 {
4808 };
4809 template<typename BuildT>
4810 struct NanoNode<BuildT, 3>
4811 {
4814 };
4815 
4836 
4858 
4859 // --------------------------> callNanoGrid <------------------------------------
4860 
4861 /**
4862 * @brief Below is an example of the struct used for generic programming with callNanoGrid
4863 * @details For an example see "struct Crc32TailOld" in nanovdb/tools/GridChecksum.h or
4864 * "struct IsNanoGridValid" in nanovdb/tools/GridValidator.h
4865 * @code
4866 * struct OpT {
4867  // define these two static functions with non-const GridData
4868 * template <typename BuildT>
4869 * static auto known( GridData *gridData, args...);
4870 * static auto unknown( GridData *gridData, args...);
4871 * // or alternatively these two static functions with const GridData
4872 * template <typename BuildT>
4873 * static auto known(const GridData *gridData, args...);
4874 * static auto unknown(const GridData *gridData, args...);
4875 * };
4876 * @endcode
4877 *
4878 * @brief Here is an example of how to use callNanoGrid in client code
4879 * @code
4880 * return callNanoGrid<OpT>(gridData, args...);
4881 * @endcode
4882 */
4883 
4884 /// @brief Use this function, which depends a pointer to GridData, to call
4885 /// other functions that depend on a NanoGrid of a known ValueType.
4886 /// @details This function allows for generic programming by converting GridData
4887 /// to a NanoGrid of the type encoded in GridData::mGridType.
4888 template<typename OpT, typename GridDataT, typename... ArgsT>
4889 auto callNanoGrid(GridDataT *gridData, ArgsT&&... args)
4890 {
4891  static_assert(util::is_same<GridDataT, GridData, const GridData>::value, "Expected gridData to be of type GridData* or const GridData*");
4892  switch (gridData->mGridType){
4893  case GridType::Float:
4894  return OpT::template known<float>(gridData, args...);
4895  case GridType::Double:
4896  return OpT::template known<double>(gridData, args...);
4897  case GridType::Int16:
4898  return OpT::template known<int16_t>(gridData, args...);
4899  case GridType::Int32:
4900  return OpT::template known<int32_t>(gridData, args...);
4901  case GridType::Int64:
4902  return OpT::template known<int64_t>(gridData, args...);
4903  case GridType::Vec3f:
4904  return OpT::template known<Vec3f>(gridData, args...);
4905  case GridType::Vec3d:
4906  return OpT::template known<Vec3d>(gridData, args...);
4907  case GridType::UInt32:
4908  return OpT::template known<uint32_t>(gridData, args...);
4909  case GridType::Mask:
4910  return OpT::template known<ValueMask>(gridData, args...);
4911  case GridType::Index:
4912  return OpT::template known<ValueIndex>(gridData, args...);
4913  case GridType::OnIndex:
4914  return OpT::template known<ValueOnIndex>(gridData, args...);
4915  case GridType::IndexMask:
4916  return OpT::template known<ValueIndexMask>(gridData, args...);
4917  case GridType::OnIndexMask:
4918  return OpT::template known<ValueOnIndexMask>(gridData, args...);
4919  case GridType::Boolean:
4920  return OpT::template known<bool>(gridData, args...);
4921  case GridType::RGBA8:
4922  return OpT::template known<math::Rgba8>(gridData, args...);
4923  case GridType::Fp4:
4924  return OpT::template known<Fp4>(gridData, args...);
4925  case GridType::Fp8:
4926  return OpT::template known<Fp8>(gridData, args...);
4927  case GridType::Fp16:
4928  return OpT::template known<Fp16>(gridData, args...);
4929  case GridType::FpN:
4930  return OpT::template known<FpN>(gridData, args...);
4931  case GridType::Vec4f:
4932  return OpT::template known<Vec4f>(gridData, args...);
4933  case GridType::Vec4d:
4934  return OpT::template known<Vec4d>(gridData, args...);
4935  case GridType::UInt8:
4936  return OpT::template known<uint8_t>(gridData, args...);
4937  default:
4938  return OpT::unknown(gridData, args...);
4939  }
4940 }// callNanoGrid
4941 
4942 // --------------------------> ReadAccessor <------------------------------------
4943 
4944 /// @brief A read-only value accessor with three levels of node caching. This allows for
4945 /// inverse tree traversal during lookup, which is on average significantly faster
4946 /// than calling the equivalent method on the tree (i.e. top-down traversal).
4947 ///
4948 /// @note By virtue of the fact that a value accessor accelerates random access operations
4949 /// by re-using cached access patterns, this access should be reused for multiple access
4950 /// operations. In other words, never create an instance of this accessor for a single
4951 /// access only. In general avoid single access operations with this accessor, and
4952 /// if that is not possible call the corresponding method on the tree instead.
4953 ///
4954 /// @warning Since this ReadAccessor internally caches raw pointers to the nodes of the tree
4955 /// structure, it is not safe to copy between host and device, or even to share among
4956 /// multiple threads on the same host or device. However, it is light-weight so simple
4957 /// instantiate one per thread (on the host and/or device).
4958 ///
4959 /// @details Used to accelerated random access into a VDB tree. Provides on average
4960 /// O(1) random access operations by means of inverse tree traversal,
4961 /// which amortizes the non-const time complexity of the root node.
4962 
4963 template<typename BuildT>
4964 class ReadAccessor<BuildT, -1, -1, -1>
4965 {
4966  using GridT = NanoGrid<BuildT>; // grid
4967  using TreeT = NanoTree<BuildT>; // tree
4968  using RootT = NanoRoot<BuildT>; // root node
4969  using LeafT = NanoLeaf<BuildT>; // Leaf node
4970  using FloatType = typename RootT::FloatType;
4971  using CoordValueType = typename RootT::CoordType::ValueType;
4972 
4973  mutable const RootT* mRoot; // 8 bytes (mutable to allow for access methods to be const)
4974 public:
4975  using BuildType = BuildT;
4976  using ValueType = typename RootT::ValueType;
4977  using CoordType = typename RootT::CoordType;
4978 
4979  static const int CacheLevels = 0;
4980 #ifndef NANOVDB_NEW_ACCESSOR_METHODS
4981  struct NodeInfo
4982  {
4983  uint32_t mLevel; // 4B
4984  uint32_t mDim; // 4B
4985  ValueType mMinimum; // typically 4B
4986  ValueType mMaximum; // typically 4B
4987  FloatType mAverage; // typically 4B
4988  FloatType mStdDevi; // typically 4B
4989  CoordType mBBoxMin; // 3*4B
4990  CoordType mBBoxMax; // 3*4B
4991  };
4992 #endif
4993  /// @brief Constructor from a root node
4995  : mRoot{&root}
4996  {
4997  }
4998 
4999  /// @brief Constructor from a grid
5000  __hostdev__ ReadAccessor(const GridT& grid)
5001  : ReadAccessor(grid.tree().root())
5002  {
5003  }
5004 
5005  /// @brief Constructor from a tree
5007  : ReadAccessor(tree.root())
5008  {
5009  }
5010 
5011  /// @brief Reset this access to its initial state, i.e. with an empty cache
5012  /// @node Noop since this template specialization has no cache
5013  __hostdev__ void clear() {}
5014 
5015  __hostdev__ const RootT& root() const { return *mRoot; }
5016 
5017  /// @brief Defaults constructors
5018  ReadAccessor(const ReadAccessor&) = default;
5019  ~ReadAccessor() = default;
5020  ReadAccessor& operator=(const ReadAccessor&) = default;
5021 #ifdef NANOVDB_NEW_ACCESSOR_METHODS
5023  {
5024  return this->template get<GetValue<BuildT>>(ijk);
5025  }
5026  __hostdev__ ValueType getValue(int i, int j, int k) const { return this->template get<GetValue<BuildT>>(CoordType(i, j, k)); }
5027  __hostdev__ ValueType operator()(const CoordType& ijk) const { return this->template get<GetValue<BuildT>>(ijk); }
5028  __hostdev__ ValueType operator()(int i, int j, int k) const { return this->template get<GetValue<BuildT>>(CoordType(i, j, k)); }
5029  __hostdev__ auto getNodeInfo(const CoordType& ijk) const { return this->template get<GetNodeInfo<BuildT>>(ijk); }
5030  __hostdev__ bool isActive(const CoordType& ijk) const { return this->template get<GetState<BuildT>>(ijk); }
5031  __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->template get<ProbeValue<BuildT>>(ijk, v); }
5032  __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const { return this->template get<GetLeaf<BuildT>>(ijk); }
5033 #else // NANOVDB_NEW_ACCESSOR_METHODS
5034  __hostdev__ ValueType getValue(const CoordType& ijk) const
5035  {
5036  return mRoot->getValueAndCache(ijk, *this);
5037  }
5038  __hostdev__ ValueType getValue(int i, int j, int k) const
5039  {
5040  return this->getValue(CoordType(i, j, k));
5041  }
5042  __hostdev__ ValueType operator()(const CoordType& ijk) const
5043  {
5044  return this->getValue(ijk);
5045  }
5046  __hostdev__ ValueType operator()(int i, int j, int k) const
5047  {
5048  return this->getValue(CoordType(i, j, k));
5049  }
5050 
5051  __hostdev__ NodeInfo getNodeInfo(const CoordType& ijk) const
5052  {
5053  return mRoot->getNodeInfoAndCache(ijk, *this);
5054  }
5055 
5056  __hostdev__ bool isActive(const CoordType& ijk) const
5057  {
5058  return mRoot->isActiveAndCache(ijk, *this);
5059  }
5060 
5061  __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const
5062  {
5063  return mRoot->probeValueAndCache(ijk, v, *this);
5064  }
5065 
5066  __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const
5067  {
5068  return mRoot->probeLeafAndCache(ijk, *this);
5069  }
5070 #endif // NANOVDB_NEW_ACCESSOR_METHODS
5071  template<typename RayT>
5072  __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const
5073  {
5074  return mRoot->getDimAndCache(ijk, ray, *this);
5075  }
5076  template<typename OpT, typename... ArgsT>
5077  __hostdev__ auto get(const CoordType& ijk, ArgsT&&... args) const
5078  {
5079  return mRoot->template get<OpT>(ijk, args...);
5080  }
5081 
5082  template<typename OpT, typename... ArgsT>
5083  __hostdev__ auto set(const CoordType& ijk, ArgsT&&... args) const
5084  {
5085  return const_cast<RootT*>(mRoot)->template set<OpT>(ijk, args...);
5086  }
5087 
5088 private:
5089  /// @brief Allow nodes to insert themselves into the cache.
5090  template<typename>
5091  friend class RootNode;
5092  template<typename, uint32_t>
5093  friend class InternalNode;
5094  template<typename, typename, template<uint32_t> class, uint32_t>
5095  friend class LeafNode;
5096 
5097  /// @brief No-op
5098  template<typename NodeT>
5099  __hostdev__ void insert(const CoordType&, const NodeT*) const {}
5100 }; // ReadAccessor<ValueT, -1, -1, -1> class
5101 
5102 /// @brief Node caching at a single tree level
5103 template<typename BuildT, int LEVEL0>
5104 class ReadAccessor<BuildT, LEVEL0, -1, -1> //e.g. 0, 1, 2
5105 {
5106  static_assert(LEVEL0 >= 0 && LEVEL0 <= 2, "LEVEL0 should be 0, 1, or 2");
5107 
5108  using GridT = NanoGrid<BuildT>; // grid
5109  using TreeT = NanoTree<BuildT>;
5110  using RootT = NanoRoot<BuildT>; // root node
5111  using LeafT = NanoLeaf<BuildT>; // Leaf node
5112  using NodeT = typename NodeTrait<TreeT, LEVEL0>::type;
5113  using CoordT = typename RootT::CoordType;
5114  using ValueT = typename RootT::ValueType;
5115 
5116  using FloatType = typename RootT::FloatType;
5117  using CoordValueType = typename RootT::CoordT::ValueType;
5118 
5119  // All member data are mutable to allow for access methods to be const
5120  mutable CoordT mKey; // 3*4 = 12 bytes
5121  mutable const RootT* mRoot; // 8 bytes
5122  mutable const NodeT* mNode; // 8 bytes
5123 
5124 public:
5125  using BuildType = BuildT;
5126  using ValueType = ValueT;
5127  using CoordType = CoordT;
5128 
5129  static const int CacheLevels = 1;
5130 #ifndef NANOVDB_NEW_ACCESSOR_METHODS
5131  using NodeInfo = typename ReadAccessor<ValueT, -1, -1, -1>::NodeInfo;
5132 #endif
5133  /// @brief Constructor from a root node
5135  : mKey(CoordType::max())
5136  , mRoot(&root)
5137  , mNode(nullptr)
5138  {
5139  }
5140 
5141  /// @brief Constructor from a grid
5143  : ReadAccessor(grid.tree().root())
5144  {
5145  }
5146 
5147  /// @brief Constructor from a tree
5149  : ReadAccessor(tree.root())
5150  {
5151  }
5152 
5153  /// @brief Reset this access to its initial state, i.e. with an empty cache
5155  {
5156  mKey = CoordType::max();
5157  mNode = nullptr;
5158  }
5159 
5160  __hostdev__ const RootT& root() const { return *mRoot; }
5161 
5162  /// @brief Defaults constructors
5163  ReadAccessor(const ReadAccessor&) = default;
5164  ~ReadAccessor() = default;
5165  ReadAccessor& operator=(const ReadAccessor&) = default;
5166 
5167  __hostdev__ bool isCached(const CoordType& ijk) const
5168  {
5169  return (ijk[0] & int32_t(~NodeT::MASK)) == mKey[0] &&
5170  (ijk[1] & int32_t(~NodeT::MASK)) == mKey[1] &&
5171  (ijk[2] & int32_t(~NodeT::MASK)) == mKey[2];
5172  }
5173 
5174 #ifdef NANOVDB_NEW_ACCESSOR_METHODS
5176  {
5177  return this->template get<GetValue<BuildT>>(ijk);
5178  }
5179  __hostdev__ ValueType getValue(int i, int j, int k) const { return this->template get<GetValue<BuildT>>(CoordType(i, j, k)); }
5180  __hostdev__ ValueType operator()(const CoordType& ijk) const { return this->template get<GetValue<BuildT>>(ijk); }
5181  __hostdev__ ValueType operator()(int i, int j, int k) const { return this->template get<GetValue<BuildT>>(CoordType(i, j, k)); }
5182  __hostdev__ auto getNodeInfo(const CoordType& ijk) const { return this->template get<GetNodeInfo<BuildT>>(ijk); }
5183  __hostdev__ bool isActive(const CoordType& ijk) const { return this->template get<GetState<BuildT>>(ijk); }
5184  __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->template get<ProbeValue<BuildT>>(ijk, v); }
5185  __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const { return this->template get<GetLeaf<BuildT>>(ijk); }
5186 #else // NANOVDB_NEW_ACCESSOR_METHODS
5187  __hostdev__ ValueType getValue(const CoordType& ijk) const
5188  {
5189  if (this->isCached(ijk))
5190  return mNode->getValueAndCache(ijk, *this);
5191  return mRoot->getValueAndCache(ijk, *this);
5192  }
5193  __hostdev__ ValueType getValue(int i, int j, int k) const
5194  {
5195  return this->getValue(CoordType(i, j, k));
5196  }
5197  __hostdev__ ValueType operator()(const CoordType& ijk) const
5198  {
5199  return this->getValue(ijk);
5200  }
5201  __hostdev__ ValueType operator()(int i, int j, int k) const
5202  {
5203  return this->getValue(CoordType(i, j, k));
5204  }
5205 
5206  __hostdev__ NodeInfo getNodeInfo(const CoordType& ijk) const
5207  {
5208  if (this->isCached(ijk))
5209  return mNode->getNodeInfoAndCache(ijk, *this);
5210  return mRoot->getNodeInfoAndCache(ijk, *this);
5211  }
5212 
5213  __hostdev__ bool isActive(const CoordType& ijk) const
5214  {
5215  if (this->isCached(ijk))
5216  return mNode->isActiveAndCache(ijk, *this);
5217  return mRoot->isActiveAndCache(ijk, *this);
5218  }
5219 
5220  __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const
5221  {
5222  if (this->isCached(ijk))
5223  return mNode->probeValueAndCache(ijk, v, *this);
5224  return mRoot->probeValueAndCache(ijk, v, *this);
5225  }
5226 
5227  __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const
5228  {
5229  if (this->isCached(ijk))
5230  return mNode->probeLeafAndCache(ijk, *this);
5231  return mRoot->probeLeafAndCache(ijk, *this);
5232  }
5233 #endif // NANOVDB_NEW_ACCESSOR_METHODS
5234  template<typename RayT>
5235  __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const
5236  {
5237  if (this->isCached(ijk))
5238  return mNode->getDimAndCache(ijk, ray, *this);
5239  return mRoot->getDimAndCache(ijk, ray, *this);
5240  }
5241 
5242  template<typename OpT, typename... ArgsT>
5243  __hostdev__ auto get(const CoordType& ijk, ArgsT&&... args) const
5244  {
5245  if (this->isCached(ijk))
5246  return mNode->template getAndCache<OpT>(ijk, *this, args...);
5247  return mRoot->template getAndCache<OpT>(ijk, *this, args...);
5248  }
5249 
5250  template<typename OpT, typename... ArgsT>
5251  __hostdev__ auto set(const CoordType& ijk, ArgsT&&... args) const
5252  {
5253  if (this->isCached(ijk))
5254  return const_cast<NodeT*>(mNode)->template setAndCache<OpT>(ijk, *this, args...);
5255  return const_cast<RootT*>(mRoot)->template setAndCache<OpT>(ijk, *this, args...);
5256  }
5257 
5258 private:
5259  /// @brief Allow nodes to insert themselves into the cache.
5260  template<typename>
5261  friend class RootNode;
5262  template<typename, uint32_t>
5263  friend class InternalNode;
5264  template<typename, typename, template<uint32_t> class, uint32_t>
5265  friend class LeafNode;
5266 
5267  /// @brief Inserts a leaf node and key pair into this ReadAccessor
5268  __hostdev__ void insert(const CoordType& ijk, const NodeT* node) const
5269  {
5270  mKey = ijk & ~NodeT::MASK;
5271  mNode = node;
5272  }
5273 
5274  // no-op
5275  template<typename OtherNodeT>
5276  __hostdev__ void insert(const CoordType&, const OtherNodeT*) const {}
5277 
5278 }; // ReadAccessor<ValueT, LEVEL0>
5279 
5280 template<typename BuildT, int LEVEL0, int LEVEL1>
5281 class ReadAccessor<BuildT, LEVEL0, LEVEL1, -1> //e.g. (0,1), (1,2), (0,2)
5282 {
5283  static_assert(LEVEL0 >= 0 && LEVEL0 <= 2, "LEVEL0 must be 0, 1, 2");
5284  static_assert(LEVEL1 >= 0 && LEVEL1 <= 2, "LEVEL1 must be 0, 1, 2");
5285  static_assert(LEVEL0 < LEVEL1, "Level 0 must be lower than level 1");
5286  using GridT = NanoGrid<BuildT>; // grid
5287  using TreeT = NanoTree<BuildT>;
5288  using RootT = NanoRoot<BuildT>;
5289  using LeafT = NanoLeaf<BuildT>;
5290  using Node1T = typename NodeTrait<TreeT, LEVEL0>::type;
5291  using Node2T = typename NodeTrait<TreeT, LEVEL1>::type;
5292  using CoordT = typename RootT::CoordType;
5293  using ValueT = typename RootT::ValueType;
5294  using FloatType = typename RootT::FloatType;
5295  using CoordValueType = typename RootT::CoordT::ValueType;
5296 
5297  // All member data are mutable to allow for access methods to be const
5298 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY // 44 bytes total
5299  mutable CoordT mKey; // 3*4 = 12 bytes
5300 #else // 68 bytes total
5301  mutable CoordT mKeys[2]; // 2*3*4 = 24 bytes
5302 #endif
5303  mutable const RootT* mRoot;
5304  mutable const Node1T* mNode1;
5305  mutable const Node2T* mNode2;
5306 
5307 public:
5308  using BuildType = BuildT;
5309  using ValueType = ValueT;
5310  using CoordType = CoordT;
5311 
5312  static const int CacheLevels = 2;
5313 #ifndef NANOVDB_NEW_ACCESSOR_METHODS
5314  using NodeInfo = typename ReadAccessor<ValueT, -1, -1, -1>::NodeInfo;
5315 #endif
5316  /// @brief Constructor from a root node
5318 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5319  : mKey(CoordType::max())
5320 #else
5321  : mKeys{CoordType::max(), CoordType::max()}
5322 #endif
5323  , mRoot(&root)
5324  , mNode1(nullptr)
5325  , mNode2(nullptr)
5326  {
5327  }
5328 
5329  /// @brief Constructor from a grid
5331  : ReadAccessor(grid.tree().root())
5332  {
5333  }
5334 
5335  /// @brief Constructor from a tree
5337  : ReadAccessor(tree.root())
5338  {
5339  }
5340 
5341  /// @brief Reset this access to its initial state, i.e. with an empty cache
5343  {
5344 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5345  mKey = CoordType::max();
5346 #else
5347  mKeys[0] = mKeys[1] = CoordType::max();
5348 #endif
5349  mNode1 = nullptr;
5350  mNode2 = nullptr;
5351  }
5352 
5353  __hostdev__ const RootT& root() const { return *mRoot; }
5354 
5355  /// @brief Defaults constructors
5356  ReadAccessor(const ReadAccessor&) = default;
5357  ~ReadAccessor() = default;
5358  ReadAccessor& operator=(const ReadAccessor&) = default;
5359 
5360 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5361  __hostdev__ bool isCached1(CoordValueType dirty) const
5362  {
5363  if (!mNode1)
5364  return false;
5365  if (dirty & int32_t(~Node1T::MASK)) {
5366  mNode1 = nullptr;
5367  return false;
5368  }
5369  return true;
5370  }
5371  __hostdev__ bool isCached2(CoordValueType dirty) const
5372  {
5373  if (!mNode2)
5374  return false;
5375  if (dirty & int32_t(~Node2T::MASK)) {
5376  mNode2 = nullptr;
5377  return false;
5378  }
5379  return true;
5380  }
5381  __hostdev__ CoordValueType computeDirty(const CoordType& ijk) const
5382  {
5383  return (ijk[0] ^ mKey[0]) | (ijk[1] ^ mKey[1]) | (ijk[2] ^ mKey[2]);
5384  }
5385 #else
5386  __hostdev__ bool isCached1(const CoordType& ijk) const
5387  {
5388  return (ijk[0] & int32_t(~Node1T::MASK)) == mKeys[0][0] &&
5389  (ijk[1] & int32_t(~Node1T::MASK)) == mKeys[0][1] &&
5390  (ijk[2] & int32_t(~Node1T::MASK)) == mKeys[0][2];
5391  }
5392  __hostdev__ bool isCached2(const CoordType& ijk) const
5393  {
5394  return (ijk[0] & int32_t(~Node2T::MASK)) == mKeys[1][0] &&
5395  (ijk[1] & int32_t(~Node2T::MASK)) == mKeys[1][1] &&
5396  (ijk[2] & int32_t(~Node2T::MASK)) == mKeys[1][2];
5397  }
5398 #endif
5399 
5400 #ifdef NANOVDB_NEW_ACCESSOR_METHODS
5402  {
5403  return this->template get<GetValue<BuildT>>(ijk);
5404  }
5405  __hostdev__ ValueType getValue(int i, int j, int k) const { return this->template get<GetValue<BuildT>>(CoordType(i, j, k)); }
5406  __hostdev__ ValueType operator()(const CoordType& ijk) const { return this->template get<GetValue<BuildT>>(ijk); }
5407  __hostdev__ ValueType operator()(int i, int j, int k) const { return this->template get<GetValue<BuildT>>(CoordType(i, j, k)); }
5408  __hostdev__ auto getNodeInfo(const CoordType& ijk) const { return this->template get<GetNodeInfo<BuildT>>(ijk); }
5409  __hostdev__ bool isActive(const CoordType& ijk) const { return this->template get<GetState<BuildT>>(ijk); }
5410  __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->template get<ProbeValue<BuildT>>(ijk, v); }
5411  __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const { return this->template get<GetLeaf<BuildT>>(ijk); }
5412 #else // NANOVDB_NEW_ACCESSOR_METHODS
5413 
5414  __hostdev__ ValueType getValue(const CoordType& ijk) const
5415  {
5416 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5417  const CoordValueType dirty = this->computeDirty(ijk);
5418 #else
5419  auto&& dirty = ijk;
5420 #endif
5421  if (this->isCached1(dirty)) {
5422  return mNode1->getValueAndCache(ijk, *this);
5423  } else if (this->isCached2(dirty)) {
5424  return mNode2->getValueAndCache(ijk, *this);
5425  }
5426  return mRoot->getValueAndCache(ijk, *this);
5427  }
5428  __hostdev__ ValueType operator()(const CoordType& ijk) const
5429  {
5430  return this->getValue(ijk);
5431  }
5432  __hostdev__ ValueType operator()(int i, int j, int k) const
5433  {
5434  return this->getValue(CoordType(i, j, k));
5435  }
5436  __hostdev__ ValueType getValue(int i, int j, int k) const
5437  {
5438  return this->getValue(CoordType(i, j, k));
5439  }
5440  __hostdev__ NodeInfo getNodeInfo(const CoordType& ijk) const
5441  {
5442 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5443  const CoordValueType dirty = this->computeDirty(ijk);
5444 #else
5445  auto&& dirty = ijk;
5446 #endif
5447  if (this->isCached1(dirty)) {
5448  return mNode1->getNodeInfoAndCache(ijk, *this);
5449  } else if (this->isCached2(dirty)) {
5450  return mNode2->getNodeInfoAndCache(ijk, *this);
5451  }
5452  return mRoot->getNodeInfoAndCache(ijk, *this);
5453  }
5454 
5455  __hostdev__ bool isActive(const CoordType& ijk) const
5456  {
5457 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5458  const CoordValueType dirty = this->computeDirty(ijk);
5459 #else
5460  auto&& dirty = ijk;
5461 #endif
5462  if (this->isCached1(dirty)) {
5463  return mNode1->isActiveAndCache(ijk, *this);
5464  } else if (this->isCached2(dirty)) {
5465  return mNode2->isActiveAndCache(ijk, *this);
5466  }
5467  return mRoot->isActiveAndCache(ijk, *this);
5468  }
5469 
5470  __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const
5471  {
5472 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5473  const CoordValueType dirty = this->computeDirty(ijk);
5474 #else
5475  auto&& dirty = ijk;
5476 #endif
5477  if (this->isCached1(dirty)) {
5478  return mNode1->probeValueAndCache(ijk, v, *this);
5479  } else if (this->isCached2(dirty)) {
5480  return mNode2->probeValueAndCache(ijk, v, *this);
5481  }
5482  return mRoot->probeValueAndCache(ijk, v, *this);
5483  }
5484 
5485  __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const
5486  {
5487 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5488  const CoordValueType dirty = this->computeDirty(ijk);
5489 #else
5490  auto&& dirty = ijk;
5491 #endif
5492  if (this->isCached1(dirty)) {
5493  return mNode1->probeLeafAndCache(ijk, *this);
5494  } else if (this->isCached2(dirty)) {
5495  return mNode2->probeLeafAndCache(ijk, *this);
5496  }
5497  return mRoot->probeLeafAndCache(ijk, *this);
5498  }
5499 #endif // NANOVDB_NEW_ACCESSOR_METHODS
5500 
5501  template<typename RayT>
5502  __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const
5503  {
5504 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5505  const CoordValueType dirty = this->computeDirty(ijk);
5506 #else
5507  auto&& dirty = ijk;
5508 #endif
5509  if (this->isCached1(dirty)) {
5510  return mNode1->getDimAndCache(ijk, ray, *this);
5511  } else if (this->isCached2(dirty)) {
5512  return mNode2->getDimAndCache(ijk, ray, *this);
5513  }
5514  return mRoot->getDimAndCache(ijk, ray, *this);
5515  }
5516 
5517  template<typename OpT, typename... ArgsT>
5518  __hostdev__ auto get(const CoordType& ijk, ArgsT&&... args) const
5519  {
5520 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5521  const CoordValueType dirty = this->computeDirty(ijk);
5522 #else
5523  auto&& dirty = ijk;
5524 #endif
5525  if (this->isCached1(dirty)) {
5526  return mNode1->template getAndCache<OpT>(ijk, *this, args...);
5527  } else if (this->isCached2(dirty)) {
5528  return mNode2->template getAndCache<OpT>(ijk, *this, args...);
5529  }
5530  return mRoot->template getAndCache<OpT>(ijk, *this, args...);
5531  }
5532 
5533  template<typename OpT, typename... ArgsT>
5534  __hostdev__ auto set(const CoordType& ijk, ArgsT&&... args) const
5535  {
5536 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5537  const CoordValueType dirty = this->computeDirty(ijk);
5538 #else
5539  auto&& dirty = ijk;
5540 #endif
5541  if (this->isCached1(dirty)) {
5542  return const_cast<Node1T*>(mNode1)->template setAndCache<OpT>(ijk, *this, args...);
5543  } else if (this->isCached2(dirty)) {
5544  return const_cast<Node2T*>(mNode2)->template setAndCache<OpT>(ijk, *this, args...);
5545  }
5546  return const_cast<RootT*>(mRoot)->template setAndCache<OpT>(ijk, *this, args...);
5547  }
5548 
5549 private:
5550  /// @brief Allow nodes to insert themselves into the cache.
5551  template<typename>
5552  friend class RootNode;
5553  template<typename, uint32_t>
5554  friend class InternalNode;
5555  template<typename, typename, template<uint32_t> class, uint32_t>
5556  friend class LeafNode;
5557 
5558  /// @brief Inserts a leaf node and key pair into this ReadAccessor
5559  __hostdev__ void insert(const CoordType& ijk, const Node1T* node) const
5560  {
5561 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5562  mKey = ijk;
5563 #else
5564  mKeys[0] = ijk & ~Node1T::MASK;
5565 #endif
5566  mNode1 = node;
5567  }
5568  __hostdev__ void insert(const CoordType& ijk, const Node2T* node) const
5569  {
5570 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5571  mKey = ijk;
5572 #else
5573  mKeys[1] = ijk & ~Node2T::MASK;
5574 #endif
5575  mNode2 = node;
5576  }
5577  template<typename OtherNodeT>
5578  __hostdev__ void insert(const CoordType&, const OtherNodeT*) const {}
5579 }; // ReadAccessor<BuildT, LEVEL0, LEVEL1>
5580 
5581 /// @brief Node caching at all (three) tree levels
5582 template<typename BuildT>
5583 class ReadAccessor<BuildT, 0, 1, 2>
5584 {
5585  using GridT = NanoGrid<BuildT>; // grid
5586  using TreeT = NanoTree<BuildT>;
5587  using RootT = NanoRoot<BuildT>; // root node
5588  using NodeT2 = NanoUpper<BuildT>; // upper internal node
5589  using NodeT1 = NanoLower<BuildT>; // lower internal node
5590  using LeafT = NanoLeaf<BuildT>; // Leaf node
5591  using CoordT = typename RootT::CoordType;
5592  using ValueT = typename RootT::ValueType;
5593 
5594  using FloatType = typename RootT::FloatType;
5595  using CoordValueType = typename RootT::CoordT::ValueType;
5596 
5597  // All member data are mutable to allow for access methods to be const
5598 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY // 44 bytes total
5599  mutable CoordT mKey; // 3*4 = 12 bytes
5600 #else // 68 bytes total
5601  mutable CoordT mKeys[3]; // 3*3*4 = 36 bytes
5602 #endif
5603  mutable const RootT* mRoot;
5604  mutable const void* mNode[3]; // 4*8 = 32 bytes
5605 
5606 public:
5607  using BuildType = BuildT;
5608  using ValueType = ValueT;
5609  using CoordType = CoordT;
5610 
5611  static const int CacheLevels = 3;
5612 #ifndef NANOVDB_NEW_ACCESSOR_METHODS
5613  using NodeInfo = typename ReadAccessor<ValueT, -1, -1, -1>::NodeInfo;
5614 #endif
5615  /// @brief Constructor from a root node
5617 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5618  : mKey(CoordType::max())
5619 #else
5621 #endif
5622  , mRoot(&root)
5623  , mNode{nullptr, nullptr, nullptr}
5624  {
5625  }
5626 
5627  /// @brief Constructor from a grid
5628  __hostdev__ ReadAccessor(const GridT& grid)
5629  : ReadAccessor(grid.tree().root())
5630  {
5631  }
5632 
5633  /// @brief Constructor from a tree
5635  : ReadAccessor(tree.root())
5636  {
5637  }
5638 
5639  __hostdev__ const RootT& root() const { return *mRoot; }
5640 
5641  /// @brief Defaults constructors
5642  ReadAccessor(const ReadAccessor&) = default;
5643  ~ReadAccessor() = default;
5644  ReadAccessor& operator=(const ReadAccessor&) = default;
5645 
5646  /// @brief Return a const point to the cached node of the specified type
5647  ///
5648  /// @warning The return value could be NULL.
5649  template<typename NodeT>
5650  __hostdev__ const NodeT* getNode() const
5651  {
5652  using T = typename NodeTrait<TreeT, NodeT::LEVEL>::type;
5653  static_assert(util::is_same<T, NodeT>::value, "ReadAccessor::getNode: Invalid node type");
5654  return reinterpret_cast<const T*>(mNode[NodeT::LEVEL]);
5655  }
5656 
5657  template<int LEVEL>
5659  {
5660  using T = typename NodeTrait<TreeT, LEVEL>::type;
5661  static_assert(LEVEL >= 0 && LEVEL <= 2, "ReadAccessor::getNode: Invalid node type");
5662  return reinterpret_cast<const T*>(mNode[LEVEL]);
5663  }
5664 
5665  /// @brief Reset this access to its initial state, i.e. with an empty cache
5667  {
5668 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5669  mKey = CoordType::max();
5670 #else
5671  mKeys[0] = mKeys[1] = mKeys[2] = CoordType::max();
5672 #endif
5673  mNode[0] = mNode[1] = mNode[2] = nullptr;
5674  }
5675 
5676 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5677  template<typename NodeT>
5678  __hostdev__ bool isCached(CoordValueType dirty) const
5679  {
5680  if (!mNode[NodeT::LEVEL])
5681  return false;
5682  if (dirty & int32_t(~NodeT::MASK)) {
5683  mNode[NodeT::LEVEL] = nullptr;
5684  return false;
5685  }
5686  return true;
5687  }
5688 
5689  __hostdev__ CoordValueType computeDirty(const CoordType& ijk) const
5690  {
5691  return (ijk[0] ^ mKey[0]) | (ijk[1] ^ mKey[1]) | (ijk[2] ^ mKey[2]);
5692  }
5693 #else
5694  template<typename NodeT>
5695  __hostdev__ bool isCached(const CoordType& ijk) const
5696  {
5697  return (ijk[0] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][0] &&
5698  (ijk[1] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][1] &&
5699  (ijk[2] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][2];
5700  }
5701 #endif
5702 
5703 #ifdef NANOVDB_NEW_ACCESSOR_METHODS
5705  {
5706  return this->template get<GetValue<BuildT>>(ijk);
5707  }
5708  __hostdev__ ValueType getValue(int i, int j, int k) const { return this->template get<GetValue<BuildT>>(CoordType(i, j, k)); }
5709  __hostdev__ ValueType operator()(const CoordType& ijk) const { return this->template get<GetValue<BuildT>>(ijk); }
5710  __hostdev__ ValueType operator()(int i, int j, int k) const { return this->template get<GetValue<BuildT>>(CoordType(i, j, k)); }
5711  __hostdev__ auto getNodeInfo(const CoordType& ijk) const { return this->template get<GetNodeInfo<BuildT>>(ijk); }
5712  __hostdev__ bool isActive(const CoordType& ijk) const { return this->template get<GetState<BuildT>>(ijk); }
5713  __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->template get<ProbeValue<BuildT>>(ijk, v); }
5714  __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const { return this->template get<GetLeaf<BuildT>>(ijk); }
5715 #else // NANOVDB_NEW_ACCESSOR_METHODS
5716 
5717  __hostdev__ ValueType getValue(const CoordType& ijk) const
5718  {
5719 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5720  const CoordValueType dirty = this->computeDirty(ijk);
5721 #else
5722  auto&& dirty = ijk;
5723 #endif
5724  if (this->isCached<LeafT>(dirty)) {
5725  return ((LeafT*)mNode[0])->getValue(ijk);
5726  } else if (this->isCached<NodeT1>(dirty)) {
5727  return ((NodeT1*)mNode[1])->getValueAndCache(ijk, *this);
5728  } else if (this->isCached<NodeT2>(dirty)) {
5729  return ((NodeT2*)mNode[2])->getValueAndCache(ijk, *this);
5730  }
5731  return mRoot->getValueAndCache(ijk, *this);
5732  }
5733  __hostdev__ ValueType operator()(const CoordType& ijk) const
5734  {
5735  return this->getValue(ijk);
5736  }
5737  __hostdev__ ValueType operator()(int i, int j, int k) const
5738  {
5739  return this->getValue(CoordType(i, j, k));
5740  }
5741  __hostdev__ ValueType getValue(int i, int j, int k) const
5742  {
5743  return this->getValue(CoordType(i, j, k));
5744  }
5745 
5746  __hostdev__ NodeInfo getNodeInfo(const CoordType& ijk) const
5747  {
5748 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5749  const CoordValueType dirty = this->computeDirty(ijk);
5750 #else
5751  auto&& dirty = ijk;
5752 #endif
5753  if (this->isCached<LeafT>(dirty)) {
5754  return ((LeafT*)mNode[0])->getNodeInfoAndCache(ijk, *this);
5755  } else if (this->isCached<NodeT1>(dirty)) {
5756  return ((NodeT1*)mNode[1])->getNodeInfoAndCache(ijk, *this);
5757  } else if (this->isCached<NodeT2>(dirty)) {
5758  return ((NodeT2*)mNode[2])->getNodeInfoAndCache(ijk, *this);
5759  }
5760  return mRoot->getNodeInfoAndCache(ijk, *this);
5761  }
5762 
5763  __hostdev__ bool isActive(const CoordType& ijk) const
5764  {
5765 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5766  const CoordValueType dirty = this->computeDirty(ijk);
5767 #else
5768  auto&& dirty = ijk;
5769 #endif
5770  if (this->isCached<LeafT>(dirty)) {
5771  return ((LeafT*)mNode[0])->isActive(ijk);
5772  } else if (this->isCached<NodeT1>(dirty)) {
5773  return ((NodeT1*)mNode[1])->isActiveAndCache(ijk, *this);
5774  } else if (this->isCached<NodeT2>(dirty)) {
5775  return ((NodeT2*)mNode[2])->isActiveAndCache(ijk, *this);
5776  }
5777  return mRoot->isActiveAndCache(ijk, *this);
5778  }
5779 
5780  __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const
5781  {
5782 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5783  const CoordValueType dirty = this->computeDirty(ijk);
5784 #else
5785  auto&& dirty = ijk;
5786 #endif
5787  if (this->isCached<LeafT>(dirty)) {
5788  return ((LeafT*)mNode[0])->probeValue(ijk, v);
5789  } else if (this->isCached<NodeT1>(dirty)) {
5790  return ((NodeT1*)mNode[1])->probeValueAndCache(ijk, v, *this);
5791  } else if (this->isCached<NodeT2>(dirty)) {
5792  return ((NodeT2*)mNode[2])->probeValueAndCache(ijk, v, *this);
5793  }
5794  return mRoot->probeValueAndCache(ijk, v, *this);
5795  }
5796  __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const
5797  {
5798 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5799  const CoordValueType dirty = this->computeDirty(ijk);
5800 #else
5801  auto&& dirty = ijk;
5802 #endif
5803  if (this->isCached<LeafT>(dirty)) {
5804  return ((LeafT*)mNode[0]);
5805  } else if (this->isCached<NodeT1>(dirty)) {
5806  return ((NodeT1*)mNode[1])->probeLeafAndCache(ijk, *this);
5807  } else if (this->isCached<NodeT2>(dirty)) {
5808  return ((NodeT2*)mNode[2])->probeLeafAndCache(ijk, *this);
5809  }
5810  return mRoot->probeLeafAndCache(ijk, *this);
5811  }
5812 #endif // NANOVDB_NEW_ACCESSOR_METHODS
5813 
5814  template<typename OpT, typename... ArgsT>
5815  __hostdev__ auto get(const CoordType& ijk, ArgsT&&... args) const
5816  {
5817 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5818  const CoordValueType dirty = this->computeDirty(ijk);
5819 #else
5820  auto&& dirty = ijk;
5821 #endif
5822  if (this->isCached<LeafT>(dirty)) {
5823  return ((const LeafT*)mNode[0])->template getAndCache<OpT>(ijk, *this, args...);
5824  } else if (this->isCached<NodeT1>(dirty)) {
5825  return ((const NodeT1*)mNode[1])->template getAndCache<OpT>(ijk, *this, args...);
5826  } else if (this->isCached<NodeT2>(dirty)) {
5827  return ((const NodeT2*)mNode[2])->template getAndCache<OpT>(ijk, *this, args...);
5828  }
5829  return mRoot->template getAndCache<OpT>(ijk, *this, args...);
5830  }
5831 
5832  template<typename OpT, typename... ArgsT>
5833  __hostdev__ auto set(const CoordType& ijk, ArgsT&&... args) const
5834  {
5835 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5836  const CoordValueType dirty = this->computeDirty(ijk);
5837 #else
5838  auto&& dirty = ijk;
5839 #endif
5840  if (this->isCached<LeafT>(dirty)) {
5841  return ((LeafT*)mNode[0])->template setAndCache<OpT>(ijk, *this, args...);
5842  } else if (this->isCached<NodeT1>(dirty)) {
5843  return ((NodeT1*)mNode[1])->template setAndCache<OpT>(ijk, *this, args...);
5844  } else if (this->isCached<NodeT2>(dirty)) {
5845  return ((NodeT2*)mNode[2])->template setAndCache<OpT>(ijk, *this, args...);
5846  }
5847  return ((RootT*)mRoot)->template setAndCache<OpT>(ijk, *this, args...);
5848  }
5849 
5850  template<typename RayT>
5851  __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const
5852  {
5853 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5854  const CoordValueType dirty = this->computeDirty(ijk);
5855 #else
5856  auto&& dirty = ijk;
5857 #endif
5858  if (this->isCached<LeafT>(dirty)) {
5859  return ((LeafT*)mNode[0])->getDimAndCache(ijk, ray, *this);
5860  } else if (this->isCached<NodeT1>(dirty)) {
5861  return ((NodeT1*)mNode[1])->getDimAndCache(ijk, ray, *this);
5862  } else if (this->isCached<NodeT2>(dirty)) {
5863  return ((NodeT2*)mNode[2])->getDimAndCache(ijk, ray, *this);
5864  }
5865  return mRoot->getDimAndCache(ijk, ray, *this);
5866  }
5867 
5868 private:
5869  /// @brief Allow nodes to insert themselves into the cache.
5870  template<typename>
5871  friend class RootNode;
5872  template<typename, uint32_t>
5873  friend class InternalNode;
5874  template<typename, typename, template<uint32_t> class, uint32_t>
5875  friend class LeafNode;
5876 
5877  /// @brief Inserts a leaf node and key pair into this ReadAccessor
5878  template<typename NodeT>
5879  __hostdev__ void insert(const CoordType& ijk, const NodeT* node) const
5880  {
5881 #ifdef NANOVDB_USE_SINGLE_ACCESSOR_KEY
5882  mKey = ijk;
5883 #else
5884  mKeys[NodeT::LEVEL] = ijk & ~NodeT::MASK;
5885 #endif
5886  mNode[NodeT::LEVEL] = node;
5887  }
5888 }; // ReadAccessor<BuildT, 0, 1, 2>
5889 
5890 //////////////////////////////////////////////////
5891 
5892 /// @brief Free-standing function for convenient creation of a ReadAccessor with
5893 /// optional and customizable node caching.
5894 ///
5895 /// @details createAccessor<>(grid): No caching of nodes and hence it's thread-safe but slow
5896 /// createAccessor<0>(grid): Caching of leaf nodes only
5897 /// createAccessor<1>(grid): Caching of lower internal nodes only
5898 /// createAccessor<2>(grid): Caching of upper internal nodes only
5899 /// createAccessor<0,1>(grid): Caching of leaf and lower internal nodes
5900 /// createAccessor<0,2>(grid): Caching of leaf and upper internal nodes
5901 /// createAccessor<1,2>(grid): Caching of lower and upper internal nodes
5902 /// createAccessor<0,1,2>(grid): Caching of all nodes at all tree levels
5903 
5904 template<int LEVEL0 = -1, int LEVEL1 = -1, int LEVEL2 = -1, typename ValueT = float>
5906 {
5908 }
5909 
5910 template<int LEVEL0 = -1, int LEVEL1 = -1, int LEVEL2 = -1, typename ValueT = float>
5912 {
5914 }
5915 
5916 template<int LEVEL0 = -1, int LEVEL1 = -1, int LEVEL2 = -1, typename ValueT = float>
5918 {
5920 }
5921 
5922 //////////////////////////////////////////////////
5923 
5924 /// @brief This is a convenient class that allows for access to grid meta-data
5925 /// that are independent of the value type of a grid. That is, this class
5926 /// can be used to get information about a grid without actually knowing
5927 /// its ValueType.
5929 { // 768 bytes (32 byte aligned)
5930  GridData mGridData; // 672B
5931  TreeData mTreeData; // 64B
5932  CoordBBox mIndexBBox; // 24B. AABB of active values in index space.
5933  uint32_t mRootTableSize, mPadding{0}; // 8B
5934 
5935 public:
5936  template<typename T>
5938  {
5939  mGridData = *grid.data();
5940  mTreeData = *grid.tree().data();
5941  mIndexBBox = grid.indexBBox();
5942  mRootTableSize = grid.tree().root().getTableSize();
5943  }
5944  GridMetaData(const GridData* gridData)
5945  {
5946  if (GridMetaData::safeCast(gridData)) {
5947  *this = *reinterpret_cast<const GridMetaData*>(gridData);
5948  //util::memcpy(this, (const GridMetaData*)gridData);
5949  } else {// otherwise copy each member individually
5950  mGridData = *gridData;
5951  mTreeData = *reinterpret_cast<const TreeData*>(gridData->treePtr());
5952  mIndexBBox = gridData->indexBBox();
5953  mRootTableSize = gridData->rootTableSize();
5954  }
5955  }
5956  GridMetaData& operator=(const GridMetaData&) = default;
5957  /// @brief return true if the RootData follows right after the TreeData.
5958  /// If so, this implies that it's safe to cast the grid from which
5959  /// this instance was constructed to a GridMetaData
5960  __hostdev__ bool safeCast() const { return mTreeData.isRootNext(); }
5961 
5962  /// @brief return true if it is safe to cast the grid to a pointer
5963  /// of type GridMetaData, i.e. construction can be avoided.
5964  __hostdev__ static bool safeCast(const GridData *gridData){
5965  NANOVDB_ASSERT(gridData && gridData->isValid());
5966  return gridData->isRootConnected();
5967  }
5968  /// @brief return true if it is safe to cast the grid to a pointer
5969  /// of type GridMetaData, i.e. construction can be avoided.
5970  template<typename T>
5971  __hostdev__ static bool safeCast(const NanoGrid<T>& grid){return grid.tree().isRootNext();}
5972  __hostdev__ bool isValid() const { return mGridData.isValid(); }
5973  __hostdev__ const GridType& gridType() const { return mGridData.mGridType; }
5974  __hostdev__ const GridClass& gridClass() const { return mGridData.mGridClass; }
5975  __hostdev__ bool isLevelSet() const { return mGridData.mGridClass == GridClass::LevelSet; }
5976  __hostdev__ bool isFogVolume() const { return mGridData.mGridClass == GridClass::FogVolume; }
5977  __hostdev__ bool isStaggered() const { return mGridData.mGridClass == GridClass::Staggered; }
5978  __hostdev__ bool isPointIndex() const { return mGridData.mGridClass == GridClass::PointIndex; }
5979  __hostdev__ bool isGridIndex() const { return mGridData.mGridClass == GridClass::IndexGrid; }
5980  __hostdev__ bool isPointData() const { return mGridData.mGridClass == GridClass::PointData; }
5981  __hostdev__ bool isMask() const { return mGridData.mGridClass == GridClass::Topology; }
5982  __hostdev__ bool isUnknown() const { return mGridData.mGridClass == GridClass::Unknown; }
5983  __hostdev__ bool hasMinMax() const { return mGridData.mFlags.isMaskOn(GridFlags::HasMinMax); }
5984  __hostdev__ bool hasBBox() const { return mGridData.mFlags.isMaskOn(GridFlags::HasBBox); }
5985  __hostdev__ bool hasLongGridName() const { return mGridData.mFlags.isMaskOn(GridFlags::HasLongGridName); }
5986  __hostdev__ bool hasAverage() const { return mGridData.mFlags.isMaskOn(GridFlags::HasAverage); }
5987  __hostdev__ bool hasStdDeviation() const { return mGridData.mFlags.isMaskOn(GridFlags::HasStdDeviation); }
5988  __hostdev__ bool isBreadthFirst() const { return mGridData.mFlags.isMaskOn(GridFlags::IsBreadthFirst); }
5989  __hostdev__ uint64_t gridSize() const { return mGridData.mGridSize; }
5990  __hostdev__ uint32_t gridIndex() const { return mGridData.mGridIndex; }
5991  __hostdev__ uint32_t gridCount() const { return mGridData.mGridCount; }
5992  __hostdev__ const char* shortGridName() const { return mGridData.mGridName; }
5993  __hostdev__ const Map& map() const { return mGridData.mMap; }
5994  __hostdev__ const Vec3dBBox& worldBBox() const { return mGridData.mWorldBBox; }
5995  __hostdev__ const CoordBBox& indexBBox() const { return mIndexBBox; }
5996  __hostdev__ Vec3d voxelSize() const { return mGridData.mVoxelSize; }
5997  __hostdev__ int blindDataCount() const { return mGridData.mBlindMetadataCount; }
5998  __hostdev__ uint64_t activeVoxelCount() const { return mTreeData.mVoxelCount; }
5999  __hostdev__ const uint32_t& activeTileCount(uint32_t level) const { return mTreeData.mTileCount[level - 1]; }
6000  __hostdev__ uint32_t nodeCount(uint32_t level) const { return mTreeData.mNodeCount[level]; }
6001  __hostdev__ const Checksum& checksum() const { return mGridData.mChecksum; }
6002  __hostdev__ uint32_t rootTableSize() const { return mRootTableSize; }
6003  __hostdev__ bool isEmpty() const { return mRootTableSize == 0; }
6004  __hostdev__ Version version() const { return mGridData.mVersion; }
6005 }; // GridMetaData
6006 
6007 /// @brief Class to access points at a specific voxel location
6008 ///
6009 /// @note If GridClass::PointIndex AttT should be uint32_t and if GridClass::PointData Vec3f
6010 template<typename AttT, typename BuildT = uint32_t>
6011 class PointAccessor : public DefaultReadAccessor<BuildT>
6012 {
6013  using AccT = DefaultReadAccessor<BuildT>;
6014  const NanoGrid<BuildT>& mGrid;
6015  const AttT* mData;
6016 
6017 public:
6019  : AccT(grid.tree().root())
6020  , mGrid(grid)
6021  , mData(grid.template getBlindData<AttT>(0))
6022  {
6023  NANOVDB_ASSERT(grid.gridType() == toGridType<BuildT>());
6026  }
6027 
6028  /// @brief return true if this access was initialized correctly
6029  __hostdev__ operator bool() const { return mData != nullptr; }
6030 
6031  __hostdev__ const NanoGrid<BuildT>& grid() const { return mGrid; }
6032 
6033  /// @brief Return the total number of point in the grid and set the
6034  /// iterators to the complete range of points.
6035  __hostdev__ uint64_t gridPoints(const AttT*& begin, const AttT*& end) const
6036  {
6037  const uint64_t count = mGrid.blindMetaData(0u).mValueCount;
6038  begin = mData;
6039  end = begin + count;
6040  return count;
6041  }
6042  /// @brief Return the number of points in the leaf node containing the coordinate @a ijk.
6043  /// If this return value is larger than zero then the iterators @a begin and @a end
6044  /// will point to all the attributes contained within that leaf node.
6045  __hostdev__ uint64_t leafPoints(const Coord& ijk, const AttT*& begin, const AttT*& end) const
6046  {
6047  auto* leaf = this->probeLeaf(ijk);
6048  if (leaf == nullptr) {
6049  return 0;
6050  }
6051  begin = mData + leaf->minimum();
6052  end = begin + leaf->maximum();
6053  return leaf->maximum();
6054  }
6055 
6056  /// @brief get iterators over attributes to points at a specific voxel location
6057  __hostdev__ uint64_t voxelPoints(const Coord& ijk, const AttT*& begin, const AttT*& end) const
6058  {
6059  begin = end = nullptr;
6060  if (auto* leaf = this->probeLeaf(ijk)) {
6061  const uint32_t offset = NanoLeaf<BuildT>::CoordToOffset(ijk);
6062  if (leaf->isActive(offset)) {
6063  begin = mData + leaf->minimum();
6064  end = begin + leaf->getValue(offset);
6065  if (offset > 0u)
6066  begin += leaf->getValue(offset - 1);
6067  }
6068  }
6069  return end - begin;
6070  }
6071 }; // PointAccessor
6072 
6073 template<typename AttT>
6074 class PointAccessor<AttT, Point> : public DefaultReadAccessor<Point>
6075 {
6076  using AccT = DefaultReadAccessor<Point>;
6077  const NanoGrid<Point>& mGrid;
6078  const AttT* mData;
6079 
6080 public:
6082  : AccT(grid.tree().root())
6083  , mGrid(grid)
6084  , mData(grid.template getBlindData<AttT>(0))
6085  {
6086  NANOVDB_ASSERT(mData);
6093  }
6094 
6095  /// @brief return true if this access was initialized correctly
6096  __hostdev__ operator bool() const { return mData != nullptr; }
6097 
6098  __hostdev__ const NanoGrid<Point>& grid() const { return mGrid; }
6099 
6100  /// @brief Return the total number of point in the grid and set the
6101  /// iterators to the complete range of points.
6102  __hostdev__ uint64_t gridPoints(const AttT*& begin, const AttT*& end) const
6103  {
6104  const uint64_t count = mGrid.blindMetaData(0u).mValueCount;
6105  begin = mData;
6106  end = begin + count;
6107  return count;
6108  }
6109  /// @brief Return the number of points in the leaf node containing the coordinate @a ijk.
6110  /// If this return value is larger than zero then the iterators @a begin and @a end
6111  /// will point to all the attributes contained within that leaf node.
6112  __hostdev__ uint64_t leafPoints(const Coord& ijk, const AttT*& begin, const AttT*& end) const
6113  {
6114  auto* leaf = this->probeLeaf(ijk);
6115  if (leaf == nullptr)
6116  return 0;
6117  begin = mData + leaf->offset();
6118  end = begin + leaf->pointCount();
6119  return leaf->pointCount();
6120  }
6121 
6122  /// @brief get iterators over attributes to points at a specific voxel location
6123  __hostdev__ uint64_t voxelPoints(const Coord& ijk, const AttT*& begin, const AttT*& end) const
6124  {
6125  if (auto* leaf = this->probeLeaf(ijk)) {
6126  const uint32_t n = NanoLeaf<Point>::CoordToOffset(ijk);
6127  if (leaf->isActive(n)) {
6128  begin = mData + leaf->first(n);
6129  end = mData + leaf->last(n);
6130  return end - begin;
6131  }
6132  }
6133  begin = end = nullptr;
6134  return 0u; // no leaf or inactive voxel
6135  }
6136 }; // PointAccessor<AttT, Point>
6137 
6138 /// @brief Class to access values in channels at a specific voxel location.
6139 ///
6140 /// @note The ChannelT template parameter can be either const and non-const.
6141 template<typename ChannelT, typename IndexT = ValueIndex>
6142 class ChannelAccessor : public DefaultReadAccessor<IndexT>
6143 {
6144  static_assert(BuildTraits<IndexT>::is_index, "Expected an index build type");
6146 
6147  const NanoGrid<IndexT>& mGrid;
6148  ChannelT* mChannel;
6149 
6150 public:
6151  using ValueType = ChannelT;
6154 
6155  /// @brief Ctor from an IndexGrid and an integer ID of an internal channel
6156  /// that is assumed to exist as blind data in the IndexGrid.
6157  __hostdev__ ChannelAccessor(const NanoGrid<IndexT>& grid, uint32_t channelID = 0u)
6158  : BaseT(grid.tree().root())
6159  , mGrid(grid)
6160  , mChannel(nullptr)
6161  {
6162  NANOVDB_ASSERT(isIndex(grid.gridType()));
6164  this->setChannel(channelID);
6165  }
6166 
6167  /// @brief Ctor from an IndexGrid and an external channel
6168  __hostdev__ ChannelAccessor(const NanoGrid<IndexT>& grid, ChannelT* channelPtr)
6169  : BaseT(grid.tree().root())
6170  , mGrid(grid)
6171  , mChannel(channelPtr)
6172  {
6173  NANOVDB_ASSERT(isIndex(grid.gridType()));
6175  }
6176 
6177  /// @brief return true if this access was initialized correctly
6178  __hostdev__ operator bool() const { return mChannel != nullptr; }
6179 
6180  /// @brief Return a const reference to the IndexGrid
6181  __hostdev__ const NanoGrid<IndexT>& grid() const { return mGrid; }
6182 
6183  /// @brief Return a const reference to the tree of the IndexGrid
6184  __hostdev__ const TreeType& tree() const { return mGrid.tree(); }
6185 
6186  /// @brief Return a vector of the axial voxel sizes
6187  __hostdev__ const Vec3d& voxelSize() const { return mGrid.voxelSize(); }
6188 
6189  /// @brief Return total number of values indexed by the IndexGrid
6190  __hostdev__ const uint64_t& valueCount() const { return mGrid.valueCount(); }
6191 
6192  /// @brief Change to an external channel
6193  /// @return Pointer to channel data
6194  __hostdev__ ChannelT* setChannel(ChannelT* channelPtr) {return mChannel = channelPtr;}
6195 
6196  /// @brief Change to an internal channel, assuming it exists as as blind data
6197  /// in the IndexGrid.
6198  /// @return Pointer to channel data, which could be NULL if channelID is out of range or
6199  /// if ChannelT does not match the value type of the blind data
6200  __hostdev__ ChannelT* setChannel(uint32_t channelID)
6201  {
6202  return mChannel = const_cast<ChannelT*>(mGrid.template getBlindData<ChannelT>(channelID));
6203  }
6204 
6205  /// @brief Return the linear offset into a channel that maps to the specified coordinate
6206  __hostdev__ uint64_t getIndex(const math::Coord& ijk) const { return BaseT::getValue(ijk); }
6207  __hostdev__ uint64_t idx(int i, int j, int k) const { return BaseT::getValue(math::Coord(i, j, k)); }
6208 
6209  /// @brief Return the value from a cached channel that maps to the specified coordinate
6210  __hostdev__ ChannelT& getValue(const math::Coord& ijk) const { return mChannel[BaseT::getValue(ijk)]; }
6211  __hostdev__ ChannelT& operator()(const math::Coord& ijk) const { return this->getValue(ijk); }
6212  __hostdev__ ChannelT& operator()(int i, int j, int k) const { return this->getValue(math::Coord(i, j, k)); }
6213 
6214  /// @brief return the state and updates the value of the specified voxel
6215  __hostdev__ bool probeValue(const math::Coord& ijk, typename util::remove_const<ChannelT>::type& v) const
6216  {
6217  uint64_t idx;
6218  const bool isActive = BaseT::probeValue(ijk, idx);
6219  v = mChannel[idx];
6220  return isActive;
6221  }
6222  /// @brief Return the value from a specified channel that maps to the specified coordinate
6223  ///
6224  /// @note The template parameter can be either const or non-const
6225  template<typename T>
6226  __hostdev__ T& getValue(const math::Coord& ijk, T* channelPtr) const { return channelPtr[BaseT::getValue(ijk)]; }
6227 
6228 }; // ChannelAccessor
6229 
6230 #if 0
6231 // This MiniGridHandle class is only included as a stand-alone example. Note that aligned_alloc is a C++17 feature!
6232 // Normally we recommend using GridHandle defined in util/GridHandle.h but this minimal implementation could be an
6233 // alternative when using the IO methods defined below.
6234 struct MiniGridHandle {
6235  struct BufferType {
6236  uint8_t *data;
6237  uint64_t size;
6238  BufferType(uint64_t n=0) : data(std::aligned_alloc(NANOVDB_DATA_ALIGNMENT, n)), size(n) {assert(isValid(data));}
6239  BufferType(BufferType &&other) : data(other.data), size(other.size) {other.data=nullptr; other.size=0;}
6240  ~BufferType() {std::free(data);}
6241  BufferType& operator=(const BufferType &other) = delete;
6242  BufferType& operator=(BufferType &&other){data=other.data; size=other.size; other.data=nullptr; other.size=0; return *this;}
6243  static BufferType create(size_t n, BufferType* dummy = nullptr) {return BufferType(n);}
6244  } buffer;
6245  MiniGridHandle(BufferType &&buf) : buffer(std::move(buf)) {}
6246  const uint8_t* data() const {return buffer.data;}
6247 };// MiniGridHandle
6248 #endif
6249 
6250 namespace io {
6251 
6252 /// @brief Define compression codecs
6253 ///
6254 /// @note NONE is the default, ZIP is slow but compact and BLOSC offers a great balance.
6255 ///
6256 /// @throw NanoVDB optionally supports ZIP and BLOSC compression and will throw an exception
6257 /// if its support is required but missing.
6258 enum class Codec : uint16_t { NONE = 0,
6259  ZIP = 1,
6260  BLOSC = 2,
6261  End = 3,
6262  StrLen = 6 + End };
6263 
6264 __hostdev__ inline const char* toStr(char *dst, Codec codec)
6265 {
6266  switch (codec){
6267  case Codec::NONE: return util::strcpy(dst, "NONE");
6268  case Codec::ZIP: return util::strcpy(dst, "ZIP");
6269  case Codec::BLOSC : return util::strcpy(dst, "BLOSC");
6270  default: return util::strcpy(dst, "END");
6271  }
6272 }
6273 
6274 __hostdev__ inline Codec toCodec(const char *str)
6275 {
6276  if (util::streq(str, "none")) return Codec::NONE;
6277  if (util::streq(str, "zip")) return Codec::ZIP;
6278  if (util::streq(str, "blosc")) return Codec::BLOSC;
6279  return Codec::End;
6280 }
6281 
6282 /// @brief Data encoded at the head of each segment of a file or stream.
6283 ///
6284 /// @note A file or stream is composed of one or more segments that each contain
6285 // one or more grids.
6286 struct FileHeader {// 16 bytes
6287  uint64_t magic;// 8 bytes
6288  Version version;// 4 bytes version numbers
6289  uint16_t gridCount;// 2 bytes
6290  Codec codec;// 2 bytes
6291  bool isValid() const {return magic == NANOVDB_MAGIC_NUMB || magic == NANOVDB_MAGIC_FILE;}
6292 }; // FileHeader ( 16 bytes = 2 words )
6293 
6294 // @brief Data encoded for each of the grids associated with a segment.
6295 // Grid size in memory (uint64_t) |
6296 // Grid size on disk (uint64_t) |
6297 // Grid name hash key (uint64_t) |
6298 // Numer of active voxels (uint64_t) |
6299 // Grid type (uint32_t) |
6300 // Grid class (uint32_t) |
6301 // Characters in grid name (uint32_t) |
6302 // AABB in world space (2*3*double) | one per grid in file
6303 // AABB in index space (2*3*int) |
6304 // Size of a voxel in world units (3*double) |
6305 // Byte size of the grid name (uint32_t) |
6306 // Number of nodes per level (4*uint32_t) |
6307 // Numer of active tiles per level (3*uint32_t) |
6308 // Codec for file compression (uint16_t) |
6309 // Padding due to 8B alignment (uint16_t) |
6310 // Version number (uint32_t) |
6312 {// 176 bytes
6313  uint64_t gridSize, fileSize, nameKey, voxelCount; // 4 * 8 = 32B.
6316  Vec3dBBox worldBBox; // 2 * 3 * 8 = 48B.
6317  CoordBBox indexBBox; // 2 * 3 * 4 = 24B.
6318  Vec3d voxelSize; // 24B.
6319  uint32_t nameSize; // 4B.
6320  uint32_t nodeCount[4]; //4 x 4 = 16B
6321  uint32_t tileCount[3];// 3 x 4 = 12B
6322  Codec codec; // 2B
6323  uint16_t padding;// 2B, due to 8B alignment from uint64_t
6325 }; // FileMetaData
6326 
6327 // the following code block uses std and therefore needs to be ignored by CUDA and HIP
6328 #if !defined(__CUDA_ARCH__) && !defined(__HIP__)
6329 
6330 // Note that starting with version 32.6.0 it is possible to write and read raw grid buffers to
6331 // files, e.g. os.write((const char*)&buffer.data(), buffer.size()) or more conveniently as
6332 // handle.write(fileName). In addition to this simple approach we offer the methods below to
6333 // write traditional uncompressed nanovdb files that unlike raw files include metadata that
6334 // is used for tools like nanovdb_print.
6335 
6336 ///
6337 /// @brief This is a standalone alternative to io::writeGrid(...,Codec::NONE) defined in util/IO.h
6338 /// Unlike the latter this function has no dependencies at all, not even NanoVDB.h, so it also
6339 /// works if client code only includes PNanoVDB.h!
6340 ///
6341 /// @details Writes a raw NanoVDB buffer, possibly with multiple grids, to a stream WITHOUT compression.
6342 /// It follows all the conventions in util/IO.h so the stream can be read by all existing client
6343 /// code of NanoVDB.
6344 ///
6345 /// @note This method will always write uncompressed grids to the stream, i.e. Blosc or ZIP compression
6346 /// is never applied! This is a fundamental limitation and feature of this standalone function.
6347 ///
6348 /// @throw std::invalid_argument if buffer does not point to a valid NanoVDB grid.
6349 ///
6350 /// @warning This is pretty ugly code that involves lots of pointer and bit manipulations - not for the faint of heart :)
6351 template<typename StreamT> // StreamT class must support: "void write(const char*, size_t)"
6352 void writeUncompressedGrid(StreamT& os, const GridData* gridData, bool raw = false)
6353 {
6354  NANOVDB_ASSERT(gridData->mMagic == NANOVDB_MAGIC_NUMB || gridData->mMagic == NANOVDB_MAGIC_GRID);
6355  NANOVDB_ASSERT(gridData->mVersion.isCompatible());
6356  if (!raw) {// segment with a single grid: FileHeader, FileMetaData, gridName, Grid
6357 #ifdef NANOVDB_USE_NEW_MAGIC_NUMBERS
6358  FileHeader head{NANOVDB_MAGIC_FILE, gridData->mVersion, 1u, Codec::NONE};
6359 #else
6360  FileHeader head{NANOVDB_MAGIC_NUMB, gridData->mVersion, 1u, Codec::NONE};
6361 #endif
6362  const char* gridName = gridData->gridName();
6363  const uint32_t nameSize = util::strlen(gridName) + 1;// include '\0'
6364  const TreeData* treeData = (const TreeData*)(gridData->treePtr());
6365  FileMetaData meta{gridData->mGridSize, gridData->mGridSize, 0u, treeData->mVoxelCount,
6366  gridData->mGridType, gridData->mGridClass, gridData->mWorldBBox,
6367  treeData->bbox(), gridData->mVoxelSize, nameSize,
6368  {treeData->mNodeCount[0], treeData->mNodeCount[1], treeData->mNodeCount[2], 1u},
6369  {treeData->mTileCount[0], treeData->mTileCount[1], treeData->mTileCount[2]},
6370  Codec::NONE, 0u, gridData->mVersion }; // FileMetaData
6371  os.write((const char*)&head, sizeof(FileHeader)); // write header
6372  os.write((const char*)&meta, sizeof(FileMetaData)); // write meta data
6373  os.write(gridName, nameSize); // write grid name
6374  }
6375  os.write((const char*)gridData, gridData->mGridSize);// write the grid
6376 }// writeUncompressedGrid
6377 
6378 /// @brief write multiple NanoVDB grids to a single file, without compression.
6379 /// @note To write all grids in a single GridHandle simply use handle.write("fieNane")
6380 template<typename GridHandleT, template<typename...> class VecT>
6381 void writeUncompressedGrids(const char* fileName, const VecT<GridHandleT>& handles, bool raw = false)
6382 {
6383 #ifdef NANOVDB_USE_IOSTREAMS // use this to switch between std::ofstream or FILE implementations
6384  std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
6385 #else
6386  struct StreamT {
6387  FILE* fptr;
6388  StreamT(const char* name) { fptr = fopen(name, "wb"); }
6389  ~StreamT() { fclose(fptr); }
6390  void write(const char* data, size_t n) { fwrite(data, 1, n, fptr); }
6391  bool is_open() const { return fptr != NULL; }
6392  } os(fileName);
6393 #endif
6394  if (!os.is_open()) {
6395  fprintf(stderr, "nanovdb::writeUncompressedGrids: Unable to open file \"%s\"for output\n", fileName);
6396  exit(EXIT_FAILURE);
6397  }
6398  for (auto& h : handles) {
6399  for (uint32_t n=0; n<h.gridCount(); ++n) writeUncompressedGrid(os, h.gridData(n), raw);
6400  }
6401 } // writeUncompressedGrids
6402 
6403 /// @brief read all uncompressed grids from a stream and return their handles.
6404 ///
6405 /// @throw std::invalid_argument if stream does not contain a single uncompressed valid NanoVDB grid
6406 ///
6407 /// @details StreamT class must support: "bool read(char*, size_t)" and "void skip(uint32_t)"
6408 template<typename GridHandleT, typename StreamT, template<typename...> class VecT>
6409 VecT<GridHandleT> readUncompressedGrids(StreamT& is, const typename GridHandleT::BufferType& pool = typename GridHandleT::BufferType())
6410 {
6411  VecT<GridHandleT> handles;
6412  GridData data;
6413  is.read((char*)&data, sizeof(GridData));
6414  if (data.isValid()) {// stream contains a raw grid buffer
6415  uint64_t size = data.mGridSize, sum = 0u;
6416  while(data.mGridIndex + 1u < data.mGridCount) {
6417  is.skip(data.mGridSize - sizeof(GridData));// skip grid
6418  is.read((char*)&data, sizeof(GridData));// read sizeof(GridData) bytes
6419  sum += data.mGridSize;
6420  }
6421  is.skip(-int64_t(sum + sizeof(GridData)));// rewind to start
6422  auto buffer = GridHandleT::BufferType::create(size + sum, &pool);
6423  is.read((char*)(buffer.data()), buffer.size());
6424  handles.emplace_back(std::move(buffer));
6425  } else {// Header0, MetaData0, gridName0, Grid0...HeaderN, MetaDataN, gridNameN, GridN
6426  is.skip(-sizeof(GridData));// rewind
6427  FileHeader head;
6428  while(is.read((char*)&head, sizeof(FileHeader))) {
6429  if (!head.isValid()) {
6430  fprintf(stderr, "nanovdb::readUncompressedGrids: invalid magic number = \"%s\"\n", (const char*)&(head.magic));
6431  exit(EXIT_FAILURE);
6432  } else if (!head.version.isCompatible()) {
6433  char str[20];
6434  fprintf(stderr, "nanovdb::readUncompressedGrids: invalid major version = \"%s\"\n", toStr(str, head.version));
6435  exit(EXIT_FAILURE);
6436  } else if (head.codec != Codec::NONE) {
6437  char str[8];
6438  fprintf(stderr, "nanovdb::readUncompressedGrids: invalid codec = \"%s\"\n", toStr(str, head.codec));
6439  exit(EXIT_FAILURE);
6440  }
6441  FileMetaData meta;
6442  for (uint16_t i = 0; i < head.gridCount; ++i) { // read all grids in segment
6443  is.read((char*)&meta, sizeof(FileMetaData));// read meta data
6444  is.skip(meta.nameSize); // skip grid name
6445  auto buffer = GridHandleT::BufferType::create(meta.gridSize, &pool);
6446  is.read((char*)buffer.data(), meta.gridSize);// read grid
6447  handles.emplace_back(std::move(buffer));
6448  }// loop over grids in segment
6449  }// loop over segments
6450  }
6451  return handles;
6452 } // readUncompressedGrids
6453 
6454 /// @brief Read a multiple un-compressed NanoVDB grids from a file and return them as a vector.
6455 template<typename GridHandleT, template<typename...> class VecT>
6456 VecT<GridHandleT> readUncompressedGrids(const char* fileName, const typename GridHandleT::BufferType& buffer = typename GridHandleT::BufferType())
6457 {
6458 #ifdef NANOVDB_USE_IOSTREAMS // use this to switch between std::ifstream or FILE implementations
6459  struct StreamT : public std::ifstream {
6460  StreamT(const char* name) : std::ifstream(name, std::ios::in | std::ios::binary){}
6461  void skip(int64_t off) { this->seekg(off, std::ios_base::cur); }
6462  };
6463 #else
6464  struct StreamT {
6465  FILE* fptr;
6466  StreamT(const char* name) { fptr = fopen(name, "rb"); }
6467  ~StreamT() { fclose(fptr); }
6468  bool read(char* data, size_t n) {
6469  size_t m = fread(data, 1, n, fptr);
6470  return n == m;
6471  }
6472  void skip(int64_t off) { fseek(fptr, (long int)off, SEEK_CUR); }
6473  bool is_open() const { return fptr != NULL; }
6474  };
6475 #endif
6476  StreamT is(fileName);
6477  if (!is.is_open()) {
6478  fprintf(stderr, "nanovdb::readUncompressedGrids: Unable to open file \"%s\"for input\n", fileName);
6479  exit(EXIT_FAILURE);
6480  }
6481  return readUncompressedGrids<GridHandleT, StreamT, VecT>(is, buffer);
6482 } // readUncompressedGrids
6483 
6484 #endif // if !defined(__CUDA_ARCH__) && !defined(__HIP__)
6485 
6486 } // namespace io
6487 
6488 // ----------------------------> Implementations of random access methods <--------------------------------------
6489 
6490 /// @brief Implements Tree::getValue(math::Coord), i.e. return the value associated with a specific coordinate @c ijk.
6491 /// @tparam BuildT Build type of the grid being called
6492 /// @details The value at a coordinate maps to the background, a tile value or a leaf value.
6493 template<typename BuildT>
6494 struct GetValue
6495 {
6496  __hostdev__ static auto get(const NanoRoot<BuildT>& root) { return root.mBackground; }
6497  __hostdev__ static auto get(const typename NanoRoot<BuildT>::Tile& tile) { return tile.value; }
6498  __hostdev__ static auto get(const NanoUpper<BuildT>& node, uint32_t n) { return node.mTable[n].value; }
6499  __hostdev__ static auto get(const NanoLower<BuildT>& node, uint32_t n) { return node.mTable[n].value; }
6500  __hostdev__ static auto get(const NanoLeaf<BuildT>& leaf, uint32_t n) { return leaf.getValue(n); } // works with all build types
6501 }; // GetValue<BuildT>
6502 
6503 template<typename BuildT>
6504 struct SetValue
6505 {
6506  static_assert(!BuildTraits<BuildT>::is_special, "SetValue does not support special value types");
6507  using ValueT = typename NanoLeaf<BuildT>::ValueType;
6508  __hostdev__ static auto set(NanoRoot<BuildT>&, const ValueT&) {} // no-op
6509  __hostdev__ static auto set(typename NanoRoot<BuildT>::Tile& tile, const ValueT& v) { tile.value = v; }
6510  __hostdev__ static auto set(NanoUpper<BuildT>& node, uint32_t n, const ValueT& v) { node.mTable[n].value = v; }
6511  __hostdev__ static auto set(NanoLower<BuildT>& node, uint32_t n, const ValueT& v) { node.mTable[n].value = v; }
6512  __hostdev__ static auto set(NanoLeaf<BuildT>& leaf, uint32_t n, const ValueT& v) { leaf.mValues[n] = v; }
6513 }; // SetValue<BuildT>
6514 
6515 template<typename BuildT>
6516 struct SetVoxel
6517 {
6518  static_assert(!BuildTraits<BuildT>::is_special, "SetVoxel does not support special value types");
6519  using ValueT = typename NanoLeaf<BuildT>::ValueType;
6520  __hostdev__ static auto set(NanoRoot<BuildT>&, const ValueT&) {} // no-op
6521  __hostdev__ static auto set(typename NanoRoot<BuildT>::Tile&, const ValueT&) {} // no-op
6522  __hostdev__ static auto set(NanoUpper<BuildT>&, uint32_t, const ValueT&) {} // no-op
6523  __hostdev__ static auto set(NanoLower<BuildT>&, uint32_t, const ValueT&) {} // no-op
6524  __hostdev__ static auto set(NanoLeaf<BuildT>& leaf, uint32_t n, const ValueT& v) { leaf.mValues[n] = v; }
6525 }; // SetVoxel<BuildT>
6526 
6527 /// @brief Implements Tree::isActive(math::Coord)
6528 /// @tparam BuildT Build type of the grid being called
6529 template<typename BuildT>
6530 struct GetState
6531 {
6532  __hostdev__ static auto get(const NanoRoot<BuildT>&) { return false; }
6533  __hostdev__ static auto get(const typename NanoRoot<BuildT>::Tile& tile) { return tile.state > 0; }
6534  __hostdev__ static auto get(const NanoUpper<BuildT>& node, uint32_t n) { return node.mValueMask.isOn(n); }
6535  __hostdev__ static auto get(const NanoLower<BuildT>& node, uint32_t n) { return node.mValueMask.isOn(n); }
6536  __hostdev__ static auto get(const NanoLeaf<BuildT>& leaf, uint32_t n) { return leaf.mValueMask.isOn(n); }
6537 }; // GetState<BuildT>
6538 
6539 /// @brief Implements Tree::getDim(math::Coord)
6540 /// @tparam BuildT Build type of the grid being called
6541 template<typename BuildT>
6542 struct GetDim
6543 {
6544  __hostdev__ static uint32_t get(const NanoRoot<BuildT>&) { return 0u; } // background
6545  __hostdev__ static uint32_t get(const typename NanoRoot<BuildT>::Tile&) { return 4096u; }
6546  __hostdev__ static uint32_t get(const NanoUpper<BuildT>&, uint32_t) { return 128u; }
6547  __hostdev__ static uint32_t get(const NanoLower<BuildT>&, uint32_t) { return 8u; }
6548  __hostdev__ static uint32_t get(const NanoLeaf<BuildT>&, uint32_t) { return 1u; }
6549 }; // GetDim<BuildT>
6550 
6551 /// @brief Return the pointer to the leaf node that contains math::Coord. Implements Tree::probeLeaf(math::Coord)
6552 /// @tparam BuildT Build type of the grid being called
6553 template<typename BuildT>
6554 struct GetLeaf
6555 {
6556  __hostdev__ static const NanoLeaf<BuildT>* get(const NanoRoot<BuildT>&) { return nullptr; }
6557  __hostdev__ static const NanoLeaf<BuildT>* get(const typename NanoRoot<BuildT>::Tile&) { return nullptr; }
6558  __hostdev__ static const NanoLeaf<BuildT>* get(const NanoUpper<BuildT>&, uint32_t) { return nullptr; }
6559  __hostdev__ static const NanoLeaf<BuildT>* get(const NanoLower<BuildT>&, uint32_t) { return nullptr; }
6560  __hostdev__ static const NanoLeaf<BuildT>* get(const NanoLeaf<BuildT>& leaf, uint32_t) { return &leaf; }
6561 }; // GetLeaf<BuildT>
6562 
6563 /// @brief Return point to the lower internal node where math::Coord maps to one of its values, i.e. terminates
6564 /// @tparam BuildT Build type of the grid being called
6565 template<typename BuildT>
6566 struct GetLower
6567 {
6568  __hostdev__ static const NanoLower<BuildT>* get(const NanoRoot<BuildT>&) { return nullptr; }
6569  __hostdev__ static const NanoLower<BuildT>* get(const typename NanoRoot<BuildT>::Tile&) { return nullptr; }
6570  __hostdev__ static const NanoLower<BuildT>* get(const NanoUpper<BuildT>&, uint32_t) { return nullptr; }
6571  __hostdev__ static const NanoLower<BuildT>* get(const NanoLower<BuildT>& node, uint32_t) { return &node; }
6572  __hostdev__ static const NanoLower<BuildT>* get(const NanoLeaf<BuildT>&, uint32_t) { return nullptr; }
6573 }; // GetLower<BuildT>
6574 
6575 /// @brief Return point to the upper internal node where math::Coord maps to one of its values, i.e. terminates
6576 /// @tparam BuildT Build type of the grid being called
6577 template<typename BuildT>
6578 struct GetUpper
6579 {
6580  __hostdev__ static const NanoUpper<BuildT>* get(const NanoRoot<BuildT>&) { return nullptr; }
6581  __hostdev__ static const NanoUpper<BuildT>* get(const typename NanoRoot<BuildT>::Tile&) { return nullptr; }
6582  __hostdev__ static const NanoUpper<BuildT>* get(const NanoUpper<BuildT>& node, uint32_t) { return &node; }
6583  __hostdev__ static const NanoUpper<BuildT>* get(const NanoLower<BuildT>& node, uint32_t) { return nullptr; }
6584  __hostdev__ static const NanoUpper<BuildT>* get(const NanoLeaf<BuildT>&, uint32_t) { return nullptr; }
6585 }; // GetUpper<BuildT>
6586 
6587 /// @brief Implements Tree::probeLeaf(math::Coord)
6588 /// @tparam BuildT Build type of the grid being called
6589 template<typename BuildT>
6590 struct ProbeValue
6591 {
6592  using ValueT = typename BuildToValueMap<BuildT>::Type;
6593  __hostdev__ static bool get(const NanoRoot<BuildT>& root, ValueT& v)
6594  {
6595  v = root.mBackground;
6596  return false;
6597  }
6598  __hostdev__ static bool get(const typename NanoRoot<BuildT>::Tile& tile, ValueT& v)
6599  {
6600  v = tile.value;
6601  return tile.state > 0u;
6602  }
6603  __hostdev__ static bool get(const NanoUpper<BuildT>& node, uint32_t n, ValueT& v)
6604  {
6605  v = node.mTable[n].value;
6606  return node.mValueMask.isOn(n);
6607  }
6608  __hostdev__ static bool get(const NanoLower<BuildT>& node, uint32_t n, ValueT& v)
6609  {
6610  v = node.mTable[n].value;
6611  return node.mValueMask.isOn(n);
6612  }
6613  __hostdev__ static bool get(const NanoLeaf<BuildT>& leaf, uint32_t n, ValueT& v)
6614  {
6615  v = leaf.getValue(n);
6616  return leaf.mValueMask.isOn(n);
6617  }
6618 }; // ProbeValue<BuildT>
6619 
6620 /// @brief Implements Tree::getNodeInfo(math::Coord)
6621 /// @tparam BuildT Build type of the grid being called
6622 template<typename BuildT>
6623 struct GetNodeInfo
6624 {
6627  struct NodeInfo
6628  {
6629  uint32_t level, dim;
6630  ValueType minimum, maximum;
6631  FloatType average, stdDevi;
6632  CoordBBox bbox;
6633  };
6634  __hostdev__ static NodeInfo get(const NanoRoot<BuildT>& root)
6635  {
6636  return NodeInfo{3u, NanoUpper<BuildT>::DIM, root.minimum(), root.maximum(), root.average(), root.stdDeviation(), root.bbox()};
6637  }
6638  __hostdev__ static NodeInfo get(const typename NanoRoot<BuildT>::Tile& tile)
6639  {
6640  return NodeInfo{3u, NanoUpper<BuildT>::DIM, tile.value, tile.value, static_cast<FloatType>(tile.value), 0, CoordBBox::createCube(tile.origin(), NanoUpper<BuildT>::DIM)};
6641  }
6642  __hostdev__ static NodeInfo get(const NanoUpper<BuildT>& node, uint32_t n)
6643  {
6644  return NodeInfo{2u, node.dim(), node.minimum(), node.maximum(), node.average(), node.stdDeviation(), node.bbox()};
6645  }
6646  __hostdev__ static NodeInfo get(const NanoLower<BuildT>& node, uint32_t n)
6647  {
6648  return NodeInfo{1u, node.dim(), node.minimum(), node.maximum(), node.average(), node.stdDeviation(), node.bbox()};
6649  }
6650  __hostdev__ static NodeInfo get(const NanoLeaf<BuildT>& leaf, uint32_t n)
6651  {
6652  return NodeInfo{0u, leaf.dim(), leaf.minimum(), leaf.maximum(), leaf.average(), leaf.stdDeviation(), leaf.bbox()};
6653  }
6654 }; // GetNodeInfo<BuildT>
6655 
6656 } // namespace nanovdb ===================================================================
6657 
6658 #endif // end of NANOVDB_NANOVDB_H_HAS_BEEN_INCLUDED
typename FloatTraits< BuildT >::FloatType FloatType
Definition: NanoVDB.h:3779
__hostdev__ ValueType getMin() const
Definition: NanoVDB.h:3814
__hostdev__ ValueOffIterator beginValueOff() const
Definition: NanoVDB.h:4445
__hostdev__ DenseIter()
Definition: NanoVDB.h:2874
__hostdev__ const GridType & gridType() const
Definition: NanoVDB.h:2174
__hostdev__ bool probeValue(const math::Coord &ijk, typename util::remove_const< ChannelT >::type &v) const
return the state and updates the value of the specified voxel
Definition: NanoVDB.h:6215
static __hostdev__ constexpr uint32_t padding()
Definition: NanoVDB.h:3924
typename BuildT::RootType RootType
Definition: NanoVDB.h:2049
__hostdev__ const Vec3d & voxelSize() const
Return a const reference to the size of a voxel in world units.
Definition: NanoVDB.h:2109
__hostdev__ ValueType getValue(const CoordType &ijk) const
Definition: NanoVDB.h:5704
__hostdev__ uint32_t operator*() const
Definition: NanoVDB.h:1082
ValueT ValueType
Definition: NanoVDB.h:5126
__hostdev__ uint64_t full() const
Definition: NanoVDB.h:1777
__hostdev__ const char * shortGridName() const
Return a c-string with the name of this grid, truncated to 255 characters.
Definition: NanoVDB.h:2208
__hostdev__ util::enable_if<!util::is_same< MaskT, Mask >::value, Mask & >::type operator=(const MaskT &other)
Assignment operator that works with openvdb::util::NodeMask.
Definition: NanoVDB.h:1179
__hostdev__ const ValueType & minimum() const
Return a const reference to the minimum active value encoded in this root node and any of its child n...
Definition: NanoVDB.h:2947
bool type
Definition: NanoVDB.h:499
Visits all tile values in this node, i.e. both inactive and active tiles.
Definition: NanoVDB.h:3378
__hostdev__ math::BBox< CoordT > bbox() const
Return the bounding box in index space of active values in this leaf node.
Definition: NanoVDB.h:4558
__hostdev__ CoordT getCoord() const
Definition: NanoVDB.h:4472
uint16_t ArrayType
Definition: NanoVDB.h:4299
__hostdev__ void next()
Definition: NanoVDB.h:2709
__hostdev__ CheckMode toCheckMode(const Checksum &checksum)
Maps 64 bit checksum to CheckMode enum.
Definition: NanoVDB.h:1816
C++11 implementation of std::enable_if.
Definition: Util.h:335
FloatType mStdDevi
Definition: NanoVDB.h:3791
float type
Definition: NanoVDB.h:506
static __hostdev__ constexpr uint32_t padding()
Definition: NanoVDB.h:4020
__hostdev__ bool probeValue(const CoordType &ijk, ValueType &v) const
Definition: NanoVDB.h:5713
__hostdev__ CoordT offsetToGlobalCoord(uint32_t n) const
Definition: NanoVDB.h:4549
static __hostdev__ uint64_t memUsage()
Definition: NanoVDB.h:4144
__hostdev__ bool isEmpty() const
Definition: NanoVDB.h:6003
__hostdev__ bool isActive(const CoordType &ijk) const
Definition: NanoVDB.h:5030
Type Pow2(Type x)
Return x2.
Definition: Math.h:548
__hostdev__ const MaskType< LOG2DIM > & getValueMask() const
Definition: NanoVDB.h:4514
__hostdev__ bool isPointData() const
Definition: NanoVDB.h:5980
typename util::match_const< DataType, RootT >::type DataT
Definition: NanoVDB.h:2695
void writeUncompressedGrids(const char *fileName, const VecT< GridHandleT > &handles, bool raw=false)
write multiple NanoVDB grids to a single file, without compression.
Definition: NanoVDB.h:6381
typename RootType::LeafNodeType LeafNodeType
Definition: NanoVDB.h:2354
__hostdev__ ValueType getValue(int i, int j, int k) const
Definition: NanoVDB.h:2973
Definition: NanoVDB.h:6311
__hostdev__ Vec3d getVoxelSize() const
Return a voxels size in each coordinate direction, measured at the origin.
Definition: NanoVDB.h:1518
__hostdev__ ReadAccessor(const GridT &grid)
Constructor from a grid.
Definition: NanoVDB.h:5000
StatsT mStdDevi
Definition: NanoVDB.h:3226
__hostdev__ bool hasStdDeviation() const
Definition: NanoVDB.h:2188
__hostdev__ void setBlindData(void *blindData)
Definition: NanoVDB.h:1574
__hostdev__ const Vec3dBBox & worldBBox() const
Definition: NanoVDB.h:5994
__hostdev__ Vec3T applyMap(const Vec3T &xyz) const
Definition: NanoVDB.h:1924
NANOVDB_HOSTDEV_DISABLE_WARNING __hostdev__ uint32_t findFirst() const
Definition: NanoVDB.h:1340
__hostdev__ TileT * tile() const
Definition: NanoVDB.h:2710
__hostdev__ bool isOff(uint32_t n) const
Return true if the given bit is NOT set.
Definition: NanoVDB.h:1208
__hostdev__ Vec3T applyMapF(const Vec3T &xyz) const
Definition: NanoVDB.h:1935
__hostdev__ const char * gridName() const
Definition: NanoVDB.h:1992
__hostdev__ ChannelT * setChannel(ChannelT *channelPtr)
Change to an external channel.
Definition: NanoVDB.h:6194
GridBlindDataClass mDataClass
Definition: NanoVDB.h:1563
typename util::match_const< Tile, RootT >::type TileT
Definition: NanoVDB.h:2696
__hostdev__ ChildT * getChild(uint32_t n)
Returns a pointer to the child node at the specifed linear offset.
Definition: NanoVDB.h:3254
__hostdev__ ValueType operator()(const CoordType &ijk) const
Definition: NanoVDB.h:5709
__hostdev__ Vec3T applyIJTF(const Vec3T &xyz) const
Definition: NanoVDB.h:1515
VDB Tree, which is a thin wrapper around a RootNode.
Definition: NanoVDB.h:2341
__hostdev__ Vec3T applyMapF(const Vec3T &ijk) const
Apply the forward affine transformation to a vector using 32bit floating point arithmetics.
Definition: NanoVDB.h:1446
decltype(mFlags) Type
Definition: NanoVDB.h:931
__hostdev__ Vec3T indexToWorld(const Vec3T &xyz) const
index to world space transformation
Definition: NanoVDB.h:2120
math::BBox< CoordType > BBoxType
Definition: NanoVDB.h:2684
__hostdev__ Tile * tile(uint32_t n)
Definition: NanoVDB.h:2598
__hostdev__ DenseIter operator++(int)
Definition: NanoVDB.h:2906
__hostdev__ bool isActive() const
Definition: NanoVDB.h:2796
__hostdev__ ValueType operator()(int i, int j, int k) const
Definition: NanoVDB.h:5710
__hostdev__ GridClass mapToGridClass(GridClass defaultClass=GridClass::Unknown)
Definition: NanoVDB.h:894
__hostdev__ bool isChild() const
Definition: NanoVDB.h:2580
__hostdev__ ValueType getValue(int i, int j, int k) const
Definition: NanoVDB.h:2386
__hostdev__ ValueIterator()
Definition: NanoVDB.h:4455
float Type
Definition: NanoVDB.h:526
float FloatType
Definition: NanoVDB.h:3849
__hostdev__ CoordT origin() const
Return the origin in index space of this leaf node.
Definition: NanoVDB.h:4534
Highest level of the data structure. Contains a tree and a world->index transform (that currently onl...
Definition: NanoVDB.h:2045
__hostdev__ ReadAccessor(const TreeT &tree)
Constructor from a tree.
Definition: NanoVDB.h:5006
__hostdev__ ValueOnIter(RootT *parent)
Definition: NanoVDB.h:2833
Vec3dBBox mWorldBBox
Definition: NanoVDB.h:1856
__hostdev__ CoordType getOrigin() const
Definition: NanoVDB.h:3363
__hostdev__ const NodeTrait< RootT, 1 >::type * getFirstLower() const
Definition: NanoVDB.h:2480
__hostdev__ Vec3T applyIJTF(const Vec3T &xyz) const
Definition: NanoVDB.h:1943
FloatType stdDevi
Definition: NanoVDB.h:6631
__hostdev__ char * toStr(char *dst, GridType gridType)
Maps a GridType to a c-string.
Definition: NanoVDB.h:253
__hostdev__ ValueType maximum() const
Return a const reference to the maximum active value encoded in this leaf node.
Definition: NanoVDB.h:4520
__hostdev__ DenseIterator(const InternalNode *parent)
Definition: NanoVDB.h:3462
static __hostdev__ uint64_t memUsage()
Definition: NanoVDB.h:4273
__hostdev__ const DataType * data() const
Definition: NanoVDB.h:2931
__hostdev__ const MaskType< LOG2DIM > & valueMask() const
Return a const reference to the bit mask of active voxels in this internal node.
Definition: NanoVDB.h:3512
__hostdev__ const LeafT * probeLeaf(const CoordType &ijk) const
Definition: NanoVDB.h:5411
#define NANOVDB_PATCH_VERSION_NUMBER
Definition: NanoVDB.h:146
__hostdev__ void init(std::initializer_list< GridFlags > list={GridFlags::IsBreadthFirst}, uint64_t gridSize=0u, const Map &map=Map(), GridType gridType=GridType::Unknown, GridClass gridClass=GridClass::Unknown)
Definition: NanoVDB.h:1868
__hostdev__ ValueType operator()(const CoordType &ijk) const
Definition: NanoVDB.h:5180
static __hostdev__ constexpr uint64_t memUsage()
Definition: NanoVDB.h:3923
__hostdev__ bool getValue(uint32_t i) const
Definition: NanoVDB.h:4151
__hostdev__ void setValueOnly(uint32_t offset, const ValueType &v)
Sets the value at the specified location but leaves its state unchanged.
Definition: NanoVDB.h:4604
__hostdev__ Vec3T applyInverseMap(const Vec3T &xyz) const
Apply the inverse affine mapping to a vector using 64bit floating point arithmetics.
Definition: NanoVDB.h:1472
__hostdev__ ValueOnIter()
Definition: NanoVDB.h:2829
Class to access values in channels at a specific voxel location.
Definition: NanoVDB.h:6142
__hostdev__ void setMask(uint32_t offset, bool v)
Definition: NanoVDB.h:4286
__hostdev__ void setOn(uint32_t offset)
Definition: NanoVDB.h:3812
static __hostdev__ uint32_t padding()
Definition: NanoVDB.h:4574
typename GridT::TreeType Type
Definition: NanoVDB.h:2327
__hostdev__ NodeT * operator->() const
Definition: NanoVDB.h:2747
__hostdev__ ValueType getValue(int i, int j, int k) const
Definition: NanoVDB.h:5708
char mGridName[MaxNameSize]
Definition: NanoVDB.h:1854
__hostdev__ bool operator>(const Version &rhs) const
Definition: NanoVDB.h:703
static __hostdev__ size_t memUsage(uint32_t bitWidth)
Definition: NanoVDB.h:4028
__hostdev__ void setChild(const CoordType &k, const void *ptr, const RootData *data)
Definition: NanoVDB.h:2566
__hostdev__ Version version() const
Definition: NanoVDB.h:2067
PointAccessor(const NanoGrid< Point > &grid)
Definition: NanoVDB.h:6081
__hostdev__ const ValueT & getMax() const
Definition: NanoVDB.h:2649
__hostdev__ ValueType getValue(uint32_t i) const
Definition: NanoVDB.h:3805
__hostdev__ Map(double s, const Vec3d &t=Vec3d(0.0, 0.0, 0.0))
Definition: NanoVDB.h:1406
__hostdev__ ChildNodeType * probeChild(const CoordType &ijk)
Definition: NanoVDB.h:3590
typename ChildT::CoordType CoordType
Definition: NanoVDB.h:3317
__hostdev__ void setLongGridNameOn(bool on=true)
Definition: NanoVDB.h:1913
__hostdev__ Mask(const Mask &other)
Copy constructor.
Definition: NanoVDB.h:1152
static __hostdev__ uint32_t CoordToOffset(const CoordT &ijk)
Return the linear offset corresponding to the given coordinate.
Definition: NanoVDB.h:4632
__hostdev__ uint64_t lastOffset() const
Definition: NanoVDB.h:4248
MaskT< LOG2DIM > mMask
Definition: NanoVDB.h:4272
__hostdev__ const BlindDataT * getBlindData(uint32_t n) const
Definition: NanoVDB.h:2238
#define NANOVDB_MAGIC_NUMB
Definition: NanoVDB.h:134
__hostdev__ void setWord(WordT w, uint32_t n)
Definition: NanoVDB.h:1170
GridClass
Classes (superset of OpenVDB) that are currently supported by NanoVDB.
Definition: NanoVDB.h:290
typename DataType::ValueT ValueType
Definition: NanoVDB.h:2679
uint64_t magic
Definition: NanoVDB.h:6287
__hostdev__ bool isPartial() const
return true if the 64 bit checksum is partial, i.e. of head only
Definition: NanoVDB.h:1786
static T scalar(const T &s)
Definition: NanoVDB.h:738
typename RootT::BuildType BuildType
Definition: NanoVDB.h:2356
__hostdev__ void setDev(const FloatType &)
Definition: NanoVDB.h:4161
Definition: NanoVDB.h:2775
__hostdev__ void * treePtr()
Definition: NanoVDB.h:1946
uint32_t state
Definition: NanoVDB.h:2586
BuildT BuildType
Definition: NanoVDB.h:3778
__hostdev__ void setDev(const FloatType &v)
Definition: NanoVDB.h:3822
typename UpperNodeType::ChildNodeType LowerNodeType
Definition: NanoVDB.h:2353
Return the pointer to the leaf node that contains math::Coord. Implements Tree::probeLeaf(math::Coord...
Definition: NanoVDB.h:1705
__hostdev__ bool getDev() const
Definition: NanoVDB.h:4155
#define NANOVDB_MAGIC_FRAG
Definition: NanoVDB.h:138
__hostdev__ bool isValid(GridType gridType, GridClass gridClass)
return true if the combination of GridType and GridClass is valid.
Definition: NanoVDB.h:613
static __hostdev__ bool isAligned(const void *p)
return true if the specified pointer is 32 byte aligned
Definition: NanoVDB.h:547
__hostdev__ void * getRoot()
Get a non-const void pointer to the root node (never NULL)
Definition: NanoVDB.h:2303
__hostdev__ const CoordBBox & indexBBox() const
Definition: NanoVDB.h:5995
__hostdev__ ChildIterator beginChild()
Definition: NanoVDB.h:3374
uint8_t mFlags
Definition: NanoVDB.h:3785
__hostdev__ LeafNodeType * getFirstLeaf()
Template specializations of getFirstNode.
Definition: NanoVDB.h:2477
uint64_t mOffset
Definition: NanoVDB.h:4307
__hostdev__ void setOrigin(const T &ijk)
Definition: NanoVDB.h:3825
__hostdev__ ValueIter(RootT *parent)
Definition: NanoVDB.h:2784
static int64_t PtrDiff(const void *p, const void *q)
Compute the distance, in bytes, between two pointers, dist = p - q.
Definition: Util.h:464
__hostdev__ uint32_t gridIndex() const
Return index of this grid in the buffer.
Definition: NanoVDB.h:2080
__hostdev__ const RootT & root() const
Definition: NanoVDB.h:2380
__hostdev__ bool isEmpty() const
Return true if the root is empty, i.e. has not child nodes or constant tiles.
Definition: NanoVDB.h:2312
Definition: NanoVDB.h:2035
__hostdev__ const StatsT & stdDeviation() const
Definition: NanoVDB.h:2651
LeafNodeType Node0
Definition: NanoVDB.h:2363
__hostdev__ ValueType getValue(const CoordType &ijk) const
Return the value of the given voxel.
Definition: NanoVDB.h:2972
Checksum mChecksum
Definition: NanoVDB.h:1848
Return point to the upper internal node where math::Coord maps to one of its values, i.e. terminates.
Definition: NanoVDB.h:6578
__hostdev__ const GridClass & gridClass() const
Definition: NanoVDB.h:2175
__hostdev__ uint64_t leafPoints(const Coord &ijk, const AttT *&begin, const AttT *&end) const
Return the number of points in the leaf node containing the coordinate ijk. If this return value is l...
Definition: NanoVDB.h:6045
typename DataType::StatsT FloatType
Definition: NanoVDB.h:2680
__hostdev__ FloatType variance() const
Return the variance of all the active values encoded in this root node and any of its child nodes...
Definition: NanoVDB.h:2956
Implements Tree::getValue(math::Coord), i.e. return the value associated with a specific coordinate i...
Definition: NanoVDB.h:1695
BitFlags()
Definition: NanoVDB.h:932
__hostdev__ FloatType getAvg() const
Definition: NanoVDB.h:3816
__hostdev__ ChildIterator beginChild()
Definition: NanoVDB.h:2771
__hostdev__ bool isActive(const CoordT &ijk) const
Return true if the voxel value at the given coordinate is active.
Definition: NanoVDB.h:4608
__hostdev__ ConstDenseIterator cbeginDense() const
Definition: NanoVDB.h:2918
__hostdev__ uint64_t getValue(uint32_t i) const
Definition: NanoVDB.h:4253
ChildT ChildNodeType
Definition: NanoVDB.h:2673
#define NANOVDB_MAGIC_GRID
Definition: NanoVDB.h:135
__hostdev__ void setAvg(const FloatType &)
Definition: NanoVDB.h:4160
__hostdev__ ValueOnIterator beginValueOn() const
Definition: NanoVDB.h:3447
__hostdev__ const MaskType< LOG2DIM > & valueMask() const
Return a const reference to the bit mask of active voxels in this leaf node.
Definition: NanoVDB.h:4513
void set(const MatT &mat, const MatT &invMat, const Vec3T &translate, double taper=1.0)
Initialize the member data from 3x3 or 4x4 matrices.
Definition: NanoVDB.h:1522
static __hostdev__ KeyT CoordToKey(const CoordType &ijk)
Definition: NanoVDB.h:2526
__hostdev__ void setAvg(float avg)
Definition: NanoVDB.h:3899
MaskT< LOG2DIM > ArrayType
Definition: NanoVDB.h:4085
T Type
Definition: NanoVDB.h:463
__hostdev__ bool isActive() const
Definition: NanoVDB.h:3406
uint64_t mMagic
Definition: NanoVDB.h:1847
__hostdev__ ChannelT * setChannel(uint32_t channelID)
Change to an internal channel, assuming it exists as as blind data in the IndexGrid.
Definition: NanoVDB.h:6200
__hostdev__ void setMax(const ValueType &)
Definition: NanoVDB.h:4159
__hostdev__ bool isOff() const
Return true if none of the bits are set in this Mask.
Definition: NanoVDB.h:1220
__hostdev__ bool isGridIndex() const
Definition: NanoVDB.h:5979
__hostdev__ uint32_t valueCount() const
Definition: NanoVDB.h:4244
uint64_t mGridSize
Definition: NanoVDB.h:1853
__hostdev__ NodeT * probeChild(ValueType &value) const
Definition: NanoVDB.h:2883
RootT Node3
Definition: NanoVDB.h:2360
PointType
Definition: NanoVDB.h:401
__hostdev__ void toggle(uint32_t n)
Definition: NanoVDB.h:1303
Trait to map from LEVEL to node type.
Definition: NanoVDB.h:4788
__hostdev__ void setDev(const FloatType &)
Definition: NanoVDB.h:4202
__hostdev__ void setMax(const ValueT &v)
Definition: NanoVDB.h:2654
__hostdev__ void setOn(uint32_t offset)
Definition: NanoVDB.h:4203
__hostdev__ bool isFogVolume() const
Definition: NanoVDB.h:2177
__hostdev__ ValueIter()
Definition: NanoVDB.h:2780
__hostdev__ const char * shortGridName() const
Definition: NanoVDB.h:5992
#define NANOVDB_MINOR_VERSION_NUMBER
Definition: NanoVDB.h:145
__hostdev__ ReadAccessor(const TreeT &tree)
Constructor from a tree.
Definition: NanoVDB.h:5148
__hostdev__ WordT getWord(uint32_t n) const
Definition: NanoVDB.h:1163
__hostdev__ FloatType variance() const
Return the variance of all the active values encoded in this leaf node.
Definition: NanoVDB.h:4526
uint64_t KeyT
Return a key based on the coordinates of a voxel.
Definition: NanoVDB.h:2524
Vec3d mVoxelSize
Definition: NanoVDB.h:1857
BuildT ValueType
Definition: NanoVDB.h:3777
uint64_t mFlags
Definition: NanoVDB.h:3219
__hostdev__ const uint32_t & getTableSize() const
Definition: NanoVDB.h:2944
int64_t mDataOffset
Definition: NanoVDB.h:1559
__hostdev__ ValueIterator()
Definition: NanoVDB.h:3384
__hostdev__ Checksum(uint32_t head, uint32_t tail)
Constructor that allows the two 32bit checksums to be initiated explicitly.
Definition: NanoVDB.h:1759
__hostdev__ uint32_t pos() const
Definition: NanoVDB.h:1111
__hostdev__ Mask()
Initialize all bits to zero.
Definition: NanoVDB.h:1139
__hostdev__ bool isCached2(const CoordType &ijk) const
Definition: NanoVDB.h:5392
__hostdev__ bool isActive(const CoordType &ijk) const
Definition: NanoVDB.h:3557
Implements Tree::getNodeInfo(math::Coord)
Definition: NanoVDB.h:1709
__hostdev__ uint64_t getMax() const
Definition: NanoVDB.h:4250
__hostdev__ void setStdDeviationOn(bool on=true)
Definition: NanoVDB.h:1915
uint64_t voxelCount
Definition: NanoVDB.h:6313
__hostdev__ uint32_t gridCount() const
Return total number of grids in the buffer.
Definition: NanoVDB.h:2083
__hostdev__ bool isRootConnected() const
return true if RootData follows TreeData in memory without any extra padding
Definition: NanoVDB.h:2030
__hostdev__ uint64_t voxelPoints(const Coord &ijk, const AttT *&begin, const AttT *&end) const
get iterators over attributes to points at a specific voxel location
Definition: NanoVDB.h:6057
__hostdev__ ValueType operator()(int i, int j, int k) const
Definition: NanoVDB.h:5028
__hostdev__ bool isValid() const
Methods related to the classification of this grid.
Definition: NanoVDB.h:2173
__hostdev__ void setValue(uint32_t n, const ValueT &v)
Definition: NanoVDB.h:3247
ValueType minimum
Definition: NanoVDB.h:6630
__hostdev__ AccessorType getAccessor() const
Definition: NanoVDB.h:2927
ChildT UpperNodeType
Definition: NanoVDB.h:2676
uint32_t mGridCount
Definition: NanoVDB.h:1852
CoordT mBBoxMin
Definition: NanoVDB.h:3783
__hostdev__ bool isLevelSet() const
Definition: NanoVDB.h:5975
__hostdev__ bool isActive() const
Definition: NanoVDB.h:4477
uint64_t FloatType
Definition: NanoVDB.h:781
__hostdev__ const void * nodePtr() const
Return a non-const void pointer to the first node at LEVEL.
Definition: NanoVDB.h:1954
__hostdev__ FloatType getDev() const
Definition: NanoVDB.h:3817
__hostdev__ FloatType stdDeviation() const
Return a const reference to the standard deviation of all the active values encoded in this leaf node...
Definition: NanoVDB.h:4529
Definition: NanoVDB.h:6627
__hostdev__ bool isValid() const
return true if the magic number and the version are both valid
Definition: NanoVDB.h:1898
typename GridOrTreeOrRootT::RootNodeType::ChildNodeType::ChildNodeType type
Definition: NanoVDB.h:1653
uint64_t FloatType
Definition: NanoVDB.h:775
__hostdev__ RootT & root()
Definition: NanoVDB.h:2378
float mQuantum
Definition: NanoVDB.h:3857
char * strcpy(char *dst, const char *src)
Copy characters from src to dst.
Definition: Util.h:166
double FloatType
Definition: NanoVDB.h:805
static const int MaxNameSize
Definition: NanoVDB.h:1558
__hostdev__ bool isIndex(GridType gridType)
Return true if the GridType maps to a special index type (not a POD integer type).
Definition: NanoVDB.h:602
Map mMap
Definition: NanoVDB.h:1855
#define NANOVDB_MAGIC_FILE
Definition: NanoVDB.h:136
__hostdev__ ValueType minimum() const
Return a const reference to the minimum active value encoded in this leaf node.
Definition: NanoVDB.h:4517
float type
Definition: NanoVDB.h:520
__hostdev__ const uint32_t & tileCount() const
Return the number of tiles encoded in this root node.
Definition: NanoVDB.h:2943
__hostdev__ Vec3T applyJacobian(const Vec3T &ijk) const
Apply the linear forward 3x3 transformation to an input 3d vector using 64bit floating point arithmet...
Definition: NanoVDB.h:1455
__hostdev__ bool hasBBox() const
Definition: NanoVDB.h:5984
Utility functions.
typename ChildT::LeafNodeType LeafNodeType
Definition: NanoVDB.h:2678
Bit-compacted representation of all three version numbers.
Definition: NanoVDB.h:678
__hostdev__ uint64_t lastOffset() const
Definition: NanoVDB.h:4227
__hostdev__ const GridType & gridType() const
Definition: NanoVDB.h:5973
__hostdev__ bool isPointIndex() const
Definition: NanoVDB.h:5978
__hostdev__ util::enable_if< BuildTraits< T >::is_index, const uint64_t & >::type valueCount() const
Return the total number of values indexed by this IndexGrid.
Definition: NanoVDB.h:2090
__hostdev__ ValueType getValue(const CoordType &ijk) const
Definition: NanoVDB.h:5022
__hostdev__ ChannelAccessor(const NanoGrid< IndexT > &grid, ChannelT *channelPtr)
Ctor from an IndexGrid and an external channel.
Definition: NanoVDB.h:6168
__hostdev__ bool operator>=(const Version &rhs) const
Definition: NanoVDB.h:704
typename DataType::ValueT ValueType
Definition: NanoVDB.h:3312
typename GridOrTreeOrRootT::LeafNodeType Type
Definition: NanoVDB.h:1637
static __hostdev__ uint32_t dim()
Return the dimension, in index space, of this leaf node (typically 8 as for openvdb leaf nodes!) ...
Definition: NanoVDB.h:4555
__hostdev__ ReadAccessor(const TreeT &tree)
Constructor from a tree.
Definition: NanoVDB.h:5634
Definition: NanoVDB.h:3207
static __hostdev__ uint32_t dim()
Return the dimension, in voxel units, of this internal node (typically 8*16 or 8*16*32) ...
Definition: NanoVDB.h:3506
__hostdev__ bool operator==(const Mask &other) const
Definition: NanoVDB.h:1193
__hostdev__ uint32_t gridIndex() const
Definition: NanoVDB.h:5990
__hostdev__ ChildIter & operator++()
Definition: NanoVDB.h:2752
__hostdev__ void setDev(const FloatType &)
Definition: NanoVDB.h:4342
__hostdev__ void setOn(uint32_t offset)
Definition: NanoVDB.h:4157
__hostdev__ const ChildT * probeChild(ValueType &value) const
Definition: NanoVDB.h:3468
__hostdev__ bool operator==(const Checksum &rhs) const
return true if the checksums are identical
Definition: NanoVDB.h:1806
__hostdev__ const NanoGrid< BuildT > & grid() const
Definition: NanoVDB.h:6031
char * strncpy(char *dst, const char *src, size_t max)
Copies the first num characters of src to dst. If the end of the source C string (which is signaled b...
Definition: Util.h:185
__hostdev__ DenseIterator beginAll() const
Definition: NanoVDB.h:1136
__hostdev__ ConstValueIterator cbeginValueAll() const
Definition: NanoVDB.h:2821
__hostdev__ bool isValid() const
return true if this meta data has a valid combination of semantic, class and value tags ...
Definition: NanoVDB.h:1591
__hostdev__ void disable()
Definition: NanoVDB.h:1795
__hostdev__ const NanoGrid< IndexT > & grid() const
Return a const reference to the IndexGrid.
Definition: NanoVDB.h:6181
static constexpr uint32_t SIZE
Definition: NanoVDB.h:1037
uint32_t mNodeCount[3]
Definition: NanoVDB.h:2291
ValueType mMaximum
Definition: NanoVDB.h:3789
typename GridOrTreeOrRootT::LeafNodeType type
Definition: NanoVDB.h:1638
MaskT< LOG2DIM > mValueMask
Definition: NanoVDB.h:4141
__hostdev__ uint64_t blindDataSize() const
return size in bytes of the blind data represented by this blind meta data
Definition: NanoVDB.h:1619
static __hostdev__ CoordT KeyToCoord(const KeyT &key)
Definition: NanoVDB.h:2534
__hostdev__ const Map & map() const
Return a const reference to the Map for this grid.
Definition: NanoVDB.h:2112
__hostdev__ ValueIterator cbeginValueAll() const
Definition: NanoVDB.h:4497
__hostdev__ void setRoot(const void *root)
Definition: NanoVDB.h:2297
static __hostdev__ uint32_t wordCount()
Return the number of machine words used by this Mask.
Definition: NanoVDB.h:1047
__hostdev__ bool hasLongGridName() const
Definition: NanoVDB.h:5985
__hostdev__ uint32_t operator*() const
Definition: NanoVDB.h:1110
__hostdev__ void setOrigin(const T &ijk)
Definition: NanoVDB.h:4115
typename DataType::BuildT BuildType
Definition: NanoVDB.h:2681
__hostdev__ void setMin(const bool &)
Definition: NanoVDB.h:4109
__hostdev__ bool isValid() const
Definition: NanoVDB.h:5972
__hostdev__ const StatsT & average() const
Definition: NanoVDB.h:2650
__hostdev__ void setMin(const ValueType &)
Definition: NanoVDB.h:4199
__hostdev__ uint32_t tail() const
Definition: NanoVDB.h:1781
__hostdev__ bool getAvg() const
Definition: NanoVDB.h:4101
__hostdev__ bool updateBBox()
Updates the local bounding box of active voxels in this node. Return true if bbox was updated...
Definition: NanoVDB.h:4735
__hostdev__ DenseIter & operator++()
Definition: NanoVDB.h:2900
__hostdev__ bool isBreadthFirst() const
Definition: NanoVDB.h:2189
__hostdev__ bool isPointData() const
Definition: NanoVDB.h:2181
__hostdev__ uint64_t last(uint32_t i) const
Definition: NanoVDB.h:4324
bool FloatType
Definition: NanoVDB.h:769
__hostdev__ const FloatType & average() const
Return a const reference to the average of all the active values encoded in this internal node and an...
Definition: NanoVDB.h:3529
__hostdev__ Iterator & operator++()
Definition: NanoVDB.h:1085
Definition: NanoVDB.h:755
#define __hostdev__
Definition: Util.h:73
__hostdev__ const Checksum & checksum() const
Definition: NanoVDB.h:6001
typename DataType::FloatType FloatType
Definition: NanoVDB.h:4373
#define NANOVDB_DATA_ALIGNMENT
Definition: NanoVDB.h:126
typename DataType::Tile Tile
Definition: NanoVDB.h:2686
__hostdev__ bool isValid(const GridBlindDataClass &blindClass, const GridBlindDataSemantic &blindSemantics, const GridType &blindType)
return true if the combination of GridBlindDataClass, GridBlindDataSemantic and GridType is valid...
Definition: NanoVDB.h:637
__hostdev__ bool isBreadthFirst() const
Definition: NanoVDB.h:5988
__hostdev__ DenseIterator operator++(int)
Definition: NanoVDB.h:1118
__hostdev__ uint64_t getValue(uint32_t i) const
Definition: NanoVDB.h:4233
__hostdev__ void setMax(const ValueT &v)
Definition: NanoVDB.h:3292
__hostdev__ bool isUnknown() const
Definition: NanoVDB.h:5982
Definition: NanoVDB.h:925
Coord CoordType
Definition: NanoVDB.h:4375
Dummy type for a 16bit quantization of float point values.
Definition: NanoVDB.h:197
uint8_t ArrayType
Definition: NanoVDB.h:3956
typename Mask< Log2Dim >::template Iterator< On > MaskIterT
Definition: NanoVDB.h:3322
__hostdev__ bool hasLongGridName() const
Definition: NanoVDB.h:2186
__hostdev__ TreeT & tree()
Return a non-const reference to the tree.
Definition: NanoVDB.h:2103
CoordT mBBoxMin
Definition: NanoVDB.h:4302
__hostdev__ void setFirstNode(const NodeT *node)
Definition: NanoVDB.h:2309
const typename GridOrTreeOrRootT::RootNodeType::ChildNodeType Type
Definition: NanoVDB.h:1673
__hostdev__ const ValueType & maximum() const
Return a const reference to the maximum active value encoded in this internal node and any of its chi...
Definition: NanoVDB.h:3526
__hostdev__ float getValue(uint32_t i) const
Definition: NanoVDB.h:3931
static __hostdev__ uint64_t memUsage()
Definition: NanoVDB.h:3238
__hostdev__ void setMin(float min)
Definition: NanoVDB.h:3893
__hostdev__ void setValue(uint32_t offset, bool)
Definition: NanoVDB.h:4156
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:110
__hostdev__ void setMax(const ValueType &v)
Definition: NanoVDB.h:3820
__hostdev__ void setOrigin(const T &ijk)
Definition: NanoVDB.h:4164
static __hostdev__ constexpr uint32_t padding()
Return padding of this class in bytes, due to aliasing and 32B alignment.
Definition: NanoVDB.h:3797
__hostdev__ uint32_t pos() const
Definition: NanoVDB.h:2708
__hostdev__ ChildIter()
Definition: NanoVDB.h:3342
__hostdev__ void setMin(const ValueType &)
Definition: NanoVDB.h:4339
__hostdev__ BlindDataT * getBlindData(uint32_t n)
Definition: NanoVDB.h:2245
__hostdev__ void setDev(const StatsT &v)
Definition: NanoVDB.h:3294
__hostdev__ ValueType getLastValue() const
If the last entry in this node&#39;s table is a tile, return the tile&#39;s value. Otherwise, return the result of calling getLastValue() on the child.
Definition: NanoVDB.h:3549
__hostdev__ void clear()
Reset this access to its initial state, i.e. with an empty cache.
Definition: NanoVDB.h:5342
__hostdev__ bool isOn(uint32_t n) const
Return true if the given bit is set.
Definition: NanoVDB.h:1205
__hostdev__ float getValue(uint32_t i) const
Definition: NanoVDB.h:4029
__hostdev__ Vec3T applyInverseJacobian(const Vec3T &xyz) const
Apply the linear inverse 3x3 transformation to an input 3d vector using 64bit floating point arithmet...
Definition: NanoVDB.h:1495
uint64_t ValueType
Definition: NanoVDB.h:4181
uint16_t ArrayType
Definition: NanoVDB.h:3986
__hostdev__ const MaskType< LOG2DIM > & childMask() const
Return a const reference to the bit mask of child nodes in this internal node.
Definition: NanoVDB.h:3516
__hostdev__ void setMax(const ValueType &)
Definition: NanoVDB.h:4200
__hostdev__ void setAvg(const FloatType &)
Definition: NanoVDB.h:4201
ValueT value
Definition: NanoVDB.h:2587
__hostdev__ void setDev(float dev)
Definition: NanoVDB.h:3902
Node caching at all (three) tree levels.
Definition: NanoVDB.h:5583
__hostdev__ void setDev(const StatsT &v)
Definition: NanoVDB.h:2656
__hostdev__ OnIterator beginOn() const
Definition: NanoVDB.h:1132
Definition: NanoVDB.h:1697
__hostdev__ void setAvg(const FloatType &)
Definition: NanoVDB.h:4341
__hostdev__ bool isActive(const CoordType &ijk) const
Definition: NanoVDB.h:5712
__hostdev__ void setOn(uint32_t offset)
Definition: NanoVDB.h:4332
typename GridOrTreeOrRootT::RootNodeType::ChildNodeType::ChildNodeType Type
Definition: NanoVDB.h:1652
__hostdev__ bool isMaskOn(uint32_t offset) const
Definition: NanoVDB.h:4285
BuildT BuildType
Definition: NanoVDB.h:5607
Stuct with all the member data of the LeafNode (useful during serialization of an openvdb LeafNode) ...
Definition: NanoVDB.h:3773
__hostdev__ const BBoxType & bbox() const
Return a const reference to the index bounding box of all the active values in this tree...
Definition: NanoVDB.h:2934
GridBlindDataSemantic
Blind-data Semantics that are currently understood by NanoVDB.
Definition: NanoVDB.h:424
Version mVersion
Definition: NanoVDB.h:1849
__hostdev__ void setAverageOn(bool on=true)
Definition: NanoVDB.h:1914
__hostdev__ bool isSequential() const
return true if nodes at all levels can safely be accessed with simple linear offsets ...
Definition: NanoVDB.h:2202
__hostdev__ Map()
Default constructor for the identity map.
Definition: NanoVDB.h:1395
GridFlags
Grid flags which indicate what extra information is present in the grid buffer.
Definition: NanoVDB.h:327
Metafunction used to determine if the first template parameter is a specialization of the class templ...
Definition: Util.h:451
static __hostdev__ constexpr uint8_t bitWidth()
Definition: NanoVDB.h:3997
__hostdev__ uint32_t & checksum(int i)
Definition: NanoVDB.h:1773
__hostdev__ DenseIterator()
Definition: NanoVDB.h:3457
uint32_t nameSize
Definition: NanoVDB.h:6319
ReadAccessor< ValueT, LEVEL0, LEVEL1, LEVEL2 > createAccessor(const NanoGrid< ValueT > &grid)
Free-standing function for convenient creation of a ReadAccessor with optional and customizable node ...
Definition: NanoVDB.h:5905
RootT RootType
Definition: NanoVDB.h:2350
static __hostdev__ constexpr uint32_t padding()
Return padding of this class in bytes, due to aliasing and 32B alignment.
Definition: NanoVDB.h:3867
Definition: GridHandle.h:27
float type
Definition: NanoVDB.h:513
__hostdev__ const uint32_t & activeTileCount(uint32_t level) const
Definition: NanoVDB.h:5999
CoordBBox bbox
Definition: NanoVDB.h:6632
float Type
Definition: NanoVDB.h:519
__hostdev__ bool probeValue(const CoordType &ijk, ValueType &v) const
Return true if this tree is empty, i.e. contains no values or nodes.
Definition: NanoVDB.h:2395
Visits all tile values and child nodes of this node.
Definition: NanoVDB.h:3451
GridType mGridType
Definition: NanoVDB.h:1859
static __hostdev__ uint64_t memUsage()
Definition: NanoVDB.h:4284
__hostdev__ uint64_t gridSize() const
Definition: NanoVDB.h:5989
__hostdev__ void clear()
Reset this access to its initial state, i.e. with an empty cache.
Definition: NanoVDB.h:5154
Definition: NanoVDB.h:1068
__hostdev__ bool probeValue(const CoordType &ijk, ValueType &v) const
return the state and updates the value of the specified voxel
Definition: NanoVDB.h:3559
GridType gridType
Definition: NanoVDB.h:6314
static __hostdev__ constexpr uint32_t padding()
Definition: NanoVDB.h:4191
Define static boolean tests for template build types.
Definition: NanoVDB.h:440
__hostdev__ bool isFull() const
return true if the 64 bit checksum is fill, i.e. of both had and nodes
Definition: NanoVDB.h:1790
__hostdev__ bool hasMinMax() const
Definition: NanoVDB.h:2184
__hostdev__ ConstChildIterator cbeginChild() const
Definition: NanoVDB.h:2772
char * sprint(char *dst, T var1, Types...var2)
prints a variable number of string and/or numbers to a destination string
Definition: Util.h:286
Bit-mask to encode active states and facilitate sequential iterators and a fast codec for I/O compres...
Definition: NanoVDB.h:1034
CoordT CoordType
Definition: NanoVDB.h:5127
__hostdev__ const GridBlindMetaData * blindMetaData(uint32_t n) const
Returns a const reference to the blindMetaData at the specified linear offset.
Definition: NanoVDB.h:1986
__hostdev__ ValueType getValue(const CoordType &ijk) const
Definition: NanoVDB.h:5175
__hostdev__ void setOrigin(const T &ijk)
Definition: NanoVDB.h:3280
static ElementType scalar(const T &v)
Definition: NanoVDB.h:749
__hostdev__ ValueIterator beginValue() const
Definition: NanoVDB.h:3413
__hostdev__ void setMax(float max)
Definition: NanoVDB.h:3896
static __hostdev__ constexpr uint8_t bitWidth()
Definition: NanoVDB.h:3930
__hostdev__ bool getMax() const
Definition: NanoVDB.h:4100
uint64_t mData2
Definition: NanoVDB.h:1864
typename ChildT::ValueType ValueT
Definition: NanoVDB.h:2516
float mMinimum
Definition: NanoVDB.h:3856
__hostdev__ uint64_t offset() const
Definition: NanoVDB.h:4321
static __hostdev__ Coord OffsetToLocalCoord(uint32_t n)
Definition: NanoVDB.h:3610
__hostdev__ const Vec3d & voxelSize() const
Return a vector of the axial voxel sizes.
Definition: NanoVDB.h:6187
__hostdev__ constexpr uint32_t strlen()
return the number of characters (including null termination) required to convert enum type to a strin...
Definition: NanoVDB.h:209
typename NanoLeaf< BuildT >::FloatType FloatType
Definition: NanoVDB.h:6626
Definition: NanoVDB.h:4177
KeyT key
Definition: NanoVDB.h:2584
uint64_t FloatType
Definition: NanoVDB.h:787
__hostdev__ uint64_t pointCount() const
Definition: NanoVDB.h:4322
typename DataType::StatsT FloatType
Definition: NanoVDB.h:3313
__hostdev__ ValueType getValue(int i, int j, int k) const
Definition: NanoVDB.h:5405
__hostdev__ uint32_t & tail()
Definition: NanoVDB.h:1782
bool ValueType
Definition: NanoVDB.h:4082
__hostdev__ Tile * probeTile(const CoordT &ijk)
Definition: NanoVDB.h:2604
__hostdev__ uint64_t getAvg() const
Definition: NanoVDB.h:4231
__hostdev__ uint32_t getDim(const CoordType &ijk, const RayT &ray) const
Definition: NanoVDB.h:5072
__hostdev__ uint64_t checksum() const
return the 64 bit checksum of this instance
Definition: NanoVDB.h:1771
Dummy type for a voxel whose value equals an offset into an external value array of active values...
Definition: NanoVDB.h:176
__hostdev__ ValueOnIterator beginValueOn() const
Definition: NanoVDB.h:4412
Top-most node of the VDB tree structure.
Definition: NanoVDB.h:2669
int64_t child
Definition: NanoVDB.h:3210
#define NANOVDB_MAJOR_VERSION_NUMBER
Definition: NanoVDB.h:144
__hostdev__ Vec3T applyJacobianF(const Vec3T &ijk) const
Apply the linear forward 3x3 transformation to an input 3d vector using 32bit floating point arithmet...
Definition: NanoVDB.h:1464
uint8_t ArrayType
Definition: NanoVDB.h:3919
static __hostdev__ uint64_t memUsage()
Definition: NanoVDB.h:3801
Struct to derive node type from its level in a given grid, tree or root while preserving constness...
Definition: NanoVDB.h:1630
typename GridT::TreeType type
Definition: NanoVDB.h:2328
__hostdev__ Codec toCodec(const char *str)
Definition: NanoVDB.h:6274
Definition: NanoVDB.h:2724
uint32_t level
Definition: NanoVDB.h:6629
uint16_t padding
Definition: NanoVDB.h:6323
__hostdev__ float getValue(uint32_t i) const
Definition: NanoVDB.h:3967
uint32_t mTileCount[3]
Definition: NanoVDB.h:2292
typename RootT::ChildNodeType Node2
Definition: NanoVDB.h:2361
__hostdev__ CoordType getOrigin() const
Definition: NanoVDB.h:3439
__hostdev__ const ValueType & minimum() const
Return a const reference to the minimum active value encoded in this internal node and any of its chi...
Definition: NanoVDB.h:3523
ValueType mMinimum
Definition: NanoVDB.h:3788
__hostdev__ const void * blindData(uint32_t n) const
Returns a const pointer to the blindData at the specified linear offset.
Definition: NanoVDB.h:2230
__hostdev__ GridType toGridType()
Maps from a templated build type to a GridType enum.
Definition: NanoVDB.h:812
size_t strlen(const char *str)
length of a c-sting, excluding &#39;\0&#39;.
Definition: Util.h:153
static __hostdev__ uint32_t dim()
Definition: NanoVDB.h:4368
__hostdev__ bool isCached(const CoordType &ijk) const
Definition: NanoVDB.h:5695
uint64_t Type
Definition: NanoVDB.h:470
uint64_t type
Definition: NanoVDB.h:478
Definition: IndexIterator.h:43
__hostdev__ float getDev() const
return the quantized standard deviation of the active values in this node
Definition: NanoVDB.h:3890
__hostdev__ ValueType operator*() const
Definition: NanoVDB.h:3434
ValueT mMaximum
Definition: NanoVDB.h:3224
__hostdev__ uint64_t idx(int i, int j, int k) const
Definition: NanoVDB.h:6207
static __hostdev__ CoordT OffsetToLocalCoord(uint32_t n)
Compute the local coordinates from a linear offset.
Definition: NanoVDB.h:4539
__hostdev__ const math::BBox< CoordType > & bbox() const
Return a const reference to the bounding box in index space of active values in this internal node an...
Definition: NanoVDB.h:3538
__hostdev__ ValueType getValue(const CoordType &ijk) const
Return the value of the given voxel.
Definition: NanoVDB.h:3556
__hostdev__ const FloatType & stdDeviation() const
Return a const reference to the standard deviation of all the active values encoded in this root node...
Definition: NanoVDB.h:2959
__hostdev__ uint64_t getValue(uint32_t i) const
Definition: NanoVDB.h:4325
__hostdev__ bool operator<=(const Version &rhs) const
Definition: NanoVDB.h:702
__hostdev__ bool getValue(uint32_t i) const
Definition: NanoVDB.h:4098
T ElementType
Definition: NanoVDB.h:737
typename RootType::LeafNodeType LeafNodeType
Definition: NanoVDB.h:2053
float Type
Definition: NanoVDB.h:533
__hostdev__ uint32_t getDim(const CoordType &ijk, const RayT &ray) const
Definition: NanoVDB.h:5235
uint64_t Type
Definition: NanoVDB.h:477
__hostdev__ uint32_t getMinor() const
Definition: NanoVDB.h:707
Struct with all the member data of the RootNode (useful during serialization of an openvdb RootNode) ...
Definition: NanoVDB.h:2514
__hostdev__ CoordType getCoord() const
Definition: NanoVDB.h:3368
Data encoded at the head of each segment of a file or stream.
Definition: NanoVDB.h:6286
__hostdev__ ValueIterator operator++(int)
Definition: NanoVDB.h:4488
__hostdev__ int findBlindDataForSemantic(GridBlindDataSemantic semantic) const
Return the index of the first blind data with specified semantic if found, otherwise -1...
Definition: NanoVDB.h:2258
static __hostdev__ bool hasStats()
Definition: NanoVDB.h:3862
__hostdev__ ValueOffIterator(const LeafNode *parent)
Definition: NanoVDB.h:4427
openvdb::GridBase Grid
Definition: Utils.h:34
__hostdev__ Mask(bool on)
Definition: NanoVDB.h:1144
__hostdev__ void setOff(uint32_t n)
Set the specified bit off.
Definition: NanoVDB.h:1231
__hostdev__ const char * gridName() const
Return a c-string with the name of this grid.
Definition: NanoVDB.h:2205
__hostdev__ ValueType operator*() const
Definition: NanoVDB.h:4433
__hostdev__ bool isFogVolume() const
Definition: NanoVDB.h:5976
typename RootNodeType::ChildNodeType UpperNodeType
Definition: NanoVDB.h:2352
double FloatType
Definition: NanoVDB.h:763
Version version
Definition: NanoVDB.h:6324
__hostdev__ int blindDataCount() const
Definition: NanoVDB.h:5997
uint64_t type
Definition: NanoVDB.h:485
__hostdev__ ChildT * getChild(const Tile *tile)
Returns a const reference to the child node in the specified tile.
Definition: NanoVDB.h:2637
__hostdev__ const Checksum & checksum() const
Return checksum of the grid buffer.
Definition: NanoVDB.h:2211
Index64 memUsage(const TreeT &tree, bool threaded=true)
Return the total amount of memory in bytes occupied by this tree.
Definition: Count.h:493
__hostdev__ ReadAccessor(const GridT &grid)
Constructor from a grid.
Definition: NanoVDB.h:5330
GridClass mGridClass
Definition: NanoVDB.h:1858
__hostdev__ Version(uint32_t data)
Constructor from a raw uint32_t data representation.
Definition: NanoVDB.h:691
Dummy type for a voxel whose value equals an offset into an external value array. ...
Definition: NanoVDB.h:173
Maps one type (e.g. the build types above) to other (actual) types.
Definition: NanoVDB.h:461
__hostdev__ const DataType * data() const
Definition: NanoVDB.h:2373
__hostdev__ uint32_t nodeCount(uint32_t level) const
Definition: NanoVDB.h:6000
__hostdev__ ValueType getLastValue() const
Return the last value in this leaf node.
Definition: NanoVDB.h:4594
__hostdev__ void setOrigin(const T &ijk)
Definition: NanoVDB.h:3905
__hostdev__ bool probeValue(const CoordType &ijk, ValueType &v) const
Definition: NanoVDB.h:5184
__hostdev__ bool isHalf() const
Definition: NanoVDB.h:1787
__hostdev__ uint64_t getDev() const
Definition: NanoVDB.h:4232
static __hostdev__ uint64_t memUsage()
Definition: NanoVDB.h:4096
math::BBox< CoordT > mBBox
Definition: NanoVDB.h:2546
__hostdev__ ValueIterator(const LeafNode *parent)
Definition: NanoVDB.h:4460
__hostdev__ ReadAccessor(const RootT &root)
Constructor from a root node.
Definition: NanoVDB.h:4994
typename RootT::ValueType ValueType
Definition: NanoVDB.h:4976
__hostdev__ uint32_t id() const
Definition: NanoVDB.h:705
__hostdev__ size_t memUsage() const
Definition: NanoVDB.h:4027
__hostdev__ ValueType getMin() const
Definition: NanoVDB.h:4334
__hostdev__ const NodeT * getFirstNode() const
return a const pointer to the first node of the specified type
Definition: NanoVDB.h:2452
typename ChildT::CoordType CoordType
Definition: NanoVDB.h:2683
__hostdev__ uint32_t getPatch() const
Definition: NanoVDB.h:708
Definition: NanoVDB.h:2824
__hostdev__ DenseIter(RootT *parent)
Definition: NanoVDB.h:2878
__hostdev__ const FloatType & stdDeviation() const
Return a const reference to the standard deviation of all the active values encoded in this internal ...
Definition: NanoVDB.h:3535
__hostdev__ void setOn(uint32_t n)
Set the specified bit on.
Definition: NanoVDB.h:1229
__hostdev__ const uint64_t & firstOffset() const
Definition: NanoVDB.h:4198
__hostdev__ CoordT getCoord() const
Definition: NanoVDB.h:4405
__hostdev__ Vec3T applyInverseJacobianF(const Vec3T &xyz) const
Apply the linear inverse 3x3 transformation to an input 3d vector using 32bit floating point arithmet...
Definition: NanoVDB.h:1504
__hostdev__ bool isCompatible() const
Definition: NanoVDB.h:709
__hostdev__ ValueType getValue(int i, int j, int k) const
Definition: NanoVDB.h:5179
__hostdev__ ValueType getValue(const CoordType &ijk) const
Definition: NanoVDB.h:5401
static __hostdev__ constexpr uint8_t bitWidth()
Definition: NanoVDB.h:3966
__hostdev__ auto getNodeInfo(const CoordType &ijk) const
Definition: NanoVDB.h:5408
__hostdev__ const ValueType & background() const
Return a const reference to the background value.
Definition: NanoVDB.h:2398
const typename GridOrTreeOrRootT::LeafNodeType type
Definition: NanoVDB.h:1645
__hostdev__ int age() const
Returns the difference between major version of this instance and NANOVDB_MAJOR_VERSION_NUMBER.
Definition: NanoVDB.h:713
__hostdev__ bool isRootNext() const
return true if RootData is layout out immediately after TreeData in memory
Definition: NanoVDB.h:2318
__hostdev__ NodeT * getFirstNode()
return a pointer to the first node of the specified type
Definition: NanoVDB.h:2442
__hostdev__ const NodeTrait< RootT, 2 >::type * getFirstUpper() const
Definition: NanoVDB.h:2482
#define NANOVDB_MAGIC_NODE
Definition: NanoVDB.h:137
CheckMode
List of different modes for computing for a checksum.
Definition: NanoVDB.h:1714
__hostdev__ void setAvg(const FloatType &v)
Definition: NanoVDB.h:3821
__hostdev__ uint8_t bitWidth() const
Definition: NanoVDB.h:4026
__hostdev__ const FloatType & average() const
Return a const reference to the average of all the active values encoded in this root node and any of...
Definition: NanoVDB.h:2953
MatType scale(const Vec3< typename MatType::value_type > &s)
Return a matrix that scales by s.
Definition: Mat.h:615
__hostdev__ ValueIter operator++(int)
Definition: NanoVDB.h:2809
bool isValid() const
Definition: NanoVDB.h:6291
static __hostdev__ constexpr uint32_t padding()
Return padding of this class in bytes, due to aliasing and 32B alignment.
Definition: NanoVDB.h:3232
__hostdev__ ValueType operator*() const
Definition: NanoVDB.h:4467
uint16_t gridCount
Definition: NanoVDB.h:6289
__hostdev__ void extrema(ValueType &min, ValueType &max) const
Sets the extrema values of all the active values in this tree, i.e. in all nodes of the tree...
Definition: NanoVDB.h:2502
__hostdev__ uint32_t pos() const
Definition: NanoVDB.h:1083
__hostdev__ void setOn(uint32_t offset)
Definition: NanoVDB.h:3877
__hostdev__ T & getValue(const math::Coord &ijk, T *channelPtr) const
Return the value from a specified channel that maps to the specified coordinate.
Definition: NanoVDB.h:6226
typename Node2::ChildNodeType Node1
Definition: NanoVDB.h:2362
Dummy type for a 16 bit floating point values (placeholder for IEEE 754 Half)
Definition: NanoVDB.h:188
static __hostdev__ uint64_t memUsage()
return memory usage in bytes for the class
Definition: NanoVDB.h:2376
RootT RootNodeType
Definition: NanoVDB.h:2351
__hostdev__ Vec3T applyInverseMapF(const Vec3T &xyz) const
Definition: NanoVDB.h:1937
__hostdev__ uint64_t first(uint32_t i) const
Definition: NanoVDB.h:4323
__hostdev__ bool isMaskOn(uint32_t offset) const
Definition: NanoVDB.h:4274
__hostdev__ bool hasStdDeviation() const
Definition: NanoVDB.h:5987
__hostdev__ bool isGridIndex() const
Definition: NanoVDB.h:2180
__hostdev__ ReadAccessor(const TreeT &tree)
Constructor from a tree.
Definition: NanoVDB.h:5336
uint32_t countOn(uint64_t v)
Definition: Util.h:622
__hostdev__ ChannelAccessor(const NanoGrid< IndexT > &grid, uint32_t channelID=0u)
Ctor from an IndexGrid and an integer ID of an internal channel that is assumed to exist as blind dat...
Definition: NanoVDB.h:6157
__hostdev__ uint64_t gridPoints(const AttT *&begin, const AttT *&end) const
Return the total number of point in the grid and set the iterators to the complete range of points...
Definition: NanoVDB.h:6035
void ArrayType
Definition: NanoVDB.h:4183
__hostdev__ ChannelT & operator()(const math::Coord &ijk) const
Definition: NanoVDB.h:6211
__hostdev__ uint32_t countOn(uint32_t i) const
Return the number of lower set bits in mask up to but excluding the i&#39;th bit.
Definition: NanoVDB.h:1059
__hostdev__ ChildIter()
Definition: NanoVDB.h:2731
__hostdev__ bool hasStats() const
Definition: NanoVDB.h:4196
Definition: NanoVDB.h:1556
__hostdev__ uint64_t memUsage() const
Return the actual memory footprint of this root node.
Definition: NanoVDB.h:2965
int64_t child
Definition: NanoVDB.h:2585
__hostdev__ void fill(const ValueType &v)
Definition: NanoVDB.h:3827
__hostdev__ bool getAvg() const
Definition: NanoVDB.h:4154
BuildT ArrayType
Definition: NanoVDB.h:3780
uint32_t mBlindMetadataCount
Definition: NanoVDB.h:1861
__hostdev__ OffIterator beginOff() const
Definition: NanoVDB.h:1134
__hostdev__ DenseIterator beginDense()
Definition: NanoVDB.h:2917
BuildT BuildType
Definition: NanoVDB.h:5125
Version version
Definition: NanoVDB.h:6288
__hostdev__ bool getMin() const
Definition: NanoVDB.h:4099
__hostdev__ const DataType * data() const
Definition: NanoVDB.h:4510
__hostdev__ const LeafT * probeLeaf(const CoordType &ijk) const
Definition: NanoVDB.h:5032
__hostdev__ bool getMax() const
Definition: NanoVDB.h:4153
__hostdev__ ValueType operator*() const
Definition: NanoVDB.h:2840
bool BuildType
Definition: NanoVDB.h:4083
__hostdev__ CoordT origin() const
Definition: NanoVDB.h:2583
__hostdev__ bool operator<(const Version &rhs) const
Definition: NanoVDB.h:701
__hostdev__ bool isActive(const CoordType &ijk) const
Definition: NanoVDB.h:5409
__hostdev__ const Vec3dBBox & worldBBox() const
return AABB of active values in world space
Definition: NanoVDB.h:2012
__hostdev__ void setOn(uint32_t offset)
Definition: NanoVDB.h:4108
__hostdev__ uint8_t flags() const
Definition: NanoVDB.h:4531
__hostdev__ const ValueT & getMax() const
Definition: NanoVDB.h:3283
typename UpperNodeType::ChildNodeType LowerNodeType
Definition: NanoVDB.h:2052
__hostdev__ bool isEmpty() const
Return true if this RootNode is empty, i.e. contains no values or nodes.
Definition: NanoVDB.h:2968
VecT< GridHandleT > readUncompressedGrids(const char *fileName, const typename GridHandleT::BufferType &buffer=typename GridHandleT::BufferType())
Read a multiple un-compressed NanoVDB grids from a file and return them as a vector.
Definition: NanoVDB.h:6456
uint64_t Type
Definition: NanoVDB.h:540
CoordT mBBoxMin
Definition: NanoVDB.h:4186
__hostdev__ uint32_t checksum(int i) const
Definition: NanoVDB.h:1775
__hostdev__ bool operator!=(const Mask &other) const
Definition: NanoVDB.h:1202
CoordT CoordType
Definition: NanoVDB.h:5310
Dummy type for a variable bit quantization of floating point values.
Definition: NanoVDB.h:200
__hostdev__ Vec3T indexToWorldF(const Vec3T &xyz) const
index to world space transformation
Definition: NanoVDB.h:2143
__hostdev__ bool isStaggered() const
Definition: NanoVDB.h:5977
__hostdev__ bool hasAverage() const
Definition: NanoVDB.h:5986
__hostdev__ const MaskType< LOG2DIM > & getChildMask() const
Definition: NanoVDB.h:3517
StatsT mAverage
Definition: NanoVDB.h:2552
Visits all values in a leaf node, i.e. both active and inactive values.
Definition: NanoVDB.h:4449
__hostdev__ void setMin(const ValueT &v)
Definition: NanoVDB.h:3291
__hostdev__ bool hasAverage() const
Definition: NanoVDB.h:2187
__hostdev__ CoordType getCoord() const
Definition: NanoVDB.h:3405
__hostdev__ bool isActive() const
Definition: NanoVDB.h:2582
Visits active tile values of this node only.
Definition: NanoVDB.h:3417
__hostdev__ const NodeTrait< RootT, LEVEL >::type * getFirstNode() const
return a const pointer to the first node of the specified level
Definition: NanoVDB.h:2471
#define NANOVDB_HOSTDEV_DISABLE_WARNING
Definition: Util.h:94
__hostdev__ void setValueOnly(uint32_t offset, const ValueType &value)
Definition: NanoVDB.h:3806
Visits all inactive values in a leaf node.
Definition: NanoVDB.h:4416
__hostdev__ const TreeType & tree() const
Return a const reference to the tree of the IndexGrid.
Definition: NanoVDB.h:6184
Like ValueIndex but with a mutable mask.
Definition: NanoVDB.h:179
typename RootT::ValueType ValueType
Definition: NanoVDB.h:2355
static __hostdev__ uint64_t memUsage(uint32_t tableSize)
Return the expected memory footprint in bytes with the specified number of tiles. ...
Definition: NanoVDB.h:2962
Definition: NanoVDB.h:1699
__hostdev__ ValueIterator beginValue() const
Definition: NanoVDB.h:4496
static __hostdev__ bool hasStats()
Definition: NanoVDB.h:4145
GridMetaData(const NanoGrid< T > &grid)
Definition: NanoVDB.h:5937
float FloatType
Definition: NanoVDB.h:757
__hostdev__ CheckMode mode() const
return the mode of the 64 bit checksum
Definition: NanoVDB.h:1798
__hostdev__ bool isMask() const
Definition: NanoVDB.h:2182
__hostdev__ Vec3T applyJacobianF(const Vec3T &xyz) const
Definition: NanoVDB.h:1939
__hostdev__ auto getNodeInfo(const CoordType &ijk) const
Definition: NanoVDB.h:5182
__hostdev__ void setMax(const bool &)
Definition: NanoVDB.h:4110
typename RootNodeType::ChildNodeType UpperNodeType
Definition: NanoVDB.h:2051
typename ChildT::BuildType BuildT
Definition: NanoVDB.h:2517
typename BuildT::ValueType ValueType
Definition: NanoVDB.h:2055
__hostdev__ uint32_t nodeCount() const
Return number of nodes at LEVEL.
Definition: NanoVDB.h:1977
float ValueType
Definition: NanoVDB.h:3848
__hostdev__ Mask & operator&=(const Mask &other)
Bitwise intersection.
Definition: NanoVDB.h:1306
__hostdev__ uint32_t getDim(const CoordType &ijk, const RayT &ray) const
Definition: NanoVDB.h:5502
__hostdev__ const TreeT & tree() const
Return a const reference to the tree.
Definition: NanoVDB.h:2100
__hostdev__ bool safeCast() const
return true if the RootData follows right after the TreeData. If so, this implies that it&#39;s safe to c...
Definition: NanoVDB.h:5960
uint32_t findLowestOn(uint32_t v)
Returns the index of the lowest, i.e. least significant, on bit in the specified 32 bit word...
Definition: Util.h:502
__hostdev__ ChannelT & getValue(const math::Coord &ijk) const
Return the value from a cached channel that maps to the specified coordinate.
Definition: NanoVDB.h:6210
uint64_t mData1
Definition: NanoVDB.h:1863
BitFlags(Type mask)
Definition: NanoVDB.h:933
__hostdev__ ChildNodeType * probeChild(const CoordType &ijk)
Definition: NanoVDB.h:3030
__hostdev__ bool isValueOn() const
Definition: NanoVDB.h:3479
bool streq(const char *lhs, const char *rhs)
Test if two null-terminated byte strings are the same.
Definition: Util.h:268
__hostdev__ Vec3T worldToIndexDirF(const Vec3T &dir) const
transformation from world space direction to index space direction
Definition: NanoVDB.h:2153
__hostdev__ Iterator()
Definition: NanoVDB.h:1071
typename ChildT::template MaskType< LOG2DIM > MaskT
Definition: NanoVDB.h:3204
__hostdev__ uint64_t getDev() const
Definition: NanoVDB.h:4252
BitFlags< 32 > mFlags
Definition: NanoVDB.h:1850
__hostdev__ Vec3T applyInverseJacobianF(const Vec3T &xyz) const
Definition: NanoVDB.h:1941
__hostdev__ ValueOnIter operator++(int)
Definition: NanoVDB.h:2853
uint8_t mFlags
Definition: NanoVDB.h:4304
__hostdev__ void setAvg(const bool &)
Definition: NanoVDB.h:4111
__hostdev__ void setMin(const ValueType &v)
Definition: NanoVDB.h:3819
__hostdev__ bool getMin() const
Definition: NanoVDB.h:4152
__hostdev__ bool isStaggered() const
Definition: NanoVDB.h:2178
__hostdev__ ConstChildIterator cbeginChild() const
Definition: NanoVDB.h:3375
void writeUncompressedGrid(StreamT &os, const GridData *gridData, bool raw=false)
This is a standalone alternative to io::writeGrid(...,Codec::NONE) defined in util/IO.h Unlike the latter this function has no dependencies at all, not even NanoVDB.h, so it also works if client code only includes PNanoVDB.h!
Definition: NanoVDB.h:6352
__hostdev__ bool isEmpty() const
test if the grid is empty, e.i the root table has size 0
Definition: NanoVDB.h:2026
__hostdev__ uint64_t gridPoints(const AttT *&begin, const AttT *&end) const
Return the total number of point in the grid and set the iterators to the complete range of points...
Definition: NanoVDB.h:6102
__hostdev__ NodeT * operator->() const
Definition: NanoVDB.h:3358
MaskT< LOG2DIM > mValueMask
Definition: NanoVDB.h:3854
#define __device__
Definition: Util.h:79
__hostdev__ Vec3T applyInverseMap(const Vec3T &xyz) const
Definition: NanoVDB.h:1926
int64_t mBlindMetadataOffset
Definition: NanoVDB.h:1860
float mTaperF
Definition: NanoVDB.h:1388
Implements Tree::probeLeaf(math::Coord)
Definition: NanoVDB.h:1707
__hostdev__ ChildIter(RootT *parent)
Definition: NanoVDB.h:2735
__hostdev__ void setValue(uint32_t offset, const ValueType &value)
Definition: NanoVDB.h:3807
__hostdev__ CoordBBox bbox() const
Return the index bounding box of all the active values in this tree, i.e. in all nodes of the tree...
Definition: NanoVDB.h:2315
MaskT< LOG2DIM > mValueMask
Definition: NanoVDB.h:4189
typename RootT::CoordType CoordType
Definition: NanoVDB.h:4977
__hostdev__ MagicType toMagic(uint64_t magic)
maps 64 bits of magic number to enum
Definition: NanoVDB.h:368
__hostdev__ const DataType * data() const
Definition: NanoVDB.h:3503
GridClass gridClass
Definition: NanoVDB.h:6315
__hostdev__ bool isLevelSet() const
Definition: NanoVDB.h:2176
Codec codec
Definition: NanoVDB.h:6290
RootType RootNodeType
Definition: NanoVDB.h:2050
__hostdev__ void clear()
Reset this access to its initial state, i.e. with an empty cache.
Definition: NanoVDB.h:5666
static __hostdev__ uint64_t memUsage()
Return memory usage in bytes for this class only.
Definition: NanoVDB.h:2009
uint64_t gridSize
Definition: NanoVDB.h:6313
__hostdev__ void setValueOnly(const CoordT &ijk, const ValueType &v)
Definition: NanoVDB.h:4605
__hostdev__ const NodeT * getNode() const
Return a const point to the cached node of the specified type.
Definition: NanoVDB.h:5650
static __hostdev__ constexpr uint32_t padding()
Definition: NanoVDB.h:3991
__hostdev__ bool isFloatingPoint(GridType gridType)
return true if the GridType maps to a floating point type
Definition: NanoVDB.h:563
CoordT mBBoxMin
Definition: NanoVDB.h:4088
__hostdev__ void setOff()
Set all bits off.
Definition: NanoVDB.h:1286
__hostdev__ void localToGlobalCoord(Coord &ijk) const
modifies local coordinates to global coordinates of a tile or child node
Definition: NanoVDB.h:3618
__hostdev__ void setAvg(const StatsT &v)
Definition: NanoVDB.h:2655
__hostdev__ CoordType getOrigin() const
Definition: NanoVDB.h:3400
__hostdev__ const LeafNodeType * probeLeaf(const CoordType &ijk) const
Definition: NanoVDB.h:3560
__hostdev__ bool probeValue(const CoordType &ijk, ValueType &v) const
return the state and updates the value of the specified voxel
Definition: NanoVDB.h:2976
__hostdev__ Vec3T indexToWorldGrad(const Vec3T &grad) const
transform the gradient from index space to world space.
Definition: NanoVDB.h:2135
__hostdev__ uint64_t activeVoxelCount() const
Computes a AABB of active values in world space.
Definition: NanoVDB.h:2170
__hostdev__ const LeafNode * probeLeaf(const CoordT &) const
Definition: NanoVDB.h:4629
__hostdev__ uint64_t * words()
Return a pointer to the list of words of the bit mask.
Definition: NanoVDB.h:1159
__hostdev__ void init(float min, float max, uint8_t bitWidth)
Definition: NanoVDB.h:3871
__hostdev__ bool probeValue(const CoordType &ijk, ValueType &v) const
Definition: NanoVDB.h:5031
__hostdev__ Version(uint32_t major, uint32_t minor, uint32_t patch)
Constructor from major.minor.patch version numbers.
Definition: NanoVDB.h:693
__hostdev__ Mask & operator|=(const Mask &other)
Bitwise union.
Definition: NanoVDB.h:1314
static __hostdev__ uint32_t voxelCount()
Return the total number of voxels (e.g. values) encoded in this leaf node.
Definition: NanoVDB.h:4572
typename ChildT::BuildType BuildT
Definition: NanoVDB.h:3201
__hostdev__ DataType * data()
Definition: NanoVDB.h:4508
__hostdev__ Mask & operator-=(const Mask &other)
Bitwise difference.
Definition: NanoVDB.h:1322
__hostdev__ Checksum(uint64_t checksum, CheckMode mode=CheckMode::Full)
Definition: NanoVDB.h:1764
static __hostdev__ bool safeCast(const NanoGrid< T > &grid)
return true if it is safe to cast the grid to a pointer of type GridMetaData, i.e. construction can be avoided.
Definition: NanoVDB.h:5971
__hostdev__ ValueIterator beginValue()
Definition: NanoVDB.h:2820
__hostdev__ const RootT & root() const
Definition: NanoVDB.h:5639
OutGridT const XformOp bool bool
Definition: ValueTransformer.h:609
uint64_t mPointCount
Definition: NanoVDB.h:4308
__hostdev__ auto getNodeInfo(const CoordType &ijk) const
Definition: NanoVDB.h:5029
static __hostdev__ uint64_t memUsage()
Definition: NanoVDB.h:4195
__hostdev__ CoordType origin() const
Return the origin in index space of this leaf node.
Definition: NanoVDB.h:3520
__hostdev__ DenseIterator(uint32_t pos=Mask::SIZE)
Definition: NanoVDB.h:1105
__hostdev__ CoordT getCoord() const
Definition: NanoVDB.h:4438
MaskT< LOG2DIM > mMask
Definition: NanoVDB.h:4283
PointAccessor(const NanoGrid< BuildT > &grid)
Definition: NanoVDB.h:6018
__hostdev__ Vec3T applyIJT(const Vec3T &xyz) const
Apply the transposed inverse 3x3 transformation to an input 3d vector using 64bit floating point arit...
Definition: NanoVDB.h:1513
__hostdev__ void setValueOnly(uint32_t offset, uint16_t value)
Definition: NanoVDB.h:4326
__hostdev__ uint64_t getIndex(const math::Coord &ijk) const
Return the linear offset into a channel that maps to the specified coordinate.
Definition: NanoVDB.h:6206
ValueT mMinimum
Definition: NanoVDB.h:3223
__hostdev__ bool setGridName(const char *src)
Definition: NanoVDB.h:1916
__hostdev__ void setMask(uint32_t offset, bool v)
Definition: NanoVDB.h:4275
MaskT< LOG2DIM > mValueMask
Definition: NanoVDB.h:4091
__hostdev__ void localToGlobalCoord(Coord &ijk) const
Converts (in place) a local index coordinate to a global index coordinate.
Definition: NanoVDB.h:4547
__hostdev__ ReadAccessor(const RootT &root)
Constructor from a root node.
Definition: NanoVDB.h:5616
__hostdev__ void setOrigin(const T &ijk)
Definition: NanoVDB.h:4345
uint64_t ValueType
Definition: NanoVDB.h:4296
Dummy type for a 8bit quantization of float point values.
Definition: NanoVDB.h:194
__hostdev__ DataType * data()
Definition: NanoVDB.h:2371
typename NanoLeaf< BuildT >::ValueType ValueType
Definition: NanoVDB.h:6625
MagicType
Enums used to identify magic numbers recognized by NanoVDB.
Definition: NanoVDB.h:357
__hostdev__ uint32_t getDim(const CoordType &ijk, const RayT &ray) const
Definition: NanoVDB.h:5851
__hostdev__ bool isValueOn() const
Definition: NanoVDB.h:2895
Dummy type for a voxel whose value equals its binary active state.
Definition: NanoVDB.h:185
uint8_t mFlags
Definition: NanoVDB.h:4188
uint64_t mPrefixSum
Definition: NanoVDB.h:4190
__hostdev__ CoordType getCoord() const
Definition: NanoVDB.h:2716
__hostdev__ Vec3T applyJacobian(const Vec3T &xyz) const
Definition: NanoVDB.h:1928
__hostdev__ util::enable_if< util::is_same< T, Point >::value, const uint64_t & >::type pointCount() const
Return the total number of points indexed by this PointGrid.
Definition: NanoVDB.h:2097
__hostdev__ const RootT & root() const
Definition: NanoVDB.h:5353
__hostdev__ ChildIter(ParentT *parent)
Definition: NanoVDB.h:3347
uint32_t mGridIndex
Definition: NanoVDB.h:1851
__hostdev__ ValueOnIterator(const LeafNode *parent)
Definition: NanoVDB.h:4394
__hostdev__ ValueType operator()(int i, int j, int k) const
Definition: NanoVDB.h:5407
uint64_t mVoxelCount
Definition: NanoVDB.h:2293
static __hostdev__ uint32_t CoordToOffset(const CoordType &ijk)
Return the linear offset corresponding to the given coordinate.
Definition: NanoVDB.h:3602
Vec3d voxelSize
Definition: NanoVDB.h:6318
__hostdev__ uint32_t nodeCount() const
Definition: NanoVDB.h:2421
__hostdev__ ValueType operator()(const CoordType &ijk) const
Definition: NanoVDB.h:5406
uint64_t type
Definition: NanoVDB.h:471
GridBlindDataSemantic mSemantic
Definition: NanoVDB.h:1562
__hostdev__ Vec3T applyMap(const Vec3T &ijk) const
Apply the forward affine transformation to a vector using 64bit floating point arithmetics.
Definition: NanoVDB.h:1438
CoordT CoordType
Definition: NanoVDB.h:5609
__hostdev__ CoordType getCoord() const
Definition: NanoVDB.h:3444
static __hostdev__ bool hasStats()
Definition: NanoVDB.h:3803
__hostdev__ const CoordBBox & indexBBox() const
return AABB of active values in index space
Definition: NanoVDB.h:2015
__hostdev__ bool isFloatingPointVector(GridType gridType)
return true if the GridType maps to a floating point vec3.
Definition: NanoVDB.h:577
ValueT mBackground
Definition: NanoVDB.h:2549
const typename GridOrTreeOrRootT::RootNodeType::ChildNodeType type
Definition: NanoVDB.h:1674
__hostdev__ ValueOnIterator()
Definition: NanoVDB.h:3423
__hostdev__ bool isInteger(GridType gridType)
Return true if the GridType maps to a POD integer type.
Definition: NanoVDB.h:589
__hostdev__ AccessorType getAccessor() const
Definition: NanoVDB.h:2382
__hostdev__ uint64_t leafPoints(const Coord &ijk, const AttT *&begin, const AttT *&end) const
Return the number of points in the leaf node containing the coordinate ijk. If this return value is l...
Definition: NanoVDB.h:6112
NANOVDB_HOSTDEV_DISABLE_WARNING __hostdev__ uint32_t findPrev(uint32_t start) const
Definition: NanoVDB.h:1364
__hostdev__ bool isActive(const CoordType &ijk) const
Definition: NanoVDB.h:2974
__hostdev__ ValueType operator*() const
Definition: NanoVDB.h:2791
math::Extrema extrema(const IterT &iter, bool threaded=true)
Iterate over a scalar grid and compute extrema (min/max) of the values of the voxels that are visited...
Definition: Statistics.h:354
__hostdev__ const RootT & root() const
Definition: NanoVDB.h:5160
const typename GridOrTreeOrRootT::RootNodeType::ChildNodeType::ChildNodeType type
Definition: NanoVDB.h:1660
Codec codec
Definition: NanoVDB.h:6322
Defines an affine transform and its inverse represented as a 3x3 matrix and a vec3 translation...
Definition: NanoVDB.h:1383
uint64_t FloatType
Definition: NanoVDB.h:4182
float Type
Definition: NanoVDB.h:512
__hostdev__ void clear()
Reset this access to its initial state, i.e. with an empty cache Noop since this template specializa...
Definition: NanoVDB.h:5013
__hostdev__ const Tile * probeTile(const CoordT &ijk) const
Definition: NanoVDB.h:2629
#define NANOVDB_ASSERT(x)
Definition: Util.h:50
typename GridOrTreeOrRootT::RootNodeType::ChildNodeType type
Definition: NanoVDB.h:1667
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:219
Vec3dBBox worldBBox
Definition: NanoVDB.h:6316
uint32_t mValueSize
Definition: NanoVDB.h:1561
typename BuildT::CoordType CoordType
Definition: NanoVDB.h:2057
__hostdev__ ValueOnIterator cbeginValueOn() const
Definition: NanoVDB.h:4413
__hostdev__ DenseIterator & operator++()
Definition: NanoVDB.h:1113
__hostdev__ void setOn()
Set all bits on.
Definition: NanoVDB.h:1280
__hostdev__ FloatType average() const
Return a const reference to the average of all the active values encoded in this leaf node...
Definition: NanoVDB.h:4523
Class to access points at a specific voxel location.
Definition: NanoVDB.h:6011
__hostdev__ Mask & operator^=(const Mask &other)
Bitwise XOR.
Definition: NanoVDB.h:1330
static __hostdev__ bool safeCast(const GridData *gridData)
return true if it is safe to cast the grid to a pointer of type GridMetaData, i.e. construction can be avoided.
Definition: NanoVDB.h:5964
ValueT mMaximum
Definition: NanoVDB.h:2551
static __hostdev__ uint64_t alignmentPadding(const void *p)
return the smallest number of bytes that when added to the specified pointer results in a 32 byte ali...
Definition: NanoVDB.h:550
__hostdev__ ReadAccessor(const RootT &root)
Constructor from a root node.
Definition: NanoVDB.h:5134
__hostdev__ Iterator operator++(int)
Definition: NanoVDB.h:1090
ValueT mMinimum
Definition: NanoVDB.h:2550
__hostdev__ ChildIter operator++(int)
Definition: NanoVDB.h:2760
bool FloatType
Definition: NanoVDB.h:799
__hostdev__ const uint32_t & activeTileCount(uint32_t level) const
Return the total number of active tiles at the specified level of the tree.
Definition: NanoVDB.h:2414
C++11 implementation of std::is_floating_point.
Definition: Util.h:329
__hostdev__ FloatType getDev() const
Definition: NanoVDB.h:4337
__hostdev__ ValueType operator*() const
Definition: NanoVDB.h:3395
__hostdev__ const RootT & root() const
Definition: NanoVDB.h:5015
uint64_t mValueCount
Definition: NanoVDB.h:1560
__hostdev__ DataType * data()
Definition: NanoVDB.h:3501
const typename GridOrTreeOrRootT::RootNodeType type
Definition: NanoVDB.h:1689
__hostdev__ const BlindDataT * getBlindData() const
Get a const pointer to the blind data represented by this meta data.
Definition: NanoVDB.h:1584
__hostdev__ void setAvg(const StatsT &v)
Definition: NanoVDB.h:3293
__hostdev__ ValueT getValue(uint32_t n) const
Definition: NanoVDB.h:3265
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:478
__hostdev__ void setValue(const CoordT &ijk, const ValueType &v)
Sets the value at the specified location and activate its state.
Definition: NanoVDB.h:4599
__hostdev__ ValueOnIter & operator++()
Definition: NanoVDB.h:2845
__hostdev__ float getAvg() const
return the quantized average of the active values in this node
Definition: NanoVDB.h:3886
Class that encapsulates two CRC32 checksums, one for the Grid, Tree and Root node meta data and one f...
Definition: NanoVDB.h:1740
__hostdev__ const LeafT * probeLeaf(const CoordType &ijk) const
Definition: NanoVDB.h:5714
__hostdev__ BaseIter(DataT *data=nullptr, uint32_t n=0)
Definition: NanoVDB.h:2699
__hostdev__ uint64_t activeVoxelCount() const
Return a const reference to the index bounding box of all the active values in this tree...
Definition: NanoVDB.h:2407
__hostdev__ ValueType operator()(const CoordType &ijk) const
Definition: NanoVDB.h:5027
__hostdev__ const GridClass & gridClass() const
Definition: NanoVDB.h:5974
__hostdev__ float getMax() const
return the quantized maximum of the active values in this node
Definition: NanoVDB.h:3883
typename ChildT::ValueType ValueT
Definition: NanoVDB.h:3200
__hostdev__ bool getDev() const
Definition: NanoVDB.h:4102
Implements Tree::getDim(math::Coord)
Definition: NanoVDB.h:1703
Definition: NanoVDB.h:2692
__hostdev__ const ValueType & background() const
Return the total number of active voxels in the root and all its child nodes.
Definition: NanoVDB.h:2940
__hostdev__ DenseIterator beginDense() const
Definition: NanoVDB.h:3492
Codec
Define compression codecs.
Definition: NanoVDB.h:6258
__hostdev__ Vec3T applyIJT(const Vec3T &xyz) const
Definition: NanoVDB.h:1932
__hostdev__ uint32_t countOn() const
Return the total number of set bits in this Mask.
Definition: NanoVDB.h:1050
uint8_t mFlags
Definition: NanoVDB.h:3853
__hostdev__ bool isChild(uint32_t n) const
Definition: NanoVDB.h:3277
Internal nodes of a VDB tree.
Definition: NanoVDB.h:3308
__hostdev__ ValueOnIterator()
Definition: NanoVDB.h:4389
__hostdev__ ValueType getMax() const
Definition: NanoVDB.h:4335
__hostdev__ ConstDenseIterator cbeginChildAll() const
Definition: NanoVDB.h:2919
static __hostdev__ T * alignPtr(T *p)
offset the specified pointer so it is 32 byte aligned. Works with both const and non-const pointers...
Definition: NanoVDB.h:558
__hostdev__ bool isOn() const
Return true if all the bits are set in this Mask.
Definition: NanoVDB.h:1211
ValueT ValueType
Definition: NanoVDB.h:5608
__hostdev__ ValueType getValue(int i, int j, int k) const
Definition: NanoVDB.h:5026
BuildT TreeType
Definition: NanoVDB.h:2048
Base-class for quantized float leaf nodes.
Definition: NanoVDB.h:3844
uint64_t FloatType
Definition: NanoVDB.h:793
math::BBox< CoordT > mBBox
Definition: NanoVDB.h:3218
__hostdev__ const LeafNodeType * probeLeaf(const CoordType &ijk) const
Definition: NanoVDB.h:2977
__hostdev__ void setMin(const ValueT &v)
Definition: NanoVDB.h:2653
__hostdev__ Vec3T worldToIndexF(const Vec3T &xyz) const
world to index space transformation
Definition: NanoVDB.h:2139
static __hostdev__ constexpr uint32_t padding()
Definition: NanoVDB.h:4095
const typename GridOrTreeOrRootT::RootNodeType::ChildNodeType::ChildNodeType Type
Definition: NanoVDB.h:1659
__hostdev__ uint64_t getMin() const
Definition: NanoVDB.h:4249
__hostdev__ CoordType getOrigin() const
Definition: NanoVDB.h:3484
__hostdev__ bool isCached(const CoordType &ijk) const
Definition: NanoVDB.h:5167
__hostdev__ Vec3T worldToIndex(const Vec3T &xyz) const
world to index space transformation
Definition: NanoVDB.h:2116
Definition: NanoVDB.h:2288
static __hostdev__ uint64_t memUsage()
Definition: NanoVDB.h:4319
C++11 implementation of std::is_same.
Definition: Util.h:314
__hostdev__ ReadAccessor(const GridT &grid)
Constructor from a grid.
Definition: NanoVDB.h:5628
static __hostdev__ uint64_t memUsage()
Definition: NanoVDB.h:3860
__hostdev__ void setValue(uint32_t offset, bool v)
Definition: NanoVDB.h:4103
__hostdev__ bool isActive() const
Return true if this node or any of its child nodes contain active values.
Definition: NanoVDB.h:3632
__hostdev__ ValueType getValue(const CoordType &ijk) const
Return the value of the given voxel (regardless of state or location in the tree.) ...
Definition: NanoVDB.h:2385
__hostdev__ uint64_t getMin() const
Definition: NanoVDB.h:4229
Struct with all the member data of the InternalNode (useful during serialization of an openvdb Intern...
Definition: NanoVDB.h:3198
static __hostdev__ constexpr int64_t memUsage()
Definition: NanoVDB.h:3959
__hostdev__ const ChildNodeType * probeChild(const CoordType &ijk) const
Definition: NanoVDB.h:3024
__hostdev__ const NanoGrid< Point > & grid() const
Definition: NanoVDB.h:6098
static __hostdev__ constexpr uint64_t memUsage()
Definition: NanoVDB.h:3990
const typename GridT::TreeType Type
Definition: NanoVDB.h:2333
Dummy type for a 4bit quantization of float point values.
Definition: NanoVDB.h:191
__hostdev__ bool operator!=(const Checksum &rhs) const
return true if the checksums are not identical
Definition: NanoVDB.h:1810
__hostdev__ uint64_t gridSize() const
Return memory usage in bytes for this class only.
Definition: NanoVDB.h:2077
__hostdev__ Version version() const
Definition: NanoVDB.h:6004
typename ChildT::CoordType CoordT
Definition: NanoVDB.h:3203
uint64_t mCRC64
Definition: NanoVDB.h:1746
__hostdev__ uint64_t & full()
Definition: NanoVDB.h:1778
__hostdev__ void setMin(const ValueType &)
Definition: NanoVDB.h:4158
Return point to the lower internal node where math::Coord maps to one of its values, i.e. terminates.
Definition: NanoVDB.h:6566
uint64_t type
Definition: NanoVDB.h:492
static __hostdev__ bool hasStats()
Definition: NanoVDB.h:4097
const typename GridT::TreeType type
Definition: NanoVDB.h:2334
__hostdev__ NodeTrait< RootT, 1 >::type * getFirstLower()
Definition: NanoVDB.h:2479
__hostdev__ ValueType operator()(int i, int j, int k) const
Definition: NanoVDB.h:5181
__hostdev__ FloatType variance() const
Return the variance of all the active values encoded in this internal node and any of its child nodes...
Definition: NanoVDB.h:3532
__hostdev__ const ValueT & getMin() const
Definition: NanoVDB.h:3282
__hostdev__ uint64_t voxelPoints(const Coord &ijk, const AttT *&begin, const AttT *&end) const
get iterators over attributes to points at a specific voxel location
Definition: NanoVDB.h:6123
uint8_t mFlags
Definition: NanoVDB.h:4090
T type
Definition: Util.h:387
__hostdev__ uint64_t getAvg() const
Definition: NanoVDB.h:4251
__hostdev__ void setBBoxOn(bool on=true)
Definition: NanoVDB.h:1912
__hostdev__ bool isUnknown() const
Definition: NanoVDB.h:2183
static __hostdev__ constexpr uint32_t padding()
Return padding of this class in bytes, due to aliasing and 32B alignment.
Definition: NanoVDB.h:2558
__hostdev__ uint32_t head() const
Definition: NanoVDB.h:1779
T type
Definition: NanoVDB.h:464
__hostdev__ ValueIterator & operator++()
Definition: NanoVDB.h:4483
__hostdev__ uint32_t blindDataCount() const
Return true if this grid is empty, i.e. contains no values or nodes.
Definition: NanoVDB.h:2217
__hostdev__ void setChild(uint32_t n, const void *ptr)
Definition: NanoVDB.h:3240
__hostdev__ Vec3T applyInverseJacobian(const Vec3T &xyz) const
Definition: NanoVDB.h:1930
__hostdev__ bool operator==(const Version &rhs) const
Definition: NanoVDB.h:700
Struct with all the member data of the Grid (useful during serialization of an openvdb grid) ...
Definition: NanoVDB.h:1844
typename ChildT::template MaskType< LOG2 > MaskType
Definition: NanoVDB.h:3320
auto callNanoGrid(GridDataT *gridData, ArgsT &&...args)
Below is an example of the struct used for generic programming with callNanoGrid. ...
Definition: NanoVDB.h:4889
Implements Tree::isActive(math::Coord)
Definition: NanoVDB.h:1701
__hostdev__ Vec3T applyInverseMapF(const Vec3T &xyz) const
Apply the inverse affine mapping to a vector using 32bit floating point arithmetics.
Definition: NanoVDB.h:1483
Definition: NanoVDB.h:728
__hostdev__ bool probeValue(const CoordT &ijk, ValueType &v) const
Return true if the voxel value at the given coordinate is active and updates v with the value...
Definition: NanoVDB.h:4622
__hostdev__ NodeTrait< RootT, 2 >::type * getFirstUpper()
Definition: NanoVDB.h:2481
__hostdev__ void toggle()
brief Toggle the state of all bits in the mask
Definition: NanoVDB.h:1298
__hostdev__ bool isPointIndex() const
Definition: NanoVDB.h:2179
__hostdev__ void setMax(const ValueType &)
Definition: NanoVDB.h:4340
uint32_t mData0
Definition: NanoVDB.h:1862
__hostdev__ ValueType operator*() const
Definition: NanoVDB.h:4400
Dummy type for indexing points into voxels.
Definition: NanoVDB.h:203
__hostdev__ const MaskType< LOG2DIM > & getValueMask() const
Definition: NanoVDB.h:3513
__hostdev__ const void * blindData() const
Definition: NanoVDB.h:1577
__hostdev__ ValueType getValue(const CoordT &ijk) const
Return the voxel value at the given coordinate.
Definition: NanoVDB.h:4589
static __hostdev__ size_t memUsage()
Return memory usage in bytes for the class.
Definition: NanoVDB.h:3509
__hostdev__ NodeT & operator*() const
Definition: NanoVDB.h:3353
typename ChildT::FloatType StatsT
Definition: NanoVDB.h:3202
Definition: NanoVDB.h:902
__hostdev__ bool isActive(const CoordType &ijk) const
Return the active state of the given voxel (regardless of state or location in the tree...
Definition: NanoVDB.h:2389
__hostdev__ const ChildT * getChild(uint32_t n) const
Definition: NanoVDB.h:3259
uint32_t findHighestOn(uint32_t v)
Returns the index of the highest, i.e. most significant, on bit in the specified 32 bit word...
Definition: Util.h:572
DataT * mData
Definition: NanoVDB.h:2697
__hostdev__ uint64_t activeVoxelCount() const
Definition: NanoVDB.h:5998
bool Type
Definition: NanoVDB.h:498
Definition: NanoVDB.h:1102
__hostdev__ ValueType getFirstValue() const
If the first entry in this node&#39;s table is a tile, return the tile&#39;s value. Otherwise, return the result of calling getFirstValue() on the child.
Definition: NanoVDB.h:3542
StatsT mAverage
Definition: NanoVDB.h:3225
__hostdev__ float getValue(uint32_t i) const
Definition: NanoVDB.h:3998
Definition: NanoVDB.h:2868
__hostdev__ const Map & map() const
Definition: NanoVDB.h:5993
__hostdev__ ValueIterator cbeginValueAll() const
Definition: NanoVDB.h:3414
CoordT mBBoxMin
Definition: NanoVDB.h:3851
__hostdev__ NodeT & operator*() const
Definition: NanoVDB.h:2742
typename ChildT::CoordType CoordT
Definition: NanoVDB.h:2518
__hostdev__ uint64_t getMax() const
Definition: NanoVDB.h:4230
__hostdev__ ValueType getValue(uint32_t offset) const
Return the voxel value at the given offset.
Definition: NanoVDB.h:4586
__hostdev__ ValueIter & operator++()
Definition: NanoVDB.h:2801
MaskT mValueMask
Definition: NanoVDB.h:3220
NANOVDB_HOSTDEV_DISABLE_WARNING __hostdev__ uint32_t findNext(uint32_t start) const
Definition: NanoVDB.h:1350
__hostdev__ CoordType getOrigin() const
Definition: NanoVDB.h:2711
__hostdev__ uint32_t totalNodeCount() const
Definition: NanoVDB.h:2433
uint16_t mMin
Definition: NanoVDB.h:3858
typename ChildT::FloatType StatsT
Definition: NanoVDB.h:2519
typename GridOrTreeOrRootT::RootNodeType::ChildNodeType Type
Definition: NanoVDB.h:1666
__hostdev__ Vec3d voxelSize() const
Definition: NanoVDB.h:5996
typename FloatTraits< ValueType >::FloatType FloatType
Definition: NanoVDB.h:4298
__hostdev__ const ValueT & getMin() const
Definition: NanoVDB.h:2648
Like ValueOnIndex but with a mutable mask.
Definition: NanoVDB.h:182
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:106
GridMetaData(const GridData *gridData)
Definition: NanoVDB.h:5944
const typename GridOrTreeOrRootT::LeafNodeType Type
Definition: NanoVDB.h:1644
__hostdev__ DataType * data()
Definition: NanoVDB.h:2069
MaskT< LOG2DIM > mValues
Definition: NanoVDB.h:4092
This is a convenient class that allows for access to grid meta-data that are independent of the value...
Definition: NanoVDB.h:5928
__hostdev__ int findBlindData(const char *name) const
Return the index of the first blind data with specified name if found, otherwise -1.
Definition: NanoVDB.h:2268
__hostdev__ uint32_t gridCount() const
Definition: NanoVDB.h:5991
uint32_t mTableSize
Definition: NanoVDB.h:2547
typename BuildT::BuildType BuildType
Definition: NanoVDB.h:2056
typename T::ValueType ElementType
Definition: NanoVDB.h:748
__hostdev__ bool isMask() const
Definition: NanoVDB.h:5981
__hostdev__ uint64_t memUsage() const
return memory usage in bytes for the leaf node
Definition: NanoVDB.h:4577
__hostdev__ bool isSequential() const
return true if the specified node type is layed out breadth-first in memory and has a fixed size...
Definition: NanoVDB.h:2194
Definition: NanoVDB.h:4364
typename RootT::CoordType CoordType
Definition: NanoVDB.h:2357
float type
Definition: NanoVDB.h:534
defines a tree type from a grid type while preserving constness
Definition: NanoVDB.h:2325
__hostdev__ bool probeValue(const CoordType &ijk, ValueType &v) const
Definition: NanoVDB.h:5410
__hostdev__ GridType mapToGridType()
Definition: NanoVDB.h:872
__hostdev__ uint32_t nodeCount(int level) const
Definition: NanoVDB.h:2427
__hostdev__ ChannelT & operator()(int i, int j, int k) const
Definition: NanoVDB.h:6212
__hostdev__ AccessorType getAccessor() const
Return a new instance of a ReadAccessor used to access values in this grid.
Definition: NanoVDB.h:2106
Visits child nodes of this node only.
Definition: NanoVDB.h:3334
__hostdev__ Coord offsetToGlobalCoord(uint32_t n) const
Definition: NanoVDB.h:3624
typename remove_const< T >::type type
Definition: Util.h:431
static __hostdev__ constexpr uint32_t padding()
Definition: NanoVDB.h:4146
__hostdev__ void setValue(uint32_t offset, uint16_t value)
Definition: NanoVDB.h:4327
__hostdev__ Checksum()
default constructor initiates checksum to EMPTY
Definition: NanoVDB.h:1754
uint64_t Type
Definition: NanoVDB.h:491
static __hostdev__ constexpr uint32_t padding()
Definition: NanoVDB.h:3960
__hostdev__ ValueIterator(const InternalNode *parent)
Definition: NanoVDB.h:3389
typename Mask< 3 >::template Iterator< ON > MaskIterT
Definition: NanoVDB.h:4380
GridType mDataType
Definition: NanoVDB.h:1564
Leaf nodes of the VDB tree. (defaults to 8x8x8 = 512 voxels)
Definition: NanoVDB.h:4361
__hostdev__ bool isActive(const CoordType &ijk) const
Definition: NanoVDB.h:5183
__hostdev__ DataType * data()
Definition: NanoVDB.h:2929
__hostdev__ const uint64_t & valueCount() const
Return total number of values indexed by the IndexGrid.
Definition: NanoVDB.h:6190
__hostdev__ NodeTrait< RootT, LEVEL >::type * getFirstNode()
return a pointer to the first node at the specified level
Definition: NanoVDB.h:2462
__hostdev__ bool isValue() const
Definition: NanoVDB.h:2581
__hostdev__ Vec3T worldToIndexDir(const Vec3T &dir) const
transformation from world space direction to index space direction
Definition: NanoVDB.h:2130
__hostdev__ DenseIterator cbeginChildAll() const
Definition: NanoVDB.h:3493
BuildT BuildType
Definition: NanoVDB.h:5308
__hostdev__ uint32_t rootTableSize() const
return the root table has size
Definition: NanoVDB.h:2018
bool FloatType
Definition: NanoVDB.h:4084
__hostdev__ bool hasBBox() const
Definition: NanoVDB.h:4619
double mTaperD
Definition: NanoVDB.h:1392
__hostdev__ CoordType getCoord() const
Definition: NanoVDB.h:3489
uint32_t dim
Definition: NanoVDB.h:6629
__hostdev__ const ValueType & maximum() const
Return a const reference to the maximum active value encoded in this root node and any of its child n...
Definition: NanoVDB.h:2950
MaskT mChildMask
Definition: NanoVDB.h:3221
__hostdev__ bool isActive(uint32_t n) const
Definition: NanoVDB.h:4609
__hostdev__ Version()
Default constructor.
Definition: NanoVDB.h:684
__hostdev__ void setMinMaxOn(bool on=true)
Definition: NanoVDB.h:1911
static __hostdev__ uint32_t valueCount()
Definition: NanoVDB.h:4225
MaskT< LOG2DIM > mValueMask
Definition: NanoVDB.h:3786
__hostdev__ const Tile * tile(uint32_t n) const
Returns a non-const reference to the tile at the specified linear offset.
Definition: NanoVDB.h:2593
__hostdev__ const StatsT & average() const
Definition: NanoVDB.h:3284
__hostdev__ ValueType getFirstValue() const
Return the first value in this leaf node.
Definition: NanoVDB.h:4592
__hostdev__ ValueOnIterator cbeginValueOn() const
Definition: NanoVDB.h:3448
typename GridOrTreeOrRootT::RootNodeType Type
Definition: NanoVDB.h:1680
__hostdev__ ValueOnIterator(const InternalNode *parent)
Definition: NanoVDB.h:3428
__hostdev__ ConstValueOnIterator cbeginValueOn() const
Definition: NanoVDB.h:2865
Definition: NanoVDB.h:2563
__hostdev__ ReadAccessor(const GridT &grid)
Constructor from a grid.
Definition: NanoVDB.h:5142
FloatType mAverage
Definition: NanoVDB.h:3790
BuildT BuildType
Definition: NanoVDB.h:4975
ValueT ValueType
Definition: NanoVDB.h:5309
__hostdev__ const ChildNodeType * probeChild(const CoordType &ijk) const
Definition: NanoVDB.h:3595
float Type
Definition: NanoVDB.h:505
typename UpperNodeType::ChildNodeType LowerNodeType
Definition: NanoVDB.h:2677
StatsT mStdDevi
Definition: NanoVDB.h:2553
__hostdev__ void setOrigin(const T &ijk)
Definition: NanoVDB.h:4205
__hostdev__ const DataType * data() const
Definition: NanoVDB.h:2071
__hostdev__ uint32_t & head()
Definition: NanoVDB.h:1780
ValueT value
Definition: NanoVDB.h:3209
static __hostdev__ constexpr uint32_t padding()
Return padding of this class in bytes, due to aliasing and 32B alignment.
Definition: NanoVDB.h:4315
__hostdev__ bool hasMinMax() const
Definition: NanoVDB.h:5983
CoordBBox indexBBox
Definition: NanoVDB.h:6317
__hostdev__ uint32_t rootTableSize() const
Definition: NanoVDB.h:6002
__hostdev__ bool isCached1(const CoordType &ijk) const
Definition: NanoVDB.h:5386
__hostdev__ bool isActive(uint32_t n) const
Definition: NanoVDB.h:3271
__hostdev__ ValueOnIterator beginValueOn()
Definition: NanoVDB.h:2864
__hostdev__ const ChildT * getChild(const Tile *tile) const
Definition: NanoVDB.h:2642
__hostdev__ bool isEmpty() const
return true if the 64 bit checksum is disables (unset)
Definition: NanoVDB.h:1793
__hostdev__ Iterator(uint32_t pos, const Mask *parent)
Definition: NanoVDB.h:1076
__hostdev__ ReadAccessor(const RootT &root)
Constructor from a root node.
Definition: NanoVDB.h:5317
__hostdev__ ValueType getMax() const
Definition: NanoVDB.h:3815
typename GridOrTreeOrRootT::RootNodeType type
Definition: NanoVDB.h:1681
__hostdev__ void * nodePtr()
Return a non-const void pointer to the first node at LEVEL.
Definition: NanoVDB.h:1966
__hostdev__ float getMin() const
return the quantized minimum of the active values in this node
Definition: NanoVDB.h:3880
__hostdev__ const LeafT * probeLeaf(const CoordType &ijk) const
Definition: NanoVDB.h:5185
__hostdev__ ValueOffIterator()
Definition: NanoVDB.h:4422
ChildT ChildNodeType
Definition: NanoVDB.h:3316
typename DataType::BuildT BuildType
Definition: NanoVDB.h:3314
__hostdev__ ValueOffIterator cbeginValueOff() const
Definition: NanoVDB.h:4446
uint32_t mSize
Definition: NanoVDB.h:2698
__hostdev__ GridClass toGridClass(GridClass defaultClass=GridClass::Unknown)
Maps from a templated build type to a GridClass enum.
Definition: NanoVDB.h:878
typename DataType::ValueType ValueType
Definition: NanoVDB.h:4372
float type
Definition: NanoVDB.h:527
__hostdev__ uint32_t getMajor() const
Definition: NanoVDB.h:706
__hostdev__ Vec3T indexToWorldGradF(const Vec3T &grad) const
Transforms the gradient from index space to world space.
Definition: NanoVDB.h:2158
__hostdev__ const NodeTrait< TreeT, LEVEL >::type * getNode() const
Definition: NanoVDB.h:5658
__hostdev__ bool hasBBox() const
Definition: NanoVDB.h:2185
uint64_t type
Definition: NanoVDB.h:541
__hostdev__ FloatType getAvg() const
Definition: NanoVDB.h:4336
typename ChildT::LeafNodeType LeafNodeType
Definition: NanoVDB.h:3315
__hostdev__ void setValue(const CoordType &k, bool s, const ValueType &v)
Definition: NanoVDB.h:2573
__hostdev__ auto getNodeInfo(const CoordType &ijk) const
Definition: NanoVDB.h:5711
__hostdev__ const uint64_t * words() const
Definition: NanoVDB.h:1160
__hostdev__ const GridBlindMetaData & blindMetaData(uint32_t n) const
Definition: NanoVDB.h:2251
static __hostdev__ uint32_t bitCount()
Return the number of bits available in this Mask.
Definition: NanoVDB.h:1044
__hostdev__ void setDev(const bool &)
Definition: NanoVDB.h:4112
uint64_t Type
Definition: NanoVDB.h:484
__hostdev__ Vec3T indexToWorldDir(const Vec3T &dir) const
transformation from index space direction to world space direction
Definition: NanoVDB.h:2125
__hostdev__ const void * getRoot() const
Get a const void pointer to the root node (never NULL)
Definition: NanoVDB.h:2306
__hostdev__ const StatsT & stdDeviation() const
Definition: NanoVDB.h:3285
__hostdev__ bool isActive() const
Return true if any of the voxel value are active in this leaf node.
Definition: NanoVDB.h:4612
GridBlindDataClass
Blind-data Classes that are currently supported by NanoVDB.
Definition: NanoVDB.h:416
MaskT< LOG2DIM > mValueMask
Definition: NanoVDB.h:4305
__hostdev__ const void * treePtr() const
Definition: NanoVDB.h:1949
static __hostdev__ size_t memUsage()
Return the memory footprint in bytes of this Mask.
Definition: NanoVDB.h:1041
const typename GridOrTreeOrRootT::RootNodeType Type
Definition: NanoVDB.h:1688
Visits all active values in a leaf node.
Definition: NanoVDB.h:4383
__hostdev__ const LeafNodeType * getFirstLeaf() const
Definition: NanoVDB.h:2478
__hostdev__ Vec3T indexToWorldDirF(const Vec3T &dir) const
transformation from index space direction to world space direction
Definition: NanoVDB.h:2148