#include <math.h>
#include <maya/MIOStream.h>
#include <apiMeshShape.h>
#include <apiMeshShapeUI.h>
#include <apiMeshCreator.h>
#include <apiMeshData.h>
#include <api_macros.h>
#include <maya/MFnPlugin.h>
#include <maya/MFnPluginData.h>
#include <maya/MMatrix.h>
#include <maya/MAttributeSpecArray.h>
#include <maya/MAttributeSpec.h>
#include <maya/MAttributeIndex.h>
#include <maya/MObjectArray.h>
#include <maya/MFnSingleIndexedComponent.h>
#include <maya/MDagPath.h>
#include <maya/MFnAttribute.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MPointArray.h>
bool debug = false;
MObject apiMesh::inputSurface;
MObject apiMesh::outputSurface;
MObject apiMesh::cachedSurface;
MObject apiMesh::worldSurface;
MObject apiMesh::bboxCorner1;
MObject apiMesh::bboxCorner2;
MTypeId apiMesh::id( 0x80099 );
apiMesh::apiMesh() {}
apiMesh::~apiMesh() {}
void apiMesh::postConstructor()
{
setRenderable( true );
fHasHistoryOnCreate = false;
}
MStatus apiMesh::compute( const MPlug& plug, MDataBlock& datablock )
{
if (debug)
cerr << "apiMesh::compute : plug " << plug.info() << endl;
if ( plug == outputSurface ) {
return computeOutputSurface( plug, datablock );
}
else if ( plug == cachedSurface ) {
return computeOutputSurface( plug, datablock );
}
else if ( plug == worldSurface ) {
return computeWorldSurface( plug, datablock );
}
else {
return MS::kUnknownParameter;
}
}
bool apiMesh::getInternalValue( const MPlug& plug, MDataHandle& result )
{
bool isOk = true;
if( (plug == mControlPoints) ||
(plug == mControlValueX) ||
(plug == mControlValueY) ||
(plug == mControlValueZ) )
{
if ( hasHistory() ) {
return MPxNode::getInternalValue( plug, result );
}
else {
double val = 0.0;
if ( (plug == mControlPoints) && !plug.isArray() ) {
MPoint pnt;
int index = plug.logicalIndex();
value( index, pnt );
result.set( pnt[0], pnt[1], pnt[2] );
}
else if ( plug == mControlValueX ) {
MPlug parentPlug = plug.parent();
int index = parentPlug.logicalIndex();
value( index, 0, val );
result.set( val );
}
else if ( plug == mControlValueY ) {
MPlug parentPlug = plug.parent();
int index = parentPlug.logicalIndex();
value( index, 1, val );
result.set( val );
}
else if ( plug == mControlValueZ ) {
MPlug parentPlug = plug.parent();
int index = parentPlug.logicalIndex();
value( index, 2, val );
result.set( val );
}
}
}
else if ( plug == mHasHistoryOnCreate ) {
result.set( fHasHistoryOnCreate );
}
else {
isOk = MPxSurfaceShape::getInternalValue( plug, result );
}
return isOk;
}
bool apiMesh::setInternalValue( const MPlug& plug, const MDataHandle& handle )
{
bool isOk = true;
if( (plug == mControlPoints) ||
(plug == mControlValueX) ||
(plug == mControlValueY) ||
(plug == mControlValueZ) )
{
if ( hasHistory() ) {
verticesUpdated();
return MPxNode::setInternalValue( plug, handle );
}
else {
if( plug == mControlPoints && !plug.isArray()) {
int index = plug.logicalIndex();
MPoint point;
double3& ptData = handle.asDouble3();
point.x = ptData[0];
point.y = ptData[1];
point.z = ptData[2];
setValue( index, point );
}
else if( plug == mControlValueX ) {
MPlug parentPlug = plug.parent();
int index = parentPlug.logicalIndex();
setValue( index, 0, handle.asDouble() );
}
else if( plug == mControlValueY ) {
MPlug parentPlug = plug.parent();
int index = parentPlug.logicalIndex();
setValue( index, 1, handle.asDouble() );
}
else if( plug == mControlValueZ ) {
MPlug parentPlug = plug.parent();
int index = parentPlug.logicalIndex();
setValue( index, 2, handle.asDouble() );
}
}
}
else if ( plug == mHasHistoryOnCreate ) {
fHasHistoryOnCreate = handle.asBool();
}
else {
isOk = MPxSurfaceShape::setInternalValue( plug, handle );
}
return isOk;
}
MStatus apiMesh::connectionMade( const MPlug& plug,
const MPlug& otherPlug,
bool asSrc )
{
if ( plug == inputSurface ) {
MStatus stat;
MObject thisObj = thisMObject();
MPlug historyPlug( thisObj, mHasHistoryOnCreate );
stat = historyPlug.setValue( true );
MCHECKERROR( stat, "connectionMade: setValue(mHasHistoryOnCreate)" );
}
return MPxNode::connectionMade( plug, otherPlug, asSrc );
}
MStatus apiMesh::connectionBroken( const MPlug& plug,
const MPlug& otherPlug,
bool asSrc )
{
if ( plug == inputSurface ) {
MStatus stat;
MObject thisObj = thisMObject();
MPlug historyPlug( thisObj, mHasHistoryOnCreate );
stat = historyPlug.setValue( false );
MCHECKERROR( stat, "connectionBroken: setValue(mHasHistoryOnCreate)" );
}
return MPxNode::connectionBroken( plug, otherPlug, asSrc );
}
MStatus apiMesh::shouldSave( const MPlug& plug, bool& result )
{
MStatus status = MS::kSuccess;
if( plug == mControlPoints || plug == mControlValueX ||
plug == mControlValueY || plug == mControlValueZ )
{
if( hasHistory() ) {
status = MPxNode::shouldSave( plug, result );
}
else {
result = false;
}
}
else if ( plug == cachedSurface ) {
if ( hasHistory() ) {
result = false;
}
else {
MObject data;
status = plug.getValue( data );
MCHECKERROR( status, "shouldSave: MPlug::getValue" );
result = ( ! data.isNull() );
}
}
else {
status = MPxNode::shouldSave( plug, result );
}
return status;
}
void apiMesh::componentToPlugs( MObject & component,
MSelectionList & list ) const
{
if ( component.hasFn(MFn::kSingleIndexedComponent) ) {
MFnSingleIndexedComponent fnVtxComp( component );
MObject thisNode = thisMObject();
MPlug plug( thisNode, mControlPoints );
convertToTweakNodePlug(plug);
int len = fnVtxComp.elementCount();
for ( int i = 0; i < len; i++ )
{
plug.selectAncestorLogicalIndex(fnVtxComp.element(i),
plug.attribute());
list.add(plug);
}
}
}
MPxSurfaceShape::MatchResult
apiMesh::matchComponent( const MSelectionList& item,
const MAttributeSpecArray& spec,
MSelectionList& list )
{
MPxSurfaceShape::MatchResult result = MPxSurfaceShape::kMatchOk;
MAttributeSpec attrSpec = spec[0];
int dim = attrSpec.dimensions();
if ( (1 == spec.length()) && (dim > 0) && (attrSpec.name() == "vtx") ) {
int numVertices = meshGeom()->vertices.length();
MAttributeIndex attrIndex = attrSpec[0];
int upper = 0;
int lower = 0;
if ( attrIndex.hasLowerBound() ) {
attrIndex.getLower( lower );
}
if ( attrIndex.hasUpperBound() ) {
attrIndex.getUpper( upper );
}
if ( (lower > upper) || (upper >= numVertices) ) {
result = MPxSurfaceShape::kMatchInvalidAttributeRange;
}
else {
MDagPath path;
item.getDagPath( 0, path );
MFnSingleIndexedComponent fnVtxComp;
MObject vtxComp = fnVtxComp.create( MFn::kMeshVertComponent );
for ( int i=lower; i<=upper; i++ )
{
fnVtxComp.addElement( i );
}
list.add( path, vtxComp );
}
}
else {
return MPxSurfaceShape::matchComponent( item, spec, list );
}
return result;
}
bool apiMesh::match( const MSelectionMask & mask,
const MObjectArray& componentList ) const
{
bool result = false;
if( componentList.length() == 0 ) {
result = mask.intersects( MSelectionMask::kSelectMeshes );
}
else {
for ( int i=0; i<(int)componentList.length(); i++ ) {
if ( (componentList[i].apiType() == MFn::kMeshVertComponent) &&
(mask.intersects(MSelectionMask::kSelectMeshVerts))
) {
result = true;
break;
}
}
}
return result;
}
MObject apiMesh::createFullVertexGroup() const
{
MFnSingleIndexedComponent fnComponent;
MObject fullComponent = fnComponent.create( MFn::kMeshVertComponent );
int numVertices = ((apiMesh*)this)->meshGeom()->vertices.length();
fnComponent.setCompleteData( numVertices );
return fullComponent;
}
MObject apiMesh::localShapeInAttr() const
{
return inputSurface;
}
MObject apiMesh::localShapeOutAttr() const
{
return outputSurface;
}
MObject apiMesh::worldShapeOutAttr() const
{
return worldSurface;
}
MObject apiMesh::cachedShapeAttr() const
{
return cachedSurface;
}
MObject apiMesh::geometryData() const
{
apiMesh* nonConstThis = (apiMesh*)this;
MDataBlock datablock = nonConstThis->forceCache();
MDataHandle handle = datablock.inputValue( inputSurface );
return handle.data();
}
void apiMesh:: closestPoint ( const MPoint & toThisPoint, \
MPoint & theClosestPoint, double tolerance ) const
{
apiMeshGeom* geomPtr = ((apiMesh*)this)->meshGeom();
int numVertices = geomPtr->vertices.length();
for (int ii=0; ii<numVertices; ii++)
{
MPoint tryThisOne = geomPtr->vertices[ii];
}
theClosestPoint = geomPtr->vertices[0];
}
void apiMesh::transformUsing( const MMatrix & mat,
const MObjectArray & componentList )
{
transformUsing( mat,
componentList,
MPxSurfaceShape::kNoPointCaching,
NULL);
}
void apiMesh::transformUsing( const MMatrix & mat,
const MObjectArray & componentList,
MVertexCachingMode cachingMode,
MPointArray* pointCache)
{
MStatus stat;
apiMeshGeom* geomPtr = meshGeom();
bool savePoints = (cachingMode == MPxSurfaceShape::kSavePoints);
unsigned int i=0,j=0;
unsigned int len = componentList.length();
if (cachingMode == MPxSurfaceShape::kRestorePoints) {
unsigned int cacheLen = pointCache->length();
if (len > 0) {
for ( i = 0; i < len && j < cacheLen; i++ )
{
MObject comp = componentList[i];
MFnSingleIndexedComponent fnComp( comp );
int elemCount = fnComp.elementCount();
for ( int idx=0; idx<elemCount && j < cacheLen; idx++, ++j ) {
int elemIndex = fnComp.element( idx );
geomPtr->vertices[elemIndex] = (*pointCache)[j];
}
}
} else {
len = geomPtr->vertices.length();
for ( unsigned int idx = 0; idx < len && j < cacheLen; ++idx, ++j ) {
geomPtr->vertices[idx] = (*pointCache)[j];
}
}
} else {
if (len > 0) {
for ( i=0; i<len; i++ )
{
MObject comp = componentList[i];
MFnSingleIndexedComponent fnComp( comp );
int elemCount = fnComp.elementCount();
if (savePoints && 0 == i) {
pointCache->setSizeIncrement(elemCount);
}
for ( int idx=0; idx<elemCount; idx++ )
{
int elemIndex = fnComp.element( idx );
if (savePoints) {
pointCache->append(geomPtr->vertices[elemIndex]);
}
geomPtr->vertices[elemIndex] *= mat;
geomPtr->normals[idx] =
geomPtr->normals[idx].transformAsNormal( mat );
}
}
} else {
len = geomPtr->vertices.length();
if (savePoints) {
pointCache->setSizeIncrement(len);
}
for ( unsigned int idx = 0; idx < len; ++idx ) {
if (savePoints) {
pointCache->append(geomPtr->vertices[idx]);
}
geomPtr->vertices[idx] *= mat;
geomPtr->normals[idx] =
geomPtr->normals[idx].transformAsNormal( mat );
}
}
}
MDataBlock datablock = forceCache();
MDataHandle cachedHandle = datablock.outputValue( cachedSurface, &stat );
MCHECKERRORNORET( stat, "computeInputSurface error getting cachedSurface")
apiMeshData* cached = (apiMeshData*) cachedHandle.asPluginData();
MDataHandle dHandle = datablock.outputValue( mControlPoints, &stat );
MCHECKERRORNORET( stat, "transformUsing get dHandle" )
if ( hasHistory() && (NULL != cached) ) {
stat = buildControlPoints( datablock, geomPtr->vertices.length() );
MCHECKERRORNORET( stat, "transformUsing buildControlPoints" )
MArrayDataHandle cpHandle( dHandle, &stat );
MCHECKERRORNORET( stat, "transformUsing get cpHandle" )
for ( i=0; i<len; i++ )
{
MObject comp = componentList[i];
MFnSingleIndexedComponent fnComp( comp );
int elemCount = fnComp.elementCount();
for ( int idx=0; idx<elemCount; idx++ )
{
int elemIndex = fnComp.element( idx );
cpHandle.jumpToElement( elemIndex );
MDataHandle pntHandle = cpHandle.outputValue();
double3& pnt = pntHandle.asDouble3();
MPoint oldPnt = cached->fGeometry->vertices[elemIndex];
MPoint newPnt = geomPtr->vertices[elemIndex];
MPoint offset = newPnt - oldPnt;
pnt[0] += offset[0];
pnt[1] += offset[1];
pnt[2] += offset[2];
}
}
}
if ( NULL == cached ) {
cerr << "NULL cachedSurface data found\n";
}
else {
*(cached->fGeometry) = *geomPtr;
}
MPlug pCPs(thisMObject(),mControlPoints);
pCPs.setValue(dHandle);
computeBoundingBox( datablock );
childChanged( MPxSurfaceShape::kBoundingBoxChanged );
}
void
apiMesh::tweakUsing( const MMatrix & mat,
const MObjectArray & componentList,
MVertexCachingMode cachingMode,
MPointArray* pointCache,
MArrayDataHandle& handle )
{
apiMeshGeom* geomPtr = meshGeom();
bool savePoints = (cachingMode == MPxSurfaceShape::kSavePoints);
bool updatePoints = (cachingMode == MPxSurfaceShape::kUpdatePoints);
MArrayDataBuilder builder = handle.builder();
MPoint delta, currPt, newPt;
unsigned int i=0;
unsigned int len = componentList.length();
unsigned int cacheIndex = 0;
unsigned int cacheLen = (NULL != pointCache) ? pointCache->length() : 0;
if (cachingMode == MPxSurfaceShape::kRestorePoints) {
if (len > 0) {
for ( i=0; i<len; i++ )
{
MObject comp = componentList[i];
MFnSingleIndexedComponent fnComp( comp );
int elemCount = fnComp.elementCount();
for ( int idx=0; idx<elemCount && cacheIndex < cacheLen; idx++, cacheIndex++) {
int elemIndex = fnComp.element( idx );
double3 & pt = builder.addElement( elemIndex ).asDouble3();
MPoint& cachePt = (*pointCache)[cacheIndex];
pt[0] += cachePt.x;
pt[1] += cachePt.y;
pt[2] += cachePt.z;
}
}
} else {
len = geomPtr->vertices.length();
for ( unsigned int idx = 0; idx < len && idx < cacheLen; ++idx ) {
double3 & pt = builder.addElement( idx ).asDouble3();
MPoint& cachePt = (*pointCache)[cacheIndex];
pt[0] += cachePt.x;
pt[1] += cachePt.y;
pt[2] += cachePt.z;
}
}
} else {
if (len > 0) {
for ( i=0; i<len; i++ )
{
MObject comp = componentList[i];
MFnSingleIndexedComponent fnComp( comp );
int elemCount = fnComp.elementCount();
if (savePoints) {
pointCache->setSizeIncrement(elemCount);
}
for ( int idx=0; idx<elemCount; idx++ )
{
int elemIndex = fnComp.element( idx );
double3 & pt = builder.addElement( elemIndex ).asDouble3();
currPt = newPt = geomPtr->vertices[elemIndex];
newPt *= mat;
delta.x = newPt.x - currPt.x;
delta.y = newPt.y - currPt.y;
delta.z = newPt.z - currPt.z;
pt[0] += delta.x;
pt[1] += delta.y;
pt[2] += delta.z;
if (savePoints) {
pointCache->append(delta*(-1.0));
} else if (updatePoints && cacheIndex < cacheLen) {
MPoint& cachePt = (*pointCache)[cacheIndex];
cachePt[0] -= delta.x;
cachePt[1] -= delta.y;
cachePt[2] -= delta.z;
cacheIndex++;
}
}
}
} else {
len = geomPtr->vertices.length();
if (savePoints) {
pointCache->setSizeIncrement(len);
}
for ( unsigned int idx = 0; idx < len; ++idx ) {
double3 & pt = builder.addElement( idx ).asDouble3();
currPt = newPt = geomPtr->vertices[idx];
newPt *= mat;
delta.x = newPt.x - currPt.x;
delta.y = newPt.y - currPt.y;
delta.z = newPt.z - currPt.z;
pt[0] += delta.x;
pt[1] += delta.y;
pt[2] += delta.z;
if (savePoints) {
pointCache->append(delta*-1.0);
} else if (updatePoints && idx < cacheLen) {
MPoint& cachePt = (*pointCache)[idx];
cachePt[0] -= delta.x;
cachePt[1] -= delta.y;
cachePt[2] -= delta.z;
}
}
}
}
handle.set(builder);
childChanged( MPxSurfaceShape::kBoundingBoxChanged );
}
bool apiMesh::vertexOffsetDirection( MObject & component,
MVectorArray & direction,
MVertexOffsetMode mode,
bool normalize )
{
MStatus stat;
bool offsetOkay = false ;
MFnSingleIndexedComponent fnComp( component, &stat );
if ( !stat || (component.apiType() != MFn::kMeshVertComponent) ) {
return false;
}
offsetOkay = true ;
apiMeshGeom * geomPtr = meshGeom();
if ( NULL == geomPtr ) {
return false;
}
int count = fnComp.elementCount();
for ( int idx=0; idx<count; idx++ )
{
MVector normal = geomPtr->normals[ fnComp.element(idx) ];
if( mode == MPxSurfaceShape::kNormal ) {
if( normalize ) normal.normalize() ;
direction.append( normal );
}
else {
MVector uAxis, vAxis ;
int i, j, k;
double a;
normal.normalize();
i = 0; a = fabs( normal[0] );
if ( a < fabs(normal[1]) ) { i = 1; a = fabs(normal[1]); }
if ( a < fabs(normal[2]) ) i = 2;
j = (i+1)%3; k = (j+1)%3;
a = sqrt(normal[i]*normal[i] + normal[j]*normal[j]);
uAxis[i] = -normal[j]/a; uAxis[j] = normal[i]/a; uAxis[k] = 0.0;
vAxis = normal^uAxis;
if ( mode == MPxSurfaceShape::kUTangent ||
mode == MPxSurfaceShape::kUVNTriad )
{
if( normalize ) uAxis.normalize() ;
direction.append( uAxis );
}
if ( mode == MPxSurfaceShape::kVTangent ||
mode == MPxSurfaceShape::kUVNTriad )
{
if( normalize ) vAxis.normalize() ;
direction.append( vAxis );
}
if ( mode == MPxSurfaceShape::kUVNTriad ) {
if( normalize ) normal.normalize() ;
direction.append( normal );
}
}
}
return offsetOkay ;
}
bool apiMesh::isBounded() const
{
return true;
}
MBoundingBox apiMesh::boundingBox() const
{
MObject thisNode = thisMObject();
MPlug c1Plug( thisNode, bboxCorner1 );
MPlug c2Plug( thisNode, bboxCorner2 );
MObject corner1Object;
MObject corner2Object;
c1Plug.getValue( corner1Object );
c2Plug.getValue( corner2Object );
double3 corner1, corner2;
MFnNumericData fnData;
fnData.setObject( corner1Object );
fnData.getData( corner1[0], corner1[1], corner1[2] );
fnData.setObject( corner2Object );
fnData.getData( corner2[0], corner2[1], corner2[2] );
MPoint corner1Point( corner1[0], corner1[1], corner1[2] );
MPoint corner2Point( corner2[0], corner2[1], corner2[2] );
return MBoundingBox( corner1Point, corner2Point );
}
MPxGeometryIterator* apiMesh::geometryIteratorSetup(MObjectArray& componentList,
MObject& components,
bool forReadOnly )
{
apiMeshGeomIterator * result = NULL;
if ( components.isNull() ) {
result = new apiMeshGeomIterator( meshGeom(), componentList );
}
else {
result = new apiMeshGeomIterator( meshGeom(), components );
}
return result;
}
bool apiMesh::acceptsGeometryIterator( bool writeable )
{
return true;
}
bool apiMesh::acceptsGeometryIterator( MObject&, bool writeable,
bool forReadOnly )
{
return true;
}
bool apiMesh::hasHistory()
{
return fHasHistoryOnCreate;
}
MStatus apiMesh::computeBoundingBox( MDataBlock& datablock )
{
MStatus stat = MS::kSuccess;
MDataHandle lowerHandle = datablock.outputValue( bboxCorner1 );
MDataHandle upperHandle = datablock.outputValue( bboxCorner2 );
double3 &lower = lowerHandle.asDouble3();
double3 &upper = upperHandle.asDouble3();
apiMeshGeom* geomPtr = meshGeom();
int cnt = geomPtr->vertices.length();
if ( cnt == 0 ) return stat;
MPoint tmppnt = geomPtr->vertices[0];
lower[0] = tmppnt[0]; lower[1] = tmppnt[1]; lower[2] = tmppnt[2];
upper[0] = tmppnt[0]; upper[1] = tmppnt[1]; upper[2] = tmppnt[2];
for ( int i=0; i<cnt; i++ )
{
MPoint pnt = geomPtr->vertices[i];
if ( pnt[0] < lower[0] ) lower[0] = pnt[0];
if ( pnt[1] < lower[1] ) lower[1] = pnt[1];
if ( pnt[2] > lower[2] ) lower[2] = pnt[2];
if ( pnt[0] > upper[0] ) upper[0] = pnt[0];
if ( pnt[1] > upper[1] ) upper[1] = pnt[1];
if ( pnt[2] < upper[2] ) upper[2] = pnt[2];
}
lowerHandle.setClean();
upperHandle.setClean();
childChanged( MPxSurfaceShape::kBoundingBoxChanged );
return stat;
}
MStatus apiMesh::computeInputSurface( const MPlug& plug, MDataBlock& datablock )
{
MStatus stat = MS::kSuccess;
if ( hasHistory() ) {
MDataHandle inputHandle = datablock.inputValue( inputSurface, &stat );
MCHECKERROR( stat, "computeInputSurface error getting inputSurface")
apiMeshData* surf = (apiMeshData*) inputHandle.asPluginData();
if ( NULL == surf ) {
cerr << "NULL inputSurface data found\n";
return stat;
}
apiMeshGeom* geomPtr = surf->fGeometry;
MFnPluginData fnDataCreator;
MTypeId tmpid( apiMeshData::id );
fnDataCreator.create( tmpid, &stat );
MCHECKERROR( stat, "compute : error creating Cached apiMeshData")
apiMeshData * newCachedData = (apiMeshData*)fnDataCreator.data( &stat );
MCHECKERROR( stat, " error gettin proxy cached apiMeshData object")
*(newCachedData->fGeometry) = *geomPtr;
MDataHandle cachedHandle = datablock.outputValue( cachedSurface,&stat );
MCHECKERROR( stat, "computeInputSurface error getting cachedSurface")
cachedHandle.set( newCachedData );
}
return stat;
}
MStatus apiMesh::computeOutputSurface( const MPlug& plug,
MDataBlock& datablock )
{
MStatus stat;
if ( ! computeInputSurface( plug, datablock ) ) {
return MS::kFailure;
}
MDataHandle cachedHandle = datablock.outputValue( cachedSurface, &stat );
MCHECKERROR( stat, "computeInputSurface error getting cachedSurface")
apiMeshData* cached = (apiMeshData*) cachedHandle.asPluginData();
if ( NULL == cached ) {
cerr << "NULL cachedSurface data found\n";
}
datablock.setClean( plug );
if ( hasHistory() ) {
applyTweaks( datablock, cached->fGeometry );
}
else {
MArrayDataHandle cpHandle = datablock.inputArrayValue( mControlPoints,
&stat );
cpHandle.setAllClean();
}
MFnPluginData fnDataCreator;
MTypeId tmpid( apiMeshData::id );
fnDataCreator.create( tmpid, &stat );
MCHECKERROR( stat, "compute : error creating apiMeshData")
apiMeshData * newData = (apiMeshData*)fnDataCreator.data( &stat );
MCHECKERROR( stat, "compute : error gettin at proxy apiMeshData object")
if ( NULL != cached ) {
*(newData->fGeometry) = *(cached->fGeometry);
}
else {
cerr << "computeOutputSurface: NULL cachedSurface data\n";
}
MDataHandle outHandle = datablock.outputValue( outputSurface );
outHandle.set( newData );
stat = computeBoundingBox( datablock );
MCHECKERROR( stat, "computeBoundingBox" )
return stat;
}
MStatus apiMesh::computeWorldSurface( const MPlug& plug, MDataBlock& datablock )
{
MStatus stat;
computeOutputSurface( plug, datablock );
MDataHandle inHandle = datablock.outputValue( outputSurface );
apiMeshData* outSurf = (apiMeshData*)inHandle.asPluginData();
if ( NULL == outSurf ) {
cerr << "computeWorldSurface: outSurf NULL\n";
return MS::kFailure;
}
MFnPluginData fnDataCreator;
MTypeId tmpid( apiMeshData::id );
fnDataCreator.create( tmpid, &stat );
MCHECKERROR( stat, "compute : error creating apiMeshData")
apiMeshData * newData = (apiMeshData*)fnDataCreator.data( &stat );
MCHECKERROR( stat, "compute : error gettin at proxy apiMeshData object")
MMatrix worldMat = getWorldMatrix(datablock, 0);
newData->setMatrix( worldMat );
*(newData->fGeometry) = *(outSurf->fGeometry);
int arrayIndex = plug.logicalIndex( &stat );
MCHECKERROR( stat, "computWorldSurface : logicalIndex" );
MArrayDataHandle worldHandle = datablock.outputArrayValue( worldSurface,
&stat );
MCHECKERROR( stat, "computWorldSurface : outputArrayValue" );
MArrayDataBuilder builder = worldHandle.builder( &stat );
MCHECKERROR( stat, "computWorldSurface : builder" );
MDataHandle outHandle = builder.addElement( arrayIndex, &stat );
MCHECKERROR( stat, "computWorldSurface : addElement" );
outHandle.set( newData );
return stat;
}
MStatus apiMesh::applyTweaks( MDataBlock& datablock, apiMeshGeom* geomPtr )
{
MStatus stat;
MArrayDataHandle cpHandle = datablock.inputArrayValue( mControlPoints,
&stat );
MCHECKERROR( stat, "applyTweaks get cpHandle" )
int elemCount = cpHandle.elementCount();
for ( int idx=0; idx<elemCount; idx++ )
{
int elemIndex = cpHandle.elementIndex();
MDataHandle pntHandle = cpHandle.outputValue();
double3& pnt = pntHandle.asDouble3();
MPoint offset( pnt[0], pnt[1], pnt[2] );
MPoint& oldPnt = geomPtr->vertices[elemIndex];
oldPnt = oldPnt + offset;
cpHandle.next();
}
return stat;
}
bool apiMesh::value( int pntInd, int vlInd, double & val ) const
{
bool result = false;
apiMesh* nonConstThis = (apiMesh*)this;
apiMeshGeom* geomPtr = nonConstThis->cachedGeom();
if ( NULL != geomPtr ) {
MPoint point = geomPtr->vertices[ pntInd ];
val = point[ vlInd ];
result = true;
}
return result;
}
bool apiMesh::value( int pntInd, MPoint & val ) const
{
bool result = false;
apiMesh* nonConstThis = (apiMesh*)this;
apiMeshGeom* geomPtr = nonConstThis->cachedGeom();
if ( NULL != geomPtr ) {
MPoint point = geomPtr->vertices[ pntInd ];
val = point;
result = true;
}
return result;
}
bool apiMesh::setValue( int pntInd, int vlInd, double val )
{
bool result = false;
apiMesh* nonConstThis = (apiMesh*)this;
apiMeshGeom* geomPtr = nonConstThis->cachedGeom();
if ( NULL != geomPtr ) {
MPoint& point = geomPtr->vertices[ pntInd ];
point[ vlInd ] = val;
result = true;
}
verticesUpdated();
return result;
}
bool apiMesh::setValue( int pntInd, const MPoint & val )
{
bool result = false;
apiMesh* nonConstThis = (apiMesh*)this;
apiMeshGeom* geomPtr = nonConstThis->cachedGeom();
if ( NULL != geomPtr ) {
geomPtr->vertices[ pntInd ] = val;
result = true;
}
verticesUpdated();
return result;
}
MObject apiMesh::meshDataRef()
{
MDataBlock datablock = forceCache();
MDataHandle handle = datablock.inputValue( outputSurface );
return handle.data();
}
apiMeshGeom* apiMesh::meshGeom()
{
MStatus stat;
apiMeshGeom * result = NULL;
MObject tmpObj = meshDataRef();
MFnPluginData fnData( tmpObj );
apiMeshData * data = (apiMeshData*)fnData.data( &stat );
MCHECKERRORNORET( stat, "meshGeom : Failed to get apiMeshData");
if ( NULL != data ) {
result = data->fGeometry;
}
return result;
}
MObject apiMesh::cachedDataRef()
{
MDataBlock datablock = forceCache();
MDataHandle handle = datablock.outputValue( cachedSurface );
return handle.data();
}
apiMeshGeom* apiMesh::cachedGeom()
{
MStatus stat;
apiMeshGeom * result = NULL;
MObject tmpObj = cachedDataRef();
MFnPluginData fnData( tmpObj );
apiMeshData * data = (apiMeshData*)fnData.data( &stat );
MCHECKERRORNORET( stat, "cachedGeom : Failed to get apiMeshData");
if ( NULL != data ) {
result = data->fGeometry;
}
return result;
}
MStatus apiMesh::buildControlPoints( MDataBlock& datablock, int count )
{
MStatus stat;
MArrayDataHandle cpH = datablock.outputArrayValue( mControlPoints, &stat );
MCHECKERROR( stat, "compute get cpH" )
MArrayDataBuilder oldBuilder = cpH.builder();
if ( count != (int)oldBuilder.elementCount() )
{
MArrayDataBuilder builder( oldBuilder );
MCHECKERROR( stat, "compute - create builder" )
for ( int vtx=0; vtx<count; vtx++ )
{
builder.addElement( vtx ).asDouble3();
}
cpH.set( builder );
}
cpH.setAllClean();
return stat;
}
void apiMesh::verticesUpdated()
{
childChanged( MPxSurfaceShape::kBoundingBoxChanged );
childChanged( MPxSurfaceShape::kObjectChanged );
}
void* apiMesh::creator()
{
return new apiMesh();
}
MStatus apiMesh::initialize()
{
MStatus stat;
MFnTypedAttribute typedAttr;
inputSurface = typedAttr.create( "inputSurface", "is",
apiMeshData::id,
MObject::kNullObj, &stat );
MCHECKERROR( stat, "create inputSurface attribute" )
typedAttr.setStorable( false );
ADD_ATTRIBUTE( inputSurface );
MAKE_NUMERIC_ATTR( bboxCorner1, "bboxCorner1", "bb1",
MFnNumericData::k3Double, 0,
false, false, false );
MAKE_NUMERIC_ATTR( bboxCorner2, "bboxCorner2", "bb2",
MFnNumericData::k3Double, 0,
false, false, false );
outputSurface = typedAttr.create( "outputSurface", "os",
apiMeshData::id,
MObject::kNullObj, &stat );
MCHECKERROR( stat, "create outputSurface attribute" )
ADD_ATTRIBUTE( outputSurface );
typedAttr.setWritable( false );
worldSurface = typedAttr.create( "worldSurface", "ws",
apiMeshData::id,
MObject::kNullObj, &stat );
MCHECKERROR( stat, "create worldSurface attribute" );
typedAttr.setCached( false );
typedAttr.setWritable( false );
stat = typedAttr.setArray( true );
MCHECKERROR( stat, "set array" );
stat = typedAttr.setUsesArrayDataBuilder( true );
MCHECKERROR( stat, "set uses array data builder" );
stat = typedAttr.setDisconnectBehavior( MFnAttribute::kDelete );
MCHECKERROR( stat, "set disconnect behavior data builder" );
stat = typedAttr.setWorldSpace( true );
MCHECKERROR( stat, "set world space" );
ADD_ATTRIBUTE( worldSurface );
cachedSurface = typedAttr.create( "cachedSurface", "cs",
apiMeshData::id,
MObject::kNullObj, &stat );
MCHECKERROR( stat, "create cachedSurface attribute" )
typedAttr.setReadable( true );
typedAttr.setWritable( true );
typedAttr.setStorable( true );
ADD_ATTRIBUTE( cachedSurface );
ATTRIBUTE_AFFECTS( inputSurface, outputSurface );
ATTRIBUTE_AFFECTS( inputSurface, worldSurface );
ATTRIBUTE_AFFECTS( outputSurface, worldSurface );
ATTRIBUTE_AFFECTS( inputSurface, bboxCorner1 );
ATTRIBUTE_AFFECTS( inputSurface, bboxCorner2 );
ATTRIBUTE_AFFECTS( cachedSurface, outputSurface );
ATTRIBUTE_AFFECTS( cachedSurface, worldSurface );
ATTRIBUTE_AFFECTS( mControlPoints, outputSurface );
ATTRIBUTE_AFFECTS( mControlValueX, outputSurface );
ATTRIBUTE_AFFECTS( mControlValueY, outputSurface );
ATTRIBUTE_AFFECTS( mControlValueZ, outputSurface );
ATTRIBUTE_AFFECTS( mControlPoints, cachedSurface );
ATTRIBUTE_AFFECTS( mControlValueX, cachedSurface );
ATTRIBUTE_AFFECTS( mControlValueY, cachedSurface );
ATTRIBUTE_AFFECTS( mControlValueZ, cachedSurface );
ATTRIBUTE_AFFECTS( mControlPoints, worldSurface );
ATTRIBUTE_AFFECTS( mControlValueX, worldSurface );
ATTRIBUTE_AFFECTS( mControlValueY, worldSurface );
ATTRIBUTE_AFFECTS( mControlValueZ, worldSurface );
return MS::kSuccess;
}
MStatus initializePlugin( MObject obj )
{
MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any");
MStatus stat1, stat2, stat3;
stat1 = plugin.registerData( "apiMeshData", apiMeshData::id,
&apiMeshData::creator,
MPxData::kGeometryData );
if ( ! stat1 ) {
cerr << "Failed to register geometry data : apiMeshData \n";
return stat1;
}
stat2 = plugin.registerShape( "apiMesh", apiMesh::id,
&apiMesh::creator,
&apiMesh::initialize,
&apiMeshUI::creator );
if ( ! stat2 ) {
cerr << "Failed to register shape\n";
if ( stat1) plugin.deregisterData( apiMeshData::id );
return stat2;
}
stat3 = plugin.registerNode( "apiMeshCreator", apiMeshCreator::id,
&apiMeshCreator::creator,
&apiMeshCreator::initialize );
if ( ! stat3 ) {
cerr << "Failed to register creator\n";
if ( stat2 ) {
plugin.deregisterNode( apiMesh::id );
plugin.deregisterData( apiMeshData::id );
}
}
return stat3;
}
MStatus uninitializePlugin( MObject obj)
{
MFnPlugin plugin( obj );
MStatus stat;
stat = plugin.deregisterNode( apiMesh::id );
if ( ! stat ) {
cerr << "Failed to deregister shape : apiMeshShape \n";
}
stat = plugin.deregisterData( apiMeshData::id );
if ( ! stat ) {
cerr << "Failed to deregister geometry data : apiMeshData \n";
}
stat = plugin.deregisterNode( apiMeshCreator::id );
if ( ! stat ) {
cerr << "Failed to deregister node : apiMeshCreator \n";
}
return stat;
}