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