#include <string.h>
#include <sys/types.h>
#include <maya/MStatus.h>
#include <maya/MPxCommand.h>
#include <maya/MString.h>
#include <maya/MStringArray.h>
#include <maya/MArgList.h>
#include <maya/MGlobal.h>
#include <maya/MSelectionList.h>
#include <maya/MItSelectionList.h>
#include <maya/MPoint.h>
#include <maya/MPointArray.h>
#include <maya/MDagPath.h>
#include <maya/MDagPathArray.h>
#include <maya/MFnPlugin.h>
#include <maya/MFnMesh.h>
#include <maya/MFnSet.h>
#include <maya/MItMeshPolygon.h>
#include <maya/MItMeshVertex.h>
#include <maya/MItMeshEdge.h>
#include <maya/MFloatVector.h>
#include <maya/MFloatVectorArray.h>
#include <maya/MFloatArray.h>
#include <maya/MObjectArray.h>
#include <maya/MObject.h>
#include <maya/MPlug.h>
#include <maya/MPxFileTranslator.h>
#include <maya/MFnDagNode.h>
#include <maya/MItDag.h>
#include <maya/MDistance.h>
#include <maya/MIntArray.h>
#include <maya/MIOStream.h>
#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
typedef struct EdgeInfo {
int polyIds[2];
int vertId;
struct EdgeInfo * next;
bool 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& );
void buildEdgeTable( MDagPath& );
void addEdgeInfo( int, int, bool );
EdgeInfoPtr findEdgeInfo( int, int );
void destroyEdgeTable();
bool smoothingAlgorithm( int, MFnMesh& );
private:
int v,vt,vn;
int voff,vtoff,vnoff;
bool groups, ptgroups, materials, smoothing, normals;
FILE *fp;
int numSets;
MObjectArray *sets;
MStringArray *objectNames;
bool **polygonTablePtr;
bool **vertexTablePtr;
bool * polygonTable;
bool * vertexTable;
bool **objectGroupsTablePtr;
MIntArray *lastSets;
MIntArray *lastMaterials;
int objectId;
int objectCount;
EdgeInfoPtr * edgeTable;
int * polySmoothingGroups;
int edgeTableSize;
int nextSmoothingGroup;
int currSmoothingGroup;
bool newSmoothingGroup;
MStringArray objectNodeNamesArray;
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_)
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;
createMacFile (fname, ¬Used, 0, 0);
convertFileRepresentation (fname, kCFURLPOSIXPathStyle, kCFURLHFSPathStyle);
fp = fopen(fname,"wb");
#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;
}
groups = true;
ptgroups = true;
materials = true;
smoothing = true;
normals = true;
if (options.length() > 0) {
int i, length;
MStringArray optionList;
MStringArray theOption;
options.split(';', optionList);
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;
}
}
}
}
setToLongUnitName(MDistance::uiUnit(), unitName);
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:
unitName = "inches";
break;
case MDistance::kFeet:
unitName = "feet";
break;
case MDistance::kYards:
unitName = "yards";
break;
case MDistance::kMiles:
unitName = "miles";
break;
case MDistance::kMillimeters:
unitName = "millimeters";
break;
case MDistance::kCentimeters:
unitName = "centimeters";
break;
case MDistance::kKilometers:
unitName = "kilometers";
break;
case MDistance::kMeters:
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");
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();
length = objectNodeNamesArray.length();
for( i=0; i<length; i++ ) {
if( objectNodeNamesArray[i] == mdagPathNodeName ) {
objectIdx = i;
break;
}
}
for ( ; !vtxIter.isDone(); vtxIter.next() ) {
MPoint p = vtxIter.position( space );
if (ptgroups && groups) {
int compIdx = vtxIter.index();
outputSetsAndGroups( mdagPath, compIdx, true, objectIdx );
}
p.x = MDistance::internalToUI(p.x);
p.y = MDistance::internalToUI(p.y);
p.z = MDistance::internalToUI(p.z);
fprintf(fp,"v %f %f %f\n",p.x,p.y,p.z);
v++;
}
MFloatArray uArray, vArray;
fnMesh.getUVs( uArray, vArray );
int uvLength = uArray.length();
for ( int x=0; x<uvLength; x++ ) {
fprintf(fp,"vt %f %f\n",uArray[x],vArray[x]);
vt++;
}
if ( normals ) {
MFloatVectorArray norms;
fnMesh.getNormals( norms, MSpace::kWorld );
int normsLength = norms.length();
for ( int t=0; t<normsLength; t++ ) {
MFloatVector tmpf = norms[t];
fprintf(fp,"vn %f %f %f\n",tmpf[0],tmpf[1],tmpf[2]);
vn++;
}
}
int lastSmoothingGroup = INITIALIZE_SMOOTHING;
for ( ; !polyIter.isDone(); polyIter.next() )
{
if ( smoothing ) {
int compIdx = polyIter.index();
int smoothingGroup = polySmoothingGroups[ compIdx ];
if ( lastSmoothingGroup != smoothingGroup ) {
if ( NO_SMOOTHING_GROUP == smoothingGroup ) {
fprintf(fp,"s off\n");
}
else {
fprintf(fp,"s %d\n", smoothingGroup );
}
lastSmoothingGroup = smoothingGroup;
}
}
if (groups || materials) {
int compIdx = polyIter.index();
outputSetsAndGroups( mdagPath, compIdx, false, objectIdx );
}
fprintf(fp,"f");
int polyVertexCount = polyIter.polygonVertexCount();
for ( int vtx=0; vtx<polyVertexCount; vtx++ ) {
fprintf(fp," %d", polyIter.vertexIndex( vtx ) +1 +voff);
bool noUV = true;
if ( fnMesh.numUVs() > 0 ) {
int uvIndex;
if ( polyIter.getUVIndex(vtx,uvIndex) ) {
fprintf(fp,"/%d",uvIndex+1 +vtoff);
noUV = false;
}
}
if ( (normals) && (fnMesh.numNormals() > 0) ) {
if ( noUV ) {
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; i<numSets; i++ )
{
if ( lookup(mdagPath,i,cid,isVertexIterator) ) {
MFnSet fnSet( (*sets)[i] );
if ( MFnSet::kRenderableOnly == fnSet.restriction(&stat) ) {
currentMaterials->append( i );
mArray.append( fnSet.name() );
}
else {
currentSets->append( i );
gArray.append( fnSet.name() );
}
}
}
if( !isVertexIterator ) {
bool *objectGroupTable = objectGroupsTablePtr[objectIdx];
length = transformNodeNameArray.length();
for( i=0; i<length; i++ ) {
if( objectGroupTable[i] ) {
currentSets->append( numSets + i );
gArray.append(transformNodeNameArray[i]);
}
}
}
if (0 == currentSets->length())
{
currentSets->append( 0 );
gArray.append( "default" );
}
bool setsEqual = false;
if ( (lastSets != NULL) &&
(lastSets->length() == currentSets->length())
) {
setsEqual = true;
length = lastSets->length();
for ( i=0; i<length; i++ )
{
if ( (*lastSets)[i] != (*currentSets)[i] ) {
setsEqual = false;
break;
}
}
}
if ( !setsEqual ) {
if ( lastSets != NULL )
delete lastSets;
lastSets = currentSets;
if (groups) {
int gLength = gArray.length();
if ( gLength > 0 ) {
fprintf(fp,"g");
for ( i=0; i<gLength; i++ ) {
fprintf(fp," %s",gArray[i].asChar());
}
fprintf(fp,"\n");
}
}
}
else
{
delete currentSets;
}
bool materialsEqual = false;
if ( (lastMaterials != NULL) &&
(lastMaterials->length() == currentMaterials->length())
) {
materialsEqual = true;
length = lastMaterials->length();
for ( i=0; i<length; i++ )
{
if ( (*lastMaterials)[i] != (*currentMaterials)[i] ) {
materialsEqual = false;
break;
}
}
}
if ( !materialsEqual ) {
if ( lastMaterials != NULL )
delete lastMaterials;
lastMaterials = currentMaterials;
if (materials) {
int mLength = mArray.length();
if ( mLength > 0 ) {
fprintf(fp,"usemtl");
for ( i=0; i<mLength; i++ ) {
fprintf(fp," %s",mArray[i].asChar());
}
fprintf(fp,"\n");
}
}
}
else
{
delete currentMaterials;
}
}
}
void ObjTranslator::initializeSetsAndLookupTables( bool exportAll )
{
int i=0,j=0, length;
MStatus stat;
numSets = 0;
sets = NULL;
lastSets = NULL;
lastMaterials = NULL;
objectId = 0;
objectCount = 0;
polygonTable = NULL;
vertexTable = NULL;
polygonTablePtr = NULL;
vertexTablePtr = NULL;
objectGroupsTablePtr = NULL;
objectNodeNamesArray.clear();
transformNodeNameArray.clear();
MStringArray result;
MGlobal::executeCommand( "ls -sets", result );
MSelectionList * setList = new MSelectionList;
length = result.length();
for ( i=0; i<length; i++ )
{
setList->add( result[i] );
}
MObject mset;
sets = new MObjectArray();
length = setList->length();
for ( i=0; i<length; i++ )
{
setList->getDependNode( 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();
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 )
{
MFnDagNode dagNode( dagPath, &stat );
if (dagNode.isIntermediateObject())
{
continue;
}
if (( dagPath.hasFn(MFn::kMesh)) &&
( dagPath.hasFn(MFn::kTransform)))
{
continue;
}
else if ( dagPath.hasFn(MFn::kMesh))
{
MFnMesh fnMesh( dagPath );
int vtxCount = fnMesh.numVertices();
int polygonCount = fnMesh.numPolygons();
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;
MItDag dagIterator( MItDag::kDepthFirst, MFn::kInvalid, &status);
for ( ; !iter.isDone(); iter.next() )
{
MDagPath objectPath;
stat = iter.getDagPath( objectPath );
status = dagIterator.reset (objectPath.node(),
MItDag::kDepthFirst, MFn::kInvalid );
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 ;
}
MFnDagNode dagNode( dagPath, &stat );
if (dagNode.isIntermediateObject())
{
continue;
}
if (( dagPath.hasFn(MFn::kMesh)) &&
( dagPath.hasFn(MFn::kTransform)))
{
continue;
}
else if ( dagPath.hasFn(MFn::kMesh))
{
MFnMesh fnMesh( dagPath );
int vtxCount = fnMesh.numVertices();
int polygonCount = fnMesh.numPolygons();
MString name = dagPath.fullPathName();
objectNames->append( name );
objectNodeNamesArray.append( fnMesh.name() );
vertexCounts.append( vtxCount );
polygonCounts.append( polygonCount );
objectCount++;
}
}
}
}
if( objectCount > 0 ) {
length = objectNodeNamesArray.length();
for( i=0; i<length; i++ ) {
MIntArray transformNodeNameIndicesArray;
recFindTransformDAGNodes( objectNodeNamesArray[i], transformNodeNameIndicesArray );
}
if( transformNodeNameArray.length() > 0 ) {
objectGroupsTablePtr = (bool**) malloc( sizeof(bool*)*objectCount );
length = transformNodeNameArray.length();
for ( i=0; i<objectCount; i++ )
{
objectGroupsTablePtr[i] =
(bool*)calloc( length, sizeof(bool) );
if ( objectGroupsTablePtr[i] == NULL ) {
cerr << "Error: calloc returned NULL (objectGroupsTablePtr)\n";
return;
}
}
}
}
if ( objectCount > 0 ) {
vertexTablePtr = (bool**) malloc( sizeof(bool*)*objectCount );
polygonTablePtr = (bool**) malloc( sizeof(bool*)*objectCount );
for ( i=0; i<objectCount; i++ )
{
vertexTablePtr[i] =
(bool*)calloc( vertexCounts[i]*numSets, sizeof(bool) );
if ( vertexTablePtr[i] == NULL ) {
cerr << "Error: calloc returned NULL (vertexTable)\n";
return;
}
polygonTablePtr[i] =
(bool*)calloc( polygonCounts[i]*numSets, sizeof(bool) );
if ( polygonTablePtr[i] == NULL ) {
cerr << "Error: calloc returned NULL (polygonTable)\n";
return;
}
}
}
if ( objectCount == 0 ) {
return;
}
bool flattenedList = true;
MDagPath object;
MObject component;
MSelectionList memberList;
for ( i=0; i<numSets; i++ )
{
MFnSet fnSet( (*sets)[i] );
memberList.clear();
stat = fnSet.getMembers( memberList, flattenedList );
if (MS::kSuccess != stat) {
fprintf(stderr,"Error in fnSet.getMembers()!\n");
}
int m, numMembers;
numMembers = memberList.length();
for ( m=0; m<numMembers; m++ )
{
if ( memberList.getDagPath(m,object,component) ) {
if ( (!component.isNull()) && (object.apiType() == MFn::kMesh) )
{
if (component.apiType() == MFn::kMeshVertComponent) {
MItMeshVertex viter( object, component );
for ( ; !viter.isDone(); viter.next() )
{
int compIdx = viter.index();
MString name = object.fullPathName();
int o, numObjectNames;
numObjectNames = objectNames->length();
for ( o=0; o<numObjectNames; o++ ) {
if ( (*objectNames)[o] == name ) {
vertexTable = vertexTablePtr[o];
*(vertexTable + numSets*compIdx + i) = true;
break;
}
}
}
}
else if (component.apiType() == MFn::kMeshPolygonComponent)
{
MItMeshPolygon piter( object, component );
for ( ; !piter.isDone(); piter.next() )
{
int compIdx = piter.index();
MString name = object.fullPathName();
int o, numObjectNames;
numObjectNames = objectNames->length();
for ( o=0; o<numObjectNames; o++ ) {
if ( (*objectNames)[o] == name ) {
if ( compIdx >= 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 {
if (object.hasFn(MFn::kMesh)) {
MFnMesh fnMesh( object, &stat );
if ( MS::kSuccess != stat) {
fprintf(stderr,"Failure in MFnMesh initialization.\n");
return;
}
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();
int o, numObjectNames;
numObjectNames = objectNames->length();
for ( o=0; o<numObjectNames; o++ ) {
if ( (*objectNames)[o] == name ) {
if ( compIdx >= 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;
}
}
}
}
}
}
}
}
length = objectNodeNamesArray.length();
for( i=0; i<length; i++ ) {
MIntArray groupTableIndicesArray;
bool *objectGroupTable = objectGroupsTablePtr[i];
int length2;
recFindTransformDAGNodes( objectNodeNamesArray[i], groupTableIndicesArray );
length2 = groupTableIndicesArray.length();
for( j=0; j<length2; j++ ) {
int groupIdx = groupTableIndicesArray[j];
objectGroupTable[groupIdx] = true;
}
}
}
void ObjTranslator::freeLookupTables()
{
for ( int i=0; i<objectCount; i++ ) {
if ( vertexTablePtr[i] != NULL ) {
free( vertexTablePtr[i] );
}
if ( polygonTablePtr[i] != NULL ) {
free( polygonTablePtr[i] );
}
}
if( objectGroupsTablePtr != NULL ) {
for ( int i=0; i<objectCount; i++ ) {
if ( objectGroupsTablePtr[i] != NULL ) {
free( objectGroupsTablePtr[i] );
}
}
free( objectGroupsTablePtr );
objectGroupsTablePtr = NULL;
}
if ( vertexTablePtr != NULL ) {
free( vertexTablePtr );
vertexTablePtr = NULL;
}
if ( polygonTablePtr != NULL ) {
free( polygonTablePtr );
polygonTablePtr = NULL;
}
if ( lastSets != NULL ) {
delete lastSets;
lastSets = NULL;
}
if ( lastMaterials != NULL ) {
delete lastMaterials;
lastMaterials = NULL;
}
if ( sets != NULL ) {
delete sets;
sets = NULL;
}
if ( objectNames != NULL ) {
delete objectNames;
objectNames = NULL;
}
}
bool ObjTranslator::lookup( MDagPath& dagPath,
int setIndex,
int compIdx,
bool isVtxIter )
{
if (isVtxIter) {
vertexTable = vertexTablePtr[objectId];
bool ret = *(vertexTable + numSets*compIdx + setIndex);
return ret;
}
else {
polygonTable = polygonTablePtr[objectId];
bool ret = *(polygonTable + numSets*compIdx + setIndex);
return ret;
}
}
void ObjTranslator::buildEdgeTable( MDagPath& mesh )
{
if ( !smoothing )
return;
MFnMesh fnMesh( mesh );
edgeTableSize = fnMesh.numVertices();
edgeTable = (EdgeInfoPtr*) calloc( edgeTableSize, sizeof(int) );
MItMeshEdge eIt( mesh );
for ( ; !eIt.isDone(); eIt.next() )
{
bool smooth = eIt.isSmooth();
addEdgeInfo( eIt.index(0), eIt.index(1), smooth );
}
MItMeshPolygon pIt( mesh );
for ( ; !pIt.isDone(); pIt.next() )
{
int pvc = pIt.polygonVertexCount();
for ( int v=0; v<pvc; v++ )
{
int a = pIt.vertexIndex( v );
int b = pIt.vertexIndex( v==(pvc-1) ? 0 : v+1 );
EdgeInfoPtr elem = findEdgeInfo( a, b );
if ( NULL != elem ) {
int edgeId = pIt.index();
if ( INVALID_ID == elem->polyIds[0] ) {
elem->polyIds[0] = edgeId;
}
else {
elem->polyIds[1] = edgeId;
}
}
}
}
int numPolygons = fnMesh.numPolygons();
polySmoothingGroups = (int*)malloc( sizeof(int) * numPolygons );
for ( int i=0; i< numPolygons; i++ ) {
polySmoothingGroups[i] = NO_SMOOTHING_GROUP;
}
nextSmoothingGroup = 1;
currSmoothingGroup = 1;
for ( int pid=0; pid<numPolygons; pid++ ) {
newSmoothingGroup = true;
if ( NO_SMOOTHING_GROUP == polySmoothingGroups[pid] ) {
if ( !smoothingAlgorithm(pid,fnMesh) ) {
polySmoothingGroups[pid] = NO_SMOOTHING_GROUP;
}
}
}
}
bool ObjTranslator::smoothingAlgorithm( int polyId, MFnMesh& fnMesh )
{
MIntArray vertexList;
fnMesh.getPolygonVertices( polyId, vertexList );
int vcount = vertexList.length();
bool smoothEdgeFound = false;
for ( int vid=0; vid<vcount;vid++ ) {
int a = vertexList[vid];
int b = vertexList[ vid==(vcount-1) ? 0 : vid+1 ];
EdgeInfoPtr elem = findEdgeInfo( a, b );
if ( NULL != elem ) {
if ( NO_SMOOTHING_GROUP != elem->polyIds[1] ) {
if ( newSmoothingGroup ) {
currSmoothingGroup = nextSmoothingGroup++;
newSmoothingGroup = false;
polySmoothingGroups[polyId] = currSmoothingGroup;
}
if ( elem->smooth ) {
polySmoothingGroups[polyId] = currSmoothingGroup;
smoothEdgeFound = true;
}
else {
continue;
}
int adjPoly = elem->polyIds[0];
if ( adjPoly == polyId ) {
adjPoly = elem->polyIds[1];
}
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 )
{
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;
}
element->vertId = v2;
element->smooth = smooth;
element->next = NULL;
element->polyIds[0] = INVALID_ID;
element->polyIds[1] = INVALID_ID;
}
EdgeInfoPtr ObjTranslator::findEdgeInfo( int v1, int v2 )
{
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()
{
if ( !smoothing )
return;
EdgeInfoPtr element = NULL;
EdgeInfoPtr tmp = NULL;
for ( int v=0; v<edgeTableSize; v++ )
{
element = edgeTable[v];
while ( NULL != element )
{
tmp = element;
element = element->next;
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 );
MSelectionList slist;
MGlobal::getActiveSelectionList( slist );
MItSelectionList iter( slist );
if (iter.isDone()) {
fprintf(stderr,"Error: Nothing is selected.\n");
return MS::kFailure;
}
MItDag dagIterator( MItDag::kDepthFirst, MFn::kInvalid, &status);
v = vt = vn = 0;
voff = vtoff = vnoff = 0;
for ( ; !iter.isDone(); iter.next() )
{
MDagPath objectPath;
status = iter.getDagPath( objectPath);
status = dagIterator.reset (objectPath.node(),
MItDag::kDepthFirst, MFn::kInvalid );
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 )
{
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)))
{
continue;
}
else if ( dagPath.hasFn(MFn::kMesh))
{
buildEdgeTable( dagPath );
status = OutputPolygons(dagPath, component);
objectId++;
if (status != MS::kSuccess) {
fprintf(stderr, "Error: exporting geom failed, check your selection.\n");
freeLookupTables();
destroyEdgeTable();
return MS::kFailure;
}
destroyEdgeTable();
}
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;
}
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;
}
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)))
{
continue;
}
else if ( dagPath.hasFn(MFn::kMesh))
{
buildEdgeTable( dagPath );
status = OutputPolygons(dagPath, component);
objectId++;
if (status != MS::kSuccess) {
fprintf(stderr,"Error: exporting geom failed.\n");
freeLookupTables();
destroyEdgeTable();
return MS::kFailure;
}
destroyEdgeTable();
}
voff = v;
vtoff = vt;
vnoff = vn;
}
freeLookupTables();
return status;
}
void ObjTranslator::recFindTransformDAGNodes( MString& nodeName, MIntArray& transformNodeIndicesArray )
{
MStringArray result;
MString cmdStr = "listRelatives -ap " + nodeName;
MGlobal::executeCommand( cmdStr, result );
if( result.length() == 0 )
return;
for( unsigned int j=0; j<result.length(); j++ ) {
MStringArray result2;
MGlobal::executeCommand( "nodeType " + result[j], result2 );
if( result2.length() == 1 && result2[0] == "transform" ) {
bool found=false;
unsigned int i;
for( i=0; i<transformNodeNameArray.length(); i++) {
if( transformNodeNameArray[i] == result[j] ) {
found = true;
break;
}
}
if( !found ) {
transformNodeIndicesArray.append(transformNodeNameArray.length());
transformNodeNameArray.append(result[j]);
}
else {
transformNodeIndicesArray.append(i);
}
recFindTransformDAGNodes(result[j], transformNodeIndicesArray);
}
}
}