#ifndef _CacheReaderAlembic_h_
#define _CacheReaderAlembic_h_
#include <maya/cxx17_enter_legacy_scope.hpp>
#include <Alembic/AbcCoreAbstract/TimeSampling.h>
#include <Alembic/Abc/IArchive.h>
#include <Alembic/AbcGeom/INuPatch.h>
#include <Alembic/AbcGeom/IPolyMesh.h>
#include <Alembic/AbcGeom/ISubD.h>
#include <Alembic/AbcGeom/IXform.h>
#include <Alembic/AbcMaterial/IMaterial.h>
#include <Alembic/AbcMaterial/MaterialAssignment.h>
#include <maya/cxx17_exit_legacy_scope.hpp>
#include "CacheReader.h"
#include <maya/MString.h>
#include <maya/MTime.h>
#include <maya/MFileObject.h>
#include <maya/MFnMesh.h>
#include <maya/MFnMeshData.h>
#include <maya/MFnNurbsSurface.h>
#include <maya/MFnNurbsSurfaceData.h>
#include <unordered_map>
#include <memory>
#include <map>
namespace GPUCache {
class AlembicCacheReader;
namespace CacheReaderAlembicPrivate {
class AlembicCacheMeshReader;
typedef Alembic::Abc::index_t index_t;
typedef Alembic::Abc::chrono_t chrono_t;
typedef Alembic::AbcGeom::IXformSchema IXformSchema;
typedef Alembic::AbcGeom::XformSample XformSample;
typedef Alembic::AbcGeom::XformOp XformOp;
typedef Alembic::AbcCoreAbstract::TimeSamplingPtr TimeSamplingPtr;
template <class ElemType>
struct BaseTypeOfElem
{
typedef ElemType value_type;
static const size_t kDimensions = 1;
};
template <>
struct BaseTypeOfElem<int32_t>
{
typedef uint32_t value_type;
static const size_t kDimensions = 1;
};
template <class T>
struct BaseTypeOfElem<Imath::Vec2<T> >
{
typedef T value_type;
static const size_t kDimensions = 2;
};
template <class T>
struct BaseTypeOfElem<Imath::Vec3<T> >
{
typedef T value_type;
static const size_t kDimensions = 3;
};
template <class ArrayProperty>
class AlembicArray :
public ReadableArray<
typename BaseTypeOfElem<
typename ArrayProperty::traits_type::value_type
>::value_type
>
{
public:
typedef typename ArrayProperty::sample_ptr_type ArraySamplePtr;
typedef typename ArrayProperty::traits_type traits_type;
typedef typename BaseTypeOfElem<typename traits_type::value_type>::value_type T;
typedef typename Array<T>::Digest Digest;
static const size_t kDimensions =
BaseTypeOfElem<typename traits_type::value_type>::kDimensions;
static std::shared_ptr<ReadableArray<T> > create(
const ArraySamplePtr& arraySamplePtr, const Digest& digest );
~AlembicArray() override;
const T* get() const override;
private:
struct MakeSharedEnabler;
AlembicArray(
const ArraySamplePtr& arraySamplePtr, const Digest& digest
)
: ReadableArray<T>(
arraySamplePtr->size() * kDimensions, digest),
fArraySamplePtr(arraySamplePtr)
{
assert(traits_type::dataType().getExtent() == kDimensions);
}
const ArraySamplePtr fArraySamplePtr;
};
template <typename PROPERTY, typename KEY, typename VALUE, typename DERIVED>
class PropertyCache
{
public:
typedef PROPERTY Property;
typedef KEY Key;
typedef VALUE Value;
typedef DERIVED Derived;
PropertyCache()
: fValidityInterval(TimeInterval::kInvalid)
{}
void reset()
{
fProperty = Property();
fValidityInterval = TimeInterval(TimeInterval::kInvalid);
fValue = Value();
}
bool valid() const
{
return fProperty.valid();
}
void init(const Property& property)
{
this->fProperty = property;
const index_t numSamples = this->fProperty.getNumSamples();
const TimeSamplingPtr sampling = this->fProperty.getTimeSampling();
if (this->fProperty.isConstant()) {
fValidityInterval = TimeInterval(TimeInterval::kInvalid);
}
else {
this->fUniqueSampleIndexes.push_back(0);
this->fTimeBoundaries.push_back(-std::numeric_limits<chrono_t>::infinity());
Key prevKey;
static_cast<Derived*>(this)->getKey(prevKey, 0);
for (index_t i=1; i<numSamples; ++i) {
Key key;
static_cast<Derived*>(this)->getKey(key, i);
if (key != prevKey) {
this->fUniqueSampleIndexes.push_back(i);
this->fTimeBoundaries.push_back(
0.5 * (sampling->getSampleTime(i-1) + sampling->getSampleTime(i))
);
prevKey = key;
}
}
this->fTimeBoundaries.push_back(+std::numeric_limits<chrono_t>::infinity());
}
}
bool setTime(chrono_t time)
{
if (fProperty.isConstant())
{
if (!fValidityInterval.valid()) {
static_cast<Derived*>(this)->readValue(0);
fValidityInterval = TimeInterval(TimeInterval::kInfinite);
}
return false;
}
if (fValidityInterval.contains(time)) {
return false;
}
std::vector<chrono_t>::const_iterator bgn = fTimeBoundaries.begin();
std::vector<chrono_t>::const_iterator end = fTimeBoundaries.end();
std::vector<chrono_t>::const_iterator it = std::upper_bound(
bgn, end, time);
assert(it != bgn);
index_t idx = fUniqueSampleIndexes[std::distance(bgn, it) - 1];
static_cast<Derived*>(this)->readValue(idx);
fValidityInterval = TimeInterval(*(it-1), *it);
return true;
}
const Value& getValue() const
{
return fValue;
}
TimeInterval getValidityInterval() const
{
return fValidityInterval;
}
protected:
Property fProperty;
std::vector<index_t> fUniqueSampleIndexes;
std::vector<chrono_t> fTimeBoundaries;
TimeInterval fValidityInterval;
Value fValue;
};
template <typename PROPERTY>
class ScalarPropertyCache
: public PropertyCache<
PROPERTY,
typename PROPERTY::value_type,
typename PROPERTY::value_type,
ScalarPropertyCache<PROPERTY>
>
{
public:
typedef PropertyCache<
PROPERTY,
typename PROPERTY::value_type,
typename PROPERTY::value_type,
ScalarPropertyCache<PROPERTY>
> BaseClass;
typedef typename BaseClass::Key Key;
void readValue(index_t idx)
{
getKey(this->fValue, idx);
}
void getKey(Key& key, index_t idx)
{
this->fProperty.get(key, idx);
}
};
class XformPropertyCache
: public PropertyCache<
IXformSchema,
MMatrix,
MMatrix,
XformPropertyCache
>
{
public:
void readValue(index_t idx)
{
getKey(fValue, idx);
}
void getKey(Key& key, index_t idx)
{
XformSample sample;
fProperty.get(sample, idx);
key = toMatrix(sample);
}
private:
static MMatrix toMatrix(
const XformSample& sample)
{
Alembic::Abc::M44d matrix = sample.getMatrix();
}
};
template <typename PROPERTY>
class ArrayPropertyCache
: public PropertyCache<
PROPERTY,
Alembic::AbcCoreAbstract::ArraySampleKey,
std::shared_ptr<
ReadableArray<
typename BaseTypeOfElem<
typename PROPERTY::traits_type::value_type
>::value_type> >,
ArrayPropertyCache<PROPERTY>
>
{
public:
typedef PropertyCache<
PROPERTY,
Alembic::AbcCoreAbstract::ArraySampleKey,
std::shared_ptr<
ReadableArray<
typename BaseTypeOfElem<
typename PROPERTY::traits_type::value_type
>::value_type> >,
ArrayPropertyCache<PROPERTY>
> BaseClass;
typedef typename BaseClass::Property Property;
typedef typename BaseClass::Key Key;
typedef typename BaseClass::Value Value;
typedef typename Property::sample_ptr_type ArraySamplePtr;
typedef typename Property::traits_type traits_type;
typedef typename BaseTypeOfElem<typename traits_type::value_type>::value_type BaseType;
static const size_t kDimensions =
BaseTypeOfElem<typename traits_type::value_type>::kDimensions;
void readValue(index_t idx)
{
Key key;
getKey(key, idx);
assert(key.origPOD == key.readPOD);
assert(key.origPOD == traits_type::dataType().getPod());
assert(sizeof(BaseType) == PODNumBytes(traits_type::dataType().getPod()));
assert(kDimensions == traits_type::dataType().getExtent());
const size_t size = size_t(key.numBytes / sizeof(BaseType));
this->fValue = Value();
{
std::lock_guard<std::mutex> lock(ArrayRegistry<BaseType>::mutex());
this->fValue = ArrayRegistry<BaseType>::lookupReadable(key.digest, size);
if (this->fValue) return;
}
ArraySamplePtr sample;
this->fProperty.get(sample, idx);
#ifndef NDEBUG
Key key2 = sample->getKey();
const size_t size2 = (sample->size() *
Property::traits_type::dataType().getExtent());
assert(key == key2);
assert(size == size2);
#endif
this->fValue = AlembicArray<Property>::create(sample, key.digest);
}
void getKey(Key& key, index_t idx)
{
#ifndef NDEBUG
bool result =
#endif
this->fProperty.getKey(key, idx);
assert(result);
}
};
template <typename PROPERTY>
class ArrayPropertyCacheWithConverter
: public PropertyCache<
PROPERTY,
Alembic::AbcCoreAbstract::ArraySampleKey,
std::shared_ptr<
ReadableArray<
typename BaseTypeOfElem<
typename PROPERTY::traits_type::value_type
>::value_type> >,
ArrayPropertyCacheWithConverter<PROPERTY>
>
{
public:
typedef PropertyCache<
PROPERTY,
Alembic::AbcCoreAbstract::ArraySampleKey,
std::shared_ptr<
ReadableArray<
typename BaseTypeOfElem<
typename PROPERTY::traits_type::value_type
>::value_type> >,
ArrayPropertyCacheWithConverter<PROPERTY>
> BaseClass;
typedef typename BaseClass::Property Property;
typedef typename BaseClass::Key Key;
typedef typename BaseClass::Value Value;
typedef typename Property::sample_ptr_type ArraySamplePtr;
typedef typename Property::traits_type traits_type;
typedef typename BaseTypeOfElem<typename traits_type::value_type>::value_type BaseType;
typedef Alembic::Util::Digest Digest;
typedef std::shared_ptr<ReadableArray<BaseType> >
(*Converter)(const typename PROPERTY::sample_ptr_type& sample);
static const size_t kDimensions =
BaseTypeOfElem<typename traits_type::value_type>::kDimensions;
ArrayPropertyCacheWithConverter(Converter converter)
: fConverter(converter)
{}
void readValue(index_t idx)
{
Key key;
getKey(key, idx);
assert(key.origPOD == key.readPOD);
assert(key.origPOD == traits_type::dataType().getPod());
assert(sizeof(BaseType) == PODNumBytes(traits_type::dataType().getPod()));
assert(kDimensions == traits_type::dataType().getExtent());
const size_t size = size_t(key.numBytes / sizeof(BaseType));
this->fValue = Value();
typename ConvertionMap::const_iterator it = fsConvertionMap.find(key.digest);
if (it != fsConvertionMap.end()) {
std::lock_guard<std::mutex> lock(ArrayRegistry<BaseType>::mutex());
this->fValue = ArrayRegistry<BaseType>::lookupReadable(it->second, size);
if (this->fValue) return;
}
ArraySamplePtr sample;
this->fProperty.get(sample, idx);
#ifndef NDEBUG
Key key2 = sample->getKey();
const size_t size2 = (sample->size() *
Property::traits_type::dataType().getExtent());
assert(key == key2);
assert(size == size2);
#endif
this->fValue = fConverter(sample);
fsConvertionMap[key.digest] = this->fValue->digest();
}
void getKey(Key& key, index_t idx)
{
#ifndef NDEBUG
bool result =
#endif
this->fProperty.getKey(key, idx);
assert(result);
}
private:
struct DigestHash
{
std::size_t operator()(Digest const& v) const
{
std::size_t seed = 0;
GPUCache::hash_combine(seed, v.words[0]);
GPUCache::hash_combine(seed, v.words[1]);
return seed;
}
};
typedef std::unordered_map<Digest, Digest, DigestHash> ConvertionMap;
static ConvertionMap fsConvertionMap;
const Converter fConverter;
};
class DataProvider
{
public:
virtual ~DataProvider();
virtual bool valid() const;
void fillBBoxAndVisSample(chrono_t time);
TimeInterval getBBoxAndVisValidityInterval() const { return fBBoxAndVisValidityInterval; }
void fillTopoAndAttrSample(chrono_t time);
TimeInterval getValidityInterval() const { return fValidityInterval; }
bool isVisible() const;
std::shared_ptr<const ShapeSample>
getBBoxPlaceHolderSample(double seconds);
virtual std::shared_ptr<const ShapeSample>
getSample(double seconds) = 0;
{
const Imath::Box<Imath::V3d> boundingBox =
fBoundingBoxCache.getValue();
if (boundingBox.isEmpty()) {
}
MPoint(boundingBox.min.x, boundingBox.min.y, boundingBox.min.z),
MPoint(boundingBox.max.x, boundingBox.max.y, boundingBox.max.z));
}
TimeInterval getBoundingBoxValidityInterval() const
{ return fBoundingBoxCache.getValidityInterval(); }
TimeInterval getAnimTimeRange() const
{ return fAnimTimeRange; }
protected:
DataProvider(const DataProvider&);
const DataProvider& operator= (const DataProvider&);
template<class INFO>
DataProvider(Alembic::AbcGeom::IGeomBaseSchema<INFO>& abcGeom,
Alembic::Abc::TimeSamplingPtr timeSampling,
size_t numSamples,
bool needUVs);
TimeInterval updateBBoxAndVisCache(chrono_t time);
virtual TimeInterval updateCache(chrono_t time);
const bool fNeedUVs;
TimeInterval fAnimTimeRange;
TimeInterval fBBoxAndVisValidityInterval;
TimeInterval fValidityInterval;
ScalarPropertyCache<Alembic::Abc::ICharProperty> fVisibilityCache;
ScalarPropertyCache<Alembic::Abc::IBox3dProperty> fBoundingBoxCache;
std::vector<ScalarPropertyCache<Alembic::Abc::ICharProperty> > fParentVisibilityCache;
};
class PolyDataProvider : public DataProvider
{
public:
~PolyDataProvider() override;
bool valid() const override;
protected:
PolyDataProvider(const PolyDataProvider&);
const PolyDataProvider& operator= (const PolyDataProvider&);
template<class SCHEMA>
PolyDataProvider(SCHEMA& abcMesh,
bool needUVs);
TimeInterval updateCache(chrono_t time) override;
ArrayPropertyCache<Alembic::Abc::IInt32ArrayProperty> fFaceCountsCache;
ArrayPropertyCache<Alembic::Abc::IP3fArrayProperty> fPositionsCache;
};
class RawDataProvider : public PolyDataProvider
{
public:
RawDataProvider(Alembic::AbcGeom::IPolyMeshSchema& abcMesh,
bool needUVs);
~RawDataProvider() override;
bool valid() const override;
std::shared_ptr<const ShapeSample>
getSample(double seconds) override;
protected:
RawDataProvider(const RawDataProvider&);
const RawDataProvider& operator= (const RawDataProvider&);
static std::shared_ptr<ReadableArray<IndexBuffer::index_t> >
correctPolygonWinding(const Alembic::Abc::Int32ArraySamplePtr& indices);
TimeInterval updateCache(chrono_t time) override;
ArrayPropertyCacheWithConverter<Alembic::Abc::IInt32ArrayProperty> fFaceIndicesCache;
ArrayPropertyCache<Alembic::Abc::IInt32ArrayProperty> fWireIndicesCache;
ArrayPropertyCache<Alembic::Abc::IInt32ArrayProperty> fGroupSizesCache;
ScalarPropertyCache<Alembic::Abc::IC4fProperty> fDiffuseColorCache;
ArrayPropertyCache<Alembic::Abc::IN3fArrayProperty> fNormalsCache;
ArrayPropertyCache<Alembic::Abc::IV2fArrayProperty> fUVsCache;
};
class Triangulator : public PolyDataProvider
{
public:
Triangulator(Alembic::AbcGeom::IPolyMeshSchema& abcMesh,
bool needUVs);
~Triangulator() override;
bool valid() const override;
std::shared_ptr<const ShapeSample>
getSample(double seconds) override;
protected:
Triangulator(const Triangulator&);
const Triangulator& operator= (const Triangulator&);
TimeInterval updateCache(chrono_t time) override;
ArrayPropertyCache<Alembic::Abc::IInt32ArrayProperty> fFaceIndicesCache;
Alembic::AbcGeom::GeometryScope fNormalsScope;
ArrayPropertyCache<Alembic::Abc::IN3fArrayProperty> fNormalsCache;
ArrayPropertyCache<Alembic::Abc::IUInt32ArrayProperty> fNormalIndicesCache;
Alembic::AbcGeom::GeometryScope fUVsScope;
ArrayPropertyCache<Alembic::Abc::IV2fArrayProperty> fUVsCache;
ArrayPropertyCache<Alembic::Abc::IUInt32ArrayProperty> fUVIndicesCache;
private:
template<size_t SIZE>
std::shared_ptr<ReadableArray<float> > convertMultiIndexedStream(
std::shared_ptr<ReadableArray<float> > attribArray,
std::shared_ptr<ReadableArray<IndexBuffer::index_t> > indexArray);
void check();
void computeNormals();
void convertMultiIndexedStreams();
void remapVertAttribs();
void computeWireIndices();
void triangulate();
Alembic::AbcGeom::GeometryScope fCheckedNormalsScope;
std::shared_ptr<ReadableArray<float> > fCheckedNormals;
std::shared_ptr<ReadableArray<IndexBuffer::index_t> > fCheckedNormalIndices;
Alembic::AbcGeom::GeometryScope fCheckedUVsScope;
std::shared_ptr<ReadableArray<float> > fCheckedUVs;
std::shared_ptr<ReadableArray<IndexBuffer::index_t> > fCheckedUVIndices;
Alembic::AbcGeom::GeometryScope fComputedNormalsScope;
std::shared_ptr<ReadableArray<float> > fComputedNormals;
std::shared_ptr<ReadableArray<IndexBuffer::index_t> > fComputedNormalIndices;
size_t fNumVertices;
GPUCache::shared_array<unsigned int> fVertAttribsIndices;
std::shared_ptr<ReadableArray<IndexBuffer::index_t> > fMappedFaceIndices;
std::shared_ptr<ReadableArray<float> > fMappedPositions;
std::shared_ptr<ReadableArray<float> > fMappedNormals;
std::shared_ptr<ReadableArray<float> > fMappedUVs;
std::shared_ptr<ReadableArray<IndexBuffer::index_t> > fWireIndices;
std::shared_ptr<ReadableArray<IndexBuffer::index_t> > fTriangleIndices;
};
class NurbsTessellator : public DataProvider
{
public:
NurbsTessellator(Alembic::AbcGeom::INuPatchSchema& abcNurbs,
bool needUVs);
~NurbsTessellator() override;
bool valid() const override;
std::shared_ptr<const ShapeSample>
getSample(double seconds) override;
protected:
NurbsTessellator(const NurbsTessellator&);
const NurbsTessellator& operator= (const NurbsTessellator&);
TimeInterval updateCache(chrono_t time) override;
ArrayPropertyCache<Alembic::Abc::IP3fArrayProperty> fPositionsCache;
ScalarPropertyCache<Alembic::Abc::IInt32Property> fNumUCache;
ScalarPropertyCache<Alembic::Abc::IInt32Property> fNumVCache;
ScalarPropertyCache<Alembic::Abc::IInt32Property> fUOrderCache;
ScalarPropertyCache<Alembic::Abc::IInt32Property> fVOrderCache;
ArrayPropertyCache<Alembic::AbcGeom::IFloatArrayProperty> fUKnotCache;
ArrayPropertyCache<Alembic::AbcGeom::IFloatArrayProperty> fVKnotCache;
ArrayPropertyCache<Alembic::AbcGeom::IFloatArrayProperty> fPositionWeightsCache;
ScalarPropertyCache<Alembic::Abc::IInt32Property> fTrimNumLoopsCache;
ArrayPropertyCache<Alembic::Abc::IInt32ArrayProperty> fTrimNumCurvesCache;
ArrayPropertyCache<Alembic::Abc::IInt32ArrayProperty> fTrimNumVerticesCache;
ArrayPropertyCache<Alembic::Abc::IInt32ArrayProperty> fTrimOrderCache;
ArrayPropertyCache<Alembic::AbcGeom::IFloatArrayProperty> fTrimKnotCache;
ArrayPropertyCache<Alembic::AbcGeom::IFloatArrayProperty> fTrimUCache;
ArrayPropertyCache<Alembic::AbcGeom::IFloatArrayProperty> fTrimVCache;
ArrayPropertyCache<Alembic::AbcGeom::IFloatArrayProperty> fTrimWCache;
private:
void check();
void setNurbs(bool rebuild, bool positionsChanged);
void tessellate();
void convertToPoly();
bool fSurfaceValid;
std::shared_ptr<ReadableArray<IndexBuffer::index_t> > fTriangleIndices;
std::shared_ptr<ReadableArray<IndexBuffer::index_t> > fWireIndices;
std::shared_ptr<ReadableArray<float> > fPositions;
std::shared_ptr<ReadableArray<float> > fNormals;
std::shared_ptr<ReadableArray<float> > fUVs;
};
class SubDSmoother : public PolyDataProvider
{
public:
SubDSmoother(Alembic::AbcGeom::ISubDSchema& abcSubd,
const bool needUVs);
~SubDSmoother() override;
bool valid() const override;
std::shared_ptr<const ShapeSample>
getSample(double seconds) override;
protected:
SubDSmoother(const SubDSmoother&);
const SubDSmoother& operator= (const SubDSmoother&);
TimeInterval updateCache(chrono_t time) override;
ArrayPropertyCache<Alembic::Abc::IInt32ArrayProperty> fFaceIndicesCache;
ArrayPropertyCache<Alembic::Abc::IInt32ArrayProperty> fCreaseIndicesCache;
ArrayPropertyCache<Alembic::Abc::IInt32ArrayProperty> fCreaseLengthsCache;
ArrayPropertyCache<Alembic::Abc::IFloatArrayProperty> fCreaseSharpnessesCache;
ArrayPropertyCache<Alembic::Abc::IInt32ArrayProperty> fCornerIndicesCache;
ArrayPropertyCache<Alembic::Abc::IFloatArrayProperty> fCornerSharpnessesCache;
ArrayPropertyCache<Alembic::Abc::IInt32ArrayProperty> fHolesCache;
Alembic::AbcGeom::GeometryScope fUVsScope;
ArrayPropertyCache<Alembic::Abc::IV2fArrayProperty> fUVsCache;
ArrayPropertyCache<Alembic::Abc::IUInt32ArrayProperty> fUVIndicesCache;
private:
void check();
void rebuildSubD();
void setPositions();
void setCreaseEdges();
void setCreaseVertices();
void setInvisibleFaces();
void setUVs();
void convertToPoly();
Alembic::AbcGeom::GeometryScope fCheckedUVsScope;
std::shared_ptr<ReadableArray<float> > fCheckedUVs;
std::shared_ptr<ReadableArray<IndexBuffer::index_t> > fCheckedUVIndices;
std::shared_ptr<ReadableArray<IndexBuffer::index_t> > fTriangleIndices;
std::shared_ptr<ReadableArray<IndexBuffer::index_t> > fWireIndices;
std::shared_ptr<ReadableArray<float> > fPositions;
std::shared_ptr<ReadableArray<float> > fNormals;
std::shared_ptr<ReadableArray<float> > fUVs;
};
class AlembicCacheObjectReader
: public std::enable_shared_from_this<AlembicCacheObjectReader>
{
public:
typedef std::shared_ptr<AlembicCacheObjectReader> Ptr;
static Ptr create(Alembic::Abc::IObject& abcObj, bool needUVs);
AlembicCacheObjectReader() {}
virtual ~AlembicCacheObjectReader() = 0;
AlembicCacheObjectReader(const AlembicCacheObjectReader&) = delete;
AlembicCacheObjectReader& operator=(const AlembicCacheObjectReader&) = delete;
virtual bool valid() const = 0;
virtual TimeInterval sampleHierarchy(double seconds,
const MMatrix& rootMatrix, TimeInterval rootMatrixInterval) = 0;
virtual TimeInterval sampleShape(double seconds) = 0;
virtual SubNode::MPtr get() const = 0;
virtual TimeInterval getBoundingBoxValidityInterval() const = 0;
virtual TimeInterval getAnimTimeRange() const = 0;
virtual void saveAndReset(AlembicCacheReader& cacheReader) = 0;
};
class AlembicCacheTopReader : public AlembicCacheObjectReader
{
public:
AlembicCacheTopReader(Alembic::Abc::IObject object, bool needUVs);
~AlembicCacheTopReader() override;
bool valid() const override;
TimeInterval sampleHierarchy(double seconds,
const MMatrix& rootMatrix, TimeInterval rootMatrixInterval)
override;
TimeInterval sampleShape(double seconds) override;
SubNode::MPtr get() const override;
TimeInterval getBoundingBoxValidityInterval() const override;
TimeInterval getAnimTimeRange() const override;
void saveAndReset(AlembicCacheReader& cacheReader) override;
private:
TimeInterval fBoundingBoxValidityInterval;
XformData::MPtr fXformData;
std::vector<AlembicCacheObjectReader::Ptr> fChildren;
};
class AlembicCacheXformReader : public AlembicCacheObjectReader
{
public:
AlembicCacheXformReader(Alembic::Abc::IObject object, bool needUVs);
~AlembicCacheXformReader() override;
bool valid() const override;
TimeInterval sampleHierarchy(double seconds,
const MMatrix& rootMatrix, TimeInterval rootMatrixInterval)
override;
TimeInterval sampleShape(double seconds) override;
SubNode::MPtr get() const override;
TimeInterval getBoundingBoxValidityInterval() const override;
TimeInterval getAnimTimeRange() const override;
void saveAndReset(AlembicCacheReader& cacheReader) override;
private:
void fillTopoAndAttrSample(chrono_t time);
bool isVisible() const;
const std::string fName;
TimeInterval fValidityInterval;
XformPropertyCache fXformCache;
ScalarPropertyCache<Alembic::Abc::ICharProperty> fVisibilityCache;
TimeInterval fBoundingBoxValidityInterval;
XformData::MPtr fXformData;
std::vector<AlembicCacheObjectReader::Ptr> fChildren;
};
class AlembicCacheMeshReader : public AlembicCacheObjectReader
{
public:
AlembicCacheMeshReader(Alembic::Abc::IObject object, bool needUVs);
~AlembicCacheMeshReader() override;
bool valid() const override;
TimeInterval sampleHierarchy(double seconds,
const MMatrix& rootMatrix, TimeInterval rootMatrixInterval)
override;
TimeInterval sampleShape(double seconds) override;
SubNode::MPtr get() const override;
protected:
TimeInterval getBoundingBoxValidityInterval() const override;
TimeInterval getAnimTimeRange() const override;
void saveAndReset(AlembicCacheReader& cacheReader) override;
private:
const std::string fName;
const std::string fFullName;
std::unique_ptr<DataProvider> fDataProvider;
TimeInterval fBoundingBoxValidityInterval;
ShapeData::MPtr fShapeData;
size_t fNumTransparentSample;
};
class AlembicCacheMaterialReader
{
public:
AlembicCacheMaterialReader(Alembic::Abc::IObject abcObj);
~AlembicCacheMaterialReader();
AlembicCacheMaterialReader(const AlembicCacheMaterialReader&) = delete;
AlembicCacheMaterialReader& operator=(const AlembicCacheMaterialReader&) = delete;
TimeInterval sampleMaterial(double seconds);
MaterialGraph::MPtr get() const;
private:
const std::string fName;
template<typename ABC_PROP>
class ScalarMaterialProp
{
public:
ScalarMaterialProp(Alembic::Abc::ICompoundProperty& parent,
const std::string& name,
MaterialNode::MPtr& node)
: fName(name)
{
ABC_PROP abcProp(parent, name);
assert(abcProp.valid());
fCache.reset(new ScalarPropertyCache<ABC_PROP>());
fCache->init(abcProp);
fProp = node->findProperty(name.c_str());
assert(!fProp || fProp->type() == propertyType<ABC_PROP>());
if (fProp && fProp->type() != propertyType<ABC_PROP>()) {
fCache.reset();
fProp.reset();
return;
}
if (!fProp) {
fProp = node->createProperty(name.c_str(), propertyType<ABC_PROP>());
assert(fProp->type() == propertyType<ABC_PROP>());
}
}
TimeInterval sample(double seconds)
{
TimeInterval validityInterval(TimeInterval::kInfinite);
if (fCache && fCache->valid()) {
fCache->setTime(seconds);
validityInterval &= fCache->getValidityInterval();
if (seconds == validityInterval.startTime()) {
setMaterialProperty<ABC_PROP>(fCache, fProp, seconds);
}
}
return validityInterval;
}
private:
std::string fName;
std::shared_ptr<ScalarPropertyCache<ABC_PROP> > fCache;
MaterialProperty::MPtr fProp;
};
template<typename T> static MaterialProperty::Type propertyType()
{ assert(0); return MaterialProperty::kFloat; }
template<typename T> static void setMaterialProperty(
std::shared_ptr<ScalarPropertyCache<T> >& cache,
MaterialProperty::MPtr prop,
double seconds)
{}
std::vector<ScalarMaterialProp<Alembic::Abc::IBoolProperty> > fBoolCaches;
std::vector<ScalarMaterialProp<Alembic::Abc::IInt32Property> > fInt32Caches;
std::vector<ScalarMaterialProp<Alembic::Abc::IFloatProperty> > fFloatCaches;
std::vector<ScalarMaterialProp<Alembic::Abc::IV2fProperty> > fFloat2Caches;
std::vector<ScalarMaterialProp<Alembic::Abc::IV3fProperty> > fFloat3Caches;
std::vector<ScalarMaterialProp<Alembic::Abc::IC3fProperty> > fRGBCaches;
std::vector<ScalarMaterialProp<Alembic::Abc::IWstringProperty> > fStringCaches;
TimeInterval fValidityInterval;
MaterialGraph::MPtr fMaterialGraph;
};
template<>
inline MaterialProperty::Type AlembicCacheMaterialReader::propertyType<Alembic::Abc::IBoolProperty>()
{ return MaterialProperty::kBool; }
template<>
inline MaterialProperty::Type AlembicCacheMaterialReader::propertyType<Alembic::Abc::IInt32Property>()
{ return MaterialProperty::kInt32; }
template<>
inline MaterialProperty::Type AlembicCacheMaterialReader::propertyType<Alembic::Abc::IFloatProperty>()
{ return MaterialProperty::kFloat; }
template<>
inline MaterialProperty::Type AlembicCacheMaterialReader::propertyType<Alembic::Abc::IV2fProperty>()
{ return MaterialProperty::kFloat2; }
template<>
inline MaterialProperty::Type AlembicCacheMaterialReader::propertyType<Alembic::Abc::IV3fProperty>()
{ return MaterialProperty::kFloat3; }
template<>
inline MaterialProperty::Type AlembicCacheMaterialReader::propertyType<Alembic::Abc::IC3fProperty>()
{ return MaterialProperty::kRGB; }
template<>
inline MaterialProperty::Type AlembicCacheMaterialReader::propertyType<Alembic::Abc::IWstringProperty>()
{ return MaterialProperty::kString; }
template<>
inline void AlembicCacheMaterialReader::setMaterialProperty<Alembic::Abc::IBoolProperty>(
std::shared_ptr<ScalarPropertyCache<Alembic::Abc::IBoolProperty> >& cache,
MaterialProperty::MPtr prop,
double seconds)
{
prop->setBool(seconds, cache->getValue());
}
template<>
inline void AlembicCacheMaterialReader::setMaterialProperty<Alembic::Abc::IInt32Property>(
std::shared_ptr<ScalarPropertyCache<Alembic::Abc::IInt32Property> >& cache,
MaterialProperty::MPtr prop,
double seconds)
{
prop->setInt32(seconds, cache->getValue());
}
template<>
inline void AlembicCacheMaterialReader::setMaterialProperty<Alembic::Abc::IFloatProperty>(
std::shared_ptr<ScalarPropertyCache<Alembic::Abc::IFloatProperty> >& cache,
MaterialProperty::MPtr prop,
double seconds)
{
prop->setFloat(seconds, cache->getValue());
}
template<>
inline void AlembicCacheMaterialReader::setMaterialProperty<Alembic::Abc::IV2fProperty>(
std::shared_ptr<ScalarPropertyCache<Alembic::Abc::IV2fProperty> >& cache,
MaterialProperty::MPtr prop,
double seconds)
{
Alembic::Abc::V2f value = cache->getValue();
prop->setFloat2(seconds, value.x, value.y);
}
template<>
inline void AlembicCacheMaterialReader::setMaterialProperty<Alembic::Abc::IV3fProperty>(
std::shared_ptr<ScalarPropertyCache<Alembic::Abc::IV3fProperty> >& cache,
MaterialProperty::MPtr prop,
double seconds)
{
Alembic::Abc::V3f value = cache->getValue();
prop->setFloat3(seconds, value.x, value.y, value.z);
}
template<>
inline void AlembicCacheMaterialReader::setMaterialProperty<Alembic::Abc::IC3fProperty>(
std::shared_ptr<ScalarPropertyCache<Alembic::Abc::IC3fProperty> >& cache,
MaterialProperty::MPtr prop,
double seconds)
{
Alembic::Abc::C3f value = cache->getValue();
prop->setColor(seconds,
MColor(value.x, value.y, value.z));
}
template<>
inline void AlembicCacheMaterialReader::setMaterialProperty<Alembic::Abc::IWstringProperty>(
std::shared_ptr<ScalarPropertyCache<Alembic::Abc::IWstringProperty> >& cache,
MaterialProperty::MPtr prop,
double seconds)
{
std::wstring value = cache->getValue();
prop->setString(seconds, value.c_str());
}
}
class AlembicCacheReader : public CacheReader
{
public:
static std::shared_ptr<CacheReader> create(
const MFileObject& file);
~AlembicCacheReader() override;
bool valid() const override;
bool validateGeomPath(
SubNode::Ptr readScene(
const MString& geomPath,
bool needUVs)
override;
SubNode::Ptr readHierarchy(
const MString& geomPath,
bool needUVs)
override;
SubNode::Ptr readShape(
const MString& geomPath,
bool needUVs)
override;
MaterialGraphMap::Ptr readMaterials() override;
bool readAnimTimeRange(TimeInterval& range) override;
void saveReader(const std::string& fullName,
CacheReaderAlembicPrivate::AlembicCacheObjectReader::Ptr& reader);
private:
friend class AlembicCacheMeshReader;
struct MakeSharedEnabler;
mutable Alembic::Abc::IArchive fAbcArchive;
typedef std::unordered_map<std::string,CacheReaderAlembicPrivate::AlembicCacheObjectReader::Ptr> ObjectReaderMap;
ObjectReaderMap fSavedReaders;
};
}
#endif