//- // ========================================================================== // Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files contain unpublished // information proprietary to Autodesk, Inc. ("Autodesk") and/or its // licensors, which is protected by U.S. and Canadian federal copyright // law and by international treaties. // // The Data is provided for use exclusively by You. You have the right // to use, modify, and incorporate this Data into other products for // purposes authorized by the Autodesk software license agreement, // without fee. // // The copyright notices in the Software and this entire statement, // including the above license grant, this restriction and the // following disclaimer, must be included in all copies of the // Software, in whole or in part, and all derivative works of // the Software, unless such copies or derivative works are solely // in the form of machine-executable object code generated by a // source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. // AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED // WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF // NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR // PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR // TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS // BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, // DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK // AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY // OR PROBABILITY OF SUCH DAMAGES. // // ========================================================================== //+ // // File: cleanPerFaceAssignmentCmd.cpp // MEL Command: cleanPerFaceAssignment // Author: Hiroyuki Haga // #include "cleanPerFaceAssignmentCmd.h" // Include Maya libary: General #include #include #include #include #include #include // Include Maya libary: Selection #include #include // Include Maya libary: Nodes #include // Include Maya libary: Polygons #include #include // Include Maya libary: Sets #include #ifdef DEBUG #include #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 requiredBCurrently 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 // { }