meshReorder/meshReorderCmd.cpp
 
 
 
meshReorder/meshReorderCmd.cpp
//-
// ==========================================================================
// Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk
// license agreement provided at the time of installation or download,
// or which otherwise accompanies this software in either electronic
// or hard copy form.
// ==========================================================================
//+

#include "meshMapUtils.h"
#include "meshReorderCmd.h"

#include <maya/MArgList.h>
#include <maya/MDagPathArray.h>
#include <maya/MFnMesh.h>
#include <maya/MFnMeshData.h>
#include <maya/MIOStream.h>
#include <maya/MItSelectionList.h>
#include <maya/MItMeshVertex.h>
#include <maya/MPlug.h>
#include <maya/MString.h>

// CONSTRUCTOR DEFINITION:
meshReorderCommand::meshReorderCommand()
{
        fClampedArray = NULL;
        fRepArray = NULL;
        fColorArrays = NULL;
        fVertexColorArrays = NULL;
        fColorIdsArrays = NULL;
        fUArrays = NULL;
        fVArrays = NULL;
        fUVIdsArrays = NULL;
}


// DESTRUCTOR DEFINITION:
meshReorderCommand::~meshReorderCommand()
{
        resetColorsUVsMemory();
}


// METHOD FOR CREATING AN INSTANCE OF THIS COMMAND:
void* meshReorderCommand::creator()
{
        return new meshReorderCommand;
}


MStatus meshReorderCommand::parseArgs(const MArgList& args)
{
        MStatus stat;
        MString err;


        if( args.length() != 3 )
        {
                displayError("3 vertices must be specified");
                return MS::kFailure;
        }

        MObjectArray selectedComponent(3);
        MDagPathArray selectedPath;

        selectedPath.setLength(3);

        int argIdx = 0;
        for (unsigned int j = 0; j < 3; j++)
        {
                MString arg;

                if( ( stat = args.get( argIdx, arg )) != MStatus::kSuccess )
                {
                        displayError( "Can't parse arg");
                        return stat;
                }

                MSelectionList list;
                if (! list.add( arg ) )
                {
                        err = arg + ": no such component";
                        displayError(err);
                        return MS::kFailure; // no such component
                }

                MItSelectionList selectionIt (list, MFn::kComponent);
                if (selectionIt.isDone ())
                {
                        err = arg + ": not a component";
                        displayError (err);
                        return MS::kFailure;
                }

                if( selectionIt.getDagPath (selectedPath[j], selectedComponent[j]) != MStatus::kSuccess )
                {
                        displayError( "Can't get path for");
                        return stat;
                }


                if (!selectedPath[j].node().hasFn(MFn::kMesh) && !(selectedPath[j].node().hasFn(MFn::kTransform) && selectedPath[j].hasFn(MFn::kMesh)))
                {
                        err = arg + ": Invalid type!  Only a mesh or its transform can be specified!";
                        displayError (err);
                        return MStatus::kFailure;
                }

                argIdx++;
        }

        if( ( stat = meshMapUtils::validateFaceSelection( selectedPath, selectedComponent, &fFaceIdxSrc, &fFaceVtxSrc ) ) != MStatus::kSuccess )
        {
                displayError("Selected vertices don't define a unique face on source mesh");
                return stat;
        }

        fDagPathSrc = selectedPath[0];

        return stat;
}

// FIRST INVOKED WHEN COMMAND IS CALLED, PARSING THE COMMAND ARGUMENTS, INITIALIZING DEFAULT PARAMETERS, THEN CALLING redoIt():
MStatus meshReorderCommand::doIt(const MArgList& args)
{
        MStatus  stat = MStatus::kSuccess;

        if ( ( stat = parseArgs( args ) ) != MStatus::kSuccess )
        {
                displayError ("Error parsing arguments");
                return stat;
        }

        return redoIt();
}

MStatus meshReorderCommand::redoIt()
{
        MStatus  stat = MStatus::kSuccess;

        MIntArray                       newPolygonCounts;
        MIntArray                       newPolygonConnects;
        MFloatPointArray        origVertices;
        MFloatPointArray        newVertices;

        unsigned i;

        MFnMesh theMesh( fDagPathSrc, &stat );
        if( stat != MStatus::kSuccess )
        {
                displayError(" MFnMesh creation");
                return stat;
        }

        //      The mesh cannot have history or this won't work.
        MPlug   historyPlug = theMesh.findPlug("inMesh", true);

        if (historyPlug.isDestination()) {
                displayError("The mesh has history. Its geometry cannot be modified.");
                return MS::kInvalidParameter;
        }

        stat = theMesh.getPoints (origVertices, MSpace::kObject );
        if( stat != MStatus::kSuccess )
        {
                displayError(" MFnMesh getPoints");
                return stat;
        }

        // Initialize the traversal flags and CV mappings for this shape 
        MIntArray                       faceTraversal( theMesh.numPolygons(), false );
        MIntArray cvMapping(theMesh.numVertices(), -1);
        MIntArray cvMappingInverse(theMesh.numVertices(), -1);

        //
        //  Starting with the user selected face, recursively rebuild the entire mesh
        //
        stat = meshMapUtils::traverseFace( fDagPathSrc, fFaceIdxSrc, fFaceVtxSrc[0], fFaceVtxSrc[1], faceTraversal,
                                        cvMapping, cvMappingInverse, 
                                        newPolygonCounts, newPolygonConnects, 
                                        origVertices, newVertices );

        if ( stat != MStatus::kSuccess )
        {
                displayError(" could not process all the mesh faces.");
                return stat;
        }

        // Store mesh vertices and connectivity information for undo. Must collect the information here before it is 
        // modified by createInPlace() call.
        fVertices.copy(origVertices);
        MItMeshPolygon polyIter(fDagPathSrc.node());
        while(!polyIter.isDone()) 
        {
                fPolygonCounts.append(polyIter.polygonVertexCount());
                for(i = 0; i < polyIter.polygonVertexCount(); i++)
                {
                        fPolygonConnects.append(polyIter.vertexIndex(i));
                }
                polyIter.next();
        }

        fColorSetNames.clear();
        theMesh.getColorSetNames(fColorSetNames);
        int numColorSets = fColorSetNames.length();
        fColorArrays = new MColorArray[numColorSets];
        fColorIdsArrays = new MIntArray[numColorSets];

        collectColorsUVs(theMesh, false);

        stat = theMesh.createInPlace( newVertices.length(), newPolygonCounts.length(), newVertices, newPolygonCounts, newPolygonConnects );

        if ( stat != MStatus::kSuccess )
        {
                displayError(" MFnMesh::createInPlace failed.");

                fCVMapping.clear();
                fCVMappingInverse.clear();
                fVertices.clear();
                fPolygonCounts.clear();
                fPolygonConnects.clear();
                delete [] fColorArrays;  fColorArrays = NULL;
                delete [] fColorIdsArrays;fColorIdsArrays = NULL;

                // Free memeory allocated in collectColorsUVs()
                resetColorsUVsMemory();

                return stat;
        }

        assignColorsUVs(theMesh, cvMapping, cvMappingInverse, false);

        // Store fCVMapping and fCVMappingInverse for undo
        fCVMapping = cvMapping;
        fCVMappingInverse = cvMappingInverse;

        return stat;
}

MStatus meshReorderCommand::undoIt()
{
        MStatus  stat = MStatus::kSuccess;
        MFnMesh theMesh( fDagPathSrc );

        fColorSetNames.clear();
        theMesh.getColorSetNames(fColorSetNames);

        collectColorsUVs(theMesh, true);

        stat = theMesh.createInPlace( fVertices.length(), fPolygonCounts.length(), fVertices, fPolygonCounts, fPolygonConnects );

        assignColorsUVs(theMesh, fCVMappingInverse, fCVMapping, true);

        fCVMapping.clear();
        fCVMappingInverse.clear();
        fVertices.clear();
        fPolygonCounts.clear();
        fPolygonConnects.clear();
        delete [] fColorArrays;  fColorArrays = NULL;
        delete [] fColorIdsArrays;fColorIdsArrays = NULL;

        return stat;
}

void meshReorderCommand::collectColorsUVs(MFnMesh &theMesh, bool isUndo)
{
        int i;
        // Store Colors
        int numColorSets = fColorSetNames.length();
        fClampedArray = new bool[numColorSets];
        fRepArray = new MFnMesh::MColorRepresentation[numColorSets];
        fVertexColorArrays = new MColorArray[numColorSets];

        for (i = 0; i < numColorSets; i++)
        {
                fClampedArray[i] = theMesh.isColorClamped(fColorSetNames[i]);
                fRepArray[i] = theMesh.getColorRepresentation(fColorSetNames[i]);
                // We need to use two different approaches to set colors because unfortunately 
                // setVertexColors() doesn't work in the case of undo and setColors() will
                // require a huge effort to construct the colorIds in the non undo case.
                theMesh.getVertexColors(fVertexColorArrays[i], &(fColorSetNames[i]));

                if(!isUndo) {
                        theMesh.getColors(fColorArrays[i], &(fColorSetNames[i]));
                        unsigned nth = 0;
                        fColorIdsArrays[i].setLength(theMesh.numColors(fColorSetNames[i]));
                        MItMeshPolygon polyIter(fDagPathSrc.node());
                        while(!polyIter.isDone()) 
                        {
                                for(unsigned j = 0; j < polyIter.polygonVertexCount(); j++)
                                {
                                        unsigned polygonIdx = polyIter.index();
                                        int colorId;
                                        theMesh.getColorIndex(polygonIdx, j, colorId, &(fColorSetNames[i]));
                                        fColorIdsArrays[i][nth] = colorId;
                                        nth++;
                                }
                                polyIter.next();
                        }
                }
                theMesh.deleteColorSet(fColorSetNames[i]);
        }

        // Store UVs 
        fUVSetNames.clear();
        theMesh.getUVSetNames(fUVSetNames);
        int numUVSets = fUVSetNames.length();
        fUArrays = new MFloatArray[numUVSets];
        fVArrays = new MFloatArray[numUVSets];
        fUVIdsArrays = new MIntArray[numUVSets];

        for (i = 0; i < numUVSets; i++) 
        {
                MIntArray uvCounts;
                MIntArray uvIds;
                theMesh.getAssignedUVs(uvCounts, uvIds, &(fUVSetNames[i]));

                unsigned nth = 0;
                fUVIdsArrays[i].setLength(fVertices.length());
                MItMeshPolygon polyIter(fDagPathSrc.node());
                while(!polyIter.isDone()) 
                {
                        for(unsigned j = 0; j < polyIter.polygonVertexCount(); j++)
                        {
                                unsigned vertexIdx = polyIter.vertexIndex(j);
                                fUVIdsArrays[i][vertexIdx] = uvIds[nth];
                                nth++;
                        }
                        polyIter.next();
                }

                theMesh.getUVs(fUArrays[i], fVArrays[i], &(fUVSetNames[i]));
                theMesh.deleteUVSet(fUVSetNames[i]);
        }
}

void meshReorderCommand::assignColorsUVs(MFnMesh &theMesh, MIntArray &colorMapping, MIntArray &uvMapping, bool isUndo)
{
        int i;

        // Copy Colors 
        MString defaultColorSetName;
        theMesh.getCurrentColorSetName(defaultColorSetName);
        int numColorSets = fColorSetNames.length();
        for (i = 0; i < numColorSets; i++) 
        {
                // Not to duplicate default color set
                if (fColorSetNames[i] != defaultColorSetName)
                {
                        theMesh.createColorSet(fColorSetNames[i], NULL, fClampedArray[i], fRepArray[i]);
                }

                if (fVertexColorArrays[i].length() > 0 && fVertexColorArrays[i].length() == fVertices.length())
                {
                        // We need to use two different approaches to set colors because unfortunately 
                        // setVertexColors() doesn't work in the case of undo and setColors() will
                        // require a huge effort to construct the colorIds in the non undo case.
                        if(!isUndo) 
                        {
                                theMesh.setVertexColors(fVertexColorArrays[i], colorMapping, NULL, fRepArray[i]);
                        } else {
                                theMesh.setColors(fColorArrays[i], NULL, fRepArray[i]);
                                theMesh.assignColors(fColorIdsArrays[i], &(fColorSetNames[i]));
                        }
                }
        }

        // Copy UVs
        MString defaultUVSetName;
        theMesh.getCurrentUVSetName(defaultUVSetName);
        int numUVSets = fUVSetNames.length();
        for (i = 0; i < numUVSets; i++) 
        {
                // Not to duplicate default uv set
                if (fUVSetNames[i] != defaultUVSetName)
                {
                        theMesh.createUVSet(fUVSetNames[i]);
                }

                if (fUArrays[i].length() > 0 && fUArrays[i].length() == fVArrays[i].length())
                {
                        theMesh.setUVs(fUArrays[i], fVArrays[i], &(fUVSetNames[i]));
                        MItMeshPolygon polyIter(fDagPathSrc.node());
                        while(!polyIter.isDone()) 
                        {
                                for(unsigned j = 0; j < polyIter.polygonVertexCount(); j++)
                                {
                                        unsigned polygonIdx = polyIter.index();
                                        unsigned vertexIdx = polyIter.vertexIndex(j);
                                        int uvId = fUVIdsArrays[i][uvMapping[vertexIdx]];
                                        theMesh.assignUV(polygonIdx, j, uvId);
                                }
                                polyIter.next();
                        }
                }
        }

        resetColorsUVsMemory();
}

void meshReorderCommand::resetColorsUVsMemory()
{
        if (fClampedArray != NULL) 
        {
                delete [] fClampedArray; 
                fClampedArray = NULL;
        }
        if (fRepArray != NULL)
        {
                delete [] fRepArray;
                fRepArray = NULL;
        }
        if (fVertexColorArrays != NULL)
        {
                delete [] fVertexColorArrays;
                fVertexColorArrays = NULL;
        }
        if (fUArrays != NULL)
        {
                delete [] fUArrays;
                fUArrays = NULL;
        }
        if (fVArrays != NULL)
        {
                delete [] fVArrays;
                fVArrays = NULL;
        }
        if (fUVIdsArrays != NULL)
        {
                delete [] fUVIdsArrays;
                fUVIdsArrays = NULL;
        }
        fColorSetNames.clear();
        fUVSetNames.clear();
}