#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/MArrayDataBuilder.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::aAttractDistance;
 
MObject torusField::aRepelDistance;
 
MObject torusField::aSwarmAmplitude;
 
MObject torusField::aSwarmFrequency;
 
void *torusField::creator()
{
    return new torusField;
}
{
    
    
    status = addAttribute( aMinDistance );
    McheckErr(status, "ERROR adding aMinDistance attribute.\n");
    aAttractDistance = numAttr.
create(
"attractDistance",
"ad",
    status = addAttribute( aAttractDistance );
    McheckErr(status, "ERROR adding aAttractDistance attribute.\n");
    aRepelDistance = numAttr.
create(
"repelDistance",
"rd",
    status = addAttribute( aRepelDistance );
    McheckErr(status, "ERROR adding aRepelDistance attribute.\n");
    status = addAttribute( aDrag );
    McheckErr(status, "ERROR adding aDrag attribute.\n");
    aSwarmAmplitude = numAttr.
create(
"swarmAmplitude", 
"samp",
    status = addAttribute( aSwarmAmplitude );
    McheckErr(status, "ERROR adding aSwarmAmplitude attribute.\n");
    aSwarmFrequency = numAttr.
create(
"swarmFrequency", 
"sfrq",
    status = addAttribute( aSwarmFrequency );
    McheckErr(status, "ERROR adding aSwarmFrequency attribute.\n");
    status = addAttribute( aSwarmPhase );
    McheckErr(status, "ERROR adding aSwarmPhase attribute.\n");
    
    
    
    
    
    
    
    
    
    
}
{
    if( !(plug == mOutputForce) )
    
    
    McheckErr(status, "ERROR in plug.logicalIndex.\n");
    
    
    
    
    
    McheckErr(status,"ERROR in hInputArray = block.outputArrayValue().\n");
    McheckErr(status, "ERROR: hInputArray.jumpToElement failed.\n");
    
    
    McheckErr(status, "ERROR in hCompond=hInputArray.inputValue\n");
    McheckErr(status, "ERROR in fnPosition.array(), not find points.\n");
    McheckErr(status, "ERROR in fnVelocity.array(), not find velocities.\n");
    McheckErr(status, "ERROR in fnMass.array(), not find masses.\n");
    
    
    bool useMaxDistSet = useMaxDistanceValue( block );
    if( useMaxDistSet )
    {
        applyMaxDist( block, points, velocities, masses, forceArray );
    }
    else
    {
        applyNoMaxDist( block, points, velocities, masses, forceArray );
    }
    
    
    McheckErr(status, "ERROR in hOutArray = block.outputArrayValue.\n");
    McheckErr(status, "ERROR in bOutArray = hOutArray.builder.\n");
    
    
    McheckErr(status, "ERROR in hOut = bOutArray.addElement.\n");
    MObject dOutputForce = fnOutputForce.
create( forceArray, &status );
 
    McheckErr(status, "ERROR in dOutputForce = fnOutputForce.create\n");
    
    
    hOut.
set( dOutputForce );
}
void torusField::applyNoMaxDist
    (
    )
{
    
    
        return;
    
    
    
    
    double magValue = magnitudeValue( block );
    
    double minDist = minDistanceValue( block );
    double attractDist = attractDistanceValue( block );
    double repelDist = repelDistanceValue( block );
    double dragMag = dragValue( block );
    double swarmAmp = swarmAmplitudeValue( block );
    
    
    
    
    ownerPosition( block, posArray );
    int fieldPosCount = posArray.
length();
 
    int receptorSize = points.
length();
 
    
    
    
    
    if (dragMag <= 0)
    {
        if (swarmAmp <= 0)
        {
            
            
            for (int ptIndex = 0; ptIndex < receptorSize; ptIndex ++ )
            {
                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;
                }
            }
        }
        else
        {
            
            
            for (int ptIndex = 0; ptIndex < receptorSize; ptIndex ++ )
            {
                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;
                    }
                }
            }
        }
    }
    else
    {
        if (swarmAmp <= 0)
        {
            
            
            for (int ptIndex = 0; ptIndex < receptorSize; ptIndex ++ )
            {
                const MVector& receptorPoint = points[ptIndex];
 
                
                
                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)
                    {
                        dragForceV = velocities[ptIndex] *
                                                (-dragMag) * fieldPosCount;
                        forceV += dragForceV;
                    }
                }
            }
        }
        else
        {
            
            
            for (int ptIndex = 0; ptIndex < receptorSize; ptIndex ++ )
            {
                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)
                {
                    if (fieldPosCount > 0)
                    {
                        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;
                    }
                }
            }
        }
    }
}
void torusField::applyMaxDist
    (
    )
{
    
    
        return;
    
    
    
    
    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 );
    
    
    
    
    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];
 
            
            
            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)
                        {
                            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];
 
            
            
            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)
                    {
                        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
    (
    )
{
    if( applyPerVertexValue(block) )
    {
        {
            {
                
                
                for( 
unsigned int i = 0; i < posArray.
length(); i ++ )
 
                    ownerPosArray.
append( posArray[i] );
            }
            else
            {
                
                status = getWorldPosition( worldPos );
                ownerPosArray.
append( worldPos );
            }
        }
        else
        {
            
            
            
            
            status = getWorldPosition( worldPos );
            ownerPosArray.
append( worldPos );
        }
    }
    else
    {
        status = ownerCentroidValue( block, centroidV );
        {
            
            
            ownerPosArray.
append( centroidV );
        }
        else
        {
            
            
            
            status = getWorldPosition( worldPos );
            ownerPosArray.
append( worldPos );
        }
    }
}
{
    
    
    MObject worldMatrixAttr = fnThisNode.attribute( 
"worldMatrix" );
 
    
    
    
    MPlug matrixPlug( thisNode, worldMatrixAttr );
 
    matrixPlug = matrixPlug.elementByLogicalIndex( 0 );
    
    
    status = matrixPlug.getValue( matrixObject );
    if( !status )
    {
        status.
perror(
"torusField::getWorldPosition: get matrixObject");
        return( status );
    }
    if( !status )
    {
        status.
perror(
"torusField::getWorldPosition: get worldMatrixData");
        return( 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 );
}
{
    
    
    MObject worldMatrixAttr = fnThisNode.attribute( 
"worldMatrix" );
 
    
    
    
    MPlug matrixPlug( thisNode, worldMatrixAttr );
 
    matrixPlug = matrixPlug.elementByLogicalIndex( 0 );
    
    McheckErr(status, "ERROR getting hWMatrix from dataBlock.\n");
    {
        vector[0] = wMatrix(3, 0);
        vector[1] = wMatrix(3, 1);
        vector[2] = wMatrix(3, 2);
    }
    return( status );
}
                                  double    )
{
    bool useMaxDistSet = useMaxDistanceValue( block );
    if( useMaxDistSet )
    {
        applyMaxDist( block, points, velocities, masses, forceArray );
    }
    else
    {
        applyNoMaxDist( block, points, velocities, masses, forceArray );
    }
}
MStatus torusField::iconSizeAndOrigin(  GLuint& width,
 
                    GLuint& height,
                    GLuint& xbo,
                    GLuint& ybo   )
{
    width = 32;
    height = 32;
    xbo = 4;
    ybo = 4;
}
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;
}
#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
{
     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();
     }
}
{
    MFnPlugin plugin(obj, PLUGIN_COMPANY, 
"3.0", 
"Any");
 
    status = plugin.registerNode( "torusField", torusField::id,
                            &torusField::creator, &torusField::initialize,
    if (!status) {
        status.
perror(
"registerNode");
        return status;
    }
    return status;
}
{
    status = plugin.deregisterNode( torusField::id );
    if (!status) {
        status.
perror(
"deregisterNode");
        return status;
    }
    return status;
}