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

# cleanPerFaceAssignmentCmd.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.
    // ==========================================================================
    //+

    //
    // File: cleanPerFaceAssignmentCmd.cpp
    // MEL Command: cleanPerFaceAssignment
    // Author: Hiroyuki Haga
    //

    #include "cleanPerFaceAssignmentCmd.h"

    // Include Maya libary: General
    #include <maya/MGlobal.h>
    #include <maya/MDagPath.h>
    #include <maya/MPlug.h>
    #include <maya/MObjectArray.h>
    #include <maya/MIntArray.h>
    #include <maya/MStringArray.h>

    // Include Maya libary: Selection
    #include <maya/MSelectionList.h>
    #include <maya/MItSelectionList.h>

    // Include Maya libary: Nodes
    #include <maya/MFnDependencyNode.h>

    // Include Maya libary: Polygons
    #include <maya/MFnMesh.h>
    #include <maya/MItMeshPolygon.h>

    // Include Maya libary: Sets
    #include <maya/MFnSet.h>

    #ifdef DEBUG
    #include <MIOStream.h>
    #endif

    MStatus cleanPerFaceAssignment::doIt( const MArgList& )
    //
    //  Description:
    //      cleanPerfaceAssignment does the followings
    //          1. It traces material connections
    //          2. If multiple conections to one material is found, it combines them.
    //          3. It changes the assignment order
    //          4. it returns a string array that can be executed as a MEL command
    //
    //  Arguments:
    //      NONE
    //
    //  Return Value:
    //      It always returns MS:kSuccess as there's no error handling
    //
    {
        MStatus stat = MS::kSuccess;

        //  Get the selection list and using the iterator to trace them
        MSelectionList list;
        MGlobal::getActiveSelectionList( list );
        MItSelectionList listIt( list);

        for ( listIt.reset(); !listIt.isDone() ; listIt.next() ){

            // Get the DAG path of each element and extend the path to its shape node
            MDagPath path;
            listIt.getDagPath( path );
            path.extendToShape();

            // if a DAG Path is MFn::kMesh, it tries to obtain its material

            if ( path.apiType() == MFn::kMesh ){

                // Create a function set for poly geometries, find faces that are assigned as a set
                MFnMesh meshFn( path );
                MObjectArray sets, comps;

                unsigned int instanceNumber = path.instanceNumber();
                meshFn.getConnectedSetsAndMembers( instanceNumber, sets, comps, 1 );

    #ifdef _DEBUG
                // Debug output
                for ( unsigned int i = 0; i < sets.length() ; i++ ){
                    MFnSet setFn ( sets[i]);
                    MItMeshPolygon faceIt( path, comps[i] );

                    cout << "-------------->" << endl;
                    cout << setFn.name() << endl;
                    cout << "FaceCount:" << faceIt.count() << endl;
                    for ( faceIt.reset() ; !faceIt.isDone() ; faceIt.next() ){
                        cout << faceIt.index() << " ";
                    }
                    cout << endl;
                    cout << "<--------------" << endl;

                }
    #endif // _DEBUG

                // Variable declaration
                MStringArray SGNames;       // Stores Shading Group name
                MIntArray sameConnectionFlag;   // a flag to check if Shading Group has same names
                MIntArray sameSGFaceCount;  // storoes the number of faces included in each shading group
                MStringArray memberFaceNames;   // stores names of faces included in each shading group

                sameConnectionFlag.clear();
                sameSGFaceCount.clear();

                // ------------------------------------------------
                // 1    Initialization
                // ------------------------------------------------

                // initialization of variables
                for ( unsigned int i = 0; i < sets.length() ; i++ ){

                    // SGName Initialization
                    //  Append Shading Group name
                    MFnSet setFn ( sets[i] );
                    SGNames.append( setFn.name() );

                    // sameConnectionFlag Initialization
                    //  set -1�@
                    sameConnectionFlag.append( -1 );

                    // sameSGFaceCount Initialization
                    //  Set the number of faces included in a Shading Group
                    MItMeshPolygon tempFaceIt ( path, comps[i] );
                    sameSGFaceCount.append( tempFaceIt.count() );

                    // memberFaceNames Initialization
                    //  Stores names of faces included in a Shading Group in a way MEL can use
                    MString aMemberFaceName;

                    MString pathName = path.fullPathName();
                    bool optimizeList = true;
                    if (optimizeList)
                    {
                        int lastIndices[2] = { -1, -1 };
                        int currentIndex = -1;
                        bool haveAFace = false;
                        for ( ;!tempFaceIt.isDone() ; tempFaceIt.next() )
                        {
                            if (lastIndices[0] == -1)
                            {
                                lastIndices[0] = tempFaceIt.index();
                                lastIndices[1] = tempFaceIt.index();
                            }
                            else
                            {
                                currentIndex = tempFaceIt.index();

                                // Hit non-contiguous face #. split out a new string
                                if (currentIndex > lastIndices[1] + 1)
                                {
                                    aMemberFaceName += (pathName + ".f[" + lastIndices[0] + ":" + lastIndices[1] + "] ");
                                    lastIndices[0] = currentIndex;
                                    lastIndices[1] = currentIndex;
                                }
                                else
                                    lastIndices[1] = currentIndex;
                            }
                            haveAFace = true;
                        }
                        // Only one member. Add it.
                        if (haveAFace)
                        {
                            aMemberFaceName += (pathName + ".f[" + lastIndices[0] + ":" + lastIndices[1] + "] ");
                        }
                    }
                    else
                    {
                        for ( ;!tempFaceIt.isDone() ; tempFaceIt.next() ){
                            aMemberFaceName += (path.fullPathName() + ".f[" + tempFaceIt.index() + "] ");
                        }
                    }
                    memberFaceNames.append( aMemberFaceName );

                }

                // ------------------------------------------------
                // 2    Finding redundant connections
                // ------------------------------------------------

                // Scan for multiple connections to a shading group and if it exists
                //  combine them
                for ( unsigned int i = 0; i < sets.length() ; i++ ){
                    MFnSet setFn ( sets[i]);
                    if ( sameConnectionFlag[i] == -1 ){

                        for ( unsigned int j = 0; j < sets.length() ; j++ ){
                            if ( i != j && sameConnectionFlag[j] == -1 ) {
                                MFnSet tempSetFn ( sets[j] );

                                if ( setFn.name() == tempSetFn.name() ){
                                    sameConnectionFlag[j] = i;
                                    sameSGFaceCount[i] += sameSGFaceCount[j];
                                    sameSGFaceCount[j] = 0;
                                    memberFaceNames[i] += memberFaceNames[j];
                                    memberFaceNames[j] = "";
                                }
                            }

                        }
                        sameConnectionFlag[i] = i;
                    }
                }

                // delete empties
                unsigned int tail = 0;
                while( tail < sameConnectionFlag.length() ){
                    if ( sameSGFaceCount[tail] == 0 ){
                        SGNames.remove( tail );
                        memberFaceNames.remove( tail );
                        sameConnectionFlag.remove( tail );
                        sameSGFaceCount.remove( tail );

                    } else {
                        tail++;
                    }
                }

                // ------------------------------------------------
                // 3    Sorting array
                // ------------------------------------------------

                // Sorting preprocess
                //      Simply assign ID from the top
                MIntArray sortMapper;
                for ( unsigned int i = 0; i < sameSGFaceCount.length() ; i++ ){
                    sortMapper.append( i );
                }
                bool needToSort = true;

                // Begin sorting
                //      in the order of number of faces
                while ( needToSort ){
                    unsigned int sortCount = 0;
                    if ( sameSGFaceCount.length() > 1 ){
                        for( unsigned int i = 0; i < ( sameSGFaceCount.length() -1 ) ; i++ ){
                            if ( sameSGFaceCount[sortMapper[i]] < sameSGFaceCount[sortMapper[i+1]] ){
                                int tmp = sortMapper[i];
                                sortMapper[i] = sortMapper[i+1];
                                sortMapper[i+1] = tmp;
                                sortCount++;
                            } else {

                            }

                        }
                    }else {
                        break;
                    }

                    // Check if sorting is completed
                    if ( sortCount > 0 ){
                        needToSort = true; //another sorting required
                    } else {
                        needToSort = false;//no sorting required and exit loop
                    }

                }

                // store the sorted arrary

                //  Variable declaration
                MStringArray sortedSGNames;
                MStringArray sortedMemberFaceNames;
                MIntArray   sortedSGFaceCount;

                //  Store
                for ( unsigned int i = 0; i < sortMapper.length(); i++ ){
                    sortedSGNames.append( SGNames[sortMapper[i]] );
                    sortedSGFaceCount.append( sameSGFaceCount[sortMapper[i]] );
                    sortedMemberFaceNames.append( memberFaceNames[sortMapper[i]]);
                }

    #ifdef _DEBUG

                // Debug information output
                for ( unsigned int i = 0; i < sortedSGFaceCount.length() ; i++ ){
                    cout << sortedSGNames[i] << "  " << sortedSGFaceCount[i] << endl;
                    cout << sortedMemberFaceNames[i] << endl;
                }

                for ( unsigned int i = 0; i < sortMapper.length() ; i++ ){
                    cout << i << " -- " << sortMapper[i] << endl;
                }
    #endif // _DEBUG

                // ------------------------------------------------
                // 4    Output
                // ------------------------------------------------
                //  This outputs a MEL executable string array
                //  This is to enable step by step excution when it can't be solved to normally

                bool executeImmediate = true;
                for ( unsigned int i = 0; i < sortedSGFaceCount.length() ; i++ ){

                    MString resultString;
                    if ( i == 0 ){

                        //�@Add object base selection MEL command
                        resultString = ("select -r " + path.fullPathName()  +";" );
                    } else {
                        //�@Add component base selection MEL command
                        resultString = ("select -r " + sortedMemberFaceNames[i] + ";");
                    }

                    if (executeImmediate )
                        MGlobal::executeCommand( resultString );

                    // Add a meterial assignemnet MEL comand
                    if (executeImmediate)
                    {
                        resultString = ("sets -e -forceElement " + sortedSGNames[i] + ";");
                        MGlobal::executeCommand( resultString );
                    }
                    else
                        resultString += ("sets -e -forceElement " + sortedSGNames[i] + ";");

                    // Append to the result
                    if (!executeImmediate)
                        appendToResult( resultString );
                }

            }

        }
        return stat; // TODO: Error handling/Additional ASSERT required�BCurrently it always returns MS::kSuccess
    }

    void* cleanPerFaceAssignment::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 cleanPerFaceAssignment();
    }

    cleanPerFaceAssignment::cleanPerFaceAssignment()
    //
    //  Description:
    //      cleanPerFaceAssignment constructor
    //
    {}

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