OpenVDB 5.1.0

AttributeArray.h
Go to the documentation of this file.
1 //
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 //
30
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>
41 #include <openvdb/math/QuantizedUnitVec.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 {
61 OPENVDB_USE_VERSION_NAMESPACE
62 namespace OPENVDB_VERSION_NAME {
63
64
65 using NamePair = std::pair<Name, Name>;
66
67 namespace points {
68
69
71
72 // Utility methods
73
74 template <typename IntegerT, typename FloatT>
75 inline IntegerT
76 floatingPointToFixedPoint(const FloatT s)
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
95 floatingPointToFixedPoint(const math::Vec3<FloatT>& v)
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
105 fixedPointToFloatingPoint(const math::Vec3<IntegerT>& v)
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
115
116
118 class OPENVDB_API AttributeArray
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,
129 HIDDEN = 0x2,
130 OUTOFCORE = 0x4,
131 CONSTANTSTRIDE = 0x8,
132 STREAMING = 0x10
133 };
134
135 enum SerializationFlag {
136 WRITESTRIDED = 0x1,
137 WRITEUNIFORM = 0x2,
138 WRITEMEMCOMPRESS = 0x4,
139 WRITEPAGED = 0x8
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
155 virtual AttributeArray::Ptr copy() const = 0;
156
158 virtual AttributeArray::Ptr copyUncompressed() const = 0;
159
162 virtual Index size() const = 0;
163
166 virtual Index stride() const = 0;
167
170 virtual Index dataSize() const = 0;
171
173 virtual size_t memUsage() const = 0;
174
176 static Ptr create(const NamePair& type, Index length, Index stride = 1, bool constantStride = true);
178 static bool isRegistered(const NamePair& type);
180 static void clearRegistry();
181
183 virtual const NamePair& type() const = 0;
185 template<typename AttributeArrayType>
186 bool isType() const { return this->type() == AttributeArrayType::attributeType(); }
187
189 template<typename ValueType>
190 bool hasValueType() const { return this->type().first == typeNameAsString<ValueType>(); }
191
193 virtual void set(const Index n, const AttributeArray& sourceArray, const Index sourceIndex) = 0;
194
196 virtual bool isUniform() const = 0;
199 virtual void expand(bool fill = true) = 0;
201 virtual void collapse() = 0;
203 virtual bool compact() = 0;
204
206 bool isCompressed() const { return mCompressedBytes != 0; }
208 virtual bool compress() = 0;
210 virtual bool decompress() = 0;
211
216 void setHidden(bool state);
218 bool isHidden() const { return bool(mFlags & HIDDEN); }
219
223 void setTransient(bool state);
225 bool isTransient() const { return bool(mFlags & TRANSIENT); }
226
231 void setStreaming(bool state);
233 bool isStreaming() const { return bool(mFlags & STREAMING); }
234
236 bool hasConstantStride() const { return bool(mFlags & CONSTANTSTRIDE); }
237
239 uint8_t flags() const { return mFlags; }
240
242 virtual void read(std::istream&) = 0;
245 virtual void write(std::ostream&, bool outputTransient) const = 0;
247 virtual void write(std::ostream&) const = 0;
248
250 virtual void readMetadata(std::istream&) = 0;
254 virtual void writeMetadata(std::ostream&, bool outputTransient, bool paged) const = 0;
255
257 virtual void readBuffers(std::istream&) = 0;
260 virtual void writeBuffers(std::ostream&, bool outputTransient) const = 0;
261
263 virtual void readPagedBuffers(compression::PagedInputStream&) = 0;
266 virtual void writePagedBuffers(compression::PagedOutputStream&, bool outputTransient) const = 0;
267
269 virtual void loadData() const = 0;
270
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
282 virtual bool isEqual(const AttributeArray& other) const = 0;
283
284 protected:
286 void setConstantStride(bool state);
287
289 virtual AccessorBasePtr getAccessor() const = 0;
290
292 static void registerType(const NamePair& type, FactoryMethod);
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
305 compression::PageHandle::Ptr mPageHandle;
306 }; // class AttributeArray
307
308
310
311
313 struct AttributeArray::AccessorBase { virtual ~AccessorBase() = default; };
314
317 template <typename T>
318 struct AttributeArray::Accessor : public AttributeArray::AccessorBase
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
327 GetterPtr mGetter;
328 SetterPtr mSetter;
329 ValuePtr mCollapser;
330 ValuePtr mFiller;
331 }; // struct AttributeArray::Accessor
332
333
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>> {
344 using Type = math::Vec3<typename TruncateTrait<T>::Type>;
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>> {
351 using Type = math::Vec3<uint8_t>;
352 };
353 template<typename T> struct UIntTypeTrait</*OneByte=*/false, math::Vec3<T>> {
354 using Type = math::Vec3<uint16_t>;
355 };
356 }
357
358
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
378 struct TruncateCodec
379 {
380 template <typename T>
381 struct Storage { using Type = typename attribute_traits::TruncateTrait<T>::Type; };
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]
390 struct PositionRange
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>
408 struct FixedPointCodec
409 {
410 template <typename T>
411 struct Storage { using Type = typename attribute_traits::UIntTypeTrait<OneByte, T>::Type; };
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
423 struct UnitVecCodec
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
437
438
440 template<typename ValueType_, typename Codec_ = NullCodec>
441 class TypedAttributeArray: public AttributeArray
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
452
454 explicit TypedAttributeArray(Index n = 1, Index strideOrTotalSize = 1, bool constantStride = true,
455 const ValueType& uniformValue = zeroVal<ValueType>());
457 TypedAttributeArray(const TypedAttributeArray&, bool uncompress = false);
459 TypedAttributeArray& operator=(const TypedAttributeArray&);
461 TypedAttributeArray(TypedAttributeArray&&) = delete;
463 TypedAttributeArray& operator=(TypedAttributeArray&&) = delete;
464
465 virtual ~TypedAttributeArray() { this->deallocate(); }
466
468 AttributeArray::Ptr copy() const override;
469
471 AttributeArray::Ptr copyUncompressed() const override;
472
474 static Ptr create(Index n, Index strideOrTotalSize = 1, bool constantStride = true);
475
477 static TypedAttributeArray& cast(AttributeArray& attributeArray);
478
480 static const TypedAttributeArray& cast(const AttributeArray& attributeArray);
481
483 static const NamePair& attributeType();
485 const NamePair& type() const override { return attributeType(); }
486
488 static bool isRegistered();
490 static void registerType();
492 static void unregisterType();
493
495 Index size() const override { return mSize; }
496
499 Index stride() const override { return hasConstantStride() ? mStrideOrTotalSize : 0; }
500
502 Index dataSize() const override {
503 return hasConstantStride() ? mSize * mStrideOrTotalSize : mStrideOrTotalSize;
504 }
505
507 size_t memUsage() const override;
508
510 ValueType getUnsafe(Index n) const;
512 ValueType get(Index n) const;
514 template<typename T> void getUnsafe(Index n, T& value) const;
516 template<typename T> void get(Index n, T& value) const;
517
520 static ValueType getUnsafe(const AttributeArray* array, const Index n);
521
523 void setUnsafe(Index n, const ValueType& value);
525 void set(Index n, const ValueType& value);
527 template<typename T> void setUnsafe(Index n, const T& value);
529 template<typename T> void set(Index n, const T& value);
530
533 static void setUnsafe(AttributeArray* array, const Index n, const ValueType& value);
534
536 void set(const Index n, const AttributeArray& sourceArray, const Index sourceIndex) override;
537
539 bool isUniform() const override { return mIsUniform; }
543 void expand(bool fill = true) override;
545 void collapse() override;
547 bool compact() override;
548
550 void collapse(const ValueType& uniformValue);
553 void fill(const ValueType& value);
554
556 static void collapse(AttributeArray* array, const ValueType& value);
558 static void fill(AttributeArray* array, const ValueType& value);
559
561 bool compress() override;
563 bool decompress() override;
564
566 void read(std::istream&) override;
570 void write(std::ostream& os, bool outputTransient) const override;
572 void write(std::ostream&) const override;
573
575 void readMetadata(std::istream&) override;
580 void writeMetadata(std::ostream& os, bool outputTransient, bool paged) const override;
581
583 void readBuffers(std::istream&) override;
587 void writeBuffers(std::ostream& os, bool outputTransient) const override;
588
590 void readPagedBuffers(compression::PagedInputStream&) override;
594 void writePagedBuffers(compression::PagedOutputStream& os, bool outputTransient) const override;
595
597 inline bool isOutOfCore() const;
598
600 void loadData() const override;
601
602 protected:
603 AccessorBasePtr getAccessor() const override;
604
605 private:
607 inline void doLoad() const;
610 inline void doLoadUnsafe(const bool compression = true) const;
612 inline bool compressUnsafe();
613
615 inline void setOutOfCore(const bool);
616
618 bool isEqual(const AttributeArray& other) const override;
619
620 size_t arrayMemUsage() const;
621 void allocate();
622 void deallocate();
623
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
639
640
643 template <typename ValueType, typename CodecType = UnknownCodec>
644 class AttributeHandle
645 {
646 public:
647 using Handle = AttributeHandle<ValueType, CodecType>;
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 protected:
675 Index index(Index n, Index m) const;
676
677 const AttributeArray* mArray;
678
679 GetterPtr mGetter;
680 SetterPtr mSetter;
681 ValuePtr mCollapser;
682 ValuePtr mFiller;
683
684 private:
685 friend class ::TestAttributeArray;
686
687 template <bool IsUnknownCodec>
688 typename std::enable_if<IsUnknownCodec, bool>::type compatibleType() const;
689
690 template <bool IsUnknownCodec>
691 typename std::enable_if<!IsUnknownCodec, bool>::type compatibleType() const;
692
693 template <bool IsUnknownCodec>
694 typename std::enable_if<IsUnknownCodec, ValueType>::type get(Index index) const;
695
696 template <bool IsUnknownCodec>
697 typename std::enable_if<!IsUnknownCodec, ValueType>::type get(Index index) const;
698
699 // local copy of AttributeArray (to preserve compression)
700 AttributeArray::Ptr mLocalArray;
701
702 Index mStrideOrTotalSize;
703 Index mSize;
704 bool mCollapseOnDestruction;
705 }; // class AttributeHandle
706
707
709
710
712 template <typename ValueType, typename CodecType = UnknownCodec>
713 class AttributeWriteHandle : public AttributeHandle<ValueType, CodecType>
714 {
715 public:
716 using Handle = AttributeWriteHandle<ValueType, CodecType>;
717 using Ptr = std::shared_ptr<Handle>;
718 using ScopedPtr = std::unique_ptr<Handle>;
719
720 static Ptr create(AttributeArray& array, const bool expand = true);
721
722 AttributeWriteHandle(AttributeArray& array, const bool expand = true);
723
724 virtual ~AttributeWriteHandle() = default;
725
728 void expand(bool fill = true);
729
731 void collapse();
732 void collapse(const ValueType& uniformValue);
733
735 bool compact();
736
739 void fill(const ValueType& value);
740
741 void set(Index n, const ValueType& value);
742 void set(Index n, Index m, const ValueType& value);
743
744 private:
745 friend class ::TestAttributeArray;
746
747 template <bool IsUnknownCodec>
748 typename std::enable_if<IsUnknownCodec, void>::type set(Index index, const ValueType& value) const;
749
750 template <bool IsUnknownCodec>
751 typename std::enable_if<!IsUnknownCodec, void>::type set(Index index, const ValueType& value) const;
752 }; // class AttributeWriteHandle
753
754
756
757
758 // Attribute codec implementation
759
760
761 template<typename ValueType>
762 inline void
763 NullCodec::decode(const ValueType& data, ValueType& val)
764 {
765 val = data;
766 }
767
768
769 template<typename ValueType>
770 inline void
771 NullCodec::encode(const ValueType& val, ValueType& data)
772 {
773 data = val;
774 }
775
776
777 template<typename StorageType, typename ValueType>
778 inline void
779 TruncateCodec::decode(const StorageType& data, ValueType& val)
780 {
781 val = static_cast<ValueType>(data);
782 }
783
784
785 template<typename StorageType, typename ValueType>
786 inline void
787 TruncateCodec::encode(const ValueType& val, StorageType& data)
788 {
789 data = static_cast<StorageType>(val);
790 }
791
792
793 template <bool OneByte, typename Range>
794 template<typename StorageType, typename ValueType>
795 inline void
796 FixedPointCodec<OneByte, Range>::decode(const StorageType& data, ValueType& val)
797 {
798 val = fixedPointToFloatingPoint<ValueType>(data);
799
800 // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
801
802 val = Range::template decode<ValueType>(val);
803 }
804
805
806 template <bool OneByte, typename Range>
807 template<typename StorageType, typename ValueType>
808 inline void
809 FixedPointCodec<OneByte, Range>::encode(const ValueType& val, StorageType& data)
810 {
811 // shift value range to be -0.5 => 0.5 (as this is most commonly used for position)
812
813 const ValueType newVal = Range::template encode<ValueType>(val);
814
815 data = floatingPointToFixedPoint<StorageType>(newVal);
816 }
817
818
819 template<typename T>
820 inline void
821 UnitVecCodec::decode(const StorageType& data, math::Vec3<T>& val)
822 {
823 val = math::QuantizedUnitVec::unpack(data);
824 }
825
826
827 template<typename T>
828 inline void
829 UnitVecCodec::encode(const math::Vec3<T>& val, StorageType& data)
830 {
831 data = math::QuantizedUnitVec::pack(val);
832 }
833
834
836
837 // TypedAttributeArray implementation
838
839 template<typename ValueType_, typename Codec_>
840 tbb::atomic<const NamePair*> TypedAttributeArray<ValueType_, Codec_>::sTypeName;
841
842
843 template<typename ValueType_, typename Codec_>
844 TypedAttributeArray<ValueType_, Codec_>::TypedAttributeArray(
845 Index n, Index strideOrTotalSize, bool constantStride, const ValueType& uniformValue)
846 : mData(new StorageType[1])
847 , mSize(n)
848 , mStrideOrTotalSize(strideOrTotalSize)
849 , mIsUniform(true)
850 {
851 if (constantStride) {
852 this->setConstantStride(true);
853 if (strideOrTotalSize == 0) {
854 OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a constant stride requires that " \
855 "stride to be at least one.")
856 }
857 }
858 else {
859 this->setConstantStride(false);
860 if (mStrideOrTotalSize < n) {
861 OPENVDB_THROW(ValueError, "Creating a TypedAttributeArray with a non-constant stride must have " \
862 "a total size of at least the number of elements in the array.")
863 }
864 }
865 mSize = std::max(Index(1), mSize);
866 mStrideOrTotalSize = std::max(Index(1), mStrideOrTotalSize);
867 Codec::encode(uniformValue, mData.get()[0]);
868 }
869
870
871 template<typename ValueType_, typename Codec_>
872 TypedAttributeArray<ValueType_, Codec_>::TypedAttributeArray(const TypedAttributeArray& rhs, bool uncompress)
873 : AttributeArray(rhs)
874 , mSize(rhs.mSize)
875 , mStrideOrTotalSize(rhs.mStrideOrTotalSize)
876 , mIsUniform(rhs.mIsUniform)
877 {
878 // disable uncompress if data is not compressed
879
880 if (!this->isCompressed()) uncompress = false;
881
882 if (this->isOutOfCore()) {
883 // do nothing
884 } else if (mIsUniform) {
885 this->allocate();
886 mData.get()[0] = rhs.mData.get()[0];
887 } else if (this->isCompressed()) {
888 std::unique_ptr<char[]> buffer;
889 if (uncompress) {
890 const char* charBuffer = reinterpret_cast<const char*>(rhs.mData.get());
891 size_t uncompressedBytes = compression::bloscUncompressedSize(charBuffer);
892 buffer = compression::bloscDecompress(charBuffer, uncompressedBytes);
893 }
894 if (buffer) {
895 mCompressedBytes = 0;
896 } else {
897 // decompression wasn't requested or failed so deep copy instead
898 buffer.reset(new char[mCompressedBytes]);
899 std::memcpy(buffer.get(), rhs.mData.get(), mCompressedBytes);
900 }
901 assert(buffer);
902 mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
903 } else {
904 this->allocate();
905 std::memcpy(mData.get(), rhs.mData.get(), this->arrayMemUsage());
906 }
907 }
908
909
910 template<typename ValueType_, typename Codec_>
911 TypedAttributeArray<ValueType_, Codec_>&
912 TypedAttributeArray<ValueType_, Codec_>::operator=(const TypedAttributeArray& rhs)
913 {
914 if (&rhs != this) {
915 tbb::spin_mutex::scoped_lock lock(mMutex);
916
917 this->deallocate();
918
919 mFlags = rhs.mFlags;
920 mSerializationFlags = rhs.mSerializationFlags;
921 mCompressedBytes = rhs.mCompressedBytes;
922 mSize = rhs.mSize;
923 mStrideOrTotalSize = rhs.mStrideOrTotalSize;
924 mIsUniform = rhs.mIsUniform;
925
926 if (rhs.isOutOfCore()) {
927 mPageHandle = rhs.mPageHandle;
928 } else if (mIsUniform) {
929 this->allocate();
930 mData.get()[0] = rhs.mData.get()[0];
931 } else if (this->isCompressed()) {
932 std::unique_ptr<char[]> buffer(new char[mCompressedBytes]);
933 std::memcpy(buffer.get(), rhs.mData.get(), mCompressedBytes);
934 mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
935 } else {
936 this->allocate();
937 std::memcpy(mData.get(), rhs.mData.get(), arrayMemUsage());
938 }
939 }
940 }
941
942
943 template<typename ValueType_, typename Codec_>
944 inline const NamePair&
945 TypedAttributeArray<ValueType_, Codec_>::attributeType()
946 {
947 if (sTypeName == nullptr) {
948 NamePair* s = new NamePair(typeNameAsString<ValueType>(), Codec::name());
949 if (sTypeName.compare_and_swap(s, nullptr) != nullptr) delete s;
950 }
951 return *sTypeName;
952 }
953
954
955 template<typename ValueType_, typename Codec_>
956 inline bool
957 TypedAttributeArray<ValueType_, Codec_>::isRegistered()
958 {
959 return AttributeArray::isRegistered(TypedAttributeArray::attributeType());
960 }
961
962
963 template<typename ValueType_, typename Codec_>
964 inline void
965 TypedAttributeArray<ValueType_, Codec_>::registerType()
966 {
967 AttributeArray::registerType(TypedAttributeArray::attributeType(), TypedAttributeArray::factory);
968 }
969
970
971 template<typename ValueType_, typename Codec_>
972 inline void
973 TypedAttributeArray<ValueType_, Codec_>::unregisterType()
974 {
975 AttributeArray::unregisterType(TypedAttributeArray::attributeType());
976 }
977
978
979 template<typename ValueType_, typename Codec_>
980 inline typename TypedAttributeArray<ValueType_, Codec_>::Ptr
981 TypedAttributeArray<ValueType_, Codec_>::create(Index n, Index stride, bool constantStride)
982 {
983 return Ptr(new TypedAttributeArray(n, stride, constantStride));
984 }
985
986 template<typename ValueType_, typename Codec_>
987 inline TypedAttributeArray<ValueType_, Codec_>&
988 TypedAttributeArray<ValueType_, Codec_>::cast(AttributeArray& attributeArray)
989 {
990 if (!attributeArray.isType<TypedAttributeArray>()) {
991 OPENVDB_THROW(TypeError, "Invalid Attribute Type");
992 }
993 return static_cast<TypedAttributeArray&>(attributeArray);
994 }
995
996 template<typename ValueType_, typename Codec_>
997 inline const TypedAttributeArray<ValueType_, Codec_>&
998 TypedAttributeArray<ValueType_, Codec_>::cast(const AttributeArray& attributeArray)
999 {
1000 if (!attributeArray.isType<TypedAttributeArray>()) {
1001 OPENVDB_THROW(TypeError, "Invalid Attribute Type");
1002 }
1003 return static_cast<const TypedAttributeArray&>(attributeArray);
1004 }
1005
1006 template<typename ValueType_, typename Codec_>
1007 AttributeArray::Ptr
1008 TypedAttributeArray<ValueType_, Codec_>::copy() const
1009 {
1010 return AttributeArray::Ptr(new TypedAttributeArray<ValueType, Codec>(*this));
1011 }
1012
1013
1014 template<typename ValueType_, typename Codec_>
1015 AttributeArray::Ptr
1016 TypedAttributeArray<ValueType_, Codec_>::copyUncompressed() const
1017 {
1018 return AttributeArray::Ptr(new TypedAttributeArray<ValueType, Codec>(*this, /*decompress = */true));
1019 }
1020
1021
1022 template<typename ValueType_, typename Codec_>
1023 size_t
1024 TypedAttributeArray<ValueType_, Codec_>::arrayMemUsage() const
1025 {
1026 if (this->isOutOfCore()) return 0;
1027 if (this->isCompressed()) return mCompressedBytes;
1028
1029 return (mIsUniform ? 1 : this->dataSize()) * sizeof(StorageType);
1030 }
1031
1032
1033 template<typename ValueType_, typename Codec_>
1034 void
1035 TypedAttributeArray<ValueType_, Codec_>::allocate()
1036 {
1037 assert(!mData);
1038 if (mIsUniform) {
1039 mData.reset(new StorageType[1]);
1040 }
1041 else {
1042 const size_t size(this->dataSize());
1043 assert(size > 0);
1044 mData.reset(new StorageType[size]);
1045 }
1046 }
1047
1048
1049 template<typename ValueType_, typename Codec_>
1050 void
1051 TypedAttributeArray<ValueType_, Codec_>::deallocate()
1052 {
1053 // detach from file if delay-loaded
1054 if (this->isOutOfCore()) {
1055 this->setOutOfCore(false);
1056 this->mPageHandle.reset();
1057 }
1058 if (mData) mData.reset();
1059 }
1060
1061
1062 template<typename ValueType_, typename Codec_>
1063 size_t
1064 TypedAttributeArray<ValueType_, Codec_>::memUsage() const
1065 {
1066 return sizeof(*this) + (bool(mData) ? this->arrayMemUsage() : 0);
1067 }
1068
1069
1070 template<typename ValueType_, typename Codec_>
1071 typename TypedAttributeArray<ValueType_, Codec_>::ValueType
1072 TypedAttributeArray<ValueType_, Codec_>::getUnsafe(Index n) const
1073 {
1074 assert(n < this->dataSize());
1075 assert(!this->isOutOfCore());
1076 assert(!this->isCompressed());
1077
1078 ValueType val;
1079 Codec::decode(/*in=*/mData.get()[mIsUniform ? 0 : n], /*out=*/val);
1080 return val;
1081 }
1082
1083
1084 template<typename ValueType_, typename Codec_>
1085 typename TypedAttributeArray<ValueType_, Codec_>::ValueType
1086 TypedAttributeArray<ValueType_, Codec_>::get(Index n) const
1087 {
1088 if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1089 if (this->isOutOfCore()) this->doLoad();
1090 if (this->isCompressed()) const_cast<TypedAttributeArray*>(this)->decompress();
1091
1092 return this->getUnsafe(n);
1093 }
1094
1095
1096 template<typename ValueType_, typename Codec_>
1097 template<typename T>
1098 void
1099 TypedAttributeArray<ValueType_, Codec_>::getUnsafe(Index n, T& val) const
1100 {
1101 val = static_cast<T>(this->getUnsafe(n));
1102 }
1103
1104
1105 template<typename ValueType_, typename Codec_>
1106 template<typename T>
1107 void
1108 TypedAttributeArray<ValueType_, Codec_>::get(Index n, T& val) const
1109 {
1110 val = static_cast<T>(this->get(n));
1111 }
1112
1113
1114 template<typename ValueType_, typename Codec_>
1115 typename TypedAttributeArray<ValueType_, Codec_>::ValueType
1116 TypedAttributeArray<ValueType_, Codec_>::getUnsafe(const AttributeArray* array, const Index n)
1117 {
1118 return static_cast<const TypedAttributeArray<ValueType, Codec>*>(array)->getUnsafe(n);
1119 }
1120
1121
1122 template<typename ValueType_, typename Codec_>
1123 void
1124 TypedAttributeArray<ValueType_, Codec_>::setUnsafe(Index n, const ValueType& val)
1125 {
1126 assert(n < this->dataSize());
1127 assert(!this->isOutOfCore());
1128 assert(!this->isCompressed());
1129 assert(!this->isUniform());
1130
1131 // this unsafe method assumes the data is not uniform, however if it is, this redirects the index
1132 // to zero, which is marginally less efficient but ensures not writing to an illegal address
1133
1134 Codec::encode(/*in=*/val, /*out=*/mData.get()[mIsUniform ? 0 : n]);
1135 }
1136
1137
1138 template<typename ValueType_, typename Codec_>
1139 void
1140 TypedAttributeArray<ValueType_, Codec_>::set(Index n, const ValueType& val)
1141 {
1142 if (n >= this->dataSize()) OPENVDB_THROW(IndexError, "Out-of-range access.");
1143 if (this->isOutOfCore()) this->doLoad();
1144 if (this->isCompressed()) this->decompress();
1145 if (this->isUniform()) this->expand();
1146
1147 this->setUnsafe(n, val);
1148 }
1149
1150
1151 template<typename ValueType_, typename Codec_>
1152 template<typename T>
1153 void
1154 TypedAttributeArray<ValueType_, Codec_>::setUnsafe(Index n, const T& val)
1155 {
1156 this->setUnsafe(n, static_cast<ValueType>(val));
1157 }
1158
1159
1160 template<typename ValueType_, typename Codec_>
1161 template<typename T>
1162 void
1163 TypedAttributeArray<ValueType_, Codec_>::set(Index n, const T& val)
1164 {
1165 this->set(n, static_cast<ValueType>(val));
1166 }
1167
1168
1169 template<typename ValueType_, typename Codec_>
1170 void
1171 TypedAttributeArray<ValueType_, Codec_>::setUnsafe(AttributeArray* array, const Index n, const ValueType& value)
1172 {
1173 static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->setUnsafe(n, value);
1174 }
1175
1176
1177 template<typename ValueType_, typename Codec_>
1178 void
1179 TypedAttributeArray<ValueType_, Codec_>::set(Index n, const AttributeArray& sourceArray, const Index sourceIndex)
1180 {
1181 const TypedAttributeArray& sourceTypedArray = static_cast<const TypedAttributeArray&>(sourceArray);
1182
1183 ValueType sourceValue;
1184 sourceTypedArray.get(sourceIndex, sourceValue);
1185
1186 this->set(n, sourceValue);
1187 }
1188
1189
1190 template<typename ValueType_, typename Codec_>
1191 void
1192 TypedAttributeArray<ValueType_, Codec_>::expand(bool fill)
1193 {
1194 if (!mIsUniform) return;
1195
1196 const StorageType val = mData.get()[0];
1197
1198 {
1199 tbb::spin_mutex::scoped_lock lock(mMutex);
1200 this->deallocate();
1201 mIsUniform = false;
1202 this->allocate();
1203 }
1204
1205 mCompressedBytes = 0;
1206
1207 if (fill) {
1208 for (Index i = 0; i < this->dataSize(); ++i) mData.get()[i] = val;
1209 }
1210 }
1211
1212
1213 template<typename ValueType_, typename Codec_>
1214 bool
1215 TypedAttributeArray<ValueType_, Codec_>::compact()
1216 {
1217 if (mIsUniform) return true;
1218
1219 // compaction is not possible if any values are different
1220 const ValueType_ val = this->get(0);
1221 for (Index i = 1; i < this->dataSize(); i++) {
1222 if (!math::isExactlyEqual(this->get(i), val)) return false;
1223 }
1224
1225 this->collapse(this->get(0));
1226 return true;
1227 }
1228
1229
1230 template<typename ValueType_, typename Codec_>
1231 void
1232 TypedAttributeArray<ValueType_, Codec_>::collapse()
1233 {
1234 this->collapse(zeroVal<ValueType>());
1235 }
1236
1237
1238 template<typename ValueType_, typename Codec_>
1239 void
1240 TypedAttributeArray<ValueType_, Codec_>::collapse(const ValueType& uniformValue)
1241 {
1242 if (!mIsUniform) {
1243 tbb::spin_mutex::scoped_lock lock(mMutex);
1244 this->deallocate();
1245 mIsUniform = true;
1246 this->allocate();
1247 }
1248 Codec::encode(uniformValue, mData.get()[0]);
1249 }
1250
1251
1252 template<typename ValueType_, typename Codec_>
1253 void
1254 TypedAttributeArray<ValueType_, Codec_>::collapse(AttributeArray* array, const ValueType& value)
1255 {
1256 static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->collapse(value);
1257 }
1258
1259
1260 template<typename ValueType_, typename Codec_>
1261 void
1262 TypedAttributeArray<ValueType_, Codec_>::fill(const ValueType& value)
1263 {
1264 if (this->isOutOfCore()) {
1265 tbb::spin_mutex::scoped_lock lock(mMutex);
1266 this->deallocate();
1267 this->allocate();
1268 }
1269
1270 const Index size = mIsUniform ? 1 : this->dataSize();
1271 for (Index i = 0; i < size; ++i) {
1272 Codec::encode(value, mData.get()[i]);
1273 }
1274 }
1275
1276
1277 template<typename ValueType_, typename Codec_>
1278 void
1279 TypedAttributeArray<ValueType_, Codec_>::fill(AttributeArray* array, const ValueType& value)
1280 {
1281 static_cast<TypedAttributeArray<ValueType, Codec>*>(array)->fill(value);
1282 }
1283
1284
1285 template<typename ValueType_, typename Codec_>
1286 inline bool
1287 TypedAttributeArray<ValueType_, Codec_>::compress()
1288 {
1289 if (!compression::bloscCanCompress()) return false;
1290
1291 if (!mIsUniform && !this->isCompressed()) {
1292
1293 tbb::spin_mutex::scoped_lock lock(mMutex);
1294
1295 this->doLoadUnsafe(/*compression=*/false);
1296
1297 if (this->isCompressed()) return true;
1298
1299 return this->compressUnsafe();
1300 }
1301
1302 return false;
1303 }
1304
1305
1306 template<typename ValueType_, typename Codec_>
1307 inline bool
1308 TypedAttributeArray<ValueType_, Codec_>::compressUnsafe()
1309 {
1310 if (!compression::bloscCanCompress()) return false;
1311 if (mIsUniform) return false;
1312
1313 // assumes mutex is locked and data is not out-of-core
1314
1315 const bool writeCompress = (mSerializationFlags & WRITEMEMCOMPRESS);
1316 const size_t inBytes = writeCompress ? mCompressedBytes : this->arrayMemUsage();
1317
1318 if (inBytes > 0) {
1319 size_t outBytes;
1320 const char* charBuffer = reinterpret_cast<const char*>(mData.get());
1321 std::unique_ptr<char[]> buffer = compression::bloscCompress(charBuffer, inBytes, outBytes);
1322 if (buffer) {
1323 mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1324 mCompressedBytes = outBytes;
1325 return true;
1326 }
1327 }
1328
1329 return false;
1330 }
1331
1332
1333 template<typename ValueType_, typename Codec_>
1334 inline bool
1335 TypedAttributeArray<ValueType_, Codec_>::decompress()
1336 {
1337 tbb::spin_mutex::scoped_lock lock(mMutex);
1338
1339 const bool writeCompress = (mSerializationFlags & WRITEMEMCOMPRESS);
1340
1341 if (writeCompress) {
1342 this->doLoadUnsafe(/*compression=*/false);
1343 return true;
1344 }
1345
1346 if (this->isCompressed()) {
1347 this->doLoadUnsafe();
1348 const char* charBuffer = reinterpret_cast<const char*>(this->mData.get());
1349 size_t uncompressedBytes = compression::bloscUncompressedSize(charBuffer);
1350 std::unique_ptr<char[]> buffer = compression::bloscDecompress(charBuffer, uncompressedBytes);
1351 if (buffer) {
1352 mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1353 mCompressedBytes = 0;
1354 return true;
1355 }
1356 }
1357
1358 return false;
1359 }
1360
1361
1362 template<typename ValueType_, typename Codec_>
1363 bool
1364 TypedAttributeArray<ValueType_, Codec_>::isOutOfCore() const
1365 {
1366 #if OPENVDB_ABI_VERSION_NUMBER >= 5
1367 return mOutOfCore;
1368 #else
1369 return (mFlags & OUTOFCORE);
1370 #endif
1371 }
1372
1373
1374 template<typename ValueType_, typename Codec_>
1375 void
1376 TypedAttributeArray<ValueType_, Codec_>::setOutOfCore(const bool b)
1377 {
1378 #if OPENVDB_ABI_VERSION_NUMBER >= 5
1379 mOutOfCore = b;
1380 #else
1381 if (b) mFlags = static_cast<uint8_t>(mFlags | OUTOFCORE);
1382 else mFlags = static_cast<uint8_t>(mFlags & ~OUTOFCORE);
1383 #endif
1384 }
1385
1386
1387 template<typename ValueType_, typename Codec_>
1388 void
1389 TypedAttributeArray<ValueType_, Codec_>::doLoad() const
1390 {
1391 if (!(this->isOutOfCore())) return;
1392
1393 TypedAttributeArray<ValueType_, Codec_>* self =
1394 const_cast<TypedAttributeArray<ValueType_, Codec_>*>(this);
1395
1396 // This lock will be contended at most once, after which this buffer
1397 // will no longer be out-of-core.
1398 tbb::spin_mutex::scoped_lock lock(self->mMutex);
1399 this->doLoadUnsafe();
1400 }
1401
1402
1403 template<typename ValueType_, typename Codec_>
1404 void
1405 TypedAttributeArray<ValueType_, Codec_>::loadData() const
1406 {
1407 this->doLoad();
1408 }
1409
1410
1411 template<typename ValueType_, typename Codec_>
1412 void
1413 TypedAttributeArray<ValueType_, Codec_>::read(std::istream& is)
1414 {
1415 this->readMetadata(is);
1416 this->readBuffers(is);
1417 }
1418
1419
1420 template<typename ValueType_, typename Codec_>
1421 void
1422 TypedAttributeArray<ValueType_, Codec_>::readMetadata(std::istream& is)
1423 {
1424 // read data
1425
1426 Index64 bytes = Index64(0);
1427 is.read(reinterpret_cast<char*>(&bytes), sizeof(Index64));
1428 bytes = bytes - /*flags*/sizeof(Int16) - /*size*/sizeof(Index);
1429
1430 uint8_t flags = uint8_t(0);
1431 is.read(reinterpret_cast<char*>(&flags), sizeof(uint8_t));
1432 mFlags = flags;
1433
1434 uint8_t serializationFlags = uint8_t(0);
1435 is.read(reinterpret_cast<char*>(&serializationFlags), sizeof(uint8_t));
1436 mSerializationFlags = serializationFlags;
1437
1438 Index size = Index(0);
1439 is.read(reinterpret_cast<char*>(&size), sizeof(Index));
1440 mSize = size;
1441
1442 // warn if an unknown flag has been set
1443 if (mFlags >= 0x20) {
1444 OPENVDB_LOG_WARN("Unknown attribute flags for VDB file format.");
1445 }
1446 // error if an unknown serialization flag has been set,
1447 // as this will adjust the layout of the data and corrupt the ability to read
1448 if (mSerializationFlags >= 0x10) {
1449 OPENVDB_THROW(IoError, "Unknown attribute serialization flags for VDB file format.");
1450 }
1451
1452 // read uniform and compressed state
1453
1454 mIsUniform = mSerializationFlags & WRITEUNIFORM;
1455 mCompressedBytes = bytes;
1456
1457 // read strided value (set to 1 if array is not strided)
1458
1459 if (mSerializationFlags & WRITESTRIDED) {
1460 Index stride = Index(0);
1461 is.read(reinterpret_cast<char*>(&stride), sizeof(Index));
1462 mStrideOrTotalSize = stride;
1463 }
1464 else {
1465 mStrideOrTotalSize = 1;
1466 }
1467 }
1468
1469
1470 template<typename ValueType_, typename Codec_>
1471 void
1472 TypedAttributeArray<ValueType_, Codec_>::readBuffers(std::istream& is)
1473 {
1474 if ((mSerializationFlags & WRITEPAGED)) {
1475 // use readBuffers(PagedInputStream&) for paged buffers
1476 OPENVDB_THROW(IoError, "Cannot read paged AttributeArray buffers.");
1477 }
1478
1479 tbb::spin_mutex::scoped_lock lock(mMutex);
1480
1481 this->deallocate();
1482
1483 uint8_t bloscCompressed(0);
1484 if (!mIsUniform) is.read(reinterpret_cast<char*>(&bloscCompressed), sizeof(uint8_t));
1485
1486 std::unique_ptr<char[]> buffer(new char[mCompressedBytes]);
1487 is.read(buffer.get(), mCompressedBytes);
1488
1489 if (mIsUniform) {
1490 // zero compressed bytes as uniform values are not compressed in memory
1491 mCompressedBytes = Index64(0);
1492 }
1493 else if (!(mSerializationFlags & WRITEMEMCOMPRESS)) {
1494 // zero compressed bytes if not compressed in memory
1495 mCompressedBytes = Index64(0);
1496 }
1497
1498 // compressed on-disk
1499
1500 if (bloscCompressed == uint8_t(1)) {
1501
1502 // decompress buffer
1503
1504 const size_t inBytes = this->dataSize() * sizeof(StorageType);
1505 std::unique_ptr<char[]> newBuffer = compression::bloscDecompress(buffer.get(), inBytes);
1506 if (newBuffer) buffer.reset(newBuffer.release());
1507 }
1508
1509 // set data to buffer
1510
1511 mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1512
1513 // clear all write flags
1514
1515 if (mIsUniform) mSerializationFlags &= uint8_t(~WRITEUNIFORM & ~WRITEMEMCOMPRESS & ~WRITEPAGED);
1516 else mSerializationFlags &= uint8_t(~WRITEUNIFORM & ~WRITEPAGED);
1517 }
1518
1519
1520 template<typename ValueType_, typename Codec_>
1521 void
1522 TypedAttributeArray<ValueType_, Codec_>::readPagedBuffers(compression::PagedInputStream& is)
1523 {
1524 if (!(mSerializationFlags & WRITEPAGED)) {
1525 if (!is.sizeOnly()) this->readBuffers(is.getInputStream());
1526 return;
1527 }
1528
1529 // If this array is being read from a memory-mapped file, delay loading of its data
1530 // until the data is actually accessed.
1531 io::MappedFile::Ptr mappedFile = io::getMappedFilePtr(is.getInputStream());
1532 const bool delayLoad = (mappedFile.get() != nullptr);
1533
1534 if (is.sizeOnly())
1535 {
1536 mPageHandle = is.createHandle(mCompressedBytes);
1537 return;
1538 }
1539
1540 assert(mPageHandle);
1541
1542 tbb::spin_mutex::scoped_lock lock(mMutex);
1543
1544 this->deallocate();
1545
1546 this->setOutOfCore(delayLoad);
1547 is.read(mPageHandle, mCompressedBytes, delayLoad);
1548
1549 if (!delayLoad) {
1550 std::unique_ptr<char[]> buffer = mPageHandle->read();
1551 mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1552 }
1553
1554 // zero compressed bytes as not compressed in memory
1555
1556 if (mIsUniform) {
1557 // zero compressed bytes as uniform values are not compressed in memory
1558 mCompressedBytes = Index64(0);
1559 }
1560 else if (!(mSerializationFlags & WRITEMEMCOMPRESS)) {
1561 mCompressedBytes = Index64(0);
1562 }
1563
1564 // clear all write flags
1565
1566 if (mIsUniform) mSerializationFlags &= uint8_t(~WRITEUNIFORM & ~WRITEMEMCOMPRESS & ~WRITEPAGED);
1567 else mSerializationFlags &= uint8_t(~WRITEUNIFORM & ~WRITEPAGED);
1568 }
1569
1570
1571 template<typename ValueType_, typename Codec_>
1572 void
1573 TypedAttributeArray<ValueType_, Codec_>::write(std::ostream& os) const
1574 {
1575 this->write(os, /*outputTransient=*/false);
1576 }
1577
1578
1579 template<typename ValueType_, typename Codec_>
1580 void
1581 TypedAttributeArray<ValueType_, Codec_>::write(std::ostream& os, bool outputTransient) const
1582 {
1583 this->writeMetadata(os, outputTransient, /*paged=*/false);
1584 this->writeBuffers(os, outputTransient);
1585 }
1586
1587
1588 template<typename ValueType_, typename Codec_>
1589 void
1590 TypedAttributeArray<ValueType_, Codec_>::writeMetadata(std::ostream& os, bool outputTransient, bool paged) const
1591 {
1592 if (!outputTransient && this->isTransient()) return;
1593
1594 #if OPENVDB_ABI_VERSION_NUMBER >= 5
1595 uint8_t flags(mFlags);
1596 #else
1597 uint8_t flags(mFlags & uint8_t(~OUTOFCORE));
1598 #endif
1599 uint8_t serializationFlags(0);
1600 Index size(mSize);
1601 Index stride(mStrideOrTotalSize);
1602 bool strideOfOne(this->stride() == 1);
1603
1604 bool bloscCompression = io::getDataCompression(os) & io::COMPRESS_BLOSC;
1605
1606 // any compressed data needs to be loaded if out-of-core
1607 if (bloscCompression || this->isCompressed()) this->doLoad();
1608
1609 size_t compressedBytes = 0;
1610
1611 if (!strideOfOne)
1612 {
1613 serializationFlags |= WRITESTRIDED;
1614 }
1615
1616 if (mIsUniform)
1617 {
1618 serializationFlags |= WRITEUNIFORM;
1619 if (bloscCompression && paged) serializationFlags |= WRITEPAGED;
1620 }
1621 else if (bloscCompression && paged)
1622 {
1623 serializationFlags |= WRITEPAGED;
1624 if (this->isCompressed()) {
1625 serializationFlags |= WRITEMEMCOMPRESS;
1626 const char* charBuffer = reinterpret_cast<const char*>(mData.get());
1627 compressedBytes = compression::bloscUncompressedSize(charBuffer);
1628 }
1629 }
1630 else if (this->isCompressed())
1631 {
1632 serializationFlags |= WRITEMEMCOMPRESS;
1633 compressedBytes = mCompressedBytes;
1634 }
1635 else if (bloscCompression)
1636 {
1637 const char* charBuffer = reinterpret_cast<const char*>(mData.get());
1638 const size_t inBytes = this->arrayMemUsage();
1639 compressedBytes = compression::bloscCompressedSize(charBuffer, inBytes);
1640 }
1641
1642 Index64 bytes = /*flags*/ sizeof(Int16) + /*size*/ sizeof(Index);
1643
1644 bytes += (compressedBytes > 0) ? compressedBytes : this->arrayMemUsage();
1645
1646 // write data
1647
1648 os.write(reinterpret_cast<const char*>(&bytes), sizeof(Index64));
1649 os.write(reinterpret_cast<const char*>(&flags), sizeof(uint8_t));
1650 os.write(reinterpret_cast<const char*>(&serializationFlags), sizeof(uint8_t));
1651 os.write(reinterpret_cast<const char*>(&size), sizeof(Index));
1652
1653 // write strided
1654 if (!strideOfOne) os.write(reinterpret_cast<const char*>(&stride), sizeof(Index));
1655 }
1656
1657
1658 template<typename ValueType_, typename Codec_>
1659 void
1660 TypedAttributeArray<ValueType_, Codec_>::writeBuffers(std::ostream& os, bool outputTransient) const
1661 {
1662 if (!outputTransient && this->isTransient()) return;
1663
1664 this->doLoad();
1665
1666 if (this->isUniform()) {
1667 os.write(reinterpret_cast<const char*>(mData.get()), sizeof(StorageType));
1668 }
1669 else if (this->isCompressed())
1670 {
1671 uint8_t bloscCompressed(0);
1672 os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1673 os.write(reinterpret_cast<const char*>(mData.get()), mCompressedBytes);
1674 }
1675 else if (io::getDataCompression(os) & io::COMPRESS_BLOSC)
1676 {
1677 std::unique_ptr<char[]> compressedBuffer;
1678 size_t compressedBytes = 0;
1679 const char* charBuffer = reinterpret_cast<const char*>(mData.get());
1680 const size_t inBytes = this->arrayMemUsage();
1681 compressedBuffer = compression::bloscCompress(charBuffer, inBytes, compressedBytes);
1682 if (compressedBuffer) {
1683 uint8_t bloscCompressed(1);
1684 os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1685 os.write(reinterpret_cast<const char*>(compressedBuffer.get()), compressedBytes);
1686 }
1687 else {
1688 uint8_t bloscCompressed(0);
1689 os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1690 os.write(reinterpret_cast<const char*>(mData.get()), inBytes);
1691 }
1692 }
1693 else
1694 {
1695 uint8_t bloscCompressed(0);
1696 os.write(reinterpret_cast<const char*>(&bloscCompressed), sizeof(uint8_t));
1697 os.write(reinterpret_cast<const char*>(mData.get()), this->arrayMemUsage());
1698 }
1699 }
1700
1701
1702 template<typename ValueType_, typename Codec_>
1703 void
1704 TypedAttributeArray<ValueType_, Codec_>::writePagedBuffers(compression::PagedOutputStream& os, bool outputTransient) const
1705 {
1706 if (!outputTransient && this->isTransient()) return;
1707
1708 // paged compression only available when Blosc is enabled
1709 bool bloscCompression = io::getDataCompression(os.getOutputStream()) & io::COMPRESS_BLOSC;
1710 if (!bloscCompression) {
1711 if (!os.sizeOnly()) this->writeBuffers(os.getOutputStream(), outputTransient);
1712 return;
1713 }
1714
1715 this->doLoad();
1716
1717 const char* buffer;
1718 size_t bytes;
1719
1720 std::unique_ptr<char[]> uncompressedBuffer;
1721 if (this->isCompressed()) {
1722 // paged streams require uncompressed buffers, so locally decompress
1723
1724 const char* charBuffer = reinterpret_cast<const char*>(this->mData.get());
1725 bytes = compression::bloscUncompressedSize(charBuffer);
1726 uncompressedBuffer = compression::bloscDecompress(charBuffer, bytes);
1727 buffer = reinterpret_cast<const char*>(uncompressedBuffer.get());
1728 }
1729 else {
1730 buffer = reinterpret_cast<const char*>(mData.get());
1731 bytes = this->arrayMemUsage();
1732 }
1733
1734 os.write(buffer, bytes);
1735 }
1736
1737
1738 template<typename ValueType_, typename Codec_>
1739 void
1740 TypedAttributeArray<ValueType_, Codec_>::doLoadUnsafe(const bool compression) const
1741 {
1742 if (!(this->isOutOfCore())) return;
1743
1744 // this function expects the mutex to already be locked
1745
1746 TypedAttributeArray<ValueType_, Codec_>* self = const_cast<TypedAttributeArray<ValueType_, Codec_>*>(this);
1747
1748 assert(self->mPageHandle);
1749
1750 std::unique_ptr<char[]> buffer = self->mPageHandle->read();
1751
1752 self->mData.reset(reinterpret_cast<StorageType*>(buffer.release()));
1753
1754 self->mPageHandle.reset();
1755
1756 // if data was compressed prior to being written to disk, re-compress
1757
1758 if (self->mSerializationFlags & WRITEMEMCOMPRESS) {
1759 if (compression) self->compressUnsafe();
1760 else self->mCompressedBytes = 0;
1761 }
1762
1763 // clear all write and out-of-core flags
1764
1765 #if OPENVDB_ABI_VERSION_NUMBER >= 5
1766 self->mOutOfCore = false;
1767 #else
1768 self->mFlags &= uint8_t(~OUTOFCORE);
1769 #endif
1770 self->mSerializationFlags &= uint8_t(~WRITEUNIFORM & ~WRITEMEMCOMPRESS & ~WRITEPAGED);
1771 }
1772
1773
1774 template<typename ValueType_, typename Codec_>
1775 AttributeArray::AccessorBasePtr
1776 TypedAttributeArray<ValueType_, Codec_>::getAccessor() const
1777 {
1778 // use the faster 'unsafe' get and set methods as attribute handles
1779 // ensure data is uncompressed and in-core when constructed
1780
1781 return AccessorBasePtr(new AttributeArray::Accessor<ValueType_>(
1782 &TypedAttributeArray<ValueType_, Codec_>::getUnsafe,
1783 &TypedAttributeArray<ValueType_, Codec_>::setUnsafe,
1784 &TypedAttributeArray<ValueType_, Codec_>::collapse,
1785 &TypedAttributeArray<ValueType_, Codec_>::fill));
1786 }
1787
1788
1789 template<typename ValueType_, typename Codec_>
1790 bool
1791 TypedAttributeArray<ValueType_, Codec_>::isEqual(const AttributeArray& other) const
1792 {
1793 const TypedAttributeArray<ValueType_, Codec_>* const otherT = dynamic_cast<const TypedAttributeArray<ValueType_, Codec_>* >(&other);
1794 if(!otherT) return false;
1795 if(this->mSize != otherT->mSize ||
1796 this->mStrideOrTotalSize != otherT->mStrideOrTotalSize ||
1797 this->mIsUniform != otherT->mIsUniform ||
1798 *this->sTypeName != *otherT->sTypeName) return false;
1799
1800 this->doLoad();
1801 otherT->doLoad();
1802
1803 const StorageType *target = this->mData.get(), *source = otherT->mData.get();
1804 if (!target && !source) return true;
1805 if (!target || !source) return false;
1806 Index n = this->mIsUniform ? 1 : mSize;
1807 while (n && math::isExactlyEqual(*target++, *source++)) --n;
1808 return n == 0;
1809 }
1810
1812
1813
1815 template <typename CodecType, typename ValueType>
1816 struct AccessorEval
1817 {
1818 using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
1819 using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
1820
1823 static ValueType get(GetterPtr /*functor*/, const AttributeArray* array, const Index n) {
1824 return TypedAttributeArray<ValueType, CodecType>::getUnsafe(array, n);
1825 }
1826
1829 static void set(SetterPtr /*functor*/, AttributeArray* array, const Index n, const ValueType& value) {
1830 TypedAttributeArray<ValueType, CodecType>::setUnsafe(array, n, value);
1831 }
1832 };
1833
1834
1836 template <typename ValueType>
1837 struct AccessorEval<UnknownCodec, ValueType>
1838 {
1839 using GetterPtr = ValueType (*)(const AttributeArray* array, const Index n);
1840 using SetterPtr = void (*)(AttributeArray* array, const Index n, const ValueType& value);
1841
1843 static ValueType get(GetterPtr functor, const AttributeArray* array, const Index n) {
1844 return (*functor)(array, n);
1845 }
1846
1848 static void set(SetterPtr functor, AttributeArray* array, const Index n, const ValueType& value) {
1849 (*functor)(array, n, value);
1850 }
1851 };
1852
1853
1855
1856 // AttributeHandle implementation
1857
1858 template <typename ValueType, typename CodecType>
1859 typename AttributeHandle<ValueType, CodecType>::Ptr
1860 AttributeHandle<ValueType, CodecType>::create(const AttributeArray& array, const bool preserveCompression)
1861 {
1862 return typename AttributeHandle<ValueType, CodecType>::Ptr(
1863 new AttributeHandle<ValueType, CodecType>(array, preserveCompression));
1864 }
1865
1866 template <typename ValueType, typename CodecType>
1867 AttributeHandle<ValueType, CodecType>::AttributeHandle(const AttributeArray& array, const bool preserveCompression)
1868 : mArray(&array)
1869 , mStrideOrTotalSize(array.hasConstantStride() ? array.stride() : 1)
1870 , mSize(array.hasConstantStride() ? array.size() : array.dataSize())
1871 , mCollapseOnDestruction(preserveCompression && array.isStreaming())
1872 {
1873 if (!this->compatibleType<std::is_same<CodecType, UnknownCodec>::value>()) {
1874 OPENVDB_THROW(TypeError, "Cannot bind handle due to incompatible type of AttributeArray.");
1875 }
1876
1877 // load data if delay-loaded
1878
1879 mArray->loadData();
1880
1881 // if array is compressed and preserve compression is true, copy and decompress
1882 // into a local copy that is destroyed with handle to maintain thread-safety
1883
1884 if (array.isCompressed())
1885 {
1886 if (preserveCompression && !array.isStreaming()) {
1887 mLocalArray = array.copyUncompressed();
1888 mLocalArray->decompress();
1889 mArray = mLocalArray.get();
1890 }
1891 else {
1892 const_cast<AttributeArray*>(mArray)->decompress();
1893 }
1894 }
1895
1896 // bind getter and setter methods
1897
1898 AttributeArray::AccessorBasePtr accessor = mArray->getAccessor();
1899 assert(accessor);
1900
1901 AttributeArray::Accessor<ValueType>* typedAccessor = static_cast<AttributeArray::Accessor<ValueType>*>(accessor.get());
1902
1903 mGetter = typedAccessor->mGetter;
1904 mSetter = typedAccessor->mSetter;
1905 mCollapser = typedAccessor->mCollapser;
1906 mFiller = typedAccessor->mFiller;
1907 }
1908
1909 template <typename ValueType, typename CodecType>
1910 AttributeHandle<ValueType, CodecType>::~AttributeHandle()
1911 {
1912 // if enabled, attribute is collapsed on destruction of the handle to save memory
1913 if (mCollapseOnDestruction) const_cast<AttributeArray*>(this->mArray)->collapse();
1914 }
1915
1916 template <typename ValueType, typename CodecType>
1917 template <bool IsUnknownCodec>
1918 typename std::enable_if<IsUnknownCodec, bool>::type
1919 AttributeHandle<ValueType, CodecType>::compatibleType() const
1920 {
1921 // if codec is unknown, just check the value type
1922
1923 return mArray->hasValueType<ValueType>();
1924 }
1925
1926 template <typename ValueType, typename CodecType>
1927 template <bool IsUnknownCodec>
1928 typename std::enable_if<!IsUnknownCodec, bool>::type
1929 AttributeHandle<ValueType, CodecType>::compatibleType() const
1930 {
1931 // if the codec is known, check the value type and codec
1932
1933 return mArray->isType<TypedAttributeArray<ValueType, CodecType>>();
1934 }
1935
1936 template <typename ValueType, typename CodecType>
1937 Index AttributeHandle<ValueType, CodecType>::index(Index n, Index m) const
1938 {
1939 Index index = n * mStrideOrTotalSize + m;
1940 assert(index < (mSize * mStrideOrTotalSize));
1941 return index;
1942 }
1943
1944 template <typename ValueType, typename CodecType>
1945 ValueType AttributeHandle<ValueType, CodecType>::get(Index n, Index m) const
1946 {
1947 return this->get<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, m));
1948 }
1949
1950 template <typename ValueType, typename CodecType>
1951 template <bool IsUnknownCodec>
1952 typename std::enable_if<IsUnknownCodec, ValueType>::type
1953 AttributeHandle<ValueType, CodecType>::get(Index index) const
1954 {
1955 // if the codec is unknown, use the getter functor
1956
1957 return (*mGetter)(mArray, index);
1958 }
1959
1960 template <typename ValueType, typename CodecType>
1961 template <bool IsUnknownCodec>
1962 typename std::enable_if<!IsUnknownCodec, ValueType>::type
1963 AttributeHandle<ValueType, CodecType>::get(Index index) const
1964 {
1965 // if the codec is known, call the method on the attribute array directly
1966
1967 return TypedAttributeArray<ValueType, CodecType>::getUnsafe(mArray, index);
1968 }
1969
1970 template <typename ValueType, typename CodecType>
1971 bool AttributeHandle<ValueType, CodecType>::isUniform() const
1972 {
1973 return mArray->isUniform();
1974 }
1975
1976 template <typename ValueType, typename CodecType>
1977 bool AttributeHandle<ValueType, CodecType>::hasConstantStride() const
1978 {
1979 return mArray->hasConstantStride();
1980 }
1981
1983
1984 // AttributeWriteHandle implementation
1985
1986 template <typename ValueType, typename CodecType>
1987 typename AttributeWriteHandle<ValueType, CodecType>::Ptr
1988 AttributeWriteHandle<ValueType, CodecType>::create(AttributeArray& array, const bool expand)
1989 {
1990 return typename AttributeWriteHandle<ValueType, CodecType>::Ptr(
1991 new AttributeWriteHandle<ValueType, CodecType>(array, expand));
1992 }
1993
1994 template <typename ValueType, typename CodecType>
1995 AttributeWriteHandle<ValueType, CodecType>::AttributeWriteHandle(AttributeArray& array, const bool expand)
1996 : AttributeHandle<ValueType, CodecType>(array, /*preserveCompression = */ false)
1997 {
1998 if (expand) array.expand();
1999 }
2000
2001 template <typename ValueType, typename CodecType>
2002 void AttributeWriteHandle<ValueType, CodecType>::set(Index n, const ValueType& value)
2003 {
2004 this->set<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, 0), value);
2005 }
2006
2007 template <typename ValueType, typename CodecType>
2008 void AttributeWriteHandle<ValueType, CodecType>::set(Index n, Index m, const ValueType& value)
2009 {
2010 this->set<std::is_same<CodecType, UnknownCodec>::value>(this->index(n, m), value);
2011 }
2012
2013 template <typename ValueType, typename CodecType>
2014 void AttributeWriteHandle<ValueType, CodecType>::expand(const bool fill)
2015 {
2016 const_cast<AttributeArray*>(this->mArray)->expand(fill);
2017 }
2018
2019 template <typename ValueType, typename CodecType>
2020 void AttributeWriteHandle<ValueType, CodecType>::collapse()
2021 {
2022 const_cast<AttributeArray*>(this->mArray)->collapse();
2023 }
2024
2025 template <typename ValueType, typename CodecType>
2026 bool AttributeWriteHandle<ValueType, CodecType>::compact()
2027 {
2028 return const_cast<AttributeArray*>(this->mArray)->compact();
2029 }
2030
2031 template <typename ValueType, typename CodecType>
2032 void AttributeWriteHandle<ValueType, CodecType>::collapse(const ValueType& uniformValue)
2033 {
2034 this->mCollapser(const_cast<AttributeArray*>(this->mArray), uniformValue);
2035 }
2036
2037 template <typename ValueType, typename CodecType>
2038 void AttributeWriteHandle<ValueType, CodecType>::fill(const ValueType& value)
2039 {
2040 this->mFiller(const_cast<AttributeArray*>(this->mArray), value);
2041 }
2042
2043 template <typename ValueType, typename CodecType>
2044 template <bool IsUnknownCodec>
2045 typename std::enable_if<IsUnknownCodec, void>::type
2046 AttributeWriteHandle<ValueType, CodecType>::set(Index index, const ValueType& value) const
2047 {
2048 // if the codec is unknown, use the setter functor
2049
2050 (*this->mSetter)(const_cast<AttributeArray*>(this->mArray), index, value);
2051 }
2052
2053 template <typename ValueType, typename CodecType>
2054 template <bool IsUnknownCodec>
2055 typename std::enable_if<!IsUnknownCodec, void>::type
2056 AttributeWriteHandle<ValueType, CodecType>::set(Index index, const ValueType& value) const
2057 {
2058 // if the codec is known, call the method on the attribute array directly
2059
2060 TypedAttributeArray<ValueType, CodecType>::setUnsafe(const_cast<AttributeArray*>(this->mArray), index, value);
2061 }
2062
2063
2064 } // namespace points
2065 } // namespace OPENVDB_VERSION_NAME
2066 } // namespace openvdb
2067
2068 #endif // OPENVDB_POINTS_ATTRIBUTE_ARRAY_HAS_BEEN_INCLUDED
2069
2070 // Copyright (c) 2012-2018 DreamWorks Animation LLC
2071 // All rights reserved. This software is distributed under the
2072 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
openvdb::v5_1::math::isExactlyEqual
bool isExactlyEqual(const T0 &a, const T1 &b)
Return true if a is exactly equal to b.
Definition: Math.h:395
openvdb::v5_1::points::TruncateCodec::Storage::Type
typename attribute_traits::TruncateTrait< T >::Type Type
Definition: AttributeArray.h:381
openvdb::v5_1::points::AttributeArray::isHidden
bool isHidden() const
Return true if this attribute is hidden (e.g., from UI or iterators).
Definition: AttributeArray.h:218
openvdb::v5_1::points::TypedAttributeArray
Typed class for storing attribute data.
Definition: AttributeArray.h:441
OPENVDB_API
#define OPENVDB_API
Helper macros for defining library symbol visibility.
Definition: Platform.h:194
openvdb::v5_1::points::TypedAttributeArray::create
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.
Definition: AttributeArray.h:981
openvdb::v5_1::points::AttributeArray::Accessor::ValuePtr
void(*)(AttributeArray *array, const T &value) ValuePtr
Definition: AttributeArray.h:322
openvdb::v5_1::points::TypedAttributeArray::setUnsafe
void setUnsafe(Index n, const ValueType &value)
Set value at the given index n (assumes uncompressed and in-core)
Definition: AttributeArray.h:1124
openvdb::v5_1::points::TypedAttributeArray::read
void read(std::istream &) override
Read attribute data from a stream.
Definition: AttributeArray.h:1413
openvdb::v5_1::points::TruncateCodec::name
static const char * name()
Definition: AttributeArray.h:385
Types.h
openvdb::v5_1::points::AccessorEval
Accessor to call unsafe get and set methods based on templated Codec and Value.
Definition: AttributeArray.h:1816
openvdb::v5_1::compression::PagedOutputStream::sizeOnly
bool sizeOnly() const
Definition: StreamCompression.h:273
openvdb::v5_1::points::AttributeHandle::mArray
const AttributeArray * mArray
Definition: AttributeArray.h:677
openvdb::v5_1::compression::PagedOutputStream::write
PagedOutputStream & write(const char *str, std::streamsize n)
Writes the given.
openvdb::v5_1::points::AttributeArray
Base class for storing attribute data.
Definition: AttributeArray.h:118
Compression.h
openvdb::v5_1::Name
std::string Name
Definition: Name.h:44
QuantizedUnitVec.h
openvdb::v5_1::io::MappedFile::Ptr
SharedPtr< MappedFile > Ptr
Definition: io.h:152
openvdb::v5_1::points::AttributeArray::Flag
Flag
Definition: AttributeArray.h:127
openvdb::v5_1::points::TypedAttributeArray::set
void set(Index n, const ValueType &value)
Set value at the given index n.
Definition: AttributeArray.h:1140
openvdb::v5_1::points::attribute_traits::TruncateTrait< float >::Type
half Type
Definition: AttributeArray.h:340
openvdb::v5_1::Int16
int16_t Int16
Definition: Types.h:62
openvdb::v5_1::points::attribute_traits::UIntTypeTrait< false, T >::Type
uint16_t Type
Definition: AttributeArray.h:349
openvdb::v5_1::points::AttributeWriteHandle::Ptr
std::shared_ptr< Handle > Ptr
Definition: AttributeArray.h:717
openvdb::v5_1::points::AttributeArray::FactoryMethod
Ptr(*)(Index, Index, bool) FactoryMethod
Definition: AttributeArray.h:145
openvdb::v5_1::compression::bloscUncompressedSize
OPENVDB_API size_t bloscUncompressedSize(const char *buffer)
Retrieves the uncompressed size of buffer when uncompressed.
openvdb::v5_1::points::AttributeHandle::mCollapser
ValuePtr mCollapser
Definition: AttributeArray.h:681
openvdb::v5_1::points::TypedAttributeArray::getAccessor
AccessorBasePtr getAccessor() const override
Obtain an Accessor that stores getter and setter functors.
Definition: AttributeArray.h:1776
openvdb::v5_1::points::TypedAttributeArray::loadData
void loadData() const override
Ensures all data is in-core.
Definition: AttributeArray.h:1405
openvdb::v5_1::points::AttributeArray::mPageHandle
compression::PageHandle::Ptr mPageHandle
used for out-of-core, paged reading
Definition: AttributeArray.h:305
openvdb::v5_1::points::AttributeArray::Accessor::SetterPtr
void(*)(AttributeArray *array, const Index n, const T &value) SetterPtr
Definition: AttributeArray.h:321
openvdb::v5_1::points::AttributeArray::Accessor::mSetter
SetterPtr mSetter
Definition: AttributeArray.h:328
OPENVDB_THROW
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
openvdb::v5_1::points::TypedAttributeArray::~TypedAttributeArray
virtual ~TypedAttributeArray()
Definition: AttributeArray.h:465
openvdb::v5_1::points::AttributeHandle::mSetter
SetterPtr mSetter
Definition: AttributeArray.h:680
openvdb::v5_1::points::AttributeArray::AccessorBasePtr
std::shared_ptr< AccessorBase > AccessorBasePtr
Definition: AttributeArray.h:124
openvdb::v5_1::points::AttributeArray::Accessor::mFiller
ValuePtr mFiller
Definition: AttributeArray.h:330
openvdb::v5_1::points::TypedAttributeArray::fill
void fill(const ValueType &value)
Fill the existing array with the given value.
Definition: AttributeArray.h:1262
openvdb::v5_1::points::AttributeHandle
Definition: AttributeArray.h:644
openvdb::v5_1::points::TypedAttributeArray::isUniform
bool isUniform() const override
Return true if this array is stored as a single uniform value.
Definition: AttributeArray.h:539
openvdb::v5_1::points::TypedAttributeArray::registerType
static void registerType()
Register this attribute type along with a factory function.
Definition: AttributeArray.h:965
openvdb::v5_1::points::NullCodec
Definition: AttributeArray.h:367
openvdb::v5_1::points::TypedAttributeArray::dataSize
Index dataSize() const override
Return the size of the data in this array.
Definition: AttributeArray.h:502
openvdb::v5_1::compression::bloscCanCompress
OPENVDB_API bool bloscCanCompress()
Returns true if compression is available.
openvdb::v5_1::points::TruncateCodec
Definition: AttributeArray.h:378
openvdb::v5_1::points::AttributeArray::isStreaming
bool isStreaming() const
Return true if this attribute is in streaming mode.
Definition: AttributeArray.h:233
openvdb::v5_1::points::TypedAttributeArray::isOutOfCore
bool isOutOfCore() const
Return true if this buffer&#39;s values have not yet been read from disk.
Definition: AttributeArray.h:1364
openvdb::v5_1::math::Vec3
Definition: Mat.h:197
openvdb::v5_1::points::AttributeHandle::mFiller
ValuePtr mFiller
Definition: AttributeArray.h:682
openvdb::v5_1::points::AttributeArray::ConstPtr
std::shared_ptr< const AttributeArray > ConstPtr
Definition: AttributeArray.h:143
openvdb::v5_1::io::getDataCompression
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.
openvdb::v5_1::points::AttributeArray::Accessor::mCollapser
ValuePtr mCollapser
Definition: AttributeArray.h:329
openvdb::v5_1::points::NullCodec::Storage::Type
T Type
Definition: AttributeArray.h:370
io.h
openvdb::v5_1::IoError
Definition: Exceptions.h:85
openvdb::v5_1::points::UnitVecCodec::StorageType
uint16_t StorageType
Definition: AttributeArray.h:425
openvdb::v5_1::compression::PagedInputStream::read
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...
logging.h
openvdb::v5_1::points::TypedAttributeArray::collapse
void collapse() override
Replace the existing array with a uniform zero value.
Definition: AttributeArray.h:1232
openvdb::v5_1::points::TypedAttributeArray::isRegistered
static bool isRegistered()
Return true if this attribute type is registered.
Definition: AttributeArray.h:957
openvdb::v5_1::points::AttributeHandle::size
Index size() const
Definition: AttributeArray.h:667
openvdb::v5_1::points::TypedAttributeArray::expand
void expand(bool fill=true) override
Replace the single value storage with an array of length size().
Definition: AttributeArray.h:1192
openvdb::v5_1::points::AttributeHandle::mGetter
GetterPtr mGetter
Definition: AttributeArray.h:679
openvdb::v5_1::points::AttributeArray::Accessor::Accessor
Accessor(GetterPtr getter, SetterPtr setter, ValuePtr collapser, ValuePtr filler)
Definition: AttributeArray.h:324
openvdb::v5_1::NamePair
std::pair< Name, Name > NamePair
Definition: AttributeArray.h:65
openvdb::v5_1::compression::PagedInputStream::sizeOnly
bool sizeOnly() const
Definition: StreamCompression.h:236
openvdb::v5_1::points::AttributeArray::operator!=
bool operator!=(const AttributeArray &other) const
Definition: AttributeArray.h:275
openvdb::v5_1::points::AttributeWriteHandle< StringIndexType, openvdb::v5_1::points::StringCodec< false > >::ScopedPtr
std::unique_ptr< Handle > ScopedPtr
Definition: AttributeArray.h:718
openvdb::v5_1::points::AttributeArray::AccessorBase
Accessor base class for AttributeArray storage where type is not available.
Definition: AttributeArray.h:313
openvdb::v5_1::points::NullCodec::Storage
Definition: AttributeArray.h:370
openvdb::v5_1::points::FixedPointCodec
Definition: AttributeArray.h:408
openvdb::v5_1::points::AttributeHandle::AttributeHandle
AttributeHandle(const AttributeArray &array, const bool preserveCompression=true)
Definition: AttributeArray.h:1867
openvdb::v5_1::points::UnitVecCodec::Storage
Definition: AttributeArray.h:428
openvdb::v5_1::points::TypedAttributeArray::writeMetadata
void writeMetadata(std::ostream &os, bool outputTransient, bool paged) const override
Definition: AttributeArray.h:1590
StreamCompression.h
Convenience wrappers to using Blosc and reading and writing of Paged data.
openvdb::v5_1::points::AttributeArray::getAccessor
virtual AccessorBasePtr getAccessor() const =0
Obtain an Accessor that stores getter and setter functors.
openvdb::v5_1::points::TypedAttributeArray::unregisterType
static void unregisterType()
Remove this attribute type from the registry.
Definition: AttributeArray.h:973
openvdb::v5_1::io::getMappedFilePtr
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.
openvdb::v5_1::compression::PagedInputStream::getInputStream
std::istream & getInputStream()
Definition: StreamCompression.h:239
openvdb::v5_1::points::AttributeArray::hasValueType
bool hasValueType() const
Return true if this attribute has a value type the same as the template parameter.
Definition: AttributeArray.h:190
openvdb::v5_1::points::AttributeArray::Ptr
std::shared_ptr< AttributeArray > Ptr
Definition: AttributeArray.h:142
openvdb::v5_1::points::TypedAttributeArray::getUnsafe
ValueType getUnsafe(Index n) const
Return the value at index n (assumes uncompressed and in-core)
Definition: AttributeArray.h:1072
openvdb::v5_1::points::AttributeHandle::create
static Ptr create(const AttributeArray &array, const bool preserveCompression=true)
Definition: AttributeArray.h:1860
openvdb::v5_1::points::AttributeHandle::hasConstantStride
bool hasConstantStride() const
Definition: AttributeArray.h:1977
openvdb::v5_1::compression::PagedInputStream::createHandle
PageHandle::Ptr createHandle(std::streamsize n)
Creates a PageHandle to access the next.
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:136
openvdb::v5_1::points::UnitRange::encode
static ValueType encode(const ValueType &value)
Definition: AttributeArray.h:402
openvdb::v5_1::points::TypedAttributeArray::attributeType
static const NamePair & attributeType()
Return the name of this attribute&#39;s type (includes codec)
Definition: AttributeArray.h:945
openvdb::v5_1::ValueError
Definition: Exceptions.h:92
openvdb::v5_1::points::attribute_traits::TruncateTrait< int >::Type
short Type
Definition: AttributeArray.h:341
openvdb::v5_1::points::UnitVecCodec::name
static const char * name()
Definition: AttributeArray.h:432
openvdb::v5_1::points::TypedAttributeArray::readPagedBuffers
void readPagedBuffers(compression::PagedInputStream &) override
Read attribute buffers from a paged stream.
Definition: AttributeArray.h:1522
OPENVDB_LOG_WARN
#define OPENVDB_LOG_WARN(message)
Log a warning message of the form &#39;someVar << "some text" << ...&#39;.
Definition: logging.h:280
openvdb::v5_1::points::AttributeArray::flags
uint8_t flags() const
Retrieve the attribute array flags.
Definition: AttributeArray.h:239
openvdb::v5_1::points::AttributeArray::mSerializationFlags
uint8_t mSerializationFlags
Definition: AttributeArray.h:298
openvdb::v5_1::points::UnitRange
Definition: AttributeArray.h:399
openvdb::v5_1::points::TypedAttributeArray::memUsage
size_t memUsage() const override
Return the number of bytes of memory used by this attribute.
Definition: AttributeArray.h:1064
openvdb::v5_1::points::TypedAttributeArray::stride
Index stride() const override
Definition: AttributeArray.h:499
openvdb::v5_1::io::COMPRESS_BLOSC
Definition: Compression.h:81
openvdb::v5_1::points::AttributeArray::isCompressed
bool isCompressed() const
Return true if this array is compressed.
Definition: AttributeArray.h:206
openvdb::v5_1::points::AttributeHandle< StringIndexType, openvdb::v5_1::points::StringCodec< false > >::Ptr
std::shared_ptr< Handle > Ptr
Definition: AttributeArray.h:648
openvdb::v5_1::Index64
uint64_t Index64
Definition: Types.h:60
openvdb::v5_1::math::Vec3::x
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
Definition: Vec3.h:110
openvdb::v5_1::points::AttributeHandle::isUniform
bool isUniform() const
Definition: AttributeArray.h:1971
openvdb::v5_1::points::attribute_traits::TruncateTrait
Definition: AttributeArray.h:339
openvdb::v5_1::points::AttributeArray::registerType
static void registerType(const NamePair &type, FactoryMethod)
Register a attribute type along with a factory function.
openvdb::v5_1::points::AttributeArray::mFlags
uint8_t mFlags
Definition: AttributeArray.h:297
openvdb
Definition: Exceptions.h:40
openvdb::v5_1::points::AccessorEval::SetterPtr
void(*)(AttributeArray *array, const Index n, const ValueType &value) SetterPtr
Definition: AttributeArray.h:1819
openvdb::v5_1::points::TypedAttributeArray::write
void write(std::ostream &os, bool outputTransient) const override
Definition: AttributeArray.h:1581
openvdb::v5_1::points::TypedAttributeArray::decompress
bool decompress() override
Uncompress the attribute array.
Definition: AttributeArray.h:1335
openvdb::v5_1::points::FixedPointCodec::Storage
Definition: AttributeArray.h:411
openvdb::v5_1::TypeError
Definition: Exceptions.h:91
openvdb::v5_1::math::operator==
bool operator==(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Equality operator, does exact floating point comparisons.
Definition: Vec3.h:488
openvdb::v5_1::compression::PagedOutputStream::getOutputStream
std::ostream & getOutputStream()
Set and get the output stream.
Definition: StreamCompression.h:276
openvdb::v5_1::points::TypedAttributeArray::cast
static TypedAttributeArray & cast(AttributeArray &attributeArray)
Cast an AttributeArray to TypedAttributeArray<T>
Definition: AttributeArray.h:988
openvdb::v5_1::points::AttributeArray::mCompressedBytes
size_t mCompressedBytes
Definition: AttributeArray.h:296
openvdb::v5_1::points::TypedAttributeArray::writePagedBuffers
void writePagedBuffers(compression::PagedOutputStream &os, bool outputTransient) const override
Definition: AttributeArray.h:1704
IndexIterator.h
Index Iterators.
openvdb::v5_1::points::TypedAttributeArray::ValueType
ValueType_ ValueType
Definition: AttributeArray.h:447
openvdb::v5_1::points::attribute_traits::UIntTypeTrait
Definition: AttributeArray.h:347
openvdb::v5_1::points::AttributeHandle< StringIndexType, openvdb::v5_1::points::StringCodec< false > >::GetterPtr
StringIndexType(*)(const AttributeArray *array, const Index n) GetterPtr
Definition: AttributeArray.h:652
openvdb::v5_1::points::AttributeArray::Accessor
Definition: AttributeArray.h:122
openvdb::v5_1::compression::PagedInputStream
A Paging wrapper to std::istream that is responsible for reading from a given input stream and creati...
Definition: StreamCompression.h:225
openvdb::v5_1::points::AttributeArray::SerializationFlag
SerializationFlag
Definition: AttributeArray.h:135
openvdb::v5_1::points::FixedPointCodec::Storage::Type
typename attribute_traits::UIntTypeTrait< OneByte, T >::Type Type
Definition: AttributeArray.h:411
openvdb::v5_1::points::AttributeWriteHandle
Write-able version of AttributeHandle.
Definition: AttributeArray.h:713
openvdb::v5_1::points::TypedAttributeArray::writeBuffers
void writeBuffers(std::ostream &os, bool outputTransient) const override
Definition: AttributeArray.h:1660
openvdb::v5_1::points::PositionRange::decode
static ValueType decode(const ValueType &value)
Definition: AttributeArray.h:394
openvdb::v5_1::points::UnitRange::decode
static ValueType decode(const ValueType &value)
Definition: AttributeArray.h:403
openvdb::v5_1::compression::bloscDecompress
OPENVDB_API void bloscDecompress(char *uncompressedBuffer, const size_t expectedBytes, const size_t bufferBytes, const char *compressedBuffer)
Decompress into the supplied buffer. Will throw if decompression fails or uncompressed buffer has ins...
openvdb::v5_1::points::AccessorEval< UnknownCodec, ValueType >::SetterPtr
void(*)(AttributeArray *array, const Index n, const ValueType &value) SetterPtr
Definition: AttributeArray.h:1840
openvdb::v5_1::points::AttributeHandle< StringIndexType, openvdb::v5_1::points::StringCodec< false > >::SetterPtr
void(*)(AttributeArray *array, const Index n, const StringIndexType &value) SetterPtr
Definition: AttributeArray.h:653
openvdb::v5_1::points::AttributeArray::Accessor::mGetter
GetterPtr mGetter
Definition: AttributeArray.h:327
openvdb::v5_1::points::AttributeArray::isType
bool isType() const
Return true if this attribute is of the same type as the template parameter.
Definition: AttributeArray.h:186
openvdb::v5_1::points::TypedAttributeArray::compact
bool compact() override
Compact the existing array to become uniform if all values are identical.
Definition: AttributeArray.h:1215
openvdb::v5_1::points::TypedAttributeArray::readBuffers
void readBuffers(std::istream &) override
Read attribute buffers from a stream.
Definition: AttributeArray.h:1472
openvdb::v5_1::points::AttributeArray::isTransient
bool isTransient() const
Return true if this attribute is not serialized during stream output.
Definition: AttributeArray.h:225
openvdb::v5_1::compression::PagedOutputStream
A Paging wrapper to std::ostream that is responsible for writing from a given output stream at interv...
Definition: StreamCompression.h:262
openvdb::v5_1::points::PositionRange::name
static const char * name()
Definition: AttributeArray.h:392
openvdb::v5_1::points::AttributeArray::hasConstantStride
bool hasConstantStride() const
Return true if this attribute has a constant stride.
Definition: AttributeArray.h:236
openvdb::v5_1::points::TypedAttributeArray::Ptr
std::shared_ptr< TypedAttributeArray > Ptr
Definition: AttributeArray.h:444
openvdb::v5_1::tools::composite::min
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:129
openvdb::v5_1::points::floatingPointToFixedPoint
IntegerVectorT floatingPointToFixedPoint(const math::Vec3< FloatT > &v)
Definition: AttributeArray.h:95
openvdb::v5_1::points::TypedAttributeArray::copy
AttributeArray::Ptr copy() const override
Return a copy of this attribute.
Definition: AttributeArray.h:1008
openvdb::v5_1::points::AttributeArray::Accessor::GetterPtr
T(*)(const AttributeArray *array, const Index n) GetterPtr
Definition: AttributeArray.h:320
openvdb::v5_1::points::TypedAttributeArray::TypedAttributeArray
TypedAttributeArray(Index n=1, Index strideOrTotalSize=1, bool constantStride=true, const ValueType &uniformValue=zeroVal< ValueType >())
Default constructor, always constructs a uniform attribute.
Definition: AttributeArray.h:844
openvdb::v5_1::points::AttributeArray::setConstantStride
void setConstantStride(bool state)
Specify whether this attribute has a constant stride or not.
openvdb::v5_1::IndexError
Definition: Exceptions.h:84
openvdb::v5_1::points::TruncateCodec::Storage
Definition: AttributeArray.h:381
openvdb::v5_1::points::fixedPointToFloatingPoint
FloatVectorT fixedPointToFloatingPoint(const math::Vec3< IntegerT > &v)
Definition: AttributeArray.h:105
openvdb::v5_1::points::FixedPointCodec::name
static const char * name()
Definition: AttributeArray.h:416
openvdb::v5_1::compression::bloscCompressedSize
OPENVDB_API size_t bloscCompressedSize(const char *buffer, const size_t uncompressedBytes)
Convenience wrapper to retrieve the compressed size of buffer when compressed.
openvdb::v5_1::points::UnitVecCodec::Storage::Type
StorageType Type
Definition: AttributeArray.h:428
openvdb::v5_1::points::TypedAttributeArray::readMetadata
void readMetadata(std::istream &) override
Read attribute metadata from a stream.
Definition: AttributeArray.h:1422
openvdb::v5_1::points::UnitVecCodec
Definition: AttributeArray.h:423
openvdb::v5_1::points::NullCodec::name
static const char * name()
Definition: AttributeArray.h:374
openvdb::v5_1::points::TypedAttributeArray::operator=
TypedAttributeArray & operator=(const TypedAttributeArray &)
Deep copy assignment operator.
Definition: AttributeArray.h:912
openvdb::v5_1::Index
Index32 Index
Definition: Types.h:61
openvdb::v5_1::points::AttributeArray::expand
virtual void expand(bool fill=true)=0
If this array is uniform, replace it with an array of length size().
openvdb::v5_1::points::AttributeArray::copyUncompressed
virtual AttributeArray::Ptr copyUncompressed() const =0
Return an uncompressed copy of this attribute (will return a copy if not compressed).
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:188
openvdb::v5_1::compression::PageHandle::Ptr
std::shared_ptr< PageHandle > Ptr
Definition: StreamCompression.h:197
openvdb::v5_1::points::AttributeArray::unregisterType
static void unregisterType(const NamePair &type)
Remove a attribute type from the registry.
openvdb::v5_1::points::AttributeArray::isRegistered
static bool isRegistered(const NamePair &type)
Return true if the given attribute type name is registered.
openvdb::v5_1::points::AccessorEval< UnknownCodec, ValueType >::GetterPtr
ValueType(*)(const AttributeArray *array, const Index n) GetterPtr
Definition: AttributeArray.h:1839
openvdb::v5_1::compression::bloscCompress
OPENVDB_API void bloscCompress(char *compressedBuffer, size_t &compressedBytes, const size_t bufferBytes, const char *uncompressedBuffer, const size_t uncompressedBytes)
Compress into the supplied buffer.
openvdb::v5_1::points::UnknownCodec
Definition: AttributeArray.h:364
openvdb::v5_1::points::PositionRange
Definition: AttributeArray.h:390
openvdb::v5_1::points::TypedAttributeArray::compress
bool compress() override
Compress the attribute array.
Definition: AttributeArray.h:1287
openvdb::v5_1::points::AttributeHandle< StringIndexType, openvdb::v5_1::points::StringCodec< false > >::UniquePtr
std::unique_ptr< Handle > UniquePtr
Definition: AttributeArray.h:649
openvdb::v5_1::points::AccessorEval::GetterPtr
ValueType(*)(const AttributeArray *array, const Index n) GetterPtr
Definition: AttributeArray.h:1818
openvdb::v5_1::tools::composite::max
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:133
openvdb::v5_1::points::UnitRange::name
static const char * name()
Definition: AttributeArray.h:401
openvdb::v5_1::points::PositionRange::encode
static ValueType encode(const ValueType &value)
Definition: AttributeArray.h:393
openvdb::v5_1::points::TypedAttributeArray::Codec
Codec_ Codec
Definition: AttributeArray.h:448
openvdb::v5_1::points::TypedAttributeArray::get
ValueType get(Index n) const
Return the value at index n.
Definition: AttributeArray.h:1086
openvdb::v5_1::points::TypedAttributeArray::size
Index size() const override
Return the number of elements in this array.
Definition: AttributeArray.h:495
openvdb::v5_1::points::AttributeHandle::stride
Index stride() const
Definition: AttributeArray.h:666
openvdb::v5_1::points::AttributeHandle< StringIndexType, openvdb::v5_1::points::StringCodec< false > >::ValuePtr
void(*)(AttributeArray *array, const StringIndexType &value) ValuePtr
Definition: AttributeArray.h:654
openvdb::v5_1::points::attribute_traits::UIntTypeTrait< true, T >::Type
uint8_t Type
Definition: AttributeArray.h:348
Name.h
openvdb::v5_1::points::TypedAttributeArray::copyUncompressed
AttributeArray::Ptr copyUncompressed() const override
Return an uncompressed copy of this attribute (will just return a copy if not compressed).
Definition: AttributeArray.h:1016
openvdb::v5_1::points::TypedAttributeArray::type
const NamePair & type() const override
Return the name of this attribute&#39;s type.
Definition: AttributeArray.h:485
openvdb::v5_1::points::TypedAttributeArray::StorageType
typename Codec::template Storage< ValueType >::Type StorageType
Definition: AttributeArray.h:449
openvdb::v5_1::math::Vec3::z
T & z()
Definition: Vec3.h:112
openvdb::v5_1::math::Vec3::y
T & y()
Definition: Vec3.h:111