1 //
2 // Copyright 2016-2019 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_USD_PLUGIN_USD_ABC_ALEMBIC_UTIL_H
25 #define PXR_USD_PLUGIN_USD_ABC_ALEMBIC_UTIL_H
26 
27 /// \file usdAbc/alembicUtil.h
28 
29 #include "pxr/pxr.h"
30 #include "pxr/usd/plugin/usdAbc/alembicReader.h"
31 #include "pxr/usd/sdf/abstractData.h"
32 #include "pxr/usd/sdf/schema.h"
33 #include "pxr/usd/sdf/types.h"
34 #include "pxr/base/vt/array.h"
35 #include "pxr/base/vt/value.h"
36 #include "pxr/base/arch/demangle.h"
37 #include "pxr/base/tf/staticTokens.h"
38 #include <Alembic/Abc/ICompoundProperty.h>
39 #include <Alembic/Abc/ISampleSelector.h>
40 #include <boost/call_traits.hpp>
41 #include <boost/operators.hpp>
42 #include <boost/optional.hpp>
43 #include <boost/shared_array.hpp>
44 #include <boost/shared_ptr.hpp>
45 #include <boost/type_traits/is_same.hpp>
46 #include <boost/type_traits/remove_const.hpp>
47 #include <boost/type_traits/remove_reference.hpp>
48 #include <boost/variant.hpp>
49 
50 #include <functional>
51 #include <algorithm>
52 #include <iosfwd>
53 #include <map>
54 #include <string>
55 #include <vector>
56 
57 
58 namespace Alembic {
59 namespace Util {
60 namespace ALEMBIC_VERSION_NS {
61     template <> struct PODTraitsFromType<PXR_NS::GfHalf>
62         : public Float16PODTraits {};
63 }}}// end namespace Alembic
64 
65 
66 PXR_NAMESPACE_OPEN_SCOPE
67 
68 
69 class SdfAbstractDataValue;
70 
71 /// Flags for readers and writers.
72 #define USDABC_ALEMBIC_CONTEXT_FLAG_NAMES \
73     (verbose) \
74     (expandInstances) \
75     (disableInstancing) \
76     (promoteInstances) \
77     /* end */
78 TF_DECLARE_PUBLIC_TOKENS(UsdAbc_AlembicContextFlagNames,
79                          USDABC_ALEMBIC_CONTEXT_FLAG_NAMES);
80 
81 // A namespace so we can bring Alembic namespaces into it.
82 namespace UsdAbc_AlembicUtil {
83 
84 using namespace ::Alembic::Abc;
85 
86 // Prim type names in the UsdGeom schema except we create new names for
87 // types that don't map directly to Alembic.
88 #define USD_ABC_PRIM_TYPE_NAMES \
89     (BasisCurves) \
90     (Camera) \
91     (HermiteCurves) \
92     (Mesh) \
93     (NurbsCurves) \
94     (Points) \
95     (PolyMesh) \
96     (PseudoRoot) \
97     (Scope) \
98     (Xform) \
99     (GeomSubset)\
100     /* end */
101 TF_DECLARE_PUBLIC_TOKENS(UsdAbcPrimTypeNames, USD_ABC_PRIM_TYPE_NAMES);
102 
103 // Property names in the UsdGeom schema.
104 #define USD_ABC_GPRIM_NAMES \
105     (primvars) \
106     (userProperties) \
107     ((defaultFamilyName, "materialBind")) \
108     ((defaultFamilyTypeAttributeName, "subsetFamily:materialBind:familyType")) \
109     /* end */
110 #define USD_ABC_POINTBASED_NAMES \
111     ((uv, "primvars:uv")) \
112     ((uvIndices, "primvars:uv:indices")) \
113     ((st, "primvars:st")) \
114     ((stIndices, "primvars:st:indices")) \
115     /* end */
116 #define USD_ABC_PROPERTY_NAMES \
117     USD_ABC_GPRIM_NAMES \
118     USD_ABC_POINTBASED_NAMES \
119     /* end */
120 TF_DECLARE_PUBLIC_TOKENS(UsdAbcPropertyNames, USD_ABC_PROPERTY_NAMES);
121 
122 #define USD_ABC_CUSTOM_METADATA \
123     (gprimDataRender) \
124     (riName) \
125     (riType) \
126     (singleSampleAsDefault) \
127     /* end */
128 TF_DECLARE_PUBLIC_TOKENS(UsdAbcCustomMetadata, USD_ABC_CUSTOM_METADATA);
129 
130 //
131 // Alembic property value types.
132 //
133 
134 /// A type to represent an Alembic value type.  An Alembic DataType has
135 /// a POD and extent but not scalar vs array;  this type includes that
136 /// extra bit.  It also supports compound types as their schema titles.
137 struct UsdAbc_AlembicType : boost::totally_ordered<UsdAbc_AlembicType> {
138     PlainOldDataType pod;     // POD type in scalar and array.
139     uint8_t extent;           // Extent of POD (e.g. 3 for a 3-tuple).
140     bool_t array;             // true for array, false otherwise.
141 
142     // An empty type.
143     UsdAbc_AlembicType() :
144         pod(kUnknownPOD), extent(0), array(false)
145     {
146         // Do nothing
147     }
148 
149     // An array or scalar type.
150     UsdAbc_AlembicType(PlainOldDataType pod_, uint8_t extent_, bool_t array_) :
151         pod(pod_), extent(extent_), array(array_)
152     {
153         // Do nothing
154     }
155 
156     // An Alembic property's type.
157     UsdAbc_AlembicType(const PropertyHeader& header) :
158         pod(header.getPropertyType() == kCompoundProperty ?
159                 kUnknownPOD : header.getDataType().getPod()),
160         extent(header.getPropertyType() == kCompoundProperty ?
161                 0 : header.getDataType().getExtent()),
162         array(header.getPropertyType() == kArrayProperty)
163     {
164         // Do nothing
165     }
166 
167     bool IsEmpty() const
168     {
169         return pod == kUnknownPOD;
170     }
171 
172     /// Returns the corresponding Alembic DataType.  This returns the
173     /// unknown type for compound types.
174     DataType GetDataType() const
175     {
176         return DataType(pod, extent);
177     }
178 
179     PropertyType GetPropertyType() const
180     {
181         return array ? kArrayProperty : kScalarProperty;
182     }
183 
184     // Debugging
185     std::string Stringify() const;
186 
187     bool operator==(const UsdAbc_AlembicType& rhs) const;
188     bool operator<(const UsdAbc_AlembicType& rhs) const;
189 };
190 
191 //
192 // Property value wrappers.
193 //
194 
195 /// Wraps a VtValue or SdfAbstractDataValue so we can access any
196 /// the same way.  This type allows us to implement some methods without
197 /// templatizing them.
198 class UsdAbc_AlembicDataAny {
199 public:
200     /// Construct an empty any.
201     UsdAbc_AlembicDataAny() { }
202 
203     /// Construct with a pointer to any supported type-erased object \p any.
204     /// If \p any is \c NULL then this object is considered to be empty.
205     template <class T>
206     explicit UsdAbc_AlembicDataAny(T* any)
207     {
208         if (any) {
209             _valuePtr = any;
210         }
211     }
212 
213     /// Assigns \p rhs to the value passed in the c'tor.
214     bool Set(const VtValue& rhs) const
215     {
216         return boost::apply_visitor(_Set(rhs), _valuePtr);
217     }
218 
219     /// Assigns \p rhs to the value passed in the c'tor.
220     template <class T>
221     bool Set(T rhs) const
222     {
223         typedef typename boost::remove_reference<
224                     typename boost::remove_const<T>::type>::type Type;
225         return boost::apply_visitor(_SetTyped<Type>(rhs), _valuePtr);
226     }
227 
228     /// Returns \c true iff constructed with a NULL pointer.
229     bool IsEmpty() const
230     {
231         return _valuePtr.which() == 0;
232     }
233 
234     /// Explicit bool conversion operator. Converts to true iff this object was
235     /// constructed with a non-NULL pointer.
236     explicit operator bool() const
237     {
238         return !IsEmpty();
239     }
240 
241 private:
242     // Object representing the NULL pointer.
243     class _Empty {};
244 
245     // Visitor for assignment.
246     struct _Set : public boost::static_visitor<bool> {
247         _Set(const VtValue& rhs) : value(rhs) { }
248 
249         bool operator()(_Empty) const
250         {
251             // Convenience for "Has" methods.  Discard the value and
252             // return true.
253             return true;
254         }
255 
256         bool operator()(VtValue* dst) const
257         {
258             *dst = value;
259             return true;
260         }
261 
262         bool operator()(SdfAbstractDataValue* dst) const
263         {
264             return dst->StoreValue(value);
265         }
266 
267         const VtValue& value;
268     };
269 
270     // Visitor for assignment.
271     template <class T>
272     struct _SetTyped : public boost::static_visitor<bool> {
273         _SetTyped(typename boost::call_traits<T>::param_type rhs) : value(rhs){}
274 
275         bool operator()(_Empty) const
276         {
277             // Convenience for "Has" methods.  Discard the value and
278             // return true.
279             return true;
280         }
281 
282         bool operator()(VtValue* dst) const
283         {
284             *dst = value;
285             return true;
286         }
287 
288         bool operator()(SdfAbstractDataValue* dst) const
289         {
290             return dst->StoreValue(value);
291         }
292 
293         typename boost::call_traits<T>::param_type value;
294     };
295 
296 private:
297     boost::variant<_Empty, VtValue*, SdfAbstractDataValue*> _valuePtr;
298 };
299 
300 //
301 // Usd -> Alembic sample
302 //
303 
304 // Helpers for _SampleForAlembic.
305 template <class T>
306 struct _ExtractAddressOfSampleForAlembic {
307     const void* operator()(const T& value) const
308     {
309         return &value;
310     }
311 };
312 template <class T, class A = _ExtractAddressOfSampleForAlembic<T> >
313 struct _ExtractSampleForAlembic {
314     const void* operator()(const VtValue& v, size_t* numSamples) const
315     {
316         *numSamples = 1;
317         return A()(v.UncheckedGet<T>());
318     }
319 };
320 template <class T>
321 struct _ExtractSampleForAlembic<VtArray<T> > {
322     const void* operator()(const VtValue& v, size_t* numSamples) const
323     {
324         const VtArray<T>& result = v.UncheckedGet<VtArray<T> >();
325         *numSamples = result.size();
326         return result.cdata();
327     }
328 };
329 
330 /// Holds a property value from Usd in a form suitable for passing to Alembic,
331 /// providing a common interface to several forms of data.
332 class _SampleForAlembic {
333 public:
334     typedef std::vector<uint32_t> IndexArray;
335     typedef boost::shared_ptr<IndexArray> IndexArrayPtr;
336 
337     class Error {
338     public:
339         Error(const std::string& msg) : message(msg) { }
340         const std::string& message;
341     };
342 
343     /// An empty sample.
344     _SampleForAlembic() :
345         _numSamples(0),
346         _value(_HolderValue(new _EmptyHolder))
347     {
348         // Do nothing
349     }
350 
351     /// A sample in error.  This doesn't have a value but does report an
352     /// error message.
353     _SampleForAlembic(const Error& error) :
354         _numSamples(0),
355         _value(_HolderValue(new _ErrorHolder(error.message)))
356     {
357         // Do nothing
358     }
359 
360     /// A sample using a given scalar value of type T.
361     template <class T>
362     _SampleForAlembic(const T& value) :
363         _numSamples(1),
364         _value(_HolderValue(new _RawHolder<T>(value)))
365     {
366         // Do nothing
367     }
368 
369     /// A sample using a given std::vector of values of type T.
370     template <class T>
371     _SampleForAlembic(const std::vector<T>& value) :
372         _numSamples(value.size()),
373         _value(_MakeRawArrayHolder(value))
374     {
375         // Do nothing
376     }
377 
378     /// A sample using raw data from a VtValue holding a value extracted
379     /// by \p extractor, which must have the function signature:
380     /// const void* ()(const VtValue&, size_t* numSamples).
381     /// It must return a pointer into the data in the value and set
382     /// the numSamples argument to the number of samples in the value.
383     template <class E>
384     _SampleForAlembic(const VtValue& value, const E& extractor) :
385         _value(_HolderValue(new _VtValueHolder(value, &_numSamples, extractor)))
386     {
387         // Do nothing
388     }
389 
390     /// A sample using raw data from a shared pointer to a T.
391     template <class T>
392     _SampleForAlembic(const boost::shared_ptr<T>& value) :
393         _numSamples(1),
394         _value(_HolderValue(new _ScalarHolder<T>(value)))
395     {
396         TF_VERIFY(value);
397     }
398 
399     /// A sample using raw data from a shared pointer to a T[].
400     template <class T>
401     _SampleForAlembic(const boost::shared_array<T>& values, size_t count) :
402         _numSamples(count),
403         _value(_HolderValue(new _ArrayHolder<T>(values)))
404     {
405         TF_VERIFY(values);
406     }
407 
408     bool IsError(std::string* message) const
409     {
410         return _value.IsError(message);
411     }
412 
413     /// Explicit bool conversion operator. Converts to \c true iff the data is
414     /// valid.
415     explicit operator bool() const
416     {
417         return _IsValid();
418     }
419 
420     /// Returns the raw data.
421     const void* GetData() const
422     {
423         return _value.Get();
424     }
425 
426     /// Returns the raw data cast to a const T*.  Do not call if this object
427     /// evaluates to \c false.
428     template <class T>
429     const T* GetDataAs() const
430     {
431         return reinterpret_cast<const T*>(_value.Get());
432     }
433 
434     /// Returns the number of POD elements.
435     size_t GetCount() const
436     {
437         return _numSamples;
438     }
439 
440     /// Saves the given indices.
441     void SetIndices(const IndexArrayPtr& indices)
442     {
443         _indices = indices;
444     }
445 
446     /// Returns the vector of indices last set by \c SetIndices().
447     IndexArrayPtr GetIndices() const
448     {
449         return _indices;
450     }
451 
452 private:
453     bool _IsValid() const
454     {
455         return _value.Get();
456     }
457 
458     // Type erased holder for pointers.
459     class _Holder {
460     public:
461         virtual ~_Holder();
462         virtual const void* Get() const = 0;
463         virtual bool Error(std::string*) const;
464     };
465 
466     // Hold nothing.
467     class _EmptyHolder : public _Holder {
468     public:
469         _EmptyHolder();
470         virtual ~_EmptyHolder();
471         virtual const void* Get() const { return NULL; }
472     };
473 
474     // Hold an error and no sample.
475     class _ErrorHolder : public _Holder {
476     public:
477         _ErrorHolder(const std::string& message);
478         virtual ~_ErrorHolder();
479         virtual const void* Get() const { return NULL; }
480         virtual bool Error(std::string*) const;
481 
482     private:
483         std::string _message;
484     };
485 
486     // Hold nothing.
487     template <class T>
488     class _RawHolder : public _Holder {
489     public:
490         _RawHolder(const T& value) : _value(value) { }
491         virtual ~_RawHolder() { }
492         virtual const void* Get() const { return &_value; }
493 
494     private:
495         const T _value;
496     };
497 
498     // Hold a VtValue.
499     class _VtValueHolder : public _Holder {
500     public:
501         template <class E>
502         _VtValueHolder(const VtValue& value,
503                        size_t* numSamples, const E& extractor) :
504             _value(new VtValue(value)),
505             _ptr(extractor(*_value, numSamples)) { }
506         virtual ~_VtValueHolder();
507         virtual const void* Get() const { return _ptr; }
508 
509     private:
510         boost::shared_ptr<VtValue> _value;
511         const void* _ptr;
512     };
513 
514     // Hold a shared_ptr.
515     template <class T>
516     class _ScalarHolder : public _Holder {
517     public:
518         _ScalarHolder(const boost::shared_ptr<T>& ptr) : _ptr(ptr) { }
519         virtual ~_ScalarHolder() { }
520         virtual const void* Get() const { return _ptr.get(); }
521 
522     private:
523         boost::shared_ptr<T> _ptr;
524     };
525 
526     // Hold a shared_array.
527     template <class T>
528     class _ArrayHolder : public _Holder {
529     public:
530         _ArrayHolder(const boost::shared_array<T>& ptr) : _ptr(ptr) { }
531         virtual ~_ArrayHolder() { }
532         virtual const void* Get() const { return _ptr.get(); }
533 
534     private:
535         boost::shared_array<T> _ptr;
536     };
537 
538     // Hold a _Holder as a value type.
539     class _HolderValue {
540     public:
541         explicit _HolderValue(_Holder* holder) : _holder(holder) { }
542 
543         const void* Get() const { return _holder->Get(); }
544         bool IsError(std::string* msg) const { return _holder->Error(msg); }
545 
546     private:
547         boost::shared_ptr<_Holder> _holder;
548     };
549 
550     template <class T>
551     static _HolderValue _MakeRawArrayHolder(const std::vector<T>& value)
552     {
553         boost::shared_array<T> copy(new T[value.size()]);
554         std::copy(value.begin(), value.end(), copy.get());
555         return _HolderValue(new _ArrayHolder<T>(copy));
556     }
557 
558 private:
559     size_t _numSamples;
560     _HolderValue _value;
561     IndexArrayPtr _indices;
562 };
563 
564 _SampleForAlembic _ErrorSampleForAlembic(const std::string& msg);
565 
566 /// Create an _SampleForAlembic pointing to the raw data in a VtValue.
567 /// This assumes the VtValue is holding a value of type UsdType.
568 template <class UsdType>
569 struct _SampleForAlembicIdentityConverter {
570     _SampleForAlembic operator()(const VtValue& value) const
571     {
572         return _SampleForAlembic(value, _ExtractSampleForAlembic<UsdType>());
573     }
574 };
575 
576 /// Create an _SampleForAlembic from a VtValue converted by construction
577 /// to the Alembic type.  This assumes the VtValue is holding a value of
578 /// type UsdType.
579 template <class UsdType, class AlembicType>
580 struct _SampleForAlembicConstructConverter {
581     _SampleForAlembic operator()(const VtValue& value) const
582     {
583         return _SampleForAlembic(boost::shared_ptr<AlembicType>(
584             new AlembicType(value.UncheckedGet<UsdType>())));
585     }
586 };
587 // Special case to identity converter.
588 template <class U>
589 struct _SampleForAlembicConstructConverter<U, U> :
590     public _SampleForAlembicIdentityConverter<U> {
591 };
592 
593 //
594 // Alembic <-> Usd POD conversions.
595 //
596 
597 //
598 // POD conversion to Usd.
599 //
600 
601 template <class UsdType, class AlembicType, size_t extent>
602 struct _ConvertPODToUsd { };
603 
604 // No conversion necessary.
605 template <class UsdType>
606 struct _ConvertPODToUsd<UsdType, UsdType, 1> {
607     const UsdType& operator()(const void* data) const
608     {
609         return *reinterpret_cast<const UsdType*>(data);
610     }
611 };
612 
613 // Conversion by construction.
614 template <class UsdType, class AlembicType>
615 struct _ConvertPODToUsd<UsdType, AlembicType, 1> {
616     UsdType operator()(const void* data) const
617     {
618         return UsdType(*reinterpret_cast<const AlembicType*>(data));
619     }
620 };
621 
622 // Construct vector.
623 template <class UsdType>
624 struct _ConvertPODToUsdVec {
625     UsdType operator()(const void* data) const
626     {
627         typedef typename UsdType::ScalarType ScalarType;
628         return UsdType(reinterpret_cast<const ScalarType*>(data));
629     }
630 };
631 template <>
632 struct _ConvertPODToUsd<GfVec2i, int32_t,   2> : _ConvertPODToUsdVec<GfVec2i>{};
633 template <>
634 struct _ConvertPODToUsd<GfVec2h, GfHalf,    2> : _ConvertPODToUsdVec<GfVec2h>{};
635 template <>
636 struct _ConvertPODToUsd<GfVec2f, float32_t, 2> : _ConvertPODToUsdVec<GfVec2f>{};
637 template <>
638 struct _ConvertPODToUsd<GfVec2d, float64_t, 2> : _ConvertPODToUsdVec<GfVec2d>{};
639 template <>
640 struct _ConvertPODToUsd<GfVec3i, int32_t,   3> : _ConvertPODToUsdVec<GfVec3i>{};
641 template <>
642 struct _ConvertPODToUsd<GfVec3h, GfHalf,    3> : _ConvertPODToUsdVec<GfVec3h>{};
643 template <>
644 struct _ConvertPODToUsd<GfVec3f, float32_t, 3> : _ConvertPODToUsdVec<GfVec3f>{};
645 template <>
646 struct _ConvertPODToUsd<GfVec3d, float64_t, 3> : _ConvertPODToUsdVec<GfVec3d>{};
647 template <>
648 struct _ConvertPODToUsd<GfVec4i, int32_t,   4> : _ConvertPODToUsdVec<GfVec4i>{};
649 template <>
650 struct _ConvertPODToUsd<GfVec4h, GfHalf,    4> : _ConvertPODToUsdVec<GfVec4h>{};
651 template <>
652 struct _ConvertPODToUsd<GfVec4f, float32_t, 4> : _ConvertPODToUsdVec<GfVec4f>{};
653 template <>
654 struct _ConvertPODToUsd<GfVec4d, float64_t, 4> : _ConvertPODToUsdVec<GfVec4d>{};
655 
656 // Construct quaternion.
657 // Note: Imath quaternions are stored as (r, i0, i1, i2) whereas the Gf
658 // versions are stored as (i0, i1, i2, r)
659 template <>
660 struct _ConvertPODToUsd<GfQuatf, float32_t, 4> {
661     GfQuatf operator()(const void* data) const
662     {
663         const float32_t* src = reinterpret_cast<const float32_t*>(data);
664         GfVec3f imaginary(src[1], src[2], src[3]);
665         return GfQuatf(src[0], imaginary);
666     }
667 };
668 
669 template <>
670 struct _ConvertPODToUsd<GfQuatd, float64_t, 4> {
671     GfQuatd operator()(const void* data) const
672     {
673         const float64_t* src = reinterpret_cast<const float64_t*>(data);
674         GfVec3d imaginary(src[1], src[2], src[3]);
675         return GfQuatd(src[0], imaginary);
676     }
677 };
678 
679 
680 // Construct matrix.
681 template <>
682 struct _ConvertPODToUsd<GfMatrix4d, float32_t, 16> {
683     GfMatrix4d operator()(const void* data) const
684     {
685         float64_t buffer[4][4];
686         const float32_t* src = reinterpret_cast<const float32_t*>(data);
687         std::copy(src, src + 16, &buffer[0][0]);
688         return GfMatrix4d(buffer);
689     }
690 };
691 template <>
692 struct _ConvertPODToUsd<GfMatrix4d, float64_t, 16> {
693     GfMatrix4d operator()(const void* data) const
694     {
695         return GfMatrix4d(reinterpret_cast<const float64_t(*)[4]>(data));
696     }
697 };
698 
699 // Copy an array -- general case.
700 template <class UsdType, class AlembicType, size_t extent>
701 struct _ConvertPODToUsdArray {
702     void operator()(UsdType* dst, const void* src, size_t size)
703     {
704         const uint8_t* typedSrc = reinterpret_cast<const uint8_t*>(src);
705         const size_t step = extent * sizeof(AlembicType);
706         for (size_t i = 0, n = size; i != n; typedSrc += step, ++i) {
707             dst[i] = _ConvertPODToUsd<UsdType, AlembicType, extent>()(typedSrc);
708         }
709     }
710 };
711 
712 // Copy an array -- no conversion necessary.
713 template <class UsdType>
714 struct _ConvertPODToUsdArray<UsdType, UsdType, 1> {
715     void operator()(UsdType* dst, const void* src, size_t size)
716     {
717         const UsdType* typedSrc = reinterpret_cast<const UsdType*>(src);
718         std::copy(typedSrc, typedSrc + size, dst);
719     }
720 };
721 
722 //
723 // POD conversion from Usd.
724 //
725 
726 template <class UsdType, class AlembicType, size_t extent>
727 struct _ConvertPODFromUsd { };
728 
729 // No conversion necessary.
730 template <class UsdType>
731 struct _ConvertPODFromUsd<UsdType, UsdType, 1> {
732     void operator()(const UsdType& src, UsdType* dst) const
733     {
734         *dst = src;
735     }
736 };
737 
738 // Conversion by construction.
739 template <class UsdType, class AlembicType>
740 struct _ConvertPODFromUsd<UsdType, AlembicType, 1> {
741     void operator()(const UsdType& src, AlembicType* dst) const
742     {
743         *dst = AlembicType(src);
744     }
745 };
746 
747 // Conversion for TfToken to std::string.
748 template <>
749 struct _ConvertPODFromUsd<TfToken, std::string, 1> {
750     void operator()(const TfToken& src, std::string* dst) const
751     {
752         *dst = src.GetString();
753     }
754 };
755 
756 // Construct vector.
757 template <class UsdType>
758 struct _ConvertPODFromUsdVec {
759     void operator()(const UsdType& src, typename UsdType::ScalarType* dst) const
760     {
761         std::copy(src.GetArray(), src.GetArray() + UsdType::dimension, dst);
762     }
763 };
764 template <>
765 struct _ConvertPODFromUsd<GfVec2i, int32_t,   2> :
766     _ConvertPODFromUsdVec<GfVec2i> { };
767 template <>
768 struct _ConvertPODFromUsd<GfVec2h, GfHalf,    2> :
769     _ConvertPODFromUsdVec<GfVec2h> { };
770 template <>
771 struct _ConvertPODFromUsd<GfVec2f, float32_t, 2> :
772     _ConvertPODFromUsdVec<GfVec2f> { };
773 template <>
774 struct _ConvertPODFromUsd<GfVec2d, float64_t, 2> :
775     _ConvertPODFromUsdVec<GfVec2d> { };
776 template <>
777 struct _ConvertPODFromUsd<GfVec3i, int32_t,   3> :
778     _ConvertPODFromUsdVec<GfVec3i> { };
779 template <>
780 struct _ConvertPODFromUsd<GfVec3h, GfHalf,    3> :
781     _ConvertPODFromUsdVec<GfVec3h> { };
782 template <>
783 struct _ConvertPODFromUsd<GfVec3f, float32_t, 3> :
784     _ConvertPODFromUsdVec<GfVec3f> { };
785 template <>
786 struct _ConvertPODFromUsd<GfVec3d, float64_t, 3> :
787     _ConvertPODFromUsdVec<GfVec3d> { };
788 template <>
789 struct _ConvertPODFromUsd<GfVec4i, int32_t,   4> :
790     _ConvertPODFromUsdVec<GfVec4i> { };
791 template <>
792 struct _ConvertPODFromUsd<GfVec4h, GfHalf,    4> :
793     _ConvertPODFromUsdVec<GfVec4h> { };
794 template <>
795 struct _ConvertPODFromUsd<GfVec4f, float32_t, 4> :
796     _ConvertPODFromUsdVec<GfVec4f> { };
797 template <>
798 struct _ConvertPODFromUsd<GfVec4d, float64_t, 4> :
799     _ConvertPODFromUsdVec<GfVec4d> { };
800 
801 // Construct quaternion.
802 // Note: Imath quaternions are stored as (r, i0, i1, i2) whereas the Gf
803 // versions are stored as (i0, i1, i2, r)
804 template <>
805 struct _ConvertPODFromUsd<GfQuatf, float32_t, 4> {
806     void operator()(const GfQuatf& src, float32_t* dst) const
807     {
808         dst[0] = src.GetReal();
809         dst[1] = src.GetImaginary()[0];
810         dst[2] = src.GetImaginary()[1];
811         dst[3] = src.GetImaginary()[2];
812     }
813 };
814 
815 template <>
816 struct _ConvertPODFromUsd<GfQuatd, float64_t, 4> {
817     void operator()(const GfQuatd& src, float64_t* dst) const
818     {
819         dst[0] = src.GetReal();
820         dst[1] = src.GetImaginary()[0];
821         dst[2] = src.GetImaginary()[1];
822         dst[3] = src.GetImaginary()[2];
823     }
824 };
825 
826 // Construct matrix.
827 template <>
828 struct _ConvertPODFromUsd<GfMatrix4d, float32_t, 16> {
829     void operator()(const GfMatrix4d& src, float32_t* dst) const
830     {
831         std::copy(src.GetArray(), src.GetArray() + 16, dst);
832     }
833 };
834 template <>
835 struct _ConvertPODFromUsd<GfMatrix4d, float64_t, 16> {
836     void operator()(const GfMatrix4d& src, float64_t* dst) const
837     {
838         std::copy(src.GetArray(), src.GetArray() + 16, dst);
839     }
840 };
841 
842 // Copy a scalar -- general case.
843 template <class UsdType, class AlembicType, size_t extent>
844 struct _ConvertPODFromUsdScalar {
845     _SampleForAlembic operator()(const VtValue& src) const
846     {
847         boost::shared_array<AlembicType> dst(new AlembicType[extent]);
848         _ConvertPODFromUsd<UsdType, AlembicType, extent>()(
849                 src.UncheckedGet<UsdType>(), dst.get());
850         return _SampleForAlembic(dst, extent);
851     }
852 };
853 
854 // Copy a scalar -- POD.
855 template <class UsdType, class AlembicType>
856 struct _ConvertPODFromUsdScalar<UsdType, AlembicType, 1> {
857     _SampleForAlembic operator()(const VtValue& src) const
858     {
859         AlembicType dst;
860         _ConvertPODFromUsd<UsdType, AlembicType, 1>()(
861                 src.UncheckedGet<UsdType>(), &dst);
862         return _SampleForAlembic(dst);
863     }
864 };
865 
866 // Copy an array -- general case.
867 template <class UsdType, class AlembicType, size_t extent>
868 struct _ConvertPODFromUsdArray {
869     _SampleForAlembic operator()(const VtValue& src)
870     {
871         const VtArray<UsdType>& data = src.UncheckedGet<VtArray<UsdType> >();
872         const size_t size = data.size();
873         boost::shared_array<AlembicType> array(new AlembicType[size * extent]);
874         AlembicType* ptr = array.get();
875         for (size_t i = 0, n = size; i != n; ptr += extent, ++i) {
876             _ConvertPODFromUsd<UsdType, AlembicType, extent>()(data[i], ptr);
877         }
878         return _SampleForAlembic(array, size * extent);
879     }
880 };
881 
882 //
883 // Alembic <-> Usd conversion registries.
884 //
885 
886 template <class UsdType, class AlembicType, size_t extent>
887 struct _ConvertPODScalar;
888 template <class UsdType, class AlembicType, size_t extent>
889 struct _ConvertPODArray;
890 
891 /// Holds a dictionary of property value conversions.  It can apply the
892 /// appropriate conversion to a given property and store the result.
893 class UsdAbc_AlembicDataConversion {
894 public:
895     /// A conversion function.  Returns \c true on success and copies the
896     /// value from the named property in the compound property at the given
897     /// sample selector to the \c UsdAbc_AlembicDataAny value.  The converter
898     /// can assume the property has the type that the converter was keyed by.
899     typedef std::function<bool (const ICompoundProperty&,
900                                 const std::string&,
901                                 const ISampleSelector&,
902                                 const UsdAbc_AlembicDataAny&)> ToUsdConverter;
903 
904     /// A reverse conversion function (Usd -> Alembic).  Returns the value
905     /// as a \c _SampleForAlembic.  The converter can assume the VtValue
906     /// is holding the expected type.
907     typedef std::function<_SampleForAlembic(const VtValue&)> FromUsdConverter;
908 
909     UsdAbc_AlembicDataConversion();
910 
911     /// Register converters between \p UsdType and \p AlembicType with
912     /// extent \p extent.  Note that this will not register a conversion
913     /// that's already been registered.  This is useful to register a
914     /// preferred conversion when there's a many-to-one mapping.
915     template <class UsdType, class AlembicType, size_t extent>
916     void AddConverter(const SdfValueTypeName& usdType)
917     {
918         const PlainOldDataType pod = PODTraitsFromType<AlembicType>::pod_enum;
919         _AddConverter(UsdAbc_AlembicType(pod, extent, false),
920                       usdType,
921                       _ConvertPODScalar<UsdType, AlembicType, extent>(),
922                       _ConvertPODScalar<UsdType, AlembicType, extent>());
923         _AddConverter(UsdAbc_AlembicType(pod, extent, true),
924                       usdType.GetArrayType(),
925                       _ConvertPODArray<UsdType, AlembicType, extent>(),
926                       _ConvertPODArray<UsdType, AlembicType, extent>());
927     }
928 
929     /// Register converters between \p UsdType and \p AlembicType with
930     /// extent \p extent.  Note that this will not register a conversion
931     /// that's already been registered.  This is useful to register a
932     /// preferred conversion when there's a many-to-one mapping.
933     template <class UsdType, class AlembicType, size_t extent>
934     void AddConverter()
935     {
936         AddConverter<UsdType, AlembicType, extent>(
937             SdfSchema::GetInstance().FindType(TfType::Find<UsdType>()));
938     }
939 
940     template <class UsdType, class AlembicType>
941     void AddConverter(const SdfValueTypeName& usdType)
942     {
943         AddConverter<UsdType, AlembicType, 1>(usdType);
944     }
945 
946     template <class UsdType, class AlembicType>
947     void AddConverter()
948     {
949         AddConverter<UsdType, AlembicType, 1>();
950     }
951 
952     /// Returns the Usd type we create by default from the Alembic type
953     /// \p alembicType.  Returns an empty token if there is no such
954     /// converter.
955     SdfValueTypeName FindConverter(const UsdAbc_AlembicType& alembicType) const;
956 
957     /// Returns a to-Usd converter that is fully specified (exactly matching
958     /// alembicType and usdType).
959     const ToUsdConverter& GetToUsdConverter(
960         const UsdAbc_AlembicType& alembicType,
961         const SdfValueTypeName& usdType) const;
962 
963     /// Returns a pointer to the default (reversible) converter for the
964     /// given Usd type, or \c NULL if there's no such converter.
965     UsdAbc_AlembicType FindConverter(const SdfValueTypeName& usdType) const;
966 
967     /// Returns the reverse converter for the given key.
968     const FromUsdConverter& GetConverter(const SdfValueTypeName& usdType) const;
969 
970 private:
971     void _AddConverter(const UsdAbc_AlembicType& alembicType,
972                        const SdfValueTypeName& usdType,
973                        const ToUsdConverter&, const FromUsdConverter&);
974 
975 private:
976 
977     // All the data that we need to convert between usd and abc types.
978     struct _ConverterData {
979         _ConverterData(const SdfValueTypeName &usdType_,
980                        const UsdAbc_AlembicType &abcType_,
981                        const ToUsdConverter &toUsdFn_,
982                        const FromUsdConverter &fromUsdFn_)
983         : usdType(usdType_)
984         , abcType(abcType_)
985         , toUsdFn(toUsdFn_)
986         , fromUsdFn(fromUsdFn_)
987         { }
988 
989         SdfValueTypeName usdType;
990         UsdAbc_AlembicType abcType;
991         ToUsdConverter toUsdFn;
992         FromUsdConverter fromUsdFn;
993     };
994 
995     // All the type converters that we have registered.
996     std::vector<_ConverterData> _typeConverters;
997 };
998 
999 /// All conversions.  This exists so we can construct all conversion types
1000 /// as a single object for convenience with TfStaticData.
1001 struct UsdAbc_AlembicConversions {
1002     UsdAbc_AlembicConversions();
1003 
1004     UsdAbc_AlembicDataConversion data;
1005 };
1006 
1007 //
1008 // Utilities
1009 //
1010 
1011 /// Format an Alembic version number as a string.
1012 std::string
1013 UsdAbc_FormatAlembicVersion(int32_t n);
1014 
1015 /// Reverse the order of the subsequences in \p values where the subsequence
1016 /// lengths are given by \p counts.
1017 template <class T>
1018 static bool
1019 UsdAbc_ReverseOrderImpl(
1020     VtArray<T>& values,
1021     const VtArray<int>& counts)
1022 {
1023     // Reverse items.
1024     for (size_t j = 0, n = values.size(),
1025             k = 0, m = counts.size(); k != m; ++k) {
1026         const int count = counts[k];
1027 
1028         // Bail out with failure if we run out of items.
1029         if (!TF_VERIFY(j + count <= n)) {
1030             return false;
1031         }
1032 
1033         // Reverse the range.
1034         std::reverse(values.begin() + j, values.begin() + j + count);
1035 
1036         // Next range.
1037         j += count;
1038     }
1039     return true;
1040 }
1041 
1042 } // namespace UsdAbc_AlembicUtil
1043 
1044 
1045 PXR_NAMESPACE_CLOSE_SCOPE
1046 
1047 #endif // PXR_USD_PLUGIN_USD_ABC_ALEMBIC_UTIL_H
1048