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;
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");
}
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");
}
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");
}
MObject oSurf = outputData.asMesh() ;
if(oSurf.isNull()) {
printf("Output surface is NULL\n");
}
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
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;
}