offsetNode.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.
// ==========================================================================
//+

//
//  File: offset.cc
//
//  Description:
//      Example implementation of a deformer. This node
//      offsets vertices according to the CV's weights.
//      The weights are set using the set editor or the
//      percent command.
//

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

#include <maya/MPxDeformerNode.h> 
#include <maya/MItGeometry.h>
#include <maya/MPxLocatorNode.h> 

#include <maya/MFnNumericAttribute.h>
#include <maya/MFnMatrixAttribute.h>
#include <maya/MFnMatrixData.h>

#include <maya/MFnPlugin.h>
#include <maya/MFnDependencyNode.h>

#include <maya/MTypeId.h> 
#include <maya/MPlug.h>

#include <maya/MDataBlock.h>
#include <maya/MDataHandle.h>
#include <maya/MArrayDataHandle.h>

#include <maya/MPoint.h>
#include <maya/MVector.h>
#include <maya/MMatrix.h>

#include <maya/MDagModifier.h>


class offset : public MPxDeformerNode
{
public:
                        offset();
    virtual             ~offset();

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

    // deformation function
    //
    virtual MStatus             deform(MDataBlock&      block,
                                       MItGeometry&     iter,
                                       const MMatrix&   mat,
                                       unsigned int     multiIndex);

    // when the accessory is deleted, this node will clean itself up
    //
    virtual MObject&            accessoryAttribute() const;

    // create accessory nodes when the node is created
    //
    virtual MStatus             accessoryNodeSetup(MDagModifier& cmd);

public:
    // local node attributes

    static  MObject     offsetMatrix;   // offset center and axis
    
    static  MTypeId     id;

private:
};

MTypeId     offset::id( 0x8000c );

// local attributes
//
MObject     offset::offsetMatrix;


offset::offset() {}
offset::~offset() {}

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

MStatus offset::initialize()
{
    // local attribute initialization

    MFnMatrixAttribute  mAttr;
    offsetMatrix=mAttr.create( "locateMatrix", "lm");
        mAttr.setStorable(false);
        mAttr.setConnectable(true);

    //  deformation attributes
    addAttribute( offsetMatrix);

    attributeAffects( offset::offsetMatrix, offset::outputGeom );

    return MStatus::kSuccess;
}


MStatus
offset::deform( MDataBlock& block,
                MItGeometry& iter,
                const MMatrix& /*m*/,
                unsigned int multiIndex)
//
// Method: deform
//
// Description:   Deform the point with a squash algorithm
//
// Arguments:
//   block      : the datablock of the node
//   iter       : an iterator for the geometry to be deformed
//   m          : matrix to transform the point into world space
//   multiIndex : the index of the geometry that we are deforming
//
//
{
    MStatus returnStatus;
    
    // Envelope data from the base class.
    // The envelope is simply a scale factor.
    //
    MDataHandle envData = block.inputValue(envelope, &returnStatus);
    if (MS::kSuccess != returnStatus) return returnStatus;
    float env = envData.asFloat();  

    // Get the matrix which is used to define the direction and scale
    // of the offset.
    //
    MDataHandle matData = block.inputValue(offsetMatrix, &returnStatus );
    if (MS::kSuccess != returnStatus) return returnStatus;
    MMatrix omat = matData.asMatrix();
    MMatrix omatinv = omat.inverse();

    // iterate through each point in the geometry
    //
    for ( ; !iter.isDone(); iter.next()) {
        MPoint pt = iter.position();
        pt *= omatinv;
        
        float weight = weightValue(block,multiIndex,iter.index());
        
        // offset algorithm
        //
        pt.y = pt.y + env*weight;
        //
        // end of offset algorithm

        pt *= omat;
        iter.setPosition(pt);
    }
    return returnStatus;
}


/* override */
MObject&
offset::accessoryAttribute() const
//
//  Description:
//    This method returns a the attribute to which an accessory 
//    shape is connected. If the accessory shape is deleted, the deformer
//    node will automatically be deleted.
//
//    This method is optional.
//
{
    return offset::offsetMatrix;
}

/* override */
MStatus
offset::accessoryNodeSetup(MDagModifier& cmd)
//
//  Description:
//      This method is called when the deformer is created by the
//      "deformer" command. You can add to the cmds in the MDagModifier
//      cmd in order to hook up any additional nodes that your node needs
//      to operate.
//
//      In this example, we create a locator and attach its matrix attribute
//      to the matrix input on the offset node. The locator is used to
//      set the direction and scale of the random field.
//
//  Description:
//      This method is optional.
//
{
    MStatus result;

    // hook up the accessory node
    //
    MObject objLoc = cmd.createNode(MString("locator"),
                                    MObject::kNullObj,
                                    &result);

    if (MS::kSuccess == result) {
        MFnDependencyNode fnLoc(objLoc);
        MString attrName;
        attrName.set("matrix");
        MObject attrMat = fnLoc.attribute(attrName);

        result = cmd.connect(objLoc,attrMat,this->thisMObject(),offset::offsetMatrix);
    }
    return result;
}


// standard initialization procedures
//

MStatus initializePlugin( MObject obj )
{
    MStatus result;
    MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any");
    result = plugin.registerNode( "offset", offset::id, offset::creator, 
                                  offset::initialize, MPxNode::kDeformerNode );

    return result;
}

MStatus uninitializePlugin( MObject obj)
{
    MStatus result;
    MFnPlugin plugin( obj );
    result = plugin.deregisterNode( offset::id );
    return result;
}