MString AlembicObject::GetUniqueName(const MString& in_Name) { Abc::OObject parent = GetParentObject(); bool unique = false; MString name = in_Name; unsigned int index = 0; while (!unique) { unique = true; for (size_t i = 0; i < parent.getNumChildren(); i++) { MString childName = parent.getChildHeader(i).getName().c_str(); if (childName == name) { index++; MString indexString; indexString.set((double)index); name = in_Name + indexString; unique = false; break; } } } return name; }
MStatus AlembicWriteJob::PreProcess() { ESS_PROFILE_SCOPE("AlembicWriteJob::PreProcess"); // check filenames if (mFileName.length() == 0) { MGlobal::displayError("[ExocortexAlembic] No filename specified."); MPxCommand::setResult( "Error caught in AlembicWriteJob::PreProcess: no filename specified"); return MStatus::kInvalidParameter; } // check objects if (mSelection.length() == 0) { MGlobal::displayError("[ExocortexAlembic] No objects specified."); MPxCommand::setResult( "Error caught in AlembicWriteJob::PreProcess: no objects specified"); return MStatus::kInvalidParameter; } // check frames if (mFrames.size() == 0) { MGlobal::displayError("[ExocortexAlembic] No frames specified."); MPxCommand::setResult( "Error caught in AlembicWriteJob::PreProcess: no frame specified"); return MStatus::kInvalidParameter; } // check if the file is currently in use if (getRefArchive(mFileName) > 0) { MGlobal::displayError("[ExocortexAlembic] Error writing to file '" + mFileName + "'. File currently in use."); MPxCommand::setResult( "Error caught in AlembicWriteJob::PreProcess: no filename already in " "use"); return MStatus::kInvalidParameter; } // init archive (use a locally scoped archive) // TODO: determine how to access the current maya scene path // MString sceneFileName = "Exported from: // "+Application().GetActiveProject().GetActiveScene().GetParameterValue("FileName").GetAsText(); try { createArchive("Exported from Maya."); mTop = mArchive.getTop(); // get the frame rate mFrameRate = MTime(1.0, MTime::kSeconds).as(MTime::uiUnit()); const double timePerSample = 1.0 / mFrameRate; std::vector<AbcA::chrono_t> frames; for (LONG i = 0; i < mFrames.size(); i++) { frames.push_back(mFrames[i] * timePerSample); } // create the sampling if (frames.size() > 1) { const double timePerCycle = frames[frames.size() - 1] - frames[0]; AbcA::TimeSamplingType samplingType((Abc::uint32_t)frames.size(), timePerCycle); AbcA::TimeSampling sampling(samplingType, frames); mTs = mArchive.addTimeSampling(sampling); } else { AbcA::TimeSampling sampling(1.0, frames[0]); mTs = mArchive.addTimeSampling(sampling); } Abc::OBox3dProperty boxProp = AbcG::CreateOArchiveBounds(mArchive, mTs); MDagPath dagPath; { MItDag().getPath(dagPath); } SceneNodePtr exoSceneRoot = buildMayaSceneGraph(dagPath, this->replacer); const bool bFlattenHierarchy = GetOption("flattenHierarchy") == "1"; const bool bTransformCache = GetOption("transformCache") == "1"; const bool bSelectChildren = false; { std::map<std::string, bool> selectionMap; for (int i = 0; i < (int)mSelection.length(); ++i) { MFnDagNode dagNode(mSelection[i]); selectionMap[dagNode.fullPathName().asChar()] = true; } selectNodes(exoSceneRoot, selectionMap, !bFlattenHierarchy || bTransformCache, bSelectChildren, !bTransformCache, true); } // create object for each MProgressWindow::reserve(); MProgressWindow::setTitle("Alembic Export: Listing objects"); MProgressWindow::setInterruptable(true); MProgressWindow::setProgressRange(0, mSelection.length()); MProgressWindow::setProgress(0); MProgressWindow::startProgress(); int interrupt = 20; bool processStopped = false; std::deque<PreProcessStackElement> sceneStack; sceneStack.push_back(PreProcessStackElement(exoSceneRoot, mTop)); while (!sceneStack.empty()) { if (--interrupt == 0) { interrupt = 20; if (MProgressWindow::isCancelled()) { processStopped = true; break; } } PreProcessStackElement &sElement = sceneStack.back(); SceneNodePtr eNode = sElement.eNode; sceneStack.pop_back(); Abc::OObject oParent = sElement.oParent; Abc::OObject oNewParent; AlembicObjectPtr pNewObject; if (eNode->selected) { switch (eNode->type) { case SceneNode::SCENE_ROOT: break; case SceneNode::ITRANSFORM: case SceneNode::ETRANSFORM: pNewObject.reset(new AlembicXform(eNode, this, oParent)); break; case SceneNode::CAMERA: pNewObject.reset(new AlembicCamera(eNode, this, oParent)); break; case SceneNode::POLYMESH: pNewObject.reset(new AlembicPolyMesh(eNode, this, oParent)); break; case SceneNode::SUBD: pNewObject.reset(new AlembicSubD(eNode, this, oParent)); break; case SceneNode::CURVES: pNewObject.reset(new AlembicCurves(eNode, this, oParent)); break; case SceneNode::PARTICLES: pNewObject.reset(new AlembicPoints(eNode, this, oParent)); break; case SceneNode::HAIR: pNewObject.reset(new AlembicHair(eNode, this, oParent)); break; default: ESS_LOG_WARNING("Unknown type: not exporting " << eNode->name); } } if (pNewObject) { AddObject(pNewObject); oNewParent = oParent.getChild(eNode->name); } else { oNewParent = oParent; } if (oNewParent.valid()) { for (std::list<SceneNodePtr>::iterator it = eNode->children.begin(); it != eNode->children.end(); ++it) { if (!bFlattenHierarchy || (bFlattenHierarchy && eNode->type == SceneNode::ETRANSFORM && isShapeNode((*it)->type))) { // If flattening the hierarchy, we want to attach each external // transform to its corresponding geometry node. // All internal transforms should be skipped. Geometry nodes will // never have children (If and XSI geonode is parented // to another geonode, each will be parented to its extracted // transform node, and one node will be parented to the // transform of the other. sceneStack.push_back(PreProcessStackElement(*it, oNewParent)); } else { // if we skip node A, we parent node A's children to the parent of A sceneStack.push_back(PreProcessStackElement(*it, oParent)); } } } //* else { ESS_LOG_ERROR("Do not have reference to parent."); MPxCommand::setResult( "Error caught in AlembicWriteJob::PreProcess: do not have " "reference to parent"); return MS::kFailure; } //*/ } MProgressWindow::endProgress(); return processStopped ? MStatus::kEndOfFile : MStatus::kSuccess; } catch (AbcU::Exception &e) { this->forceCloseArchive(); MString exc(e.what()); MGlobal::displayError("[ExocortexAlembic] Error writing to file '" + mFileName + "' (" + exc + "). Do you still have it opened?"); MPxCommand::setResult( "Error caught in AlembicWriteJob::PreProcess: error writing file"); } return MS::kFailure; }
bool AlembicWriteJob::PreProcess() { // check filenames if(mFileName.empty()) { ESS_LOG_WARNING("[alembic] No filename specified."); return false; } //// check objects //if(mSelection.Count() == 0) //{ // ESS_LOG_WARNING("[alembic] No objects specified."); // return false; //} // check frames if(mFrames.size() == 0) { ESS_LOG_WARNING("[alembic] No frames specified."); return false; } const bool bParticleMesh = GetOption("exportParticlesAsMesh"); bool bMergePolyMeshSubtree = GetOption("mergePolyMeshSubtree"); bool bSelectParents = GetOption("includeParentNodes");/*|| !bFlattenHierarchy || bTransformCache*/ const bool bSelectChildren = false; bool bTransformCache = GetOption("transformCache"); const bool bFlattenHierarchy = GetOption("flattenHierarchy"); if(bMergePolyMeshSubtree){ bTransformCache = false; //bSelectParents = true; } bcsgSelection::types buildSelection = bcsgSelection::ALL; const bool bExportSelected = GetOption("exportSelected"); const bool bObjectsParameterExists = GetOption("objectsParameterExists"); if(bExportSelected){ //copy max selection buildSelection = bcsgSelection::APP; } else if(bObjectsParameterExists){ //select nothing when building, fill in later from parameter data buildSelection = bcsgSelection::NONE; } else{ //select everything } int nNumNodes = 0; exoSceneRoot = buildCommonSceneGraph(nNumNodes, true, buildSelection); //WARNING ILM robot right crashes when printing //printSceneGraph(exoSceneRoot, false); if(bObjectsParameterExists){ //Might be better to use refineSelection here, but call a function that sets up dccSelected flag first, then delete this function from codebase selectNodes(exoSceneRoot, mObjectsMap, bSelectParents, bSelectChildren, !bTransformCache); bool bAllResolved = true; if(bObjectsParameterExists){ for(SceneNode::SelectionT::iterator it = mObjectsMap.begin(); it != mObjectsMap.end(); it++){ if(it->second == false){ bAllResolved = false; ESS_LOG_ERROR("Could not resolve objects identifier: "<<it->first); } } } if(bAllResolved){ removeUnselectedNodes(exoSceneRoot); } else{ return false; } } else if(bExportSelected){ refineSelection(exoSceneRoot, bSelectParents, bSelectChildren, !bTransformCache); removeUnselectedNodes(exoSceneRoot); } if(bMergePolyMeshSubtree){ replacePolyMeshSubtree<SceneNodeMaxPtr, SceneNodeMax>(exoSceneRoot); } if(bFlattenHierarchy){ nNumNodes = 0; flattenSceneGraph(exoSceneRoot, nNumNodes); } if(GetOption("renameConflictingNodes")){ renameConflictingNodes(exoSceneRoot, false); } else{ int nRenameCount = renameConflictingNodes(exoSceneRoot, true); if(nRenameCount){ ESS_LOG_ERROR("Can not export due sibling node naming conflict. Consider exporting with renameConflictingNodes=true"); return false; } } const bool bUseOgawa = (bool)GetOption("useOgawa"); // init archive (use a locally scoped archive) std::string sceneFileName = ""; sceneFileName.append( EC_MSTR_to_UTF8( mApplication->GetCurFilePath() ) ); try { if(bUseOgawa){ mArchive = CreateArchiveWithInfo( Alembic::AbcCoreOgawa::WriteArchive(), mFileName.c_str(), getExporterName( "3DS Max " EC_QUOTE( crate_Max_Version ) ).c_str(), getExporterFileName( sceneFileName ).c_str(), Abc::ErrorHandler::kThrowPolicy); } else{ mArchive = CreateArchiveWithInfo( Alembic::AbcCoreHDF5::WriteArchive( true ), mFileName.c_str(), getExporterName( "3DS Max " EC_QUOTE( crate_Max_Version ) ).c_str(), getExporterFileName( sceneFileName ).c_str(), Abc::ErrorHandler::kThrowPolicy); } } catch(Alembic::Util::Exception& e) { std::string exc(e.what()); ESS_LOG_ERROR("[alembic] Error writing to file: "<<e.what()); return false; } // get the frame rate mFrameRate = static_cast<float>(GetFrameRate()); if(mFrameRate == 0.0f) { mFrameRate = 25.0f; } std::vector<AbcA::chrono_t> frames; for(LONG i=0;i<mFrames.size();i++) { frames.push_back(mFrames[i] / mFrameRate); } // create the sampling double timePerSample = 1.0 / mFrameRate; if(frames.size() > 1) { if( ! HasAlembicWriterLicense() ) { if( HasAlembicInvalidLicense() ) { ESS_LOG_ERROR("[alembic] No license available and EXOCORTEX_ALEMBIC_NO_DEMO defined, aborting." ); return false; } if(frames.size() > 75) { frames.resize(75); ESS_LOG_WARNING("[ExocortexAlembic] Writer license not found: Maximum exportable samplecount is 75!"); } } double timePerCycle = frames[frames.size()-1] - frames[0]; AbcA::TimeSamplingType samplingType((boost::uint32_t)frames.size(),timePerCycle); AbcA::TimeSampling sampling(samplingType,frames); mTs = mArchive.addTimeSampling(sampling); } else { AbcA::TimeSampling sampling(1.0,frames[0]); mTs = mArchive.addTimeSampling(sampling); } m_ArchiveBoxProp = AbcG::CreateOArchiveBounds(mArchive,mTs); std::list<PreProcessStackElement> sceneStack; sceneStack.push_back(PreProcessStackElement(exoSceneRoot, mArchive.getTop())); try{ while( !sceneStack.empty() ) { PreProcessStackElement sElement = sceneStack.back(); SceneNodePtr eNode = sElement.eNode; sceneStack.pop_back(); Abc::OObject oParent = sElement.oParent; Abc::OObject oNewParent; AlembicObjectPtr pNewObject; if(eNode->type == SceneNode::SCENE_ROOT){ //we do not want to export the Scene_Root (the alembic archive has one already) } else if(eNode->type == SceneNode::ITRANSFORM || eNode->type == SceneNode::ETRANSFORM){ pNewObject.reset(new AlembicXForm(eNode, this, oParent)); } else if(eNode->type == SceneNode::CAMERA){ pNewObject.reset(new AlembicCamera(eNode, this, oParent)); } else if(eNode->type == SceneNode::POLYMESH || eNode->type == SceneNode::POLYMESH_SUBTREE){ pNewObject.reset(new AlembicPolyMesh(eNode, this, oParent)); } //TODO: as far I recall we dont support SUBD. verify... //else if(eNode->type == SceneNode::SUBD){ // pNewObject.reset(new AlembicSubD(eNode, this, oParent)); //} else if(eNode->type == SceneNode::CURVES){ pNewObject.reset(new AlembicCurves(eNode, this, oParent)); } else if(eNode->type == SceneNode::PARTICLES || eNode->type == SceneNode::PARTICLES_TP){ if(bParticleMesh){ pNewObject.reset(new AlembicPolyMesh(eNode, this, oParent)); } else{ pNewObject.reset(new AlembicPoints(eNode, this, oParent)); } } //else{ // ESS_LOG_WARNING("Unknown type: not exporting "<<eNode->name);//Export as transform, and give warning? //} if(pNewObject){ //add the AlembicObject to export list if it is not being skipped AddObject(pNewObject); } if(pNewObject){ oNewParent = oParent.getChild(eNode->name); } else{ //this case should be unecessary //if we skip node A, we parent node A's children to the parent of A oNewParent = oParent; } if(oNewParent.valid()){ for( std::list<SceneNodePtr>::iterator it = eNode->children.begin(); it != eNode->children.end(); it++){ sceneStack.push_back(PreProcessStackElement(*it, oNewParent)); } } else{ ESS_LOG_ERROR("Do not have refernce to parent."); return false; } } }catch( std::exception& exp ){ ESS_LOG_ERROR("An std::exception occured: "<<exp.what()); return false; }catch(...){ ESS_LOG_ERROR("Exception ecountered when exporting."); } if(mObjects.empty()){ ESS_LOG_ERROR("No objects specified."); return false; } return true; }