#include <maya/MIOStream.h>
#include <math.h>
#include <torusField.h>
#include <maya/MTime.h>
#include <maya/MVectorArray.h>
#include <maya/MDoubleArray.h>
#include <maya/MMatrix.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MFnTypedAttribute.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnCompoundAttribute.h>
#include <maya/MFnUnitAttribute.h>
#include <maya/MFnVectorArrayData.h>
#include <maya/MFnDoubleArrayData.h>
#include <maya/MFnMatrixData.h>
MObject torusField::aMinDistance;
MObject torusField::aAttractDistance;
MObject torusField::aRepelDistance;
MObject torusField::aDrag;
MObject torusField::aSwarmAmplitude;
MObject torusField::aSwarmFrequency;
MObject torusField::aSwarmPhase;
MTypeId torusField::id( 0x80018 );
void *torusField::creator()
{
return new torusField;
}
MStatus torusField::initialize()
{
MStatus status;
MFnNumericAttribute numAttr;
aMinDistance = numAttr.create("minDistance","mnd",MFnNumericData::kDouble);
numAttr.setDefault( 0.0 );
numAttr.setKeyable( true );
status = addAttribute( aMinDistance );
McheckErr(status, "ERROR adding aMinDistance attribute.\n");
aAttractDistance = numAttr.create("attractDistance","ad",
MFnNumericData::kDouble);
numAttr.setDefault( 20.0 );
numAttr.setKeyable( true );
status = addAttribute( aAttractDistance );
McheckErr(status, "ERROR adding aAttractDistance attribute.\n");
aRepelDistance = numAttr.create("repelDistance","rd",
MFnNumericData::kDouble);
numAttr.setDefault( 10.0 );
numAttr.setKeyable( true );
status = addAttribute( aRepelDistance );
McheckErr(status, "ERROR adding aRepelDistance attribute.\n");
aDrag = numAttr.create("drag", "d", MFnNumericData::kDouble);
numAttr.setDefault( 0.0 );
numAttr.setKeyable( true );
status = addAttribute( aDrag );
McheckErr(status, "ERROR adding aDrag attribute.\n");
aSwarmAmplitude = numAttr.create("swarmAmplitude", "samp",
MFnNumericData::kDouble);
numAttr.setDefault( 0.0 );
numAttr.setKeyable( true );
status = addAttribute( aSwarmAmplitude );
McheckErr(status, "ERROR adding aSwarmAmplitude attribute.\n");
aSwarmFrequency = numAttr.create("swarmFrequency", "sfrq",
MFnNumericData::kDouble);
numAttr.setDefault( 1.0 );
numAttr.setKeyable( true );
status = addAttribute( aSwarmFrequency );
McheckErr(status, "ERROR adding aSwarmFrequency attribute.\n");
aSwarmPhase = numAttr.create("swarmPhase", "sa", MFnNumericData::kDouble);
numAttr.setDefault( 0.0 );
numAttr.setKeyable( true );
status = addAttribute( aSwarmPhase );
McheckErr(status, "ERROR adding aSwarmPhase attribute.\n");
return( MS::kSuccess );
}
MStatus torusField::compute(const MPlug& plug, MDataBlock& block)
{
MStatus status;
if( !(plug == mOutputForce) )
return( MS::kUnknownParameter );
int multiIndex = plug.logicalIndex( &status );
McheckErr(status, "ERROR in plug.logicalIndex.\n");
MArrayDataHandle hInputArray = block.outputArrayValue( mInputData, &status );
McheckErr(status,"ERROR in hInputArray = block.outputArrayValue().\n");
status = hInputArray.jumpToElement( multiIndex );
McheckErr(status, "ERROR: hInputArray.jumpToElement failed.\n");
MDataHandle hCompond = hInputArray.inputValue( &status );
McheckErr(status, "ERROR in hCompond=hInputArray.inputValue\n");
MDataHandle hPosition = hCompond.child( mInputPositions );
MObject dPosition = hPosition.data();
MFnVectorArrayData fnPosition( dPosition );
MVectorArray points = fnPosition.array( &status );
McheckErr(status, "ERROR in fnPosition.array(), not find points.\n");
MDataHandle hVelocity = hCompond.child( mInputVelocities );
MObject dVelocity = hVelocity.data();
MFnVectorArrayData fnVelocity( dVelocity );
MVectorArray velocities = fnVelocity.array( &status );
McheckErr(status, "ERROR in fnVelocity.array(), not find velocities.\n");
MDataHandle hMass = hCompond.child( mInputMass );
MObject dMass = hMass.data();
MFnDoubleArrayData fnMass( dMass );
MDoubleArray masses = fnMass.array( &status );
McheckErr(status, "ERROR in fnMass.array(), not find masses.\n");
MVectorArray forceArray;
bool useMaxDistSet = useMaxDistanceValue( block );
if( useMaxDistSet )
{
applyMaxDist( block, points, velocities, masses, forceArray );
}
else
{
applyNoMaxDist( block, points, velocities, masses, forceArray );
}
MArrayDataHandle hOutArray = block.outputArrayValue( mOutputForce, &status);
McheckErr(status, "ERROR in hOutArray = block.outputArrayValue.\n");
MArrayDataBuilder bOutArray = hOutArray.builder( &status );
McheckErr(status, "ERROR in bOutArray = hOutArray.builder.\n");
MDataHandle hOut = bOutArray.addElement(multiIndex, &status);
McheckErr(status, "ERROR in hOut = bOutArray.addElement.\n");
MFnVectorArrayData fnOutputForce;
MObject dOutputForce = fnOutputForce.create( forceArray, &status );
McheckErr(status, "ERROR in dOutputForce = fnOutputForce.create\n");
hOut.set( dOutputForce );
block.setClean( plug );
return( MS::kSuccess );
}
void torusField::applyNoMaxDist
(
MDataBlock &block,
const MVectorArray &points,
const MVectorArray &velocities,
const MDoubleArray &,
MVectorArray &outputForce
)
{
if( points.length() != velocities.length() )
return;
outputForce.clear();
double magValue = magnitudeValue( block );
double minDist = minDistanceValue( block );
double attractDist = attractDistanceValue( block );
double repelDist = repelDistanceValue( block );
double dragMag = dragValue( block );
double swarmAmp = swarmAmplitudeValue( block );
MVectorArray posArray;
posArray.clear();
ownerPosition( block, posArray );
int fieldPosCount = posArray.length();
int receptorSize = points.length();
if (dragMag <= 0)
{
if (swarmAmp <= 0)
{
for (int ptIndex = 0; ptIndex < receptorSize; ptIndex ++ )
{
MVector forceV(0.0,0.0,0.0);
const MVector &receptorPoint = points[ptIndex];
for(int i = fieldPosCount; --i>=0; )
{
MVector difference = (receptorPoint-posArray[i]);
double distance = difference.length();
if (distance < minDist) continue;
if (distance <= repelDist)
forceV += difference * magValue;
else if (distance >= attractDist)
forceV += -difference * magValue;
}
outputForce.append( forceV );
}
}
else
{
for (int ptIndex = 0; ptIndex < receptorSize; ptIndex ++ )
{
MVector forceV(0.0,0.0,0.0);
const MVector &receptorPoint = points[ptIndex];
double distance = 0.0;
int i;
for(i = fieldPosCount; --i>=0; )
{
MVector difference = (receptorPoint-posArray[i]);
distance = difference.length();
if (distance < minDist) continue;
if (distance <= repelDist)
forceV += difference * magValue;
else if (distance >= attractDist)
forceV += -difference * magValue;
}
if ( distance >= repelDist && distance <= attractDist)
{
double frequency = swarmFrequencyValue( block );
MVector phase( 0.0, 0.0, swarmPhaseValue(block) );
for(i = fieldPosCount; --i >= 0;)
{
MVector difference = receptorPoint - posArray[i];
difference = (difference + phase) * frequency;
double *noiseEffect = &difference.x;
if( (noiseEffect[0] < -2147483647.0) ||
(noiseEffect[0] > 2147483647.0) ||
(noiseEffect[1] < -2147483647.0) ||
(noiseEffect[1] > 2147483647.0) ||
(noiseEffect[2] < -2147483647.0) ||
(noiseEffect[2] > 2147483647.0) )
continue;
double noiseOut[4];
noiseFunction( noiseEffect, noiseOut );
MVector swarmForce( noiseOut[0] * swarmAmp,
noiseOut[1] * swarmAmp,
noiseOut[2] * swarmAmp );
forceV += swarmForce;
}
}
outputForce.append( forceV );
}
}
}
else
{
if (swarmAmp <= 0)
{
for (int ptIndex = 0; ptIndex < receptorSize; ptIndex ++ )
{
const MVector& receptorPoint = points[ptIndex];
MVector forceV(0,0,0);
double distance = 0.0;
for(int i = fieldPosCount; --i>=0; )
{
MVector difference = (receptorPoint-posArray[i]);
distance = difference.length();
if (distance < minDist) continue;
if (distance <= repelDist)
forceV += difference * magValue;
else if (distance >= attractDist)
forceV += -difference * magValue;
}
if ( distance >= repelDist && distance <= attractDist)
{
if (fieldPosCount > 0)
{
MVector dragForceV;
dragForceV = velocities[ptIndex] *
(-dragMag) * fieldPosCount;
forceV += dragForceV;
}
}
outputForce.append( forceV );
}
}
else
{
for (int ptIndex = 0; ptIndex < receptorSize; ptIndex ++ )
{
const MVector &receptorPoint = points[ptIndex];
MVector forceV(0,0,0);
double distance = 0.0;
int i;
for(i = fieldPosCount; --i>=0; )
{
MVector difference = (receptorPoint-posArray[i]);
distance = difference.length();
if (distance < minDist) continue;
if (distance <= repelDist)
forceV += difference * magValue;
else if (distance >= attractDist)
forceV += -difference * magValue;
}
if ( distance >= repelDist && distance <= attractDist)
{
if (fieldPosCount > 0)
{
MVector dragForceV;
dragForceV = velocities[ptIndex] *
(-dragMag) * fieldPosCount;
forceV += dragForceV;
}
double frequency = swarmFrequencyValue( block );
MVector phase( 0.0, 0.0, swarmPhaseValue(block) );
for(i = fieldPosCount; --i>=0; )
{
MVector difference = receptorPoint - posArray[i];
difference = (difference + phase) * frequency;
double *noiseEffect = &difference.x;
if( (noiseEffect[0] < -2147483647.0) ||
(noiseEffect[0] > 2147483647.0) ||
(noiseEffect[1] < -2147483647.0) ||
(noiseEffect[1] > 2147483647.0) ||
(noiseEffect[2] < -2147483647.0) ||
(noiseEffect[2] > 2147483647.0) )
continue;
double noiseOut[4];
noiseFunction( noiseEffect, noiseOut );
MVector swarmForce( noiseOut[0] * swarmAmp,
noiseOut[1] * swarmAmp,
noiseOut[2] * swarmAmp );
forceV += swarmForce;
}
}
outputForce.append( forceV );
}
}
}
}
void torusField::applyMaxDist
(
MDataBlock& block,
const MVectorArray &points,
const MVectorArray &velocities,
const MDoubleArray &,
MVectorArray &outputForce
)
{
if( points.length() != velocities.length() )
return;
outputForce.clear();
double magValue = magnitudeValue( block );
double attenValue = attenuationValue( block );
double maxDist = maxDistanceValue( block );
double minDist = minDistanceValue( block );
double attractDist = attractDistanceValue( block );
double repelDist = repelDistanceValue( block );
double dragMag = dragValue( block );
double swarmAmp = swarmAmplitudeValue( block );
MVectorArray posArray;
posArray.clear();
ownerPosition( block, posArray );
int fieldPosCount = posArray.length();
int receptorSize = points.length();
if (attenValue > 0.0)
{
for (int ptIndex = 0; ptIndex < receptorSize; ptIndex ++ )
{
const MVector &receptorPoint = points[ptIndex];
MVector forceV(0,0,0);
MVector sumForceV(0,0,0);
for(int i = fieldPosCount; --i>=0; )
{
MVector difference = receptorPoint-posArray[i];
double distance = difference.length();
if (distance <= maxDist && distance >= minDist )
{
double force = magValue *
(pow((1.0-(distance/maxDist)),attenValue));
forceV = difference * force;
if ( distance >= repelDist && distance <= attractDist)
{
if (fieldPosCount > 0 && dragMag > 0)
{
MVector dragForceV;
dragForceV = velocities[ptIndex] *
(-dragMag) * fieldPosCount;
forceV += dragForceV;
}
if (swarmAmp > 0)
{
double frequency = swarmFrequencyValue( block );
MVector phase( 0.0, 0.0, swarmPhaseValue(block) );
difference = receptorPoint - posArray[i];
difference = (difference + phase) * frequency;
double *noiseEffect = &difference.x;
if( (noiseEffect[0] < -2147483647.0) ||
(noiseEffect[0] > 2147483647.0) ||
(noiseEffect[1] < -2147483647.0) ||
(noiseEffect[1] > 2147483647.0) ||
(noiseEffect[2] < -2147483647.0) ||
(noiseEffect[2] > 2147483647.0) )
continue;
double noiseOut[4];
noiseFunction( noiseEffect, noiseOut );
MVector swarmForce( noiseOut[0] * swarmAmp,
noiseOut[1] * swarmAmp,
noiseOut[2] * swarmAmp );
forceV += swarmForce;
}
}
}
if (maxDist > 0.0) forceV *= falloffCurve(distance/maxDist);
sumForceV += forceV;
}
outputForce.append( sumForceV );
}
}
else
{
for (int ptIndex = 0; ptIndex < receptorSize; ptIndex ++ )
{
const MVector & receptorPoint = points[ptIndex];
MVector forceV(0,0,0);
MVector sumForceV(0,0,0);
int i;
for(i = fieldPosCount; --i>=0; )
{
MVector difference = (receptorPoint-posArray[i]);
double distance = difference.length();
if (distance < minDist || distance > maxDist) continue;
if (distance <= repelDist)
forceV = difference * magValue;
else if (distance >= attractDist)
forceV = -difference * magValue;
if ( distance >= repelDist && distance <= attractDist)
{
if (fieldPosCount > 0 && dragMag > 0)
{
MVector dragForceV;
dragForceV = velocities[ptIndex] *
(-dragMag) * fieldPosCount;
forceV += dragForceV;
}
if (swarmAmp > 0)
{
double frequency = swarmFrequencyValue( block );
MVector phase( 0.0, 0.0, swarmPhaseValue(block) );
for(i = fieldPosCount; --i >= 0;)
{
difference = receptorPoint - posArray[i];
difference = (difference + phase) * frequency;
double *noiseEffect = &difference.x;
if( (noiseEffect[0] < -2147483647.0) ||
(noiseEffect[0] > 2147483647.0) ||
(noiseEffect[1] < -2147483647.0) ||
(noiseEffect[1] > 2147483647.0) ||
(noiseEffect[2] < -2147483647.0) ||
(noiseEffect[2] > 2147483647.0) )
continue;
double noiseOut[4];
noiseFunction( noiseEffect, noiseOut );
MVector swarmForce( noiseOut[0] * swarmAmp,
noiseOut[1] * swarmAmp,
noiseOut[2] * swarmAmp );
forceV += swarmForce;
}
}
}
if (maxDist > 0.0) forceV *= falloffCurve(distance/maxDist);
sumForceV += forceV;
}
outputForce.append( sumForceV );
}
}
}
void torusField::ownerPosition
(
MDataBlock& block,
MVectorArray &ownerPosArray
)
{
MStatus status;
if( applyPerVertexValue(block) )
{
MDataHandle hOwnerPos = block.inputValue( mOwnerPosData, &status );
if( status == MS::kSuccess )
{
MObject dOwnerPos = hOwnerPos.data();
MFnVectorArrayData fnOwnerPos( dOwnerPos );
MVectorArray posArray = fnOwnerPos.array( &status );
if( status == MS::kSuccess )
{
for( unsigned int i = 0; i < posArray.length(); i ++ )
ownerPosArray.append( posArray[i] );
}
else
{
MVector worldPos(0.0, 0.0, 0.0);
status = getWorldPosition( worldPos );
ownerPosArray.append( worldPos );
}
}
else
{
MVector worldPos(0.0, 0.0, 0.0);
status = getWorldPosition( worldPos );
ownerPosArray.append( worldPos );
}
}
else
{
MVector centroidV(0.0, 0.0, 0.0);
status = ownerCentroidValue( block, centroidV );
if( status == MS::kSuccess )
{
ownerPosArray.append( centroidV );
}
else
{
MVector worldPos(0.0, 0.0, 0.0);
status = getWorldPosition( worldPos );
ownerPosArray.append( worldPos );
}
}
}
MStatus torusField::getWorldPosition( MVector &vector )
{
MStatus status;
MObject thisNode = thisMObject();
MFnDependencyNode fnThisNode( thisNode );
MObject worldMatrixAttr = fnThisNode.attribute( "worldMatrix" );
MPlug matrixPlug( thisNode, worldMatrixAttr );
matrixPlug = matrixPlug.elementByLogicalIndex( 0 );
MObject matrixObject;
status = matrixPlug.getValue( matrixObject );
if( !status )
{
status.perror("torusField::getWorldPosition: get matrixObject");
return( status );
}
MFnMatrixData worldMatrixData( matrixObject, &status );
if( !status )
{
status.perror("torusField::getWorldPosition: get worldMatrixData");
return( status );
}
MMatrix worldMatrix = worldMatrixData.matrix( &status );
if( !status )
{
status.perror("torusField::getWorldPosition: get worldMatrix");
return( status );
}
vector[0] = worldMatrix( 3, 0 );
vector[1] = worldMatrix( 3, 1 );
vector[2] = worldMatrix( 3, 2 );
return( status );
}
MStatus torusField::getWorldPosition( MDataBlock& block, MVector &vector )
{
MStatus status;
MObject thisNode = thisMObject();
MFnDependencyNode fnThisNode( thisNode );
MObject worldMatrixAttr = fnThisNode.attribute( "worldMatrix" );
MPlug matrixPlug( thisNode, worldMatrixAttr );
matrixPlug = matrixPlug.elementByLogicalIndex( 0 );
MDataHandle hWMatrix = block.inputValue( matrixPlug, &status );
McheckErr(status, "ERROR getting hWMatrix from dataBlock.\n");
if( status == MS::kSuccess )
{
MMatrix wMatrix = hWMatrix.asMatrix();
vector[0] = wMatrix(3, 0);
vector[1] = wMatrix(3, 1);
vector[2] = wMatrix(3, 2);
}
return( status );
}
MStatus torusField::getForceAtPoint(const MVectorArray& points,
const MVectorArray& velocities,
const MDoubleArray& masses,
MVectorArray& forceArray,
double )
{
MDataBlock block = forceCache();
bool useMaxDistSet = useMaxDistanceValue( block );
if( useMaxDistSet )
{
applyMaxDist( block, points, velocities, masses, forceArray );
}
else
{
applyNoMaxDist( block, points, velocities, masses, forceArray );
}
return MS::kSuccess;
}
MStatus torusField::iconSizeAndOrigin( GLuint& width,
GLuint& height,
GLuint& xbo,
GLuint& ybo )
{
width = 32;
height = 32;
xbo = 4;
ybo = 4;
return MS::kSuccess;
}
MStatus torusField::iconBitmap(GLubyte* bitmap)
{
bitmap[0] = 0x18;
bitmap[4] = 0x66;
bitmap[8] = 0xC3;
bitmap[12] = 0x81;
bitmap[16] = 0x81;
bitmap[20] = 0xC3;
bitmap[24] = 0x66;
bitmap[28] = 0x18;
return MS::kSuccess;
}
#define rand3a(x,y,z) frand(67*(x)+59*(y)+71*(z))
#define rand3b(x,y,z) frand(73*(x)+79*(y)+83*(z))
#define rand3c(x,y,z) frand(89*(x)+97*(y)+101*(z))
#define rand3d(x,y,z) frand(103*(x)+107*(y)+109*(z))
int xlim[3][2];
double xarg[3];
double frand( register int s )
{
s = s << 13^s;
return(1. - ((s*(s*s*15731+789221)+1376312589)&0x7fffffff)/1073741824.);
}
double hermite( double p0, double p1, double r0, double r1, double t )
{
register double t2, t3, _3t2, _2t3 ;
t2 = t * t;
t3 = t2 * t;
_3t2 = 3. * t2;
_2t3 = 2. * t3 ;
return(p0*(_2t3-_3t2+1) + p1*(-_2t3+_3t2) + r0*(t3-2.*t2+t) + r1*(t3-t2));
}
void interpolate( double f[4], register int i, register int n )
{
double f0[4], f1[4] ;
if( n == 0 )
{
f[0] = rand3a( xlim[0][i&1], xlim[1][i>>1&1], xlim[2][i>>2] );
f[1] = rand3b( xlim[0][i&1], xlim[1][i>>1&1], xlim[2][i>>2] );
f[2] = rand3c( xlim[0][i&1], xlim[1][i>>1&1], xlim[2][i>>2] );
f[3] = rand3d( xlim[0][i&1], xlim[1][i>>1&1], xlim[2][i>>2] );
return;
}
n--;
interpolate( f0, i, n );
interpolate( f1, i| 1<<n, n );
f[0] = (1. - xarg[n]) * f0[0] + xarg[n] * f1[0];
f[1] = (1. - xarg[n]) * f0[1] + xarg[n] * f1[1];
f[2] = (1. - xarg[n]) * f0[2] + xarg[n] * f1[2];
f[3] = hermite( f0[3], f1[3], f0[n], f1[n], xarg[n] );
}
void torusField::noiseFunction( double *inNoise, double *out )
{
xlim[0][0] = (int)floor( inNoise[0] );
xlim[0][1] = xlim[0][0] + 1;
xlim[1][0] = (int)floor( inNoise[1] );
xlim[1][1] = xlim[1][0] + 1;
xlim[2][0] = (int)floor( inNoise[2] );
xlim[2][1] = xlim[2][0] + 1;
xarg[0] = inNoise[0] - xlim[0][0];
xarg[1] = inNoise[1] - xlim[1][0];
xarg[2] = inNoise[2] - xlim[2][0];
interpolate( out, 0, 3 ) ;
}
#define TORUS_PI 3.14159265
#define TORUS_2PI 2*TORUS_PI
#define EDGES 30
#define SEGMENTS 20
void torusField::draw( M3dView& view, const MDagPath& path, M3dView::DisplayStyle style, M3dView:: DisplayStatus )
{
view.beginGL();
for (int j = 0; j < SEGMENTS; j++ )
{
glPushMatrix();
glRotatef( GLfloat(360 * j / SEGMENTS), 0.0, 1.0, 0.0 );
glTranslatef( 1.5, 0.0, 0.0 );
for (int i = 0; i < EDGES; i++ )
{
glBegin(GL_LINE_STRIP);
float p0 = float( TORUS_2PI * i / EDGES );
float p1 = float( TORUS_2PI * (i+1) / EDGES );
glVertex2f( cos(p0), sin(p0) );
glVertex2f( cos(p1), sin(p1) );
glEnd();
}
glPopMatrix();
}
view.endGL ();
}
MStatus initializePlugin(MObject obj)
{
MStatus status;
MFnPlugin plugin(obj, PLUGIN_COMPANY, "3.0", "Any");
status = plugin.registerNode( "torusField", torusField::id,
&torusField::creator, &torusField::initialize,
MPxNode::kFieldNode );
if (!status) {
status.perror("registerNode");
return status;
}
return status;
}
MStatus uninitializePlugin(MObject obj)
{
MStatus status;
MFnPlugin plugin(obj);
status = plugin.deregisterNode( torusField::id );
if (!status) {
status.perror("deregisterNode");
return status;
}
return status;
}