- Main Page
- Related Pages
- Modules
- Classes
- Examples

# 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 "meshReorderCmd.h"
    #include "meshMapUtils.h"

    #include <maya/MIOStream.h>
    #include <maya/MItSelectionList.h>
    #include <maya/MItMeshVertex.h>
    #include <maya/MArgList.h>
    #include <maya/MFnMesh.h>
    #include <maya/MFnMeshData.h>
    #include <maya/MDagPathArray.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;
        }

        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();
    }