Pnt3f LineParticleSystemDrawer::getLineEndpoint(ParticleSystemUnrecPtr System,
                                                UInt32 Index) const
{
	Vec3f Direction;

	//Calculate Direction
	switch(getLineDirectionSource())
	{
	case DIRECTION_POSITION_CHANGE:
		Direction = System->getPositionChange(Index);
		break;
	case DIRECTION_VELOCITY_CHANGE:
		Direction = System->getVelocityChange(Index);
		break;
	case DIRECTION_VELOCITY:
		Direction = System->getVelocity(Index);
		break;
	case DIRECTION_ACCELERATION:
		Direction = System->getAcceleration(Index);
		break;
	case DIRECTION_STATIC:
		Direction = getLineDirection();
		break;
	case DIRECTION_NORMAL:
	default:
		Direction = System->getNormal(Index);
		break;
	}


	//Calculate Length
	Real32 LineLength;

	switch(getLineLengthSource())
	{
	case LENGTH_SIZE_X:
		LineLength = System->getSize(Index).x();
		break;
	case LENGTH_SIZE_Y:
		LineLength = System->getSize(Index).y();
		break;
	case LENGTH_SIZE_Z:
		LineLength = System->getSize(Index).z();
		break;
	case LENGTH_SPEED:
		LineLength = System->getVelocity(Index).length();
		break;
	case LENGTH_ACCELERATION:
		LineLength = System->getAcceleration(Index).length();
		break;
	case LENGTH_STATIC:
		default:
		LineLength = getLineLength();   ///could not find anything, line length field
		break;
		}
    LineLength *= getLineLengthScaling();
		
	return System->getPosition(Index)+(LineLength*Direction);

}
void LineParticleSystemDrawer::adjustVolume(ParticleSystemUnrecPtr System, Volume & volume)
{
    UInt32 NumParticles = System->getNumParticles();
    for(UInt32 i(0) ; i<NumParticles ; ++i)
    {
        volume.extendBy(System->getPosition(i));
        volume.extendBy(getLineEndpoint(System, i));
    }
}
Vec3f QuadParticleSystemDrawer::getQuadNormal(DrawEnv *pEnv, ParticleSystemUnrecPtr System, UInt32 Index)
{
	Vec3f Direction;
	
	switch(getNormalSource())
	{
	case NORMAL_POSITION_CHANGE:
		Direction = System->getPositionChange(Index);
			Direction.normalize();
		break;
	case NORMAL_VELOCITY_CHANGE:
		Direction = System->getVelocityChange(Index);
			Direction.normalize();
		break;
	case NORMAL_VELOCITY:
		Direction = System->getVelocity(Index);
			Direction.normalize();
		break;
	case NORMAL_ACCELERATION:
		Direction = System->getAcceleration(Index);
			Direction.normalize();
		break;
	case NORMAL_PARTICLE_NORMAL:
		Direction = System->getNormal(Index);
		break;
	case NORMAL_VIEW_POSITION:
		{
			//TODO: make this more efficient
            Matrix ModelView(pEnv->getCameraViewing()); 
			Pnt3f Position(ModelView[0][3],ModelView[1][3],ModelView[2][3]);
			Direction = Position - System->getPosition(Index);
			Direction.normalize();
		
		break;
		}
	case NORMAL_STATIC:
		Direction = getNormal();
			break;
	case NORMAL_VIEW_DIRECTION:
	default:
		{
            Matrix ModelView(pEnv->getCameraViewing()); 
            ModelView.mult(pEnv->getObjectToWorld());
			Direction.setValues(ModelView[0][2],ModelView[1][2],ModelView[2][2]);
		break;
		}
	}
	return Direction;
}
Action::ResultE QuadParticleSystemDrawer::draw(DrawEnv *pEnv, ParticleSystemUnrecPtr System, const MFUInt32& Sort)
{
    bool isSorted(Sort.size() > 0);
    UInt32 NumParticles;
    if(isSorted)
    {
        NumParticles = Sort.size();
    }
    else
    {
        NumParticles = System->getNumParticles();
    }
    Pnt3f P1,P2,P3,P4;
    UInt32 Index;

    //Calculate the CameraToObject basis
    Matrix WorldToObject(pEnv->getObjectToWorld()); 
    WorldToObject.invert();

    Matrix CameraToObject(pEnv->getCameraToWorld()); 
    CameraToObject.mult(WorldToObject);

    glBegin(GL_QUADS);
        for(UInt32 i(0); i<NumParticles;++i)
        {
            if(isSorted)
            {
                Index = Sort[i];
            }
            else
            {
                Index = i;
            }
            //Loop through all particles
            //Get The Normal of the Particle
            Vec3f Normal = getQuadNormal(pEnv, System, Index, CameraToObject);


            //Calculate the Binormal as the cross between Normal and Up
            Vec3f Binormal = getQuadUpDir(pEnv,  System, Index, CameraToObject).cross(Normal);

            //Get the Up Direction of the Particle
            Vec3f Up = Normal.cross(Binormal);

            //Determine Local Space of the Particle
            //This is where error occurs
            Pnt3f Position = System->getPosition(Index);

            //Determine the Width and Height of the quad
            Real32 Width = System->getSize(Index).x()*getQuadSizeScaling().x(),Height =System->getSize(Index).y()*getQuadSizeScaling().y();

            //Calculate Quads positions
            P1 = Position + (Width/2.0f)*Binormal + (Height/2.0f)*Up;
            P2 = Position + (Width/2.0f)*Binormal - (Height/2.0f)*Up;
            P3 = Position - (Width/2.0f)*Binormal - (Height/2.0f)*Up;
            P4 = Position - (Width/2.0f)*Binormal + (Height/2.0f)*Up;

            //Draw the Quad
            glNormal3fv(Normal.getValues());

            glColor4fv(System->getColor(Index).getValuesRGBA());
            glTexCoord2f(1.0, 1.0);
            glVertex3fv(P1.getValues());


            glTexCoord2f(0.0, 1.0);
            glVertex3fv(P4.getValues());


            glTexCoord2f(0.0, 0.0);
            glVertex3fv(P3.getValues());

            glTexCoord2f(1.0, 0.0);
            glVertex3fv(P2.getValues());
        }
        glColor4f(1.0f,1.0f,1.0f,1.0f);
    glEnd();

    //Generate a local space for the particle
    return Action::Continue;
}
Vec3f QuadParticleSystemDrawer::getQuadNormal(DrawEnv *pEnv,
                                              ParticleSystemUnrecPtr System,
                                              UInt32 Index,
                                              const Matrix& CameraToObject )
{
    Vec3f Direction;

    switch(getNormalSource())
    {
        case NORMAL_POSITION_CHANGE:
            Direction = System->getPositionChange(Index);
            Direction.normalize();
            break;
        case NORMAL_VELOCITY_CHANGE:
            Direction = System->getVelocityChange(Index);
            Direction.normalize();
            break;
        case NORMAL_VELOCITY:
            Direction = System->getVelocity(Index);
            Direction.normalize();
            break;
        case NORMAL_ACCELERATION:
            Direction = System->getAcceleration(Index);
            Direction.normalize();
            break;
        case NORMAL_PARTICLE_NORMAL:
            Direction = System->getNormal(Index);
            break;
        case NORMAL_VIEW_POSITION:
            {
                Direction = Pnt3f(CameraToObject[3][0],CameraToObject[3][1],CameraToObject[3][2]) - System->getPosition(Index);
                Direction.normalize();
                break;
            }
        case NORMAL_STATIC:
            Direction = getNormal();
            break;
        case NORMAL_VIEW_DIRECTION:
        default:
            {
                Direction.setValues(CameraToObject[2][0],CameraToObject[2][1],CameraToObject[2][2]);
                break;
            }
    }
    return Direction;
}
Action::ResultE LineParticleSystemDrawer::draw(DrawEnv *pEnv,
                                               ParticleSystemUnrecPtr System,
                                               const MFUInt32& Sort)
{
 	UInt32 NumParticles(System->getNumParticles());

	bool areEndpointsFadeSame(getEndPointFading().x() == getEndPointFading().y());
	Color4f Color;

	if(NumParticles != 0)
	{

		bool SeparateColors(System->getNumColors() > 1);
		bool SeparateSizes(System->getNumSizes() > 1);
		bool SeparateNormals(System->getNumNormals() > 1);

		glBegin(GL_LINES);
			//Colors
			if(!SeparateColors && areEndpointsFadeSame)
			{
				Color = System->getColor(0);
				glColor4f(Color.red(), Color.green(), Color.blue(), Color.alpha() * getEndPointFading().x());
			}
			//Sizes
			if(!SeparateSizes)
			{
				//glColor4fv(System->getColor(0).getValuesRGBA());
			}
			//Normals
			if(!SeparateNormals)
			{
				glNormal3fv(System->getNormal(0).getValues());
			}
			for(UInt32 i(0) ; i<NumParticles ; ++i)
			{
				//Start Color
				if(SeparateColors)
				{
					Color = System->getColor(i);
					glColor4f(Color.red(), Color.green(), Color.blue(), Color.alpha() * getEndPointFading().x());
				}
				else if(!SeparateColors && !areEndpointsFadeSame)
				{
					Color = System->getColor(0);
					glColor4f(Color.red(), Color.green(), Color.blue(), Color.alpha() * getEndPointFading().x());
				}
				//Sizes
				if(SeparateSizes)
				{
					//glColor4fv(System->getColor(i).getValuesRGBA());
				}
				//Normals
				if(SeparateNormals)
				{
					glNormal3fv(System->getNormal(i).getValues());
				}
				//Positions
				glVertex3fv(System->getPosition(i).getValues());
				
				//End Color
				if(SeparateColors && !areEndpointsFadeSame)
				{
					Color = System->getColor(i);
					glColor4f(Color.red(), Color.green(), Color.blue(), Color.alpha() * getEndPointFading().y());
				}
				else if(!SeparateColors && !areEndpointsFadeSame)
				{
					Color = System->getColor(0);
					glColor4f(Color.red(), Color.green(), Color.blue(), Color.alpha() * getEndPointFading().y());
				}
				glVertex3fv(getLineEndpoint(System, i).getValues());
			}
		glEnd();
	}

    return Action::Continue;
}