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;
}