OpenVDB 10.1.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#if OPENVDB_ABI_VERSION_NUMBER >= 9
771 /// Return the raw data buffer
772 inline const StorageType* constData() const { return this->data(); }
773#endif
774
775protected:
776 AccessorBasePtr getAccessor() const override;
777
778 /// Return the raw data buffer
779 inline StorageType* data() { assert(validData()); return mData.get(); }
780 inline const StorageType* data() const { assert(validData()); return mData.get(); }
781
782 /// Verify that data is not out-of-core or in a partially-read state
783 inline bool validData() const { return !(isOutOfCore() || (flags() & PARTIALREAD)); }
784
785private:
786 friend class ::TestAttributeArray;
787
788 TypedAttributeArray(const TypedAttributeArray&, const tbb::spin_mutex::scoped_lock&);
789
790 /// Load data from memory-mapped file.
791 inline void doLoad() const;
792 /// Load data from memory-mapped file (unsafe as this function is not protected by a mutex).
793#if OPENVDB_ABI_VERSION_NUMBER >= 10
794 inline void doLoadUnsafe() const;
795#else
796 /// @param compression parameter no longer used
797 inline void doLoadUnsafe(const bool compression = true) const;
798 /// Compress in-core data assuming mutex is locked
799 inline bool compressUnsafe();
800#endif
801
802 /// Toggle out-of-core state
803 inline void setOutOfCore(const bool);
804
805 /// Compare the this data to another attribute array. Used by the base class comparison operator
806 bool isEqual(const AttributeArray& other) const override;
807
808 /// Virtual function to retrieve the data buffer from the derived class cast to a char byte array
809 char* dataAsByteArray() override;
810 const char* dataAsByteArray() const override;
811
812 size_t arrayMemUsage() const;
813 void allocate();
814 void deallocate();
815
816 /// Helper function for use with registerType()
817 static AttributeArray::Ptr factory(Index n, Index strideOrTotalSize, bool constantStride,
818 const Metadata* metadata) {
819 return TypedAttributeArray::create(n, strideOrTotalSize, constantStride, metadata);
820 }
821
822 std::unique_ptr<StorageType[]> mData;
823 Index mSize;
824 Index mStrideOrTotalSize;
825}; // class TypedAttributeArray
826
827
828////////////////////////////////////////
829
830
831/// AttributeHandles provide access to specific TypedAttributeArray methods without needing
832/// to know the compression codec, however these methods also incur the cost of a function pointer
833template <typename ValueType, typename CodecType = UnknownCodec>
835{
836public:
838 using Ptr = std::shared_ptr<Handle>;
839 using UniquePtr = std::unique_ptr<Handle>;
840
841protected:
842 using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
843 using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
844 using ValuePtr = void (*)(AttributeArray* array, const ValueType& value);
845
846public:
847 static Ptr create(const AttributeArray& array, const bool collapseOnDestruction = true);
848
849 AttributeHandle(const AttributeArray& array, const bool collapseOnDestruction = true);
850
853
855
856 Index stride() const { return mStrideOrTotalSize; }
857 Index size() const { return mSize; }
858
859 bool isUniform() const;
860 bool hasConstantStride() const;
861
862 ValueType get(Index n, Index m = 0) const;
863
864 const AttributeArray& array() const;
865
866protected:
867 Index index(Index n, Index m) const;
868
870
875
876private:
877 friend class ::TestAttributeArray;
878
879 template <bool IsUnknownCodec>
880 typename std::enable_if<IsUnknownCodec, bool>::type compatibleType() const;
881
882 template <bool IsUnknownCodec>
883 typename std::enable_if<!IsUnknownCodec, bool>::type compatibleType() const;
884
885 template <bool IsUnknownCodec>
886 typename std::enable_if<IsUnknownCodec, ValueType>::type get(Index index) const;
887
888 template <bool IsUnknownCodec>
889 typename std::enable_if<!IsUnknownCodec, ValueType>::type get(Index index) const;
890
891 // local copy of AttributeArray (to preserve compression)
892 AttributeArray::Ptr mLocalArray;
893
894 Index mStrideOrTotalSize;
895 Index mSize;
896 bool mCollapseOnDestruction;
897}; // class AttributeHandle
898
899
900////////////////////////////////////////
901
902
903/// Write-able version of AttributeHandle
904template <typename ValueType, typename CodecType = UnknownCodec>
905class AttributeWriteHandle : public AttributeHandle<ValueType, CodecType>
906{
907public:
909 using Ptr = std::shared_ptr<Handle>;
910 using ScopedPtr = std::unique_ptr<Handle>;
911
912 static Ptr create(AttributeArray& array, const bool expand = true);
913
914 AttributeWriteHandle(AttributeArray& array, const bool expand = true);
915
916 virtual ~AttributeWriteHandle() = default;
917
918 /// @brief If this array is uniform, replace it with an array of length size().
919 /// @param fill if true, assign the uniform value to each element of the array.
920 void expand(bool fill = true);
921
922 /// Replace the existing array with a uniform value (zero if none provided).
923 void collapse();
924 void collapse(const ValueType& uniformValue);
925
926 /// Compact the existing array to become uniform if all values are identical
927 bool compact();
928
929 /// @brief Fill the existing array with the given value.
930 /// @note Identical to collapse() except a non-uniform array will not become uniform.
931 void fill(const ValueType& value);
932
933 void set(Index n, const ValueType& value);
934 void set(Index n, Index m, const ValueType& value);
935
937
938private:
939 friend class ::TestAttributeArray;
940
941 template <bool IsUnknownCodec>
942 typename std::enable_if<IsUnknownCodec, void>::type set(Index index, const ValueType& value) const;
943
944 template <bool IsUnknownCodec>
945 typename std::enable_if<!IsUnknownCodec, void>::type set(Index index, const ValueType& value) const;
946}; // class AttributeWriteHandle
947
948
949////////////////////////////////////////
950
951
952// Attribute codec implementation
953
954
955template<typename ValueType>
956inline void
957NullCodec::decode(const ValueType& data, ValueType& val)
958{
959 val = data;
960}
961
962
963template<typename ValueType>
964inline void
965NullCodec::encode(const ValueType& val, ValueType& data)
966{
967 data = val;
968}
969
970
971template<typename StorageType, typename ValueType>
972inline void
973TruncateCodec::decode(const StorageType& data, ValueType& val)
974{
975 val = static_cast<ValueType>(data);
976}
977
978
979template<typename StorageType, typename ValueType>
980inline void
981TruncateCodec::encode(const ValueType& val, StorageType& data)
982{
983 data = static_cast<StorageType>(val);
984}
985
986
987template <bool OneByte, typename Range>
988template<typename StorageType, typename ValueType>
989inline void
990FixedPointCodec<OneByte, Range>::decode(const StorageType& data, ValueType& val)
991{
992 val = fixedPointToFloatingPoint<ValueType>(data);
993
994 // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
995
996 val = Range::template decode<ValueType>(val);
997}
998
999
1000template <bool OneByte, typename Range>
1001template<typename StorageType, typename ValueType>
1002inline void
1003FixedPointCodec<OneByte, Range>::encode(const ValueType& val, StorageType& data)
1004{
1005 // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
1006
1007 const ValueType newVal = Range::template encode<ValueType>(val);
1008
1009 data = floatingPointToFixedPoint<StorageType>(newVal);
1010}
1011
1012
1013template<typename T>
1014inline void
1015UnitVecCodec::decode(const StorageType& data, math::Vec3<T>& val)
1016{
1017 val = math::QuantizedUnitVec::unpack(data);
1018}
1019
1020
1021template<typename T>
1022inline void
1023UnitVecCodec::encode(const math::Vec3<T>& val, StorageType& data)
1024{
1025 data = math::QuantizedUnitVec::pack(val);
1026}
1027
1028
1029////////////////////////////////////////
1030
1031// AttributeArray implementation
1032
1033template <typename IterT>
1034void AttributeArray::doCopyValues(const AttributeArray& sourceArray, const IterT& iter,
1035 bool rangeChecking/*=true*/)
1036{
1037 // ensure both arrays have float-float or integer-integer value types
1038 assert(sourceArray.valueTypeIsFloatingPoint() == this->valueTypeIsFloatingPoint());
1039 // ensure both arrays have been loaded from disk (if delay-loaded)
1040 assert(sourceArray.isDataLoaded() && this->isDataLoaded());
1041 // ensure storage size * stride matches on both arrays
1042 assert(this->storageTypeSize()*this->stride() ==
1043 sourceArray.storageTypeSize()*sourceArray.stride());
1044
1045 const size_t bytes(sourceArray.storageTypeSize()*sourceArray.stride());
1046 const char* const sourceBuffer = sourceArray.dataAsByteArray();
1047 char* const targetBuffer = this->dataAsByteArray();
1048 assert(sourceBuffer && targetBuffer);
1049
1050 if (rangeChecking && this->isUniform()) {
1051 OPENVDB_THROW(IndexError, "Cannot copy array data as target array is uniform.");
1052 }
1053
1054 const bool sourceIsUniform = sourceArray.isUniform();
1055
1056 const Index sourceDataSize = rangeChecking ? sourceArray.dataSize() : 0;
1057 const Index targetDataSize = rangeChecking ? this->dataSize() : 0;
1058
1059 for (IterT it(iter); it; ++it) {
1060 const Index sourceIndex = sourceIsUniform ? 0 : it.sourceIndex();
1061 const Index targetIndex = it.targetIndex();
1062
1063 if (rangeChecking) {
1064 if (sourceIndex >= sourceDataSize) {
1066 "Cannot copy array data as source index exceeds size of source array.");
1067 }
1068 if (targetIndex >= targetDataSize) {
1070 "Cannot copy array data as target index exceeds size of target array.");
1071 }
1072 } else {
1073 // range-checking asserts
1074 assert(sourceIndex < sourceArray.dataSize());
1075 assert(targetIndex < this->dataSize());
1076 if (this->isUniform()) assert(targetIndex == Index(0));
1077 }
1078
1079 const size_t targetOffset(targetIndex * bytes);
1080 const size_t sourceOffset(sourceIndex * bytes);
1081
1082 std::memcpy(targetBuffer + targetOffset, sourceBuffer + sourceOffset, bytes);
1083 }
1084}
1085
1086template <typename IterT>
1087void AttributeArray::copyValuesUnsafe(const AttributeArray& sourceArray, const IterT& iter)
1088{
1089 this->doCopyValues(sourceArray, iter, /*range-checking=*/false);
1090}
1091
1092template <typename IterT>
1093void AttributeArray::copyValues(const AttributeArray& sourceArray, const IterT& iter,
1094 bool compact/* = true*/)
1095{
1096 const Index bytes = sourceArray.storageTypeSize();
1097 if (bytes != this->storageTypeSize()) {
1098 OPENVDB_THROW(TypeError, "Cannot copy array data due to mis-match in storage type sizes.");
1099 }
1100
1101 // ensure both arrays have been loaded from disk
1102 sourceArray.loadData();
1103 this->loadData();
1104
1105 // if the target array is uniform, expand it first
1106 this->expand();
1107
1108 // TODO: Acquire mutex locks for source and target arrays to ensure that
1109 // value copying is always thread-safe. Note that the unsafe method will be
1110 // faster, but can only be used if neither the source or target arrays are
1111 // modified during copying. Note that this will require a new private
1112 // virtual method with ABI=7 to access the mutex from the derived class.
1113
1114 this->doCopyValues(sourceArray, iter, true);
1115
1116 // attempt to compact target array
1117 if (compact) {
1118 this->compact();
1119 }
1120}
1121
1122
1123////////////////////////////////////////
1124
1125// TypedAttributeArray implementation
1126
1127
1128template<typename ValueType_, typename Codec_>
1130 Index n, Index strideOrTotalSize, bool constantStride, const ValueType& uniformValue)
1131 : AttributeArray()
1132 , mData(new StorageType[1])
1133 , mSize(n)
1134 , mStrideOrTotalSize(strideOrTotalSize)
1135{
1136 if (constantStride) {
1137 this->setConstantStride(true);
1138 if (strideOrTotalSize == 0) {
1139 OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a constant stride requires that " \
1140 "stride to be at least one.")
1141 }
1142 }
1143 else {
1144 this->setConstantStride(false);
1145 if (mStrideOrTotalSize < n) {
1146 OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a non-constant stride must have " \
1147 "a total size of at least the number of elements in the array.")
1148 }
1149 }
1150 mSize = std::max(Index(1), mSize);
1151 mStrideOrTotalSize = std::max(Index(1), mStrideOrTotalSize);
1152 Codec::encode(uniformValue, this->data()[0]);
1153}
1154
1155
1156template<typename ValueType_, typename Codec_>
1158 : TypedAttributeArray(rhs, tbb::spin_mutex::scoped_lock(rhs.mMutex))
1159{
1160}
1161
1162
1163template<typename ValueType_, typename Codec_>
1165 const tbb::spin_mutex::scoped_lock& lock)
1166 : AttributeArray(rhs, lock)
1167 , mSize(rhs.mSize)
1168 , mStrideOrTotalSize(rhs.mStrideOrTotalSize)
1169{
1170 if (this->validData()) {
1171 this->allocate();
1172 std::memcpy(static_cast<void*>(this->data()), rhs.data(), this->arrayMemUsage());
1173 }
1174}
1175
1176
1177template<typename ValueType_, typename Codec_>
1178TypedAttributeArray<ValueType_, Codec_>&
1180{
1181 if (&rhs != this) {
1182 // lock both the source and target arrays to ensure thread-safety
1183 tbb::spin_mutex::scoped_lock lock(mMutex);
1184 tbb::spin_mutex::scoped_lock rhsLock(rhs.mMutex);
1185
1186 this->deallocate();
1187
1188 mFlags = rhs.mFlags;
1189 mUsePagedRead = rhs.mUsePagedRead;
1190 mSize = rhs.mSize;
1191 mStrideOrTotalSize = rhs.mStrideOrTotalSize;
1192 mIsUniform = rhs.mIsUniform;
1193
1194 if (this->validData()) {
1195 this->allocate();
1196 std::memcpy(static_cast<void*>(this->data()), rhs.data(), this->arrayMemUsage());
1197 }
1198 }
1199
1200 return *this;
1201}
1202
1203
1204template<typename ValueType_, typename Codec_>
1205inline const NamePair&
1207{
1208 static NamePair sTypeName = []() {
1209 return NamePair(typeNameAsString<ValueType>(), Codec::name());
1210 }();
1211 return sTypeName;
1212}
1213
1214
1215template<typename ValueType_, typename Codec_>
1216inline bool
1218{
1220}
1221
1222
1223template<typename ValueType_, typename Codec_>
1224inline void
1226{
1228}
1229
1230
1231template<typename ValueType_, typename Codec_>
1232inline void
1234{
1236}
1237
1238
1239template<typename ValueType_, typename Codec_>
1242 const Metadata* metadata)
1243{
1244 const TypedMetadata<ValueType>* typedMetadata = metadata ?
1245 dynamic_cast<const TypedMetadata<ValueType>*>(metadata) : nullptr;
1246
1247 return Ptr(new TypedAttributeArray(n, stride, constantStride,
1248 typedMetadata ? typedMetadata->value() : zeroVal<ValueType>()));
1249}
1250
1251template<typename ValueType_, typename Codec_>
1254{
1255 if (!attributeArray.isType<TypedAttributeArray>()) {
1256 OPENVDB_THROW(TypeError, "Invalid Attribute Type");
1257 }
1258 return static_cast<TypedAttributeArray&>(attributeArray);
1259}
1260
1261template<typename ValueType_, typename Codec_>
1264{
1265 if (!attributeArray.isType<TypedAttributeArray>()) {
1266 OPENVDB_THROW(TypeError, "Invalid Attribute Type");
1267 }
1268 return static_cast<const TypedAttributeArray&>(attributeArray);
1269}
1270
1271template<typename ValueType_, typename Codec_>
1274{
1276}
1277
1278
1279#if OPENVDB_ABI_VERSION_NUMBER < 10
1280template<typename ValueType_, typename Codec_>
1283{
1284 return this->copy();
1285}
1286#endif
1287
1288template<typename ValueType_, typename Codec_>
1289size_t
1290TypedAttributeArray<ValueType_, Codec_>::arrayMemUsage() const
1291{
1292 if (this->isOutOfCore()) return 0;
1293
1294 return (mIsUniform ? 1 : this->dataSize()) * sizeof(StorageType);
1295}
1296
1297
1298template<typename ValueType_, typename Codec_>
1299void
1300TypedAttributeArray<ValueType_, Codec_>::allocate()
1301{
1302 assert(!mData);
1303 if (mIsUniform) {
1304 mData.reset(new StorageType[1]);
1305 }
1306 else {
1307 const size_t size(this->dataSize());
1308 assert(size > 0);
1309 mData.reset(new StorageType[size]);
1310 }
1311}
1312
1313
1314template<typename ValueType_, typename Codec_>
1315void
1316TypedAttributeArray<ValueType_, Codec_>::deallocate()
1317{
1318 // detach from file if delay-loaded
1319 if (this->isOutOfCore()) {
1320 this->setOutOfCore(false);
1321 this->mPageHandle.reset();
1322 }
1323 if (mData) mData.reset();
1324}
1325
1326
1327template<typename ValueType_, typename Codec_>
1328bool
1330{
1331 // TODO: Update to use Traits that correctly handle matrices and quaternions.
1332
1333 if (std::is_same<ValueType, Quats>::value ||
1334 std::is_same<ValueType, Quatd>::value ||
1335 std::is_same<ValueType, Mat3s>::value ||
1336 std::is_same<ValueType, Mat3d>::value ||
1337 std::is_same<ValueType, Mat4s>::value ||
1338 std::is_same<ValueType, Mat4d>::value) return true;
1339
1340 using ElementT = typename VecTraits<ValueType>::ElementType;
1341
1342 // half is not defined as float point as expected, so explicitly handle it
1343 return std::is_floating_point<ElementT>::value || std::is_same<math::half, ElementT>::value;
1344}
1345
1346
1347template<typename ValueType_, typename Codec_>
1348bool
1350{
1351 // half is not defined as a non-class type as expected, so explicitly exclude it
1352 return std::is_class<ValueType>::value && !std::is_same<math::half, ValueType>::value;
1353}
1354
1355
1356template<typename ValueType_, typename Codec_>
1357bool
1359{
1361}
1362
1363
1364template<typename ValueType_, typename Codec_>
1365bool
1367{
1368 // TODO: improve performance by making this a compile-time check using type traits
1369 return !this->valueType().compare(0, 4, "quat");
1370}
1371
1372
1373template<typename ValueType_, typename Codec_>
1374bool
1376{
1377 // TODO: improve performance by making this a compile-time check using type traits
1378 return !this->valueType().compare(0, 3, "mat");
1379}
1380
1381
1382template<typename ValueType_, typename Codec_>
1383size_t
1385{
1386 return sizeof(*this) + (bool(mData) ? this->arrayMemUsage() : 0);
1387}
1388
1389#if OPENVDB_ABI_VERSION_NUMBER >= 10
1390template<typename ValueType_, typename Codec_>
1391size_t
1393{
1394 return sizeof(*this) + (mIsUniform ? 1 : this->dataSize()) * sizeof(StorageType);
1395}
1396#endif
1397
1398
1399template<typename ValueType_, typename Codec_>
1402{
1403 assert(n < this->dataSize());
1404
1405 ValueType val;
1406 Codec::decode(/*in=*/this->data()[mIsUniform ? 0 : n], /*out=*/val);
1407 return val;
1408}
1409
1410
1411template<typename ValueType_, typename Codec_>
1414{
1415 if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1416 if (this->isOutOfCore()) this->doLoad();
1417
1418 return this->getUnsafe(n);
1419}
1420
1421
1422template<typename ValueType_, typename Codec_>
1423template<typename T>
1424void
1426{
1427 val = static_cast<T>(this->getUnsafe(n));
1428}
1429
1430
1431template<typename ValueType_, typename Codec_>
1432template<typename T>
1433void
1435{
1436 val = static_cast<T>(this->get(n));
1437}
1438
1439
1440template<typename ValueType_, typename Codec_>
1443{
1444 return static_cast<const TypedAttributeArray<ValueType, Codec>*>(array)->getUnsafe(n);
1445}
1446
1447
1448template<typename ValueType_, typename Codec_>
1449void
1451{
1452 assert(n < this->dataSize());
1453 assert(!this->isOutOfCore());
1454 assert(!this->isUniform());
1455
1456 // this unsafe method assumes the data is not uniform, however if it is, this redirects the index
1457 // to zero, which is marginally less efficient but ensures not writing to an illegal address
1458
1459 Codec::encode(/*in=*/val, /*out=*/this->data()[mIsUniform ? 0 : n]);
1460}
1461
1462
1463template<typename ValueType_, typename Codec_>
1464void
1466{
1467 if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1468 if (this->isOutOfCore()) this->doLoad();
1469 if (this->isUniform()) this->expand();
1470
1471 this->setUnsafe(n, val);
1472}
1473
1474
1475template<typename ValueType_, typename Codec_>
1476template<typename T>
1477void
1479{
1480 this->setUnsafe(n, static_cast<ValueType>(val));
1481}
1482
1483
1484template<typename ValueType_, typename Codec_>
1485template<typename T>
1486void
1488{
1489 this->set(n, static_cast<ValueType>(val));
1490}
1491
1492
1493template<typename ValueType_, typename Codec_>
1494void
1496{
1497 static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->setUnsafe(n, value);
1498}
1499
1500
1501#if OPENVDB_ABI_VERSION_NUMBER < 10
1502template<typename ValueType_, typename Codec_>
1503void
1504TypedAttributeArray<ValueType_, Codec_>::set(Index n, const AttributeArray& sourceArray, const Index sourceIndex)
1505{
1506 const TypedAttributeArray& sourceTypedArray = static_cast<const TypedAttributeArray&>(sourceArray);
1507
1508 ValueType sourceValue;
1509 sourceTypedArray.get(sourceIndex, sourceValue);
1510
1511 this->set(n, sourceValue);
1512}
1513#endif
1514
1515
1516template<typename ValueType_, typename Codec_>
1517void
1519{
1520 if (!mIsUniform) return;
1521
1522 const StorageType val = this->data()[0];
1523
1524 {
1525 tbb::spin_mutex::scoped_lock lock(mMutex);
1526 this->deallocate();
1527 mIsUniform = false;
1528 this->allocate();
1529 }
1530
1531 if (fill) {
1532 for (Index i = 0; i < this->dataSize(); ++i) this->data()[i] = val;
1533 }
1534}
1535
1536
1537template<typename ValueType_, typename Codec_>
1538bool
1540{
1541 if (mIsUniform) return true;
1542
1543 // compaction is not possible if any values are different
1544 const ValueType_ val = this->get(0);
1545 for (Index i = 1; i < this->dataSize(); i++) {
1546 if (!math::isExactlyEqual(this->get(i), val)) return false;
1547 }
1548
1549 this->collapse(this->get(0));
1550 return true;
1551}
1552
1553
1554template<typename ValueType_, typename Codec_>
1555void
1557{
1558 this->collapse(zeroVal<ValueType>());
1559}
1560
1561
1562template<typename ValueType_, typename Codec_>
1563void
1565{
1566 if (!mIsUniform) {
1567 tbb::spin_mutex::scoped_lock lock(mMutex);
1568 this->deallocate();
1569 mIsUniform = true;
1570 this->allocate();
1571 }
1572 Codec::encode(uniformValue, this->data()[0]);
1573}
1574
1575
1576template<typename ValueType_, typename Codec_>
1577void
1579{
1580 static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->collapse(value);
1581}
1582
1583
1584template<typename ValueType_, typename Codec_>
1585void
1587{
1588 if (this->isOutOfCore()) {
1589 tbb::spin_mutex::scoped_lock lock(mMutex);
1590 this->deallocate();
1591 this->allocate();
1592 }
1593
1594 const Index size = mIsUniform ? 1 : this->dataSize();
1595 for (Index i = 0; i < size; ++i) {
1596 Codec::encode(value, this->data()[i]);
1597 }
1598}
1599
1600
1601template<typename ValueType_, typename Codec_>
1602void
1604{
1605 static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->fill(value);
1606}
1607
1608
1609#if OPENVDB_ABI_VERSION_NUMBER < 10
1610template<typename ValueType_, typename Codec_>
1611inline bool
1613{
1614 return false;
1615}
1616
1617
1618template<typename ValueType_, typename Codec_>
1619inline bool
1620TypedAttributeArray<ValueType_, Codec_>::compressUnsafe()
1621{
1622 return false;
1623}
1624
1625
1626template<typename ValueType_, typename Codec_>
1627inline bool
1628TypedAttributeArray<ValueType_, Codec_>::decompress()
1629{
1630 return false;
1631}
1632#endif
1633
1634
1635template<typename ValueType_, typename Codec_>
1636bool
1638{
1639 return mOutOfCore;
1640}
1641
1642
1643template<typename ValueType_, typename Codec_>
1644void
1646{
1647 mOutOfCore = b;
1648}
1649
1650
1651template<typename ValueType_, typename Codec_>
1652void
1653TypedAttributeArray<ValueType_, Codec_>::doLoad() const
1654{
1655 if (!(this->isOutOfCore())) return;
1656
1657 TypedAttributeArray<ValueType_, Codec_>* self =
1658 const_cast<TypedAttributeArray<ValueType_, Codec_>*>(this);
1659
1660 // This lock will be contended at most once, after which this buffer
1661 // will no longer be out-of-core.
1662 tbb::spin_mutex::scoped_lock lock(self->mMutex);
1663 this->doLoadUnsafe();
1664}
1665
1666
1667template<typename ValueType_, typename Codec_>
1668void
1670{
1671 this->doLoad();
1672}
1673
1674
1675template<typename ValueType_, typename Codec_>
1676bool
1678{
1679 return !this->isOutOfCore();
1680}
1681
1682
1683template<typename ValueType_, typename Codec_>
1684void
1686{
1687 this->readMetadata(is);
1688 this->readBuffers(is);
1689}
1690
1691
1692template<typename ValueType_, typename Codec_>
1693void
1695{
1696 // read data
1697
1698 Index64 bytes = Index64(0);
1699 is.read(reinterpret_cast<char*>(&bytes), sizeof(Index64));
1700 bytes = bytes - /*flags*/sizeof(Int16) - /*size*/sizeof(Index);
1701
1702 uint8_t flags = uint8_t(0);
1703 is.read(reinterpret_cast<char*>(&flags), sizeof(uint8_t));
1704 mFlags = flags;
1705
1706 uint8_t serializationFlags = uint8_t(0);
1707 is.read(reinterpret_cast<char*>(&serializationFlags), sizeof(uint8_t));
1708
1709 Index size = Index(0);
1710 is.read(reinterpret_cast<char*>(&size), sizeof(Index));
1711 mSize = size;
1712
1713 // warn if an unknown flag has been set
1714 if (mFlags >= 0x20) {
1715 OPENVDB_LOG_WARN("Unknown attribute flags for VDB file format.");
1716 }
1717 // error if an unknown serialization flag has been set,
1718 // as this will adjust the layout of the data and corrupt the ability to read
1719 if (serializationFlags >= 0x10) {
1720 OPENVDB_THROW(IoError, "Unknown attribute serialization flags for VDB file format.");
1721 }
1722
1723 // set uniform, compressed and page read state
1724
1725 mIsUniform = serializationFlags & WRITEUNIFORM;
1726 mUsePagedRead = serializationFlags & WRITEPAGED;
1727 mCompressedBytes = bytes;
1728 mFlags |= PARTIALREAD; // mark data as having been partially read
1729
1730 // read strided value (set to 1 if array is not strided)
1731
1732 if (serializationFlags & WRITESTRIDED) {
1733 Index stride = Index(0);
1734 is.read(reinterpret_cast<char*>(&stride), sizeof(Index));
1735 mStrideOrTotalSize = stride;
1736 }
1737 else {
1738 mStrideOrTotalSize = 1;
1739 }
1740}
1741
1742
1743template<typename ValueType_, typename Codec_>
1744void
1746{
1747 if (mUsePagedRead) {
1748 // use readBuffers(PagedInputStream&) for paged buffers
1749 OPENVDB_THROW(IoError, "Cannot read paged AttributeArray buffers.");
1750 }
1751
1752 tbb::spin_mutex::scoped_lock lock(mMutex);
1753
1754 this->deallocate();
1755
1756 uint8_t bloscCompressed(0);
1757 if (!mIsUniform) is.read(reinterpret_cast<char*>(&bloscCompressed), sizeof(uint8_t));
1758
1759 assert(mFlags & PARTIALREAD);
1760 std::unique_ptr<char[]> buffer(new char[mCompressedBytes]);
1761 is.read(buffer.get(), mCompressedBytes);
1762 mCompressedBytes = 0;
1763 mFlags = static_cast<uint8_t>(mFlags & ~PARTIALREAD); // mark data read as having completed
1764
1765 // compressed on-disk
1766
1767 if (bloscCompressed == uint8_t(1)) {
1768
1769 // decompress buffer
1770
1771 const size_t inBytes = this->dataSize() * sizeof(StorageType);
1772 std::unique_ptr<char[]> newBuffer = compression::bloscDecompress(buffer.get(), inBytes);
1773 if (newBuffer) buffer.reset(newBuffer.release());
1774 }
1775
1776 // set data to buffer
1777
1778 mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1779}
1780
1781
1782template<typename ValueType_, typename Codec_>
1783void
1785{
1786 if (!mUsePagedRead) {
1787 if (!is.sizeOnly()) this->readBuffers(is.getInputStream());
1788 return;
1789 }
1790
1791#ifdef OPENVDB_USE_DELAYED_LOADING
1792 // If this array is being read from a memory-mapped file, delay loading of its data
1793 // until the data is actually accessed.
1794 io::MappedFile::Ptr mappedFile = io::getMappedFilePtr(is.getInputStream());
1795 const bool delayLoad = (mappedFile.get() != nullptr);
1796#endif
1797
1798 if (is.sizeOnly())
1799 {
1800 size_t compressedBytes(mCompressedBytes);
1801 mCompressedBytes = 0; // if not set to zero, mPageHandle will attempt to destroy invalid memory
1802 mFlags = static_cast<uint8_t>(mFlags & ~PARTIALREAD); // mark data read as having completed
1803 assert(!mPageHandle);
1804 mPageHandle = is.createHandle(compressedBytes);
1805 return;
1806 }
1807
1808 assert(mPageHandle);
1809
1810 tbb::spin_mutex::scoped_lock lock(mMutex);
1811
1812 this->deallocate();
1813
1814#ifdef OPENVDB_USE_DELAYED_LOADING
1815 this->setOutOfCore(delayLoad);
1816 is.read(mPageHandle, std::streamsize(mPageHandle->size()), delayLoad);
1817#else
1818 is.read(mPageHandle, std::streamsize(mPageHandle->size()), false);
1819#endif // OPENVDB_USE_DELAYED_LOADING
1820
1821#ifdef OPENVDB_USE_DELAYED_LOADING
1822 if (!delayLoad) {
1823#endif
1824 std::unique_ptr<char[]> buffer = mPageHandle->read();
1825 mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1826 mPageHandle.reset();
1827#ifdef OPENVDB_USE_DELAYED_LOADING
1828 }
1829#endif
1830
1831 // clear page state
1832
1833 mUsePagedRead = 0;
1834}
1835
1836
1837template<typename ValueType_, typename Codec_>
1838void
1840{
1841 this->write(os, /*outputTransient=*/false);
1842}
1843
1844
1845template<typename ValueType_, typename Codec_>
1846void
1847TypedAttributeArray<ValueType_, Codec_>::write(std::ostream& os, bool outputTransient) const
1848{
1849 this->writeMetadata(os, outputTransient, /*paged=*/false);
1850 this->writeBuffers(os, outputTransient);
1851}
1852
1853
1854template<typename ValueType_, typename Codec_>
1855void
1856TypedAttributeArray<ValueType_, Codec_>::writeMetadata(std::ostream& os, bool outputTransient, bool paged) const
1857{
1858 if (!outputTransient && this->isTransient()) return;
1859
1860 if (mFlags & PARTIALREAD) {
1861 OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1862 }
1863
1864 uint8_t flags(mFlags);
1865 uint8_t serializationFlags(0);
1866 Index size(mSize);
1867 Index stride(mStrideOrTotalSize);
1868 bool strideOfOne(this->stride() == 1);
1869
1870 bool bloscCompression = io::getDataCompression(os) & io::COMPRESS_BLOSC;
1871
1872 // any compressed data needs to be loaded if out-of-core
1873 if (bloscCompression) this->doLoad();
1874
1875 size_t compressedBytes = 0;
1876
1877 if (!strideOfOne)
1878 {
1879 serializationFlags |= WRITESTRIDED;
1880 }
1881
1882 if (mIsUniform)
1883 {
1884 serializationFlags |= WRITEUNIFORM;
1885 if (bloscCompression && paged) serializationFlags |= WRITEPAGED;
1886 }
1887 else if (bloscCompression)
1888 {
1889 if (paged) serializationFlags |= WRITEPAGED;
1890 else {
1891 const char* charBuffer = reinterpret_cast<const char*>(this->data());
1892 const size_t inBytes = this->arrayMemUsage();
1893 compressedBytes = compression::bloscCompressedSize(charBuffer, inBytes);
1894 }
1895 }
1896
1897 Index64 bytes = /*flags*/ sizeof(Int16) + /*size*/ sizeof(Index);
1898
1899 bytes += (compressedBytes > 0) ? compressedBytes : this->arrayMemUsage();
1900
1901 // write data
1902
1903 os.write(reinterpret_cast<const char*>(&bytes), sizeof(Index64));
1904 os.write(reinterpret_cast<const char*>(&flags), sizeof(uint8_t));
1905 os.write(reinterpret_cast<const char*>(&serializationFlags), sizeof(uint8_t));
1906 os.write(reinterpret_cast<const char*>(&size), sizeof(Index));
1907
1908 // write strided
1909 if (!strideOfOne) os.write(reinterpret_cast<const char*>(&stride), sizeof(Index));
1910}
1911
1912
1913template<typename ValueType_, typename Codec_>
1914void
1915TypedAttributeArray<ValueType_, Codec_>::writeBuffers(std::ostream& os, bool outputTransient) const
1916{
1917 if (!outputTransient && this->isTransient()) return;
1918
1919 if (mFlags & PARTIALREAD) {
1920 OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1921 }
1922
1923 this->doLoad();
1924
1925 if (this->isUniform()) {
1926 os.write(reinterpret_cast<const char*>(this->data()), sizeof(StorageType));
1927 }
1929 {
1930 std::unique_ptr<char[]> compressedBuffer;
1931 size_t compressedBytes = 0;
1932 const char* charBuffer = reinterpret_cast<const char*>(this->data());
1933 const size_t inBytes = this->arrayMemUsage();
1934 compressedBuffer = compression::bloscCompress(charBuffer, inBytes, compressedBytes);
1935 if (compressedBuffer) {
1936 uint8_t bloscCompressed(1);
1937 os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1938 os.write(reinterpret_cast<const char*>(compressedBuffer.get()), compressedBytes);
1939 }
1940 else {
1941 uint8_t bloscCompressed(0);
1942 os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1943 os.write(reinterpret_cast<const char*>(this->data()), inBytes);
1944 }
1945 }
1946 else
1947 {
1948 uint8_t bloscCompressed(0);
1949 os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1950 os.write(reinterpret_cast<const char*>(this->data()), this->arrayMemUsage());
1951 }
1952}
1953
1954
1955template<typename ValueType_, typename Codec_>
1956void
1958{
1959 if (!outputTransient && this->isTransient()) return;
1960
1961 // paged compression only available when Blosc is enabled
1962 bool bloscCompression = io::getDataCompression(os.getOutputStream()) & io::COMPRESS_BLOSC;
1963 if (!bloscCompression) {
1964 if (!os.sizeOnly()) this->writeBuffers(os.getOutputStream(), outputTransient);
1965 return;
1966 }
1967
1968 if (mFlags & PARTIALREAD) {
1969 OPENVDB_THROW(IoError, "Cannot write out a partially-read AttributeArray.");
1970 }
1971
1972 this->doLoad();
1973
1974 os.write(reinterpret_cast<const char*>(this->data()), this->arrayMemUsage());
1975}
1976
1977
1978template<typename ValueType_, typename Codec_>
1979void
1980#if OPENVDB_ABI_VERSION_NUMBER >= 10
1982#else
1983TypedAttributeArray<ValueType_, Codec_>::doLoadUnsafe(const bool /*compression*/) const
1984#endif
1985{
1986 if (!(this->isOutOfCore())) return;
1987
1988 // this function expects the mutex to already be locked
1989
1990 auto* self = const_cast<TypedAttributeArray<ValueType_, Codec_>*>(this);
1991
1992 assert(self->mPageHandle);
1993 assert(!(self->mFlags & PARTIALREAD));
1994
1995 std::unique_ptr<char[]> buffer = self->mPageHandle->read();
1996
1997 self->mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1998
1999 self->mPageHandle.reset();
2000
2001 // clear all write and out-of-core flags
2002
2003 self->mOutOfCore = false;
2004}
2005
2006
2007template<typename ValueType_, typename Codec_>
2010{
2011 // use the faster 'unsafe' get and set methods as attribute handles
2012 // ensure data is in-core when constructed
2013
2019}
2020
2021
2022template<typename ValueType_, typename Codec_>
2023bool
2025{
2026 const TypedAttributeArray<ValueType_, Codec_>* const otherT = dynamic_cast<const TypedAttributeArray<ValueType_, Codec_>* >(&other);
2027 if(!otherT) return false;
2028 if(this->mSize != otherT->mSize ||
2029 this->mStrideOrTotalSize != otherT->mStrideOrTotalSize ||
2030 this->mIsUniform != otherT->mIsUniform ||
2031 this->attributeType() != this->attributeType()) return false;
2032
2033 this->doLoad();
2034 otherT->doLoad();
2035
2036 const StorageType *target = this->data(), *source = otherT->data();
2037 if (!target && !source) return true;
2038 if (!target || !source) return false;
2039 Index n = this->mIsUniform ? 1 : mSize;
2040 while (n && math::isExactlyEqual(*target++, *source++)) --n;
2041 return n == 0;
2042}
2043
2044
2045template<typename ValueType_, typename Codec_>
2046char*
2047TypedAttributeArray<ValueType_, Codec_>::dataAsByteArray()
2048{
2049 return reinterpret_cast<char*>(this->data());
2050}
2051
2052
2053template<typename ValueType_, typename Codec_>
2054const char*
2055TypedAttributeArray<ValueType_, Codec_>::dataAsByteArray() const
2056{
2057 return reinterpret_cast<const char*>(this->data());
2058}
2059
2060
2061////////////////////////////////////////
2062
2063
2064/// Accessor to call unsafe get and set methods based on templated Codec and Value
2065template <typename CodecType, typename ValueType>
2067{
2068 using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
2069 using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
2070
2071 /// Getter that calls to TypedAttributeArray::getUnsafe()
2072 /// @note Functor argument is provided but not required for the generic case
2073 static ValueType get(GetterPtr /*functor*/, const AttributeArray* array, const Index n) {
2075 }
2076
2077 /// Getter that calls to TypedAttributeArray::setUnsafe()
2078 /// @note Functor argument is provided but not required for the generic case
2079 static void set(SetterPtr /*functor*/, AttributeArray* array, const Index n, const ValueType& value) {
2081 }
2082};
2083
2084
2085/// Partial specialization when Codec is not known at compile-time to use the supplied functor instead
2086template <typename ValueType>
2087struct AccessorEval<UnknownCodec, ValueType>
2088{
2089 using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
2090 using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
2091
2092 /// Getter that calls the supplied functor
2093 static ValueType get(GetterPtr functor, const AttributeArray* array, const Index n) {
2094 return (*functor)(array, n);
2095 }
2096
2097 /// Setter that calls the supplied functor
2098 static void set(SetterPtr functor, AttributeArray* array, const Index n, const ValueType& value) {
2099 (*functor)(array, n, value);
2100 }
2101};
2102
2103
2104////////////////////////////////////////
2105
2106// AttributeHandle implementation
2107
2108template <typename ValueType, typename CodecType>
2110AttributeHandle<ValueType, CodecType>::create(const AttributeArray& array, const bool collapseOnDestruction)
2111{
2113 new AttributeHandle<ValueType, CodecType>(array, collapseOnDestruction));
2114}
2115
2116template <typename ValueType, typename CodecType>
2117AttributeHandle<ValueType, CodecType>::AttributeHandle(const AttributeArray& array, const bool collapseOnDestruction)
2118 : mArray(&array)
2119 , mStrideOrTotalSize(array.hasConstantStride() ? array.stride() : 1)
2120 , mSize(array.hasConstantStride() ? array.size() : array.dataSize())
2121 , mCollapseOnDestruction(collapseOnDestruction && array.isStreaming())
2122{
2123 if (!this->compatibleType<std::is_same<CodecType, UnknownCodec>::value>()) {
2124 OPENVDB_THROW(TypeError, "Cannot bind handle due to incompatible type of AttributeArray.");
2125 }
2126
2127 // load data if delay-loaded
2128
2129 mArray->loadData();
2130
2131 // bind getter and setter methods
2132
2134 assert(accessor);
2135
2136 AttributeArray::Accessor<ValueType>* typedAccessor = static_cast<AttributeArray::Accessor<ValueType>*>(accessor.get());
2137
2138 mGetter = typedAccessor->mGetter;
2139 mSetter = typedAccessor->mSetter;
2140 mCollapser = typedAccessor->mCollapser;
2141 mFiller = typedAccessor->mFiller;
2142}
2143
2144template <typename ValueType, typename CodecType>
2146{
2147 // if enabled, attribute is collapsed on destruction of the handle to save memory
2148 if (mCollapseOnDestruction) const_cast<AttributeArray*>(this->mArray)->collapse();
2149}
2150
2151template <typename ValueType, typename CodecType>
2152template <bool IsUnknownCodec>
2153typename std::enable_if<IsUnknownCodec, bool>::type
2155{
2156 // if codec is unknown, just check the value type
2157
2158 return mArray->hasValueType<ValueType>();
2159}
2160
2161template <typename ValueType, typename CodecType>
2162template <bool IsUnknownCodec>
2163typename std::enable_if<!IsUnknownCodec, bool>::type
2164AttributeHandle<ValueType, CodecType>::compatibleType() const
2165{
2166 // if the codec is known, check the value type and codec
2167
2168 return mArray->isType<TypedAttributeArray<ValueType, CodecType>>();
2169}
2170
2171template <typename ValueType, typename CodecType>
2173{
2174 assert(mArray);
2175 return *mArray;
2176}
2177
2178template <typename ValueType, typename CodecType>
2180{
2181 Index index = n * mStrideOrTotalSize + m;
2182 assert(index < (mSize * mStrideOrTotalSize));
2183 return index;
2184}
2185
2186template <typename ValueType, typename CodecType>
2188{
2189 return this->get<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, m));
2190}
2191
2192template <typename ValueType, typename CodecType>
2193template <bool IsUnknownCodec>
2194typename std::enable_if<IsUnknownCodec, ValueType>::type
2196{
2197 // if the codec is unknown, use the getter functor
2198
2199 return (*mGetter)(mArray, index);
2200}
2201
2202template <typename ValueType, typename CodecType>
2203template <bool IsUnknownCodec>
2204typename std::enable_if<!IsUnknownCodec, ValueType>::type
2206{
2207 // if the codec is known, call the method on the attribute array directly
2208
2210}
2211
2212template <typename ValueType, typename CodecType>
2214{
2215 return mArray->isUniform();
2216}
2217
2218template <typename ValueType, typename CodecType>
2220{
2221 return mArray->hasConstantStride();
2222}
2223
2224////////////////////////////////////////
2225
2226// AttributeWriteHandle implementation
2227
2228template <typename ValueType, typename CodecType>
2231{
2234}
2235
2236template <typename ValueType, typename CodecType>
2238 : AttributeHandle<ValueType, CodecType>(array, /*collapseOnDestruction=*/false)
2239{
2240 if (expand) array.expand();
2241}
2242
2243template <typename ValueType, typename CodecType>
2245{
2246 this->set<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, 0), value);
2247}
2248
2249template <typename ValueType, typename CodecType>
2251{
2252 this->set<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, m), value);
2253}
2254
2255template <typename ValueType, typename CodecType>
2257{
2258 const_cast<AttributeArray*>(this->mArray)->expand(fill);
2259}
2260
2261template <typename ValueType, typename CodecType>
2263{
2264 const_cast<AttributeArray*>(this->mArray)->collapse();
2265}
2266
2267template <typename ValueType, typename CodecType>
2269{
2270 return const_cast<AttributeArray*>(this->mArray)->compact();
2271}
2272
2273template <typename ValueType, typename CodecType>
2275{
2276 this->mCollapser(const_cast<AttributeArray*>(this->mArray), uniformValue);
2277}
2278
2279template <typename ValueType, typename CodecType>
2281{
2282 this->mFiller(const_cast<AttributeArray*>(this->mArray), value);
2283}
2284
2285template <typename ValueType, typename CodecType>
2286template <bool IsUnknownCodec>
2287typename std::enable_if<IsUnknownCodec, void>::type
2288AttributeWriteHandle<ValueType, CodecType>::set(Index index, const ValueType& value) const
2289{
2290 // if the codec is unknown, use the setter functor
2291
2292 (*this->mSetter)(const_cast<AttributeArray*>(this->mArray), index, value);
2293}
2294
2295template <typename ValueType, typename CodecType>
2296template <bool IsUnknownCodec>
2297typename std::enable_if<!IsUnknownCodec, void>::type
2298AttributeWriteHandle<ValueType, CodecType>::set(Index index, const ValueType& value) const
2299{
2300 // if the codec is known, call the method on the attribute array directly
2301
2302 TypedAttributeArray<ValueType, CodecType>::setUnsafe(const_cast<AttributeArray*>(this->mArray), index, value);
2303}
2304
2305template <typename ValueType, typename CodecType>
2307{
2308 assert(this->mArray);
2309 return *const_cast<AttributeArray*>(this->mArray);
2310}
2311
2312
2313} // namespace points
2314} // namespace OPENVDB_VERSION_NAME
2315} // namespace openvdb
2316
2317#endif // OPENVDB_POINTS_ATTRIBUTE_ARRAY_HAS_BEEN_INCLUDED
ValueT value
Definition GridBuilder.h:1290
Index Iterators.
#define OPENVDB_API
Definition Platform.h:280
#define OPENVDB_DEPRECATED_MESSAGE(msg)
Definition Platform.h:154
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:835
virtual ~AttributeHandle()
Definition AttributeArray.h:2145
Index size() const
Definition AttributeArray.h:857
void(*)(AttributeArray *array, const ValueType &value) ValuePtr
Definition AttributeArray.h:844
SetterPtr mSetter
Definition AttributeArray.h:872
Index stride() const
Definition AttributeArray.h:856
std::shared_ptr< Handle > Ptr
Definition AttributeArray.h:838
GetterPtr mGetter
Definition AttributeArray.h:871
void(*)(AttributeArray *array, const Index n, const ValueType &value) SetterPtr
Definition AttributeArray.h:843
static Ptr create(const AttributeArray &array, const bool collapseOnDestruction=true)
Definition AttributeArray.h:2110
AttributeHandle(const AttributeArray &array, const bool collapseOnDestruction=true)
Definition AttributeArray.h:2117
ValuePtr mFiller
Definition AttributeArray.h:874
ValueType get(Index n, Index m=0) const
Definition AttributeArray.h:2187
ValueType(*)(const AttributeArray *array, const Index n) GetterPtr
Definition AttributeArray.h:842
AttributeHandle(const AttributeHandle &)=default
ValuePtr mCollapser
Definition AttributeArray.h:873
const AttributeArray & array() const
Definition AttributeArray.h:2172
const AttributeArray * mArray
Definition AttributeArray.h:869
bool isUniform() const
Definition AttributeArray.h:2213
std::unique_ptr< Handle > UniquePtr
Definition AttributeArray.h:839
bool hasConstantStride() const
Definition AttributeArray.h:2219
AttributeHandle & operator=(const AttributeHandle &)=default
Index index(Index n, Index m) const
Definition AttributeArray.h:2179
Write-able version of AttributeHandle.
Definition AttributeArray.h:906
AttributeWriteHandle(AttributeArray &array, const bool expand=true)
Definition AttributeArray.h:2237
std::shared_ptr< Handle > Ptr
Definition AttributeArray.h:909
bool compact()
Compact the existing array to become uniform if all values are identical.
Definition AttributeArray.h:2268
void collapse()
Replace the existing array with a uniform value (zero if none provided).
Definition AttributeArray.h:2262
void set(Index n, const ValueType &value)
Definition AttributeArray.h:2244
void expand(bool fill=true)
If this array is uniform, replace it with an array of length size().
Definition AttributeArray.h:2256
AttributeArray & array()
Definition AttributeArray.h:2306
std::unique_ptr< Handle > ScopedPtr
Definition AttributeArray.h:910
static Ptr create(AttributeArray &array, const bool expand=true)
Definition AttributeArray.h:2230
void set(Index n, Index m, const ValueType &value)
Definition AttributeArray.h:2250
void fill(const ValueType &value)
Fill the existing array with the given value.
Definition AttributeArray.h:2280
void collapse(const ValueType &uniformValue)
Definition AttributeArray.h:2274
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:1392
ValueType getUnsafe(Index n) const
Return the value at index n (assumes in-core)
Definition AttributeArray.h:1401
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:1745
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:2009
void write(std::ostream &os, bool outputTransient) const override
Definition AttributeArray.h:1847
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:1384
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:1129
bool isDataLoaded() const override
Return true if all data has been loaded.
Definition AttributeArray.h:1677
bool isOutOfCore() const
Return true if this buffer's values have not yet been read from disk.
Definition AttributeArray.h:1637
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:1358
bool validData() const
Verify that data is not out-of-core or in a partially-read state.
Definition AttributeArray.h:783
bool compact() override
Compact the existing array to become uniform if all values are identical.
Definition AttributeArray.h:1539
static TypedAttributeArray & cast(AttributeArray &attributeArray)
Cast an AttributeArray to TypedAttributeArray<T>
Definition AttributeArray.h:1253
TypedAttributeArray & operator=(TypedAttributeArray &&)=delete
Move assignment operator disabled.
void writeBuffers(std::ostream &os, bool outputTransient) const override
Definition AttributeArray.h:1915
AttributeArray::Ptr copy() const override
Definition AttributeArray.h:1273
Index storageTypeSize() const override
Definition AttributeArray.h:639
bool valueTypeIsQuaternion() const override
Return true if the value type is a quaternion.
Definition AttributeArray.h:1366
void readPagedBuffers(compression::PagedInputStream &) override
Read attribute buffers from a paged stream.
Definition AttributeArray.h:1784
void set(Index n, const ValueType &value)
Set value at the given index n.
Definition AttributeArray.h:1465
TypedAttributeArray & operator=(const TypedAttributeArray &)
Definition AttributeArray.h:1179
static void registerType()
Register this attribute type along with a factory function.
Definition AttributeArray.h:1225
bool valueTypeIsFloatingPoint() const override
Return true if the value type is floating point.
Definition AttributeArray.h:1329
void writeMetadata(std::ostream &os, bool outputTransient, bool paged) const override
Definition AttributeArray.h:1856
static void unregisterType()
Remove this attribute type from the registry.
Definition AttributeArray.h:1233
const StorageType * data() const
Definition AttributeArray.h:780
void loadData() const override
Ensures all data is in-core.
Definition AttributeArray.h:1669
void read(std::istream &) override
Read attribute data from a stream.
Definition AttributeArray.h:1685
ValueType get(Index n) const
Return the value at index n.
Definition AttributeArray.h:1413
TypedAttributeArray(TypedAttributeArray &&)=delete
Move constructor disabled.
static const NamePair & attributeType()
Return the name of this attribute's type (includes codec)
Definition AttributeArray.h:1206
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:1349
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:1556
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:1518
static bool isRegistered()
Return true if this attribute type is registered.
Definition AttributeArray.h:1217
bool valueTypeIsMatrix() const override
Return true if the value type is a matrix.
Definition AttributeArray.h:1375
StorageType * data()
Return the raw data buffer.
Definition AttributeArray.h:779
const StorageType * constData() const
Return the raw data buffer.
Definition AttributeArray.h:772
void fill(const ValueType &value)
Fill the existing array with the given value.
Definition AttributeArray.h:1586
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:1241
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:1957
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:1450
void readMetadata(std::istream &) override
Read attribute metadata from a stream.
Definition AttributeArray.h:1694
#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:2093
void(*)(AttributeArray *array, const Index n, const ValueType &value) SetterPtr
Definition AttributeArray.h:2090
static void set(SetterPtr functor, AttributeArray *array, const Index n, const ValueType &value)
Setter that calls the supplied functor.
Definition AttributeArray.h:2098
ValueType(*)(const AttributeArray *array, const Index n) GetterPtr
Definition AttributeArray.h:2089
Accessor to call unsafe get and set methods based on templated Codec and Value.
Definition AttributeArray.h:2067
void(*)(AttributeArray *array, const Index n, const ValueType &value) SetterPtr
Definition AttributeArray.h:2069
static ValueType get(GetterPtr, const AttributeArray *array, const Index n)
Definition AttributeArray.h:2073
ValueType(*)(const AttributeArray *array, const Index n) GetterPtr
Definition AttributeArray.h:2068
static void set(SetterPtr, AttributeArray *array, const Index n, const ValueType &value)
Definition AttributeArray.h:2079
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