#include <maya/MIOStream.h>
#include <math.h>
#include <stdlib.h>
#include <simpleEmitter.h>
#include <maya/MVectorArray.h>
#include <maya/MDoubleArray.h>
#include <maya/MIntArray.h>
#include <maya/MMatrix.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MFnUnitAttribute.h>
#include <maya/MFnVectorArrayData.h>
#include <maya/MFnDoubleArrayData.h>
#include <maya/MFnArrayAttrsData.h>
#include <maya/MFnMatrixData.h>
MTypeId simpleEmitter::id( 0x80014 );
simpleEmitter::simpleEmitter()
: lastWorldPoint(0, 0, 0, 1)
{
}
simpleEmitter::~simpleEmitter()
{
}
void *simpleEmitter::creator()
{
return new simpleEmitter;
}
MStatus simpleEmitter::initialize()
{
return( MS::kSuccess );
}
MStatus simpleEmitter::compute(const MPlug& plug, MDataBlock& block)
{
MStatus status;
if( !(plug == mOutput) )
return( MS::kUnknownParameter );
int multiIndex = plug.logicalIndex( &status );
McheckErr(status, "ERROR in plug.logicalIndex.\n");
MArrayDataHandle hOutArray = block.outputArrayValue( mOutput, &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");
MFnArrayAttrsData fnOutput;
MObject dOutput = fnOutput.create ( &status );
McheckErr(status, "ERROR in fnOutput.create.\n");
bool beenFull = isFullValue( multiIndex, block );
if( beenFull )
{
return( MS::kSuccess );
}
MVectorArray inPosAry;
inPosAry.clear();
MPoint worldPos(0.0, 0.0, 0.0);
status = getWorldPosition( worldPos );
MVector worldV;
worldV[0] = worldPos[0];
worldV[1] = worldPos[1];
worldV[2] = worldPos[2];
inPosAry.append( worldV );
MVectorArray inVelAry;
inVelAry.clear();
MVector velocity(0,0,0);
inVelAry.append( velocity );
MTime cT = currentTimeValue( block );
MTime sT = startTimeValue( multiIndex, block );
MTime dT = deltaTimeValue( multiIndex, block );
if( (cT <= sT) || (dT <= 0.0) )
{
hOut.set( dOutput );
block.setClean( plug );
return( MS::kSuccess );
}
MIntArray emitCountPP;
emitCountPP.clear();
int plugIndex = plug.logicalIndex( &status );
double rate = rateValue( block );
MTime dtRate = deltaTimeValue( plugIndex, block );
double dblCount = rate * dtRate.as( MTime::kSeconds );
int intCount = (int)dblCount;
emitCountPP.append( intCount );
double speed = speedValue( block );
MVector dirV = directionVector( block );
double inheritFactor = inheritFactorValue( multiIndex, block );
MVectorArray fnOutPos = fnOutput.vectorArray("position", &status);
MVectorArray fnOutVel = fnOutput.vectorArray("velocity", &status);
MDoubleArray fnOutTime = fnOutput.doubleArray("timeInStep", &status);
double dt = dT.as( MTime::kSeconds );
MVector rotatedV = useRotation ( dirV );
emit( inPosAry, inVelAry, emitCountPP,
dt, speed, inheritFactor, rotatedV, fnOutPos, fnOutVel, fnOutTime );
hOut.set( dOutput );
block.setClean( plug );
return( MS::kSuccess );
}
void simpleEmitter::emit
(
const MVectorArray &inPosAry,
const MVectorArray &inVelAry,
const MIntArray &emitCountPP,
double dt,
double speed,
double inheritFactor,
MVector dirV,
MVectorArray &outPosAry,
MVectorArray &outVelAry,
MDoubleArray &outTimeAry
)
{
int posLength = inPosAry.length();
int velLength = inVelAry.length();
int countLength = emitCountPP.length();
if( (posLength != velLength) || (posLength != countLength) )
return;
int index;
int totalCount = 0;
for( index = 0; index < countLength; index ++ )
totalCount += emitCountPP[index];
if( totalCount <= 0 )
return;
dirV.normalize();
int emitCount;
MVector newPos, newVel;
MVector prePos, sPos, sVel;
for( index = 0; index < posLength; index++ )
{
emitCount = emitCountPP[index];
if( emitCount <= 0 )
continue;
sPos = inPosAry[index];
sVel = inVelAry[index];
prePos = sPos - sVel * dt;
for( int i = 0; i < emitCount; i++ )
{
double alpha = ( (double)i + drand48() ) / (double)emitCount;
newPos = (1 - alpha) * prePos + alpha * sPos;
newVel = dirV * speed;
newPos += newVel * ( dt * (1 - alpha) );
newVel += sVel * inheritFactor;
outPosAry.append( newPos );
outVelAry.append( newVel );
outTimeAry.append( alpha );
}
}
}
MStatus simpleEmitter::getWorldPosition( MPoint &point )
{
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("simpleEmitter::getWorldPosition: get matrixObject");
return( status );
}
MFnMatrixData worldMatrixData( matrixObject, &status );
if( !status )
{
status.perror("simpleEmitter::getWorldPosition: get worldMatrixData");
return( status );
}
MMatrix worldMatrix = worldMatrixData.matrix( &status );
if( !status )
{
status.perror("simpleEmitter::getWorldPosition: get worldMatrix");
return( status );
}
point[0] = worldMatrix( 3, 0 );
point[1] = worldMatrix( 3, 1 );
point[2] = worldMatrix( 3, 2 );
return( status );
}
MStatus simpleEmitter::getWorldPosition( MDataBlock& block, MPoint &point )
{
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();
point[0] = wMatrix(3, 0);
point[1] = wMatrix(3, 1);
point[2] = wMatrix(3, 2);
}
return( status );
}
MVector simpleEmitter::useRotation ( MVector &direction )
{
MStatus status;
MVector rotatedVector;
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("simpleEmitter::getWorldPosition: get matrixObject");
return ( direction );
}
MFnMatrixData worldMatrixData( matrixObject, &status );
if( !status )
{
status.perror("simpleEmitter::getWorldPosition: get worldMatrixData");
return( direction );
}
MMatrix worldMatrix = worldMatrixData.matrix( &status );
if( !status )
{
status.perror("simpleEmitter::getWorldPosition: get worldMatrix");
return( direction );
}
rotatedVector = direction * worldMatrix;
return( rotatedVector );
}
#define TORUS_PI 3.14159265
#define TORUS_2PI 2*TORUS_PI
#define EDGES 30
#define SEGMENTS 20
void simpleEmitter::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( "simpleEmitter", simpleEmitter::id,
&simpleEmitter::creator, &simpleEmitter::initialize,
MPxNode::kEmitterNode );
if (!status) {
status.perror("registerNode");
return status;
}
return status;
}
MStatus uninitializePlugin(MObject obj)
{
MStatus status;
MFnPlugin plugin(obj);
status = plugin.deregisterNode( simpleEmitter::id );
if (!status) {
status.perror("deregisterNode");
return status;
}
return status;
}