#include <maya/MIOStream.h>
#include <maya/MStatus.h>
#include <maya/MDagPath.h>
#include <maya/MFloatPointArray.h>
#include <maya/MObject.h>
#include <maya/MPlugArray.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MFnDagNode.h>
#include <maya/MFnMesh.h>
#include <maya/MHairSystem.h>
#include <maya/MFnPlugin.h>
#include <math.h> 
#define kPluginName     "hairCollisionSolver"
typedef struct {
    int             numVerts;   
    double          minx;       
    double          miny;       
    double          minz;       
    double          maxx;       
    double          maxy;       
    double          maxz;       
} COLLISION_OBJ ;
typedef struct {
    int             numObjs;    
    COLLISION_OBJ   *objs;      
} COLLISION_INFO ;
bool        preFrame(
                const double        curTime,
                void                **privateData )
{
    
    
    
    
    
    
    
    
    fprintf( stderr,
            "preFrame: calling hairSystem node=`%s', time=%g\n",
            fnHairSystem.name().asChar(), curTime );
            cols, logIdxs ), false );
    int nobj = cols.length();
    
    
    
    
    
    
    
    COLLISION_INFO *collisionInfo = (COLLISION_INFO *) malloc(
            sizeof( COLLISION_INFO ) );
    collisionInfo->objs = (COLLISION_OBJ *) malloc(
            nobj * sizeof( COLLISION_OBJ ) );
    collisionInfo->numObjs = nobj;
    
    
    
    
    
    
    
    
    
    
    
    
    *privateData = (void *) collisionInfo;
    
    
    
    int    obj;
    for ( obj = 0; obj < nobj; ++obj ) {
        
        
        
        
        
        status = fnDagNode.getPath( path );
            fprintf( stderr,
                    "%s:%d: collide was not passed a valid mesh shape\n",
                    __FILE__, __LINE__ );
            return( false );
        }
        
        
        
        
        
        
        double minx, miny, minz, maxx, maxy, maxz, x, y, z;
        minx = maxx = verts[0].x;
        miny = maxy = verts[0].y;
        minz = maxz = verts[0].z;
        int i;
        for ( i = 1; i < nv; ++i ) {
            x = verts[i].x;
            y = verts[i].y;
            z = verts[i].z;
            if ( x < minx ) {
                minx = x;
            }
            if ( y < miny ) {
                miny = y;
            }
            if ( z < minz ) {
                minz = z;
            }
            if ( x > maxx ) {
                maxx = x;
            }
            if ( y > maxy ) {
                maxy = y;
            }
            if ( z > maxz ) {
                maxz = z;
            }
        }
        
        
        
        collisionInfo->objs[obj].numVerts = nv;
        collisionInfo->objs[obj].minx = minx;
        collisionInfo->objs[obj].miny = miny;
        collisionInfo->objs[obj].minz = minz;
        collisionInfo->objs[obj].maxx = maxx;
        collisionInfo->objs[obj].maxy = maxy;
        collisionInfo->objs[obj].maxz = maxz;
        fprintf( stderr, "Inside preFrameInit, bbox=%g %g %g %g %g %g\n",
                minx,miny,minz,maxx,maxy,maxz);
    }
    return( true );
}
bool    belowCollisionPlane( 
const COLLISION_OBJ *co, 
const MVector &pnt )
 
{
    return(    pnt.
x > co->minx && pnt.
x < co->maxx
 
            && pnt.
z > co->minz && pnt.
z < co->maxz );
}
#define EPSILON 0.0001
bool    collide(
                const int           follicleIndex,
                const int           startIndex,
                const int           endIndex,
                const double        curTime,
                const double        friction,
                const void          *privateData )
{
    
    
    
    COLLISION_INFO *ci = (COLLISION_INFO *) privateData;
    if ( !ci ) {
        fprintf( stderr,"%s:%d: collide() privateData pointer is NULL\n",
                __FILE__, __LINE__ );
        return( false );
    }
    
    
    
    
    
    
    
    if ( ci->numObjs <= 0 || hairPositions.
length() <= 0 ) {
 
        return( true );
    }
    int     obj;
    for ( obj = 0; obj < ci->numObjs; ++obj ) {
        COLLISION_OBJ *co = &ci->objs[obj];
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        int     numSegments = hairPositions.
length() - 1;
 
        int     seg;
        for ( seg = 0; seg < numSegments; ++seg ) {
            
            
            
            
            
            
            
            
            
            MVector pStart = hairPositions[seg];
 
            MVector pEnd = hairPositions[seg + 1];
 
            MVector vStart = pStart - hairPositionsLast[seg];
 
            MVector vEnd = pEnd - hairPositionsLast[seg + 1];
 
            
            
            
            
            
            
            
            
            #define STEPS 4
            int     step;
            for ( step = 0; step < STEPS; ++step ) {
                
                
                
                
                
                double fracAlongSeg = step / ( (double) STEPS );
                v = vStart * ( 1.0 - fracAlongSeg ) + vEnd * fracAlongSeg;
                MVector p1 = pStart * ( 1.0 - fracAlongSeg )
 
                        + pEnd * fracAlongSeg;
                
                
                
                
                
                if (       (p0.x < co->minx && p1.x < co->minx)
                        || (p0.y < co->miny && p1.y < co->miny)
                        || (p0.z < co->minz && p1.z < co->minz)
                        || (p0.x > co->maxx && p1.x > co->maxx)
                        || (p0.y > co->maxy && p1.y > co->maxy)
                        || (p0.z > co->maxz && p1.z > co->maxz) ) {
                    continue;
                }
                
                
                
                
                
                
                
                
                
                
                
                MVector where(-100000,-100000,-100000); 
 
                double  fracTime;   
                if ( fabs( v.y ) < EPSILON      
                        && fabs( p1.y - co->maxy ) < EPSILON ) {    
                    
                    
                    
                    where = p1;
                    fracTime = 1.0;     
                } else {
                    fracTime = ( co->maxy -  p0.y ) / v.y;
                    if ( fracTime >= 0.0 && fracTime <= 1.0 ) {
                        
                        
                        
                        where = p0 + v * fracTime;
                    }
                }
                
                
                
                
                if ( seg >= startIndex && seg <= endIndex ) {
                    
                    
                    
                    
                    
                    
                    
                    bool segCollides = false;
                    
                    
                    
                    
                    
                    
                    if ( where.x >= co->minx && where.x <= co->maxx
                            && where.z >= co->minz && where.z <= co->maxz
                            && fracTime >= 0.0 && fracTime <= 0.0 ) {
                        
                        
                        
                        
                        MVector objVelAlongNormal = (objectVel * normal)
 
                                * normal;
                        MVector objVelAlongTangent = objectVel
 
                                - objVelAlongNormal;
                        MVector pntVelAlongTangent = v - ( v * normal )
 
                                * normal;
                        MVector reflectedPntVelAlongTangent
 
                                = pntVelAlongTangent * ( 1.0 - friction )
                                + objVelAlongTangent * friction;
                                + reflectedPntVelAlongTangent;
                        
                        
                        
                        
                        
                        
                        
                        
                        
                        if ( fracAlongSeg > 0.5 ) {
                            MVector deltaPos = -newVel * fracTime;
 
                            hairPositionsLast[seg + 1] += deltaPos;
                            hairPositions[seg + 1] = hairPositionsLast[seg]
                                    + newVel;
                        } else {
                            MVector deltaPos = newVel * fracTime;
 
                            hairPositionsLast[seg] += deltaPos;
                            hairPositions[seg] = hairPositionsLast[seg]
                                    + newVel;
                        }
                        segCollides = true;
                    }
                    
                    
                    
                    
                    
                    
                    
                    
                    bool inside = false;
                    if ( belowCollisionPlane( co, hairPositions[seg] ) ) {
                        hairPositions[seg].y = co->maxy + EPSILON;
                        hairPositionsLast[seg] = hairPositions[seg] - objectVel;
                        inside = true;
                    }
                    if ( belowCollisionPlane( co, hairPositions[seg+1] ) ) {
                        hairPositions[seg+1].y = co->maxy + EPSILON;
                        hairPositionsLast[seg+1] = hairPositions[seg+1] - objectVel;
                        inside = true;
                    }
                    
                    
                    if ( segCollides || inside ) {
                        goto nextSeg;
                    }
                }
            }
nextSeg:;
        }
    }
    
    
    
    
    
    
    return( true );
}
{
    MFnPlugin   plugin( obj, 
"Autodesk", 
"8.0", 
"Any" );
 
}
{
}