OpenVDB 10.1.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: MPL-2.0
3
4/*!
5 \file 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 openToNanoVDB
33 or the GridBuilder. This explains why none of the grid nodes defined below
34 have public constructors or destructors.
35
36 \details Please see the following paper for more details on the data structure:
37 K. Museth, “VDB: High-Resolution Sparse Volumes with Dynamic Topology”,
38 ACM Transactions on Graphics 32(3), 2013, which can be found here:
39 http://www.museth.org/Ken/Publications_files/Museth_TOG13.pdf
40
41 NanoVDB was first published there: https://dl.acm.org/doi/fullHtml/10.1145/3450623.3464653
42
43
44 Overview: This file implements the following fundamental class that when combined
45 forms the backbone of the VDB tree data structure:
46
47 Coord- a signed integer coordinate
48 Vec3 - a 3D vector
49 Vec4 - a 4D vector
50 BBox - a bounding box
51 Mask - a bitmask essential to the non-root tree nodes
52 Map - an affine coordinate transformation
53 Grid - contains a Tree and a map for world<->index transformations. Use
54 this class as the main API with client code!
55 Tree - contains a RootNode and getValue methods that should only be used for debugging
56 RootNode - the top-level node of the VDB data structure
57 InternalNode - the internal nodes of the VDB data structure
58 LeafNode - the lowest level tree nodes that encode voxel values and state
59 ReadAccessor - implements accelerated random access operations
60
61 Semantics: A VDB data structure encodes values and (binary) states associated with
62 signed integer coordinates. Values encoded at the leaf node level are
63 denoted voxel values, and values associated with other tree nodes are referred
64 to as tile values, which by design cover a larger coordinate index domain.
65
66
67 Memory layout:
68
69 It's important to emphasize that all the grid data (defined below) are explicitly 32 byte
70 aligned, which implies that any memory buffer that contains a NanoVDB grid must also be at
71 32 byte aligned. That is, the memory address of the beginning of a buffer (see ascii diagram below)
72 must be divisible by 32, i.e. uintptr_t(&buffer)%32 == 0! If this is not the case, the C++ standard
73 says the behaviour is undefined! Normally this is not a concerns on GPUs, because they use 256 byte
74 aligned allocations, but the same cannot be said about the CPU.
75
76 GridData is always at the very beginning of the buffer immediately followed by TreeData!
77 The remaining nodes and blind-data are allowed to be scattered throughout the buffer,
78 though in practice they are arranged as:
79
80 GridData: 672 bytes (e.g. magic, checksum, major, flags, index, count, size, name, map, world bbox, voxel size, class, type, offset, count)
81
82 TreeData: 64 bytes (node counts and byte offsets)
83
84 ... optional padding ...
85
86 RootData: size depends on ValueType (index bbox, voxel count, tile count, min/max/avg/standard deviation)
87
88 Array of: RootData::Tile
89
90 ... optional padding ...
91
92 Array of: Upper InternalNodes of size 32^3: bbox, two bit masks, 32768 tile values, and min/max/avg/standard deviation values
93
94 ... optional padding ...
95
96 Array of: Lower InternalNodes of size 16^3: bbox, two bit masks, 4096 tile values, and min/max/avg/standard deviation values
97
98 ... optional padding ...
99
100 Array of: LeafNodes of size 8^3: bbox, bit masks, 512 voxel values, and min/max/avg/standard deviation values
101
102
103 Notation: "]---[" implies it has optional padding, and "][" implies zero padding
104
105 [GridData(672B)][TreeData(64B)]---[RootData][N x Root::Tile]---[NodeData<5>]---[ModeData<4>]---[LeafData<3>]---[BLINDMETA...]---[BLIND0]---[BLIND1]---etc.
106 ^ ^ ^ ^ ^ ^
107 | | | | | |
108 +-- Start of 32B aligned buffer | | | | +-- Node0::DataType* leafData
109 GridType::DataType* gridData | | | |
110 | | | +-- Node1::DataType* lowerData
111 RootType::DataType* rootData --+ | |
112 | +-- Node2::DataType* upperData
113 |
114 +-- RootType::DataType::Tile* tile
115
116*/
117
118#ifndef NANOVDB_NANOVDB_H_HAS_BEEN_INCLUDED
119#define NANOVDB_NANOVDB_H_HAS_BEEN_INCLUDED
120
121#define NANOVDB_MAGIC_NUMBER 0x304244566f6e614eUL // "NanoVDB0" in hex - little endian (uint64_t)
122
123#define NANOVDB_MAJOR_VERSION_NUMBER 32 // reflects changes to the ABI and hence also the file format
124#define NANOVDB_MINOR_VERSION_NUMBER 4 // reflects changes to the API but not ABI
125#define NANOVDB_PATCH_VERSION_NUMBER 2 // reflects changes that does not affect the ABI or API
126
127// This replaces a Coord key at the root level with a single uint64_t
128#define USE_SINGLE_ROOT_KEY
129
130// This replaces three levels of Coord keys in the ReadAccessor with one Coord
131//#define USE_SINGLE_ACCESSOR_KEY
132
133//#define NANOVDB_USE_IOSTREAMS
134
135#define NANOVDB_FPN_BRANCHLESS
136
137#define NANOVDB_DATA_ALIGNMENT 32
138
139#if !defined(NANOVDB_ALIGN)
140#define NANOVDB_ALIGN(n) alignas(n)
141#endif // !defined(NANOVDB_ALIGN)
142
143#ifdef __CUDACC_RTC__
144
145typedef signed char int8_t;
146typedef short int16_t;
147typedef int int32_t;
148typedef long long int64_t;
149typedef unsigned char uint8_t;
150typedef unsigned int uint32_t;
151typedef unsigned short uint16_t;
152typedef unsigned long long uint64_t;
153
154#define NANOVDB_ASSERT(x)
155
156#define UINT64_C(x) (x ## ULL)
157
158#else // !__CUDACC_RTC__
159
160#include <stdlib.h> // for abs in clang7
161#include <stdint.h> // for types like int32_t etc
162#include <stddef.h> // for size_t type
163#include <cassert> // for assert
164#include <cstdio> // for snprintf
165#include <cmath> // for sqrt and fma
166#include <limits> // for numeric_limits
167#include <utility>// for std::move
168#ifdef NANOVDB_USE_IOSTREAMS
169#include <fstream>// for read/writeUncompressedGrids
170#endif
171// All asserts can be disabled here, even for debug builds
172#if 1
173#define NANOVDB_ASSERT(x) assert(x)
174#else
175#define NANOVDB_ASSERT(x)
176#endif
177
178#if defined(NANOVDB_USE_INTRINSICS) && defined(_MSC_VER)
179#include <intrin.h>
180#pragma intrinsic(_BitScanReverse)
181#pragma intrinsic(_BitScanForward)
182#pragma intrinsic(_BitScanReverse64)
183#pragma intrinsic(_BitScanForward64)
184#endif
185
186#endif // __CUDACC_RTC__
187
188#if defined(__CUDACC__) || defined(__HIP__)
189// Only define __hostdev__ when using NVIDIA CUDA or HIP compiler
190#define __hostdev__ __host__ __device__
191#else
192#define __hostdev__
193#endif
194
195// The following macro will suppress annoying warnings when nvcc
196// compiles functions that call (host) intrinsics (which is perfectly valid)
197#if defined(_MSC_VER) && defined(__CUDACC__)
198#define NANOVDB_HOSTDEV_DISABLE_WARNING __pragma("hd_warning_disable")
199#elif defined(__GNUC__) && defined(__CUDACC__)
200#define NANOVDB_HOSTDEV_DISABLE_WARNING _Pragma("hd_warning_disable")
201#else
202#define NANOVDB_HOSTDEV_DISABLE_WARNING
203#endif
204
205// A portable implementation of offsetof - unfortunately it doesn't work with static_assert
206#define NANOVDB_OFFSETOF(CLASS, MEMBER) ((int)(size_t)((char*)&((CLASS*)0)->MEMBER - (char*)0))
207
208namespace nanovdb {
209
210// --------------------------> Build types <------------------------------------
211
212/// @brief Dummy type for a voxel whose value equals an offset into an external value array
213class ValueIndex {};
214
215/// @brief Dummy type for a voxel whose value equals its binary active state
216class ValueMask {};
217
218/// @brief Dummy type for a 16 bit floating point values
219class Half {};
220
221/// @brief Dummy type for a 4bit quantization of float point values
222class Fp4 {};
223
224/// @brief Dummy type for a 8bit quantization of float point values
225class Fp8 {};
226
227/// @brief Dummy type for a 16bit quantization of float point values
228class Fp16 {};
229
230/// @brief Dummy type for a variable bit quantization of floating point values
231class FpN {};
232
233// --------------------------> GridType <------------------------------------
234
235/// @brief List of types that are currently supported by NanoVDB
236///
237/// @note To expand on this list do:
238/// 1) Add the new type between Unknown and End in the enum below
239/// 2) Add the new type to OpenToNanoVDB::processGrid that maps OpenVDB types to GridType
240/// 3) Verify that the ConvertTrait in NanoToOpenVDB.h works correctly with the new type
241/// 4) Add the new type to mapToGridType (defined below) that maps NanoVDB types to GridType
242/// 5) Add the new type to toStr (defined below)
243enum class GridType : uint32_t { Unknown = 0,
244 Float = 1,// single precision floating point value
245 Double = 2,// double precision floating point value
246 Int16 = 3,// half precision signed integer value
247 Int32 = 4,// single precision signed integer value
248 Int64 = 5,// double precision signed integer value
249 Vec3f = 6,// single precision floating 3D vector
250 Vec3d = 7,// double precision floating 3D vector
251 Mask = 8,// no value, just the active state
252 Half = 9,// half precision floating point value
253 UInt32 = 10,// single precision unsigned integer value
254 Boolean = 11,// boolean value, encoded in bit array
255 RGBA8 = 12,// RGBA packed into 32bit word in reverse-order. R in low bits.
256 Fp4 = 13,// 4bit quantization of float point value
257 Fp8 = 14,// 8bit quantization of float point value
258 Fp16 = 15,// 16bit quantization of float point value
259 FpN = 16,// variable bit quantization of floating point value
260 Vec4f = 17,// single precision floating 4D vector
261 Vec4d = 18,// double precision floating 4D vector
262 Index = 19,// index into an external array of values
263 End = 20 };
264
265#ifndef __CUDACC_RTC__
266/// @brief Retuns a c-string used to describe a GridType
267inline const char* toStr(GridType gridType)
268{
269 static const char * LUT[] = { "?", "float", "double" , "int16", "int32",
270 "int64", "Vec3f", "Vec3d", "Mask", "Half",
271 "uint32", "bool", "RGBA8", "Float4", "Float8",
272 "Float16", "FloatN", "Vec4f", "Vec4d", "Index", "End" };
273 static_assert( sizeof(LUT)/sizeof(char*) - 1 == int(GridType::End), "Unexpected size of LUT" );
274 return LUT[static_cast<int>(gridType)];
275}
276#endif
277
278// --------------------------> GridClass <------------------------------------
279
280/// @brief Classes (defined in OpenVDB) that are currently supported by NanoVDB
281enum class GridClass : uint32_t { Unknown = 0,
282 LevelSet = 1, // narrow band level set, e.g. SDF
283 FogVolume = 2, // fog volume, e.g. density
284 Staggered = 3, // staggered MAC grid, e.g. velocity
285 PointIndex = 4, // point index grid
286 PointData = 5, // point data grid
287 Topology = 6, // grid with active states only (no values)
288 VoxelVolume = 7, // volume of geometric cubes, e.g. Minecraft
289 IndexGrid = 8,// grid whose values are offsets, e.g. into an external array
290 End = 9 };
291
292#ifndef __CUDACC_RTC__
293/// @brief Retuns a c-string used to describe a GridClass
294inline const char* toStr(GridClass gridClass)
295{
296 static const char * LUT[] = { "?", "SDF", "FOG" , "MAC", "PNTIDX",
297 "PNTDAT", "TOPO", "VOX", "INDEX", "END" };
298 static_assert( sizeof(LUT)/sizeof(char*) - 1 == int(GridClass::End), "Unexpected size of LUT" );
299 return LUT[static_cast<int>(gridClass)];
300}
301#endif
302
303// --------------------------> GridFlags <------------------------------------
304
305/// @brief Grid flags which indicate what extra information is present in the grid buffer.
306enum class GridFlags : uint32_t {
307 HasLongGridName = 1 << 0,// grid name is longer than 256 characters
308 HasBBox = 1 << 1,// nodes contain bounding-boxes of active values
309 HasMinMax = 1 << 2,// nodes contain min/max of active values
310 HasAverage = 1 << 3,// nodes contain averages of active values
311 HasStdDeviation = 1 << 4,// nodes contain standard deviations of active values
312 IsBreadthFirst = 1 << 5,// nodes are arranged breadth-first in memory
313 End = 1 << 6,
314};
315
316#ifndef __CUDACC_RTC__
317/// @brief Retuns a c-string used to describe a GridFlags
318inline const char* toStr(GridFlags gridFlags)
319{
320 static const char * LUT[] = { "has long grid name",
321 "has bbox",
322 "has min/max",
323 "has average",
324 "has standard deviation",
325 "is breadth-first",
326 "end" };
327 static_assert( 1 << (sizeof(LUT)/sizeof(char*) - 1) == int(GridFlags::End), "Unexpected size of LUT" );
328 return LUT[static_cast<int>(gridFlags)];
329}
330#endif
331
332// --------------------------> GridBlindData enums <------------------------------------
333
334/// @brief Blind-data Classes that are currently supported by NanoVDB
335enum class GridBlindDataClass : uint32_t { Unknown = 0,
336 IndexArray = 1,
337 AttributeArray = 2,
338 GridName = 3,
339 ChannelArray = 4,
340 End = 5 };
341
342/// @brief Blind-data Semantics that are currently understood by NanoVDB
343enum class GridBlindDataSemantic : uint32_t { Unknown = 0,
344 PointPosition = 1,
345 PointColor = 2,
346 PointNormal = 3,
347 PointRadius = 4,
348 PointVelocity = 5,
349 PointId = 6,
350 End = 8 };
351
352// --------------------------> is_same <------------------------------------
353
354/// @brief C++11 implementation of std::is_same
355template<typename T1, typename T2>
357{
358 static constexpr bool value = false;
359};
360
361template<typename T>
362struct is_same<T, T>
363{
364 static constexpr bool value = true;
365};
366
367// --------------------------> enable_if <------------------------------------
368
369/// @brief C++11 implementation of std::enable_if
370template <bool, typename T = void>
372{
373};
374
375template <typename T>
376struct enable_if<true, T>
377{
378 using type = T;
379};
380
381// --------------------------> is_const <------------------------------------
382
383template<typename T>
385{
386 static constexpr bool value = false;
387};
388
389template<typename T>
390struct is_const<const T>
391{
392 static constexpr bool value = true;
393};
394
395// --------------------------> remove_const <------------------------------------
396
397template<typename T>
399{
400 using type = T;
401};
402
403template<typename T>
404struct remove_const<const T>
405{
406 using type = T;
407};
408
409// --------------------------> is_floating_point <------------------------------------
410
411/// @brief C++11 implementation of std::is_floating_point
412template<typename T>
414{
416};
417
418// --------------------------> is_specialization <------------------------------------
419
420/// @brief Metafunction used to determine if the first template
421/// parameter is a specialization of the class template
422/// given in the second template parameter.
423///
424/// @details is_specialization<Vec3<float>, Vec3>::value == true;
425template<typename AnyType, template<typename...> class TemplateType>
427{
428 static const bool value = false;
429};
430template<typename... Args, template<typename...> class TemplateType>
431struct is_specialization<TemplateType<Args...>, TemplateType>
432{
433 static const bool value = true;
434};
435
436// --------------------------> Value Map <------------------------------------
437
438/// @brief Maps one type (e.g. the build types above) to other (actual) types
439template <typename T>
441{
442 using Type = T;
443 using type = T;
444};
445
446template<>
448{
449 using Type = uint64_t;
450 using type = uint64_t;
451};
452
453template<>
455{
456 using Type = bool;
457 using type = bool;
458};
459
460template<>
462{
463 using Type = float;
464 using type = float;
465};
466
467template<>
469{
470 using Type = float;
471 using type = float;
472};
473
474template<>
476{
477 using Type = float;
478 using type = float;
479};
480
481template<>
483{
484 using Type = float;
485 using type = float;
486};
487
488template<>
490{
491 using Type = float;
492 using type = float;
493};
494
495// --------------------------> utility functions related to alignment <------------------------------------
496
497/// @brief return true if the specified pointer is aligned
498__hostdev__ inline static bool isAligned(const void* p)
499{
500 return uint64_t(p) % NANOVDB_DATA_ALIGNMENT == 0;
501}
502
503/// @brief return true if the specified pointer is aligned and not NULL
504__hostdev__ inline static bool isValid(const void* p)
505{
506 return p != nullptr && uint64_t(p) % NANOVDB_DATA_ALIGNMENT == 0;
507}
508
509/// @brief return the smallest number of bytes that when added to the specified pointer results in an aligned pointer
510__hostdev__ inline static uint64_t alignmentPadding(const void* p)
511{
514}
515
516/// @brief offset the specified pointer so it is aligned.
517template <typename T>
518__hostdev__ inline static T* alignPtr(T* p)
519{
521 return reinterpret_cast<T*>( (uint8_t*)p + alignmentPadding(p) );
522}
523
524/// @brief offset the specified pointer so it is aligned.
525template <typename T>
526__hostdev__ inline static const T* alignPtr(const T* p)
527{
529 return reinterpret_cast<const T*>( (const uint8_t*)p + alignmentPadding(p) );
530}
531
532// --------------------------> PtrDiff PtrAdd <------------------------------------
533
534template <typename T1, typename T2>
535__hostdev__ inline static int64_t PtrDiff(const T1* p, const T2* q)
536{
537 NANOVDB_ASSERT(p && q);
538 return reinterpret_cast<const char*>(p) - reinterpret_cast<const char*>(q);
539}
540
541template <typename DstT, typename SrcT>
542__hostdev__ inline static DstT* PtrAdd(SrcT *p, int64_t offset)
543{
545 return reinterpret_cast<DstT*>(reinterpret_cast<char*>(p) + offset);
546}
547
548template <typename DstT, typename SrcT>
549__hostdev__ inline static const DstT* PtrAdd(const SrcT *p, int64_t offset)
550{
552 return reinterpret_cast<const DstT*>(reinterpret_cast<const char*>(p) + offset);
553}
554
555// --------------------------> Rgba8 <------------------------------------
556
557/// @brief 8-bit red, green, blue, alpha packed into 32 bit unsigned int
558class Rgba8
559{
560 union {
561 uint8_t c[4];// 4 color channels of red, green, blue and alpha components.
562 uint32_t packed;// 32 bit packed representation
563 } mData;
564public:
565 static const int SIZE = 4;
566 using ValueType = uint8_t;
567
568 Rgba8(const Rgba8&) = default;
569 Rgba8(Rgba8&&) = default;
570 Rgba8& operator=(Rgba8&&) = default;
571 Rgba8& operator=(const Rgba8&) = default;
572 __hostdev__ Rgba8() : mData{{0,0,0,0}} {static_assert(sizeof(uint32_t) == sizeof(Rgba8),"Unexpected sizeof");}
573 __hostdev__ Rgba8(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255u) : mData{{r, g, b, a}} {}
574 explicit __hostdev__ Rgba8(uint8_t v) : Rgba8(v,v,v,v) {}
575 __hostdev__ Rgba8(float r, float g, float b, float a = 1.0f)
576 : mData{{(uint8_t(0.5f + r * 255.0f)), // round to nearest
577 (uint8_t(0.5f + g * 255.0f)), // round to nearest
578 (uint8_t(0.5f + b * 255.0f)), // round to nearest
579 (uint8_t(0.5f + a * 255.0f))}}// round to nearest
580 {
581 }
582 __hostdev__ bool operator<(const Rgba8& rhs) const { return mData.packed < rhs.mData.packed; }
583 __hostdev__ bool operator==(const Rgba8& rhs) const { return mData.packed == rhs.mData.packed; }
584 __hostdev__ float lengthSqr() const
585 {
586 return 0.0000153787005f*(float(mData.c[0])*mData.c[0] +
587 float(mData.c[1])*mData.c[1] +
588 float(mData.c[2])*mData.c[2]);//1/255^2
589 }
590 __hostdev__ float length() const { return sqrtf(this->lengthSqr() ); }
591 __hostdev__ const uint8_t& operator[](int n) const { return mData.c[n]; }
592 __hostdev__ uint8_t& operator[](int n) { return mData.c[n]; }
593 __hostdev__ const uint32_t& packed() const { return mData.packed; }
594 __hostdev__ uint32_t& packed() { return mData.packed; }
595 __hostdev__ const uint8_t& r() const { return mData.c[0]; }
596 __hostdev__ const uint8_t& g() const { return mData.c[1]; }
597 __hostdev__ const uint8_t& b() const { return mData.c[2]; }
598 __hostdev__ const uint8_t& a() const { return mData.c[3]; }
599 __hostdev__ uint8_t& r() { return mData.c[0]; }
600 __hostdev__ uint8_t& g() { return mData.c[1]; }
601 __hostdev__ uint8_t& b() { return mData.c[2]; }
602 __hostdev__ uint8_t& a() { return mData.c[3]; }
603};// Rgba8
604
605using PackedRGBA8 = Rgba8;// for backwards compatibility
606
607// --------------------------> isValue(GridType, GridClass) <------------------------------------
608
609/// @brief return true if the GridType maps to a floating point value.
611{
612 return gridType == GridType::Float ||
613 gridType == GridType::Double ||
614 gridType == GridType::Fp4 ||
615 gridType == GridType::Fp8 ||
616 gridType == GridType::Fp16 ||
617 gridType == GridType::FpN;
618}
619
620// --------------------------> isValue(GridType, GridClass) <------------------------------------
621
622/// @brief return true if the combination of GridType and GridClass is valid.
623__hostdev__ inline bool isValid(GridType gridType, GridClass gridClass)
624{
625 if (gridClass == GridClass::LevelSet || gridClass == GridClass::FogVolume) {
626 return isFloatingPoint(gridType);
627 } else if (gridClass == GridClass::Staggered) {
628 return gridType == GridType::Vec3f || gridType == GridType::Vec3d ||
629 gridType == GridType::Vec4f || gridType == GridType::Vec4d;
630 } else if (gridClass == GridClass::PointIndex || gridClass == GridClass::PointData) {
631 return gridType == GridType::UInt32;
632 } else if (gridClass == GridClass::Topology) {
633 return gridType == GridType::Mask;
634 } else if (gridClass == GridClass::IndexGrid) {
635 return gridType == GridType::Index;
636 } else if (gridClass == GridClass::VoxelVolume) {
637 return gridType == GridType::RGBA8 || gridType == GridType::Float || gridType == GridType::Double || gridType == GridType::Vec3f || gridType == GridType::Vec3d || gridType == GridType::UInt32;
638 }
639 return gridClass < GridClass::End && gridType < GridType::End;// any valid combination
640}
641
642// ----------------------------> Version class <-------------------------------------
643
644/// @brief Bit-compacted representation of all three version numbers
645///
646/// @details major is the top 11 bits, minor is the 11 middle bits and patch is the lower 10 bits
648{
649 uint32_t mData;// 11 + 11 + 10 bit packing of major + minor + patch
650public:
652 uint32_t(NANOVDB_MINOR_VERSION_NUMBER) << 10 |
654 {
655 }
656 __hostdev__ Version(uint32_t major, uint32_t minor, uint32_t patch)
657 : mData( major << 21 | minor << 10 | patch )
658 {
659 NANOVDB_ASSERT(major < (1u << 11));// max value of major is 2047
660 NANOVDB_ASSERT(minor < (1u << 11));// max value of minor is 2047
661 NANOVDB_ASSERT(patch < (1u << 10));// max value of patch is 1023
662 }
663 __hostdev__ bool operator==(const Version &rhs) const {return mData == rhs.mData;}
664 __hostdev__ bool operator< (const Version &rhs) const {return mData < rhs.mData;}
665 __hostdev__ bool operator<=(const Version &rhs) const {return mData <= rhs.mData;}
666 __hostdev__ bool operator> (const Version &rhs) const {return mData > rhs.mData;}
667 __hostdev__ bool operator>=(const Version &rhs) const {return mData >= rhs.mData;}
668 __hostdev__ uint32_t id() const { return mData; }
669 __hostdev__ uint32_t getMajor() const { return (mData >> 21) & ((1u << 11) - 1);}
670 __hostdev__ uint32_t getMinor() const { return (mData >> 10) & ((1u << 11) - 1);}
671 __hostdev__ uint32_t getPatch() const { return mData & ((1u << 10) - 1);}
672
673#ifndef __CUDACC_RTC__
674 const char* c_str() const
675 {
676 char *buffer = (char*)malloc(4 + 1 + 4 + 1 + 4 + 1);// xxxx.xxxx.xxxx\0
677 snprintf(buffer, 4 + 1 + 4 + 1 + 4 + 1, "%d.%d.%d", this->getMajor(), this->getMinor(), this->getPatch()); // Prevents overflows by enforcing a fixed size of buffer
678 return buffer;
679 }
680#endif
681};// Version
682
683// ----------------------------> Various math functions <-------------------------------------
684
685//@{
686/// Tolerance for floating-point comparison
687template<typename T>
689template<>
690struct Tolerance<float>
691{
692 __hostdev__ static float value() { return 1e-8f; }
693};
694template<>
695struct Tolerance<double>
696{
697 __hostdev__ static double value() { return 1e-15; }
698};
699//@}
700
701//@{
702/// Delta for small floating-point offsets
703template<typename T>
704struct Delta;
705template<>
706struct Delta<float>
707{
708 __hostdev__ static float value() { return 1e-5f; }
709};
710template<>
711struct Delta<double>
712{
713 __hostdev__ static double value() { return 1e-9; }
714};
715//@}
716
717//@{
718/// Maximum floating-point values
719template<typename T>
720struct Maximum;
721#if defined(__CUDA_ARCH__) || defined(__HIP__)
722template<>
723struct Maximum<int>
724{
725 __hostdev__ static int value() { return 2147483647; }
726};
727template<>
728struct Maximum<uint32_t>
729{
730 __hostdev__ static uint32_t value() { return 4294967295; }
731};
732template<>
733struct Maximum<float>
734{
735 __hostdev__ static float value() { return 1e+38f; }
736};
737template<>
738struct Maximum<double>
739{
740 __hostdev__ static double value() { return 1e+308; }
741};
742#else
743template<typename T>
745{
746 static T value() { return std::numeric_limits<T>::max(); }
747};
748#endif
749//@}
750
751template<typename Type>
752__hostdev__ inline bool isApproxZero(const Type& x)
753{
754 return !(x > Tolerance<Type>::value()) && !(x < -Tolerance<Type>::value());
755}
756
757template<typename Type>
758__hostdev__ inline Type Min(Type a, Type b)
759{
760 return (a < b) ? a : b;
761}
762__hostdev__ inline int32_t Min(int32_t a, int32_t b)
763{
764 return int32_t(fminf(float(a), float(b)));
765}
766__hostdev__ inline uint32_t Min(uint32_t a, uint32_t b)
767{
768 return uint32_t(fminf(float(a), float(b)));
769}
770__hostdev__ inline float Min(float a, float b)
771{
772 return fminf(a, b);
773}
774__hostdev__ inline double Min(double a, double b)
775{
776 return fmin(a, b);
777}
778template<typename Type>
779__hostdev__ inline Type Max(Type a, Type b)
780{
781 return (a > b) ? a : b;
782}
783
784__hostdev__ inline int32_t Max(int32_t a, int32_t b)
785{
786 return int32_t(fmaxf(float(a), float(b)));
787}
788__hostdev__ inline uint32_t Max(uint32_t a, uint32_t b)
789{
790 return uint32_t(fmaxf(float(a), float(b)));
791}
792__hostdev__ inline float Max(float a, float b)
793{
794 return fmaxf(a, b);
795}
796__hostdev__ inline double Max(double a, double b)
797{
798 return fmax(a, b);
799}
800__hostdev__ inline float Clamp(float x, float a, float b)
801{
802 return Max(Min(x, b), a);
803}
804__hostdev__ inline double Clamp(double x, double a, double b)
805{
806 return Max(Min(x, b), a);
807}
808
809__hostdev__ inline float Fract(float x)
810{
811 return x - floorf(x);
812}
813__hostdev__ inline double Fract(double x)
814{
815 return x - floor(x);
816}
817
818__hostdev__ inline int32_t Floor(float x)
819{
820 return int32_t(floorf(x));
821}
822__hostdev__ inline int32_t Floor(double x)
823{
824 return int32_t(floor(x));
825}
826
827__hostdev__ inline int32_t Ceil(float x)
828{
829 return int32_t(ceilf(x));
830}
831__hostdev__ inline int32_t Ceil(double x)
832{
833 return int32_t(ceil(x));
834}
835
836template<typename T>
837__hostdev__ inline T Pow2(T x)
838{
839 return x * x;
840}
841
842template<typename T>
843__hostdev__ inline T Pow3(T x)
844{
845 return x * x * x;
846}
847
848template<typename T>
849__hostdev__ inline T Pow4(T x)
850{
851 return Pow2(x * x);
852}
853template<typename T>
854__hostdev__ inline T Abs(T x)
855{
856 return x < 0 ? -x : x;
857}
858
859template<>
860__hostdev__ inline float Abs(float x)
861{
862 return fabs(x);
863}
864
865template<>
866__hostdev__ inline double Abs(double x)
867{
868 return fabs(x);
869}
870
871template<>
872__hostdev__ inline int Abs(int x)
873{
874 return abs(x);
875}
876
877template<typename CoordT, typename RealT, template<typename> class Vec3T>
878__hostdev__ inline CoordT Round(const Vec3T<RealT>& xyz);
879
880template<typename CoordT, template<typename> class Vec3T>
881__hostdev__ inline CoordT Round(const Vec3T<float>& xyz)
882{
883 return CoordT(int32_t(rintf(xyz[0])), int32_t(rintf(xyz[1])), int32_t(rintf(xyz[2])));
884 //return CoordT(int32_t(roundf(xyz[0])), int32_t(roundf(xyz[1])), int32_t(roundf(xyz[2])) );
885 //return CoordT(int32_t(floorf(xyz[0] + 0.5f)), int32_t(floorf(xyz[1] + 0.5f)), int32_t(floorf(xyz[2] + 0.5f)));
886}
887
888template<typename CoordT, template<typename> class Vec3T>
889__hostdev__ inline CoordT Round(const Vec3T<double>& xyz)
890{
891 return CoordT(int32_t(floor(xyz[0] + 0.5)), int32_t(floor(xyz[1] + 0.5)), int32_t(floor(xyz[2] + 0.5)));
892}
893
894template<typename CoordT, typename RealT, template<typename> class Vec3T>
895__hostdev__ inline CoordT RoundDown(const Vec3T<RealT>& xyz)
896{
897 return CoordT(Floor(xyz[0]), Floor(xyz[1]), Floor(xyz[2]));
898}
899
900//@{
901/// Return the square root of a floating-point value.
902__hostdev__ inline float Sqrt(float x)
903{
904 return sqrtf(x);
905}
906__hostdev__ inline double Sqrt(double x)
907{
908 return sqrt(x);
909}
910//@}
911
912/// Return the sign of the given value as an integer (either -1, 0 or 1).
913template <typename T>
914__hostdev__ inline T Sign(const T &x) { return ((T(0) < x)?T(1):T(0)) - ((x < T(0))?T(1):T(0)); }
915
916template<typename Vec3T>
917__hostdev__ inline int MinIndex(const Vec3T& v)
918{
919#if 0
920 static const int hashTable[8] = {2, 1, 9, 1, 2, 9, 0, 0}; //9 are dummy values
921 const int hashKey = ((v[0] < v[1]) << 2) + ((v[0] < v[2]) << 1) + (v[1] < v[2]); // ?*4+?*2+?*1
922 return hashTable[hashKey];
923#else
924 if (v[0] < v[1] && v[0] < v[2])
925 return 0;
926 if (v[1] < v[2])
927 return 1;
928 else
929 return 2;
930#endif
931}
932
933template<typename Vec3T>
934__hostdev__ inline int MaxIndex(const Vec3T& v)
935{
936#if 0
937 static const int hashTable[8] = {2, 1, 9, 1, 2, 9, 0, 0}; //9 are dummy values
938 const int hashKey = ((v[0] > v[1]) << 2) + ((v[0] > v[2]) << 1) + (v[1] > v[2]); // ?*4+?*2+?*1
939 return hashTable[hashKey];
940#else
941 if (v[0] > v[1] && v[0] > v[2])
942 return 0;
943 if (v[1] > v[2])
944 return 1;
945 else
946 return 2;
947#endif
948}
949
950/// @brief round up byteSize to the nearest wordSize, e.g. to align to machine word: AlignUp<sizeof(size_t)(n)
951///
952/// @details both wordSize and byteSize are in byte units
953template<uint64_t wordSize>
954__hostdev__ inline uint64_t AlignUp(uint64_t byteCount)
955{
956 const uint64_t r = byteCount % wordSize;
957 return r ? byteCount - r + wordSize : byteCount;
958}
959
960// ------------------------------> Coord <--------------------------------------
961
962// forward declaration so we can define Coord::asVec3s and Coord::asVec3d
963template<typename> class Vec3;
964
965/// @brief Signed (i, j, k) 32-bit integer coordinate class, similar to openvdb::math::Coord
966class Coord
967{
968 int32_t mVec[3]; // private member data - three signed index coordinates
969public:
970 using ValueType = int32_t;
971 using IndexType = uint32_t;
972
973 /// @brief Initialize all coordinates to zero.
975 : mVec{0, 0, 0}
976 {
977 }
978
979 /// @brief Initializes all coordinates to the given signed integer.
981 : mVec{n, n, n}
982 {
983 }
984
985 /// @brief Initializes coordinate to the given signed integers.
987 : mVec{i, j, k}
988 {
989 }
990
992 : mVec{ptr[0], ptr[1], ptr[2]}
993 {
994 }
995
996 __hostdev__ int32_t x() const { return mVec[0]; }
997 __hostdev__ int32_t y() const { return mVec[1]; }
998 __hostdev__ int32_t z() const { return mVec[2]; }
999
1000 __hostdev__ int32_t& x() { return mVec[0]; }
1001 __hostdev__ int32_t& y() { return mVec[1]; }
1002 __hostdev__ int32_t& z() { return mVec[2]; }
1003
1004 __hostdev__ static Coord max() { return Coord(int32_t((1u << 31) - 1)); }
1005
1006 __hostdev__ static Coord min() { return Coord(-int32_t((1u << 31) - 1) - 1); }
1007
1008 __hostdev__ static size_t memUsage() { return sizeof(Coord); }
1009
1010 /// @brief Return a const reference to the given Coord component.
1011 /// @warning The argument is assumed to be 0, 1, or 2.
1012 __hostdev__ const ValueType& operator[](IndexType i) const { return mVec[i]; }
1013
1014 /// @brief Return a non-const reference to the given Coord component.
1015 /// @warning The argument is assumed to be 0, 1, or 2.
1017
1018 /// @brief Assignment operator that works with openvdb::Coord
1019 template <typename CoordT>
1020 __hostdev__ Coord& operator=(const CoordT &other)
1021 {
1022 static_assert(sizeof(Coord) == sizeof(CoordT), "Mis-matched sizeof");
1023 mVec[0] = other[0];
1024 mVec[1] = other[1];
1025 mVec[2] = other[2];
1026 return *this;
1027 }
1028
1029 /// @brief Return a new instance with coordinates masked by the given unsigned integer.
1030 __hostdev__ Coord operator&(IndexType n) const { return Coord(mVec[0] & n, mVec[1] & n, mVec[2] & n); }
1031
1032 // @brief Return a new instance with coordinates left-shifted by the given unsigned integer.
1033 __hostdev__ Coord operator<<(IndexType n) const { return Coord(mVec[0] << n, mVec[1] << n, mVec[2] << n); }
1034
1035 // @brief Return a new instance with coordinates right-shifted by the given unsigned integer.
1036 __hostdev__ Coord operator>>(IndexType n) const { return Coord(mVec[0] >> n, mVec[1] >> n, mVec[2] >> n); }
1037
1038 /// @brief Return true if this Coord is lexicographically less than the given Coord.
1039 __hostdev__ bool operator<(const Coord& rhs) const
1040 {
1041 return mVec[0] < rhs[0] ? true : mVec[0] > rhs[0] ? false : mVec[1] < rhs[1] ? true : mVec[1] > rhs[1] ? false : mVec[2] < rhs[2] ? true : false;
1042 }
1043
1044 // @brief Return true if the Coord components are identical.
1045 __hostdev__ bool operator==(const Coord& rhs) const { return mVec[0] == rhs[0] && mVec[1] == rhs[1] && mVec[2] == rhs[2]; }
1046 __hostdev__ bool operator!=(const Coord& rhs) const { return mVec[0] != rhs[0] || mVec[1] != rhs[1] || mVec[2] != rhs[2]; }
1048 {
1049 mVec[0] &= n;
1050 mVec[1] &= n;
1051 mVec[2] &= n;
1052 return *this;
1053 }
1055 {
1056 mVec[0] <<= n;
1057 mVec[1] <<= n;
1058 mVec[2] <<= n;
1059 return *this;
1060 }
1062 {
1063 mVec[0] >>= n;
1064 mVec[1] >>= n;
1065 mVec[2] >>= n;
1066 return *this;
1067 }
1069 {
1070 mVec[0] += n;
1071 mVec[1] += n;
1072 mVec[2] += n;
1073 return *this;
1074 }
1075 __hostdev__ Coord operator+(const Coord& rhs) const { return Coord(mVec[0] + rhs[0], mVec[1] + rhs[1], mVec[2] + rhs[2]); }
1076 __hostdev__ Coord operator-(const Coord& rhs) const { return Coord(mVec[0] - rhs[0], mVec[1] - rhs[1], mVec[2] - rhs[2]); }
1078 {
1079 mVec[0] += rhs[0];
1080 mVec[1] += rhs[1];
1081 mVec[2] += rhs[2];
1082 return *this;
1083 }
1085 {
1086 mVec[0] -= rhs[0];
1087 mVec[1] -= rhs[1];
1088 mVec[2] -= rhs[2];
1089 return *this;
1090 }
1091
1092 /// @brief Perform a component-wise minimum with the other Coord.
1094 {
1095 if (other[0] < mVec[0])
1096 mVec[0] = other[0];
1097 if (other[1] < mVec[1])
1098 mVec[1] = other[1];
1099 if (other[2] < mVec[2])
1100 mVec[2] = other[2];
1101 return *this;
1102 }
1103
1104 /// @brief Perform a component-wise maximum with the other Coord.
1106 {
1107 if (other[0] > mVec[0])
1108 mVec[0] = other[0];
1109 if (other[1] > mVec[1])
1110 mVec[1] = other[1];
1111 if (other[2] > mVec[2])
1112 mVec[2] = other[2];
1113 return *this;
1114 }
1115
1117 {
1118 return Coord(mVec[0] + dx, mVec[1] + dy, mVec[2] + dz);
1119 }
1120
1121 __hostdev__ Coord offsetBy(ValueType n) const { return this->offsetBy(n, n, n); }
1122
1123 /// Return true if any of the components of @a a are smaller than the
1124 /// corresponding components of @a b.
1125 __hostdev__ static inline bool lessThan(const Coord& a, const Coord& b)
1126 {
1127 return (a[0] < b[0] || a[1] < b[1] || a[2] < b[2]);
1128 }
1129
1130 /// @brief Return the largest integer coordinates that are not greater
1131 /// than @a xyz (node centered conversion).
1132 template<typename Vec3T>
1133 __hostdev__ static Coord Floor(const Vec3T& xyz) { return Coord(nanovdb::Floor(xyz[0]), nanovdb::Floor(xyz[1]), nanovdb::Floor(xyz[2])); }
1134
1135 /// @brief Return a hash key derived from the existing coordinates.
1136 /// @details For details on this hash function please see the VDB paper.
1137 /// The prime numbers are modified based on the ACM Transactions on Graphics paper:
1138 /// "Real-time 3D reconstruction at scale using voxel hashing"
1139 template<int Log2N = 3 + 4 + 5>
1140 __hostdev__ uint32_t hash() const { return ((1 << Log2N) - 1) & (mVec[0] * 73856093 ^ mVec[1] * 19349669 ^ mVec[2] * 83492791); }
1141
1142 /// @brief Return the octant of this Coord
1143 //__hostdev__ size_t octant() const { return (uint32_t(mVec[0])>>31) | ((uint32_t(mVec[1])>>31)<<1) | ((uint32_t(mVec[2])>>31)<<2); }
1144 __hostdev__ uint8_t octant() const { return uint8_t((uint8_t(bool(mVec[0] & (1u << 31)))) |
1145 (uint8_t(bool(mVec[1] & (1u << 31))) << 1) |
1146 (uint8_t(bool(mVec[2] & (1u << 31))) << 2)); }
1147
1148 /// @brief Return a single precision floating-point vector of this coordinate
1149 __hostdev__ inline Vec3<float> asVec3s() const;
1150
1151 /// @brief Return a double precision floating-point vector of this coordinate
1152 __hostdev__ inline Vec3<double> asVec3d() const;
1153}; // Coord class
1154
1155// ----------------------------> Vec3 <--------------------------------------
1156
1157/// @brief A simple vector class with three double components, similar to openvdb::math::Vec3
1158template<typename T>
1159class Vec3
1160{
1161 T mVec[3];
1162
1163public:
1164 static const int SIZE = 3;
1165 using ValueType = T;
1166 Vec3() = default;
1167 __hostdev__ explicit Vec3(T x)
1168 : mVec{x, x, x}
1169 {
1170 }
1171 __hostdev__ Vec3(T x, T y, T z)
1172 : mVec{x, y, z}
1173 {
1174 }
1175 template<typename T2>
1176 __hostdev__ explicit Vec3(const Vec3<T2>& v)
1177 : mVec{T(v[0]), T(v[1]), T(v[2])}
1178 {
1179 }
1180 __hostdev__ explicit Vec3(const Coord& ijk)
1181 : mVec{T(ijk[0]), T(ijk[1]), T(ijk[2])}
1182 {
1183 }
1184 __hostdev__ bool operator==(const Vec3& rhs) const { return mVec[0] == rhs[0] && mVec[1] == rhs[1] && mVec[2] == rhs[2]; }
1185 __hostdev__ bool operator!=(const Vec3& rhs) const { return mVec[0] != rhs[0] || mVec[1] != rhs[1] || mVec[2] != rhs[2]; }
1186 template<typename Vec3T>
1187 __hostdev__ Vec3& operator=(const Vec3T& rhs)
1188 {
1189 mVec[0] = rhs[0];
1190 mVec[1] = rhs[1];
1191 mVec[2] = rhs[2];
1192 return *this;
1193 }
1194 __hostdev__ const T& operator[](int i) const { return mVec[i]; }
1195 __hostdev__ T& operator[](int i) { return mVec[i]; }
1196 template<typename Vec3T>
1197 __hostdev__ T dot(const Vec3T& v) const { return mVec[0] * v[0] + mVec[1] * v[1] + mVec[2] * v[2]; }
1198 template<typename Vec3T>
1199 __hostdev__ Vec3 cross(const Vec3T& v) const
1200 {
1201 return Vec3(mVec[1] * v[2] - mVec[2] * v[1],
1202 mVec[2] * v[0] - mVec[0] * v[2],
1203 mVec[0] * v[1] - mVec[1] * v[0]);
1204 }
1206 {
1207 return mVec[0] * mVec[0] + mVec[1] * mVec[1] + mVec[2] * mVec[2]; // 5 flops
1208 }
1209 __hostdev__ T length() const { return Sqrt(this->lengthSqr()); }
1210 __hostdev__ Vec3 operator-() const { return Vec3(-mVec[0], -mVec[1], -mVec[2]); }
1211 __hostdev__ Vec3 operator*(const Vec3& v) const { return Vec3(mVec[0] * v[0], mVec[1] * v[1], mVec[2] * v[2]); }
1212 __hostdev__ Vec3 operator/(const Vec3& v) const { return Vec3(mVec[0] / v[0], mVec[1] / v[1], mVec[2] / v[2]); }
1213 __hostdev__ Vec3 operator+(const Vec3& v) const { return Vec3(mVec[0] + v[0], mVec[1] + v[1], mVec[2] + v[2]); }
1214 __hostdev__ Vec3 operator-(const Vec3& v) const { return Vec3(mVec[0] - v[0], mVec[1] - v[1], mVec[2] - v[2]); }
1215 __hostdev__ Vec3 operator*(const T& s) const { return Vec3(s * mVec[0], s * mVec[1], s * mVec[2]); }
1216 __hostdev__ Vec3 operator/(const T& s) const { return (T(1) / s) * (*this); }
1218 {
1219 mVec[0] += v[0];
1220 mVec[1] += v[1];
1221 mVec[2] += v[2];
1222 return *this;
1223 }
1225 {
1226 mVec[0] -= v[0];
1227 mVec[1] -= v[1];
1228 mVec[2] -= v[2];
1229 return *this;
1230 }
1232 {
1233 mVec[0] *= s;
1234 mVec[1] *= s;
1235 mVec[2] *= s;
1236 return *this;
1237 }
1238 __hostdev__ Vec3& operator/=(const T& s) { return (*this) *= T(1) / s; }
1239 __hostdev__ Vec3& normalize() { return (*this) /= this->length(); }
1240 /// @brief Perform a component-wise minimum with the other Coord.
1242 {
1243 if (other[0] < mVec[0])
1244 mVec[0] = other[0];
1245 if (other[1] < mVec[1])
1246 mVec[1] = other[1];
1247 if (other[2] < mVec[2])
1248 mVec[2] = other[2];
1249 return *this;
1250 }
1251
1252 /// @brief Perform a component-wise maximum with the other Coord.
1254 {
1255 if (other[0] > mVec[0])
1256 mVec[0] = other[0];
1257 if (other[1] > mVec[1])
1258 mVec[1] = other[1];
1259 if (other[2] > mVec[2])
1260 mVec[2] = other[2];
1261 return *this;
1262 }
1263 /// @brief Return the smallest vector component
1265 {
1266 return mVec[0] < mVec[1] ? (mVec[0] < mVec[2] ? mVec[0] : mVec[2]) : (mVec[1] < mVec[2] ? mVec[1] : mVec[2]);
1267 }
1268 /// @brief Return the largest vector component
1270 {
1271 return mVec[0] > mVec[1] ? (mVec[0] > mVec[2] ? mVec[0] : mVec[2]) : (mVec[1] > mVec[2] ? mVec[1] : mVec[2]);
1272 }
1273 __hostdev__ Coord floor() const { return Coord(Floor(mVec[0]), Floor(mVec[1]), Floor(mVec[2])); }
1274 __hostdev__ Coord ceil() const { return Coord(Ceil(mVec[0]), Ceil(mVec[1]), Ceil(mVec[2])); }
1275 __hostdev__ Coord round() const { return Coord(Floor(mVec[0] + 0.5), Floor(mVec[1] + 0.5), Floor(mVec[2] + 0.5)); }
1276}; // Vec3<T>
1277
1278template<typename T1, typename T2>
1279__hostdev__ inline Vec3<T2> operator*(T1 scalar, const Vec3<T2>& vec)
1280{
1281 return Vec3<T2>(scalar * vec[0], scalar * vec[1], scalar * vec[2]);
1282}
1283template<typename T1, typename T2>
1284__hostdev__ inline Vec3<T2> operator/(T1 scalar, const Vec3<T2>& vec)
1285{
1286 return Vec3<T2>(scalar / vec[0], scalar / vec[1], scalar / vec[2]);
1287}
1288
1293
1294/// @brief Return a single precision floating-point vector of this coordinate
1295__hostdev__ inline Vec3f Coord::asVec3s() const { return Vec3f(float(mVec[0]), float(mVec[1]), float(mVec[2])); }
1296
1297/// @brief Return a double precision floating-point vector of this coordinate
1298__hostdev__ inline Vec3d Coord::asVec3d() const { return Vec3d(double(mVec[0]), double(mVec[1]), double(mVec[2])); }
1299
1300// ----------------------------> Vec4 <--------------------------------------
1301
1302/// @brief A simple vector class with three double components, similar to openvdb::math::Vec4
1303template<typename T>
1304class Vec4
1305{
1306 T mVec[4];
1307
1308public:
1309 static const int SIZE = 4;
1310 using ValueType = T;
1311 Vec4() = default;
1312 __hostdev__ explicit Vec4(T x)
1313 : mVec{x, x, x, x}
1314 {
1315 }
1316 __hostdev__ Vec4(T x, T y, T z, T w)
1317 : mVec{x, y, z, w}
1318 {
1319 }
1320 template<typename T2>
1321 __hostdev__ explicit Vec4(const Vec4<T2>& v)
1322 : mVec{T(v[0]), T(v[1]), T(v[2]), T(v[3])}
1323 {
1324 }
1325 __hostdev__ bool operator==(const Vec4& rhs) const { return mVec[0] == rhs[0] && mVec[1] == rhs[1] && mVec[2] == rhs[2] && mVec[3] == rhs[3]; }
1326 __hostdev__ bool operator!=(const Vec4& rhs) const { return mVec[0] != rhs[0] || mVec[1] != rhs[1] || mVec[2] != rhs[2] || mVec[3] != rhs[3]; }
1327 template<typename Vec4T>
1328 __hostdev__ Vec4& operator=(const Vec4T& rhs)
1329 {
1330 mVec[0] = rhs[0];
1331 mVec[1] = rhs[1];
1332 mVec[2] = rhs[2];
1333 mVec[3] = rhs[3];
1334 return *this;
1335 }
1336 __hostdev__ const T& operator[](int i) const { return mVec[i]; }
1337 __hostdev__ T& operator[](int i) { return mVec[i]; }
1338 template<typename Vec4T>
1339 __hostdev__ T dot(const Vec4T& v) const { return mVec[0] * v[0] + mVec[1] * v[1] + mVec[2] * v[2] + mVec[3] * v[3]; }
1341 {
1342 return mVec[0] * mVec[0] + mVec[1] * mVec[1] + mVec[2] * mVec[2] + mVec[3] * mVec[3]; // 7 flops
1343 }
1344 __hostdev__ T length() const { return Sqrt(this->lengthSqr()); }
1345 __hostdev__ Vec4 operator-() const { return Vec4(-mVec[0], -mVec[1], -mVec[2], -mVec[3]); }
1346 __hostdev__ Vec4 operator*(const Vec4& v) const { return Vec4(mVec[0] * v[0], mVec[1] * v[1], mVec[2] * v[2], mVec[3] * v[3]); }
1347 __hostdev__ Vec4 operator/(const Vec4& v) const { return Vec4(mVec[0] / v[0], mVec[1] / v[1], mVec[2] / v[2], mVec[3] / v[3]); }
1348 __hostdev__ Vec4 operator+(const Vec4& v) const { return Vec4(mVec[0] + v[0], mVec[1] + v[1], mVec[2] + v[2], mVec[3] + v[3]); }
1349 __hostdev__ Vec4 operator-(const Vec4& v) const { return Vec4(mVec[0] - v[0], mVec[1] - v[1], mVec[2] - v[2], mVec[3] - v[3]); }
1350 __hostdev__ Vec4 operator*(const T& s) const { return Vec4(s * mVec[0], s * mVec[1], s * mVec[2], s * mVec[3]); }
1351 __hostdev__ Vec4 operator/(const T& s) const { return (T(1) / s) * (*this); }
1353 {
1354 mVec[0] += v[0];
1355 mVec[1] += v[1];
1356 mVec[2] += v[2];
1357 mVec[3] += v[3];
1358 return *this;
1359 }
1361 {
1362 mVec[0] -= v[0];
1363 mVec[1] -= v[1];
1364 mVec[2] -= v[2];
1365 mVec[3] -= v[3];
1366 return *this;
1367 }
1369 {
1370 mVec[0] *= s;
1371 mVec[1] *= s;
1372 mVec[2] *= s;
1373 mVec[3] *= s;
1374 return *this;
1375 }
1376 __hostdev__ Vec4& operator/=(const T& s) { return (*this) *= T(1) / s; }
1377 __hostdev__ Vec4& normalize() { return (*this) /= this->length(); }
1378 /// @brief Perform a component-wise minimum with the other Coord.
1380 {
1381 if (other[0] < mVec[0])
1382 mVec[0] = other[0];
1383 if (other[1] < mVec[1])
1384 mVec[1] = other[1];
1385 if (other[2] < mVec[2])
1386 mVec[2] = other[2];
1387 if (other[3] < mVec[3])
1388 mVec[3] = other[3];
1389 return *this;
1390 }
1391
1392 /// @brief Perform a component-wise maximum with the other Coord.
1394 {
1395 if (other[0] > mVec[0])
1396 mVec[0] = other[0];
1397 if (other[1] > mVec[1])
1398 mVec[1] = other[1];
1399 if (other[2] > mVec[2])
1400 mVec[2] = other[2];
1401 if (other[3] > mVec[3])
1402 mVec[3] = other[3];
1403 return *this;
1404 }
1405}; // Vec4<T>
1406
1407template<typename T1, typename T2>
1408__hostdev__ inline Vec4<T2> operator*(T1 scalar, const Vec4<T2>& vec)
1409{
1410 return Vec4<T2>(scalar * vec[0], scalar * vec[1], scalar * vec[2], scalar * vec[3]);
1411}
1412template<typename T1, typename T2>
1413__hostdev__ inline Vec4<T2> operator/(T1 scalar, const Vec3<T2>& vec)
1414{
1415 return Vec4<T2>(scalar / vec[0], scalar / vec[1], scalar / vec[2], scalar / vec[3]);
1416}
1417
1422
1423// ----------------------------> TensorTraits <--------------------------------------
1424
1425template<typename T, int Rank = (is_specialization<T, Vec3>::value ||
1426 is_specialization<T, Vec4>::value ||
1427 is_same<T, Rgba8>::value) ? 1 : 0>
1429
1430template<typename T>
1431struct TensorTraits<T, 0>
1432{
1433 static const int Rank = 0; // i.e. scalar
1434 static const bool IsScalar = true;
1435 static const bool IsVector = false;
1436 static const int Size = 1;
1437 using ElementType = T;
1438 static T scalar(const T& s) { return s; }
1439};
1440
1441template<typename T>
1442struct TensorTraits<T, 1>
1443{
1444 static const int Rank = 1; // i.e. vector
1445 static const bool IsScalar = false;
1446 static const bool IsVector = true;
1447 static const int Size = T::SIZE;
1448 using ElementType = typename T::ValueType;
1449 static ElementType scalar(const T& v) { return v.length(); }
1450};
1451
1452// ----------------------------> FloatTraits <--------------------------------------
1453
1454template<typename T, int = sizeof(typename TensorTraits<T>::ElementType)>
1456{
1457 using FloatType = float;
1458};
1459
1460template<typename T>
1461struct FloatTraits<T, 8>
1462{
1463 using FloatType = double;
1464};
1465
1466template<>
1467struct FloatTraits<bool, 1>
1468{
1469 using FloatType = bool;
1470};
1471
1472template<>
1473struct FloatTraits<ValueIndex, 1>// size of empty class in C++ is 1 byte and not 0 byte
1474{
1475 using FloatType = uint64_t;
1476};
1477
1478template<>
1479struct FloatTraits<ValueMask, 1>// size of empty class in C++ is 1 byte and not 0 byte
1480{
1481 using FloatType = bool;
1482};
1483
1484// ----------------------------> mapping ValueType -> GridType <--------------------------------------
1485
1486/// @brief Maps from a templated value type to a GridType enum
1487template<typename BuildT>
1489{
1490 if (is_same<BuildT, float>::value) { // resolved at compile-time
1491 return GridType::Float;
1492 } else if (is_same<BuildT, double>::value) {
1493 return GridType::Double;
1495 return GridType::Int16;
1497 return GridType::Int32;
1499 return GridType::Int64;
1500 } else if (is_same<BuildT, Vec3f>::value) {
1501 return GridType::Vec3f;
1502 } else if (is_same<BuildT, Vec3d>::value) {
1503 return GridType::Vec3d;
1505 return GridType::UInt32;
1507 return GridType::Mask;
1509 return GridType::Index;
1510 } else if (is_same<BuildT, bool>::value) {
1511 return GridType::Boolean;
1512 } else if (is_same<BuildT, Rgba8>::value) {
1513 return GridType::RGBA8;
1514 } else if (is_same<BuildT, Fp4>::value) {
1515 return GridType::Fp4;
1516 } else if (is_same<BuildT, Fp8>::value) {
1517 return GridType::Fp8;
1518 } else if (is_same<BuildT, Fp16>::value) {
1519 return GridType::Fp16;
1520 } else if (is_same<BuildT, FpN>::value) {
1521 return GridType::FpN;
1522 } else if (is_same<BuildT, Vec4f>::value) {
1523 return GridType::Vec4f;
1524 } else if (is_same<BuildT, Vec4d>::value) {
1525 return GridType::Vec4d;
1526 }
1527 return GridType::Unknown;
1528}
1529
1530// ----------------------------> matMult <--------------------------------------
1531
1532template<typename Vec3T>
1533__hostdev__ inline Vec3T matMult(const float* mat, const Vec3T& xyz)
1534{
1535 return Vec3T(fmaf(xyz[0], mat[0], fmaf(xyz[1], mat[1], xyz[2] * mat[2])),
1536 fmaf(xyz[0], mat[3], fmaf(xyz[1], mat[4], xyz[2] * mat[5])),
1537 fmaf(xyz[0], mat[6], fmaf(xyz[1], mat[7], xyz[2] * mat[8]))); // 6 fmaf + 3 mult = 9 flops
1538}
1539
1540template<typename Vec3T>
1541__hostdev__ inline Vec3T matMult(const double* mat, const Vec3T& xyz)
1542{
1543 return Vec3T(fma(static_cast<double>(xyz[0]), mat[0], fma(static_cast<double>(xyz[1]), mat[1], static_cast<double>(xyz[2]) * mat[2])),
1544 fma(static_cast<double>(xyz[0]), mat[3], fma(static_cast<double>(xyz[1]), mat[4], static_cast<double>(xyz[2]) * mat[5])),
1545 fma(static_cast<double>(xyz[0]), mat[6], fma(static_cast<double>(xyz[1]), mat[7], static_cast<double>(xyz[2]) * mat[8]))); // 6 fmaf + 3 mult = 9 flops
1546}
1547
1548template<typename Vec3T>
1549__hostdev__ inline Vec3T matMult(const float* mat, const float* vec, const Vec3T& xyz)
1550{
1551 return Vec3T(fmaf(xyz[0], mat[0], fmaf(xyz[1], mat[1], fmaf(xyz[2], mat[2], vec[0]))),
1552 fmaf(xyz[0], mat[3], fmaf(xyz[1], mat[4], fmaf(xyz[2], mat[5], vec[1]))),
1553 fmaf(xyz[0], mat[6], fmaf(xyz[1], mat[7], fmaf(xyz[2], mat[8], vec[2])))); // 9 fmaf = 9 flops
1554}
1555
1556template<typename Vec3T>
1557__hostdev__ inline Vec3T matMult(const double* mat, const double* vec, const Vec3T& xyz)
1558{
1559 return Vec3T(fma(static_cast<double>(xyz[0]), mat[0], fma(static_cast<double>(xyz[1]), mat[1], fma(static_cast<double>(xyz[2]), mat[2], vec[0]))),
1560 fma(static_cast<double>(xyz[0]), mat[3], fma(static_cast<double>(xyz[1]), mat[4], fma(static_cast<double>(xyz[2]), mat[5], vec[1]))),
1561 fma(static_cast<double>(xyz[0]), mat[6], fma(static_cast<double>(xyz[1]), mat[7], fma(static_cast<double>(xyz[2]), mat[8], vec[2])))); // 9 fma = 9 flops
1562}
1563
1564// matMultT: Multiply with the transpose:
1565
1566template<typename Vec3T>
1567__hostdev__ inline Vec3T matMultT(const float* mat, const Vec3T& xyz)
1568{
1569 return Vec3T(fmaf(xyz[0], mat[0], fmaf(xyz[1], mat[3], xyz[2] * mat[6])),
1570 fmaf(xyz[0], mat[1], fmaf(xyz[1], mat[4], xyz[2] * mat[7])),
1571 fmaf(xyz[0], mat[2], fmaf(xyz[1], mat[5], xyz[2] * mat[8]))); // 6 fmaf + 3 mult = 9 flops
1572}
1573
1574template<typename Vec3T>
1575__hostdev__ inline Vec3T matMultT(const double* mat, const Vec3T& xyz)
1576{
1577 return Vec3T(fma(static_cast<double>(xyz[0]), mat[0], fma(static_cast<double>(xyz[1]), mat[3], static_cast<double>(xyz[2]) * mat[6])),
1578 fma(static_cast<double>(xyz[0]), mat[1], fma(static_cast<double>(xyz[1]), mat[4], static_cast<double>(xyz[2]) * mat[7])),
1579 fma(static_cast<double>(xyz[0]), mat[2], fma(static_cast<double>(xyz[1]), mat[5], static_cast<double>(xyz[2]) * mat[8]))); // 6 fmaf + 3 mult = 9 flops
1580}
1581
1582template<typename Vec3T>
1583__hostdev__ inline Vec3T matMultT(const float* mat, const float* vec, const Vec3T& xyz)
1584{
1585 return Vec3T(fmaf(xyz[0], mat[0], fmaf(xyz[1], mat[3], fmaf(xyz[2], mat[6], vec[0]))),
1586 fmaf(xyz[0], mat[1], fmaf(xyz[1], mat[4], fmaf(xyz[2], mat[7], vec[1]))),
1587 fmaf(xyz[0], mat[2], fmaf(xyz[1], mat[5], fmaf(xyz[2], mat[8], vec[2])))); // 9 fmaf = 9 flops
1588}
1589
1590template<typename Vec3T>
1591__hostdev__ inline Vec3T matMultT(const double* mat, const double* vec, const Vec3T& xyz)
1592{
1593 return Vec3T(fma(static_cast<double>(xyz[0]), mat[0], fma(static_cast<double>(xyz[1]), mat[3], fma(static_cast<double>(xyz[2]), mat[6], vec[0]))),
1594 fma(static_cast<double>(xyz[0]), mat[1], fma(static_cast<double>(xyz[1]), mat[4], fma(static_cast<double>(xyz[2]), mat[7], vec[1]))),
1595 fma(static_cast<double>(xyz[0]), mat[2], fma(static_cast<double>(xyz[1]), mat[5], fma(static_cast<double>(xyz[2]), mat[8], vec[2])))); // 9 fma = 9 flops
1596}
1597
1598// ----------------------------> BBox <-------------------------------------
1599
1600// Base-class for static polymorphism (cannot be constructed directly)
1601template<typename Vec3T>
1603{
1604 Vec3T mCoord[2];
1605 __hostdev__ bool operator==(const BaseBBox& rhs) const { return mCoord[0] == rhs.mCoord[0] && mCoord[1] == rhs.mCoord[1]; };
1606 __hostdev__ bool operator!=(const BaseBBox& rhs) const { return mCoord[0] != rhs.mCoord[0] || mCoord[1] != rhs.mCoord[1]; };
1607 __hostdev__ const Vec3T& operator[](int i) const { return mCoord[i]; }
1608 __hostdev__ Vec3T& operator[](int i) { return mCoord[i]; }
1609 __hostdev__ Vec3T& min() { return mCoord[0]; }
1610 __hostdev__ Vec3T& max() { return mCoord[1]; }
1611 __hostdev__ const Vec3T& min() const { return mCoord[0]; }
1612 __hostdev__ const Vec3T& max() const { return mCoord[1]; }
1613 __hostdev__ Coord& translate(const Vec3T& xyz)
1614 {
1615 mCoord[0] += xyz;
1616 mCoord[1] += xyz;
1617 return *this;
1618 }
1619 // @brief Expand this bounding box to enclose point (i, j, k).
1620 __hostdev__ BaseBBox& expand(const Vec3T& xyz)
1621 {
1622 mCoord[0].minComponent(xyz);
1623 mCoord[1].maxComponent(xyz);
1624 return *this;
1625 }
1626
1627 /// @brief Intersect this bounding box with the given bounding box.
1629 {
1630 mCoord[0].maxComponent(bbox.min());
1631 mCoord[1].minComponent(bbox.max());
1632 return *this;
1633 }
1634
1635 //__hostdev__ BaseBBox expandBy(typename Vec3T::ValueType padding) const
1636 //{
1637 // return BaseBBox(mCoord[0].offsetBy(-padding),mCoord[1].offsetBy(padding));
1638 //}
1639 __hostdev__ bool isInside(const Vec3T& xyz)
1640 {
1641 if (xyz[0] < mCoord[0][0] || xyz[1] < mCoord[0][1] || xyz[2] < mCoord[0][2])
1642 return false;
1643 if (xyz[0] > mCoord[1][0] || xyz[1] > mCoord[1][1] || xyz[2] > mCoord[1][2])
1644 return false;
1645 return true;
1646 }
1647
1648protected:
1650 __hostdev__ BaseBBox(const Vec3T& min, const Vec3T& max)
1651 : mCoord{min, max}
1652 {
1653 }
1654}; // BaseBBox
1655
1656template<typename Vec3T, bool = is_floating_point<typename Vec3T::ValueType>::value>
1657struct BBox;
1658
1659/// @brief Partial template specialization for floating point coordinate types.
1660///
1661/// @note Min is inclusive and max is exclusive. If min = max the dimension of
1662/// the bounding box is zero and therefore it is also empty.
1663template<typename Vec3T>
1664struct BBox<Vec3T, true> : public BaseBBox<Vec3T>
1665{
1666 using Vec3Type = Vec3T;
1667 using ValueType = typename Vec3T::ValueType;
1668 static_assert(is_floating_point<ValueType>::value, "Expected a floating point coordinate type");
1670 using BaseT::mCoord;
1672 : BaseT(Vec3T( Maximum<typename Vec3T::ValueType>::value()),
1673 Vec3T(-Maximum<typename Vec3T::ValueType>::value()))
1674 {
1675 }
1676 __hostdev__ BBox(const Vec3T& min, const Vec3T& max)
1677 : BaseT(min, max)
1678 {
1679 }
1680 __hostdev__ BBox(const Coord& min, const Coord& max)
1681 : BaseT(Vec3T(ValueType(min[0]), ValueType(min[1]), ValueType(min[2])),
1682 Vec3T(ValueType(max[0] + 1), ValueType(max[1] + 1), ValueType(max[2] + 1)))
1683 {
1684 }
1685 __hostdev__ static BBox createCube(const Coord& min, typename Coord::ValueType dim)
1686 {
1687 return BBox(min, min.offsetBy(dim));
1688 }
1689
1690 __hostdev__ BBox(const BaseBBox<Coord>& bbox) : BBox(bbox[0], bbox[1]) {}
1691 __hostdev__ bool empty() const { return mCoord[0][0] >= mCoord[1][0] ||
1692 mCoord[0][1] >= mCoord[1][1] ||
1693 mCoord[0][2] >= mCoord[1][2]; }
1694 __hostdev__ Vec3T dim() const { return this->empty() ? Vec3T(0) : this->max() - this->min(); }
1695 __hostdev__ bool isInside(const Vec3T& p) const
1696 {
1697 return p[0] > mCoord[0][0] && p[1] > mCoord[0][1] && p[2] > mCoord[0][2] &&
1698 p[0] < mCoord[1][0] && p[1] < mCoord[1][1] && p[2] < mCoord[1][2];
1699 }
1700
1701};// BBox<Vec3T, true>
1702
1703/// @brief Partial template specialization for integer coordinate types
1704///
1705/// @note Both min and max are INCLUDED in the bbox so dim = max - min + 1. So,
1706/// if min = max the bounding box contains exactly one point and dim = 1!
1707template<typename CoordT>
1708struct BBox<CoordT, false> : public BaseBBox<CoordT>
1709{
1710 static_assert(is_same<int, typename CoordT::ValueType>::value, "Expected \"int\" coordinate type");
1712 using BaseT::mCoord;
1713 /// @brief Iterator over the domain covered by a BBox
1714 /// @details z is the fastest-moving coordinate.
1715 class Iterator
1716 {
1717 const BBox& mBBox;
1718 CoordT mPos;
1719 public:
1721 : mBBox(b)
1722 , mPos(b.min())
1723 {
1724 }
1726 {
1727 if (mPos[2] < mBBox[1][2]) {// this is the most common case
1728 ++mPos[2];
1729 } else if (mPos[1] < mBBox[1][1]) {
1730 mPos[2] = mBBox[0][2];
1731 ++mPos[1];
1732 } else if (mPos[0] <= mBBox[1][0]) {
1733 mPos[2] = mBBox[0][2];
1734 mPos[1] = mBBox[0][1];
1735 ++mPos[0];
1736 }
1737 return *this;
1738 }
1740 {
1741 auto tmp = *this;
1742 ++(*this);
1743 return tmp;
1744 }
1745 /// @brief Return @c true if the iterator still points to a valid coordinate.
1746 __hostdev__ operator bool() const { return mPos[0] <= mBBox[1][0]; }
1747 __hostdev__ const CoordT& operator*() const { return mPos; }
1748 }; // Iterator
1749 __hostdev__ Iterator begin() const { return Iterator{*this}; }
1751 : BaseT(CoordT::max(), CoordT::min())
1752 {
1753 }
1754 __hostdev__ BBox(const CoordT& min, const CoordT& max)
1755 : BaseT(min, max)
1756 {
1757 }
1758
1759 template<typename SplitT>
1760 __hostdev__ BBox(BBox& other, const SplitT&)
1761 : BaseT(other.mCoord[0], other.mCoord[1])
1762 {
1763 NANOVDB_ASSERT(this->is_divisible());
1764 const int n = MaxIndex(this->dim());
1765 mCoord[1][n] = (mCoord[0][n] + mCoord[1][n]) >> 1;
1766 other.mCoord[0][n] = mCoord[1][n] + 1;
1767 }
1768
1769 __hostdev__ static BBox createCube(const CoordT& min, typename CoordT::ValueType dim)
1770 {
1771 return BBox(min, min.offsetBy(dim - 1));
1772 }
1773
1774 __hostdev__ bool is_divisible() const { return mCoord[0][0] < mCoord[1][0] &&
1775 mCoord[0][1] < mCoord[1][1] &&
1776 mCoord[0][2] < mCoord[1][2]; }
1777 /// @brief Return true if this bounding box is empty, i.e. uninitialized
1778 __hostdev__ bool empty() const { return mCoord[0][0] > mCoord[1][0] ||
1779 mCoord[0][1] > mCoord[1][1] ||
1780 mCoord[0][2] > mCoord[1][2]; }
1781 __hostdev__ CoordT dim() const { return this->empty() ? Coord(0) : this->max() - this->min() + Coord(1); }
1782 __hostdev__ uint64_t volume() const { auto d = this->dim(); return uint64_t(d[0])*uint64_t(d[1])*uint64_t(d[2]); }
1783 __hostdev__ bool isInside(const CoordT& p) const { return !(CoordT::lessThan(p, this->min()) || CoordT::lessThan(this->max(), p)); }
1784 /// @brief Return @c true if the given bounding box is inside this bounding box.
1785 __hostdev__ bool isInside(const BBox& b) const
1786 {
1787 return !(CoordT::lessThan(b.min(), this->min()) || CoordT::lessThan(this->max(), b.max()));
1788 }
1789
1790 /// @brief Return @c true if the given bounding box overlaps with this bounding box.
1791 __hostdev__ bool hasOverlap(const BBox& b) const
1792 {
1793 return !(CoordT::lessThan(this->max(), b.min()) || CoordT::lessThan(b.max(), this->min()));
1794 }
1795
1796 /// @warning This converts a CoordBBox into a floating-point bounding box which implies that max += 1 !
1797 template<typename RealT>
1799 {
1800 static_assert(is_floating_point<RealT>::value, "CoordBBox::asReal: Expected a floating point coordinate");
1801 return BBox<Vec3<RealT>>(Vec3<RealT>(RealT(mCoord[0][0]), RealT(mCoord[0][1]), RealT(mCoord[0][2])),
1802 Vec3<RealT>(RealT(mCoord[1][0] + 1), RealT(mCoord[1][1] + 1), RealT(mCoord[1][2] + 1)));
1803 }
1804 /// @brief Return a new instance that is expanded by the specified padding.
1805 __hostdev__ BBox expandBy(typename CoordT::ValueType padding) const
1806 {
1807 return BBox(mCoord[0].offsetBy(-padding), mCoord[1].offsetBy(padding));
1808 }
1809};// BBox<CoordT, false>
1810
1813
1814// -------------------> Find lowest and highest bit in a word <----------------------------
1815
1816/// @brief Returns the index of the lowest, i.e. least significant, on bit in the specified 32 bit word
1817///
1818/// @warning Assumes that at least one bit is set in the word, i.e. @a v != uint32_t(0)!
1820__hostdev__ static inline uint32_t FindLowestOn(uint32_t v)
1821{
1822 NANOVDB_ASSERT(v);
1823#if (defined(__CUDA_ARCH__) || defined(__HIP__)) && defined(NANOVDB_USE_INTRINSICS)
1824 return __ffs(v);
1825#elif defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS)
1826 unsigned long index;
1827 _BitScanForward(&index, v);
1828 return static_cast<uint32_t>(index);
1829#elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS)
1830 return static_cast<uint32_t>(__builtin_ctzl(v));
1831#else
1832//#warning Using software implementation for FindLowestOn(uint32_t)
1833 static const unsigned char DeBruijn[32] = {
1834 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9};
1835// disable unary minus on unsigned warning
1836#if defined(_MSC_VER) && !defined(__NVCC__)
1837#pragma warning(push)
1838#pragma warning(disable : 4146)
1839#endif
1840 return DeBruijn[uint32_t((v & -v) * 0x077CB531U) >> 27];
1841#if defined(_MSC_VER) && !defined(__NVCC__)
1842#pragma warning(pop)
1843#endif
1844
1845#endif
1846}
1847
1848/// @brief Returns the index of the highest, i.e. most significant, on bit in the specified 32 bit word
1849///
1850/// @warning Assumes that at least one bit is set in the word, i.e. @a v != uint32_t(0)!
1852__hostdev__ static inline uint32_t FindHighestOn(uint32_t v)
1853{
1854 NANOVDB_ASSERT(v);
1855#if defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS)
1856 unsigned long index;
1857 _BitScanReverse(&index, v);
1858 return static_cast<uint32_t>(index);
1859#elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS)
1860 return sizeof(unsigned long) * 8 - 1 - __builtin_clzl(v);
1861#else
1862//#warning Using software implementation for FindHighestOn(uint32_t)
1863 static const unsigned char DeBruijn[32] = {
1864 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31};
1865 v |= v >> 1; // first round down to one less than a power of 2
1866 v |= v >> 2;
1867 v |= v >> 4;
1868 v |= v >> 8;
1869 v |= v >> 16;
1870 return DeBruijn[uint32_t(v * 0x07C4ACDDU) >> 27];
1871#endif
1872}
1873
1874/// @brief Returns the index of the lowest, i.e. least significant, on bit in the specified 64 bit word
1875///
1876/// @warning Assumes that at least one bit is set in the word, i.e. @a v != uint32_t(0)!
1878__hostdev__ static inline uint32_t FindLowestOn(uint64_t v)
1879{
1880 NANOVDB_ASSERT(v);
1881#if (defined(__CUDA_ARCH__) || defined(__HIP__)) && defined(NANOVDB_USE_INTRINSICS)
1882 return __ffsll(static_cast<unsigned long long int>(v));
1883#elif defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS)
1884 unsigned long index;
1885 _BitScanForward64(&index, v);
1886 return static_cast<uint32_t>(index);
1887#elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS)
1888 return static_cast<uint32_t>(__builtin_ctzll(v));
1889#else
1890//#warning Using software implementation for FindLowestOn(uint64_t)
1891 static const unsigned char DeBruijn[64] = {
1892 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
1893 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
1894 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
1895 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12,
1896 };
1897// disable unary minus on unsigned warning
1898#if defined(_MSC_VER) && !defined(__NVCC__)
1899#pragma warning(push)
1900#pragma warning(disable : 4146)
1901#endif
1902 return DeBruijn[uint64_t((v & -v) * UINT64_C(0x022FDD63CC95386D)) >> 58];
1903#if defined(_MSC_VER) && !defined(__NVCC__)
1904#pragma warning(pop)
1905#endif
1906
1907#endif
1908}
1909
1910/// @brief Returns the index of the highest, i.e. most significant, on bit in the specified 64 bit word
1911///
1912/// @warning Assumes that at least one bit is set in the word, i.e. @a v != uint32_t(0)!
1914__hostdev__ static inline uint32_t FindHighestOn(uint64_t v)
1915{
1916 NANOVDB_ASSERT(v);
1917#if defined(_MSC_VER) && defined(NANOVDB_USE_INTRINSICS)
1918 unsigned long index;
1919 _BitScanReverse64(&index, v);
1920 return static_cast<uint32_t>(index);
1921#elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS)
1922 return sizeof(unsigned long) * 8 - 1 - __builtin_clzll(v);
1923#else
1924 const uint32_t* p = reinterpret_cast<const uint32_t*>(&v);
1925 return p[1] ? 32u + FindHighestOn(p[1]) : FindHighestOn(p[0]);
1926#endif
1927}
1928
1929// ----------------------------> CountOn <--------------------------------------
1930
1931/// @return Number of bits that are on in the specified 64-bit word
1933__hostdev__ inline uint32_t CountOn(uint64_t v)
1934{
1935#if (defined(__CUDA_ARCH__) || defined(__HIP__)) && defined(NANOVDB_USE_INTRINSICS)
1936//#warning Using popcll for CountOn
1937 return __popcll(v);
1938// __popcnt64 intrinsic support was added in VS 2019 16.8
1939#elif defined(_MSC_VER) && defined(_M_X64) && (_MSC_VER >= 1928) && defined(NANOVDB_USE_INTRINSICS)
1940//#warning Using popcnt64 for CountOn
1941 return __popcnt64(v);
1942#elif (defined(__GNUC__) || defined(__clang__)) && defined(NANOVDB_USE_INTRINSICS)
1943//#warning Using builtin_popcountll for CountOn
1944 return __builtin_popcountll(v);
1945#else// use software implementation
1946//#warning Using software implementation for CountOn
1947 v = v - ((v >> 1) & uint64_t(0x5555555555555555));
1948 v = (v & uint64_t(0x3333333333333333)) + ((v >> 2) & uint64_t(0x3333333333333333));
1949 return (((v + (v >> 4)) & uint64_t(0xF0F0F0F0F0F0F0F)) * uint64_t(0x101010101010101)) >> 56;
1950#endif
1951}
1952
1953// ----------------------------> Mask <--------------------------------------
1954
1955/// @brief Bit-mask to encode active states and facilitate sequential iterators
1956/// and a fast codec for I/O compression.
1957template<uint32_t LOG2DIM>
1958class Mask
1959{
1960 static constexpr uint32_t SIZE = 1U << (3 * LOG2DIM); // Number of bits in mask
1961 static constexpr uint32_t WORD_COUNT = SIZE >> 6; // Number of 64 bit words
1962 uint64_t mWords[WORD_COUNT];
1963
1964public:
1965 /// @brief Return the memory footprint in bytes of this Mask
1966 __hostdev__ static size_t memUsage() { return sizeof(Mask); }
1967
1968 /// @brief Return the number of bits available in this Mask
1969 __hostdev__ static uint32_t bitCount() { return SIZE; }
1970
1971 /// @brief Return the number of machine words used by this Mask
1972 __hostdev__ static uint32_t wordCount() { return WORD_COUNT; }
1973
1974 /// @brief Return the total number of set bits in this Mask
1975 __hostdev__ uint32_t countOn() const
1976 {
1977 uint32_t sum = 0, n = WORD_COUNT;
1978 for (const uint64_t* w = mWords; n--; ++w)
1979 sum += CountOn(*w);
1980 return sum;
1981 }
1982
1983 /// @brief Return the number of lower set bits in mask up to but excluding the i'th bit
1984 inline __hostdev__ uint32_t countOn(uint32_t i) const
1985 {
1986 uint32_t n = i >> 6, sum = CountOn( mWords[n] & ((uint64_t(1) << (i & 63u))-1u) );
1987 for (const uint64_t* w = mWords; n--; ++w) sum += CountOn(*w);
1988 return sum;
1989 }
1990
1991 template <bool On>
1993 {
1994 public:
1995 __hostdev__ Iterator() : mPos(Mask::SIZE), mParent(nullptr){}
1996 __hostdev__ Iterator(uint32_t pos, const Mask* parent) : mPos(pos), mParent(parent){}
1997 Iterator& operator=(const Iterator&) = default;
1998 __hostdev__ uint32_t operator*() const { return mPos; }
1999 __hostdev__ uint32_t pos() const { return mPos; }
2000 __hostdev__ operator bool() const { return mPos != Mask::SIZE; }
2002 {
2003 mPos = mParent->findNext<On>(mPos + 1);
2004 return *this;
2005 }
2007 {
2008 auto tmp = *this;
2009 ++(*this);
2010 return tmp;
2011 }
2012
2013 private:
2014 uint32_t mPos;
2015 const Mask* mParent;
2016 }; // Member class Iterator
2017
2020
2021 __hostdev__ OnIterator beginOn() const { return OnIterator(this->findFirst<true>(), this); }
2022
2023 __hostdev__ OffIterator beginOff() const { return OffIterator(this->findFirst<false>(), this); }
2024
2025 /// @brief Initialize all bits to zero.
2027 {
2028 for (uint32_t i = 0; i < WORD_COUNT; ++i)
2029 mWords[i] = 0;
2030 }
2032 {
2033 const uint64_t v = on ? ~uint64_t(0) : uint64_t(0);
2034 for (uint32_t i = 0; i < WORD_COUNT; ++i)
2035 mWords[i] = v;
2036 }
2037
2038 /// @brief Copy constructor
2039 __hostdev__ Mask(const Mask& other)
2040 {
2041 for (uint32_t i = 0; i < WORD_COUNT; ++i)
2042 mWords[i] = other.mWords[i];
2043 }
2044
2045 /// @brief Return a const reference to the <i>n</i>th word of the bit mask, for a word of arbitrary size.
2046 template<typename WordT>
2047 __hostdev__ const WordT& getWord(int n) const
2048 {
2049 NANOVDB_ASSERT(n * 8 * sizeof(WordT) < SIZE);
2050 return reinterpret_cast<const WordT*>(mWords)[n];
2051 }
2052
2053 /// @brief Return a reference to the <i>n</i>th word of the bit mask, for a word of arbitrary size.
2054 template<typename WordT>
2055 __hostdev__ WordT& getWord(int n)
2056 {
2057 NANOVDB_ASSERT(n * 8 * sizeof(WordT) < SIZE);
2058 return reinterpret_cast<WordT*>(mWords)[n];
2059 }
2060
2061 /// @brief Assignment operator that works with openvdb::util::NodeMask
2062 template<typename MaskT>
2063 __hostdev__ Mask& operator=(const MaskT& other)
2064 {
2065 static_assert(sizeof(Mask) == sizeof(MaskT), "Mismatching sizeof");
2066 static_assert(WORD_COUNT == MaskT::WORD_COUNT, "Mismatching word count");
2067 static_assert(LOG2DIM == MaskT::LOG2DIM, "Mismatching LOG2DIM");
2068 auto *src = reinterpret_cast<const uint64_t*>(&other);
2069 uint64_t *dst = mWords;
2070 for (uint32_t i = 0; i < WORD_COUNT; ++i) {
2071 *dst++ = *src++;
2072 }
2073 return *this;
2074 }
2075
2076 __hostdev__ bool operator==(const Mask& other) const
2077 {
2078 for (uint32_t i = 0; i < WORD_COUNT; ++i) {
2079 if (mWords[i] != other.mWords[i]) return false;
2080 }
2081 return true;
2082 }
2083
2084 __hostdev__ bool operator!=(const Mask& other) const { return !((*this) == other); }
2085
2086 /// @brief Return true if the given bit is set.
2087 __hostdev__ bool isOn(uint32_t n) const { return 0 != (mWords[n >> 6] & (uint64_t(1) << (n & 63))); }
2088
2089 /// @brief Return true if the given bit is NOT set.
2090 __hostdev__ bool isOff(uint32_t n) const { return 0 == (mWords[n >> 6] & (uint64_t(1) << (n & 63))); }
2091
2092 /// @brief Return true if all the bits are set in this Mask.
2093 __hostdev__ bool isOn() const
2094 {
2095 for (uint32_t i = 0; i < WORD_COUNT; ++i)
2096 if (mWords[i] != ~uint64_t(0))
2097 return false;
2098 return true;
2099 }
2100
2101 /// @brief Return true if none of the bits are set in this Mask.
2102 __hostdev__ bool isOff() const
2103 {
2104 for (uint32_t i = 0; i < WORD_COUNT; ++i)
2105 if (mWords[i] != uint64_t(0))
2106 return false;
2107 return true;
2108 }
2109
2110 /// @brief Set the specified bit on.
2111 __hostdev__ void setOn(uint32_t n) { mWords[n >> 6] |= uint64_t(1) << (n & 63); }
2112
2113 /// @brief Set the specified bit off.
2114 __hostdev__ void setOff(uint32_t n) { mWords[n >> 6] &= ~(uint64_t(1) << (n & 63)); }
2115
2116 /// @brief Set the specified bit on or off.
2117 __hostdev__ void set(uint32_t n, bool On)
2118 {
2119#if 1 // switch between branchless
2120 auto &word = mWords[n >> 6];
2121 n &= 63;
2122 word &= ~(uint64_t(1) << n);
2123 word |= uint64_t(On) << n;
2124#else
2125 On ? this->setOn(n) : this->setOff(n);
2126#endif
2127 }
2128
2129 /// @brief Set all bits on
2131 {
2132 for (uint32_t i = 0; i < WORD_COUNT; ++i)
2133 mWords[i] = ~uint64_t(0);
2134 }
2135
2136 /// @brief Set all bits off
2138 {
2139 for (uint32_t i = 0; i < WORD_COUNT; ++i)
2140 mWords[i] = uint64_t(0);
2141 }
2142
2143 /// @brief Set all bits off
2144 __hostdev__ void set(bool on)
2145 {
2146 const uint64_t v = on ? ~uint64_t(0) : uint64_t(0);
2147 for (uint32_t i = 0; i < WORD_COUNT; ++i)
2148 mWords[i] = v;
2149 }
2150 /// brief Toggle the state of all bits in the mask
2152 {
2153 uint32_t n = WORD_COUNT;
2154 for (auto* w = mWords; n--; ++w)
2155 *w = ~*w;
2156 }
2157 __hostdev__ void toggle(uint32_t n) { mWords[n >> 6] ^= uint64_t(1) << (n & 63); }
2158
2159 /// @brief Bitwise intersection
2161 {
2162 uint64_t *w1 = mWords;
2163 const uint64_t *w2 = other.mWords;
2164 for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 &= *w2;
2165 return *this;
2166 }
2167 /// @brief Bitwise union
2169 {
2170 uint64_t *w1 = mWords;
2171 const uint64_t *w2 = other.mWords;
2172 for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 |= *w2;
2173 return *this;
2174 }
2175 /// @brief Bitwise difference
2177 {
2178 uint64_t *w1 = mWords;
2179 const uint64_t *w2 = other.mWords;
2180 for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 &= ~*w2;
2181 return *this;
2182 }
2183 /// @brief Bitwise XOR
2185 {
2186 uint64_t *w1 = mWords;
2187 const uint64_t *w2 = other.mWords;
2188 for (uint32_t n = WORD_COUNT; n--; ++w1, ++w2) *w1 ^= *w2;
2189 return *this;
2190 }
2191
2192private:
2193
2195 template <bool On>
2196 __hostdev__ uint32_t findFirst() const
2197 {
2198 uint32_t n = 0;
2199 const uint64_t* w = mWords;
2200 for (; n<WORD_COUNT && !(On ? *w : ~*w); ++w, ++n);
2201 return n==WORD_COUNT ? SIZE : (n << 6) + FindLowestOn(On ? *w : ~*w);
2202 }
2203
2205 template <bool On>
2206 __hostdev__ uint32_t findNext(uint32_t start) const
2207 {
2208 uint32_t n = start >> 6; // initiate
2209 if (n >= WORD_COUNT)
2210 return SIZE; // check for out of bounds
2211 uint32_t m = start & 63;
2212 uint64_t b = On ? mWords[n] : ~mWords[n];
2213 if (b & (uint64_t(1) << m))
2214 return start; // simple case: start is on
2215 b &= ~uint64_t(0) << m; // mask out lower bits
2216 while (!b && ++n < WORD_COUNT)
2217 b = On ? mWords[n] : ~mWords[n]; // find next non-zero word
2218 return (!b ? SIZE : (n << 6) + FindLowestOn(b)); // catch last word=0
2219 }
2220}; // Mask class
2221
2222// ----------------------------> Map <--------------------------------------
2223
2224/// @brief Defines an affine transform and its inverse represented as a 3x3 matrix and a vec3 translation
2225struct Map
2226{
2227 float mMatF[9]; // 9*4B <- 3x3 matrix
2228 float mInvMatF[9]; // 9*4B <- 3x3 matrix
2229 float mVecF[3]; // 3*4B <- translation
2230 float mTaperF; // 4B, placeholder for taper value
2231 double mMatD[9]; // 9*8B <- 3x3 matrix
2232 double mInvMatD[9]; // 9*8B <- 3x3 matrix
2233 double mVecD[3]; // 3*8B <- translation
2234 double mTaperD; // 8B, placeholder for taper value
2235
2236 /// @brief Initialize the member data
2237 template<typename Mat3T, typename Vec3T>
2238 __hostdev__ void set(const Mat3T& mat, const Mat3T& invMat, const Vec3T& translate, double taper);
2239
2240 /// @brief Initialize the member data
2241 /// @note The last (4th) row of invMat is actually ignored.
2242 template<typename Mat4T>
2243 __hostdev__ void set(const Mat4T& mat, const Mat4T& invMat, double taper) {this->set(mat, invMat, mat[3], taper);}
2244
2245 template<typename Vec3T>
2246 __hostdev__ void set(double scale, const Vec3T &translation, double taper);
2247
2248 template<typename Vec3T>
2249 __hostdev__ Vec3T applyMap(const Vec3T& xyz) const { return matMult(mMatD, mVecD, xyz); }
2250 template<typename Vec3T>
2251 __hostdev__ Vec3T applyMapF(const Vec3T& xyz) const { return matMult(mMatF, mVecF, xyz); }
2252
2253 template<typename Vec3T>
2254 __hostdev__ Vec3T applyJacobian(const Vec3T& xyz) const { return matMult(mMatD, xyz); }
2255 template<typename Vec3T>
2256 __hostdev__ Vec3T applyJacobianF(const Vec3T& xyz) const { return matMult(mMatF, xyz); }
2257
2258 template<typename Vec3T>
2259 __hostdev__ Vec3T applyInverseMap(const Vec3T& xyz) const
2260 {
2261 return matMult(mInvMatD, Vec3T(xyz[0] - mVecD[0], xyz[1] - mVecD[1], xyz[2] - mVecD[2]));
2262 }
2263 template<typename Vec3T>
2264 __hostdev__ Vec3T applyInverseMapF(const Vec3T& xyz) const
2265 {
2266 return matMult(mInvMatF, Vec3T(xyz[0] - mVecF[0], xyz[1] - mVecF[1], xyz[2] - mVecF[2]));
2267 }
2268
2269 template<typename Vec3T>
2270 __hostdev__ Vec3T applyInverseJacobian(const Vec3T& xyz) const { return matMult(mInvMatD, xyz); }
2271 template<typename Vec3T>
2272 __hostdev__ Vec3T applyInverseJacobianF(const Vec3T& xyz) const { return matMult(mInvMatF, xyz); }
2273
2274 template<typename Vec3T>
2275 __hostdev__ Vec3T applyIJT(const Vec3T& xyz) const { return matMultT(mInvMatD, xyz); }
2276 template<typename Vec3T>
2277 __hostdev__ Vec3T applyIJTF(const Vec3T& xyz) const { return matMultT(mInvMatF, xyz); }
2278}; // Map
2279
2280template<typename Mat3T, typename Vec3T>
2281__hostdev__ inline void Map::set(const Mat3T& mat, const Mat3T& invMat, const Vec3T& translate, double taper)
2282{
2283 float *mf = mMatF, *vf = mVecF, *mif = mInvMatF;
2284 double *md = mMatD, *vd = mVecD, *mid = mInvMatD;
2285 mTaperF = static_cast<float>(taper);
2286 mTaperD = taper;
2287 for (int i = 0; i < 3; ++i) {
2288 *vd++ = translate[i]; //translation
2289 *vf++ = static_cast<float>(translate[i]);
2290 for (int j = 0; j < 3; ++j) {
2291 *md++ = mat[j][i]; //transposed
2292 *mid++ = invMat[j][i];
2293 *mf++ = static_cast<float>(mat[j][i]);
2294 *mif++ = static_cast<float>(invMat[j][i]);
2295 }
2296 }
2297}
2298
2299template<typename Vec3T>
2300__hostdev__ inline void Map::set(double dx, const Vec3T &trans, double taper)
2301{
2302 const double mat[3][3] = {
2303 {dx, 0.0, 0.0}, // row 0
2304 {0.0, dx, 0.0}, // row 1
2305 {0.0, 0.0, dx}, // row 2
2306 }, idx = 1.0/dx, invMat[3][3] = {
2307 {idx, 0.0, 0.0}, // row 0
2308 {0.0, idx, 0.0}, // row 1
2309 {0.0, 0.0, idx}, // row 2
2310 };
2311 this->set(mat, invMat, trans, taper);
2312}
2313
2314// ----------------------------> GridBlindMetaData <--------------------------------------
2315
2316struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridBlindMetaData
2317{
2318 static const int MaxNameSize = 256;// due to NULL termination the maximum length is one less!
2319 int64_t mByteOffset; // byte offset to the blind data, relative to the GridData.
2320 uint64_t mElementCount; // number of elements, e.g. point count
2321 uint32_t mFlags; // flags
2322 GridBlindDataSemantic mSemantic; // semantic meaning of the data.
2325 char mName[MaxNameSize];// note this include the NULL termination
2326
2327 /// @brief return memory usage in bytes for the class (note this computes for all blindMetaData structures.)
2328 __hostdev__ static uint64_t memUsage(uint64_t blindDataCount = 0)
2329 {
2330 return blindDataCount * sizeof(GridBlindMetaData);
2331 }
2332
2333 __hostdev__ void setBlindData(void *ptr) { mByteOffset = PtrDiff(ptr, this); }
2334
2335 template <typename T>
2336 __hostdev__ const T* getBlindData() const { return PtrAdd<T>(this, mByteOffset); }
2337
2338}; // GridBlindMetaData
2339
2340// ----------------------------> NodeTrait <--------------------------------------
2341
2342/// @brief Struct to derive node type from its level in a given
2343/// grid, tree or root while preserving constness
2344template<typename GridOrTreeOrRootT, int LEVEL>
2346
2347// Partial template specialization of above Node struct
2348template<typename GridOrTreeOrRootT>
2349struct NodeTrait<GridOrTreeOrRootT, 0>
2350{
2351 static_assert(GridOrTreeOrRootT::RootType::LEVEL == 3, "Tree depth is not supported");
2352 using Type = typename GridOrTreeOrRootT::LeafNodeType;
2353 using type = typename GridOrTreeOrRootT::LeafNodeType;
2354};
2355template<typename GridOrTreeOrRootT>
2356struct NodeTrait<const GridOrTreeOrRootT, 0>
2357{
2358 static_assert(GridOrTreeOrRootT::RootType::LEVEL == 3, "Tree depth is not supported");
2359 using Type = const typename GridOrTreeOrRootT::LeafNodeType;
2360 using type = const typename GridOrTreeOrRootT::LeafNodeType;
2361};
2362
2363template<typename GridOrTreeOrRootT>
2364struct NodeTrait<GridOrTreeOrRootT, 1>
2365{
2366 static_assert(GridOrTreeOrRootT::RootType::LEVEL == 3, "Tree depth is not supported");
2367 using Type = typename GridOrTreeOrRootT::RootType::ChildNodeType::ChildNodeType;
2368 using type = typename GridOrTreeOrRootT::RootType::ChildNodeType::ChildNodeType;
2369};
2370template<typename GridOrTreeOrRootT>
2371struct NodeTrait<const GridOrTreeOrRootT, 1>
2372{
2373 static_assert(GridOrTreeOrRootT::RootType::LEVEL == 3, "Tree depth is not supported");
2374 using Type = const typename GridOrTreeOrRootT::RootType::ChildNodeType::ChildNodeType;
2375 using type = const typename GridOrTreeOrRootT::RootType::ChildNodeType::ChildNodeType;
2376};
2377template<typename GridOrTreeOrRootT>
2378struct NodeTrait<GridOrTreeOrRootT, 2>
2379{
2380 static_assert(GridOrTreeOrRootT::RootType::LEVEL == 3, "Tree depth is not supported");
2381 using Type = typename GridOrTreeOrRootT::RootType::ChildNodeType;
2382 using type = typename GridOrTreeOrRootT::RootType::ChildNodeType;
2383};
2384template<typename GridOrTreeOrRootT>
2385struct NodeTrait<const GridOrTreeOrRootT, 2>
2386{
2387 static_assert(GridOrTreeOrRootT::RootType::LEVEL == 3, "Tree depth is not supported");
2388 using Type = const typename GridOrTreeOrRootT::RootType::ChildNodeType;
2389 using type = const typename GridOrTreeOrRootT::RootType::ChildNodeType;
2390};
2391template<typename GridOrTreeOrRootT>
2392struct NodeTrait<GridOrTreeOrRootT, 3>
2393{
2394 static_assert(GridOrTreeOrRootT::RootType::LEVEL == 3, "Tree depth is not supported");
2395 using Type = typename GridOrTreeOrRootT::RootType;
2396 using type = typename GridOrTreeOrRootT::RootType;
2397};
2398
2399template<typename GridOrTreeOrRootT>
2400struct NodeTrait<const GridOrTreeOrRootT, 3>
2401{
2402 static_assert(GridOrTreeOrRootT::RootType::LEVEL == 3, "Tree depth is not supported");
2403 using Type = const typename GridOrTreeOrRootT::RootType;
2404 using type = const typename GridOrTreeOrRootT::RootType;
2405};
2406
2407// ----------------------------> Grid <--------------------------------------
2408
2409/*
2410 The following class and comment is for internal use only
2411
2412 Memory layout:
2413
2414 Grid -> 39 x double (world bbox and affine transformation)
2415 Tree -> Root 3 x ValueType + int32_t + N x Tiles (background,min,max,tileCount + tileCount x Tiles)
2416
2417 N2 upper InternalNodes each with 2 bit masks, N2 tiles, and min/max values
2418
2419 N1 lower InternalNodes each with 2 bit masks, N1 tiles, and min/max values
2420
2421 N0 LeafNodes each with a bit mask, N0 ValueTypes and min/max
2422
2423 Example layout: ("---" implies it has a custom offset, "..." implies zero or more)
2424 [GridData][TreeData]---[RootData][ROOT TILES...]---[NodeData<5>]---[ModeData<4>]---[LeafData<3>]---[BLINDMETA...]---[BLIND0]---[BLIND1]---etc.
2425*/
2426
2427/// @brief Struct with all the member data of the Grid (useful during serialization of an openvdb grid)
2428///
2429/// @note The transform is assumed to be affine (so linear) and have uniform scale! So frustum transforms
2430/// and non-uniform scaling are not supported (primarily because they complicate ray-tracing in index space)
2431///
2432/// @note No client code should (or can) interface with this struct so it can safely be ignored!
2433struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) GridData
2434{// sizeof(GridData) = 672B
2435 static const int MaxNameSize = 256;// due to NULL termination the maximum length is one less
2436 uint64_t mMagic; // 8B (0) magic to validate it is valid grid data.
2437 uint64_t mChecksum; // 8B (8). Checksum of grid buffer.
2438 Version mVersion;// 4B (16) major, minor, and patch version numbers
2439 uint32_t mFlags; // 4B (20). flags for grid.
2440 uint32_t mGridIndex; // 4B (24). Index of this grid in the buffer
2441 uint32_t mGridCount; // 4B (28). Total number of grids in the buffer
2442 uint64_t mGridSize; // 8B (32). byte count of this entire grid occupied in the buffer.
2443 char mGridName[MaxNameSize]; // 256B (40)
2444 Map mMap; // 264B (296). affine transformation between index and world space in both single and double precision
2445 BBox<Vec3R> mWorldBBox; // 48B (560). floating-point AABB of active values in WORLD SPACE (2 x 3 doubles)
2446 Vec3R mVoxelSize; // 24B (608). size of a voxel in world units
2447 GridClass mGridClass; // 4B (632).
2448 GridType mGridType; // 4B (636).
2449 int64_t mBlindMetadataOffset; // 8B (640). offset of GridBlindMetaData structures that follow this grid.
2450 uint32_t mBlindMetadataCount; // 4B (648). count of GridBlindMetaData structures that follow this grid.
2451 uint32_t mData0;// 4B (652)
2452 uint64_t mData1, mData2;// 2x8B (656) padding to 32 B alignment. mData1 is use for the total number of values indexed by an IndexGrid
2453
2454 // Set and unset various bit flags
2455 __hostdev__ void setFlagsOff() { mFlags = uint32_t(0); }
2456 __hostdev__ void setMinMaxOn(bool on = true)
2457 {
2458 if (on) {
2459 mFlags |= static_cast<uint32_t>(GridFlags::HasMinMax);
2460 } else {
2461 mFlags &= ~static_cast<uint32_t>(GridFlags::HasMinMax);
2462 }
2463 }
2464 __hostdev__ void setBBoxOn(bool on = true)
2465 {
2466 if (on) {
2467 mFlags |= static_cast<uint32_t>(GridFlags::HasBBox);
2468 } else {
2469 mFlags &= ~static_cast<uint32_t>(GridFlags::HasBBox);
2470 }
2471 }
2472 __hostdev__ void setLongGridNameOn(bool on = true)
2473 {
2474 if (on) {
2475 mFlags |= static_cast<uint32_t>(GridFlags::HasLongGridName);
2476 } else {
2477 mFlags &= ~static_cast<uint32_t>(GridFlags::HasLongGridName);
2478 }
2479 }
2480 __hostdev__ void setAverageOn(bool on = true)
2481 {
2482 if (on) {
2483 mFlags |= static_cast<uint32_t>(GridFlags::HasAverage);
2484 } else {
2485 mFlags &= ~static_cast<uint32_t>(GridFlags::HasAverage);
2486 }
2487 }
2488 __hostdev__ void setStdDeviationOn(bool on = true)
2489 {
2490 if (on) {
2491 mFlags |= static_cast<uint32_t>(GridFlags::HasStdDeviation);
2492 } else {
2493 mFlags &= ~static_cast<uint32_t>(GridFlags::HasStdDeviation);
2494 }
2495 }
2496 __hostdev__ void setBreadthFirstOn(bool on = true)
2497 {
2498 if (on) {
2499 mFlags |= static_cast<uint32_t>(GridFlags::IsBreadthFirst);
2500 } else {
2501 mFlags &= ~static_cast<uint32_t>(GridFlags::IsBreadthFirst);
2502 }
2503 }
2504
2505 // Affine transformations based on double precision
2506 template<typename Vec3T>
2507 __hostdev__ Vec3T applyMap(const Vec3T& xyz) const { return mMap.applyMap(xyz); } // Pos: index -> world
2508 template<typename Vec3T>
2509 __hostdev__ Vec3T applyInverseMap(const Vec3T& xyz) const { return mMap.applyInverseMap(xyz); } // Pos: world -> index
2510 template<typename Vec3T>
2511 __hostdev__ Vec3T applyJacobian(const Vec3T& xyz) const { return mMap.applyJacobian(xyz); } // Dir: index -> world
2512 template<typename Vec3T>
2513 __hostdev__ Vec3T applyInverseJacobian(const Vec3T& xyz) const { return mMap.applyInverseJacobian(xyz); } // Dir: world -> index
2514 template<typename Vec3T>
2515 __hostdev__ Vec3T applyIJT(const Vec3T& xyz) const { return mMap.applyIJT(xyz); }
2516 // Affine transformations based on single precision
2517 template<typename Vec3T>
2518 __hostdev__ Vec3T applyMapF(const Vec3T& xyz) const { return mMap.applyMapF(xyz); } // Pos: index -> world
2519 template<typename Vec3T>
2520 __hostdev__ Vec3T applyInverseMapF(const Vec3T& xyz) const { return mMap.applyInverseMapF(xyz); } // Pos: world -> index
2521 template<typename Vec3T>
2522 __hostdev__ Vec3T applyJacobianF(const Vec3T& xyz) const { return mMap.applyJacobianF(xyz); } // Dir: index -> world
2523 template<typename Vec3T>
2524 __hostdev__ Vec3T applyInverseJacobianF(const Vec3T& xyz) const { return mMap.applyInverseJacobianF(xyz); } // Dir: world -> index
2525 template<typename Vec3T>
2526 __hostdev__ Vec3T applyIJTF(const Vec3T& xyz) const { return mMap.applyIJTF(xyz); }
2527
2528 // @brief Return a non-const void pointer to the tree
2529 __hostdev__ void* treePtr() { return this + 1; }
2530
2531 // @brief Return a const void pointer to the tree
2532 __hostdev__ const void* treePtr() const { return this + 1; }
2533
2534 /// @brief Returns a const reference to the blindMetaData at the specified linear offset.
2535 ///
2536 /// @warning The linear offset is assumed to be in the valid range
2538 {
2539 NANOVDB_ASSERT(n < mBlindMetadataCount);
2540 return PtrAdd<GridBlindMetaData>(this, mBlindMetadataOffset) + n;
2541 }
2542
2543}; // GridData
2544
2545// Forward declaration of accelerated random access class
2546template <typename BuildT, int LEVEL0 = -1, int LEVEL1 = -1, int LEVEL2 = -1>
2548
2549template <typename BuildT>
2551
2552/// @brief Highest level of the data structure. Contains a tree and a world->index
2553/// transform (that currently only supports uniform scaling and translation).
2554///
2555/// @note This the API of this class to interface with client code
2556template<typename TreeT>
2557class Grid : private GridData
2558{
2559public:
2560 using TreeType = TreeT;
2561 using RootType = typename TreeT::RootType;
2563 using ValueType = typename TreeT::ValueType;
2564 using BuildType = typename TreeT::BuildType;// in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool
2565 using CoordType = typename TreeT::CoordType;
2567
2568 /// @brief Disallow constructions, copy and assignment
2569 ///
2570 /// @note Only a Serializer, defined elsewhere, can instantiate this class
2571 Grid(const Grid&) = delete;
2572 Grid& operator=(const Grid&) = delete;
2573 ~Grid() = delete;
2574
2575 __hostdev__ Version version() const { return DataType::mVersion; }
2576
2577 __hostdev__ DataType* data() { return reinterpret_cast<DataType*>(this); }
2578
2579 __hostdev__ const DataType* data() const { return reinterpret_cast<const DataType*>(this); }
2580
2581 /// @brief Return memory usage in bytes for this class only.
2582 __hostdev__ static uint64_t memUsage() { return sizeof(GridData); }
2583
2584 /// @brief Return the memory footprint of the entire grid, i.e. including all nodes and blind data
2585 __hostdev__ uint64_t gridSize() const { return DataType::mGridSize; }
2586
2587 /// @brief Return index of this grid in the buffer
2588 __hostdev__ uint32_t gridIndex() const { return DataType::mGridIndex; }
2589
2590 /// @brief Return total number of grids in the buffer
2591 __hostdev__ uint32_t gridCount() const { return DataType::mGridCount; }
2592
2593 /// @brief @brief Return the total number of values indexed by this IndexGrid
2594 ///
2595 /// @note This method is only defined for IndexGrid = NanoGrid<ValueIndex>
2596 template <typename T = BuildType>
2597 __hostdev__ typename enable_if<is_same<T, ValueIndex>::value, const uint64_t&>::type valueCount() const {return DataType::mData1;}
2598
2599 /// @brief Return a const reference to the tree
2600 __hostdev__ const TreeT& tree() const { return *reinterpret_cast<const TreeT*>(this->treePtr()); }
2601
2602 /// @brief Return a non-const reference to the tree
2603 __hostdev__ TreeT& tree() { return *reinterpret_cast<TreeT*>(this->treePtr()); }
2604
2605 /// @brief Return a new instance of a ReadAccessor used to access values in this grid
2606 __hostdev__ AccessorType getAccessor() const { return AccessorType(this->tree().root()); }
2607
2608 /// @brief Return a const reference to the size of a voxel in world units
2609 __hostdev__ const Vec3R& voxelSize() const { return DataType::mVoxelSize; }
2610
2611 /// @brief Return a const reference to the Map for this grid
2612 __hostdev__ const Map& map() const { return DataType::mMap; }
2613
2614 /// @brief world to index space transformation
2615 template<typename Vec3T>
2616 __hostdev__ Vec3T worldToIndex(const Vec3T& xyz) const { return this->applyInverseMap(xyz); }
2617
2618 /// @brief index to world space transformation
2619 template<typename Vec3T>
2620 __hostdev__ Vec3T indexToWorld(const Vec3T& xyz) const { return this->applyMap(xyz); }
2621
2622 /// @brief transformation from index space direction to world space direction
2623 /// @warning assumes dir to be normalized
2624 template<typename Vec3T>
2625 __hostdev__ Vec3T indexToWorldDir(const Vec3T& dir) const { return this->applyJacobian(dir); }
2626
2627 /// @brief transformation from world space direction to index space direction
2628 /// @warning assumes dir to be normalized
2629 template<typename Vec3T>
2630 __hostdev__ Vec3T worldToIndexDir(const Vec3T& dir) const { return this->applyInverseJacobian(dir); }
2631
2632 /// @brief transform the gradient from index space to world space.
2633 /// @details Applies the inverse jacobian transform map.
2634 template<typename Vec3T>
2635 __hostdev__ Vec3T indexToWorldGrad(const Vec3T& grad) const { return this->applyIJT(grad); }
2636
2637 /// @brief world to index space transformation
2638 template<typename Vec3T>
2639 __hostdev__ Vec3T worldToIndexF(const Vec3T& xyz) const { return this->applyInverseMapF(xyz); }
2640
2641 /// @brief index to world space transformation
2642 template<typename Vec3T>
2643 __hostdev__ Vec3T indexToWorldF(const Vec3T& xyz) const { return this->applyMapF(xyz); }
2644
2645 /// @brief transformation from index space direction to world space direction
2646 /// @warning assumes dir to be normalized
2647 template<typename Vec3T>
2648 __hostdev__ Vec3T indexToWorldDirF(const Vec3T& dir) const { return this->applyJacobianF(dir); }
2649
2650 /// @brief transformation from world space direction to index space direction
2651 /// @warning assumes dir to be normalized
2652 template<typename Vec3T>
2653 __hostdev__ Vec3T worldToIndexDirF(const Vec3T& dir) const { return this->applyInverseJacobianF(dir); }
2654
2655 /// @brief Transforms the gradient from index space to world space.
2656 /// @details Applies the inverse jacobian transform map.
2657 template<typename Vec3T>
2658 __hostdev__ Vec3T indexToWorldGradF(const Vec3T& grad) const { return DataType::applyIJTF(grad); }
2659
2660 /// @brief Computes a AABB of active values in world space
2661 __hostdev__ const BBox<Vec3R>& worldBBox() const { return DataType::mWorldBBox; }
2662
2663 /// @brief Computes a AABB of active values in index space
2664 ///
2665 /// @note This method is returning a floating point bounding box and not a CoordBBox. This makes
2666 /// it more useful for clipping rays.
2667 __hostdev__ const BBox<CoordType>& indexBBox() const { return this->tree().bbox(); }
2668
2669 /// @brief Return the total number of active voxels in this tree.
2670 __hostdev__ uint64_t activeVoxelCount() const { return this->tree().activeVoxelCount(); }
2671
2672 /// @brief Methods related to the classification of this grid
2673 __hostdev__ bool isValid() const { return DataType::mMagic == NANOVDB_MAGIC_NUMBER; }
2674 __hostdev__ const GridType& gridType() const { return DataType::mGridType; }
2675 __hostdev__ const GridClass& gridClass() const { return DataType::mGridClass; }
2676 __hostdev__ bool isLevelSet() const { return DataType::mGridClass == GridClass::LevelSet; }
2677 __hostdev__ bool isFogVolume() const { return DataType::mGridClass == GridClass::FogVolume; }
2678 __hostdev__ bool isStaggered() const { return DataType::mGridClass == GridClass::Staggered; }
2679 __hostdev__ bool isPointIndex() const { return DataType::mGridClass == GridClass::PointIndex; }
2680 __hostdev__ bool isGridIndex() const { return DataType::mGridClass == GridClass::IndexGrid; }
2681 __hostdev__ bool isPointData() const { return DataType::mGridClass == GridClass::PointData; }
2682 __hostdev__ bool isMask() const { return DataType::mGridClass == GridClass::Topology; }
2683 __hostdev__ bool isUnknown() const { return DataType::mGridClass == GridClass::Unknown; }
2684 __hostdev__ bool hasMinMax() const { return DataType::mFlags & static_cast<uint32_t>(GridFlags::HasMinMax); }
2685 __hostdev__ bool hasBBox() const { return DataType::mFlags & static_cast<uint32_t>(GridFlags::HasBBox); }
2686 __hostdev__ bool hasLongGridName() const { return DataType::mFlags & static_cast<uint32_t>(GridFlags::HasLongGridName); }
2687 __hostdev__ bool hasAverage() const { return DataType::mFlags & static_cast<uint32_t>(GridFlags::HasAverage); }
2688 __hostdev__ bool hasStdDeviation() const { return DataType::mFlags & static_cast<uint32_t>(GridFlags::HasStdDeviation); }
2689 __hostdev__ bool isBreadthFirst() const { return DataType::mFlags & static_cast<uint32_t>(GridFlags::IsBreadthFirst); }
2690
2691 /// @brief return true if the specified node type is layed out breadth-first in memory and has a fixed size.
2692 /// This allows for sequential access to the nodes.
2693 template <typename NodeT>
2694 __hostdev__ bool isSequential() const { return NodeT::FIXED_SIZE && this->isBreadthFirst(); }
2695
2696 /// @brief return true if the specified node level is layed out breadth-first in memory and has a fixed size.
2697 /// This allows for sequential access to the nodes.
2698 template <int LEVEL>
2699 __hostdev__ bool isSequential() const { return NodeTrait<TreeT,LEVEL>::type::FIXED_SIZE && this->isBreadthFirst(); }
2700
2701 /// @brief Return a c-string with the name of this grid
2702 __hostdev__ const char* gridName() const
2703 {
2704 if (this->hasLongGridName()) {
2705 NANOVDB_ASSERT(DataType::mBlindMetadataCount>0);
2706 const auto &metaData = this->blindMetaData(DataType::mBlindMetadataCount-1);// always the last
2707 NANOVDB_ASSERT(metaData.mDataClass == GridBlindDataClass::GridName);
2708 return metaData.template getBlindData<const char>();
2709 }
2710 return DataType::mGridName;
2711 }
2712
2713 /// @brief Return a c-string with the name of this grid, truncated to 255 characters
2714 __hostdev__ const char* shortGridName() const { return DataType::mGridName; }
2715
2716 /// @brief Return checksum of the grid buffer.
2717 __hostdev__ uint64_t checksum() const { return DataType::mChecksum; }
2718
2719 /// @brief Return true if this grid is empty, i.e. contains no values or nodes.
2720 __hostdev__ bool isEmpty() const { return this->tree().isEmpty(); }
2721
2722 /// @brief Return the count of blind-data encoded in this grid
2723 __hostdev__ uint32_t blindDataCount() const { return DataType::mBlindMetadataCount; }
2724
2725 /// @brief Return the index of the blind data with specified semantic if found, otherwise -1.
2726 __hostdev__ int findBlindDataForSemantic(GridBlindDataSemantic semantic) const;
2727
2728 /// @brief Returns a const pointer to the blindData at the specified linear offset.
2729 ///
2730 /// @warning Point might be NULL and the linear offset is assumed to be in the valid range
2731 __hostdev__ const void* blindData(uint32_t n) const
2732 {
2733 if (DataType::mBlindMetadataCount == 0u) {
2734 return nullptr;
2735 }
2736 NANOVDB_ASSERT(n < DataType::mBlindMetadataCount);
2737 return this->blindMetaData(n).template getBlindData<void>();
2738 }
2739
2740 __hostdev__ const GridBlindMetaData& blindMetaData(uint32_t n) const { return *DataType::blindMetaData(n); }
2741
2742private:
2743 static_assert(sizeof(GridData) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(GridData) is misaligned");
2744}; // Class Grid
2745
2746template<typename TreeT>
2748{
2749 for (uint32_t i = 0, n = this->blindDataCount(); i < n; ++i)
2750 if (this->blindMetaData(i).mSemantic == semantic)
2751 return int(i);
2752 return -1;
2753}
2754
2755// ----------------------------> Tree <--------------------------------------
2756
2757template<int ROOT_LEVEL = 3>
2758struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) TreeData
2759{// sizeof(TreeData<3>) == 64B
2760 static_assert(ROOT_LEVEL == 3, "Root level is assumed to be three");
2761 uint64_t mNodeOffset[4];//32B, byte offset from this tree to first leaf, lower, upper and root node
2762 uint32_t mNodeCount[3];// 12B, total number of nodes of type: leaf, lower internal, upper internal
2763 uint32_t mTileCount[3];// 12B, total number of active tile values at the lower internal, upper internal and root node levels
2764 uint64_t mVoxelCount;// 8B, total number of active voxels in the root and all its child nodes.
2765 // No padding since it's always 32B aligned
2766 template <typename RootT>
2767 __hostdev__ void setRoot(const RootT* root) { mNodeOffset[3] = PtrDiff(root, this); }
2768 template <typename RootT>
2769 __hostdev__ RootT* getRoot() { return PtrAdd<RootT>(this, mNodeOffset[3]); }
2770 template <typename RootT>
2771 __hostdev__ const RootT* getRoot() const { return PtrAdd<RootT>(this, mNodeOffset[3]); }
2772
2773 template <typename NodeT>
2774 __hostdev__ void setFirstNode(const NodeT* node)
2775 {
2776 mNodeOffset[NodeT::LEVEL] = node ? PtrDiff(node, this) : 0;
2777 }
2778};
2779
2780// ----------------------------> GridTree <--------------------------------------
2781
2782/// @brief defines a tree type from a grid type while preserving constness
2783template<typename GridT>
2785{
2786 using Type = typename GridT::TreeType;
2787 using type = typename GridT::TreeType;
2788};
2789template<typename GridT>
2790struct GridTree<const GridT>
2791{
2792 using Type = const typename GridT::TreeType;
2793 using type = const typename GridT::TreeType;
2794};
2795
2796// ----------------------------> Tree <--------------------------------------
2797
2798/// @brief VDB Tree, which is a thin wrapper around a RootNode.
2799template<typename RootT>
2800class Tree : private TreeData<RootT::LEVEL>
2801{
2802 static_assert(RootT::LEVEL == 3, "Tree depth is not supported");
2803 static_assert(RootT::ChildNodeType::LOG2DIM == 5, "Tree configuration is not supported");
2804 static_assert(RootT::ChildNodeType::ChildNodeType::LOG2DIM == 4, "Tree configuration is not supported");
2805 static_assert(RootT::LeafNodeType::LOG2DIM == 3, "Tree configuration is not supported");
2806
2807public:
2809 using RootType = RootT;
2810 using LeafNodeType = typename RootT::LeafNodeType;
2811 using ValueType = typename RootT::ValueType;
2812 using BuildType = typename RootT::BuildType;// in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool
2813 using CoordType = typename RootT::CoordType;
2815
2816 using Node3 = RootT;
2817 using Node2 = typename RootT::ChildNodeType;
2818 using Node1 = typename Node2::ChildNodeType;
2820
2821 /// @brief This class cannot be constructed or deleted
2822 Tree() = delete;
2823 Tree(const Tree&) = delete;
2824 Tree& operator=(const Tree&) = delete;
2825 ~Tree() = delete;
2826
2827 __hostdev__ DataType* data() { return reinterpret_cast<DataType*>(this); }
2828
2829 __hostdev__ const DataType* data() const { return reinterpret_cast<const DataType*>(this); }
2830
2831 /// @brief return memory usage in bytes for the class
2832 __hostdev__ static uint64_t memUsage() { return sizeof(DataType); }
2833
2834 __hostdev__ RootT& root() { return *DataType::template getRoot<RootT>(); }
2835
2836 __hostdev__ const RootT& root() const { return *DataType::template getRoot<RootT>(); }
2837
2838 __hostdev__ AccessorType getAccessor() const { return AccessorType(this->root()); }
2839
2840 /// @brief Return the value of the given voxel (regardless of state or location in the tree.)
2841 __hostdev__ ValueType getValue(const CoordType& ijk) const { return this->root().getValue(ijk); }
2842
2843 /// @brief Return the active state of the given voxel (regardless of state or location in the tree.)
2844 __hostdev__ bool isActive(const CoordType& ijk) const { return this->root().isActive(ijk); }
2845
2846 /// @brief Return true if this tree is empty, i.e. contains no values or nodes
2847 __hostdev__ bool isEmpty() const { return this->root().isEmpty(); }
2848
2849 /// @brief Combines the previous two methods in a single call
2850 __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const { return this->root().probeValue(ijk, v); }
2851
2852 /// @brief Return a const reference to the background value.
2853 __hostdev__ const ValueType& background() const { return this->root().background(); }
2854
2855 /// @brief Sets the extrema values of all the active values in this tree, i.e. in all nodes of the tree
2856 __hostdev__ void extrema(ValueType& min, ValueType& max) const;
2857
2858 /// @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
2859 __hostdev__ const BBox<CoordType>& bbox() const { return this->root().bbox(); }
2860
2861 /// @brief Return the total number of active voxels in this tree.
2862 __hostdev__ uint64_t activeVoxelCount() const { return DataType::mVoxelCount; }
2863
2864 /// @brief Return the total number of active tiles at the specified level of the tree.
2865 ///
2866 /// @details level = 1,2,3 corresponds to active tile count in lower internal nodes, upper
2867 /// internal nodes, and the root level. Note active values at the leaf level are
2868 /// referred to as active voxels (see activeVoxelCount defined above).
2869 __hostdev__ const uint32_t& activeTileCount(uint32_t level) const
2870 {
2871 NANOVDB_ASSERT(level > 0 && level <= 3);// 1, 2, or 3
2872 return DataType::mTileCount[level - 1];
2873 }
2874
2875 template<typename NodeT>
2876 __hostdev__ uint32_t nodeCount() const
2877 {
2878 static_assert(NodeT::LEVEL < 3, "Invalid NodeT");
2879 return DataType::mNodeCount[NodeT::LEVEL];
2880 }
2881
2882 __hostdev__ uint32_t nodeCount(int level) const
2883 {
2884 NANOVDB_ASSERT(level < 3);
2885 return DataType::mNodeCount[level];
2886 }
2887
2888 /// @brief return a pointer to the first node of the specified type
2889 ///
2890 /// @warning Note it may return NULL if no nodes exist
2891 template <typename NodeT>
2893 {
2894 const uint64_t offset = DataType::mNodeOffset[NodeT::LEVEL];
2895 return offset>0 ? PtrAdd<NodeT>(this, offset) : nullptr;
2896 }
2897
2898 /// @brief return a const pointer to the first node of the specified type
2899 ///
2900 /// @warning Note it may return NULL if no nodes exist
2901 template <typename NodeT>
2902 __hostdev__ const NodeT* getFirstNode() const
2903 {
2904 const uint64_t offset = DataType::mNodeOffset[NodeT::LEVEL];
2905 return offset>0 ? PtrAdd<NodeT>(this, offset) : nullptr;
2906 }
2907
2908 /// @brief return a pointer to the first node at the specified level
2909 ///
2910 /// @warning Note it may return NULL if no nodes exist
2911 template <int LEVEL>
2914 {
2915 return this->template getFirstNode<typename NodeTrait<RootT,LEVEL>::type>();
2916 }
2917
2918 /// @brief return a const pointer to the first node of the specified level
2919 ///
2920 /// @warning Note it may return NULL if no nodes exist
2921 template <int LEVEL>
2924 {
2925 return this->template getFirstNode<typename NodeTrait<RootT,LEVEL>::type>();
2926 }
2927
2928 /// @brief Template specializations of getFirstNode
2929 __hostdev__ LeafNodeType* getFirstLeaf() {return this->getFirstNode<LeafNodeType>();}
2930 __hostdev__ const LeafNodeType* getFirstLeaf() const {return this->getFirstNode<LeafNodeType>();}
2931 __hostdev__ typename NodeTrait<RootT, 1>::type* getFirstLower() {return this->getFirstNode<1>();}
2932 __hostdev__ const typename NodeTrait<RootT, 1>::type* getFirstLower() const {return this->getFirstNode<1>();}
2933 __hostdev__ typename NodeTrait<RootT, 2>::type* getFirstUpper() {return this->getFirstNode<2>();}
2934 __hostdev__ const typename NodeTrait<RootT, 2>::type* getFirstUpper() const {return this->getFirstNode<2>();}
2935
2936private:
2937 static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(TreeData) is misaligned");
2938
2939}; // Tree class
2940
2941template<typename RootT>
2943{
2944 min = this->root().minimum();
2945 max = this->root().maximum();
2946}
2947
2948// --------------------------> RootNode <------------------------------------
2949
2950/// @brief Struct with all the member data of the RootNode (useful during serialization of an openvdb RootNode)
2951///
2952/// @note No client code should (or can) interface with this struct so it can safely be ignored!
2953template<typename ChildT>
2954struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) RootData
2955{
2956 using ValueT = typename ChildT::ValueType;
2957 using BuildT = typename ChildT::BuildType;// in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool
2958 using CoordT = typename ChildT::CoordType;
2959 using StatsT = typename ChildT::FloatType;
2960 static constexpr bool FIXED_SIZE = false;
2961
2962 /// @brief Return a key based on the coordinates of a voxel
2963#ifdef USE_SINGLE_ROOT_KEY
2964 using KeyT = uint64_t;
2965 template <typename CoordType>
2966 __hostdev__ static KeyT CoordToKey(const CoordType& ijk)
2967 {
2968 static_assert(sizeof(CoordT) == sizeof(CoordType), "Mismatching sizeof");
2969 static_assert(32 - ChildT::TOTAL <= 21, "Cannot use 64 bit root keys");
2970 return (KeyT(uint32_t(ijk[2]) >> ChildT::TOTAL)) | // z is the lower 21 bits
2971 (KeyT(uint32_t(ijk[1]) >> ChildT::TOTAL) << 21) | // y is the middle 21 bits
2972 (KeyT(uint32_t(ijk[0]) >> ChildT::TOTAL) << 42); // x is the upper 21 bits
2973 }
2975 {
2976 static constexpr uint64_t MASK = (1u << 21) - 1;
2977 return CoordT(((key >> 42) & MASK) << ChildT::TOTAL,
2978 ((key >> 21) & MASK) << ChildT::TOTAL,
2979 (key & MASK) << ChildT::TOTAL);
2980 }
2981#else
2982 using KeyT = CoordT;
2983 __hostdev__ static KeyT CoordToKey(const CoordT& ijk) { return ijk & ~ChildT::MASK; }
2984 __hostdev__ static CoordT KeyToCoord(const KeyT& key) { return key; }
2985#endif
2986 BBox<CoordT> mBBox; // 24B. AABB of active values in index space.
2987 uint32_t mTableSize; // 4B. number of tiles and child pointers in the root node
2988
2989 ValueT mBackground; // background value, i.e. value of any unset voxel
2990 ValueT mMinimum; // typically 4B, minimum of all the active values
2991 ValueT mMaximum; // typically 4B, maximum of all the active values
2992 StatsT mAverage; // typically 4B, average of all the active values in this node and its child nodes
2993 StatsT mStdDevi; // typically 4B, standard deviation of all the active values in this node and its child nodes
2994
2995 /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment
2996 ///
2997 /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members.
2998 __hostdev__ static constexpr uint32_t padding() {
2999 return sizeof(RootData) - (24 + 4 + 3*sizeof(ValueT) + 2*sizeof(StatsT));
3000 }
3001
3002 struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) Tile
3003 {
3004 template <typename CoordType>
3005 __hostdev__ void setChild(const CoordType& k, const ChildT *ptr, const RootData *data)
3006 {
3007 key = CoordToKey(k);
3008 child = PtrDiff(ptr, data);
3009 }
3010 template <typename CoordType, typename ValueType>
3011 __hostdev__ void setValue(const CoordType& k, bool s, const ValueType &v)
3012 {
3013 key = CoordToKey(k);
3014 state = s;
3015 value = v;
3016 child = 0;
3017 }
3018 __hostdev__ bool isChild() const { return child!=0; }
3019 __hostdev__ bool isValue() const { return child==0; }
3020 __hostdev__ bool isActive() const { return child==0 && state; }
3021 __hostdev__ CoordT origin() const { return KeyToCoord(key); }
3022 KeyT key; // USE_SINGLE_ROOT_KEY ? 8B : 12B
3023 int64_t child; // 8B. signed byte offset from this node to the child node. 0 means it is a constant tile, so use value.
3024 uint32_t state; // 4B. state of tile value
3025 ValueT value; // value of tile (i.e. no child node)
3026 }; // Tile
3027
3028 /// @brief Returns a non-const reference to the tile at the specified linear offset.
3029 ///
3030 /// @warning The linear offset is assumed to be in the valid range
3031 __hostdev__ const Tile* tile(uint32_t n) const
3032 {
3033 NANOVDB_ASSERT(n < mTableSize);
3034 return reinterpret_cast<const Tile*>(this + 1) + n;
3035 }
3036 __hostdev__ Tile* tile(uint32_t n)
3037 {
3038 NANOVDB_ASSERT(n < mTableSize);
3039 return reinterpret_cast<Tile*>(this + 1) + n;
3040 }
3041
3042 /// @brief Returns a const reference to the child node in the specified tile.
3043 ///
3044 /// @warning A child node is assumed to exist in the specified tile
3045 __hostdev__ ChildT* getChild(const Tile* tile)
3046 {
3047 NANOVDB_ASSERT(tile->child);
3048 return PtrAdd<ChildT>(this, tile->child);
3049 }
3050 __hostdev__ const ChildT* getChild(const Tile* tile) const
3051 {
3052 NANOVDB_ASSERT(tile->child);
3053 return PtrAdd<ChildT>(this, tile->child);
3054 }
3055
3056 __hostdev__ const ValueT& getMin() const { return mMinimum; }
3057 __hostdev__ const ValueT& getMax() const { return mMaximum; }
3058 __hostdev__ const StatsT& average() const { return mAverage; }
3059 __hostdev__ const StatsT& stdDeviation() const { return mStdDevi; }
3060
3061 __hostdev__ void setMin(const ValueT& v) { mMinimum = v; }
3062 __hostdev__ void setMax(const ValueT& v) { mMaximum = v; }
3063 __hostdev__ void setAvg(const StatsT& v) { mAverage = v; }
3064 __hostdev__ void setDev(const StatsT& v) { mStdDevi = v; }
3065
3066 /// @brief This class cannot be constructed or deleted
3067 RootData() = delete;
3068 RootData(const RootData&) = delete;
3069 RootData& operator=(const RootData&) = delete;
3070 ~RootData() = delete;
3071}; // RootData
3072
3073/// @brief Top-most node of the VDB tree structure.
3074template<typename ChildT>
3075class RootNode : private RootData<ChildT>
3076{
3077public:
3079 using LeafNodeType = typename ChildT::LeafNodeType;
3080 using ChildNodeType = ChildT;
3081 using RootType = RootNode<ChildT>;// this allows RootNode to behave like a Tree
3082
3083 using ValueType = typename DataType::ValueT;
3084 using FloatType = typename DataType::StatsT;
3085 using BuildType = typename DataType::BuildT;// in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool
3086
3087 using CoordType = typename ChildT::CoordType;
3090 using Tile = typename DataType::Tile;
3091 static constexpr bool FIXED_SIZE = DataType::FIXED_SIZE;
3092
3093 static constexpr uint32_t LEVEL = 1 + ChildT::LEVEL; // level 0 = leaf
3094
3096 {
3097 const DataType *mParent;
3098 uint32_t mPos, mSize;
3099 public:
3100 __hostdev__ ChildIterator() : mParent(nullptr), mPos(0), mSize(0) {}
3101 __hostdev__ ChildIterator(const RootNode *parent) : mParent(parent->data()), mPos(0), mSize(parent->tileCount()) {
3102 NANOVDB_ASSERT(mParent);
3103 while (mPos<mSize && !mParent->tile(mPos)->isChild()) ++mPos;
3104 }
3106 __hostdev__ const ChildT& operator*() const {NANOVDB_ASSERT(*this); return *mParent->getChild(mParent->tile(mPos));}
3107 __hostdev__ const ChildT* operator->() const {NANOVDB_ASSERT(*this); return mParent->getChild(mParent->tile(mPos));}
3108 __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); mParent->tile(mPos)->origin();}
3109 __hostdev__ operator bool() const {return mPos < mSize;}
3110 __hostdev__ uint32_t pos() const {return mPos;}
3112 NANOVDB_ASSERT(mParent);
3113 ++mPos;
3114 while (mPos < mSize && mParent->tile(mPos)->isValue()) ++mPos;
3115 return *this;
3116 }
3118 auto tmp = *this;
3119 ++(*this);
3120 return tmp;
3121 }
3122 }; // Member class ChildIterator
3123
3125
3127 {
3128 const DataType *mParent;
3129 uint32_t mPos, mSize;
3130 public:
3131 __hostdev__ ValueIterator() : mParent(nullptr), mPos(0), mSize(0) {}
3132 __hostdev__ ValueIterator(const RootNode *parent) : mParent(parent->data()), mPos(0), mSize(parent->tileCount()){
3133 NANOVDB_ASSERT(mParent);
3134 while (mPos < mSize && mParent->tile(mPos)->isChild()) ++mPos;
3135 }
3137 __hostdev__ ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->tile(mPos)->value;}
3138 __hostdev__ bool isActive() const {NANOVDB_ASSERT(*this); return mParent->tile(mPos)->state;}
3139 __hostdev__ operator bool() const {return mPos < mSize;}
3140 __hostdev__ uint32_t pos() const {return mPos;}
3141 __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); mParent->tile(mPos)->origin();}
3143 NANOVDB_ASSERT(mParent);
3144 ++mPos;
3145 while (mPos < mSize && mParent->tile(mPos)->isChild()) ++mPos;
3146 return *this;
3147 }
3149 auto tmp = *this;
3150 ++(*this);
3151 return tmp;
3152 }
3153 }; // Member class ValueIterator
3154
3156
3158 {
3159 const DataType *mParent;
3160 uint32_t mPos, mSize;
3161 public:
3162 __hostdev__ ValueOnIterator() : mParent(nullptr), mPos(0), mSize(0) {}
3163 __hostdev__ ValueOnIterator(const RootNode *parent) : mParent(parent->data()), mPos(0), mSize(parent->tileCount()){
3164 NANOVDB_ASSERT(mParent);
3165 while (mPos < mSize && !mParent->tile(mPos)->isActive()) ++mPos;
3166 }
3168 __hostdev__ ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->tile(mPos)->value;}
3169 __hostdev__ operator bool() const {return mPos < mSize;}
3170 __hostdev__ uint32_t pos() const {return mPos;}
3171 __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); mParent->tile(mPos)->origin();}
3173 NANOVDB_ASSERT(mParent);
3174 ++mPos;
3175 while (mPos < mSize && !mParent->tile(mPos)->isActive()) ++mPos;
3176 return *this;
3177 }
3179 auto tmp = *this;
3180 ++(*this);
3181 return tmp;
3182 }
3183 }; // Member class ValueOnIterator
3184
3186
3187 /// @brief This class cannot be constructed or deleted
3188 RootNode() = delete;
3189 RootNode(const RootNode&) = delete;
3190 RootNode& operator=(const RootNode&) = delete;
3191 ~RootNode() = delete;
3192
3194
3195 __hostdev__ DataType* data() { return reinterpret_cast<DataType*>(this); }
3196
3197 __hostdev__ const DataType* data() const { return reinterpret_cast<const DataType*>(this); }
3198
3199 /// @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
3200 __hostdev__ const BBoxType& bbox() const { return DataType::mBBox; }
3201
3202 /// @brief Return the total number of active voxels in the root and all its child nodes.
3203
3204 /// @brief Return a const reference to the background value, i.e. the value associated with
3205 /// any coordinate location that has not been set explicitly.
3206 __hostdev__ const ValueType& background() const { return DataType::mBackground; }
3207
3208 /// @brief Return the number of tiles encoded in this root node
3209 __hostdev__ const uint32_t& tileCount() const { return DataType::mTableSize; }
3210
3211 /// @brief Return a const reference to the minimum active value encoded in this root node and any of its child nodes
3212 __hostdev__ const ValueType& minimum() const { return this->getMin(); }
3213
3214 /// @brief Return a const reference to the maximum active value encoded in this root node and any of its child nodes
3215 __hostdev__ const ValueType& maximum() const { return this->getMax(); }
3216
3217 /// @brief Return a const reference to the average of all the active values encoded in this root node and any of its child nodes
3218 __hostdev__ const FloatType& average() const { return DataType::mAverage; }
3219
3220 /// @brief Return the variance of all the active values encoded in this root node and any of its child nodes
3221 __hostdev__ FloatType variance() const { return DataType::mStdDevi * DataType::mStdDevi; }
3222
3223 /// @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
3224 __hostdev__ const FloatType& stdDeviation() const { return DataType::mStdDevi; }
3225
3226 /// @brief Return the expected memory footprint in bytes with the specified number of tiles
3227 __hostdev__ static uint64_t memUsage(uint32_t tableSize) { return sizeof(RootNode) + tableSize * sizeof(Tile); }
3228
3229 /// @brief Return the actual memory footprint of this root node
3230 __hostdev__ uint64_t memUsage() const { return sizeof(RootNode) + DataType::mTableSize * sizeof(Tile); }
3231
3232 /// @brief Return the value of the given voxel
3234 {
3235 if (const Tile* tile = this->probeTile(ijk)) {
3236 return tile->isChild() ? this->getChild(tile)->getValue(ijk) : tile->value;
3237 }
3238 return DataType::mBackground;
3239 }
3240
3241 __hostdev__ bool isActive(const CoordType& ijk) const
3242 {
3243 if (const Tile* tile = this->probeTile(ijk)) {
3244 return tile->isChild() ? this->getChild(tile)->isActive(ijk) : tile->state;
3245 }
3246 return false;
3247 }
3248
3249 /// @brief Return true if this RootNode is empty, i.e. contains no values or nodes
3250 __hostdev__ bool isEmpty() const { return DataType::mTableSize == uint32_t(0); }
3251
3252 __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const
3253 {
3254 if (const Tile* tile = this->probeTile(ijk)) {
3255 if (tile->isChild()) {
3256 const auto *child = this->getChild(tile);
3257 return child->probeValue(ijk, v);
3258 }
3259 v = tile->value;
3260 return tile->state;
3261 }
3262 v = DataType::mBackground;
3263 return false;
3264 }
3265
3267 {
3268 const Tile* tile = this->probeTile(ijk);
3269 if (tile && tile->isChild()) {
3270 const auto *child = this->getChild(tile);
3271 return child->probeLeaf(ijk);
3272 }
3273 return nullptr;
3274 }
3275
3277 {
3278 const Tile* tile = this->probeTile(ijk);
3279 if (tile && tile->isChild()) {
3280 return this->getChild(tile);
3281 }
3282 return nullptr;
3283 }
3284
3285 /// @brief Find and return a Tile of this root node
3286 __hostdev__ const Tile* probeTile(const CoordType& ijk) const
3287 {
3288 const Tile* tiles = reinterpret_cast<const Tile*>(this + 1);
3289 const auto key = DataType::CoordToKey(ijk);
3290#if 1 // switch between linear and binary seach
3291 for (uint32_t i = 0; i < DataType::mTableSize; ++i) {
3292 if (tiles[i].key == key) return &tiles[i];
3293 }
3294#else// do not enable binary search if tiles are not guaranteed to be sorted!!!!!!
3295 // binary-search of pre-sorted elements
3296 int32_t low = 0, high = DataType::mTableSize; // low is inclusive and high is exclusive
3297 while (low != high) {
3298 int mid = low + ((high - low) >> 1);
3299 const Tile* tile = &tiles[mid];
3300 if (tile->key == key) {
3301 return tile;
3302 } else if (tile->key < key) {
3303 low = mid + 1;
3304 } else {
3305 high = mid;
3306 }
3307 }
3308#endif
3309 return nullptr;
3310 }
3311
3312private:
3313 static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(RootData) is misaligned");
3314 static_assert(sizeof(typename DataType::Tile) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(RootData::Tile) is misaligned");
3315
3316 template<typename, int, int, int>
3317 friend class ReadAccessor;
3318
3319 template<typename>
3320 friend class Tree;
3321
3322 /// @brief Private method to return node information and update a ReadAccessor
3323 template<typename AccT>
3324 __hostdev__ typename AccT::NodeInfo getNodeInfoAndCache(const CoordType& ijk, const AccT& acc) const
3325 {
3326 using NodeInfoT = typename AccT::NodeInfo;
3327 if (const Tile* tile = this->probeTile(ijk)) {
3328 if (tile->isChild()) {
3329 const auto *child = this->getChild(tile);
3330 acc.insert(ijk, child);
3331 return child->getNodeInfoAndCache(ijk, acc);
3332 }
3333 return NodeInfoT{LEVEL, ChildT::dim(), tile->value, tile->value, tile->value,
3334 0, tile->origin(), tile->origin() + CoordType(ChildT::DIM)};
3335 }
3336 return NodeInfoT{LEVEL, ChildT::dim(), this->minimum(), this->maximum(),
3337 this->average(), this->stdDeviation(), this->bbox()[0], this->bbox()[1]};
3338 }
3339
3340 /// @brief Private method to return a voxel value and update a ReadAccessor
3341 template<typename AccT>
3342 __hostdev__ ValueType getValueAndCache(const CoordType& ijk, const AccT& acc) const
3343 {
3344 if (const Tile* tile = this->probeTile(ijk)) {
3345 if (tile->isChild()) {
3346 const auto *child = this->getChild(tile);
3347 acc.insert(ijk, child);
3348 return child->getValueAndCache(ijk, acc);
3349 }
3350 return tile->value;
3351 }
3352 return DataType::mBackground;
3353 }
3354
3355 template<typename AccT>
3356 __hostdev__ bool isActiveAndCache(const CoordType& ijk, const AccT& acc) const
3357 {
3358 const Tile* tile = this->probeTile(ijk);
3359 if (tile && tile->isChild()) {
3360 const auto *child = this->getChild(tile);
3361 acc.insert(ijk, child);
3362 return child->isActiveAndCache(ijk, acc);
3363 }
3364 return false;
3365 }
3366
3367 template<typename AccT>
3368 __hostdev__ bool probeValueAndCache(const CoordType& ijk, ValueType& v, const AccT& acc) const
3369 {
3370 if (const Tile* tile = this->probeTile(ijk)) {
3371 if (tile->isChild()) {
3372 const auto *child = this->getChild(tile);
3373 acc.insert(ijk, child);
3374 return child->probeValueAndCache(ijk, v, acc);
3375 }
3376 v = tile->value;
3377 return tile->state;
3378 }
3379 v = DataType::mBackground;
3380 return false;
3381 }
3382
3383 template<typename AccT>
3384 __hostdev__ const LeafNodeType* probeLeafAndCache(const CoordType& ijk, const AccT& acc) const
3385 {
3386 const Tile* tile = this->probeTile(ijk);
3387 if (tile && tile->isChild()) {
3388 const auto *child = this->getChild(tile);
3389 acc.insert(ijk, child);
3390 return child->probeLeafAndCache(ijk, acc);
3391 }
3392 return nullptr;
3393 }
3394
3395 template<typename RayT, typename AccT>
3396 __hostdev__ uint32_t getDimAndCache(const CoordType& ijk, const RayT& ray, const AccT& acc) const
3397 {
3398 if (const Tile* tile = this->probeTile(ijk)) {
3399 if (tile->isChild()) {
3400 const auto *child = this->getChild(tile);
3401 acc.insert(ijk, child);
3402 return child->getDimAndCache(ijk, ray, acc);
3403 }
3404 return 1 << ChildT::TOTAL; //tile value
3405 }
3406 return ChildNodeType::dim(); // background
3407 }
3408
3409}; // RootNode class
3410
3411// After the RootNode the memory layout is assumed to be the sorted Tiles
3412
3413// --------------------------> InternalNode <------------------------------------
3414
3415/// @brief Struct with all the member data of the InternalNode (useful during serialization of an openvdb InternalNode)
3416///
3417/// @note No client code should (or can) interface with this struct so it can safely be ignored!
3418template<typename ChildT, uint32_t LOG2DIM>
3419struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) InternalData
3420{
3421 using ValueT = typename ChildT::ValueType;
3422 using BuildT = typename ChildT::BuildType;// in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool
3423 using StatsT = typename ChildT::FloatType;
3424 using CoordT = typename ChildT::CoordType;
3425 using MaskT = typename ChildT::template MaskType<LOG2DIM>;
3426 static constexpr bool FIXED_SIZE = true;
3427
3428 union Tile
3429 {
3431 int64_t child;//signed 64 bit byte offset relative to the InternalData!!
3432 /// @brief This class cannot be constructed or deleted
3433 Tile() = delete;
3434 Tile(const Tile&) = delete;
3435 Tile& operator=(const Tile&) = delete;
3436 ~Tile() = delete;
3437 };
3438
3439 BBox<CoordT> mBBox; // 24B. node bounding box. |
3440 uint64_t mFlags; // 8B. node flags. | 32B aligned
3441 MaskT mValueMask; // LOG2DIM(5): 4096B, LOG2DIM(4): 512B | 32B aligned
3442 MaskT mChildMask; // LOG2DIM(5): 4096B, LOG2DIM(4): 512B | 32B aligned
3443
3444 ValueT mMinimum; // typically 4B
3445 ValueT mMaximum; // typically 4B
3446 StatsT mAverage; // typically 4B, average of all the active values in this node and its child nodes
3447 StatsT mStdDevi; // typically 4B, standard deviation of all the active values in this node and its child nodes
3448 // possible padding, e.g. 28 byte padding when ValueType = bool
3449
3450 /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment
3451 ///
3452 /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members.
3453 __hostdev__ static constexpr uint32_t padding() {
3454 return sizeof(InternalData) - (24u + 8u + 2*(sizeof(MaskT) + sizeof(ValueT) + sizeof(StatsT))
3455 + (1u << (3 * LOG2DIM))*(sizeof(ValueT) > 8u ? sizeof(ValueT) : 8u));
3456 }
3457 alignas(32) Tile mTable[1u << (3 * LOG2DIM)]; // sizeof(ValueT) x (16*16*16 or 32*32*32)
3458
3459 __hostdev__ static uint64_t memUsage() { return sizeof(InternalData); }
3460
3461 __hostdev__ void setChild(uint32_t n, const void *ptr)
3462 {
3463 NANOVDB_ASSERT(mChildMask.isOn(n));
3464 mTable[n].child = PtrDiff(ptr, this);
3465 }
3466
3467 template <typename ValueT>
3468 __hostdev__ void setValue(uint32_t n, const ValueT &v)
3469 {
3470 NANOVDB_ASSERT(!mChildMask.isOn(n));
3471 mTable[n].value = v;
3472 }
3473
3474 /// @brief Returns a pointer to the child node at the specifed linear offset.
3475 __hostdev__ ChildT* getChild(uint32_t n)
3476 {
3477 NANOVDB_ASSERT(mChildMask.isOn(n));
3478 return PtrAdd<ChildT>(this, mTable[n].child);
3479 }
3480 __hostdev__ const ChildT* getChild(uint32_t n) const
3481 {
3482 NANOVDB_ASSERT(mChildMask.isOn(n));
3483 return PtrAdd<ChildT>(this, mTable[n].child);
3484 }
3485
3486 __hostdev__ ValueT getValue(uint32_t n) const
3487 {
3488 NANOVDB_ASSERT(!mChildMask.isOn(n));
3489 return mTable[n].value;
3490 }
3491
3492 __hostdev__ bool isActive(uint32_t n) const
3493 {
3494 NANOVDB_ASSERT(!mChildMask.isOn(n));
3495 return mValueMask.isOn(n);
3496 }
3497
3498 __hostdev__ bool isChild(uint32_t n) const {return mChildMask.isOn(n);}
3499
3500 template <typename T>
3501 __hostdev__ void setOrigin(const T& ijk) { mBBox[0] = ijk; }
3502
3503 __hostdev__ const ValueT& getMin() const { return mMinimum; }
3504 __hostdev__ const ValueT& getMax() const { return mMaximum; }
3505 __hostdev__ const StatsT& average() const { return mAverage; }
3506 __hostdev__ const StatsT& stdDeviation() const { return mStdDevi; }
3507
3508 __hostdev__ void setMin(const ValueT& v) { mMinimum = v; }
3509 __hostdev__ void setMax(const ValueT& v) { mMaximum = v; }
3510 __hostdev__ void setAvg(const StatsT& v) { mAverage = v; }
3511 __hostdev__ void setDev(const StatsT& v) { mStdDevi = v; }
3512
3513 /// @brief This class cannot be constructed or deleted
3514 InternalData() = delete;
3515 InternalData(const InternalData&) = delete;
3517 ~InternalData() = delete;
3518}; // InternalData
3519
3520/// @brief Internal nodes of a VDB treedim(),
3521template<typename ChildT, uint32_t Log2Dim = ChildT::LOG2DIM + 1>
3522class InternalNode : private InternalData<ChildT, Log2Dim>
3523{
3524public:
3526 using ValueType = typename DataType::ValueT;
3527 using FloatType = typename DataType::StatsT;
3528 using BuildType = typename DataType::BuildT; // in rare cases BuildType != ValueType, e.g. then BuildType = ValueMask and ValueType = bool
3529 using LeafNodeType = typename ChildT::LeafNodeType;
3530 using ChildNodeType = ChildT;
3531 using CoordType = typename ChildT::CoordType;
3532 static constexpr bool FIXED_SIZE = DataType::FIXED_SIZE;
3533 template<uint32_t LOG2>
3534 using MaskType = typename ChildT::template MaskType<LOG2>;
3535 template<bool On>
3536 using MaskIterT = typename Mask<Log2Dim>::template Iterator<On>;
3537
3538 static constexpr uint32_t LOG2DIM = Log2Dim;
3539 static constexpr uint32_t TOTAL = LOG2DIM + ChildT::TOTAL; // dimension in index space
3540 static constexpr uint32_t DIM = 1u << TOTAL; // number of voxels along each axis of this node
3541 static constexpr uint32_t SIZE = 1u << (3 * LOG2DIM); // number of tile values (or child pointers)
3542 static constexpr uint32_t MASK = (1u << TOTAL) - 1u;
3543 static constexpr uint32_t LEVEL = 1 + ChildT::LEVEL; // level 0 = leaf
3544 static constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node
3545
3546 /// @brief Visits child nodes of this node only
3547 class ChildIterator : public MaskIterT<true>
3548 {
3549 using BaseT = MaskIterT<true>;
3550 const DataType *mParent;
3551 public:
3552 __hostdev__ ChildIterator() : BaseT(), mParent(nullptr) {}
3553 __hostdev__ ChildIterator(const InternalNode* parent) : BaseT(parent->data()->mChildMask.beginOn()), mParent(parent->data()) {}
3555 __hostdev__ const ChildT& operator*() const {NANOVDB_ASSERT(*this); return *mParent->getChild(BaseT::pos());}
3556 __hostdev__ const ChildT* operator->() const {NANOVDB_ASSERT(*this); return mParent->getChild(BaseT::pos());}
3557 __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); return (*this)->origin();}
3558 }; // Member class ChildIterator
3559
3561
3562 /// @brief Visits all tile values in this node, i.e. both inactive and active tiles
3563 class ValueIterator : public MaskIterT<false>
3564 {
3565 using BaseT = MaskIterT<false>;
3566 const InternalNode *mParent;
3567 public:
3568 __hostdev__ ValueIterator() : BaseT(), mParent(nullptr) {}
3569 __hostdev__ ValueIterator(const InternalNode* parent) : BaseT(parent->data()->mChildMask.beginOff()), mParent(parent) {}
3571 __hostdev__ ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->data()->getValue(BaseT::pos());}
3572 __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); return mParent->localToGlobalCoord(BaseT::pos());}
3573 __hostdev__ bool isActive() const { NANOVDB_ASSERT(*this); return mParent->data()->isActive(BaseT::mPos);}
3574 }; // Member class ValueIterator
3575
3577
3578 /// @brief Visits active tile values of this node only
3579 class ValueOnIterator : public MaskIterT<true>
3580 {
3581 using BaseT = MaskIterT<true>;
3582 const InternalNode *mParent;
3583 public:
3584 __hostdev__ ValueOnIterator() : BaseT(), mParent(nullptr) {}
3585 __hostdev__ ValueOnIterator(const InternalNode* parent) : BaseT(parent->data()->mValueMask.beginOn()), mParent(parent) {}
3587 __hostdev__ ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->data()->getValue(BaseT::pos());}
3588 __hostdev__ CoordType getOrigin() const { NANOVDB_ASSERT(*this); return mParent->localToGlobalCoord(BaseT::pos());}
3589 }; // Member class ValueOnIterator
3590
3592
3593 /// @brief This class cannot be constructed or deleted
3594 InternalNode() = delete;
3595 InternalNode(const InternalNode&) = delete;
3597 ~InternalNode() = delete;
3598
3599 __hostdev__ DataType* data() { return reinterpret_cast<DataType*>(this); }
3600
3601 __hostdev__ const DataType* data() const { return reinterpret_cast<const DataType*>(this); }
3602
3603 /// @brief Return the dimension, in voxel units, of this internal node (typically 8*16 or 8*16*32)
3604 __hostdev__ static uint32_t dim() { return 1u << TOTAL; }
3605
3606 /// @brief Return memory usage in bytes for the class
3607 __hostdev__ static size_t memUsage() { return DataType::memUsage(); }
3608
3609 /// @brief Return a const reference to the bit mask of active voxels in this internal node
3610 __hostdev__ const MaskType<LOG2DIM>& valueMask() const { return DataType::mValueMask; }
3611
3612 /// @brief Return a const reference to the bit mask of child nodes in this internal node
3613 __hostdev__ const MaskType<LOG2DIM>& childMask() const { return DataType::mChildMask; }
3614
3615 /// @brief Return the origin in index space of this leaf node
3616 __hostdev__ CoordType origin() const { return DataType::mBBox.min() & ~MASK; }
3617
3618 /// @brief Return a const reference to the minimum active value encoded in this internal node and any of its child nodes
3619 __hostdev__ const ValueType& minimum() const { return this->getMin(); }
3620
3621 /// @brief Return a const reference to the maximum active value encoded in this internal node and any of its child nodes
3622 __hostdev__ const ValueType& maximum() const { return this->getMax(); }
3623
3624 /// @brief Return a const reference to the average of all the active values encoded in this internal node and any of its child nodes
3625 __hostdev__ const FloatType& average() const { return DataType::mAverage; }
3626
3627 /// @brief Return the variance of all the active values encoded in this internal node and any of its child nodes
3628 __hostdev__ FloatType variance() const { return DataType::mStdDevi*DataType::mStdDevi; }
3629
3630 /// @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
3631 __hostdev__ const FloatType& stdDeviation() const { return DataType::mStdDevi; }
3632
3633 /// @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
3634 __hostdev__ const BBox<CoordType>& bbox() const { return DataType::mBBox; }
3635
3636 /// @brief Return the value of the given voxel
3638 {
3639 const uint32_t n = CoordToOffset(ijk);
3640 return DataType::mChildMask.isOn(n) ? this->getChild(n)->getValue(ijk) : DataType::getValue(n);
3641 }
3642
3643 __hostdev__ bool isActive(const CoordType& ijk) const
3644 {
3645 const uint32_t n = CoordToOffset(ijk);
3646 return DataType::mChildMask.isOn(n) ? this->getChild(n)->isActive(ijk) : DataType::isActive(n);
3647 }
3648
3649 /// @brief return the state and updates the value of the specified voxel
3650 __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const
3651 {
3652 const uint32_t n = CoordToOffset(ijk);
3653 if (DataType::mChildMask.isOn(n))
3654 return this->getChild(n)->probeValue(ijk, v);
3655 v = DataType::getValue(n);
3656 return DataType::isActive(n);
3657 }
3658
3660 {
3661 const uint32_t n = CoordToOffset(ijk);
3662 if (DataType::mChildMask.isOn(n))
3663 return this->getChild(n)->probeLeaf(ijk);
3664 return nullptr;
3665 }
3666
3668 {
3669 const uint32_t n = CoordToOffset(ijk);
3670 return DataType::mChildMask.isOn(n) ? this->getChild(n) : nullptr;
3671 }
3672
3673 /// @brief Return the linear offset corresponding to the given coordinate
3674 __hostdev__ static uint32_t CoordToOffset(const CoordType& ijk)
3675 {
3676#if 0
3677 return (((ijk[0] & MASK) >> ChildT::TOTAL) << (2 * LOG2DIM)) +
3678 (((ijk[1] & MASK) >> ChildT::TOTAL) << (LOG2DIM)) +
3679 ((ijk[2] & MASK) >> ChildT::TOTAL);
3680#else
3681 return (((ijk[0] & MASK) >> ChildT::TOTAL) << (2 * LOG2DIM)) |
3682 (((ijk[1] & MASK) >> ChildT::TOTAL) << (LOG2DIM)) |
3683 ((ijk[2] & MASK) >> ChildT::TOTAL);
3684#endif
3685 }
3686
3687 /// @return the local coordinate of the n'th tile or child node
3689 {
3690 NANOVDB_ASSERT(n < SIZE);
3691 const uint32_t m = n & ((1 << 2 * LOG2DIM) - 1);
3692 return Coord(n >> 2 * LOG2DIM, m >> LOG2DIM, m & ((1 << LOG2DIM) - 1));
3693 }
3694
3695 /// @brief modifies local coordinates to global coordinates of a tile or child node
3697 {
3698 ijk <<= ChildT::TOTAL;
3699 ijk += this->origin();
3700 }
3701
3703 {
3704 Coord ijk = InternalNode::OffsetToLocalCoord(n);
3705 this->localToGlobalCoord(ijk);
3706 return ijk;
3707 }
3708
3709 /// @brief Return true if this node or any of its child nodes contain active values
3711 {
3712 return DataType::mFlags & uint32_t(2);
3713 }
3714
3715private:
3716 static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(InternalData) is misaligned");
3717 //static_assert(offsetof(DataType, mTable) % 32 == 0, "InternalData::mTable is misaligned");
3718
3719 template<typename, int, int, int>
3720 friend class ReadAccessor;
3721
3722 template<typename>
3723 friend class RootNode;
3724 template<typename, uint32_t>
3725 friend class InternalNode;
3726
3727 /// @brief Private read access method used by the ReadAccessor
3728 template<typename AccT>
3729 __hostdev__ ValueType getValueAndCache(const CoordType& ijk, const AccT& acc) const
3730 {
3731 const uint32_t n = CoordToOffset(ijk);
3732 if (!DataType::mChildMask.isOn(n))
3733 return DataType::getValue(n);
3734 const ChildT* child = this->getChild(n);
3735 acc.insert(ijk, child);
3736 return child->getValueAndCache(ijk, acc);
3737 }
3738
3739 template<typename AccT>
3740 __hostdev__ typename AccT::NodeInfo getNodeInfoAndCache(const CoordType& ijk, const AccT& acc) const
3741 {
3742 using NodeInfoT = typename AccT::NodeInfo;
3743 const uint32_t n = CoordToOffset(ijk);
3744 if (!DataType::mChildMask.isOn(n)) {
3745 return NodeInfoT{LEVEL, this->dim(), this->minimum(), this->maximum(), this->average(),
3746 this->stdDeviation(), this->bbox()[0], this->bbox()[1]};
3747 }
3748 const ChildT* child = this->getChild(n);
3749 acc.insert(ijk, child);
3750 return child->getNodeInfoAndCache(ijk, acc);
3751 }
3752
3753 template<typename AccT>
3754 __hostdev__ bool isActiveAndCache(const CoordType& ijk, const AccT& acc) const
3755 {
3756 const uint32_t n = CoordToOffset(ijk);
3757 if (!DataType::mChildMask.isOn(n))
3758 return DataType::isActive(n);
3759 const ChildT* child = this->getChild(n);
3760 acc.insert(ijk, child);
3761 return child->isActiveAndCache(ijk, acc);
3762 }
3763
3764 template<typename AccT>
3765 __hostdev__ bool probeValueAndCache(const CoordType& ijk, ValueType& v, const AccT& acc) const
3766 {
3767 const uint32_t n = CoordToOffset(ijk);
3768 if (!DataType::mChildMask.isOn(n)) {
3769 v = DataType::getValue(n);
3770 return DataType::isActive(n);
3771 }
3772 const ChildT* child = this->getChild(n);
3773 acc.insert(ijk, child);
3774 return child->probeValueAndCache(ijk, v, acc);
3775 }
3776
3777 template<typename AccT>
3778 __hostdev__ const LeafNodeType* probeLeafAndCache(const CoordType& ijk, const AccT& acc) const
3779 {
3780 const uint32_t n = CoordToOffset(ijk);
3781 if (!DataType::mChildMask.isOn(n))
3782 return nullptr;
3783 const ChildT* child = this->getChild(n);
3784 acc.insert(ijk, child);
3785 return child->probeLeafAndCache(ijk, acc);
3786 }
3787
3788 template<typename RayT, typename AccT>
3789 __hostdev__ uint32_t getDimAndCache(const CoordType& ijk, const RayT& ray, const AccT& acc) const
3790 {
3791 if (DataType::mFlags & uint32_t(1u)) return this->dim(); // skip this node if the 1st bit is set
3792 //if (!ray.intersects( this->bbox() )) return 1<<TOTAL;
3793
3794 const uint32_t n = CoordToOffset(ijk);
3795 if (DataType::mChildMask.isOn(n)) {
3796 const ChildT* child = this->getChild(n);
3797 acc.insert(ijk, child);
3798 return child->getDimAndCache(ijk, ray, acc);
3799 }
3800 return ChildNodeType::dim(); // tile value
3801 }
3802
3803}; // InternalNode class
3804
3805// --------------------------> LeafNode <------------------------------------
3806
3807/// @brief Stuct with all the member data of the LeafNode (useful during serialization of an openvdb LeafNode)
3808///
3809/// @note No client code should (or can) interface with this struct so it can safely be ignored!
3810template<typename ValueT, typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
3811struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData
3812{
3813 static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof");
3814 static_assert(sizeof(MaskT<LOG2DIM>) == sizeof(Mask<LOG2DIM>), "Mismatching sizeof");
3815 using ValueType = ValueT;
3816 using BuildType = ValueT;
3818 using ArrayType = ValueT;// type used for the internal mValue array
3819 static constexpr bool FIXED_SIZE = true;
3820
3821 CoordT mBBoxMin; // 12B.
3822 uint8_t mBBoxDif[3]; // 3B.
3823 uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: is sparse ValueIndex, bits5,6,7: bit-width for FpN
3824 MaskT<LOG2DIM> mValueMask; // LOG2DIM(3): 64B.
3825
3826 ValueType mMinimum; // typically 4B
3827 ValueType mMaximum; // typically 4B
3828 FloatType mAverage; // typically 4B, average of all the active values in this node and its child nodes
3829 FloatType mStdDevi; // typically 4B, standard deviation of all the active values in this node and its child nodes
3830 alignas(32) ValueType mValues[1u << 3 * LOG2DIM];
3831
3832 /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment
3833 ///
3834 /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members.
3835 __hostdev__ static constexpr uint32_t padding() {
3836 return sizeof(LeafData) - (12 + 3 + 1 + sizeof(MaskT<LOG2DIM>)
3837 + 2*(sizeof(ValueT) + sizeof(FloatType))
3838 + (1u << (3 * LOG2DIM))*sizeof(ValueT));
3839 }
3840 __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); }
3841
3842 //__hostdev__ const ValueType* values() const { return mValues; }
3843 __hostdev__ ValueType getValue(uint32_t i) const { return mValues[i]; }
3844 __hostdev__ void setValueOnly(uint32_t offset, const ValueType& value) { mValues[offset] = value; }
3845 __hostdev__ void setValue(uint32_t offset, const ValueType& value)
3846 {
3847 mValueMask.setOn(offset);
3848 mValues[offset] = value;
3849 }
3850
3851 __hostdev__ ValueType getMin() const { return mMinimum; }
3852 __hostdev__ ValueType getMax() const { return mMaximum; }
3853 __hostdev__ FloatType getAvg() const { return mAverage; }
3854 __hostdev__ FloatType getDev() const { return mStdDevi; }
3855
3856 __hostdev__ void setMin(const ValueType& v) { mMinimum = v; }
3857 __hostdev__ void setMax(const ValueType& v) { mMaximum = v; }
3858 __hostdev__ void setAvg(const FloatType& v) { mAverage = v; }
3859 __hostdev__ void setDev(const FloatType& v) { mStdDevi = v; }
3860
3861 template <typename T>
3862 __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; }
3863
3864 /// @brief This class cannot be constructed or deleted
3865 LeafData() = delete;
3866 LeafData(const LeafData&) = delete;
3867 LeafData& operator=(const LeafData&) = delete;
3868 ~LeafData() = delete;
3869}; // LeafData<ValueT>
3870
3871/// @brief Base-class for quantized float leaf nodes
3872template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
3873struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafFnBase
3874{
3875 static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof");
3876 static_assert(sizeof(MaskT<LOG2DIM>) == sizeof(Mask<LOG2DIM>), "Mismatching sizeof");
3877 using ValueType = float;
3878 using FloatType = float;
3879
3880 CoordT mBBoxMin; // 12B.
3881 uint8_t mBBoxDif[3]; // 3B.
3882 uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: is sparse ValueIndex, bits5,6,7: bit-width for FpN
3883 MaskT<LOG2DIM> mValueMask; // LOG2DIM(3): 64B.
3884
3885 float mMinimum; // 4B - minimum of ALL values in this node
3886 float mQuantum; // = (max - min)/15 4B
3887 uint16_t mMin, mMax, mAvg, mDev;// quantized representations of statistics of active values
3888 // no padding since it's always 32B aligned
3889 __hostdev__ static uint64_t memUsage() { return sizeof(LeafFnBase); }
3890
3891 /// @brief Return padding of this class in bytes, due to aliasing and 32B alignment
3892 ///
3893 /// @note The extra bytes are not necessarily at the end, but can come from aliasing of individual data members.
3894 __hostdev__ static constexpr uint32_t padding() {
3895 return sizeof(LeafFnBase) - (12 + 3 + 1 + sizeof(MaskT<LOG2DIM>) + 2*4 + 4*2);
3896 }
3897 __hostdev__ void init(float min, float max, uint8_t bitWidth)
3898 {
3899 mMinimum = min;
3900 mQuantum = (max - min)/float((1 << bitWidth)-1);
3901 }
3902
3903 /// @brief return the quantized minimum of the active values in this node
3904 __hostdev__ float getMin() const { return mMin*mQuantum + mMinimum; }
3905
3906 /// @brief return the quantized maximum of the active values in this node
3907 __hostdev__ float getMax() const { return mMax*mQuantum + mMinimum; }
3908
3909 /// @brief return the quantized average of the active values in this node
3910 __hostdev__ float getAvg() const { return mAvg*mQuantum + mMinimum; }
3911 /// @brief return the quantized standard deviation of the active values in this node
3912
3913 /// @note 0 <= StdDev <= max-min or 0 <= StdDev/(max-min) <= 1
3914 __hostdev__ float getDev() const { return mDev*mQuantum; }
3915
3916 /// @note min <= X <= max or 0 <= (X-min)/(min-max) <= 1
3917 __hostdev__ void setMin(float min) { mMin = uint16_t((min - mMinimum)/mQuantum + 0.5f); }
3918
3919 /// @note min <= X <= max or 0 <= (X-min)/(min-max) <= 1
3920 __hostdev__ void setMax(float max) { mMax = uint16_t((max - mMinimum)/mQuantum + 0.5f); }
3921
3922 /// @note min <= avg <= max or 0 <= (avg-min)/(min-max) <= 1
3923 __hostdev__ void setAvg(float avg) { mAvg = uint16_t((avg - mMinimum)/mQuantum + 0.5f); }
3924
3925 /// @note 0 <= StdDev <= max-min or 0 <= StdDev/(max-min) <= 1
3926 __hostdev__ void setDev(float dev) { mDev = uint16_t(dev/mQuantum + 0.5f); }
3927
3928 template <typename T>
3929 __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; }
3930};// LeafFnBase
3931
3932/// @brief Stuct with all the member data of the LeafNode (useful during serialization of an openvdb LeafNode)
3933///
3934/// @note No client code should (or can) interface with this struct so it can safely be ignored!
3935template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
3936struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<Fp4, CoordT, MaskT, LOG2DIM>
3937 : public LeafFnBase<CoordT, MaskT, LOG2DIM>
3938{
3941 using ArrayType = uint8_t;// type used for the internal mValue array
3942 static constexpr bool FIXED_SIZE = true;
3943 alignas(32) uint8_t mCode[1u << (3 * LOG2DIM - 1)];// LeafFnBase is 32B aligned and so is mCode
3944
3945 __hostdev__ static constexpr uint64_t memUsage() { return sizeof(LeafData); }
3946 __hostdev__ static constexpr uint32_t padding() {
3947 static_assert(BaseT::padding()==0, "expected no padding in LeafFnBase");
3948 return sizeof(LeafData) - sizeof(BaseT) - (1u << (3 * LOG2DIM - 1));
3949 }
3950
3951 __hostdev__ static constexpr uint8_t bitWidth() { return 4u; }
3952 __hostdev__ float getValue(uint32_t i) const
3953 {
3954#if 0
3955 const uint8_t c = mCode[i>>1];
3956 return ( (i&1) ? c >> 4 : c & uint8_t(15) )*BaseT::mQuantum + BaseT::mMinimum;
3957#else
3958 return ((mCode[i>>1] >> ((i&1)<<2)) & uint8_t(15))*BaseT::mQuantum + BaseT::mMinimum;
3959#endif
3960 }
3961
3962 /// @brief This class cannot be constructed or deleted
3963 LeafData() = delete;
3964 LeafData(const LeafData&) = delete;
3965 LeafData& operator=(const LeafData&) = delete;
3966 ~LeafData() = delete;
3967}; // LeafData<Fp4>
3968
3969template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
3970struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<Fp8, CoordT, MaskT, LOG2DIM>
3971 : public LeafFnBase<CoordT, MaskT, LOG2DIM>
3972{
3975 using ArrayType = uint8_t;// type used for the internal mValue array
3976 static constexpr bool FIXED_SIZE = true;
3977 alignas(32) uint8_t mCode[1u << 3 * LOG2DIM];
3978 __hostdev__ static constexpr int64_t memUsage() { return sizeof(LeafData); }
3979 __hostdev__ static constexpr uint32_t padding() {
3980 static_assert(BaseT::padding()==0, "expected no padding in LeafFnBase");
3981 return sizeof(LeafData) - sizeof(BaseT) - (1u << 3 * LOG2DIM);
3982 }
3983
3984 __hostdev__ static constexpr uint8_t bitWidth() { return 8u; }
3985 __hostdev__ float getValue(uint32_t i) const
3986 {
3987 return mCode[i]*BaseT::mQuantum + BaseT::mMinimum;// code * (max-min)/255 + min
3988 }
3989 /// @brief This class cannot be constructed or deleted
3990 LeafData() = delete;
3991 LeafData(const LeafData&) = delete;
3992 LeafData& operator=(const LeafData&) = delete;
3993 ~LeafData() = delete;
3994}; // LeafData<Fp8>
3995
3996template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
3997struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<Fp16, CoordT, MaskT, LOG2DIM>
3998 : public LeafFnBase<CoordT, MaskT, LOG2DIM>
3999{
4002 using ArrayType = uint16_t;// type used for the internal mValue array
4003 static constexpr bool FIXED_SIZE = true;
4004 alignas(32) uint16_t mCode[1u << 3 * LOG2DIM];
4005
4006 __hostdev__ static constexpr uint64_t memUsage() { return sizeof(LeafData); }
4007 __hostdev__ static constexpr uint32_t padding() {
4008 static_assert(BaseT::padding()==0, "expected no padding in LeafFnBase");
4009 return sizeof(LeafData) - sizeof(BaseT) - 2*(1u << 3 * LOG2DIM);
4010 }
4011
4012 __hostdev__ static constexpr uint8_t bitWidth() { return 16u; }
4013 __hostdev__ float getValue(uint32_t i) const
4014 {
4015 return mCode[i]*BaseT::mQuantum + BaseT::mMinimum;// code * (max-min)/65535 + min
4016 }
4017
4018 /// @brief This class cannot be constructed or deleted
4019 LeafData() = delete;
4020 LeafData(const LeafData&) = delete;
4021 LeafData& operator=(const LeafData&) = delete;
4022 ~LeafData() = delete;
4023}; // LeafData<Fp16>
4024
4025template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
4026struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<FpN, CoordT, MaskT, LOG2DIM>
4027 : public LeafFnBase<CoordT, MaskT, LOG2DIM>
4028{// this class has no data members, however every instance is immediately followed
4029// bitWidth*64 bytes. Since its base class is 32B aligned so are the bitWidth*64 bytes
4032 static constexpr bool FIXED_SIZE = false;
4033 __hostdev__ static constexpr uint32_t padding() {
4034 static_assert(BaseT::padding()==0, "expected no padding in LeafFnBase");
4035 return 0;
4036 }
4037
4038 __hostdev__ uint8_t bitWidth() const { return 1 << (BaseT::mFlags >> 5); }// 4,8,16,32 = 2^(2,3,4,5)
4039 __hostdev__ size_t memUsage() const { return sizeof(*this) + this->bitWidth()*64; }
4040 __hostdev__ static size_t memUsage(uint32_t bitWidth) { return 96u + bitWidth*64; }
4041 __hostdev__ float getValue(uint32_t i) const
4042 {
4043#ifdef NANOVDB_FPN_BRANCHLESS// faster
4044 const int b = BaseT::mFlags >> 5;// b = 0, 1, 2, 3, 4 corresponding to 1, 2, 4, 8, 16 bits
4045#if 0// use LUT
4046 uint16_t code = reinterpret_cast<const uint16_t*>(this + 1)[i >> (4 - b)];
4047 const static uint8_t shift[5] = {15, 7, 3, 1, 0};
4048 const static uint16_t mask[5] = {1, 3, 15, 255, 65535};
4049 code >>= (i & shift[b]) << b;
4050 code &= mask[b];
4051#else// no LUT
4052 uint32_t code = reinterpret_cast<const uint32_t*>(this + 1)[i >> (5 - b)];
4053 //code >>= (i & ((16 >> b) - 1)) << b;
4054 code >>= (i & ((32 >> b) - 1)) << b;
4055 code &= (1 << (1 << b)) - 1;
4056#endif
4057#else// use branched version (slow)
4058 float code;
4059 auto *values = reinterpret_cast<const uint8_t*>(this+1);
4060 switch (BaseT::mFlags >> 5) {
4061 case 0u:// 1 bit float
4062 code = float((values[i>>3] >> (i&7) ) & uint8_t(1));
4063 break;
4064 case 1u:// 2 bits float
4065 code = float((values[i>>2] >> ((i&3)<<1)) & uint8_t(3));
4066 break;
4067 case 2u:// 4 bits float
4068 code = float((values[i>>1] >> ((i&1)<<2)) & uint8_t(15));
4069 break;
4070 case 3u:// 8 bits float
4071 code = float(values[i]);
4072 break;
4073 default:// 16 bits float
4074 code = float(reinterpret_cast<const uint16_t*>(values)[i]);
4075 }
4076#endif
4077 return float(code) * BaseT::mQuantum + BaseT::mMinimum;// code * (max-min)/UNITS + min
4078 }
4079
4080 /// @brief This class cannot be constructed or deleted
4081 LeafData() = delete;
4082 LeafData(const LeafData&) = delete;
4083 LeafData& operator=(const LeafData&) = delete;
4084 ~LeafData() = delete;
4085}; // LeafData<FpN>
4086
4087// Partial template specialization of LeafData with bool
4088template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
4089struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<bool, CoordT, MaskT, LOG2DIM>
4090{
4091 static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof");
4092 static_assert(sizeof(MaskT<LOG2DIM>) == sizeof(Mask<LOG2DIM>), "Mismatching sizeof");
4093 using ValueType = bool;
4094 using BuildType = bool;
4095 using FloatType = bool;// dummy value type
4096 using ArrayType = MaskT<LOG2DIM>;// type used for the internal mValue array
4097 static constexpr bool FIXED_SIZE = true;
4098
4099 CoordT mBBoxMin; // 12B.
4100 uint8_t mBBoxDif[3]; // 3B.
4101 uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: is sparse ValueIndex, bits5,6,7: bit-width for FpN
4102 MaskT<LOG2DIM> mValueMask; // LOG2DIM(3): 64B.
4103 MaskT<LOG2DIM> mValues; // LOG2DIM(3): 64B.
4104 uint64_t mPadding[2];// 16B padding to 32B alignment
4105
4106 __hostdev__ static constexpr uint32_t padding() {return sizeof(LeafData) - 12u - 3u - 1u - 2*sizeof(MaskT<LOG2DIM>) - 16u;}
4107 __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); }
4108
4109 //__hostdev__ const ValueType* values() const { return nullptr; }
4110 __hostdev__ bool getValue(uint32_t i) const { return mValues.isOn(i); }
4111 __hostdev__ bool getMin() const { return false; }// dummy
4112 __hostdev__ bool getMax() const { return false; }// dummy
4113 __hostdev__ bool getAvg() const { return false; }// dummy
4114 __hostdev__ bool getDev() const { return false; }// dummy
4115 __hostdev__ void setValue(uint32_t offset, bool v)
4116 {
4117 mValueMask.setOn(offset);
4118 mValues.set(offset, v);
4119 }
4120
4121 __hostdev__ void setMin(const bool&) {}// no-op
4122 __hostdev__ void setMax(const bool&) {}// no-op
4123 __hostdev__ void setAvg(const bool&) {}// no-op
4124 __hostdev__ void setDev(const bool&) {}// no-op
4125
4126 template <typename T>
4127 __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; }
4128
4129 /// @brief This class cannot be constructed or deleted
4130 LeafData() = delete;
4131 LeafData(const LeafData&) = delete;
4132 LeafData& operator=(const LeafData&) = delete;
4133 ~LeafData() = delete;
4134}; // LeafData<bool>
4135
4136// Partial template specialization of LeafData with ValueMask
4137template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
4138struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<ValueMask, CoordT, MaskT, LOG2DIM>
4139{
4140 static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof");
4141 static_assert(sizeof(MaskT<LOG2DIM>) == sizeof(Mask<LOG2DIM>), "Mismatching sizeof");
4142 using ValueType = bool;
4144 using FloatType = bool;// dummy value type
4145 using ArrayType = void;// type used for the internal mValue array - void means missing
4146 static constexpr bool FIXED_SIZE = true;
4147
4148 CoordT mBBoxMin; // 12B.
4149 uint8_t mBBoxDif[3]; // 3B.
4150 uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: is sparse ValueIndex, bits5,6,7: bit-width for FpN
4151 MaskT<LOG2DIM> mValueMask; // LOG2DIM(3): 64B.
4152 uint64_t mPadding[2];// 16B padding to 32B alignment
4153
4154 __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); }
4155
4156 __hostdev__ static constexpr uint32_t padding() {
4157 return sizeof(LeafData) - (12u + 3u + 1u + sizeof(MaskT<LOG2DIM>) + 2*8u);
4158 }
4159
4160 //__hostdev__ const ValueType* values() const { return nullptr; }
4161 __hostdev__ bool getValue(uint32_t i) const { return mValueMask.isOn(i); }
4162 __hostdev__ bool getMin() const { return false; }// dummy
4163 __hostdev__ bool getMax() const { return false; }// dummy
4164 __hostdev__ bool getAvg() const { return false; }// dummy
4165 __hostdev__ bool getDev() const { return false; }// dummy
4166 __hostdev__ void setValue(uint32_t offset, bool)
4167 {
4168 mValueMask.setOn(offset);
4169 }
4170
4171 __hostdev__ void setMin(const ValueType&) {}// no-op
4172 __hostdev__ void setMax(const ValueType&) {}// no-op
4173 __hostdev__ void setAvg(const FloatType&) {}// no-op
4174 __hostdev__ void setDev(const FloatType&) {}// no-op
4175
4176 template <typename T>
4177 __hostdev__ void setOrigin(const T& ijk) { mBBoxMin = ijk; }
4178
4179 /// @brief This class cannot be constructed or deleted
4180 LeafData() = delete;
4181 LeafData(const LeafData&) = delete;
4182 LeafData& operator=(const LeafData&) = delete;
4183 ~LeafData() = delete;
4184}; // LeafData<ValueMask>
4185
4186// Partial template specialization of LeafData with ValueIndex
4187template<typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
4188struct NANOVDB_ALIGN(NANOVDB_DATA_ALIGNMENT) LeafData<ValueIndex, CoordT, MaskT, LOG2DIM>
4189{
4190 static_assert(sizeof(CoordT) == sizeof(Coord), "Mismatching sizeof");
4191 static_assert(sizeof(MaskT<LOG2DIM>) == sizeof(Mask<LOG2DIM>), "Mismatching sizeof");
4192 using ValueType = uint64_t;
4194 using FloatType = uint64_t;
4195 using ArrayType = void;// type used for the internal mValue array - void means missing
4196 static constexpr bool FIXED_SIZE = true;
4197
4198 CoordT mBBoxMin; // 12B.
4199 uint8_t mBBoxDif[3]; // 3B.
4200 uint8_t mFlags; // 1B. bit0: skip render?, bit1: has bbox?, bit3: unused, bit4: is sparse ValueIndex, bits5,6,7: bit-width for FpN
4201
4202 MaskT<LOG2DIM> mValueMask; // LOG2DIM(3): 64B.
4203 uint64_t mStatsOff;// 8B offset to min/max/avg/sdv
4204 uint64_t mValueOff;// 8B offset to values
4205 // No padding since it's always 32B aligned
4206
4207 __hostdev__ static constexpr uint32_t padding() {
4208 return sizeof(LeafData) - (12u + 3u + 1u + sizeof(MaskT<LOG2DIM>) + 2*8u);
4209 }
4210
4211 __hostdev__ static uint64_t memUsage() { return sizeof(LeafData); }
4212
4213 __hostdev__ uint64_t getMin() const { NANOVDB_ASSERT(mStatsOff); return mStatsOff + 0; }
4214 __hostdev__ uint64_t getMax() const { NANOVDB_ASSERT(mStatsOff); return mStatsOff + 1; }
4215 __hostdev__ uint64_t getAvg() const { NANOVDB_ASSERT(mStatsOff); return mStatsOff + 2; }
4216 __hostdev__ uint64_t getDev() const { NANOVDB_ASSERT(mStatsOff); return mStatsOff + 3; }
4217 __hostdev__ void setValue(uint32_t offset, uint64_t)
4218 {
4219 mValueMask.setOn(offset);
4220 }
4221
4222 __hostdev__ uint64_t getValue(uint32_t i) const
4223 {
4224 if (mFlags & uint8_t(16u)) {// if 4th bit is set only active voxels are indexed
4225 return mValueMask.isOn(i) ? mValueOff + mValueMask.countOn(i) : 0;// 0 is background
4226 }
4227 return mValueOff + i;// dense array of active and inactive voxels
4228 }
4229
4230 template <typename T>
4231 __hostdev__ void setMin(const T &min, T *p) { NANOVDB_ASSERT(mStatsOff); p[mStatsOff + 0] = min; }
4232 template <typename T>
4233 __hostdev__ void setMax(const T &max, T *p) { NANOVDB_ASSERT(mStatsOff); p[mStatsOff + 1] = max; }
4234 template <typename T>
4235 __hostdev__ void setAvg(const T &avg, T *p) { NANOVDB_ASSERT(mStatsOff); p[mStatsOff + 2] = avg; }
4236 template <typename T>
4237 __hostdev__ void setDev(const T &dev, T *p) { NANOVDB_ASSERT(mStatsOff); p[mStatsOff + 3] = dev; }
4238 template <typename T>
4239 __hostdev__ void setOrigin(const T &ijk) { mBBoxMin = ijk; }
4240
4241 /// @brief This class cannot be constructed or deleted
4242 LeafData() = delete;
4243 LeafData(const LeafData&) = delete;
4244 LeafData& operator=(const LeafData&) = delete;
4245 ~LeafData() = delete;
4246}; // LeafData<ValueIndex>
4247
4248/// @brief Leaf nodes of the VDB tree. (defaults to 8x8x8 = 512 voxels)
4249template<typename BuildT,
4250 typename CoordT = Coord,
4251 template<uint32_t> class MaskT = Mask,
4252 uint32_t Log2Dim = 3>
4253class LeafNode : private LeafData<BuildT, CoordT, MaskT, Log2Dim>
4254{
4255public:
4257 {
4258 static constexpr uint32_t TOTAL = 0;
4259 static constexpr uint32_t DIM = 1;
4260 __hostdev__ static uint32_t dim() { return 1u; }
4261 }; // Voxel
4267 using CoordType = CoordT;
4268 static constexpr bool FIXED_SIZE = DataType::FIXED_SIZE;
4269 template<uint32_t LOG2>
4270 using MaskType = MaskT<LOG2>;
4271 template<bool ON>
4272 using MaskIterT = typename Mask<Log2Dim>::template Iterator<ON>;
4273
4274 /// @brief Visits all active values in a leaf node
4275 class ValueOnIterator : public MaskIterT<true>
4276 {
4277 using BaseT = MaskIterT<true>;
4278 const LeafNode *mParent;
4279 public:
4280 __hostdev__ ValueOnIterator() : BaseT(), mParent(nullptr) {}
4281 __hostdev__ ValueOnIterator(const LeafNode* parent) : BaseT(parent->data()->mValueMask.beginOn()), mParent(parent) {}
4283 __hostdev__ ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->getValue(BaseT::pos());}
4284 __hostdev__ CoordT getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BaseT::pos());}
4285 }; // Member class ValueOnIterator
4286
4288
4289 /// @brief Visits all inactive values in a leaf node
4290 class ValueOffIterator : public MaskIterT<false>
4291 {
4292 using BaseT = MaskIterT<false>;
4293 const LeafNode *mParent;
4294 public:
4295 __hostdev__ ValueOffIterator() : BaseT(), mParent(nullptr) {}
4296 __hostdev__ ValueOffIterator(const LeafNode* parent) : BaseT(parent->data()->mValueMask.beginOff()), mParent(parent) {}
4298 __hostdev__ ValueType operator*() const {NANOVDB_ASSERT(*this); return mParent->getValue(BaseT::pos());}
4299 __hostdev__ CoordT getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(BaseT::pos());}
4300 }; // Member class ValueOffIterator
4301
4303
4304 /// @brief Visits all values in a leaf node, i.e. both active and inactive values
4306 {
4307 const LeafNode *mParent;
4308 uint32_t mPos;
4309 public:
4310 __hostdev__ ValueIterator() : mParent(nullptr), mPos(1u << 3 * Log2Dim) {}
4311 __hostdev__ ValueIterator(const LeafNode* parent) : mParent(parent), mPos(0) {NANOVDB_ASSERT(parent);}
4313 __hostdev__ ValueType operator*() const { NANOVDB_ASSERT(*this); return mParent->getValue(mPos);}
4314 __hostdev__ CoordT getCoord() const { NANOVDB_ASSERT(*this); return mParent->offsetToGlobalCoord(mPos);}
4315 __hostdev__ bool isActive() const { NANOVDB_ASSERT(*this); return mParent->isActive(mPos);}
4316 __hostdev__ operator bool() const {return mPos < (1u << 3 * Log2Dim);}
4317 __hostdev__ ValueIterator& operator++() {++mPos; return *this;}
4319 auto tmp = *this;
4320 ++(*this);
4321 return tmp;
4322 }
4323 }; // Member class ValueIterator
4324
4326
4327 static_assert(is_same<ValueType,typename BuildToValueMap<BuildType>::Type>::value, "Mismatching BuildType");
4328 static constexpr uint32_t LOG2DIM = Log2Dim;
4329 static constexpr uint32_t TOTAL = LOG2DIM; // needed by parent nodes
4330 static constexpr uint32_t DIM = 1u << TOTAL; // number of voxels along each axis of this node
4331 static constexpr uint32_t SIZE = 1u << 3 * LOG2DIM; // total number of voxels represented by this node
4332 static constexpr uint32_t MASK = (1u << LOG2DIM) - 1u; // mask for bit operations
4333 static constexpr uint32_t LEVEL = 0; // level 0 = leaf
4334 static constexpr uint64_t NUM_VALUES = uint64_t(1) << (3 * TOTAL); // total voxel count represented by this node
4335
4336 __hostdev__ DataType* data() { return reinterpret_cast<DataType*>(this); }
4337
4338 __hostdev__ const DataType* data() const { return reinterpret_cast<const DataType*>(this); }
4339
4340 /// @brief Return a const reference to the bit mask of active voxels in this leaf node
4341 __hostdev__ const MaskType<LOG2DIM>& valueMask() const { return DataType::mValueMask; }
4342
4343 /// @brief Return a const reference to the minimum active value encoded in this leaf node
4344 __hostdev__ ValueType minimum() const { return this->getMin(); }
4345
4346 /// @brief Return a const reference to the maximum active value encoded in this leaf node
4347 __hostdev__ ValueType maximum() const { return this->getMax(); }
4348
4349 /// @brief Return a const reference to the average of all the active values encoded in this leaf node
4350 __hostdev__ FloatType average() const { return DataType::getAvg(); }
4351
4352 /// @brief Return the variance of all the active values encoded in this leaf node
4353 __hostdev__ FloatType variance() const { return DataType::getDev()*DataType::getDev(); }
4354
4355 /// @brief Return a const reference to the standard deviation of all the active values encoded in this leaf node
4356 __hostdev__ FloatType stdDeviation() const { return DataType::getDev(); }
4357
4358 __hostdev__ uint8_t flags() const { return DataType::mFlags; }
4359
4360 /// @brief Return the origin in index space of this leaf node
4361 __hostdev__ CoordT origin() const { return DataType::mBBoxMin & ~MASK; }
4362
4363 __hostdev__ static CoordT OffsetToLocalCoord(uint32_t n)
4364 {
4365 NANOVDB_ASSERT(n < SIZE);
4366 const uint32_t m = n & ((1 << 2 * LOG2DIM) - 1);
4367 return CoordT(n >> 2 * LOG2DIM, m >> LOG2DIM, m & MASK);
4368 }
4369
4370 /// @brief Converts (in place) a local index coordinate to a global index coordinate
4371 __hostdev__ void localToGlobalCoord(Coord& ijk) const { ijk += this->origin(); }
4372
4373 __hostdev__ CoordT offsetToGlobalCoord(uint32_t n) const
4374 {
4375 return OffsetToLocalCoord(n) + this->origin();
4376 }
4377
4378 /// @brief Return the dimension, in index space, of this leaf node (typically 8 as for openvdb leaf nodes!)
4379 __hostdev__ static uint32_t dim() { return 1u << LOG2DIM; }
4380
4381 /// @brief Return the bounding box in index space of active values in this leaf node
4383 {
4384 BBox<CoordT> bbox(DataType::mBBoxMin, DataType::mBBoxMin);
4385 if ( this->hasBBox() ) {
4386 bbox.max()[0] += DataType::mBBoxDif[0];
4387 bbox.max()[1] += DataType::mBBoxDif[1];
4388 bbox.max()[2] += DataType::mBBoxDif[2];
4389 } else {// very rare case
4390 bbox = BBox<CoordT>();// invalid
4391 }
4392 return bbox;
4393 }
4394
4395 /// @brief Return the total number of voxels (e.g. values) encoded in this leaf node
4396 __hostdev__ static uint32_t voxelCount() { return 1u << (3 * LOG2DIM); }
4397
4398 __hostdev__ static uint32_t padding() {return DataType::padding();}
4399
4400 /// @brief return memory usage in bytes for the class
4401 __hostdev__ uint64_t memUsage() { return DataType::memUsage(); }
4402
4403 /// @brief This class cannot be constructed or deleted
4404 LeafNode() = delete;
4405 LeafNode(const LeafNode&) = delete;
4406 LeafNode& operator=(const LeafNode&) = delete;
4407 ~LeafNode() = delete;
4408
4409 /// @brief Return the voxel value at the given offset.
4410 __hostdev__ ValueType getValue(uint32_t offset) const { return DataType::getValue(offset); }
4411
4412 /// @brief Return the voxel value at the given coordinate.
4413 __hostdev__ ValueType getValue(const CoordT& ijk) const { return DataType::getValue(CoordToOffset(ijk)); }
4414
4415 /// @brief Sets the value at the specified location and activate its state.
4416 ///
4417 /// @note This is safe since it does not change the topology of the tree (unlike setValue methods on the other nodes)
4418 __hostdev__ void setValue(const CoordT& ijk, const ValueType& v) { DataType::setValue(CoordToOffset(ijk), v); }
4419
4420 /// @brief Sets the value at the specified location but leaves its state unchanged.
4421 ///
4422 /// @note This is safe since it does not change the topology of the tree (unlike setValue methods on the other nodes)
4423 __hostdev__ void setValueOnly(uint32_t offset, const ValueType& v) { DataType::setValueOnly(offset, v); }
4424 __hostdev__ void setValueOnly(const CoordT& ijk, const ValueType& v) { DataType::setValueOnly(CoordToOffset(ijk), v); }
4425
4426 /// @brief Return @c true if the voxel value at the given coordinate is active.
4427 __hostdev__ bool isActive(const CoordT& ijk) const { return DataType::mValueMask.isOn(CoordToOffset(ijk)); }
4428 __hostdev__ bool isActive(uint32_t n) const { return DataType::mValueMask.isOn(n); }
4429
4430 /// @brief Return @c true if any of the voxel value are active in this leaf node.
4432 {
4433 //NANOVDB_ASSERT( bool(DataType::mFlags & uint8_t(2)) != DataType::mValueMask.isOff() );
4434 //return DataType::mFlags & uint8_t(2);
4435 return !DataType::mValueMask.isOff();
4436 }
4437
4438 __hostdev__ bool hasBBox() const {return DataType::mFlags & uint8_t(2);}
4439
4440 /// @brief Return @c true if the voxel value at the given coordinate is active and updates @c v with the value.
4441 __hostdev__ bool probeValue(const CoordT& ijk, ValueType& v) const
4442 {
4443 const uint32_t n = CoordToOffset(ijk);
4444 v = DataType::getValue(n);
4445 return DataType::mValueMask.isOn(n);
4446 }
4447
4448 __hostdev__ const LeafNode* probeLeaf(const CoordT&) const { return this; }
4449
4450 /// @brief Return the linear offset corresponding to the given coordinate
4451 __hostdev__ static uint32_t CoordToOffset(const CoordT& ijk)
4452 {
4453 #if 0
4454 return ((ijk[0] & MASK) << (2 * LOG2DIM)) + ((ijk[1] & MASK) << LOG2DIM) + (ijk[2] & MASK);
4455 #else
4456 return ((ijk[0] & MASK) << (2 * LOG2DIM)) | ((ijk[1] & MASK) << LOG2DIM) | (ijk[2] & MASK);
4457 #endif
4458 }
4459
4460 /// @brief Updates the local bounding box of active voxels in this node. Return true if bbox was updated.
4461 ///
4462 /// @warning It assumes that the origin and value mask have already been set.
4463 ///
4464 /// @details This method is based on few (intrinsic) bit operations and hence is relatively fast.
4465 /// However, it should only only be called of either the value mask has changed or if the
4466 /// active bounding box is still undefined. e.g. during construction of this node.
4467 __hostdev__ bool updateBBox();
4468
4469private:
4470 static_assert(sizeof(DataType) % NANOVDB_DATA_ALIGNMENT == 0, "sizeof(LeafData) is misaligned");
4471 //static_assert(offsetof(DataType, mValues) % 32 == 0, "LeafData::mValues is misaligned");
4472
4473 template<typename, int, int, int>
4474 friend class ReadAccessor;
4475
4476 template<typename>
4477 friend class RootNode;
4478 template<typename, uint32_t>
4479 friend class InternalNode;
4480
4481 /// @brief Private method to return a voxel value and update a (dummy) ReadAccessor
4482 template<typename AccT>
4483 __hostdev__ ValueType getValueAndCache(const CoordT& ijk, const AccT&) const { return this->getValue(ijk); }
4484
4485 /// @brief Return the node information.
4486 template<typename AccT>
4487 __hostdev__ typename AccT::NodeInfo getNodeInfoAndCache(const CoordType& /*ijk*/, const AccT& /*acc*/) const {
4488 using NodeInfoT = typename AccT::NodeInfo;
4489 return NodeInfoT{LEVEL, this->dim(), this->minimum(), this->maximum(),
4490 this->average(), this->stdDeviation(), this->bbox()[0], this->bbox()[1]};
4491 }
4492
4493 template<typename AccT>
4494 __hostdev__ bool isActiveAndCache(const CoordT& ijk, const AccT&) const { return this->isActive(ijk); }
4495
4496 template<typename AccT>
4497 __hostdev__ bool probeValueAndCache(const CoordT& ijk, ValueType& v, const AccT&) const { return this->probeValue(ijk, v); }
4498
4499 template<typename AccT>
4500 __hostdev__ const LeafNode* probeLeafAndCache(const CoordT&, const AccT&) const { return this; }
4501
4502 template<typename RayT, typename AccT>
4503 __hostdev__ uint32_t getDimAndCache(const CoordT&, const RayT& /*ray*/, const AccT&) const
4504 {
4505 if (DataType::mFlags & uint8_t(1u)) return this->dim(); // skip this node if the 1st bit is set
4506
4507 //if (!ray.intersects( this->bbox() )) return 1 << LOG2DIM;
4508 return ChildNodeType::dim();
4509 }
4510
4511}; // LeafNode class
4512
4513template<typename ValueT, typename CoordT, template<uint32_t> class MaskT, uint32_t LOG2DIM>
4515{
4516 static_assert(LOG2DIM == 3, "LeafNode::updateBBox: only supports LOGDIM = 3!");
4517 if (DataType::mValueMask.isOff()) {
4518 DataType::mFlags &= ~uint8_t(2);// set 2nd bit off, which indicates that this nodes has no bbox
4519 return false;
4520 }
4521 auto update = [&](uint32_t min, uint32_t max, int axis) {
4522 NANOVDB_ASSERT(min <= max && max < 8);
4523 DataType::mBBoxMin[axis] = (DataType::mBBoxMin[axis] & ~MASK) + int(min);
4524 DataType::mBBoxDif[axis] = uint8_t(max - min);
4525 };
4526 uint64_t word64 = DataType::mValueMask.template getWord<uint64_t>(0);
4527 uint32_t Xmin = word64 ? 0u : 8u;
4528 uint32_t Xmax = Xmin;
4529 for (int i = 1; i < 8; ++i) { // last loop over 8 64 words
4530 if (uint64_t w = DataType::mValueMask.template getWord<uint64_t>(i)) { // skip if word has no set bits
4531 word64 |= w; // union 8 x 64 bits words into one 64 bit word
4532 if (Xmin == 8) {
4533 Xmin = i; // only set once
4534 }
4535 Xmax = i;
4536 }
4537 }
4538 NANOVDB_ASSERT(word64);
4539 update(Xmin, Xmax, 0);
4540 update(FindLowestOn(word64) >> 3, FindHighestOn(word64) >> 3, 1);
4541 const uint32_t *p = reinterpret_cast<const uint32_t*>(&word64), word32 = p[0] | p[1];
4542 const uint16_t *q = reinterpret_cast<const uint16_t*>(&word32), word16 = q[0] | q[1];
4543 const uint8_t *b = reinterpret_cast<const uint8_t* >(&word16), byte = b[0] | b[1];
4544 NANOVDB_ASSERT(byte);
4545 update(FindLowestOn(static_cast<uint32_t>(byte)), FindHighestOn(static_cast<uint32_t>(byte)), 2);
4546 DataType::mFlags |= uint8_t(2);// set 2nd bit on, which indicates that this nodes has a bbox
4547 return true;
4548} // LeafNode::updateBBox
4549
4550// --------------------------> Template specializations and traits <------------------------------------
4551
4552/// @brief Template specializations to the default configuration used in OpenVDB:
4553/// Root -> 32^3 -> 16^3 -> 8^3
4554template<typename BuildT>
4556template<typename BuildT>
4558template<typename BuildT>
4560template<typename BuildT>
4562template<typename BuildT>
4564template<typename BuildT>
4566
4567/// @brief Trait to map from LEVEL to node type
4568template<typename BuildT, int LEVEL>
4570
4571// Partial template specialization of above Node struct
4572template<typename BuildT>
4573struct NanoNode<BuildT, 0>
4574{
4577};
4578template<typename BuildT>
4579struct NanoNode<BuildT, 1>
4580{
4583};
4584template<typename BuildT>
4585struct NanoNode<BuildT, 2>
4586{
4589};
4590template<typename BuildT>
4591struct NanoNode<BuildT, 3>
4592{
4595};
4596
4610
4624
4625// --------------------------> ReadAccessor <------------------------------------
4626
4627/// @brief A read-only value accessor with three levels of node caching. This allows for
4628/// inverse tree traversal during lookup, which is on average significantly faster
4629/// than calling the equivalent method on the tree (i.e. top-down traversal).
4630///
4631/// @note By virtue of the fact that a value accessor accelerates random access operations
4632/// by re-using cached access patterns, this access should be reused for multiple access
4633/// operations. In other words, never create an instance of this accessor for a single
4634/// access only. In general avoid single access operations with this accessor, and
4635/// if that is not possible call the corresponding method on the tree instead.
4636///
4637/// @warning Since this ReadAccessor internally caches raw pointers to the nodes of the tree
4638/// structure, it is not safe to copy between host and device, or even to share among
4639/// multiple threads on the same host or device. However, it is light-weight so simple
4640/// instantiate one per thread (on the host and/or device).
4641///
4642/// @details Used to accelerated random access into a VDB tree. Provides on average
4643/// O(1) random access operations by means of inverse tree traversal,
4644/// which amortizes the non-const time complexity of the root node.
4645
4646template <typename BuildT>
4647class ReadAccessor<BuildT, -1, -1, -1>
4648{
4649 using GridT = NanoGrid<BuildT>;// grid
4650 using TreeT = NanoTree<BuildT>;// tree
4651 using RootT = NanoRoot<BuildT>; // root node
4652 using LeafT = NanoLeaf<BuildT>; // Leaf node
4653 using FloatType = typename RootT::FloatType;
4654 using CoordValueType = typename RootT::CoordType::ValueType;
4655
4656 mutable const RootT* mRoot; // 8 bytes (mutable to allow for access methods to be const)
4657public:
4658 using ValueType = typename RootT::ValueType;
4659 using CoordType = typename RootT::CoordType;
4660
4661 static const int CacheLevels = 0;
4662
4663 struct NodeInfo {
4664 uint32_t mLevel; // 4B
4665 uint32_t mDim; // 4B
4666 ValueType mMinimum; // typically 4B
4667 ValueType mMaximum; // typically 4B
4668 FloatType mAverage; // typically 4B
4669 FloatType mStdDevi; // typically 4B
4672 };
4673
4674 /// @brief Constructor from a root node
4675 __hostdev__ ReadAccessor(const RootT& root) : mRoot{&root} {}
4676
4677 /// @brief Constructor from a grid
4678 __hostdev__ ReadAccessor(const GridT& grid) : ReadAccessor(grid.tree().root()) {}
4679
4680 /// @brief Constructor from a tree
4681 __hostdev__ ReadAccessor(const TreeT& tree) : ReadAccessor(tree.root()) {}
4682
4683 /// @brief Reset this access to its initial state, i.e. with an empty cache
4684 /// @node Noop since this template specialization has no cache
4686
4687 __hostdev__ const RootT& root() const { return *mRoot; }
4688
4689 /// @brief Defaults constructors
4690 ReadAccessor(const ReadAccessor&) = default;
4691 ~ReadAccessor() = default;
4693
4695 {
4696 return mRoot->getValueAndCache(ijk, *this);
4697 }
4699 {
4700 return this->getValue(ijk);
4701 }
4702 __hostdev__ ValueType operator()(int i, int j, int k) const
4703 {
4704 return this->getValue(CoordType(i,j,k));
4705 }
4706
4707 __hostdev__ NodeInfo getNodeInfo(const CoordType& ijk) const
4708 {
4709 return mRoot->getNodeInfoAndCache(ijk, *this);
4710 }
4711
4712 __hostdev__ bool isActive(const CoordType& ijk) const
4713 {
4714 return mRoot->isActiveAndCache(ijk, *this);
4715 }
4716
4717 __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const
4718 {
4719 return mRoot->probeValueAndCache(ijk, v, *this);
4720 }
4721
4722 __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const
4723 {
4724 return mRoot->probeLeafAndCache(ijk, *this);
4725 }
4726
4727 template<typename RayT>
4728 __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const
4729 {
4730 return mRoot->getDimAndCache(ijk, ray, *this);
4731 }
4732
4733private:
4734 /// @brief Allow nodes to insert themselves into the cache.
4735 template<typename>
4736 friend class RootNode;
4737 template<typename, uint32_t>
4738 friend class InternalNode;
4739 template<typename, typename, template<uint32_t> class, uint32_t>
4740 friend class LeafNode;
4741
4742 /// @brief No-op
4743 template<typename NodeT>
4744 __hostdev__ void insert(const CoordType&, const NodeT*) const {}
4745}; // ReadAccessor<ValueT, -1, -1, -1> class
4746
4747/// @brief Node caching at a single tree level
4748template <typename BuildT, int LEVEL0>
4749class ReadAccessor<BuildT, LEVEL0, -1, -1>//e.g. 0, 1, 2
4750{
4751 static_assert(LEVEL0 >= 0 && LEVEL0 <= 2, "LEVEL0 should be 0, 1, or 2");
4752
4753 using GridT = NanoGrid<BuildT>;// grid
4754 using TreeT = NanoTree<BuildT>;
4755 using RootT = NanoRoot<BuildT>; // root node
4756 using LeafT = NanoLeaf<BuildT>; // Leaf node
4757 using NodeT = typename NodeTrait<TreeT, LEVEL0>::type;
4758 using CoordT = typename RootT::CoordType;
4759 using ValueT = typename RootT::ValueType;
4760
4761 using FloatType = typename RootT::FloatType;
4762 using CoordValueType = typename RootT::CoordT::ValueType;
4763
4764 // All member data are mutable to allow for access methods to be const
4765 mutable CoordT mKey; // 3*4 = 12 bytes
4766 mutable const RootT* mRoot; // 8 bytes
4767 mutable const NodeT* mNode; // 8 bytes
4768
4769public:
4770 using ValueType = ValueT;
4771 using CoordType = CoordT;
4772
4773 static const int CacheLevels = 1;
4774
4775 using NodeInfo = typename ReadAccessor<ValueT, -1, -1, -1>::NodeInfo;
4776
4777 /// @brief Constructor from a root node
4779 : mKey(CoordType::max())
4780 , mRoot(&root)
4781 , mNode(nullptr)
4782 {
4783 }
4784
4785 /// @brief Constructor from a grid
4786 __hostdev__ ReadAccessor(const GridT& grid) : ReadAccessor(grid.tree().root()) {}
4787
4788 /// @brief Constructor from a tree
4789 __hostdev__ ReadAccessor(const TreeT& tree) : ReadAccessor(tree.root()) {}
4790
4791 /// @brief Reset this access to its initial state, i.e. with an empty cache
4793 {
4794 mKey = CoordType::max();
4795 mNode = nullptr;
4796 }
4797
4798 __hostdev__ const RootT& root() const { return *mRoot; }
4799
4800 /// @brief Defaults constructors
4801 ReadAccessor(const ReadAccessor&) = default;
4802 ~ReadAccessor() = default;
4804
4805 __hostdev__ bool isCached(const CoordType& ijk) const
4806 {
4807 return (ijk[0] & int32_t(~NodeT::MASK)) == mKey[0] &&
4808 (ijk[1] & int32_t(~NodeT::MASK)) == mKey[1] &&
4809 (ijk[2] & int32_t(~NodeT::MASK)) == mKey[2];
4810 }
4811
4813 {
4814 if (this->isCached(ijk)) {
4815 return mNode->getValueAndCache(ijk, *this);
4816 }
4817 return mRoot->getValueAndCache(ijk, *this);
4818 }
4820 {
4821 return this->getValue(ijk);
4822 }
4823 __hostdev__ ValueType operator()(int i, int j, int k) const
4824 {
4825 return this->getValue(CoordType(i,j,k));
4826 }
4827
4829 {
4830 if (this->isCached(ijk)) {
4831 return mNode->getNodeInfoAndCache(ijk, *this);
4832 }
4833 return mRoot->getNodeInfoAndCache(ijk, *this);
4834 }
4835
4836 __hostdev__ bool isActive(const CoordType& ijk) const
4837 {
4838 if (this->isCached(ijk)) {
4839 return mNode->isActiveAndCache(ijk, *this);
4840 }
4841 return mRoot->isActiveAndCache(ijk, *this);
4842 }
4843
4844 __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const
4845 {
4846 if (this->isCached(ijk)) {
4847 return mNode->probeValueAndCache(ijk, v, *this);
4848 }
4849 return mRoot->probeValueAndCache(ijk, v, *this);
4850 }
4851
4852 __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const
4853 {
4854 if (this->isCached(ijk)) {
4855 return mNode->probeLeafAndCache(ijk, *this);
4856 }
4857 return mRoot->probeLeafAndCache(ijk, *this);
4858 }
4859
4860 template<typename RayT>
4861 __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const
4862 {
4863 if (this->isCached(ijk)) {
4864 return mNode->getDimAndCache(ijk, ray, *this);
4865 }
4866 return mRoot->getDimAndCache(ijk, ray, *this);
4867 }
4868
4869private:
4870 /// @brief Allow nodes to insert themselves into the cache.
4871 template<typename>
4872 friend class RootNode;
4873 template<typename, uint32_t>
4874 friend class InternalNode;
4875 template<typename, typename, template<uint32_t> class, uint32_t>
4876 friend class LeafNode;
4877
4878 /// @brief Inserts a leaf node and key pair into this ReadAccessor
4879 __hostdev__ void insert(const CoordType& ijk, const NodeT* node) const
4880 {
4881 mKey = ijk & ~NodeT::MASK;
4882 mNode = node;
4883 }
4884
4885 // no-op
4886 template<typename OtherNodeT>
4887 __hostdev__ void insert(const CoordType&, const OtherNodeT*) const {}
4888
4889}; // ReadAccessor<ValueT, LEVEL0>
4890
4891template <typename BuildT, int LEVEL0, int LEVEL1>
4892class ReadAccessor<BuildT, LEVEL0, LEVEL1, -1>//e.g. (0,1), (1,2), (0,2)
4893{
4894 static_assert(LEVEL0 >= 0 && LEVEL0 <= 2, "LEVEL0 must be 0, 1, 2");
4895 static_assert(LEVEL1 >= 0 && LEVEL1 <= 2, "LEVEL1 must be 0, 1, 2");
4896 static_assert(LEVEL0 < LEVEL1, "Level 0 must be lower than level 1");
4897 using GridT = NanoGrid<BuildT>;// grid
4898 using TreeT = NanoTree<BuildT>;
4899 using RootT = NanoRoot<BuildT>;
4900 using LeafT = NanoLeaf<BuildT>;
4901 using Node1T = typename NodeTrait<TreeT, LEVEL0>::type;
4902 using Node2T = typename NodeTrait<TreeT, LEVEL1>::type;
4903 using CoordT = typename RootT::CoordType;
4904 using ValueT = typename RootT::ValueType;
4905 using FloatType = typename RootT::FloatType;
4906 using CoordValueType = typename RootT::CoordT::ValueType;
4907
4908 // All member data are mutable to allow for access methods to be const
4909#ifdef USE_SINGLE_ACCESSOR_KEY // 44 bytes total
4910 mutable CoordT mKey; // 3*4 = 12 bytes
4911#else // 68 bytes total
4912 mutable CoordT mKeys[2]; // 2*3*4 = 24 bytes
4913#endif
4914 mutable const RootT* mRoot;
4915 mutable const Node1T* mNode1;
4916 mutable const Node2T* mNode2;
4917
4918public:
4919 using ValueType = ValueT;
4920 using CoordType = CoordT;
4921
4922 static const int CacheLevels = 2;
4923
4924 using NodeInfo = typename ReadAccessor<ValueT,-1,-1,-1>::NodeInfo;
4925
4926 /// @brief Constructor from a root node
4928#ifdef USE_SINGLE_ACCESSOR_KEY
4929 : mKey(CoordType::max())
4930#else
4931 : mKeys{CoordType::max(), CoordType::max()}
4932#endif
4933 , mRoot(&root)
4934 , mNode1(nullptr)
4935 , mNode2(nullptr)
4936 {
4937 }
4938
4939 /// @brief Constructor from a grid
4940 __hostdev__ ReadAccessor(const GridT& grid) : ReadAccessor(grid.tree().root()) {}
4941
4942 /// @brief Constructor from a tree
4943 __hostdev__ ReadAccessor(const TreeT& tree) : ReadAccessor(tree.root()) {}
4944
4945 /// @brief Reset this access to its initial state, i.e. with an empty cache
4947 {
4948#ifdef USE_SINGLE_ACCESSOR_KEY
4949 mKey = CoordType::max();
4950#else
4951 mKeys[0] = mKeys[1] = CoordType::max();
4952#endif
4953 mNode1 = nullptr;
4954 mNode2 = nullptr;
4955 }
4956
4957 __hostdev__ const RootT& root() const { return *mRoot; }
4958
4959 /// @brief Defaults constructors
4960 ReadAccessor(const ReadAccessor&) = default;
4961 ~ReadAccessor() = default;
4963
4964#ifdef USE_SINGLE_ACCESSOR_KEY
4965 __hostdev__ bool isCached1(CoordValueType dirty) const
4966 {
4967 if (!mNode1)
4968 return false;
4969 if (dirty & int32_t(~Node1T::MASK)) {
4970 mNode1 = nullptr;
4971 return false;
4972 }
4973 return true;
4974 }
4975 __hostdev__ bool isCached2(CoordValueType dirty) const
4976 {
4977 if (!mNode2)
4978 return false;
4979 if (dirty & int32_t(~Node2T::MASK)) {
4980 mNode2 = nullptr;
4981 return false;
4982 }
4983 return true;
4984 }
4985 __hostdev__ CoordValueType computeDirty(const CoordType& ijk) const
4986 {
4987 return (ijk[0] ^ mKey[0]) | (ijk[1] ^ mKey[1]) | (ijk[2] ^ mKey[2]);
4988 }
4989#else
4990 __hostdev__ bool isCached1(const CoordType& ijk) const
4991 {
4992 return (ijk[0] & int32_t(~Node1T::MASK)) == mKeys[0][0] &&
4993 (ijk[1] & int32_t(~Node1T::MASK)) == mKeys[0][1] &&
4994 (ijk[2] & int32_t(~Node1T::MASK)) == mKeys[0][2];
4995 }
4996 __hostdev__ bool isCached2(const CoordType& ijk) const
4997 {
4998 return (ijk[0] & int32_t(~Node2T::MASK)) == mKeys[1][0] &&
4999 (ijk[1] & int32_t(~Node2T::MASK)) == mKeys[1][1] &&
5000 (ijk[2] & int32_t(~Node2T::MASK)) == mKeys[1][2];
5001 }
5002#endif
5003
5005 {
5006#ifdef USE_SINGLE_ACCESSOR_KEY
5007 const CoordValueType dirty = this->computeDirty(ijk);
5008#else
5009 auto&& dirty = ijk;
5010#endif
5011 if (this->isCached1(dirty)) {
5012 return mNode1->getValueAndCache(ijk, *this);
5013 } else if (this->isCached2(dirty)) {
5014 return mNode2->getValueAndCache(ijk, *this);
5015 }
5016 return mRoot->getValueAndCache(ijk, *this);
5017 }
5019 {
5020 return this->getValue(ijk);
5021 }
5022 __hostdev__ ValueType operator()(int i, int j, int k) const
5023 {
5024 return this->getValue(CoordType(i,j,k));
5025 }
5026
5028 {
5029#ifdef USE_SINGLE_ACCESSOR_KEY
5030 const CoordValueType dirty = this->computeDirty(ijk);
5031#else
5032 auto&& dirty = ijk;
5033#endif
5034 if (this->isCached1(dirty)) {
5035 return mNode1->getNodeInfoAndCache(ijk, *this);
5036 } else if (this->isCached2(dirty)) {
5037 return mNode2->getNodeInfoAndCache(ijk, *this);
5038 }
5039 return mRoot->getNodeInfoAndCache(ijk, *this);
5040 }
5041
5042 __hostdev__ bool isActive(const CoordType& ijk) const
5043 {
5044#ifdef USE_SINGLE_ACCESSOR_KEY
5045 const CoordValueType dirty = this->computeDirty(ijk);
5046#else
5047 auto&& dirty = ijk;
5048#endif
5049 if (this->isCached1(dirty)) {
5050 return mNode1->isActiveAndCache(ijk, *this);
5051 } else if (this->isCached2(dirty)) {
5052 return mNode2->isActiveAndCache(ijk, *this);
5053 }
5054 return mRoot->isActiveAndCache(ijk, *this);
5055 }
5056
5057 __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const
5058 {
5059#ifdef USE_SINGLE_ACCESSOR_KEY
5060 const CoordValueType dirty = this->computeDirty(ijk);
5061#else
5062 auto&& dirty = ijk;
5063#endif
5064 if (this->isCached1(dirty)) {
5065 return mNode1->probeValueAndCache(ijk, v, *this);
5066 } else if (this->isCached2(dirty)) {
5067 return mNode2->probeValueAndCache(ijk, v, *this);
5068 }
5069 return mRoot->probeValueAndCache(ijk, v, *this);
5070 }
5071
5072 __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const
5073 {
5074#ifdef USE_SINGLE_ACCESSOR_KEY
5075 const CoordValueType dirty = this->computeDirty(ijk);
5076#else
5077 auto&& dirty = ijk;
5078#endif
5079 if (this->isCached1(dirty)) {
5080 return mNode1->probeLeafAndCache(ijk, *this);
5081 } else if (this->isCached2(dirty)) {
5082 return mNode2->probeLeafAndCache(ijk, *this);
5083 }
5084 return mRoot->probeLeafAndCache(ijk, *this);
5085 }
5086
5087 template<typename RayT>
5088 __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const
5089 {
5090#ifdef USE_SINGLE_ACCESSOR_KEY
5091 const CoordValueType dirty = this->computeDirty(ijk);
5092#else
5093 auto&& dirty = ijk;
5094#endif
5095 if (this->isCached1(dirty)) {
5096 return mNode1->getDimAndCache(ijk, ray, *this);
5097 } else if (this->isCached2(dirty)) {
5098 return mNode2->getDimAndCache(ijk, ray, *this);
5099 }
5100 return mRoot->getDimAndCache(ijk, ray, *this);
5101 }
5102
5103private:
5104 /// @brief Allow nodes to insert themselves into the cache.
5105 template<typename>
5106 friend class RootNode;
5107 template<typename, uint32_t>
5108 friend class InternalNode;
5109 template<typename, typename, template<uint32_t> class, uint32_t>
5110 friend class LeafNode;
5111
5112 /// @brief Inserts a leaf node and key pair into this ReadAccessor
5113 __hostdev__ void insert(const CoordType& ijk, const Node1T* node) const
5114 {
5115#ifdef USE_SINGLE_ACCESSOR_KEY
5116 mKey = ijk;
5117#else
5118 mKeys[0] = ijk & ~Node1T::MASK;
5119#endif
5120 mNode1 = node;
5121 }
5122 __hostdev__ void insert(const CoordType& ijk, const Node2T* node) const
5123 {
5124#ifdef USE_SINGLE_ACCESSOR_KEY
5125 mKey = ijk;
5126#else
5127 mKeys[1] = ijk & ~Node2T::MASK;
5128#endif
5129 mNode2 = node;
5130 }
5131 template <typename OtherNodeT>
5132 __hostdev__ void insert(const CoordType&, const OtherNodeT*) const {}
5133}; // ReadAccessor<BuildT, LEVEL0, LEVEL1>
5134
5135
5136/// @brief Node caching at all (three) tree levels
5137template <typename BuildT>
5138class ReadAccessor<BuildT, 0, 1, 2>
5139{
5140 using GridT = NanoGrid<BuildT>;// grid
5141 using TreeT = NanoTree<BuildT>;
5142 using RootT = NanoRoot<BuildT>; // root node
5143 using NodeT2 = NanoUpper<BuildT>; // upper internal node
5144 using NodeT1 = NanoLower<BuildT>; // lower internal node
5145 using LeafT = NanoLeaf< BuildT>; // Leaf node
5146 using CoordT = typename RootT::CoordType;
5147 using ValueT = typename RootT::ValueType;
5148
5149 using FloatType = typename RootT::FloatType;
5150 using CoordValueType = typename RootT::CoordT::ValueType;
5151
5152 // All member data are mutable to allow for access methods to be const
5153#ifdef USE_SINGLE_ACCESSOR_KEY // 44 bytes total
5154 mutable CoordT mKey; // 3*4 = 12 bytes
5155#else // 68 bytes total
5156 mutable CoordT mKeys[3]; // 3*3*4 = 36 bytes
5157#endif
5158 mutable const RootT* mRoot;
5159 mutable const void* mNode[3]; // 4*8 = 32 bytes
5160
5161public:
5162 using ValueType = ValueT;
5163 using CoordType = CoordT;
5164
5165 static const int CacheLevels = 3;
5166
5167 using NodeInfo = typename ReadAccessor<ValueT, -1, -1, -1>::NodeInfo;
5168
5169 /// @brief Constructor from a root node
5171#ifdef USE_SINGLE_ACCESSOR_KEY
5172 : mKey(CoordType::max())
5173#else
5174 : mKeys{CoordType::max(), CoordType::max(), CoordType::max()}
5175#endif
5176 , mRoot(&root)
5177 , mNode{nullptr, nullptr, nullptr}
5178 {
5179 }
5180
5181 /// @brief Constructor from a grid
5182 __hostdev__ ReadAccessor(const GridT& grid) : ReadAccessor(grid.tree().root()) {}
5183
5184 /// @brief Constructor from a tree
5185 __hostdev__ ReadAccessor(const TreeT& tree) : ReadAccessor(tree.root()) {}
5186
5187 __hostdev__ const RootT& root() const { return *mRoot; }
5188
5189 /// @brief Defaults constructors
5190 ReadAccessor(const ReadAccessor&) = default;
5191 ~ReadAccessor() = default;
5193
5194 /// @brief Return a const point to the cached node of the specified type
5195 ///
5196 /// @warning The return value could be NULL.
5197 template<typename NodeT>
5198 __hostdev__ const NodeT* getNode() const
5199 {
5200 using T = typename NodeTrait<TreeT, NodeT::LEVEL>::type;
5201 static_assert(is_same<T, NodeT>::value, "ReadAccessor::getNode: Invalid node type");
5202 return reinterpret_cast<const T*>(mNode[NodeT::LEVEL]);
5203 }
5204
5205 template <int LEVEL>
5207 {
5208 using T = typename NodeTrait<TreeT, LEVEL>::type;
5209 static_assert(LEVEL>=0 && LEVEL<=2, "ReadAccessor::getNode: Invalid node type");
5210 return reinterpret_cast<const T*>(mNode[LEVEL]);
5211 }
5212
5213
5214 /// @brief Reset this access to its initial state, i.e. with an empty cache
5216 {
5217#ifdef USE_SINGLE_ACCESSOR_KEY
5218 mKey = CoordType::max();
5219#else
5220 mKeys[0] = mKeys[1] = mKeys[2] = CoordType::max();
5221#endif
5222 mNode[0] = mNode[1] = mNode[2] = nullptr;
5223 }
5224
5225#ifdef USE_SINGLE_ACCESSOR_KEY
5226 template<typename NodeT>
5227 __hostdev__ bool isCached(CoordValueType dirty) const
5228 {
5229 if (!mNode[NodeT::LEVEL])
5230 return false;
5231 if (dirty & int32_t(~NodeT::MASK)) {
5232 mNode[NodeT::LEVEL] = nullptr;
5233 return false;
5234 }
5235 return true;
5236 }
5237
5238 __hostdev__ CoordValueType computeDirty(const CoordType& ijk) const
5239 {
5240 return (ijk[0] ^ mKey[0]) | (ijk[1] ^ mKey[1]) | (ijk[2] ^ mKey[2]);
5241 }
5242#else
5243 template<typename NodeT>
5244 __hostdev__ bool isCached(const CoordType& ijk) const
5245 {
5246 return (ijk[0] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][0] && (ijk[1] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][1] && (ijk[2] & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL][2];
5247 }
5248#endif
5249
5251 {
5252#ifdef USE_SINGLE_ACCESSOR_KEY
5253 const CoordValueType dirty = this->computeDirty(ijk);
5254#else
5255 auto&& dirty = ijk;
5256#endif
5257 if (this->isCached<LeafT>(dirty)) {
5258 return ((LeafT*)mNode[0])->getValue(ijk);
5259 } else if (this->isCached<NodeT1>(dirty)) {
5260 return ((NodeT1*)mNode[1])->getValueAndCache(ijk, *this);
5261 } else if (this->isCached<NodeT2>(dirty)) {
5262 return ((NodeT2*)mNode[2])->getValueAndCache(ijk, *this);
5263 }
5264 return mRoot->getValueAndCache(ijk, *this);
5265 }
5267 {
5268 return this->getValue(ijk);
5269 }
5270 __hostdev__ ValueType operator()(int i, int j, int k) const
5271 {
5272 return this->getValue(CoordType(i,j,k));
5273 }
5274
5276 {
5277#ifdef USE_SINGLE_ACCESSOR_KEY
5278 const CoordValueType dirty = this->computeDirty(ijk);
5279#else
5280 auto&& dirty = ijk;
5281#endif
5282 if (this->isCached<LeafT>(dirty)) {
5283 return ((LeafT*)mNode[0])->getNodeInfoAndCache(ijk, *this);
5284 } else if (this->isCached<NodeT1>(dirty)) {
5285 return ((NodeT1*)mNode[1])->getNodeInfoAndCache(ijk, *this);
5286 } else if (this->isCached<NodeT2>(dirty)) {
5287 return ((NodeT2*)mNode[2])->getNodeInfoAndCache(ijk, *this);
5288 }
5289 return mRoot->getNodeInfoAndCache(ijk, *this);
5290 }
5291
5292 __hostdev__ bool isActive(const CoordType& ijk) const
5293 {
5294#ifdef USE_SINGLE_ACCESSOR_KEY
5295 const CoordValueType dirty = this->computeDirty(ijk);
5296#else
5297 auto&& dirty = ijk;
5298#endif
5299 if (this->isCached<LeafT>(dirty)) {
5300 return ((LeafT*)mNode[0])->isActive(ijk);
5301 } else if (this->isCached<NodeT1>(dirty)) {
5302 return ((NodeT1*)mNode[1])->isActiveAndCache(ijk, *this);
5303 } else if (this->isCached<NodeT2>(dirty)) {
5304 return ((NodeT2*)mNode[2])->isActiveAndCache(ijk, *this);
5305 }
5306 return mRoot->isActiveAndCache(ijk, *this);
5307 }
5308
5309 __hostdev__ bool probeValue(const CoordType& ijk, ValueType& v) const
5310 {
5311#ifdef USE_SINGLE_ACCESSOR_KEY
5312 const CoordValueType dirty = this->computeDirty(ijk);
5313#else
5314 auto&& dirty = ijk;
5315#endif
5316 if (this->isCached<LeafT>(dirty)) {
5317 return ((LeafT*)mNode[0])->probeValue(ijk, v);
5318 } else if (this->isCached<NodeT1>(dirty)) {
5319 return ((NodeT1*)mNode[1])->probeValueAndCache(ijk, v, *this);
5320 } else if (this->isCached<NodeT2>(dirty)) {
5321 return ((NodeT2*)mNode[2])->probeValueAndCache(ijk, v, *this);
5322 }
5323 return mRoot->probeValueAndCache(ijk, v, *this);
5324 }
5325
5326 __hostdev__ const LeafT* probeLeaf(const CoordType& ijk) const
5327 {
5328#ifdef USE_SINGLE_ACCESSOR_KEY
5329 const CoordValueType dirty = this->computeDirty(ijk);
5330#else
5331 auto&& dirty = ijk;
5332#endif
5333 if (this->isCached<LeafT>(dirty)) {
5334 return ((LeafT*)mNode[0]);
5335 } else if (this->isCached<NodeT1>(dirty)) {
5336 return ((NodeT1*)mNode[1])->probeLeafAndCache(ijk, *this);
5337 } else if (this->isCached<NodeT2>(dirty)) {
5338 return ((NodeT2*)mNode[2])->probeLeafAndCache(ijk, *this);
5339 }
5340 return mRoot->probeLeafAndCache(ijk, *this);
5341 }
5342
5343 template<typename RayT>
5344 __hostdev__ uint32_t getDim(const CoordType& ijk, const RayT& ray) const
5345 {
5346#ifdef USE_SINGLE_ACCESSOR_KEY
5347 const CoordValueType dirty = this->computeDirty(ijk);
5348#else
5349 auto&& dirty = ijk;
5350#endif
5351 if (this->isCached<LeafT>(dirty)) {
5352 return ((LeafT*)mNode[0])->getDimAndCache(ijk, ray, *this);
5353 } else if (this->isCached<NodeT1>(dirty)) {
5354 return ((NodeT1*)mNode[1])->getDimAndCache(ijk, ray, *this);
5355 } else if (this->isCached<NodeT2>(dirty)) {
5356 return ((NodeT2*)mNode[2])->getDimAndCache(ijk, ray, *this);
5357 }
5358 return mRoot->getDimAndCache(ijk, ray, *this);
5359 }
5360
5361private:
5362 /// @brief Allow nodes to insert themselves into the cache.
5363 template<typename>
5364 friend class RootNode;
5365 template<typename, uint32_t>
5366 friend class InternalNode;
5367 template<typename, typename, template<uint32_t> class, uint32_t>
5368 friend class LeafNode;
5369
5370 /// @brief Inserts a leaf node and key pair into this ReadAccessor
5371 template<typename NodeT>
5372 __hostdev__ void insert(const CoordType& ijk, const NodeT* node) const
5373 {
5374#ifdef USE_SINGLE_ACCESSOR_KEY
5375 mKey = ijk;
5376#else
5377 mKeys[NodeT::LEVEL] = ijk & ~NodeT::MASK;
5378#endif
5379 mNode[NodeT::LEVEL] = node;
5380 }
5381}; // ReadAccessor<BuildT, 0, 1, 2>
5382
5383//////////////////////////////////////////////////
5384
5385/// @brief Free-standing function for convenient creation of a ReadAccessor with
5386/// optional and customizable node caching.
5387///
5388/// @details createAccessor<>(grid): No caching of nodes and hence it's thread-safe but slow
5389/// createAccessor<0>(grid): Caching of leaf nodes only
5390/// createAccessor<1>(grid): Caching of lower internal nodes only
5391/// createAccessor<2>(grid): Caching of upper internal nodes only
5392/// createAccessor<0,1>(grid): Caching of leaf and lower internal nodes
5393/// createAccessor<0,2>(grid): Caching of leaf and upper internal nodes
5394/// createAccessor<1,2>(grid): Caching of lower and upper internal nodes
5395/// createAccessor<0,1,2>(grid): Caching of all nodes at all tree levels
5396
5397template <int LEVEL0 = -1, int LEVEL1 = -1, int LEVEL2 = -1, typename ValueT = float>
5399{
5401}
5402
5403template <int LEVEL0 = -1, int LEVEL1 = -1, int LEVEL2 = -1, typename ValueT = float>
5405{
5407}
5408
5409template <int LEVEL0 = -1, int LEVEL1 = -1, int LEVEL2 = -1, typename ValueT = float>
5411{
5413}
5414
5415//////////////////////////////////////////////////
5416
5417/// @brief This is a convenient class that allows for access to grid meta-data
5418/// that are independent of the value type of a grid. That is, this class
5419/// can be used to get information about a grid without actually knowing
5420/// its ValueType.
5422{
5423 // We cast to a grid templated on a dummy ValueType which is safe because we are very
5424 // careful only to call certain methods which are known to be invariant to the ValueType!
5425 // In other words, don't use this technique unless you are intimately familiar with the
5426 // memory-layout of the data structure and the reasons why certain methods are safe
5427 // to call and others are not!
5428 using GridT = NanoGrid<int>;
5429 __hostdev__ const GridT& grid() const { return *reinterpret_cast<const GridT*>(this); }
5430
5431public:
5432 __hostdev__ bool isValid() const { return this->grid().isValid(); }
5433 __hostdev__ uint64_t gridSize() const { return this->grid().gridSize(); }
5434 __hostdev__ uint32_t gridIndex() const { return this->grid().gridIndex(); }
5435 __hostdev__ uint32_t gridCount() const { return this->grid().gridCount(); }
5436 __hostdev__ const char* shortGridName() const { return this->grid().shortGridName(); }
5437 __hostdev__ GridType gridType() const { return this->grid().gridType(); }
5438 __hostdev__ GridClass gridClass() const { return this->grid().gridClass(); }
5439 __hostdev__ bool isLevelSet() const { return this->grid().isLevelSet(); }
5440 __hostdev__ bool isFogVolume() const { return this->grid().isFogVolume(); }
5441 __hostdev__ bool isPointIndex() const { return this->grid().isPointIndex(); }
5442 __hostdev__ bool isPointData() const { return this->grid().isPointData(); }
5443 __hostdev__ bool isMask() const { return this->grid().isMask(); }
5444 __hostdev__ bool isStaggered() const { return this->grid().isStaggered(); }
5445 __hostdev__ bool isUnknown() const { return this->grid().isUnknown(); }
5446 __hostdev__ const Map& map() const { return this->grid().map(); }
5447 __hostdev__ const BBox<Vec3R>& worldBBox() const { return this->grid().worldBBox(); }
5448 __hostdev__ const BBox<Coord>& indexBBox() const { return this->grid().indexBBox(); }
5449 __hostdev__ Vec3R voxelSize() const { return this->grid().voxelSize(); }
5450 __hostdev__ int blindDataCount() const { return this->grid().blindDataCount(); }
5451 __hostdev__ const GridBlindMetaData& blindMetaData(uint32_t n) const { return this->grid().blindMetaData(n); }
5452 __hostdev__ uint64_t activeVoxelCount() const { return this->grid().activeVoxelCount(); }
5453 __hostdev__ const uint32_t& activeTileCount(uint32_t level) const { return this->grid().tree().activeTileCount(level); }
5454 __hostdev__ uint32_t nodeCount(uint32_t level) const { return this->grid().tree().nodeCount(level); }
5455 __hostdev__ uint64_t checksum() const { return this->grid().checksum(); }
5456 __hostdev__ bool isEmpty() const { return this->grid().isEmpty(); }
5457 __hostdev__ Version version() const { return this->grid().version(); }
5458}; // GridMetaData
5459
5460/// @brief Class to access points at a specific voxel location
5461template<typename AttT>
5462class PointAccessor : public DefaultReadAccessor<uint32_t>
5463{
5465 const UInt32Grid* mGrid;
5466 const AttT* mData;
5467
5468public:
5470
5472 : AccT(grid.tree().root())
5473 , mGrid(&grid)
5474 , mData(reinterpret_cast<const AttT*>(grid.blindData(0)))
5475 {
5476 NANOVDB_ASSERT(grid.gridType() == GridType::UInt32);
5477 NANOVDB_ASSERT((grid.gridClass() == GridClass::PointIndex && is_same<uint32_t, AttT>::value) ||
5478 (grid.gridClass() == GridClass::PointData && is_same<Vec3f, AttT>::value));
5479 NANOVDB_ASSERT(grid.blindDataCount() >= 1);
5480 }
5481 /// @brief Return the total number of point in the grid and set the
5482 /// iterators to the complete range of points.
5483 __hostdev__ uint64_t gridPoints(const AttT*& begin, const AttT*& end) const
5484 {
5485 const uint64_t count = mGrid->blindMetaData(0u).mElementCount;
5486 begin = mData;
5487 end = begin + count;
5488 return count;
5489 }
5490 /// @brief Return the number of points in the leaf node containing the coordinate @a ijk.
5491 /// If this return value is larger than zero then the iterators @a begin and @a end
5492 /// will point to all the attributes contained within that leaf node.
5493 __hostdev__ uint64_t leafPoints(const Coord& ijk, const AttT*& begin, const AttT*& end) const
5494 {
5495 auto* leaf = this->probeLeaf(ijk);
5496 if (leaf == nullptr) {
5497 return 0;
5498 }
5499 begin = mData + leaf->minimum();
5500 end = begin + leaf->maximum();
5501 return leaf->maximum();
5502 }
5503
5504 /// @brief get iterators over offsets to points at a specific voxel location
5505 __hostdev__ uint64_t voxelPoints(const Coord& ijk, const AttT*& begin, const AttT*& end) const
5506 {
5507 auto* leaf = this->probeLeaf(ijk);
5508 if (leaf == nullptr)
5509 return 0;
5510 const uint32_t offset = LeafNodeType::CoordToOffset(ijk);
5511 if (leaf->isActive(offset)) {
5512 auto* p = mData + leaf->minimum();
5513 begin = p + (offset == 0 ? 0 : leaf->getValue(offset - 1));
5514 end = p + leaf->getValue(offset);
5515 return end - begin;
5516 }
5517 return 0;
5518 }
5519}; // PointAccessor
5520
5521/// @brief Class to access values in channels at a specific voxel location.
5522///
5523/// @note The ChannelT template parameter can be either const and non-const.
5524template<typename ChannelT>
5525class ChannelAccessor : public DefaultReadAccessor<ValueIndex>
5526{
5528 const IndexGrid &mGrid;
5529 ChannelT *mChannel;
5530
5531public:
5532 using ValueType = ChannelT;
5535
5536 /// @brief Ctor from an IndexGrid and an integer ID of an internal channel
5537 /// that is assumed to exist as blind data in the IndexGrid.
5538 __hostdev__ ChannelAccessor(const IndexGrid& grid, uint32_t channelID = 0u)
5539 : BaseT(grid.tree().root())
5540 , mGrid(grid)
5541 , mChannel(nullptr)
5542 {
5543 NANOVDB_ASSERT(grid.gridType() == GridType::Index);
5544 NANOVDB_ASSERT(grid.gridClass() == GridClass::IndexGrid);
5545 this->setChannel(channelID);
5546 }
5547
5548 /// @brief Ctor from an IndexGrid and an external channel
5549 __hostdev__ ChannelAccessor(const IndexGrid& grid, ChannelT *channelPtr)
5550 : BaseT(grid.tree().root())
5551 , mGrid(grid)
5552 , mChannel(channelPtr)
5553 {
5554 NANOVDB_ASSERT(grid.gridType() == GridType::Index);
5555 NANOVDB_ASSERT(grid.gridClass() == GridClass::IndexGrid);
5556 NANOVDB_ASSERT(mChannel);
5557 }
5558
5559 /// @brief Return a const reference to the IndexGrid
5560 __hostdev__ const IndexGrid &grid() const {return mGrid;}
5561
5562 /// @brief Return a const reference to the tree of the IndexGrid
5563 __hostdev__ const IndexTree &tree() const {return mGrid.tree();}
5564
5565 /// @brief Return a vector of the axial voxel sizes
5566 __hostdev__ const Vec3R& voxelSize() const { return mGrid.voxelSize(); }
5567
5568 /// @brief Return total number of values indexed by the IndexGrid
5569 __hostdev__ const uint64_t& valueCount() const { return mGrid.valueCount(); }
5570
5571 /// @brief Change to an external channel
5572 __hostdev__ void setChannel(ChannelT *channelPtr)
5573 {
5574 mChannel = channelPtr;
5575 NANOVDB_ASSERT(mChannel);
5576 }
5577
5578 /// @brief Change to an internal channel, assuming it exists as as blind data
5579 /// in the IndexGrid.
5580 __hostdev__ void setChannel(uint32_t channelID)
5581 {
5582 this->setChannel(reinterpret_cast<ChannelT*>(const_cast<void*>(mGrid.blindData(channelID))));
5583 }
5584
5585 /// @brief Return the linear offset into a channel that maps to the specified coordinate
5586 __hostdev__ uint64_t getIndex(const Coord& ijk) const {return BaseT::getValue(ijk);}
5587 __hostdev__ uint64_t idx(int i, int j, int k) const {return BaseT::getValue(Coord(i,j,k));}
5588
5589 /// @brief Return the value from a cached channel that maps to the specified coordinate
5590 __hostdev__ ChannelT& getValue(const Coord& ijk) const {return mChannel[BaseT::getValue(ijk)];}
5591 __hostdev__ ChannelT& operator()(const Coord& ijk) const {return this->getValue(ijk);}
5592 __hostdev__ ChannelT& operator()(int i, int j, int k) const {return this->getValue(Coord(i,j,k));}
5593
5594 /// @brief return the state and updates the value of the specified voxel
5596 {
5597 uint64_t idx;
5598 const bool isActive = BaseT::probeValue(ijk, idx);
5599 v = mChannel[idx];
5600 return isActive;
5601 }
5602 /// @brief Return the value from a specified channel that maps to the specified coordinate
5603 ///
5604 /// @note The template parameter can be either const or non-const
5605 template <typename T>
5606 __hostdev__ T& getValue(const Coord& ijk, T* channelPtr) const {return channelPtr[BaseT::getValue(ijk)];}
5607
5608}; // ChannelAccessor
5609
5610
5611#if !defined(__CUDA_ARCH__) && !defined(__HIP__)
5612
5613#if 0
5614// This MiniGridHandle class is only included as a stand-alone example. Note that aligned_alloc is a C++17 feature!
5615// Normally we recommend using GridHandle defined in util/GridHandle.h
5616struct MiniGridHandle {
5617 struct BufferType {
5618 uint8_t *data;
5619 uint64_t size;
5620 BufferType(uint64_t n=0) : data(std::aligned_alloc(NANOVDB_DATA_ALIGNMENT, n)), size(n) {assert(isValid(data));}
5621 BufferType(BufferType &&other) : data(other.data), size(other.size) {other.data=nullptr; other.size=0;}
5622 ~BufferType() {std::free(data);}
5623 BufferType& operator=(const BufferType &other) = delete;
5624 BufferType& operator=(BufferType &&other){data=other.data; size=other.size; other.data=nullptr; other.size=0; return *this;}
5625 static BufferType create(size_t n, BufferType* dummy = nullptr) {return BufferType(n);}
5626 } buffer;
5627 MiniGridHandle(BufferType &&buf) : buffer(std::move(buf)) {}
5628 const uint8_t* data() const {return buffer.data;}
5629};// MiniGridHandle
5630#endif
5631namespace io {
5632
5633///
5634/// @brief This is a standalone alternative to io::writeGrid(...,Codec::NONE) defined in util/IO.h
5635/// Unlike the latter this function has no dependencies at all, not even NanoVDB.h, so it also
5636/// works if client code only includes PNanoVDB.h!
5637///
5638/// @details Writes a raw NanoVDB buffer, possibly with multiple grids, to a stream WITHOUT compression.
5639/// It follows all the conventions in util/IO.h so the stream can be read by all existing client
5640/// code of NanoVDB.
5641///
5642/// @note This method will always write uncompressed grids to the stream, i.e. Blosc or ZIP compression
5643/// is never applied! This is a fundamental limitation and feature of this standalone function.
5644///
5645/// @throw std::invalid_argument if buffer does not point to a valid NanoVDB grid.
5646///
5647/// @warning This is pretty ugly code that involves lots of pointer and bit manipulations - not for the faint of heart :)
5648template <typename StreamT>// StreamT class must support: "void write(char*, size_t)"
5649void writeUncompressedGrid(StreamT &os, const void *buffer)
5650{
5651 char header[192] = {0}, *dst = header;// combines io::Header + io::MetaData, see util/IO.h
5652 const char *grid = (const char*)buffer, *tree = grid + 672, *root = tree + *(const uint64_t*)(tree + 24);
5653 auto cpy = [&](const char *src, int n){for (auto *end=src+n; src!=end; ++src) *dst++ = *src;};
5654 if (*(const uint64_t*)(grid)!=0x304244566f6e614eUL) {
5655 fprintf(stderr, "nanovdb::writeUncompressedGrid: invalid magic number\n"); exit(EXIT_FAILURE);
5656 } else if (*(const uint32_t*)(grid+16)>>21!=32) {
5657 fprintf(stderr, "nanovdb::writeUncompressedGrid: invalid major version\n"); exit(EXIT_FAILURE);
5658 }
5659 cpy(grid , 8);// uint64_t Header::magic
5660 cpy(grid + 16, 4);// uint32_t Heder::version
5661 *(uint16_t*)(dst) = 1; dst += 4;// uint16_t Header::gridCount=1 and uint16_t Header::codec=0
5662 cpy(grid + 32, 8);// uint64_t MetaData::gridSize
5663 cpy(grid + 32, 8);// uint64_t MetaData::fileSize
5664 dst += 8;// uint64_t MetaData::nameKey
5665 cpy(tree + 56, 8);// uint64_t MetaData::voxelCount
5666 cpy(grid + 636, 4);// uint32_t MetaData::gridType
5667 cpy(grid + 632, 4);// uint32_t MetaData::gridClass
5668 cpy(grid + 560, 48);// double[6] MetaData::worldBBox
5669 cpy(root , 24);// int[6] MetaData::indexBBox
5670 cpy(grid + 608, 24);// double[3] MetaData::voxelSize
5671 const char *gridName = grid + 40;// shortGridName
5672 if (*(const uint32_t*)(grid+20) & uint32_t(1)) {// has long grid name
5673 gridName = grid + *(const int64_t*)(grid + 640) + 288*(*(const uint32_t*)(grid + 648) - 1);
5674 gridName += *(const uint64_t*)gridName;// long grid name encoded in blind meta data
5675 }
5676 uint32_t nameSize = 1; // '\0'
5677 for (const char *p = gridName; *p!='\0'; ++p) ++nameSize;
5678 *(uint32_t*)(dst) = nameSize; dst += 4;// uint32_t MetaData::nameSize
5679 cpy(tree + 32, 12);// uint32_t[3] MetaData::nodeCount
5680 *(uint32_t*)(dst) = 1; dst += 4;// uint32_t MetaData::nodeCount[3]=1
5681 cpy(tree + 44, 12);// uint32_t[3] MetaData::tileCount
5682 dst += 4;// uint16_t codec and padding
5683 cpy(grid + 16, 4);// uint32_t MetaData::version
5684 assert(dst - header == 192);
5685 os.write(header, 192);// write header
5686 os.write(gridName, nameSize);// write grid name
5687 while(1) {// loop over all grids in the buffer (typically just one grid per buffer)
5688 const uint64_t gridSize = *(const uint64_t*)(grid + 32);
5689 os.write(grid, gridSize);// write grid <- bulk of writing!
5690 if (*(const uint32_t*)(grid+24) >= *(const uint32_t*)(grid+28) - 1) break;
5691 grid += gridSize;
5692 }
5693}// writeUncompressedGrid
5694
5695/// @brief write multiple NanoVDB grids to a single file, without compression.
5696template<typename GridHandleT, template<typename...> class VecT>
5697void writeUncompressedGrids(const char* fileName, const VecT<GridHandleT>& handles)
5698{
5699#ifdef NANOVDB_USE_IOSTREAMS// use this to switch between std::ofstream or FILE implementations
5700 std::ofstream os(fileName, std::ios::out | std::ios::binary | std::ios::trunc);
5701#else
5702 struct StreamT {
5703 FILE *fptr;
5704 StreamT(const char *name) {fptr = fopen(name, "wb");}
5705 ~StreamT() {fclose(fptr);}
5706 void write(const char *data, size_t n){fwrite(data, 1, n, fptr);}
5707 bool is_open() const {return fptr != NULL;}
5708 } os(fileName);
5709#endif
5710 if (!os.is_open()) {
5711 fprintf(stderr, "nanovdb::writeUncompressedGrids: Unable to open file \"%s\"for output\n",fileName); exit(EXIT_FAILURE);
5712 }
5713 for (auto &handle : handles) writeUncompressedGrid(os, handle.data());
5714}// writeUncompressedGrids
5715
5716/// @brief read all uncompressed grids from a stream and return their handles.
5717///
5718/// @throw std::invalid_argument if stream does not contain a single uncompressed valid NanoVDB grid
5719///
5720/// @details StreamT class must support: "bool read(char*, size_t)" and "void skip(uint32_t)"
5721template<typename GridHandleT, typename StreamT, template<typename...> class VecT>
5722VecT<GridHandleT> readUncompressedGrids(StreamT& is, const typename GridHandleT::BufferType& buffer = typename GridHandleT::BufferType())
5723{// header1, metadata11, grid11, metadata12, grid2 ... header2, metadata21, grid21, metadata22, grid22 ...
5724 char header[16], metadata[176];
5725 VecT<GridHandleT> handles;
5726 while(is.read(header, 16)) {// read all segments, e.g. header1, metadata11, grid11, metadata12, grid2 ...
5727 if (*(uint64_t*)(header)!=0x304244566f6e614eUL) {
5728 fprintf(stderr, "nanovdb::readUncompressedGrids: invalid magic number\n"); exit(EXIT_FAILURE);
5729 } else if (*(uint32_t*)(header+8)>>21!=32) {
5730 fprintf(stderr, "nanovdb::readUncompressedGrids: invalid major version\n"); exit(EXIT_FAILURE);
5731 } else if (*(uint16_t*)(header+14)!=0) {
5732 fprintf(stderr, "nanovdb::readUncompressedGrids: invalid codec\n"); exit(EXIT_FAILURE);
5733 }
5734 for (uint16_t i=0, e=*(uint16_t*)(header+12); i<e; ++i) {// read all grids in segment
5735 if (!is.read(metadata, 176)) {
5736 fprintf(stderr, "nanovdb::readUncompressedGrids: error reading metadata\n"); exit(EXIT_FAILURE);
5737 }
5738 const uint64_t gridSize = *(uint64_t*)(metadata);
5739 GridHandleT handle(GridHandleT::BufferType::create(gridSize, &buffer));
5740 is.skip(*(uint32_t*)(metadata + 136));// skip grid name
5741 is.read((char*)handle.data(), gridSize);
5742 handles.emplace_back(std::move(handle));
5743 }
5744 }
5745 return handles;
5746}// readUncompressedGrids
5747
5748/// @brief Read a multiple un-compressed NanoVDB grids from a file and return them as a vector.
5749template<typename GridHandleT, template<typename...> class VecT>
5750VecT<GridHandleT> readUncompressedGrids(const char *fileName, const typename GridHandleT::BufferType& buffer = typename GridHandleT::BufferType())
5751{
5752#ifdef NANOVDB_USE_IOSTREAMS// use this to switch between std::ifstream or FILE implementations
5753 struct StreamT : public std::ifstream {
5754 StreamT(const char *name) : std::ifstream(name, std::ios::in | std::ios::binary) {}
5755 void skip(uint32_t off) {this->seekg(off, std::ios_base::cur);}
5756 };
5757#else
5758 struct StreamT {
5759 FILE *fptr;
5760 StreamT(const char *name) {fptr = fopen(name, "rb");}
5761 ~StreamT() {fclose(fptr);}
5762 bool read(char *data, size_t n){size_t m=fread(data, 1, n, fptr); return n==m;}
5763 void skip(uint32_t off){fseek(fptr, off, SEEK_CUR);}
5764 bool is_open() const {return fptr != NULL;}
5765 };
5766#endif
5767 StreamT is(fileName);
5768 if (!is.is_open()) {
5769 fprintf(stderr, "nanovdb::readUncompressedGrids: Unable to open file \"%s\"for input\n",fileName); exit(EXIT_FAILURE);
5770 }
5771 return readUncompressedGrids<GridHandleT, StreamT, VecT>(is, buffer);
5772}// readUncompressedGrids
5773
5774} // namespace io
5775
5776#endif// if !defined(__CUDA_ARCH__) && !defined(__HIP__)
5777
5778} // namespace nanovdb
5779
5780#endif // end of NANOVDB_NANOVDB_H_HAS_BEEN_INCLUDED
#define ROOT_LEVEL
Definition CNanoVDB.h:53
ValueT value
Definition GridBuilder.h:1290
ChildT * child
Definition GridBuilder.h:1289
#define NANOVDB_HOSTDEV_DISABLE_WARNING
Definition NanoVDB.h:202
#define NANOVDB_MINOR_VERSION_NUMBER
Definition NanoVDB.h:124
#define NANOVDB_DATA_ALIGNMENT
Definition NanoVDB.h:137
#define __hostdev__
Definition NanoVDB.h:192
#define NANOVDB_MAJOR_VERSION_NUMBER
Definition NanoVDB.h:123
#define NANOVDB_ASSERT(x)
Definition NanoVDB.h:173
#define NANOVDB_MAGIC_NUMBER
Definition NanoVDB.h:121
#define NANOVDB_PATCH_VERSION_NUMBER
Definition NanoVDB.h:125
const CoordT & operator*() const
Definition NanoVDB.h:1747
Iterator(const BBox &b)
Definition NanoVDB.h:1720
Iterator operator++(int)
Definition NanoVDB.h:1739
Iterator & operator++()
Definition NanoVDB.h:1725
Class to access values in channels at a specific voxel location.
Definition NanoVDB.h:5526
T & getValue(const Coord &ijk, T *channelPtr) const
Return the value from a specified channel that maps to the specified coordinate.
Definition NanoVDB.h:5606
uint64_t getIndex(const Coord &ijk) const
Return the linear offset into a channel that maps to the specified coordinate.
Definition NanoVDB.h:5586
const IndexGrid & grid() const
Return a const reference to the IndexGrid.
Definition NanoVDB.h:5560
const uint64_t & valueCount() const
Return total number of values indexed by the IndexGrid.
Definition NanoVDB.h:5569
const Vec3R & voxelSize() const
Return a vector of the axial voxel sizes.
Definition NanoVDB.h:5566
ChannelT & operator()(int i, int j, int k) const
Definition NanoVDB.h:5592
uint64_t idx(int i, int j, int k) const
Definition NanoVDB.h:5587
void setChannel(uint32_t channelID)
Change to an internal channel, assuming it exists as as blind data in the IndexGrid.
Definition NanoVDB.h:5580
ChannelAccessor(const IndexGrid &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:5538
ChannelAccessor(const IndexGrid &grid, ChannelT *channelPtr)
Ctor from an IndexGrid and an external channel.
Definition NanoVDB.h:5549
const IndexTree & tree() const
Return a const reference to the tree of the IndexGrid.
Definition NanoVDB.h:5563
bool probeValue(const CoordType &ijk, typename remove_const< ChannelT >::type &v) const
return the state and updates the value of the specified voxel
Definition NanoVDB.h:5595
ChannelT ValueType
Definition NanoVDB.h:5532
void setChannel(ChannelT *channelPtr)
Change to an external channel.
Definition NanoVDB.h:5572
ChannelT & getValue(const Coord &ijk) const
Return the value from a cached channel that maps to the specified coordinate.
Definition NanoVDB.h:5590
ChannelT & operator()(const Coord &ijk) const
Definition NanoVDB.h:5591
Signed (i, j, k) 32-bit integer coordinate class, similar to openvdb::math::Coord.
Definition NanoVDB.h:967
Coord & operator&=(int n)
Definition NanoVDB.h:1047
Coord operator-(const Coord &rhs) const
Definition NanoVDB.h:1076
uint32_t IndexType
Definition NanoVDB.h:971
Coord operator<<(IndexType n) const
Definition NanoVDB.h:1033
static Coord Floor(const Vec3T &xyz)
Return the largest integer coordinates that are not greater than xyz (node centered conversion).
Definition NanoVDB.h:1133
Coord(ValueType n)
Initializes all coordinates to the given signed integer.
Definition NanoVDB.h:980
Coord & operator-=(const Coord &rhs)
Definition NanoVDB.h:1084
Coord & operator>>=(uint32_t n)
Definition NanoVDB.h:1061
Coord & minComponent(const Coord &other)
Perform a component-wise minimum with the other Coord.
Definition NanoVDB.h:1093
Coord operator+(const Coord &rhs) const
Definition NanoVDB.h:1075
static size_t memUsage()
Definition NanoVDB.h:1008
bool operator<(const Coord &rhs) const
Return true if this Coord is lexicographically less than the given Coord.
Definition NanoVDB.h:1039
Coord & operator+=(const Coord &rhs)
Definition NanoVDB.h:1077
Coord & operator=(const CoordT &other)
Assignment operator that works with openvdb::Coord.
Definition NanoVDB.h:1020
int32_t y() const
Definition NanoVDB.h:997
Coord & maxComponent(const Coord &other)
Perform a component-wise maximum with the other Coord.
Definition NanoVDB.h:1105
Coord operator&(IndexType n) const
Return a new instance with coordinates masked by the given unsigned integer.
Definition NanoVDB.h:1030
Coord()
Initialize all coordinates to zero.
Definition NanoVDB.h:974
uint8_t octant() const
Return the octant of this Coord.
Definition NanoVDB.h:1144
const ValueType & operator[](IndexType i) const
Return a const reference to the given Coord component.
Definition NanoVDB.h:1012
int32_t z() const
Definition NanoVDB.h:998
Coord & operator<<=(uint32_t n)
Definition NanoVDB.h:1054
int32_t x() const
Definition NanoVDB.h:996
Coord(ValueType i, ValueType j, ValueType k)
Initializes coordinate to the given signed integers.
Definition NanoVDB.h:986
int32_t & y()
Definition NanoVDB.h:1001
Coord offsetBy(ValueType n) const
Definition NanoVDB.h:1121
int32_t & x()
Definition NanoVDB.h:1000
Coord(ValueType *ptr)
Definition NanoVDB.h:991
bool operator!=(const Coord &rhs) const
Definition NanoVDB.h:1046
static Coord min()
Definition NanoVDB.h:1006
ValueType & operator[](IndexType i)
Return a non-const reference to the given Coord component.
Definition NanoVDB.h:1016
bool operator==(const Coord &rhs) const
Definition NanoVDB.h:1045
Coord offsetBy(ValueType dx, ValueType dy, ValueType dz) const
Definition NanoVDB.h:1116
static Coord max()
Definition NanoVDB.h:1004
int32_t & z()
Definition NanoVDB.h:1002
static bool lessThan(const Coord &a, const Coord &b)
Definition NanoVDB.h:1125
Coord operator>>(IndexType n) const
Definition NanoVDB.h:1036
uint32_t hash() const
Return a hash key derived from the existing coordinates.
Definition NanoVDB.h:1140
int32_t ValueType
Definition NanoVDB.h:970
Coord & operator+=(int n)
Definition NanoVDB.h:1068
Dummy type for a 16bit quantization of float point values.
Definition NanoVDB.h:228
Dummy type for a 4bit quantization of float point values.
Definition NanoVDB.h:222
Dummy type for a 8bit quantization of float point values.
Definition NanoVDB.h:225
Dummy type for a variable bit quantization of floating point values.
Definition NanoVDB.h:231
This is a convenient class that allows for access to grid meta-data that are independent of the value...
Definition NanoVDB.h:5422
const uint32_t & activeTileCount(uint32_t level) const
Definition NanoVDB.h:5453
bool isPointData() const
Definition NanoVDB.h:5442
uint32_t gridIndex() const
Definition NanoVDB.h:5434
const char * shortGridName() const
Definition NanoVDB.h:5436
uint64_t activeVoxelCount() const
Definition NanoVDB.h:5452
bool isStaggered() const
Definition NanoVDB.h:5444
bool isValid() const
Definition NanoVDB.h:5432
const BBox< Vec3R > & worldBBox() const
Definition NanoVDB.h:5447
GridType gridType() const
Definition NanoVDB.h:5437
uint64_t gridSize() const
Definition NanoVDB.h:5433
const GridBlindMetaData & blindMetaData(uint32_t n) const
Definition NanoVDB.h:5451
int blindDataCount() const
Definition NanoVDB.h:5450
uint64_t checksum() const
Definition NanoVDB.h:5455
bool isFogVolume() const
Definition NanoVDB.h:5440
bool isMask() const
Definition NanoVDB.h:5443
uint32_t gridCount() const
Definition NanoVDB.h:5435
GridClass gridClass() const
Definition NanoVDB.h:5438
Version version() const
Definition NanoVDB.h:5457
bool isEmpty() const
Definition NanoVDB.h:5456
Vec3R voxelSize() const
Definition NanoVDB.h:5449
const BBox< Coord > & indexBBox() const
Definition NanoVDB.h:5448
const Map & map() const
Definition NanoVDB.h:5446
bool isLevelSet() const
Definition NanoVDB.h:5439
uint32_t nodeCount(uint32_t level) const
Definition NanoVDB.h:5454
bool isPointIndex() const
Definition NanoVDB.h:5441
bool isUnknown() const
Definition NanoVDB.h:5445
Highest level of the data structure. Contains a tree and a world->index transform (that currently onl...
Definition NanoVDB.h:2558
Vec3T indexToWorld(const Vec3T &xyz) const
index to world space transformation
Definition NanoVDB.h:2620
Vec3T indexToWorldF(const Vec3T &xyz) const
index to world space transformation
Definition NanoVDB.h:2643
const GridType & gridType() const
Definition NanoVDB.h:2674
uint32_t blindDataCount() const
Return the count of blind-data encoded in this grid.
Definition NanoVDB.h:2723
typename TreeT::ValueType ValueType
Definition NanoVDB.h:2563
enable_if< is_same< T, ValueIndex >::value, constuint64_t & >::type valueCount() const
Return the total number of values indexed by this IndexGrid.
Definition NanoVDB.h:2597
typename TreeT::RootType RootType
Definition NanoVDB.h:2561
bool isSequential() const
return true if the specified node type is layed out breadth-first in memory and has a fixed size....
Definition NanoVDB.h:2694
~Grid()=delete
bool isPointData() const
Definition NanoVDB.h:2681
uint32_t gridIndex() const
Return index of this grid in the buffer.
Definition NanoVDB.h:2588
const char * shortGridName() const
Return a c-string with the name of this grid, truncated to 255 characters.
Definition NanoVDB.h:2714
bool isBreadthFirst() const
Definition NanoVDB.h:2689
uint64_t activeVoxelCount() const
Return the total number of active voxels in this tree.
Definition NanoVDB.h:2670
Vec3T indexToWorldDirF(const Vec3T &dir) const
transformation from index space direction to world space direction
Definition NanoVDB.h:2648
typename TreeT::CoordType CoordType
Definition NanoVDB.h:2565
Vec3T worldToIndexF(const Vec3T &xyz) const
world to index space transformation
Definition NanoVDB.h:2639
Vec3T worldToIndexDirF(const Vec3T &dir) const
transformation from world space direction to index space direction
Definition NanoVDB.h:2653
const Vec3R & voxelSize() const
Return a const reference to the size of a voxel in world units.
Definition NanoVDB.h:2609
bool isStaggered() const
Definition NanoVDB.h:2678
const GridClass & gridClass() const
Definition NanoVDB.h:2675
bool isValid() const
Methods related to the classification of this grid.
Definition NanoVDB.h:2673
DataType * data()
Definition NanoVDB.h:2577
bool hasAverage() const
Definition NanoVDB.h:2687
bool hasMinMax() const
Definition NanoVDB.h:2684
const char * gridName() const
Return a c-string with the name of this grid.
Definition NanoVDB.h:2702
const BBox< Vec3R > & worldBBox() const
Computes a AABB of active values in world space.
Definition NanoVDB.h:2661
AccessorType getAccessor() const
Return a new instance of a ReadAccessor used to access values in this grid.
Definition NanoVDB.h:2606
uint64_t gridSize() const
Return the memory footprint of the entire grid, i.e. including all nodes and blind data.
Definition NanoVDB.h:2585
const GridBlindMetaData & blindMetaData(uint32_t n) const
Definition NanoVDB.h:2740
Vec3T indexToWorldDir(const Vec3T &dir) const
transformation from index space direction to world space direction
Definition NanoVDB.h:2625
Vec3T indexToWorldGradF(const Vec3T &grad) const
Transforms the gradient from index space to world space.
Definition NanoVDB.h:2658
uint64_t checksum() const
Return checksum of the grid buffer.
Definition NanoVDB.h:2717
bool isFogVolume() const
Definition NanoVDB.h:2677
const TreeT & tree() const
Return a const reference to the tree.
Definition NanoVDB.h:2600
bool isMask() const
Definition NanoVDB.h:2682
const BBox< CoordType > & indexBBox() const
Computes a AABB of active values in index space.
Definition NanoVDB.h:2667
bool hasLongGridName() const
Definition NanoVDB.h:2686
const void * blindData(uint32_t n) const
Returns a const pointer to the blindData at the specified linear offset.
Definition NanoVDB.h:2731
static uint64_t memUsage()
Return memory usage in bytes for this class only.
Definition NanoVDB.h:2582
TreeT & tree()
Return a non-const reference to the tree.
Definition NanoVDB.h:2603
Vec3T worldToIndex(const Vec3T &xyz) const
world to index space transformation
Definition NanoVDB.h:2616
uint32_t gridCount() const
Return total number of grids in the buffer.
Definition NanoVDB.h:2591
Vec3T worldToIndexDir(const Vec3T &dir) const
transformation from world space direction to index space direction
Definition NanoVDB.h:2630
Version version() const
Definition NanoVDB.h:2575
bool isEmpty() const
Return true if this grid is empty, i.e. contains no values or nodes.
Definition NanoVDB.h:2720
const Map & map() const
Return a const reference to the Map for this grid.
Definition NanoVDB.h:2612
bool hasStdDeviation() const
Definition NanoVDB.h:2688
bool hasBBox() const
Definition NanoVDB.h:2685
bool isLevelSet() const
Definition NanoVDB.h:2676
bool isGridIndex() const
Definition NanoVDB.h:2680
TreeT TreeType
Definition NanoVDB.h:2560
Grid(const Grid &)=delete
Disallow constructions, copy and assignment.
typename TreeT::BuildType BuildType
Definition NanoVDB.h:2564
Grid & operator=(const Grid &)=delete
Vec3T indexToWorldGrad(const Vec3T &grad) const
transform the gradient from index space to world space.
Definition NanoVDB.h:2635
const DataType * data() const
Definition NanoVDB.h:2579
bool isPointIndex() const
Definition NanoVDB.h:2679
bool isUnknown() const
Definition NanoVDB.h:2683
Dummy type for a 16 bit floating point values.
Definition NanoVDB.h:219
Visits child nodes of this node only.
Definition NanoVDB.h:3548
ChildIterator()
Definition NanoVDB.h:3552
CoordType getOrigin() const
Definition NanoVDB.h:3557
const ChildT * operator->() const
Definition NanoVDB.h:3556
ChildIterator & operator=(const ChildIterator &)=default
ChildIterator(const InternalNode *parent)
Definition NanoVDB.h:3553
const ChildT & operator*() const
Definition NanoVDB.h:3555
Visits all tile values in this node, i.e. both inactive and active tiles.
Definition NanoVDB.h:3564
ValueIterator & operator=(const ValueIterator &)=default
ValueIterator(const InternalNode *parent)
Definition NanoVDB.h:3569
bool isActive() const
Definition NanoVDB.h:3573
ValueIterator()
Definition NanoVDB.h:3568
CoordType getOrigin() const
Definition NanoVDB.h:3572
ValueType operator*() const
Definition NanoVDB.h:3571
Visits active tile values of this node only.
Definition NanoVDB.h:3580
ValueOnIterator(const InternalNode *parent)
Definition NanoVDB.h:3585
ValueOnIterator & operator=(const ValueOnIterator &)=default
CoordType getOrigin() const
Definition NanoVDB.h:3588
ValueType operator*() const
Definition NanoVDB.h:3587
ValueOnIterator()
Definition NanoVDB.h:3584
Internal nodes of a VDB treedim(),.
Definition NanoVDB.h:3523
Coord offsetToGlobalCoord(uint32_t n) const
Definition NanoVDB.h:3702
const MaskType< LOG2DIM > & valueMask() const
Return a const reference to the bit mask of active voxels in this internal node.
Definition NanoVDB.h:3610
ValueIterator beginValue() const
Definition NanoVDB.h:3576
bool isActive() const
Return true if this node or any of its child nodes contain active values.
Definition NanoVDB.h:3710
static uint32_t dim()
Return the dimension, in voxel units, of this internal node (typically 8*16 or 8*16*32)
Definition NanoVDB.h:3604
static size_t memUsage()
Return memory usage in bytes for the class.
Definition NanoVDB.h:3607
CoordType origin() const
Return the origin in index space of this leaf node.
Definition NanoVDB.h:3616
typename ChildT::CoordType CoordType
Definition NanoVDB.h:3531
ChildIterator beginChild() const
Definition NanoVDB.h:3560
const BBox< CoordType > & bbox() const
Return a const reference to the bounding box in index space of active values in this internal node an...
Definition NanoVDB.h:3634
FloatType variance() const
Return the variance of all the active values encoded in this internal node and any of its child nodes...
Definition NanoVDB.h:3628
const MaskType< LOG2DIM > & childMask() const
Return a const reference to the bit mask of child nodes in this internal node.
Definition NanoVDB.h:3613
const FloatType & average() const
Return a const reference to the average of all the active values encoded in this internal node and an...
Definition NanoVDB.h:3625
DataType * data()
Definition NanoVDB.h:3599
void localToGlobalCoord(Coord &ijk) const
modifies local coordinates to global coordinates of a tile or child node
Definition NanoVDB.h:3696
typename DataType::BuildT BuildType
Definition NanoVDB.h:3528
typename Mask< Log2Dim >::template Iterator< On > MaskIterT
Definition NanoVDB.h:3536
ChildT ChildNodeType
Definition NanoVDB.h:3530
const LeafNodeType * probeLeaf(const CoordType &ijk) const
Definition NanoVDB.h:3659
bool isActive(const CoordType &ijk) const
Definition NanoVDB.h:3643
typename DataType::ValueT ValueType
Definition NanoVDB.h:3526
static uint32_t CoordToOffset(const CoordType &ijk)
Return the linear offset corresponding to the given coordinate.
Definition NanoVDB.h:3674
typename DataType::StatsT FloatType
Definition NanoVDB.h:3527
static Coord OffsetToLocalCoord(uint32_t n)
Definition NanoVDB.h:3688
bool probeValue(const CoordType &ijk, ValueType &v) const
return the state and updates the value of the specified voxel
Definition NanoVDB.h:3650
typename ChildT::LeafNodeType LeafNodeType
Definition NanoVDB.h:3529
const ChildNodeType * probeChild(const CoordType &ijk) const
Definition NanoVDB.h:3667
const FloatType & stdDeviation() const
Return a const reference to the standard deviation of all the active values encoded in this internal ...
Definition NanoVDB.h:3631
const ValueType & maximum() const
Return a const reference to the maximum active value encoded in this internal node and any of its chi...
Definition NanoVDB.h:3622
InternalNode()=delete
This class cannot be constructed or deleted.
ValueType getValue(const CoordType &ijk) const
Return the value of the given voxel.
Definition NanoVDB.h:3637
typename ChildT::template MaskType< LOG2 > MaskType
Definition NanoVDB.h:3534
const ValueType & minimum() const
Return a const reference to the minimum active value encoded in this internal node and any of its chi...
Definition NanoVDB.h:3619
const DataType * data() const
Definition NanoVDB.h:3601
InternalNode & operator=(const InternalNode &)=delete
InternalNode(const InternalNode &)=delete
ValueOnIterator beginValueOn() const
Definition NanoVDB.h:3591
Visits all values in a leaf node, i.e. both active and inactive values.
Definition NanoVDB.h:4306
ValueIterator & operator=(const ValueIterator &)=default
ValueIterator & operator++()
Definition NanoVDB.h:4317
ValueIterator operator++(int)
Definition NanoVDB.h:4318
ValueIterator(const LeafNode *parent)
Definition NanoVDB.h:4311
bool isActive() const
Definition NanoVDB.h:4315
CoordT getCoord() const
Definition NanoVDB.h:4314
ValueIterator()
Definition NanoVDB.h:4310
ValueType operator*() const
Definition NanoVDB.h:4313
Visits all inactive values in a leaf node.
Definition NanoVDB.h:4291
ValueOffIterator()
Definition NanoVDB.h:4295
CoordT getCoord() const
Definition NanoVDB.h:4299
ValueOffIterator & operator=(const ValueOffIterator &)=default
ValueType operator*() const
Definition NanoVDB.h:4298
ValueOffIterator(const LeafNode *parent)
Definition NanoVDB.h:4296
Visits all active values in a leaf node.
Definition NanoVDB.h:4276
CoordT getCoord() const
Definition NanoVDB.h:4284
ValueOnIterator(const LeafNode *parent)
Definition NanoVDB.h:4281
ValueOnIterator & operator=(const ValueOnIterator &)=default
ValueType operator*() const
Definition NanoVDB.h:4283
ValueOnIterator()
Definition NanoVDB.h:4280
Leaf nodes of the VDB tree. (defaults to 8x8x8 = 512 voxels)
Definition NanoVDB.h:4254
void setValue(const CoordT &ijk, const ValueType &v)
Sets the value at the specified location and activate its state.
Definition NanoVDB.h:4418
void setValueOnly(uint32_t offset, const ValueType &v)
Sets the value at the specified location but leaves its state unchanged.
Definition NanoVDB.h:4423
bool isActive(const CoordT &ijk) const
Return true if the voxel value at the given coordinate is active.
Definition NanoVDB.h:4427
typename DataType::BuildType BuildType
Definition NanoVDB.h:4266
const MaskType< LOG2DIM > & valueMask() const
Return a const reference to the bit mask of active voxels in this leaf node.
Definition NanoVDB.h:4341
ValueIterator beginValue() const
Definition NanoVDB.h:4325
bool isActive() const
Return true if any of the voxel value are active in this leaf node.
Definition NanoVDB.h:4431
CoordT CoordType
Definition NanoVDB.h:4267
static uint32_t dim()
Return the dimension, in index space, of this leaf node (typically 8 as for openvdb leaf nodes!...
Definition NanoVDB.h:4379
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:4441
FloatType variance() const
Return the variance of all the active values encoded in this leaf node.
Definition NanoVDB.h:4353
LeafNode & operator=(const LeafNode &)=delete
bool isActive(uint32_t n) const
Definition NanoVDB.h:4428
DataType * data()
Definition NanoVDB.h:4336
uint8_t flags() const
Definition NanoVDB.h:4358
void localToGlobalCoord(Coord &ijk) const
Converts (in place) a local index coordinate to a global index coordinate.
Definition NanoVDB.h:4371
ValueType maximum() const
Return a const reference to the maximum active value encoded in this leaf node.
Definition NanoVDB.h:4347
typename DataType::FloatType FloatType
Definition NanoVDB.h:4265
CoordT origin() const
Return the origin in index space of this leaf node.
Definition NanoVDB.h:4361
typename Mask< Log2Dim >::template Iterator< ON > MaskIterT
Definition NanoVDB.h:4272
static uint32_t CoordToOffset(const CoordT &ijk)
Return the linear offset corresponding to the given coordinate.
Definition NanoVDB.h:4451
CoordT offsetToGlobalCoord(uint32_t n) const
Definition NanoVDB.h:4373
void setValueOnly(const CoordT &ijk, const ValueType &v)
Definition NanoVDB.h:4424
ValueType getValue(uint32_t offset) const
Return the voxel value at the given offset.
Definition NanoVDB.h:4410
FloatType average() const
Return a const reference to the average of all the active values encoded in this leaf node.
Definition NanoVDB.h:4350
const LeafNode * probeLeaf(const CoordT &) const
Definition NanoVDB.h:4448
ValueType getValue(const CoordT &ijk) const
Return the voxel value at the given coordinate.
Definition NanoVDB.h:4413
MaskT< LOG2 > MaskType
Definition NanoVDB.h:4270
static uint32_t voxelCount()
Return the total number of voxels (e.g. values) encoded in this leaf node.
Definition NanoVDB.h:4396
LeafNode(const LeafNode &)=delete
ValueOffIterator beginValueOff() const
Definition NanoVDB.h:4302
BBox< CoordT > bbox() const
Return the bounding box in index space of active values in this leaf node.
Definition NanoVDB.h:4382
LeafNode()=delete
This class cannot be constructed or deleted.
ValueType minimum() const
Return a const reference to the minimum active value encoded in this leaf node.
Definition NanoVDB.h:4344
typename DataType::ValueType ValueType
Definition NanoVDB.h:4264
static uint32_t padding()
Definition NanoVDB.h:4398
static CoordT OffsetToLocalCoord(uint32_t n)
Definition NanoVDB.h:4363
bool hasBBox() const
Definition NanoVDB.h:4438
uint64_t memUsage()
return memory usage in bytes for the class
Definition NanoVDB.h:4401
const DataType * data() const
Definition NanoVDB.h:4338
ValueOnIterator beginValueOn() const
Definition NanoVDB.h:4287
FloatType stdDeviation() const
Return a const reference to the standard deviation of all the active values encoded in this leaf node...
Definition NanoVDB.h:4356
Definition NanoVDB.h:1993
Iterator()
Definition NanoVDB.h:1995
Iterator & operator=(const Iterator &)=default
uint32_t operator*() const
Definition NanoVDB.h:1998
Iterator operator++(int)
Definition NanoVDB.h:2006
uint32_t pos() const
Definition NanoVDB.h:1999
Iterator(uint32_t pos, const Mask *parent)
Definition NanoVDB.h:1996
Iterator & operator++()
Definition NanoVDB.h:2001
Bit-mask to encode active states and facilitate sequential iterators and a fast codec for I/O compres...
Definition NanoVDB.h:1959
void set(uint32_t n, bool On)
Set the specified bit on or off.
Definition NanoVDB.h:2117
OnIterator beginOn() const
Definition NanoVDB.h:2021
bool isOff(uint32_t n) const
Return true if the given bit is NOT set.
Definition NanoVDB.h:2090
const WordT & getWord(int n) const
Return a const reference to the nth word of the bit mask, for a word of arbitrary size.
Definition NanoVDB.h:2047
bool operator==(const Mask &other) const
Definition NanoVDB.h:2076
static size_t memUsage()
Return the memory footprint in bytes of this Mask.
Definition NanoVDB.h:1966
OffIterator beginOff() const
Definition NanoVDB.h:2023
void setOn()
Set all bits on.
Definition NanoVDB.h:2130
void toggle(uint32_t n)
Definition NanoVDB.h:2157
uint32_t countOn() const
Return the total number of set bits in this Mask.
Definition NanoVDB.h:1975
Mask & operator^=(const Mask &other)
Bitwise XOR.
Definition NanoVDB.h:2184
void setOff(uint32_t n)
Set the specified bit off.
Definition NanoVDB.h:2114
Mask(const Mask &other)
Copy constructor.
Definition NanoVDB.h:2039
WordT & getWord(int n)
Return a reference to the nth word of the bit mask, for a word of arbitrary size.
Definition NanoVDB.h:2055
Mask(bool on)
Definition NanoVDB.h:2031
Mask & operator=(const MaskT &other)
Assignment operator that works with openvdb::util::NodeMask.
Definition NanoVDB.h:2063
bool isOn(uint32_t n) const
Return true if the given bit is set.
Definition NanoVDB.h:2087
void set(bool on)
Set all bits off.
Definition NanoVDB.h:2144
Mask & operator|=(const Mask &other)
Bitwise union.
Definition NanoVDB.h:2168
void setOff()
Set all bits off.
Definition NanoVDB.h:2137
Mask & operator&=(const Mask &other)
Bitwise intersection.
Definition NanoVDB.h:2160
static uint32_t bitCount()
Return the number of bits available in this Mask.
Definition NanoVDB.h:1969
bool isOff() const
Return true if none of the bits are set in this Mask.
Definition NanoVDB.h:2102
bool operator!=(const Mask &other) const
Definition NanoVDB.h:2084
void toggle()
brief Toggle the state of all bits in the mask
Definition NanoVDB.h:2151
Mask & operator-=(const Mask &other)
Bitwise difference.
Definition NanoVDB.h:2176
static uint32_t wordCount()
Return the number of machine words used by this Mask.
Definition NanoVDB.h:1972
bool isOn() const
Return true if all the bits are set in this Mask.
Definition NanoVDB.h:2093
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:1984
Mask()
Initialize all bits to zero.
Definition NanoVDB.h:2026
void setOn(uint32_t n)
Set the specified bit on.
Definition NanoVDB.h:2111
Class to access points at a specific voxel location.
Definition NanoVDB.h:5463
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:5483
typename NanoRoot< uint32_t >::LeafNodeType LeafNodeType
Definition NanoVDB.h:5469
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:5493
PointAccessor(const UInt32Grid &grid)
Definition NanoVDB.h:5471
uint64_t voxelPoints(const Coord &ijk, const AttT *&begin, const AttT *&end) const
get iterators over offsets to points at a specific voxel location
Definition NanoVDB.h:5505
ReadAccessor & operator=(const ReadAccessor &)=default
ValueType operator()(int i, int j, int k) const
Definition NanoVDB.h:4702
ReadAccessor(const GridT &grid)
Constructor from a grid.
Definition NanoVDB.h:4678
NodeInfo getNodeInfo(const CoordType &ijk) const
Definition NanoVDB.h:4707
ReadAccessor(const TreeT &tree)
Constructor from a tree.
Definition NanoVDB.h:4681
ValueType operator()(const CoordType &ijk) const
Definition NanoVDB.h:4698
bool isActive(const CoordType &ijk) const
Definition NanoVDB.h:4712
bool probeValue(const CoordType &ijk, ValueType &v) const
Definition NanoVDB.h:4717
typename RootT::CoordType CoordType
Definition NanoVDB.h:4659
ReadAccessor(const ReadAccessor &)=default
Defaults constructors.
const RootT & root() const
Definition NanoVDB.h:4687
void clear()
Reset this access to its initial state, i.e. with an empty cache @node Noop since this template speci...
Definition NanoVDB.h:4685
ValueType getValue(const CoordType &ijk) const
Definition NanoVDB.h:4694
typename RootT::ValueType ValueType
Definition NanoVDB.h:4658
const LeafT * probeLeaf(const CoordType &ijk) const
Definition NanoVDB.h:4722
uint32_t getDim(const CoordType &ijk, const RayT &ray) const
Definition NanoVDB.h:4728
ReadAccessor(const RootT &root)
Constructor from a root node.
Definition NanoVDB.h:4675
Node caching at all (three) tree levels.
Definition NanoVDB.h:5139
ReadAccessor & operator=(const ReadAccessor &)=default
typename ReadAccessor< ValueT, -1, -1, -1 >::NodeInfo NodeInfo
Definition NanoVDB.h:5167
const NodeTrait< TreeT, LEVEL >::type * getNode() const
Definition NanoVDB.h:5206
CoordT CoordType
Definition NanoVDB.h:5163
ValueType operator()(int i, int j, int k) const
Definition NanoVDB.h:5270
ReadAccessor(const GridT &grid)
Constructor from a grid.
Definition NanoVDB.h:5182
NodeInfo getNodeInfo(const CoordType &ijk) const
Definition NanoVDB.h:5275
ReadAccessor(const TreeT &tree)
Constructor from a tree.
Definition NanoVDB.h:5185
ValueType operator()(const CoordType &ijk) const
Definition NanoVDB.h:5266
ValueT ValueType
Definition NanoVDB.h:5162
bool isActive(const CoordType &ijk) const
Definition NanoVDB.h:5292
const NodeT * getNode() const
Return a const point to the cached node of the specified type.
Definition NanoVDB.h:5198
bool probeValue(const CoordType &ijk, ValueType &v) const
Definition NanoVDB.h:5309
ReadAccessor(const ReadAccessor &)=default
Defaults constructors.
const RootT & root() const
Definition NanoVDB.h:5187
void clear()
Reset this access to its initial state, i.e. with an empty cache.
Definition NanoVDB.h:5215
ValueType getValue(const CoordType &ijk) const
Definition NanoVDB.h:5250
bool isCached(const CoordType &ijk) const
Definition NanoVDB.h:5244
const LeafT * probeLeaf(const CoordType &ijk) const
Definition NanoVDB.h:5326
uint32_t getDim(const CoordType &ijk, const RayT &ray) const
Definition NanoVDB.h:5344
ReadAccessor(const RootT &root)
Constructor from a root node.
Definition NanoVDB.h:5170
ReadAccessor & operator=(const ReadAccessor &)=default
typename ReadAccessor< ValueT, -1, -1, -1 >::NodeInfo NodeInfo
Definition NanoVDB.h:4775
CoordT CoordType
Definition NanoVDB.h:4771
ValueType operator()(int i, int j, int k) const
Definition NanoVDB.h:4823
ReadAccessor(const GridT &grid)
Constructor from a grid.
Definition NanoVDB.h:4786
bool isCached(const CoordType &ijk) const
Definition NanoVDB.h:4805
NodeInfo getNodeInfo(const CoordType &ijk) const
Definition NanoVDB.h:4828
ReadAccessor(const TreeT &tree)
Constructor from a tree.
Definition NanoVDB.h:4789
ValueType operator()(const CoordType &ijk) const
Definition NanoVDB.h:4819
ValueT ValueType
Definition NanoVDB.h:4770
bool isActive(const CoordType &ijk) const
Definition NanoVDB.h:4836
bool probeValue(const CoordType &ijk, ValueType &v) const
Definition NanoVDB.h:4844
ReadAccessor(const ReadAccessor &)=default
Defaults constructors.
const RootT & root() const
Definition NanoVDB.h:4798
void clear()
Reset this access to its initial state, i.e. with an empty cache.
Definition NanoVDB.h:4792
ValueType getValue(const CoordType &ijk) const
Definition NanoVDB.h:4812
const LeafT * probeLeaf(const CoordType &ijk) const
Definition NanoVDB.h:4852
uint32_t getDim(const CoordType &ijk, const RayT &ray) const
Definition NanoVDB.h:4861
ReadAccessor(const RootT &root)
Constructor from a root node.
Definition NanoVDB.h:4778
ReadAccessor & operator=(const ReadAccessor &)=default
ValueType operator()(int i, int j, int k) const
Definition NanoVDB.h:5022
ReadAccessor(const GridT &grid)
Constructor from a grid.
Definition NanoVDB.h:4940
NodeInfo getNodeInfo(const CoordType &ijk) const
Definition NanoVDB.h:5027
ReadAccessor(const TreeT &tree)
Constructor from a tree.
Definition NanoVDB.h:4943
ValueType operator()(const CoordType &ijk) const
Definition NanoVDB.h:5018
bool isActive(const CoordType &ijk) const
Definition NanoVDB.h:5042
bool probeValue(const CoordType &ijk, ValueType &v) const
Definition NanoVDB.h:5057
typename ReadAccessor< ValueT,-1,-1,-1 >::NodeInfo NodeInfo
Definition NanoVDB.h:4924
bool isCached1(const CoordType &ijk) const
Definition NanoVDB.h:4990
ReadAccessor(const ReadAccessor &)=default
Defaults constructors.
const RootT & root() const
Definition NanoVDB.h:4957
void clear()
Reset this access to its initial state, i.e. with an empty cache.
Definition NanoVDB.h:4946
ValueType getValue(const CoordType &ijk) const
Definition NanoVDB.h:5004
bool isCached2(const CoordType &ijk) const
Definition NanoVDB.h:4996
const LeafT * probeLeaf(const CoordType &ijk) const
Definition NanoVDB.h:5072
uint32_t getDim(const CoordType &ijk, const RayT &ray) const
Definition NanoVDB.h:5088
ReadAccessor(const RootT &root)
Constructor from a root node.
Definition NanoVDB.h:4927
Definition NanoVDB.h:2547
8-bit red, green, blue, alpha packed into 32 bit unsigned int
Definition NanoVDB.h:559
const uint32_t & packed() const
Definition NanoVDB.h:593
Rgba8(uint8_t r, uint8_t g, uint8_t b, uint8_t a=255u)
Definition NanoVDB.h:573
Rgba8 & operator=(const Rgba8 &)=default
const uint8_t & g() const
Definition NanoVDB.h:596
uint8_t & g()
Definition NanoVDB.h:600
Rgba8(float r, float g, float b, float a=1.0f)
Definition NanoVDB.h:575
uint32_t packed
Definition NanoVDB.h:562
const uint8_t & a() const
Definition NanoVDB.h:598
bool operator<(const Rgba8 &rhs) const
Definition NanoVDB.h:582
Rgba8(Rgba8 &&)=default
const uint8_t & r() const
Definition NanoVDB.h:595
Rgba8()
Definition NanoVDB.h:572
Rgba8(uint8_t v)
Definition NanoVDB.h:574
float lengthSqr() const
Definition NanoVDB.h:584
Rgba8 & operator=(Rgba8 &&)=default
const uint8_t & b() const
Definition NanoVDB.h:597
uint32_t & packed()
Definition NanoVDB.h:594
uint8_t & r()
Definition NanoVDB.h:599
uint8_t & operator[](int n)
Definition NanoVDB.h:592
float length() const
Definition NanoVDB.h:590
const uint8_t & operator[](int n) const
Definition NanoVDB.h:591
bool operator==(const Rgba8 &rhs) const
Definition NanoVDB.h:583
uint8_t ValueType
Definition NanoVDB.h:566
Rgba8(const Rgba8 &)=default
uint8_t & b()
Definition NanoVDB.h:601
uint8_t c[4]
Definition NanoVDB.h:561
uint8_t & a()
Definition NanoVDB.h:602
static const int SIZE
Definition NanoVDB.h:565
Definition NanoVDB.h:3096
ChildIterator()
Definition NanoVDB.h:3100
ChildIterator & operator++()
Definition NanoVDB.h:3111
ChildIterator operator++(int)
Definition NanoVDB.h:3117
CoordType getOrigin() const
Definition NanoVDB.h:3108
const ChildT * operator->() const
Definition NanoVDB.h:3107
ChildIterator & operator=(const ChildIterator &)=default
uint32_t pos() const
Definition NanoVDB.h:3110
const ChildT & operator*() const
Definition NanoVDB.h:3106
ChildIterator(const RootNode *parent)
Definition NanoVDB.h:3101
Definition NanoVDB.h:3127
ValueIterator & operator=(const ValueIterator &)=default
ValueIterator & operator++()
Definition NanoVDB.h:3142
ValueIterator operator++(int)
Definition NanoVDB.h:3148
bool isActive() const
Definition NanoVDB.h:3138
ValueIterator()
Definition NanoVDB.h:3131
CoordType getOrigin() const
Definition NanoVDB.h:3141
ValueType operator*() const
Definition NanoVDB.h:3137
uint32_t pos() const
Definition NanoVDB.h:3140
ValueIterator(const RootNode *parent)
Definition NanoVDB.h:3132
Definition NanoVDB.h:3158
ValueOnIterator operator++(int)
Definition NanoVDB.h:3178
ValueOnIterator(const RootNode *parent)
Definition NanoVDB.h:3163
ValueOnIterator & operator=(const ValueOnIterator &)=default
CoordType getOrigin() const
Definition NanoVDB.h:3171
ValueOnIterator & operator++()
Definition NanoVDB.h:3172
ValueType operator*() const
Definition NanoVDB.h:3168
uint32_t pos() const
Definition NanoVDB.h:3170
ValueOnIterator()
Definition NanoVDB.h:3162
Top-most node of the VDB tree structure.
Definition NanoVDB.h:3076
const uint32_t & tileCount() const
Return the number of tiles encoded in this root node.
Definition NanoVDB.h:3209
static uint64_t memUsage(uint32_t tableSize)
Return the expected memory footprint in bytes with the specified number of tiles.
Definition NanoVDB.h:3227
ValueIterator beginValue() const
Definition NanoVDB.h:3155
typename ChildT::CoordType CoordType
Definition NanoVDB.h:3087
ChildIterator beginChild() const
Definition NanoVDB.h:3124
FloatType variance() const
Return the variance of all the active values encoded in this root node and any of its child nodes.
Definition NanoVDB.h:3221
const FloatType & average() const
Return a const reference to the average of all the active values encoded in this root node and any of...
Definition NanoVDB.h:3218
RootNode & operator=(const RootNode &)=delete
DataType * data()
Definition NanoVDB.h:3195
AccessorType getAccessor() const
Definition NanoVDB.h:3193
typename DataType::BuildT BuildType
Definition NanoVDB.h:3085
const BBoxType & bbox() const
Return a const reference to the index bounding box of all the active values in this tree,...
Definition NanoVDB.h:3200
RootNode(const RootNode &)=delete
ChildT ChildNodeType
Definition NanoVDB.h:3080
const LeafNodeType * probeLeaf(const CoordType &ijk) const
Definition NanoVDB.h:3266
bool isActive(const CoordType &ijk) const
Definition NanoVDB.h:3241
typename DataType::ValueT ValueType
Definition NanoVDB.h:3083
typename DataType::StatsT FloatType
Definition NanoVDB.h:3084
uint64_t memUsage() const
Return the actual memory footprint of this root node.
Definition NanoVDB.h:3230
bool probeValue(const CoordType &ijk, ValueType &v) const
Definition NanoVDB.h:3252
typename ChildT::LeafNodeType LeafNodeType
Definition NanoVDB.h:3079
const ChildNodeType * probeChild(const CoordType &ijk) const
Definition NanoVDB.h:3276
const FloatType & stdDeviation() const
Return a const reference to the standard deviation of all the active values encoded in this root node...
Definition NanoVDB.h:3224
const Tile * probeTile(const CoordType &ijk) const
Find and return a Tile of this root node.
Definition NanoVDB.h:3286
const ValueType & maximum() const
Return a const reference to the maximum active value encoded in this root node and any of its child n...
Definition NanoVDB.h:3215
typename DataType::Tile Tile
Definition NanoVDB.h:3090
ValueType getValue(const CoordType &ijk) const
Return the value of the given voxel.
Definition NanoVDB.h:3233
const ValueType & background() const
Return the total number of active voxels in the root and all its child nodes.
Definition NanoVDB.h:3206
bool isEmpty() const
Return true if this RootNode is empty, i.e. contains no values or nodes.
Definition NanoVDB.h:3250
RootNode()=delete
This class cannot be constructed or deleted.
const ValueType & minimum() const
Return a const reference to the minimum active value encoded in this root node and any of its child n...
Definition NanoVDB.h:3212
const DataType * data() const
Definition NanoVDB.h:3197
ValueOnIterator beginValueOn() const
Definition NanoVDB.h:3185
VDB Tree, which is a thin wrapper around a RootNode.
Definition NanoVDB.h:2801
typename RootT::ChildNodeType Node2
Definition NanoVDB.h:2817
const NodeTrait< RootT, 1 >::type * getFirstLower() const
Definition NanoVDB.h:2932
RootT Node3
Definition NanoVDB.h:2816
const uint32_t & activeTileCount(uint32_t level) const
Return the total number of active tiles at the specified level of the tree.
Definition NanoVDB.h:2869
const NodeT * getFirstNode() const
return a const pointer to the first node of the specified type
Definition NanoVDB.h:2902
uint64_t activeVoxelCount() const
Return the total number of active voxels in this tree.
Definition NanoVDB.h:2862
typename RootT::LeafNodeType LeafNodeType
Definition NanoVDB.h:2810
const BBox< CoordType > & bbox() const
Return a const reference to the index bounding box of all the active values in this tree,...
Definition NanoVDB.h:2859
const NodeTrait< RootT, 2 >::type * getFirstUpper() const
Definition NanoVDB.h:2934
DataType * data()
Definition NanoVDB.h:2827
uint32_t nodeCount() const
Definition NanoVDB.h:2876
NodeTrait< RootT, 1 >::type * getFirstLower()
Definition NanoVDB.h:2931
Tree()=delete
This class cannot be constructed or deleted.
AccessorType getAccessor() const
Definition NanoVDB.h:2838
NodeTrait< RootT, 2 >::type * getFirstUpper()
Definition NanoVDB.h:2933
bool isActive(const CoordType &ijk) const
Return the active state of the given voxel (regardless of state or location in the tree....
Definition NanoVDB.h:2844
const LeafNodeType * getFirstLeaf() const
Definition NanoVDB.h:2930
NodeTrait< RootT, LEVEL >::type * getFirstNode()
return a pointer to the first node at the specified level
Definition NanoVDB.h:2913
~Tree()=delete
bool probeValue(const CoordType &ijk, ValueType &v) const
Combines the previous two methods in a single call.
Definition NanoVDB.h:2850
typename RootT::CoordType CoordType
Definition NanoVDB.h:2813
RootT & root()
Definition NanoVDB.h:2834
LeafNodeType * getFirstLeaf()
Template specializations of getFirstNode.
Definition NanoVDB.h:2929
Tree(const Tree &)=delete
static uint64_t memUsage()
return memory usage in bytes for the class
Definition NanoVDB.h:2832
LeafNodeType Node0
Definition NanoVDB.h:2819
NodeT * getFirstNode()
return a pointer to the first node of the specified type
Definition NanoVDB.h:2892
uint32_t nodeCount(int level) const
Definition NanoVDB.h:2882
typename Node2::ChildNodeType Node1
Definition NanoVDB.h:2818
const NodeTrait< RootT, LEVEL >::type * getFirstNode() const
return a const pointer to the first node of the specified level
Definition NanoVDB.h:2923
const RootT & root() const
Definition NanoVDB.h:2836
ValueType getValue(const CoordType &ijk) const
Return the value of the given voxel (regardless of state or location in the tree.)
Definition NanoVDB.h:2841
RootT RootType
Definition NanoVDB.h:2809
const ValueType & background() const
Return a const reference to the background value.
Definition NanoVDB.h:2853
bool isEmpty() const
Return true if this tree is empty, i.e. contains no values or nodes.
Definition NanoVDB.h:2847
Tree & operator=(const Tree &)=delete
typename RootT::ValueType ValueType
Definition NanoVDB.h:2811
const DataType * data() const
Definition NanoVDB.h:2829
typename RootT::BuildType BuildType
Definition NanoVDB.h:2812
Dummy type for a voxel whose value equals an offset into an external value array.
Definition NanoVDB.h:213
Dummy type for a voxel whose value equals its binary active state.
Definition NanoVDB.h:216
Vec3(const Vec3< T2 > &v)
Definition NanoVDB.h:1176
Coord round() const
Definition NanoVDB.h:1275
Vec3(T x)
Definition NanoVDB.h:1167
ValueType min() const
Return the smallest vector component.
Definition NanoVDB.h:1264
Vec3 & minComponent(const Vec3 &other)
Perform a component-wise minimum with the other Coord.
Definition NanoVDB.h:1241
Vec3(const Coord &ijk)
Definition NanoVDB.h:1180
bool operator==(const Vec3 &rhs) const
Definition NanoVDB.h:1184
Vec3 operator-() const
Definition NanoVDB.h:1210
T length() const
Definition NanoVDB.h:1209
Vec3 operator*(const Vec3 &v) const
Definition NanoVDB.h:1211
Vec3 & maxComponent(const Vec3 &other)
Perform a component-wise maximum with the other Coord.
Definition NanoVDB.h:1253
Vec3 & operator-=(const Vec3 &v)
Definition NanoVDB.h:1224
Coord floor() const
Definition NanoVDB.h:1273
Vec3 operator*(const T &s) const
Definition NanoVDB.h:1215
Vec3(T x, T y, T z)
Definition NanoVDB.h:1171
Vec3 operator/(const Vec3 &v) const
Definition NanoVDB.h:1212
T dot(const Vec3T &v) const
Definition NanoVDB.h:1197
Vec3 & operator=(const Vec3T &rhs)
Definition NanoVDB.h:1187
Vec3 & operator*=(const T &s)
Definition NanoVDB.h:1231
Vec3 & normalize()
Definition NanoVDB.h:1239
T lengthSqr() const
Definition NanoVDB.h:1205
Vec3 & operator+=(const Vec3 &v)
Definition NanoVDB.h:1217
Coord ceil() const
Definition NanoVDB.h:1274
Vec3()=default
const T & operator[](int i) const
Definition NanoVDB.h:1194
Vec3 cross(const Vec3T &v) const
Definition NanoVDB.h:1199
Vec3 operator/(const T &s) const
Definition NanoVDB.h:1216
bool operator!=(const Vec3 &rhs) const
Definition NanoVDB.h:1185
Vec3 operator+(const Vec3 &v) const
Definition NanoVDB.h:1213
T & operator[](int i)
Definition NanoVDB.h:1195
Vec3 operator-(const Vec3 &v) const
Definition NanoVDB.h:1214
ValueType max() const
Return the largest vector component.
Definition NanoVDB.h:1269
Vec3 & operator/=(const T &s)
Definition NanoVDB.h:1238
T ValueType
Definition NanoVDB.h:1165
A simple vector class with three double components, similar to openvdb::math::Vec4.
Definition NanoVDB.h:1305
Vec4 & normalize()
Definition NanoVDB.h:1377
Vec4 & operator/=(const T &s)
Definition NanoVDB.h:1376
Vec4 operator/(const Vec4 &v) const
Definition NanoVDB.h:1347
Vec4 & operator+=(const Vec4 &v)
Definition NanoVDB.h:1352
Vec4 operator*(const T &s) const
Definition NanoVDB.h:1350
T length() const
Definition NanoVDB.h:1344
Vec4 operator-(const Vec4 &v) const
Definition NanoVDB.h:1349
Vec4 & operator*=(const T &s)
Definition NanoVDB.h:1368
Vec4 operator*(const Vec4 &v) const
Definition NanoVDB.h:1346
Vec4(T x, T y, T z, T w)
Definition NanoVDB.h:1316
bool operator!=(const Vec4 &rhs) const
Definition NanoVDB.h:1326
Vec4 & maxComponent(const Vec4 &other)
Perform a component-wise maximum with the other Coord.
Definition NanoVDB.h:1393
Vec4(const Vec4< T2 > &v)
Definition NanoVDB.h:1321
T lengthSqr() const
Definition NanoVDB.h:1340
const T & operator[](int i) const
Definition NanoVDB.h:1336
Vec4 & operator=(const Vec4T &rhs)
Definition NanoVDB.h:1328
Vec4 & operator-=(const Vec4 &v)
Definition NanoVDB.h:1360
Vec4()=default
bool operator==(const Vec4 &rhs) const
Definition NanoVDB.h:1325
Vec4 & minComponent(const Vec4 &other)
Perform a component-wise minimum with the other Coord.
Definition NanoVDB.h:1379
T & operator[](int i)
Definition NanoVDB.h:1337
Vec4 operator-() const
Definition NanoVDB.h:1345
Vec4 operator/(const T &s) const
Definition NanoVDB.h:1351
T dot(const Vec4T &v) const
Definition NanoVDB.h:1339
T ValueType
Definition NanoVDB.h:1310
Vec4(T x)
Definition NanoVDB.h:1312
Vec4 operator+(const Vec4 &v) const
Definition NanoVDB.h:1348
Bit-compacted representation of all three version numbers.
Definition NanoVDB.h:648
const char * c_str() const
Definition NanoVDB.h:674
uint32_t getPatch() const
Definition NanoVDB.h:671
bool operator<=(const Version &rhs) const
Definition NanoVDB.h:665
Version()
Definition NanoVDB.h:651
bool operator==(const Version &rhs) const
Definition NanoVDB.h:663
Version(uint32_t major, uint32_t minor, uint32_t patch)
Definition NanoVDB.h:656
uint32_t getMajor() const
Definition NanoVDB.h:669
bool operator>=(const Version &rhs) const
Definition NanoVDB.h:667
uint32_t getMinor() const
Definition NanoVDB.h:670
uint32_t id() const
Definition NanoVDB.h:668
void writeUncompressedGrid(StreamT &os, const void *buffer)
This is a standalone alternative to io::writeGrid(...,Codec::NONE) defined in util/IO....
Definition NanoVDB.h:5649
VecT< GridHandleT > readUncompressedGrids(StreamT &is, const typename GridHandleT::BufferType &buffer=typename GridHandleT::BufferType())
read all uncompressed grids from a stream and return their handles.
Definition NanoVDB.h:5722
void writeUncompressedGrids(const char *fileName, const VecT< GridHandleT > &handles)
write multiple NanoVDB grids to a single file, without compression.
Definition NanoVDB.h:5697
Definition NanoVDB.h:208
uint64_t AlignUp(uint64_t byteCount)
round up byteSize to the nearest wordSize, e.g. to align to machine word: AlignUp<sizeof(size_t)(n)
Definition NanoVDB.h:954
const char * toStr(GridType gridType)
Retuns a c-string used to describe a GridType.
Definition NanoVDB.h:267
float Fract(float x)
Definition NanoVDB.h:809
static int64_t PtrDiff(const T1 *p, const T2 *q)
Definition NanoVDB.h:535
static uint64_t alignmentPadding(const void *p)
return the smallest number of bytes that when added to the specified pointer results in an aligned po...
Definition NanoVDB.h:510
Vec3T matMult(const float *mat, const Vec3T &xyz)
Definition NanoVDB.h:1533
static DstT * PtrAdd(SrcT *p, int64_t offset)
Definition NanoVDB.h:542
GridClass
Classes (defined in OpenVDB) that are currently supported by NanoVDB.
Definition NanoVDB.h:281
Vec3T matMultT(const float *mat, const Vec3T &xyz)
Definition NanoVDB.h:1567
GridType
List of types that are currently supported by NanoVDB.
Definition NanoVDB.h:243
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:5398
static T * alignPtr(T *p)
offset the specified pointer so it is aligned.
Definition NanoVDB.h:518
GridFlags
Grid flags which indicate what extra information is present in the grid buffer.
Definition NanoVDB.h:306
int32_t Floor(float x)
Definition NanoVDB.h:818
GridBlindDataClass
Blind-data Classes that are currently supported by NanoVDB.
Definition NanoVDB.h:335
GridType mapToGridType()
Maps from a templated value type to a GridType enum.
Definition NanoVDB.h:1488
static bool isAligned(const void *p)
return true if the specified pointer is aligned
Definition NanoVDB.h:498
GridBlindDataSemantic
Blind-data Semantics that are currently understood by NanoVDB.
Definition NanoVDB.h:343
bool isFloatingPoint(GridType gridType)
return true if the GridType maps to a floating point value.
Definition NanoVDB.h:610
static bool isValid(const void *p)
return true if the specified pointer is aligned and not NULL
Definition NanoVDB.h:504
Definition Coord.h:589
Iterator begin() const
Definition NanoVDB.h:1749
BBox()
Definition NanoVDB.h:1750
bool is_divisible() const
Definition NanoVDB.h:1774
BBox(const CoordT &min, const CoordT &max)
Definition NanoVDB.h:1754
CoordT dim() const
Definition NanoVDB.h:1781
bool empty() const
Return true if this bounding box is empty, i.e. uninitialized.
Definition NanoVDB.h:1778
BBox expandBy(typename CoordT::ValueType padding) const
Return a new instance that is expanded by the specified padding.
Definition NanoVDB.h:1805
bool isInside(const BBox &b) const
Return true if the given bounding box is inside this bounding box.
Definition NanoVDB.h:1785
bool hasOverlap(const BBox &b) const
Return true if the given bounding box overlaps with this bounding box.
Definition NanoVDB.h:1791
uint64_t volume() const
Definition NanoVDB.h:1782
static BBox createCube(const CoordT &min, typename CoordT::ValueType dim)
Definition NanoVDB.h:1769
BBox(BBox &other, const SplitT &)
Definition NanoVDB.h:1760
BBox< Vec3< RealT > > asReal() const
Definition NanoVDB.h:1798
bool isInside(const CoordT &p) const
Definition NanoVDB.h:1783
Vec3T dim() const
Definition NanoVDB.h:1694
bool isInside(const Vec3T &p) const
Definition NanoVDB.h:1695
BBox()
Definition NanoVDB.h:1671
BBox(const Coord &min, const Coord &max)
Definition NanoVDB.h:1680
bool empty() const
Definition NanoVDB.h:1691
BBox(const Vec3T &min, const Vec3T &max)
Definition NanoVDB.h:1676
Vec3T Vec3Type
Definition NanoVDB.h:1666
typename Vec3T::ValueType ValueType
Definition NanoVDB.h:1667
static BBox createCube(const Coord &min, typename Coord::ValueType dim)
Definition NanoVDB.h:1685
BBox(const BaseBBox< Coord > &bbox)
Definition NanoVDB.h:1690
Definition NanoVDB.h:1657
Definition NanoVDB.h:1603
Vec3T mCoord[2]
Definition NanoVDB.h:1604
BaseBBox()
Definition NanoVDB.h:1649
const Vec3T & max() const
Definition NanoVDB.h:1612
Coord & translate(const Vec3T &xyz)
Definition NanoVDB.h:1613
BaseBBox & expand(const Vec3T &xyz)
Definition NanoVDB.h:1620
bool operator!=(const BaseBBox &rhs) const
Definition NanoVDB.h:1606
const Vec3T & operator[](int i) const
Definition NanoVDB.h:1607
Vec3T & operator[](int i)
Definition NanoVDB.h:1608
bool isInside(const Vec3T &xyz)
Definition NanoVDB.h:1639
const Vec3T & min() const
Definition NanoVDB.h:1611
BaseBBox(const Vec3T &min, const Vec3T &max)
Definition NanoVDB.h:1650
Vec3T & min()
Definition NanoVDB.h:1609
bool operator==(const BaseBBox &rhs) const
Definition NanoVDB.h:1605
Vec3T & max()
Definition NanoVDB.h:1610
BaseBBox & intersect(const BaseBBox &bbox)
Intersect this bounding box with the given bounding box.
Definition NanoVDB.h:1628
float type
Definition NanoVDB.h:485
float Type
Definition NanoVDB.h:484
float type
Definition NanoVDB.h:471
float Type
Definition NanoVDB.h:470
float type
Definition NanoVDB.h:478
float Type
Definition NanoVDB.h:477
float type
Definition NanoVDB.h:492
float Type
Definition NanoVDB.h:491
float type
Definition NanoVDB.h:464
float Type
Definition NanoVDB.h:463
uint64_t Type
Definition NanoVDB.h:449
uint64_t type
Definition NanoVDB.h:450
bool Type
Definition NanoVDB.h:456
bool type
Definition NanoVDB.h:457
Maps one type (e.g. the build types above) to other (actual) types.
Definition NanoVDB.h:441
T Type
Definition NanoVDB.h:442
T type
Definition NanoVDB.h:443
static double value()
Definition NanoVDB.h:713
static float value()
Definition NanoVDB.h:708
Delta for small floating-point offsets.
Definition NanoVDB.h:704
double FloatType
Definition NanoVDB.h:1463
uint64_t FloatType
Definition NanoVDB.h:1475
bool FloatType
Definition NanoVDB.h:1481
bool FloatType
Definition NanoVDB.h:1469
Definition NanoVDB.h:1456
float FloatType
Definition NanoVDB.h:1457
Definition NanoVDB.h:2317
uint32_t mFlags
Definition NanoVDB.h:2321
static uint64_t memUsage(uint64_t blindDataCount=0)
return memory usage in bytes for the class (note this computes for all blindMetaData structures....
Definition NanoVDB.h:2328
void setBlindData(void *ptr)
Definition NanoVDB.h:2333
GridType mDataType
Definition NanoVDB.h:2324
GridBlindDataSemantic mSemantic
Definition NanoVDB.h:2322
int64_t mByteOffset
Definition NanoVDB.h:2319
GridBlindDataClass mDataClass
Definition NanoVDB.h:2323
uint64_t mElementCount
Definition NanoVDB.h:2320
const T * getBlindData() const
Definition NanoVDB.h:2336
Struct with all the member data of the Grid (useful during serialization of an openvdb grid)
Definition NanoVDB.h:2434
uint32_t mFlags
Definition NanoVDB.h:2439
const void * treePtr() const
Definition NanoVDB.h:2532
void setMinMaxOn(bool on=true)
Definition NanoVDB.h:2456
void setAverageOn(bool on=true)
Definition NanoVDB.h:2480
Vec3T applyInverseJacobianF(const Vec3T &xyz) const
Definition NanoVDB.h:2524
Vec3T applyIJTF(const Vec3T &xyz) const
Definition NanoVDB.h:2526
uint32_t mBlindMetadataCount
Definition NanoVDB.h:2450
Version mVersion
Definition NanoVDB.h:2438
uint32_t mData0
Definition NanoVDB.h:2451
GridType mGridType
Definition NanoVDB.h:2448
uint64_t mMagic
Definition NanoVDB.h:2436
void setStdDeviationOn(bool on=true)
Definition NanoVDB.h:2488
Vec3T applyIJT(const Vec3T &xyz) const
Definition NanoVDB.h:2515
GridClass mGridClass
Definition NanoVDB.h:2447
void setBBoxOn(bool on=true)
Definition NanoVDB.h:2464
void setLongGridNameOn(bool on=true)
Definition NanoVDB.h:2472
Vec3T applyJacobianF(const Vec3T &xyz) const
Definition NanoVDB.h:2522
uint64_t mGridSize
Definition NanoVDB.h:2442
BBox< Vec3R > mWorldBBox
Definition NanoVDB.h:2445
Vec3T applyInverseJacobian(const Vec3T &xyz) const
Definition NanoVDB.h:2513
void * treePtr()
Definition NanoVDB.h:2529
const GridBlindMetaData * blindMetaData(uint32_t n) const
Returns a const reference to the blindMetaData at the specified linear offset.
Definition NanoVDB.h:2537
void setBreadthFirstOn(bool on=true)
Definition NanoVDB.h:2496
uint64_t mChecksum
Definition NanoVDB.h:2437
Vec3T applyMapF(const Vec3T &xyz) const
Definition NanoVDB.h:2518
uint64_t mData1
Definition NanoVDB.h:2452
uint32_t mGridCount
Definition NanoVDB.h:2441
Vec3R mVoxelSize
Definition NanoVDB.h:2446
Vec3T applyInverseMap(const Vec3T &xyz) const
Definition NanoVDB.h:2509
Map mMap
Definition NanoVDB.h:2444
Vec3T applyJacobian(const Vec3T &xyz) const
Definition NanoVDB.h:2511
void setFlagsOff()
Definition NanoVDB.h:2455
int64_t mBlindMetadataOffset
Definition NanoVDB.h:2449
uint32_t mGridIndex
Definition NanoVDB.h:2440
Vec3T applyMap(const Vec3T &xyz) const
Definition NanoVDB.h:2507
Vec3T applyInverseMapF(const Vec3T &xyz) const
Definition NanoVDB.h:2520
const typename GridT::TreeType Type
Definition NanoVDB.h:2792
const typename GridT::TreeType type
Definition NanoVDB.h:2793
defines a tree type from a grid type while preserving constness
Definition NanoVDB.h:2785
typename GridT::TreeType Type
Definition NanoVDB.h:2786
typename GridT::TreeType type
Definition NanoVDB.h:2787
Struct with all the member data of the InternalNode (useful during serialization of an openvdb Intern...
Definition NanoVDB.h:3420
void setOrigin(const T &ijk)
Definition NanoVDB.h:3501
StatsT mAverage
Definition NanoVDB.h:3446
typename ChildT::CoordType CoordT
Definition NanoVDB.h:3424
void setChild(uint32_t n, const void *ptr)
Definition NanoVDB.h:3461
MaskT mChildMask
Definition NanoVDB.h:3442
void setValue(uint32_t n, const ValueT &v)
Definition NanoVDB.h:3468
InternalData(const InternalData &)=delete
const ValueT & getMax() const
Definition NanoVDB.h:3504
void setDev(const StatsT &v)
Definition NanoVDB.h:3511
const ChildT * getChild(uint32_t n) const
Definition NanoVDB.h:3480
bool isActive(uint32_t n) const
Definition NanoVDB.h:3492
void setMin(const ValueT &v)
Definition NanoVDB.h:3508
typename ChildT::FloatType StatsT
Definition NanoVDB.h:3423
bool isChild(uint32_t n) const
Definition NanoVDB.h:3498
typename ChildT::BuildType BuildT
Definition NanoVDB.h:3422
ValueT getValue(uint32_t n) const
Definition NanoVDB.h:3486
static constexpr uint32_t padding()
Return padding of this class in bytes, due to aliasing and 32B alignment.
Definition NanoVDB.h:3453
const ValueT & getMin() const
Definition NanoVDB.h:3503
void setMax(const ValueT &v)
Definition NanoVDB.h:3509
StatsT mStdDevi
Definition NanoVDB.h:3447
BBox< CoordT > mBBox
Definition NanoVDB.h:3439
ChildT * getChild(uint32_t n)
Returns a pointer to the child node at the specifed linear offset.
Definition NanoVDB.h:3475
ValueT mMaximum
Definition NanoVDB.h:3445
const StatsT & stdDeviation() const
Definition NanoVDB.h:3506
static uint64_t memUsage()
Definition NanoVDB.h:3459
const StatsT & average() const
Definition NanoVDB.h:3505
MaskT mValueMask
Definition NanoVDB.h:3441
typename ChildT::template MaskType< LOG2DIM > MaskT
Definition NanoVDB.h:3425
InternalData & operator=(const InternalData &)=delete
void setAvg(const StatsT &v)
Definition NanoVDB.h:3510
typename ChildT::ValueType ValueT
Definition NanoVDB.h:3421
ValueT mMinimum
Definition NanoVDB.h:3444
InternalData()=delete
This class cannot be constructed or deleted.
uint64_t mFlags
Definition NanoVDB.h:3440
static constexpr uint8_t bitWidth()
Definition NanoVDB.h:4012
float getValue(uint32_t i) const
Definition NanoVDB.h:4013
LeafData & operator=(const LeafData &)=delete
static constexpr uint32_t padding()
Definition NanoVDB.h:4007
uint16_t ArrayType
Definition NanoVDB.h:4002
LeafData()=delete
This class cannot be constructed or deleted.
static constexpr uint64_t memUsage()
Definition NanoVDB.h:4006
static constexpr uint8_t bitWidth()
Definition NanoVDB.h:3951
float getValue(uint32_t i) const
Definition NanoVDB.h:3952
LeafData & operator=(const LeafData &)=delete
static constexpr uint32_t padding()
Definition NanoVDB.h:3946
LeafData()=delete
This class cannot be constructed or deleted.
uint8_t ArrayType
Definition NanoVDB.h:3941
static constexpr uint64_t memUsage()
Definition NanoVDB.h:3945
static constexpr uint8_t bitWidth()
Definition NanoVDB.h:3984
float getValue(uint32_t i) const
Definition NanoVDB.h:3985
LeafData & operator=(const LeafData &)=delete
static constexpr uint32_t padding()
Definition NanoVDB.h:3979
static constexpr int64_t memUsage()
Definition NanoVDB.h:3978
LeafData()=delete
This class cannot be constructed or deleted.
uint8_t ArrayType
Definition NanoVDB.h:3975
size_t memUsage() const
Definition NanoVDB.h:4039
float getValue(uint32_t i) const
Definition NanoVDB.h:4041
LeafData & operator=(const LeafData &)=delete
uint8_t bitWidth() const
Definition NanoVDB.h:4038
static constexpr uint32_t padding()
Definition NanoVDB.h:4033
LeafData()=delete
This class cannot be constructed or deleted.
static size_t memUsage(uint32_t bitWidth)
Definition NanoVDB.h:4040
void setOrigin(const T &ijk)
Definition NanoVDB.h:4239
void setDev(const T &dev, T *p)
Definition NanoVDB.h:4237
uint64_t getMax() const
Definition NanoVDB.h:4214
LeafData & operator=(const LeafData &)=delete
uint64_t getValue(uint32_t i) const
Definition NanoVDB.h:4222
MaskT< LOG2DIM > mValueMask
Definition NanoVDB.h:4202
static constexpr uint32_t padding()
Definition NanoVDB.h:4207
void setValue(uint32_t offset, uint64_t)
Definition NanoVDB.h:4217
LeafData()=delete
This class cannot be constructed or deleted.
void setMax(const T &max, T *p)
Definition NanoVDB.h:4233
static uint64_t memUsage()
Definition NanoVDB.h:4211
void setMin(const T &min, T *p)
Definition NanoVDB.h:4231
uint64_t getAvg() const
Definition NanoVDB.h:4215
uint64_t getDev() const
Definition NanoVDB.h:4216
void setAvg(const T &avg, T *p)
Definition NanoVDB.h:4235
uint64_t getMin() const
Definition NanoVDB.h:4213
void setOrigin(const T &ijk)
Definition NanoVDB.h:4177
bool getDev() const
Definition NanoVDB.h:4165
bool getMin() const
Definition NanoVDB.h:4162
void setMax(const ValueType &)
Definition NanoVDB.h:4172
bool getValue(uint32_t i) const
Definition NanoVDB.h:4161
LeafData & operator=(const LeafData &)=delete
bool getMax() const
Definition NanoVDB.h:4163
void setDev(const FloatType &)
Definition NanoVDB.h:4174
bool getAvg() const
Definition NanoVDB.h:4164
MaskT< LOG2DIM > mValueMask
Definition NanoVDB.h:4151
void setValue(uint32_t offset, bool)
Definition NanoVDB.h:4166
static constexpr uint32_t padding()
Definition NanoVDB.h:4156
LeafData()=delete
This class cannot be constructed or deleted.
void setAvg(const FloatType &)
Definition NanoVDB.h:4173
static uint64_t memUsage()
Definition NanoVDB.h:4154
void setMin(const ValueType &)
Definition NanoVDB.h:4171
void setOrigin(const T &ijk)
Definition NanoVDB.h:4127
bool getDev() const
Definition NanoVDB.h:4114
void setMin(const bool &)
Definition NanoVDB.h:4121
bool getMin() const
Definition NanoVDB.h:4111
void setMax(const bool &)
Definition NanoVDB.h:4122
void setValue(uint32_t offset, bool v)
Definition NanoVDB.h:4115
bool getValue(uint32_t i) const
Definition NanoVDB.h:4110
uint8_t mFlags
Definition NanoVDB.h:4101
LeafData & operator=(const LeafData &)=delete
bool getMax() const
Definition NanoVDB.h:4112
MaskT< LOG2DIM > ArrayType
Definition NanoVDB.h:4096
bool getAvg() const
Definition NanoVDB.h:4113
MaskT< LOG2DIM > mValueMask
Definition NanoVDB.h:4102
MaskT< LOG2DIM > mValues
Definition NanoVDB.h:4103
CoordT mBBoxMin
Definition NanoVDB.h:4099
static constexpr uint32_t padding()
Definition NanoVDB.h:4106
void setDev(const bool &)
Definition NanoVDB.h:4124
LeafData()=delete
This class cannot be constructed or deleted.
static uint64_t memUsage()
Definition NanoVDB.h:4107
void setAvg(const bool &)
Definition NanoVDB.h:4123
Stuct with all the member data of the LeafNode (useful during serialization of an openvdb LeafNode)
Definition NanoVDB.h:3812
void setOrigin(const T &ijk)
Definition NanoVDB.h:3862
ValueType mMaximum
Definition NanoVDB.h:3827
FloatType getDev() const
Definition NanoVDB.h:3854
typename FloatTraits< ValueT >::FloatType FloatType
Definition NanoVDB.h:3817
void setMin(const ValueType &v)
Definition NanoVDB.h:3856
void setMax(const ValueType &v)
Definition NanoVDB.h:3857
FloatType mAverage
Definition NanoVDB.h:3828
void setDev(const FloatType &v)
Definition NanoVDB.h:3859
uint8_t mFlags
Definition NanoVDB.h:3823
LeafData & operator=(const LeafData &)=delete
LeafData(const LeafData &)=delete
ValueType getMin() const
Definition NanoVDB.h:3851
ValueType getValue(uint32_t i) const
Definition NanoVDB.h:3843
void setValue(uint32_t offset, const ValueType &value)
Definition NanoVDB.h:3845
ValueT ValueType
Definition NanoVDB.h:3815
MaskT< LOG2DIM > mValueMask
Definition NanoVDB.h:3824
void setValueOnly(uint32_t offset, const ValueType &value)
Definition NanoVDB.h:3844
CoordT mBBoxMin
Definition NanoVDB.h:3821
static constexpr uint32_t padding()
Return padding of this class in bytes, due to aliasing and 32B alignment.
Definition NanoVDB.h:3835
ValueType getMax() const
Definition NanoVDB.h:3852
LeafData()=delete
This class cannot be constructed or deleted.
ValueT ArrayType
Definition NanoVDB.h:3818
FloatType getAvg() const
Definition NanoVDB.h:3853
static uint64_t memUsage()
Definition NanoVDB.h:3840
ValueType mMinimum
Definition NanoVDB.h:3826
void setAvg(const FloatType &v)
Definition NanoVDB.h:3858
ValueT BuildType
Definition NanoVDB.h:3816
FloatType mStdDevi
Definition NanoVDB.h:3829
Base-class for quantized float leaf nodes.
Definition NanoVDB.h:3874
void setOrigin(const T &ijk)
Definition NanoVDB.h:3929
float ValueType
Definition NanoVDB.h:3877
float getMin() const
return the quantized minimum of the active values in this node
Definition NanoVDB.h:3904
void setDev(float dev)
Definition NanoVDB.h:3926
void setMin(float min)
Definition NanoVDB.h:3917
float getAvg() const
return the quantized average of the active values in this node
Definition NanoVDB.h:3910
uint8_t mFlags
Definition NanoVDB.h:3882
float mQuantum
Definition NanoVDB.h:3886
MaskT< LOG2DIM > mValueMask
Definition NanoVDB.h:3883
void init(float min, float max, uint8_t bitWidth)
Definition NanoVDB.h:3897
uint16_t mAvg
Definition NanoVDB.h:3887
CoordT mBBoxMin
Definition NanoVDB.h:3880
static constexpr uint32_t padding()
Return padding of this class in bytes, due to aliasing and 32B alignment.
Definition NanoVDB.h:3894
float mMinimum
Definition NanoVDB.h:3885
float FloatType
Definition NanoVDB.h:3878
void setMax(float max)
Definition NanoVDB.h:3920
void setAvg(float avg)
Definition NanoVDB.h:3923
static uint64_t memUsage()
Definition NanoVDB.h:3889
float getDev() const
return the quantized standard deviation of the active values in this node
Definition NanoVDB.h:3914
float getMax() const
return the quantized maximum of the active values in this node
Definition NanoVDB.h:3907
Definition NanoVDB.h:4257
static uint32_t dim()
Definition NanoVDB.h:4260
Defines an affine transform and its inverse represented as a 3x3 matrix and a vec3 translation.
Definition NanoVDB.h:2226
double mTaperD
Definition NanoVDB.h:2234
Vec3T applyInverseJacobianF(const Vec3T &xyz) const
Definition NanoVDB.h:2272
Vec3T applyIJTF(const Vec3T &xyz) const
Definition NanoVDB.h:2277
Vec3T applyIJT(const Vec3T &xyz) const
Definition NanoVDB.h:2275
Vec3T applyJacobianF(const Vec3T &xyz) const
Definition NanoVDB.h:2256
Vec3T applyInverseJacobian(const Vec3T &xyz) const
Definition NanoVDB.h:2270
void set(const Mat4T &mat, const Mat4T &invMat, double taper)
Initialize the member data.
Definition NanoVDB.h:2243
Vec3T applyMapF(const Vec3T &xyz) const
Definition NanoVDB.h:2251
Vec3T applyInverseMap(const Vec3T &xyz) const
Definition NanoVDB.h:2259
Vec3T applyJacobian(const Vec3T &xyz) const
Definition NanoVDB.h:2254
Vec3T applyMap(const Vec3T &xyz) const
Definition NanoVDB.h:2249
Vec3T applyInverseMapF(const Vec3T &xyz) const
Definition NanoVDB.h:2264
float mTaperF
Definition NanoVDB.h:2230
Maximum floating-point values.
Definition NanoVDB.h:745
static T value()
Definition NanoVDB.h:746
Trait to map from LEVEL to node type.
Definition NanoVDB.h:4569
typename GridOrTreeOrRootT::LeafNodeType type
Definition NanoVDB.h:2353
typename GridOrTreeOrRootT::LeafNodeType Type
Definition NanoVDB.h:2352
typename GridOrTreeOrRootT::RootType::ChildNodeType::ChildNodeType Type
Definition NanoVDB.h:2367
typename GridOrTreeOrRootT::RootType::ChildNodeType::ChildNodeType type
Definition NanoVDB.h:2368
typename GridOrTreeOrRootT::RootType::ChildNodeType Type
Definition NanoVDB.h:2381
typename GridOrTreeOrRootT::RootType::ChildNodeType type
Definition NanoVDB.h:2382
typename GridOrTreeOrRootT::RootType type
Definition NanoVDB.h:2396
typename GridOrTreeOrRootT::RootType Type
Definition NanoVDB.h:2395
const typename GridOrTreeOrRootT::LeafNodeType Type
Definition NanoVDB.h:2359
const typename GridOrTreeOrRootT::LeafNodeType type
Definition NanoVDB.h:2360
const typename GridOrTreeOrRootT::RootType::ChildNodeType::ChildNodeType Type
Definition NanoVDB.h:2374
const typename GridOrTreeOrRootT::RootType::ChildNodeType::ChildNodeType type
Definition NanoVDB.h:2375
const typename GridOrTreeOrRootT::RootType::ChildNodeType type
Definition NanoVDB.h:2389
const typename GridOrTreeOrRootT::RootType::ChildNodeType Type
Definition NanoVDB.h:2388
const typename GridOrTreeOrRootT::RootType type
Definition NanoVDB.h:2404
const typename GridOrTreeOrRootT::RootType Type
Definition NanoVDB.h:2403
Struct to derive node type from its level in a given grid, tree or root while preserving constness.
Definition NanoVDB.h:2345
ValueType mMaximum
Definition NanoVDB.h:4667
FloatType mAverage
Definition NanoVDB.h:4668
CoordType mBBoxMax
Definition NanoVDB.h:4671
ValueType mMinimum
Definition NanoVDB.h:4666
CoordType mBBoxMin
Definition NanoVDB.h:4670
FloatType mStdDevi
Definition NanoVDB.h:4669
Definition NanoVDB.h:3003
ValueT value
Definition NanoVDB.h:3025
void setChild(const CoordType &k, const ChildT *ptr, const RootData *data)
Definition NanoVDB.h:3005
uint32_t state
Definition NanoVDB.h:3024
bool isActive() const
Definition NanoVDB.h:3020
KeyT key
Definition NanoVDB.h:3022
void setValue(const CoordType &k, bool s, const ValueType &v)
Definition NanoVDB.h:3011
CoordT origin() const
Definition NanoVDB.h:3021
bool isValue() const
Definition NanoVDB.h:3019
bool isChild() const
Definition NanoVDB.h:3018
int64_t child
Definition NanoVDB.h:3023
Struct with all the member data of the RootNode (useful during serialization of an openvdb RootNode)
Definition NanoVDB.h:2955
StatsT mAverage
Definition NanoVDB.h:2992
typename ChildT::CoordType CoordT
Definition NanoVDB.h:2958
static CoordT KeyToCoord(const KeyT &key)
Definition NanoVDB.h:2974
const ChildT * getChild(const Tile *tile) const
Definition NanoVDB.h:3050
RootData()=delete
This class cannot be constructed or deleted.
ValueT mBackground
Definition NanoVDB.h:2989
Tile * tile(uint32_t n)
Definition NanoVDB.h:3036
const Tile * tile(uint32_t n) const
Returns a non-const reference to the tile at the specified linear offset.
Definition NanoVDB.h:3031
uint32_t mTableSize
Definition NanoVDB.h:2987
const ValueT & getMax() const
Definition NanoVDB.h:3057
void setDev(const StatsT &v)
Definition NanoVDB.h:3064
uint64_t KeyT
Return a key based on the coordinates of a voxel.
Definition NanoVDB.h:2964
void setMin(const ValueT &v)
Definition NanoVDB.h:3061
typename ChildT::FloatType StatsT
Definition NanoVDB.h:2959
typename ChildT::BuildType BuildT
Definition NanoVDB.h:2957
ChildT * getChild(const Tile *tile)
Returns a const reference to the child node in the specified tile.
Definition NanoVDB.h:3045
static constexpr uint32_t padding()
Return padding of this class in bytes, due to aliasing and 32B alignment.
Definition NanoVDB.h:2998
const ValueT & getMin() const
Definition NanoVDB.h:3056
void setMax(const ValueT &v)
Definition NanoVDB.h:3062
StatsT mStdDevi
Definition NanoVDB.h:2993
RootData(const RootData &)=delete
static KeyT CoordToKey(const CoordType &ijk)
Definition NanoVDB.h:2966
RootData & operator=(const RootData &)=delete
BBox< CoordT > mBBox
Definition NanoVDB.h:2986
ValueT mMaximum
Definition NanoVDB.h:2991
const StatsT & stdDeviation() const
Definition NanoVDB.h:3059
const StatsT & average() const
Definition NanoVDB.h:3058
void setAvg(const StatsT &v)
Definition NanoVDB.h:3063
typename ChildT::ValueType ValueT
Definition NanoVDB.h:2956
ValueT mMinimum
Definition NanoVDB.h:2990
T ElementType
Definition NanoVDB.h:1437
static T scalar(const T &s)
Definition NanoVDB.h:1438
static ElementType scalar(const T &v)
Definition NanoVDB.h:1449
typename T::ValueType ElementType
Definition NanoVDB.h:1448
Definition NanoVDB.h:1428
static double value()
Definition NanoVDB.h:697
static float value()
Definition NanoVDB.h:692
Tolerance for floating-point comparison.
Definition NanoVDB.h:688
Definition NanoVDB.h:2759
const RootT * getRoot() const
Definition NanoVDB.h:2771
void setFirstNode(const NodeT *node)
Definition NanoVDB.h:2774
RootT * getRoot()
Definition NanoVDB.h:2769
void setRoot(const RootT *root)
Definition NanoVDB.h:2767
uint64_t mVoxelCount
Definition NanoVDB.h:2764
T type
Definition NanoVDB.h:378
C++11 implementation of std::enable_if.
Definition NanoVDB.h:372
Definition NanoVDB.h:385
static constexpr bool value
Definition NanoVDB.h:386
C++11 implementation of std::is_floating_point.
Definition NanoVDB.h:414
static const bool value
Definition NanoVDB.h:415
C++11 implementation of std::is_same.
Definition NanoVDB.h:357
static constexpr bool value
Definition NanoVDB.h:358
Metafunction used to determine if the first template parameter is a specialization of the class templ...
Definition NanoVDB.h:427
static const bool value
Definition NanoVDB.h:428
T type
Definition NanoVDB.h:406
Definition NanoVDB.h:399
T type
Definition NanoVDB.h:400
Definition NanoVDB.h:3429
ValueT value
Definition NanoVDB.h:3430
Tile(const Tile &)=delete
Tile & operator=(const Tile &)=delete
Tile()=delete
This class cannot be constructed or deleted.
int64_t child
Definition NanoVDB.h:3431