latticeNoise/latticeNoiseNode.cpp
 
 
 
latticeNoise/latticeNoiseNode.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.
// ==========================================================================
//+

//
//  Class: latticeNoiseNode
//
//  Description:
//      A "latticeNoise" node adds random noise to lattice geometry over time.
//      This makes the geometry being deformed by the lattice look like 
//      wobbly jello.
//
//
//  Node:       latticeNoise
//
//  Attributes: input     - input lattice 
//              amplitude - amplitude of the noise
//              frequency - frequency of the noise
//              time      - the current time
//              output    - the modified lattice
//  
#include "latticeNoise.h"

#include <string.h>
#include <maya/MIOStream.h>
#include <stdio.h>
#include <math.h>

#include <maya/MFnUnitAttribute.h>  
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnTypedAttribute.h>  
#include <maya/MFnLattice.h>
#include <maya/MFnLatticeData.h>

#include <maya/MString.h> 
#include <maya/MTypeId.h> 
#include <maya/MPlug.h> 
#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h> 
#include <maya/MTime.h>

// CONSTANTS
//
#define DEF_AMPLITUDE 0.2
#define DEF_FREQ      4.0 

#define McheckErr(stat,msg)          \
    if ( MS::kSuccess != stat ) {   \
                cerr << msg;                \
                return MS::kFailure;        \
        }


//             latticeNoiseNode Methods                 //

MTypeId     latticeNoiseNode::id( 0x80010 );
MObject     latticeNoiseNode::input;  
MObject     latticeNoiseNode::amplitude;  
MObject     latticeNoiseNode::frequency;  
MObject     latticeNoiseNode::time;      
MObject     latticeNoiseNode::output;       

MStatus latticeNoiseNode::compute( const MPlug& plug, MDataBlock& data )
{ 
        MStatus returnStatus;

        float noiseAmplitude;
        float noiseFreq;
 
        if( plug == output )
        {
                // Get the lattice data from the input attribute.  First get the 
                // data object, and then use the lattice data function set to extract
                // the actual lattice.
                //

                // Get the data handle
                //
                MDataHandle inputData = data.inputValue( input, &returnStatus );
                McheckErr( returnStatus, "ERROR getting lattice data handle\n" ); 
                // Get the data object
                //
                MObject latticeData = inputData.data(); 
                MFnLatticeData dataFn( latticeData );
                // Get the actual geometry
                // 
                MObject lattice = dataFn.lattice();
                MFnLattice lattFn( lattice, &returnStatus );
                McheckErr( returnStatus, "ERROR getting lattice geometry\n" );  


                // Do the same for the output lattice
                //
                MDataHandle outputData = data.outputValue( output, &returnStatus ); 
                McheckErr( returnStatus, "ERROR getting lattice data handle\n" );
                // Get the data object
                //
                latticeData = outputData.data(); 
                if ( latticeData.isNull() ) { 
                        // The data object for this attribute has not been created yet, so
                        // we'll create it
                        //
                        latticeData = dataFn.create();
                } else {
                        // Use the data object that is already there
                        // 
                        dataFn.setObject( latticeData );
                }
                // Get the actual geometry
                // 
                MObject outLattice = dataFn.lattice();
                MFnLattice outLattFn( outLattice, &returnStatus );
                McheckErr( returnStatus, "ERROR getting lattice geometry\n" );  

                // Get the amplitude and frequency
                //
                MDataHandle ampData = data.inputValue( amplitude, &returnStatus );
                McheckErr( returnStatus, "ERROR getting amplitude\n" );
                noiseAmplitude = ampData.asFloat(); 

                MDataHandle freqData = data.inputValue( frequency, &returnStatus );
                McheckErr( returnStatus, "ERROR getting frequency\n" );
                noiseFreq = freqData.asFloat(); 

                // Get the time.  
                //
                MDataHandle timeData = data.inputValue( time, &returnStatus ); 
                McheckErr( returnStatus, "ERROR getting time data handle\n" );
                MTime time = timeData.asTime();
                float seconds = (float)time.as( MTime::kSeconds );

                // Easiest way to modify frequency is by modifying the time
                //
                seconds = seconds * noiseFreq;

                // We have the information we need now.  We'll apply noise to the
                // points upon the lattice
                //
                unsigned s, t, u;
                lattFn.getDivisions( s, t, u );
                // match up the divisions in the lattices
                //
                outLattFn.setDivisions( s, t, u );   

                for ( unsigned i = 0; i < s; i++ ) {
                        for ( unsigned j = 0; j < t; j++ ) {
                                for ( unsigned k = 0; k < u; k++ ) {
                                        MPoint & point = lattFn.point( i, j, k );
                                        MPoint & outPoint = outLattFn.point( i, j, k );
                                        pnt noisePnt = noise::atPointAndTime( (float)point.x, (float)point.y, 
                                                                                                                  (float)point.z, seconds );
                                        // Make noise between -1 and 1 instead of 0 and 1
                                        //
                                        noisePnt.x =  ( noisePnt.x * 2.0F ) - 1.0F;
                                        noisePnt.y =  ( noisePnt.y * 2.0F ) - 1.0F;
                                        noisePnt.z =  ( noisePnt.z * 2.0F ) - 1.0F;

                                        outPoint.x = point.x + ( noisePnt.x * noiseAmplitude );
                                        outPoint.y = point.y + ( noisePnt.y * noiseAmplitude );
                                        outPoint.z = point.z + ( noisePnt.z * noiseAmplitude );  
                                }
                        }
                } 
                outputData.set( latticeData );
                data.setClean(plug); 
        } else {
                return MS::kUnknownParameter;
        }

        return MS::kSuccess;
}

void* latticeNoiseNode::creator()
{
        return new latticeNoiseNode;
}

MStatus latticeNoiseNode::initialize()
{ 
        MFnUnitAttribute    unitAttr;
        MFnTypedAttribute   typedAttr;
        MFnNumericAttribute numAttr;

        MStatus stat;

        input = typedAttr.create( "input", "in", MFnData::kLattice, &stat );
        if ( !stat ) {
                stat.perror("ERROR creating latticeNoiseNode input lattice attribute");
                return stat;
        }

        amplitude = numAttr.create( "amplitude", "amp", 
                                                                                           MFnNumericData::kFloat,
                                                                                           DEF_AMPLITUDE,
                                                                                           &stat );
        if ( !stat ) {
                stat.perror("ERROR creating latticeNoiseNode amplitude attribute");
                return stat;
        }

        frequency = numAttr.create( "frequency", "fq", 
                                                                                           MFnNumericData::kFloat,
                                                                                           DEF_FREQ,
                                                                                           &stat );
        if ( !stat ) {
                stat.perror("ERROR creating latticeNoiseNode frequency attribute");
                return stat;
        }

        time = unitAttr.create( "time", "tm", MFnUnitAttribute::kTime,
                                                                                        0.0, &stat );
        if ( !stat ) {
                stat.perror("ERROR creating latticeNoiseNode time attribute");
                return stat;
        }

        output = typedAttr.create( "output", "out", MFnData::kLattice, &stat ); 
        if ( !stat ) {
                stat.perror("ERROR creating latticeNoiseNode output attribute");
                return stat;
        }
        typedAttr.setWritable(false);

        stat = addAttribute( input );
                if (!stat) { stat.perror("addAttribute"); return stat;}
        stat = addAttribute( amplitude );
                if (!stat) { stat.perror("addAttribute"); return stat;}
        stat = addAttribute( frequency );
                if (!stat) { stat.perror("addAttribute"); return stat;}
        stat = addAttribute( time );
                if (!stat) { stat.perror("addAttribute"); return stat;}
        stat = addAttribute( output );
                if (!stat) { stat.perror("addAttribute"); return stat;}

        stat = attributeAffects( input, output );
                if (!stat) { stat.perror("attributeAffects"); return stat;}
        stat = attributeAffects( amplitude, output );
                if (!stat) { stat.perror("attributeAffects"); return stat;}
        stat = attributeAffects( frequency, output );
                if (!stat) { stat.perror("attributeAffects"); return stat;}
        stat = attributeAffects( time, output );
                if (!stat) { stat.perror("attributeAffects"); return stat;}


        return MS::kSuccess;
}