#include <gl\glut.h>
#include "Particles.h"


/*
	A V-E-R-Y basic particle engine, doesn't get any more basic than this.
	This code just simulates the motion of silt particles settling to the 
	ocean floor.  Once a particle reaches the bottom, we just send it back
	to the top and reuse it.  Simple enough.
*/


//-----------------------------------------------------------------------------
// Name: CParticleManager::CParticleManager
// Desc: Class constructor; initializes particle system.
//-----------------------------------------------------------------------------
CParticleManager::CParticleManager( int ParticleCount, float Range, float MaxHeight )
{
	// Set particle count (default 500)
	m_ParticleCount = ParticleCount;

	// Set particle range (default 500.0f)
	m_fRange = Range;

	// Set max particle height (default 300.0f)
	m_fMaxHeight = MaxHeight;

	// Set minimum and maximum particle fall velocity (time elapsed*((vmax-vmin)*rand))
	m_fMinFallVelocity = 10.0f;
	m_fMaxFallVelocity = 20.0f;

	// Allocate enough vectors for each particle
	m_pvecParticles = new Vector3[ParticleCount];
	m_pfVelocities = new float[ParticleCount];

	// Give each particle a random position
	for( int i = 0; i < ParticleCount; i++ )
	{
		extern float myRandom();
		float x = Range * myRandom();
		float z = Range * myRandom();
		float y = MaxHeight * myRandom();

		if( (i%3) == 1 )
			x = -x;
		if( (i%2) == 0 )
			z = -z;

		m_pvecParticles[i].set( x, y, z );

		float vd = m_fMaxFallVelocity - m_fMinFallVelocity;
		m_pfVelocities[i] = m_fMinFallVelocity + ( vd * myRandom() );
	}
}

//-----------------------------------------------------------------------------
// Name: CParticleManager::~CParticleManager()
// Desc: Class deconstructor; uninitializes the particle system.
//-----------------------------------------------------------------------------
CParticleManager::~CParticleManager()
{
	// Delete particle array
	if( m_pvecParticles )
	{
		delete [] m_pvecParticles;
		m_pvecParticles = 0;

		delete [] m_pfVelocities;
		m_pfVelocities;
	}
}

//-----------------------------------------------------------------------------
// Name: CParticleManager::Render
// Desc: Renders each particle as a point.
//-----------------------------------------------------------------------------
void CParticleManager::Render()
{
//	glPushMatrix();
//	glLoadIdentity();

	// Disable unnecessary render states
	glPushAttrib( GL_ALL_ATTRIB_BITS );
	glDisable( GL_BLEND );
	glDisable( GL_LIGHTING );

	// Set default colour (white, opaque)
	glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );

#if 0
	// Render all particles as a vertex array
	glEnableClientState( GL_VERTEX_ARRAY );
	glVertexPointer( 3, GL_FLOAT, 0, &m_pvecParticles[0] );
	glDrawArrays( GL_POINTS, 0, m_ParticleCount );
	glDisableClientState( GL_VERTEX_ARRAY );
#else
	glBegin( GL_POINTS );
	for( int i = 0; i < m_ParticleCount; i++ )
	{
		glVertex3fv( m_pvecParticles[i].get() );
	}
	glEnd();
#endif

	// Restore render states
	glPopAttrib();

//	glPopMatrix();
}

//-----------------------------------------------------------------------------
// Name: CParticleManager::Update
// Desc: Updates each particle and resets the particle once it reaches the ocean
//		 floor to be used again.
//-----------------------------------------------------------------------------
void CParticleManager::Update()
{
	extern float queryElapsedTime();
	extern float myRandom();

	float fTime = 0.0f, fDeltaTime;
	static float fLastTime = 0.0f;

	// Update timing variables
	fTime = queryElapsedTime();
	fDeltaTime = fTime - fLastTime;
	fLastTime = fTime;

	// Update each particle by subtracting the particle velocity multiplied
	// with fDeltaTime.  If the particle reaches the ocean floor, send it to
	// the top and give it a new position.
	for( int i = 0; i < m_ParticleCount; i++ )
	{
		m_pvecParticles[i].get()[1] -= m_pfVelocities[i] * fDeltaTime;

		if( m_pvecParticles[i].get()[1] < -80.0f )
		{
			float x = m_fRange * myRandom();
			float z = m_fRange * myRandom();

			if( (i%3) == 1 )
				x = -x;
			if( (i%2) == 0 )
				z = -z;

			m_pvecParticles[i].set( x, m_fMaxHeight, z );
		}
	}
}
