HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
AttributeArray.h
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2012-2017 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
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  /// used for out-of-core, paged reading
302 }; // class AttributeArray
303 
304 
305 ////////////////////////////////////////
306 
307 
308 /// Accessor base class for AttributeArray storage where type is not available
309 struct AttributeArray::AccessorBase { virtual ~AccessorBase() = default; };
310 
311 /// Templated Accessor stores typed function pointers used in binding
312 /// AttributeHandles
313 template <typename T>
315 {
316  using GetterPtr = T (*)(const AttributeArray* array, const Index n);
317  using SetterPtr = void (*)(AttributeArray* array, const Index n, const T& value);
318  using ValuePtr = void (*)(AttributeArray* array, const T& value);
319 
320  Accessor(GetterPtr getter, SetterPtr setter, ValuePtr collapser, ValuePtr filler) :
321  mGetter(getter), mSetter(setter), mCollapser(collapser), mFiller(filler) { }
322 
327 }; // struct AttributeArray::Accessor
328 
329 
330 ////////////////////////////////////////
331 
332 
333 namespace attribute_traits
334 {
335  template <typename T> struct TruncateTrait { };
336  template <> struct TruncateTrait<float> { using Type = half; };
337  template <> struct TruncateTrait<int> { using Type = short; };
338 
339  template <typename T> struct TruncateTrait<math::Vec3<T>> {
341  };
342 
343  template <bool OneByte, typename T> struct UIntTypeTrait { };
344  template<typename T> struct UIntTypeTrait</*OneByte=*/true, T> { using Type = uint8_t; };
345  template<typename T> struct UIntTypeTrait</*OneByte=*/false, T> { using Type = uint16_t; };
346  template<typename T> struct UIntTypeTrait</*OneByte=*/true, math::Vec3<T>> {
348  };
349  template<typename T> struct UIntTypeTrait</*OneByte=*/false, math::Vec3<T>> {
351  };
352 }
353 
354 
355 ////////////////////////////////////////
356 
357 
358 // Attribute codec schemes
359 
360 struct UnknownCodec { };
361 
362 
363 struct NullCodec
364 {
365  template <typename T>
366  struct Storage { using Type = T; };
367 
368  template<typename ValueType> static void decode(const ValueType&, ValueType&);
369  template<typename ValueType> static void encode(const ValueType&, ValueType&);
370  static const char* name() { return "null"; }
371 };
372 
373 
375 {
376  template <typename T>
378 
379  template<typename StorageType, typename ValueType> static void decode(const StorageType&, ValueType&);
380  template<typename StorageType, typename ValueType> static void encode(const ValueType&, StorageType&);
381  static const char* name() { return "trnc"; }
382 };
383 
384 
385 // Fixed-point codec range for voxel-space positions [-0.5,0.5]
387 {
388  static const char* name() { return "fxpt"; }
389  template <typename ValueType> static ValueType encode(const ValueType& value) { return value + ValueType(0.5); }
390  template <typename ValueType> static ValueType decode(const ValueType& value) { return value - ValueType(0.5); }
391 };
392 
393 
394 // Fixed-point codec range for unsigned values in the unit range [0.0,1.0]
395 struct UnitRange
396 {
397  static const char* name() { return "ufxpt"; }
398  template <typename ValueType> static ValueType encode(const ValueType& value) { return value; }
399  template <typename ValueType> static ValueType decode(const ValueType& value) { return value; }
400 };
401 
402 
403 template <bool OneByte, typename Range=PositionRange>
405 {
406  template <typename T>
408 
409  template<typename StorageType, typename ValueType> static void decode(const StorageType&, ValueType&);
410  template<typename StorageType, typename ValueType> static void encode(const ValueType&, StorageType&);
411 
412  static const char* name() {
413  static const std::string Name = std::string(Range::name()) + (OneByte ? "8" : "16");
414  return Name.c_str();
415  }
416 };
417 
418 
420 {
421  using StorageType = uint16_t;
422 
423  template <typename T>
424  struct Storage { using Type = StorageType; };
425 
426  template<typename T> static void decode(const StorageType&, math::Vec3<T>&);
427  template<typename T> static void encode(const math::Vec3<T>&, StorageType&);
428  static const char* name() { return "uvec"; }
429 };
430 
431 
432 ////////////////////////////////////////
433 
434 
435 /// Typed class for storing attribute data
436 template<typename ValueType_, typename Codec_ = NullCodec>
438 {
439 public:
440  using Ptr = std::shared_ptr<TypedAttributeArray>;
441  using ConstPtr = std::shared_ptr<const TypedAttributeArray>;
442 
443  using ValueType = ValueType_;
444  using Codec = Codec_;
445  using StorageType = typename Codec::template Storage<ValueType>::Type;
446 
447  //////////
448 
449  /// Default constructor, always constructs a uniform attribute.
450  explicit TypedAttributeArray(Index n = 1, Index strideOrTotalSize = 1, bool constantStride = true,
451  const ValueType& uniformValue = zeroVal<ValueType>());
452  /// Deep copy constructor (optionally decompress during copy).
453  TypedAttributeArray(const TypedAttributeArray&, bool uncompress = false);
454  /// Deep copy assignment operator.
456  /// Move constructor disabled.
458  /// Move assignment operator disabled.
460 
461  virtual ~TypedAttributeArray() { this->deallocate(); }
462 
463  /// Return a copy of this attribute.
464  AttributeArray::Ptr copy() const override;
465 
466  /// Return an uncompressed copy of this attribute (will just return a copy if not compressed).
467  AttributeArray::Ptr copyUncompressed() const override;
468 
469  /// Return a new attribute array of the given length @a n and @a stride with uniform value zero.
470  static Ptr create(Index n, Index strideOrTotalSize = 1, bool constantStride = true);
471 
472  /// Cast an AttributeArray to TypedAttributeArray<T>
473  static TypedAttributeArray& cast(AttributeArray& attributeArray);
474 
475  /// Cast an AttributeArray to TypedAttributeArray<T>
476  static const TypedAttributeArray& cast(const AttributeArray& attributeArray);
477 
478  /// Return the name of this attribute's type (includes codec)
479  static const NamePair& attributeType();
480  /// Return the name of this attribute's type.
481  const NamePair& type() const override { return attributeType(); }
482 
483  /// Return @c true if this attribute type is registered.
484  static bool isRegistered();
485  /// Register this attribute type along with a factory function.
486  static void registerType();
487  /// Remove this attribute type from the registry.
488  static void unregisterType();
489 
490  /// Return the number of elements in this array.
491  Index size() const override { return mSize; }
492 
493  /// Return the stride of this array.
494  /// @note A return value of zero means a variable stride
495  Index stride() const override { return hasConstantStride() ? mStrideOrTotalSize : 0; }
496 
497  /// Return the size of the data in this array.
498  Index dataSize() const override {
499  return hasConstantStride() ? mSize * mStrideOrTotalSize : mStrideOrTotalSize;
500  }
501 
502  /// Return the number of bytes of memory used by this attribute.
503  size_t memUsage() const override;
504 
505  /// Return the value at index @a n (assumes uncompressed and in-core)
506  ValueType getUnsafe(Index n) const;
507  /// Return the value at index @a n
508  ValueType get(Index n) const;
509  /// Return the @a value at index @a n (assumes uncompressed and in-core)
510  template<typename T> void getUnsafe(Index n, T& value) const;
511  /// Return the @a value at index @a n
512  template<typename T> void get(Index n, T& value) const;
513 
514  /// Non-member equivalent to getUnsafe() that static_casts array to this TypedAttributeArray
515  /// (assumes uncompressed and in-core)
516  static ValueType getUnsafe(const AttributeArray* array, const Index n);
517 
518  /// Set @a value at the given index @a n (assumes uncompressed and in-core)
519  void setUnsafe(Index n, const ValueType& value);
520  /// Set @a value at the given index @a n
521  void set(Index n, const ValueType& value);
522  /// Set @a value at the given index @a n (assumes uncompressed and in-core)
523  template<typename T> void setUnsafe(Index n, const T& value);
524  /// Set @a value at the given index @a n
525  template<typename T> void set(Index n, const T& value);
526 
527  /// Non-member equivalent to setUnsafe() that static_casts array to this TypedAttributeArray
528  /// (assumes uncompressed and in-core)
529  static void setUnsafe(AttributeArray* array, const Index n, const ValueType& value);
530 
531  /// Set value at given index @a n from @a sourceIndex of another @a sourceArray
532  void set(const Index n, const AttributeArray& sourceArray, const Index sourceIndex) override;
533 
534  /// Return @c true if this array is stored as a single uniform value.
535  bool isUniform() const override { return mIsUniform; }
536  /// @brief Replace the single value storage with an array of length size().
537  /// @note Non-uniform attributes are unchanged.
538  /// @param fill toggle to initialize the array elements with the pre-expanded value.
539  void expand(bool fill = true) override;
540  /// Replace the existing array with a uniform zero value.
541  void collapse() override;
542  /// Compact the existing array to become uniform if all values are identical
543  bool compact() override;
544 
545  /// Replace the existing array with the given uniform value.
546  void collapse(const ValueType& uniformValue);
547  /// @brief Fill the existing array with the given value.
548  /// @note Identical to collapse() except a non-uniform array will not become uniform.
549  void fill(const ValueType& value);
550 
551  /// Non-member equivalent to collapse() that static_casts array to this TypedAttributeArray
552  static void collapse(AttributeArray* array, const ValueType& value);
553  /// Non-member equivalent to fill() that static_casts array to this TypedAttributeArray
554  static void fill(AttributeArray* array, const ValueType& value);
555 
556  /// Compress the attribute array.
557  bool compress() override;
558  /// Uncompress the attribute array.
559  bool decompress() override;
560 
561  /// Read attribute data from a stream.
562  void read(std::istream&) override;
563  /// Write attribute data to a stream.
564  /// @param os the output stream
565  /// @param outputTransient if true, write out transient attributes
566  void write(std::ostream& os, bool outputTransient) const override;
567  /// Write attribute data to a stream, don't write transient attributes.
568  void write(std::ostream&) const override;
569 
570  /// Read attribute metadata from a stream.
571  void readMetadata(std::istream&) override;
572  /// Write attribute metadata to a stream.
573  /// @param os the output stream
574  /// @param outputTransient if true, write out transient attributes
575  /// @param paged if true, data is written out in pages
576  void writeMetadata(std::ostream& os, bool outputTransient, bool paged) const override;
577 
578  /// Read attribute buffers from a stream.
579  void readBuffers(std::istream&) override;
580  /// Write attribute buffers to a stream.
581  /// @param os the output stream
582  /// @param outputTransient if true, write out transient attributes
583  void writeBuffers(std::ostream& os, bool outputTransient) const override;
584 
585  /// Read attribute buffers from a paged stream.
587  /// Write attribute buffers to a paged stream.
588  /// @param os the output stream
589  /// @param outputTransient if true, write out transient attributes
590  void writePagedBuffers(compression::PagedOutputStream& os, bool outputTransient) const override;
591 
592  /// Return @c true if this buffer's values have not yet been read from disk.
593  inline bool isOutOfCore() const;
594 
595  /// Ensures all data is in-core
596  void loadData() const override;
597 
598 protected:
599  AccessorBasePtr getAccessor() const override;
600 
601 private:
602  /// Load data from memory-mapped file.
603  inline void doLoad() const;
604  /// Load data from memory-mapped file (unsafe as this function is not protected by a mutex).
605  /// @param compression if true, loading previously compressed data will re-compressed it
606  inline void doLoadUnsafe(const bool compression = true) const;
607  /// Compress in-core data assuming mutex is locked
608  inline bool compressUnsafe();
609 
610  /// Toggle out-of-core state
611  inline void setOutOfCore(const bool);
612 
613  /// Compare the this data to another attribute array. Used by the base class comparison operator
614  bool isEqual(const AttributeArray& other) const override;
615 
616  size_t arrayMemUsage() const;
617  void allocate();
618  void deallocate();
619 
620  /// Helper function for use with registerType()
621  static AttributeArray::Ptr factory(Index n, Index strideOrTotalSize, bool constantStride) {
622  return TypedAttributeArray::create(n, strideOrTotalSize, constantStride);
623  }
624 
625  static tbb::atomic<const NamePair*> sTypeName;
626  std::unique_ptr<StorageType[]> mData;
627  Index mSize;
628  Index mStrideOrTotalSize;
629  bool mIsUniform = false;
630  tbb::spin_mutex mMutex;
631 }; // class TypedAttributeArray
632 
633 
634 ////////////////////////////////////////
635 
636 
637 /// AttributeHandles provide access to specific TypedAttributeArray methods without needing
638 /// to know the compression codec, however these methods also incur the cost of a function pointer
639 template <typename ValueType, typename CodecType = UnknownCodec>
641 {
642 public:
644  using Ptr = std::shared_ptr<Handle>;
645  using UniquePtr = std::unique_ptr<Handle>;
646 
647 protected:
648  using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
649  using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
650  using ValuePtr = void (*)(AttributeArray* array, const ValueType& value);
651 
652 public:
653  static Ptr create(const AttributeArray& array, const bool preserveCompression = true);
654 
655  AttributeHandle(const AttributeArray& array, const bool preserveCompression = true);
656 
657  AttributeHandle(const AttributeHandle&) = default;
658  AttributeHandle& operator=(const AttributeHandle&) = default;
659 
660  virtual ~AttributeHandle();
661 
662  Index stride() const { return mStrideOrTotalSize; }
663  Index size() const { return mSize; }
664 
665  bool isUniform() const;
666  bool hasConstantStride() const;
667 
668  ValueType get(Index n, Index m = 0) const;
669 
670 protected:
671  Index index(Index n, Index m) const;
672 
674 
679 
680 private:
681  friend class ::TestAttributeArray;
682 
683  template <bool IsUnknownCodec>
684  typename std::enable_if<IsUnknownCodec, bool>::type compatibleType() const;
685 
686  template <bool IsUnknownCodec>
687  typename std::enable_if<!IsUnknownCodec, bool>::type compatibleType() const;
688 
689  template <bool IsUnknownCodec>
691 
692  template <bool IsUnknownCodec>
694 
695  // local copy of AttributeArray (to preserve compression)
696  AttributeArray::Ptr mLocalArray;
697 
698  Index mStrideOrTotalSize;
699  Index mSize;
700  bool mCollapseOnDestruction;
701 }; // class AttributeHandle
702 
703 
704 ////////////////////////////////////////
705 
706 
707 /// Write-able version of AttributeHandle
708 template <typename ValueType, typename CodecType = UnknownCodec>
709 class AttributeWriteHandle : public AttributeHandle<ValueType, CodecType>
710 {
711 public:
713  using Ptr = std::shared_ptr<Handle>;
714  using ScopedPtr = std::unique_ptr<Handle>;
715 
716  static Ptr create(AttributeArray& array, const bool expand = true);
717 
718  AttributeWriteHandle(AttributeArray& array, const bool expand = true);
719 
720  virtual ~AttributeWriteHandle() = default;
721 
722  /// @brief If this array is uniform, replace it with an array of length size().
723  /// @param fill if true, assign the uniform value to each element of the array.
724  void expand(bool fill = true);
725 
726  /// Replace the existing array with a uniform value (zero if none provided).
727  void collapse();
728  void collapse(const ValueType& uniformValue);
729 
730  /// Compact the existing array to become uniform if all values are identical
731  bool compact();
732 
733  /// @brief Fill the existing array with the given value.
734  /// @note Identical to collapse() except a non-uniform array will not become uniform.
735  void fill(const ValueType& value);
736 
737  void set(Index n, const ValueType& value);
738  void set(Index n, Index m, const ValueType& value);
739 
740 private:
741  friend class ::TestAttributeArray;
742 
743  template <bool IsUnknownCodec>
744  typename std::enable_if<IsUnknownCodec, void>::type set(Index index, const ValueType& value) const;
745 
746  template <bool IsUnknownCodec>
747  typename std::enable_if<!IsUnknownCodec, void>::type set(Index index, const ValueType& value) const;
748 }; // class AttributeWriteHandle
749 
750 
751 ////////////////////////////////////////
752 
753 
754 // Attribute codec implementation
755 
756 
757 template<typename ValueType>
758 inline void
759 NullCodec::decode(const ValueType& data, ValueType& val)
760 {
761  val = data;
762 }
763 
764 
765 template<typename ValueType>
766 inline void
767 NullCodec::encode(const ValueType& val, ValueType& data)
768 {
769  data = val;
770 }
771 
772 
773 template<typename StorageType, typename ValueType>
774 inline void
775 TruncateCodec::decode(const StorageType& data, ValueType& val)
776 {
777  val = static_cast<ValueType>(data);
778 }
779 
780 
781 template<typename StorageType, typename ValueType>
782 inline void
783 TruncateCodec::encode(const ValueType& val, StorageType& data)
784 {
785  data = static_cast<StorageType>(val);
786 }
787 
788 
789 template <bool OneByte, typename Range>
790 template<typename StorageType, typename ValueType>
791 inline void
792 FixedPointCodec<OneByte, Range>::decode(const StorageType& data, ValueType& val)
793 {
794  val = fixedPointToFloatingPoint<ValueType>(data);
795 
796  // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
797 
798  val = Range::template decode<ValueType>(val);
799 }
800 
801 
802 template <bool OneByte, typename Range>
803 template<typename StorageType, typename ValueType>
804 inline void
805 FixedPointCodec<OneByte, Range>::encode(const ValueType& val, StorageType& data)
806 {
807  // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
808 
809  const ValueType newVal = Range::template encode<ValueType>(val);
810 
811  data = floatingPointToFixedPoint<StorageType>(newVal);
812 }
813 
814 
815 template<typename T>
816 inline void
818 {
819  val = math::QuantizedUnitVec::unpack(data);
820 }
821 
822 
823 template<typename T>
824 inline void
826 {
827  data = math::QuantizedUnitVec::pack(val);
828 }
829 
830 
831 ////////////////////////////////////////
832 
833 // TypedAttributeArray implementation
834 
835 template<typename ValueType_, typename Codec_>
836 tbb::atomic<const NamePair*> TypedAttributeArray<ValueType_, Codec_>::sTypeName;
837 
838 
839 template<typename ValueType_, typename Codec_>
841  Index n, Index strideOrTotalSize, bool constantStride, const ValueType& uniformValue)
842  : mData(new StorageType[1])
843  , mSize(n)
844  , mStrideOrTotalSize(strideOrTotalSize)
845  , mIsUniform(true)
846 {
847  if (constantStride) {
848  this->setConstantStride(true);
849  if (strideOrTotalSize == 0) {
850  OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a constant stride requires that " \
851  "stride to be at least one.")
852  }
853  }
854  else {
855  this->setConstantStride(false);
856  if (mStrideOrTotalSize < n) {
857  OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a non-constant stride must have " \
858  "a total size of at least the number of elements in the array.")
859  }
860  }
861  mSize = std::max(Index(1), mSize);
862  mStrideOrTotalSize = std::max(Index(1), mStrideOrTotalSize);
863  Codec::encode(uniformValue, mData.get()[0]);
864 }
865 
866 
867 template<typename ValueType_, typename Codec_>
869  : AttributeArray(rhs)
870  , mSize(rhs.mSize)
871  , mStrideOrTotalSize(rhs.mStrideOrTotalSize)
872  , mIsUniform(rhs.mIsUniform)
873 {
874  // disable uncompress if data is not compressed
875 
876  if (!this->isCompressed()) uncompress = false;
877 
878  if (this->isOutOfCore()) {
879  // do nothing
880  } else if (mIsUniform) {
881  this->allocate();
882  mData.get()[0] = rhs.mData.get()[0];
883  } else if (this->isCompressed()) {
884  std::unique_ptr<char[]> buffer;
885  if (uncompress) {
886  const char* charBuffer = reinterpret_cast<const char*>(rhs.mData.get());
887  size_t uncompressedBytes = compression::bloscUncompressedSize(charBuffer);
888  buffer = compression::bloscDecompress(charBuffer, uncompressedBytes);
889  }
890  if (buffer) {
891  mCompressedBytes = 0;
892  } else {
893  // decompression wasn't requested or failed so deep copy instead
894  buffer.reset(new char[mCompressedBytes]);
895  std::memcpy(buffer.get(), rhs.mData.get(), mCompressedBytes);
896  }
897  assert(buffer);
898  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
899  } else {
900  this->allocate();
901  std::memcpy(mData.get(), rhs.mData.get(), this->arrayMemUsage());
902  }
903 }
904 
905 
906 template<typename ValueType_, typename Codec_>
909 {
910  if (&rhs != this) {
911  tbb::spin_mutex::scoped_lock lock(mMutex);
912 
913  this->deallocate();
914 
915  mFlags = rhs.mFlags;
916  mSerializationFlags = rhs.mSerializationFlags;
917  mCompressedBytes = rhs.mCompressedBytes;
918  mSize = rhs.mSize;
919  mStrideOrTotalSize = rhs.mStrideOrTotalSize;
920  mIsUniform = rhs.mIsUniform;
921 
922  if (rhs.isOutOfCore()) {
923  mPageHandle = rhs.mPageHandle;
924  } else if (mIsUniform) {
925  this->allocate();
926  mData.get()[0] = rhs.mData.get()[0];
927  } else if (this->isCompressed()) {
928  std::unique_ptr<char[]> buffer(new char[mCompressedBytes]);
929  std::memcpy(buffer.get(), rhs.mData.get(), mCompressedBytes);
930  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
931  } else {
932  this->allocate();
933  std::memcpy(mData.get(), rhs.mData.get(), arrayMemUsage());
934  }
935  }
936 }
937 
938 
939 template<typename ValueType_, typename Codec_>
940 inline const NamePair&
942 {
943  if (sTypeName == nullptr) {
944  NamePair* s = new NamePair(typeNameAsString<ValueType>(), Codec::name());
945  if (sTypeName.compare_and_swap(s, nullptr) != nullptr) delete s;
946  }
947  return *sTypeName;
948 }
949 
950 
951 template<typename ValueType_, typename Codec_>
952 inline bool
954 {
956 }
957 
958 
959 template<typename ValueType_, typename Codec_>
960 inline void
962 {
963  AttributeArray::registerType(TypedAttributeArray::attributeType(), TypedAttributeArray::factory);
964 }
965 
966 
967 template<typename ValueType_, typename Codec_>
968 inline void
970 {
972 }
973 
974 
975 template<typename ValueType_, typename Codec_>
978 {
979  return Ptr(new TypedAttributeArray(n, stride, constantStride));
980 }
981 
982 template<typename ValueType_, typename Codec_>
985 {
986  if (!attributeArray.isType<TypedAttributeArray>()) {
987  OPENVDB_THROW(TypeError, "Invalid Attribute Type");
988  }
989  return static_cast<TypedAttributeArray&>(attributeArray);
990 }
991 
992 template<typename ValueType_, typename Codec_>
995 {
996  if (!attributeArray.isType<TypedAttributeArray>()) {
997  OPENVDB_THROW(TypeError, "Invalid Attribute Type");
998  }
999  return static_cast<const TypedAttributeArray&>(attributeArray);
1000 }
1001 
1002 template<typename ValueType_, typename Codec_>
1005 {
1007 }
1008 
1009 
1010 template<typename ValueType_, typename Codec_>
1013 {
1014  return AttributeArray::Ptr(new TypedAttributeArray<ValueType, Codec>(*this, /*decompress = */true));
1015 }
1016 
1017 
1018 template<typename ValueType_, typename Codec_>
1019 size_t
1021 {
1022  if (this->isOutOfCore()) return 0;
1023  if (this->isCompressed()) return mCompressedBytes;
1024 
1025  return (mIsUniform ? 1 : this->dataSize()) * sizeof(StorageType);
1026 }
1027 
1028 
1029 template<typename ValueType_, typename Codec_>
1030 void
1031 TypedAttributeArray<ValueType_, Codec_>::allocate()
1032 {
1033  assert(!mData);
1034  if (mIsUniform) {
1035  mData.reset(new StorageType[1]);
1036  }
1037  else {
1038  const size_t size(this->dataSize());
1039  assert(size > 0);
1040  mData.reset(new StorageType[size]);
1041  }
1042 }
1043 
1044 
1045 template<typename ValueType_, typename Codec_>
1046 void
1047 TypedAttributeArray<ValueType_, Codec_>::deallocate()
1048 {
1049  // detach from file if delay-loaded
1050  if (this->isOutOfCore()) {
1051  this->setOutOfCore(false);
1052  this->mPageHandle.reset();
1053  }
1054  if (mData) mData.reset();
1055 }
1056 
1057 
1058 template<typename ValueType_, typename Codec_>
1059 size_t
1061 {
1062  return sizeof(*this) + (bool(mData) ? this->arrayMemUsage() : 0);
1063 }
1064 
1065 
1066 template<typename ValueType_, typename Codec_>
1069 {
1070  assert(n < this->dataSize());
1071  assert(!this->isOutOfCore());
1072  assert(!this->isCompressed());
1073 
1074  ValueType val;
1075  Codec::decode(/*in=*/mData.get()[mIsUniform ? 0 : n], /*out=*/val);
1076  return val;
1077 }
1078 
1079 
1080 template<typename ValueType_, typename Codec_>
1083 {
1084  if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1085  if (this->isOutOfCore()) this->doLoad();
1086  if (this->isCompressed()) const_cast<TypedAttributeArray*>(this)->decompress();
1087 
1088  return this->getUnsafe(n);
1089 }
1090 
1091 
1092 template<typename ValueType_, typename Codec_>
1093 template<typename T>
1094 void
1096 {
1097  val = static_cast<T>(this->getUnsafe(n));
1098 }
1099 
1100 
1101 template<typename ValueType_, typename Codec_>
1102 template<typename T>
1103 void
1105 {
1106  val = static_cast<T>(this->get(n));
1107 }
1108 
1109 
1110 template<typename ValueType_, typename Codec_>
1113 {
1114  return static_cast<const TypedAttributeArray<ValueType, Codec>*>(array)->getUnsafe(n);
1115 }
1116 
1117 
1118 template<typename ValueType_, typename Codec_>
1119 void
1121 {
1122  assert(n < this->dataSize());
1123  assert(!this->isOutOfCore());
1124  assert(!this->isCompressed());
1125  assert(!this->isUniform());
1126 
1127  // this unsafe method assumes the data is not uniform, however if it is, this redirects the index
1128  // to zero, which is marginally less efficient but ensures not writing to an illegal address
1129 
1130  Codec::encode(/*in=*/val, /*out=*/mData.get()[mIsUniform ? 0 : n]);
1131 }
1132 
1133 
1134 template<typename ValueType_, typename Codec_>
1135 void
1137 {
1138  if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1139  if (this->isOutOfCore()) this->doLoad();
1140  if (this->isCompressed()) this->decompress();
1141  if (this->isUniform()) this->expand();
1142 
1143  this->setUnsafe(n, val);
1144 }
1145 
1146 
1147 template<typename ValueType_, typename Codec_>
1148 template<typename T>
1149 void
1151 {
1152  this->setUnsafe(n, static_cast<ValueType>(val));
1153 }
1154 
1155 
1156 template<typename ValueType_, typename Codec_>
1157 template<typename T>
1158 void
1160 {
1161  this->set(n, static_cast<ValueType>(val));
1162 }
1163 
1164 
1165 template<typename ValueType_, typename Codec_>
1166 void
1168 {
1169  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->setUnsafe(n, value);
1170 }
1171 
1172 
1173 template<typename ValueType_, typename Codec_>
1174 void
1176 {
1177  const TypedAttributeArray& sourceTypedArray = static_cast<const TypedAttributeArray&>(sourceArray);
1178 
1179  ValueType sourceValue;
1180  sourceTypedArray.get(sourceIndex, sourceValue);
1181 
1182  this->set(n, sourceValue);
1183 }
1184 
1185 
1186 template<typename ValueType_, typename Codec_>
1187 void
1189 {
1190  if (!mIsUniform) return;
1191 
1192  const StorageType val = mData.get()[0];
1193 
1194  {
1195  tbb::spin_mutex::scoped_lock lock(mMutex);
1196  this->deallocate();
1197  mIsUniform = false;
1198  this->allocate();
1199  }
1200 
1201  mCompressedBytes = 0;
1202 
1203  if (fill) {
1204  for (Index i = 0; i < this->dataSize(); ++i) mData.get()[i] = val;
1205  }
1206 }
1207 
1208 
1209 template<typename ValueType_, typename Codec_>
1210 bool
1212 {
1213  if (mIsUniform) return true;
1214 
1215  // compaction is not possible if any values are different
1216  const ValueType_ val = this->get(0);
1217  for (Index i = 1; i < this->dataSize(); i++) {
1218  if (!math::isExactlyEqual(this->get(i), val)) return false;
1219  }
1220 
1221  this->collapse(this->get(0));
1222  return true;
1223 }
1224 
1225 
1226 template<typename ValueType_, typename Codec_>
1227 void
1229 {
1230  this->collapse(zeroVal<ValueType>());
1231 }
1232 
1233 
1234 template<typename ValueType_, typename Codec_>
1235 void
1237 {
1238  if (!mIsUniform) {
1239  tbb::spin_mutex::scoped_lock lock(mMutex);
1240  this->deallocate();
1241  mIsUniform = true;
1242  this->allocate();
1243  }
1244  Codec::encode(uniformValue, mData.get()[0]);
1245 }
1246 
1247 
1248 template<typename ValueType_, typename Codec_>
1249 void
1251 {
1252  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->collapse(value);
1253 }
1254 
1255 
1256 template<typename ValueType_, typename Codec_>
1257 void
1259 {
1260  if (this->isOutOfCore()) {
1261  tbb::spin_mutex::scoped_lock lock(mMutex);
1262  this->deallocate();
1263  this->allocate();
1264  }
1265 
1266  const Index size = mIsUniform ? 1 : this->dataSize();
1267  for (Index i = 0; i < size; ++i) {
1268  Codec::encode(value, mData.get()[i]);
1269  }
1270 }
1271 
1272 
1273 template<typename ValueType_, typename Codec_>
1274 void
1276 {
1277  static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->fill(value);
1278 }
1279 
1280 
1281 template<typename ValueType_, typename Codec_>
1282 inline bool
1284 {
1285  if (!compression::bloscCanCompress()) return false;
1286 
1287  if (!mIsUniform && !this->isCompressed()) {
1288 
1289  tbb::spin_mutex::scoped_lock lock(mMutex);
1290 
1291  this->doLoadUnsafe(/*compression=*/false);
1292 
1293  if (this->isCompressed()) return true;
1294 
1295  return this->compressUnsafe();
1296  }
1297 
1298  return false;
1299 }
1300 
1301 
1302 template<typename ValueType_, typename Codec_>
1303 inline bool
1305 {
1306  if (!compression::bloscCanCompress()) return false;
1307  if (mIsUniform) return false;
1308 
1309  // assumes mutex is locked and data is not out-of-core
1310 
1311  const bool writeCompress = (mSerializationFlags & WRITEMEMCOMPRESS);
1312  const size_t inBytes = writeCompress ? mCompressedBytes : this->arrayMemUsage();
1313 
1314  if (inBytes > 0) {
1315  size_t outBytes;
1316  const char* charBuffer = reinterpret_cast<const char*>(mData.get());
1317  std::unique_ptr<char[]> buffer = compression::bloscCompress(charBuffer, inBytes, outBytes);
1318  if (buffer) {
1319  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1320  mCompressedBytes = outBytes;
1321  return true;
1322  }
1323  }
1324 
1325  return false;
1326 }
1327 
1328 
1329 template<typename ValueType_, typename Codec_>
1330 inline bool
1332 {
1333  tbb::spin_mutex::scoped_lock lock(mMutex);
1334 
1335  const bool writeCompress = (mSerializationFlags & WRITEMEMCOMPRESS);
1336 
1337  if (writeCompress) {
1338  this->doLoadUnsafe(/*compression=*/false);
1339  return true;
1340  }
1341 
1342  if (this->isCompressed()) {
1343  this->doLoadUnsafe();
1344  const char* charBuffer = reinterpret_cast<const char*>(this->mData.get());
1345  size_t uncompressedBytes = compression::bloscUncompressedSize(charBuffer);
1346  std::unique_ptr<char[]> buffer = compression::bloscDecompress(charBuffer, uncompressedBytes);
1347  if (buffer) {
1348  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1349  mCompressedBytes = 0;
1350  return true;
1351  }
1352  }
1353 
1354  return false;
1355 }
1356 
1357 
1358 template<typename ValueType_, typename Codec_>
1359 bool
1361 {
1362  return (mFlags & OUTOFCORE);
1363 }
1364 
1365 
1366 template<typename ValueType_, typename Codec_>
1367 void
1369 {
1370  if (b) mFlags = static_cast<uint8_t>(mFlags | OUTOFCORE);
1371  else mFlags = static_cast<uint8_t>(mFlags & ~OUTOFCORE);
1372 }
1373 
1374 
1375 template<typename ValueType_, typename Codec_>
1376 void
1377 TypedAttributeArray<ValueType_, Codec_>::doLoad() const
1378 {
1379  if (!(this->isOutOfCore())) return;
1380 
1381  TypedAttributeArray<ValueType_, Codec_>* self =
1382  const_cast<TypedAttributeArray<ValueType_, Codec_>*>(this);
1383 
1384  // This lock will be contended at most once, after which this buffer
1385  // will no longer be out-of-core.
1386  tbb::spin_mutex::scoped_lock lock(self->mMutex);
1387  this->doLoadUnsafe();
1388 }
1389 
1390 
1391 template<typename ValueType_, typename Codec_>
1392 void
1394 {
1395  this->doLoad();
1396 }
1397 
1398 
1399 template<typename ValueType_, typename Codec_>
1400 void
1402 {
1403  this->readMetadata(is);
1404  this->readBuffers(is);
1405 }
1406 
1407 
1408 template<typename ValueType_, typename Codec_>
1409 void
1411 {
1412  // read data
1413 
1414  Index64 bytes = Index64(0);
1415  is.read(reinterpret_cast<char*>(&bytes), sizeof(Index64));
1416  bytes = bytes - /*flags*/sizeof(Int16) - /*size*/sizeof(Index);
1417 
1418  uint8_t flags = uint8_t(0);
1419  is.read(reinterpret_cast<char*>(&flags), sizeof(uint8_t));
1420  mFlags = flags;
1421 
1422  uint8_t serializationFlags = uint8_t(0);
1423  is.read(reinterpret_cast<char*>(&serializationFlags), sizeof(uint8_t));
1424  mSerializationFlags = serializationFlags;
1425 
1426  Index size = Index(0);
1427  is.read(reinterpret_cast<char*>(&size), sizeof(Index));
1428  mSize = size;
1429 
1430  // read uniform and compressed state
1431 
1432  mIsUniform = mSerializationFlags & WRITEUNIFORM;
1433  mCompressedBytes = bytes;
1434 
1435  // read strided value (set to 1 if array is not strided)
1436 
1437  if (mSerializationFlags & WRITESTRIDED) {
1438  Index stride = Index(0);
1439  is.read(reinterpret_cast<char*>(&stride), sizeof(Index));
1440  mStrideOrTotalSize = stride;
1441  }
1442  else {
1443  mStrideOrTotalSize = 1;
1444  }
1445 }
1446 
1447 
1448 template<typename ValueType_, typename Codec_>
1449 void
1451 {
1452  if ((mSerializationFlags & WRITEPAGED)) {
1453  // use readBuffers(PagedInputStream&) for paged buffers
1454  OPENVDB_THROW(IoError, "Cannot read paged AttributeArray buffers.");
1455  }
1456 
1457  tbb::spin_mutex::scoped_lock lock(mMutex);
1458 
1459  this->deallocate();
1460 
1461  uint8_t bloscCompressed(0);
1462  if (!mIsUniform) is.read(reinterpret_cast<char*>(&bloscCompressed), sizeof(uint8_t));
1463 
1464  std::unique_ptr<char[]> buffer(new char[mCompressedBytes]);
1465  is.read(buffer.get(), mCompressedBytes);
1466 
1467  if (mIsUniform) {
1468  // zero compressed bytes as uniform values are not compressed in memory
1469  mCompressedBytes = Index64(0);
1470  }
1471  else if (!(mSerializationFlags & WRITEMEMCOMPRESS)) {
1472  // zero compressed bytes if not compressed in memory
1473  mCompressedBytes = Index64(0);
1474  }
1475 
1476  // compressed on-disk
1477 
1478  if (bloscCompressed == uint8_t(1)) {
1479 
1480  // decompress buffer
1481 
1482  const size_t inBytes = this->dataSize() * sizeof(StorageType);
1483  std::unique_ptr<char[]> newBuffer = compression::bloscDecompress(buffer.get(), inBytes);
1484  if (newBuffer) buffer.reset(newBuffer.release());
1485  }
1486 
1487  // set data to buffer
1488 
1489  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1490 
1491  // clear all write flags
1492 
1493  if (mIsUniform) mSerializationFlags &= uint8_t(~WRITEUNIFORM & ~WRITEMEMCOMPRESS & ~WRITEPAGED);
1494  else mSerializationFlags &= uint8_t(~WRITEUNIFORM & ~WRITEPAGED);
1495 }
1496 
1497 
1498 template<typename ValueType_, typename Codec_>
1499 void
1501 {
1502  if (!(mSerializationFlags & WRITEPAGED)) {
1503  if (!is.sizeOnly()) this->readBuffers(is.getInputStream());
1504  return;
1505  }
1506 
1507  // If this array is being read from a memory-mapped file, delay loading of its data
1508  // until the data is actually accessed.
1510  const bool delayLoad = (mappedFile.get() != nullptr);
1511 
1512  if (is.sizeOnly())
1513  {
1514  mPageHandle = is.createHandle(mCompressedBytes);
1515  return;
1516  }
1517 
1518  assert(mPageHandle);
1519 
1520  tbb::spin_mutex::scoped_lock lock(mMutex);
1521 
1522  this->deallocate();
1523 
1524  this->setOutOfCore(delayLoad);
1525  is.read(mPageHandle, mCompressedBytes, delayLoad);
1526 
1527  if (!delayLoad) {
1528  std::unique_ptr<char[]> buffer = mPageHandle->read();
1529  mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1530  }
1531 
1532  // zero compressed bytes as not compressed in memory
1533 
1534  if (mIsUniform) {
1535  // zero compressed bytes as uniform values are not compressed in memory
1536  mCompressedBytes = Index64(0);
1537  }
1538  else if (!(mSerializationFlags & WRITEMEMCOMPRESS)) {
1539  mCompressedBytes = Index64(0);
1540  }
1541 
1542  // clear all write flags
1543 
1544  if (mIsUniform) mSerializationFlags &= uint8_t(~WRITEUNIFORM & ~WRITEMEMCOMPRESS & ~WRITEPAGED);
1545  else mSerializationFlags &= uint8_t(~WRITEUNIFORM & ~WRITEPAGED);
1546 }
1547 
1548 
1549 template<typename ValueType_, typename Codec_>
1550 void
1552 {
1553  this->write(os, /*outputTransient=*/false);
1554 }
1555 
1556 
1557 template<typename ValueType_, typename Codec_>
1558 void
1559 TypedAttributeArray<ValueType_, Codec_>::write(std::ostream& os, bool outputTransient) const
1560 {
1561  this->writeMetadata(os, outputTransient, /*paged=*/false);
1562  this->writeBuffers(os, outputTransient);
1563 }
1564 
1565 
1566 template<typename ValueType_, typename Codec_>
1567 void
1568 TypedAttributeArray<ValueType_, Codec_>::writeMetadata(std::ostream& os, bool outputTransient, bool paged) const
1569 {
1570  if (!outputTransient && this->isTransient()) return;
1571 
1572  uint8_t flags(mFlags);
1573  uint8_t serializationFlags(mSerializationFlags);
1574  Index size(mSize);
1575  Index stride(mStrideOrTotalSize);
1576  bool strideOfOne(this->stride() == 1);
1577 
1578  bool bloscCompression = io::getDataCompression(os) & io::COMPRESS_BLOSC;
1579 
1580  size_t compressedBytes = 0;
1581 
1582  if (!strideOfOne)
1583  {
1584  serializationFlags |= WRITESTRIDED;
1585  }
1586 
1587  if (mIsUniform)
1588  {
1589  serializationFlags |= WRITEUNIFORM;
1590  if (bloscCompression && paged) serializationFlags |= WRITEPAGED;
1591  }
1592  else if (bloscCompression && paged)
1593  {
1594  serializationFlags |= WRITEPAGED;
1595  if (this->isCompressed()) {
1596  serializationFlags |= WRITEMEMCOMPRESS;
1597  const char* charBuffer = reinterpret_cast<const char*>(mData.get());
1598  compressedBytes = compression::bloscUncompressedSize(charBuffer);
1599  }
1600  }
1601  else if (this->isCompressed())
1602  {
1603  serializationFlags |= WRITEMEMCOMPRESS;
1604  compressedBytes = mCompressedBytes;
1605  }
1606  else if (bloscCompression)
1607  {
1608  this->doLoad();
1609 
1610  const char* charBuffer = reinterpret_cast<const char*>(mData.get());
1611  const size_t inBytes = this->arrayMemUsage();
1612  compressedBytes = compression::bloscCompressedSize(charBuffer, inBytes);
1613  }
1614 
1615  Index64 bytes = /*flags*/ sizeof(Int16) + /*size*/ sizeof(Index);
1616 
1617  bytes += (compressedBytes > 0) ? compressedBytes : this->arrayMemUsage();
1618 
1619  // write data
1620 
1621  os.write(reinterpret_cast<const char*>(&bytes), sizeof(Index64));
1622  os.write(reinterpret_cast<const char*>(&flags), sizeof(uint8_t));
1623  os.write(reinterpret_cast<const char*>(&serializationFlags), sizeof(uint8_t));
1624  os.write(reinterpret_cast<const char*>(&size), sizeof(Index));
1625 
1626  // write strided
1627  if (!strideOfOne) os.write(reinterpret_cast<const char*>(&stride), sizeof(Index));
1628 }
1629 
1630 
1631 template<typename ValueType_, typename Codec_>
1632 void
1633 TypedAttributeArray<ValueType_, Codec_>::writeBuffers(std::ostream& os, bool outputTransient) const
1634 {
1635  if (!outputTransient && this->isTransient()) return;
1636 
1637  this->doLoad();
1638 
1639  if (this->isUniform()) {
1640  os.write(reinterpret_cast<const char*>(mData.get()), sizeof(StorageType));
1641  }
1642  else if (this->isCompressed())
1643  {
1644  uint8_t bloscCompressed(0);
1645  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1646  os.write(reinterpret_cast<const char*>(mData.get()), mCompressedBytes);
1647  }
1649  {
1650  std::unique_ptr<char[]> compressedBuffer;
1651  size_t compressedBytes = 0;
1652  const char* charBuffer = reinterpret_cast<const char*>(mData.get());
1653  const size_t inBytes = this->arrayMemUsage();
1654  compressedBuffer = compression::bloscCompress(charBuffer, inBytes, compressedBytes);
1655  if (compressedBuffer) {
1656  uint8_t bloscCompressed(1);
1657  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1658  os.write(reinterpret_cast<const char*>(compressedBuffer.get()), compressedBytes);
1659  }
1660  else {
1661  uint8_t bloscCompressed(0);
1662  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1663  os.write(reinterpret_cast<const char*>(mData.get()), inBytes);
1664  }
1665  }
1666  else
1667  {
1668  uint8_t bloscCompressed(0);
1669  os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1670  os.write(reinterpret_cast<const char*>(mData.get()), this->arrayMemUsage());
1671  }
1672 }
1673 
1674 
1675 template<typename ValueType_, typename Codec_>
1676 void
1678 {
1679  if (!outputTransient && this->isTransient()) return;
1680 
1681  // paged compression only available when Blosc is enabled
1682  bool bloscCompression = io::getDataCompression(os.getOutputStream()) & io::COMPRESS_BLOSC;
1683  if (!bloscCompression) {
1684  if (!os.sizeOnly()) this->writeBuffers(os.getOutputStream(), outputTransient);
1685  return;
1686  }
1687 
1688  this->doLoad();
1689 
1690  const char* buffer;
1691  size_t bytes;
1692 
1693  std::unique_ptr<char[]> uncompressedBuffer;
1694  if (this->isCompressed()) {
1695  // paged streams require uncompressed buffers, so locally decompress
1696 
1697  const char* charBuffer = reinterpret_cast<const char*>(this->mData.get());
1698  bytes = compression::bloscUncompressedSize(charBuffer);
1699  uncompressedBuffer = compression::bloscDecompress(charBuffer, bytes);
1700  buffer = reinterpret_cast<const char*>(uncompressedBuffer.get());
1701  }
1702  else {
1703  buffer = reinterpret_cast<const char*>(mData.get());
1704  bytes = this->arrayMemUsage();
1705  }
1706 
1707  os.write(buffer, bytes);
1708 }
1709 
1710 
1711 template<typename ValueType_, typename Codec_>
1712 void
1713 TypedAttributeArray<ValueType_, Codec_>::doLoadUnsafe(const bool compression) const
1714 {
1715  if (!(this->isOutOfCore())) return;
1716 
1717  // this function expects the mutex to already be locked
1718 
1720 
1721  assert(self->mPageHandle);
1722 
1723  std::unique_ptr<char[]> buffer = self->mPageHandle->read();
1724 
1725  self->mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1726 
1727  self->mPageHandle.reset();
1728 
1729  // if data was compressed prior to being written to disk, re-compress
1730 
1731  if (self->mSerializationFlags & WRITEMEMCOMPRESS) {
1732  if (compression) self->compressUnsafe();
1733  else self->mCompressedBytes = 0;
1734  }
1735 
1736  // clear all write and out-of-core flags
1737 
1738  self->mFlags &= uint8_t(~OUTOFCORE);
1739  self->mSerializationFlags &= uint8_t(~WRITEUNIFORM & ~WRITEMEMCOMPRESS & ~WRITEPAGED);
1740 }
1741 
1742 
1743 template<typename ValueType_, typename Codec_>
1746 {
1747  // use the faster 'unsafe' get and set methods as attribute handles
1748  // ensure data is uncompressed and in-core when constructed
1749 
1755 }
1756 
1757 
1758 template<typename ValueType_, typename Codec_>
1759 bool
1761 {
1762  const TypedAttributeArray<ValueType_, Codec_>* const otherT = dynamic_cast<const TypedAttributeArray<ValueType_, Codec_>* >(&other);
1763  if(!otherT) return false;
1764  if(this->mSize != otherT->mSize ||
1765  this->mStrideOrTotalSize != otherT->mStrideOrTotalSize ||
1766  this->mIsUniform != otherT->mIsUniform ||
1767  *this->sTypeName != *otherT->sTypeName) return false;
1768 
1769  this->doLoad();
1770  otherT->doLoad();
1771 
1772  const StorageType *target = this->mData.get(), *source = otherT->mData.get();
1773  if (!target && !source) return true;
1774  if (!target || !source) return false;
1775  Index n = this->mIsUniform ? 1 : mSize;
1776  while (n && math::isExactlyEqual(*target++, *source++)) --n;
1777  return n == 0;
1778 }
1779 
1780 ////////////////////////////////////////
1781 
1782 
1783 /// Accessor to call unsafe get and set methods based on templated Codec and Value
1784 template <typename CodecType, typename ValueType>
1786 {
1787  using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
1788  using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
1789 
1790  /// Getter that calls to TypedAttributeArray::getUnsafe()
1791  /// @note Functor argument is provided but not required for the generic case
1792  static ValueType get(GetterPtr /*functor*/, const AttributeArray* array, const Index n) {
1794  }
1795 
1796  /// Getter that calls to TypedAttributeArray::setUnsafe()
1797  /// @note Functor argument is provided but not required for the generic case
1798  static void set(SetterPtr /*functor*/, AttributeArray* array, const Index n, const ValueType& value) {
1800  }
1801 };
1802 
1803 
1804 /// Partial specialization when Codec is not known at compile-time to use the supplied functor instead
1805 template <typename ValueType>
1806 struct AccessorEval<UnknownCodec, ValueType>
1807 {
1808  using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
1809  using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
1810 
1811  /// Getter that calls the supplied functor
1812  static ValueType get(GetterPtr functor, const AttributeArray* array, const Index n) {
1813  return (*functor)(array, n);
1814  }
1815 
1816  /// Setter that calls the supplied functor
1817  static void set(SetterPtr functor, AttributeArray* array, const Index n, const ValueType& value) {
1818  (*functor)(array, n, value);
1819  }
1820 };
1821 
1822 
1823 ////////////////////////////////////////
1824 
1825 // AttributeHandle implementation
1826 
1827 template <typename ValueType, typename CodecType>
1828 typename AttributeHandle<ValueType, CodecType>::Ptr
1829 AttributeHandle<ValueType, CodecType>::create(const AttributeArray& array, const bool preserveCompression)
1830 {
1832  new AttributeHandle<ValueType, CodecType>(array, preserveCompression));
1833 }
1834 
1835 template <typename ValueType, typename CodecType>
1836 AttributeHandle<ValueType, CodecType>::AttributeHandle(const AttributeArray& array, const bool preserveCompression)
1837  : mArray(&array)
1838  , mStrideOrTotalSize(array.hasConstantStride() ? array.stride() : 1)
1839  , mSize(array.hasConstantStride() ? array.size() : array.dataSize())
1840  , mCollapseOnDestruction(preserveCompression && array.isStreaming())
1841 {
1842  if (!this->compatibleType<std::is_same<CodecType, UnknownCodec>::value>()) {
1843  OPENVDB_THROW(TypeError, "Cannot bind handle due to incompatible type of AttributeArray.");
1844  }
1845 
1846  // load data if delay-loaded
1847 
1848  mArray->loadData();
1849 
1850  // if array is compressed and preserve compression is true, copy and decompress
1851  // into a local copy that is destroyed with handle to maintain thread-safety
1852 
1853  if (array.isCompressed())
1854  {
1855  if (preserveCompression && !array.isStreaming()) {
1856  mLocalArray = array.copyUncompressed();
1857  mLocalArray->decompress();
1858  mArray = mLocalArray.get();
1859  }
1860  else {
1861  const_cast<AttributeArray*>(mArray)->decompress();
1862  }
1863  }
1864 
1865  // bind getter and setter methods
1866 
1868  assert(accessor);
1869 
1870  AttributeArray::Accessor<ValueType>* typedAccessor = static_cast<AttributeArray::Accessor<ValueType>*>(accessor.get());
1871 
1872  mGetter = typedAccessor->mGetter;
1873  mSetter = typedAccessor->mSetter;
1874  mCollapser = typedAccessor->mCollapser;
1875  mFiller = typedAccessor->mFiller;
1876 }
1877 
1878 template <typename ValueType, typename CodecType>
1880 {
1881  // if enabled, attribute is collapsed on destruction of the handle to save memory
1882  if (mCollapseOnDestruction) const_cast<AttributeArray*>(this->mArray)->collapse();
1883 }
1884 
1885 template <typename ValueType, typename CodecType>
1886 template <bool IsUnknownCodec>
1889 {
1890  // if codec is unknown, just check the value type
1891 
1892  return mArray->hasValueType<ValueType>();
1893 }
1894 
1895 template <typename ValueType, typename CodecType>
1896 template <bool IsUnknownCodec>
1898 AttributeHandle<ValueType, CodecType>::compatibleType() const
1899 {
1900  // if the codec is known, check the value type and codec
1901 
1902  return mArray->isType<TypedAttributeArray<ValueType, CodecType>>();
1903 }
1904 
1905 template <typename ValueType, typename CodecType>
1907 {
1908  Index index = n * mStrideOrTotalSize + m;
1909  assert(index < (mSize * mStrideOrTotalSize));
1910  return index;
1911 }
1912 
1913 template <typename ValueType, typename CodecType>
1915 {
1916  return this->get<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, m));
1917 }
1918 
1919 template <typename ValueType, typename CodecType>
1920 template <bool IsUnknownCodec>
1923 {
1924  // if the codec is unknown, use the getter functor
1925 
1926  return (*mGetter)(mArray, index);
1927 }
1928 
1929 template <typename ValueType, typename CodecType>
1930 template <bool IsUnknownCodec>
1933 {
1934  // if the codec is known, call the method on the attribute array directly
1935 
1937 }
1938 
1939 template <typename ValueType, typename CodecType>
1941 {
1942  return mArray->isUniform();
1943 }
1944 
1945 template <typename ValueType, typename CodecType>
1947 {
1948  return mArray->hasConstantStride();
1949 }
1950 
1951 ////////////////////////////////////////
1952 
1953 // AttributeWriteHandle implementation
1954 
1955 template <typename ValueType, typename CodecType>
1958 {
1960  new AttributeWriteHandle<ValueType, CodecType>(array, expand));
1961 }
1962 
1963 template <typename ValueType, typename CodecType>
1965  : AttributeHandle<ValueType, CodecType>(array, /*preserveCompression = */ false)
1966 {
1967  if (expand) array.expand();
1968 }
1969 
1970 template <typename ValueType, typename CodecType>
1972 {
1974 }
1975 
1976 template <typename ValueType, typename CodecType>
1978 {
1980 }
1981 
1982 template <typename ValueType, typename CodecType>
1984 {
1985  const_cast<AttributeArray*>(this->mArray)->expand(fill);
1986 }
1987 
1988 template <typename ValueType, typename CodecType>
1990 {
1991  const_cast<AttributeArray*>(this->mArray)->collapse();
1992 }
1993 
1994 template <typename ValueType, typename CodecType>
1996 {
1997  return const_cast<AttributeArray*>(this->mArray)->compact();
1998 }
1999 
2000 template <typename ValueType, typename CodecType>
2001 void AttributeWriteHandle<ValueType, CodecType>::collapse(const ValueType& uniformValue)
2002 {
2003  this->mCollapser(const_cast<AttributeArray*>(this->mArray), uniformValue);
2004 }
2005 
2006 template <typename ValueType, typename CodecType>
2008 {
2009  this->mFiller(const_cast<AttributeArray*>(this->mArray), value);
2010 }
2011 
2012 template <typename ValueType, typename CodecType>
2013 template <bool IsUnknownCodec>
2015 AttributeWriteHandle<ValueType, CodecType>::set(Index index, const ValueType& value) const
2016 {
2017  // if the codec is unknown, use the setter functor
2018 
2019  (*this->mSetter)(const_cast<AttributeArray*>(this->mArray), index, value);
2020 }
2021 
2022 template <typename ValueType, typename CodecType>
2023 template <bool IsUnknownCodec>
2025 AttributeWriteHandle<ValueType, CodecType>::set(Index index, const ValueType& value) const
2026 {
2027  // if the codec is known, call the method on the attribute array directly
2028 
2029  TypedAttributeArray<ValueType, CodecType>::setUnsafe(const_cast<AttributeArray*>(this->mArray), index, value);
2030 }
2031 
2032 
2033 } // namespace points
2034 } // namespace OPENVDB_VERSION_NAME
2035 } // namespace openvdb
2036 
2037 #endif // OPENVDB_POINTS_ATTRIBUTE_ARRAY_HAS_BEEN_INCLUDED
2038 
2039 // Copyright (c) 2012-2017 DreamWorks Animation LLC
2040 // All rights reserved. This software is distributed under the
2041 // 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().
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:407
bool isHidden() const
Return true if this attribute is hidden (e.g., from UI or iterators).
ValueType(*)(const AttributeArray *array, const Index n) GetterPtr
TypedAttributeArray & operator=(const TypedAttributeArray &)
Deep copy assignment operator.
const hboost::disable_if_c< VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:128
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
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).
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.
const hboost::disable_if_c< VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:132
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)
#define OPENVDB_VERSION_NAME
Definition: version.h:43
Index size() const override
Return the number of elements in this array.
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:109
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.
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
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.
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:101
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:794