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