OpenVDB 11.0.0
Loading...
Searching...
No Matches
AttributeArray.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: MPL-2.0
3
4/// @file points/AttributeArray.h
5///
6/// @authors Dan Bailey, Mihai Alden, Nick Avramoussis, James Bird, Khang Ngo
7///
8/// @brief Attribute Array storage templated on type and compression codec.
9
10#ifndef OPENVDB_POINTS_ATTRIBUTE_ARRAY_HAS_BEEN_INCLUDED
11#define OPENVDB_POINTS_ATTRIBUTE_ARRAY_HAS_BEEN_INCLUDED
12
13#include <openvdb/Types.h>
15#include <openvdb/util/Name.h>
17#include <openvdb/io/io.h> // MappedFile
18#include <openvdb/io/Compression.h> // COMPRESS_BLOSC
19
20#include "IndexIterator.h"
21#include "StreamCompression.h"
22
23#include <tbb/spin_mutex.h>
24#include <atomic>
25
26#include <memory>
27#include <mutex>
28#include <string>
29#include <type_traits>
30
31
32class TestAttributeArray;
33
34namespace openvdb {
36namespace OPENVDB_VERSION_NAME {
37
38
39using NamePair = std::pair<Name, Name>;
40
41namespace points {
42
43
44////////////////////////////////////////
45
46// Utility methods
47
48template <typename IntegerT, typename FloatT>
49inline IntegerT
51{
52 static_assert(std::is_unsigned<IntegerT>::value, "IntegerT must be unsigned");
53 if (FloatT(0.0) > s) return std::numeric_limits<IntegerT>::min();
54 else if (FloatT(1.0) <= s) return std::numeric_limits<IntegerT>::max();
55 return IntegerT(s * FloatT(std::numeric_limits<IntegerT>::max()));
56}
57
58
59template <typename FloatT, typename IntegerT>
60inline FloatT
62{
63 static_assert(std::is_unsigned<IntegerT>::value, "IntegerT must be unsigned");
64 return FloatT(s) / FloatT((std::numeric_limits<IntegerT>::max()));
65}
66
67template <typename IntegerVectorT, typename FloatT>
68inline IntegerVectorT
70{
71 return IntegerVectorT(
72 floatingPointToFixedPoint<typename IntegerVectorT::ValueType>(v.x()),
73 floatingPointToFixedPoint<typename IntegerVectorT::ValueType>(v.y()),
74 floatingPointToFixedPoint<typename IntegerVectorT::ValueType>(v.z()));
75}
76
77template <typename FloatVectorT, typename IntegerT>
78inline FloatVectorT
80{
81 return FloatVectorT(
82 fixedPointToFloatingPoint<typename FloatVectorT::ValueType>(v.x()),
83 fixedPointToFloatingPoint<typename FloatVectorT::ValueType>(v.y()),
84 fixedPointToFloatingPoint<typename FloatVectorT::ValueType>(v.z()));
85}
86
87
88////////////////////////////////////////
89
90
91/// Base class for storing attribute data
93{
94protected:
95 struct AccessorBase;
96 template <typename T> struct Accessor;
97
98 using AccessorBasePtr = std::shared_ptr<AccessorBase>;
99
100public:
101 enum Flag {
102 TRANSIENT = 0x1, /// by default not written to disk
103 HIDDEN = 0x2, /// hidden from UIs or iterators
104 CONSTANTSTRIDE = 0x8, /// stride size does not vary in the array
105 STREAMING = 0x10, /// streaming mode collapses attributes when first accessed
106 PARTIALREAD = 0x20 /// data has been partially read (compressed bytes is used)
107 };
108
110 WRITESTRIDED = 0x1, /// data is marked as strided when written
111 WRITEUNIFORM = 0x2, /// data is marked as uniform when written
112 WRITEMEMCOMPRESS = 0x4, /// data is marked as compressed in-memory when written
113 /// (deprecated flag as of ABI=6)
114 WRITEPAGED = 0x8 /// data is written out in pages
115 };
116
117 // Scoped Lock wrapper class that locks the AttributeArray registry mutex
119 {
120 tbb::spin_mutex::scoped_lock lock;
121 public:
123 }; // class ScopedRegistryLock
124
125 using Ptr = std::shared_ptr<AttributeArray>;
126 using ConstPtr = std::shared_ptr<const AttributeArray>;
127
128 using FactoryMethod = Ptr (*)(Index, Index, bool, const Metadata*);
129
130 template <typename ValueType, typename CodecType> friend class AttributeHandle;
131
132 AttributeArray(): mPageHandle() { mOutOfCore = 0; }
134 {
135 // if this AttributeArray has been partially read, zero the compressed bytes,
136 // so the page handle won't attempt to clean up invalid memory
137 if (mFlags & PARTIALREAD) mCompressedBytes = 0;
138 }
143
144 /// Return a copy of this attribute.
145 virtual AttributeArray::Ptr copy() const = 0;
146
147#if OPENVDB_ABI_VERSION_NUMBER < 10
148 /// Return a copy of this attribute.
149#ifndef _MSC_VER
150 OPENVDB_DEPRECATED_MESSAGE("In-memory compression no longer supported, use AttributeArray::copy() instead")
151#endif
152 virtual AttributeArray::Ptr copyUncompressed() const = 0;
153#endif
154
155 /// Return the number of elements in this array.
156 /// @note This does not count each data element in a strided array
157 virtual Index size() const = 0;
158
159 /// Return the stride of this array.
160 /// @note a return value of zero means a non-constant stride
161 virtual Index stride() const = 0;
162
163 /// Return the total number of data elements in this array.
164 /// @note This counts each data element in a strided array
165 virtual Index dataSize() const = 0;
166
167 /// Return the name of the value type of a single element in this array (e.g., "float" or "vec3d").
168 virtual Name valueType() const = 0;
169
170 /// Return the name of the codec used by this array (e.g., "trnc" or "fxpt").
171 virtual Name codecType() const = 0;
172
173 /// Return the size in bytes of the value type of a single element in this array.
174 /// (e.g. "float" -> 4 bytes, "vec3d" -> 24 bytes").
175 virtual Index valueTypeSize() const = 0;
176
177 /// Return the size in bytes of the storage type of a single element of this array.
178 /// @note If the Codec is a NullCodec, valueSize() == storageSize()
179 virtual Index storageTypeSize() const = 0;
180
181 /// Return @c true if the value type is floating point
182 virtual bool valueTypeIsFloatingPoint() const = 0;
183
184 /// Return @c true if the value type is a class (ie vector, matrix or quaternion return true)
185 virtual bool valueTypeIsClass() const = 0;
186
187 /// Return @c true if the value type is a vector
188 virtual bool valueTypeIsVector() const = 0;
189
190 /// Return @c true if the value type is a quaternion
191 virtual bool valueTypeIsQuaternion() const = 0;
192
193 /// Return @c true if the value type is a matrix
194 virtual bool valueTypeIsMatrix() const = 0;
195
196 /// Return the number of bytes of memory used by this attribute.
197 virtual size_t memUsage() const = 0;
198
199#if OPENVDB_ABI_VERSION_NUMBER >= 10
200 /// Return the number of bytes of memory used by this attribute array once it
201 /// has been deserialized (this may be different to memUsage() if delay-loading
202 /// is in use). Note that this method does NOT consider the fact that a
203 /// uniform attribute could be expanded and only deals with delay-loading.
204 virtual size_t memUsageIfLoaded() const = 0;
205#endif
206
207 /// Create a new attribute array of the given (registered) type, length and stride.
208 /// @details If @a lock is non-null, the AttributeArray registry mutex
209 /// has already been locked
210 static Ptr create(const NamePair& type, Index length, Index stride = 1,
211 bool constantStride = true,
212 const Metadata* metadata = nullptr,
213 const ScopedRegistryLock* lock = nullptr);
214
215 /// Return @c true if the given attribute type name is registered.
216 static bool isRegistered(const NamePair& type, const ScopedRegistryLock* lock = nullptr);
217 /// Clear the attribute type registry.
218 static void clearRegistry(const ScopedRegistryLock* lock = nullptr);
219
220 /// Return the name of this attribute's type.
221 virtual const NamePair& type() const = 0;
222 /// Return @c true if this attribute is of the same type as the template parameter.
223 template<typename AttributeArrayType>
224 bool isType() const { return this->type() == AttributeArrayType::attributeType(); }
225
226 /// Return @c true if this attribute has a value type the same as the template parameter
227 template<typename ValueType>
228 bool hasValueType() const { return this->type().first == typeNameAsString<ValueType>(); }
229
230#if OPENVDB_ABI_VERSION_NUMBER < 10
231 /// @brief Set value at given index @a n from @a sourceIndex of another @a sourceArray.
232 // Windows does not allow base classes to be easily deprecated.
233#ifndef _MSC_VER
234 OPENVDB_DEPRECATED_MESSAGE("Use copyValues() with source-target index pairs")
235#endif
236 virtual void set(const Index n, const AttributeArray& sourceArray, const Index sourceIndex) = 0;
237#endif
238
239 /// @brief Copy values into this array from a source array to a target array
240 /// as referenced by an iterator.
241 /// @details Iterators must adhere to the ForwardIterator interface described
242 /// in the example below:
243 /// @code
244 /// struct MyIterator
245 /// {
246 /// // returns true if the iterator is referencing valid copying indices
247 /// operator bool() const;
248 /// // increments the iterator
249 /// MyIterator& operator++();
250 /// // returns the source index that the iterator is referencing for copying
251 /// Index sourceIndex() const;
252 /// // returns the target index that the iterator is referencing for copying
253 /// Index targetIndex() const;
254 /// };
255 /// @endcode
256 /// @note It is assumed that the strided storage sizes match, the arrays are both in-core,
257 /// and both value types are floating-point or both integer.
258 /// @note It is possible to use this method to write to a uniform target array
259 /// if the iterator does not have non-zero target indices.
260 /// @note This method is not thread-safe, it must be guaranteed that this array is not
261 /// concurrently modified by another thread and that the source array is also not modified.
262 template<typename IterT>
263 void copyValuesUnsafe(const AttributeArray& sourceArray, const IterT& iter);
264 /// @brief Like copyValuesUnsafe(), but if @a compact is true, attempt to collapse this array.
265 /// @note This method is not thread-safe, it must be guaranteed that this array is not
266 /// concurrently modified by another thread and that the source array is also not modified.
267 template<typename IterT>
268 void copyValues(const AttributeArray& sourceArray, const IterT& iter, bool compact = true);
269
270 /// Return @c true if this array is stored as a single uniform value.
271 virtual bool isUniform() const = 0;
272 /// @brief If this array is uniform, replace it with an array of length size().
273 /// @param fill if true, assign the uniform value to each element of the array.
274 virtual void expand(bool fill = true) = 0;
275 /// Replace the existing array with a uniform zero value.
276 virtual void collapse() = 0;
277 /// Compact the existing array to become uniform if all values are identical
278 virtual bool compact() = 0;
279
280#if OPENVDB_ABI_VERSION_NUMBER < 10
281 // Windows does not allow base classes to be deprecated
282#ifndef _MSC_VER
283 OPENVDB_DEPRECATED_MESSAGE("Previously this compressed the attribute array, now it does nothing")
284#endif
285 virtual bool compress() = 0;
286 // Windows does not allow base classes to be deprecated
287#ifndef _MSC_VER
288 OPENVDB_DEPRECATED_MESSAGE("Previously this uncompressed the attribute array, now it does nothing")
289#endif
290 virtual bool decompress() = 0;
291#endif
292
293 /// @brief Specify whether this attribute should be hidden (e.g., from UI or iterators).
294 /// @details This is useful if the attribute is used for blind data or as scratch space
295 /// for a calculation.
296 /// @note Attributes are not hidden by default.
297 void setHidden(bool state);
298 /// Return @c true if this attribute is hidden (e.g., from UI or iterators).
299 bool isHidden() const { return bool(mFlags & HIDDEN); }
300
301 /// @brief Specify whether this attribute should only exist in memory
302 /// and not be serialized during stream output.
303 /// @note Attributes are not transient by default.
304 void setTransient(bool state);
305 /// Return @c true if this attribute is not serialized during stream output.
306 bool isTransient() const { return bool(mFlags & TRANSIENT); }
307
308 /// @brief Specify whether this attribute is to be streamed off disk, in which
309 /// case, the attributes are collapsed after being first loaded leaving them
310 /// in a destroyed state.
311 /// @note This operation is not thread-safe.
312 void setStreaming(bool state);
313 /// Return @c true if this attribute is in streaming mode.
314 bool isStreaming() const { return bool(mFlags & STREAMING); }
315
316 /// Return @c true if this attribute has a constant stride
317 bool hasConstantStride() const { return bool(mFlags & CONSTANTSTRIDE); }
318
319 /// @brief Retrieve the attribute array flags
320 uint8_t flags() const { return mFlags; }
321
322 /// Read attribute metadata and buffers from a stream.
323 virtual void read(std::istream&) = 0;
324 /// Write attribute metadata and buffers to a stream.
325 /// @param outputTransient if true, write out transient attributes
326 virtual void write(std::ostream&, bool outputTransient) const = 0;
327 /// Write attribute metadata and buffers to a stream, don't write transient attributes.
328 virtual void write(std::ostream&) const = 0;
329
330 /// Read attribute metadata from a stream.
331 virtual void readMetadata(std::istream&) = 0;
332 /// Write attribute metadata to a stream.
333 /// @param outputTransient if true, write out transient attributes
334 /// @param paged if true, data is written out in pages
335 virtual void writeMetadata(std::ostream&, bool outputTransient, bool paged) const = 0;
336
337 /// Read attribute buffers from a stream.
338 virtual void readBuffers(std::istream&) = 0;
339 /// Write attribute buffers to a stream.
340 /// @param outputTransient if true, write out transient attributes
341 virtual void writeBuffers(std::ostream&, bool outputTransient) const = 0;
342
343 /// Read attribute buffers from a paged stream.
345 /// Write attribute buffers to a paged stream.
346 /// @param outputTransient if true, write out transient attributes
347 virtual void writePagedBuffers(compression::PagedOutputStream&, bool outputTransient) const = 0;
348
349 /// Ensures all data is in-core
350 virtual void loadData() const = 0;
351
352 /// Return @c true if all data has been loaded
353 virtual bool isDataLoaded() const = 0;
354
355 /// Check the compressed bytes and flags. If they are equal, perform a deeper
356 /// comparison check necessary on the inherited types (TypedAttributeArray)
357 /// Requires non operator implementation due to inheritance
358 bool operator==(const AttributeArray& other) const;
359 bool operator!=(const AttributeArray& other) const { return !this->operator==(other); }
360
361#if OPENVDB_ABI_VERSION_NUMBER >= 9
362 /// Indirect virtual function to retrieve the data buffer cast to a char byte array
363 const char* constDataAsByteArray() const { return this->dataAsByteArray(); }
364#endif
365
366private:
367 friend class ::TestAttributeArray;
368
369 /// Virtual function used by the comparison operator to perform
370 /// comparisons on inherited types
371 virtual bool isEqual(const AttributeArray& other) const = 0;
372
373 /// Virtual function to retrieve the data buffer cast to a char byte array
374 virtual char* dataAsByteArray() = 0;
375 virtual const char* dataAsByteArray() const = 0;
376
377 /// Private implementation for copyValues/copyValuesUnsafe
378 template <typename IterT>
379 void doCopyValues(const AttributeArray& sourceArray, const IterT& iter,
380 bool rangeChecking = true);
381
382protected:
383 AttributeArray(const AttributeArray& rhs, const tbb::spin_mutex::scoped_lock&);
384
385 /// @brief Specify whether this attribute has a constant stride or not.
386 void setConstantStride(bool state);
387
388 /// Obtain an Accessor that stores getter and setter functors.
389 virtual AccessorBasePtr getAccessor() const = 0;
390
391 /// Register a attribute type along with a factory function.
392 static void registerType(const NamePair& type, FactoryMethod,
393 const ScopedRegistryLock* lock = nullptr);
394 /// Remove a attribute type from the registry.
395 static void unregisterType(const NamePair& type,
396 const ScopedRegistryLock* lock = nullptr);
397
398 bool mIsUniform = true;
399 mutable tbb::spin_mutex mMutex;
400 uint8_t mFlags = 0;
401 uint8_t mUsePagedRead = 0;
402 std::atomic<Index32> mOutOfCore; // interpreted as bool
403 /// used for out-of-core, paged reading
404 union {
407 };
408}; // class AttributeArray
409
410
411////////////////////////////////////////
412
413
414/// Accessor base class for AttributeArray storage where type is not available
415struct AttributeArray::AccessorBase { virtual ~AccessorBase() = default; };
416
417/// Templated Accessor stores typed function pointers used in binding
418/// AttributeHandles
419template <typename T>
421{
422 using GetterPtr = T (*)(const AttributeArray* array, const Index n);
423 using SetterPtr = void (*)(AttributeArray* array, const Index n, const T& value);
424 using ValuePtr = void (*)(AttributeArray* array, const T& value);
425
426 Accessor(GetterPtr getter, SetterPtr setter, ValuePtr collapser, ValuePtr filler) :
427 mGetter(getter), mSetter(setter), mCollapser(collapser), mFiller(filler) { }
428
433}; // struct AttributeArray::Accessor
434
435
436////////////////////////////////////////
437
438
439namespace attribute_traits
440{
441 template <typename T> struct TruncateTrait { };
442 template <> struct TruncateTrait<float> { using Type = math::half; };
443 template <> struct TruncateTrait<int> { using Type = short; };
444
445 template <typename T> struct TruncateTrait<math::Vec3<T>> {
447 };
448
449 template <bool OneByte, typename T> struct UIntTypeTrait { };
450 template<typename T> struct UIntTypeTrait</*OneByte=*/true, T> { using Type = uint8_t; };
451 template<typename T> struct UIntTypeTrait</*OneByte=*/false, T> { using Type = uint16_t; };
452 template<typename T> struct UIntTypeTrait</*OneByte=*/true, math::Vec3<T>> {
454 };
455 template<typename T> struct UIntTypeTrait</*OneByte=*/false, math::Vec3<T>> {
457 };
458}
459
460
461////////////////////////////////////////
462
463
464// Attribute codec schemes
465
466struct UnknownCodec { };
467
468
470{
471 template <typename T>
472 struct Storage { using Type = T; };
473
474 template<typename ValueType> static void decode(const ValueType&, ValueType&);
475 template<typename ValueType> static void encode(const ValueType&, ValueType&);
476 static const char* name() { return "null"; }
477};
478
479
481{
482 template <typename T>
484
485 template<typename StorageType, typename ValueType> static void decode(const StorageType&, ValueType&);
486 template<typename StorageType, typename ValueType> static void encode(const ValueType&, StorageType&);
487 static const char* name() { return "trnc"; }
488};
489
490
491// Fixed-point codec range for voxel-space positions [-0.5,0.5]
493{
494 static const char* name() { return "fxpt"; }
495 template <typename ValueType> static ValueType encode(const ValueType& value) { return value + ValueType(0.5); }
496 template <typename ValueType> static ValueType decode(const ValueType& value) { return value - ValueType(0.5); }
497};
498
499
500// Fixed-point codec range for unsigned values in the unit range [0.0,1.0]
502{
503 static const char* name() { return "ufxpt"; }
504 template <typename ValueType> static ValueType encode(const ValueType& value) { return value; }
505 template <typename ValueType> static ValueType decode(const ValueType& value) { return value; }
506};
507
508
509template <bool OneByte, typename Range=PositionRange>
511{
512 template <typename T>
514
515 template<typename StorageType, typename ValueType> static void decode(const StorageType&, ValueType&);
516 template<typename StorageType, typename ValueType> static void encode(const ValueType&, StorageType&);
517
518 static const char* name() {
519 static const std::string Name = std::string(Range::name()) + (OneByte ? "8" : "16");
520 return Name.c_str();
521 }
522};
523
524
526{
527 using StorageType = uint16_t;
528
529 template <typename T>
530 struct Storage { using Type = StorageType; };
531
532 template<typename T> static void decode(const StorageType&, math::Vec3<T>&);
533 template<typename T> static void encode(const math::Vec3<T>&, StorageType&);
534 static const char* name() { return "uvec"; }
535};
536
537
538////////////////////////////////////////
539
540
541/// Typed class for storing attribute data
542
543template<typename ValueType_, typename Codec_ = NullCodec>
545{
546public:
547 using Ptr = std::shared_ptr<TypedAttributeArray>;
548 using ConstPtr = std::shared_ptr<const TypedAttributeArray>;
549
550 using ValueType = ValueType_;
551 using Codec = Codec_;
552 using StorageType = typename Codec::template Storage<ValueType>::Type;
553
554 //////////
555
556 /// Default constructor, always constructs a uniform attribute.
557 explicit TypedAttributeArray(Index n = 1, Index strideOrTotalSize = 1, bool constantStride = true,
558 const ValueType& uniformValue = zeroVal<ValueType>());
559
560 /// Deep copy constructor.
561 /// @note This method is thread-safe (as of ABI=7) for concurrently reading from the
562 /// source attribute array while being deep-copied. Specifically, this means that the
563 /// attribute array being deep-copied can be out-of-core and safely loaded in one thread
564 /// while being copied using this copy-constructor in another thread.
565 /// It is not thread-safe for write.
567#if OPENVDB_ABI_VERSION_NUMBER < 10
568 /// Deep copy constructor.
569 OPENVDB_DEPRECATED_MESSAGE("Use copy-constructor without unused bool parameter")
570 TypedAttributeArray(const TypedAttributeArray&, bool /*unused*/);
571#endif
572
573 /// Deep copy assignment operator.
574 /// @note this operator is thread-safe.
575 TypedAttributeArray& operator=(const TypedAttributeArray&);
576 /// Move constructor disabled.
578 /// Move assignment operator disabled.
580
581 ~TypedAttributeArray() override { this->deallocate(); }
582
583 /// Return a copy of this attribute.
584 /// @note This method is thread-safe.
585 AttributeArray::Ptr copy() const override;
586
587#if OPENVDB_ABI_VERSION_NUMBER < 10
588 /// Return a copy of this attribute.
589 /// @note This method is thread-safe.
590 OPENVDB_DEPRECATED_MESSAGE("In-memory compression no longer supported, use AttributeArray::copy() instead")
591 AttributeArray::Ptr copyUncompressed() const override;
592#endif
593
594 /// Return a new attribute array of the given length @a n and @a stride with uniform value zero.
595 static Ptr create(Index n, Index strideOrTotalSize = 1, bool constantStride = true,
596 const Metadata* metadata = nullptr);
597
598 /// Cast an AttributeArray to TypedAttributeArray<T>
599 static TypedAttributeArray& cast(AttributeArray& attributeArray);
600
601 /// Cast an AttributeArray to TypedAttributeArray<T>
602 static const TypedAttributeArray& cast(const AttributeArray& attributeArray);
603
604 /// Return the name of this attribute's type (includes codec)
605 static const NamePair& attributeType();
606 /// Return the name of this attribute's type.
607 const NamePair& type() const override { return attributeType(); }
608
609 /// Return @c true if this attribute type is registered.
610 static bool isRegistered();
611 /// Register this attribute type along with a factory function.
612 static void registerType();
613 /// Remove this attribute type from the registry.
614 static void unregisterType();
615
616 /// Return the number of elements in this array.
617 Index size() const override { return mSize; }
618
619 /// Return the stride of this array.
620 /// @note A return value of zero means a variable stride
621 Index stride() const override { return hasConstantStride() ? mStrideOrTotalSize : 0; }
622
623 /// Return the size of the data in this array.
624 Index dataSize() const override {
625 return hasConstantStride() ? mSize * mStrideOrTotalSize : mStrideOrTotalSize;
626 }
627
628 /// Return the name of the value type of a single element in this array (e.g., "float" or "vec3d").
629 Name valueType() const override { return typeNameAsString<ValueType>(); }
630
631 /// Return the name of the codec used by this array (e.g., "trnc" or "fxpt").
632 Name codecType() const override { return Codec::name(); }
633
634 /// Return the size in bytes of the value type of a single element in this array.
635 Index valueTypeSize() const override { return sizeof(ValueType); }
636
637 /// Return the size in bytes of the storage type of a single element of this array.
638 /// @note If the Codec is a NullCodec, valueSize() == storageSize()
639 Index storageTypeSize() const override { return sizeof(StorageType); }
640
641 /// Return @c true if the value type is floating point
642 bool valueTypeIsFloatingPoint() const override;
643
644 /// Return @c true if the value type is a class (ie vector, matrix or quaternion return true)
645 bool valueTypeIsClass() const override;
646
647 /// Return @c true if the value type is a vector
648 bool valueTypeIsVector() const override;
649
650 /// Return @c true if the value type is a quaternion
651 bool valueTypeIsQuaternion() const override;
652
653 /// Return @c true if the value type is a matrix
654 bool valueTypeIsMatrix() const override;
655
656 /// Return the number of bytes of memory used by this attribute.
657 size_t memUsage() const override;
658
659#if OPENVDB_ABI_VERSION_NUMBER >= 10
660 /// Return the number of bytes of memory used by this attribute array once it
661 /// has been deserialized (this may be different to memUsage() if delay-loading
662 /// is in use). Note that this method does NOT consider the fact that a
663 /// uniform attribute could be expanded and only deals with delay-loading.
664 size_t memUsageIfLoaded() const override;
665#endif
666
667 /// Return the value at index @a n (assumes in-core)
668 ValueType getUnsafe(Index n) const;
669 /// Return the value at index @a n
670 ValueType get(Index n) const;
671 /// Return the @a value at index @a n (assumes in-core)
672 template<typename T> void getUnsafe(Index n, T& value) const;
673 /// Return the @a value at index @a n
674 template<typename T> void get(Index n, T& value) const;
675
676 /// Non-member equivalent to getUnsafe() that static_casts array to this TypedAttributeArray
677 /// (assumes in-core)
678 static ValueType getUnsafe(const AttributeArray* array, const Index n);
679
680 /// Set @a value at the given index @a n (assumes in-core)
681 void setUnsafe(Index n, const ValueType& value);
682 /// Set @a value at the given index @a n
683 void set(Index n, const ValueType& value);
684 /// Set @a value at the given index @a n (assumes in-core)
685 template<typename T> void setUnsafe(Index n, const T& value);
686 /// Set @a value at the given index @a n
687 template<typename T> void set(Index n, const T& value);
688
689 /// Non-member equivalent to setUnsafe() that static_casts array to this TypedAttributeArray
690 /// (assumes in-core)
691 static void setUnsafe(AttributeArray* array, const Index n, const ValueType& value);
692
693#if OPENVDB_ABI_VERSION_NUMBER < 10
694 /// Set value at given index @a n from @a sourceIndex of another @a sourceArray
695 OPENVDB_DEPRECATED_MESSAGE("Use copyValues() with source-target index pairs")
696 void set(const Index n, const AttributeArray& sourceArray, const Index sourceIndex) override;
697#endif
698
699 /// Return @c true if this array is stored as a single uniform value.
700 bool isUniform() const override { return mIsUniform; }
701 /// @brief Replace the single value storage with an array of length size().
702 /// @note Non-uniform attributes are unchanged.
703 /// @param fill toggle to initialize the array elements with the pre-expanded value.
704 void expand(bool fill = true) override;
705 /// Replace the existing array with a uniform zero value.
706 void collapse() override;
707 /// Compact the existing array to become uniform if all values are identical
708 bool compact() override;
709
710 /// Replace the existing array with the given uniform value.
711 void collapse(const ValueType& uniformValue);
712 /// @brief Fill the existing array with the given value.
713 /// @note Identical to collapse() except a non-uniform array will not become uniform.
714 void fill(const ValueType& value);
715
716 /// Non-member equivalent to collapse() that static_casts array to this TypedAttributeArray
717 static void collapse(AttributeArray* array, const ValueType& value);
718 /// Non-member equivalent to fill() that static_casts array to this TypedAttributeArray
719 static void fill(AttributeArray* array, const ValueType& value);
720
721#if OPENVDB_ABI_VERSION_NUMBER < 10
722 /// Compress the attribute array.
723 OPENVDB_DEPRECATED_MESSAGE("Previously this compressed the attribute array, now it does nothing")
724 bool compress() override;
725 /// Uncompress the attribute array.
726 OPENVDB_DEPRECATED_MESSAGE("Previously this uncompressed the attribute array, now it does nothing")
727 bool decompress() override;
728#endif
729
730 /// Read attribute data from a stream.
731 void read(std::istream&) override;
732 /// Write attribute data to a stream.
733 /// @param os the output stream
734 /// @param outputTransient if true, write out transient attributes
735 void write(std::ostream& os, bool outputTransient) const override;
736 /// Write attribute data to a stream, don't write transient attributes.
737 void write(std::ostream&) const override;
738
739 /// Read attribute metadata from a stream.
740 void readMetadata(std::istream&) override;
741 /// Write attribute metadata to a stream.
742 /// @param os the output stream
743 /// @param outputTransient if true, write out transient attributes
744 /// @param paged if true, data is written out in pages
745 void writeMetadata(std::ostream& os, bool outputTransient, bool paged) const override;
746
747 /// Read attribute buffers from a stream.
748 void readBuffers(std::istream&) override;
749 /// Write attribute buffers to a stream.
750 /// @param os the output stream
751 /// @param outputTransient if true, write out transient attributes
752 void writeBuffers(std::ostream& os, bool outputTransient) const override;
753
754 /// Read attribute buffers from a paged stream.
755 void readPagedBuffers(compression::PagedInputStream&) override;
756 /// Write attribute buffers to a paged stream.
757 /// @param os the output stream
758 /// @param outputTransient if true, write out transient attributes
759 void writePagedBuffers(compression::PagedOutputStream& os, bool outputTransient) const override;
760
761 /// Return @c true if this buffer's values have not yet been read from disk.
762 inline bool isOutOfCore() const;
763
764 /// Ensures all data is in-core
765 void loadData() const override;
766
767 /// Return @c true if all data has been loaded
768 bool isDataLoaded() const override;
769
770 /// Return the raw data buffer
771 inline const StorageType* constData() const { return this->data(); }
772
773protected:
774 AccessorBasePtr getAccessor() const override;
775
776 /// Return the raw data buffer
777 inline StorageType* data() { assert(validData()); return mData.get(); }
778 inline const StorageType* data() const { assert(validData()); return mData.get(); }
779
780 /// Verify that data is not out-of-core or in a partially-read state
781 inline bool validData() const { return !(isOutOfCore() || (flags() & PARTIALREAD)); }
782
783private:
784 friend class ::TestAttributeArray;
785
786 TypedAttributeArray(const TypedAttributeArray&, const tbb::spin_mutex::scoped_lock&);
787
788 /// Load data from memory-mapped file.
789 inline void doLoad() const;
790 /// Load data from memory-mapped file (unsafe as this function is not protected by a mutex).
791#if OPENVDB_ABI_VERSION_NUMBER >= 10
792 inline void doLoadUnsafe() const;
793#else
794 /// @param compression parameter no longer used
795 inline void doLoadUnsafe(const bool compression = true) const;
796 /// Compress in-core data assuming mutex is locked
797 inline bool compressUnsafe();
798#endif
799
800 /// Toggle out-of-core state
801 inline void setOutOfCore(const bool);
802
803 /// Compare the this data to another attribute array. Used by the base class comparison operator
804 bool isEqual(const AttributeArray& other) const override;
805
806 /// Virtual function to retrieve the data buffer from the derived class cast to a char byte array
807 char* dataAsByteArray() override;
808 const char* dataAsByteArray() const override;
809
810 size_t arrayMemUsage() const;
811 void allocate();
812 void deallocate();
813
814 /// Helper function for use with registerType()
815 static AttributeArray::Ptr factory(Index n, Index strideOrTotalSize, bool constantStride,
816 const Metadata* metadata) {
817 return TypedAttributeArray::create(n, strideOrTotalSize, constantStride, metadata);
818 }
819
820 std::unique_ptr<StorageType[]> mData;
821 Index mSize;
822 Index mStrideOrTotalSize;
823}; // class TypedAttributeArray
824
825
826////////////////////////////////////////
827
828
829/// AttributeHandles provide access to specific TypedAttributeArray methods without needing
830/// to know the compression codec, however these methods also incur the cost of a function pointer
831template <typename ValueType, typename CodecType = UnknownCodec>
833{
834public:
836 using Ptr = std::shared_ptr<Handle>;
837 using UniquePtr = std::unique_ptr<Handle>;
838
839protected:
840 using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
841 using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
842 using ValuePtr = void (*)(AttributeArray* array, const ValueType& value);
843
844public:
845 static Ptr create(const AttributeArray& array, const bool collapseOnDestruction = true);
846
847 AttributeHandle(const AttributeArray& array, const bool collapseOnDestruction = true);
848
851
853
854 Index stride() const { return mStrideOrTotalSize; }
855 Index size() const { return mSize; }
856
857 bool isUniform() const;
858 bool hasConstantStride() const;
859
860 ValueType get(Index n, Index m = 0) const;
861
862 const AttributeArray& array() const;
863
864protected:
865 Index index(Index n, Index m) const;
866
868
873
874private:
875 friend class ::TestAttributeArray;
876
877 template <bool IsUnknownCodec>
878 typename std::enable_if<IsUnknownCodec, bool>::type compatibleType() const;
879
880 template <bool IsUnknownCodec>
881 typename std::enable_if<!IsUnknownCodec, bool>::type compatibleType() const;
882
883 template <bool IsUnknownCodec>
884 typename std::enable_if<IsUnknownCodec, ValueType>::type get(Index index) const;
885
886 template <bool IsUnknownCodec>
887 typename std::enable_if<!IsUnknownCodec, ValueType>::type get(Index index) const;
888
889 // local copy of AttributeArray (to preserve compression)
890 AttributeArray::Ptr mLocalArray;
891
892 Index mStrideOrTotalSize;
893 Index mSize;
894 bool mCollapseOnDestruction;
895}; // class AttributeHandle
896
897
898////////////////////////////////////////
899
900
901/// Write-able version of AttributeHandle
902template <typename ValueType, typename CodecType = UnknownCodec>
903class AttributeWriteHandle : public AttributeHandle<ValueType, CodecType>
904{
905public:
907 using Ptr = std::shared_ptr<Handle>;
908 using ScopedPtr = std::unique_ptr<Handle>;
909
910 static Ptr create(AttributeArray& array, const bool expand = true);
911
912 AttributeWriteHandle(AttributeArray& array, const bool expand = true);
913
914 virtual ~AttributeWriteHandle() = default;
915
916 /// @brief If this array is uniform, replace it with an array of length size().
917 /// @param fill if true, assign the uniform value to each element of the array.
918 void expand(bool fill = true);
919
920 /// Replace the existing array with a uniform value (zero if none provided).
921 void collapse();
922 void collapse(const ValueType& uniformValue);
923
924 /// Compact the existing array to become uniform if all values are identical
925 bool compact();
926
927 /// @brief Fill the existing array with the given value.
928 /// @note Identical to collapse() except a non-uniform array will not become uniform.
929 void fill(const ValueType& value);
930
931 void set(Index n, const ValueType& value);
932 void set(Index n, Index m, const ValueType& value);
933
935
936private:
937 friend class ::TestAttributeArray;
938
939 template <bool IsUnknownCodec>
940 typename std::enable_if<IsUnknownCodec, void>::type set(Index index, const ValueType& value) const;
941
942 template <bool IsUnknownCodec>
943 typename std::enable_if<!IsUnknownCodec, void>::type set(Index index, const ValueType& value) const;
944}; // class AttributeWriteHandle
945
946
947////////////////////////////////////////
948
949
950// Attribute codec implementation
951
952
953template<typename ValueType>
954inline void
955NullCodec::decode(const ValueType& data, ValueType& val)
956{
957 val = data;
958}
959
960
961template<typename ValueType>
962inline void
963NullCodec::encode(const ValueType& val, ValueType& data)
964{
965 data = val;
966}
967
968
969template<typename StorageType, typename ValueType>
970inline void
971TruncateCodec::decode(const StorageType& data, ValueType& val)
972{
973 val = static_cast<ValueType>(data);
974}
975
976
977template<typename StorageType, typename ValueType>
978inline void
979TruncateCodec::encode(const ValueType& val, StorageType& data)
980{
981 data = static_cast<StorageType>(val);
982}
983
984
985template <bool OneByte, typename Range>
986template<typename StorageType, typename ValueType>
987inline void
988FixedPointCodec<OneByte, Range>::decode(const StorageType& data, ValueType& val)
989{
990 val = fixedPointToFloatingPoint<ValueType>(data);
991
992 // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
993
994 val = Range::template decode<ValueType>(val);
995}
996
997
998template <bool OneByte, typename Range>
999template<typename StorageType, typename ValueType>
1000inline void
1001FixedPointCodec<OneByte, Range>::encode(const ValueType& val, StorageType& data)
1002{
1003 // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
1004
1005 const ValueType newVal = Range::template encode<ValueType>(val);
1006
1007 data = floatingPointToFixedPoint<StorageType>(newVal);
1008}
1009
1010
1011template<typename T>
1012inline void
1013UnitVecCodec::decode(const StorageType& data, math::Vec3<T>& val)
1014{
1015 val = math::QuantizedUnitVec::unpack(data);
1016}
1017
1018
1019template<typename T>
1020inline void
1021UnitVecCodec::encode(const math::Vec3<T>& val, StorageType& data)
1022{
1023 data = math::QuantizedUnitVec::pack(val);
1024}
1025
1026
1027////////////////////////////////////////
1028
1029// AttributeArray implementation
1030
1031template <typename IterT>
1032void AttributeArray::doCopyValues(const AttributeArray& sourceArray, const IterT& iter,
1033 bool rangeChecking/*=true*/)
1034{
1035 // ensure both arrays have float-float or integer-integer value types
1036 assert(sourceArray.valueTypeIsFloatingPoint() == this->valueTypeIsFloatingPoint());
1037 // ensure both arrays have been loaded from disk (if delay-loaded)
1038 assert(sourceArray.isDataLoaded() && this->isDataLoaded());
1039 // ensure storage size * stride matches on both arrays
1040 assert(this->storageTypeSize()*this->stride() ==
1041 sourceArray.storageTypeSize()*sourceArray.stride());
1042
1043 const size_t bytes(sourceArray.storageTypeSize()*sourceArray.stride());
1044 const char* const sourceBuffer = sourceArray.dataAsByteArray();
1045 char* const targetBuffer = this->dataAsByteArray();
1046 assert(sourceBuffer && targetBuffer);
1047
1048 if (rangeChecking && this->isUniform()) {
1049 OPENVDB_THROW(IndexError, "Cannot copy array data as target array is uniform.");
1050 }
1051
1052 const bool sourceIsUniform = sourceArray.isUniform();
1053
1054 const Index sourceDataSize = rangeChecking ? sourceArray.dataSize() : 0;
1055 const Index targetDataSize = rangeChecking ? this->dataSize() : 0;
1056
1057 for (IterT it(iter); it; ++it) {
1058 const Index sourceIndex = sourceIsUniform ? 0 : it.sourceIndex();
1059 const Index targetIndex = it.targetIndex();
1060
1061 if (rangeChecking) {
1062 if (sourceIndex >= sourceDataSize) {
1064 "Cannot copy array data as source index exceeds size of source array.");
1065 }
1066 if (targetIndex >= targetDataSize) {
1068 "Cannot copy array data as target index exceeds size of target array.");
1069 }
1070 } else {
1071 // range-checking asserts
1072 assert(sourceIndex < sourceArray.dataSize());
1073 assert(targetIndex < this->dataSize());
1074 if (this->isUniform()) assert(targetIndex == Index(0));
1075 }
1076
1077 const size_t targetOffset(targetIndex * bytes);
1078 const size_t sourceOffset(sourceIndex * bytes);
1079
1080 std::memcpy(targetBuffer + targetOffset, sourceBuffer + sourceOffset, bytes);
1081 }
1082}
1083
1084template <typename IterT>
1085void AttributeArray::copyValuesUnsafe(const AttributeArray& sourceArray, const IterT& iter)
1086{
1087 this->doCopyValues(sourceArray, iter, /*range-checking=*/false);
1088}
1089
1090template <typename IterT>
1091void AttributeArray::copyValues(const AttributeArray& sourceArray, const IterT& iter,
1092 bool compact/* = true*/)
1093{
1094 const Index bytes = sourceArray.storageTypeSize();
1095 if (bytes != this->storageTypeSize()) {
1096 OPENVDB_THROW(TypeError, "Cannot copy array data due to mis-match in storage type sizes.");
1097 }
1098
1099 // ensure both arrays have been loaded from disk
1100 sourceArray.loadData();
1101 this->loadData();
1102
1103 // if the target array is uniform, expand it first
1104 this->expand();
1105
1106 // TODO: Acquire mutex locks for source and target arrays to ensure that
1107 // value copying is always thread-safe. Note that the unsafe method will be
1108 // faster, but can only be used if neither the source or target arrays are
1109 // modified during copying. Note that this will require a new private
1110 // virtual method with ABI=7 to access the mutex from the derived class.
1111
1112 this->doCopyValues(sourceArray, iter, true);
1113
1114 // attempt to compact target array
1115 if (compact) {
1116 this->compact();
1117 }
1118}
1119
1120
1121////////////////////////////////////////
1122
1123// TypedAttributeArray implementation
1124
1125
1126template<typename ValueType_, typename Codec_>
1128 Index n, Index strideOrTotalSize, bool constantStride, const ValueType& uniformValue)
1129 : AttributeArray()
1130 , mData(new StorageType[1])
1131 , mSize(n)
1132 , mStrideOrTotalSize(strideOrTotalSize)
1133{
1134 if (constantStride) {
1135 this->setConstantStride(true);
1136 if (strideOrTotalSize == 0) {
1137 OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a constant stride requires that " \
1138 "stride to be at least one.")
1139 }
1140 }
1141 else {
1142 this->setConstantStride(false);
1143 if (mStrideOrTotalSize < n) {
1144 OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a non-constant stride must have " \
1145 "a total size of at least the number of elements in the array.")
1146 }
1147 }
1148 mSize = std::max(Index(1), mSize);
1149 mStrideOrTotalSize = std::max(Index(1), mStrideOrTotalSize);
1150 Codec::encode(uniformValue, this->data()[0]);
1151}
1152
1153
1154template<typename ValueType_, typename Codec_>
1156 : TypedAttributeArray(rhs, tbb::spin_mutex::scoped_lock(rhs.mMutex))
1157{
1158}
1159
1160
1161template<typename ValueType_, typename Codec_>
1163 const tbb::spin_mutex::scoped_lock& lock)
1164 : AttributeArray(rhs, lock)
1165 , mSize(rhs.mSize)
1166 , mStrideOrTotalSize(rhs.mStrideOrTotalSize)
1167{
1168 if (this->validData()) {
1169 this->allocate();
1170 std::memcpy(static_cast<void*>(this->data()), rhs.data(), this->arrayMemUsage());
1171 }
1172}
1173
1174
1175template<typename ValueType_, typename Codec_>
1176TypedAttributeArray<ValueType_, Codec_>&
1178{
1179 if (&rhs != this) {
1180 // lock both the source and target arrays to ensure thread-safety
1181 tbb::spin_mutex::scoped_lock lock(mMutex);
1182 tbb::spin_mutex::scoped_lock rhsLock(rhs.mMutex);
1183
1184 this->deallocate();
1185
1186 mFlags = rhs.mFlags;
1187 mUsePagedRead = rhs.mUsePagedRead;
1188 mSize = rhs.mSize;
1189 mStrideOrTotalSize = rhs.mStrideOrTotalSize;
1190 mIsUniform = rhs.mIsUniform;
1191
1192 if (this->validData()) {
1193 this->allocate();
1194 std::memcpy(static_cast<void*>(this->data()), rhs.data(), this->arrayMemUsage());
1195 }
1196 }
1197
1198 return *this;
1199}
1200
1201
1202template<typename ValueType_, typename Codec_>
1203inline const NamePair&
1205{
1206 static NamePair sTypeName = []() {
1207 return NamePair(typeNameAsString<ValueType>(), Codec::name());
1208 }();
1209 return sTypeName;
1210}
1211
1212
1213template<typename ValueType_, typename Codec_>
1214inline bool
1219
1220
1221template<typename ValueType_, typename Codec_>
1222inline void
1227
1228
1229template<typename ValueType_, typename Codec_>
1230inline void
1235
1236
1237template<typename ValueType_, typename Codec_>
1240 const Metadata* metadata)
1241{
1242 const TypedMetadata<ValueType>* typedMetadata = metadata ?
1243 dynamic_cast<const TypedMetadata<ValueType>*>(metadata) : nullptr;
1244
1245 return Ptr(new TypedAttributeArray(n, stride, constantStride,
1246 typedMetadata ? typedMetadata->value() : zeroVal<ValueType>()));
1247}
1248
1249template<typename ValueType_, typename Codec_>
1252{
1253 if (!attributeArray.isType<TypedAttributeArray>()) {
1254 OPENVDB_THROW(TypeError, "Invalid Attribute Type");
1255 }
1256 return static_cast<TypedAttributeArray&>(attributeArray);
1257}
1258
1259template<typename ValueType_, typename Codec_>
1262{
1263 if (!attributeArray.isType<TypedAttributeArray>()) {
1264 OPENVDB_THROW(TypeError, "Invalid Attribute Type");
1265 }
1266 return static_cast<const TypedAttributeArray&>(attributeArray);
1267}
1268
1269template<typename ValueType_, typename Codec_>
1275
1276
1277#if OPENVDB_ABI_VERSION_NUMBER < 10
1278template<typename ValueType_, typename Codec_>
1281{
1282 return this->copy();
1283}
1284#endif
1285
1286template<typename ValueType_, typename Codec_>
1287size_t
1288TypedAttributeArray<ValueType_, Codec_>::arrayMemUsage() const
1289{
1290 if (this->isOutOfCore()) return 0;
1291
1292 return (mIsUniform ? 1 : this->dataSize()) * sizeof(StorageType);
1293}
1294
1295
1296template<typename ValueType_, typename Codec_>
1297void
1298TypedAttributeArray<ValueType_, Codec_>::allocate()
1299{
1300 assert(!mData);
1301 if (mIsUniform) {
1302 mData.reset(new StorageType[1]);
1303 }
1304 else {
1305 const size_t size(this->dataSize());
1306 assert(size > 0);
1307 mData.reset(new StorageType[size]);
1308 }
1309}
1310
1311
1312template<typename ValueType_, typename Codec_>
1313void
1314TypedAttributeArray<ValueType_, Codec_>::deallocate()
1315{
1316 // detach from file if delay-loaded
1317 if (this->isOutOfCore()) {
1318 this->setOutOfCore(false);
1319 this->mPageHandle.reset();
1320 }
1321 if (mData) mData.reset();
1322}
1323
1324
1325template<typename ValueType_, typename Codec_>
1326bool
1328{
1329 // TODO: Update to use Traits that correctly handle matrices and quaternions.
1330
1331 if (std::is_same<ValueType, Quats>::value ||
1332 std::is_same<ValueType, Quatd>::value ||
1333 std::is_same<ValueType, Mat3s>::value ||
1334 std::is_same<ValueType, Mat3d>::value ||
1335 std::is_same<ValueType, Mat4s>::value ||
1336 std::is_same<ValueType, Mat4d>::value) return true;
1337
1338 using ElementT = typename VecTraits<ValueType>::ElementType;
1339
1340 // half is not defined as float point as expected, so explicitly handle it
1341 return std::is_floating_point<ElementT>::value || std::is_same<math::half, ElementT>::value;
1342}
1343
1344
1345template<typename ValueType_, typename Codec_>
1346bool
1348{
1349 // half is not defined as a non-class type as expected, so explicitly exclude it
1350 return std::is_class<ValueType>::value && !std::is_same<math::half, ValueType>::value;
1351}
1352
1353
1354template<typename ValueType_, typename Codec_>
1355bool
1360
1361
1362template<typename ValueType_, typename Codec_>
1363bool
1365{
1366 // TODO: improve performance by making this a compile-time check using type traits
1367 return !this->valueType().compare(0, 4, "quat");
1368}
1369
1370
1371template<typename ValueType_, typename Codec_>
1372bool
1374{
1375 // TODO: improve performance by making this a compile-time check using type traits
1376 return !this->valueType().compare(0, 3, "mat");
1377}
1378
1379
1380template<typename ValueType_, typename Codec_>
1381size_t
1383{
1384 return sizeof(*this) + (bool(mData) ? this->arrayMemUsage() : 0);
1385}
1386
1387#if OPENVDB_ABI_VERSION_NUMBER >= 10
1388template<typename ValueType_, typename Codec_>
1389size_t
1391{
1392 return sizeof(*this) + (mIsUniform ? 1 : this->dataSize()) * sizeof(StorageType);
1393}
1394#endif
1395
1396
1397template<typename ValueType_, typename Codec_>
1400{
1401 assert(n < this->dataSize());
1402
1403 ValueType val;
1404 Codec::decode(/*in=*/this->data()[mIsUniform ? 0 : n], /*out=*/val);
1405 return val;
1406}
1407
1408
1409template<typename ValueType_, typename Codec_>
1412{
1413 if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1414 if (this->isOutOfCore()) this->doLoad();
1415
1416 return this->getUnsafe(n);
1417}
1418
1419
1420template<typename ValueType_, typename Codec_>
1421template<typename T>
1422void
1424{
1425 val = static_cast<T>(this->getUnsafe(n));
1426}
1427
1428
1429template<typename ValueType_, typename Codec_>
1430template<typename T>
1431void
1433{
1434 val = static_cast<T>(this->get(n));
1435}
1436
1437
1438template<typename ValueType_, typename Codec_>
1441{
1442 return static_cast<const TypedAttributeArray<ValueType, Codec>*>(array)->getUnsafe(n);
1443}
1444
1445
1446template<typename ValueType_, typename Codec_>
1447void
1449{
1450 assert(n < this->dataSize());
1451 assert(!this->isOutOfCore());
1452 assert(!this->isUniform());
1453
1454 // this unsafe method assumes the data is not uniform, however if it is, this redirects the index
1455 // to zero, which is marginally less efficient but ensures not writing to an illegal address
1456
1457 Codec::encode(/*in=*/val, /*out=*/this->data()[mIsUniform ? 0 : n]);
1458}
1459
1460
1461template<typename ValueType_, typename Codec_>
1462void
1464{
1465 if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1466 if (this->isOutOfCore()) this->doLoad();
1467 if (this->isUniform()) this->expand();
1468
1469 this->setUnsafe(n, val);
1470}
1471
1472
1473template<typename ValueType_, typename Codec_>
1474template<typename T>
1475void
1477{
1478 this->setUnsafe(n, static_cast<ValueType>(val));
1479}
1480
1481
1482template<typename ValueType_, typename Codec_>
1483template<typename T>
1484void
1486{
1487 this->set(n, static_cast<ValueType>(val));
1488}
1489
1490
1491template<typename ValueType_, typename Codec_>
1492void
1494{
1495 static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->setUnsafe(n, value);
1496}
1497
1498
1499#if OPENVDB_ABI_VERSION_NUMBER < 10
1500template<typename ValueType_, typename Codec_>
1501void
1502TypedAttributeArray<ValueType_, Codec_>::set(Index n, const AttributeArray& sourceArray, const Index sourceIndex)
1503{
1504 const TypedAttributeArray& sourceTypedArray = static_cast<const TypedAttributeArray&>(sourceArray);
1505
1506 ValueType sourceValue;
1507 sourceTypedArray.get(sourceIndex, sourceValue);
1508
1509 this->set(n, sourceValue);
1510}
1511#endif
1512
1513
1514template<typename ValueType_, typename Codec_>
1515void
1517{
1518 if (!mIsUniform) return;
1519
1520 const StorageType val = this->data()[0];
1521
1522 {
1523 tbb::spin_mutex::scoped_lock lock(mMutex);
1524 this->deallocate();
1525 mIsUniform = false;
1526 this->allocate();
1527 }
1528
1529 if (fill) {
1530 for (Index i = 0; i < this->dataSize(); ++i) this->data()[i] = val;
1531 }
1532}
1533
1534
1535template<typename ValueType_, typename Codec_>
1536bool
1538{
1539 if (mIsUniform) return true;
1540
1541 // compaction is not possible if any values are different
1542 const ValueType_ val = this->get(0);
1543 for (Index i = 1; i < this->dataSize(); i++) {
1544 if (!math::isExactlyEqual(this->get(i), val)) return false;
1545 }
1546
1547 this->collapse(this->get(0));
1548 return true;
1549}
1550
1551
1552template<typename ValueType_, typename Codec_>
1553void
1555{
1556 this->collapse(zeroVal<ValueType>());
1557}
1558
1559
1560template<typename ValueType_, typename Codec_>
1561void
1563{
1564 if (!mIsUniform) {
1565 tbb::spin_mutex::scoped_lock lock(mMutex);
1566 this->deallocate();
1567 mIsUniform = true;
1568 this->allocate();
1569 }
1570 Codec::encode(uniformValue, this->data()[0]);
1571}
1572
1573
1574template<typename ValueType_, typename Codec_>
1575void
1577{
1578 static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->collapse(value);
1579}
1580
1581
1582template<typename ValueType_, typename Codec_>
1583void
1585{
1586 if (this->isOutOfCore()) {
1587 tbb::spin_mutex::scoped_lock lock(mMutex);
1588 this->deallocate();
1589 this->allocate();
1590 }
1591
1592 const Index size = mIsUniform ? 1 : this->dataSize();
1593 for (Index i = 0; i < size; ++i) {
1594 Codec::encode(value, this->data()[i]);
1595 }
1596}
1597
1598
1599template<typename ValueType_, typename Codec_>
1600void
1602{
1603 static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->fill(value);
1604}
1605
1606
1607#if OPENVDB_ABI_VERSION_NUMBER < 10
1608template<typename ValueType_, typename Codec_>
1609inline bool
1611{
1612 return false;
1613}
1614
1615
1616template<typename ValueType_, typename Codec_>
1617inline bool
1619{
1620 return false;
1621}
1622
1623
1624template<typename ValueType_, typename Codec_>
1625inline bool
1626TypedAttributeArray<ValueType_, Codec_>::decompress()
1627{
1628 return false;
1629}
1630#endif
1631
1632
1633template<typename ValueType_, typename Codec_>
1634bool
1636{
1637 return mOutOfCore;
1638}
1639
1640
1641template<typename ValueType_, typename Codec_>
1642void
1644{
1645 mOutOfCore = b;
1646}
1647
1648
1649template<typename ValueType_, typename Codec_>
1650void
1651TypedAttributeArray<ValueType_, Codec_>::doLoad() const
1652{
1653 if (!(this->isOutOfCore())) return;
1654
1655 TypedAttributeArray<ValueType_, Codec_>* self =
1656 const_cast<TypedAttributeArray<ValueType_, Codec_>*>(this);
1657
1658 // This lock will be contended at most once, after which this buffer
1659 // will no longer be out-of-core.
1660 tbb::spin_mutex::scoped_lock lock(self->mMutex);
1661 this->doLoadUnsafe();
1662}
1663
1664
1665template<typename ValueType_, typename Codec_>
1666void
1668{
1669 this->doLoad();
1670}
1671
1672
1673template<typename ValueType_, typename Codec_>
1674bool
1676{
1677 return !this->isOutOfCore();
1678}
1679
1680
1681template<typename ValueType_, typename Codec_>
1682void
1684{
1685 this->readMetadata(is);
1686 this->readBuffers(is);
1687}
1688
1689
1690template<typename ValueType_, typename Codec_>
1691void
1693{
1694 // read data
1695
1696 Index64 bytes = Index64(0);
1697 is.read(reinterpret_cast<char*>(&bytes), sizeof(Index64));
1698 bytes = bytes - /*flags*/sizeof(Int16) - /*size*/sizeof(Index);
1699
1700 uint8_t flags = uint8_t(0);
1701 is.read(reinterpret_cast<char*>(&flags), sizeof(uint8_t));
1702 mFlags = flags;
1703
1704 uint8_t serializationFlags = uint8_t(0);
1705 is.read(reinterpret_cast<char*>(&serializationFlags), sizeof(uint8_t));
1706
1707 Index size = Index(0);
1708 is.read(reinterpret_cast<char*>(&size), sizeof(Index));
1709 mSize = size;
1710
1711 // warn if an unknown flag has been set
1712 if (mFlags >= 0x20) {
1713 OPENVDB_LOG_WARN("Unknown attribute flags for VDB file format.");
1714 }
1715 // error if an unknown serialization flag has been set,
1716 // as this will adjust the layout of the data and corrupt the ability to read
1717 if (serializationFlags >= 0x10) {
1718 OPENVDB_THROW(IoError, "Unknown attribute serialization flags for VDB file format.");
1719 }
1720
1721 // set uniform, compressed and page read state
1722
1723 mIsUniform = serializationFlags & WRITEUNIFORM;
1724 mUsePagedRead = serializationFlags & WRITEPAGED;
1725 mCompressedBytes = bytes;
1726 mFlags |= PARTIALREAD; // mark data as having been partially read
1727
1728 // read strided value (set to 1 if array is not strided)
1729
1730 if (serializationFlags & WRITESTRIDED) {
1731 Index stride = Index(0);
1732 is.read(reinterpret_cast<char*>(&stride), sizeof(Index));
1733 mStrideOrTotalSize = stride;
1734 }
1735 else {
1736 mStrideOrTotalSize = 1;
1737 }
1738}
1739
1740
1741template<typename ValueType_, typename Codec_>
1742void
1744{
1745 if (mUsePagedRead) {
1746 // use readBuffers(PagedInputStream&) for paged buffers
1747 OPENVDB_THROW(IoError, "Cannot read paged AttributeArray buffers.");
1748 }
1749
1750 tbb::spin_mutex::scoped_lock lock(mMutex);
1751
1752 this->deallocate();
1753
1754 uint8_t bloscCompressed(0);
1755 if (!mIsUniform) is.read(reinterpret_cast<char*>(&bloscCompressed), sizeof(uint8_t));
1756
1757 assert(mFlags & PARTIALREAD);
1758 std::unique_ptr<char[]> buffer(new char[mCompressedBytes]);
1759 is.read(buffer.get(), mCompressedBytes);
1760 mCompressedBytes = 0;
1761 mFlags = static_cast<uint8_t>(mFlags & ~PARTIALREAD); // mark data read as having completed
1762
1763 // compressed on-disk
1764
1765 if (bloscCompressed == uint8_t(1)) {
1766
1767 // decompress buffer
1768
1769 const size_t inBytes = this->dataSize() * sizeof(StorageType);
1770 std::unique_ptr<char[]> newBuffer = compression::bloscDecompress(buffer.get(), inBytes);
1771 if (newBuffer) buffer.reset(newBuffer.release());
1772 }
1773
1774 // set data to buffer
1775
1776 mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1777}
1778
1779
1780template<typename ValueType_, typename Codec_>
1781void
1783{
1784 if (!mUsePagedRead) {
1785 if (!is.sizeOnly()) this->readBuffers(is.getInputStream());
1786 return;
1787 }
1788
1789#ifdef OPENVDB_USE_DELAYED_LOADING
1790 // If this array is being read from a memory-mapped file, delay loading of its data
1791 // until the data is actually accessed.
1792 io::MappedFile::Ptr mappedFile = io::getMappedFilePtr(is.getInputStream());
1793 const bool delayLoad = (mappedFile.get() != nullptr);
1794#endif
1795
1796 if (is.sizeOnly())
1797 {
1798 size_t compressedBytes(mCompressedBytes);
1799 mCompressedBytes = 0; // if not set to zero, mPageHandle will attempt to destroy invalid memory
1800 mFlags = static_cast<uint8_t>(mFlags & ~PARTIALREAD); // mark data read as having completed
1801 assert(!mPageHandle);
1802 mPageHandle = is.createHandle(compressedBytes);
1803 return;
1804 }
1805
1806 assert(mPageHandle);
1807
1808 tbb::spin_mutex::scoped_lock lock(mMutex);
1809
1810 this->deallocate();
1811
1812#ifdef OPENVDB_USE_DELAYED_LOADING
1813 this->setOutOfCore(delayLoad);
1814 is.read(mPageHandle, std::streamsize(mPageHandle->size()), delayLoad);
1815#else
1816 is.read(mPageHandle, std::streamsize(mPageHandle->size()), false);
1817#endif // OPENVDB_USE_DELAYED_LOADING
1818
1819#ifdef OPENVDB_USE_DELAYED_LOADING
1820 if (!delayLoad) {
1821#endif
1822 std::unique_ptr<char[]> buffer = mPageHandle->read();
1823 mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1824 mPageHandle.reset();
1825#ifdef OPENVDB_USE_DELAYED_LOADING
1826 }
1827#endif
1828
1829 // clear page state
1830
1831 mUsePagedRead = 0;
1832}
1833
1834
1835template<typename ValueType_, typename Codec_>
1836void
1838{
1839 this->write(os, /*outputTransient=*/false);
1840}
1841
1842
1843template<typename ValueType_, typename Codec_>
1844void
1845TypedAttributeArray<ValueType_, Codec_>::write(std::ostream& os, bool outputTransient) const
1846{
1847 this->writeMetadata(os, outputTransient, /*paged=*/false);
1848 this->writeBuffers(os, outputTransient);
1849}
1850
1851
1852template<typename ValueType_, typename Codec_>
1853void
1854TypedAttributeArray<ValueType_, Codec_>::writeMetadata(std::ostream& os, bool outputTransient, bool paged) const
1855{
1856 if (!outputTransient && this->isTransient()) return;
1857
1858 if (mFlags & PARTIALREAD) {
1859 OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1860 }
1861
1862 uint8_t flags(mFlags);
1863 uint8_t serializationFlags(0);
1864 Index size(mSize);
1865 Index strideOrTotalSize(mStrideOrTotalSize);
1866 bool strideOfOne(this->stride() == 1);
1867
1868 bool bloscCompression = io::getDataCompression(os) & io::COMPRESS_BLOSC;
1869
1870 // any compressed data needs to be loaded if out-of-core
1871 if (bloscCompression) this->doLoad();
1872
1873 size_t compressedBytes = 0;
1874
1875 if (!strideOfOne)
1876 {
1877 serializationFlags |= WRITESTRIDED;
1878 }
1879
1880 if (mIsUniform)
1881 {
1882 serializationFlags |= WRITEUNIFORM;
1883 if (bloscCompression && paged) serializationFlags |= WRITEPAGED;
1884 }
1885 else if (bloscCompression)
1886 {
1887 if (paged) serializationFlags |= WRITEPAGED;
1888 else {
1889 const char* charBuffer = reinterpret_cast<const char*>(this->data());
1890 const size_t inBytes = this->arrayMemUsage();
1891 compressedBytes = compression::bloscCompressedSize(charBuffer, inBytes);
1892 }
1893 }
1894
1895 Index64 bytes = /*flags*/ sizeof(Int16) + /*size*/ sizeof(Index);
1896
1897 bytes += (compressedBytes > 0) ? compressedBytes : this->arrayMemUsage();
1898
1899 // write data
1900
1901 os.write(reinterpret_cast<const char*>(&bytes), sizeof(Index64));
1902 os.write(reinterpret_cast<const char*>(&flags), sizeof(uint8_t));
1903 os.write(reinterpret_cast<const char*>(&serializationFlags), sizeof(uint8_t));
1904 os.write(reinterpret_cast<const char*>(&size), sizeof(Index));
1905
1906 // write strided
1907 if (!strideOfOne) os.write(reinterpret_cast<const char*>(&strideOrTotalSize), sizeof(Index));
1908}
1909
1910
1911template<typename ValueType_, typename Codec_>
1912void
1913TypedAttributeArray<ValueType_, Codec_>::writeBuffers(std::ostream& os, bool outputTransient) const
1914{
1915 if (!outputTransient && this->isTransient()) return;
1916
1917 if (mFlags & PARTIALREAD) {
1918 OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1919 }
1920
1921 this->doLoad();
1922
1923 if (this->isUniform()) {
1924 os.write(reinterpret_cast<const char*>(this->data()), sizeof(StorageType));
1925 }
1927 {
1928 std::unique_ptr<char[]> compressedBuffer;
1929 size_t compressedBytes = 0;
1930 const char* charBuffer = reinterpret_cast<const char*>(this->data());
1931 const size_t inBytes = this->arrayMemUsage();
1932 compressedBuffer = compression::bloscCompress(charBuffer, inBytes, compressedBytes);
1933 if (compressedBuffer) {
1934 uint8_t bloscCompressed(1);
1935 os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1936 os.write(reinterpret_cast<const char*>(compressedBuffer.get()), compressedBytes);
1937 }
1938 else {
1939 uint8_t bloscCompressed(0);
1940 os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1941 os.write(reinterpret_cast<const char*>(this->data()), inBytes);
1942 }
1943 }
1944 else
1945 {
1946 uint8_t bloscCompressed(0);
1947 os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1948 os.write(reinterpret_cast<const char*>(this->data()), this->arrayMemUsage());
1949 }
1950}
1951
1952
1953template<typename ValueType_, typename Codec_>
1954void
1956{
1957 if (!outputTransient && this->isTransient()) return;
1958
1959 // paged compression only available when Blosc is enabled
1960 bool bloscCompression = io::getDataCompression(os.getOutputStream()) & io::COMPRESS_BLOSC;
1961 if (!bloscCompression) {
1962 if (!os.sizeOnly()) this->writeBuffers(os.getOutputStream(), outputTransient);
1963 return;
1964 }
1965
1966 if (mFlags & PARTIALREAD) {
1967 OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1968 }
1969
1970 this->doLoad();
1971
1972 os.write(reinterpret_cast<const char*>(this->data()), this->arrayMemUsage());
1973}
1974
1975
1976template<typename ValueType_, typename Codec_>
1977void
1978#if OPENVDB_ABI_VERSION_NUMBER >= 10
1980#else
1981TypedAttributeArray<ValueType_, Codec_>::doLoadUnsafe(const bool /*compression*/) const
1982#endif
1983{
1984 if (!(this->isOutOfCore())) return;
1985
1986 // this function expects the mutex to already be locked
1987
1988 auto* self = const_cast<TypedAttributeArray<ValueType_, Codec_>*>(this);
1989
1990 assert(self->mPageHandle);
1991 assert(!(self->mFlags & PARTIALREAD));
1992
1993 std::unique_ptr<char[]> buffer = self->mPageHandle->read();
1994
1995 self->mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1996
1997 self->mPageHandle.reset();
1998
1999 // clear all write and out-of-core flags
2000
2001 self->mOutOfCore = false;
2002}
2003
2004
2005template<typename ValueType_, typename Codec_>
2018
2019
2020template<typename ValueType_, typename Codec_>
2021bool
2023{
2024 const TypedAttributeArray<ValueType_, Codec_>* const otherT = dynamic_cast<const TypedAttributeArray<ValueType_, Codec_>* >(&other);
2025 if(!otherT) return false;
2026 if(this->mSize != otherT->mSize ||
2027 this->mStrideOrTotalSize != otherT->mStrideOrTotalSize ||
2028 this->mIsUniform != otherT->mIsUniform ||
2029 this->attributeType() != this->attributeType()) return false;
2030
2031 this->doLoad();
2032 otherT->doLoad();
2033
2034 const StorageType *target = this->data(), *source = otherT->data();
2035 if (!target && !source) return true;
2036 if (!target || !source) return false;
2037 Index n = this->mIsUniform ? 1 : mSize;
2038 while (n && math::isExactlyEqual(*target++, *source++)) --n;
2039 return n == 0;
2040}
2041
2042
2043template<typename ValueType_, typename Codec_>
2044char*
2045TypedAttributeArray<ValueType_, Codec_>::dataAsByteArray()
2046{
2047 return reinterpret_cast<char*>(this->data());
2048}
2049
2050
2051template<typename ValueType_, typename Codec_>
2052const char*
2053TypedAttributeArray<ValueType_, Codec_>::dataAsByteArray() const
2054{
2055 return reinterpret_cast<const char*>(this->data());
2056}
2057
2058
2059////////////////////////////////////////
2060
2061
2062/// Accessor to call unsafe get and set methods based on templated Codec and Value
2063template <typename CodecType, typename ValueType>
2065{
2066 using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
2067 using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
2068
2069 /// Getter that calls to TypedAttributeArray::getUnsafe()
2070 /// @note Functor argument is provided but not required for the generic case
2071 static ValueType get(GetterPtr /*functor*/, const AttributeArray* array, const Index n) {
2073 }
2074
2075 /// Getter that calls to TypedAttributeArray::setUnsafe()
2076 /// @note Functor argument is provided but not required for the generic case
2077 static void set(SetterPtr /*functor*/, AttributeArray* array, const Index n, const ValueType& value) {
2079 }
2080};
2081
2082
2083/// Partial specialization when Codec is not known at compile-time to use the supplied functor instead
2084template <typename ValueType>
2085struct AccessorEval<UnknownCodec, ValueType>
2086{
2087 using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
2088 using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
2089
2090 /// Getter that calls the supplied functor
2091 static ValueType get(GetterPtr functor, const AttributeArray* array, const Index n) {
2092 return (*functor)(array, n);
2093 }
2094
2095 /// Setter that calls the supplied functor
2096 static void set(SetterPtr functor, AttributeArray* array, const Index n, const ValueType& value) {
2097 (*functor)(array, n, value);
2098 }
2099};
2100
2101
2102////////////////////////////////////////
2103
2104// AttributeHandle implementation
2105
2106template <typename ValueType, typename CodecType>
2108AttributeHandle<ValueType, CodecType>::create(const AttributeArray& array, const bool collapseOnDestruction)
2109{
2111 new AttributeHandle<ValueType, CodecType>(array, collapseOnDestruction));
2112}
2113
2114template <typename ValueType, typename CodecType>
2115AttributeHandle<ValueType, CodecType>::AttributeHandle(const AttributeArray& array, const bool collapseOnDestruction)
2116 : mArray(&array)
2117 , mStrideOrTotalSize(array.hasConstantStride() ? array.stride() : 1)
2118 , mSize(array.hasConstantStride() ? array.size() : array.dataSize())
2119 , mCollapseOnDestruction(collapseOnDestruction && array.isStreaming())
2120{
2121 if (!this->compatibleType<std::is_same<CodecType, UnknownCodec>::value>()) {
2122 OPENVDB_THROW(TypeError, "Cannot bind handle due to incompatible type of AttributeArray.");
2123 }
2124
2125 // load data if delay-loaded
2126
2127 mArray->loadData();
2128
2129 // bind getter and setter methods
2130
2132 assert(accessor);
2133
2135
2137 mSetter = typedAccessor->mSetter;
2138 mCollapser = typedAccessor->mCollapser;
2139 mFiller = typedAccessor->mFiller;
2140}
2141
2142template <typename ValueType, typename CodecType>
2144{
2145 // if enabled, attribute is collapsed on destruction of the handle to save memory
2146 if (mCollapseOnDestruction) const_cast<AttributeArray*>(this->mArray)->collapse();
2147}
2148
2149template <typename ValueType, typename CodecType>
2150template <bool IsUnknownCodec>
2151typename std::enable_if<IsUnknownCodec, bool>::type
2153{
2154 // if codec is unknown, just check the value type
2155
2156 return mArray->hasValueType<ValueType>();
2157}
2158
2159template <typename ValueType, typename CodecType>
2160template <bool IsUnknownCodec>
2161typename std::enable_if<!IsUnknownCodec, bool>::type
2162AttributeHandle<ValueType, CodecType>::compatibleType() const
2163{
2164 // if the codec is known, check the value type and codec
2165
2166 return mArray->isType<TypedAttributeArray<ValueType, CodecType>>();
2167}
2168
2169template <typename ValueType, typename CodecType>
2171{
2172 assert(mArray);
2173 return *mArray;
2174}
2175
2176template <typename ValueType, typename CodecType>
2178{
2179 Index index = n * mStrideOrTotalSize + m;
2180 assert(index < (mSize * mStrideOrTotalSize));
2181 return index;
2182}
2183
2184template <typename ValueType, typename CodecType>
2186{
2187 return this->get<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, m));
2188}
2189
2190template <typename ValueType, typename CodecType>
2191template <bool IsUnknownCodec>
2192typename std::enable_if<IsUnknownCodec, ValueType>::type
2194{
2195 // if the codec is unknown, use the getter functor
2196
2197 return (*mGetter)(mArray, index);
2198}
2199
2200template <typename ValueType, typename CodecType>
2201template <bool IsUnknownCodec>
2202typename std::enable_if<!IsUnknownCodec, ValueType>::type
2204{
2205 // if the codec is known, call the method on the attribute array directly
2206
2208}
2209
2210template <typename ValueType, typename CodecType>
2212{
2213 return mArray->isUniform();
2214}
2215
2216template <typename ValueType, typename CodecType>
2218{
2219 return mArray->hasConstantStride();
2220}
2221
2222////////////////////////////////////////
2223
2224// AttributeWriteHandle implementation
2225
2226template <typename ValueType, typename CodecType>
2233
2234template <typename ValueType, typename CodecType>
2236 : AttributeHandle<ValueType, CodecType>(array, /*collapseOnDestruction=*/false)
2237{
2238 if (expand) array.expand();
2239}
2240
2241template <typename ValueType, typename CodecType>
2243{
2244 this->set<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, 0), value);
2245}
2246
2247template <typename ValueType, typename CodecType>
2249{
2250 this->set<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, m), value);
2251}
2252
2253template <typename ValueType, typename CodecType>
2255{
2256 const_cast<AttributeArray*>(this->mArray)->expand(fill);
2257}
2258
2259template <typename ValueType, typename CodecType>
2261{
2262 const_cast<AttributeArray*>(this->mArray)->collapse();
2263}
2264
2265template <typename ValueType, typename CodecType>
2267{
2268 return const_cast<AttributeArray*>(this->mArray)->compact();
2269}
2270
2271template <typename ValueType, typename CodecType>
2273{
2274 this->mCollapser(const_cast<AttributeArray*>(this->mArray), uniformValue);
2275}
2276
2277template <typename ValueType, typename CodecType>
2279{
2280 this->mFiller(const_cast<AttributeArray*>(this->mArray), value);
2281}
2282
2283template <typename ValueType, typename CodecType>
2284template <bool IsUnknownCodec>
2285typename std::enable_if<IsUnknownCodec, void>::type
2286AttributeWriteHandle<ValueType, CodecType>::set(Index index, const ValueType& value) const
2287{
2288 // if the codec is unknown, use the setter functor
2289
2290 (*this->mSetter)(const_cast<AttributeArray*>(this->mArray), index, value);
2291}
2292
2293template <typename ValueType, typename CodecType>
2294template <bool IsUnknownCodec>
2295typename std::enable_if<!IsUnknownCodec, void>::type
2296AttributeWriteHandle<ValueType, CodecType>::set(Index index, const ValueType& value) const
2297{
2298 // if the codec is known, call the method on the attribute array directly
2299
2300 TypedAttributeArray<ValueType, CodecType>::setUnsafe(const_cast<AttributeArray*>(this->mArray), index, value);
2301}
2302
2303template <typename ValueType, typename CodecType>
2305{
2306 assert(this->mArray);
2307 return *const_cast<AttributeArray*>(this->mArray);
2308}
2309
2310
2311} // namespace points
2312} // namespace OPENVDB_VERSION_NAME
2313} // namespace openvdb
2314
2315#endif // OPENVDB_POINTS_ATTRIBUTE_ARRAY_HAS_BEEN_INCLUDED
Index Iterators.
#define OPENVDB_API
Definition Platform.h:274
#define OPENVDB_DEPRECATED_MESSAGE(msg)
Definition Platform.h:148
Convenience wrappers to using Blosc and reading and writing of Paged data.
Definition Exceptions.h:57
Definition Exceptions.h:58
Base class for storing metadata information in a grid.
Definition Metadata.h:24
Definition Exceptions.h:64
Templated metadata class to hold specific types.
Definition Metadata.h:122
T & value()
Return this metadata's value.
Definition Metadata.h:249
Definition Exceptions.h:65
std::unique_ptr< PageHandle > Ptr
Definition StreamCompression.h:172
A Paging wrapper to std::istream that is responsible for reading from a given input stream and creati...
Definition StreamCompression.h:207
PageHandle::Ptr createHandle(std::streamsize n)
Creates a PageHandle to access the next.
bool sizeOnly() const
Definition StreamCompression.h:217
void read(PageHandle::Ptr &pageHandle, std::streamsize n, bool delayed=true)
Takes a pageHandle and updates the referenced page with the current stream pointer position and if de...
std::istream & getInputStream()
Definition StreamCompression.h:220
A Paging wrapper to std::ostream that is responsible for writing from a given output stream at interv...
Definition StreamCompression.h:244
std::ostream & getOutputStream()
Set and get the output stream.
Definition StreamCompression.h:257
bool sizeOnly() const
Definition StreamCompression.h:254
PagedOutputStream & write(const char *str, std::streamsize n)
Writes the given.
Definition Vec3.h:24
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
Definition Vec3.h:85
T & y()
Definition Vec3.h:86
T & z()
Definition Vec3.h:87
Base class for storing attribute data.
Definition AttributeArray.h:93
virtual Name valueType() const =0
Return the name of the value type of a single element in this array (e.g., "float" or "vec3d").
const char * constDataAsByteArray() const
Indirect virtual function to retrieve the data buffer cast to a char byte array.
Definition AttributeArray.h:363
AttributeArray(const AttributeArray &rhs, const tbb::spin_mutex::scoped_lock &)
void setConstantStride(bool state)
Specify whether this attribute has a constant stride or not.
static Ptr create(const NamePair &type, Index length, Index stride=1, bool constantStride=true, const Metadata *metadata=nullptr, const ScopedRegistryLock *lock=nullptr)
bool isTransient() const
Return true if this attribute is not serialized during stream output.
Definition AttributeArray.h:306
SerializationFlag
Definition AttributeArray.h:109
AttributeArray & operator=(const AttributeArray &rhs)
virtual Index dataSize() const =0
virtual bool isUniform() const =0
Return true if this array is stored as a single uniform value.
virtual void readBuffers(std::istream &)=0
Read attribute buffers from a stream.
std::shared_ptr< AttributeArray > Ptr
Definition AttributeArray.h:125
virtual ~AttributeArray()
Definition AttributeArray.h:133
compression::PageHandle::Ptr mPageHandle
Definition AttributeArray.h:405
Flag
Definition AttributeArray.h:101
AttributeArray()
Definition AttributeArray.h:132
virtual Index stride() const =0
bool isHidden() const
Return true if this attribute is hidden (e.g., from UI or iterators).
Definition AttributeArray.h:299
bool isType() const
Return true if this attribute is of the same type as the template parameter.
Definition AttributeArray.h:224
virtual bool valueTypeIsQuaternion() const =0
Return true if the value type is a quaternion.
virtual bool valueTypeIsVector() const =0
Return true if the value type is a vector.
uint8_t mFlags
Definition AttributeArray.h:400
virtual AccessorBasePtr getAccessor() const =0
Obtain an Accessor that stores getter and setter functors.
void setStreaming(bool state)
Specify whether this attribute is to be streamed off disk, in which case, the attributes are collapse...
AttributeArray(const AttributeArray &rhs)
virtual bool isDataLoaded() const =0
Return true if all data has been loaded.
uint8_t flags() const
Retrieve the attribute array flags.
Definition AttributeArray.h:320
bool hasValueType() const
Return true if this attribute has a value type the same as the template parameter.
Definition AttributeArray.h:228
std::atomic< Index32 > mOutOfCore
Definition AttributeArray.h:402
virtual void writeBuffers(std::ostream &, bool outputTransient) const =0
static void clearRegistry(const ScopedRegistryLock *lock=nullptr)
Clear the attribute type registry.
std::shared_ptr< AccessorBase > AccessorBasePtr
Definition AttributeArray.h:98
void setTransient(bool state)
Specify whether this attribute should only exist in memory and not be serialized during stream output...
virtual void read(std::istream &)=0
Read attribute metadata and buffers from a stream.
void setHidden(bool state)
Specify whether this attribute should be hidden (e.g., from UI or iterators).
virtual void write(std::ostream &, bool outputTransient) const =0
virtual bool compact()=0
Compact the existing array to become uniform if all values are identical.
virtual void readPagedBuffers(compression::PagedInputStream &)=0
Read attribute buffers from a paged stream.
virtual bool valueTypeIsClass() const =0
Return true if the value type is a class (ie vector, matrix or quaternion return true)
virtual void loadData() const =0
Ensures all data is in-core.
uint8_t mUsePagedRead
Definition AttributeArray.h:401
virtual bool valueTypeIsMatrix() const =0
Return true if the value type is a matrix.
bool operator==(const AttributeArray &other) const
tbb::spin_mutex mMutex
Definition AttributeArray.h:399
bool operator!=(const AttributeArray &other) const
Definition AttributeArray.h:359
bool isStreaming() const
Return true if this attribute is in streaming mode.
Definition AttributeArray.h:314
virtual void writeMetadata(std::ostream &, bool outputTransient, bool paged) const =0
AttributeArray & operator=(AttributeArray &&)=delete
static bool isRegistered(const NamePair &type, const ScopedRegistryLock *lock=nullptr)
Return true if the given attribute type name is registered.
Ptr(*)(Index, Index, bool, const Metadata *) FactoryMethod
Definition AttributeArray.h:128
virtual Name codecType() const =0
Return the name of the codec used by this array (e.g., "trnc" or "fxpt").
virtual size_t memUsageIfLoaded() const =0
virtual void readMetadata(std::istream &)=0
Read attribute metadata from a stream.
std::shared_ptr< const AttributeArray > ConstPtr
Definition AttributeArray.h:126
virtual void collapse()=0
Replace the existing array with a uniform zero value.
virtual void writePagedBuffers(compression::PagedOutputStream &, bool outputTransient) const =0
virtual Index storageTypeSize() const =0
virtual void write(std::ostream &) const =0
Write attribute metadata and buffers to a stream, don't write transient attributes.
static void registerType(const NamePair &type, FactoryMethod, const ScopedRegistryLock *lock=nullptr)
Register a attribute type along with a factory function.
virtual AttributeArray::Ptr copy() const =0
Return a copy of this attribute.
virtual Index valueTypeSize() const =0
virtual bool valueTypeIsFloatingPoint() const =0
Return true if the value type is floating point.
static void unregisterType(const NamePair &type, const ScopedRegistryLock *lock=nullptr)
Remove a attribute type from the registry.
bool hasConstantStride() const
Return true if this attribute has a constant stride.
Definition AttributeArray.h:317
virtual const NamePair & type() const =0
Return the name of this attribute's type.
size_t mCompressedBytes
Definition AttributeArray.h:406
bool mIsUniform
Definition AttributeArray.h:398
virtual void expand(bool fill=true)=0
If this array is uniform, replace it with an array of length size().
virtual size_t memUsage() const =0
Return the number of bytes of memory used by this attribute.
AttributeArray(AttributeArray &&)=delete
Definition AttributeArray.h:833
virtual ~AttributeHandle()
Definition AttributeArray.h:2143
Index size() const
Definition AttributeArray.h:855
void(*)(AttributeArray *array, const ValueType &value) ValuePtr
Definition AttributeArray.h:842
SetterPtr mSetter
Definition AttributeArray.h:870
Index stride() const
Definition AttributeArray.h:854
std::shared_ptr< Handle > Ptr
Definition AttributeArray.h:836
GetterPtr mGetter
Definition AttributeArray.h:869
void(*)(AttributeArray *array, const Index n, const ValueType &value) SetterPtr
Definition AttributeArray.h:841
static Ptr create(const AttributeArray &array, const bool collapseOnDestruction=true)
Definition AttributeArray.h:2108
AttributeHandle(const AttributeArray &array, const bool collapseOnDestruction=true)
Definition AttributeArray.h:2115
ValuePtr mFiller
Definition AttributeArray.h:872
ValueType get(Index n, Index m=0) const
Definition AttributeArray.h:2185
ValueType(*)(const AttributeArray *array, const Index n) GetterPtr
Definition AttributeArray.h:840
AttributeHandle(const AttributeHandle &)=default
ValuePtr mCollapser
Definition AttributeArray.h:871
const AttributeArray & array() const
Definition AttributeArray.h:2170
const AttributeArray * mArray
Definition AttributeArray.h:867
bool isUniform() const
Definition AttributeArray.h:2211
std::unique_ptr< Handle > UniquePtr
Definition AttributeArray.h:837
bool hasConstantStride() const
Definition AttributeArray.h:2217
AttributeHandle & operator=(const AttributeHandle &)=default
Index index(Index n, Index m) const
Definition AttributeArray.h:2177
Write-able version of AttributeHandle.
Definition AttributeArray.h:904
AttributeWriteHandle(AttributeArray &array, const bool expand=true)
Definition AttributeArray.h:2235
std::shared_ptr< Handle > Ptr
Definition AttributeArray.h:907
bool compact()
Compact the existing array to become uniform if all values are identical.
Definition AttributeArray.h:2266
void collapse()
Replace the existing array with a uniform value (zero if none provided).
Definition AttributeArray.h:2260
void set(Index n, const ValueType &value)
Definition AttributeArray.h:2242
void expand(bool fill=true)
If this array is uniform, replace it with an array of length size().
Definition AttributeArray.h:2254
AttributeArray & array()
Definition AttributeArray.h:2304
std::unique_ptr< Handle > ScopedPtr
Definition AttributeArray.h:908
static Ptr create(AttributeArray &array, const bool expand=true)
Definition AttributeArray.h:2228
void set(Index n, Index m, const ValueType &value)
Definition AttributeArray.h:2248
void fill(const ValueType &value)
Fill the existing array with the given value.
Definition AttributeArray.h:2278
void collapse(const ValueType &uniformValue)
Definition AttributeArray.h:2272
Typed class for storing attribute data.
Definition AttributeArray.h:545
Index valueTypeSize() const override
Return the size in bytes of the value type of a single element in this array.
Definition AttributeArray.h:635
size_t memUsageIfLoaded() const override
Definition AttributeArray.h:1390
ValueType getUnsafe(Index n) const
Return the value at index n (assumes in-core)
Definition AttributeArray.h:1399
bool isUniform() const override
Return true if this array is stored as a single uniform value.
Definition AttributeArray.h:700
void readBuffers(std::istream &) override
Read attribute buffers from a stream.
Definition AttributeArray.h:1743
std::shared_ptr< TypedAttributeArray > Ptr
Definition AttributeArray.h:547
AccessorBasePtr getAccessor() const override
Obtain an Accessor that stores getter and setter functors.
Definition AttributeArray.h:2007
void write(std::ostream &os, bool outputTransient) const override
Definition AttributeArray.h:1845
typename Codec::template Storage< ValueType >::Type StorageType
Definition AttributeArray.h:552
size_t memUsage() const override
Return the number of bytes of memory used by this attribute.
Definition AttributeArray.h:1382
ValueType_ ValueType
Definition AttributeArray.h:550
TypedAttributeArray(Index n=1, Index strideOrTotalSize=1, bool constantStride=true, const ValueType &uniformValue=zeroVal< ValueType >())
Default constructor, always constructs a uniform attribute.
Definition AttributeArray.h:1127
bool isDataLoaded() const override
Return true if all data has been loaded.
Definition AttributeArray.h:1675
bool isOutOfCore() const
Return true if this buffer's values have not yet been read from disk.
Definition AttributeArray.h:1635
std::shared_ptr< const TypedAttributeArray > ConstPtr
Definition AttributeArray.h:548
bool valueTypeIsVector() const override
Return true if the value type is a vector.
Definition AttributeArray.h:1356
bool validData() const
Verify that data is not out-of-core or in a partially-read state.
Definition AttributeArray.h:781
bool compact() override
Compact the existing array to become uniform if all values are identical.
Definition AttributeArray.h:1537
static TypedAttributeArray & cast(AttributeArray &attributeArray)
Cast an AttributeArray to TypedAttributeArray<T>
Definition AttributeArray.h:1251
TypedAttributeArray & operator=(TypedAttributeArray &&)=delete
Move assignment operator disabled.
void writeBuffers(std::ostream &os, bool outputTransient) const override
Definition AttributeArray.h:1913
AttributeArray::Ptr copy() const override
Definition AttributeArray.h:1271
Index storageTypeSize() const override
Definition AttributeArray.h:639
bool valueTypeIsQuaternion() const override
Return true if the value type is a quaternion.
Definition AttributeArray.h:1364
void readPagedBuffers(compression::PagedInputStream &) override
Read attribute buffers from a paged stream.
Definition AttributeArray.h:1782
void set(Index n, const ValueType &value)
Set value at the given index n.
Definition AttributeArray.h:1463
TypedAttributeArray & operator=(const TypedAttributeArray &)
Definition AttributeArray.h:1177
static void registerType()
Register this attribute type along with a factory function.
Definition AttributeArray.h:1223
bool valueTypeIsFloatingPoint() const override
Return true if the value type is floating point.
Definition AttributeArray.h:1327
void writeMetadata(std::ostream &os, bool outputTransient, bool paged) const override
Definition AttributeArray.h:1854
static void unregisterType()
Remove this attribute type from the registry.
Definition AttributeArray.h:1231
const StorageType * data() const
Definition AttributeArray.h:778
void loadData() const override
Ensures all data is in-core.
Definition AttributeArray.h:1667
void read(std::istream &) override
Read attribute data from a stream.
Definition AttributeArray.h:1683
ValueType get(Index n) const
Return the value at index n.
Definition AttributeArray.h:1411
TypedAttributeArray(TypedAttributeArray &&)=delete
Move constructor disabled.
static const NamePair & attributeType()
Return the name of this attribute's type (includes codec)
Definition AttributeArray.h:1204
const NamePair & type() const override
Return the name of this attribute's type.
Definition AttributeArray.h:607
bool valueTypeIsClass() const override
Return true if the value type is a class (ie vector, matrix or quaternion return true)
Definition AttributeArray.h:1347
Index size() const override
Return the number of elements in this array.
Definition AttributeArray.h:617
void collapse() override
Replace the existing array with a uniform zero value.
Definition AttributeArray.h:1554
Index dataSize() const override
Return the size of the data in this array.
Definition AttributeArray.h:624
Codec_ Codec
Definition AttributeArray.h:551
~TypedAttributeArray() override
Definition AttributeArray.h:581
void expand(bool fill=true) override
Replace the single value storage with an array of length size().
Definition AttributeArray.h:1516
static bool isRegistered()
Return true if this attribute type is registered.
Definition AttributeArray.h:1215
bool valueTypeIsMatrix() const override
Return true if the value type is a matrix.
Definition AttributeArray.h:1373
StorageType * data()
Return the raw data buffer.
Definition AttributeArray.h:777
const StorageType * constData() const
Return the raw data buffer.
Definition AttributeArray.h:771
void fill(const ValueType &value)
Fill the existing array with the given value.
Definition AttributeArray.h:1584
Index stride() const override
Definition AttributeArray.h:621
static Ptr create(Index n, Index strideOrTotalSize=1, bool constantStride=true, const Metadata *metadata=nullptr)
Return a new attribute array of the given length n and stride with uniform value zero.
Definition AttributeArray.h:1239
Name codecType() const override
Return the name of the codec used by this array (e.g., "trnc" or "fxpt").
Definition AttributeArray.h:632
void writePagedBuffers(compression::PagedOutputStream &os, bool outputTransient) const override
Definition AttributeArray.h:1955
Name valueType() const override
Return the name of the value type of a single element in this array (e.g., "float" or "vec3d").
Definition AttributeArray.h:629
void setUnsafe(Index n, const ValueType &value)
Set value at the given index n (assumes in-core)
Definition AttributeArray.h:1448
void readMetadata(std::istream &) override
Read attribute metadata from a stream.
Definition AttributeArray.h:1692
#define OPENVDB_LOG_WARN(message)
Log a warning message of the form 'someVar << "some text" << ...'.
Definition logging.h:256
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...
OPENVDB_API size_t bloscCompressedSize(const char *buffer, const size_t uncompressedBytes)
Convenience wrapper to retrieve the compressed size of buffer when compressed.
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.
OPENVDB_API uint32_t getDataCompression(std::ios_base &)
Return a bitwise OR of compression option flags (COMPRESS_ZIP, COMPRESS_ACTIVE_MASK,...
@ COMPRESS_BLOSC
Definition Compression.h:56
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition Math.h:443
FloatT fixedPointToFloatingPoint(const IntegerT s)
Definition AttributeArray.h:61
IntegerT floatingPointToFixedPoint(const FloatT s)
Definition AttributeArray.h:50
std::string Name
Definition Name.h:19
Index32 Index
Definition Types.h:54
int16_t Int16
Definition Types.h:55
std::pair< Name, Name > NamePair
Definition AttributeArray.h:39
uint64_t Index64
Definition Types.h:53
Definition Exceptions.h:13
#define OPENVDB_THROW(exception, message)
Definition Exceptions.h:74
static pnanovdb_uint32_t allocate(pnanovdb_uint32_t *poffset, pnanovdb_uint32_t size, pnanovdb_uint32_t alignment)
Definition pnanovdb_validate_strides.h:20
Definition Types.h:244
typename T::ValueType ElementType
Definition Types.h:247
static ValueType get(GetterPtr functor, const AttributeArray *array, const Index n)
Getter that calls the supplied functor.
Definition AttributeArray.h:2091
void(*)(AttributeArray *array, const Index n, const ValueType &value) SetterPtr
Definition AttributeArray.h:2088
static void set(SetterPtr functor, AttributeArray *array, const Index n, const ValueType &value)
Setter that calls the supplied functor.
Definition AttributeArray.h:2096
ValueType(*)(const AttributeArray *array, const Index n) GetterPtr
Definition AttributeArray.h:2087
Accessor to call unsafe get and set methods based on templated Codec and Value.
Definition AttributeArray.h:2065
void(*)(AttributeArray *array, const Index n, const ValueType &value) SetterPtr
Definition AttributeArray.h:2067
static ValueType get(GetterPtr, const AttributeArray *array, const Index n)
Definition AttributeArray.h:2071
ValueType(*)(const AttributeArray *array, const Index n) GetterPtr
Definition AttributeArray.h:2066
static void set(SetterPtr, AttributeArray *array, const Index n, const ValueType &value)
Definition AttributeArray.h:2077
Accessor base class for AttributeArray storage where type is not available.
Definition AttributeArray.h:415
SetterPtr mSetter
Definition AttributeArray.h:430
GetterPtr mGetter
Definition AttributeArray.h:429
void(*)(AttributeArray *array, const T &value) ValuePtr
Definition AttributeArray.h:424
T(*)(const AttributeArray *array, const Index n) GetterPtr
Definition AttributeArray.h:422
void(*)(AttributeArray *array, const Index n, const T &value) SetterPtr
Definition AttributeArray.h:423
ValuePtr mFiller
Definition AttributeArray.h:432
Accessor(GetterPtr getter, SetterPtr setter, ValuePtr collapser, ValuePtr filler)
Definition AttributeArray.h:426
ValuePtr mCollapser
Definition AttributeArray.h:431
typename attribute_traits::UIntTypeTrait< OneByte, T >::Type Type
Definition AttributeArray.h:513
Definition AttributeArray.h:511
static const char * name()
Definition AttributeArray.h:518
Definition AttributeArray.h:472
T Type
Definition AttributeArray.h:472
Definition AttributeArray.h:470
static const char * name()
Definition AttributeArray.h:476
Definition AttributeArray.h:493
static ValueType decode(const ValueType &value)
Definition AttributeArray.h:496
static ValueType encode(const ValueType &value)
Definition AttributeArray.h:495
static const char * name()
Definition AttributeArray.h:494
Definition AttributeArray.h:483
typename attribute_traits::TruncateTrait< T >::Type Type
Definition AttributeArray.h:483
Definition AttributeArray.h:481
static const char * name()
Definition AttributeArray.h:487
Definition AttributeArray.h:502
static ValueType decode(const ValueType &value)
Definition AttributeArray.h:505
static ValueType encode(const ValueType &value)
Definition AttributeArray.h:504
static const char * name()
Definition AttributeArray.h:503
Definition AttributeArray.h:530
StorageType Type
Definition AttributeArray.h:530
Definition AttributeArray.h:526
uint16_t StorageType
Definition AttributeArray.h:527
static const char * name()
Definition AttributeArray.h:534
Definition AttributeArray.h:466
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:212