genericAttributeNode/genericAttributeNode.cpp
 
 
 
genericAttributeNode/genericAttributeNode.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 <string.h>
#include <maya/MIOStream.h>
#include <math.h>

#include <maya/MPxNode.h> 

#include <maya/MFnNumericAttribute.h>
#include <maya/MFnGenericAttribute.h>
#include <maya/MFnPlugin.h>

#include <maya/MTypeId.h> 
#include <maya/MPlug.h>
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>
#include <maya/MGlobal.h>
 
//
// Node definition
//
class genericAttributeNode : public MPxNode
{
public:
                                                genericAttributeNode();
        virtual                         ~genericAttributeNode(); 

        virtual MStatus         compute( const MPlug& plug, MDataBlock& data );

        static  void*           creator();
        static  MStatus         initialize();

        static MStatus  addComplexFloatGenericAttribute( MObject& attrObject, const char *longName, const char *shortName );
        
public:
        // Numeric attribute
        static MObject          gInputInt;
        // Generic attribute that can be a float, 2float, 3float
        static MObject          gOutputFloat_2Float_3Float;
        // Type id
        static  MTypeId         id;
};

// Static initialization
MTypeId genericAttributeNode::id( 0x81031 );
MObject genericAttributeNode::gInputInt;
MObject genericAttributeNode::gOutputFloat_2Float_3Float;

// No-op constructor and destructor
genericAttributeNode::genericAttributeNode() {}
genericAttributeNode::~genericAttributeNode() {}

//
// Compute that will update the generic attribute
// when requested.
//
MStatus genericAttributeNode::compute( const MPlug& plug, MDataBlock& data )
{
        MStatus returnStatus;
 
        if ( plug == gOutputFloat_2Float_3Float )
        {
                // attribute affecting generic attribute case.  Based on the
                // input attribute, we modify the output generic attribute
                MDataHandle inputDataInt = data.inputValue( gInputInt );
                int inputInt = inputDataInt.asInt();
                
                // Get the output handle
                MDataHandle outputData = data.outputValue( plug );      
                bool isGenericNumeric = false;
                bool isGenericNull = false;
                
                // Is the output handle generic data
                if ( outputData.isGeneric( isGenericNumeric, isGenericNull ) )
                {
                        // Based on the inputHandle, update the generic
                        // output handle
                        if ( inputInt == 1 )
                                outputData.setGenericBool( false, true );
                        else if ( inputInt == 2 )
                                outputData.setGenericBool( true, true );
                        else if ( inputInt == 3 )
                                outputData.setGenericChar( 127, true );
                        else if ( inputInt == 4 )
                                outputData.setGenericDouble( 3.145, true );
                        else if ( inputInt == 5 )
                                outputData.setGenericFloat( (float)9.98, true );        
                        else if ( inputInt == 6 )
                                outputData.setGenericShort( 3245, true );
                        else if ( inputInt == 7 )
                                outputData.setGenericInt( 32768, true );
                        else if ( inputInt == 8 )
                        {
                                MFnNumericData numericData;
                                MObject obj = numericData.create( MFnNumericData::k2Float, &returnStatus );
                                CHECK_MSTATUS( returnStatus );
                                
                                returnStatus = numericData.setData( (float)1.5, (float)6.7 );
                                CHECK_MSTATUS( returnStatus );

                                outputData.set( obj );
                        }
                        else if ( inputInt == 9 )
                        {
                                MFnNumericData numericData;
                                MObject obj = numericData.create( MFnNumericData::k3Float, &returnStatus );
                                CHECK_MSTATUS( returnStatus );

                                returnStatus = numericData.setData( (float)2.5, (float)8.7, (float)2.3345 );
                                CHECK_MSTATUS( returnStatus );

                                outputData.set( obj );
                        }
                        else if ( inputInt == 10 )
                        {
                                outputData.setGenericInt( 909, true );
                        }                                                       

                        // Mark the data clean
                        outputData.setClean();
                        data.setClean( gOutputFloat_2Float_3Float );
                }
        } 
        else 
        {
                return MS::kUnknownParameter;
        }

        return MS::kSuccess;
}

// Creator
void* genericAttributeNode::creator()
{
        return new genericAttributeNode();
}

// Adds a generic attribute that accepts a float, float2, float3
MStatus genericAttributeNode::addComplexFloatGenericAttribute( 
        MObject& attrObject,
        const char *longName, const char *shortName )
{
        // Create the generic attribute and set the 3 accepts types
        MFnGenericAttribute gAttr; 
        attrObject = gAttr.create( longName, shortName ); 
        MStatus status = gAttr.addAccept(MFnNumericData::kFloat); 
        CHECK_MSTATUS( status );

        status = gAttr.addAccept(MFnNumericData::k2Float); 
        CHECK_MSTATUS( status );

        status = gAttr.addAccept(MFnNumericData::k3Float); 
        CHECK_MSTATUS( status );

        gAttr.setWritable(false);
        gAttr.setStorable( false );
        
        // Add the attribute to the node
        status = addAttribute( attrObject );
        CHECK_MSTATUS( status );

        return MS::kSuccess;
}

// Create and add attributes
MStatus genericAttributeNode::initialize()
{
        MFnNumericAttribute nAttr;
        MStatus status;

        // single float attribute affecting a generic attribute
        gInputInt = nAttr.create( "gInputInt", "gii",
                   MFnNumericData::kInt, 0, &status );
        nAttr.setStorable(true);
        nAttr.setKeyable(true);
        CHECK_MSTATUS( status );

        status = addAttribute( gInputInt );
        CHECK_MSTATUS( status );

        if ( !addComplexFloatGenericAttribute( gOutputFloat_2Float_3Float,
                                         "gOutputFloat_2Float_3Float", "gof2f3f" ) )
                return MS::kFailure;

        status = attributeAffects( gInputInt, gOutputFloat_2Float_3Float );
        CHECK_MSTATUS( status );
        
        return MS::kSuccess;
}

MStatus initializePlugin( MObject obj )
{ 
        MStatus   status;
        MFnPlugin plugin( obj, PLUGIN_COMPANY, "7.0", "Any");

        status = plugin.registerNode( "genericAttributeNode", 
                                                                        genericAttributeNode::id, genericAttributeNode::creator,
                                                                        genericAttributeNode::initialize );
        if (!status) {
                status.perror("registerNode");
                return status;
        }

        return status;
}

MStatus uninitializePlugin( MObject obj)
{
        MStatus   status;
        MFnPlugin plugin( obj );

        status = plugin.deregisterNode( genericAttributeNode::id );
        if (!status) {
                status.perror("deregisterNode");
                return status;
        }

        return status;
}