HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AttributeArray.h
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2012-2018 DreamWorks Animation LLC
4 //
5 // All rights reserved. This software is distributed under the
6 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
7 //
8 // Redistributions of source code must retain the above copyright
9 // and license notice and the following restrictions and disclaimer.
10 //
11 // * Neither the name of DreamWorks Animation nor the names of
12 // its contributors may be used to endorse or promote products derived
13 // from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
27 // LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
28 //
29 ///////////////////////////////////////////////////////////////////////////
30 
31 /// @file points/AttributeArray.h
32 ///
33 /// @authors Dan Bailey, Mihai Alden, Nick Avramoussis, James Bird, Khang Ngo
34 ///
35 /// @brief Attribute Array storage templated on type and compression codec.
36 
37 #ifndef OPENVDB_POINTS_ATTRIBUTE_ARRAY_HAS_BEEN_INCLUDED
38 #define OPENVDB_POINTS_ATTRIBUTE_ARRAY_HAS_BEEN_INCLUDED
39 
40 #include <openvdb/Types.h>
42 #include <openvdb/util/Name.h>
43 #include <openvdb/util/logging.h>
44 #include <openvdb/io/io.h> // MappedFile
45 #include <openvdb/io/Compression.h> // COMPRESS_BLOSC
46 
47 #include "IndexIterator.h"
48 #include "StreamCompression.h"
49 
50 #include <tbb/spin_mutex.h>
51 #include <tbb/atomic.h>
52 
53 #include <memory>
54 #include <string>
55 #include <type_traits>
56 
57 
58 class TestAttributeArray;
59 
60 namespace openvdb {
62 namespace OPENVDB_VERSION_NAME {
63 
64 
65 using NamePair = std::pair<Name, Name>;
66 
67 namespace points {
68 
69 
70 ////////////////////////////////////////
71 
72 // Utility methods
73 
74 template <typename IntegerT, typename FloatT>
75 inline IntegerT
77 {
78  static_assert(std::is_unsigned<IntegerT>::value, "IntegerT must be unsigned");
79  if (FloatT(0.0) > s) return std::numeric_limits<IntegerT>::min();
80  else if (FloatT(1.0) <= s) return std::numeric_limits<IntegerT>::max();
81  return IntegerT(std::floor(s * FloatT(std::numeric_limits<IntegerT>::max())));
82 }
83 
84 
85 template <typename FloatT, typename IntegerT>
86 inline FloatT
87 fixedPointToFloatingPoint(const IntegerT s)
88 {
89  static_assert(std::is_unsigned<IntegerT>::value, "IntegerT must be unsigned");
90  return FloatT(s) / FloatT((std::numeric_limits<IntegerT>::max()));
91 }
92 
93 template <typename IntegerVectorT, typename FloatT>
94 inline IntegerVectorT
96 {
97  return IntegerVectorT(
98  floatingPointToFixedPoint<typename IntegerVectorT::ValueType>(v.x()),
99  floatingPointToFixedPoint<typename IntegerVectorT::ValueType>(v.y()),
100  floatingPointToFixedPoint<typename IntegerVectorT::ValueType>(v.z()));
101 }
102 
103 template <typename FloatVectorT, typename IntegerT>
104 inline FloatVectorT
106 {
107  return FloatVectorT(
108  fixedPointToFloatingPoint<typename FloatVectorT::ValueType>(v.x()),
109  fixedPointToFloatingPoint<typename FloatVectorT::ValueType>(v.y()),
110  fixedPointToFloatingPoint<typename FloatVectorT::ValueType>(v.z()));
111 }
112 
113 
114 ////////////////////////////////////////
115 
116 
117 /// Base class for storing attribute data
119 {
120 protected:
121  struct AccessorBase;
122  template <typename T> struct Accessor;
123 
124  using AccessorBasePtr = std::shared_ptr<AccessorBase>;
125 
126 public:
127  enum Flag {
128  TRANSIENT = 0x1, /// by default not written to disk
129  HIDDEN = 0x2, /// hidden from UIs or iterators
130  OUTOFCORE = 0x4, /// data not yet loaded from disk (deprecated flag as of ABI=5)
131  CONSTANTSTRIDE = 0x8, /// stride size does not vary in the array
132  STREAMING = 0x10 /// streaming mode collapses attributes when first accessed
133  };
134 
136  WRITESTRIDED = 0x1, /// data is marked as strided when written
137  WRITEUNIFORM = 0x2, /// data is marked as uniform when written
138  WRITEMEMCOMPRESS = 0x4, /// data is marked as compressed in-memory when written
139  WRITEPAGED = 0x8 /// data is written out in pages
140  };
141 
142  using Ptr = std::shared_ptr<AttributeArray>;
143  using ConstPtr = std::shared_ptr<const AttributeArray>;
144 
145  using FactoryMethod = Ptr (*)(Index, Index, bool);
146 
147  template <typename ValueType, typename CodecType> friend class AttributeHandle;
148 
149  AttributeArray() = default;
150  AttributeArray(const AttributeArray&) = default;
151  AttributeArray& operator=(const AttributeArray&) = default;
152  virtual ~AttributeArray() = default;
153 
154  /// Return a copy of this attribute.
155  virtual AttributeArray::Ptr copy() const = 0;
156 
157  /// Return an uncompressed copy of this attribute (will return a copy if not compressed).
158  virtual AttributeArray::Ptr copyUncompressed() const = 0;
159 
160  /// Return the number of elements in this array.
161  /// @note This does not count each data element in a strided array
162  virtual Index size() const = 0;
163 
164  /// Return the stride of this array.
165  /// @note a return value of zero means a non-constant stride
166  virtual Index stride() const = 0;
167 
168  /// Return the total number of data elements in this array.
169  /// @note This counts each data element in a strided array
170  virtual Index dataSize() const = 0;
171 
172  /// Return the number of bytes of memory used by this attribute.
173  virtual size_t memUsage() const = 0;
174 
175  /// Create a new attribute array of the given (registered) type, length and stride.
176  static Ptr create(const NamePair& type, Index length, Index stride = 1, bool constantStride = true);
177  /// Return @c true if the given attribute type name is registered.
178  static bool isRegistered(const NamePair& type);
179  /// Clear the attribute type registry.
180  static void clearRegistry();
181 
182  /// Return the name of this attribute's type.
183  virtual const NamePair& type() const = 0;
184  /// Return @c true if this attribute is of the same type as the template parameter.
185  template<typename AttributeArrayType>
186  bool isType() const { return this->type() == AttributeArrayType::attributeType(); }
187 
188  /// Return @c true if this attribute has a value type the same as the template parameter
189  template<typename ValueType>
190  bool hasValueType() const { return this->type().first == typeNameAsString<ValueType>(); }
191 
192  /// Set value at given index @a n from @a sourceIndex of another @a sourceArray
193  virtual void set(const Index n, const AttributeArray& sourceArray, const Index sourceIndex) = 0;
194 
195  /// Return @c true if this array is stored as a single uniform value.
196  virtual bool isUniform() const = 0;
197  /// @brief If this array is uniform, replace it with an array of length size().
198  /// @param fill if true, assign the uniform value to each element of the array.
199  virtual void expand(bool fill = true) = 0;
200  /// Replace the existing array with a uniform zero value.
201  virtual void collapse() = 0;
202  /// Compact the existing array to become uniform if all values are identical
203  virtual bool compact() = 0;
204 
205  /// Return @c true if this array is compressed.
206  bool isCompressed() const { return mCompressedBytes != 0; }
207  /// Compress the attribute array.
208  virtual bool compress() = 0;
209  /// Uncompress the attribute array.
210  virtual bool decompress() = 0;
211 
212  /// @brief Specify whether this attribute should be hidden (e.g., from UI or iterators).
213  /// @details This is useful if the attribute is used for blind data or as scratch space
214  /// for a calculation.
215  /// @note Attributes are not hidden by default.
216  void setHidden(bool state);
217  /// Return @c true if this attribute is hidden (e.g., from UI or iterators).
218  bool isHidden() const { return bool(mFlags & HIDDEN); }
219 
220  /// @brief Specify whether this attribute should only exist in memory
221  /// and not be serialized during stream output.
222  /// @note Attributes are not transient by default.
223  void setTransient(bool state);
224  /// Return @c true if this attribute is not serialized during stream output.
225  bool isTransient() const { return bool(mFlags & TRANSIENT); }
226 
227  /// @brief Specify whether this attribute is to be streamed off disk, in which
228  /// case, the attributes are collapsed after being first loaded leaving them
229  /// in a destroyed state.
230  /// @note This operation is not thread-safe.
231  void setStreaming(bool state);
232  /// Return @c true if this attribute is in streaming mode.
233  bool isStreaming() const { return bool(mFlags & STREAMING); }
234 
235  /// Return @c true if this attribute has a constant stride
236  bool hasConstantStride() const { return bool(mFlags & CONSTANTSTRIDE); }
237 
238  /// @brief Retrieve the attribute array flags
239  uint8_t flags() const { return mFlags; }
240 
241  /// Read attribute metadata and buffers from a stream.
242  virtual void read(std::istream&) = 0;
243  /// Write attribute metadata and buffers to a stream.
244  /// @param outputTransient if true, write out transient attributes
245  virtual void write(std::ostream&, bool outputTransient) const = 0;
246  /// Write attribute metadata and buffers to a stream, don't write transient attributes.
247  virtual void write(std::ostream&) const = 0;
248 
249  /// Read attribute metadata from a stream.
250  virtual void readMetadata(std::istream&) = 0;
251  /// Write attribute metadata to a stream.
252  /// @param outputTransient if true, write out transient attributes
253  /// @param paged if true, data is written out in pages
254  virtual void writeMetadata(std::ostream&, bool outputTransient, bool paged) const = 0;
255 
256  /// Read attribute buffers from a stream.
257  virtual void readBuffers(std::istream&) = 0;
258  /// Write attribute buffers to a stream.
259  /// @param outputTransient if true, write out transient attributes
260  virtual void writeBuffers(std::ostream&, bool outputTransient) const = 0;
261 
262  /// Read attribute buffers from a paged stream.
263  virtual void readPagedBuffers(compression::PagedInputStream&) = 0;
264  /// Write attribute buffers to a paged stream.
265  /// @param outputTransient if true, write out transient attributes
266  virtual void writePagedBuffers(compression::PagedOutputStream&, bool outputTransient) const = 0;
267 
268  /// Ensures all data is in-core
269  virtual void loadData() const = 0;
270 
271  /// Check the compressed bytes and flags. If they are equal, perform a deeper
272  /// comparison check necessary on the inherited types (TypedAttributeArray)
273  /// Requires non operator implementation due to inheritance
274  bool operator==(const AttributeArray& other) const;
275  bool operator!=(const AttributeArray& other) const { return !this->operator==(other); }
276 
277 private:
278  friend class ::TestAttributeArray;
279 
280  /// Virtual function used by the comparison operator to perform
281  /// comparisons on inherited types
282  virtual bool isEqual(const AttributeArray& other) const = 0;
283 
284 protected:
285  /// @brief Specify whether this attribute has a constant stride or not.
286  void setConstantStride(bool state);
287 
288  /// Obtain an Accessor that stores getter and setter functors.
289  virtual AccessorBasePtr getAccessor() const = 0;
290 
291  /// Register a attribute type along with a factory function.
292  static void registerType(const NamePair& type, FactoryMethod);
293  /// Remove a attribute type from the registry.
294  static void unregisterType(const NamePair& type);
295 
296  size_t mCompressedBytes = 0;
297  uint8_t mFlags = 0;
298  uint8_t mSerializationFlags = 0;
299 
300 #if OPENVDB_ABI_VERSION_NUMBER >= 5
301  tbb::atomic<Index32> mOutOfCore = 0; // interpreted as bool
302 #endif
303 
304  /// used for out-of-core, paged reading
306 }; // class AttributeArray
307 
308 
309 ////////////////////////////////////////
310 
311 
312 /// Accessor base class for AttributeArray storage where type is not available
313 struct AttributeArray::AccessorBase { virtual ~AccessorBase() = default; };
314 
315 /// Templated Accessor stores typed function pointers used in binding
316 /// AttributeHandles
317 template <typename T>
319 {
320  using GetterPtr = T (*)(const AttributeArray* array, const Index n);
321  using SetterPtr = void (*)(AttributeArray* array, const Index n, const T& value);
322  using ValuePtr = void (*)(AttributeArray* array, const T& value);
323 
324  Accessor(GetterPtr getter, SetterPtr setter, ValuePtr collapser, ValuePtr filler) :
325  mGetter(getter), mSetter(setter), mCollapser(collapser), mFiller(filler) { }
326 
331 }; // struct AttributeArray::Accessor
332 
333 
334 ////////////////////////////////////////
335 
336 
337 namespace attribute_traits
338 {
339  template <typename T> struct TruncateTrait { };
340  template <> struct TruncateTrait<float> { using Type = half; };
341  template <> struct TruncateTrait<int> { using Type = short; };
342 
343  template <typename T> struct TruncateTrait<math::Vec3<T>> {
345  };
346 
347  template <bool OneByte, typename T> struct UIntTypeTrait { };
348  template<typename T> struct UIntTypeTrait</*OneByte=*/true, T> { using Type = uint8_t; };
349  template<typename T> struct UIntTypeTrait</*OneByte=*/false, T> { using Type = uint16_t; };
350  template<typename T> struct UIntTypeTrait</*OneByte=*/true, math::Vec3<T>> {
352  };
353  template<typename T> struct UIntTypeTrait</*OneByte=*/false, math::Vec3<T>> {
355  };
356 }
357 
358 
359 ////////////////////////////////////////
360 
361 
362 // Attribute codec schemes
363 
364 struct UnknownCodec { };
365 
366 
367 struct NullCodec
368 {
369  template <typename T>
370  struct Storage { using Type = T; };
371 
372  template<typename ValueType> static void decode(const ValueType&, ValueType&);
373  template<typename ValueType> static void encode(const ValueType&, ValueType&);
374  static const char* name() { return "null"; }
375 };
376 
377 
379 {
380  template <typename T>
382 
383  template<typename StorageType, typename ValueType> static void decode(const StorageType&, ValueType&);
384  template<typename StorageType, typename ValueType> static void encode(const ValueType&, StorageType&);
385  static const char* name() { return "trnc"; }
386 };
387 
388 
389 // Fixed-point codec range for voxel-space positions [-0.5,0.5]
391 {
392  static const char* name() { return "fxpt"; }
393  template <typename ValueType> static ValueType encode(const ValueType& value) { return value + ValueType(0.5); }
394  template <typename ValueType> static ValueType decode(const ValueType& value) { return value - ValueType(0.5); }
395 };
396 
397 
398 // Fixed-point codec range for unsigned values in the unit range [0.0,1.0]
399 struct UnitRange
400 {
401  static const char* name() { return "ufxpt"; }
402  template <typename ValueType> static ValueType encode(const ValueType& value) { return value; }
403  template <typename ValueType> static ValueType decode(const ValueType& value) { return value; }
404 };
405 
406 
407 template <bool OneByte, typename Range=PositionRange>
409 {
410  template <typename T>
412 
413  template<typename StorageType, typename ValueType> static void decode(const StorageType&, ValueType&);
414  template<typename StorageType, typename ValueType> static void encode(const ValueType&, StorageType&);
415 
416  static const char* name() {
417  static const std::string Name = std::string(Range::name()) + (OneByte ? "8" : "16");
418  return Name.c_str();
419  }
420 };
421 
422 
424 {
425  using StorageType = uint16_t;
426 
427  template <typename T>
428  struct Storage { using Type = StorageType; };
429 
430  template<typename T> static void decode(const StorageType&, math::Vec3<T>&);
431  template<typename T> static void encode(const math::Vec3<T>&, StorageType&);
432  static const char* name() { return "uvec"; }
433 };
434 
435 
436 ////////////////////////////////////////
437 
438 
439 /// Typed class for storing attribute data
440 template<typename ValueType_, typename Codec_ = NullCodec>
442 {
443 public:
444  using Ptr = std::shared_ptr<TypedAttributeArray>;
445  using ConstPtr = std::shared_ptr<const TypedAttributeArray>;
446 
447  using ValueType = ValueType_;
448  using Codec = Codec_;
449  using StorageType = typename Codec::template Storage<ValueType>::Type;
450 
451  //////////
452 
453  /// Default constructor, always constructs a uniform attribute.
454  explicit TypedAttributeArray(Index n = 1, Index strideOrTotalSize = 1, bool constantStride = true,
455  const ValueType& uniformValue = zeroVal<ValueType>());
456  /// Deep copy constructor (optionally decompress during copy).
457  TypedAttributeArray(const TypedAttributeArray&, bool uncompress = false);
458  /// Deep copy assignment operator.
460  /// Move constructor disabled.
462  /// Move assignment operator disabled.
464 
465  virtual ~TypedAttributeArray() { this->deallocate(); }
466 
467  /// Return a copy of this attribute.
468  AttributeArray::Ptr copy() const override;
469 
470  /// Return an uncompressed copy of this attribute (will just return a copy if not compressed).
471  AttributeArray::Ptr copyUncompressed() const override;
472 
473  /// Return a new attribute array of the given length @a n and @a stride with uniform value zero.
474  static Ptr create(Index n, Index strideOrTotalSize = 1, bool constantStride = true);
475 
476  /// Cast an AttributeArray to TypedAttributeArray<T>
477  static TypedAttributeArray& cast(AttributeArray& attributeArray);
478 
479  /// Cast an AttributeArray to TypedAttributeArray<T>
480  static const TypedAttributeArray& cast(const AttributeArray& attributeArray);
481 
482  /// Return the name of this attribute's type (includes codec)
483  static const NamePair& attributeType();
484  /// Return the name of this attribute's type.
485  const NamePair& type() const override { return attributeType(); }
486 
487  /// Return @c true if this attribute type is registered.
488  static bool isRegistered();
489  /// Register this attribute type along with a factory function.
490  static void registerType();
491  /// Remove this attribute type from the registry.
492  static void unregisterType();
493 
494  /// Return the number of elements in this array.
495  Index size() const override { return mSize; }
496 
497  /// Return the stride of this array.
498  /// @note A return value of zero means a variable stride
499  Index stride() const override { return hasConstantStride() ? mStrideOrTotalSize : 0; }
500 
501  /// Return the size of the data in this array.
502  Index dataSize() const override {
503  return hasConstantStride() ? mSize * mStrideOrTotalSize : mStrideOrTotalSize;
504  }
505 
506  /// Return the number of bytes of memory used by this attribute.
507  size_t memUsage() const override;
508 
509  /// Return the value at index @a n (assumes uncompressed and in-core)
510  ValueType getUnsafe(Index n) const;
511  /// Return the value at index @a n
512  ValueType get(Index n) const;
513  /// Return the @a value at index @a n (assumes uncompressed and in-core)
514  template<typename T> void getUnsafe(Index n, T& value) const;
515  /// Return the @a value at index @a n
516  template<typename T> void get(Index n, T& value) const;
517 
518  /// Non-member equivalent to getUnsafe() that static_casts array to this TypedAttributeArray
519  /// (assumes uncompressed and in-core)
520  static ValueType getUnsafe(const AttributeArray* array, const Index n);
521 
522  /// Set @a value at the given index @a n (assumes uncompressed and in-core)
523  void setUnsafe(Index n, const ValueType& value);
524  /// Set @a value at the given index @a n
525  void set(Index n, const ValueType& value);
526  /// Set @a value at the given index @a n (assumes uncompressed and in-core)
527  template<typename T> void setUnsafe(Index n, const T& value);
528  /// Set @a value at the given index @a n
529  template<typename T> void set(Index n, const T& value);
530 
531  /// Non-member equivalent to setUnsafe() that static_casts array to this TypedAttributeArray
532  /// (assumes uncompressed and in-core)
533  static void setUnsafe(AttributeArray* array, const Index n, const ValueType& value);
534 
535  /// Set value at given index @a n from @a sourceIndex of another @a sourceArray
536  void set(const Index n, const AttributeArray& sourceArray, const Index sourceIndex) override;
537 
538  /// Return @c true if this array is stored as a single uniform value.
539  bool isUniform() const override { return mIsUniform; }
540  /// @brief Replace the single value storage with an array of length size().
541  /// @note Non-uniform attributes are unchanged.
542  /// @param fill toggle to initialize the array elements with the pre-expanded value.
543  void expand(bool fill = true) override;
544  /// Replace the existing array with a uniform zero value.
545  void collapse() override;
546  /// Compact the existing array to become uniform if all values are identical
547  bool compact() override;
548 
549  /// Replace the existing array with the given uniform value.
550  void collapse(const ValueType& uniformValue);
551  /// @brief Fill the existing array with the given value.
552  /// @note Identical to collapse() except a non-uniform array will not become uniform.
553  void fill(const ValueType& value);
554 
555  /// Non-member equivalent to collapse() that static_casts array to this TypedAttributeArray
556  static void collapse(AttributeArray* array, const ValueType& value);
557  /// Non-member equivalent to fill() that static_casts array to this TypedAttributeArray
558  static void fill(AttributeArray* array, const ValueType& value);
559 
560  /// Compress the attribute array.
561  bool compress() override;
562  /// Uncompress the attribute array.
563  bool decompress() override;
564 
565  /// Read attribute data from a stream.
566  void read(std::istream&) override;
567  /// Write attribute data to a stream.
568  /// @param os the output stream
569  /// @param outputTransient if true, write out transient attributes
570  void write(std::ostream& os, bool outputTransient) const override;
571  /// Write attribute data to a stream, don't write transient attributes.
572  void write(std::ostream&) const override;
573 
574  /// Read attribute metadata from a stream.
575  void readMetadata(std::istream&) override;
576  /// Write attribute metadata to a stream.
577  /// @param os the output stream
578  /// @param outputTransient if true, write out transient attributes
579  /// @param paged if true, data is written out in pages
580  void writeMetadata(std::ostream& os, bool outputTransient, bool paged) const override;
581 
582  /// Read attribute buffers from a stream.
583  void readBuffers(std::istream&) override;
584  /// Write attribute buffers to a stream.
585  /// @param os the output stream
586  /// @param outputTransient if true, write out transient attributes
587  void writeBuffers(std::ostream& os, bool outputTransient) const override;
588 
589  /// Read attribute buffers from a paged stream.
591  /// Write attribute buffers to a paged stream.
592  /// @param os the output stream
593  /// @param outputTransient if true, write out transient attributes
594  void writePagedBuffers(compression::PagedOutputStream& os, bool outputTransient) const override;
595 
596  /// Return @c true if this buffer's values have not yet been read from disk.
597  inline bool isOutOfCore() const;
598 
599  /// Ensures all data is in-core
600  void loadData() const override;
601 
602 protected:
603  AccessorBasePtr getAccessor() const override;
604 
605 private:
606  /// Load data from memory-mapped file.
607  inline void doLoad() const;
608  /// Load data from memory-mapped file (unsafe as this function is not protected by a mutex).
609  /// @param compression if true, loading previously compressed data will re-compressed it
610  inline void doLoadUnsafe(const bool compression = true) const;
611  /// Compress in-core data assuming mutex is locked
612  inline bool compressUnsafe();
613 
614  /// Toggle out-of-core state
615  inline void setOutOfCore(const bool);
616 
617  /// Compare the this data to another attribute array. Used by the base class comparison operator
618  bool isEqual(const AttributeArray& other) const override;
619 
620  size_t arrayMemUsage() const;
621  void allocate();
622  void deallocate();
623 
624  /// Helper function for use with registerType()
625  static AttributeArray::Ptr factory(Index n, Index strideOrTotalSize, bool constantStride) {
626  return TypedAttributeArray::create(n, strideOrTotalSize, constantStride);
627  }
628 
629  static tbb::atomic<const NamePair*> sTypeName;
630  std::unique_ptr<StorageType[]> mData;
631  Index mSize;
632  Index mStrideOrTotalSize;
633  bool mIsUniform = false;
634  tbb::spin_mutex mMutex;
635 }; // class TypedAttributeArray
636 
637 
638 ////////////////////////////////////////
639 
640 
641 /// AttributeHandles provide access to specific TypedAttributeArray methods without needing
642 /// to know the compression codec, however these methods also incur the cost of a function pointer
643 template <typename ValueType, typename CodecType = UnknownCodec>
645 {
646 public:
648  using Ptr = std::shared_ptr<Handle>;
649  using UniquePtr = std::unique_ptr<Handle>;
650 
651 protected:
652  using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
653  using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
654  using ValuePtr = void (*)(AttributeArray* array, const ValueType& value);
655 
656 public:
657  static Ptr create(const AttributeArray& array, const bool preserveCompression = true);
658 
659  AttributeHandle(const AttributeArray& array, const bool preserveCompression = true);
660 
661  AttributeHandle(const AttributeHandle&) = default;
662  AttributeHandle& operator=(const AttributeHandle&) = default;
663 
664  virtual ~AttributeHandle();
665 
666  Index stride() const { return mStrideOrTotalSize; }
667  Index size() const { return mSize; }
668 
669  bool isUniform() const;
670  bool hasConstantStride() const;
671 
672  ValueType get(Index n, Index m = 0) const;
673 
674  const AttributeArray& array() const;
675 
676 protected:
677  Index index(Index n, Index m) const;
678 
680 
685 
686 private:
687  friend class ::TestAttributeArray;
688 
689  template <bool IsUnknownCodec>
690  typename std::enable_if<IsUnknownCodec, bool>::type compatibleType() const;
691 
692  template <bool IsUnknownCodec>
693  typename std::enable_if<!IsUnknownCodec, bool>::type compatibleType() const;
694 
695  template <bool IsUnknownCodec>
697 
698  template <bool IsUnknownCodec>
700 
701  // local copy of AttributeArray (to preserve compression)
702  AttributeArray::Ptr mLocalArray;
703 
704  Index mStrideOrTotalSize;
705  Index mSize;
706  bool mCollapseOnDestruction;
707 }; // class AttributeHandle
708 
709 
710 ////////////////////////////////////////
711 
712 
713 /// Write-able version of AttributeHandle
714 template <typename ValueType, typename CodecType = UnknownCodec>
715 class AttributeWriteHandle : public AttributeHandle<ValueType, CodecType>
716 {
717 public:
719  using Ptr = std::shared_ptr<Handle>;
720  using ScopedPtr = std::unique_ptr<Handle>;
721 
722  static Ptr create(AttributeArray& array, const bool expand = true);
723 
724  AttributeWriteHandle(AttributeArray& array, const bool expand = true);
725 
726  virtual ~AttributeWriteHandle() = default;
727 
728  /// @brief If this array is uniform, replace it with an array of length size().
729  /// @param fill if true, assign the uniform value to each element of the array.
730  void expand(bool fill = true);
731 
732  /// Replace the existing array with a uniform value (zero if none provided).
733  void collapse();
734  void collapse(const ValueType& uniformValue);
735 
736  /// Compact the existing array to become uniform if all values are identical
737  bool compact();
738 
739  /// @brief Fill the existing array with the given value.
740  /// @note Identical to collapse() except a non-uniform array will not become uniform.
741  void fill(const ValueType& value);
742 
743  void set(Index n, const ValueType& value);
744  void set(Index n, Index m, const ValueType& value);
745 
747 
748 private:
749  friend class ::TestAttributeArray;
750 
751  template <bool IsUnknownCodec>
752  typename std::enable_if<IsUnknownCodec, void>::type set(Index index, const ValueType& value) const;
753 
754  template <bool IsUnknownCodec>
755  typename std::enable_if<!IsUnknownCodec, void>::type set(Index index, const ValueType& value) const;
756 }; // class AttributeWriteHandle
757 
758 
759 ////////////////////////////////////////
760 
761 
762 // Attribute codec implementation
763 
764 
765 template<typename ValueType>
766 inline void
767 NullCodec::decode(const ValueType& data, ValueType& val)
768 {
769  val = data;
770 }
771 
772 
773 template<typename ValueType>
774 inline void
775 NullCodec::encode(const ValueType& val, ValueType& data)
776 {
777  data = val;
778 }
779 
780 
781 template<typename StorageType, typename ValueType>
782 inline void
783 TruncateCodec::decode(const StorageType& data, ValueType& val)
784 {
785  val = static_cast<ValueType>(data);
786 }
787 
788 
789 template<typename StorageType, typename ValueType>
790 inline void
791 TruncateCodec::encode(const ValueType& val, StorageType& data)
792 {
793  data = static_cast<StorageType>(val);
794 }
795 
796 
797 template <bool OneByte, typename Range>
798 template<typename StorageType, typename ValueType>
799 inline void
800 FixedPointCodec<OneByte, Range>::decode(const StorageType& data, ValueType& val)
801 {
802  val = fixedPointToFloatingPoint<ValueType>(data);
803 
804  // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
805 
806  val = Range::template decode<ValueType>(val);
807 }
808 
809 
810 template <bool OneByte, typename Range>
811 template<typename StorageType, typename ValueType>
812 inline void
813 FixedPointCodec<OneByte, Range>::encode(const ValueType& val, StorageType& data)
814 {
815  // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
816 
817  const ValueType newVal = Range::template encode<ValueType>(val);
818 
819  data = floatingPointToFixedPoint<StorageType>(newVal);
820 }
821 
822 
823 template<typename T>
824 inline void
826 {
827  val = math::QuantizedUnitVec::unpack(data);
828 }
829 
830 
831 template<typename T>
832 inline void
834 {
835  data = math::QuantizedUnitVec::pack(val);
836 }
837 
838 
839 ////////////////////////////////////////
840 
841 // TypedAttributeArray implementation
842 
843 template<typename ValueType_, typename Codec_>
844 tbb::atomic<const NamePair*> TypedAttributeArray<ValueType_, Codec_>::sTypeName;
845 
846 
847 template<typename ValueType_, typename Codec_>
849  Index n, Index strideOrTotalSize, bool constantStride, const ValueType& uniformValue)
850  : mData(new StorageType[1])
851  , mSize(n)
852  , mStrideOrTotalSize(strideOrTotalSize)
853  , mIsUniform(true)
854 {
855  if (constantStride) {
856  this->setConstantStride(true);
857  if (strideOrTotalSize == 0) {
858  OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a constant stride requires that " \
859  "stride to be at least one.")
860  }
861  }
862  else {
863  this->setConstantStride(false);
864  if (mStrideOrTotalSize < n) {
865  OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a non-constant stride must have " \
866  "a total size of at least the number of elements in the array.")
867  }
868  }
869  mSize = std::max(Index(1), mSize);
870  mStrideOrTotalSize = std::max(Index(1), mStrideOrTotalSize);
871  Codec::encode(uniformValue, mData.get()[0]);
872 }
873 
874 
875 template<typename ValueType_, typename Codec_>
877  : AttributeArray(rhs)
878  , mSize(rhs.mSize)
879  , mStrideOrTotalSize(rhs.mStrideOrTotalSize)
880  , mIsUniform(rhs.mIsUniform)
881 {
882  // disable uncompress if data is not compressed
883 
884  if (!this->isCompressed()) uncompress = false;
885 
886  if (this->isOutOfCore()) {
887  // do nothing
888  } else if (mIsUniform) {
889  this->allocate();
890  mData.get()[0] = rhs.mData.get()[0];
891  } else if (this->isCompressed()) {
892  std::unique_ptr<char[]> buffer;
893  if (uncompress) {
894  const char* charBuffer = reinterpret_cast<const char*>(rhs.mData.get());
895  size_t uncompressedBytes = compression::bloscUncompressedSize(charBuffer);
896  buffer = compression::bloscDecompress(charBuffer, uncompressedBytes);
897  }
898  if (buffer) {
899  mCompressedBytes = 0;
900  } else {
901  // decompression wasn't requested or failed so deep copy instead
902  buffer.reset(new char[mCompressedBytes]);
903  std::memcpy(buffer.get(), rhs.mData.get(), mCompressedBytes);
904  }
905  assert(buffer);
906  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
907  } else {
908  this->allocate();
909  std::memcpy(mData.get(), rhs.mData.get(), this->arrayMemUsage());
910  }
911 }
912 
913 
914 template<typename ValueType_, typename Codec_>
917 {
918  if (&rhs != this) {
919  tbb::spin_mutex::scoped_lock lock(mMutex);
920 
921  this->deallocate();
922 
923  mFlags = rhs.mFlags;
924  mSerializationFlags = rhs.mSerializationFlags;
925  mCompressedBytes = rhs.mCompressedBytes;
926  mSize = rhs.mSize;
927  mStrideOrTotalSize = rhs.mStrideOrTotalSize;
928  mIsUniform = rhs.mIsUniform;
929 
930  if (rhs.isOutOfCore()) {
931  mPageHandle = rhs.mPageHandle;
932  } else if (mIsUniform) {
933  this->allocate();
934  mData.get()[0] = rhs.mData.get()[0];
935  } else if (this->isCompressed()) {
936  std::unique_ptr<char[]> buffer(new char[mCompressedBytes]);
937  std::memcpy(buffer.get(), rhs.mData.get(), mCompressedBytes);
938  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
939  } else {
940  this->allocate();
941  std::memcpy(mData.get(), rhs.mData.get(), arrayMemUsage());
942  }
943  }
944 }
945 
946 
947 template<typename ValueType_, typename Codec_>
948 inline const NamePair&
950 {
951  if (sTypeName == nullptr) {
952  NamePair* s = new NamePair(typeNameAsString<ValueType>(), Codec::name());
953  if (sTypeName.compare_and_swap(s, nullptr) != nullptr) delete s;
954  }
955  return *sTypeName;
956 }
957 
958 
959 template<typename ValueType_, typename Codec_>
960 inline bool
962 {
964 }
965 
966 
967 template<typename ValueType_, typename Codec_>
968 inline void
970 {
971  AttributeArray::registerType(TypedAttributeArray::attributeType(), TypedAttributeArray::factory);
972 }
973 
974 
975 template<typename ValueType_, typename Codec_>
976 inline void
978 {
980 }
981 
982 
983 template<typename ValueType_, typename Codec_>
986 {
987  return Ptr(new TypedAttributeArray(n, stride, constantStride));
988 }
989 
990 template<typename ValueType_, typename Codec_>
993 {
994  if (!attributeArray.isType<TypedAttributeArray>()) {
995  OPENVDB_THROW(TypeError, "Invalid Attribute Type");
996  }
997  return static_cast<TypedAttributeArray&>(attributeArray);
998 }
999 
1000 template<typename ValueType_, typename Codec_>
1003 {
1004  if (!attributeArray.isType<TypedAttributeArray>()) {
1005  OPENVDB_THROW(TypeError, "Invalid Attribute Type");
1006  }
1007  return static_cast<const TypedAttributeArray&>(attributeArray);
1008 }
1009 
1010 template<typename ValueType_, typename Codec_>
1013 {
1015 }
1016 
1017 
1018 template<typename ValueType_, typename Codec_>
1021 {
1022  return AttributeArray::Ptr(new TypedAttributeArray<ValueType, Codec>(*this, /*decompress = */true));
1023 }
1024 
1025 
1026 template<typename ValueType_, typename Codec_>
1027 size_t
1029 {
1030  if (this->isOutOfCore()) return 0;
1031  if (this->isCompressed()) return mCompressedBytes;
1032 
1033  return (mIsUniform ? 1 : this->dataSize()) * sizeof(StorageType);
1034 }
1035 
1036 
1037 template<typename ValueType_, typename Codec_>
1038 void
1039 TypedAttributeArray<ValueType_, Codec_>::allocate()
1040 {
1041  assert(!mData);
1042  if (mIsUniform) {
1043  mData.reset(new StorageType[1]);
1044  }
1045  else {
1046  const size_t size(this->dataSize());
1047  assert(size > 0);
1048  mData.reset(new StorageType[size]);
1049  }
1050 }
1051 
1052 
1053 template<typename ValueType_, typename Codec_>
1054 void
1055 TypedAttributeArray<ValueType_, Codec_>::deallocate()
1056 {
1057  // detach from file if delay-loaded
1058  if (this->isOutOfCore()) {
1059  this->setOutOfCore(false);
1060  this->mPageHandle.reset();
1061  }
1062  if (mData) mData.reset();
1063 }
1064 
1065 
1066 template<typename ValueType_, typename Codec_>
1067 size_t
1069 {
1070  return sizeof(*this) + (bool(mData) ? this->arrayMemUsage() : 0);
1071 }
1072 
1073 
1074 template<typename ValueType_, typename Codec_>
1077 {
1078  assert(n < this->dataSize());
1079  assert(!this->isOutOfCore());
1080  assert(!this->isCompressed());
1081 
1082  ValueType val;
1083  Codec::decode(/*in=*/mData.get()[mIsUniform ? 0 : n], /*out=*/val);
1084  return val;
1085 }
1086 
1087 
1088 template<typename ValueType_, typename Codec_>
1091 {
1092  if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1093  if (this->isOutOfCore()) this->doLoad();
1094  if (this->isCompressed()) const_cast<TypedAttributeArray*>(this)->decompress();
1095 
1096  return this->getUnsafe(n);
1097 }
1098 
1099 
1100 template<typename ValueType_, typename Codec_>
1101 template<typename T>
1102 void
1104 {
1105  val = static_cast<T>(this->getUnsafe(n));
1106 }
1107 
1108 
1109 template<typename ValueType_, typename Codec_>
1110 template<typename T>
1111 void
1113 {
1114  val = static_cast<T>(this->get(n));
1115 }
1116 
1117 
1118 template<typename ValueType_, typename Codec_>
1121 {
1122  return static_cast<const TypedAttributeArray<ValueType, Codec>*>(array)->getUnsafe(n);
1123 }
1124 
1125 
1126 template<typename ValueType_, typename Codec_>
1127 void
1129 {
1130  assert(n < this->dataSize());
1131  assert(!this->isOutOfCore());
1132  assert(!this->isCompressed());
1133  assert(!this->isUniform());
1134 
1135  // this unsafe method assumes the data is not uniform, however if it is, this redirects the index
1136  // to zero, which is marginally less efficient but ensures not writing to an illegal address
1137 
1138  Codec::encode(/*in=*/val, /*out=*/mData.get()[mIsUniform ? 0 : n]);
1139 }
1140 
1141 
1142 template<typename ValueType_, typename Codec_>
1143 void
1145 {
1146  if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1147  if (this->isOutOfCore()) this->doLoad();
1148  if (this->isCompressed()) this->decompress();
1149  if (this->isUniform()) this->expand();
1150 
1151  this->setUnsafe(n, val);
1152 }
1153 
1154 
1155 template<typename ValueType_, typename Codec_>
1156 template<typename T>
1157 void
1159 {
1160  this->setUnsafe(n, static_cast<ValueType>(val));
1161 }
1162 
1163 
1164 template<typename ValueType_, typename Codec_>
1165 template<typename T>
1166 void
1168 {
1169  this->set(n, static_cast<ValueType>(val));
1170 }
1171 
1172 
1173 template<typename ValueType_, typename Codec_>
1174 void
1176 {
1177  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->setUnsafe(n, value);
1178 }
1179 
1180 
1181 template<typename ValueType_, typename Codec_>
1182 void
1184 {
1185  const TypedAttributeArray& sourceTypedArray = static_cast<const TypedAttributeArray&>(sourceArray);
1186 
1187  ValueType sourceValue;
1188  sourceTypedArray.get(sourceIndex, sourceValue);
1189 
1190  this->set(n, sourceValue);
1191 }
1192 
1193 
1194 template<typename ValueType_, typename Codec_>
1195 void
1197 {
1198  if (!mIsUniform) return;
1199 
1200  const StorageType val = mData.get()[0];
1201 
1202  {
1203  tbb::spin_mutex::scoped_lock lock(mMutex);
1204  this->deallocate();
1205  mIsUniform = false;
1206  this->allocate();
1207  }
1208 
1209  mCompressedBytes = 0;
1210 
1211  if (fill) {
1212  for (Index i = 0; i < this->dataSize(); ++i) mData.get()[i] = val;
1213  }
1214 }
1215 
1216 
1217 template<typename ValueType_, typename Codec_>
1218 bool
1220 {
1221  if (mIsUniform) return true;
1222 
1223  // compaction is not possible if any values are different
1224  const ValueType_ val = this->get(0);
1225  for (Index i = 1; i < this->dataSize(); i++) {
1226  if (!math::isExactlyEqual(this->get(i), val)) return false;
1227  }
1228 
1229  this->collapse(this->get(0));
1230  return true;
1231 }
1232 
1233 
1234 template<typename ValueType_, typename Codec_>
1235 void
1237 {
1238  this->collapse(zeroVal<ValueType>());
1239 }
1240 
1241 
1242 template<typename ValueType_, typename Codec_>
1243 void
1245 {
1246  if (!mIsUniform) {
1247  tbb::spin_mutex::scoped_lock lock(mMutex);
1248  this->deallocate();
1249  mIsUniform = true;
1250  this->allocate();
1251  }
1252  Codec::encode(uniformValue, mData.get()[0]);
1253 }
1254 
1255 
1256 template<typename ValueType_, typename Codec_>
1257 void
1259 {
1260  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->collapse(value);
1261 }
1262 
1263 
1264 template<typename ValueType_, typename Codec_>
1265 void
1267 {
1268  if (this->isOutOfCore()) {
1269  tbb::spin_mutex::scoped_lock lock(mMutex);
1270  this->deallocate();
1271  this->allocate();
1272  }
1273 
1274  const Index size = mIsUniform ? 1 : this->dataSize();
1275  for (Index i = 0; i < size; ++i) {
1276  Codec::encode(value, mData.get()[i]);
1277  }
1278 }
1279 
1280 
1281 template<typename ValueType_, typename Codec_>
1282 void
1284 {
1285  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->fill(value);
1286 }
1287 
1288 
1289 template<typename ValueType_, typename Codec_>
1290 inline bool
1292 {
1293  if (!compression::bloscCanCompress()) return false;
1294 
1295  if (!mIsUniform && !this->isCompressed()) {
1296 
1297  tbb::spin_mutex::scoped_lock lock(mMutex);
1298 
1299  this->doLoadUnsafe(/*compression=*/false);
1300 
1301  if (this->isCompressed()) return true;
1302 
1303  return this->compressUnsafe();
1304  }
1305 
1306  return false;
1307 }
1308 
1309 
1310 template<typename ValueType_, typename Codec_>
1311 inline bool
1313 {
1314  if (!compression::bloscCanCompress()) return false;
1315  if (mIsUniform) return false;
1316 
1317  // assumes mutex is locked and data is not out-of-core
1318 
1319  const bool writeCompress = (mSerializationFlags & WRITEMEMCOMPRESS);
1320  const size_t inBytes = writeCompress ? mCompressedBytes : this->arrayMemUsage();
1321 
1322  if (inBytes > 0) {
1323  size_t outBytes;
1324  const char* charBuffer = reinterpret_cast<const char*>(mData.get());
1325  std::unique_ptr<char[]> buffer = compression::bloscCompress(charBuffer, inBytes, outBytes);
1326  if (buffer) {
1327  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1328  mCompressedBytes = outBytes;
1329  return true;
1330  }
1331  }
1332 
1333  return false;
1334 }
1335 
1336 
1337 template<typename ValueType_, typename Codec_>
1338 inline bool
1340 {
1341  tbb::spin_mutex::scoped_lock lock(mMutex);
1342 
1343  const bool writeCompress = (mSerializationFlags & WRITEMEMCOMPRESS);
1344 
1345  if (writeCompress) {
1346  this->doLoadUnsafe(/*compression=*/false);
1347  return true;
1348  }
1349 
1350  if (this->isCompressed()) {
1351  this->doLoadUnsafe();
1352  const char* charBuffer = reinterpret_cast<const char*>(this->mData.get());
1353  size_t uncompressedBytes = compression::bloscUncompressedSize(charBuffer);
1354  std::unique_ptr<char[]> buffer = compression::bloscDecompress(charBuffer, uncompressedBytes);
1355  if (buffer) {
1356  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1357  mCompressedBytes = 0;
1358  return true;
1359  }
1360  }
1361 
1362  return false;
1363 }
1364 
1365 
1366 template<typename ValueType_, typename Codec_>
1367 bool
1369 {
1370 #if OPENVDB_ABI_VERSION_NUMBER >= 5
1371  return mOutOfCore;
1372 #else
1373  return (mFlags & OUTOFCORE);
1374 #endif
1375 }
1376 
1377 
1378 template<typename ValueType_, typename Codec_>
1379 void
1381 {
1382 #if OPENVDB_ABI_VERSION_NUMBER >= 5
1383  mOutOfCore = b;
1384 #else
1385  if (b) mFlags = static_cast<uint8_t>(mFlags | OUTOFCORE);
1386  else mFlags = static_cast<uint8_t>(mFlags & ~OUTOFCORE);
1387 #endif
1388 }
1389 
1390 
1391 template<typename ValueType_, typename Codec_>
1392 void
1393 TypedAttributeArray<ValueType_, Codec_>::doLoad() const
1394 {
1395  if (!(this->isOutOfCore())) return;
1396 
1397  TypedAttributeArray<ValueType_, Codec_>* self =
1398  const_cast<TypedAttributeArray<ValueType_, Codec_>*>(this);
1399 
1400  // This lock will be contended at most once, after which this buffer
1401  // will no longer be out-of-core.
1402  tbb::spin_mutex::scoped_lock lock(self->mMutex);
1403  this->doLoadUnsafe();
1404 }
1405 
1406 
1407 template<typename ValueType_, typename Codec_>
1408 void
1410 {
1411  this->doLoad();
1412 }
1413 
1414 
1415 template<typename ValueType_, typename Codec_>
1416 void
1418 {
1419  this->readMetadata(is);
1420  this->readBuffers(is);
1421 }
1422 
1423 
1424 template<typename ValueType_, typename Codec_>
1425 void
1427 {
1428  // read data
1429 
1430  Index64 bytes = Index64(0);
1431  is.read(reinterpret_cast<char*>(&bytes), sizeof(Index64));
1432  bytes = bytes - /*flags*/sizeof(Int16) - /*size*/sizeof(Index);
1433 
1434  uint8_t flags = uint8_t(0);
1435  is.read(reinterpret_cast<char*>(&flags), sizeof(uint8_t));
1436  mFlags = flags;
1437 
1438  uint8_t serializationFlags = uint8_t(0);
1439  is.read(reinterpret_cast<char*>(&serializationFlags), sizeof(uint8_t));
1440  mSerializationFlags = serializationFlags;
1441 
1442  Index size = Index(0);
1443  is.read(reinterpret_cast<char*>(&size), sizeof(Index));
1444  mSize = size;
1445 
1446  // warn if an unknown flag has been set
1447  if (mFlags >= 0x20) {
1448  OPENVDB_LOG_WARN("Unknown attribute flags for VDB file format.");
1449  }
1450  // error if an unknown serialization flag has been set,
1451  // as this will adjust the layout of the data and corrupt the ability to read
1452  if (mSerializationFlags >= 0x10) {
1453  OPENVDB_THROW(IoError, "Unknown attribute serialization flags for VDB file format.");
1454  }
1455 
1456  // read uniform and compressed state
1457 
1458  mIsUniform = mSerializationFlags & WRITEUNIFORM;
1459  mCompressedBytes = bytes;
1460 
1461  // read strided value (set to 1 if array is not strided)
1462 
1463  if (mSerializationFlags & WRITESTRIDED) {
1464  Index stride = Index(0);
1465  is.read(reinterpret_cast<char*>(&stride), sizeof(Index));
1466  mStrideOrTotalSize = stride;
1467  }
1468  else {
1469  mStrideOrTotalSize = 1;
1470  }
1471 }
1472 
1473 
1474 template<typename ValueType_, typename Codec_>
1475 void
1477 {
1478  if ((mSerializationFlags & WRITEPAGED)) {
1479  // use readBuffers(PagedInputStream&) for paged buffers
1480  OPENVDB_THROW(IoError, "Cannot read paged AttributeArray buffers.");
1481  }
1482 
1483  tbb::spin_mutex::scoped_lock lock(mMutex);
1484 
1485  this->deallocate();
1486 
1487  uint8_t bloscCompressed(0);
1488  if (!mIsUniform) is.read(reinterpret_cast<char*>(&bloscCompressed), sizeof(uint8_t));
1489 
1490  std::unique_ptr<char[]> buffer(new char[mCompressedBytes]);
1491  is.read(buffer.get(), mCompressedBytes);
1492 
1493  if (mIsUniform) {
1494  // zero compressed bytes as uniform values are not compressed in memory
1495  mCompressedBytes = Index64(0);
1496  }
1497  else if (!(mSerializationFlags & WRITEMEMCOMPRESS)) {
1498  // zero compressed bytes if not compressed in memory
1499  mCompressedBytes = Index64(0);
1500  }
1501 
1502  // compressed on-disk
1503 
1504  if (bloscCompressed == uint8_t(1)) {
1505 
1506  // decompress buffer
1507 
1508  const size_t inBytes = this->dataSize() * sizeof(StorageType);
1509  std::unique_ptr<char[]> newBuffer = compression::bloscDecompress(buffer.get(), inBytes);
1510  if (newBuffer) buffer.reset(newBuffer.release());
1511  }
1512 
1513  // set data to buffer
1514 
1515  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1516 
1517  // clear all write flags
1518 
1519  if (mIsUniform) mSerializationFlags &= uint8_t(~WRITEUNIFORM & ~WRITEMEMCOMPRESS & ~WRITEPAGED);
1520  else mSerializationFlags &= uint8_t(~WRITEUNIFORM & ~WRITEPAGED);
1521 }
1522 
1523 
1524 template<typename ValueType_, typename Codec_>
1525 void
1527 {
1528  if (!(mSerializationFlags & WRITEPAGED)) {
1529  if (!is.sizeOnly()) this->readBuffers(is.getInputStream());
1530  return;
1531  }
1532 
1533  // If this array is being read from a memory-mapped file, delay loading of its data
1534  // until the data is actually accessed.
1536  const bool delayLoad = (mappedFile.get() != nullptr);
1537 
1538  if (is.sizeOnly())
1539  {
1540  mPageHandle = is.createHandle(mCompressedBytes);
1541  return;
1542  }
1543 
1544  assert(mPageHandle);
1545 
1546  tbb::spin_mutex::scoped_lock lock(mMutex);
1547 
1548  this->deallocate();
1549 
1550  this->setOutOfCore(delayLoad);
1551  is.read(mPageHandle, mCompressedBytes, delayLoad);
1552 
1553  if (!delayLoad) {
1554  std::unique_ptr<char[]> buffer = mPageHandle->read();
1555  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1556  }
1557 
1558  // zero compressed bytes as not compressed in memory
1559 
1560  if (mIsUniform) {
1561  // zero compressed bytes as uniform values are not compressed in memory
1562  mCompressedBytes = Index64(0);
1563  }
1564  else if (!(mSerializationFlags & WRITEMEMCOMPRESS)) {
1565  mCompressedBytes = Index64(0);
1566  }
1567 
1568  // clear all write flags
1569 
1570  if (mIsUniform) mSerializationFlags &= uint8_t(~WRITEUNIFORM & ~WRITEMEMCOMPRESS & ~WRITEPAGED);
1571  else mSerializationFlags &= uint8_t(~WRITEUNIFORM & ~WRITEPAGED);
1572 }
1573 
1574 
1575 template<typename ValueType_, typename Codec_>
1576 void
1578 {
1579  this->write(os, /*outputTransient=*/false);
1580 }
1581 
1582 
1583 template<typename ValueType_, typename Codec_>
1584 void
1585 TypedAttributeArray<ValueType_, Codec_>::write(std::ostream& os, bool outputTransient) const
1586 {
1587  this->writeMetadata(os, outputTransient, /*paged=*/false);
1588  this->writeBuffers(os, outputTransient);
1589 }
1590 
1591 
1592 template<typename ValueType_, typename Codec_>
1593 void
1594 TypedAttributeArray<ValueType_, Codec_>::writeMetadata(std::ostream& os, bool outputTransient, bool paged) const
1595 {
1596  if (!outputTransient && this->isTransient()) return;
1597 
1598 #if OPENVDB_ABI_VERSION_NUMBER >= 5
1599  uint8_t flags(mFlags);
1600 #else
1601  uint8_t flags(mFlags & uint8_t(~OUTOFCORE));
1602 #endif
1603  uint8_t serializationFlags(0);
1604  Index size(mSize);
1605  Index stride(mStrideOrTotalSize);
1606  bool strideOfOne(this->stride() == 1);
1607 
1608  bool bloscCompression = io::getDataCompression(os) & io::COMPRESS_BLOSC;
1609 
1610  // any compressed data needs to be loaded if out-of-core
1611  if (bloscCompression || this->isCompressed()) this->doLoad();
1612 
1613  size_t compressedBytes = 0;
1614 
1615  if (!strideOfOne)
1616  {
1617  serializationFlags |= WRITESTRIDED;
1618  }
1619 
1620  if (mIsUniform)
1621  {
1622  serializationFlags |= WRITEUNIFORM;
1623  if (bloscCompression && paged) serializationFlags |= WRITEPAGED;
1624  }
1625  else if (bloscCompression && paged)
1626  {
1627  serializationFlags |= WRITEPAGED;
1628  if (this->isCompressed()) {
1629  serializationFlags |= WRITEMEMCOMPRESS;
1630  const char* charBuffer = reinterpret_cast<const char*>(mData.get());
1631  compressedBytes = compression::bloscUncompressedSize(charBuffer);
1632  }
1633  }
1634  else if (this->isCompressed())
1635  {
1636  serializationFlags |= WRITEMEMCOMPRESS;
1637  compressedBytes = mCompressedBytes;
1638  }
1639  else if (bloscCompression)
1640  {
1641  const char* charBuffer = reinterpret_cast<const char*>(mData.get());
1642  const size_t inBytes = this->arrayMemUsage();
1643  compressedBytes = compression::bloscCompressedSize(charBuffer, inBytes);
1644  }
1645 
1646  Index64 bytes = /*flags*/ sizeof(Int16) + /*size*/ sizeof(Index);
1647 
1648  bytes += (compressedBytes > 0) ? compressedBytes : this->arrayMemUsage();
1649 
1650  // write data
1651 
1652  os.write(reinterpret_cast<const char*>(&bytes), sizeof(Index64));
1653  os.write(reinterpret_cast<const char*>(&flags), sizeof(uint8_t));
1654  os.write(reinterpret_cast<const char*>(&serializationFlags), sizeof(uint8_t));
1655  os.write(reinterpret_cast<const char*>(&size), sizeof(Index));
1656 
1657  // write strided
1658  if (!strideOfOne) os.write(reinterpret_cast<const char*>(&stride), sizeof(Index));
1659 }
1660 
1661 
1662 template<typename ValueType_, typename Codec_>
1663 void
1664 TypedAttributeArray<ValueType_, Codec_>::writeBuffers(std::ostream& os, bool outputTransient) const
1665 {
1666  if (!outputTransient && this->isTransient()) return;
1667 
1668  this->doLoad();
1669 
1670  if (this->isUniform()) {
1671  os.write(reinterpret_cast<const char*>(mData.get()), sizeof(StorageType));
1672  }
1673  else if (this->isCompressed())
1674  {
1675  uint8_t bloscCompressed(0);
1676  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1677  os.write(reinterpret_cast<const char*>(mData.get()), mCompressedBytes);
1678  }
1680  {
1681  std::unique_ptr<char[]> compressedBuffer;
1682  size_t compressedBytes = 0;
1683  const char* charBuffer = reinterpret_cast<const char*>(mData.get());
1684  const size_t inBytes = this->arrayMemUsage();
1685  compressedBuffer = compression::bloscCompress(charBuffer, inBytes, compressedBytes);
1686  if (compressedBuffer) {
1687  uint8_t bloscCompressed(1);
1688  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1689  os.write(reinterpret_cast<const char*>(compressedBuffer.get()), compressedBytes);
1690  }
1691  else {
1692  uint8_t bloscCompressed(0);
1693  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1694  os.write(reinterpret_cast<const char*>(mData.get()), inBytes);
1695  }
1696  }
1697  else
1698  {
1699  uint8_t bloscCompressed(0);
1700  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1701  os.write(reinterpret_cast<const char*>(mData.get()), this->arrayMemUsage());
1702  }
1703 }
1704 
1705 
1706 template<typename ValueType_, typename Codec_>
1707 void
1709 {
1710  if (!outputTransient && this->isTransient()) return;
1711 
1712  // paged compression only available when Blosc is enabled
1713  bool bloscCompression = io::getDataCompression(os.getOutputStream()) & io::COMPRESS_BLOSC;
1714  if (!bloscCompression) {
1715  if (!os.sizeOnly()) this->writeBuffers(os.getOutputStream(), outputTransient);
1716  return;
1717  }
1718 
1719  this->doLoad();
1720 
1721  const char* buffer;
1722  size_t bytes;
1723 
1724  std::unique_ptr<char[]> uncompressedBuffer;
1725  if (this->isCompressed()) {
1726  // paged streams require uncompressed buffers, so locally decompress
1727 
1728  const char* charBuffer = reinterpret_cast<const char*>(this->mData.get());
1729  bytes = compression::bloscUncompressedSize(charBuffer);
1730  uncompressedBuffer = compression::bloscDecompress(charBuffer, bytes);
1731  buffer = reinterpret_cast<const char*>(uncompressedBuffer.get());
1732  }
1733  else {
1734  buffer = reinterpret_cast<const char*>(mData.get());
1735  bytes = this->arrayMemUsage();
1736  }
1737 
1738  os.write(buffer, bytes);
1739 }
1740 
1741 
1742 template<typename ValueType_, typename Codec_>
1743 void
1744 TypedAttributeArray<ValueType_, Codec_>::doLoadUnsafe(const bool compression) const
1745 {
1746  if (!(this->isOutOfCore())) return;
1747 
1748  // this function expects the mutex to already be locked
1749 
1751 
1752  assert(self->mPageHandle);
1753 
1754  std::unique_ptr<char[]> buffer = self->mPageHandle->read();
1755 
1756  self->mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1757 
1758  self->mPageHandle.reset();
1759 
1760  // if data was compressed prior to being written to disk, re-compress
1761 
1762  if (self->mSerializationFlags & WRITEMEMCOMPRESS) {
1763  if (compression) self->compressUnsafe();
1764  else self->mCompressedBytes = 0;
1765  }
1766 
1767  // clear all write and out-of-core flags
1768 
1769 #if OPENVDB_ABI_VERSION_NUMBER >= 5
1770  self->mOutOfCore = false;
1771 #else
1772  self->mFlags &= uint8_t(~OUTOFCORE);
1773 #endif
1774  self->mSerializationFlags &= uint8_t(~WRITEUNIFORM & ~WRITEMEMCOMPRESS & ~WRITEPAGED);
1775 }
1776 
1777 
1778 template<typename ValueType_, typename Codec_>
1781 {
1782  // use the faster 'unsafe' get and set methods as attribute handles
1783  // ensure data is uncompressed and in-core when constructed
1784 
1790 }
1791 
1792 
1793 template<typename ValueType_, typename Codec_>
1794 bool
1796 {
1797  const TypedAttributeArray<ValueType_, Codec_>* const otherT = dynamic_cast<const TypedAttributeArray<ValueType_, Codec_>* >(&other);
1798  if(!otherT) return false;
1799  if(this->mSize != otherT->mSize ||
1800  this->mStrideOrTotalSize != otherT->mStrideOrTotalSize ||
1801  this->mIsUniform != otherT->mIsUniform ||
1802  *this->sTypeName != *otherT->sTypeName) return false;
1803 
1804  this->doLoad();
1805  otherT->doLoad();
1806 
1807  const StorageType *target = this->mData.get(), *source = otherT->mData.get();
1808  if (!target && !source) return true;
1809  if (!target || !source) return false;
1810  Index n = this->mIsUniform ? 1 : mSize;
1811  while (n && math::isExactlyEqual(*target++, *source++)) --n;
1812  return n == 0;
1813 }
1814 
1815 ////////////////////////////////////////
1816 
1817 
1818 /// Accessor to call unsafe get and set methods based on templated Codec and Value
1819 template <typename CodecType, typename ValueType>
1821 {
1822  using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
1823  using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
1824 
1825  /// Getter that calls to TypedAttributeArray::getUnsafe()
1826  /// @note Functor argument is provided but not required for the generic case
1827  static ValueType get(GetterPtr /*functor*/, const AttributeArray* array, const Index n) {
1829  }
1830 
1831  /// Getter that calls to TypedAttributeArray::setUnsafe()
1832  /// @note Functor argument is provided but not required for the generic case
1833  static void set(SetterPtr /*functor*/, AttributeArray* array, const Index n, const ValueType& value) {
1835  }
1836 };
1837 
1838 
1839 /// Partial specialization when Codec is not known at compile-time to use the supplied functor instead
1840 template <typename ValueType>
1841 struct AccessorEval<UnknownCodec, ValueType>
1842 {
1843  using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
1844  using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
1845 
1846  /// Getter that calls the supplied functor
1847  static ValueType get(GetterPtr functor, const AttributeArray* array, const Index n) {
1848  return (*functor)(array, n);
1849  }
1850 
1851  /// Setter that calls the supplied functor
1852  static void set(SetterPtr functor, AttributeArray* array, const Index n, const ValueType& value) {
1853  (*functor)(array, n, value);
1854  }
1855 };
1856 
1857 
1858 ////////////////////////////////////////
1859 
1860 // AttributeHandle implementation
1861 
1862 template <typename ValueType, typename CodecType>
1863 typename AttributeHandle<ValueType, CodecType>::Ptr
1864 AttributeHandle<ValueType, CodecType>::create(const AttributeArray& array, const bool preserveCompression)
1865 {
1867  new AttributeHandle<ValueType, CodecType>(array, preserveCompression));
1868 }
1869 
1870 template <typename ValueType, typename CodecType>
1871 AttributeHandle<ValueType, CodecType>::AttributeHandle(const AttributeArray& array, const bool preserveCompression)
1872  : mArray(&array)
1873  , mStrideOrTotalSize(array.hasConstantStride() ? array.stride() : 1)
1874  , mSize(array.hasConstantStride() ? array.size() : array.dataSize())
1875  , mCollapseOnDestruction(preserveCompression && array.isStreaming())
1876 {
1877  if (!this->compatibleType<std::is_same<CodecType, UnknownCodec>::value>()) {
1878  OPENVDB_THROW(TypeError, "Cannot bind handle due to incompatible type of AttributeArray.");
1879  }
1880 
1881  // load data if delay-loaded
1882 
1883  mArray->loadData();
1884 
1885  // if array is compressed and preserve compression is true, copy and decompress
1886  // into a local copy that is destroyed with handle to maintain thread-safety
1887 
1888  if (array.isCompressed())
1889  {
1890  if (preserveCompression && !array.isStreaming()) {
1891  mLocalArray = array.copyUncompressed();
1892  mLocalArray->decompress();
1893  mArray = mLocalArray.get();
1894  }
1895  else {
1896  const_cast<AttributeArray*>(mArray)->decompress();
1897  }
1898  }
1899 
1900  // bind getter and setter methods
1901 
1903  assert(accessor);
1904 
1905  AttributeArray::Accessor<ValueType>* typedAccessor = static_cast<AttributeArray::Accessor<ValueType>*>(accessor.get());
1906 
1907  mGetter = typedAccessor->mGetter;
1908  mSetter = typedAccessor->mSetter;
1909  mCollapser = typedAccessor->mCollapser;
1910  mFiller = typedAccessor->mFiller;
1911 }
1912 
1913 template <typename ValueType, typename CodecType>
1915 {
1916  // if enabled, attribute is collapsed on destruction of the handle to save memory
1917  if (mCollapseOnDestruction) const_cast<AttributeArray*>(this->mArray)->collapse();
1918 }
1919 
1920 template <typename ValueType, typename CodecType>
1921 template <bool IsUnknownCodec>
1924 {
1925  // if codec is unknown, just check the value type
1926 
1927  return mArray->hasValueType<ValueType>();
1928 }
1929 
1930 template <typename ValueType, typename CodecType>
1931 template <bool IsUnknownCodec>
1933 AttributeHandle<ValueType, CodecType>::compatibleType() const
1934 {
1935  // if the codec is known, check the value type and codec
1936 
1937  return mArray->isType<TypedAttributeArray<ValueType, CodecType>>();
1938 }
1939 
1940 template <typename ValueType, typename CodecType>
1942 {
1943  assert(mArray);
1944  return *mArray;
1945 }
1946 
1947 template <typename ValueType, typename CodecType>
1949 {
1950  Index index = n * mStrideOrTotalSize + m;
1951  assert(index < (mSize * mStrideOrTotalSize));
1952  return index;
1953 }
1954 
1955 template <typename ValueType, typename CodecType>
1957 {
1958  return this->get<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, m));
1959 }
1960 
1961 template <typename ValueType, typename CodecType>
1962 template <bool IsUnknownCodec>
1965 {
1966  // if the codec is unknown, use the getter functor
1967 
1968  return (*mGetter)(mArray, index);
1969 }
1970 
1971 template <typename ValueType, typename CodecType>
1972 template <bool IsUnknownCodec>
1975 {
1976  // if the codec is known, call the method on the attribute array directly
1977 
1979 }
1980 
1981 template <typename ValueType, typename CodecType>
1983 {
1984  return mArray->isUniform();
1985 }
1986 
1987 template <typename ValueType, typename CodecType>
1989 {
1990  return mArray->hasConstantStride();
1991 }
1992 
1993 ////////////////////////////////////////
1994 
1995 // AttributeWriteHandle implementation
1996 
1997 template <typename ValueType, typename CodecType>
2000 {
2002  new AttributeWriteHandle<ValueType, CodecType>(array, expand));
2003 }
2004 
2005 template <typename ValueType, typename CodecType>
2007  : AttributeHandle<ValueType, CodecType>(array, /*preserveCompression = */ false)
2008 {
2009  if (expand) array.expand();
2010 }
2011 
2012 template <typename ValueType, typename CodecType>
2014 {
2016 }
2017 
2018 template <typename ValueType, typename CodecType>
2020 {
2022 }
2023 
2024 template <typename ValueType, typename CodecType>
2026 {
2027  const_cast<AttributeArray*>(this->mArray)->expand(fill);
2028 }
2029 
2030 template <typename ValueType, typename CodecType>
2032 {
2033  const_cast<AttributeArray*>(this->mArray)->collapse();
2034 }
2035 
2036 template <typename ValueType, typename CodecType>
2038 {
2039  return const_cast<AttributeArray*>(this->mArray)->compact();
2040 }
2041 
2042 template <typename ValueType, typename CodecType>
2043 void AttributeWriteHandle<ValueType, CodecType>::collapse(const ValueType& uniformValue)
2044 {
2045  this->mCollapser(const_cast<AttributeArray*>(this->mArray), uniformValue);
2046 }
2047 
2048 template <typename ValueType, typename CodecType>
2050 {
2051  this->mFiller(const_cast<AttributeArray*>(this->mArray), value);
2052 }
2053 
2054 template <typename ValueType, typename CodecType>
2055 template <bool IsUnknownCodec>
2057 AttributeWriteHandle<ValueType, CodecType>::set(Index index, const ValueType& value) const
2058 {
2059  // if the codec is unknown, use the setter functor
2060 
2061  (*this->mSetter)(const_cast<AttributeArray*>(this->mArray), index, value);
2062 }
2063 
2064 template <typename ValueType, typename CodecType>
2065 template <bool IsUnknownCodec>
2067 AttributeWriteHandle<ValueType, CodecType>::set(Index index, const ValueType& value) const
2068 {
2069  // if the codec is known, call the method on the attribute array directly
2070 
2071  TypedAttributeArray<ValueType, CodecType>::setUnsafe(const_cast<AttributeArray*>(this->mArray), index, value);
2072 }
2073 
2074 template <typename ValueType, typename CodecType>
2076 {
2077  assert(this->mArray);
2078  return *const_cast<AttributeArray*>(this->mArray);
2079 }
2080 
2081 
2082 } // namespace points
2083 } // namespace OPENVDB_VERSION_NAME
2084 } // namespace openvdb
2085 
2086 #endif // OPENVDB_POINTS_ATTRIBUTE_ARRAY_HAS_BEEN_INCLUDED
2087 
2088 // Copyright (c) 2012-2018 DreamWorks Animation LLC
2089 // All rights reserved. This software is distributed under the
2090 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
bool isUniform() const override
Return true if this array is stored as a single uniform value.
OPENVDB_API SharedPtr< MappedFile > getMappedFilePtr(std::ios_base &)
Return a shared pointer to the memory-mapped file with which the given stream is associated, or a null pointer if the stream is not associated with a memory-mapped file.
void readBuffers(std::istream &) override
Read attribute buffers from a stream.
AttributeHandle(const AttributeArray &array, const bool preserveCompression=true)
static void unregisterType()
Remove this attribute type from the registry.
Definition: ImfName.h:53
ValueType getUnsafe(Index n) const
Return the value at index n (assumes uncompressed and in-core)
static Ptr create(Index n, Index strideOrTotalSize=1, bool constantStride=true)
Return a new attribute array of the given length n and stride with uniform value zero.
void(*)(AttributeArray *array, const Index n, const ValueType &value) SetterPtr
void loadData() const override
Ensures all data is in-core.
virtual void expand(bool fill=true)=0
If this array is uniform, replace it with an array of length size().
#define OPENVDB_LOG_WARN(mesg)
Definition: logging.h:301
size_t memUsage() const override
Return the number of bytes of memory used by this attribute.
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:395
bool isHidden() const
Return true if this attribute is hidden (e.g., from UI or iterators).
ValueType(*)(const AttributeArray *array, const Index n) GetterPtr
bool isStreaming() const
Return true if this attribute is in streaming mode.
bool compact()
Compact the existing array to become uniform if all values are identical.
PagedOutputStream & write(const char *str, std::streamsize n)
Writes the given.
const GLdouble * v
Definition: glcorearb.h:836
static TypedAttributeArray & cast(AttributeArray &attributeArray)
Cast an AttributeArray to TypedAttributeArray<T>
typename attribute_traits::TruncateTrait< T >::Type Type
GLsizei const GLchar *const * string
Definition: glcorearb.h:813
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
static void decode(const StorageType &, ValueType &)
OPENVDB_API uint32_t getDataCompression(std::ios_base &)
Return a bitwise OR of compression option flags (COMPRESS_ZIP, COMPRESS_ACTIVE_MASK, etc.) specifying whether and how input data is compressed or output data should be compressed.
void collapse() override
Replace the existing array with a uniform zero value.
IntegerT floatingPointToFixedPoint(const FloatT s)
void(*)(AttributeArray *array, const Index n, const T &value) SetterPtr
ValueType get(Index n) const
Return the value at index n.
ValueType(*)(const AttributeArray *array, const Index n) GetterPtr
GLbitfield flags
Definition: glcorearb.h:1595
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:189
static ValueType encode(const ValueType &value)
bool hasConstantStride() const
Return true if this attribute has a constant stride.
bool isOutOfCore() const
Return true if this buffer's values have not yet been read from disk.
SharedPtr< MappedFile > Ptr
Definition: io.h:152
bool compact() override
Compact the existing array to become uniform if all values are identical.
A Paging wrapper to std::istream that is responsible for reading from a given input stream and creati...
static void encode(const ValueType &, StorageType &)
void expand(bool fill=true)
If this array is uniform, replace it with an array of length size().
void read(T &in, bool &v)
Definition: ImfXdr.h:611
GLuint buffer
Definition: glcorearb.h:659
std::ostream & getOutputStream()
Set and get the output stream.
png_uint_32 i
Definition: png.h:2877
const NamePair & type() const override
Return the name of this attribute's type.
static void encode(const math::Vec3< T > &, StorageType &)
void collapse()
Replace the existing array with a uniform value (zero if none provided).
TypedAttributeArray & operator=(const TypedAttributeArray &)
Deep copy assignment operator.
static Ptr create(AttributeArray &array, const bool expand=true)
static void decode(const StorageType &, ValueType &)
GLsizeiptr size
Definition: glcorearb.h:663
AttributeArray::Ptr copy() const override
Return a copy of this attribute.
static bool isRegistered(const NamePair &type)
Return true if the given attribute type name is registered.
TypedAttributeArray(Index n=1, Index strideOrTotalSize=1, bool constantStride=true, const ValueType &uniformValue=zeroVal< ValueType >())
Default constructor, always constructs a uniform attribute.
typename attribute_traits::UIntTypeTrait< OneByte, T >::Type Type
static void unregisterType(const NamePair &type)
Remove a attribute type from the registry.
void(*)(AttributeArray *array, const T &value) ValuePtr
static Ptr create(const AttributeArray &array, const bool preserveCompression=true)
bool operator==(const BaseDimensions< T > &a, const BaseDimensions< Y > &b)
Definition: Dimensions.h:137
void setConstantStride(bool state)
Specify whether this attribute has a constant stride or not.
bool operator!=(const AttributeArray &other) const
GLdouble n
Definition: glcorearb.h:2007
Base class for storing attribute data.
AttributeWriteHandle(AttributeArray &array, const bool expand=true)
#define OPENVDB_API
Helper macros for defining library symbol visibility.
Definition: Platform.h:194
void writeBuffers(std::ostream &os, bool outputTransient) const override
FloatT fixedPointToFloatingPoint(const IntegerT s)
Index size() const override
Return the number of elements in this array.
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:133
Accessor to call unsafe get and set methods based on templated Codec and Value.
static uint16_t pack(const Vec3< T > &vec)
virtual AccessorBasePtr getAccessor() const =0
Obtain an Accessor that stores getter and setter functors.
virtual void loadData() const =0
Ensures all data is in-core.
static const NamePair & attributeType()
Return the name of this attribute's type (includes codec)
GLint GLenum GLboolean GLsizei stride
Definition: glcorearb.h:871
GLsizei GLsizei GLchar * source
Definition: glcorearb.h:802
OPENVDB_API void bloscDecompress(char *uncompressedBuffer, const size_t expectedBytes, const size_t bufferBytes, const char *compressedBuffer)
Decompress into the supplied buffer. Will throw if decompression fails or uncompressed buffer has ins...
void readMetadata(std::istream &) override
Read attribute metadata from a stream.
Index Iterators.
GLenum target
Definition: glcorearb.h:1666
Convenience wrappers to using Blosc and reading and writing of Paged data.
void readPagedBuffers(compression::PagedInputStream &) override
Read attribute buffers from a paged stream.
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...
AttributeArray::Ptr copyUncompressed() const override
Return an uncompressed copy of this attribute (will just return a copy if not compressed).
GLboolean * data
Definition: glcorearb.h:130
std::pair< Name, Name > NamePair
void writeMetadata(std::ostream &os, bool outputTransient, bool paged) const override
GLuint const GLchar * name
Definition: glcorearb.h:785
bool isTransient() const
Return true if this attribute is not serialized during stream output.
static void registerType(const NamePair &type, FactoryMethod)
Register a attribute type along with a factory function.
static ValueType encode(const ValueType &value)
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1221
bool hasValueType() const
Return true if this attribute has a value type the same as the template parameter.
static ValueType decode(const ValueType &value)
std::shared_ptr< const AttributeArray > ConstPtr
bool compress() override
Compress the attribute array.
int floor(T x)
Definition: ImathFun.h:150
static bool isRegistered()
Return true if this attribute type is registered.
virtual AttributeArray::Ptr copyUncompressed() const =0
Return an uncompressed copy of this attribute (will return a copy if not compressed).
bool isCompressed() const
Return true if this array is compressed.
AttributeHandle & operator=(const AttributeHandle &)=default
static ValueType decode(const ValueType &value)
void(*)(AttributeArray *array, const Index n, const ValueType &value) SetterPtr
PageHandle::Ptr createHandle(std::streamsize n)
Creates a PageHandle to access the next.
GLsizei const GLfloat * value
Definition: glcorearb.h:823
OPENVDB_API void bloscCompress(char *compressedBuffer, size_t &compressedBytes, const size_t bufferBytes, const char *uncompressedBuffer, const size_t uncompressedBytes)
Compress into the supplied buffer.
static void decode(const StorageType &, math::Vec3< T > &)
void writePagedBuffers(compression::PagedOutputStream &os, bool outputTransient) const override
uint8_t flags() const
Retrieve the attribute array flags.
typedef int
Definition: png.h:1175
void set(Index n, const ValueType &value)
Set value at the given index n.
Typed class for storing attribute data.
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
Definition: Vec3.h:110
GLuint index
Definition: glcorearb.h:785
OPENVDB_API size_t bloscCompressedSize(const char *buffer, const size_t uncompressedBytes)
Convenience wrapper to retrieve the compressed size of buffer when compressed.
void fill(const ValueType &value)
Fill the existing array with the given value.
GLuint GLfloat * val
Definition: glcorearb.h:1607
void write(std::ostream &os, bool outputTransient) const override
AccessorBasePtr getAccessor() const override
Obtain an Accessor that stores getter and setter functors.
OPENVDB_API bool bloscCanCompress()
Returns true if compression is available.
A Paging wrapper to std::ostream that is responsible for writing from a given output stream at interv...
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:107
typename Codec::template Storage< ValueType >::Type StorageType
void read(std::istream &) override
Read attribute data from a stream.
static void set(SetterPtr functor, AttributeArray *array, const Index n, const ValueType &value)
Setter that calls the supplied functor.
static void encode(const ValueType &, StorageType &)
OPENVDB_API size_t bloscUncompressedSize(const char *buffer)
Retrieves the uncompressed size of buffer when uncompressed.
Accessor base class for AttributeArray storage where type is not available.
static void decode(const ValueType &, ValueType &)
compression::PageHandle::Ptr mPageHandle
used for out-of-core, paged reading
T(*)(const AttributeArray *array, const Index n) GetterPtr
static void set(SetterPtr, AttributeArray *array, const Index n, const ValueType &value)
void setUnsafe(Index n, const ValueType &value)
Set value at the given index n (assumes uncompressed and in-core)
void fill(const ValueType &value)
Fill the existing array with the given value.
void write(T &out, bool v)
Definition: ImfXdr.h:332
bool isType() const
Return true if this attribute is of the same type as the template parameter.
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:129
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:135
static void registerType()
Register this attribute type along with a factory function.
Definition: half.h:91
Accessor(GetterPtr getter, SetterPtr setter, ValuePtr collapser, ValuePtr filler)
png_uint_32 filler
Definition: png.h:1733
void expand(bool fill=true) override
Replace the single value storage with an array of length size().
bool decompress() override
Uncompress the attribute array.
static void encode(const ValueType &, ValueType &)
Index dataSize() const override
Return the size of the data in this array.
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:794