bool getBasicSchemaDataFromObject(Alembic::Abc::IObject &object, BasicSchemaData &bsd) { ESS_PROFILE_SCOPE("getBasicSchemaDataFromObject"); const Alembic::Abc::MetaData &md = object.getMetaData(); if(Alembic::AbcGeom::IXform::matches(md)) return __getBasicSchemaDataFromObject(BasicSchemaData::__XFORM, Alembic::AbcGeom::IXform(object,Alembic::Abc::kWrapExisting).getSchema(), bsd); else if(Alembic::AbcGeom::IPolyMesh::matches(md)) return __getBasicSchemaDataFromObject(BasicSchemaData::__POLYMESH, Alembic::AbcGeom::IPolyMesh(object,Alembic::Abc::kWrapExisting).getSchema(), bsd); else if(Alembic::AbcGeom::ICurves::matches(md)) return __getBasicSchemaDataFromObject(BasicSchemaData::__CURVES, Alembic::AbcGeom::ICurves(object,Alembic::Abc::kWrapExisting).getSchema(), bsd); else if(Alembic::AbcGeom::INuPatch::matches(md)) return __getBasicSchemaDataFromObject(BasicSchemaData::__NUPATCH, Alembic::AbcGeom::INuPatch(object,Alembic::Abc::kWrapExisting).getSchema(), bsd); else if(Alembic::AbcGeom::IPoints::matches(md)) return __getBasicSchemaDataFromObject(BasicSchemaData::__POINTS, Alembic::AbcGeom::IPoints(object,Alembic::Abc::kWrapExisting).getSchema(), bsd); else if(Alembic::AbcGeom::ISubD::matches(md)) return __getBasicSchemaDataFromObject(BasicSchemaData::__SUBDIV, Alembic::AbcGeom::ISubD(object,Alembic::Abc::kWrapExisting).getSchema(), bsd); else if(Alembic::AbcGeom::ICamera::matches(md)) return __getBasicSchemaDataFromObject(BasicSchemaData::__CAMERA, Alembic::AbcGeom::ICamera(object,Alembic::Abc::kWrapExisting).getSchema(), bsd); else if(Alembic::AbcGeom::IFaceSet::matches(md)) return __getBasicSchemaDataFromObject(BasicSchemaData::__FACESET, Alembic::AbcGeom::IFaceSet(object,Alembic::Abc::kWrapExisting).getSchema(), bsd); return false; };
bool AlembicWriteJob::ObjectExists(const MObject &in_Ref) { ESS_PROFILE_SCOPE("AlembicWriteJob::ObjectExists"); std::string fullName(getFullNameFromRef(in_Ref).asChar()); return mapObjects.find(fullName) != mapObjects.end(); }
MStatus AlembicResolvePathCommand::doIt(const MArgList & args) { ESS_PROFILE_SCOPE("AlembicResolvePathCommand::doIt"); MStatus status = MS::kSuccess; MArgParser argData(syntax(), args, &status); if (argData.isFlagSet("help")) { MGlobal::displayInfo("[ExocortexAlembic]: ExocortexAlembic_resolvePath command:"); MGlobal::displayInfo(" -f : provide an unresolved fileName (string)"); return MS::kSuccess; } if(!argData.isFlagSet("fileNameArg")) { // TODO: display dialog MGlobal::displayError("[ExocortexAlembic] No fileName specified."); return status; } // get the filename arg MString fileName = argData.flagArgumentString("fileNameArg",0); setResult(resolvePath(fileName)); return status; }
bool archiveExists(std::string const& path) { ESS_PROFILE_SCOPE("archiveExists"); std::string resolvedPath = resolvePath(path); std::map<std::string, AlembicArchiveInfo>::iterator it; it = gArchives.find(resolvedPath); return it != gArchives.end(); }
std::string addArchive(Alembic::Abc::IArchive * archive) { ESS_PROFILE_SCOPE("addArchive"); AlembicArchiveInfo info; info.archive = archive; gArchives.insert(std::pair<std::string,AlembicArchiveInfo>(archive->getName(),info)); return archive->getName().c_str(); }
bool createAbcArchiveCache( Abc::IArchive *pArchive, AbcArchiveCache* fullNameToObjectCache, CommonProgressBar *pBar ) { ESS_PROFILE_SCOPE("createAbcArchiveCache"); EC_LOG_INFO( "Creating AbcArchiveCache for archive: " << pArchive->getName() ); runonce(); Abc::IObject top = pArchive->getTop(); return addObjectToCache( fullNameToObjectCache, top, "", pBar ) != 0; }
int getRefArchive(std::string const& path) { ESS_PROFILE_SCOPE("getRefArchive"); std::string resolvedPath = resolvePath(path); std::map<std::string, AlembicArchiveInfo>::iterator it; it = gArchives.find(resolvedPath); if (it == gArchives.end()) return -1; return it->second.refCount; }
Abc::IObject getObjectFromArchive(std::string const& path, std::string const& identifier) { ESS_PROFILE_SCOPE("getObjectFromArchive"); AbcObjectCache* objectCache = getObjectCacheFromArchive(path,identifier ); if( objectCache == NULL ) { return Alembic::Abc::IObject(); } return objectCache->obj; }
void deleteAllArchives() { ESS_PROFILE_SCOPE("deleteAllArchives"); for(std::map<std::string,AlembicArchiveInfo>::iterator it = gArchives.begin(); it != gArchives.end(); ++it) { it->second.archive->reset(); delete(it->second.archive); } gArchives.clear(); }
void AlembicWriteJob::SetOption(const MString &in_Name, const MString &in_Value) { ESS_PROFILE_SCOPE("AlembicWriteJob::SetOption"); std::map<std::string, std::string>::iterator it = mOptions.find(in_Name.asChar()); if (it == mOptions.end()) mOptions.insert(std::pair<std::string, std::string>(in_Name.asChar(), in_Value.asChar())); else { it->second = in_Value.asChar(); } }
void deleteArchive(std::string const& path) { ESS_PROFILE_SCOPE("deleteArchive"); std::string resolvedPath = resolvePath(path); std::map<std::string, AlembicArchiveInfo>::iterator it; it = gArchives.find(resolvedPath); if (it == gArchives.end()) return; EC_LOG_INFO("Closing Abc Archive: " << it->second.archive->getName()); it->second.archive->reset(); delete (it->second.archive); gArchives.erase(it); }
int decRefArchive(std::string const& path) { ESS_PROFILE_SCOPE("decRefArchive"); std::string resolvedPath = resolvePath(path); std::map<std::string, AlembicArchiveInfo>::iterator it; it = gArchives.find(resolvedPath); if (it == gArchives.end()) return -1; it->second.refCount--; #ifdef _DEBUG EC_LOG_INFO("ref count (d): " << it->second.refCount); #endif return it->second.refCount; }
std::string resolvePath( std::string const& originalPath ) { ESS_PROFILE_SCOPE("resolvePath"); /* static std::map<std::string,std::string> s_originalToResolvedPath; if( s_originalToResolvedPath.find( originalPath ) != s_originalToResolvedPath.end() ) { return s_originalToResolvedPath[ originalPath ]; }*/ std::string resolvedPath = resolvePath_Internal( EnvVariables::replace( originalPath ) ); //s_originalToResolvedPath.insert( std::pair<std::string,std::string>( originalPath, resolvedPath ) ); return resolvedPath; }
bool AlembicWriteJob::AddObject(AlembicObjectPtr in_Obj) { ESS_PROFILE_SCOPE("AlembicWriteJob::AddObject"); if (!in_Obj) { return false; } const MObject &in_Ref = in_Obj->GetRef(); if (in_Ref.isNull()) { return false; } const std::string fullName(getFullNameFromRef(in_Ref).asChar()); mapObjects.insert( pairStrAbcObj(fullName, in_Obj)); // add it in the multi map! return true; }
Alembic::Abc::TimeSamplingPtr getTimeSamplingFromObject( Alembic::Abc::IObject& object) { ESS_PROFILE_SCOPE("getTimeSamplingFromObject"); const Alembic::Abc::MetaData& md = object.getMetaData(); if (Alembic::AbcGeom::IXform::matches(md)) { return Alembic::AbcGeom::IXform(object, Alembic::Abc::kWrapExisting) .getSchema() .getTimeSampling(); } else if (Alembic::AbcGeom::IPolyMesh::matches(md)) { return Alembic::AbcGeom::IPolyMesh(object, Alembic::Abc::kWrapExisting) .getSchema() .getTimeSampling(); } else if (Alembic::AbcGeom::ICurves::matches(md)) { return Alembic::AbcGeom::ICurves(object, Alembic::Abc::kWrapExisting) .getSchema() .getTimeSampling(); } else if (Alembic::AbcGeom::INuPatch::matches(md)) { return Alembic::AbcGeom::INuPatch(object, Alembic::Abc::kWrapExisting) .getSchema() .getTimeSampling(); } else if (Alembic::AbcGeom::IPoints::matches(md)) { return Alembic::AbcGeom::IPoints(object, Alembic::Abc::kWrapExisting) .getSchema() .getTimeSampling(); } else if (Alembic::AbcGeom::ISubD::matches(md)) { return Alembic::AbcGeom::ISubD(object, Alembic::Abc::kWrapExisting) .getSchema() .getTimeSampling(); } else if (Alembic::AbcGeom::ICamera::matches(md)) { return Alembic::AbcGeom::ICamera(object, Alembic::Abc::kWrapExisting) .getSchema() .getTimeSampling(); } else if (Alembic::AbcGeom::IFaceSet::matches(md)) { return Alembic::AbcGeom::IFaceSet(object, Alembic::Abc::kWrapExisting) .getSchema() .getTimeSampling(); } return Alembic::Abc::TimeSamplingPtr(); }
bool isObjectConstant(Alembic::Abc::IObject& object) { ESS_PROFILE_SCOPE("isObjectConstant"); const Alembic::Abc::MetaData& md = object.getMetaData(); if (Alembic::AbcGeom::IXform::matches(md)) { return isObjectSchemaConstant( Alembic::AbcGeom::IXform(object, Alembic::Abc::kWrapExisting) .getSchema()); } else if (Alembic::AbcGeom::IPolyMesh::matches(md)) { return isObjectSchemaConstant( Alembic::AbcGeom::IPolyMesh(object, Alembic::Abc::kWrapExisting) .getSchema()); } else if (Alembic::AbcGeom::ICurves::matches(md)) { return isObjectSchemaConstant( Alembic::AbcGeom::ICurves(object, Alembic::Abc::kWrapExisting) .getSchema()); } else if (Alembic::AbcGeom::INuPatch::matches(md)) { return isObjectSchemaConstant( Alembic::AbcGeom::INuPatch(object, Alembic::Abc::kWrapExisting) .getSchema()); } else if (Alembic::AbcGeom::IPoints::matches(md)) { return isObjectSchemaConstant( Alembic::AbcGeom::IPoints(object, Alembic::Abc::kWrapExisting) .getSchema()); } else if (Alembic::AbcGeom::ISubD::matches(md)) { return isObjectSchemaConstant( Alembic::AbcGeom::ISubD(object, Alembic::Abc::kWrapExisting) .getSchema()); } else if (Alembic::AbcGeom::ICamera::matches(md)) { return isObjectSchemaConstant( Alembic::AbcGeom::ICamera(object, Alembic::Abc::kWrapExisting) .getSchema()); } else if (Alembic::AbcGeom::IFaceSet::matches(md)) { return isObjectSchemaConstant( Alembic::AbcGeom::IFaceSet(object, Alembic::Abc::kWrapExisting) .getSchema()); } return true; }
MStatus AlembicWriteJob::Process(double frame) { ESS_PROFILE_SCOPE("AlembicWriteJob::Process"); // find the right time frame! int i = -1; for (size_t j = 0; j < mFrames.size(); ++j) { // compare the frames if (fabs(mFrames[j] - frame) <= 0.001) { i = (int)j; break; } } if (i < 0) { return MS::kSuccess; } // run the export for all objects MayaProgressBar pBar; pBar.init(0, (int)mapObjects.size(), 1); pBar.start(); int interrupt = 20; MStatus status; const double currentFrame = mFrames[i]; const bool isFirstFrame = (i == 0); for (multiMapStrAbcObj::iterator it = mapObjects.begin(); it != mapObjects.end(); ++it, --interrupt) { if (interrupt == 0) { interrupt = 20; if (pBar.isCancelled()) { break; } pBar.incr(20); } status = it->second->Save(currentFrame, mTs, isFirstFrame); if (status != MStatus::kSuccess) { MPxCommand::setResult("Error caught in AlembicWriteJob::Process: " + status.errorString()); break; } } pBar.stop(); return status; }
int addRefArchive(std::string const& path) { ESS_PROFILE_SCOPE("addRefArchive"); if (path.empty()) return -1; std::string resolvedPath = resolvePath(path); // call get archive to ensure to create it! getArchiveFromID(path); std::map<std::string, AlembicArchiveInfo>::iterator it; it = gArchives.find(resolvedPath); if (it == gArchives.end()) return -1; it->second.refCount++; #ifdef _DEBUG EC_LOG_INFO("ref count (a): " << it->second.refCount); #endif return it->second.refCount; }
Alembic::Abc::TimeSamplingPtr getTimeSamplingFromObject( Alembic::Abc::OObject* object) { ESS_PROFILE_SCOPE("getTimeSamplingFromObject"); const Alembic::Abc::MetaData& md = object->getMetaData(); if (Alembic::AbcGeom::OXform::matches(md)) { return ((Alembic::AbcGeom::OXform*)(&object)) ->getSchema() .getTimeSampling(); } else if (Alembic::AbcGeom::OPolyMesh::matches(md)) { return ((Alembic::AbcGeom::OPolyMesh*)(&object)) ->getSchema() .getTimeSampling(); } else if (Alembic::AbcGeom::OCurves::matches(md)) { return ((Alembic::AbcGeom::OCurves*)(&object)) ->getSchema() .getTimeSampling(); } else if (Alembic::AbcGeom::ONuPatch::matches(md)) { return ((Alembic::AbcGeom::ONuPatch*)(&object)) ->getSchema() .getTimeSampling(); } else if (Alembic::AbcGeom::OPoints::matches(md)) { return ((Alembic::AbcGeom::OPoints*)(&object)) ->getSchema() .getTimeSampling(); } else if (Alembic::AbcGeom::OSubD::matches(md)) { return ((Alembic::AbcGeom::OSubD*)(&object))->getSchema().getTimeSampling(); } else if (Alembic::AbcGeom::OCamera::matches(md)) { return ((Alembic::AbcGeom::OCamera*)(&object)) ->getSchema() .getTimeSampling(); } else if (Alembic::AbcGeom::OFaceSet::matches(md)) { return ((Alembic::AbcGeom::OFaceSet*)(&object)) ->getSchema() .getTimeSampling(); } return Alembic::Abc::TimeSamplingPtr(); }
AbcObjectCache::AbcObjectCache( Alembic::Abc::IObject & objToCache ) : obj( objToCache ), isMeshTopoDynamic(false), isMeshPointCache(false), fullName(objToCache.getFullName()) { ESS_PROFILE_SCOPE("AbcObjectCache::AbcObjectCache"); BasicSchemaData bsd; getBasicSchemaDataFromObject(objToCache, bsd); isConstant = bsd.isConstant; numSamples = bsd.nbSamples; bool isMesh = true; if ( bsd.type == bsd.__POLYMESH || !( isMesh = (bsd.type != bsd.__SUBDIV) ) ) { bool isTopoDyn = false; extractMeshInfo(&objToCache, isMesh, isMeshPointCache, isTopoDyn); if (!isConstant) isMeshTopoDynamic = isTopoDyn; } }
SampleInfo getSampleInfo ( double iFrame, Alembic::AbcCoreAbstract::TimeSamplingPtr iTime, size_t numSamps ) { ESS_PROFILE_SCOPE("getSampleInfo"); SampleInfo result; if (numSamps == 0) numSamps = 1; std::pair<Alembic::AbcCoreAbstract::index_t, double> floorIndex = iTime->getFloorIndex(iFrame, numSamps); result.floorIndex = floorIndex.first; result.ceilIndex = result.floorIndex; if (fabs(iFrame - floorIndex.second) < 0.0001) { result.alpha = 0.0f; return result; } std::pair<Alembic::AbcCoreAbstract::index_t, double> ceilIndex = iTime->getCeilIndex(iFrame, numSamps); if (fabs(iFrame - ceilIndex.second) < 0.0001) { result.floorIndex = ceilIndex.first; result.ceilIndex = result.floorIndex; result.alpha = 0.0f; return result; } if (result.floorIndex == ceilIndex.first) { result.alpha = 0.0f; return result; } result.ceilIndex = ceilIndex.first; result.alpha = (iFrame - floorIndex.second) / (ceilIndex.second - floorIndex.second); return result; }
AbcArchiveCache* getArchiveCache(std::string const& path, CommonProgressBar* pBar) { ESS_PROFILE_SCOPE("getArchiveCache"); getArchiveFromID(path); std::string resolvedPath = resolvePath(path); std::map<std::string, AlembicArchiveInfo>::iterator it; it = gArchives.find(resolvedPath); if (it == gArchives.end()) return NULL; // compute cache if required. if (it->second.archiveCache.size() == 0) { if (!createAbcArchiveCache(it->second.archive, &(it->second.archiveCache), pBar)) { it->second.archiveCache.clear(); return 0; } } return &(it->second.archiveCache); }
ALEMBIC_TYPE getAlembicTypeFromObject(Abc::IObject object) { ESS_PROFILE_SCOPE("getAlembicTypeFromObject"); const Abc::MetaData &md = object.getMetaData(); if(AbcG::IXform::matches(md)) return AT_Xform; else if(AbcG::IPolyMesh::matches(md)) return AT_PolyMesh; else if(AbcG::ICurves::matches(md)) return AT_Curves; else if(AbcG::INuPatch::matches(md)) return AT_NuPatch; else if(AbcG::IPoints::matches(md)) return AT_Points; else if(AbcG::ISubD::matches(md)) return AT_SubD; else if(AbcG::ICamera::matches(md)) return AT_Camera; return AT_UNKNOWN; }
AbcObjectCache* addObjectToCache( AbcArchiveCache* fullNameToObjectCache, Abc::IObject &obj, std::string parentIdentifier, CommonProgressBar *pBar ) { ESS_PROFILE_SCOPE("addObjectToCache"); AbcObjectCache objectCache( obj ); objectCache.parentIdentifier = parentIdentifier; for( int i = 0; i < obj.getNumChildren(); i ++ ) { if (pBar) { pBar->incr(1); if (!(i % 20) && pBar->isCancelled()) return 0; } Abc::IObject child = obj.getChild( i ); AbcObjectCache* childObjectCache = addObjectToCache( fullNameToObjectCache, child, objectCache.fullName, pBar ); if (childObjectCache == 0) return 0; objectCache.childIdentifiers.push_back( childObjectCache->fullName ); } fullNameToObjectCache->insert( AbcArchiveCache::value_type( objectCache.fullName, objectCache ) ); return &( fullNameToObjectCache->find( objectCache.fullName )->second ); }
MStatus AlembicAssignInitialSGCommand::doIt(const MArgList& args) { MStatus status; MArgParser argData(syntax(), args, &status); if (argData.isFlagSet("help")) { MGlobal::displayInfo("[ExocortexAlembic]: ExocortexAlembic_assignFaceset command:"); MGlobal::displayInfo(" -m : mesh to assign the initialShadingGroup on"); return MS::kSuccess; } if (!argData.isFlagSet("mesh")) { MGlobal::displayError("No mesh/subdiv specified!"); return MS::kFailure; } MObject initShader; MDagPath dagPath; if (getObjectByName("initialShadingGroup", initShader) == MS::kSuccess && getDagPathByName(argData.flagArgumentString("mesh", 0), dagPath) == MS::kSuccess) { ESS_PROFILE_SCOPE("AlembicAssignInitialSGCommand::doIt::MFnSet"); MFnSet set(initShader); set.addMember(dagPath); } else { MString theError("Error getting adding "); theError += argData.flagArgumentString("mesh", 0); theError += MString(" to initalShadingGroup."); MGlobal::displayError(theError); return MS::kFailure; } return MS::kSuccess; }
Alembic::Abc::IArchive* getArchiveFromID(std::string const& path) { ESS_PROFILE_SCOPE("getArchiveFromID-1"); std::map<std::string, AlembicArchiveInfo>::iterator it; std::string resolvedPath = resolvePath(path); it = gArchives.find(resolvedPath); if (it == gArchives.end()) { // check if the file exists if (!boost::filesystem::exists(resolvedPath.c_str())) { ESS_LOG_ERROR("Can't find Alembic file. Path: " << path << " Resolved path: " << resolvedPath); return NULL; } FILE* file = fopen(resolvedPath.c_str(), "rb"); if (file == NULL) { return NULL; } else { fclose(file); AbcF::IFactory iFactory; AbcF::IFactory::CoreType oType; addArchive(new Abc::IArchive(iFactory.getArchive(resolvedPath, oType))); // addArchive(new Abc::IArchive( Alembic::AbcCoreHDF5::ReadArchive(), // resolvedPath)); Abc::IArchive* pArchive = gArchives.find(resolvedPath)->second.archive; EC_LOG_INFO("Opening Abc Archive: " << pArchive->getName()); return pArchive; } } return it->second.archive; }
AlembicPoints::meshInfo AlembicPoints::CacheShapeMesh(Mesh* pShapeMesh, BOOL bNeedDelete, Matrix3 meshTM, int nMatId, int particleId, TimeValue ticks, ShapeType &type, Abc::uint16_t &instanceId, float &animationTime) { ESS_PROFILE_FUNC(); type = ShapeType_Instance; //animationTime = 0; //Mesh* pShapeMesh = pExt->GetParticleShapeByIndex(particleId); if(pShapeMesh->getNumFaces() == 0 || pShapeMesh->getNumVerts() == 0){ meshInfo mi; return mi; } meshDigests digests; { ESS_PROFILE_SCOPE("AlembicPoints::CacheShapeMesh - compute hash"); AbcU::MurmurHash3_x64_128( pShapeMesh->verts, pShapeMesh->numVerts * sizeof(Point3), sizeof(Point3), digests.Vertices.words ); AbcU::MurmurHash3_x64_128( pShapeMesh->faces, pShapeMesh->numFaces * sizeof(Face), sizeof(Face), digests.Faces.words ); if(mJob->GetOption("exportMaterialIds")){ std::vector<MtlID> matIds; if(nMatId < 0){ matIds.reserve(pShapeMesh->getNumFaces()); for(int i=0; i<pShapeMesh->getNumFaces(); i++){ matIds.push_back(pShapeMesh->getFaceMtlIndex(i)); } } else{ matIds.push_back(nMatId); } AbcU::MurmurHash3_x64_128( &matIds[0], matIds.size() * sizeof(MtlID), sizeof(MtlID), digests.MatIds.words ); } if(mJob->GetOption("exportUVs")){ //TODO... } } mTotalShapeMeshes++; meshInfo currShapeInfo; faceVertexHashToShapeMap::iterator it = mShapeMeshCache.find(digests); if( it != mShapeMeshCache.end() ){ currShapeInfo = it->second; } else{ meshInfo& mi = mShapeMeshCache[digests]; mi.pMesh = pShapeMesh; mi.bbox = computeBoundingBox(pShapeMesh); mi.nMatId = nMatId; std::stringstream nameStream; nameStream<< EC_MCHAR_to_UTF8( mMaxNode->GetName() ) <<"_"; nameStream<<"InstanceMesh"<<mNumShapeMeshes; mi.name=nameStream.str(); mi.bNeedDelete = bNeedDelete; mi.meshTM = meshTM; mi.nMeshInstanceId = mNumShapeMeshes; currShapeInfo = mi; mNumShapeMeshes++; mMeshesToSaveForCurrentFrame.push_back(&mi); //ESS_LOG_WARNING("ticks: "<<ticks<<" particleId: "<<particleId); //ESS_LOG_WARNING("Adding shape with hash("<<vertexDigest.str()<<", "<<faceDigest.str()<<") \n auto assigned name "<<mi.name <<" efficiency:"<<(double)mNumShapeMeshes/mTotalShapeMeshes); } instanceId = currShapeInfo.nMeshInstanceId; // { // ESS_PROFILE_SCOPE("CacheShapeMesh push_back instance name"); //std::string pathName("/"); //pathName += currShapeInfo.name; //instanceId = FindInstanceName(pathName); //if (instanceId == USHRT_MAX){ // mInstanceNames.push_back(pathName); // instanceId = (Abc::uint16_t)mInstanceNames.size()-1; //} // } return currShapeInfo; }
MStatus AlembicHair::Save(double time, unsigned int timeIndex, bool isFirstFrame) { ESS_PROFILE_SCOPE("AlembicHair::Save"); MStatus status; // access the geometry MFnPfxGeometry node(GetRef()); // save the metadata SaveMetaData(this); // save the attributes if (isFirstFrame) { Abc::OCompoundProperty cp; Abc::OCompoundProperty up; if (AttributesWriter::hasAnyAttr(node, *GetJob())) { cp = mSchema.getArbGeomParams(); up = mSchema.getUserProperties(); } mAttrs = AttributesWriterPtr( new AttributesWriter(cp, up, GetMyParent(), node, timeIndex, *GetJob()) ); } else { mAttrs->write(); } // prepare the bounding box Abc::Box3d bbox; // check if we have the global cache option const bool globalCache = GetJob()->GetOption(L"exportInGlobalSpace").asInt() > 0; MRenderLineArray mainLines, leafLines, flowerLines; node.getLineData(mainLines, leafLines, flowerLines, true, false, mNumSamples == 0, false, false, mNumSamples == 0, false, true, globalCache); // first we need to count the number of points unsigned int vertexCount = 0; for (unsigned int i = 0; i < (unsigned int)mainLines.length(); i++) { vertexCount += mainLines.renderLine(i, &status).getLine().length(); } mPosVec.resize(vertexCount); unsigned int offset = 0; if (mNumSamples == 0) { mNbVertices.resize((size_t)mainLines.length()); mRadiusVec.resize(vertexCount); mColorVec.resize(vertexCount); for (unsigned int i = 0; i < (unsigned int)mainLines.length(); i++) { const MRenderLine &line = mainLines.renderLine(i, &status); const MVectorArray &positions = line.getLine(); const MDoubleArray &radii = line.getWidth(); const MVectorArray &colors = line.getColor(); const MVectorArray &transparencies = line.getTransparency(); mNbVertices[i] = positions.length(); for (unsigned int j = 0; j < positions.length(); j++) { const MVector &opos = positions[j]; Imath::V3f &ipos = mPosVec[offset]; ipos.x = (float)opos.x; ipos.y = (float)opos.y; ipos.z = (float)opos.z; bbox.extendBy(Imath::V3d(ipos)); mRadiusVec[offset] = (float)radii[j]; const MVector &ocol = colors[j]; Imath::C4f &icol = mColorVec[offset]; icol.r = (float)ocol.x; icol.g = (float)ocol.y; icol.b = (float)ocol.z; icol.a = 1.0f - (float)transparencies[j].x; offset++; } } } else { for (unsigned int i = 0; i < (unsigned int)mainLines.length(); i++) { const MRenderLine &line = mainLines.renderLine(i, &status); const MVectorArray &positions = line.getLine(); for (unsigned int j = 0; j < positions.length(); j++) { const MVector &opos = positions[j]; Imath::V3f &ipos = mPosVec[offset]; ipos.x = (float)opos.x; ipos.y = (float)opos.y; ipos.z = (float)opos.z; bbox.extendBy(Imath::V3d(ipos)); offset++; } } } // store the positions to the samples mSample.setPositions(Abc::P3fArraySample(&mPosVec.front(), mPosVec.size())); mSample.setSelfBounds(bbox); if (mNumSamples == 0) { mSample.setCurvesNumVertices(Abc::Int32ArraySample(mNbVertices)); mSample.setWrap(AbcG::kNonPeriodic); mSample.setType(AbcG::kLinear); mRadiusProperty.set( Abc::FloatArraySample(&mRadiusVec.front(), mRadiusVec.size())); mColorProperty.set( Abc::C4fArraySample(&mColorVec.front(), mColorVec.size())); } // save the sample mSchema.set(mSample); mNumSamples++; return MStatus::kSuccess; }
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; }
MStatus AlembicExportCommand::doIt(const MArgList &args) { ESS_PROFILE_SCOPE("AlembicExportCommand::doIt"); MStatus status = MS::kFailure; MTime currentAnimStartTime = MAnimControl::animationStartTime(), currentAnimEndTime = MAnimControl::animationEndTime(), oldCurTime = MAnimControl::currentTime(), curMinTime = MAnimControl::minTime(), curMaxTime = MAnimControl::maxTime(); MArgParser argData(syntax(), args, &status); if (argData.isFlagSet("help")) { // TODO: implement help for this command // MGlobal::displayInfo(util::getHelpText()); return MS::kSuccess; } unsigned int jobCount = argData.numberOfFlagUses("jobArg"); MStringArray jobStrings; if (jobCount == 0) { // TODO: display dialog MGlobal::displayError("[ExocortexAlembic] No jobs specified."); MPxCommand::setResult( "Error caught in AlembicExportCommand::doIt: no job specified"); return status; } else { // get all of the jobstrings for (unsigned int i = 0; i < jobCount; i++) { MArgList jobArgList; argData.getFlagArgumentList("jobArg", i, jobArgList); jobStrings.append(jobArgList.asString(0)); } } // create a vector to store the jobs std::vector<AlembicWriteJob *> jobPtrs; double minFrame = 1000000.0; double maxFrame = -1000000.0; double maxSteps = 1; double maxSubsteps = 1; // init the curve accumulators AlembicCurveAccumulator::Initialize(); try { // for each job, check the arguments bool failure = false; for (unsigned int i = 0; i < jobStrings.length(); ++i) { double frameIn = 1.0; double frameOut = 1.0; double frameSteps = 1.0; double frameSubSteps = 1.0; MString filename; bool purepointcache = false; bool normals = true; bool uvs = true; bool facesets = true; bool bindpose = true; bool dynamictopology = false; bool globalspace = false; bool withouthierarchy = false; bool transformcache = false; bool useInitShadGrp = false; bool useOgawa = false; // Later, will need to be changed! MStringArray objectStrings; std::vector<std::string> prefixFilters; std::set<std::string> attributes; std::vector<std::string> userPrefixFilters; std::set<std::string> userAttributes; MObjectArray objects; std::string search_str, replace_str; // process all tokens of the job MStringArray tokens; jobStrings[i].split(';', tokens); for (unsigned int j = 0; j < tokens.length(); j++) { MStringArray valuePair; tokens[j].split('=', valuePair); if (valuePair.length() != 2) { MGlobal::displayWarning( "[ExocortexAlembic] Skipping invalid token: " + tokens[j]); continue; } const MString &lowerValue = valuePair[0].toLowerCase(); if (lowerValue == "in") { frameIn = valuePair[1].asDouble(); } else if (lowerValue == "out") { frameOut = valuePair[1].asDouble(); } else if (lowerValue == "step") { frameSteps = valuePair[1].asDouble(); } else if (lowerValue == "substep") { frameSubSteps = valuePair[1].asDouble(); } else if (lowerValue == "normals") { normals = valuePair[1].asInt() != 0; } else if (lowerValue == "uvs") { uvs = valuePair[1].asInt() != 0; } else if (lowerValue == "facesets") { facesets = valuePair[1].asInt() != 0; } else if (lowerValue == "bindpose") { bindpose = valuePair[1].asInt() != 0; } else if (lowerValue == "purepointcache") { purepointcache = valuePair[1].asInt() != 0; } else if (lowerValue == "dynamictopology") { dynamictopology = valuePair[1].asInt() != 0; } else if (lowerValue == "globalspace") { globalspace = valuePair[1].asInt() != 0; } else if (lowerValue == "withouthierarchy") { withouthierarchy = valuePair[1].asInt() != 0; } else if (lowerValue == "transformcache") { transformcache = valuePair[1].asInt() != 0; } else if (lowerValue == "filename") { filename = valuePair[1]; } else if (lowerValue == "objects") { // try to find each object valuePair[1].split(',', objectStrings); } else if (lowerValue == "useinitshadgrp") { useInitShadGrp = valuePair[1].asInt() != 0; } // search/replace else if (lowerValue == "search") { search_str = valuePair[1].asChar(); } else if (lowerValue == "replace") { replace_str = valuePair[1].asChar(); } else if (lowerValue == "ogawa") { useOgawa = valuePair[1].asInt() != 0; } else if (lowerValue == "attrprefixes") { splitListArg(valuePair[1], prefixFilters); } else if (lowerValue == "attrs") { splitListArg(valuePair[1], attributes); } else if (lowerValue == "userattrprefixes") { splitListArg(valuePair[1], userPrefixFilters); } else if (lowerValue == "userattrs") { splitListArg(valuePair[1], userAttributes); } else { MGlobal::displayWarning( "[ExocortexAlembic] Skipping invalid token: " + tokens[j]); continue; } } // now check the object strings for (unsigned int k = 0; k < objectStrings.length(); k++) { MSelectionList sl; MString objectString = objectStrings[k]; sl.add(objectString); MDagPath dag; for (unsigned int l = 0; l < sl.length(); l++) { sl.getDagPath(l, dag); MObject objRef = dag.node(); if (objRef.isNull()) { MGlobal::displayWarning("[ExocortexAlembic] Skipping object '" + objectStrings[k] + "', not found."); break; } // get all parents MObjectArray parents; // check if this is a camera bool isCamera = false; for (unsigned int m = 0; m < dag.childCount(); ++m) { MFnDagNode child(dag.child(m)); MFn::Type ctype = child.object().apiType(); if (ctype == MFn::kCamera) { isCamera = true; break; } } if (dag.node().apiType() == MFn::kTransform && !isCamera && !globalspace && !withouthierarchy) { MDagPath ppath = dag; while (!ppath.node().isNull() && ppath.length() > 0 && ppath.isValid()) { parents.append(ppath.node()); if (ppath.pop() != MStatus::kSuccess) { break; } } } else { parents.append(dag.node()); } // push all parents in while (parents.length() > 0) { bool found = false; for (unsigned int m = 0; m < objects.length(); m++) { if (objects[m] == parents[parents.length() - 1]) { found = true; break; } } if (!found) { objects.append(parents[parents.length() - 1]); } parents.remove(parents.length() - 1); } // check all of the shapes below if (!transformcache) { sl.getDagPath(l, dag); for (unsigned int m = 0; m < dag.childCount(); m++) { MFnDagNode child(dag.child(m)); if (child.isIntermediateObject()) { continue; } objects.append(child.object()); } } } } // check if we have incompatible subframes if (maxSubsteps > 1.0 && frameSubSteps > 1.0) { const double part = (frameSubSteps > maxSubsteps) ? (frameSubSteps / maxSubsteps) : (maxSubsteps / frameSubSteps); if (abs(part - floor(part)) > 0.001) { MString frameSubStepsStr, maxSubstepsStr; frameSubStepsStr.set(frameSubSteps); maxSubstepsStr.set(maxSubsteps); MGlobal::displayError( "[ExocortexAlembic] You cannot combine substeps " + frameSubStepsStr + " and " + maxSubstepsStr + " in one export. Aborting."); return MStatus::kInvalidParameter; } } // remember the min and max values for the frames if (frameIn < minFrame) { minFrame = frameIn; } if (frameOut > maxFrame) { maxFrame = frameOut; } if (frameSteps > maxSteps) { maxSteps = frameSteps; } if (frameSteps > 1.0) { frameSubSteps = 1.0; } if (frameSubSteps > maxSubsteps) { maxSubsteps = frameSubSteps; } // check if we have a filename if (filename.length() == 0) { MGlobal::displayError("[ExocortexAlembic] No filename specified."); for (size_t k = 0; k < jobPtrs.size(); k++) { delete (jobPtrs[k]); } MPxCommand::setResult( "Error caught in AlembicExportCommand::doIt: no filename " "specified"); return MStatus::kFailure; } // construct the frames MDoubleArray frames; { const double frameIncr = frameSteps / frameSubSteps; for (double frame = frameIn; frame <= frameOut; frame += frameIncr) { frames.append(frame); } } AlembicWriteJob *job = new AlembicWriteJob(filename, objects, frames, useOgawa, prefixFilters, attributes, userPrefixFilters, userAttributes); job->SetOption("exportNormals", normals ? "1" : "0"); job->SetOption("exportUVs", uvs ? "1" : "0"); job->SetOption("exportFaceSets", facesets ? "1" : "0"); job->SetOption("exportInitShadGrp", useInitShadGrp ? "1" : "0"); job->SetOption("exportBindPose", bindpose ? "1" : "0"); job->SetOption("exportPurePointCache", purepointcache ? "1" : "0"); job->SetOption("exportDynamicTopology", dynamictopology ? "1" : "0"); job->SetOption("indexedNormals", "1"); job->SetOption("indexedUVs", "1"); job->SetOption("exportInGlobalSpace", globalspace ? "1" : "0"); job->SetOption("flattenHierarchy", withouthierarchy ? "1" : "0"); job->SetOption("transformCache", transformcache ? "1" : "0"); // check if the search/replace strings are valid! if (search_str.length() ? !replace_str.length() : replace_str.length()) // either search or // replace string is // missing or empty! { ESS_LOG_WARNING( "Missing search or replace parameter. No strings will be " "replaced."); job->replacer = SearchReplace::createReplacer(); } else { job->replacer = SearchReplace::createReplacer(search_str, replace_str); } // check if the job is satifsied if (job->PreProcess() != MStatus::kSuccess) { MGlobal::displayError("[ExocortexAlembic] Job skipped. Not satisfied."); delete (job); failure = true; break; } // push the job to our registry MGlobal::displayInfo("[ExocortexAlembic] Using WriteJob:" + jobStrings[i]); jobPtrs.push_back(job); } if (failure) { for (size_t k = 0; k < jobPtrs.size(); k++) { delete (jobPtrs[k]); } return MS::kFailure; } // compute the job count unsigned int jobFrameCount = 0; for (size_t i = 0; i < jobPtrs.size(); i++) jobFrameCount += (unsigned int)jobPtrs[i]->GetNbObjects() * (unsigned int)jobPtrs[i]->GetFrames().size(); // now, let's run through all frames, and process the jobs const double frameRate = MTime(1.0, MTime::kSeconds).as(MTime::uiUnit()); const double incrSteps = maxSteps / maxSubsteps; double nextFrame = minFrame + incrSteps; for (double frame = minFrame; frame <= maxFrame; frame += incrSteps, nextFrame += incrSteps) { MAnimControl::setCurrentTime(MTime(frame / frameRate, MTime::kSeconds)); MAnimControl::setAnimationEndTime( MTime(nextFrame / frameRate, MTime::kSeconds)); MAnimControl::playForward(); // this way, it forces Maya to play exactly // one frame! and particles are updated! AlembicCurveAccumulator::StartRecordingFrame(); for (size_t i = 0; i < jobPtrs.size(); i++) { MStatus status = jobPtrs[i]->Process(frame); if (status != MStatus::kSuccess) { MGlobal::displayError("[ExocortexAlembic] Job aborted :" + jobPtrs[i]->GetFileName()); for (size_t k = 0; k < jobPtrs.size(); k++) { delete (jobPtrs[k]); } restoreOldTime(currentAnimStartTime, currentAnimEndTime, oldCurTime, curMinTime, curMaxTime); return status; } } AlembicCurveAccumulator::StopRecordingFrame(); } } catch (...) { MGlobal::displayError( "[ExocortexAlembic] Jobs aborted, force closing all archives!"); for (std::vector<AlembicWriteJob *>::iterator beg = jobPtrs.begin(); beg != jobPtrs.end(); ++beg) { (*beg)->forceCloseArchive(); } restoreOldTime(currentAnimStartTime, currentAnimEndTime, oldCurTime, curMinTime, curMaxTime); MPxCommand::setResult("Error caught in AlembicExportCommand::doIt"); status = MS::kFailure; } MAnimControl::stop(); AlembicCurveAccumulator::Destroy(); // restore the animation start/end time and the current time! restoreOldTime(currentAnimStartTime, currentAnimEndTime, oldCurTime, curMinTime, curMaxTime); // delete all jobs for (size_t k = 0; k < jobPtrs.size(); k++) { delete (jobPtrs[k]); } // remove all known archives deleteAllArchives(); return status; }