// Author : Chris Tolley
// Date   : 7/25/2004
// WaterPool.h contains the class declaration for a water pool derived from
// Object to use in the survival game

#pragma warning ( disable : 4305 )
#pragma warning ( disable : 4309 )

#include <windows.h>
#include <gl/gl.h>
#include <math.h>

#include "quadTreeTerrain.h"
#include "WaterPool.h"

// Static WaterPool variable declaration
quadTreeTerrain* WaterPool::m_sqtTerrain = NULL;
unsigned int	 WaterPool::m_suiList	 = 0;
texture			 WaterPool::m_Texture;


WaterPool::WaterPool( int x, int z, int radius ) 
: m_fLevel( MAX_LEVEL ), m_iRadius( radius ), m_bHasWater( true )
{
	// Make sure that x and z are on the map
	int size = m_sqtTerrain->GetSize();
	if( x < radius ) x = radius;
	if( z < radius ) z = radius;
	if( x > size - radius ) x = size - radius;
	if( z > size - radius ) z = size - radius;

	// Now set up the map
	int stopX  = x + radius;
	int stopZ  = z + radius;

	// Get the height at the center point
	float midHeight = m_sqtTerrain->GetHeightAt( x, z );

	// For each point in the this WaterPool
	for( int lx = x - radius; lx <= stopX; ++lx )
	{
		for( int lz = z - radius; lz <= stopZ; ++lz )
		{
			// If we are on the outer ring of the WaterPool
			if( lx == x - radius || lx == x + radius ||
				lz == z - radius || lz == z + radius )
			{
				// Set the height of the map the center heigth plus 1 to
				// create rim around the pool
				m_sqtTerrain->SetHeightAt( lx, lz, midHeight + 1.5 );
			}// End if
			else
			{
				// Otherwise, we are on the inside of the WaterPool and we 
				// need to set the height to midHeight
				m_sqtTerrain->SetHeightAt( lx, lz, midHeight );
			}// End else
		}// End for lz
	}// End for lx

	// Set up the local coordinate system
	m_mLocal.Translate( x, m_sqtTerrain->GetHeightAt( x, z ), z );
}// End WaterPool::Constructor



// Destructor
WaterPool::~WaterPool()
{
}// End WaterPool::Destructor


// Initializes the static water pool data
void WaterPool::Initialize( quadTreeTerrain* qtTerrain, 
							const char* waterTexture )
{
	// Set the terrain
	m_sqtTerrain = qtTerrain;

	// Load the texture
	m_Texture.load( waterTexture );
}// End WaterPool::Initialize

// Updates the object.  Must be implemented at a derived level
void WaterPool::Update( float elapsedSec )
{
	// If the water level is zero
	if( m_fLevel == 0 )
	{
		// Set the flag indicating that there is no water
		m_bHasWater = false;
	}// End if

	// Update the water level
	m_fLevel += ( elapsedSec * 2 );

	// Make sure that the water level is still in range
	if( m_fLevel > MAX_LEVEL )
		m_fLevel = MAX_LEVEL;

	// If this waterpool has no water in it
	if( ! m_bHasWater )
	{
		// If enough time has passed since it ran dry
		if( m_fLevel >= RAISE_TIME )
		{
			m_bHasWater = true;
		}// End if
	}// End if
}// End WaterPool::Update


// Renders the object to the screen. Must be implemented at a derived level
void WaterPool::Render()
{
	// If there is some water in this pool
	if( m_bHasWater )
	{
		// Draw this water pool
		// Set up the matrix stack
		glPushMatrix();
		glMultMatrixf( m_mLocal.get() );

		// Apply the translation to move the water up to the level it should be
		glTranslatef( 0, ( m_fLevel / MAX_LEVEL ), 0 );


		// Enable texturing and select the water texture
		glEnable( GL_TEXTURE_2D );
		m_Texture.select();

		// Enable blending
		glEnable( GL_BLEND );

		// Set the transparency up
		glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

		// Set the blending colors
		glColor4f( 1, 1, 1, .7 );

		// Draw the water
		glBegin( GL_POLYGON );
			glTexCoord2f( 0, 0 );
			glVertex3f( -m_iRadius, 0, -m_iRadius );

			glTexCoord2f( 1, 0 );
			glVertex3f( -m_iRadius, 0, m_iRadius );

			glTexCoord2f( 1, 1 );
			glVertex3f( m_iRadius, 0, m_iRadius );

			glTexCoord2f( 0, 1 );
			glVertex3f( m_iRadius, 0, -m_iRadius );
		glEnd();

		// Change the color back to none transparent
		glColor4f( 1, 1, 1, 1 );

		// Disable blending
		glDisable( GL_BLEND );

		// Deselect the water texture and disable texturing
		m_Texture.deselect();
		glDisable( GL_TEXTURE_2D );

		// Restore the matrix stack
		glPopMatrix();
	}// End if
}// End WaterPool::Render


// Returns true if this Object is inside the sphere.  Derived from Object
bool WaterPool::InSphere( float x, float z, float radius )
{
	// Get the position of this WaterPool
	float wx, wy, wz;
	GetPos( wx, wy, wz );

	// Calculate the distance between this WaterPool and point x,z
	float distance = sqrt( ( ( x - wx ) * ( x - wx ) ) +
						   ( ( z - wz ) * ( z - wz ) ) );

	// If the distance between this WaterPool and point x,z is less than
	// radius plus this WaterPool's radius, then it is inside the sphere
	return distance <= ( radius + m_iRadius );
}// End WaterPool::InSphere


// Returns the amount of water available from this WaterPool
int WaterPool::GetWaterUnits()
{
	// The return value
	int returnValue = 0;
	if( m_bHasWater )
	{
		// Set the return value to a water unit
		returnValue = WATER_UNIT;

		// If there is some water
		if( m_fLevel >= WATER_UNIT )
		{
			// Then we can leave returnValue alone and indate the water level
			m_fLevel -= WATER_UNIT;
		}// End if
		else
		{
			// Otherwise, just return what is left
			returnValue = m_fLevel;
			m_fLevel = 0;
		}// End else
	}// End if

	// Return the return value
	return returnValue;
}// End WaterPool::GetWaterUnits
