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

# meshOpCmd.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 "meshOpCmd.h"
    #include "meshOpNode.h"

    // Function Sets
    //
    #include <maya/MFnDependencyNode.h>
    #include <maya/MFnMesh.h>
    #include <maya/MFnSingleIndexedComponent.h>

    // Iterators
    //
    #include <maya/MItSelectionList.h>
    #include <maya/MItMeshPolygon.h>

    // General Includes
    //
    #include <maya/MGlobal.h>
    #include <maya/MSelectionList.h>
    #include <maya/MPlug.h>
    #include <maya/MArgList.h>

    #include <maya/MIOStream.h>

    // Status Checking Macro - MCheckStatus (Debugging tool)
    //
    #define MCheckStatus(status,message)    \
        if( MS::kSuccess != status ) {      \
            cerr << message << "\n";        \
            return status;                  \
        }

    meshOp::meshOp()
    //
    //  Description:
    //      meshOp constructor
    //
    {
        fOperation = (MeshOperation) 0;
    }

    meshOp::~meshOp()
    //
    //  Description:
    //      meshOp destructor
    //
    {}

    void* meshOp::creator()
    //
    //  Description:
    //      this method exists to give Maya a way to create new objects
    //      of this type.
    //
    //  Return Value:
    //      a new object of this type
    //
    {
        return new meshOp();
    }

    bool meshOp::isUndoable() const
    //
    //  Description:
    //      this method tells Maya this command is undoable.  It is added to the
    //      undo queue if it is.
    //
    //  Return Value:
    //      true if this command is undoable.
    //
    {
        return true;
    }

    MStatus meshOp::doIt( const MArgList& argList )
    //
    //  Description:
    //      implements the MEL meshOp command.
    //
    //  Arguments:
    //      argList - the argument list that was passes to the command from MEL
    //
    //  Return Value:
    //      MS::kSuccess - command succeeded
    //      MS::kFailure - command failed (returning this value will cause the
    //                     MEL script that is being run to terminate unless the
    //                     error is caught using a "catch" statement.
    //
    {
        MStatus status;
        bool badArgument = false;

        // Only one parameter is expected to be passed to this command: the mesh
        // operation type. Get it, validate it or stop prematurely
        //
        if (argList.length() == 1)
        {
            int operationTypeArgument = argList.asInt(0);
            if (operationTypeArgument < 0
                || operationTypeArgument > kMeshOperationCount - 1)
            {
                badArgument = true;
            }
            else
            {
                fOperation = (MeshOperation)operationTypeArgument;
            }
        }
        else badArgument = true;

        if (badArgument)
        {
            cerr << "Expecting one parameter: the operation type." << endl;
            cerr << "Valid types are: " << endl;
            cerr << "   0 - Subdivide edge(s)." << endl;
            cerr << "   1 - Subdivide face(s)." << endl;
            cerr << "   2 - Extrude edge(s)." << endl;
            cerr << "   3 - Extrude face(s)." << endl;
            cerr << "   4 - Collapse edge(s)." << endl;
            cerr << "   5 - Collapse face(s)." << endl;
            cerr << "   6 - Duplicate face(s)." << endl;
            cerr << "   7 - Extract face(s)." << endl;
            cerr << "   8 - Split face(s)." << endl;
            displayError(" Expecting one parameter: the operation type.");
            return MS::kFailure;
        }

        // Each mesh operation only supports one type of components
        //
        MFn::Type componentType = meshOpFty::getExpectedComponentType(fOperation);

        // Parse the selection list for selected components of the right type.
        // To simplify things, we only take the first object that we find with
        // selected components and operate on that object alone.
        //
        // All other objects are ignored and return warning messages indicating
        // this limitation.
        //
        MSelectionList selList;
        MGlobal::getActiveSelectionList( selList );
        MItSelectionList selListIter( selList );
        selListIter.setFilter( MFn::kMesh );

        // The meshOperation node only accepts a component list input, so we build
        // a component list using MFnComponentListData.
        //
        // MIntArrays could also be passed into the node to represent the ids,
        // but are less storage efficient than component lists, since consecutive
        // components are bundled into a single entry in component lists.
        //
        MFnComponentListData compListFn;
        compListFn.create();
        bool found = false;
        bool foundMultiple = false;

        for( ; !selListIter.isDone(); selListIter.next() )
        {
            MDagPath dagPath;
            MObject component;
            selListIter.getDagPath( dagPath, component );

            // Check for selected components of the right type
            //
            if( component.apiType() == componentType )
            {
                if( !found )
                {
                    // The variable 'component' holds all selected components
                    // on the selected object, thus only a single call to
                    // MFnComponentListData::add() is needed to store the selected
                    // components for a given object.
                    //
                    compListFn.add( component );

                    // Copy the component list created by MFnComponentListData
                    // into our local component list MObject member.
                    //
                    fComponentList = compListFn.object();

                    // Locally store the actual ids of the selected components so
                    // that this command can directly modify the mesh in the case
                    // when there is no history and history is turned off.
                    //
                    MFnSingleIndexedComponent compFn( component );

                    // Ensure that this DAG path will point to the shape
                    // of our object. Set the DAG path for the polyModifierCmd.
                    //
                    dagPath.extendToShape();
                    setMeshNode( dagPath );
                    found = true;
                }
                else
                {
                    // Break once we have found a multiple object holding
                    // selected components, since we are not interested in how
                    // many multiple objects there are, only the fact that there
                    // are multiple objects.
                    //
                    foundMultiple = true;
                    break;
                }
            }
        }
        if( foundMultiple )
        {
            displayWarning("Found more than one object with selected components.");
            displayWarning("Only operating on first found object.");
        }

        // Initialize the polyModifierCmd node type - mesh node already set
        //
        setModifierNodeType( meshOpNode::id );

        if( found )
        {
            // Now, pass control over to the polyModifierCmd::doModifyPoly() method
            // to handle the operation.
            //
            status = doModifyPoly();

            if( status == MS::kSuccess )
            {
                setResult( "meshOp command succeeded!" );
            }
            else
            {
                displayError( "meshOp command failed!" );
            }
        }
        else
        {
            displayError(
                "meshOp command failed: Unable to find selected components" );
            status = MS::kFailure;
        }

        return status;
    }

    MStatus meshOp::redoIt()
    //
    //  Description:
    //      Implements redo for the MEL meshOp command.
    //
    //      This method is called when the user has undone a command of this type
    //      and then redoes it.  No arguments are passed in as all of the necessary
    //      information is cached by the doIt method.
    //
    //  Return Value:
    //      MS::kSuccess - command succeeded
    //      MS::kFailure - redoIt failed.  this is a serious problem that will
    //                     likely cause the undo queue to be purged
    //
    {
        MStatus status;

        // Process the polyModifierCmd
        //
        status = redoModifyPoly();

        if( status == MS::kSuccess )
        {
            setResult( "meshOp command succeeded!" );
        }
        else
        {
            displayError( "meshOp command failed!" );
        }

        return status;
    }

    MStatus meshOp::undoIt()
    //
    //  Description:
    //      implements undo for the MEL meshOp command.
    //
    //      This method is called to undo a previous command of this type.  The
    //      system should be returned to the exact state that it was it previous
    //      to this command being executed.  That includes the selection state.
    //
    //  Return Value:
    //      MS::kSuccess - command succeeded
    //      MS::kFailure - redoIt failed.  this is a serious problem that will
    //                     likely cause the undo queue to be purged
    //
    {
        MStatus status;

        status = undoModifyPoly();

        if( status == MS::kSuccess )
        {
            setResult( "meshOp undo succeeded!" );
        }
        else
        {
            setResult( "meshOp undo failed!" );
        }

        return status;
    }

    MStatus meshOp::initModifierNode( MObject modifierNode )
    {
        MStatus status;

        // We need to tell the meshOp node which components to operate on.
        // By overriding, the polyModifierCmd::initModifierNode() method,
        // we can insert our own modifierNode initialization code.
        //
        MFnDependencyNode depNodeFn( modifierNode );
        MObject cpListAttr = depNodeFn.attribute( "inputComponents" );

        // Pass the component list down to the meshOp node
        //
        MPlug cpListPlug( modifierNode, cpListAttr );
        status = cpListPlug.setValue( fComponentList );
        if (status != MS::kSuccess) return status;

        // Similarly for the operation type
        //
        MObject opTypeAttr = depNodeFn.attribute( "operationType" );
        MPlug opTypePlug( modifierNode, opTypeAttr );
        status = opTypePlug.setValue( fOperation );

        return status;
    }

    MStatus meshOp::directModifier( MObject mesh )
    {
        MStatus status;

        fmeshOpFactory.setMesh( mesh );
        fmeshOpFactory.setComponentList( fComponentList );
        fmeshOpFactory.setComponentIDs( fComponentIDs );
        fmeshOpFactory.setMeshOperation( fOperation );

        // Now, perform the meshOp
        //
        status = fmeshOpFactory.doIt();

        return status;
    }