#include "gpuCacheCmd.h"
#include "gpuCacheShapeNode.h"
#include "gpuCacheStrings.h"
#include "gpuCacheUtil.h"
#include "gpuCacheConfig.h"
#include "gpuCacheVBOProxy.h"
#include "gpuCacheVramQuery.h"
#include "gpuCacheMaterialBakers.h"
#include "gpuCacheSubSceneOverride.h"
#include "gpuCacheUnitBoundingBox.h"
#include "CacheWriter.h"
#include "CacheReader.h"
#include "gpuCacheGeometry.h"
#include <maya/MArgList.h>
#include <maya/MAnimControl.h>
#include <maya/MDagPathArray.h>
#include <maya/MFnDagNode.h>
#include <maya/MFnMesh.h>
#include <maya/MFnMeshData.h>
#include <maya/MFnNurbsSurface.h>
#include <maya/MFnSet.h>
#include <maya/MFnSubd.h>
#include <maya/MGlobal.h>
#include <maya/MPlugArray.h>
#include <maya/MSyntax.h>
#include <maya/MBoundingBox.h>
#include <maya/MFileObject.h>
#include <maya/MItDag.h>
#include <maya/MVector.h>
#include <maya/MFnTransform.h>
#include <maya/MFnSingleIndexedComponent.h>
#include <maya/MFnComponentListData.h>
#include <maya/MFnLambertShader.h>
#include <maya/MViewport2Renderer.h>
#include <maya/MDagPath.h>
#include <maya/MPointArray.h>
#include <maya/MUintArray.h>
#include <unordered_set>
#include <cfloat>
#include <limits>
#include <list>
#include <iomanip>
#include <map>
#include <sstream>
#include <fstream>
#include <memory>
#define MStatError(status,msg) \
if ( MS::kSuccess != (status) ) { \
MPxCommand::displayError( \
(msg) + MString(":") + (status).errorString()); \
return (status); \
}
#define MStatErrorNullObj(status,msg) \
if ( MS::kSuccess != (status) ) { \
MPxCommand::displayError( \
(msg) + MString(":") + (status).errorString()); \
return MObject::kNullObj; \
}
#define MCheckReturn(expression) \
{ \
MStatus status = (expression); \
if ( MS::kSuccess != (status) ) { \
return (status); \
} \
}
#define MUpdateProgressAndCheckInterruption(progressBar) \
{ \
(progressBar).stepProgress(); \
if ((progressBar).isCancelled()) { \
return MS::kFailure; \
} \
} \
namespace {
using namespace GPUCache;
std::shared_ptr<CacheWriter> createWriter(
const MFileObject& targetFile,
const char compressLevel,
{
if (!cacheDirectory.
exists()) {
}
bool writeable;
{
std::ofstream ofs(resolvedFullName.
asChar());
writeable = ofs.is_open();
}
if (!writeable) {
msg.
format(fmt, resolvedFullName);
return std::shared_ptr<CacheWriter>();
}
if (
remove(resolvedFullName.
asChar()) != 0) {
msg.
format(fmt, resolvedFullName);
return std::shared_ptr<CacheWriter>();
}
}
std::shared_ptr<CacheWriter> cacheWriter =
CacheWriter::create("Alembic", targetFile, compressLevel, dataFormat);
if (!cacheWriter) {
return std::shared_ptr<CacheWriter>();
}
if (!cacheWriter->valid()) {
cacheWriter.reset();
return std::shared_ptr<CacheWriter>();
}
return cacheWriter;
}
bool isPlugConnectedToTexture2d(
const MPlug& plug)
{
assert(connections.
length() == 1);
return false;
MObject srcNode = connections[0].node();
}
return false;
}
{
assert(connections.
length() == 1);
assert(!diffusePlugR.
isNull());
assert(!diffusePlugG.
isNull());
assert(!diffusePlugB.
isNull());
float r = diffusePlugR.
asFloat(&statusR);
float g = diffusePlugG.
asFloat(&statusG);
float b = diffusePlugB.
asFloat(&statusB);
assert(statusR == MS::kSuccess);
assert(statusG == MS::kSuccess);
assert(statusB == MS::kSuccess);
}
}
bool isPlugConnectedToTextureNode(
const MPlug& plug)
{
assert(connections.
length() == 1);
return false;
MObject srcNode = connections[0].node();
return true;
}
}
return false;
}
MStatus getShapeDiffuseColors(
const std::vector<MDagPath>& paths,
std::vector<MColor>& diffuseColors)
{
diffuseColors.resize(paths.size(), Config::kDefaultGrayColor);
for (size_t pathIndex = 0; pathIndex < paths.size(); pathIndex++) {
assert(status == MS::kSuccess);
MPlug instObjectGroupsParent = shape.
findPlug(
"instObjGroups",
true);
assert(!instObjectGroupsParent.
isNull());
paths[pathIndex].instanceNumber());
assert(!instObjectGroups.isNull());
if (instObjectGroups.isConnected()) {
instObjectGroups.connectedTo(dstPlugs, false, true, &status);
if (status && dstPlugs.
length() > 0) {
shadingGroup = dstPlugs[0].node();
}
}
MPlug objectGroupsParent = instObjectGroups.
child(0);
assert(!objectGroupsParent.
isNull());
for (unsigned int parts = 0;
parts++) {
MPlug objectGroups = objectGroupsParent[parts];
objectGroups.
connectedTo(dstPlugs,
false,
true, &status);
if (status && dstPlugs.
length() > 0) {
shadingGroup = dstPlugs[0].node();
}
}
}
assert(status == MS::kSuccess);
MPlug surfaceShaderPlug = shadingEngine.
findPlug(
"surfaceShader",
true);
assert(!surfaceShaderPlug.
isNull());
surfaceShaderPlug.
connectedTo(srcPlugs,
true,
false, &status);
if (status && srcPlugs.
length() > 0) {
shaderObj = srcPlugs[0].node();
}
}
}
MColor diffuseColor = Config::kDefaultGrayColor;
MColor transparency = Config::kDefaultTransparency;
assert(status == MS::kSuccess);
assert(!diffusePlug.isNull());
assert(!transparencyPlug.isNull());
if (isPlugConnectedToTexture2d(colorPlug)) {
diffuseColor = getTexture2dDefaultColor(colorPlug);
}
else if (!isPlugConnectedToTextureNode(colorPlug)) {
diffuseColor = lambert.
color();
}
if (!isPlugConnectedToTextureNode(diffusePlug)) {
}
if (!isPlugConnectedToTextureNode(transparencyPlug)) {
}
}
diffuseColor.
a = 1.0f - (transparency.
r * 0.3f +
transparency.
g * 0.59f + transparency.
b * 0.11f);
diffuseColors[pathIndex] = diffuseColor;
}
}
return MS::kSuccess;
}
{
"basenameEx(`file -q -sceneName`)");
if (sceneName.
length() == 0) {
}
return sceneName;
}
MString getSceneNameAsValidObjectName()
{
}
size_t maxNumVerts(const ShapeData::Ptr& geom)
{
size_t maxNumVerts = 0;
for(
const ShapeData::SampleMap::value_type& smv : geom->getSamples()
) {
maxNumVerts = std::max(maxNumVerts, smv.second->numVerts());
}
return maxNumVerts;
}
double toHumanUnits(MUint64 bytes,
MString& units)
{
const MUint64 KB = 1024;
const MUint64 MB = 1024 * KB;
const MUint64 GB = 1024 * MB;
const MUint64 TB = 1024 * GB;
double value;
if (bytes >= TB) {
units = "TB";
value = double(bytes)/TB;
}
else if (bytes >= GB) {
units = "GB";
value = double(bytes)/GB;
}
else if (bytes >= MB) {
units = "MB";
value = double(bytes)/MB;
}
else if (bytes >= KB) {
units = "KB";
value = double(bytes)/KB;
}
else {
units = "bytes";
value = double(bytes);
}
return value;
}
class Baker
{
public:
static std::shared_ptr<Baker> create(
const MObject&
object,
const std::vector<MDagPath>& paths);
static bool isBakeable(
const MObject& dagNode);
Baker(
const MObject&
object,
const std::vector<MDagPath>& paths)
: fNode(object), fPaths(paths)
{}
virtual ~Baker() {}
virtual const SubNode::MPtr getNode(size_t instIndex) const = 0;
virtual void setWriteMaterials() {}
virtual void setUseBaseTessellation() {}
protected:
std::vector<MDagPath> fPaths;
};
class ShapeBaker : public Baker
{
public:
~ShapeBaker() override {}
void enableUVs()
{
fCacheMeshSampler->enableUVs();
}
{
MCheckReturn( sampleTopologyAndAttributes() );
std::vector<MColor> diffuseColors;
MCheckReturn( getShapeDiffuseColors(fPaths, diffuseColors) );
bool diffuseColorsAnimated = (fPrevDiffuseColors != diffuseColors);
if (fCacheMeshSampler->isAnimated() || diffuseColorsAnimated) {
for (size_t i = 0; i < fGeometryInstances.size(); i++) {
fGeometryInstances[i]->addSample(
fCacheMeshSampler->getSample(
diffuseColors[i]));
}
}
fPrevDiffuseColors.swap(diffuseColors);
return MS::kSuccess;
}
const SubNode::MPtr getNode(size_t instIndex) const override
{
return SubNode::create(
fNode.name(),
fGeometryInstances[instIndex]
);
}
protected:
ShapeBaker(
const MObject& node,
const std::vector<MDagPath>& paths)
: Baker(node, paths),
fCacheMeshSampler(
CacheMeshSampler::create(!Config::isIgnoringUVs())),
fGeometryInstances(paths.size())
{
for (size_t i = 0; i < paths.size(); i++) {
fGeometryInstances[i] = ShapeData::create();
}
}
void setWriteMaterials() override
{
for (size_t i = 0; i < fPaths.size(); i++) {
InstanceMaterialLookup lookup(fPaths[i]);
if (lookup.hasWholeObjectMaterial()) {
MObject material = lookup.findWholeObjectSurfaceMaterial();
surfaceMaterial = dgMaterial.
name();
}
}
else if (lookup.hasComponentMaterials()) {
std::vector<MObject> materials;
lookup.findSurfaceMaterials(materials);
for(
const MObject& material : materials) {
if (!material.isNull()) {
surfaceMaterial = dgMaterial.
name();
break;
}
}
}
if (surfaceMaterial.
length() > 0) {
fGeometryInstances[i]->setMaterial(surfaceMaterial);
}
}
}
void setUseBaseTessellation() override
{
fCacheMeshSampler->setUseBaseTessellation();
}
virtual MStatus sampleTopologyAndAttributes() = 0;
private:
ShapeBaker(const ShapeBaker&);
const ShapeBaker& operator=(const ShapeBaker&);
protected:
const std::shared_ptr<CacheMeshSampler> fCacheMeshSampler;
std::vector<MColor> fPrevDiffuseColors;
std::vector<ShapeData::MPtr> fGeometryInstances;
};
class XformBaker : public Baker
{
public:
~XformBaker() override
{}
XformBaker(
const MObject& xformNode,
const std::vector<MDagPath>& xformPaths)
: Baker(xformNode, xformPaths),
fCacheXformSamplers(CacheXformSampler::create(xformNode)),
fXformInstances(xformPaths.size())
{
for (size_t i = 0; i < fXformInstances.size(); i++) {
fXformInstances[i] = XformData::create();
}
}
{
fCacheXformSamplers->addSample();
if (fCacheXformSamplers->isAnimated()) {
for (size_t i = 0; i < fXformInstances.size(); i++) {
fXformInstances[i]->addSample(
}
}
return MS::kSuccess;
}
const SubNode::MPtr getNode(size_t instIndex) const override
{
return SubNode::create(
fNode.name(),
fXformInstances[instIndex]
);
}
private:
std::shared_ptr<CacheXformSampler> fCacheXformSamplers;
std::vector<XformData::MPtr> fXformInstances;
};
class MeshDataBaker : public ShapeBaker
{
public:
~MeshDataBaker() override {}
protected:
MStatus sampleTopologyAndAttributes()
override
{
MObject meshData = getMeshData(&status);
MStatError(status, "getMeshData()");
bool shapeVisibility = ShapeVisibilityChecker(fNode.object()).isVisible();
return fCacheMeshSampler->addSample(meshData, shapeVisibility) ?
MS::kSuccess : MS::kFailure;
}
MeshDataBaker(
const MObject& shapeNode,
const std::vector<MDagPath>& shapePaths)
: ShapeBaker(shapeNode, shapePaths)
{}
private:
MeshDataBaker(const MeshDataBaker&);
const MeshDataBaker& operator=(const MeshDataBaker&);
};
class MeshBaker : public ShapeBaker
{
public:
MeshBaker(
const MObject& meshNode,
const std::vector<MDagPath>& meshPaths)
: ShapeBaker(meshNode, meshPaths), fMeshNode(meshNode)
{}
~MeshBaker() override {}
protected:
MStatus sampleTopologyAndAttributes()
override
{
return fCacheMeshSampler->addSampleFromMesh(fMeshNode) ?
MS::kSuccess : MS::kFailure;
}
private:
MeshBaker(const MeshBaker&);
const MeshBaker& operator=(const MeshBaker&);
};
class NurbsBaker : public MeshDataBaker
{
public:
NurbsBaker(
const MObject& nurbsNode,
const std::vector<MDagPath>& nurbsPaths)
: MeshDataBaker(nurbsNode, nurbsPaths)
{
}
protected:
{
modifier.
connect(nurbsNode.findPlug(
"explicitTessellationAttributes",
true),
tessellatorNode.
findPlug(
"explicitTessellationAttributes",
true));
modifier.
connect(nurbsNode.findPlug(
"curvatureTolerance",
true),
tessellatorNode.
findPlug(
"curvatureTolerance",
true));
modifier.
connect(nurbsNode.findPlug(
"uDivisionsFactor",
true),
tessellatorNode.
findPlug(
"uDivisionsFactor",
true));
modifier.
connect(nurbsNode.findPlug(
"vDivisionsFactor",
true),
tessellatorNode.
findPlug(
"vDivisionsFactor",
true));
modifier.
connect(nurbsNode.findPlug(
"modeU",
true),
tessellatorNode.
findPlug(
"uType",
true));
modifier.
connect(nurbsNode.findPlug(
"modeV",
true),
tessellatorNode.
findPlug(
"vType",
true));
modifier.
connect(nurbsNode.findPlug(
"numberU",
true),
tessellatorNode.
findPlug(
"uNumber",
true));
modifier.
connect(nurbsNode.findPlug(
"numberV",
true),
tessellatorNode.
findPlug(
"vNumber",
true));
modifier.
connect(nurbsNode.findPlug(
"useChordHeight",
true),
tessellatorNode.
findPlug(
"useChordHeight",
true));
modifier.
connect(nurbsNode.findPlug(
"useChordHeightRatio",
true),
tessellatorNode.
findPlug(
"useChordHeightRatio",
true));
modifier.
connect(nurbsNode.findPlug(
"chordHeight",
true),
tessellatorNode.
findPlug(
"chordHeight",
true));
modifier.
connect(nurbsNode.findPlug(
"chordHeightRatio",
true),
tessellatorNode.
findPlug(
"chordHeightRatio",
true));
modifier.
connect(nurbsNode.findPlug(
"smoothEdge",
true),
tessellatorNode.
findPlug(
"smoothEdge",
true));
modifier.
connect(nurbsNode.findPlug(
"smoothEdgeRatio",
true),
tessellatorNode.
findPlug(
"smoothEdgeRatio",
true));
modifier.
connect(nurbsNode.findPlug(
"edgeSwap",
true),
tessellatorNode.
findPlug(
"edgeSwap",
true));
modifier.
connect(nurbsNode.findPlug(
"local",
true),
tessellatorNode.
findPlug(
"inputSurface",
true));
return mesh;
}
};
class SubdBaker : public MeshDataBaker
{
public:
SubdBaker(
const MObject& subdNode,
const std::vector<MDagPath>& subdPaths)
: MeshDataBaker(subdNode, subdPaths)
{}
protected:
{
if (!*status) return meshData.object();
int format = -1;
int depth = -1;
int sampleCount = -1;
MPlug formatPlug = subdNode.findPlug(
"format",
true);
MPlug depthPlug = subdNode.findPlug(
"depth",
true);
MPlug sampleCountPlug = subdNode.findPlug(
"sampleCount",
true);
subdNode.tesselate(
format==0, depth, sampleCount, meshData.object(), status);
return meshData.object();
}
};
class RecursiveBaker : public Baker
{
public:
RecursiveBaker(
const MObject& shapeNode,
const std::vector<MDagPath>& shapePaths)
: Baker(shapeNode, shapePaths)
{
MPxNode* userNode = fNode.userNode();
assert(userNode);
ShapeNode* bakedNode = userNode ?
dynamic_cast<ShapeNode*>(userNode) : NULL;
assert(bakedNode);
if (bakedNode) {
GlobalReaderCache::theCache().waitForRead(bakedNode->getCacheFileEntry().get());
fSrcTopNode = bakedNode->getCachedGeometry();
if (fSrcTopNode) {
fSampleReplicator.reset(new SampleReplicator);
fSrcTopNode->accept(*fSampleReplicator);
}
}
}
~RecursiveBaker() override
{}
{
if (!fSrcTopNode) {
return MS::kFailure;
}
return fSampleReplicator->sample(time);
}
const SubNode::MPtr getNode(size_t instIndex) const override
{
if (fSrcTopNode && !fDstTopNode) {
HierarchyReplicator hierarchyReplicator(fSampleReplicator);
fSrcTopNode->accept(hierarchyReplicator);
RecursiveBaker* nonConstThis = const_cast<RecursiveBaker*>(this);
nonConstThis->fDstTopNode = hierarchyReplicator.dstSubNode();
}
return fDstTopNode;
}
private:
RecursiveBaker(const RecursiveBaker&);
const RecursiveBaker& operator=(const RecursiveBaker&);
class SampleReplicator : public SubNodeVisitor
{
public:
typedef std::shared_ptr<SampleReplicator> MPtr;
SampleReplicator()
{}
void visit(const XformData& srcXform,
const SubNode& srcSubNode) override
{
XformData::MPtr dstXform = XformData::create();
fXforms[&srcXform] = std::make_pair(
dstXform, std::shared_ptr<const XformSample>());
for(const SubNode::Ptr& srcChild : srcSubNode.getChildren()) {
srcChild->accept(*this);
}
}
void visit(const ShapeData& srcShape,
const SubNode& srcSubNode) override
{
ShapeData::MPtr dstShape = ShapeData::create();
dstShape->setMaterials(srcShape.getMaterials());
fShapes[&srcShape] = std::make_pair(
dstShape, std::shared_ptr<const ShapeSample>());
}
{
for(XformMapping::value_type& xform : fXforms) {
std::shared_ptr<const XformSample> srcXformSample =
xform.first->getSample(time);
if (xform.second.second != srcXformSample) {
std::shared_ptr<XformSample> dstXformSample =
XformSample::create(
srcXformSample->xform(),
srcXformSample->boundingBox(),
srcXformSample->visibility());
xform.second.first->addSample(dstXformSample);
xform.second.second = srcXformSample;
}
}
for(ShapeMapping::value_type& shape : fShapes) {
std::shared_ptr<const ShapeSample> srcShapeSample =
shape.first->getSample(time);
if (shape.second.second != srcShapeSample) {
std::shared_ptr<ShapeSample> dstShapeSample =
ShapeSample::create(
srcShapeSample->numWires(),
srcShapeSample->numVerts(),
srcShapeSample->wireVertIndices(),
srcShapeSample->triangleVertexIndexGroups(),
srcShapeSample->positions(),
srcShapeSample->boundingBox(),
srcShapeSample->diffuseColor(),
srcShapeSample->visibility());
if (srcShapeSample->normals()) {
dstShapeSample->setNormals(srcShapeSample->normals());
}
if (srcShapeSample->uvs()) {
dstShapeSample->setUVs(srcShapeSample->uvs());
}
shape.second.first->addSample(dstShapeSample);
shape.second.second = srcShapeSample;
}
}
return MS::kSuccess;
}
XformData::MPtr xform(const XformData& xform)
{
XformMapping::iterator iter = fXforms.find(&xform);
assert(iter != fXforms.end());
return (*iter).second.first;
}
ShapeData::MPtr shape(const ShapeData& shape)
{
ShapeMapping::iterator iter = fShapes.find(&shape);
assert(iter != fShapes.end());
return (*iter).second.first;
}
private:
SampleReplicator(const SampleReplicator&);
const SampleReplicator& operator=(const SampleReplicator&);
typedef std::pair<XformData::MPtr,std::shared_ptr<const XformSample> > XformWithPrev;
typedef std::pair<ShapeData::MPtr,std::shared_ptr<const ShapeSample> > ShapeWithPrev;
typedef std::map<const XformData*,XformWithPrev> XformMapping;
typedef std::map<const ShapeData*,ShapeWithPrev> ShapeMapping;
XformMapping fXforms;
ShapeMapping fShapes;
};
class HierarchyReplicator : public SubNodeVisitor
{
public:
HierarchyReplicator(SampleReplicator::MPtr sampleReplicator)
: fSampleReplicator(sampleReplicator)
{}
void visit(const XformData& srcXform,
const SubNode& srcSubNode) override
{
XformData::MPtr dstXform = fSampleReplicator->xform(srcXform);
fDstSubNode = SubNode::create(srcSubNode.getName() != "|" ?
srcSubNode.getName() : "top", dstXform);
for(const SubNode::Ptr& srcChild : srcSubNode.getChildren())
{
HierarchyReplicator replicator(fSampleReplicator);
srcChild->accept(replicator);
SubNode::connect(fDstSubNode, replicator.dstSubNode());
}
}
void visit(const ShapeData& srcShape,
const SubNode& srcSubNode) override
{
ShapeData::MPtr dstShape = fSampleReplicator->shape(srcShape);
fDstSubNode = SubNode::create(srcSubNode.getName(), dstShape);
}
SubNode::MPtr dstSubNode() const
{ return fDstSubNode; }
private:
HierarchyReplicator(const HierarchyReplicator&);
const HierarchyReplicator& operator=(const HierarchyReplicator&);
SampleReplicator::MPtr fSampleReplicator;
SubNode::MPtr fDstSubNode;
};
SubNode::Ptr fSrcTopNode;
SubNode::MPtr fDstTopNode;
SampleReplicator::MPtr fSampleReplicator;
};
bool Baker::isBakeable(
const MObject& dagNode)
{
{
return true;
}
return false;
}
std::shared_ptr<Baker> Baker::create(
const MObject& shapeNode,
const std::vector<MDagPath>& shapePaths)
{
return std::make_shared<XformBaker>(shapeNode, shapePaths);
}
return std::make_shared<MeshBaker>(shapeNode, shapePaths);
}
return std::make_shared<NurbsBaker>(shapeNode, shapePaths);
}
return std::make_shared<SubdBaker>(shapeNode, shapePaths);
}
assert(status == MS::kSuccess);
if (shape.
typeId() == ShapeNode::id) {
return std::make_shared<RecursiveBaker>(shapeNode, shapePaths);
}
assert(false);
return std::shared_ptr<Baker>();
}
class Writer
{
public:
Writer(const char compressLevel,
const MTime& timePerCycle,
: fCompressLevel(compressLevel),
fDataFormat(dataFormat),
{}
Writer(const Writer&) = delete;
Writer& operator=(const Writer&) = delete;
MStatus writeNode(
const SubNode::Ptr& subNode,
const MaterialGraphMap::Ptr& materials,
{
std::shared_ptr<CacheWriter> writer = createWriter(
targetFile,
fCompressLevel,
fDataFormat
);
if (!writer) {
return MS::kFailure;
}
writer->writeSubNodeHierarchy(
subNode,
fTimePerCycleInSeconds, fStartTimeInSeconds);
if (materials) {
writer->writeMaterials(
materials,
fTimePerCycleInSeconds, fStartTimeInSeconds);
}
return MS::kSuccess;
}
MStatus writeNodes(
const std::vector<SubNode::Ptr>& subNodes,
const MaterialGraphMap::Ptr& materials,
{
std::shared_ptr<CacheWriter> writer = createWriter(
targetFile,
fCompressLevel,
fDataFormat
);
if (!writer) {
return MS::kFailure;
}
for(const SubNode::Ptr& subNode : subNodes) {
writer->writeSubNodeHierarchy(
subNode,
fTimePerCycleInSeconds,
fStartTimeInSeconds);
}
if (materials) {
writer->writeMaterials(materials,
fTimePerCycleInSeconds, fStartTimeInSeconds);
}
return MS::kSuccess;
}
private:
const char fCompressLevel;
const double fTimePerCycleInSeconds;
const double fStartTimeInSeconds;
};
class Stat
{
public:
Stat(MUint64 bytesPerUnit)
: fMin(std::numeric_limits<MUint64>::max()),
fMax(0),
fTotal(0),
fInstancedTotal(0),
fBytesPerUnit(bytesPerUnit)
{}
void addSample(
const std::shared_ptr<const IndexBuffer> buffer, const int indicesPerElem)
{
addSample(buffer->numIndices() / indicesPerElem, buffer.get());
};
void addSample(
const std::shared_ptr<const VertexBuffer> buffer)
{
addSample(buffer->numVerts(), buffer.get());
};
void addSample(
{
addSample(numIndices, (void*)buffer);
}
void addSample(
{
addSample(numVertices, (void*)buffer);
}
void addSample(
const std::shared_ptr<const VBOBuffer> buffer, size_t numPrimitives)
{
addSample(numPrimitives, buffer.get());
}
MUint64 getNbSamples() const { return fUniqueEntries.size(); }
MUint64 getMin() const { return fMin;}
MUint64 getMax() const { return fMin;}
MUint64 getTotal() const { return fTotal;}
MUint64 getInstancedTotal() const { return fInstancedTotal;}
double getAverage() const {
return double(getTotal())/double(getNbSamples());
}
MUint64 getSize() const {
return fTotal * fBytesPerUnit;
}
{
if (getNbSamples() == 0) {
name);
result = msg;
}
else {
double memSize = toHumanUnits(getSize(), memUnit);
MString msg_buffers; msg_buffers += (double)getNbSamples();
MString msg_avrg; msg_avrg += (double)getAverage();
MString msg_min; msg_min += (double)fMin;
MString msg_max; msg_max += (double)fMax;
MString msg_total; msg_total += (double)fTotal;
MString msg_memSize; msg_memSize += memSize;
name, msg_buffers, msg_avrg,
msg_min, msg_max, msg_total, msg_memSize, memUnit);
result = msg;
}
return result;
}
private:
void addSample(MUint64 value, const void* buffer)
{
if (fUniqueEntries.insert(buffer).second) {
fMin = std::min(fMin, value);
fMax = std::max(fMax, value);
fTotal += value;
}
fInstancedTotal += value;
};
std::unordered_set<const void*> fUniqueEntries;
MUint64 fMin;
MUint64 fMax;
MUint64 fTotal;
const MUint64 fBytesPerUnit;
MUint64 fInstancedTotal;
};
class Stats
{
public:
Stats()
: fNbNodes(0),
fNbSubNodes(0),
fWires( 2 * sizeof(IndexBuffer::index_t)),
fTriangles( 3 * sizeof(IndexBuffer::index_t)),
fVerts( 3 * sizeof(float)),
fNormals( 3 * sizeof(float)),
fUVs( 2 * sizeof(float)),
fVP2Index( sizeof(IndexBuffer::index_t)),
fVP2Vertex( sizeof(float)),
fVBOIndex( sizeof(IndexBuffer::index_t)),
fVBOVertex( sizeof(float)),
fNbMaterialGraphs(0),
fNbMaterialNodes(0)
{}
void accumulateNode()
{
++fNbNodes;
}
void accumulateMaterialGraph(const MaterialGraph::Ptr&)
{
++fNbMaterialGraphs;
}
void accumulateMaterialNode(const MaterialNode::Ptr&)
{
++fNbMaterialNodes;
}
void accumulate(const ShapeData& shape)
{
++fNbSubNodes;
for(const ShapeData::SampleMap::value_type& v :
shape.getSamples()) {
accumSample(v.second);
}
}
void accumulate(const ShapeData& shape,
{
++fNbSubNodes;
accumSample(shape.getSample(time));
}
void print(
MStringArray& result,
bool printInstancedInfo)
const
{
{
MString msg_nbGeom; msg_nbGeom += fNbNodes;
MString msg_nbSubNodes; msg_nbSubNodes += fNbSubNodes;
msg_nbGeom, msg_nbSubNodes);
}
if (printInstancedInfo) {
MString msgInstWires; msgInstWires += (double)fWires.getInstancedTotal();
MString msgInstTris; msgInstTris += (double)fTriangles.getInstancedTotal();
msgInstWires, msgInstTris);
}
{
MUint64 totalMem = (fWires.getSize() +
fTriangles.getSize() +
fVerts.getSize() +
fNormals.getSize() +
fUVs.getSize());
double memSize = toHumanUnits(totalMem, memUnit);
MString msg_memSize; msg_memSize += memSize;
msg_memSize, memUnit);
}
{
MUint64 totalMem = (fVBOIndex.getSize() + fVBOVertex.getSize());
if (Config::vp2OverrideAPI() != Config::kMPxDrawOverride) {
totalMem += (fVP2Index.getSize() + fVP2Vertex.getSize());
}
double memSize = toHumanUnits(totalMem, memUnit);
MString msg_memSize; msg_memSize += memSize;
msg_memSize, memUnit);
}
{
msg_nbGraphs += fNbMaterialGraphs;
msg_nbNodes += fNbMaterialNodes;
msg_nbGraphs, msg_nbNodes);
}
}
private:
void accumSample(const std::shared_ptr<const ShapeSample>& sample) {
accumIndexBuffer(fWires, sample->wireVertIndices(), 2);
for(size_t i=0; i<sample->numIndexGroups(); ++i) {
accumIndexBuffer(fTriangles, sample->triangleVertIndices(i), 3);
}
accumVertexBuffer(fVerts, sample->positions());
accumVertexBuffer(fNormals, sample->normals());
accumVertexBuffer(fUVs, sample->uvs());
}
void accumIndexBuffer(
Stat& stat,
const std::shared_ptr<const IndexBuffer> indexBuffer,
const int indicesPerElem
)
{
if (indexBuffer && indexBuffer != UnitBoundingBox::indices()) {
stat.addSample(indexBuffer, indicesPerElem);
{
SubSceneOverride::lookup(indexBuffer);
if (vp2Buffer)
fVP2Index.addSample(vp2Buffer, indexBuffer->numIndices());
}
{
std::shared_ptr<const VBOBuffer> vboBuffer =
VBOBuffer::lookup(indexBuffer);
if (vboBuffer)
fVBOIndex.addSample(vboBuffer, indexBuffer->numIndices());
}
}
}
void accumVertexBuffer(
Stat& stat,
const std::shared_ptr<const VertexBuffer> vertexBuffer
)
{
if (vertexBuffer && vertexBuffer != UnitBoundingBox::positions()) {
stat.addSample(vertexBuffer);
{
SubSceneOverride::lookup(vertexBuffer);
if (vp2Buffer)
fVP2Vertex.addSample(
vp2Buffer, 3 * vertexBuffer->numVerts());
}
{
std::shared_ptr<const VBOBuffer> vboBuffer =
VBOBuffer::lookup(vertexBuffer);
if (vboBuffer)
fVBOVertex.addSample(
vboBuffer, 3 * vertexBuffer->numVerts());
}
{
std::shared_ptr<const VBOBuffer> vboBuffer =
VBOBuffer::lookupFlippedNormals(vertexBuffer);
if (vboBuffer)
fVBOVertex.addSample(
vboBuffer, 3 * vertexBuffer->numVerts());
}
}
}
int fNbNodes;
int fNbSubNodes;
Stat fWires;
Stat fTriangles;
Stat fVerts;
Stat fNormals;
Stat fUVs;
Stat fVP2Index;
Stat fVP2Vertex;
Stat fVBOIndex;
Stat fVBOVertex;
int fNbMaterialGraphs;
int fNbMaterialNodes;
};
class StatsVisitor : public SubNodeVisitor
{
public:
StatsVisitor() : fAtGivenTime(false) {}
StatsVisitor(
MTime time) : fAtGivenTime(
true), fTime(time) {}
void accumulateNode(const SubNode::Ptr& topNode)
{
fStats.accumulateNode();
if (topNode) {
topNode->accept(*this);
}
}
void accumulateMaterialGraph(const MaterialGraphMap::Ptr& materials)
{
if (materials) {
for(
const MaterialGraphMap::NamedMap::value_type& val :
materials->getGraphs()) {
fStats.accumulateMaterialGraph(val.second);
accumulateMaterialNode(val.second);
}
}
}
void accumulateMaterialNode(const MaterialGraph::Ptr& material)
{
if (material) {
for(
const MaterialGraph::NamedMap::value_type& val :
material->getNodes()) {
fStats.accumulateMaterialNode(val.second);
}
}
}
void print(
MStringArray& result,
bool printInstancedInfo)
const
{
fStats.print(result, printInstancedInfo);
}
private:
void visit(const XformData& ,
const SubNode& subNode) override
{
for(const SubNode::Ptr& child :
subNode.getChildren() ) {
child->accept(*this);
}
}
void visit(const ShapeData& shape,
const SubNode& ) override
{
if (fAtGivenTime) {
fStats.accumulate(shape, fTime);
}
else {
fStats.accumulate(shape);
}
}
const bool fAtGivenTime;
Stats fStats;
};
class DumpHierarchyVisitor : public SubNodeVisitor
{
public:
: fResult(result),
fLevel(0)
{}
void visit(const XformData& xform,
const SubNode& subNode) override
{
using namespace std;
{
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "xform name = " << subNode.getName().asChar()
<< ", tt = " << subNode.transparentType()
<< ", ptr = " << (void*)&subNode
<< " {" << ends;
fResult.append(
MString(tmp.str().c_str()));
}
++fLevel;
{
std::string indent(kIndent*fLevel, ' ');
for(const XformData::SampleMap::value_type& sample :
xform.getSamples()) {
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "time = " << setw(10) << sample.first
<< ", ptr = " << (void*)sample.second.get()
<< ", vis = " << sample.second->visibility()
<< ", bbox = ("
<< setw(8) << sample.second->boundingBox().min().x << ","
<< setw(8) << sample.second->boundingBox().min().y << ","
<< setw(8) << sample.second->boundingBox().min().z << ") - ("
<< setw(8) << sample.second->boundingBox().max().x << ","
<< setw(8) << sample.second->boundingBox().max().y << ","
<< setw(8) << sample.second->boundingBox().max().z << ")"
<< ends;
fResult.append(
MString(tmp.str().c_str()));
}
for(const SubNode::Ptr& child :
subNode.getChildren() ) {
child->accept(*this);
}
}
--fLevel;
{
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "}" << ends;
fResult.append(
MString(tmp.str().c_str()));
}
}
void visit(const ShapeData& shape,
const SubNode& subNode) override
{
using namespace std;
{
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "shape name = " << subNode.getName().asChar()
<< ", tt = " << subNode.transparentType()
<< ", ptr = " << (void*)&subNode
<< " {" << ends;
fResult.append(
MString(tmp.str().c_str()));
}
++fLevel;
{
std::string indent(kIndent*fLevel, ' ');
for(const ShapeData::SampleMap::value_type& sample :
shape.getSamples()) {
{
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "time = " << setw(10) << sample.first
<< ", ptr = " << (void*)sample.second.get()
<< ", vis = " << sample.second->visibility()
<< ", nT = " << sample.second->numTriangles()
<< ", nW = " << sample.second->numWires()
<< ", nV = " << sample.second->numVerts()
<< "," << ends;
fResult.append(
MString(tmp.str().c_str()));
}
{
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "P = " << (void*)sample.second->positions().get()
<< ", N = " << (void*)sample.second->normals().get()
<< "," << ends;
fResult.append(
MString(tmp.str().c_str()));
}
{
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "C = ("
<< setw(8) << sample.second->diffuseColor()[0] << ","
<< setw(8) << sample.second->diffuseColor()[1] << ","
<< setw(8) << sample.second->diffuseColor()[2] << ","
<< setw(8) << sample.second->diffuseColor()[3] << ","
<< "), bbox = ("
<< setw(8) << sample.second->boundingBox().min().x << ","
<< setw(8) << sample.second->boundingBox().min().y << ","
<< setw(8) << sample.second->boundingBox().min().z << ") - ("
<< setw(8) << sample.second->boundingBox().max().x << ","
<< setw(8) << sample.second->boundingBox().max().y << ","
<< setw(8) << sample.second->boundingBox().max().z << ")"
<< ends;
fResult.append(
MString(tmp.str().c_str()));
}
{
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "bbox place holder = " << (sample.second->isBoundingBoxPlaceHolder() ? "yes" : "no")
<< ends;
fResult.append(
MString(tmp.str().c_str()));
}
}
}
if (!shape.getMaterials().empty()) {
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "materials = ";
for(
const MString& material : shape.getMaterials()) {
tmp << material.asChar() << ' ';
}
tmp << ends;
fResult.append(
MString(tmp.str().c_str()));
}
--fLevel;
{
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "}" << ends;
fResult.append(
MString(tmp.str().c_str()));
}
}
private:
static const int kIndent = 2;
int fLevel;
};
class DumpMaterialVisitor
{
public:
: fResult(result),
fLevel(0)
{}
void dumpMaterials(const MaterialGraphMap::Ptr& materials)
{
using namespace std;
for(const MaterialGraphMap::NamedMap::value_type& val : materials->getGraphs())
{
const MaterialGraph::Ptr& graph = val.second;
{
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "material graph name = " << graph->name().asChar()
<< ", nNodes = " << graph->getNodes().size()
<< ", ptr = " << (void*)graph.get()
<< " {" << ends;
fResult.append(
MString(tmp.str().c_str()));
}
++fLevel;
for(const MaterialGraph::NamedMap::value_type& val : graph->getNodes())
{
dumpMaterialNode(val.second);
}
--fLevel;
{
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "}" << ends;
fResult.append(
MString(tmp.str().c_str()));
}
}
}
void dumpMaterialNode(const MaterialNode::Ptr& node)
{
using namespace std;
{
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "material node name = " << node->name().asChar()
<< ", type = " << node->type()
<< ", ptr = " << (void*)node.get()
<< " {" << ends;
fResult.append(
MString(tmp.str().c_str()));
}
++fLevel;
for(const MaterialNode::PropertyMap::value_type& val : node->properties())
{
dumpMaterialProperty(val.second);
}
--fLevel;
{
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "}" << ends;
fResult.append(
MString(tmp.str().c_str()));
}
}
void dumpMaterialProperty(const MaterialProperty::Ptr& prop)
{
using namespace std;
{
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "prop name = " << prop->name().asChar()
<< ", type = " << propertyTypeString(prop)
<< ", ptr = " << (void*)prop.get()
<< " {" << ends;
fResult.append(
MString(tmp.str().c_str()));
}
++fLevel;
for(const MaterialProperty::SampleMap::value_type& val : prop->getSamples())
{
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "time = " << setw(10) << val.first
<< ", value = " << propertyValueString(val.first, prop)
<< ", ptr = " << (void*)val.second.get()
<< ends;
fResult.append(
MString(tmp.str().c_str()));
}
const MaterialNode::Ptr srcNode = prop->srcNode();
const MaterialProperty::Ptr srcProp = prop->srcProp();
if (srcNode && srcProp) {
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "src node = " << srcNode->name().asChar()
<< ", src prop = " << srcProp->name().asChar()
<< ends;
fResult.append(
MString(tmp.str().c_str()));
}
--fLevel;
{
ostringstream tmp;
tmp << setw(kIndent*fLevel) << ' '
<< "}" << ends;
fResult.append(
MString(tmp.str().c_str()));
}
}
std::string propertyTypeString(const MaterialProperty::Ptr& prop)
{
switch (prop->type()) {
case MaterialProperty::kBool: return "bool";
case MaterialProperty::kInt32: return "int32";
case MaterialProperty::kFloat: return "float";
case MaterialProperty::kFloat2: return "float2";
case MaterialProperty::kFloat3: return "float3";
case MaterialProperty::kRGB: return "rgb";
case MaterialProperty::kString: return "string";
default: assert(0); return "unknown";
}
}
std::string propertyValueString(double seconds, const MaterialProperty::Ptr& prop)
{
std::ostringstream tmp;
switch (prop->type()) {
case MaterialProperty::kBool:
tmp << (prop->asBool(seconds) ? "true" : "false");
break;
case MaterialProperty::kInt32:
tmp << prop->asInt32(seconds);
break;
case MaterialProperty::kFloat:
tmp << prop->asFloat(seconds);
break;
case MaterialProperty::kFloat2:
{
float x, y;
prop->asFloat2(seconds, x, y);
tmp << "(" << x << "," << y << ")";
break;
}
case MaterialProperty::kFloat3:
{
float x, y, z;
prop->asFloat3(seconds, x, y, z);
tmp << "(" << x << "," << y << "," << z << ")";
break;
}
case MaterialProperty::kRGB:
{
MColor c = prop->asColor(seconds);
tmp <<
"rgb(" << c.
r <<
"," << c.
g <<
"," << c.
b <<
")";
break;
}
case MaterialProperty::kString:
tmp << prop->asString(seconds).asChar();
break;
default:
assert(0);
tmp << "unknown type";
break;
}
return tmp.str();
}
private:
static const int kIndent = 2;
int fLevel;
};
class ProgressBar
{
public:
{
reset(msg, max);
}
{
}
~ProgressBar()
{
endProgress();
}
void stepProgress() const
{
if (fShowProgress) {
}
}
bool isCancelled() const
{
int isCancelled = 0;
if (fShowProgress) {
}
if (isCancelled) {
return true;
}
return false;
}
private:
ProgressBar(const ProgressBar&);
const ProgressBar& operator=(const ProgressBar&);
ProgressBar(
const MString& msg,
unsigned int max)
{
beginProgress(msg, max);
}
void beginProgress(
const MString& msg,
unsigned int max)
const
{
if (fShowProgress) {
if (max <= 0) {
max = 1;
}
maxValue += max;
progressBarCmd.
format(
"progressBar -e -bp -ii 1 -st \"^1s\" -max ^2s $gMainProgressBar",
msg, maxValue);
}
}
void endProgress() const
{
if (fShowProgress) {
}
}
bool fShowProgress;
};
class GroupCreator
{
public:
GroupCreator() {}
~GroupCreator() {}
void addChild(const SubNode::MPtr& childNode)
{
XformData::Ptr childXform = std::dynamic_pointer_cast<const XformData>(
childNode->getData());
assert(childXform);
if (childXform) {
fChildNodes.push_back(childNode);
fChildXforms.push_back(childXform);
}
}
void group()
{
assert(!fGroup);
fGroup = XformData::create();
std::set<double> times;
for(const XformData::Ptr child : fChildXforms) {
for(const XformData::SampleMap::value_type& val : child->getSamples()) {
times.insert(val.first);
}
}
std::set<double>::const_iterator timeIt = times.begin();
std::set<double>::const_iterator timeEnd = times.end();
if (timeIt != timeEnd) {
fGroup->addSample(XformSample::create(
*timeIt,
true));
}
}
SubNode::MPtr getSubNode(
const MString& name)
{
SubNode::MPtr subNode = SubNode::create(name, fGroup);
for(const SubNode::MPtr& childNode : fChildNodes) {
SubNode::connect(subNode, childNode);
}
return subNode;
}
private:
GroupCreator(const GroupCreator&);
const GroupCreator& operator= (const GroupCreator&);
std::vector<SubNode::MPtr> fChildNodes;
std::vector<XformData::Ptr> fChildXforms;
XformData::MPtr fGroup;
};
class XformFreezer : public SubNodeVisitor
{
public:
typedef std::vector<ShapeData::Ptr> FrozenGeometries;
typedef std::vector<std::pair<XformData::Ptr,ShapeData::Ptr> > AnimatedGeometries;
typedef std::set<double> TimeSet;
XformFreezer(const XformData::Ptr& parentXform,
FrozenGeometries& frozenGeometries,
bool dontFreezeAnimatedObjects,
AnimatedGeometries& animatedGeometries)
: fParentXform(parentXform),
fFrozenGeometries(frozenGeometries),
fDontFreezeAnimatedObjects(dontFreezeAnimatedObjects),
fAnimatedGeometries(animatedGeometries)
{}
void visit(const XformData& xform,
const SubNode& subNode) override
{
TimeSet times;
for(const XformData::SampleMap::value_type& val :
fParentXform->getSamples() ) {
times.insert(val.first);
}
for(const XformData::SampleMap::value_type& val :
xform.getSamples()) {
times.insert(val.first);
}
XformData::MPtr frozenXform = XformData::create();
for(const double& time : times) {
std::shared_ptr<const XformSample> parentSample =
fParentXform->getSample(time);
std::shared_ptr<const XformSample> sample =
xform.getSample(time);
frozenXform->addSample(XformSample::create(
time,
sample->xform() * parentSample->xform(),
sample->visibility() && parentSample->visibility()));
}
for(const SubNode::Ptr& child : subNode.getChildren()) {
XformFreezer xformFreezer(frozenXform, fFrozenGeometries,
fDontFreezeAnimatedObjects, fAnimatedGeometries);
child->accept(xformFreezer);
}
}
void visit(const ShapeData& shape,
const SubNode& subNode) override
{
if (fDontFreezeAnimatedObjects) {
if (fParentXform->getSamples().size() > 1 && shape.getSamples().size() <= 1) {
XformData::MPtr animatedXform = XformData::create();
for(const XformData::SampleMap::value_type& val :
fParentXform->getSamples()) {
animatedXform->addSample(val.second);
}
ShapeData::MPtr animatedShape = ShapeData::create();
for(const ShapeData::SampleMap::value_type& val :
shape.getSamples()) {
animatedShape->addSample(val.second);
}
animatedShape->setMaterials(shape.getMaterials());
fAnimatedGeometries.push_back(
std::make_pair(animatedXform, animatedShape));
return;
}
}
TimeSet times;
for(const XformData::SampleMap::value_type& val :
fParentXform->getSamples()) {
times.insert(val.first);
}
for(const ShapeData::SampleMap::value_type& val :
shape.getSamples()) {
times.insert(val.first);
}
ShapeData::MPtr frozenShape = ShapeData::create();
TimeSet::const_iterator it = times.begin();
TimeSet::const_iterator end = times.end();
if (it != end) {
std::shared_ptr<const XformSample> xformSample =
fParentXform->getSample(*it);
std::shared_ptr<const ShapeSample> shapeSample =
shape.getSample(*it);
std::shared_ptr<const ShapeSample> frozenSample;
if (xformSample->visibility() && shapeSample->visibility()) {
frozenSample = freezeSample(*it, xformSample, shapeSample);
}
else {
frozenSample = ShapeSample::createEmptySample(*it);
}
frozenShape->addSample(frozenSample);
++it;
for (; it != end; ++it) {
std::shared_ptr<const XformSample> prevXformSample = xformSample;
std::shared_ptr<const ShapeSample> prevShapeSample = shapeSample;
xformSample = fParentXform->getSample(*it);
shapeSample = shape.getSample(*it);
if (xformSample->visibility() && shapeSample->visibility()) {
if (!xformSample->xform().isEquivalent(prevXformSample->xform()) ||
xformSample->visibility() != prevXformSample->visibility() ||
shapeSample->wireVertIndices() != prevShapeSample->wireVertIndices() ||
shapeSample->triangleVertexIndexGroups() != prevShapeSample->triangleVertexIndexGroups() ||
shapeSample->positions() != prevShapeSample->positions() ||
shapeSample->normals() != prevShapeSample->normals() ||
shapeSample->diffuseColor() != prevShapeSample->diffuseColor() ||
shapeSample->visibility() != prevShapeSample->visibility())
{
frozenSample = freezeSample(*it, xformSample, shapeSample);
}
else {
std::shared_ptr<ShapeSample> newFrozenSample =
ShapeSample::create(
*it,
shapeSample->numWires(),
shapeSample->numVerts(),
shapeSample->wireVertIndices(),
shapeSample->triangleVertexIndexGroups(),
frozenSample->positions(),
frozenSample->boundingBox(),
shapeSample->diffuseColor(),
xformSample->visibility() && shapeSample->visibility());
newFrozenSample->setNormals(frozenSample->normals());
newFrozenSample->setUVs(shapeSample->uvs());
frozenSample = newFrozenSample;
}
}
else {
frozenSample = ShapeSample::createEmptySample(*it);
}
frozenShape->addSample(frozenSample);
}
}
frozenShape->setMaterials(shape.getMaterials());
fFrozenGeometries.push_back(frozenShape);
}
private:
std::shared_ptr<const ShapeSample> freezeSample(
const double time,
const std::shared_ptr<const XformSample>& xform,
const std::shared_ptr<const ShapeSample>& shape)
{
const size_t numWires = shape->numWires();
const size_t numVerts = shape->numVerts();
std::shared_ptr<IndexBuffer> wireVertIndices =
shape->wireVertIndices();
std::vector<std::shared_ptr<IndexBuffer> > triangleVertexIndexGroups =
shape->triangleVertexIndexGroups();
std::shared_ptr<VertexBuffer> uvs =
shape->uvs();
MColor diffuseColor = shape->diffuseColor();
bool visibility = shape->visibility() && xform->visibility();
if (numWires == 0 || numVerts == 0 || !wireVertIndices ||
triangleVertexIndexGroups.empty()) {
return ShapeSample::createEmptySample(time);
}
std::shared_ptr<VertexBuffer> positions;
std::shared_ptr<VertexBuffer> normals;
MMatrix xformMatrix = xform->xform();
positions = shape->positions();
normals = shape->normals();
boundingBox = shape->boundingBox();
}
else {
float xform[4][4];
float xformIT[4][4];
const bool isReflection = xformMatrix.
det3x3() < 0.0;
if (isReflection) {
std::vector<std::shared_ptr<IndexBuffer> > newTriangleVertexIndexGroups;
for(const std::shared_ptr<IndexBuffer>& srcIdxBuf :
triangleVertexIndexGroups) {
typedef IndexBuffer::index_t index_t;
const size_t numIndices = srcIdxBuf->numIndices();
IndexBuffer::ReadInterfacePtr readable = srcIdxBuf->readableInterface();
const index_t* srcIndices = readable->get();
const GPUCache::shared_array<IndexBuffer::index_t> dstIndices(
new index_t[numIndices]);
for (size_t i=0; i<numIndices; i+=3) {
dstIndices[i + 0] = srcIndices[i + 2];
dstIndices[i + 1] = srcIndices[i + 1];
dstIndices[i + 2] = srcIndices[i + 0];
}
std::shared_ptr<IndexBuffer> dstIdxBuf(
IndexBuffer::create(
SharedArray<index_t>::create(dstIndices, numIndices)));
newTriangleVertexIndexGroups.push_back(dstIdxBuf);
}
triangleVertexIndexGroups.swap(newTriangleVertexIndexGroups);
}
VertexBuffer::ReadInterfacePtr srcPosRead = shape->positions()->readableInterface();
const float* srcPositions = srcPosRead->get();
VertexBuffer::ReadInterfacePtr srcNormRead = shape->normals()->readableInterface();
const float* srcNormals = srcNormRead->get();
GPUCache::shared_array<float> dstPositions(new float[3 * numVerts]);
GPUCache::shared_array<float> dstNormals(new float[3 * numVerts]);
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();
for (size_t i=0; i<numVerts; ++i) {
const float x = srcPositions[3*i + 0];
const float y = srcPositions[3*i + 1];
const float z = srcPositions[3*i + 2];
const float xp =
xform[0][0] * x + xform[1][0] * y + xform[2][0] * z + xform[3][0];
const float yp =
xform[0][1] * x + xform[1][1] * y + xform[2][1] * z + xform[3][1];
const float zp =
xform[0][2] * x + xform[1][2] * y + xform[2][2] * z + xform[3][2];
minX = std::min(xp, minX);
minY = std::min(yp, minY);
minZ = std::min(zp, minZ);
maxX = std::max(xp, maxX);
maxY = std::max(yp, maxY);
maxZ = std::max(zp, maxZ);
dstPositions[3*i + 0] = xp;
dstPositions[3*i + 1] = yp;
dstPositions[3*i + 2] = zp;
const float nx = srcNormals[3*i + 0];
const float ny = srcNormals[3*i + 1];
const float nz = srcNormals[3*i + 2];
dstNormals[3*i + 0] =
xformIT[0][0] * nx + xformIT[1][0] * ny + xformIT[2][0] * nz + xformIT[3][0];
dstNormals[3*i + 1] =
xformIT[0][1] * nx + xformIT[1][1] * ny + xformIT[2][1] * nz + xformIT[3][1];
dstNormals[3*i + 2] =
xformIT[0][2] * nx + xformIT[1][2] * ny + xformIT[2][2] * nz + xformIT[3][2];
}
positions = VertexBuffer::createPositions(
SharedArray<float>::create(dstPositions, 3 * numVerts));
normals = VertexBuffer::createNormals(
SharedArray<float>::create(dstNormals, 3 * numVerts));
}
std::shared_ptr<ShapeSample> frozenSample =
ShapeSample::create(
time,
numWires,
numVerts,
wireVertIndices,
triangleVertexIndexGroups,
positions,
boundingBox,
diffuseColor,
visibility);
frozenSample->setNormals(normals);
frozenSample->setUVs(uvs);
return frozenSample;
}
XformFreezer(const XformFreezer&);
const XformFreezer& operator= (const XformFreezer&);
XformData::Ptr fParentXform;
FrozenGeometries& fFrozenGeometries;
AnimatedGeometries& fAnimatedGeometries;
bool fDontFreezeAnimatedObjects;
};
class ConsolidateBuckets
{
public:
struct BucketKey
{
typedef std::map<double,MColor> DiffuseColorMap;
typedef std::map<double,bool> VisibilityMap;
typedef std::map<double,size_t> IndexGroupMap;
typedef std::vector<MString> MaterialsAssignment;
BucketKey(const ShapeData::Ptr& shape)
{
ShapeData::SampleMap::const_iterator it = shape->getSamples().begin();
ShapeData::SampleMap::const_iterator end = shape->getSamples().end();
if (it != end) {
MColor diffuseColor = (*it).second->diffuseColor();
bool visibility = (*it).second->visibility();
size_t indexGroups = (*it).second->numIndexGroups();
fDiffuseColor[(*it).first] = diffuseColor;
fVisibility[(*it).first] = visibility;
fIndexGroup[(*it).first] = indexGroups;
++it;
for (; it != end; ++it) {
MColor prevDiffuseColor = diffuseColor;
bool prevVisibility = visibility;
size_t prevIndexGroups = indexGroups;
MColor diffuseColor = (*it).second->diffuseColor();
bool visibility = (*it).second->visibility();
size_t indexGroups = (*it).second->numIndexGroups();
if (prevDiffuseColor != diffuseColor) {
fDiffuseColor[(*it).first] = diffuseColor;
}
if (prevVisibility != visibility) {
fVisibility[(*it).first] = visibility;
}
if (prevIndexGroups != indexGroups) {
fIndexGroup[(*it).first] = indexGroups;
}
}
}
fMaterials = shape->getMaterials();
}
struct Hash : std::unary_function<BucketKey, std::size_t>
{
std::size_t operator()(const BucketKey& key) const
{
std::size_t seed = 0;
for(const DiffuseColorMap::value_type& val : key.fDiffuseColor) {
GPUCache::hash_combine(seed, val.first);
GPUCache::hash_combine(seed, val.second.r);
GPUCache::hash_combine(seed, val.second.g);
GPUCache::hash_combine(seed, val.second.b);
GPUCache::hash_combine(seed, val.second.a);
}
for(const VisibilityMap::value_type& val : key.fVisibility) {
GPUCache::hash_combine(seed, val.first);
GPUCache::hash_combine(seed, val.second);
}
for(const IndexGroupMap::value_type& val : key.fIndexGroup) {
GPUCache::hash_combine(seed, val.first);
GPUCache::hash_combine(seed, val.second);
}
for(
const MString& material : key.fMaterials) {
unsigned int length = material.
length();
const char* begin = material.
asChar();
size_t hash = GPUCache::hash_range(begin, begin + length);
GPUCache::hash_combine(seed, hash);
}
return seed;
}
};
struct EqualTo : std::binary_function<BucketKey, BucketKey, bool>
{
bool operator()(const BucketKey& x, const BucketKey& y) const
{
return x.fDiffuseColor == y.fDiffuseColor &&
x.fVisibility == y.fVisibility &&
x.fIndexGroup == y.fIndexGroup &&
x.fMaterials == y.fMaterials;
}
};
DiffuseColorMap fDiffuseColor;
VisibilityMap fVisibility;
IndexGroupMap fIndexGroup;
MaterialsAssignment fMaterials;
};
typedef std::multimap<size_t,ShapeData::Ptr> Bucket;
typedef std::unordered_map<BucketKey,Bucket,BucketKey::Hash,BucketKey::EqualTo> BucketMap;
typedef std::list<Bucket> BucketList;
ConsolidateBuckets(const XformFreezer::FrozenGeometries& shapes)
: fShapes(shapes)
{}
void divide()
{
for(const ShapeData::Ptr& shape : fShapes) {
BucketKey key(shape);
std::pair<BucketMap::iterator,bool> ret =
fBucketMap.insert(std::make_pair(key, Bucket()));
ret.first->second.insert(std::make_pair(maxNumVerts(shape), shape));
}
}
void getBucketList(BucketList& bucketList)
{
bucketList.clear();
for(const BucketMap::value_type& val : fBucketMap) {
bucketList.push_back(val.second);
}
}
private:
ConsolidateBuckets(const ConsolidateBuckets&);
const ConsolidateBuckets& operator= (const ConsolidateBuckets&);
const XformFreezer::FrozenGeometries& fShapes;
BucketMap fBucketMap;
};
class FirstSampleTime : public SubNodeVisitor
{
public:
FirstSampleTime()
: fTime(0)
{}
void visit(const XformData& xform,
const SubNode& subNode) override
{
fTime = xform.getSamples().begin()->first;
}
void visit(const ShapeData& shape,
const SubNode& subNode) override
{
fTime = shape.getSamples().begin()->first;
}
double get()
{ return fTime; }
private:
FirstSampleTime(const FirstSampleTime&);
const FirstSampleTime& operator= (const FirstSampleTime&);
double fTime;
};
class Consolidator
{
public:
Consolidator(SubNode::MPtr rootNode, const int threshold, const bool motionBlur)
: fRootNode(rootNode), fThreshold(threshold), fMotionBlur(motionBlur)
{}
~Consolidator()
{}
{
double firstSampleTime = 0;
{
FirstSampleTime firstSampleTimeVisitor;
fRootNode->accept(firstSampleTimeVisitor);
firstSampleTime = firstSampleTimeVisitor.get();
}
XformFreezer::FrozenGeometries frozenGeometries;
XformFreezer::AnimatedGeometries animatedGeometries;
{
XformData::MPtr identityXformData = XformData::create();
identityXformData->addSample(XformSample::create(
firstSampleTime,
true));
XformFreezer xformFreezer(identityXformData, frozenGeometries,
fMotionBlur, animatedGeometries);
fRootNode->accept(xformFreezer);
}
ConsolidateBuckets::BucketList bucketList;
{
ConsolidateBuckets buckets(frozenGeometries);
buckets.divide();
buckets.getBucketList(bucketList);
}
ProgressBar progressBar(kOptimizingMsg, (unsigned int)frozenGeometries.size());
std::vector<ShapeData::Ptr> newShapes;
std::vector<ShapeData::Ptr> consolidatedShapes;
for(ConsolidateBuckets::Bucket& bucket : bucketList) {
while (!bucket.empty()) {
const ConsolidateBuckets::Bucket::iterator largestNode = --bucket.end();
MInt64 numRemainingVerts = fThreshold - largestNode->first;
if (numRemainingVerts < 0) {
newShapes.push_back(largestNode->second);
bucket.erase(largestNode);
MUpdateProgressAndCheckInterruption(progressBar);
}
else {
consolidatedShapes.push_back(largestNode->second);
bucket.erase(largestNode);
MUpdateProgressAndCheckInterruption(progressBar);
while (numRemainingVerts > 0 && !bucket.empty()) {
ConsolidateBuckets::Bucket::iterator node =
bucket.upper_bound((size_t)numRemainingVerts);
if (node == bucket.begin()) break;
--node;
numRemainingVerts -= (MInt64)node->first;
consolidatedShapes.push_back(node->second);
bucket.erase(node);
MUpdateProgressAndCheckInterruption(progressBar);
}
consolidateGeometry(newShapes, consolidatedShapes);
}
}
}
std::vector<XformData::Ptr> newXforms;
for(const ShapeData::Ptr& newShape : newShapes) {
XformData::MPtr newXform = XformData::create();
ShapeData::SampleMap::const_iterator it = newShape->getSamples().begin();
ShapeData::SampleMap::const_iterator end = newShape->getSamples().end();
if (it != end) {
newXform->addSample(XformSample::create(
(*it).first,
true));
}
newXforms.push_back(newXform);
}
std::vector<std::pair<XformData::Ptr,ShapeData::Ptr> > finalXformsAndShapes;
for (size_t i = 0; i < newXforms.size(); i++) {
finalXformsAndShapes.push_back(std::make_pair(newXforms[i], newShapes[i]));
}
finalXformsAndShapes.insert(finalXformsAndShapes.end(),
animatedGeometries.begin(), animatedGeometries.end());
if (finalXformsAndShapes.size() == 1) {
SubNode::MPtr xformNode = SubNode::create(
fRootNode->getName(),
finalXformsAndShapes[0].first);
SubNode::MPtr shapeNode = SubNode::create(
fRootNode->getName() + "Shape",
finalXformsAndShapes[0].second);
SubNode::connect(xformNode, shapeNode);
fConsolidatedRootNode = xformNode;
}
else if (finalXformsAndShapes.size() > 1) {
XformData::MPtr topXform = XformData::create();
std::set<double> times;
for (size_t i = 0; i < finalXformsAndShapes.size(); i++) {
for(const XformData::SampleMap::value_type& val :
finalXformsAndShapes[i].first->getSamples()) {
times.insert(val.first);
}
for(const ShapeData::SampleMap::value_type& val :
finalXformsAndShapes[i].second->getSamples()) {
times.insert(val.first);
}
}
std::set<double>::const_iterator timeIt = times.begin();
std::set<double>::const_iterator timeEnd = times.end();
if (timeIt != timeEnd) {
topXform->addSample(XformSample::create(
*timeIt,
true));
}
SubNode::MPtr topXformNode = SubNode::create(
fRootNode->getName(),
topXform);
for (size_t i = 0; i < finalXformsAndShapes.size(); i++) {
SubNode::MPtr xformNode = SubNode::create(
fRootNode->getName() + (i + 1),
finalXformsAndShapes[i].first);
SubNode::MPtr shapeNode = SubNode::create(
fRootNode->getName() + "Shape" + (i + 1),
finalXformsAndShapes[i].second);
SubNode::connect(xformNode, shapeNode);
SubNode::connect(topXformNode, xformNode);
}
fConsolidatedRootNode = topXformNode;
}
return MS::kSuccess;
}
SubNode::MPtr consolidatedRootNode()
{ return fConsolidatedRootNode; }
private:
Consolidator(const Consolidator&);
const Consolidator& operator= (const Consolidator&);
void consolidateGeometry(std::vector<ShapeData::Ptr>& newShapes,
std::vector<ShapeData::Ptr>& consolidatedShapes)
{
std::set<double> times;
for(const ShapeData::Ptr& shape : consolidatedShapes) {
for(const ShapeData::SampleMap::value_type& smv :
shape->getSamples()) {
times.insert(smv.first);
}
}
ShapeData::MPtr newShape = ShapeData::create();
const size_t nbShapes = consolidatedShapes.size();
std::set<double>::const_iterator timeIt = times.begin();
std::set<double>::const_iterator timeEnd = times.end();
typedef IndexBuffer::index_t index_t;
GPUCache::shared_array<index_t> wireVertIndices;
std::vector<GPUCache::shared_array<index_t> > triangleVertIndices;
GPUCache::shared_array<float> positions;
GPUCache::shared_array<float> normals;
GPUCache::shared_array<float> uvs;
bool visibility = true;
{
size_t totalWires = 0;
size_t totalVerts = 0;
std::vector<size_t> totalTriangles;
size_t numIndexGroups = 0;
bool uvExists = false;
for (size_t i = 0; i < nbShapes; i++) {
ShapeData::Ptr& shape = consolidatedShapes[i];
const std::shared_ptr<const ShapeSample>& sample =
shape->getSample(*timeIt);
totalWires += sample->numWires();
totalVerts += sample->numVerts();
if (numIndexGroups == 0) {
numIndexGroups = sample->numIndexGroups();
totalTriangles.resize(numIndexGroups, 0);
diffuseColor = sample->diffuseColor();
visibility = sample->visibility();
}
assert(numIndexGroups == sample->numIndexGroups());
assert(fabs(diffuseColor.
r - sample->diffuseColor().r) < 1e-5);
assert(fabs(diffuseColor.
g - sample->diffuseColor().g) < 1e-5);
assert(fabs(diffuseColor.
b - sample->diffuseColor().b) < 1e-5);
assert(fabs(diffuseColor.
a - sample->diffuseColor().a) < 1e-5);
assert(visibility == sample->visibility());
for (size_t j = 0; j < totalTriangles.size(); j++) {
totalTriangles[j] += sample->numTriangles(j);
}
if (!uvExists && sample->uvs()) {
uvExists = true;
}
}
wireVertIndices = GPUCache::shared_array<index_t>(
new index_t[2 * totalWires]);
triangleVertIndices.resize(totalTriangles.size());
for (size_t i = 0; i < totalTriangles.size(); i++) {
triangleVertIndices[i] = GPUCache::shared_array<index_t>(
new index_t[3 * totalTriangles[i]]);
}
positions = GPUCache::shared_array<float>(
new float[3 * totalVerts]);
normals = GPUCache::shared_array<float>(
new float[3 * totalVerts]);
if (uvExists) {
uvs = GPUCache::shared_array<float>(
new float[2 * totalVerts]);
}
{
size_t wireIdx = 0;
size_t vertIdx = 0;
std::vector<size_t> triangleIdx(numIndexGroups, 0);
for (size_t i = 0; i < nbShapes; i++) {
const std::shared_ptr<const ShapeSample>& sample =
consolidatedShapes[i]->getSample(*timeIt);
const size_t numWires = sample->numWires();
const size_t numVerts = sample->numVerts();
if (sample->wireVertIndices()) {
IndexBuffer::ReadInterfacePtr readable = sample->wireVertIndices()->readableInterface();
const index_t* srcWireVertIndices = readable->get();
for (size_t j = 0; j < numWires; j++) {
wireVertIndices[2*(j + wireIdx) + 0] = index_t(srcWireVertIndices[2*j + 0] + vertIdx);
wireVertIndices[2*(j + wireIdx) + 1] = index_t(srcWireVertIndices[2*j + 1] + vertIdx);
}
}
for (size_t group = 0; group < numIndexGroups; group++) {
const size_t numTriangles = sample->numTriangles(group);
if (sample->triangleVertIndices(group)) {
IndexBuffer::ReadInterfacePtr readable = sample->triangleVertIndices(group)->readableInterface();
const index_t* srcTriangleVertIndices = readable->get();
for (size_t j = 0; j < numTriangles; j++) {
triangleVertIndices[group][3*(j + triangleIdx[group]) + 0] = index_t(srcTriangleVertIndices[3*j + 0] + vertIdx);
triangleVertIndices[group][3*(j + triangleIdx[group]) + 1] = index_t(srcTriangleVertIndices[3*j + 1] + vertIdx);
triangleVertIndices[group][3*(j + triangleIdx[group]) + 2] = index_t(srcTriangleVertIndices[3*j + 2] + vertIdx);
}
}
}
if (sample->positions()) {
VertexBuffer::ReadInterfacePtr readable = sample->positions()->readableInterface();
memcpy(&positions[3*vertIdx], readable->get(), 3*numVerts*sizeof(float));
}
if (sample->normals()) {
VertexBuffer::ReadInterfacePtr readable = sample->normals()->readableInterface();
memcpy(&normals[3*vertIdx], readable->get(), 3*numVerts*sizeof(float));
}
if (sample->uvs()) {
VertexBuffer::ReadInterfacePtr readable = sample->uvs()->readableInterface();
memcpy(&uvs[2*vertIdx], readable->get(), 2*numVerts*sizeof(float));
}
else if (uvExists) {
memset(&uvs[2*vertIdx], 0, 2*numVerts*sizeof(float));
}
wireIdx += numWires;
vertIdx += numVerts;
for (size_t i = 0; i < numIndexGroups; i++) {
triangleIdx[i] += sample->numTriangles(i);
}
boundingBox.
expand(sample->boundingBox());
}
}
std::vector<std::shared_ptr<IndexBuffer> > newTriangleVertIndices(numIndexGroups);
for (size_t i = 0; i < numIndexGroups; i++) {
newTriangleVertIndices[i] = IndexBuffer::create(
SharedArray<index_t>::create(
triangleVertIndices[i], 3 * totalTriangles[i]));
}
std::shared_ptr<ShapeSample> newSample = ShapeSample::create(
*timeIt,
totalWires,
totalVerts,
IndexBuffer::create(
SharedArray<index_t>::create(
wireVertIndices, 2 * totalWires)),
newTriangleVertIndices,
VertexBuffer::createPositions(
SharedArray<float>::create(
positions, 3 * totalVerts)),
boundingBox,
diffuseColor,
visibility);
if (normals) {
newSample->setNormals(
VertexBuffer::createNormals(
SharedArray<float>::create(
normals, 3 * totalVerts)));
}
if (uvs) {
newSample->setUVs(
VertexBuffer::createUVs(
SharedArray<float>::create(
uvs, 2 * totalVerts)));
}
newShape->addSample(newSample);
}
std::set<double>::const_iterator timePrev = timeIt;
++timeIt;
for (; timeIt != timeEnd; ++timeIt) {
size_t totalWires = 0;
size_t totalVerts = 0;
std::vector<size_t> totalTriangles;
size_t numIndexGroups = 0;
bool uvExists = false;
bool wiresDirty = false;
bool trianglesDirty = false;
bool positionsDirty = false;
bool normalsDirty = false;
bool uvsDirty = false;
for (size_t i = 0; i < nbShapes; i++) {
ShapeData::Ptr& shape = consolidatedShapes[i];
const std::shared_ptr<const ShapeSample>& sample =
shape->getSample(*timeIt);
const std::shared_ptr<const ShapeSample>& prevSample =
shape->getSample(*timePrev);
totalWires += sample->numWires();
totalVerts += sample->numVerts();
if (numIndexGroups == 0) {
numIndexGroups = sample->numIndexGroups();
totalTriangles.resize(numIndexGroups, 0);
diffuseColor = sample->diffuseColor();
visibility = sample->visibility();
}
assert(numIndexGroups == sample->numIndexGroups());
assert(fabs(diffuseColor.
r - sample->diffuseColor().r) < 1e-5);
assert(fabs(diffuseColor.
g - sample->diffuseColor().g) < 1e-5);
assert(fabs(diffuseColor.
b - sample->diffuseColor().b) < 1e-5);
assert(fabs(diffuseColor.
a - sample->diffuseColor().a) < 1e-5);
assert(visibility == sample->visibility());
for (size_t j = 0; j < totalTriangles.size(); j++) {
totalTriangles[j] += sample->numTriangles(j);
}
if (!uvExists && sample->uvs()) {
uvExists = true;
}
for (size_t j = 0; j < numIndexGroups; j++) {
trianglesDirty |= sample->triangleVertIndices(j) != prevSample->triangleVertIndices(j);
}
wiresDirty |= sample->wireVertIndices() != prevSample->wireVertIndices();
positionsDirty |= sample->positions() != prevSample->positions();
normalsDirty |= sample->normals() != prevSample->normals();
uvsDirty |= sample->uvs() != prevSample->uvs();
}
if (wiresDirty || trianglesDirty ||
positionsDirty || normalsDirty || uvsDirty) {
if (wiresDirty) {
wireVertIndices = GPUCache::shared_array<index_t>(
new index_t[2 * totalWires]);
}
if (trianglesDirty) {
triangleVertIndices.resize(totalTriangles.size());
for (size_t i = 0; i < totalTriangles.size(); i++) {
triangleVertIndices[i] = GPUCache::shared_array<index_t>(
new index_t[3 * totalTriangles[i]]);
}
}
if (positionsDirty) {
positions = GPUCache::shared_array<float>(
new float[3 * totalVerts]);
}
if (normalsDirty) {
normals = GPUCache::shared_array<float>(
new float[3 * totalVerts]);
}
if (uvsDirty) {
uvs.reset();
if (uvExists) {
uvs = GPUCache::shared_array<float>(
new float[2 * totalVerts]);
}
}
{
size_t wireIdx = 0;
size_t vertIdx = 0;
std::vector<size_t> triangleIdx(numIndexGroups, 0);
for (size_t i = 0; i < nbShapes; i++) {
const std::shared_ptr<const ShapeSample>& sample =
consolidatedShapes[i]->getSample(*timeIt);
const size_t numWires = sample->numWires();
const size_t numVerts = sample->numVerts();
if (wiresDirty && sample->wireVertIndices()) {
IndexBuffer::ReadInterfacePtr readable = sample->wireVertIndices()->readableInterface();
const index_t* srcWireVertIndices = readable->get();
for (size_t j = 0; j < numWires; j++) {
wireVertIndices[2*(j + wireIdx) + 0] = index_t(srcWireVertIndices[2*j + 0] + vertIdx);
wireVertIndices[2*(j + wireIdx) + 1] = index_t(srcWireVertIndices[2*j + 1] + vertIdx);
}
}
if (trianglesDirty) {
for (size_t group = 0; group < numIndexGroups; group++) {
const size_t numTriangles = sample->numTriangles(group);
if (sample->triangleVertIndices(group)) {
IndexBuffer::ReadInterfacePtr readable = sample->triangleVertIndices(group)->readableInterface();
const index_t* srcTriangleVertIndices = readable->get();
for (size_t j = 0; j < numTriangles; j++) {
triangleVertIndices[group][3*(j + triangleIdx[group]) + 0] = index_t(srcTriangleVertIndices[3*j + 0] + vertIdx);
triangleVertIndices[group][3*(j + triangleIdx[group]) + 1] = index_t(srcTriangleVertIndices[3*j + 1] + vertIdx);
triangleVertIndices[group][3*(j + triangleIdx[group]) + 2] = index_t(srcTriangleVertIndices[3*j + 2] + vertIdx);
}
}
}
}
if (positionsDirty && sample->positions()) {
VertexBuffer::ReadInterfacePtr readable = sample->positions()->readableInterface();
memcpy(&positions[3*vertIdx], readable->get(),
3*numVerts*sizeof(float));
}
if (normalsDirty && sample->normals()) {
VertexBuffer::ReadInterfacePtr readable = sample->normals()->readableInterface();
memcpy(&normals[3*vertIdx], readable->get(),
3*numVerts*sizeof(float));
}
if (uvsDirty) {
if (sample->uvs()) {
VertexBuffer::ReadInterfacePtr readable = sample->uvs()->readableInterface();
memcpy(&uvs[2*vertIdx], readable->get(),
2*numVerts*sizeof(float));
} else if (uvExists) {
memset(&uvs[2*vertIdx], 0, 2*numVerts*sizeof(float));
}
}
wireIdx += numWires;
vertIdx += numVerts;
for (size_t i = 0; i < numIndexGroups; i++) {
triangleIdx[i] += sample->numTriangles(i);
}
boundingBox.
expand(sample->boundingBox());
}
}
}
std::vector<std::shared_ptr<IndexBuffer> > newTriangleVertIndices(numIndexGroups);
for (size_t i = 0; i < numIndexGroups; i++) {
newTriangleVertIndices[i] = IndexBuffer::create(
SharedArray<index_t>::create(
triangleVertIndices[i], 3 * totalTriangles[i]));
}
std::shared_ptr<ShapeSample> newSample = ShapeSample::create(
*timeIt,
totalWires,
totalVerts,
IndexBuffer::create(
SharedArray<index_t>::create(
wireVertIndices, 2 * totalWires)),
newTriangleVertIndices,
VertexBuffer::createPositions(
SharedArray<float>::create(
positions, 3 * totalVerts)),
boundingBox,
diffuseColor,
visibility);
if (normals) {
newSample->setNormals(
VertexBuffer::createNormals(
SharedArray<float>::create(
normals, 3 * totalVerts)));
}
if (uvs) {
newSample->setUVs(
VertexBuffer::createUVs(
SharedArray<float>::create(
uvs, 2 * totalVerts)));
}
newShape->addSample(newSample);
timePrev = timeIt;
}
newShape->setMaterials(consolidatedShapes[0]->getMaterials());
newShapes.push_back(newShape);
consolidatedShapes.clear();
}
SubNode::MPtr fRootNode;
const int fThreshold;
const bool fMotionBlur;
SubNode::MPtr fConsolidatedRootNode;
};
class SelectionChecker
{
public:
{
for (
unsigned int i = 0; i < selection.
length(); i++) {
if (status == MS::kSuccess) {
fSelectionPaths.insert(fullDagPath);
}
}
for (
unsigned int i = 0; i < selection.
length(); i++) {
if (status == MS::kSuccess && check(dagPath)) {
fSelection.add(dagPath);
}
}
}
{ return fSelection; }
private:
SelectionChecker(const SelectionChecker&);
const SelectionChecker& operator= (const SelectionChecker&);
{
if (fSelectionPaths.find(fullDagPath) != fSelectionPaths.end()) {
return false;
}
}
return checkGeometry(dagPath);
}
bool checkGeometry(
const MDagPath& dagPath)
{
if ((Baker::isBakeable(object) ||
dagNode.
typeId() == ShapeNode::id) &&
return true;
}
bool hasGeometry = false;
for (
unsigned int i = 0; i < dagPath.
childCount(); i++) {
continue;
}
if (checkGeometry(child)) {
hasGeometry= true;
break;
}
}
return hasGeometry;
}
std::set<std::string> fSelectionPaths;
};
class ScopedPauseWorkerThread
{
public:
ScopedPauseWorkerThread()
{
GlobalReaderCache::theCache().pauseRead();
}
~ScopedPauseWorkerThread()
{
GlobalReaderCache::theCache().resumeRead();
}
ScopedPauseWorkerThread(const ScopedPauseWorkerThread&) = delete;
ScopedPauseWorkerThread& operator=(const ScopedPauseWorkerThread&) = delete;
};
class FileAndSubNode
{
public:
SubNode::MPtr subNode;
bool isDummy;
FileAndSubNode()
: isDummy(false)
{}
FileAndSubNode(
const MFileObject& f,
const SubNode::MPtr& n,
bool d)
: targetFile(f), subNode(n), isDummy(d)
{}
};
typedef std::vector<FileAndSubNode> FileAndSubNodeList;
class NodePathRegistry
{
public:
enum Stages {
kResolveStage,
kConstructStage,
kComplete
};
NodePathRegistry(const bool allDagObjects,
const bool saveMultipleFiles,
: fStage(kResolveStage),
fAllDagObjects(allDagObjects),
fSaveMultipleFiles(saveMultipleFiles),
fDirectory(directory),
fFilePrefix(filePrefix),
fFileName(fileName),
fClashOption(clashOption),
fExtension(".abc")
{}
~NodePathRegistry()
{}
NodePathRegistry(const NodePathRegistry&) = delete;
NodePathRegistry& operator=(const NodePathRegistry&) = delete;
{
assert(fStage == kResolveStage);
std::string fullPath = fullPathName(dagPath);
assert(fPathMap.find(fullPath) == fPathMap.end());
std::string parentFullPath = fullPathName(parentPath);
PathEntry pathEntry;
pathEntry.dagPath = dagPath;
pathEntry.parentPath = parentFullPath;
fPathMap[fullPath] = pathEntry;
}
void resolve()
{
assert(fStage == kResolveStage);
fStage = kConstructStage;
for(const PathMapType::value_type& v : fPathMap) {
PathMapType::const_iterator it = fPathMap.find(v.second.parentPath);
if (it == fPathMap.end()) {
assert(fRootMap.find(v.first) == fRootMap.end());
std::string nodeName = dagNode.name().asChar();
std::replace(nodeName.begin(), nodeName.end(), ':', '_');
RootEntry rootEntry;
rootEntry.nodeName = nodeName;
rootEntry.uniqueName = "Not_Specified";
rootEntry.sequence = std::numeric_limits<size_t>::max();
rootEntry.overwrite = true;
fRootMap[v.first] = rootEntry;
}
}
std::map<std::string,size_t> nameTable;
for(const RootMapType::value_type& v : fRootMap) {
nameTable.insert(std::make_pair(v.second.nodeName, 0)).first->second++;
}
size_t counter = 0;
for(RootMapType::value_type& v : fRootMap) {
std::string uniqueName = v.second.nodeName;
if (nameTable.find(uniqueName)->second > 1) {
uniqueName = v.first.substr(1);
std::replace(uniqueName.begin(), uniqueName.end(), '|', '_');
std::replace(uniqueName.begin(), uniqueName.end(), ':', '_');
}
v.second.uniqueName = uniqueName;
v.second.sequence = counter++;
}
const bool singleFile = fAllDagObjects || !fSaveMultipleFiles || fRootMap.size() == 1;
const MString directory = validatedDirectory();
const MString fileName = validatedFileName();
for(RootMapType::value_type& v : fRootMap) {
MString targetFileName = fFilePrefix;
if (singleFile) {
targetFileName += fileName;
}
else {
if (fClashOption == "numericalIncrement") {
targetFileName += (unsigned int)v.second.sequence;
}
else {
targetFileName += v.second.uniqueName.c_str();
}
}
MString targetFullName = directory +
"/" + targetFileName + fExtension;
v.second.targetFile.setRawFullName(targetFullName);
}
}
void promptOverwrite()
{
assert(fStage == kConstructStage);
"if (!(`exists showGpuCacheExportConfirmDialog`))\n"
"{\n"
" eval(\"source \\\"doGpuCacheExportArgList.mel\\\"\");\n"
"}\n"
);
const bool singleFile = fAllDagObjects || !fSaveMultipleFiles || fRootMap.size() == 1;
enum OverwriteChoice { kUnknownOverwrite, kAlwaysOverwrite, kNeverOverwrite };
OverwriteChoice choice = kUnknownOverwrite;
for(RootMapType::value_type& v : fRootMap) {
if (!v.second.targetFile.exists()) continue;
if (choice == kUnknownOverwrite) {
"showGpuCacheExportConfirmDialog \"" +
EncodeString(v.second.targetFile.resolvedFullName()) +
"\""
);
if (result == "yes") {
v.second.overwrite = true;
if (singleFile) choice = kAlwaysOverwrite;
}
else if (result == "no") {
v.second.overwrite = false;
if (singleFile) choice = kNeverOverwrite;
}
else if (result == "yesAll") {
v.second.overwrite = true;
choice = kAlwaysOverwrite;
}
else if (result == "noAll" || result == "dismiss") {
v.second.overwrite = false;
choice = kNeverOverwrite;
}
else {
assert(0);
}
}
else if (choice == kAlwaysOverwrite) {
v.second.overwrite = true;
}
else if (choice == kNeverOverwrite) {
v.second.overwrite = false;
}
else {
assert(0);
}
}
}
void associateSubNode(
const MDagPath& dagPath,
const SubNode::MPtr& subNode)
{
assert(fStage == kConstructStage);
assert(subNode);
std::string fullPath = fullPathName(dagPath);
PathMapType::iterator it = fPathMap.find(fullPath);
assert(it != fPathMap.end());
if (it != fPathMap.end()) {
it->second.subNode = subNode;
}
}
void constructHierarchy()
{
assert(fStage == kConstructStage);
fStage = kComplete;
for(const PathMapType::value_type& v : fPathMap) {
const SubNode::MPtr& thisSubNode = v.second.subNode;
PathMapType::iterator parentIt = fPathMap.find(v.second.parentPath);
if (parentIt != fPathMap.end()) {
const SubNode::MPtr& parentSubNode = parentIt->second.subNode;
SubNode::connect(parentSubNode, thisSubNode);
}
else {
RootMapType::iterator rootIt = fRootMap.find(v.first);
assert(rootIt != fRootMap.end());
if (rootIt != fRootMap.end()) {
rootIt->second.subNode = thisSubNode;
}
}
}
}
void generateFileAndSubNodes(FileAndSubNodeList& list)
{
assert(fStage == kComplete);
if (fAllDagObjects || !fSaveMultipleFiles) {
if (!fRootMap.empty() && fRootMap.begin()->second.overwrite) {
GroupCreator groupCreator;
for(const RootMapType::value_type& v : fRootMap) {
v.second.subNode->setName(v.second.uniqueName.c_str());
groupCreator.addChild(v.second.subNode);
}
groupCreator.group();
const RootEntry& rootEntry = fRootMap.begin()->second;
const MString rootNodeName = (fRootMap.size() == 1) ?
rootEntry.subNode->getName() : getSceneNameAsValidObjectName();
list.push_back(FileAndSubNode(
rootEntry.targetFile,
groupCreator.getSubNode(rootNodeName),
true
));
}
}
else {
for(const RootMapType::value_type& v : fRootMap) {
if (!v.second.overwrite) continue;
list.push_back(FileAndSubNode(
v.second.targetFile,
v.second.subNode,
false
));
}
}
}
void dump()
{
using namespace std;
stringstream out;
out << "Current Stage: ";
switch (fStage) {
case kResolveStage: out << "ResolveStage"; break;
case kConstructStage: out << "ConstructStage"; break;
case kComplete: out << "Complete"; break;
}
out << endl;
out << "Path Map: " << endl;
for(const PathMapType::value_type& v : fPathMap) {
out << "Path: "
<< v.first
<< ", Parent: "
<< v.second.parentPath
<< ", SubNode: "
<< (void*)v.second.subNode.get()
<< endl;
}
out << "Root Map: " << endl;
for(const RootMapType::value_type& v : fRootMap) {
out << "Path: "
<< v.first
<< ", Node: "
<< v.second.nodeName
<< ", Unique: "
<< v.second.uniqueName
<< ", Sequence: "
<< v.second.sequence
<< ", Overwrite: "
<< v.second.overwrite
<< ", Target: "
<< v.second.targetFile.resolvedFullName().asChar()
<< ", SubNode: "
<< (void*)v.second.subNode.get()
<< endl;
}
cout << out.str() << endl;
}
private:
static std::string fullPathName(
const MDagPath& dagPath)
{
return std::string(buffer.
asChar());
}
{
if (fDirectory.length() > 0) {
}
else {
const MString alembicFileRule =
"alembicCache";
const MString alembicFilePath =
"cache/alembic";
queryFileRuleCmd.
format(
"workspace -q -fre \"^1s\"", alembicFileRule);
queryFolderCmd.
format(
"workspace -en `workspace -q -fre \"^1s\"`", alembicFileRule);
}
else {
addFileRuleCmd.
format(
"workspace -fr \"^1s\" \"^2s\"", alembicFileRule, alembicFilePath);
}
if (expandName.
length() == 0) {
expandName = alembicFilePath;
}
}
}
{
if (fFileName.length() > 0) {
fileName = fFileName;
}
else {
if (fRootMap.size() == 1) {
fileName = fRootMap.begin()->second.uniqueName.c_str();
}
else {
fileName = getSceneName();
}
}
return fileName;
}
struct PathEntry {
std::string parentPath;
SubNode::MPtr subNode;
};
typedef std::unordered_map<std::string,PathEntry> PathMapType;
struct RootEntry {
std::string nodeName;
std::string uniqueName;
size_t sequence;
bool overwrite;
SubNode::MPtr subNode;
};
typedef std::unordered_map<std::string,RootEntry> RootMapType;
Stages fStage;
PathMapType fPathMap;
RootMapType fRootMap;
const bool fAllDagObjects;
const bool fSaveMultipleFiles;
};
}
namespace GPUCache {
void* Command::creator()
{
return new Command();
}
{
syntax.
addFlag(
"-o",
"-optimize" );
syntax.
addFlag(
"-sf",
"-showFailed" );
syntax.
addFlag(
"-ss",
"-showStats" );
syntax.
addFlag(
"-sgs",
"-showGlobalStats" );
syntax.
addFlag(
"-atr",
"-animTimeRange" );
syntax.
addFlag(
"-gma",
"-gpuManufacturer" );
syntax.
addFlag(
"-gmo",
"-gpuModel" );
syntax.
addFlag(
"-gdv",
"-gpuDriverVersion" );
syntax.
addFlag(
"-gms",
"-gpuMemorySize" );
syntax.
addFlag(
"-ado",
"-allDagObjects" );
syntax.
addFlag(
"-ra",
"-refreshAll" );
syntax.
addFlag(
"-rs",
"-refreshSettings" );
syntax.
addFlag(
"-wbr",
"-waitForBackgroundReading" );
syntax.
addFlag(
"-wm",
"-writeMaterials" );
syntax.
addFlag(
"-wuv",
"-writeUVs" );
syntax.
addFlag(
"-omb",
"-optimizeAnimationsForMotionBlur" );
syntax.
addFlag(
"-ubt",
"-useBaseTessellation" );
syntax.
addFlag(
"-lfe",
"-listFileEntries" );
syntax.
addFlag(
"-lse",
"-listShapeEntries" );
return syntax;
}
Command::Command()
: fMode(kCreate)
{}
Command::~Command()
{}
bool Command::isUndoable() const
{
return false;
}
bool Command::hasSyntax() const
{
return true;
}
void Command::AddHierarchy(
std::map<std::string, int>* idMap,
std::vector<MObject>* sourceNodes,
std::vector<std::vector<MDagPath> >* sourcePaths,
std::vector<MObject>* gpuCacheNodes)
{
MStatus status = dagNode.getPath(firstDagPath);
if (status != MS::kSuccess) return;
std::string firstPath(firstDagPath.partialPathName().asChar());
std::map<std::string, int>::iterator pos = idMap->find(firstPath);
if (pos != idMap->end()){
(*sourcePaths)[pos->second].push_back(dagPath);
}
else {
bool isWarning = true;
if (dagNode.typeId() == ShapeNode::id) {
if (fMode == kCreate) {
(*idMap)[firstPath] = (int)sourceNodes->size();
sourceNodes->push_back(object);
sourcePaths->push_back(std::vector<MDagPath>(1, dagPath));
}
else {
gpuCacheNodes->push_back(object);
}
}
else if (Baker::isBakeable(object)) {
(*idMap)[firstPath] = (int)sourceNodes->size();
sourceNodes->push_back(object);
sourcePaths->push_back(std::vector<MDagPath>(1, dagPath));
if (fMode != kCreate && fShowFailedFlag.isSet()) {
}
}
else if (fShowFailedFlag.isSet()) {
}
if (msgFmt.length() > 0) {
MString nodeName = firstDagPath.fullPathName();
if (isWarning) {
}
else {
}
}
}
for(unsigned int i = 0; i < numChild; ++i) {
if (!childNode.isIntermediateObject())
AddHierarchy(childPath, idMap, sourceNodes, sourcePaths, gpuCacheNodes);
}
}
bool Command::AddSelected(
std::vector<MObject>* sourceNodes,
std::vector<std::vector<MDagPath> >* sourcePaths,
std::vector<MObject>* gpuCacheNodes)
{
std::map<std::string, int> idMap;
for (
unsigned int i = 0; i<objects.
length(); ++i) {
if (status == MS::kSuccess) {
AddHierarchy(sourceDagPath, &idMap, sourceNodes, sourcePaths, gpuCacheNodes);
}
}
if (fMode == kCreate) {
if (sourceNodes->empty()) {
if (gpuCacheNodes->empty()) {
}
else {
}
displayWarning(msg);
return false;
}
return true;
}
else {
if (!fRefreshSettingsFlag.isSet() && gpuCacheNodes->empty()) {
if (sourceNodes->empty()) {
}
else {
}
displayWarning(msg);
return false;
}
return true;
}
}
{
if (!status) return status;
unsigned int numFlags = 0;
if (argsDb.isEdit()) {
if (argsDb.isQuery()) {
displayError(msg);
return MS::kFailure;
}
fMode = kEdit;
numFlags++;
}
else if (argsDb.isQuery()) {
fMode = kQuery;
numFlags++;
}
numFlags += fDirectoryFlag.parse(argsDb, "-directory");
if (!fDirectoryFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fFileNameFlag.parse(argsDb, "-fileName");
if (!fFileNameFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fSaveMultipleFilesFlag.parse(argsDb, "-saveMultipleFiles");
if (!fSaveMultipleFilesFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fFilePrefixFlag.parse(argsDb, "-filePrefix");
if (!fFilePrefixFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fClashOptionFlag.parse(argsDb, "-clashOption");
if (!fClashOptionFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fOptimizeFlag.parse(argsDb, "-optimize");
if (!fOptimizeFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fOptimizationThresholdFlag.parse(argsDb, "-optimizationThreshold");
if (!fOptimizationThresholdFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fStartTimeFlag.parse(argsDb, "-startTime");
if (!fStartTimeFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fEndTimeFlag.parse(argsDb, "-endTime");
if (!fEndTimeFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fSimulationRateFlag.parse(argsDb, "-simulationRate");
if (!fSimulationRateFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
if (fSimulationRateFlag.isSet()) {
if (fSimulationRateFlag.arg() < minRate) {
displayError(msg);
return MS::kFailure;
}
}
numFlags += fSampleMultiplierFlag.parse(argsDb, "-sampleMultiplier");
if (!fSampleMultiplierFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
if (fSampleMultiplierFlag.isSet() && fSampleMultiplierFlag.arg() <= 0) {
displayError(msg);
return MS::kFailure;
}
numFlags += fCompressLevelFlag.parse(argsDb, "-compressLevel");
if (!fCompressLevelFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fDataFormatFlag.parse(argsDb, "-dataFormat");
if (!fDataFormatFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fShowFailedFlag.parse(argsDb, "-showFailed");
assert(fShowFailedFlag.isModeValid(fMode));
numFlags += fShowStats.parse(argsDb, "-showStats");
assert(fShowStats.isModeValid(fMode));
numFlags += fShowGlobalStats.parse(argsDb, "-showGlobalStats");
assert(fShowGlobalStats.isModeValid(fMode));
numFlags += fDumpHierarchy.parse(argsDb, "-dumpHierarchy");
assert(fDumpHierarchy.isModeValid(fMode));
numFlags += fAnimTimeRangeFlag.parse(argsDb, "-animTimeRange");
if (!fAnimTimeRangeFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fAllDagObjectsFlag.parse(argsDb, "-allDagObjects");
if (!fAllDagObjectsFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fRefreshFlag.parse(argsDb, "-refresh");
if (!fRefreshFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fRefreshAllFlag.parse(argsDb, "-refreshAll");
if (!fRefreshAllFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fListFileEntriesFlag.parse(argsDb, "-listFileEntries");
if (!fListFileEntriesFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fListShapeEntriesFlag.parse(argsDb, "-listShapeEntries");
if (!fListShapeEntriesFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fRefreshSettingsFlag.parse(argsDb, "-refreshSettings");
if (!fRefreshSettingsFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fGpuManufacturerFlag.parse(argsDb, "-gpuManufacturer");
if (!fGpuManufacturerFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fGpuModelFlag.parse(argsDb, "-gpuModel");
if (!fGpuModelFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fGpuDriverVersion.parse(argsDb, "-gpuDriverVersion");
if (!fGpuDriverVersion.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fGpuMemorySize.parse(argsDb, "-gpuMemorySize");
if (!fGpuMemorySize.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fWaitForBackgroundReadingFlag.parse(argsDb, "-waitForBackgroundReading");
if (!fWaitForBackgroundReadingFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fWriteMaterials.parse(argsDb, "-writeMaterials");
if (!fWriteMaterials.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fUVsFlag.parse(argsDb, "-writeUVs");
if( !fUVsFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fOptimizeAnimationsForMotionBlurFlag.parse(argsDb, "-optimizeAnimationsForMotionBlur");
if (!fOptimizeAnimationsForMotionBlurFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fUseBaseTessellationFlag.parse(argsDb, "-useBaseTessellation");
if (!fUseBaseTessellationFlag.isModeValid(fMode)) {
displayError(msg);
return MS::kFailure;
}
numFlags += fPromptFlag.parse(argsDb, "-prompt");
if (fRefreshAllFlag.isSet())
{
if( numFlags > 1 )
{
displayError(msg);
return MS::kFailure;
}
refreshAll();
return MS::kSuccess;
}
if (fListFileEntriesFlag.isSet())
{
if( numFlags > 1 )
{
displayError(msg);
return MS::kFailure;
}
listFileEntries();
return MS::kSuccess;
}
if (fListShapeEntriesFlag.isSet())
{
if( numFlags > 1 )
{
displayError(msg);
return MS::kFailure;
}
listShapeEntries();
return MS::kSuccess;
}
if (fAllDagObjectsFlag.isSet()) {
for (
unsigned int i = 0; i < result.
length(); i++) {
}
}
else {
status = argsDb.getObjects(selectedObjectArgs);
MStatError(status, "argsDb.getObjects()");
if (!selectedObjectArgs.
isEmpty()) {
MStatError(status, "objects.merge()");
}
}
!(fMode == kQuery && fShowGlobalStats.isSet()) &&
!(fMode == kEdit && fRefreshSettingsFlag.isSet()) &&
!(fMode == kQuery && fGpuManufacturerFlag.isSet()) &&
!(fMode == kQuery && fGpuModelFlag.isSet()) &&
!(fMode == kQuery && fGpuDriverVersion.isSet()) &&
!(fMode == kQuery && fGpuMemorySize.isSet())
) {
return MS::kFailure;
}
{
SelectionChecker selectionChecker(objects);
objects = selectionChecker.selection();
}
std::vector<MObject> sourceNodes;
std::vector<std::vector<MDagPath> > sourcePaths;
std::vector<MObject> gpuCacheNodes;
if (fMode == kCreate || fMode == kEdit || fShowStats.isSet() ||
fDumpHierarchy.isSet() || fAnimTimeRangeFlag.isSet() ||
fWaitForBackgroundReadingFlag.isSet()) {
if (!AddSelected(objects, &sourceNodes, &sourcePaths, &gpuCacheNodes))
return MS::kFailure;
}
switch (fMode) {
case kCreate: status = doCreate(sourceNodes, sourcePaths, objects); break;
case kEdit: status = doEdit(gpuCacheNodes); break;
case kQuery: status = doQuery(gpuCacheNodes); break;
}
return status;
}
MStatus Command::doCreate(
const std::vector<MObject>& sourceNodes,
const std::vector<std::vector<MDagPath> >& sourcePaths,
{
MCheckReturn(
Command::doBaking(
sourceNodes,
sourcePaths,
fSampleMultiplierFlag.arg(1)));
return MS::kSuccess;
}
MStatus Command::doQuery(
const std::vector<MObject>& gpuCacheNodes)
const
{
if (fShowStats.isSet() ||
fShowGlobalStats.isSet() ||
fDumpHierarchy.isSet()
) {
if (fAnimTimeRangeFlag.isSet()) {
return MS::kFailure;
}
if (fShowStats.isSet()) {
showStats(gpuCacheNodes, result);
}
if (fShowGlobalStats.isSet()) {
showGlobalStats(result);
}
if (fDumpHierarchy.isSet()) {
if (fDumpHierarchy.isArgValid()) {
MCheckReturn( dumpHierarchyToFile(gpuCacheNodes, file) );
}
else {
dumpHierarchy(gpuCacheNodes, result);
}
}
{
for (
unsigned int i = 0; i < result.
length(); i++) {
if (i > 0) output += "\n";
output += result[i];
}
}
}
else if (fAnimTimeRangeFlag.isSet()) {
showAnimTimeRange(gpuCacheNodes, animTimeRange);
}
else if (fGpuManufacturerFlag.isSet()) {
}
else if (fGpuModelFlag.isSet()) {
}
else if (fGpuDriverVersion.isSet()) {
int driverVersion[3];
VramQuery::driverVersion(driverVersion);
verionStr += driverVersion[0];
verionStr += ".";
verionStr += driverVersion[1];
verionStr += ".";
verionStr += driverVersion[2];
}
else if (fGpuMemorySize.isSet()) {
}
else if (fWaitForBackgroundReadingFlag.isSet()) {
for(
const MObject& node : gpuCacheNodes) {
ShapeNode* shapeNode = (ShapeNode*)dagNode.userNode();
if (shapeNode) {
shapeNode->getCachedGeometry();
}
GlobalReaderCache::theCache().waitForRead(shapeNode->getCacheFileEntry().get());
if (shapeNode) {
shapeNode->getCachedGeometry();
}
}
}
return MS::kSuccess;
}
MStatus Command::doEdit(
const std::vector<MObject>& gpuCacheNodes)
{
if (fRefreshSettingsFlag.isSet()) {
Config::refresh();
}
if (fRefreshFlag.isSet()) {
refresh(gpuCacheNodes);
}
return MS::kSuccess;
}
const std::vector<MObject>& sourceNodes,
const std::vector<std::vector<MDagPath> >& sourcePaths,
int samplingRate
)
{
if (startTime > endTime) {
return MS::kFailure;
}
NodePathRegistry pathRegistry(
fAllDagObjectsFlag.isSet(),
fSaveMultipleFilesFlag.arg(true),
fDirectoryFlag.arg(),
fFilePrefixFlag.arg(),
fFileNameFlag.arg(),
fClashOptionFlag.arg()
);
for(const std::vector<MDagPath>& dagPaths : sourcePaths) {
pathRegistry.add(path);
}
}
pathRegistry.resolve();
pathRegistry.promptOverwrite();
}
ProgressBar progressBar(kExportingMsg,
(unsigned int)(sourceNodes.size() * (int)(
MTime currentTime = startTime;
typedef std::vector< std::shared_ptr<Baker> > Bakers;
Bakers bakers;
std::shared_ptr<MaterialBaker> materialBaker;
if (fWriteMaterials.isSet()) {
materialBaker = std::make_shared<MaterialBaker>();
}
for (size_t i = 0; i < sourceNodes.size(); i++) {
const std::shared_ptr<Baker> baker(
Baker::create(sourceNodes[i], sourcePaths[i]));
if (!baker) {
return MS::kFailure;
}
const std::shared_ptr<ShapeBaker> shapeBaker = std::dynamic_pointer_cast<ShapeBaker,Baker>( baker );
if( shapeBaker && fUVsFlag.isSet() )
{
shapeBaker->enableUVs();
}
if (materialBaker) {
baker->setWriteMaterials();
}
if (fUseBaseTessellationFlag.isSet()) {
baker->setUseBaseTessellation();
}
bakers.push_back(baker);
MCheckReturn(baker->sample(currentTime));
if (materialBaker) {
for(
const MDagPath& path : sourcePaths[i]) {
MCheckReturn( materialBaker->addShapePath(path) );
}
}
}
MUpdateProgressAndCheckInterruption(progressBar);
}
if (materialBaker) {
MCheckReturn( materialBaker->sample(currentTime) );
}
currentTime += simulationRate;
for (int sampleIdx = 1; currentTime<=endTime;
currentTime += simulationRate, ++sampleIdx) {
if (sampleIdx % samplingRate == 0) {
for(const std::shared_ptr<Baker>& baker : bakers) {
MCheckReturn(baker->sample(currentTime));
MUpdateProgressAndCheckInterruption(progressBar);
}
if (materialBaker) {
MCheckReturn( materialBaker->sample(currentTime) );
}
}
}
MaterialGraphMap::Ptr materials;
if (materialBaker) {
materialBaker->buildGraph();
materials = materialBaker->get();
}
{
assert(bakers.size() == sourceNodes.size());
assert(bakers.size() == sourcePaths.size());
for (size_t i = 0; i < sourcePaths.size(); i++) {
for (size_t j = 0; j < sourcePaths[i].size(); j++) {
const MDagPath& path = sourcePaths[i][j];
SubNode::MPtr subNode = bakers[i]->getNode(j);
pathRegistry.associateSubNode(path, subNode);
}
}
pathRegistry.constructHierarchy();
}
bakers.clear();
materialBaker.reset();
FileAndSubNodeList fileList;
pathRegistry.generateFileAndSubNodes(fileList);
if (fOptimizeFlag.isSet()) {
const int threshold = fOptimizationThresholdFlag.arg(40000);
const bool motionBlur = fOptimizeAnimationsForMotionBlurFlag.isSet();
for(FileAndSubNode& v : fileList) {
Consolidator consolidator(v.subNode, threshold, motionBlur);
MCheckReturn( consolidator.consolidate() );
SubNode::MPtr consolidatedRootNode = consolidator.consolidatedRootNode();
if (consolidatedRootNode) {
v.subNode = consolidatedRootNode;
v.isDummy = false;
}
}
}
progressBar.reset(kWritingMsg, (unsigned int)fileList.size());
const MTime timePerCycle = simulationRate * samplingRate;
Writer gpuCacheWriter(
(char)fCompressLevelFlag.arg(-1),
fDataFormatFlag.arg("hdf"),
timePerCycle,
startTime
);
for(const FileAndSubNode& v : fileList) {
if (v.isDummy) {
MCheckReturn(
gpuCacheWriter.writeNodes(
v.subNode->getChildren(),
materials,
v.targetFile
)
);
}
else {
MCheckReturn(
gpuCacheWriter.writeNode(
v.subNode,
materials,
v.targetFile
)
);
}
appendToResult(v.targetFile.resolvedFullName());
MUpdateProgressAndCheckInterruption(progressBar);
}
return MS::kSuccess;
}
void Command::showStats(
const std::vector<MObject>& gpuCacheNodes,
) const
{
{
StatsVisitor stats;
for(
const MObject& gpuCacheObject : gpuCacheNodes) {
MPxNode* node = gpuCacheFn.userNode();
assert(node);
assert(dynamic_cast<ShapeNode*>(node));
ShapeNode* gpuCacheNode =
static_cast<ShapeNode*>(node);
stats.accumulateNode(gpuCacheNode->getCachedGeometry());
stats.accumulateMaterialGraph(gpuCacheNode->getCachedMaterial());
}
stats.print(result, false);
}
{
for(
const MObject& gpuCacheObject : gpuCacheNodes) {
MPxNode* node = gpuCacheFn.userNode();
assert(node);
assert(dynamic_cast<ShapeNode*>(node));
ShapeNode* gpuCacheNode =
static_cast<ShapeNode*>(node);
stats.accumulateNode(gpuCacheNode->getCachedGeometry());
stats.accumulateMaterialGraph(gpuCacheNode->getCachedMaterial());
}
stats.print(result, true);
}
}
void Command::showGlobalStats(
) const
{
const size_t unitBoundingBoxIndicesBytes = UnitBoundingBox::indices()->bytes();
const size_t unitBoundingBoxPositionsBytes = UnitBoundingBox::positions()->bytes();
const size_t unitBoundingBoxBytes = unitBoundingBoxIndicesBytes + unitBoundingBoxPositionsBytes;
const size_t unitBoundingBoxNbIndices = 1;
const size_t unitBoundingBoxNbVertices = 1;
const size_t unitBoundingBoxNbBuffers = unitBoundingBoxNbIndices + unitBoundingBoxNbVertices;
{
double memSize =
toHumanUnits(IndexBuffer::nbAllocatedBytes() +
VertexBuffer::nbAllocatedBytes() -
unitBoundingBoxBytes,
memUnit);
MString msg_buffers; msg_buffers += (double)(IndexBuffer::nbAllocated() +
VertexBuffer::nbAllocated() -
unitBoundingBoxNbBuffers);
MString msg_memSize; msg_memSize += memSize;
msg_buffers, msg_memSize, memUnit);
}
{
double memSize =
toHumanUnits(IndexBuffer::nbAllocatedBytes() - unitBoundingBoxIndicesBytes, memUnit);
MString msg_buffers; msg_buffers += (double)(IndexBuffer::nbAllocated() - unitBoundingBoxNbIndices);
MString msg_memSize; msg_memSize += memSize;
msg_buffers, msg_memSize, memUnit);
}
{
double memSize =
toHumanUnits(VertexBuffer::nbAllocatedBytes() - unitBoundingBoxPositionsBytes, memUnit);
MString msg_buffers; msg_buffers +=
(double)(VertexBuffer::nbAllocated() - unitBoundingBoxNbVertices);
MString msg_memSize; msg_memSize += memSize;
msg_buffers, msg_memSize, memUnit);
}
{
double memSize = toHumanUnits(VBOBuffer::nbAllocatedBytes(),
memUnit);
MString msg_buffers; msg_buffers += (double)(VBOBuffer::nbAllocated());
MString msg_memSize; msg_memSize += memSize;
msg_buffers, msg_memSize, memUnit);
}
{
double memSize = toHumanUnits(VBOBuffer::nbIndexAllocatedBytes(),
memUnit);
MString msg_buffers; msg_buffers +=
(double)VBOBuffer::nbIndexAllocated();
MString msg_memSize; msg_memSize += memSize;
msg_buffers, msg_memSize, memUnit);
}
{
double memSize = toHumanUnits(VBOBuffer::nbVertexAllocatedBytes(),
memUnit);
MString msg_buffers; msg_buffers +=
(double)VBOBuffer::nbVertexAllocated();
MString msg_memSize; msg_memSize += memSize;
msg_buffers, msg_memSize, memUnit);
}
{
}
{
double memSize = toHumanUnits(VBOBuffer::nbUploadedBytes(),
memUnit);
MString msg_buffers; msg_buffers +=
(double)VBOBuffer::nbUploaded();
MString msg_memSize; msg_memSize += memSize;
msg_buffers, msg_memSize, memUnit);
}
{
double memSize = toHumanUnits(VBOBuffer::nbEvictedBytes(),
memUnit);
MString msg_buffers; msg_buffers +=
(double)VBOBuffer::nbEvicted();
MString msg_memSize; msg_memSize += memSize;
msg_buffers, msg_memSize, memUnit);
}
}
void Command::dumpHierarchy(
const std::vector<MObject>& gpuCacheNodes,
) const
{
for(
const MObject& gpuCacheObject : gpuCacheNodes) {
MPxNode* node = gpuCacheFn.userNode();
assert(node);
assert(dynamic_cast<ShapeNode*>(node));
ShapeNode* gpuCacheNode =
static_cast<ShapeNode*>(node);
SubNode::Ptr rootNode = gpuCacheNode->getCachedGeometry();
if (rootNode) {
DumpHierarchyVisitor visitor(result);
rootNode->accept(visitor);
}
MaterialGraphMap::Ptr materials = gpuCacheNode->getCachedMaterial();
if (materials) {
DumpMaterialVisitor visitor(result);
visitor.dumpMaterials(materials);
}
}
}
MStatus Command::dumpHierarchyToFile(
const std::vector<MObject>& gpuCacheNodes,
) const
{
dumpHierarchy(gpuCacheNodes, result);
if (!output.is_open()) {
return MS::kFailure;
}
for (
unsigned int i = 0; i < result.
length(); i++) {
output << result[i].asChar() << std::endl;
}
output.close();
return MS::kSuccess;
}
void Command::showAnimTimeRange(
const std::vector<MObject>& gpuCacheNodes,
) const
{
TimeInterval animTimeRange(TimeInterval::kInvalid);
for(
const MObject& node : gpuCacheNodes) {
if (dagNode.typeId() != ShapeNode::id) {
continue;
}
ShapeNode* userNode = dynamic_cast<ShapeNode*>(dagNode.userNode());
if (userNode == NULL) {
continue;
}
const SubNode::Ptr topNode = userNode->getCachedGeometry();
if (userNode->backgroundReadingState() != CacheFileEntry::kReadingDone) {
ScopedPauseWorkerThread pause;
GlobalReaderCache::CacheReaderProxy::Ptr proxy =
GlobalReaderCache::theCache().getCacheReaderProxy(cacheFile);
GlobalReaderCache::CacheReaderHolder holder(proxy);
std::shared_ptr<CacheReader> reader = holder.getCacheReader();
if (reader && reader->valid()) {
TimeInterval interval(TimeInterval::kInvalid);
if (reader->readAnimTimeRange(interval)) {
animTimeRange |= interval;
}
}
}
}
else if (topNode) {
const SubNodeData::Ptr data = topNode->getData();
if (data) {
animTimeRange |= data->animTimeRange();
}
}
}
}
void Command::refresh(const std::vector<MObject>& gpuCacheNodes)
{
for(
const MObject& node : gpuCacheNodes) {
if (dagNode.typeId() != ShapeNode::id) {
continue;
}
ShapeNode* userNode = dynamic_cast<ShapeNode*>(dagNode.userNode());
if (userNode == NULL) {
continue;
}
userNode->refreshCachedGeometry( true );
}
}
}
void Command::refreshAll()
{
CacheFileRegistry::theCache().clear();
std::vector<MObjectHandle> shapes;
CacheShapeRegistry::theCache().getAll( shapes );
for( size_t i = 0; i < shapes.size(); i++ )
{
if( !shapes[i].isValid() )
{
continue;
}
assert( nodeFn.
typeId() == ShapeNode::id );
ShapeNode* shape = (ShapeNode*) nodeFn.
userNode();
assert( shape );
shape->refreshCachedGeometry( false );
}
}
}
void Command::listFileEntries()
{
std::vector<CacheFileEntry::MPtr> entries;
CacheFileRegistry::theCache().getAll(entries);
size_t nEntries = entries.size();
for( size_t i = 0; i < nEntries; i++ )
{
output.
append( entries[i]->fResolvedCacheFileName );
}
}
void Command::listShapeEntries()
{
std::vector<MObjectHandle> shapes;
CacheShapeRegistry::theCache().getAll(shapes);
size_t nShapes = shapes.size();
for( size_t i = 0; i < nShapes; i++ )
{
if( stat )
{
ShapeNode* shapeNode = (ShapeNode*) nodeFn.
userNode();
CacheFileEntry::MPtr entry = shapeNode->getCacheFileEntry();
str += ":";
if( entry )
{
str += entry->fResolvedCacheFileName;
}
}
else
{
str += "kNullObj:";
}
}
}
}