/*********************************************************************//**
*	Frustum.
*		Frustum se pouziva k orezavani vykreslovanych polygonu, tak
*	aby jejich pocet byl co nejmensi.
*                                                                        
*
*	author: Michal Jirous
*	date: 19.02.2009
*	file: game_frustum.h
**********************************************************************/    

#include "game_frustum.h"

Frustum::Frustum()
{
	memset( this, 0, sizeof(*this) );
}

/** @param w Sirka rozliseni.
*	@param h Vyska rozliseni.
*/
void Frustum::update( float w, float h)
{
	m_fHalfWFov = myatan( mytan( m_fHalfFov ) * w / h );
	Vector tmp( -1.0f, 0.0f, mytan( m_fHalfWFov ) );
	tmp.normalize();

	leftPlaneStatic[0] = tmp.x;
	leftPlaneStatic[1] = tmp.y;		//dont forget to use OpenGL coords...this is Z
	leftPlaneStatic[2] = tmp.z;

	
	rightPlaneStatic[0] = -tmp.x;
	rightPlaneStatic[1] = tmp.y;
	rightPlaneStatic[2] = tmp.z;

	
	tmp = Vector( 0.0f, 1.0f, mytan( m_fHalfFov ) );
	tmp.normalize();

	topPlaneStatic[0]=	tmp.x;
	topPlaneStatic[1]=	tmp.y;
	topPlaneStatic[2]=	tmp.z;

	bottomPlaneStatic[0] = tmp.x;
	bottomPlaneStatic[1] = -tmp.y;
	bottomPlaneStatic[2] = tmp.z;
}

GLfloat transformationMatrix[16];
GLfloat		tlPoint[4] = {0},
			trPoint[4] = {0}, blPoint[4] = {0}, brPoint[4] = {0};

void Frustum::updateFrustumPlanes( const Vector &vecDir, const Point &position, float fNear, float fFar, float fFov, float w, float h )
{
		Vector vecDirection = vecDir;	//TODO - zbytecne

			//vecDirection.normalize();	//ted uz snad bude normalizovan

			//Dva parametry frustum
			m_fFar = fFar;
			m_fHalfFov = fFov / 2.0f;

			m_Planes[FRONT].m_vecNormal = -vecDirection;
			m_Planes[FRONT].determineDistance( position + vecDirection * fNear );

			m_Planes[BACK].m_vecNormal = vecDirection;
			m_Planes[BACK].determineDistance( position + vecDirection * fFar );

			//pokud se znenily tyto parametry, tak je potreba prepocitat staticke frustum roviny
			if( compareFloats( lastHalfFov, m_fHalfFov ) || compareFloats( lastFar, m_fFar ) )
			{
				update( w, h );
				lastHalfFov = m_fHalfFov;
				lastFar = m_fFar;
			}

				
			glGetFloatv( GL_MODELVIEW_MATRIX, transformationMatrix);

			matrixMultFastTransformPoint( transformationMatrix, (float*)leftPlaneStatic, tlPoint );	//TODO - hodit sem ten normalovej vektor rovnou at se nemusi zbytecne kopirovat
			matrixMultFastTransformPoint( transformationMatrix, (float*)rightPlaneStatic, trPoint );
			matrixMultFastTransformPoint( transformationMatrix, (float*)topPlaneStatic, blPoint );
			matrixMultFastTransformPoint( transformationMatrix, (float*)bottomPlaneStatic, brPoint );


			m_Planes[RIGHT].m_vecNormal = trPoint;
			m_Planes[RIGHT].determineDistance( position );

			m_Planes[LEFT].m_vecNormal = tlPoint;
			m_Planes[LEFT].determineDistance( position );

			m_Planes[TOP].m_vecNormal = blPoint;
			m_Planes[TOP].determineDistance( position );

			m_Planes[BOTTOM].m_vecNormal = brPoint;
			m_Planes[BOTTOM].determineDistance( position );

}


bool Frustum::isBoundsInsideFrustum( const BoundingBox &bounds ) const
{
	float result;
	for( int i = 0; i < 6; i++ )
	{
		if( m_Planes[i].m_vecNormal.x < 0 )
			result = bounds.m_fBounds[MAX_X] * m_Planes[i].m_vecNormal.x;
		else 
			result = bounds.m_fBounds[MIN_X] * m_Planes[i].m_vecNormal.x;
	
		if( m_Planes[i].m_vecNormal.y < 0 )
			result += bounds.m_fBounds[MAX_Y] * m_Planes[i].m_vecNormal.y;
		else 
			result += bounds.m_fBounds[MIN_Y] * m_Planes[i].m_vecNormal.y;

		if( m_Planes[i].m_vecNormal.z < 0 )
			result += bounds.m_fBounds[MAX_Z] * m_Planes[i].m_vecNormal.z;
		else 
			result += bounds.m_fBounds[MIN_Z] * m_Planes[i].m_vecNormal.z;

		result += m_Planes[i].m_fDistance;

		if( result > 0.0f )
			return false;
	}
	return true;
}
