HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PointDataGrid.h
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2012-2018 DreamWorks Animation LLC
4 //
5 // All rights reserved. This software is distributed under the
6 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
7 //
8 // Redistributions of source code must retain the above copyright
9 // and license notice and the following restrictions and disclaimer.
10 //
11 // * Neither the name of DreamWorks Animation nor the names of
12 // its contributors may be used to endorse or promote products derived
13 // from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
27 // LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
28 //
29 ///////////////////////////////////////////////////////////////////////////
30 
31 /// @author Dan Bailey
32 ///
33 /// @file points/PointDataGrid.h
34 ///
35 /// @brief Attribute-owned data structure for points. Point attributes are
36 /// stored in leaf nodes and ordered by voxel for fast random and
37 /// sequential access.
38 
39 #ifndef OPENVDB_POINTS_POINT_DATA_GRID_HAS_BEEN_INCLUDED
40 #define OPENVDB_POINTS_POINT_DATA_GRID_HAS_BEEN_INCLUDED
41 
42 #include <openvdb/version.h>
43 #include <openvdb/Grid.h>
44 #include <openvdb/tree/Tree.h>
45 #include <openvdb/tree/LeafNode.h>
47 #include "AttributeArray.h"
48 #include "AttributeArrayString.h"
49 #include "AttributeGroup.h"
50 #include "AttributeSet.h"
51 #include "StreamCompression.h"
52 #include <cstring> // std::memcpy
53 #include <iostream>
54 #include <limits>
55 #include <memory>
56 #include <type_traits> // std::is_same
57 #include <utility> // std::pair, std::make_pair
58 #include <vector>
59 
60 #include <hboost/mpl/vector.hpp>//for hboost::mpl::vector
61 #include <hboost/mpl/push_back.hpp>
62 #include <hboost/mpl/back.hpp>
63 
64 class TestPointDataLeaf;
65 
66 namespace openvdb {
68 namespace OPENVDB_VERSION_NAME {
69 
70 namespace io
71 {
72 
73 /// @brief openvdb::io::readCompressedValues specialized on PointDataIndex32 arrays to
74 /// ignore the value mask, use a larger block size and use 16-bit size instead of 64-bit
75 template<>
76 inline void
77 readCompressedValues( std::istream& is, PointDataIndex32* destBuf, Index destCount,
78  const util::NodeMask<3>& /*valueMask*/, bool /*fromHalf*/)
79 {
81 
82  const bool seek = destBuf == nullptr;
83 
84  const size_t destBytes = destCount*sizeof(PointDataIndex32);
85  const size_t maximumBytes = std::numeric_limits<uint16_t>::max();
86  if (destBytes >= maximumBytes) {
87  OPENVDB_THROW(openvdb::IoError, "Cannot read more than " <<
88  maximumBytes << " bytes in voxel values.")
89  }
90 
91  uint16_t bytes16;
92 
94 
95  if (seek && meta) {
96  // buffer size temporarily stored in the StreamMetadata pass
97  // to avoid having to perform an expensive disk read for 2-bytes
98  bytes16 = static_cast<uint16_t>(meta->pass());
99  // seek over size of the compressed buffer
100  is.seekg(sizeof(uint16_t), std::ios_base::cur);
101  }
102  else {
103  // otherwise read from disk
104  is.read(reinterpret_cast<char*>(&bytes16), sizeof(uint16_t));
105  }
106 
107  if (bytes16 == std::numeric_limits<uint16_t>::max()) {
108  // read or seek uncompressed data
109  if (seek) {
110  is.seekg(destBytes, std::ios_base::cur);
111  }
112  else {
113  is.read(reinterpret_cast<char*>(destBuf), destBytes);
114  }
115  }
116  else {
117  // read or seek uncompressed data
118  if (seek) {
119  is.seekg(int(bytes16), std::ios_base::cur);
120  }
121  else {
122  // decompress into the destination buffer
123  std::unique_ptr<char[]> bloscBuffer(new char[int(bytes16)]);
124  is.read(bloscBuffer.get(), bytes16);
125  std::unique_ptr<char[]> buffer = bloscDecompress( bloscBuffer.get(),
126  destBytes,
127  /*resize=*/false);
128  std::memcpy(destBuf, buffer.get(), destBytes);
129  }
130  }
131 }
132 
133 /// @brief openvdb::io::writeCompressedValues specialized on PointDataIndex32 arrays to
134 /// ignore the value mask, use a larger block size and use 16-bit size instead of 64-bit
135 template<>
136 inline void
137 writeCompressedValues( std::ostream& os, PointDataIndex32* srcBuf, Index srcCount,
138  const util::NodeMask<3>& /*valueMask*/,
139  const util::NodeMask<3>& /*childMask*/, bool /*toHalf*/)
140 {
142 
143  const size_t srcBytes = srcCount*sizeof(PointDataIndex32);
144  const size_t maximumBytes = std::numeric_limits<uint16_t>::max();
145  if (srcBytes >= maximumBytes) {
146  OPENVDB_THROW(openvdb::IoError, "Cannot write more than " <<
147  maximumBytes << " bytes in voxel values.")
148  }
149 
150  const char* charBuffer = reinterpret_cast<const char*>(srcBuf);
151 
152  size_t compressedBytes;
153  std::unique_ptr<char[]> buffer = bloscCompress( charBuffer, srcBytes,
154  compressedBytes, /*resize=*/false);
155 
156  if (compressedBytes > 0) {
157  auto bytes16 = static_cast<uint16_t>(compressedBytes); // clamp to 16-bit unsigned integer
158  os.write(reinterpret_cast<const char*>(&bytes16), sizeof(uint16_t));
159  os.write(reinterpret_cast<const char*>(buffer.get()), compressedBytes);
160  }
161  else {
162  auto bytes16 = static_cast<uint16_t>(maximumBytes); // max value indicates uncompressed
163  os.write(reinterpret_cast<const char*>(&bytes16), sizeof(uint16_t));
164  os.write(reinterpret_cast<const char*>(srcBuf), srcBytes);
165  }
166 }
167 
168 template <typename T>
169 inline void
170 writeCompressedValuesSize(std::ostream& os, const T* srcBuf, Index srcCount)
171 {
173 
174  const size_t srcBytes = srcCount*sizeof(T);
175  const size_t maximumBytes = std::numeric_limits<uint16_t>::max();
176  if (srcBytes >= maximumBytes) {
177  OPENVDB_THROW(openvdb::IoError, "Cannot write more than " <<
178  maximumBytes << " bytes in voxel values.")
179  }
180 
181  const char* charBuffer = reinterpret_cast<const char*>(srcBuf);
182 
183  // calculate voxel buffer size after compression
184  size_t compressedBytes = bloscCompressedSize(charBuffer, srcBytes);
185 
186  if (compressedBytes > 0) {
187  auto bytes16 = static_cast<uint16_t>(compressedBytes); // clamp to 16-bit unsigned integer
188  os.write(reinterpret_cast<const char*>(&bytes16), sizeof(uint16_t));
189  }
190  else {
191  auto bytes16 = static_cast<uint16_t>(maximumBytes); // max value indicates uncompressed
192  os.write(reinterpret_cast<const char*>(&bytes16), sizeof(uint16_t));
193  }
194 }
195 
196 } // namespace io
197 
198 
199 // forward declaration
200 namespace tree {
201  template<Index, typename> struct SameLeafConfig;
202 }
203 
204 
205 ////////////////////////////////////////
206 
207 
208 namespace points {
209 
210 
211 // forward declaration
212 template<typename T, Index Log2Dim> class PointDataLeafNode;
213 
214 /// @brief Point index tree configured to match the default VDB configurations.
217 
218 
219 /// @brief Point data grid.
221 
222 
223 /// @brief Deep copy the descriptor across all leaf nodes.
224 ///
225 /// @param tree the PointDataTree.
226 ///
227 /// @return the new descriptor.
228 ///
229 /// @note This method will fail if the Descriptors in the tree are not all identical.
230 template <typename PointDataTreeT>
231 inline AttributeSet::Descriptor::Ptr
232 makeDescriptorUnique(PointDataTreeT& tree);
233 
234 
235 /// @brief Toggle the streaming mode on all attributes in the tree to collapse the attributes
236 /// after deconstructing a bound AttributeHandle to each array. This results in better
237 /// memory efficiency when the data is streamed into another data structure
238 /// (typically for rendering).
239 ///
240 /// @param tree the PointDataTree.
241 /// @param on @c true to enable streaming
242 ///
243 /// @note Multiple threads cannot safely access the same AttributeArray when using streaming.
244 template <typename PointDataTreeT>
245 inline void
246 setStreamingMode(PointDataTreeT& tree, bool on = true);
247 
248 
249 /// @brief Sequentially pre-fetch all delayed-load voxel and attribute data from disk in order
250 /// to accelerate subsequent random access.
251 ///
252 /// @param tree the PointDataTree.
253 /// @param position if enabled, prefetch the position attribute (default is on)
254 /// @param otherAttributes if enabled, prefetch all other attributes (default is on)
255 template <typename PointDataTreeT>
256 inline void
257 prefetch(PointDataTreeT& tree, bool position = true, bool otherAttributes = true);
258 
259 
260 ////////////////////////////////////////
261 
262 
263 template <typename T, Index Log2Dim>
264 class PointDataLeafNode : public tree::LeafNode<T, Log2Dim>, io::MultiPass {
265 
266 public:
268  using Ptr = std::shared_ptr<PointDataLeafNode>;
269 
270  using ValueType = T;
271  using ValueTypePair = std::pair<ValueType, ValueType>;
272  using IndexArray = std::vector<ValueType>;
273 
275 
276  ////////////////////////////////////////
277 
278  // The following methods had to be copied from the LeafNode class
279  // to make the derived PointDataLeafNode class compatible with the tree structure.
280 
283 
284  using BaseLeaf::LOG2DIM;
285  using BaseLeaf::TOTAL;
286  using BaseLeaf::DIM;
287  using BaseLeaf::NUM_VALUES;
288  using BaseLeaf::NUM_VOXELS;
289  using BaseLeaf::SIZE;
290  using BaseLeaf::LEVEL;
291 
292  /// Default constructor
294  : mAttributeSet(new AttributeSet) { }
295 
296  ~PointDataLeafNode() = default;
297 
298  /// Construct using deep copy of other PointDataLeafNode
299  explicit PointDataLeafNode(const PointDataLeafNode& other)
300  : BaseLeaf(other)
301  , mAttributeSet(new AttributeSet(*other.mAttributeSet)) { }
302 
303  /// Construct using supplied origin, value and active status
304  explicit
305  PointDataLeafNode(const Coord& coords, const T& value = zeroVal<T>(), bool active = false)
306  : BaseLeaf(coords, zeroVal<T>(), active)
307  , mAttributeSet(new AttributeSet) { assertNonModifiableUnlessZero(value); }
308 
309  /// Construct using supplied origin, value and active status
310  /// use attribute map from another PointDataLeafNode
311  PointDataLeafNode(const PointDataLeafNode& other, const Coord& coords,
312  const T& value = zeroVal<T>(), bool active = false)
313  : BaseLeaf(coords, zeroVal<T>(), active)
314  , mAttributeSet(new AttributeSet(*other.mAttributeSet))
315  {
317  }
318 
319  // Copy-construct from a PointIndexLeafNode with the same configuration but a different ValueType.
320  template<typename OtherValueType>
322  : BaseLeaf(other)
323  , mAttributeSet(new AttributeSet) { }
324 
325  // Copy-construct from a LeafNode with the same configuration but a different ValueType.
326  // Used for topology copies - explicitly sets the value (background) to zeroVal
327  template <typename ValueType>
329  : BaseLeaf(other, zeroVal<T>(), TopologyCopy())
330  , mAttributeSet(new AttributeSet) { assertNonModifiableUnlessZero(value); }
331 
332  // Copy-construct from a LeafNode with the same configuration but a different ValueType.
333  // Used for topology copies - explicitly sets the on and off value (background) to zeroVal
334  template <typename ValueType>
335  PointDataLeafNode(const tree::LeafNode<ValueType, Log2Dim>& other, const T& /*offValue*/, const T& /*onValue*/, TopologyCopy)
336  : BaseLeaf(other, zeroVal<T>(), zeroVal<T>(), TopologyCopy())
337  , mAttributeSet(new AttributeSet) { }
338 
339 #if OPENVDB_ABI_VERSION_NUMBER >= 3
340  PointDataLeafNode(PartialCreate, const Coord& coords,
341  const T& value = zeroVal<T>(), bool active = false)
342  : BaseLeaf(PartialCreate(), coords, value, active)
343  , mAttributeSet(new AttributeSet) { assertNonModifiableUnlessZero(value); }
344 #endif
345 
346 public:
347 
348  /// Retrieve the attribute set.
349  const AttributeSet& attributeSet() const { return *mAttributeSet; }
350 
351  /// @brief Create a new attribute set. Existing attributes will be removed.
352  void initializeAttributes(const Descriptor::Ptr& descriptor, const Index arrayLength);
353  /// @brief Clear the attribute set.
354  void clearAttributes(const bool updateValueMask = true);
355 
356  /// @brief Returns @c true if an attribute with this index exists.
357  /// @param pos Index of the attribute
358  bool hasAttribute(const size_t pos) const;
359  /// @brief Returns @c true if an attribute with this name exists.
360  /// @param attributeName Name of the attribute
361  bool hasAttribute(const Name& attributeName) const;
362 
363  /// @brief Append an attribute to the leaf.
364  /// @param expected Existing descriptor is expected to match this parameter.
365  /// @param replacement New descriptor to replace the existing one.
366  /// @param pos Index of the new attribute in the descriptor replacement.
367  /// @param strideOrTotalSize Stride of the attribute array (if constantStride), total size otherwise
368  /// @param constantStride if @c false, stride is interpreted as total size of the array
369  AttributeArray::Ptr appendAttribute(const Descriptor& expected, Descriptor::Ptr& replacement,
370  const size_t pos, const Index strideOrTotalSize = 1,
371  const bool constantStride = true);
372 
373  /// @brief Drop list of attributes.
374  /// @param pos vector of attribute indices to drop
375  /// @param expected Existing descriptor is expected to match this parameter.
376  /// @param replacement New descriptor to replace the existing one.
377  void dropAttributes(const std::vector<size_t>& pos,
378  const Descriptor& expected, Descriptor::Ptr& replacement);
379  /// @brief Reorder attribute set.
380  /// @param replacement New descriptor to replace the existing one.
381  void reorderAttributes(const Descriptor::Ptr& replacement);
382  /// @brief Rename attributes in attribute set (order must remain the same).
383  /// @param expected Existing descriptor is expected to match this parameter.
384  /// @param replacement New descriptor to replace the existing one.
385  void renameAttributes(const Descriptor& expected, Descriptor::Ptr& replacement);
386  /// @brief Compact all attributes in attribute set.
387  void compactAttributes();
388 
389  /// @brief Replace the underlying attribute set with the given @a attributeSet.
390  /// @details This leaf will assume ownership of the given attribute set. The descriptors must
391  /// match and the voxel offsets values will need updating if the point order is different.
392  /// @throws ValueError if @a allowMismatchingDescriptors is @c false and the descriptors
393  /// do not match
394  void replaceAttributeSet(AttributeSet* attributeSet, bool allowMismatchingDescriptors = false);
395 
396  /// @brief Replace the descriptor with a new one
397  /// The new Descriptor must exactly match the old one
398  void resetDescriptor(const Descriptor::Ptr& replacement);
399 
400  /// @brief Sets all of the voxel offset values on this leaf, from the given vector
401  /// of @a offsets. If @a updateValueMask is true, then the active value mask will
402  /// be updated so voxels with points are active and empty voxels are inactive.
403  void setOffsets(const std::vector<ValueType>& offsets, const bool updateValueMask = true);
404 
405  /// @brief Throws an error if the voxel values on this leaf are not monotonically
406  /// increasing or within the bounds of the attribute arrays
407  void validateOffsets() const;
408 
409  /// @brief Read-write attribute array reference from index
410  /// {
411  AttributeArray& attributeArray(const size_t pos);
412  const AttributeArray& attributeArray(const size_t pos) const;
413  const AttributeArray& constAttributeArray(const size_t pos) const;
414  /// }
415  /// @brief Read-write attribute array reference from name
416  /// {
417  AttributeArray& attributeArray(const Name& attributeName);
418  const AttributeArray& attributeArray(const Name& attributeName) const;
419  const AttributeArray& constAttributeArray(const Name& attributeName) const;
420  /// }
421 
422  /// @brief Read-only group handle from group index
423  GroupHandle groupHandle(const AttributeSet::Descriptor::GroupIndex& index) const;
424  /// @brief Read-only group handle from group name
425  GroupHandle groupHandle(const Name& group) const;
426  /// @brief Read-write group handle from group index
427  GroupWriteHandle groupWriteHandle(const AttributeSet::Descriptor::GroupIndex& index);
428  /// @brief Read-write group handle from group name
430 
431  /// @brief Compute the total point count for the leaf
432  Index64 pointCount() const;
433  /// @brief Compute the total active (on) point count for the leaf
434  Index64 onPointCount() const;
435  /// @brief Compute the total inactive (off) point count for the leaf
436  Index64 offPointCount() const;
437  /// @brief Compute the point count in a specific group for the leaf
438  Index64 groupPointCount(const Name& groupName) const;
439 
440  /// @brief Activate voxels with non-zero points, deactivate voxels with zero points.
441  void updateValueMask();
442 
443  ////////////////////////////////////////
444 
445  void setOffsetOn(Index offset, const ValueType& val);
446  void setOffsetOnly(Index offset, const ValueType& val);
447 
448  /// @brief Return @c true if the given node (which may have a different @c ValueType
449  /// than this node) has the same active value topology as this node.
450  template<typename OtherType, Index OtherLog2Dim>
452  return BaseLeaf::hasSameTopology(other);
453  }
454 
455  /// Check for buffer, state and origin equivalence first.
456  /// If this returns true, do a deeper comparison on the attribute set to check
457  bool operator==(const PointDataLeafNode& other) const {
458  if(BaseLeaf::operator==(other) != true) return false;
459  return (*this->mAttributeSet == *other.mAttributeSet);
460  }
461 
462  bool operator!=(const PointDataLeafNode& other) const { return !(other == *this); }
463 
465  template<typename AccessorT>
466  void addLeafAndCache(PointDataLeafNode*, AccessorT&) {}
467 
468  //@{
469  /// @brief Return a pointer to this node.
470  PointDataLeafNode* touchLeaf(const Coord&) { return this; }
471  template<typename AccessorT>
472  PointDataLeafNode* touchLeafAndCache(const Coord&, AccessorT&) { return this; }
473 
474  template<typename NodeT, typename AccessorT>
475  NodeT* probeNodeAndCache(const Coord&, AccessorT&)
476  {
478  if (!(std::is_same<NodeT,PointDataLeafNode>::value)) return nullptr;
479  return reinterpret_cast<NodeT*>(this);
481  }
482  PointDataLeafNode* probeLeaf(const Coord&) { return this; }
483  template<typename AccessorT>
484  PointDataLeafNode* probeLeafAndCache(const Coord&, AccessorT&) { return this; }
485  //@}
486 
487  //@{
488  /// @brief Return a @const pointer to this node.
489  const PointDataLeafNode* probeConstLeaf(const Coord&) const { return this; }
490  template<typename AccessorT>
491  const PointDataLeafNode* probeConstLeafAndCache(const Coord&, AccessorT&) const { return this; }
492  template<typename AccessorT>
493  const PointDataLeafNode* probeLeafAndCache(const Coord&, AccessorT&) const { return this; }
494  const PointDataLeafNode* probeLeaf(const Coord&) const { return this; }
495  template<typename NodeT, typename AccessorT>
496  const NodeT* probeConstNodeAndCache(const Coord&, AccessorT&) const
497  {
499  if (!(std::is_same<NodeT,PointDataLeafNode>::value)) return nullptr;
500  return reinterpret_cast<const NodeT*>(this);
502  }
503  //@}
504 
505  // I/O methods
506 
507  void readTopology(std::istream& is, bool fromHalf = false);
508  void writeTopology(std::ostream& os, bool toHalf = false) const;
509 
510  Index buffers() const;
511 
512  void readBuffers(std::istream& is, bool fromHalf = false);
513  void readBuffers(std::istream& is, const CoordBBox&, bool fromHalf = false);
514  void writeBuffers(std::ostream& os, bool toHalf = false) const;
515 
516 
517  Index64 memUsage() const;
518 
519  void evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels = true) const;
520 
521  /// @brief Return the bounding box of this node, i.e., the full index space
522  /// spanned by this leaf node.
523  CoordBBox getNodeBoundingBox() const;
524 
525  ////////////////////////////////////////
526 
527  // Disable all write methods to avoid unintentional changes
528  // to the point-array offsets.
529 
531  assert(false && "Cannot modify voxel values in a PointDataTree.");
532  }
533 
534  // some methods silently ignore attempts to modify the
535  // point-array offsets if a zero value is used
536 
538  if (value != zeroVal<T>()) this->assertNonmodifiable();
539  }
540 
541  void setActiveState(const Coord& xyz, bool on) { BaseLeaf::setActiveState(xyz, on); }
542  void setActiveState(Index offset, bool on) { BaseLeaf::setActiveState(offset, on); }
543 
544  void setValueOnly(const Coord&, const ValueType&) { assertNonmodifiable(); }
546 
547  void setValueOff(const Coord& xyz) { BaseLeaf::setValueOff(xyz); }
549 
550  void setValueOff(const Coord&, const ValueType&) { assertNonmodifiable(); }
552 
553  void setValueOn(const Coord& xyz) { BaseLeaf::setValueOn(xyz); }
555 
556  void setValueOn(const Coord&, const ValueType&) { assertNonmodifiable(); }
558 
559  void setValue(const Coord&, const ValueType&) { assertNonmodifiable(); }
560 
563 
564  template<typename ModifyOp>
565  void modifyValue(Index, const ModifyOp&) { assertNonmodifiable(); }
566 
567  template<typename ModifyOp>
568  void modifyValue(const Coord&, const ModifyOp&) { assertNonmodifiable(); }
569 
570  template<typename ModifyOp>
571  void modifyValueAndActiveState(const Coord&, const ModifyOp&) { assertNonmodifiable(); }
572 
573  // clipping is not yet supported
574  void clip(const CoordBBox&, const ValueType& value) { assertNonModifiableUnlessZero(value); }
575 
576  void fill(const CoordBBox&, const ValueType&, bool);
578  void fill(const ValueType&, bool);
579 
580  template<typename AccessorT>
581  void setValueOnlyAndCache(const Coord&, const ValueType&, AccessorT&) {assertNonmodifiable();}
582 
583  template<typename ModifyOp, typename AccessorT>
584  void modifyValueAndActiveStateAndCache(const Coord&, const ModifyOp&, AccessorT&) {
586  }
587 
588  template<typename AccessorT>
589  void setValueOffAndCache(const Coord&, const ValueType&, AccessorT&) { assertNonmodifiable(); }
590 
591  template<typename AccessorT>
592  void setActiveStateAndCache(const Coord& xyz, bool on, AccessorT& parent) {
593  BaseLeaf::setActiveStateAndCache(xyz, on, parent);
594  }
595 
596  void resetBackground(const ValueType&, const ValueType& newBackground) {
597  assertNonModifiableUnlessZero(newBackground);
598  }
599 
602 
604 
605  friend class ::TestPointDataLeaf;
606 
607  using ValueOn = typename BaseLeaf::ValueOn;
608  using ValueOff = typename BaseLeaf::ValueOff;
609  using ValueAll = typename BaseLeaf::ValueAll;
610 
611 private:
612  std::unique_ptr<AttributeSet> mAttributeSet;
613  uint16_t mVoxelBufferSize = 0;
614 
615 protected:
616  using ChildOn = typename BaseLeaf::ChildOn;
617  using ChildOff = typename BaseLeaf::ChildOff;
618  using ChildAll = typename BaseLeaf::ChildAll;
619 
623 
624  // During topology-only construction, access is needed
625  // to protected/private members of other template instances.
626  template<typename, Index> friend class PointDataLeafNode;
627 
631 
632 public:
633  /// @brief Leaf value voxel iterator
634  ValueVoxelCIter beginValueVoxel(const Coord& ijk) const;
635 
636 public:
637 
638 #if defined(_MSC_VER) && (_MSC_VER < 1914)
639  using ValueOnIter = typename BaseLeaf::ValueIter<
641  using ValueOnCIter = typename BaseLeaf::ValueIter<
643  using ValueOffIter = typename BaseLeaf::ValueIter<
645  using ValueOffCIter = typename BaseLeaf::ValueIter<
647  using ValueAllIter = typename BaseLeaf::ValueIter<
649  using ValueAllCIter = typename BaseLeaf::ValueIter<
651  using ChildOnIter = typename BaseLeaf::ChildIter<
653  using ChildOnCIter = typename BaseLeaf::ChildIter<
655  using ChildOffIter = typename BaseLeaf::ChildIter<
657  using ChildOffCIter = typename BaseLeaf::ChildIter<
659  using ChildAllIter = typename BaseLeaf::DenseIter<
661  using ChildAllCIter = typename BaseLeaf::DenseIter<
662  const PointDataLeafNode, const ValueType, ChildAll>;
663 #else
664  using ValueOnIter = typename BaseLeaf::template ValueIter<
666  using ValueOnCIter = typename BaseLeaf::template ValueIter<
668  using ValueOffIter = typename BaseLeaf::template ValueIter<
670  using ValueOffCIter = typename BaseLeaf::template ValueIter<
672  using ValueAllIter = typename BaseLeaf::template ValueIter<
674  using ValueAllCIter = typename BaseLeaf::template ValueIter<
676  using ChildOnIter = typename BaseLeaf::template ChildIter<
678  using ChildOnCIter = typename BaseLeaf::template ChildIter<
680  using ChildOffIter = typename BaseLeaf::template ChildIter<
682  using ChildOffCIter = typename BaseLeaf::template ChildIter<
684  using ChildAllIter = typename BaseLeaf::template DenseIter<
686  using ChildAllCIter = typename BaseLeaf::template DenseIter<
688 #endif
689 
694 
695  /// @brief Leaf index iterator
697  {
699  return this->beginIndex<ValueAllCIter, NullFilter>(filter);
700  }
702  {
704  return this->beginIndex<ValueOnCIter, NullFilter>(filter);
705  }
707  {
709  return this->beginIndex<ValueOffCIter, NullFilter>(filter);
710  }
711 
712  template<typename IterT, typename FilterT>
713  IndexIter<IterT, FilterT> beginIndex(const FilterT& filter) const;
714 
715  /// @brief Filtered leaf index iterator
716  template<typename FilterT>
718  {
719  return this->beginIndex<ValueAllCIter, FilterT>(filter);
720  }
721  template<typename FilterT>
723  {
724  return this->beginIndex<ValueOnCIter, FilterT>(filter);
725  }
726  template<typename FilterT>
728  {
729  return this->beginIndex<ValueOffCIter, FilterT>(filter);
730  }
731 
732  /// @brief Leaf index iterator from voxel
733  IndexVoxelIter beginIndexVoxel(const Coord& ijk) const;
734 
735  /// @brief Filtered leaf index iterator from voxel
736  template<typename FilterT>
737  IndexIter<ValueVoxelCIter, FilterT> beginIndexVoxel(const Coord& ijk, const FilterT& filter) const;
738 
739 #define VMASK_ this->getValueMask()
740  ValueOnCIter cbeginValueOn() const { return ValueOnCIter(VMASK_.beginOn(), this); }
741  ValueOnCIter beginValueOn() const { return ValueOnCIter(VMASK_.beginOn(), this); }
742  ValueOnIter beginValueOn() { return ValueOnIter(VMASK_.beginOn(), this); }
743  ValueOffCIter cbeginValueOff() const { return ValueOffCIter(VMASK_.beginOff(), this); }
744  ValueOffCIter beginValueOff() const { return ValueOffCIter(VMASK_.beginOff(), this); }
745  ValueOffIter beginValueOff() { return ValueOffIter(VMASK_.beginOff(), this); }
746  ValueAllCIter cbeginValueAll() const { return ValueAllCIter(VMASK_.beginDense(), this); }
747  ValueAllCIter beginValueAll() const { return ValueAllCIter(VMASK_.beginDense(), this); }
748  ValueAllIter beginValueAll() { return ValueAllIter(VMASK_.beginDense(), this); }
749 
750  ValueOnCIter cendValueOn() const { return ValueOnCIter(VMASK_.endOn(), this); }
751  ValueOnCIter endValueOn() const { return ValueOnCIter(VMASK_.endOn(), this); }
752  ValueOnIter endValueOn() { return ValueOnIter(VMASK_.endOn(), this); }
753  ValueOffCIter cendValueOff() const { return ValueOffCIter(VMASK_.endOff(), this); }
754  ValueOffCIter endValueOff() const { return ValueOffCIter(VMASK_.endOff(), this); }
755  ValueOffIter endValueOff() { return ValueOffIter(VMASK_.endOff(), this); }
756  ValueAllCIter cendValueAll() const { return ValueAllCIter(VMASK_.endDense(), this); }
757  ValueAllCIter endValueAll() const { return ValueAllCIter(VMASK_.endDense(), this); }
758  ValueAllIter endValueAll() { return ValueAllIter(VMASK_.endDense(), this); }
759 
760  ChildOnCIter cbeginChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
761  ChildOnCIter beginChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
762  ChildOnIter beginChildOn() { return ChildOnIter(VMASK_.endOn(), this); }
763  ChildOffCIter cbeginChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
764  ChildOffCIter beginChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
765  ChildOffIter beginChildOff() { return ChildOffIter(VMASK_.endOff(), this); }
766  ChildAllCIter cbeginChildAll() const { return ChildAllCIter(VMASK_.beginDense(), this); }
767  ChildAllCIter beginChildAll() const { return ChildAllCIter(VMASK_.beginDense(), this); }
768  ChildAllIter beginChildAll() { return ChildAllIter(VMASK_.beginDense(), this); }
769 
770  ChildOnCIter cendChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
771  ChildOnCIter endChildOn() const { return ChildOnCIter(VMASK_.endOn(), this); }
772  ChildOnIter endChildOn() { return ChildOnIter(VMASK_.endOn(), this); }
773  ChildOffCIter cendChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
774  ChildOffCIter endChildOff() const { return ChildOffCIter(VMASK_.endOff(), this); }
775  ChildOffIter endChildOff() { return ChildOffIter(VMASK_.endOff(), this); }
776  ChildAllCIter cendChildAll() const { return ChildAllCIter(VMASK_.endDense(), this); }
777  ChildAllCIter endChildAll() const { return ChildAllCIter(VMASK_.endDense(), this); }
778  ChildAllIter endChildAll() { return ChildAllIter(VMASK_.endDense(), this); }
779 #undef VMASK_
780 }; // struct PointDataLeafNode
781 
782 ////////////////////////////////////////
783 
784 // PointDataLeafNode implementation
785 
786 template<typename T, Index Log2Dim>
787 inline void
788 PointDataLeafNode<T, Log2Dim>::initializeAttributes(const Descriptor::Ptr& descriptor, const Index arrayLength)
789 {
790  if (descriptor->size() != 1 ||
791  descriptor->find("P") == AttributeSet::INVALID_POS ||
792  descriptor->valueType(0) != typeNameAsString<Vec3f>())
793  {
794  OPENVDB_THROW(IndexError, "Initializing attributes only allowed with one Vec3f position attribute.");
795  }
796 
797  mAttributeSet.reset(new AttributeSet(descriptor, arrayLength));
798 }
799 
800 template<typename T, Index Log2Dim>
801 inline void
803 {
804  mAttributeSet.reset(new AttributeSet(*mAttributeSet, 0));
805 
806  // zero voxel values
807 
808  this->buffer().fill(ValueType(0));
809 
810  // if updateValueMask, also de-activate all voxels
811 
812  if (updateValueMask) this->setValuesOff();
813 }
814 
815 template<typename T, Index Log2Dim>
816 inline bool
818 {
819  return pos < mAttributeSet->size();
820 }
821 
822 template<typename T, Index Log2Dim>
823 inline bool
825 {
826  const size_t pos = mAttributeSet->find(attributeName);
827  return pos != AttributeSet::INVALID_POS;
828 }
829 
830 template<typename T, Index Log2Dim>
831 inline AttributeArray::Ptr
832 PointDataLeafNode<T, Log2Dim>::appendAttribute( const Descriptor& expected, Descriptor::Ptr& replacement,
833  const size_t pos, const Index strideOrTotalSize,
834  const bool constantStride)
835 {
836  return mAttributeSet->appendAttribute(expected, replacement, pos, strideOrTotalSize, constantStride);
837 }
838 
839 template<typename T, Index Log2Dim>
840 inline void
841 PointDataLeafNode<T, Log2Dim>::dropAttributes(const std::vector<size_t>& pos,
842  const Descriptor& expected, Descriptor::Ptr& replacement)
843 {
844  mAttributeSet->dropAttributes(pos, expected, replacement);
845 }
846 
847 template<typename T, Index Log2Dim>
848 inline void
849 PointDataLeafNode<T, Log2Dim>::reorderAttributes(const Descriptor::Ptr& replacement)
850 {
851  mAttributeSet->reorderAttributes(replacement);
852 }
853 
854 template<typename T, Index Log2Dim>
855 inline void
856 PointDataLeafNode<T, Log2Dim>::renameAttributes(const Descriptor& expected, Descriptor::Ptr& replacement)
857 {
858  mAttributeSet->renameAttributes(expected, replacement);
859 }
860 
861 template<typename T, Index Log2Dim>
862 inline void
864 {
865  for (size_t i = 0; i < mAttributeSet->size(); i++) {
866  AttributeArray* array = mAttributeSet->get(i);
867  array->compact();
868  }
869 }
870 
871 template<typename T, Index Log2Dim>
872 inline void
873 PointDataLeafNode<T, Log2Dim>::replaceAttributeSet(AttributeSet* attributeSet, bool allowMismatchingDescriptors)
874 {
875  if (!attributeSet) {
876  OPENVDB_THROW(ValueError, "Cannot replace with a null attribute set");
877  }
878 
879  if (!allowMismatchingDescriptors && mAttributeSet->descriptor() != attributeSet->descriptor()) {
880  OPENVDB_THROW(ValueError, "Attribute set descriptors are not equal.");
881  }
882 
883  mAttributeSet.reset(attributeSet);
884 }
885 
886 template<typename T, Index Log2Dim>
887 inline void
888 PointDataLeafNode<T, Log2Dim>::resetDescriptor(const Descriptor::Ptr& replacement)
889 {
890  mAttributeSet->resetDescriptor(replacement);
891 }
892 
893 template<typename T, Index Log2Dim>
894 inline void
895 PointDataLeafNode<T, Log2Dim>::setOffsets(const std::vector<ValueType>& offsets, const bool updateValueMask)
896 {
897  if (offsets.size() != LeafNodeType::NUM_VALUES) {
898  OPENVDB_THROW(ValueError, "Offset vector size doesn't match number of voxels.")
899  }
900 
901  for (Index index = 0; index < offsets.size(); ++index) {
902  setOffsetOnly(index, offsets[index]);
903  }
904 
905  if (updateValueMask) this->updateValueMask();
906 }
907 
908 template<typename T, Index Log2Dim>
909 inline void
911 {
912  // Ensure all of the offset values are monotonically increasing
913  for (Index index = 1; index < BaseLeaf::SIZE; ++index) {
914  if (this->getValue(index-1) > this->getValue(index)) {
915  OPENVDB_THROW(ValueError, "Voxel offset values are not monotonically increasing");
916  }
917  }
918 
919  // Ensure all attribute arrays are of equal length
920  for (size_t attributeIndex = 1; attributeIndex < mAttributeSet->size(); ++attributeIndex ) {
921  if (mAttributeSet->getConst(attributeIndex-1)->size() != mAttributeSet->getConst(attributeIndex)->size()) {
922  OPENVDB_THROW(ValueError, "Attribute arrays have inconsistent length");
923  }
924  }
925 
926  // Ensure the last voxel's offset value matches the size of each attribute array
927  if (mAttributeSet->size() > 0 && this->getValue(BaseLeaf::SIZE-1) != mAttributeSet->getConst(0)->size()) {
928  OPENVDB_THROW(ValueError, "Last voxel offset value does not match attribute array length");
929  }
930 }
931 
932 template<typename T, Index Log2Dim>
933 inline AttributeArray&
935 {
936  if (pos >= mAttributeSet->size()) OPENVDB_THROW(LookupError, "Attribute Out Of Range - " << pos);
937  return *mAttributeSet->get(pos);
938 }
939 
940 template<typename T, Index Log2Dim>
941 inline const AttributeArray&
943 {
944  if (pos >= mAttributeSet->size()) OPENVDB_THROW(LookupError, "Attribute Out Of Range - " << pos);
945  return *mAttributeSet->getConst(pos);
946 }
947 
948 template<typename T, Index Log2Dim>
949 inline const AttributeArray&
951 {
952  return this->attributeArray(pos);
953 }
954 
955 template<typename T, Index Log2Dim>
956 inline AttributeArray&
958 {
959  const size_t pos = mAttributeSet->find(attributeName);
960  if (pos == AttributeSet::INVALID_POS) OPENVDB_THROW(LookupError, "Attribute Not Found - " << attributeName);
961  return *mAttributeSet->get(pos);
962 }
963 
964 template<typename T, Index Log2Dim>
965 inline const AttributeArray&
967 {
968  const size_t pos = mAttributeSet->find(attributeName);
969  if (pos == AttributeSet::INVALID_POS) OPENVDB_THROW(LookupError, "Attribute Not Found - " << attributeName);
970  return *mAttributeSet->getConst(pos);
971 }
972 
973 template<typename T, Index Log2Dim>
974 inline const AttributeArray&
976 {
977  return this->attributeArray(attributeName);
978 }
979 
980 template<typename T, Index Log2Dim>
981 inline GroupHandle
982 PointDataLeafNode<T, Log2Dim>::groupHandle(const AttributeSet::Descriptor::GroupIndex& index) const
983 {
984  const AttributeArray& array = this->attributeArray(index.first);
985  assert(isGroup(array));
986 
987  const GroupAttributeArray& groupArray = GroupAttributeArray::cast(array);
988 
989  return GroupHandle(groupArray, index.second);
990 }
991 
992 template<typename T, Index Log2Dim>
993 inline GroupHandle
995 {
996  const AttributeSet::Descriptor::GroupIndex index = this->attributeSet().groupIndex(name);
997  return this->groupHandle(index);
998 }
999 
1000 template<typename T, Index Log2Dim>
1001 inline GroupWriteHandle
1002 PointDataLeafNode<T, Log2Dim>::groupWriteHandle(const AttributeSet::Descriptor::GroupIndex& index)
1003 {
1004  AttributeArray& array = this->attributeArray(index.first);
1005  assert(isGroup(array));
1006 
1007  GroupAttributeArray& groupArray = GroupAttributeArray::cast(array);
1008 
1009  return GroupWriteHandle(groupArray, index.second);
1010 }
1011 
1012 template<typename T, Index Log2Dim>
1013 inline GroupWriteHandle
1015 {
1016  const AttributeSet::Descriptor::GroupIndex index = this->attributeSet().groupIndex(name);
1017  return this->groupWriteHandle(index);
1018 }
1019 
1020 template<typename T, Index Log2Dim>
1021 template<typename ValueIterT, typename FilterT>
1024 {
1025  // generate no-op iterator if filter evaluates no indices
1026 
1027  if (filter.state() == index::NONE) {
1028  return IndexIter<ValueIterT, FilterT>(ValueIterT(), filter);
1029  }
1030 
1031  // copy filter to ensure thread-safety
1032 
1033  FilterT newFilter(filter);
1034  newFilter.reset(*this);
1035 
1036  using IterTraitsT = tree::IterTraits<LeafNodeType, ValueIterT>;
1037 
1038  // construct the value iterator and reset the filter to use this leaf
1039 
1040  ValueIterT valueIter = IterTraitsT::begin(*this);
1041 
1042  return IndexIter<ValueIterT, FilterT>(valueIter, newFilter);
1043 }
1044 
1045 template<typename T, Index Log2Dim>
1046 inline ValueVoxelCIter
1048 {
1049  const Index index = LeafNodeType::coordToOffset(ijk);
1050  assert(index < BaseLeaf::SIZE);
1051  const ValueType end = this->getValue(index);
1052  const ValueType start = (index == 0) ? ValueType(0) : this->getValue(index - 1);
1053  return ValueVoxelCIter(start, end);
1054 }
1055 
1056 template<typename T, Index Log2Dim>
1059 {
1060  ValueVoxelCIter iter = this->beginValueVoxel(ijk);
1061  return IndexVoxelIter(iter, NullFilter());
1062 }
1063 
1064 template<typename T, Index Log2Dim>
1065 template<typename FilterT>
1067 PointDataLeafNode<T, Log2Dim>::beginIndexVoxel(const Coord& ijk, const FilterT& filter) const
1068 {
1069  ValueVoxelCIter iter = this->beginValueVoxel(ijk);
1070  FilterT newFilter(filter);
1071  newFilter.reset(*this);
1072  return IndexIter<ValueVoxelCIter, FilterT>(iter, newFilter);
1073 }
1074 
1075 template<typename T, Index Log2Dim>
1076 inline Index64
1078 {
1079  return this->getLastValue();
1080 }
1081 
1082 template<typename T, Index Log2Dim>
1083 inline Index64
1085 {
1086  if (this->isEmpty()) return 0;
1087  else if (this->isDense()) return this->pointCount();
1088  return iterCount(this->beginIndexOn());
1089 }
1090 
1091 template<typename T, Index Log2Dim>
1092 inline Index64
1094 {
1095  if (this->isEmpty()) return this->pointCount();
1096  else if (this->isDense()) return 0;
1097  return iterCount(this->beginIndexOff());
1098 }
1099 
1100 template<typename T, Index Log2Dim>
1101 inline Index64
1103 {
1104  if (!this->attributeSet().descriptor().hasGroup(groupName)) {
1105  return Index64(0);
1106  }
1107  GroupFilter filter(groupName, this->attributeSet());
1108  if (filter.state() == index::ALL) {
1109  return this->pointCount();
1110  } else {
1111  return iterCount(this->beginIndexAll(filter));
1112  }
1113 }
1114 
1115 template<typename T, Index Log2Dim>
1116 inline void
1118 {
1119  ValueType start = 0, end = 0;
1120  for (Index n = 0; n < LeafNodeType::NUM_VALUES; n++) {
1121  end = this->getValue(n);
1122  this->setValueMask(n, (end - start) > 0);
1123  start = end;
1124  }
1125 }
1126 
1127 template<typename T, Index Log2Dim>
1128 inline void
1130 {
1131  this->buffer().setValue(offset, val);
1132  this->setValueMaskOn(offset);
1133 }
1134 
1135 template<typename T, Index Log2Dim>
1136 inline void
1138 {
1139  this->buffer().setValue(offset, val);
1140 }
1141 
1142 template<typename T, Index Log2Dim>
1143 inline void
1144 PointDataLeafNode<T, Log2Dim>::readTopology(std::istream& is, bool fromHalf)
1145 {
1146  BaseLeaf::readTopology(is, fromHalf);
1147 }
1148 
1149 template<typename T, Index Log2Dim>
1150 inline void
1151 PointDataLeafNode<T, Log2Dim>::writeTopology(std::ostream& os, bool toHalf) const
1152 {
1153  BaseLeaf::writeTopology(os, toHalf);
1154 }
1155 
1156 template<typename T, Index Log2Dim>
1157 inline Index
1159 {
1160  return Index( /*voxel buffer sizes*/ 1 +
1161  /*voxel buffers*/ 1 +
1162  /*attribute metadata*/ 1 +
1163  /*attribute uniform values*/ mAttributeSet->size() +
1164  /*attribute buffers*/ mAttributeSet->size() +
1165  /*cleanup*/ 1);
1166 }
1167 
1168 template<typename T, Index Log2Dim>
1169 inline void
1170 PointDataLeafNode<T, Log2Dim>::readBuffers(std::istream& is, bool fromHalf)
1171 {
1172  this->readBuffers(is, CoordBBox::inf(), fromHalf);
1173 }
1174 
1175 template<typename T, Index Log2Dim>
1176 inline void
1177 PointDataLeafNode<T, Log2Dim>::readBuffers(std::istream& is, const CoordBBox& /*bbox*/, bool fromHalf)
1178 {
1179  struct Local
1180  {
1181  static void destroyPagedStream(const io::StreamMetadata::AuxDataMap& auxData, const Index index)
1182  {
1183  // if paged stream exists, delete it
1184  std::string key("paged:" + std::to_string(index));
1185  auto it = auxData.find(key);
1186  if (it != auxData.end()) {
1187  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(it);
1188  }
1189  }
1190 
1191  static compression::PagedInputStream& getOrInsertPagedStream( const io::StreamMetadata::AuxDataMap& auxData,
1192  const Index index)
1193  {
1194  std::string key("paged:" + std::to_string(index));
1195  auto it = auxData.find(key);
1196  if (it != auxData.end()) {
1197  return *(hboost::any_cast<compression::PagedInputStream::Ptr>(it->second));
1198  }
1199  else {
1200  compression::PagedInputStream::Ptr pagedStream = std::make_shared<compression::PagedInputStream>();
1201  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[key] = pagedStream;
1202  return *pagedStream;
1203  }
1204  }
1205 
1206  static bool hasMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1207  {
1208  std::string matchingKey("hasMatchingDescriptor");
1209  auto itMatching = auxData.find(matchingKey);
1210  return itMatching != auxData.end();
1211  }
1212 
1213  static void clearMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1214  {
1215  std::string matchingKey("hasMatchingDescriptor");
1216  std::string descriptorKey("descriptorPtr");
1217  auto itMatching = auxData.find(matchingKey);
1218  auto itDescriptor = auxData.find(descriptorKey);
1219  if (itMatching != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itMatching);
1220  if (itDescriptor != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1221  }
1222 
1223  static void insertDescriptor( const io::StreamMetadata::AuxDataMap& auxData,
1224  const Descriptor::Ptr descriptor)
1225  {
1226  std::string descriptorKey("descriptorPtr");
1227  std::string matchingKey("hasMatchingDescriptor");
1228  auto itMatching = auxData.find(matchingKey);
1229  if (itMatching == auxData.end()) {
1230  // if matching bool is not found, insert "true" and the descriptor
1231  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = true;
1232  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[descriptorKey] = descriptor;
1233  }
1234  }
1235 
1236  static AttributeSet::Descriptor::Ptr retrieveMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1237  {
1238  std::string descriptorKey("descriptorPtr");
1239  auto itDescriptor = auxData.find(descriptorKey);
1240  assert(itDescriptor != auxData.end());
1241  const Descriptor::Ptr descriptor = hboost::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1242  return descriptor;
1243  }
1244  };
1245 
1247 
1248  if (!meta) {
1249  OPENVDB_THROW(IoError, "Cannot read in a PointDataLeaf without StreamMetadata.");
1250  }
1251 
1252  const Index pass(static_cast<uint16_t>(meta->pass()));
1253  const Index maximumPass(static_cast<uint16_t>(meta->pass() >> 16));
1254 
1255  const Index attributes = (maximumPass - 4) / 2;
1256 
1257  if (pass == 0) {
1258  // pass 0 - voxel data sizes
1259  is.read(reinterpret_cast<char*>(&mVoxelBufferSize), sizeof(uint16_t));
1260  Local::clearMatchingDescriptor(meta->auxData());
1261  }
1262  else if (pass == 1) {
1263  // pass 1 - descriptor and attribute metadata
1264  if (Local::hasMatchingDescriptor(meta->auxData())) {
1265  AttributeSet::Descriptor::Ptr descriptor = Local::retrieveMatchingDescriptor(meta->auxData());
1266  mAttributeSet->resetDescriptor(descriptor, /*allowMismatchingDescriptors=*/true);
1267  }
1268  else {
1269  uint8_t header;
1270  is.read(reinterpret_cast<char*>(&header), sizeof(uint8_t));
1271  mAttributeSet->readDescriptor(is);
1272  if (header & uint8_t(1)) {
1273  AttributeSet::DescriptorPtr descriptor = mAttributeSet->descriptorPtr();
1274  Local::insertDescriptor(meta->auxData(), descriptor);
1275  }
1276  // a forwards-compatibility mechanism for future use,
1277  // if a 0x2 bit is set, read and skip over a specific number of bytes
1278  if (header & uint8_t(2)) {
1279  uint64_t bytesToSkip;
1280  is.read(reinterpret_cast<char*>(&bytesToSkip), sizeof(uint64_t));
1281  if (bytesToSkip > uint64_t(0)) {
1282  auto metadata = io::getStreamMetadataPtr(is);
1283  if (metadata && metadata->seekable()) {
1284  is.seekg(bytesToSkip, std::ios_base::cur);
1285  }
1286  else {
1287  std::vector<uint8_t> tempData(bytesToSkip);
1288  is.read(reinterpret_cast<char*>(&tempData[0]), bytesToSkip);
1289  }
1290  }
1291  }
1292  // this reader is only able to read headers with 0x1 and 0x2 bits set
1293  if (header > uint8_t(3)) {
1294  OPENVDB_THROW(IoError, "Unrecognised header flags in PointDataLeafNode");
1295  }
1296  }
1297  mAttributeSet->readMetadata(is);
1298  }
1299  else if (pass < (attributes + 2)) {
1300  // pass 2...n+2 - attribute uniform values
1301  const size_t attributeIndex = pass - 2;
1302  AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1303  mAttributeSet->get(attributeIndex) : nullptr;
1304  if (array) {
1305  compression::PagedInputStream& pagedStream =
1306  Local::getOrInsertPagedStream(meta->auxData(), static_cast<Index>(attributeIndex));
1307  pagedStream.setInputStream(is);
1308  pagedStream.setSizeOnly(true);
1309  array->readPagedBuffers(pagedStream);
1310  }
1311  }
1312  else if (pass == attributes + 2) {
1313  // pass n+2 - voxel data
1314 
1315  const Index passValue(meta->pass());
1316 
1317  // StreamMetadata pass variable used to temporarily store voxel buffer size
1318  io::StreamMetadata& nonConstMeta = const_cast<io::StreamMetadata&>(*meta);
1319  nonConstMeta.setPass(mVoxelBufferSize);
1320 
1321  // readBuffers() calls readCompressedValues specialization above
1322  BaseLeaf::readBuffers(is, fromHalf);
1323 
1324  // pass now reset to original value
1325  nonConstMeta.setPass(passValue);
1326  }
1327  else if (pass < (attributes*2 + 3)) {
1328  // pass n+2..2n+2 - attribute buffers
1329  const Index attributeIndex = pass - attributes - 3;
1330  AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1331  mAttributeSet->get(attributeIndex) : nullptr;
1332  if (array) {
1333  compression::PagedInputStream& pagedStream =
1334  Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1335  pagedStream.setInputStream(is);
1336  pagedStream.setSizeOnly(false);
1337  array->readPagedBuffers(pagedStream);
1338  }
1339  // cleanup paged stream reference in auxiliary metadata
1340  if (pass > attributes + 3) {
1341  Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1342  }
1343  }
1344  else if (pass < buffers()) {
1345  // pass 2n+3 - cleanup last paged stream
1346  const Index attributeIndex = pass - attributes - 4;
1347  Local::destroyPagedStream(meta->auxData(), attributeIndex);
1348  }
1349 }
1350 
1351 template<typename T, Index Log2Dim>
1352 inline void
1353 PointDataLeafNode<T, Log2Dim>::writeBuffers(std::ostream& os, bool toHalf) const
1354 {
1355  struct Local
1356  {
1357  static void destroyPagedStream(const io::StreamMetadata::AuxDataMap& auxData, const Index index)
1358  {
1359  // if paged stream exists, flush and delete it
1360  std::string key("paged:" + std::to_string(index));
1361  auto it = auxData.find(key);
1362  if (it != auxData.end()) {
1364  stream.flush();
1365  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(it);
1366  }
1367  }
1368 
1369  static compression::PagedOutputStream& getOrInsertPagedStream( const io::StreamMetadata::AuxDataMap& auxData,
1370  const Index index)
1371  {
1372  std::string key("paged:" + std::to_string(index));
1373  auto it = auxData.find(key);
1374  if (it != auxData.end()) {
1375  return *(hboost::any_cast<compression::PagedOutputStream::Ptr>(it->second));
1376  }
1377  else {
1378  compression::PagedOutputStream::Ptr pagedStream = std::make_shared<compression::PagedOutputStream>();
1379  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[key] = pagedStream;
1380  return *pagedStream;
1381  }
1382  }
1383 
1384  static void insertDescriptor( const io::StreamMetadata::AuxDataMap& auxData,
1385  const Descriptor::Ptr descriptor)
1386  {
1387  std::string descriptorKey("descriptorPtr");
1388  std::string matchingKey("hasMatchingDescriptor");
1389  auto itMatching = auxData.find(matchingKey);
1390  auto itDescriptor = auxData.find(descriptorKey);
1391  if (itMatching == auxData.end()) {
1392  // if matching bool is not found, insert "true" and the descriptor
1393  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = true;
1394  assert(itDescriptor == auxData.end());
1395  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[descriptorKey] = descriptor;
1396  }
1397  else {
1398  // if matching bool is found and is false, early exit (a previous descriptor did not match)
1399  bool matching = hboost::any_cast<bool>(itMatching->second);
1400  if (!matching) return;
1401  assert(itDescriptor != auxData.end());
1402  // if matching bool is true, check whether the existing descriptor matches the current one and set
1403  // matching bool to false if not
1404  const Descriptor::Ptr existingDescriptor = hboost::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1405  if (*existingDescriptor != *descriptor) {
1406  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData))[matchingKey] = false;
1407  }
1408  }
1409  }
1410 
1411  static bool hasMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1412  {
1413  std::string matchingKey("hasMatchingDescriptor");
1414  auto itMatching = auxData.find(matchingKey);
1415  // if matching key is not found, no matching descriptor
1416  if (itMatching == auxData.end()) return false;
1417  // if matching key is found and is false, no matching descriptor
1418  if (!hboost::any_cast<bool>(itMatching->second)) return false;
1419  return true;
1420  }
1421 
1422  static AttributeSet::Descriptor::Ptr retrieveMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1423  {
1424  std::string descriptorKey("descriptorPtr");
1425  auto itDescriptor = auxData.find(descriptorKey);
1426  // if matching key is true, however descriptor is not found, it has already been retrieved
1427  if (itDescriptor == auxData.end()) return nullptr;
1428  // otherwise remove it and return it
1429  const Descriptor::Ptr descriptor = hboost::any_cast<AttributeSet::Descriptor::Ptr>(itDescriptor->second);
1430  (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1431  return descriptor;
1432  }
1433 
1434  static void clearMatchingDescriptor(const io::StreamMetadata::AuxDataMap& auxData)
1435  {
1436  std::string matchingKey("hasMatchingDescriptor");
1437  std::string descriptorKey("descriptorPtr");
1438  auto itMatching = auxData.find(matchingKey);
1439  auto itDescriptor = auxData.find(descriptorKey);
1440  if (itMatching != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itMatching);
1441  if (itDescriptor != auxData.end()) (const_cast<io::StreamMetadata::AuxDataMap&>(auxData)).erase(itDescriptor);
1442  }
1443  };
1444 
1446 
1447  if (!meta) {
1448  OPENVDB_THROW(IoError, "Cannot write out a PointDataLeaf without StreamMetadata.");
1449  }
1450 
1451  const Index pass(static_cast<uint16_t>(meta->pass()));
1452 
1453  // leaf traversal analysis deduces the number of passes to perform for this leaf
1454  // then updates the leaf traversal value to ensure all passes will be written
1455 
1456  if (meta->countingPasses()) {
1457  const Index requiredPasses = this->buffers();
1458  if (requiredPasses > pass) {
1459  meta->setPass(requiredPasses);
1460  }
1461  return;
1462  }
1463 
1464  const Index maximumPass(static_cast<uint16_t>(meta->pass() >> 16));
1465  const Index attributes = (maximumPass - 4) / 2;
1466 
1467  if (pass == 0) {
1468  // pass 0 - voxel data sizes
1470  // track if descriptor is shared or not
1471  Local::insertDescriptor(meta->auxData(), mAttributeSet->descriptorPtr());
1472  }
1473  else if (pass == 1) {
1474  // pass 1 - descriptor and attribute metadata
1475  bool matchingDescriptor = Local::hasMatchingDescriptor(meta->auxData());
1476  if (matchingDescriptor) {
1477  AttributeSet::Descriptor::Ptr descriptor = Local::retrieveMatchingDescriptor(meta->auxData());
1478  if (descriptor) {
1479  // write a header to indicate a shared descriptor
1480  uint8_t header(1);
1481  os.write(reinterpret_cast<const char*>(&header), sizeof(uint8_t));
1482  mAttributeSet->writeDescriptor(os, /*transient=*/false);
1483  }
1484  }
1485  else {
1486  // write a header to indicate a non-shared descriptor
1487  uint8_t header(0);
1488  os.write(reinterpret_cast<const char*>(&header), sizeof(uint8_t));
1489  mAttributeSet->writeDescriptor(os, /*transient=*/false);
1490  }
1491  mAttributeSet->writeMetadata(os, /*transient=*/false, /*paged=*/true);
1492  }
1493  else if (pass < attributes + 2) {
1494  // pass 2...n+2 - attribute buffer sizes
1495  const Index attributeIndex = pass - 2;
1496  // destroy previous paged stream
1497  if (pass > 2) {
1498  Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1499  }
1500  const AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1501  mAttributeSet->getConst(attributeIndex) : nullptr;
1502  if (array) {
1503  compression::PagedOutputStream& pagedStream =
1504  Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1505  pagedStream.setOutputStream(os);
1506  pagedStream.setSizeOnly(true);
1507  array->writePagedBuffers(pagedStream, /*outputTransient*/false);
1508  }
1509  }
1510  else if (pass == attributes + 2) {
1511  const Index attributeIndex = pass - 3;
1512  Local::destroyPagedStream(meta->auxData(), attributeIndex);
1513  // pass n+2 - voxel data
1514  BaseLeaf::writeBuffers(os, toHalf);
1515  }
1516  else if (pass < (attributes*2 + 3)) {
1517  // pass n+3...2n+3 - attribute buffers
1518  const Index attributeIndex = pass - attributes - 3;
1519  // destroy previous paged stream
1520  if (pass > attributes + 2) {
1521  Local::destroyPagedStream(meta->auxData(), attributeIndex-1);
1522  }
1523  const AttributeArray* array = attributeIndex < mAttributeSet->size() ?
1524  mAttributeSet->getConst(attributeIndex) : nullptr;
1525  if (array) {
1526  compression::PagedOutputStream& pagedStream =
1527  Local::getOrInsertPagedStream(meta->auxData(), attributeIndex);
1528  pagedStream.setOutputStream(os);
1529  pagedStream.setSizeOnly(false);
1530  array->writePagedBuffers(pagedStream, /*outputTransient*/false);
1531  }
1532  }
1533  else if (pass < buffers()) {
1534  Local::clearMatchingDescriptor(meta->auxData());
1535  // pass 2n+3 - cleanup last paged stream
1536  const Index attributeIndex = pass - attributes - 4;
1537  Local::destroyPagedStream(meta->auxData(), attributeIndex);
1538  }
1539 }
1540 
1541 template<typename T, Index Log2Dim>
1542 inline Index64
1544 {
1545  return BaseLeaf::memUsage() + mAttributeSet->memUsage();
1546 }
1547 
1548 template<typename T, Index Log2Dim>
1549 inline void
1550 PointDataLeafNode<T, Log2Dim>::evalActiveBoundingBox(CoordBBox& bbox, bool visitVoxels) const
1551 {
1552  BaseLeaf::evalActiveBoundingBox(bbox, visitVoxels);
1553 }
1554 
1555 template<typename T, Index Log2Dim>
1556 inline CoordBBox
1558 {
1559  return BaseLeaf::getNodeBoundingBox();
1560 }
1561 
1562 template<typename T, Index Log2Dim>
1563 inline void
1564 PointDataLeafNode<T, Log2Dim>::fill(const CoordBBox& bbox, const ValueType& value, bool active)
1565 {
1566 #if OPENVDB_ABI_VERSION_NUMBER >= 3
1567  if (!this->allocate()) return;
1568 #endif
1569 
1570  this->assertNonModifiableUnlessZero(value);
1571 
1572  // active state is permitted to be updated
1573 
1574  for (Int32 x = bbox.min().x(); x <= bbox.max().x(); ++x) {
1575  const Index offsetX = (x & (DIM-1u)) << 2*Log2Dim;
1576  for (Int32 y = bbox.min().y(); y <= bbox.max().y(); ++y) {
1577  const Index offsetXY = offsetX + ((y & (DIM-1u)) << Log2Dim);
1578  for (Int32 z = bbox.min().z(); z <= bbox.max().z(); ++z) {
1579  const Index offset = offsetXY + (z & (DIM-1u));
1580  this->setValueMask(offset, active);
1581  }
1582  }
1583  }
1584 }
1585 
1586 template<typename T, Index Log2Dim>
1587 inline void
1589 {
1590  this->assertNonModifiableUnlessZero(value);
1591 
1592  // active state is permitted to be updated
1593 
1594  if (active) this->setValuesOn();
1595  else this->setValuesOff();
1596 }
1597 
1598 
1599 ////////////////////////////////////////
1600 
1601 
1602 template <typename PointDataTreeT>
1603 inline AttributeSet::Descriptor::Ptr
1604 makeDescriptorUnique(PointDataTreeT& tree)
1605 {
1606  auto leafIter = tree.beginLeaf();
1607  if (!leafIter) return nullptr;
1608 
1609  const AttributeSet::Descriptor& descriptor = leafIter->attributeSet().descriptor();
1610  auto newDescriptor = std::make_shared<AttributeSet::Descriptor>(descriptor);
1611  for (; leafIter; ++leafIter) {
1612  leafIter->resetDescriptor(newDescriptor);
1613  }
1614 
1615  return newDescriptor;
1616 }
1617 
1618 
1619 template <typename PointDataTreeT>
1620 inline void
1621 setStreamingMode(PointDataTreeT& tree, bool on)
1622 {
1623  auto leafIter = tree.beginLeaf();
1624  for (; leafIter; ++leafIter) {
1625  for (size_t i = 0; i < leafIter->attributeSet().size(); i++) {
1626  leafIter->attributeArray(i).setStreaming(on);
1627  }
1628  }
1629 }
1630 
1631 
1632 template <typename PointDataTreeT>
1633 inline void
1634 prefetch(PointDataTreeT& tree, bool position, bool otherAttributes)
1635 {
1636  // NOTE: the following is intentionally not multi-threaded, as the I/O
1637  // is faster if done in the order in which it is stored in the file
1638 
1639  auto leaf = tree.cbeginLeaf();
1640  if (!leaf) return;
1641 
1642  const auto& attributeSet = leaf->attributeSet();
1643 
1644  // pre-fetch leaf data
1645 
1646  for ( ; leaf; ++leaf) {
1647  leaf->buffer().data();
1648  }
1649 
1650  // pre-fetch position attribute data (position will typically have index 0)
1651 
1652  size_t positionIndex = attributeSet.find("P");
1653 
1654  if (position && positionIndex != AttributeSet::INVALID_POS) {
1655  for (leaf = tree.cbeginLeaf(); leaf; ++leaf) {
1656  assert(leaf->hasAttribute(positionIndex));
1657  leaf->constAttributeArray(positionIndex).loadData();
1658  }
1659  }
1660 
1661  // pre-fetch other attribute data
1662 
1663  if (otherAttributes) {
1664  const size_t attributes = attributeSet.size();
1665  for (size_t attributeIndex = 0; attributeIndex < attributes; attributeIndex++) {
1666  if (attributeIndex == positionIndex) continue;
1667  for (leaf = tree.cbeginLeaf(); leaf; ++leaf) {
1668  assert(leaf->hasAttribute(attributeIndex));
1669  leaf->constAttributeArray(attributeIndex).loadData();
1670  }
1671  }
1672  }
1673 }
1674 
1675 
1676 namespace internal {
1677 
1678 /// @brief Global registration of point data-related types
1679 /// @note This is called from @c openvdb::initialize, so there is
1680 /// no need to call it directly.
1681 void initialize();
1682 
1683 /// @brief Global deregistration of point data-related types
1684 /// @note This is called from @c openvdb::uninitialize, so there is
1685 /// no need to call it directly.
1686 void uninitialize();
1687 
1688 
1689 /// @brief Recursive node chain which generates a hboost::mpl::vector listing
1690 /// value converted types of nodes to PointDataGrid nodes of the same configuration,
1691 /// rooted at RootNodeType in reverse order, from LeafNode to RootNode.
1692 /// See also TreeConverter<>.
1693 template<typename HeadT, int HeadLevel>
1695 {
1696  using SubtreeT = typename PointDataNodeChain<typename HeadT::ChildNodeType, HeadLevel-1>::Type;
1699 };
1700 
1701 // Specialization for internal nodes which require their embedded child type to
1702 // be switched
1703 template <typename ChildT, Index Log2Dim, int HeadLevel>
1704 struct PointDataNodeChain<tree::InternalNode<ChildT, Log2Dim>, HeadLevel>
1705 {
1706  using SubtreeT = typename PointDataNodeChain<ChildT, HeadLevel-1>::Type;
1709 };
1710 
1711 // Specialization for the last internal node of a node chain, expected
1712 // to be templated on a leaf node
1713 template <typename ChildT, Index Log2Dim>
1714 struct PointDataNodeChain<tree::InternalNode<ChildT, Log2Dim>, /*HeadLevel=*/1>
1715 {
1719 };
1720 
1721 } // namespace internal
1722 
1723 
1724 /// @brief Similiar to ValueConverter, but allows for tree configuration conversion
1725 /// to a PointDataTree. ValueConverter<PointDataIndex32> cannot be used as a
1726 /// PointDataLeafNode is not a specialization of LeafNode
1727 template <typename TreeType>
1729  using RootNodeT = typename TreeType::RootNodeType;
1732 };
1733 
1734 
1735 } // namespace points
1736 
1737 
1738 ////////////////////////////////////////
1739 
1740 
1741 namespace tree
1742 {
1743 
1744 /// Helper metafunction used to implement LeafNode::SameConfiguration
1745 /// (which, as an inner class, can't be independently specialized)
1746 template<Index Dim1, typename T2>
1747 struct SameLeafConfig<Dim1, points::PointDataLeafNode<T2, Dim1>> { static const bool value = true; };
1748 
1749 } // namespace tree
1750 } // namespace OPENVDB_VERSION_NAME
1751 } // namespace openvdb
1752 
1753 #endif // OPENVDB_POINTS_POINT_DATA_GRID_HAS_BEEN_INCLUDED
1754 
1755 // Copyright (c) 2012-2018 DreamWorks Animation LLC
1756 // All rights reserved. This software is distributed under the
1757 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
void modifyValueAndActiveStateAndCache(const Coord &, const ModifyOp &, AccessorT &)
GLuint GLuint stream
Definition: glcorearb.h:1831
PointIndex< Index32, 1 > PointDataIndex32
Definition: Types.h:208
Index64 onPointCount() const
Compute the total active (on) point count for the leaf.
AttributeSet::Descriptor::Ptr makeDescriptorUnique(PointDataTreeT &tree)
Deep copy the descriptor across all leaf nodes.
void setValue(const Coord &, const ValueType &)
Leaf nodes have no children, so their child iterators have no get/set accessors.
Definition: LeafNode.h:271
Definition: ImfName.h:53
Descriptor & descriptor()
Return a reference to this attribute set's descriptor, which might be shared with other sets...
Definition: AttributeSet.h:121
bool operator!=(const PointDataLeafNode &other) const
virtual void readPagedBuffers(compression::PagedInputStream &)=0
Read attribute buffers from a paged stream.
typename BaseLeaf::template DenseIter< const PointDataLeafNode, const ValueType, ChildAll > ChildAllCIter
PointDataLeafNode * touchLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
const PointDataLeafNode * probeLeafAndCache(const Coord &, AccessorT &) const
Return a pointer to this node.
IndexVoxelIter beginIndexVoxel(const Coord &ijk) const
Leaf index iterator from voxel.
typename BaseLeaf::template ValueIter< MaskOffIterator, PointDataLeafNode, const ValueType, ValueOff > ValueOffIter
void modifyValueAndActiveState(const Coord &, const ModifyOp &)
PointDataLeafNode(const tree::LeafNode< ValueType, Log2Dim > &other, const T &value, TopologyCopy)
void setOffsets(const std::vector< ValueType > &offsets, const bool updateValueMask=true)
Sets all of the voxel offset values on this leaf, from the given vector of offsets. If updateValueMask is true, then the active value mask will be updated so voxels with points are active and empty voxels are inactive.
void modifyValue(const Coord &, const ModifyOp &)
GroupWriteHandle groupWriteHandle(const AttributeSet::Descriptor::GroupIndex &index)
Read-write group handle from group index.
bool hasSameTopology(const PointDataLeafNode< OtherType, OtherLog2Dim > *other) const
Return true if the given node (which may have a different ValueType than this node) has the same acti...
void setValueOn(const Coord &xyz)
Mark the voxel at the given coordinates as active but don't change its value.
Definition: LeafNode.h:440
void setValueOff(const Coord &, const ValueType &)
static TypedAttributeArray & cast(AttributeArray &attributeArray)
Cast an AttributeArray to TypedAttributeArray<T>
typename hboost::mpl::push_back< SubtreeT, RootNodeT >::type Type
GLuint start
Definition: glcorearb.h:474
GLsizei const GLchar *const * string
Definition: glcorearb.h:813
void writeCompressedValues(std::ostream &os, ValueT *srcBuf, Index srcCount, const MaskT &valueMask, const MaskT &childMask, bool toHalf)
Definition: Compression.h:462
void renameAttributes(const Descriptor &expected, Descriptor::Ptr &replacement)
Rename attributes in attribute set (order must remain the same).
void writeTopology(std::ostream &os, bool toHalf=false) const
void dropAttributes(const std::vector< size_t > &pos, const Descriptor &expected, Descriptor::Ptr &replacement)
Drop list of attributes.
void prefetch(PointDataTreeT &tree, bool position=true, bool otherAttributes=true)
Sequentially pre-fetch all delayed-load voxel and attribute data from disk in order to accelerate sub...
SharedPtr< StreamMetadata > Ptr
Definition: io.h:59
bool hasAttribute(const size_t pos) const
Returns true if an attribute with this index exists.
typename BaseLeaf::template ValueIter< MaskOnIterator, PointDataLeafNode, const ValueType, ValueOn > ValueOnIter
PointDataLeafNode * probeLeafAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:847
void validateOffsets() const
Throws an error if the voxel values on this leaf are not monotonically increasing or within the bound...
Leaf nodes that require multi-pass I/O must inherit from this struct.
Definition: io.h:140
void updateValueMask()
Activate voxels with non-zero points, deactivate voxels with zero points.
PointDataLeafNode * touchLeaf(const Coord &)
Return a pointer to this node.
typename BaseLeaf::template ChildIter< MaskOnIterator, const PointDataLeafNode, ChildOn > ChildOnCIter
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only reading size data.
typename BaseLeaf::template ValueIter< MaskDenseIterator, const PointDataLeafNode, const ValueType, ValueAll > ValueAllCIter
typename internal::PointDataNodeChain< RootNodeT, RootNodeT::LEVEL >::Type NodeChainT
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:189
typename BaseLeaf::template ChildIter< MaskOffIterator, const PointDataLeafNode, ChildOff > ChildOffCIter
IndexIter< IterT, FilterT > beginIndex(const FilterT &filter) const
AttributeArray::Ptr appendAttribute(const Descriptor &expected, Descriptor::Ptr &replacement, const size_t pos, const Index strideOrTotalSize=1, const bool constantStride=true)
Append an attribute to the leaf.
void readBuffers(std::istream &is, bool fromHalf=false)
Base class for iterators over internal and leaf nodes.
Definition: Iterator.h:56
void initializeAttributes(const Descriptor::Ptr &descriptor, const Index arrayLength)
Create a new attribute set. Existing attributes will be removed.
GLint y
Definition: glcorearb.h:102
const PointDataLeafNode * probeLeaf(const Coord &) const
Return a pointer to this node.
void signedFloodFill(const ValueType &, const ValueType &)
typename BaseLeaf::template DenseIter< PointDataLeafNode, ValueType, ChildAll > ChildAllIter
CoordBBox getNodeBoundingBox() const
Return the bounding box of this node, i.e., the full index space spanned by this leaf node...
void initialize()
Global registration of point data-related types.
Definition: logging.h:318
A Paging wrapper to std::istream that is responsible for reading from a given input stream and creati...
A no-op filter that can be used when iterating over all indices.
Definition: IndexIterator.h:77
GLuint buffer
Definition: glcorearb.h:659
png_uint_32 i
Definition: png.h:2877
Tag dispatch class that distinguishes constructors during file input.
Definition: Types.h:520
virtual void writePagedBuffers(compression::PagedOutputStream &, bool outputTransient) const =0
void readTopology(std::istream &is, bool fromHalf=false)
PointDataLeafNode(const tree::LeafNode< ValueType, Log2Dim > &other, const T &, const T &, TopologyCopy)
void setActiveState(const Coord &xyz, bool on)
Set the active state of the voxel at the given coordinates but don't change its value.
Definition: LeafNode.h:1137
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only writing size data.
void setValuesOn()
Mark all voxels as active but don't change their values.
Definition: LeafNode.h:486
bool isGroup(const AttributeArray &array)
GLuint GLsizei const GLuint const GLintptr * offsets
Definition: glcorearb.h:2620
void readCompressedValues(std::istream &is, ValueT *destBuf, Index destCount, const MaskT &valueMask, bool fromHalf)
Definition: Compression.h:339
const NodeT * probeConstNodeAndCache(const Coord &, AccessorT &) const
Return a pointer to this node.
PointDataLeafNode(const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Construct using supplied origin, value and active status.
const PointDataLeafNode * probeConstLeaf(const Coord &) const
Return a pointer to this node.
typename BaseLeaf::template ChildIter< MaskOffIterator, PointDataLeafNode, ChildOff > ChildOffIter
void compactAttributes()
Compact all attributes in attribute set.
IndexIter< ValueAllCIter, FilterT > beginIndexAll(const FilterT &filter) const
Filtered leaf index iterator.
const char * typeNameAsString< Vec3f >()
Definition: Types.h:356
GLdouble n
Definition: glcorearb.h:2007
OffMaskIterator< NodeMask > OffIterator
Definition: NodeMasks.h:351
Base class for storing attribute data.
typename NodeMaskType::OffIterator MaskOffIterator
typename PointDataNodeChain< typename HeadT::ChildNodeType, HeadLevel-1 >::Type SubtreeT
IndexIter< ValueVoxelCIter, NullFilter > IndexVoxelIter
A forward iterator over array indices in a single voxel.
Definition: IndexIterator.h:91
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &parent)
void setActiveStateAndCache(const Coord &xyz, bool on, AccessorT &)
Set the active state of the voxel at the given coordinates without changing its value.
Definition: LeafNode.h:607
NodeT * probeNodeAndCache(const Coord &, AccessorT &)
Return a pointer to this node.
Bit mask for the internal and leaf nodes of VDB. This is a 64-bit implementation. ...
Definition: NodeMasks.h:309
void setStreamingMode(PointDataTreeT &tree, bool on=true)
Toggle the streaming mode on all attributes in the tree to collapse the attributes after deconstructi...
const PointDataLeafNode * probeConstLeafAndCache(const Coord &, AccessorT &) const
Return a pointer to this node.
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:133
void uninitialize()
Global deregistration of point data-related types.
Templated block class to hold specific data types and a fixed number of values determined by Log2Dim...
Definition: LeafNode.h:64
IndexAllIter beginIndexAll() const
Leaf index iterator.
GLuint GLuint end
Definition: glcorearb.h:474
bool operator==(const PointDataLeafNode &other) const
Attribute array storage for string data using Descriptor Metadata.
GLintptr offset
Definition: glcorearb.h:664
typename BaseLeaf::template ValueIter< MaskOnIterator, const PointDataLeafNode, const ValueType, ValueOn > ValueOnCIter
typename BaseLeaf::template ChildIter< MaskOnIterator, PointDataLeafNode, ChildOn > ChildOnIter
OPENVDB_API void bloscDecompress(char *uncompressedBuffer, const size_t expectedBytes, const size_t bufferBytes, const char *compressedBuffer)
Decompress into the supplied buffer. Will throw if decompression fails or uncompressed buffer has ins...
void clip(const CoordBBox &, const ValueType &value)
void evalActiveBoundingBox(CoordBBox &bbox, bool visitVoxels=true) const
void writeCompressedValuesSize(std::ostream &os, const T *srcBuf, Index srcCount)
void setValueOnly(const Coord &, const ValueType &)
void setOffsetOn(Index offset, const ValueType &val)
Convenience wrappers to using Blosc and reading and writing of Paged data.
Recursive node chain which generates a hboost::mpl::vector listing value converted types of nodes to ...
void setValueOff(const Coord &xyz)
Mark the voxel at the given coordinates as inactive but don't change its value.
Definition: LeafNode.h:430
GLboolean * data
Definition: glcorearb.h:130
Index64 pointCount(const PointDataTreeT &tree, const FilterT &filter=NullFilter(), const bool inCoreOnly=false, const bool threaded=true)
Count the total number of points in a PointDataTree.
Definition: PointCount.h:115
A forward iterator over array indices with filtering IteratorT can be either IndexIter or ValueIndexI...
GLuint const GLchar * name
Definition: glcorearb.h:785
Index64 offPointCount() const
Compute the total inactive (off) point count for the leaf.
void setValueOffAndCache(const Coord &, const ValueType &, AccessorT &)
void reorderAttributes(const Descriptor::Ptr &replacement)
Reorder attribute set.
PointDataLeafNode(const PointDataLeafNode &other, const Coord &coords, const T &value=zeroVal< T >(), bool active=false)
Index filtering on group membership.
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:55
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition: Platform.h:129
const AttributeArray & constAttributeArray(const size_t pos) const
PointDataLeafNode(const PointDataLeafNode &other)
Construct using deep copy of other PointDataLeafNode.
typename BaseLeaf::template ValueIter< MaskDenseIterator, PointDataLeafNode, const ValueType, ValueAll > ValueAllIter
const GLuint * buffers
Definition: glcorearb.h:660
void flush()
Manually flushes the current page to disk if non-zero.
IndexIter< ValueOffCIter, FilterT > beginIndexOff(const FilterT &filter) const
GLsizei const GLfloat * value
Definition: glcorearb.h:823
OPENVDB_API void bloscCompress(char *compressedBuffer, size_t &compressedBytes, const size_t bufferBytes, const char *uncompressedBuffer, const size_t uncompressedBytes)
Compress into the supplied buffer.
void fill(const CoordBBox &, const ValueType &, bool)
DenseMaskIterator< NodeMask > DenseIterator
Definition: NodeMasks.h:352
ValueVoxelCIter beginValueVoxel(const Coord &ijk) const
Leaf value voxel iterator.
GroupHandle groupHandle(const AttributeSet::Descriptor::GroupIndex &index) const
}
void setOffsetOnly(Index offset, const ValueType &val)
Typed class for storing attribute data.
Set of Attribute Arrays which tracks metadata about each array.
PointDataLeafNode * probeLeaf(const Coord &)
Return a pointer to this node.
Space-partitioning acceleration structure for points. Partitions the points into voxels to accelerate...
Attribute Group access and filtering for iteration.
GLuint index
Definition: glcorearb.h:785
OPENVDB_API size_t bloscCompressedSize(const char *buffer, const size_t uncompressedBytes)
Convenience wrapper to retrieve the compressed size of buffer when compressed.
OnMaskIterator< NodeMask > OnIterator
Definition: NodeMasks.h:350
void resetBackground(const ValueType &, const ValueType &newBackground)
GLint GLenum GLint x
Definition: glcorearb.h:408
GLuint GLfloat * val
Definition: glcorearb.h:1607
Ordered collection of uniquely-named attribute arrays.
Definition: AttributeSet.h:62
#define VMASK_
std::map< std::string, hboost::any > AuxDataMap
Definition: io.h:113
A Paging wrapper to std::ostream that is responsible for writing from a given output stream at interv...
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:107
void replaceAttributeSet(AttributeSet *attributeSet, bool allowMismatchingDescriptors=false)
Replace the underlying attribute set with the given attributeSet.
OPENVDB_API SharedPtr< StreamMetadata > getStreamMetadataPtr(std::ios_base &)
Return a shared pointer to an object that stores metadata (file format, compression scheme...
Integer wrapper, required to distinguish PointIndexGrid and PointDataGrid from Int32Grid and Int64Gri...
Definition: Types.h:183
#define SIZE
Definition: simple.C:40
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition: Platform.h:130
virtual bool compact()=0
Compact the existing array to become uniform if all values are identical.
void writeBuffers(std::ostream &os, bool toHalf=false) const
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition: Types.h:518
void setValuesOff()
Mark all voxels as inactive but don't change their values.
Definition: LeafNode.h:488
Container for metadata describing how to unserialize grids from and/or serialize grids to a stream (w...
Definition: io.h:56
Index64 iterCount(const IterT &iter)
Count up the number of times the iterator can iterate.
typename BaseLeaf::template ValueIter< MaskOffIterator, const PointDataLeafNode, const ValueType, ValueOff > ValueOffCIter
void clearAttributes(const bool updateValueMask=true)
Clear the attribute set.
bool hasSameTopology(const LeafNode< OtherType, OtherLog2Dim > *other) const
Return true if the given node (which may have a different ValueType than this node) has the same acti...
Definition: LeafNode.h:1502
T zeroVal()
Return the value of type T that corresponds to zero.
Definition: Math.h:86
Index64 groupPointCount(const Name &groupName) const
Compute the point count in a specific group for the leaf.
PointDataLeafNode(const tools::PointIndexLeafNode< OtherValueType, Log2Dim > &other)
void addLeafAndCache(PointDataLeafNode *, AccessorT &)
Attribute Array storage templated on type and compression codec.
const AttributeSet & attributeSet() const
Retrieve the attribute set.
Similiar to ValueConverter, but allows for tree configuration conversion to a PointDataTree. ValueConverter<PointDataIndex32> cannot be used as a PointDataLeafNode is not a specialization of LeafNode.
typename NodeMaskType::DenseIterator MaskDenseIterator
void setValueOnlyAndCache(const Coord &, const ValueType &, AccessorT &)
AttributeArray & attributeArray(const size_t pos)
Read-write attribute array reference from index {.
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:135
IndexIter< ValueOnCIter, FilterT > beginIndexOn(const FilterT &filter) const
void setValueOn(const Coord &, const ValueType &)
Index64 pointCount() const
Compute the total point count for the leaf.
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
void resetDescriptor(const Descriptor::Ptr &replacement)
Replace the descriptor with a new one The new Descriptor must exactly match the old one...
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glcorearb.h:1296