//- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined (_WIN32) #define strcasecmp stricmp #elif defined (OSMac_) extern "C" int strcasecmp (const char *, const char *); extern "C" Boolean createMacFile (const char *fileName, FSRef *fsRef, long creator, long type); #endif #define NO_SMOOTHING_GROUP -1 #define INITIALIZE_SMOOTHING -2 #define INVALID_ID -1 // // Edge info structure // typedef struct EdgeInfo { int polyIds[2]; // Id's of polygons that reference edge int vertId; // The second vertex of this edge struct EdgeInfo * next; // Pointer to next edge bool smooth; // Is this edge smooth } * EdgeInfoPtr; ////////////////////////////////////////////////////////////// class ObjTranslator : public MPxFileTranslator { public: ObjTranslator () {}; virtual ~ObjTranslator () {}; static void* creator(); MStatus reader ( const MFileObject& file, const MString& optionsString, FileAccessMode mode); MStatus writer ( const MFileObject& file, const MString& optionsString, FileAccessMode mode ); bool haveReadMethod () const; bool haveWriteMethod () const; MString defaultExtension () const; MFileKind identifyFile ( const MFileObject& fileName, const char* buffer, short size) const; private: void outputSetsAndGroups ( MDagPath&, int, bool, int ); MStatus OutputPolygons( MDagPath&, MObject& ); MStatus exportSelected(); MStatus exportAll(); void initializeSetsAndLookupTables( bool exportAll ); void freeLookupTables(); bool lookup( MDagPath&, int, int, bool ); void setToLongUnitName( const MDistance::Unit&, MString& ); void recFindTransformDAGNodes( MString&, MIntArray& ); // Edge lookup methods // void buildEdgeTable( MDagPath& ); void addEdgeInfo( int, int, bool ); EdgeInfoPtr findEdgeInfo( int, int ); void destroyEdgeTable(); bool smoothingAlgorithm( int, MFnMesh& ); private: // counters int v,vt,vn; // offsets int voff,vtoff,vnoff; // options bool groups, ptgroups, materials, smoothing, normals; FILE *fp; // Keeps track of all sets. // int numSets; MObjectArray *sets; // Keeps track of all objects and components. // The Tables are used to mark which sets each // component belongs to. // MStringArray *objectNames; bool **polygonTablePtr; bool **vertexTablePtr; bool * polygonTable; bool * vertexTable; bool **objectGroupsTablePtr; // Used to determine if the last set(s) written out are the same // as the current sets to be written. We don't need to write out // sets unless they change between components. Same goes for // materials. // MIntArray *lastSets; MIntArray *lastMaterials; // We have to do 2 dag iterations so keep track of the // objects found in the first iteration by this index. // int objectId; int objectCount; // Edge lookup table (by vertex id) and smoothing group info // EdgeInfoPtr * edgeTable; int * polySmoothingGroups; int edgeTableSize; int nextSmoothingGroup; int currSmoothingGroup; bool newSmoothingGroup; // List of names of the mesh shapes that we export from maya MStringArray objectNodeNamesArray; // Used to keep track of Maya groups (transform DAG nodes) that // contain objects being exported MStringArray transformNodeNameArray; }; ////////////////////////////////////////////////////////////// const char *const objOptionScript = "objExportOptions"; const char *const objDefaultOptions = "groups=1;" "ptgroups=1;" "materials=1;" "smoothing=1;" "normals=1;" ; ////////////////////////////////////////////////////////////// void* ObjTranslator::creator() { return new ObjTranslator(); } ////////////////////////////////////////////////////////////// MStatus ObjTranslator::reader ( const MFileObject& file, const MString& options, FileAccessMode mode) { fprintf(stderr, "ObjTranslator::reader called in error\n"); return MS::kFailure; } ////////////////////////////////////////////////////////////// #if defined (OSMac_) // Convert file system representations // Possible styles: kCFURLHFSPathStyle, kCFURLPOSIXPathStyle // kCFURLHFSPathStyle = Emerald:aw:Maya:projects:default:scenes:eagle.ma // kCFURLPOSIXPathStyle = /Volumes/Emerald/aw/Maya/projects/default/scenes/eagle.ma // The conversion will be done in place, so make sure fileName is big enough // to hold the result // static Boolean convertFileRepresentation (char *fileName, short inStyle, short outStyle) { if (fileName == NULL) { return (false); } if (inStyle == outStyle) { return (true); } CFStringRef rawPath = CFStringCreateWithCString (NULL, fileName, kCFStringEncodingUTF8); if (rawPath == NULL) { return (false); } CFURLRef baseURL = CFURLCreateWithFileSystemPath (NULL, rawPath, (CFURLPathStyle)inStyle, false); CFRelease (rawPath); if (baseURL == NULL) { return (false); } CFStringRef newURL = CFURLCopyFileSystemPath (baseURL, (CFURLPathStyle)outStyle); CFRelease (baseURL); if (newURL == NULL) { return (false); } char newPath[MAXPATHLEN]; CFStringGetCString (newURL, newPath, MAXPATHLEN, kCFStringEncodingUTF8); CFRelease (newURL); strcpy (fileName, newPath); return (true); } #endif MStatus ObjTranslator::writer ( const MFileObject& file, const MString& options, FileAccessMode mode ) { MStatus status; MString mname = file.fullName(), unitName; #if defined (OSMac_) char fname[MAXPATHLEN]; strcpy (fname, file.fullName().asChar()); FSRef notUsed; //Create a file else convertFileRep will fail. createMacFile (fname, ¬Used, 0, 0); convertFileRepresentation (fname, kCFURLPOSIXPathStyle, kCFURLHFSPathStyle); fp = fopen(fname,"wb");//MAYAMACTODO #else const char *fname = mname.asChar(); fp = fopen(fname,"w"); #endif if (fp == NULL) { cerr << "Error: The file " << fname << " could not be opened for writing." << endl; return MS::kFailure; } // Options // groups = true; // write out facet groups ptgroups = true; // write out vertex groups materials = true; // write out shading groups smoothing = true; // write out facet smoothing information normals = true; // write out normal table and facet normals if (options.length() > 0) { int i, length; // Start parsing. MStringArray optionList; MStringArray theOption; options.split(';', optionList); // break out all the options. length = optionList.length(); for( i = 0; i < length; ++i ){ theOption.clear(); optionList[i].split( '=', theOption ); if( theOption[0] == MString("groups") && theOption.length() > 1 ) { if( theOption[1].asInt() > 0 ){ groups = true; }else{ groups = false; } } if( theOption[0] == MString("materials") && theOption.length() > 1 ) { if( theOption[1].asInt() > 0 ){ materials = true; }else{ materials = false; } } if( theOption[0] == MString("ptgroups") && theOption.length() > 1 ) { if( theOption[1].asInt() > 0 ){ ptgroups = true; }else{ ptgroups = false; } } if( theOption[0] == MString("normals") && theOption.length() > 1 ) { if( theOption[1].asInt() > 0 ){ normals = true; }else{ normals = false; } } if( theOption[0] == MString("smoothing") && theOption.length() > 1 ) { if( theOption[1].asInt() > 0 ){ smoothing = true; }else{ smoothing = false; } } } } /* print current linear units used as a comment in the obj file */ setToLongUnitName(MDistance::uiUnit(), unitName); //fprintf( fp, "# This file uses %s as units for non-parametric coordinates.\n\n", unitName.asChar() ); fprintf( fp, "# The units used in this file are %s.\n", unitName.asChar() ); if( ( mode == MPxFileTranslator::kExportAccessMode ) || ( mode == MPxFileTranslator::kSaveAccessMode ) ) { exportAll(); } else if( mode == MPxFileTranslator::kExportActiveAccessMode ) { exportSelected(); } fclose(fp); return MS::kSuccess; } ////////////////////////////////////////////////////////////// void ObjTranslator::setToLongUnitName(const MDistance::Unit &unit, MString& unitName) { switch( unit ) { case MDistance::kInches: /// Inches unitName = "inches"; break; case MDistance::kFeet: /// Feet unitName = "feet"; break; case MDistance::kYards: /// Yards unitName = "yards"; break; case MDistance::kMiles: /// Miles unitName = "miles"; break; case MDistance::kMillimeters: /// Millimeters unitName = "millimeters"; break; case MDistance::kCentimeters: /// Centimeters unitName = "centimeters"; break; case MDistance::kKilometers: /// Kilometers unitName = "kilometers"; break; case MDistance::kMeters: /// Meters unitName = "meters"; break; } } ////////////////////////////////////////////////////////////// bool ObjTranslator::haveReadMethod () const { return false; } ////////////////////////////////////////////////////////////// bool ObjTranslator::haveWriteMethod () const { return true; } ////////////////////////////////////////////////////////////// MString ObjTranslator::defaultExtension () const { return "obj"; } ////////////////////////////////////////////////////////////// MPxFileTranslator::MFileKind ObjTranslator::identifyFile ( const MFileObject& fileName, const char* buffer, short size) const { const char * name = fileName.name().asChar(); int nameLength = strlen(name); if ((nameLength > 4) && !strcasecmp(name+nameLength-4, ".obj")) return kCouldBeMyFileType; else return kNotMyFileType; } ////////////////////////////////////////////////////////////// MStatus initializePlugin( MObject obj ) { MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any"); // Register the translator with the system return plugin.registerFileTranslator( "OBJexport", "none", ObjTranslator::creator, (char *)objOptionScript, (char *)objDefaultOptions ); } ////////////////////////////////////////////////////////////// MStatus uninitializePlugin( MObject obj ) { MFnPlugin plugin( obj ); return plugin.deregisterFileTranslator( "OBJexport" ); } ////////////////////////////////////////////////////////////// MStatus ObjTranslator::OutputPolygons( MDagPath& mdagPath, MObject& mComponent ) { MStatus stat = MS::kSuccess; MSpace::Space space = MSpace::kWorld; int i; MFnMesh fnMesh( mdagPath, &stat ); if ( MS::kSuccess != stat) { fprintf(stderr,"Failure in MFnMesh initialization.\n"); return MS::kFailure; } MItMeshPolygon polyIter( mdagPath, mComponent, &stat ); if ( MS::kSuccess != stat) { fprintf(stderr,"Failure in MItMeshPolygon initialization.\n"); return MS::kFailure; } MItMeshVertex vtxIter( mdagPath, mComponent, &stat ); if ( MS::kSuccess != stat) { fprintf(stderr,"Failure in MItMeshVertex initialization.\n"); return MS::kFailure; } int objectIdx, length; MString mdagPathNodeName = fnMesh.name(); // Find i such that objectGroupsTablePtr[i] corresponds to the // object node pointed to by mdagPath length = objectNodeNamesArray.length(); for( i=0; i 0 ) { int uvIndex; // If the call to getUVIndex fails then there is no // mapping information for this polyon so we don't write // anything // if ( polyIter.getUVIndex(vtx,uvIndex) ) { fprintf(fp,"/%d",uvIndex+1 +vtoff); noUV = false; } } if ( (normals) && (fnMesh.numNormals() > 0) ) { if ( noUV ) { // If there are no UVs then our polygon is written // in the form vertex//normal // fprintf(fp,"/"); } fprintf(fp,"/%d",polyIter.normalIndex( vtx ) +1 +vnoff); } } fprintf(fp,"\n"); fflush(fp); } return stat; } ////////////////////////////////////////////////////////////// void ObjTranslator::outputSetsAndGroups( MDagPath & mdagPath, int cid, bool isVertexIterator, int objectIdx ) { MStatus stat; int i, length; MIntArray * currentSets = new MIntArray; MIntArray * currentMaterials = new MIntArray; MStringArray gArray, mArray; if (groups || materials) { for ( i=0; iappend( i ); mArray.append( fnSet.name() ); } else { currentSets->append( i ); gArray.append( fnSet.name() ); } } } if( !isVertexIterator ) { // export group nodes (transform DAG nodes) in Maya that // the current object is a // child/grandchild/grandgrandchild/... of bool *objectGroupTable = objectGroupsTablePtr[objectIdx]; length = transformNodeNameArray.length(); for( i=0; iappend( numSets + i ); gArray.append(transformNodeNameArray[i]); } } } // prevent grouping incoherence, use tav default group schema. // if (0 == currentSets->length()) { currentSets->append( 0 ); gArray.append( "default" ); } // Test for equivalent sets // bool setsEqual = false; if ( (lastSets != NULL) && (lastSets->length() == currentSets->length()) ) { setsEqual = true; length = lastSets->length(); for ( i=0; i 0 ) { fprintf(fp,"g"); for ( i=0; ilength() == currentMaterials->length()) ) { materialsEqual = true; length = lastMaterials->length(); for ( i=0; i 0 ) { fprintf(fp,"usemtl"); for ( i=0; iadd( result[i] ); } // Extract each set as an MObject and add them to the // sets array. // We may be excluding groups, matierials, or ptGroups // in which case we can ignore those sets. // MObject mset; sets = new MObjectArray(); length = setList->length(); for ( i=0; igetDependNode( i, mset ); MFnSet fnSet( mset, &stat ); if ( stat ) { if ( MFnSet::kRenderableOnly == fnSet.restriction(&stat) ) { if ( materials ) { sets->append( mset ); } } else { if ( groups ) { sets->append( mset ); } } } } delete setList; numSets = sets->length(); ////////////////////////////////////////////////////////////////// // // Do a dag-iteration and for every mesh found, create facet and // vertex look-up tables. These tables will keep track of which // sets each component belongs to. // // If exportAll is false then iterate over the activeSelection // list instead of the entire DAG. // // These arrays have a corrisponding entry in the name // stringArray. // ////////////////////////////////////////////////////////////////// MIntArray vertexCounts; MIntArray polygonCounts; if ( exportAll ) { MItDag dagIterator( MItDag::kBreadthFirst, MFn::kInvalid, &stat); if ( MS::kSuccess != stat) { fprintf(stderr,"Failure in DAG iterator setup.\n"); return; } objectNames = new MStringArray; for ( ; !dagIterator.isDone(); dagIterator.next() ) { MDagPath dagPath; stat = dagIterator.getPath( dagPath ); if ( stat ) { // skip over intermediate objects // MFnDagNode dagNode( dagPath, &stat ); if (dagNode.isIntermediateObject()) { continue; } if (( dagPath.hasFn(MFn::kMesh)) && ( dagPath.hasFn(MFn::kTransform))) { // We want only the shape, // not the transform-extended-to-shape. continue; } else if ( dagPath.hasFn(MFn::kMesh)) { // We have a mesh so create a vertex and polygon table // for this object. // MFnMesh fnMesh( dagPath ); int vtxCount = fnMesh.numVertices(); int polygonCount = fnMesh.numPolygons(); // we do not need this call anymore, we have the shape. // dagPath.extendToShape(); MString name = dagPath.fullPathName(); objectNames->append( name ); objectNodeNamesArray.append( fnMesh.name() ); vertexCounts.append( vtxCount ); polygonCounts.append( polygonCount ); objectCount++; } } } } else { MSelectionList slist; MGlobal::getActiveSelectionList( slist ); MItSelectionList iter( slist ); MStatus status; objectNames = new MStringArray; // We will need to interate over a selected node's heirarchy // in the case where shapes are grouped, and the group is selected. MItDag dagIterator( MItDag::kDepthFirst, MFn::kInvalid, &status); for ( ; !iter.isDone(); iter.next() ) { MDagPath objectPath; stat = iter.getDagPath( objectPath ); // reset iterator's root node to be the selected node. status = dagIterator.reset (objectPath.node(), MItDag::kDepthFirst, MFn::kInvalid ); // DAG iteration beginning at at selected node for ( ; !dagIterator.isDone(); dagIterator.next() ) { MDagPath dagPath; MObject component = MObject::kNullObj; status = dagIterator.getPath(dagPath); if (!status) { fprintf(stderr,"Failure getting DAG path.\n"); freeLookupTables(); return ; } // skip over intermediate objects // MFnDagNode dagNode( dagPath, &stat ); if (dagNode.isIntermediateObject()) { continue; } if (( dagPath.hasFn(MFn::kMesh)) && ( dagPath.hasFn(MFn::kTransform))) { // We want only the shape, // not the transform-extended-to-shape. continue; } else if ( dagPath.hasFn(MFn::kMesh)) { // We have a mesh so create a vertex and polygon table // for this object. // MFnMesh fnMesh( dagPath ); int vtxCount = fnMesh.numVertices(); int polygonCount = fnMesh.numPolygons(); // we do not need this call anymore, we have the shape. // dagPath.extendToShape(); MString name = dagPath.fullPathName(); objectNames->append( name ); objectNodeNamesArray.append( fnMesh.name() ); vertexCounts.append( vtxCount ); polygonCounts.append( polygonCount ); objectCount++; } } } } // Now we know how many objects we are dealing with // and we have counts of the vertices/polygons for each // object so create the maya group look-up table. // if( objectCount > 0 ) { // To export Maya groups we traverse the hierarchy starting at // each objectNodeNamesArray[i] going towards the root collecting transform // nodes as we go. length = objectNodeNamesArray.length(); for( i=0; i 0 ) { objectGroupsTablePtr = (bool**) malloc( sizeof(bool*)*objectCount ); length = transformNodeNameArray.length(); for ( i=0; i 0 ) { vertexTablePtr = (bool**) malloc( sizeof(bool*)*objectCount ); polygonTablePtr = (bool**) malloc( sizeof(bool*)*objectCount ); for ( i=0; ilength(); for ( o=0; olength(); for ( o=0; o= polygonCounts[o] ) { cerr << "Error: component in set >= numPolygons, skipping!\n"; cerr << " Component index = " << compIdx << endl; cerr << " Number of polygons = " << polygonCounts[o] << endl; break; } polygonTable = polygonTablePtr[o]; *(polygonTable + numSets*compIdx + i) = true; break; } } } } } else { // There are no components, therefore we can mark // all polygons as members of the given set. // if (object.hasFn(MFn::kMesh)) { MFnMesh fnMesh( object, &stat ); if ( MS::kSuccess != stat) { fprintf(stderr,"Failure in MFnMesh initialization.\n"); return; } // We are going to iterate over all the polygons. // MItMeshPolygon piter( object, MObject::kNullObj, &stat ); if ( MS::kSuccess != stat) { fprintf(stderr, "Failure in MItMeshPolygon initialization.\n"); return; } for ( ; !piter.isDone(); piter.next() ) { int compIdx = piter.index(); MString name = object.fullPathName(); // Figure out which object polygonTable to get. // int o, numObjectNames; numObjectNames = objectNames->length(); for ( o=0; o= polygonCounts[o] ) { cerr << "Error: component in set >= numPolygons, skipping!\n"; cerr << " Component index = " << compIdx << endl; cerr << " Number of polygons = " << polygonCounts[o] << endl; break; } // Mark set i as true in the table // polygonTable = polygonTablePtr[o]; *(polygonTable + numSets*compIdx + i) = true; break; } } } // end of piter.next() loop } // end of condition if (object.hasFn(MFn::kMesh)) } // end of else condifion if (!component.isNull()) } // end of memberList.getDagPath(m,object,component) } // end of memberList loop } // end of for-loop for sets // Go through all of the group members and mark in the // lookup-table, the group that each shape belongs to. length = objectNodeNamesArray.length(); for( i=0; ipolyIds[0] ) { elem->polyIds[0] = edgeId; } else { elem->polyIds[1] = edgeId; } } } } // Now create a polyId->smoothingGroup table // int numPolygons = fnMesh.numPolygons(); polySmoothingGroups = (int*)malloc( sizeof(int) * numPolygons ); for ( int i=0; i< numPolygons; i++ ) { polySmoothingGroups[i] = NO_SMOOTHING_GROUP; } // Now call the smoothingAlgorithm to fill in the polySmoothingGroups // table. // Note: we have to traverse ALL polygons to handle the case // of disjoint polygons. // nextSmoothingGroup = 1; currSmoothingGroup = 1; for ( int pid=0; pidpolyIds[1] ) { // Edge not a border // We are starting a new smoothing group // if ( newSmoothingGroup ) { currSmoothingGroup = nextSmoothingGroup++; newSmoothingGroup = false; // This is a SEED (starting) polygon and so we always // give it the new smoothing group id. // Even if all edges are hard this must be done so // that we know we have visited the polygon. // polySmoothingGroups[polyId] = currSmoothingGroup; } // If we have a smooth edge then this poly must be a member // of the current smoothing group. // if ( elem->smooth ) { polySmoothingGroups[polyId] = currSmoothingGroup; smoothEdgeFound = true; } else { // Hard edge so ignore this polygon continue; } // Find the adjacent poly id // int adjPoly = elem->polyIds[0]; if ( adjPoly == polyId ) { adjPoly = elem->polyIds[1]; } // If we are this far then adjacent poly belongs in this // smoothing group. // If the adjacent polygon's smoothing group is not // NO_SMOOTHING_GROUP then it has already been visited // so we ignore it. // if ( NO_SMOOTHING_GROUP == polySmoothingGroups[adjPoly] ) { smoothingAlgorithm( adjPoly, fnMesh ); } else if ( polySmoothingGroups[adjPoly] != currSmoothingGroup ) { cerr << "Warning: smoothing group problem at polyon "; cerr << adjPoly << endl; } } } } return smoothEdgeFound; } ////////////////////////////////////////////////////////////// void ObjTranslator::addEdgeInfo( int v1, int v2, bool smooth ) // // Adds a new edge info element to the vertex table. // { EdgeInfoPtr element = NULL; if ( NULL == edgeTable[v1] ) { edgeTable[v1] = (EdgeInfoPtr)malloc( sizeof(struct EdgeInfo) ); element = edgeTable[v1]; } else { element = edgeTable[v1]; while ( NULL != element->next ) { element = element->next; } element->next = (EdgeInfoPtr)malloc( sizeof(struct EdgeInfo) ); element = element->next; } // Setup data for new edge // element->vertId = v2; element->smooth = smooth; element->next = NULL; // Initialize array of id's of polygons that reference this edge. // There are at most 2 polygons per edge. // element->polyIds[0] = INVALID_ID; element->polyIds[1] = INVALID_ID; } ////////////////////////////////////////////////////////////// EdgeInfoPtr ObjTranslator::findEdgeInfo( int v1, int v2 ) // // Finds the info for the specified edge. // { EdgeInfoPtr element = NULL; element = edgeTable[v1]; while ( NULL != element ) { if ( v2 == element->vertId ) { return element; } element = element->next; } if ( element == NULL ) { element = edgeTable[v2]; while ( NULL != element ) { if ( v1 == element->vertId ) { return element; } element = element->next; } } return NULL; } ////////////////////////////////////////////////////////////// void ObjTranslator::destroyEdgeTable() // // Free up all of the memory used by the edgeTable. // { if ( !smoothing ) return; EdgeInfoPtr element = NULL; EdgeInfoPtr tmp = NULL; for ( int v=0; vnext; free( tmp ); } } if ( NULL != edgeTable ) { free( edgeTable ); edgeTable = NULL; } if ( NULL != polySmoothingGroups ) { free( polySmoothingGroups ); polySmoothingGroups = NULL; } } ////////////////////////////////////////////////////////////// MStatus ObjTranslator::exportSelected( ) { MStatus status; MString filename; initializeSetsAndLookupTables( false ); // Create an iterator for the active selection list // MSelectionList slist; MGlobal::getActiveSelectionList( slist ); MItSelectionList iter( slist ); if (iter.isDone()) { fprintf(stderr,"Error: Nothing is selected.\n"); return MS::kFailure; } // We will need to interate over a selected node's heirarchy // in the case where shapes are grouped, and the group is selected. MItDag dagIterator( MItDag::kDepthFirst, MFn::kInvalid, &status); // reset counters v = vt = vn = 0; voff = vtoff = vnoff = 0; // Selection list loop for ( ; !iter.isDone(); iter.next() ) { MDagPath objectPath; // get the selected node status = iter.getDagPath( objectPath); // reset iterator's root node to be the selected node. status = dagIterator.reset (objectPath.node(), MItDag::kDepthFirst, MFn::kInvalid ); // DAG iteration beginning at at selected node for ( ; !dagIterator.isDone(); dagIterator.next() ) { MDagPath dagPath; MObject component = MObject::kNullObj; status = dagIterator.getPath(dagPath); if (!status) { fprintf(stderr,"Failure getting DAG path.\n"); freeLookupTables(); return MS::kFailure; } if (status ) { // skip over intermediate objects // MFnDagNode dagNode( dagPath, &status ); if (dagNode.isIntermediateObject()) { continue; } if (dagPath.hasFn(MFn::kNurbsSurface)) { status = MS::kSuccess; fprintf(stderr,"Warning: skipping Nurbs Surface.\n"); } else if (( dagPath.hasFn(MFn::kMesh)) && ( dagPath.hasFn(MFn::kTransform))) { // We want only the shape, // not the transform-extended-to-shape. continue; } else if ( dagPath.hasFn(MFn::kMesh)) { // Build a lookup table so we can determine which // polygons belong to a particular edge as well as // smoothing information // buildEdgeTable( dagPath ); status = OutputPolygons(dagPath, component); objectId++; if (status != MS::kSuccess) { fprintf(stderr, "Error: exporting geom failed, check your selection.\n"); freeLookupTables(); destroyEdgeTable(); // Free up the edge table return MS::kFailure; } destroyEdgeTable(); // Free up the edge table } voff = v; vtoff = vt; vnoff = vn; } } } freeLookupTables(); return status; } ////////////////////////////////////////////////////////////// MStatus ObjTranslator::exportAll( ) { MStatus status = MS::kSuccess; initializeSetsAndLookupTables( true ); MItDag dagIterator( MItDag::kBreadthFirst, MFn::kInvalid, &status); if ( MS::kSuccess != status) { fprintf(stderr,"Failure in DAG iterator setup.\n"); return MS::kFailure; } // reset counters v = vt = vn = 0; voff = vtoff = vnoff = 0; for ( ; !dagIterator.isDone(); dagIterator.next() ) { MDagPath dagPath; MObject component = MObject::kNullObj; status = dagIterator.getPath(dagPath); if (!status) { fprintf(stderr,"Failure getting DAG path.\n"); freeLookupTables(); return MS::kFailure; } // skip over intermediate objects // MFnDagNode dagNode( dagPath, &status ); if (dagNode.isIntermediateObject()) { continue; } if (( dagPath.hasFn(MFn::kNurbsSurface)) && ( dagPath.hasFn(MFn::kTransform))) { status = MS::kSuccess; fprintf(stderr,"Warning: skipping Nurbs Surface.\n"); } else if (( dagPath.hasFn(MFn::kMesh)) && ( dagPath.hasFn(MFn::kTransform))) { // We want only the shape, // not the transform-extended-to-shape. continue; } else if ( dagPath.hasFn(MFn::kMesh)) { // Build a lookup table so we can determine which // polygons belong to a particular edge as well as // smoothing information // buildEdgeTable( dagPath ); // Now output the polygon information // status = OutputPolygons(dagPath, component); objectId++; if (status != MS::kSuccess) { fprintf(stderr,"Error: exporting geom failed.\n"); freeLookupTables(); destroyEdgeTable(); // Free up the edge table return MS::kFailure; } destroyEdgeTable(); // Free up the edge table } voff = v; vtoff = vt; vnoff = vn; } freeLookupTables(); return status; } ////////////////////////////////////////////////////////////// void ObjTranslator::recFindTransformDAGNodes( MString& nodeName, MIntArray& transformNodeIndicesArray ) { // To handle Maya groups we traverse the hierarchy starting at // each objectNames[i] going towards the root collecting transform // nodes as we go. MStringArray result; MString cmdStr = "listRelatives -ap " + nodeName; MGlobal::executeCommand( cmdStr, result ); if( result.length() == 0 ) // nodeName must be at the root of the DAG. Stop recursing return; for( unsigned int j=0; j