CBaseNode *CMayaNode::GetChild(int childId) { MStatus status; MFnDagNode dagNode (m_dagPath, &status); if (status != MS::kSuccess) return 0; MObject objChild = dagNode.child (childId, &status); if (status != MS::kSuccess) return 0; MFnDagNode childDagNode (objChild, &status); if (status != MS::kSuccess) return 0; MDagPath childPath; if (childDagNode.getPath (childPath) != MS::kSuccess) return 0; CMayaNode *pNode = new CMayaNode; if (!pNode->Create (childPath)) { delete pNode; return 0; } return pNode; }
void EntityInstanceNode::Hide() { MFnTransform transformFn( thisMObject() ); u32 len = transformFn.childCount(); MFnDagNode nodeFn; for( u32 i = 0; i < len; ++i ) { nodeFn.setObject( transformFn.child( 0 ) ); MDagPath path; nodeFn.getPath( path ); MGlobal::deleteNode( path.node() ); } }
MStatus unShowAvailableSystems::doIt( const MArgList& args ) { MItDag dagIter; MFnDagNode worldDag (dagIter.root()); MDagPath worldPath; worldDag.getPath(worldPath); std::string str; findAvailableSystems(str,worldPath); if(!str.empty()) { MessageBox(0,str.c_str(),"Particle or Ribbon Systems",0); } else { MessageBox(0,"no particle or ribbon system yet","Particle or Ribbon Systems",0); } return MS::kSuccess; }
void DMPDSExporter::fillSkeleton( DMPParameters* param ) { MStatus stat; mSkelData.clear(); if (!param->bExportSkeleton) { return; } mSkelData.skeleton.name = param->skeletonFileName.asUTF8(); // Get the selection list MSelectionList activeList; stat = MGlobal::getActiveSelectionList(activeList); if(param->bExportAll) { // We are exporting the whole scene MItDag dagIter; MFnDagNode worldDag (dagIter.root()); MDagPath worldPath; worldDag.getPath(worldPath); traverseSubSkeleton(param, worldPath); } else { if (MStatus::kSuccess != stat) { return; } MItSelectionList iter(activeList); for ( ; !iter.isDone(); iter.next()) { MDagPath dagPath; iter.getDagPath(dagPath); traverseSubSkeleton(param, dagPath); } } // may lose selection while exporting, so reset it. MGlobal::setActiveSelectionList(activeList); }
void EntityNode::AddToInstances( MObject &addedNode ) { MStatus stat; MFnDagNode instanceFn; MFnDagNode nodeFn( addedNode ); MDagPath source; nodeFn.getPath( source ); M_EntityNode::iterator itor = m_Instances.begin(); M_EntityNode::iterator end = m_Instances.end(); for( ; itor != end; ++itor) { instanceFn.setObject( itor->second->thisMObject() ); instanceFn.setObject( instanceFn.parent( 0 ) ); MDagPath parent; instanceFn.getPath( parent ); MDagPath result; Maya::duplicate( source, parent, result, true ); } }
MStatus cgfxShaderCmd::doCmd(const MArgList& args) // // Description: // implements the MEL cgfxShader command. // // Arguments: // -fx/fxFile The CgFX file to load. // -e/edit Edit an existing cgfxShader rather than creating // a new one. // -q/query Get specified info // // 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. // { // Get the current state of the flag // and store it in a temporary variable // static int tmpFlag = -1; #if defined(_WIN32) && defined(CGFX_DEBUG_MEMORY) if (tmpFlag == -1) { tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ); // Turn On (OR) - call _CrtCheckMemory at every // allocation request tmpFlag |= _CRTDBG_CHECK_ALWAYS_DF; // Turn on (OR) - check for memory leaks at end // of program. tmpFlag |= _CRTDBG_LEAK_CHECK_DF; _CrtSetDbgFlag( tmpFlag ); } #endif /* _WIN32 && CGFX_DEBUG_MEMORY */ MStatus status; MSelectionList selList; MObject oNode; MString sResult; MStringArray saResult; MString sFeedback; MString sTemp; MString sWho = "cgfxShader : "; status = parseArgs(args, selList); if (!status) { return status; } // -pp / -pluginPath // Returns the directory path where this plug-in's auxiliary // files, such as MEL scripts, are expected to be found. // The path name is in Maya format ('/' delimited) with no // trailing slash. Result type is string. (Query only) if ( fPluginPath ) { setResult( sPluginPath ); return MS::kSuccess; } // -lp / -listProfiles // // Return the names of the profiles supported on the current // platform. // // Each item in the result array has the form // "VertexProfileName<,GeometryProfileName,FragmentProfileName" // // Result type is string[]. (Query only; set internally) if ( fListProfiles ) { setResult( cgfxProfile::getProfileList() ); return status; } // -mtc / -maxTexCoords // Returns the maximum number of texcoord inputs that can be // passed to vertex shaders under the currently installed // OpenGL implementation. Returns 0 if the information is // not available. Result type is integer. (Query only) // // Don't use GL_MAX_TEXTURE_UNITS as this does not provide a proper // count when the # of image or texcoord inputs differs // from the conventional (older) notion of texture unit. // // Instead take the minimum of GL_MAX_TEXTURE_COORDS_ARB and // GL_MAX_TEXUTRE_IMAGE_UNITS_ARB according to the // ARB_FRAGMENT_PROGRAM specification. if ( fMaxTexCoords ) { GLint mtc = 0; M3dView vw = M3dView::active3dView( &status ); if ( status && vw.beginGL() ) { glGetIntegerv( GL_MAX_TEXTURE_COORDS_ARB, &mtc ); GLint mic = 0; glGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &mic ); if (mic < mtc) mtc = mic; if ( mtc < 1 ) mtc = 1; else if ( mtc > CGFXSHADERNODE_GL_TEXTURE_MAX ) mtc = CGFXSHADERNODE_GL_TEXTURE_MAX; vw.endGL(); } setResult( (int)mtc ); return MS::kSuccess; } // If edit or query, find the specified cgfxShaderNode. MFnDependencyNode fnNode; cgfxShaderNode* pNode = NULL; if ( fIsEdit || fIsQuery ) { // We are editing an existing node which must have been // provided in the args (or the current selection list). // Get the correct node name into fNodeName; // if (selList.length() != 1) { status = MS::kNotFound; return status; } // Get the name of the node into fNodeName so that it can // be saved for undo/redo // MStringArray tmpList; selList.getSelectionStrings(tmpList); fNodeName = tmpList[0]; if ( fNodeName.length() ) { sWho += " \""; sWho += fNodeName; sWho += "\""; } status = selList.getDependNode(0, oNode); if (!status) { return status; } status = fnNode.setObject( oNode ); if (!status) { sFeedback = sWho; sFeedback += " is not a cgfxShader node."; MGlobal::displayError( sFeedback ); return status; } if (fnNode.typeId() != cgfxShaderNode::sId) { status = MS::kInvalidParameter; sFeedback = sWho; sFeedback += " is not a cgfxShader node."; MGlobal::displayError( sFeedback ); return status; } pNode = (cgfxShaderNode*)fnNode.userNode(); if (!pNode) { status = MS::kInvalidParameter; sFeedback = sWho; sFeedback += " is not cgfxShader node."; MGlobal::displayError( sFeedback ); return status; } } if ( fIsQuery ) { // -fx / -fxFile // Returns the shader file name. if ( fFxFile ) { MString path = pNode->shaderFxFile(); setResult( path ); return MS::kSuccess; } // -fxp / -fxPath // Returns the path of the fx file. The path name is in Maya // format ('/' delimited). Result type is string. // (Query only) if ( fFxPath ) { MString path = cgfxFindFile(pNode->shaderFxFile()); setResult( path ); return MS::kSuccess; } // -t / -technique // Returns the currently active technique if ( fTechnique ) { MString path = pNode->getTechnique(); setResult( path ); return MS::kSuccess; } // -p / -profile // Returns the current profile if ( fProfile ) { MString path = pNode->getProfile(); setResult( path ); return MS::kSuccess; } // -lt / -listTechniques // Return the technique names defined by the current effect. // // Each item in the result array has the form // "techniqueName<TAB>numPasses" // where // numPasses is the number of passes defined by the // technique, or 0 if the technique is not valid. // (Future versions of the cgfxShader plug-in may append // additional tab-separated fields.) // // Result type is string[]. (Query only; set internally) if ( fListTechniques ) { setResult( pNode->getTechniqueList() ); return status; } // -lp / -listParameters // Return the attribute names corresponding to the // shader's tweakable uniform parameters. // Result type is string[]. (Query only; set internally) // -des / -description // If specified, each item in the result array has the form // "attrName<TAB>type<TAB>semantic<TAB>description<TAB>extraAttrSuffix" // (Future versions of the cgfxShader plug-in may provide // additional tab-separated fields after the semantic.) // A missing field is indicated by a single space (" ") // so the string can be parsed more easily using the MEL // "tokenize" function, which treats a group of consecutive // delimiters the same as a single delimiter. if ( fListParameters ) { cgfxRCPtr<cgfxAttrDefList> list = cgfxAttrDef::attrsFromNode( oNode ); for ( cgfxAttrDefList::iterator it = list; it; ++it ) { cgfxAttrDef* aDef = *it; if ( fDescription ) { sResult = aDef->fName.length() ? aDef->fName : " "; sResult += "\t"; sTemp = aDef->typeName(); sResult += sTemp.length() ? sTemp : " "; sResult += "\t"; sResult += aDef->fSemantic.length() ? aDef->fSemantic : " "; sResult += "\t"; sResult += aDef->fDescription.length() ? aDef->fDescription : " "; sResult += "\t"; const char* suffix = aDef->getExtraAttrSuffix(); sResult += suffix ? suffix : " "; } else sResult = aDef->fName; saResult.append( sResult ); } setResult( saResult ); return status; } // -p / -parameter <name> // Return a string describing the data type and usage of // the attribute whose name is specified. // Result type is string (with no -description flag), or // string array (if you specify -description). // (Query only; set internally) // -ci / -caseInsensitive // If specified, returns information for the first // attribute that matches the specified name assuming // no distinction between upper and lower case letters. // -des / -description // If specified, the result is a string array containing: // [0] = attribute name // [1] = type // [2] = semantic // [3] = description from "desc" or "uiname" annotation // [4] = extra attribute suffix for Vector4 ("W") / Color4 ("Alpha") // (Future versions of the cgfxShader plug-in may provide // additional tab-separated fields after the semantic.) // If omitted, only the type is returned (a string). if ( fParameterName.length() > 0 ) { cgfxRCPtr<cgfxAttrDefList> list = cgfxAttrDef::attrsFromNode( oNode ); cgfxAttrDefList::iterator it; if ( fCaseInsensitive ) it = list->findInsensitive( fParameterName ); else it = list->find( fParameterName ); if ( fDescription ) { if ( it ) { cgfxAttrDef* aDef = *it; saResult.append( aDef->fName ); saResult.append( aDef->typeName() ); saResult.append( aDef->fSemantic ); saResult.append( aDef->fDescription ); const char* suffix = aDef->getExtraAttrSuffix(); saResult.append( suffix ? suffix : "" ); } setResult( saResult ); } else { if ( it ) sResult = (*it)->typeName(); setResult( sResult ); } return status; } // -euv / -emptyUV // Returns the names of blacklisted UV sets. These UV sets // are disabled from being passed to the shader because there // is at least one mesh where the UV set name is defined but // has no faces mapped. Due to a bug in Maya (in 5.0 and // possibly some other releases), Maya crashes if an empty // UV set is accessed by a hardware shader. Blacklisting is // intended to protect the user against accidentally hitting // the bug and crashing Maya. After the Maya fix has been // verified, this option can continue to be accepted for awhile // for compatibility, returning an empty result array. // Result type is string[]. (Query only; set internally) if ( fEmptyUV ) { setResult( pNode->getEmptyUVSets() ); return MS::kSuccess; } // -eus / -emptyUVShapes // Returns the names of shape nodes that have empty UV sets // which are causing the UV set names to be blacklisted. // After the Maya bug fix has been verified, this option // can remain for awhile for compatibility, returning an // empty result array. // Result type is string[]. (Query only; set internally) if ( fEmptyUVShapes ) { const MObjectArray& oaShapes = pNode->getEmptyUVSetShapes(); MFnDagNode fnDagNode; MDagPath dpShape; for ( unsigned iShape = 0; iShape < oaShapes.length(); ++iShape ) { fnDagNode.setObject( oaShapes[ iShape ] ); fnDagNode.getPath( dpShape ); saResult.append( dpShape.partialPathName() ); } setResult( saResult ); return MS::kSuccess; } // -tcs / -texCoordSource // Returns the value of the texCoordSource attribute, because // the MEL "getAttr" command doesn't work with string arrays. // Result type is string[]. (Query only; set via "setAttr") if ( fTexCoordSource ) { setResult( pNode->getTexCoordSource() ); return MS::kSuccess; } #if MAYA_API_VERSION >= 700 // -cs / -colorSource // Returns the value of the colorSource attribute, because // the MEL "getAttr" command doesn't work with string arrays. // Result type is string[]. (Query only; set via "setAttr") if ( fColorSource ) { setResult( pNode->getColorSource() ); return MS::kSuccess; } #endif // Error if -q with no other query flags. return MS::kInvalidParameter; } // If user didn't specify shader fx file, default to current // value of our cgfxShader node's "shader" attribute. if (!fFxFile && pNode) fNewFxFile = pNode->shaderFxFile(); // If user didn't specify technique name, default to current // value of our cgfxShader node's "technique" attribute. // // If a new fx file has been specified without a technique, we // leave the technique name empty so that the first technique of // the effect will be selected. if (!fTechnique && pNode) fNewTechnique = pNode->getTechnique(); // If user didn't specify profile name, default to current // value of our cgfxShader node's "profile" attribute. if (!fProfile && pNode) fNewProfile = pNode->getProfile(); // // Load the effect from the .fx file. // if (fFxFile) { // Attempt to read the new fEffect from the file // MString file = cgfxFindFile(fNewFxFile); MString projectFile = cgfxFindFile(fNewFxFile, true); // Compile and create the effect. fNewEffect = cgfxEffect::loadEffect(file, cgfxProfile::getProfile(fNewProfile)); //// Set the device. if (fNewEffect->isValid()) { // There is no current view in batch mode, just return // success then const MGlobal::MMayaState mayaState = MGlobal::mayaState(&status); if ( !status ) return status; if ( mayaState == MGlobal::kBatch ) return MS::kSuccess; fNewFxFile = projectFile; M3dView view = M3dView::active3dView(); // The M3dView class doesn't return the correct status if // there isn't an active 3D view, so we rely on the // success of beginGL() which will make the context // current. // if (!view.beginGL()) { MString es = "There is no active view to bind " + sWho + " to."; MGlobal::displayWarning( es ); return MS::kSuccess; } view.endGL(); } // Tell user if successful. if (fNewEffect->isValid()) { sFeedback = sWho; sFeedback += " loaded effect \""; sFeedback += file; sFeedback += "\""; MGlobal::displayInfo( sFeedback ); } else { sFeedback = sWho; sFeedback += " unable to load effect \""; sFeedback += file.length() ? file : fNewFxFile; sFeedback += "\""; MGlobal::displayError( sFeedback ); return MS::kFailure; } } // Create an MDGModifier to hold an agenda of operations to be // performed to update the DG. We build the agenda here; // then invoke it to do/redo/undo the updates. fDagMod = new MDGModifier; // Create new cgfxShader node if requested. if ( !fIsEdit ) { // Create node. oNode = fDagMod->createNode(cgfxShaderNode::sId, &status); M_CHECK( status ); if ( fNodeName.length() > 0 ) { status = fDagMod->renameNode(oNode, fNodeName); M_CHECK( status ); } status = fnNode.setObject( oNode ); M_CHECK( status && fnNode.typeId() == cgfxShaderNode::sId ); pNode = (cgfxShaderNode*)fnNode.userNode(); M_CHECK( pNode ); // On successful completion, redoCmd() will select the new node. // Save old selection for undo. status = MGlobal::getActiveSelectionList( fOldSelection ); M_CHECK( status ); } if (fFxFile) { // Save the current state of the node for undo purposes fOldFxFile = pNode->shaderFxFile(); fOldEffect = pNode->effect(); // save old CGeffect cgfxShaderNode::NodeList nodes; // getNodesToUpdate will return the list of nodes that will need to be updated : // if the new fx file is the same as the old fx file, the action is considered a reload, // we'll gather all the nodes that are using the old effect and reload them all. // else the effect file is different and only the current node will be updated. getNodesToUpdate(fOldEffect, pNode, nodes); cgfxShaderNode::NodeList::const_iterator it = nodes.begin(); cgfxShaderNode::NodeList::const_iterator itEnd = nodes.end(); for(; it != itEnd; ++it) { cgfxShaderNode* node = *it; MStringArray &oldAttributeList = fOldAttributeList[node]; cgfxRCPtr<cgfxAttrDefList> &oldAttrDefList = fOldAttrDefList[node]; MStringArray &newAttributeList = fNewAttributeList[node]; cgfxRCPtr<cgfxAttrDefList> &newAttrDefList = fNewAttrDefList[node]; node->getAttributeList( oldAttributeList ); oldAttrDefList = node->attrDefList(); // save old cgfxAttrDefList ptr // Now figure out what to do with the node. // // updateNode does a fair amount of work. First, it gets the // cgfxAttrDefList from the effect. Then it gets the equivalent // list from the node itself. It determines which attributes need // to be added and which need to be deleted and fills in all the // changes in the MDagModifier fDagMod. Then it builds a new value // for the attributeList attribute. Finally, it builds a new // value for the attrDefList internal value. All these values are // returned here where we can set them into the node. // cgfxAttrDef::updateNode( fNewEffect, // IN node, // IN fDagMod, // UPD newAttrDefList, // OUT newAttributeList ); // OUT } } // Save a reference to the node in a selection list for undo/redo. status = fNodeSelection.add( oNode ); M_CHECK( status ); // Save the current state of the node for undo purposes fOldTechnique = pNode->getTechnique(); fOldProfile = pNode->getProfile(); // I think we have all the information to redoIt(). // // Typically, the doIt() method only collects the infomation required // to do/undo the action and then stores it in class members. The // redo method is then called to do the actuall work. This prevents // code duplication. // return redoCmd( oNode, fnNode, pNode ); } // cgfxShaderCmd::doCmd
// -------------------------------------------------------------------------------------------- MStatus polyModifierCmd::processUpstreamNode( modifyPolyData& data ) // -------------------------------------------------------------------------------------------- { MStatus status = MS::kSuccess; // Declare our function sets - Although dagNodeFn derives from depNodeFn, we need // both since dagNodeFn can only refer to DAG objects. // We will use depNodeFn for all times other when dealing // with the DAG. // MFnDependencyNode depNodeFn; MFnDagNode dagNodeFn; // Use the selected node's plug connections to find the upstream plug. // Since we are looking at the selected node's inMesh attribute, it will // always have only one connection coming in if it has history, and none // otherwise. // // If there is no history, copy the selected node and place it ahead of the // modifierNode as the new upstream node so that the modifierNode has an // input mesh to operate on. // //save the meshDagPath for later use MDagPath::getAPathTo(data.meshNodeShape,myMeshPath); MPlugArray tempPlugArray; if( fHasHistory ) { // Since we have history, look for what connections exist on the // meshNode "inMesh" plug. "inMesh" plugs should only ever have one // connection. // data.meshNodeDestPlug.connectedTo( tempPlugArray, true, false); // ASSERT: Only one connection should exist on meshNodeShape.inMesh! // MStatusAssert( (tempPlugArray.length() == 1), "tempPlugArray.length() == 1 -- 0 or >1 connections on meshNodeShape.inMesh" ); data.upstreamNodeSrcPlug = tempPlugArray[0]; // Construction history only deals with shapes, so we can grab the // upstreamNodeShape off of the source plug. // // Dieser Bereich muss bleiben, weil diese Attribute noch bentigt werden data.upstreamNodeShape = data.upstreamNodeSrcPlug.node(); depNodeFn.setObject( data.upstreamNodeShape ); data.upstreamNodeSrcAttr = data.upstreamNodeSrcPlug.attribute(); // Disconnect the upstream node and the selected node, so we can // replace them with our own connections below. // MPlug nodePlug(data.meshNodeShape,data.meshNodeDestAttr ) ; INVIS(cout<<data.upstreamNodeSrcPlug.name().asChar()<<" --|-- "<<nodePlug.name().asChar()<<endl); status = fDGModifier.disconnect( data.upstreamNodeSrcPlug, nodePlug ); MCheckStatus( status, "Disconnect Upstream mit meshNode" ); } else // No History (!fHasHistory) { // Use the DAG node function set to duplicate the shape of the meshNode. // The duplicate method will return an MObject handle to the transform // of the duplicated shape, so traverse the dag to locate the shape. Store // this duplicate shape as our "upstream" node to drive the input for the // modifierNode. // depNodeFn.setObject( data.meshNodeShape ); data.upstreamNodeTransform = createDuplicate.createNode("mesh"); createDuplicate.doIt(); dagNodeFn.setObject( data.upstreamNodeTransform ); // Ensure that our upstreamNode is pointing to a shape. // MStatusAssert( (0 < dagNodeFn.childCount()), "0 < dagNodeFn.childCount() -- Duplicate meshNode transform has no shape." ); data.upstreamNodeShape = dagNodeFn.child(0); MPlug outMeshPlug = depNodeFn.findPlug("outMesh"); depNodeFn.setObject(data.upstreamNodeShape); //jetzt inMesh upstreamNodeShape mit outMesh meshShape füllen MDGModifier tempMod; tempMod.connect(outMeshPlug,depNodeFn.findPlug("inMesh")); tempMod.doIt(); //force DGEVAL MString cmd = "dgeval -src "; cmd += depNodeFn.name(); cmd += ".outMesh"; MGlobal::executeCommand(cmd,false,false); tempMod.undoIt(); // Re-parent the upstreamNodeShape under our original transform // reparentDuplicate.reparentNode( data.upstreamNodeShape, data.meshNodeTransform ); reparentDuplicate.doIt(); deleteDuplicate.deleteNode( data.upstreamNodeTransform ); deleteDuplicate.doIt(); /* status = fDagModifier.reparentNode( data.upstreamNodeShape, data.meshNodeTransform ); MCheckStatus( status, "reparentNode" ); // Perform the DAG re-parenting // // Note: This reparent must be performed before the deleteNode() is called. // See polyModifierCmd.h (see definition of fDagModifier) for more details. // status = fDagModifier.doIt(); MCheckStatus( status, "fDagModifier.doIt()" ); */ // Mark the upstreamNodeShape (the original shape) as an intermediate object // (making it invisible to the user) // dagNodeFn.setObject( data.upstreamNodeShape ); dagNodeFn.setIntermediateObject( true ); // Get the upstream node source attribute // data.upstreamNodeSrcAttr = dagNodeFn.attribute( "outMesh" ); data.upstreamNodeSrcPlug = MPlug(data.upstreamNodeShape, data.upstreamNodeSrcAttr); /* // Remove the duplicated transform node (clean up) // status = fDagModifier.deleteNode( data.upstreamNodeTransform ); MCheckStatus( status, "deleteNode" ); // Perform the DAG delete node // // Note: This deleteNode must be performed after the reparentNode() method is // completed. See polyModifierCmd.h (see definition of fDagModifier) for // details. // status = fDagModifier.doIt(); MCheckStatus( status, "fDagModifier.doIt()" ); */ // Cache the DAG path to the duplicate shape // dagNodeFn.getPath( fDuplicateDagPath ); //finally delete the tweaks to avoid double transformation deleteTweaks(); } return status; }
MStatus polyModifierCmd::processUpstreamNode( modifyPolyData& data ) { MStatus status = MS::kSuccess; // Declare our function sets - Although dagNodeFn derives from depNodeFn, we need // both since dagNodeFn can only refer to DAG objects. // We will use depNodeFn for all times other when dealing // with the DAG. // MFnDependencyNode depNodeFn; MFnDagNode dagNodeFn; // Use the selected node's plug connections to find the upstream plug. // Since we are looking at the selected node's inMesh attribute, it will // always have only one connection coming in if it has history, and none // otherwise. // // If there is no history, copy the selected node and place it ahead of the // modifierNode as the new upstream node so that the modifierNode has an // input mesh to operate on. // MPlugArray tempPlugArray; if( fHasHistory ) { // Since we have history, look for what connections exist on the // meshNode "inMesh" plug. "inMesh" plugs should only ever have one // connection. // data.meshNodeDestPlug.connectedTo( tempPlugArray, true, false); // ASSERT: Only one connection should exist on meshNodeShape.inMesh! // MStatusAssert( (tempPlugArray.length() == 1), "tempPlugArray.length() == 1 -- 0 or >1 connections on meshNodeShape.inMesh" ); data.upstreamNodeSrcPlug = tempPlugArray[0]; // Construction history only deals with shapes, so we can grab the // upstreamNodeShape off of the source plug. // data.upstreamNodeShape = data.upstreamNodeSrcPlug.node(); depNodeFn.setObject( data.upstreamNodeShape ); data.upstreamNodeSrcAttr = data.upstreamNodeSrcPlug.attribute(); // Disconnect the upstream node and the selected node, so we can // replace them with our own connections below. // fDGModifier.disconnect( data.upstreamNodeShape, data.upstreamNodeSrcAttr, data.meshNodeShape, data.meshNodeDestAttr ); } else // No History (!fHasHistory) { // Use the DAG node function set to duplicate the shape of the meshNode. // The duplicate method will return an MObject handle to the transform // of the duplicated shape, so traverse the dag to locate the shape. Store // this duplicate shape as our "upstream" node to drive the input for the // modifierNode. // dagNodeFn.setObject( data.meshNodeShape ); data.upstreamNodeTransform = dagNodeFn.duplicate( false, false ); dagNodeFn.setObject( data.upstreamNodeTransform ); // Ensure that our upstreamNode is pointing to a shape. // MStatusAssert( (0 < dagNodeFn.childCount()), "0 < dagNodeFn.childCount() -- Duplicate meshNode transform has no shape." ); data.upstreamNodeShape = dagNodeFn.child(0); // Re-parent the upstreamNodeShape under our original transform // status = fDagModifier.reparentNode( data.upstreamNodeShape, data.meshNodeTransform ); MCheckStatus( status, "reparentNode" ); // Perform the DAG re-parenting // // Note: This reparent must be performed before the deleteNode() is called. // See polyModifierCmd.h (see definition of fDagModifier) for more details. // status = fDagModifier.doIt(); MCheckStatus( status, "fDagModifier.doIt()" ); // Mark the upstreamNodeShape (the original shape) as an intermediate object // (making it invisible to the user) // dagNodeFn.setObject( data.upstreamNodeShape ); dagNodeFn.setIntermediateObject( true ); // Get the upstream node source attribute // data.upstreamNodeSrcAttr = dagNodeFn.attribute( "outMesh" ); // Remove the duplicated transform node (clean up) // status = fDagModifier.deleteNode( data.upstreamNodeTransform ); MCheckStatus( status, "deleteNode" ); // Perform the DAG delete node // // Note: This deleteNode must be performed after the reparentNode() method is // completed. See polyModifierCmd.h (see definition of fDagModifier) for // details. // status = fDagModifier.doIt(); MCheckStatus( status, "fDagModifier.doIt()" ); // Cache the DAG path to the duplicate shape // dagNodeFn.getPath( fDuplicateDagPath ); } return status; }
MFnMesh* GDExporter::GetSelectedMesh(void) { MSelectionList currSelection; MGlobal::getActiveSelectionList(currSelection); unsigned int selectionCount = currSelection.length(); MFnMesh* exportingMesh = 0; for(unsigned int selectionIndex = 0; selectionIndex < selectionCount; ++selectionIndex ) { MDagPath currPath; currSelection.getDagPath(selectionIndex, currPath); if( currPath.apiType() != MFn::kTransform ) continue; MFnTransform currTransform(currPath); unsigned int childCount = currTransform.childCount(); for(unsigned int childIndex = 0; childIndex < childCount; ++childIndex) { MObject childObject = currTransform.child(childIndex); if( childObject.apiType() == MFn::kMesh ) { MFnDagNode dagNode; dagNode.setObject(childObject); MDagPath childPath; dagNode.getPath(childPath); MFnMesh* pChildMesh = new MFnMesh(childPath); if( pChildMesh->isIntermediateObject() ) continue; bool bExportMesh = true; if( pChildMesh->isInstanced(false) ) if( childPath.instanceNumber() != 0 ) bExportMesh = false; if( bExportMesh ) { if( exportingMesh != 0 ) { delete exportingMesh; delete pChildMesh; MGlobal::displayError(MString("GDExporter - More than one mesh object selected.")); return 0; } exportingMesh = pChildMesh; } } } } if( exportingMesh == 0 ) { MGlobal::displayError(MString("GDExporter - No mesh objects currently selected.")); return 0; } return exportingMesh; }
// Execute the command MStatus OgreExporter::doIt(const MArgList& args) { // clean up delete m_pMesh; delete m_pMaterialSet; // Parse the arguments. m_params.parseArgs(args); // Create output files m_params.openFiles(); // Create a new empty mesh m_pMesh = new Mesh(); // Create a new empty material set m_pMaterialSet = new MaterialSet(); // Save current time for later restore m_curTime = MAnimControl::currentTime(); // Save active selection list for later restore MGlobal::getActiveSelectionList(m_selList); /**************************** LOAD DATA **********************************/ if (m_params.exportAll) { // We are exporting the whole scene std::cout << "Export the whole scene\n"; std::cout.flush(); MItDag dagIter; MFnDagNode worldDag (dagIter.root()); MDagPath worldPath; worldDag.getPath(worldPath); stat = translateNode(worldPath); } else { // We are translating a selection std::cout << "Export selected objects\n"; std::cout.flush(); // Get the selection list MSelectionList activeList; stat = MGlobal::getActiveSelectionList(activeList); if (MS::kSuccess != stat) { std::cout << "Error retrieving selection list\n"; std::cout.flush(); exit(); return MS::kFailure; } MItSelectionList iter(activeList); for ( ; !iter.isDone(); iter.next()) { MDagPath dagPath; stat = iter.getDagPath(dagPath); stat = translateNode(dagPath); } } // Load vertex animations if (m_params.exportVertAnims) m_pMesh->loadAnims(m_params); // Load blend shapes if (m_params.exportBlendShapes) m_pMesh->loadBlendShapes(m_params); // Restore skeleton to correct pose if (m_pMesh->getSkeleton()) m_pMesh->getSkeleton()->restorePose(); // Load skeleton animation (do it now, so we have loaded all needed joints) if (m_pMesh->getSkeleton() && m_params.exportSkelAnims) { // Load skeleton animations m_pMesh->getSkeleton()->loadAnims(m_params); } /**************************** WRITE DATA **********************************/ stat = writeOgreData(); std::cout << "Export completed succesfully\n"; std::cout.flush(); exit(); return MS::kSuccess; }