//-***************************************************************************** // // Copyright (c) 2009-2014, // Sony Pictures Imageworks Inc. and // Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd. // // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Sony Pictures Imageworks, nor // Industrial Light & Magic, nor the names of their contributors may be used // to endorse or promote products derived from this software without specific // prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // //-***************************************************************************** #include "AbcWriteJob.h" #ifdef ALEMBIC_WITH_HDF5 #include #endif #include namespace { void hasDuplicates(const util::ShapeSet & dagPath, unsigned int stripDepth) { std::map roots; const util::ShapeSet::const_iterator end = dagPath.end(); for (util::ShapeSet::const_iterator it = dagPath.begin(); it != end; it++) { std::string fullName = it->fullPathName().asChar(); if (!fullName.empty() && fullName[0] == '|') { fullName = fullName.substr(1); } if (stripDepth > 0) { MString name = fullName.c_str(); fullName = util::stripNamespaces(name, stripDepth).asChar(); } std::map::iterator strIt = roots.find(fullName); if (strIt != roots.end()) { std::string theError = "Conflicting root node names specified: "; theError += it->fullPathName().asChar(); theError += " "; theError += strIt->second.fullPathName().asChar(); if (stripDepth > 0) { theError += " with -stripNamespace specified."; } throw std::runtime_error(theError); } else { roots[fullName] = *it; } } } void addToString(std::string & str, const std::string & name, unsigned int value) { if (value > 0) { std::stringstream ss; ss << value; str += name + std::string(" ") + ss.str() + std::string(" "); } } void processCallback(std::string iCallback, bool isMelCallback, double iFrame, const MBoundingBox & iBbox) { if (iCallback.empty()) return; size_t pos = iCallback.find("#FRAME#"); if ( pos != std::string::npos ) { std::stringstream sstrm; sstrm.precision(std::numeric_limits::digits10); sstrm << iFrame; std::string str = sstrm.str(); iCallback.replace(pos, 7, str); } pos = iCallback.find("#BOUNDS#"); if ( pos != std::string::npos ) { std::stringstream sstrm; sstrm.precision(std::numeric_limits::digits10); sstrm << " " << iBbox.min().x << " " << iBbox.min().y << " " << iBbox.min().z << " " << iBbox.max().x << " " << iBbox.max().y << " " <::digits10); if (isMelCallback) { sstrm << " {"; } else { sstrm << " ["; } sstrm << iBbox.min().x << "," << iBbox.min().y << "," << iBbox.min().z << "," << iBbox.max().x << "," << iBbox.max().y << "," << iBbox.max().z; if (isMelCallback) { sstrm << "} "; } else { sstrm << "] "; } std::string str = sstrm.str(); iCallback.replace(pos, 13, str); } if (isMelCallback) MGlobal::executeCommand(iCallback.c_str(), true); else MGlobal::executePythonCommand(iCallback.c_str(), true); } } AbcWriteJob::AbcWriteJob(const char * iFileName, bool iAsOgawa, std::set & iTransFrames, Alembic::AbcCoreAbstract::TimeSamplingPtr iTransTime, std::set & iShapeFrames, Alembic::AbcCoreAbstract::TimeSamplingPtr iShapeTime, const JobArgs & iArgs) { MStatus status; mFileName = iFileName; mAsOgawa = iAsOgawa; mBoxIndex = 0; mArgs = iArgs; mShapeSamples = 1; mTransSamples = 1; if (mArgs.useSelectionList) { bool emptyDagPaths = mArgs.dagPaths.empty(); // get the active selection MSelectionList activeList; MGlobal::getActiveSelectionList(activeList); mSList = activeList; unsigned int selectionSize = activeList.length(); for (unsigned int index = 0; index < selectionSize; index ++) { MDagPath dagPath; status = activeList.getDagPath(index, dagPath); if (status == MS::kSuccess) { unsigned int length = dagPath.length(); while (--length) { dagPath.pop(); mSList.add(dagPath, MObject::kNullObj, true); } if (emptyDagPaths) { mArgs.dagPaths.insert(dagPath); } } } } mTransFrames = iTransFrames; mShapeFrames = iShapeFrames; // only needed during creation of the transforms and shapes mTransTime = iTransTime; mTransTimeIndex = 0; mShapeTime = iShapeTime; mShapeTimeIndex = 0; // should have at least 1 value assert(!mTransFrames.empty() && !mShapeFrames.empty()); mFirstFrame = *(mTransFrames.begin()); std::set::iterator last = mTransFrames.end(); last--; mLastFrame = *last; last = mShapeFrames.end(); last--; double lastShapeFrame = *last; if (lastShapeFrame > mLastFrame) mLastFrame = lastShapeFrame; } MBoundingBox AbcWriteJob::getBoundingBox(double iFrame, const MMatrix & eMInvMat) { MStatus status; MBoundingBox curBBox; if (iFrame == mFirstFrame) { // Set up bbox shape map in the first frame. // If we have a lot of transforms and shapes, we don't need to // iterate them for each frame. MItDag dagIter; for (dagIter.reset(mCurDag); !dagIter.isDone(); dagIter.next()) { MObject object = dagIter.currentItem(); MDagPath path; dagIter.getPath(path); // short-circuit if the selection flag is on but this node is not in the // active selection // MGlobal::isSelected(ob) doesn't work, because DG node and DAG node is // not the same even if they refer to the same MObject if (mArgs.useSelectionList && !mSList.hasItem(path)) { dagIter.prune(); continue; } MFnDagNode dagNode(path, &status); if (status == MS::kSuccess) { // check for riCurves flag for flattening all curve object to // one curve group MPlug riCurvesPlug = dagNode.findPlug("riCurves", true, &status); if ( status == MS::kSuccess && riCurvesPlug.asBool() == true) { MBoundingBox box = dagNode.boundingBox(); box.transformUsing(path.exclusiveMatrix()*eMInvMat); curBBox.expand(box); // Prune this curve group dagIter.prune(); // Save children paths std::map< MDagPath, util::ShapeSet, util::cmpDag >::iterator iter = mBBoxShapeMap.insert(std::make_pair(mCurDag, util::ShapeSet())).first; if (iter != mBBoxShapeMap.end()) (*iter).second.insert(path); } else if (object.hasFn(MFn::kParticle) || object.hasFn(MFn::kMesh) || object.hasFn(MFn::kNurbsCurve) || object.hasFn(MFn::kNurbsSurface) ) { if (util::isIntermediate(object)) continue; MBoundingBox box = dagNode.boundingBox(); box.transformUsing(path.exclusiveMatrix()*eMInvMat); curBBox.expand(box); // Save children paths std::map< MDagPath, util::ShapeSet, util::cmpDag >::iterator iter = mBBoxShapeMap.insert(std::make_pair(mCurDag, util::ShapeSet())).first; if (iter != mBBoxShapeMap.end()) (*iter).second.insert(path); } } } } else { // We have already find out all the shapes for the dag path. std::map< MDagPath, util::ShapeSet, util::cmpDag >::iterator iter = mBBoxShapeMap.find(mCurDag); if (iter != mBBoxShapeMap.end()) { // Iterate through the saved paths to calculate the box. util::ShapeSet& paths = (*iter).second; for (util::ShapeSet::iterator pathIter = paths.begin(); pathIter != paths.end(); pathIter++) { MFnDagNode dagNode(*pathIter, &status); if (status == MS::kSuccess) { MBoundingBox box = dagNode.boundingBox(); box.transformUsing((*pathIter).exclusiveMatrix()*eMInvMat); curBBox.expand(box); } } } } return curBBox; } bool AbcWriteJob::checkCurveGrp() { MItDag itDag(MItDag::kBreadthFirst, MFn::kNurbsCurve); itDag.reset(mCurDag, MItDag::kBreadthFirst, MFn::kNurbsCurve); bool init = false; int degree = 0; MFnNurbsCurve::Form form = MFnNurbsCurve::kInvalid; for (; !itDag.isDone(); itDag.next()) { MDagPath curvePath; if (itDag.getPath(curvePath) == MS::kSuccess) { MObject curve = curvePath.node(); if (!util::isIntermediate(curve) && curve.hasFn(MFn::kNurbsCurve)) { MFnNurbsCurve fn(curvePath); if (!init) { degree = fn.degree(); form = fn.form(); init = true; } else { if (degree != fn.degree() || form != fn.form()) return false; } } } } return true; } void AbcWriteJob::setup(double iFrame, MayaTransformWriterPtr iParent) { MStatus status; // short-circuit if selection flag is on but this node isn't actively // selected if (mArgs.useSelectionList && !mSList.hasItem(mCurDag)) return; MObject ob = mCurDag.node(); // skip all intermediate nodes (and their children) if (util::isIntermediate(ob)) { return; } // skip nodes that aren't renderable (and their children) if (mArgs.excludeInvisible && !util::isRenderable(ob)) { return; } // look for riCurves flag for flattening all curve objects to a curve group MFnDependencyNode fnDepNode(ob, &status); MPlug riCurvesPlug = fnDepNode.findPlug("riCurves", true, &status); bool riCurvesVal = riCurvesPlug.asBool(); bool writeOutAsGroup = false; if (riCurvesVal) { writeOutAsGroup = checkCurveGrp(); if (writeOutAsGroup == false) { MString msg = "Curves have different degrees or close "; msg += "states, not writing out as curve group"; MGlobal::displayWarning(msg); } } if ( status == MS::kSuccess && riCurvesVal && writeOutAsGroup) { if( !mArgs.writeCurvesGroup ) { return; } MayaNurbsCurveWriterPtr nurbsCurve; if (iParent == NULL) { Alembic::Abc::OObject obj = mRoot.getTop(); nurbsCurve = MayaNurbsCurveWriterPtr(new MayaNurbsCurveWriter( mCurDag, obj, mShapeTimeIndex, true, mArgs)); } else { Alembic::Abc::OObject obj = iParent->getObject(); nurbsCurve = MayaNurbsCurveWriterPtr(new MayaNurbsCurveWriter( mCurDag, obj, mShapeTimeIndex, true, mArgs)); } if (nurbsCurve->isAnimated() && mShapeTimeIndex != 0) { mCurveList.push_back(nurbsCurve); mStats.mCurveAnimNum++; mStats.mCurveAnimCurves += nurbsCurve->getNumCurves(); mStats.mCurveAnimCVs += nurbsCurve->getNumCVs(); } else { mStats.mCurveStaticNum++; mStats.mCurveStaticCurves += nurbsCurve->getNumCurves(); mStats.mCurveStaticCVs += nurbsCurve->getNumCVs(); } AttributesWriterPtr attrs = nurbsCurve->getAttrs(); if (mShapeTimeIndex != 0 && attrs->isAnimated()) mShapeAttrList.push_back(attrs); } else if (ob.hasFn(MFn::kTransform)) { MayaTransformWriterPtr trans; MFnTransform fnTrans(ob, &status); if (status != MS::kSuccess) { MString msg = "Initialize transform node "; msg += mCurDag.fullPathName(); msg += " failed, skipping."; MGlobal::displayWarning(msg); return; } // parented to the root case if (iParent == NULL) { Alembic::Abc::OObject obj = mRoot.getTop(); trans = MayaTransformWriterPtr(new MayaTransformWriter( obj, mCurDag, mTransTimeIndex, mArgs)); } else { trans = MayaTransformWriterPtr(new MayaTransformWriter( *iParent, mCurDag, mTransTimeIndex, mArgs)); } if (trans->isAnimated() && mTransTimeIndex != 0) { mTransList.push_back(trans); mStats.mTransAnimNum++; } else { mStats.mTransStaticNum++; } AttributesWriterPtr attrs = trans->getAttrs(); if (mTransTimeIndex != 0 && attrs->isAnimated()) mTransAttrList.push_back(attrs); // loop through the children, making sure to push and pop them // from the MDagPath unsigned int numChild = mCurDag.childCount(); for (unsigned int i = 0; i < numChild; ++i) { if (mCurDag.push(mCurDag.child(i)) == MS::kSuccess) { setup(iFrame, trans); mCurDag.pop(); } } } else if (ob.hasFn(MFn::kLocator)) { if( !mArgs.writeLocators ) { return; } MFnDependencyNode fnLocator(ob, & status); if (status != MS::kSuccess) { MString msg = "Initialize locator node "; msg += mCurDag.fullPathName(); msg += " failed, skipping."; MGlobal::displayWarning(msg); return; } if (iParent != NULL) { Alembic::Abc::OObject obj = iParent->getObject(); MayaLocatorWriterPtr locator(new MayaLocatorWriter( mCurDag, obj, mShapeTimeIndex, mArgs)); if (locator->isAnimated() && mShapeTimeIndex != 0) { mLocatorList.push_back(locator); mStats.mLocatorAnimNum++; } else { mStats.mLocatorStaticNum++; } AttributesWriterPtr attrs = locator->getAttrs(); if (mShapeTimeIndex != 0 && attrs->isAnimated()) mShapeAttrList.push_back(attrs); } else { MString err = "Can't translate "; err += fnLocator.name() + " since it doesn't have a parent."; MGlobal::displayError(err); } } else if (ob.hasFn(MFn::kParticle)) { if( !mArgs.writeParticles ) { return; } MFnParticleSystem mFnParticle(ob, &status); if (status != MS::kSuccess) { MString msg = "Initialize particle system "; msg += mCurDag.fullPathName(); msg += " failed, skipping."; MGlobal::displayWarning(msg); return; } if (iParent != NULL) { Alembic::Abc::OObject obj = iParent->getObject(); MayaPointPrimitiveWriterPtr particle(new MayaPointPrimitiveWriter( iFrame, mCurDag, obj, mShapeTimeIndex, mArgs)); if (particle->isAnimated() && mShapeTimeIndex != 0) { mPointList.push_back(particle); mStats.mPointAnimNum++; mStats.mPointAnimCVs += particle->getNumCVs(); } else { mStats.mPointStaticNum++; mStats.mPointStaticCVs += particle->getNumCVs(); } AttributesWriterPtr attrs = particle->getAttrs(); if (mShapeTimeIndex != 0 && attrs->isAnimated()) mShapeAttrList.push_back(attrs); } else { MString err = "Can't translate "; err += mFnParticle.name() + " since it doesn't have a parent."; MGlobal::displayError(err); } } else if (ob.hasFn(MFn::kMesh)) { if( !mArgs.writeMeshes) { return; } MFnMesh fnMesh(ob, &status); if (status != MS::kSuccess) { MString msg = "Initialize mesh node "; msg += mCurDag.fullPathName(); msg += " failed, skipping."; MGlobal::displayWarning(msg); return; } if (iParent != NULL) { Alembic::Abc::OObject obj = iParent->getObject(); MayaMeshWriterPtr mesh(new MayaMeshWriter(mCurDag, obj, mShapeTimeIndex, mArgs)); if (mesh->isAnimated() && mShapeTimeIndex != 0) { mMeshList.push_back(mesh); if (mesh->isSubD()) { mStats.mSubDAnimNum++; mStats.mSubDAnimCVs += mesh->getNumCVs(); mStats.mSubDAnimFaces += mesh->getNumFaces(); } else { mStats.mPolyAnimNum++; mStats.mPolyAnimCVs += mesh->getNumCVs(); mStats.mPolyAnimFaces += mesh->getNumFaces(); } } else { if (mesh->isSubD()) { mStats.mSubDStaticNum++; mStats.mSubDStaticCVs += mesh->getNumCVs(); mStats.mSubDStaticFaces += mesh->getNumFaces(); } else { mStats.mPolyStaticNum++; mStats.mPolyStaticCVs += mesh->getNumCVs(); mStats.mPolyStaticFaces += mesh->getNumFaces(); } } AttributesWriterPtr attrs = mesh->getAttrs(); if (mShapeTimeIndex != 0 && attrs->isAnimated()) mShapeAttrList.push_back(attrs); if (mShapeTimeIndex != 0) { std::vector< MayaFaceSetWriterPtr >::iterator it; for (it = mesh->beginFaces(); it != mesh->endFaces(); ++it) { if ((*it)->getAttrs() && (*it)->getAttrs()->isAnimated()) { mShapeAttrList.push_back((*it)->getAttrs()); } } } } else { MString err = "Can't translate "; err += fnMesh.name() + " since it doesn't have a parent."; MGlobal::displayError(err); } } else if (ob.hasFn(MFn::kCamera)) { if( !mArgs.writeCameras ) { return; } MFnCamera fnCamera(ob, &status); if (status != MS::kSuccess) { MString msg = "Initialize camera node "; msg += mCurDag.fullPathName(); msg += " failed, skipping."; MGlobal::displayWarning(msg); return; } if (iParent != NULL) { Alembic::Abc::OObject obj = iParent->getObject(); MayaCameraWriterPtr camera(new MayaCameraWriter( mCurDag, obj, mShapeTimeIndex, mArgs)); if (camera->isAnimated() && mShapeTimeIndex != 0) { mCameraList.push_back(camera); mStats.mCameraAnimNum++; } else mStats.mCameraStaticNum++; AttributesWriterPtr attrs = camera->getAttrs(); if (mShapeTimeIndex != 0 && attrs->isAnimated()) mShapeAttrList.push_back(attrs); } else { MString err = "Can't translate "; err += fnCamera.name() + " since it doesn't have a parent."; MGlobal::displayError(err); } } else if (ob.hasFn(MFn::kNurbsSurface)) { if( !mArgs.writeNurbsSurfaces ) { return; } MFnNurbsSurface fnNurbsSurface(ob, &status); if (status != MS::kSuccess) { MString msg = "Initialize nurbs surface "; msg += mCurDag.fullPathName(); msg += " failed, skipping."; MGlobal::displayWarning(msg); return; } if (iParent != NULL) { Alembic::Abc::OObject obj = iParent->getObject(); MayaNurbsSurfaceWriterPtr nurbsSurface(new MayaNurbsSurfaceWriter( mCurDag, obj, mShapeTimeIndex, mArgs)); if (nurbsSurface->isAnimated() && mShapeTimeIndex != 0) { mNurbsList.push_back(nurbsSurface); mStats.mNurbsAnimNum++; mStats.mNurbsAnimCVs += nurbsSurface->getNumCVs(); } else { mStats.mNurbsStaticNum++; mStats.mNurbsStaticCVs += nurbsSurface->getNumCVs(); } AttributesWriterPtr attrs = nurbsSurface->getAttrs(); if (mShapeTimeIndex != 0 && attrs->isAnimated()) mShapeAttrList.push_back(attrs); } else { MString err = "Can't translate "; err += fnNurbsSurface.name() + " since it doesn't have a parent."; MGlobal::displayError(err); } } else if (ob.hasFn(MFn::kNurbsCurve)) { if( !mArgs.writeNurbsCurves ) { return; } MFnNurbsCurve fnNurbsCurve(ob, &status); if (status != MS::kSuccess) { MString msg = "Initialize curve node "; msg += mCurDag.fullPathName(); msg += " failed, skipping."; MGlobal::displayWarning(msg); return; } if (iParent != NULL) { Alembic::Abc::OObject obj = iParent->getObject(); MayaNurbsCurveWriterPtr nurbsCurve(new MayaNurbsCurveWriter( mCurDag, obj, mShapeTimeIndex, false, mArgs)); if (nurbsCurve->isAnimated() && mShapeTimeIndex != 0) { mCurveList.push_back(nurbsCurve); mStats.mCurveAnimNum++; mStats.mCurveAnimCurves++; mStats.mCurveAnimCVs += nurbsCurve->getNumCVs(); } else { mStats.mCurveStaticNum++; mStats.mCurveStaticCurves++; mStats.mCurveStaticCVs += nurbsCurve->getNumCVs(); } AttributesWriterPtr attrs = nurbsCurve->getAttrs(); if (mShapeTimeIndex != 0 && attrs->isAnimated()) mShapeAttrList.push_back(attrs); } else { MString err = "Can't translate "; err += fnNurbsCurve.name() + " since it doesn't have a parent."; MGlobal::displayError(err); } } else { MString warn = mCurDag.fullPathName() + " is an unsupported type of "; warn += ob.apiTypeStr(); MGlobal::displayWarning(warn); } } AbcWriteJob::~AbcWriteJob() { } bool AbcWriteJob::eval(double iFrame) { if (iFrame == mFirstFrame) { // check if the shortnames of any two nodes are the same // if so, exit here hasDuplicates(mArgs.dagPaths, mArgs.stripNamespace); std::string appWriter = "Maya "; appWriter += MGlobal::mayaVersion().asChar(); appWriter += " AbcExport v"; appWriter += ABCEXPORT_VERSION; std::string userInfo = "Exported from: "; userInfo += MFileIO::currentFile().asChar(); // these symbols can't be in the meta data if (userInfo.find('=') != std::string::npos || userInfo.find(';') != std::string::npos) { userInfo = ""; } MTime sec(1.0, MTime::kSeconds); double fps(sec.as(MTime::uiUnit())); #ifdef ALEMBIC_WITH_HDF5 if (mAsOgawa) { mRoot = CreateArchiveWithInfo(Alembic::AbcCoreOgawa::WriteArchive(), mFileName, fps, appWriter, userInfo, Alembic::Abc::ErrorHandler::kThrowPolicy); } else { mRoot = CreateArchiveWithInfo(Alembic::AbcCoreHDF5::WriteArchive(), mFileName, fps, appWriter, userInfo, Alembic::Abc::ErrorHandler::kThrowPolicy); } #else // just write it out as Ogawa mRoot = CreateArchiveWithInfo(Alembic::AbcCoreOgawa::WriteArchive(), mFileName, fps, appWriter, userInfo, Alembic::Abc::ErrorHandler::kThrowPolicy); #endif mShapeTimeIndex = mRoot.addTimeSampling(*mShapeTime); mTransTimeIndex = mRoot.addTimeSampling(*mTransTime); mBoxProp = Alembic::AbcGeom::CreateOArchiveBounds(mRoot, mTransTimeIndex); if (!mRoot.valid()) { std::string theError = "Unable to create abc file"; throw std::runtime_error(theError); } mArgs.setFirstAnimShape = (iFrame == *mShapeFrames.begin()); util::ShapeSet::const_iterator end = mArgs.dagPaths.end(); for (util::ShapeSet::const_iterator it = mArgs.dagPaths.begin(); it != end; ++it) { mCurDag = *it; setup(iFrame * util::spf(), MayaTransformWriterPtr()); } perFrameCallback(iFrame); } else { std::set::iterator checkFrame = mShapeFrames.find(iFrame); bool foundShapeFrame = false; if (checkFrame != mShapeFrames.end()) { assert(mRoot != NULL); foundShapeFrame = true; mShapeSamples ++; double curTime = iFrame * util::spf(); std::vector< MayaCameraWriterPtr >::iterator camIt, camEnd; camEnd = mCameraList.end(); for (camIt = mCameraList.begin(); camIt != camEnd; camIt++) { (*camIt)->write(); } std::vector< MayaMeshWriterPtr >::iterator meshIt, meshEnd; meshEnd = mMeshList.end(); for (meshIt = mMeshList.begin(); meshIt != meshEnd; meshIt++) { (*meshIt)->write(); if ((*meshIt)->isSubD()) { mStats.mSubDAnimCVs += (*meshIt)->getNumCVs(); } else { mStats.mPolyAnimCVs += (*meshIt)->getNumCVs(); } } std::vector< MayaNurbsCurveWriterPtr >::iterator curveIt, curveEnd; curveEnd = mCurveList.end(); for (curveIt = mCurveList.begin(); curveIt != curveEnd; curveIt++) { (*curveIt)->write(); mStats.mCurveAnimCVs += (*curveIt)->getNumCVs(); } std::vector< MayaNurbsSurfaceWriterPtr >::iterator nurbsIt,nurbsEnd; nurbsEnd = mNurbsList.end(); for (nurbsIt = mNurbsList.begin(); nurbsIt != nurbsEnd; nurbsIt++) { (*nurbsIt)->write(); mStats.mNurbsAnimCVs += (*nurbsIt)->getNumCVs(); } std::vector< MayaLocatorWriterPtr >::iterator locIt, locEnd; locEnd = mLocatorList.end(); for (locIt = mLocatorList.begin(); locIt != locEnd; locIt++) { (*locIt)->write(); } std::vector< MayaPointPrimitiveWriterPtr >::iterator ptIt, ptEnd; ptEnd = mPointList.end(); for (ptIt = mPointList.begin(); ptIt != ptEnd; ptIt++) { (*ptIt)->write(curTime); mStats.mPointAnimCVs += (*ptIt)->getNumCVs(); } std::vector< AttributesWriterPtr >::iterator sattrCur = mShapeAttrList.begin(); std::vector< AttributesWriterPtr >::iterator sattrEnd = mShapeAttrList.end(); for(; sattrCur != sattrEnd; sattrCur++) { (*sattrCur)->write(); } } checkFrame = mTransFrames.find(iFrame); bool foundTransFrame = false; if (checkFrame != mTransFrames.end()) { assert(mRoot.valid()); foundTransFrame = true; mTransSamples ++; std::vector< MayaTransformWriterPtr >::iterator tcur = mTransList.begin(); std::vector< MayaTransformWriterPtr >::iterator tend = mTransList.end(); for (; tcur != tend; tcur++) { (*tcur)->write(); } std::vector< AttributesWriterPtr >::iterator tattrCur = mTransAttrList.begin(); std::vector< AttributesWriterPtr >::iterator tattrEnd = mTransAttrList.end(); for(; tattrCur != tattrEnd; tattrCur++) { (*tattrCur)->write(); } } if (foundTransFrame || foundShapeFrame) perFrameCallback(iFrame); } if (iFrame == mLastFrame) { postCallback(iFrame); return true; } return false; } void AbcWriteJob::perFrameCallback(double iFrame) { MBoundingBox bbox; util::ShapeSet::iterator it = mArgs.dagPaths.begin(); const util::ShapeSet::iterator end = mArgs.dagPaths.end(); for (; it != end; it ++) { mCurDag = *it; MMatrix eMInvMat; if (mArgs.worldSpace) { eMInvMat.setToIdentity(); } else { eMInvMat = mCurDag.exclusiveMatrixInverse(); } bbox.expand(getBoundingBox(iFrame, eMInvMat)); } Alembic::Abc::V3d min(bbox.min().x, bbox.min().y, bbox.min().z); Alembic::Abc::V3d max(bbox.max().x, bbox.max().y, bbox.max().z); Alembic::Abc::Box3d b(min, max); mBoxProp.set(b); processCallback(mArgs.melPerFrameCallback, true, iFrame, bbox); processCallback(mArgs.pythonPerFrameCallback, false, iFrame, bbox); } // write the frame ranges and statistic string on the root // Also call the post callbacks void AbcWriteJob::postCallback(double iFrame) { std::string statsStr = ""; addToString(statsStr, "SubDStaticNum", mStats.mSubDStaticNum); addToString(statsStr, "SubDAnimNum", mStats.mSubDAnimNum); addToString(statsStr, "SubDStaticCVs", mStats.mSubDStaticCVs); addToString(statsStr, "SubDAnimCVs", mStats.mSubDAnimCVs); addToString(statsStr, "SubDStaticFaces", mStats.mSubDStaticFaces); addToString(statsStr, "SubDAnimFaces", mStats.mSubDAnimFaces); addToString(statsStr, "PolyStaticNum", mStats.mPolyStaticNum); addToString(statsStr, "PolyAnimNum", mStats.mPolyAnimNum); addToString(statsStr, "PolyStaticCVs", mStats.mPolyStaticCVs); addToString(statsStr, "PolyAnimCVs", mStats.mPolyAnimCVs); addToString(statsStr, "PolyStaticFaces", mStats.mPolyStaticFaces); addToString(statsStr, "PolyAnimFaces", mStats.mPolyAnimFaces); addToString(statsStr, "CurveStaticNum", mStats.mCurveStaticNum); addToString(statsStr, "CurveStaticCurves", mStats.mCurveStaticCurves); addToString(statsStr, "CurveAnimNum", mStats.mCurveAnimNum); addToString(statsStr, "CurveAnimCurves", mStats.mCurveAnimCurves); addToString(statsStr, "CurveStaticCVs", mStats.mCurveStaticCVs); addToString(statsStr, "CurveAnimCVs", mStats.mCurveAnimCVs); addToString(statsStr, "PointStaticNum", mStats.mPointStaticNum); addToString(statsStr, "PointAnimNum", mStats.mPointAnimNum); addToString(statsStr, "PointStaticCVs", mStats.mPointStaticCVs); addToString(statsStr, "PointAnimCVs", mStats.mPointAnimCVs); addToString(statsStr, "NurbsStaticNum", mStats.mNurbsStaticNum); addToString(statsStr, "NurbsAnimNum", mStats.mNurbsAnimNum); addToString(statsStr, "NurbsStaticCVs", mStats.mNurbsStaticCVs); addToString(statsStr, "NurbsAnimCVs", mStats.mNurbsAnimCVs); addToString(statsStr, "TransStaticNum", mStats.mTransStaticNum); addToString(statsStr, "TransAnimNum", mStats.mTransAnimNum); addToString(statsStr, "LocatorStaticNum", mStats.mLocatorStaticNum); addToString(statsStr, "LocatorAnimNum", mStats.mLocatorAnimNum); addToString(statsStr, "CameraStaticNum", mStats.mCameraStaticNum); addToString(statsStr, "CameraAnimNum", mStats.mCameraAnimNum); if (statsStr.length() > 0) { Alembic::Abc::OStringProperty stats(mRoot.getTop().getProperties(), "statistics"); stats.set(statsStr); } if (mTransTimeIndex != 0) { MString propName; propName += static_cast(mTransTimeIndex); propName += ".samples"; Alembic::Abc::OUInt32Property samp(mRoot.getTop().getProperties(), propName.asChar()); samp.set(mTransSamples); } if (mShapeTimeIndex != 0 && mShapeTimeIndex != mTransTimeIndex) { MString propName; propName += static_cast(mShapeTimeIndex); propName += ".samples"; Alembic::Abc::OUInt32Property samp(mRoot.getTop().getProperties(), propName.asChar()); samp.set(mShapeSamples); } MBoundingBox bbox; if (mArgs.melPostCallback.find("#BOUNDS#") != std::string::npos || mArgs.pythonPostCallback.find("#BOUNDS#") != std::string::npos || mArgs.melPostCallback.find("#BOUNDSARRAY#") != std::string::npos || mArgs.pythonPostCallback.find("#BOUNDSARRAY#") != std::string::npos) { util::ShapeSet::const_iterator it = mArgs.dagPaths.begin(); const util::ShapeSet::const_iterator end = mArgs.dagPaths.end(); for (; it != end; it ++) { mCurDag = *it; MMatrix eMInvMat; if (mArgs.worldSpace) { eMInvMat.setToIdentity(); } else { eMInvMat = mCurDag.exclusiveMatrixInverse(); } bbox.expand(getBoundingBox(iFrame, eMInvMat)); } } processCallback(mArgs.melPostCallback, true, iFrame, bbox); processCallback(mArgs.pythonPostCallback, false, iFrame, bbox); }