#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;
public:
                    ObjTranslator () {};
    virtual         ~ObjTranslator () {};
    static void*    creator();
                             FileAccessMode mode);
                             FileAccessMode mode );
                                   const char* buffer,
                                   short size) const;
private:
    void            outputSetsAndGroups    ( 
MDagPath&, 
int, 
bool, 
int );
 
    void            initializeSetsAndLookupTables( bool exportAll );
    void            freeLookupTables();
    bool            lookup( 
MDagPath&, 
int, 
int, 
bool );
 
    
    
    
    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;
    
    
    
    
    
    
    bool **polygonTablePtr;
    bool **vertexTablePtr;
    bool * polygonTable;
    bool * vertexTable;
    bool **objectGroupsTablePtr;
    
    
    
    
    
    
    
    
    
    
    
    int objectId;
    int objectCount;
    
    
    
    EdgeInfoPtr *   edgeTable;
    int *           polySmoothingGroups;
    int             edgeTableSize;
    int             nextSmoothingGroup;
    int             currSmoothingGroup;
    bool            newSmoothingGroup;
    
    
    
};
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();
}
                                FileAccessMode mode)
{
    fprintf(stderr, "ObjTranslator::reader called in error\n");
}
#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
                                FileAccessMode mode )
{
    
    
#if defined (OSMac_)
    char fname[MAXPATHLEN];
    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;
    }
    
    
    groups      = true; 
    ptgroups    = true; 
    materials   = true; 
    smoothing   = true; 
    normals     = true; 
    
        int i, length;
        
        options.
split(
';', optionList); 
        for( i = 0; i < length; ++i ){
            optionList[i].split( '=', theOption );
            if( theOption[0] == 
MString(
"groups") &&
 
                if( theOption[1].asInt() > 0 ){
                    groups = true;
                }else{
                    groups = false;
                }
            }
            if( theOption[0] == 
MString(
"materials") &&
 
                if( theOption[1].asInt() > 0 ){
                    materials = true;
                }else{
                    materials = false;
                }
            }
            if( theOption[0] == 
MString(
"ptgroups") &&
 
                if( theOption[1].asInt() > 0 ){
                    ptgroups = true;
                }else{
                    ptgroups = false;
                }
            }
            if( theOption[0] == 
MString(
"normals") &&
 
                if( theOption[1].asInt() > 0 ){
                    normals = true;
                }else{
                    normals = false;
                }
            }
            if( theOption[0] == 
MString(
"smoothing") &&
 
                if( theOption[1].asInt() > 0 ){
                    smoothing = true;
                }else{
                    smoothing = false;
                }
            }
        }
    }
    
    
    fprintf( fp, "# The units used in this file are %s.\n", unitName.asChar() );
    {
        exportAll();
    }
    {
        exportSelected();
    }
    fclose(fp);
}
{
    switch( unit ) 
    {
        unitName = "inches";
        break;
        unitName = "feet";
        break;
        unitName = "yards";
        break;
        unitName = "miles";
        break;
        unitName = "millimeters";
        break;
        unitName = "centimeters";
        break;
        unitName = "kilometers";
        break;
        unitName = "meters";
        break;
    default:
        break;
    }
}
bool ObjTranslator::haveReadMethod () const
{
    return false;
}
bool ObjTranslator::haveWriteMethod () const
{
    return true;
}
MString ObjTranslator::defaultExtension ()
 const 
{
    return "obj";
}
                                        const char* buffer,
                                        short size) const
{
    int   nameLength = strlen(name);
    
    if ((nameLength > 4) && !strcasecmp(name+nameLength-4, ".obj"))
        return kCouldBeMyFileType;
    else
        return kNotMyFileType;
}
{
    MFnPlugin plugin( obj, PLUGIN_COMPANY, 
"3.0", 
"Any");
 
    
    return plugin.registerFileTranslator( "OBJexport", "none",
                                          ObjTranslator::creator,
                                          (char *)objOptionScript,
                                          (char *)objDefaultOptions );                                        
}
{
        return plugin.deregisterFileTranslator( "OBJexport" );
}
MStatus ObjTranslator::OutputPolygons( 
 
)
{
    int i;
        fprintf(stderr,"Failure in MFnMesh initialization.\n");
    }
        fprintf(stderr,"Failure in MItMeshPolygon initialization.\n");
    }
        fprintf(stderr,"Failure in MItMeshVertex initialization.\n");
    }
    int objectIdx = -1, 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 && (objectIdx >= 0)) {
            int compIdx = vtxIter.index();
            outputSetsAndGroups( mdagPath, compIdx, true, objectIdx );
        }
        
        fprintf(fp,
"v %f %f %f\n",p.
x,p.
y,p.
z);
        v++;
    }
    
    
    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 ) {
        int normsLength = norms.
length();
 
        for ( int t=0; t<normsLength; 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) && (objectIdx >= 0)) {
            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");
        
        
        
    }
    return stat;
}
void ObjTranslator::outputSetsAndGroups( 
    int cid,
    bool isVertexIterator,
    int objectIdx
    
)
{
    
    int i, length;
    if (groups || materials) {
        for ( i=0; i<numSets; i++ )
        {
            if ( lookup(mdagPath,i,cid,isVertexIterator) ) {
            
                    currentMaterials->
append( i );
                    mArray.
append( fnSet.name() );
                }
                else {
                    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())
 
        {
        }
        
                    
        
        
        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;
    
    
    
    
    
    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();
    
    
    
    
    
    
    
    
    for ( i=0; i<length; i++ )
    {   
        setList->
add( result[i] );
    }
    
    
    
    
    
    
    for ( i=0; i<length; i++ )
    {
        
        if ( stat ) {
                if ( materials ) {
                    sets->append( mset );
                }
            } 
            else {
                if ( groups ) {
                    sets->append( mset );
                }
            }
        }   
    }
    delete setList;
    
            
    
    
    
    
    
    
    
    
    
    
    
            
    if ( exportAll ) {
            fprintf(stderr,"Failure in DAG iterator setup.\n");
            return;
        }
        
        
        for ( ; !dagIterator.isDone(); dagIterator.next() ) 
        {
            stat = dagIterator.getPath( dagPath );
            if ( stat ) 
            {
                
                
                if (dagNode.isIntermediateObject()) 
                {
                    continue;
                }
                {
                    
                    
                    continue;
                }
                {
                    
                    
                    
                    int vtxCount = fnMesh.numVertices();
                    int polygonCount = fnMesh.numPolygons();
                    
                    
                    objectNames->append( name );
                    objectNodeNamesArray.append( fnMesh.name() );
                    vertexCounts.
append( vtxCount );
                    polygonCounts.
append( polygonCount );
                    objectCount++;
                }
            }
        }   
    }
    else 
    {
        
        
        for ( ; !iter.isDone(); iter.next() ) 
        {
            stat = iter.getDagPath( objectPath );
            
            status = dagIterator.reset (objectPath.
node(), 
            
            for ( ; !dagIterator.isDone(); dagIterator.next() )
            {
                status = dagIterator.getPath(dagPath);
                if (!status) {
                    fprintf(stderr,"Failure getting DAG path.\n");
                    freeLookupTables();
                    return ;
                }
                
                
                if (dagNode.isIntermediateObject()) 
                {
                    continue;
                }
                {
                    
                    
                    continue;
                }
                {
                    
                    
                    
                    int vtxCount = fnMesh.numVertices();
                    int polygonCount = fnMesh.numPolygons();
                    
                    
                    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++ ) {
            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;
    
    
    for ( i=0; i<numSets; i++ )
    {
        stat = fnSet.getMembers( memberList, flattenedList );
            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) ) {
 
                {
                        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;
                                }
                            }
                        }
                    }
                    {
                        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 { 
                
                
                
                        fprintf(stderr,"Failure in MFnMesh initialization.\n");
                        return;
                    }
                    
                    
                        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++ ) {
        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;
    
    
    
    edgeTableSize = fnMesh.numVertices();
    edgeTable = (EdgeInfoPtr*) calloc( edgeTableSize, sizeof(EdgeInfoPtr) );
    
    
    for ( ; !eIt.isDone(); eIt.next() )
    {
        bool smooth = eIt.isSmooth();
        addEdgeInfo( eIt.index(0), eIt.index(1), smooth );
    }
    
    
    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 )
 
{
    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( )
 
{
    initializeSetsAndLookupTables( false );
    
    
    if (iter.isDone()) {
        fprintf(stderr,"Error: Nothing is selected.\n");
    }
    
    
    
    v = vt = vn = 0;
    voff = vtoff = vnoff = 0;
    
    for ( ; !iter.isDone(); iter.next() )
    {    
        
        status = iter.getDagPath( objectPath);
        
        status = dagIterator.reset (objectPath.
node(), 
        
        for ( ; !dagIterator.isDone(); dagIterator.next() )
        {
            status = dagIterator.getPath(dagPath);
            if (!status) {
                fprintf(stderr,"Failure getting DAG path.\n");
                freeLookupTables();
            }
            if (status ) 
            {
                
                
                if (dagNode.isIntermediateObject()) 
                {
                    continue;
                }
                {
                    fprintf(stderr,"Warning: skipping Nurbs Surface.\n");
                }
                {
                    
                    
                    continue;
                }
                {
                    
                    
                    
                    
                    buildEdgeTable( dagPath );
                    
                    status = OutputPolygons(dagPath, component);
                    objectId++;
                        fprintf(stderr, "Error: exporting geom failed, check your selection.\n");
                        freeLookupTables();
                        destroyEdgeTable(); 
                    }
                    destroyEdgeTable(); 
                }
                voff = v;
                vtoff = vt;
                vnoff = vn;
            }
        }
    }
    
    freeLookupTables();
    
    return status;
}
MStatus ObjTranslator::exportAll( )
 
{
    initializeSetsAndLookupTables( true );
        fprintf(stderr,"Failure in DAG iterator setup.\n");
    }
    
    v = vt = vn = 0;
    voff = vtoff = vnoff = 0;
    for ( ; !dagIterator.isDone(); dagIterator.next() )
    {
        status = dagIterator.getPath(dagPath);
        if (!status) {
            fprintf(stderr,"Failure getting DAG path.\n");
            freeLookupTables();
        }
        
        
        if (dagNode.isIntermediateObject()) 
        {
            continue;
        }
        {
            fprintf(stderr,"Warning: skipping Nurbs Surface.\n");
        }
        {
            
            
            continue;
        }
        {
            
            
            
            
            buildEdgeTable( dagPath );
            
            
            
            status = OutputPolygons(dagPath, component);
            objectId++;
                fprintf(stderr,"Error: exporting geom failed.\n");
                freeLookupTables();                
                destroyEdgeTable(); 
            }
            destroyEdgeTable(); 
        }
        voff = v;
        vtoff = vt;
        vnoff = vn;
    }
    freeLookupTables();
    return status;
}
void ObjTranslator::recFindTransformDAGNodes( 
MString& nodeName, 
MIntArray& transformNodeIndicesArray )
 
{
    
    
    
    MString cmdStr = 
"listRelatives -ap " + nodeName;
 
    
        
        return;
    for( 
unsigned int j=0; j<result.
length(); j++ ) {
 
        
        
        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);
        }
    }
}