OpenVDB  10.0.1
IndexGridBuilder.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 IndexGridBuilder.h
6 
7  \author Ken Museth
8 
9  \date July 8, 2022
10 
11  \brief Generates a NanoVDB IndexGrid from any existing NanoVDB grid.
12 
13  \note An IndexGrid encodes index offsets to external value arrays
14 */
15 
16 #ifndef NANOVDB_INDEXGRIDBUILDER_H_HAS_BEEN_INCLUDED
17 #define NANOVDB_INDEXGRIDBUILDER_H_HAS_BEEN_INCLUDED
18 
19 #include "GridHandle.h"
20 #include "NodeManager.h"
21 #include "Range.h"
22 #include "ForEach.h"
23 
24 #include <map>
25 #include <limits>
26 #include <iostream>
27 #include <sstream> // for stringstream
28 #include <vector>
29 #include <cstring> // for memcpy
30 
31 namespace nanovdb {
32 
33 /// @brief Allows for the construction of NanoVDB grids without any dependency
34 template <typename SrcValueT>
36 {
40  using SrcData0 = typename SrcNode0::DataType;
41  using SrcData1 = typename SrcNode1::DataType;
42  using SrcData2 = typename SrcNode2::DataType;
46 
56 
57  NodeManagerHandle<> mSrcMgrHandle;
58  NodeManager<SrcValueT> *mSrcMgr;
59  std::vector<uint64_t> mValIdx2, mValIdx1, mValIdx0;// store id of first value in node
60  uint8_t* mBufferPtr;// pointer to the beginning of the buffer
61  uint64_t mBufferOffsets[9];//grid, tree, root, upper, lower, leafs, meta, data, buffer size
62  uint64_t mValueCount;
63  const bool mIsSparse, mIncludeStats;// include inactive values and stats
64 
65  DstNode0* getLeaf( int i=0) const {return PtrAdd<DstNode0>(mBufferPtr, mBufferOffsets[5]) + i;}
66  DstNode1* getLower(int i=0) const {return PtrAdd<DstNode1>(mBufferPtr, mBufferOffsets[4]) + i;}
67  DstNode2* getUpper(int i=0) const {return PtrAdd<DstNode2>(mBufferPtr, mBufferOffsets[3]) + i;}
68  DstRootT* getRoot() const {return PtrAdd<DstRootT>(mBufferPtr, mBufferOffsets[2]);}
69  DstTreeT* getTree() const {return PtrAdd<DstTreeT>(mBufferPtr, mBufferOffsets[1]);}
70  DstGridT* getGrid() const {return PtrAdd<DstGridT>(mBufferPtr, mBufferOffsets[0]);}
71 
72  // Count the number of values (possibly only active)
73  void countValues();
74 
75  // Below are private methods use to serialize nodes into NanoVDB
76  template<typename BufferT>
77  GridHandle<BufferT> initHandle(uint32_t channels, const BufferT& buffer);
78 
79  void processLeafs();
80 
81  void processLower();
82 
83  void processUpper();
84 
85  void processRoot();
86 
87  void processTree();
88 
89  void processGrid(const std::string& name, uint32_t channels);
90 
91  void processChannels(uint32_t channels);
92 
93 public:
94 
95  /// @brief Constructor based on a source grid
96  ///
97  /// @param srcGrid Source grid used to generate the IndexGrid
98  /// @param includeInactive Include inactive values or only active values
99  /// @param includeStats Include min/max/avg/std per node or not
100  ///
101  /// @note For minimum memory consumption set the two boolean options to false
102  IndexGridBuilder(const SrcGridT& srcGrid, bool includeInactive = true, bool includeStats = true)
103  : mSrcMgrHandle(createNodeManager(srcGrid))
104  , mSrcMgr(mSrcMgrHandle.template mgr<SrcValueT>())
105  , mValueCount(0)
106  , mIsSparse(!includeInactive)
107  , mIncludeStats(includeStats)
108  {}
109 
110  /// @brief Return an instance of a GridHandle (invoking move semantics)
111  template<typename BufferT = HostBuffer>
112  GridHandle<BufferT> getHandle(const std::string& name = "", uint32_t channels = 0u, const BufferT& buffer = BufferT());
113 
114  /// @brief return the total number of values located in the source grid.
115  ///
116  /// @note This is minimum number of elements required for the external array that the IndexGrid
117  /// points to.
118  uint64_t getValueCount() const { return mValueCount; }
119 
120  /// @brief return a buffer with all the values in the source grid
121  template<typename BufferT = HostBuffer>
122  BufferT getValues(uint32_t channels = 1u, const BufferT &buffer = BufferT());
123 
124  /// @brief copy values from the source grid into the provided array and returns number of values copied
125  uint64_t copyValues(SrcValueT *buffer, size_t maxValueCount = -1);
126 }; // IndexGridBuilder
127 
128 //================================================================================================
129 
130 template<typename SrcValueT>
131 template<typename BufferT>
132 GridHandle<BufferT> IndexGridBuilder<SrcValueT>::
133 getHandle(const std::string &name, uint32_t channels, const BufferT &buffer)
134 {
135  this->countValues();
136 
137  auto handle = this->template initHandle<BufferT>(channels, buffer);// initialize the arrays of nodes
138 
139  this->processLeafs();
140 
141  this->processLower();
142 
143  this->processUpper();
144 
145  this->processRoot();
146 
147  this->processTree();
148 
149  this->processGrid(name, channels);
150 
151  this->processChannels(channels);
152 
153  return handle;
154 } // IndexGridBuilder::getHandle
155 
156 //================================================================================================
157 
158 template<typename SrcValueT>
160 {
161  const uint64_t stats = mIncludeStats ? 4u : 0u;
162 
163  uint64_t valueCount = 1u + stats;//background, [minimum, maximum, average, and deviation]
164 
165  // root values
166  if (mIsSparse) {
167  for (auto it = mSrcMgr->root().beginValueOn(); it; ++it) ++valueCount;
168  } else {
169  for (auto it = mSrcMgr->root().beginValue(); it; ++it) ++valueCount;
170  }
171 
172  // tile values in upper internal nodes
173  mValIdx2.resize(mSrcMgr->nodeCount(2) + 1);
174  if (mIsSparse) {
175  forEach(1, mValIdx2.size(), 8, [&](const Range1D& r){
176  for (auto i = r.begin(); i!=r.end(); ++i) {
177  mValIdx2[i] = stats + mSrcMgr->upper(i-1).data()->mValueMask.countOn();
178  }
179  });
180  } else {
181  forEach(1, mValIdx2.size(), 8, [&](const Range1D& r){
182  const uint64_t n = 32768u + stats;
183  for (auto i = r.begin(); i!=r.end(); ++i) {
184  mValIdx2[i] = n - mSrcMgr->upper(i-1).data()->mChildMask.countOn();
185  }
186  });
187  }
188  mValIdx2[0] = valueCount;
189  for (size_t i=1; i<mValIdx2.size(); ++i) mValIdx2[i] += mValIdx2[i-1];// pre-fixed sum
190  valueCount = mValIdx2.back();
191 
192  // tile values in lower internal nodes
193  mValIdx1.resize(mSrcMgr->nodeCount(1) + 1);
194  if (mIsSparse) {
195  forEach(1, mValIdx1.size(), 8, [&](const Range1D& r){
196  for (auto i = r.begin(); i!=r.end(); ++i) {
197  mValIdx1[i] = stats + mSrcMgr->lower(i-1).data()->mValueMask.countOn();
198  }
199  });
200  } else {
201  forEach(1, mValIdx1.size(), 8, [&](const Range1D& r){
202  const uint64_t n = 4096u + stats;
203  for (auto i = r.begin(); i!=r.end(); ++i) {
204  mValIdx1[i] = n - mSrcMgr->lower(i-1).data()->mChildMask.countOn();
205  }
206  });
207  }
208  mValIdx1[0] = valueCount;
209  for (size_t i=1; i<mValIdx1.size(); ++i) mValIdx1[i] += mValIdx1[i-1];// pre-fixed sum
210  valueCount = mValIdx1.back();
211 
212  // voxel values in leaf nodes
213  mValIdx0.clear();
214  mValIdx0.resize(mSrcMgr->nodeCount(0) + 1, 512u + stats);
215  if (mIsSparse) {
216  forEach(1, mValIdx0.size(), 8, [&](const Range1D& r) {
217  for (auto i = r.begin(); i != r.end(); ++i) {
218  mValIdx0[i] = stats + mSrcMgr->leaf(i-1).data()->mValueMask.countOn();
219  }
220  });
221  }
222  mValIdx0[0] = valueCount;
223  for (size_t i=1; i<mValIdx0.size(); ++i) mValIdx0[i] += mValIdx0[i-1];// pre-fixed sum
224 
225  mValueCount = mValIdx0.back();
226 }// countValues
227 
228 
229 //================================================================================================
230 template<typename SrcValueT>
231 uint64_t IndexGridBuilder<SrcValueT>::copyValues(SrcValueT *buffer, size_t maxValueCount)
232 {
233  assert(mBufferPtr);
234  if (maxValueCount < mValueCount) return 0;
235 
236  // Value array always starts with these entries
237  buffer[0] = mSrcMgr->root().background();
238  if (mIncludeStats) {
239  buffer[1] = mSrcMgr->root().minimum();
240  buffer[2] = mSrcMgr->root().maximum();
241  buffer[3] = mSrcMgr->root().average();
242  buffer[4] = mSrcMgr->root().stdDeviation();
243  }
244  {// copy root tile values
245  auto *srcData = mSrcMgr->root().data();
246  SrcValueT *v = buffer + (mIncludeStats ? 5u : 1u);
247  for (uint32_t tileID = 0; tileID < srcData->mTableSize; ++tileID) {
248  auto *srcTile = srcData->tile(tileID);
249  if (srcTile->isChild() ||(mIsSparse&&!srcTile->state)) continue;
250  NANOVDB_ASSERT(v - buffer < mValueCount);
251  *v++ = srcTile->value;
252  }
253  }
254 
255  {// upper nodes
256  auto kernel = [&](const Range1D& r) {
257  DstData2 *dstData = this->getUpper(r.begin())->data();
258  for (auto i = r.begin(); i != r.end(); ++i, ++dstData) {
259  SrcValueT *v = buffer + mValIdx2[i];
260  const SrcNode2 &srcNode = mSrcMgr->upper(i);
261  if (mIncludeStats) {
262  *v++ = srcNode.minimum();
263  *v++ = srcNode.maximum();
264  *v++ = srcNode.average();
265  *v++ = srcNode.stdDeviation();
266  }
267  if (mIsSparse) {
268  for (auto it = srcNode.beginValueOn(); it; ++it) {
269  NANOVDB_ASSERT(v - buffer < mValueCount);
270  *v++ = *it;
271  }
272  } else {
273  auto *srcData = srcNode.data();
274  for (uint32_t j = 0; j != 32768; ++j) {
275  if (srcData->mChildMask.isOn(j)) continue;
276  NANOVDB_ASSERT(v - buffer < mValueCount);
277  *v++ = srcData->getValue(j);
278  }
279  }
280  }
281  };
282  forEach(0, mSrcMgr->nodeCount(2), 1, kernel);
283  }
284 
285  {// lower nodes
286  auto kernel = [&](const Range1D& r) {
287  DstData1 *dstData = this->getLower(r.begin())->data();
288  for (auto i = r.begin(); i != r.end(); ++i, ++dstData) {
289  SrcValueT *v = buffer + mValIdx1[i];
290  const SrcNode1 &srcNode = mSrcMgr->lower(i);
291  if (mIncludeStats) {
292  *v++ = srcNode.minimum();
293  *v++ = srcNode.maximum();
294  *v++ = srcNode.average();
295  *v++ = srcNode.stdDeviation();
296  }
297  if (mIsSparse) {
298  for (auto it = srcNode.beginValueOn(); it; ++it) {
299  NANOVDB_ASSERT(v - buffer < mValueCount);
300  *v++ = *it;
301  }
302  } else {
303  auto *srcData = srcNode.data();
304  for (uint32_t j = 0; j != 4096; ++j) {
305  if (srcData->mChildMask.isOn(j)) continue;
306  NANOVDB_ASSERT(v - buffer < mValueCount);
307  *v++ = srcData->getValue(j);
308  }
309  }
310  }
311  };
312  forEach(0, mSrcMgr->nodeCount(1), 4, kernel);
313  }
314  {// leaf nodes
315  auto kernel = [&](const Range1D& r) {
316  DstData0 *dstLeaf = this->getLeaf(r.begin())->data();
317  for (auto i = r.begin(); i != r.end(); ++i, ++dstLeaf) {
318  SrcValueT *v = buffer + mValIdx0[i];// bug!?
319  const SrcNode0 &srcLeaf = mSrcMgr->leaf(i);
320  if (mIncludeStats) {
321  *v++ = srcLeaf.minimum();
322  *v++ = srcLeaf.maximum();
323  *v++ = srcLeaf.average();
324  *v++ = srcLeaf.stdDeviation();
325  }
326  if (mIsSparse) {
327  for (auto it = srcLeaf.beginValueOn(); it; ++it) {
328  NANOVDB_ASSERT(v - buffer < mValueCount);
329  *v++ = *it;
330  }
331  } else {
332  const SrcData0 *srcData = srcLeaf.data();
333  for (uint32_t j = 0; j != 512; ++j) {
334  NANOVDB_ASSERT(v - buffer < mValueCount);
335  *v++ = srcData->getValue(j);
336  }
337  }
338  }
339  };
340  forEach(0, mSrcMgr->nodeCount(0), 8, kernel);
341  }
342  return mValueCount;
343 } // IndexGridBuilder::copyValues
344 
345 template<typename SrcValueT>
346 template<typename BufferT>
347 BufferT IndexGridBuilder<SrcValueT>::getValues(uint32_t channels, const BufferT &buffer)
348 {
349  assert(channels > 0);
350  auto values = BufferT::create(channels*sizeof(SrcValueT)*mValueCount, &buffer);
351  SrcValueT *p = reinterpret_cast<SrcValueT*>(values.data());
352  if (!this->copyValues(p, mValueCount)) {
353  throw std::runtime_error("getValues: insufficient channels");
354  }
355  for (uint32_t i=1; i<channels; ++i) {
356  nanovdb::forEach(0,mValueCount,1024,[&](const nanovdb::Range1D &r){
357  SrcValueT *dst=p+i*mValueCount+r.begin(), *end=dst+r.size(), *src=dst-mValueCount;
358  while(dst!=end) *dst++ = *src++;
359  });
360  }
361  return values;
362 } // IndexGridBuilder::getValues
363 
364 //================================================================================================
365 
366 template<typename SrcValueT>
367 template<typename BufferT>
369 initHandle(uint32_t channels, const BufferT& buffer)
370 {
371  const SrcTreeT &srcTree = mSrcMgr->tree();
372  mBufferOffsets[0] = 0;// grid is always stored at the start of the buffer!
373  mBufferOffsets[1] = DstGridT::memUsage(); // tree
374  mBufferOffsets[2] = mBufferOffsets[1] + DstTreeT::memUsage(); // root
375  mBufferOffsets[3] = mBufferOffsets[2] + DstRootT::memUsage(srcTree.root().tileCount());// upper internal nodes
376  mBufferOffsets[4] = mBufferOffsets[3] + srcTree.nodeCount(2)*sizeof(DstData2); // lower internal nodes
377  mBufferOffsets[5] = mBufferOffsets[4] + srcTree.nodeCount(1)*sizeof(DstData1); // leaf nodes
378  mBufferOffsets[6] = mBufferOffsets[5] + srcTree.nodeCount(0)*sizeof(DstData0); // meta data
379  mBufferOffsets[7] = mBufferOffsets[6] + GridBlindMetaData::memUsage(channels); // channel values
380  mBufferOffsets[8] = mBufferOffsets[7] + channels*mValueCount*sizeof(SrcValueT);// total size
381 #if 0
382  std::cerr << "grid starts at " << mBufferOffsets[0] <<" byte" << std::endl;
383  std::cerr << "tree starts at " << mBufferOffsets[1] <<" byte" << std::endl;
384  std::cerr << "root starts at " << mBufferOffsets[2] <<" byte" << std::endl;
385  std::cerr << "node starts at " << mBufferOffsets[3] <<" byte" << " #" << srcTree.nodeCount(2) << std::endl;
386  std::cerr << "node starts at " << mBufferOffsets[4] <<" byte" << " #" << srcTree.nodeCount(1) << std::endl;
387  std::cerr << "leaf starts at " << mBufferOffsets[5] <<" byte" << " #" << srcTree.nodeCount(0) << std::endl;
388  std::cerr << "meta starts at " << mBufferOffsets[6] <<" byte" << std::endl;
389  std::cerr << "data starts at " << mBufferOffsets[7] <<" byte" << std::endl;
390  std::cerr << "buffer ends at " << mBufferOffsets[8] <<" byte" << std::endl;
391  std::cerr << "creating buffer of size " << (mBufferOffsets[8]>>20) << "MB" << std::endl;
392 #endif
393  GridHandle<BufferT> handle(BufferT::create(mBufferOffsets[8], &buffer));
394  mBufferPtr = handle.data();
395 
396  return handle;
397 } // IndexGridBuilder::initHandle
398 
399 //================================================================================================
400 
401 template<typename SrcValueT>
402 void IndexGridBuilder<SrcValueT>::processGrid(const std::string& name, uint32_t channels)
403 {
404  auto *srcData = mSrcMgr->grid().data();
405  auto *dstData = this->getGrid()->data();
406 
407  dstData->mMagic = NANOVDB_MAGIC_NUMBER;
408  dstData->mChecksum = 0u;
409  dstData->mVersion = Version();
410  dstData->mFlags = static_cast<uint32_t>(GridFlags::IsBreadthFirst);
411  dstData->mGridIndex = 0;
412  dstData->mGridCount = 1;
413  dstData->mGridSize = mBufferOffsets[8];
414  std::memset(dstData->mGridName, '\0', GridData::MaxNameSize);//overwrite mGridName
415  strncpy(dstData->mGridName, name.c_str(), GridData::MaxNameSize-1);
416  dstData->mMap = srcData->mMap;
417  dstData->mWorldBBox = srcData->mWorldBBox;
418  dstData->mVoxelSize = srcData->mVoxelSize;
419  dstData->mGridClass = GridClass::IndexGrid;
420  dstData->mGridType = mapToGridType<ValueIndex>();
421  dstData->mBlindMetadataOffset = mBufferOffsets[6];
422  dstData->mBlindMetadataCount = channels;
423  dstData->mData0 = 0u;
424  dstData->mData1 = mValueCount;// encode the total number of values being indexed
425  dstData->mData2 = 0u;
426 
427  if (name.length() >= GridData::MaxNameSize) {// currently we don't support long grid names
428  std::stringstream ss;
429  ss << "Grid name \"" << name << "\" is more then " << GridData::MaxNameSize << " characters";
430  throw std::runtime_error(ss.str());
431  }
432 } // IndexGridBuilder::processGrid
433 
434 //================================================================================================
435 
436 template<typename SrcValueT>
437 void IndexGridBuilder<SrcValueT>::processTree()
438 {
439  auto *srcData = mSrcMgr->tree().data();
440  auto *dstData = this->getTree()->data();
441  for (int i=0; i<4; ++i) dstData->mNodeOffset[i] = mBufferOffsets[5-i] - mBufferOffsets[1];// byte offset from tree to first leaf, lower, upper and root node
442  for (int i=0; i<3; ++i) {
443  dstData->mNodeCount[i] = srcData->mNodeCount[i];// total number of nodes of type: leaf, lower internal, upper internal
444  dstData->mTileCount[i] = srcData->mTileCount[i];// total number of active tile values at the lower internal, upper internal and root node levels
445  }
446  dstData->mVoxelCount = srcData->mVoxelCount;// total number of active voxels in the root and all its child nodes
447 } // IndexGridBuilder::processTree
448 
449 //================================================================================================
450 
451 template<typename SrcValueT>
452 void IndexGridBuilder<SrcValueT>::processRoot()
453 {
454  auto *srcData = mSrcMgr->root().data();
455  auto *dstData = this->getRoot()->data();
456 
457  if (dstData->padding()>0) std::memset(dstData, 0, DstRootT::memUsage(mSrcMgr->root().tileCount()));
458  dstData->mBBox = srcData->mBBox;
459  dstData->mTableSize = srcData->mTableSize;
460  dstData->mBackground = 0u;
461  uint64_t valueCount = 1u;// the first entry is always the background value
462  if (mIncludeStats) {
463  valueCount += 4u;
464  dstData->mMinimum = 1u;
465  dstData->mMaximum = 2u;
466  dstData->mAverage = 3u;
467  dstData->mStdDevi = 4u;
468  } else if (dstData->padding()==0) {
469  dstData->mMinimum = 0u;
470  dstData->mMaximum = 0u;
471  dstData->mAverage = 0u;
472  dstData->mStdDevi = 0u;
473  }
474  //uint64_t valueCount = 5u;// this is always the first available index
475  for (uint32_t tileID = 0, childID = 0; tileID < dstData->mTableSize; ++tileID) {
476  auto *srcTile = srcData->tile(tileID);
477  auto *dstTile = dstData->tile(tileID);
478  dstTile->key = srcTile->key;
479  if (srcTile->isChild()) {
480  dstTile->child = childID * sizeof(DstNode2) + mBufferOffsets[3] - mBufferOffsets[2];
481  dstTile->state = false;
482  dstTile->value = std::numeric_limits<uint64_t>::max();
483  ++childID;
484  } else {
485  dstTile->child = 0;
486  dstTile->state = srcTile->state;
487  if (!(mIsSparse && !dstTile->state)) dstTile->value = valueCount++;
488  }
489  }
490 } // IndexGridBuilder::processRoot
491 
492 //================================================================================================
493 
494 template<typename SrcValueT>
495 void IndexGridBuilder<SrcValueT>::processUpper()
496 {
497  static_assert(DstData2::padding()==0u, "Expected upper internal nodes to have no padding");
498  auto kernel = [&](const Range1D& r) {
499  const bool activeOnly = mIsSparse;
500  const bool hasStats = mIncludeStats;
501  auto *dstData1 = this->getLower()->data();// fixed size
502  auto *dstData2 = this->getUpper(r.begin())->data();// fixed size
503  for (auto i = r.begin(); i != r.end(); ++i, ++dstData2) {
504  SrcData2 *srcData2 = mSrcMgr->upper(i).data();// might vary in size due to compression
505  dstData2->mBBox = srcData2->mBBox;
506  dstData2->mFlags = srcData2->mFlags;
507  srcData2->mFlags = i;// encode node ID
508  dstData2->mChildMask = srcData2->mChildMask;
509  dstData2->mValueMask = srcData2->mValueMask;
510  uint64_t n = mValIdx2[i];
511  if (mIncludeStats) {
512  dstData2->mMinimum = n++;
513  dstData2->mMaximum = n++;
514  dstData2->mAverage = n++;
515  dstData2->mStdDevi = n++;
516  } else {
517  dstData2->mMinimum = 0u;
518  dstData2->mMaximum = 0u;
519  dstData2->mAverage = 0u;
520  dstData2->mStdDevi = 0u;
521  }
522  for (uint32_t j = 0; j != 32768; ++j) {
523  if (dstData2->isChild(j)) {
524  SrcData1 *srcChild = srcData2->getChild(j)->data();
525  DstData1 *dstChild = dstData1 + srcChild->mFlags;
526  dstData2->setChild(j, dstChild);
527  srcChild->mFlags = dstChild->mFlags;// restore
528  } else {
529  const bool test = activeOnly && !srcData2->mValueMask.isOn(j);
530  dstData2->setValue(j, test ? 0 : n++);
531  }
532  }
533 
534  }
535  };
536  forEach(0, mSrcMgr->nodeCount(2), 1, kernel);
537 } // IndexGridBuilder::processUpper
538 
539 //================================================================================================
540 
541 template<typename SrcValueT>
542 void IndexGridBuilder<SrcValueT>::processLower()
543 {
544  static_assert(DstData1::padding()==0u, "Expected lower internal nodes to have no padding");
545  auto kernel = [&](const Range1D& r) {
546  const bool activeOnly = mIsSparse;
547  DstData0 *dstData0 = this->getLeaf()->data();// first dst leaf node
548  DstData1 *dstData1 = this->getLower(r.begin())->data();// fixed size
549  for (auto i = r.begin(); i != r.end(); ++i, ++dstData1) {
550  SrcData1 *srcData1 = mSrcMgr->lower(i).data();// might vary in size due to compression
551  dstData1->mBBox = srcData1->mBBox;
552  dstData1->mFlags = srcData1->mFlags;
553  srcData1->mFlags = i;// encode node ID
554  dstData1->mChildMask = srcData1->mChildMask;
555  dstData1->mValueMask = srcData1->mValueMask;
556  uint64_t n = mValIdx1[i];
557  if (mIncludeStats) {
558  dstData1->mMinimum = n++;
559  dstData1->mMaximum = n++;
560  dstData1->mAverage = n++;
561  dstData1->mStdDevi = n++;
562  } else {
563  dstData1->mMinimum = 0u;
564  dstData1->mMaximum = 0u;
565  dstData1->mAverage = 0u;
566  dstData1->mStdDevi = 0u;
567  }
568  for (uint32_t j = 0; j != 4096; ++j) {
569  if (dstData1->isChild(j)) {
570  SrcData0 *srcChild = srcData1->getChild(j)->data();
571  DstData0 *dstChild = dstData0 + srcChild->mBBoxMin[0];
572  dstData1->setChild(j, dstChild);
573  srcChild->mBBoxMin[0] = dstChild->mBBoxMin[0];// restore
574  } else {
575  const bool test = activeOnly && !srcData1->mValueMask.isOn(j);
576  dstData1->setValue(j, test ? 0 : n++);
577  }
578  }
579  }
580  };
581  forEach(0, mSrcMgr->nodeCount(1), 4, kernel);
582 } // IndexGridBuilder::processLower
583 
584 //================================================================================================
585 
586 template<typename SrcValueT>
587 void IndexGridBuilder<SrcValueT>::processLeafs()
588 {
589  static_assert(DstData0::padding()==0u, "Expected leaf nodes to have no padding");
590 
591  auto kernel = [&](const Range1D& r) {
592  DstData0 *dstData0 = this->getLeaf(r.begin())->data();// fixed size
593  const uint8_t flags = mIsSparse ? 16u : 0u;// 4th bit indicates sparseness
594  for (auto i = r.begin(); i != r.end(); ++i, ++dstData0) {
595  SrcData0 *srcData0 = mSrcMgr->leaf(i).data();// might vary in size due to compression
596  dstData0->mBBoxMin = srcData0->mBBoxMin;
597  srcData0->mBBoxMin[0] = int(i);// encode node ID
598  dstData0->mBBoxDif[0] = srcData0->mBBoxDif[0];
599  dstData0->mBBoxDif[1] = srcData0->mBBoxDif[1];
600  dstData0->mBBoxDif[2] = srcData0->mBBoxDif[2];
601  dstData0->mFlags = flags | (srcData0->mFlags & 2u);// 2nd bit indicates a bbox
602  dstData0->mValueMask = srcData0->mValueMask;
603 
604  if (mIncludeStats) {
605  dstData0->mStatsOff = mValIdx0[i];// first 4 entries are leaf stats
606  dstData0->mValueOff = mValIdx0[i] + 4u;
607  } else {
608  dstData0->mStatsOff = 0u;// set to background which indicates no stats!
609  dstData0->mValueOff = mValIdx0[i];
610  }
611  }
612  };
613  forEach(0, mSrcMgr->nodeCount(0), 8, kernel);
614 } // IndexGridBuilder::processLeafs
615 
616 //================================================================================================
617 
618 template<typename SrcValueT>
619 void IndexGridBuilder<SrcValueT>::processChannels(uint32_t channels)
620 {
621  for (uint32_t i=0; i<channels; ++i) {
622  auto *metaData = PtrAdd<GridBlindMetaData>(mBufferPtr, mBufferOffsets[6]) + i;
623  auto *blindData = PtrAdd<SrcValueT>(mBufferPtr, mBufferOffsets[7]) + i*mValueCount;
624  metaData->setBlindData(blindData);
625  metaData->mElementCount = mValueCount;
626  metaData->mFlags = 0;
627  metaData->mSemantic = GridBlindDataSemantic::Unknown;
628  metaData->mDataClass = GridBlindDataClass::ChannelArray;
629  metaData->mDataType = mapToGridType<SrcValueT>();
630  std::memset(metaData->mName, '\0', GridBlindMetaData::MaxNameSize);
631  std::stringstream ss;
632  ss << toStr(metaData->mDataType) << "_channel_" << i;
633  strncpy(metaData->mName, ss.str().c_str(), GridBlindMetaData::MaxNameSize-1);
634  if (i) {// deep copy from previous channel
635 #if 0
636  this->copyValues(blindData, mValueCount);
637  //std::memcpy(blindData, blindData-mValueCount, mValueCount*sizeof(SrcValueT));
638 #else
639  nanovdb::forEach(0,mValueCount,1024,[&](const nanovdb::Range1D &r){
640  SrcValueT *dst=blindData+r.begin(), *end=dst+r.size(), *src=dst-mValueCount;
641  while(dst!=end) *dst++ = *src++;
642  });
643 #endif
644  } else {
645  this->copyValues(blindData, mValueCount);
646  }
647  }
648 }
649 
650 } // namespace nanovdb
651 
652 #endif // NANOVDB_INDEXGRIDBUILDER_H_HAS_BEEN_INCLUDED
NodeManagerHandle manages the memory of a NodeManager.
Definition: NodeManager.h:31
InternalData< ChildT, Log2Dim > DataType
Definition: NanoVDB.h:3523
VDB Tree, which is a thin wrapper around a RootNode.
Definition: NanoVDB.h:2798
Highest level of the data structure. Contains a tree and a world->index transform (that currently onl...
Definition: NanoVDB.h:2555
A unified wrapper for tbb::parallel_for and a naive std::thread fallback.
Defines two classes, a GridRegister the defines the value type (e.g. Double, Float etc) of a NanoVDB ...
uint64_t mMagic
Definition: NanoVDB.h:2434
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:3620
GridHandle< BufferT > getHandle(const std::string &name="", uint32_t channels=0u, const BufferT &buffer=BufferT())
Return an instance of a GridHandle (invoking move semantics)
Definition: IndexGridBuilder.h:133
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:110
static const int MaxNameSize
Definition: NanoVDB.h:2316
LeafData< BuildT, CoordT, MaskT, Log2Dim > DataType
Definition: NanoVDB.h:4261
const FloatType & stdDeviation() const
Return a const reference to the standard deviation of all the active values encoded in this internal ...
Definition: NanoVDB.h:3629
void forEach(RangeT range, const FuncT &func)
simple wrapper for tbb::parallel_for with a naive std fallback
Definition: ForEach.h:40
Index64 memUsage(const TreeT &tree, bool threaded=true)
Return the total amount of memory in bytes occupied by this tree.
Definition: Count.h:493
FloatType stdDeviation() const
Return a const reference to the standard deviation of all the active values encoded in this leaf node...
Definition: NanoVDB.h:4354
ValueOnIterator beginValueOn() const
Definition: NanoVDB.h:3589
Allows for the construction of NanoVDB grids without any dependency.
Definition: IndexGridBuilder.h:35
DataType * data()
Definition: NanoVDB.h:3597
This class serves to manage a raw memory buffer of a NanoVDB Grid.
Definition: GridHandle.h:70
const Node0 & leaf(uint32_t i) const
Return the i&#39;th leaf node with respect to breadth-first ordering.
Definition: NodeManager.h:275
Definition: NanoVDB.h:208
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:3623
Top-most node of the VDB tree structure.
Definition: NanoVDB.h:3073
Custom Range class that is compatible with the tbb::blocked_range classes.
DataType * data()
Definition: NanoVDB.h:4334
const Node1 & lower(uint32_t i) const
Return the i&#39;th lower internal node with respect to breadth-first ordering.
Definition: NodeManager.h:279
const Node2 & upper(uint32_t i) const
Return the i&#39;th upper internal node with respect to breadth-first ordering.
Definition: NodeManager.h:283
#define NANOVDB_MAGIC_NUMBER
Definition: NanoVDB.h:121
Definition: Range.h:28
Range< 1, size_t > Range1D
Definition: Range.h:30
ValueType maximum() const
Return a const reference to the maximum active value encoded in this leaf node.
Definition: NanoVDB.h:4345
IndexGridBuilder(const SrcGridT &srcGrid, bool includeInactive=true, bool includeStats=true)
Constructor based on a source grid.
Definition: IndexGridBuilder.h:102
DataType * data()
Definition: NanoVDB.h:2575
uint64_t nodeCount(int level) const
Return the number of tree nodes at the specified level.
Definition: NodeManager.h:244
const char * toStr(GridType gridType)
Retuns a c-string used to describe a GridType.
Definition: NanoVDB.h:267
#define NANOVDB_ASSERT(x)
Definition: NanoVDB.h:173
ValueOnIterator beginValueOn() const
Definition: NanoVDB.h:4285
BufferT getValues(uint32_t channels=1u, const BufferT &buffer=BufferT())
return a buffer with all the values in the source grid
Definition: IndexGridBuilder.h:347
FloatType average() const
Return a const reference to the average of all the active values encoded in this leaf node...
Definition: NanoVDB.h:4348
Internal nodes of a VDB treedim(),.
Definition: NanoVDB.h:3520
TreeT & tree()
Return a reference to the tree.
Definition: NodeManager.h:235
static const int MaxNameSize
Definition: NanoVDB.h:2433
NodeManagerHandle< BufferT > createNodeManager(const NanoGrid< BuildT > &grid, const BufferT &buffer=BufferT())
brief Construct a NodeManager and return its handle
Definition: NodeManager.h:289
uint64_t getValueCount() const
return the total number of values located in the source grid.
Definition: IndexGridBuilder.h:118
RootT & root()
Return a reference to the root.
Definition: NodeManager.h:239
ValueType minimum() const
Return a const reference to the minimum active value encoded in this leaf node.
Definition: NanoVDB.h:4342
Leaf nodes of the VDB tree. (defaults to 8x8x8 = 512 voxels)
Definition: NanoVDB.h:4251
uint64_t copyValues(SrcValueT *buffer, size_t maxValueCount=-1)
copy values from the source grid into the provided array and returns number of values copied ...
Definition: IndexGridBuilder.h:231
GridT & grid()
Return a reference to the grid.
Definition: NodeManager.h:231
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:2326
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:3617