sseDeformer/sseDeformer.cpp
 
 
 
sseDeformer/sseDeformer.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: sseDeformer.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 <float.h> // for FLT_MAX
#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/MTimer.h>

#include <maya/MDagModifier.h>
#include <maya/MFnMesh.h>
#include <maya/MFloatPointArray.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MFnMeshData.h>
#include <maya/MFloatVectorArray.h>

// Macros
//
#define MCheckStatus(status,message)    \
        if( MStatus::kSuccess != status ) {     \
                cerr << message << "\n";                \
                return status;                                  \
        }

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

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

        // deformation function
        //
        virtual MStatus compute(const MPlug& plug, MDataBlock& dataBlock);

public:
        // local node attributes
        static  MObject sseEnabled;

        static  MTypeId         id;

private:
};

MTypeId     sseDeformer::id( 0x8104E );

// local attributes
MObject sseDeformer::sseEnabled;

sseDeformer::sseDeformer() {}
sseDeformer::~sseDeformer() {}

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

MStatus sseDeformer::initialize()
{
        // local attribute initialization
        MStatus status;
        MFnNumericAttribute mSSEAttr;
        sseEnabled=mSSEAttr.create( "enableSSE", "sse", MFnNumericData::kBoolean, 0, &status);
        mSSEAttr.setStorable(true);

        //  deformation attributes
        status = addAttribute( sseEnabled );
        MCheckStatus(status, "ERROR in addAttribute\n");

        status = attributeAffects( sseEnabled, outputGeom );
        MCheckStatus(status, "ERROR in attributeAffects\n");

        return MStatus::kSuccess;
}

MStatus sseDeformer::compute(const MPlug& plug, MDataBlock& data)
{
        MStatus status;
        if (plug.attribute() != outputGeom) {
                printf("Ignoring requested plug\n");
                return status;
        }
        unsigned int index = plug.logicalIndex();
        MObject thisNode = this->thisMObject();

        // get input value
        MPlug inPlug(thisNode,input);
        inPlug.selectAncestorLogicalIndex(index,input);
        MDataHandle hInput = data.inputValue(inPlug, &status);
        MCheckStatus(status, "ERROR getting input mesh\n");
        
        // get the input geometry
        MDataHandle inputData = hInput.child(inputGeom);
        if (inputData.type() != MFnData::kMesh) {
                printf("Incorrect input geometry type\n");
                return MStatus::kFailure;
        }

        MObject iSurf = inputData.asMesh() ;
        MFnMesh inMesh;
        inMesh.setObject( iSurf ) ;

        MDataHandle outputData = data.outputValue(plug);
        outputData.copy(inputData);
        if (outputData.type() != MFnData::kMesh) {
                printf("Incorrect output mesh type\n");
                return MStatus::kFailure;
        }
        
        MObject oSurf = outputData.asMesh() ;
        if(oSurf.isNull()) {
                printf("Output surface is NULL\n");
                return MStatus::kFailure;
        }

        MFnMesh outMesh;
        outMesh.setObject( oSurf ) ;
        MCheckStatus(status, "ERROR setting points\n");

        // get all points at once for demo purposes. Really should get points from the current group using iterator
        MFloatPointArray pts;
        outMesh.getPoints(pts);

        int nPoints = pts.length();

        MDataHandle envData = data.inputValue(envelope, &status);
        float env = envData.asFloat();  

        MDataHandle sseData = data.inputValue(sseEnabled, &status);
        bool sseEnabled = (bool) sseData.asBool();      

        // NOTE: Using MTimer and possibly other classes disables
        // autovectorization with Intel <=10.1 compiler on OSX and Linux!!
        // Must compile this function with -fno-exceptions on OSX and
        // Linux to guarantee autovectorization is done. Use -fvec_report2
        // to check for vectorization status messages with Intel compiler.
        MTimer timer; timer.beginTimer();

        if(sseEnabled) {

                // Innter loop will autovectorize. Around 3x faster than the
                // loop below it. It would be faster if first element was
                // guaranteed to be aligned on 16 byte boundary.
                for(int i=0; i<nPoints; i++) {
                        float* ptPtr = &pts[i].x;
                        for(int j=0; j<4; j++) {
                                ptPtr[j] = env * (cosf(ptPtr[j]) * sinf(ptPtr[j]) * tanf(ptPtr[j]));
                        }
                }

        } else {

                // This inner loop will not autovectorize.
                for(int i=0; i<nPoints; i++) {
                        MFloatPoint& pt = pts[i];
                        for(int j=0; j<3; j++) {
                                pt[j] = env * (cosf(pt[j]) * sinf(pt[j]) * tanf(pt[j]));
                        }

                }
        }

        timer.endTimer(); 
        if(sseEnabled) {
                printf("SSE enabled, runtime %f\n", timer.elapsedTime());
        } else {
                printf("SSE disabled, runtime %f\n", timer.elapsedTime());
        }

        outMesh.setPoints(pts);

        return status;
}


// standard initialization procedures
//

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

        return result;
}

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