/*********************************************************************//**
*	Mlha.
*	Entita vytvari kvadr mlhy
*	
*	author: Michal Jirous
*	date: 23.04.2009
*	file: ent_env_fog.cpp
**********************************************************************/

#include "ent_env_fog.h"
#include "level_loader.h"

EnvFog::EnvFog() : CBaseFunction()
{
	m_iProperties = ENT_PARM_RENDER | ENT_PARM_RUNNABLE;
	m_iType = LINEAR;
}


void EnvFog::setParameters( parameters_t &parametersMap )
{
	CBaseFunction::setParameters( parametersMap );
	
	std::string value = getParameterValue( parametersMap, "fogorigin" );
	if( !value.empty() )
		m_FogOrigin = Vector( value );

				
	value = getParameterValue( parametersMap, "fogtype" );
	if( !value.empty() )
		m_iType = atoi( value.c_str() );

	value = getParameterValue( parametersMap, "start" );
	if( !value.empty() )
		m_fStart = (float)atof( value.c_str() );

	value = getParameterValue( parametersMap, "end" );
	if( !value.empty() )
		m_fEnd = (float)atof( value.c_str() );

	value = getParameterValue( parametersMap, "density" );
	if( !value.empty() )
		m_fDensity = (float)atof( value.c_str() );

	value = getParameterValue( parametersMap, "color" );
	if( !value.empty() )
		m_FogColor = Vector(value) / 255.0f;
}

bool EnvFog::renderCullTest(  RenderData &renderData )
{
	dmodel_t &model = levelLoader.m_LevelData.models[m_SolidModel];
	return (m_bRenderSelf = renderData.frustum->isBoundsInsideFrustum( model.bounds ));
}

#include "game.h"
bool calculateFogCoords( Face &face, EnvFog *pFog )
{
	for( int i = 0; i < face.elements_count; ++i)
	{
		float fog_coord = 0.0f;
		float distance = Vector( levelLoader.m_LevelData.vertices_array[ face.firstvertex + i ] - game.m_pPlayer->getRenderOrigin() ).absolute();
		switch( pFog->m_iType )
		{
			case LINEAR:
				fog_coord = 1.0f - std::max( 0.0f, ( pFog->m_fEnd - distance) / (pFog->m_fEnd - pFog->m_fStart) );
				break;
			case EXP:
				fog_coord = pow(M_E, -pFog->m_fDensity*distance);
				break;
			case EXP2:
				float tmp =(pFog->m_fDensity*distance);
				fog_coord = pow(M_E, -tmp*tmp);
				break;
		}

		levelLoader.m_LevelData.fog_coords_array[face.firstvertex + i ] = fog_coord;
	}


	return false;
}


void EnvFog::update( float s )
{
	compile();
}

void EnvFog::compile()
{
	levelLoader.forEachFaceDo( m_SolidModel, (bool (*)(Face &face, void*))calculateFogCoords, this );
}
#include "graphics.h"
void EnvFog::render( RenderData &renderData )
{
	glEnable( GL_FOG );
	glEnableClientState( GL_FOG_COORD_ARRAY );
	glFogCoordPointer( GL_FLOAT, 0, levelLoader.m_LevelData.fog_coords_array );
	glFogi(GL_FOG_MODE, GL_LINEAR);						// Fog Fade Is Linear
	glFogfv(GL_FOG_COLOR, (GLfloat*)&m_FogColor);					// Set The Fog Color
	glFogf(GL_FOG_START,  0.0f);						// Set The Fog Start (Least Dense)
	glFogf(GL_FOG_END,    1.0f);						// Set The Fog End (Most Dense)
	glHint(GL_FOG_HINT, GL_NICEST);						// Per-Pixel Fog Calculation
	glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);		// Set Fog Based On Vertice Coordinates
	renderData.backfacecull = false;
	CBaseFunction::render( renderData );
	renderData.backfacecull = true;
	glDisable( GL_FOG );

}
