//////////////////////////////////////////////////////////////////////////////
//
// Asura_PS3_PFXRender.cpp
//
// Copyright (c) 2005 Rebellion. All rights reserved.
//
// Description:
//
//     Code to write particle render data to vertex buffer. To be compiled on
//     both PPU and SPU. 
//
//////////////////////////////////////////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

#include "Core/Asura.h"

// This file's header...
#include "SpecialFX/Asura_PS3_PFXRender.h"

#include "Core/Asura_Maths.h"
#include "SpecialFX/PFX/Asura_PFX_Classes.h"
#include "SpecialFX/PFX/Asura_PFX_Effect.h"
#include "SpecialFX/PFX/Asura_PFX_System.h"
#include "SpecialFX/PFX/Asura_PFX_Templates.h"


////////////////////////////////////////////////////////////////////////////////
// Function     : CalculateParticleColour
// Author       : Andy Tate
// Date         : 30-Jun-2005
//
// Description  : Calculates the expected colour of the specified particle.
//
// Parameters   : 
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

static void CalculateParticleColour (const Asura_PFX_Particle& xParticle,
                                     const Asura_PFX_Particle_Template& xTemplate,
                                     const Asura_RGBA& xLightColour,
                                     Asura_RGBA& xColour,
									 const Asura_Vector_3& xCameraPosition)
{
	// Start with the particle colour...
	xColour = xTemplate.m_xColour.GetValueAtTime_Discrete( xParticle.m_fAge );

    // Does the particle need to be lit?
    if (xTemplate.m_bUseLighting)
    {
        // Yes - scale the colour accordingly...
        xColour.m_fR    *= xLightColour.m_fR;
        xColour.m_fG    *= xLightColour.m_fG;
        xColour.m_fB    *= xLightColour.m_fB;
    }

    // Does the particle fade with proximity to the camera?
	if( xTemplate.m_bNearCameraFade || xTemplate.m_bFarCameraFade )
	{
        const float             fDist       = (xCameraPosition - xParticle.m_xPosition).Magnitude();

		float fNearFade	= Asura_Maths::Min( 1.0f, Asura_Maths::Max( 0.0f, ( fDist - xTemplate.m_fNearZeroDistance ) / ( xTemplate.m_fNearFadeDistance - xTemplate.m_fNearZeroDistance ) ) );
		float fFarFade	= Asura_Maths::Min( 1.0f, Asura_Maths::Max( 0.0f, ( fDist - xTemplate.m_fFarZeroDistance ) / ( xTemplate.m_fFarFadeDistance - xTemplate.m_fFarZeroDistance ) ) );
		xColour.m_fA    *= Asura_Maths::Min( fNearFade, fFarFade );
	}
}

/// End of function 'CalculateParticleColour'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : CalculateParticleSize
// Author       : Andy Tate
// Date         : 30-Jun-2005
//
// Description  : Calculates the size of the specified particle.
//
// Parameters   : 
//
// Return value : The size of the particle.
////////////////////////////////////////////////////////////////////////////////

static float CalculateParticleSize (float fEffectSizeScale,
									const Asura_PFX_Particle& xParticle,
									const Asura_PFX_Particle_Template& xTemplate)
{
	float	fSize	= xTemplate.m_xSize.GetValueAtTime_Discrete (xParticle.m_fAge);

	// Does the particle size alter?
	if (xTemplate.m_bUseSizeScale)
	{
		// Yes - apply the scale...
		fSize	*= fEffectSizeScale;
	}

	// Scale the particle using the size-variation...
	fSize	*= (1.0f - xParticle.m_fSeed * xTemplate.m_xSizeVariation.GetValueAtTime_Discrete(xParticle.m_fAge));

	// Return the size...
	return	(fSize);
}

/// End of function 'CalculateParticleSize'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : CalculateParticleAngle
// Author       : Andy Tate
// Date         : 30-Jun-2005
//
// Description  : Calculates the angle of rotation for the specified particle.
//
// Parameters   : 
//
// Return value : The angle this particle is rotated to.
////////////////////////////////////////////////////////////////////////////////

static float CalculateParticleAngle (const Asura_PFX_Particle& xParticle,
									 const Asura_PFX_Particle_Template& xTemplate,
									 bool bPaused)
{
	float	fTheta;

	// Does the particle have a rotation?
	if (xTemplate.m_bFixedRotation)
	{
		// Yes - and it's fixed - calculate the angle...
		fTheta	= Asura_Maths::DegToRad (xTemplate.m_fFixedRotation);

		if (xTemplate.m_uNumFixedRotations > 1)
		{
			int	iRotation	= Asura_Maths::FloatToInt_Chop (xParticle.m_fSeed * xTemplate.m_uNumFixedRotations);
			// Add the fixed-rotation...
			fTheta	+= (iRotation * Asura_Maths::Pi * 2.0f) / xTemplate.m_uNumFixedRotations;
		}
	}
	else if (xTemplate.m_b3DRotation || !xTemplate.m_bUseMotionBlur)
	{
		// We need a rotation - is it to be random?
		if (xTemplate.m_bUseRandomRotation)
		{
			// Yes - Get the random rotation...
			fTheta	= bPaused ? 0.0f : (Asura_Random::GetFloat() * Asura_Maths::Deg360);
		}
		else
		{
			// No - get the appropriate rotation...
			fTheta	= (xParticle.m_fSeed + xTemplate.m_xRotation.GetValueAtTime_Discrete(xParticle.m_fAge)) * Asura_Maths::Pi * 2.0f;
		}

        // Does the rotation need mirroring?
        if( xTemplate.m_bMirrorRotation )
        {
            // 50-50 chance of mirroring, based on seed. The seed value is
            // in the range [0,1] so...
            if( xParticle.m_fSeed < 0.5f )
            {
                fTheta = -fTheta;
            }
        }
	}
	else
	{
		// No rotation...
		fTheta	= 0.0f;
	}

	// Return the angle...
	return	(fTheta);
}
/// End of function 'CalculateParticleAngle'. ///

#if 0

static float CalculateParticleAngleFixedRotation(const Asura_PFX_Particle& xParticle,
												const Asura_PFX_Particle_Template& xTemplate)
{
	float	fTheta;

//	if (xTemplate.m_bFixedRotation)
	{
		// Yes - and it's fixed - calculate the angle...
		fTheta	= Asura_Maths::DegToRad (xTemplate.m_fFixedRotation);

		if (xTemplate.m_uNumFixedRotations > 1)
		{
			int	iRotation	= Asura_Maths::FloatToInt_Chop (xParticle.m_fSeed * xTemplate.m_uNumFixedRotations);
			// Add the fixed-rotation...
			fTheta	+= (iRotation * Asura_Maths::Pi * 2.0f) / xTemplate.m_uNumFixedRotations;
		}
	}

	// Return the angle...
	return	(fTheta);
}

static float CalculateParticleAngleNormalRotation(const Asura_PFX_Particle& xParticle,
												const Asura_PFX_Particle_Template& xTemplate)
{
	return (xParticle.m_fSeed + xTemplate.m_xRotation.GetValueAtTime_Discrete(xParticle.m_fAge)) * Asura_Maths::Pi * 2.0f;
}

static float CalculateParticleAngleRandomRotation(const Asura_PFX_Particle& xParticle,
												const Asura_PFX_Particle_Template& xTemplate)
{
	return Asura_Random::GetFloat() * Asura_Maths::Pi * 2.0f;
}

static float CalculateParticleAngleNormalRotationMirrored(const Asura_PFX_Particle& xParticle,
												const Asura_PFX_Particle_Template& xTemplate)
{
	float fTheta = CalculateParticleAngleNormalRotation(xParticle, xTemplate);
	const int*	piRandom	= reinterpret_cast<const int*>(&xParticle.m_fSeed);
#error can't do this! it's aliasing the data and also the masking below is wrong since we're big endian
	// Yes - but is it time?
	float afTheta[2] = { fTheta, -fTheta };
	fTheta = afTheta[*piRandom & 1];
	return fTheta;
}

static float CalculateParticleAngleRandomRotationMirrored(const Asura_PFX_Particle& xParticle,
												const Asura_PFX_Particle_Template& xTemplate)
{
	float fTheta = Asura_Random::GetFloat() * Asura_Maths::Pi * 2.0f;
	const int*	piRandom	= reinterpret_cast<const int*>(&xParticle.m_fSeed);
#error can't do this! it's aliasing the data and also the masking below is wrong since we're big endian
	// Yes - but is it time?
	float afTheta[2] = { fTheta, -fTheta };
	fTheta = afTheta[*piRandom & 1];
	return fTheta;
}

#endif


////////////////////////////////////////////////////////////////////////////////
// Function     : CalculateParticleDimensions
// Author       : Andy Tate
// Date         : 30-Jun-2005
//
// Description  : Calculates the dimensions of the specified particle.
//
// Parameters   : 
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

static void CalculateParticleDimensions (const Asura_Matrix_3x3* pxEffectOrientation,
										 const Asura_PFX_Particle& xParticle,
										 const Asura_PFX_Particle_Template& xTemplate,
										 const float fSize,
										 const float fTheta,
										 const Asura_Vector_3& xCameraDeltaX,
										 const Asura_Vector_3& xCameraDeltaY,
										 Asura_Vector_3& xDeltaX,
										 Asura_Vector_3& xDeltaY)
{
    // Calculate the dimensions of the particle...
    if (xTemplate.m_b3DRotation)
    {
        const Asura_Euler_3 xEuler (fTheta, fTheta, 0.0f);
        Asura_Matrix_3x3    xMatrix;

        // KOR - 9/9/2004 - not optimal, and possibly not the way we want to do 3D rotation
        // (intended for effects such as glass shards or scattering debris). Need artist feedback to improve.
        xEuler.ToMatrix (xMatrix);

        xDeltaX.x   = xMatrix.e11;
        xDeltaX.y   = xMatrix.e21;
        xDeltaX.z   = xMatrix.e31;

        xDeltaY.x   = xMatrix.e12;
        xDeltaY.y   = xMatrix.e22;
        xDeltaY.z   = xMatrix.e32;
    }
    else if (xTemplate.m_bAlignEffectX && pxEffectOrientation)
    {
        // Calculate the deltas...
        xDeltaX.x   = pxEffectOrientation->e12;
        xDeltaX.y   = pxEffectOrientation->e22;
        xDeltaX.z   = pxEffectOrientation->e32;

        xDeltaY.x   = pxEffectOrientation->e13;
        xDeltaY.y   = pxEffectOrientation->e23;
        xDeltaY.z   = pxEffectOrientation->e33;
    }
    else if (xTemplate.m_bAlignEffectY && pxEffectOrientation)
    {
        // Calculate the deltas...
        xDeltaX.x   = pxEffectOrientation->e11;
        xDeltaX.y   = pxEffectOrientation->e21;
        xDeltaX.z   = pxEffectOrientation->e31;

        xDeltaY.x   = pxEffectOrientation->e13;
        xDeltaY.y   = pxEffectOrientation->e23;
        xDeltaY.z   = pxEffectOrientation->e33;
    }
    else if (xTemplate.m_bAlignEffectZ && pxEffectOrientation)
    {
        // Calculate the deltas...
        xDeltaX.x   = pxEffectOrientation->e11;
        xDeltaX.y   = pxEffectOrientation->e21;
        xDeltaX.z   = pxEffectOrientation->e31;

        xDeltaY.x   = pxEffectOrientation->e12;
        xDeltaY.y   = pxEffectOrientation->e22;
        xDeltaY.z   = pxEffectOrientation->e32;
    }
    else if( xTemplate.m_bBillboardJustY && pxEffectOrientation )
    {
        xDeltaX = xCameraDeltaX;

        xDeltaY.x = pxEffectOrientation->e13;
        xDeltaY.y = pxEffectOrientation->e23;
        xDeltaY.z = pxEffectOrientation->e33;
    }
    else if( xTemplate.m_bBillboardJustX && pxEffectOrientation )
    {
        xDeltaX.x = pxEffectOrientation->e12;
        xDeltaX.y = pxEffectOrientation->e22;
        xDeltaX.z = pxEffectOrientation->e32;

        xDeltaY = xCameraDeltaY;
    }
    else
    {
        // Use the camera deltas...
        xDeltaX = xCameraDeltaX;
        xDeltaY = xCameraDeltaY;
    }


	// Finally, multiply by the size...
	xDeltaX	*= fSize;
	xDeltaY	*= fSize;
}
/// End of function 'CalculateParticleDimensions'. ///


static void WriteParticlePosition(Asura_PS3_ParticleRender_Vertex* pxVertex,
								  const Asura_PFX_Particle* const pxParticle,
								  const Asura_PFX_Particle_Template& xTemplate,
								  const float fTheta,
								  const Asura_Vector_3 xDeltaX,
								  const Asura_Vector_3 xDeltaY)
{
	const Asura_Vector_3 xParticlePosition = pxParticle->m_xPosition;

	/// Kevin Lea - 27/03/2002 11:43:15 - code to draw particle stretched along its path
	/// ucky and needs rewriting
	if (xTemplate.m_bUseMotionBlur)
	{
		const float				fAgeInSeconds	= pxParticle->m_fAge * xTemplate.GetLifetimeFromSeed(pxParticle->m_fSeed);
		const float				fLength			= Asura_Maths::Min(xTemplate.m_fBlurLength, fAgeInSeconds);
		const Asura_Vector_3	xPrevPosition	= xParticlePosition - (pxParticle->m_xVelocity * fLength);
		Asura_Vector_3			xBeta			= xParticlePosition - xPrevPosition;

		if (xBeta.MagnitudeSquared() > (0.1f*0.1f))
		{
			xBeta.Normalise	();
			xBeta	*= 0.1f;
		}
			
		if (Asura_Maths::Abs(xBeta * xDeltaX) > Asura_Maths::Abs(xBeta*xDeltaY))
		{
			if (xBeta * xDeltaX > 0)
			{
				pxVertex[0].m_xPosition	= xPrevPosition		- xBeta - xDeltaX - xDeltaY; 
				pxVertex[1].m_xPosition	= xParticlePosition	+ xBeta + xDeltaX - xDeltaY;
				pxVertex[2].m_xPosition	= xParticlePosition	+ xBeta + xDeltaX + xDeltaY;
				pxVertex[3].m_xPosition	= xPrevPosition		- xBeta - xDeltaX + xDeltaY;
			}
			else
			{
				pxVertex[0].m_xPosition = xParticlePosition	+ xBeta - xDeltaX - xDeltaY; 
				pxVertex[1].m_xPosition	= xPrevPosition		- xBeta + xDeltaX - xDeltaY;
				pxVertex[2].m_xPosition = xPrevPosition		- xBeta + xDeltaX + xDeltaY;
				pxVertex[3].m_xPosition = xParticlePosition	+ xBeta - xDeltaX + xDeltaY;
			}
		}
		else
		{
			if (xBeta * xDeltaY > 0)
			{
				pxVertex[0].m_xPosition 	= xPrevPosition		- xBeta - xDeltaX - xDeltaY; 
				pxVertex[1].m_xPosition 	= xPrevPosition		- xBeta + xDeltaX - xDeltaY;
				pxVertex[2].m_xPosition 	= xParticlePosition	+ xBeta + xDeltaX + xDeltaY;
				pxVertex[3].m_xPosition 	= xParticlePosition	+ xBeta - xDeltaX + xDeltaY;
			}				  
			else			  
			{				  
				pxVertex[0].m_xPosition 	= xParticlePosition	+ xBeta - xDeltaX - xDeltaY; 
				pxVertex[1].m_xPosition 	= xParticlePosition	+ xBeta + xDeltaX - xDeltaY;
				pxVertex[2].m_xPosition 	= xPrevPosition		- xBeta + xDeltaX + xDeltaY;
				pxVertex[3].m_xPosition 	= xPrevPosition		- xBeta - xDeltaX + xDeltaY;
			}
		}
	}

	else
	{
		// Do we have a rotation?
		if (0.0f == fTheta)
		{
			// No simply copy the deltas...
			pxVertex[0].m_xPosition 	= xParticlePosition - xDeltaX - xDeltaY; 
			pxVertex[1].m_xPosition 	= xParticlePosition + xDeltaX - xDeltaY;
			pxVertex[2].m_xPosition 	= xParticlePosition + xDeltaX + xDeltaY;
			pxVertex[3].m_xPosition 	= xParticlePosition - xDeltaX + xDeltaY;
		}
		else
		{
			float fSin;
			float fCos;

			// Yes - rotate the deltas...
			Asura_Maths::SinCos	(fTheta, fSin, fCos);

			const Asura_Vector_3 	xCosDeltaX	= xDeltaX * fCos;
			const Asura_Vector_3 	xSinDeltaX	= xDeltaX * fSin;
			const Asura_Vector_3 	xCosDeltaY	= xDeltaY * fCos;
			const Asura_Vector_3 	xSinDeltaY	= xDeltaY * fSin;

			// Calculate the vertices...
			pxVertex[0].m_xPosition 	= xParticlePosition + (-xCosDeltaX + xSinDeltaX) + (-xSinDeltaY - xCosDeltaY);
			pxVertex[1].m_xPosition 	= xParticlePosition + ( xCosDeltaX + xSinDeltaX) + ( xSinDeltaY - xCosDeltaY);
			pxVertex[2].m_xPosition 	= xParticlePosition + ( xCosDeltaX - xSinDeltaX) + ( xSinDeltaY + xCosDeltaY);
			pxVertex[3].m_xPosition 	= xParticlePosition + (-xCosDeltaX - xSinDeltaX) + (-xSinDeltaY + xCosDeltaY);
		}
	}
}


static void WriteParticleTextureCoords( Asura_PS3_ParticleRender_Vertex* pxVertex,
									    const Asura_PFX_Particle* const pxParticle,
										const Asura_PFX_Particle_Template& xTemplate,
                                        Asura_Vector_3* pxDeltaX )
{
	const u_int	uTexOrient	= (xTemplate.m_bRandomTextureOrient)
							? Asura_Maths::FloatToInt_Chop(pxParticle->m_fSeed * 4.0f)
							: 0;

	// get the texture frame(s) for this particle
	const Asura_PFX_TextureFrame* pxTextureFrame;
	const Asura_PFX_TextureFrame* pxTextureFrame2;

	float fWeight = 0.0f;

	if (xTemplate.m_bCrossfadeTextureFrames)
	{
		xTemplate.GetTextureFramesForCrossfadeAtTime(pxParticle->m_fAge, pxTextureFrame, pxTextureFrame2, fWeight);
	}
	else
	{
		pxTextureFrame = xTemplate.GetTextureFrameAtTime(pxParticle->m_fAge);
		pxTextureFrame2 = pxTextureFrame;
	}

    if( xTemplate.m_bUseUVAsAspect )
    {
        const float fDV = pxTextureFrame->m_afTextureUVs[3] - pxTextureFrame->m_afTextureUVs[1];
        if( fDV != 0.0f )
        {
            const float fDU = pxTextureFrame->m_afTextureUVs[2] - pxTextureFrame->m_afTextureUVs[0];
            *pxDeltaX *= (fDU / fDV);
        }
    }

	for ( u_int u = 0; u < 4; ++u )
	{
		pxVertex[ u ].m_fFrameInfo[0] = fWeight;
	}

	// Do we need to mirror the U texture-coord?
	switch (uTexOrient)
	{
		case 0:
		case 1:
		{
			// Normal
			pxVertex[0].m_axTextureCoords[0].x	= pxTextureFrame->m_afTextureUVs[0];
			pxVertex[1].m_axTextureCoords[0].x	= pxTextureFrame->m_afTextureUVs[2];
			pxVertex[2].m_axTextureCoords[0].x	= pxTextureFrame->m_afTextureUVs[2];
			pxVertex[3].m_axTextureCoords[0].x	= pxTextureFrame->m_afTextureUVs[0];
		
			pxVertex[0].m_axTextureCoords[1].x	= pxTextureFrame2->m_afTextureUVs[0];
			pxVertex[1].m_axTextureCoords[1].x	= pxTextureFrame2->m_afTextureUVs[2];
			pxVertex[2].m_axTextureCoords[1].x	= pxTextureFrame2->m_afTextureUVs[2];
			pxVertex[3].m_axTextureCoords[1].x	= pxTextureFrame2->m_afTextureUVs[0];
			break;
		}

		case 2:
		case 3:
		default:
		{
			// Mirrored
			pxVertex[0].m_axTextureCoords[0].x	= pxTextureFrame->m_afTextureUVs[2];
			pxVertex[1].m_axTextureCoords[0].x	= pxTextureFrame->m_afTextureUVs[0];
			pxVertex[2].m_axTextureCoords[0].x	= pxTextureFrame->m_afTextureUVs[0];
			pxVertex[3].m_axTextureCoords[0].x	= pxTextureFrame->m_afTextureUVs[2];

			pxVertex[0].m_axTextureCoords[1].x	= pxTextureFrame->m_afTextureUVs[2];
			pxVertex[1].m_axTextureCoords[1].x	= pxTextureFrame->m_afTextureUVs[0];
			pxVertex[2].m_axTextureCoords[1].x	= pxTextureFrame->m_afTextureUVs[0];
			pxVertex[3].m_axTextureCoords[1].x	= pxTextureFrame->m_afTextureUVs[2];
			break;
		}
	}		// End of switch.


	// Do we need to mirror the V texture-coord?
	switch (uTexOrient)
	{
		case 0:
		case 3:
		{
			// Normal
			pxVertex[0].m_axTextureCoords[0].y	= pxTextureFrame->m_afTextureUVs[1];
			pxVertex[1].m_axTextureCoords[0].y	= pxTextureFrame->m_afTextureUVs[1];
			pxVertex[2].m_axTextureCoords[0].y	= pxTextureFrame->m_afTextureUVs[3];
			pxVertex[3].m_axTextureCoords[0].y	= pxTextureFrame->m_afTextureUVs[3];

			pxVertex[0].m_axTextureCoords[1].y	= pxTextureFrame2->m_afTextureUVs[1];
			pxVertex[1].m_axTextureCoords[1].y	= pxTextureFrame2->m_afTextureUVs[1];
			pxVertex[2].m_axTextureCoords[1].y	= pxTextureFrame2->m_afTextureUVs[3];
			pxVertex[3].m_axTextureCoords[1].y	= pxTextureFrame2->m_afTextureUVs[3];
			break;
		}

		case 1:
		case 2:
		default:
		{
			// Mirrored
			pxVertex[0].m_axTextureCoords[0].y	= pxTextureFrame->m_afTextureUVs[3];
			pxVertex[1].m_axTextureCoords[0].y	= pxTextureFrame->m_afTextureUVs[3];
			pxVertex[2].m_axTextureCoords[0].y	= pxTextureFrame->m_afTextureUVs[1];
			pxVertex[3].m_axTextureCoords[0].y	= pxTextureFrame->m_afTextureUVs[1];

			pxVertex[0].m_axTextureCoords[1].y	= pxTextureFrame2->m_afTextureUVs[3];
			pxVertex[1].m_axTextureCoords[1].y	= pxTextureFrame2->m_afTextureUVs[3];
			pxVertex[2].m_axTextureCoords[1].y	= pxTextureFrame2->m_afTextureUVs[1];
			pxVertex[3].m_axTextureCoords[1].y	= pxTextureFrame2->m_afTextureUVs[1];
			break;
		}
	}		// End of switch.
}


////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PS3_RenderPFXForCurrentCamera
// Author       : Andy Tate
// Date         : 30-Jun-2005
//
// Description  : 
//
// Parameters   : An array of pointers to PFX particles to render, the number of
//				  particles to render, a pointer to the particle-template to
//				  render along with the colour of the light.
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

void Asura_PS3_RenderPFXForCurrentCamera (Asura_PS3_ParticleRender_Vertex* const pxVB,
											 float fEffectSizeScale,
											 const Asura_Matrix_3x3* pxEffectOrientation,
											 const Asura_PFX_Particle* const pxParticles,
											 const u_int uNumParticles,
											 const Asura_PFX_Particle_Template& xTemplate,
											 const Asura_RGBA& xLightColour,
											 const Asura_Vector_3& xCameraDeltaX,
											 const Asura_Vector_3& xCameraDeltaY,
											 const Asura_Vector_3& xCameraPos,
											 bool  bPaused )
{
	Asura_PS3_ParticleRender_Vertex* pxVertex = pxVB;

	// Go through each particle in the array...
	for (u_int p = 0; p < uNumParticles; p++)
	{
		const Asura_PFX_Particle*	pxParticle	= &pxParticles [p];
		Asura_RGBA					xColour;

		// Calculate the colour of this particle...
		CalculateParticleColour	(*pxParticle, xTemplate, xLightColour, xColour, xCameraPos);

		// only continue if not fully-transparent
        // (MH - 08.09.2005) TODO: check if it's worth putting this back in. If the SPUs are doing 
		// all this we would need to figure out a way for them to send the actual num particles back.
		// For the moment we will render fully-transparent particles.
		//if (xColour.m_fA > 0.0f)
		{
			float			fSize	= CalculateParticleSize (fEffectSizeScale, *pxParticle, xTemplate);
			float			fTheta	= CalculateParticleAngle(*pxParticle, xTemplate, bPaused);

			// In case the particle is completely transparent set the size to zero.
			if( xColour.m_fA < 0.001f )
			{
				fSize = 0.0f;
			}
			// Calculate the dimensions of the particle...
			Asura_Vector_3	xDeltaX;
			Asura_Vector_3	xDeltaY;
			CalculateParticleDimensions(pxEffectOrientation, *pxParticle, xTemplate, fSize, fTheta, xCameraDeltaX, xCameraDeltaY, xDeltaX, xDeltaY);

			WriteParticleTextureCoords( pxVertex, pxParticle, xTemplate, &xDeltaX );

			WriteParticlePosition(pxVertex, pxParticle, xTemplate, fTheta, xDeltaX, xDeltaY);

			// Copy the remaining vertex data...
			for (int i = 0; i < 4; i++)
			{
				pxVertex[ i ].m_fFrameInfo[ 1 ] = fSize;

				pxVertex[ i ].m_R = xColour.m_fR;
				pxVertex[ i ].m_G = xColour.m_fG;
				pxVertex[ i ].m_B = xColour.m_fB;
				pxVertex[ i ].m_A = xColour.m_fA;
			}
			
			pxVertex		+= NUM_VERTICES_PER_PARTICLE;
			//uCurrentVertex	+= NUM_VERTICES_PER_PARTICLE;
		}
	}
}
/// End of function 'Asura_PS3_RenderPFXForCurrentCamera'. ///
