//- // ========================================================================== // 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 <maya/MIOStream.h> #include <string.h> #include <math.h> #include <maya/MPxNode.h> #include <maya/MFnNumericAttribute.h> #include <maya/MFnDependencyNode.h> #include <maya/MFnPlugin.h> #include <maya/MString.h> #include <maya/MTypeId.h> #include <maya/MPlug.h> #include <maya/MPlugArray.h> #include <maya/MVector.h> #include <maya/MDataBlock.h> #include <maya/MDataHandle.h> // Plugin Affects Class // // INTRODUCTION: // This class will create an "affects" node. This node is used for // demonstrating attributeAffects relationships involving dynamic // attributes. // // WHAT THIS PLUG-IN DEMONSTRATES: // This plug-in creates a node called "affects". Add two dynamic // integer attributes called "A" and "B". When you change the value on // A, note that B will recompute. // // HOW TO USE THIS PLUG-IN: // (1) Compile the plug-in // (2) Load the compiled plug-in into Maya via the plug-in manager // (3) Create an "affects" node by typing the MEL command: // createNode affects; // (4) Add two integer dynamic attributes to the newly created // affects node by typing the MEL command: // addAttr -ln A -at long affects1; // addAttr -ln B -at long affects1; // (5) Change the value of "A" to 10 by typing the MEL command: // setAttr affects1.A 10; // At this point, the affectsNode::setDependentsDirty() method // gets called which causes "B" to be marked dirty. // (6) Compute the value on "B" by doing a getAttr: // getAttr affects1.B; // The affectsNode::compute() method is entered which copies the // value from "A" (i.e. 10) to "B". // class affects : public MPxNode { public: affects(); virtual ~affects(); virtual MStatus compute( const MPlug& plug, MDataBlock& data ); virtual MStatus setDependentsDirty( const MPlug& plugBeingDirtied, MPlugArray &affectedPlugs ); static void* creator(); static MStatus initialize(); static MTypeId id; // The IFF type id }; // IFF type ID // Each node requires a unique identifier which is used by // MFnDependencyNode::create() to identify which node to create, and by // the Maya file format. // // For local testing of nodes you can use any identifier between // 0x00000000 and 0x0007ffff, but for any node that you plan to use for // more permanent purposes, you should get a universally unique id from // Autodesk Support. You will be assigned a unique range that you can manage // on your own. // MTypeId affects::id( 0x80028 ); // This node does not need to perform any special actions on creation or // destruction // affects::affects() {} affects::~affects() {} // The compute() method does the actual work of the node using the inputs // of the node to generate its output. // // Compute takes two parameters: plug and data. // - Plug is the the data value that needs to be recomputed // - Data provides handles to all of the nodes attributes, only these // handles should be used when performing computations. // MStatus affects::compute( const MPlug& plug, MDataBlock& data ) { MStatus status; MObject thisNode = thisMObject(); MFnDependencyNode fnThisNode( thisNode ); fprintf(stderr,"affects::compute(), plug being computed is \"%s\"\n", plug.name().asChar()); if ( plug.partialName() == "B" ) { // Plug "B" is being computed. Assign it the value on plug "A" // if "A" exists. // MPlug pA = fnThisNode.findPlug( "A", &status ); if ( MStatus::kSuccess == status ) { fprintf(stderr,"\t\t... found dynamic attribute \"A\", copying its value to \"B\"\n"); MDataHandle inputData = data.inputValue( pA, &status ); CHECK_MSTATUS( status ); int value = inputData.asInt(); MDataHandle outputHandle = data.outputValue( plug ); outputHandle.set( value ); data.setClean(plug); } } else { return MS::kUnknownParameter; } return( MS::kSuccess ); } // The creator() method allows Maya to instantiate instances of this node. // It is called every time a new instance of the node is requested by // either the createNode command or the MFnDependencyNode::create() // method. // // In this case creator simply returns a new affects object. // void* affects::creator() { return( new affects() ); } // The initialize method is called only once when the node is first // registered with Maya. In general, // MStatus affects::initialize() { return( MS::kSuccess ); } // The setDependentsDirty() method allows attributeAffects relationships // in a much more general way than via MPxNode::attributeAffects // which is limited to static attributes only. // The setDependentsDirty() method allows relationships to be established // between any combination of dynamic and static attributes. // // Within a setDependentsDirty() implementation you get passed in the // plug which is being set dirty, and then, based upon which plug it is, // you may choose to dirty any other plugs by adding them to the // affectedPlugs list. // // In almost all cases, the relationships you set up will be fixed for // the duration of Maya, such as "A affects B". However, you can also // set up relationships which depend upon some external factor, such // as the current frame number, the time of day, if maya was invoked in // batch mode, etc. These sorts of relationships are straightforward to // implement in your setDependentsDirty() method. // // There may also be situations where you need to look at values in the // dependency graph. It is VERY IMPORTANT that when accessing DG values // you do not cause a DG evaluation. This is because your setDependentsDirty() // method is called during dirty processing and causing an evalutaion could // put Maya into an infinite loop. The only safe way to look at values // on plugs is via the MDataBlock::outputValue() which does not trigger // an evaluation. It is recommeneded that you only look at plugs whose // values are constant or you know have already been computed. // // For this example routine, we will only implement the simplest case // of a relationship. // MStatus affects::setDependentsDirty( const MPlug &plugBeingDirtied, MPlugArray &affectedPlugs ) { MStatus status; MObject thisNode = thisMObject(); MFnDependencyNode fnThisNode( thisNode ); if ( plugBeingDirtied.partialName() == "A" ) { // "A" is dirty, so mark "B" dirty if "B" exists. // This implements the relationship "A affects B". // fprintf(stderr,"affects::setDependentsDirty, \"A\" being dirtied\n"); MPlug pB = fnThisNode.findPlug( "B", &status ); if ( MStatus::kSuccess == status ) { fprintf(stderr,"\t\t... dirtying \"B\"\n"); CHECK_MSTATUS( affectedPlugs.append( pB ) ); } } return( MS::kSuccess ); } // These methods load and unload the plugin, registerNode registers the // new node type with maya // MStatus initializePlugin( MObject obj ) { MStatus status; MFnPlugin plugin( obj, PLUGIN_COMPANY , "6.0", "Any"); status = plugin.registerNode( "affects", affects::id, affects::creator, affects::initialize ); if (!status) { status.perror("registerNode"); return( status ); } return( status ); } MStatus uninitializePlugin( MObject obj) { MStatus status; MFnPlugin plugin( obj ); status = plugin.deregisterNode( affects::id ); if (!status) { status.perror("deregisterNode"); return( status ); } return( status ); }