#include "CacheWriter.h"
#include "gpuCacheUtil.h"
#include "gpuCacheStrings.h"
#include <maya/MFnDagNode.h>
#include <maya/MAnimControl.h>
#include <maya/MFnMeshData.h>
#include <maya/MIntArray.h>
#include <maya/MFloatArray.h>
#include <maya/MFloatPointArray.h>
#include <maya/MFloatVectorArray.h>
#include <maya/MFnMesh.h>
#include <maya/MUintArray.h>
#include <maya/MHWGeometry.h>
#include <maya/MGeometryExtractor.h>
#include <maya/MFnSingleIndexedComponent.h>
#include <maya/MDagPathArray.h>
#include <maya/MGlobal.h>
#include <maya/MPlug.h>
#include <maya/MFnTransform.h>
#include <string.h>
#include <string>
#include <cassert>
using namespace GPUCache;
std::map<std::string,void*> CacheWriter::fsRegistry;
std::shared_ptr<CacheWriter> CacheWriter::create(
const MString& impl,
{
std::string key = impl.
asChar();
std::map<std::string,void*>::iterator iter = fsRegistry.find(key);
if (iter != fsRegistry.end()) {
return ((CreateFunction*)(*iter).second)(file, compressLevel);
}
assert("not implemented");
return std::shared_ptr<CacheWriter>();
}
void CacheWriter::registerWriter(
const MString& impl, CreateFunction func)
{
std::string key = impl.
asChar();
fsRegistry[key] = (void*)func;
}
struct CacheXformSampler::MakeSharedEnabler: public CacheXformSampler {
MakeSharedEnabler(
const MObject& xformObject): CacheXformSampler(xformObject) {}
};
std::shared_ptr<CacheXformSampler>
CacheXformSampler::create(
const MObject& xformObject)
{
return std::make_shared<MakeSharedEnabler>(xformObject);
}
CacheXformSampler::CacheXformSampler(
const MObject& xformObject)
: fXform(xformObject),
fIsFirstSample(true),
fXformAnimated(true),
fVisibilitySample(false),
fVisibilityAnimated(true)
{}
CacheXformSampler::~CacheXformSampler()
{}
void CacheXformSampler::addSample()
{
MMatrix prevXformSample = fXformSample;
bool prevVisibilitySample = fVisibilitySample;
fXformSample = fXform.transformationMatrix();
fVisibilitySample = ShapeVisibilityChecker(fXform.object()).isVisible();
if (fIsFirstSample) {
fIsFirstSample = false;
}
else {
fXformAnimated = (prevXformSample != fXformSample);
fVisibilityAnimated = (prevVisibilitySample != fVisibilitySample);
}
}
std::shared_ptr<const XformSample>
CacheXformSampler::getSample(double timeInSeconds)
{
std::shared_ptr<XformSample> sample =
XformSample::create(
timeInSeconds,fXformSample,
MBoundingBox(), fVisibilitySample);
return sample;
}
CacheMeshSampler::AttributeSet::AttributeSet(
const bool visibility,
const bool needUVs
)
{
typedef IndexBuffer::index_t index_t;
MayaMeshExtractor<index_t> extractor(meshObject);
extractor.setWantUVs(needUVs);
extractor.compute();
std::shared_ptr<Array<index_t> > wireIndices = extractor.wireIndices();
std::shared_ptr<Array<index_t> > triangleIndices = extractor.triangleIndices();
std::shared_ptr<Array<float> > positions = extractor.positions();
std::shared_ptr<Array<float> > normals = extractor.normals();
std::shared_ptr<Array<float> > uvs;
if (needUVs) {
uvs = extractor.uvs();
}
fNumWires = wireIndices->size() / 2;
fNumTriangles = triangleIndices->size() / 3;
fNumVerts = positions->size() / 3;
fWireVertIndices = IndexBuffer::create(wireIndices);
fTriangleVertIndices.push_back(IndexBuffer::create(triangleIndices));
fPositions = VertexBuffer::createPositions(positions);
fNormals = VertexBuffer::createNormals(normals);
if (needUVs) {
fUVs = VertexBuffer::createUVs(uvs);
}
{
float minX = +std::numeric_limits<float>::max();
float minY = +std::numeric_limits<float>::max();
float minZ = +std::numeric_limits<float>::max();
float maxX = -std::numeric_limits<float>::max();
float maxY = -std::numeric_limits<float>::max();
float maxZ = -std::numeric_limits<float>::max();
VertexBuffer::ReadInterfacePtr readable = fPositions->readableInterface();
const float* srcPositions = readable->get();
for (size_t i=0; i<fNumVerts; ++i) {
const float x = srcPositions[3*i + 0];
const float y = srcPositions[3*i + 1];
const float z = srcPositions[3*i + 2];
minX = std::min(x, minX);
minY = std::min(y, minY);
minZ = std::min(z, minZ);
maxX = std::max(x, maxX);
maxY = std::max(y, maxY);
maxZ = std::max(z, maxZ);
}
}
fVisibility = visibility;
}
CacheMeshSampler::AttributeSet::AttributeSet(
const bool needUVs,
const bool useBaseTessellation
)
:fNumWires(0),
fNumTriangles(0),
fNumVerts(0),
fVisibility(false)
{
if (needUVs)
MIndexBufferDescriptor edgeDesc(MIndexBufferDescriptor::kEdgeLine, noName, MGeometry::kLines, 2, edgeCompObj);
MIndexBufferDescriptor triangleDesc(MIndexBufferDescriptor::kTriangle, noName, MGeometry::kTriangles, 3, compObj);
typedef IndexBuffer::index_t index_t;
int extractorOptions = MHWRender::kPolyGeom_Normal;
if (useBaseTessellation) {
extractorOptions |= MHWRender::kPolyGeom_BaseMesh;
}
if (MS::kFailure==status)
return;
unsigned int numVertices = extractor.vertexCount();
unsigned int numWires = extractor.primitiveCount(edgeDesc);
GPUCache::shared_array<float> vertices(new float[numVertices*posDesc.stride()]);
GPUCache::shared_array<float> normals(new float[numVertices*normalDesc.stride()]);
GPUCache::shared_array<float> uvs(new float[numVertices*uvDesc.stride()]);
unsigned int minBufferSize = extractor.minimumBufferSize(numWires, edgeDesc.primitive());
GPUCache::shared_array<index_t> wireframeIdx(new index_t[minBufferSize]);
if (MS::kFailure==extractor.populateIndexBuffer(wireframeIdx.get(), numWires, edgeDesc))
return;
if (MS::kFailure==extractor.populateVertexBuffer(vertices.get(), numVertices, posDesc))
return;
if (MS::kFailure==extractor.populateVertexBuffer(normals.get(), numVertices, normalDesc))
return;
if (needUVs && MS::kFailure==extractor.populateVertexBuffer(uvs.get(), numVertices, uvDesc))
return;
{
std::vector<std::shared_ptr<Array<index_t> > > trgIdxGrps;
unsigned int numTriangles = extractor.primitiveCount(triangleDesc);
minBufferSize = extractor.minimumBufferSize(numTriangles, triangleDesc.primitive());
GPUCache::shared_array<index_t> triangleIdx(new index_t[minBufferSize]);
if (numTriangles != 0)
{
if (MS::kFailure==extractor.populateIndexBuffer(triangleIdx.get(), numTriangles, triangleDesc))
return;
fNumTriangles += (size_t)numTriangles;
}
trgIdxGrps.push_back(SharedArray<index_t>::create(
triangleIdx, 3 * numTriangles));
for(size_t i=0, offset=0; i<trgIdxGrps.size(); ++i) {
fTriangleVertIndices.push_back(IndexBuffer::create(
trgIdxGrps[0], offset, offset + trgIdxGrps[i]->size()));
offset += trgIdxGrps[i]->size();
}
}
fNumWires = (size_t)numWires;
fNumVerts = (size_t)numVertices;
fWireVertIndices = IndexBuffer::create(
SharedArray<index_t>::create( wireframeIdx, 2 * fNumWires));
fPositions = VertexBuffer::createPositions(
SharedArray<float>::create( vertices, 3 * fNumVerts));
fNormals = VertexBuffer::createNormals(
SharedArray<float>::create( normals, 3 * fNumVerts));
if (needUVs) {
fUVs = VertexBuffer::createUVs(
SharedArray<float>::create(uvs, 2 * fNumVerts));
}
fVisibility = ShapeVisibilityChecker(mesh.
object()).isVisible();
}
bool CacheMeshSampler::AttributeSet::updateAnimatedChannels(
bool& animated, const AttributeSet& newer
)
{
const bool numWiresAnimated = fNumWires != newer.fNumWires;
const bool numTrianglesAnimated = fNumTriangles != newer.fNumTriangles;
const bool numVertsAnimated = fNumVerts != newer.fNumVerts;
const bool wiresAnimated = fWireVertIndices != newer.fWireVertIndices;
const bool trianglesAnimated =
(!numWiresAnimated && !numTrianglesAnimated && !numVertsAnimated &&
!wiresAnimated) ?
false :
(fTriangleVertIndices != newer.fTriangleVertIndices);
const bool positionsAnimated = fPositions != newer.fPositions;
const bool normalsAnimated = fNormals != newer.fNormals;
const bool uvsAnimated = fUVs != newer.fUVs;
const bool boundingBoxAnimated =
(!fBoundingBox.min().isEquivalent(newer.fBoundingBox.min()) ||
!fBoundingBox.max().isEquivalent(newer.fBoundingBox.max()));
const bool visibilityAnimated = fVisibility != newer.fVisibility;
fNumWires = newer.fNumWires;
fNumTriangles = newer.fNumTriangles;
fNumVerts = newer.fNumVerts;
fWireVertIndices = wiresAnimated ? newer.fWireVertIndices : fWireVertIndices;
fTriangleVertIndices = trianglesAnimated ? newer.fTriangleVertIndices : fTriangleVertIndices;
fPositions = positionsAnimated ? newer.fPositions : fPositions;
fNormals = normalsAnimated ? newer.fNormals : fNormals;
fUVs = uvsAnimated ? newer.fUVs : fUVs;
fBoundingBox = newer.fBoundingBox;
fVisibility = newer.fVisibility;
animated =
numWiresAnimated || numTrianglesAnimated || numVertsAnimated ||
wiresAnimated || trianglesAnimated ||
positionsAnimated || normalsAnimated || uvsAnimated ||
boundingBoxAnimated || visibilityAnimated;
return true;
}
struct CacheMeshSampler::MakeSharedEnabler: public CacheMeshSampler{
MakeSharedEnabler(bool needUVs):CacheMeshSampler(needUVs){}
};
std::shared_ptr<CacheMeshSampler> CacheMeshSampler::create(
const bool needUVs)
{
return std::make_shared<MakeSharedEnabler>(needUVs);
}
CacheMeshSampler::CacheMeshSampler(const bool needUVs)
: fNeedUVs(needUVs), fUseBaseTessellation(false), fIsAnimated(true)
{}
CacheMeshSampler::~CacheMeshSampler()
{}
bool CacheMeshSampler::addSample(
MObject meshObject,
bool visibility)
{
return fAttributeSet.updateAnimatedChannels(
fIsAnimated, AttributeSet(meshObject, visibility, fNeedUVs));
}
bool CacheMeshSampler::addSampleFromMesh(
MFnMesh& mesh)
{
return fAttributeSet.updateAnimatedChannels(
fIsAnimated, AttributeSet(mesh, fNeedUVs, fUseBaseTessellation));
}
std::shared_ptr<const ShapeSample>
CacheMeshSampler::getSample(
double timeInSeconds,
const MColor& diffuseColor)
{
if (!fAttributeSet.fVisibility) {
std::shared_ptr<ShapeSample> sample =
ShapeSample::createEmptySample(timeInSeconds);
return sample;
}
std::shared_ptr<ShapeSample> sample =
ShapeSample::create(
timeInSeconds,
fAttributeSet.fNumWires,
fAttributeSet.fNumVerts,
fAttributeSet.fWireVertIndices,
fAttributeSet.fTriangleVertIndices,
fAttributeSet.fPositions,
fAttributeSet.fBoundingBox,
diffuseColor,
fAttributeSet.fVisibility
);
sample->setNormals(fAttributeSet.fNormals);
sample->setUVs(fAttributeSet.fUVs);
return sample;
}