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

# affectsNode.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 <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 );
    }