/*
 * ExNihilo 3D Engine
 * 
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * Please read AUTHORS file !!!
 * 
 * $Id: ExManagerFog.cpp,v 1.8 2002/12/13 11:45:01 data Exp $
 *
 */

#include "ExManagerFog.h"

bool ExManagerFog::m_flag = false; 
ExManagerFog* ExManagerFog::m_instance = NULL; 

ExManagerFog* ExManagerFog::CreateSingleton(void){
Guard(ExManagerFog* ExManagerFog::CreateSingleton(void))
	if(!m_flag)
	{
		m_flag = true; // We are creating the error log now, so set flag to true
		m_instance = new ExManagerFog; // Create the error log
	}else
	{
		std::cout<<"Error singleton already created"<<std::endl;
	}
	return m_instance; 
UnGuard
}

ExManagerFog::ExManagerFog(void)
{
Guard(ExManagerFog::ExManagerFog(void))
	Reset();
UnGuard
}

ExManagerFog::~ExManagerFog(void)
{
Guard(ExManagerFog::~ExManagerFog(void))
UnGuard
}

void ExManagerFog::Init(void)
{
Guard(ExManagerFog::Init(void))
	glFogCoordfEXT = NULL;

	char *blah = (char *) glGetString(GL_EXTENSIONS);
	//--------------------------------
	//VOLUMETRIC FOG EXTENSION
	//--------------------------------
	if (strstr( (const char *)blah, "GL_EXT_fog_coord" )) 
	{ 
		glFogCoordfEXT = (PFNGLFOGCOORDFEXTPROC) wglGetProcAddress("glFogCoordfEXT");
		*Consol<<"ExManagerFog::glFogCoordfEXT found and enable"<<std::endl;
	}else
	{
		*Consol<<"ExManagerFog::OpenGl glFogCoordfEXT extension missing"<<std::endl; 
	}
UnGuard
}

void ExManagerFog::Reset(void)
{
Guard(ExManagerFog::Reset(void))
	SetAlgo(GL_LINEAR);
	SetFogColor(0.8f,0.8f,0.8f,1.0f);
	SetStartPoint(100.0f);
	SetEndPoint(300.0f);
	SetDensity(0.50);
	m_State=false;
	DisableFog();
UnGuard
}

void ExManagerFog::Draw(void)
{
Guard(ExManagerFog::Draw(void))
EnableFog();
glPushAttrib(GL_ALL_ATTRIB_BITS);
	glColor3f(0.0f,0.0f,0.5f);
	glBegin(GL_QUADS);													// Back Wall
	 	glFogCoordfEXT( 0.0f);	glVertex3f(-100.0f,-100.0f,-100.0f);
		glFogCoordfEXT( 0.0f);	glVertex3f( 100.0f,-100.0f,-100.0f);
		glFogCoordfEXT( 0.0f);	glVertex3f( 100.0f, 100.0f,-100.0f);
		glFogCoordfEXT( 0.0f);	glVertex3f(-100.0f, 100.0f,-100.0f);
	glEnd();

	glBegin(GL_QUADS);													// Floor
	 	glFogCoordfEXT( 0.0f);	glVertex3f(-100.0f,-100.0f,-100.0f);
		glFogCoordfEXT( 0.0f);	glVertex3f( 100.0f,-100.0f,-100.0f);
		glFogCoordfEXT( 1.0f);	glVertex3f( 100.0f,-100.0f, 100.0f);
		glFogCoordfEXT( 1.0f);	glVertex3f(-100.0f,-100.0f, 100.0f);
	glEnd();

	glBegin(GL_QUADS);													// Roof
		glFogCoordfEXT( 0.0f);	glVertex3f(-100.0f, 100.0f,-100.0f);
		glFogCoordfEXT( 0.0f);	glVertex3f( 100.0f, 100.0f,-100.0f);
		glFogCoordfEXT( 1.0f);	glVertex3f( 100.0f, 100.0f, 100.0f);
		glFogCoordfEXT( 1.0f);	glVertex3f(-100.0f, 100.0f, 100.0f);
	glEnd();

	glBegin(GL_QUADS);													// Right Wall
		glFogCoordfEXT( 1.0f);	glVertex3f( 100.0f,-100.0f, 100.0f);
		glFogCoordfEXT( 1.0f);	glVertex3f( 100.0f, 100.0f, 100.0f);
		glFogCoordfEXT( 0.0f);	glVertex3f( 100.0f, 100.0f,-100.0f);
		glFogCoordfEXT( 0.0f);	glVertex3f( 100.0f,-100.0f,-100.0f);
	glEnd();

	glBegin(GL_QUADS);													// Left Wall
	 	glFogCoordfEXT( 1.0f);	glVertex3f(-100.0f,-100.0f, 100.0f);
		glFogCoordfEXT( 1.0f);	glVertex3f(-100.0f, 100.0f, 100.0f);
		glFogCoordfEXT( 0.0f);	glVertex3f(-100.0f, 100.0f,-100.0f);
		glFogCoordfEXT( 0.0f);	glVertex3f(-100.0f,-100.0f,-100.0f);
	glEnd();

	glPopAttrib();
DisableFog();
UnGuard
}

void ExManagerFog::SetVolumetricFogCoord(GLfloat Value)
{
Guard(ExManagerFog::SetVolumetricFogCoord(GLfloat Value))
	//stay to Check if extension ok....
	glFogCoordfEXT(Value);	
UnGuard
}

void ExManagerFog::EnableFog(void)
{
Guard(ExManagerFog::EnableFog(void))
	m_State=true;
/*	glEnable(GL_FOG);
	glFogi(GL_FOG_MODE,m_FogAlgo);//GL_EXP,GL_EXP2,GL_LINEAR
	glFogfv(GL_FOG_COLOR,m_FogColor);
	glFogf(GL_FOG_START,m_StartPoint);
	glFogf(GL_FOG_END,m_EndPoint);

	glFogf(GL_FOG_DENSITY,m_Density);
	glHint(GL_FOG_HINT,GL_DONT_CARE);

	glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
*/
	/*glEnable(GL_FOG);													// Enable Fog
	glFogi(GL_FOG_MODE, GL_LINEAR);										// Fog Fade Is Linear
	glFogfv(GL_FOG_COLOR, m_FogColor);									// Set The Fog Color
	glFogf(GL_FOG_START,  1.0f);										// Set The Fog Start
	glFogf(GL_FOG_END,    0.0f);										// Set The Fog End
	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
	*/
	float fogColor[4] = {0.8f, 0.8f, 0.8f, 1.0f};

	glEnable(GL_FOG);						// Turn on fog
	glFogi(GL_FOG_MODE, GL_LINEAR);			// Set the fog mode to LINEAR (Important)
	glFogfv(GL_FOG_COLOR, fogColor);		// Give OpenGL our fog color
	glFogf(GL_FOG_START, 0.0);				// Set the start position for the depth at 0
	glFogf(GL_FOG_END, 50.0);				// Set the end position for the detph at 50
	glHint(GL_FOG_HINT, GL_NICEST);	

	// Now we tell OpenGL that we are using our fog extension for per vertex
	// fog calculations.  For each vertex that needs fog applied to it we must
	// use the glFogCoordfEXT() function with a depth value passed in.
	// These flags are defined in main.h and are not apart of the normal opengl headers.
	glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);

UnGuard
}

void ExManagerFog::DisableFog(void)
{
Guard(ExManagerFog::DisableFog(void))
	glDisable(GL_FOG);
	m_State=false;
UnGuard
}


void ExManagerFog::SetFogColor(float R,float G,float B,float A)
{
Guard(ExManagerFog::SetFogColor(float R,float G,float B,float A))
	SetFogColorR(R);
	SetFogColorG(G);
	SetFogColorB(B);
	SetFogColorA(A);
UnGuard
}

void ExManagerFog::SetFogColorR(float R)
{
Guard(ExManagerFog::SetFogColorR(float R))
	if(R>1.0f)R=1.0f;
	if(R<0.0f)R=0.0f;
	m_FogColor[0]=R;
	glFogfv(GL_FOG_COLOR,m_FogColor);
UnGuard
}

void ExManagerFog::SetFogColorG(float G)
{
Guard(ExManagerFog::SetFogColorG(float G))
	if(G>1.0f)G=1.0f;
	if(G<0.0f)G=0.0f;
	m_FogColor[1]=G;
	glFogfv(GL_FOG_COLOR,m_FogColor);
UnGuard
}

void ExManagerFog::SetFogColorB(float B)
{
Guard(ExManagerFog::SetFogColorB(float B))
	if(B>1.0f)B=1.0f;
	if(B<0.0f)B=0.0f;
	m_FogColor[2]=B;
	glFogfv(GL_FOG_COLOR,m_FogColor);
UnGuard
}

void ExManagerFog::SetFogColorA(float A)
{
Guard(ExManagerFog::SetFogColorA(float A))
	if(A>1.0f)A=1.0f;
	if(A<0.0f)A=0.0f;
	m_FogColor[3]=A;
	glFogfv(GL_FOG_COLOR,m_FogColor);
UnGuard
}

void ExManagerFog::IncFogColorR(float inc)
{
Guard(ExManagerFog::IncFogColorR(float inc))
	SetFogColorR(GetFogColorR()+inc);
UnGuard
}

void ExManagerFog::IncFogColorG(float inc)
{
Guard(ExManagerFog::IncFogColorG(float inc))
	SetFogColorG(GetFogColorG()+inc);
UnGuard
}

void ExManagerFog::IncFogColorB(float inc)
{
Guard(ExManagerFog::IncFogColorB(float inc))
	SetFogColorB(GetFogColorB()+inc);
UnGuard
}

void ExManagerFog::IncFogColorA(float inc)
{
Guard(ExManagerFog::IncFogColorA(float inc))
	SetFogColorA(GetFogColorA()+inc);
UnGuard
}

void ExManagerFog::SetStartPoint(float P)
{
Guard(ExManagerFog::SetStartPoint(float P))
	m_StartPoint=P;
	glFogf(GL_FOG_START,m_StartPoint);
UnGuard
}

void ExManagerFog::IncStartPoint(float inc)
{
Guard(ExManagerFog::IncStartPoint(float inc))
	SetStartPoint(GetStarPoint()+inc);
UnGuard
}

void ExManagerFog::SetEndPoint(float P)
{
Guard(ExManagerFog::SetEndPoint(float P))
	m_EndPoint=P;
	glFogf(GL_FOG_END,m_EndPoint);
UnGuard
}

void ExManagerFog::IncEndPoint(float inc)
{
Guard(ExManagerFog::IncEndPoint(float inc))
	SetEndPoint(GetEndPoint()+inc);
UnGuard
}

void ExManagerFog::SetDensity(float P)
{
Guard(ExManagerFog::SetDensity(float P))
	m_Density=P;
	glFogf(GL_FOG_DENSITY,m_Density);
UnGuard
}

void ExManagerFog::IncDensity(float inc)
{
Guard(ExManagerFog::IncDensity(float inc))
	SetDensity(GetDensity()+inc);
UnGuard
}

void ExManagerFog::SetAlgo(GLenum algo)
{
Guard(ExManagerFog::SetAlgo(GLenum algo))
	switch(algo)
	{
		case GL_LINEAR:
			m_FogAlgo=GL_LINEAR;
			glFogi(GL_FOG_MODE,GL_LINEAR);
			break;
		case GL_EXP:
			m_FogAlgo=GL_EXP;
			glFogi(GL_FOG_MODE,GL_EXP);
			break;
		case GL_EXP2:
			m_FogAlgo=GL_EXP2;
			glFogi(GL_FOG_MODE,GL_EXP2);
			break;
		default :
			m_FogAlgo=GL_LINEAR;
			glFogi(GL_FOG_MODE,GL_LINEAR);
			break;
	}
UnGuard
}

ExCAction ExManagerFog::InputCommand(ExCCommand Command)
{
Guard(ExCAction ExManagerFog::InputCommand(ExCCommand Command))
	return NOTHING;
UnGuard
}

ExCAction ExManagerFog::InputAction(ExCAction Action)
{
Guard(ExCAction ExManagerFog::InputAction(ExCAction Action))
	switch(Action.m_Action)
	{
	case ENABLE_FOG:EnableFog();break;
	case DISABEL_FOG:DisableFog();break;
	case SET_FOG_ALGO_LINEAR:SetAlgo(GL_LINEAR);break;
	case SET_FOG_ALGO_EXP:SetAlgo(GL_EXP);break;
	case SET_FOG_ALGO_EXP2:SetAlgo(GL_LINEAR);break;

	case SET_FOG_COLOR_R:
		try
		{
			SetFogColorR(atof(Action.m_Param.data()));
		}catch(...)
		{
			*Consol<<"Enter a float value"<<std::endl;
		}
		break;

	case SET_FOG_COLOR_G:
		try
		{
			SetFogColorG(atof(Action.m_Param.data()));
		}catch(...)
		{
			*Consol<<"Enter a float value"<<std::endl;
		}
		break;
		
	case SET_FOG_COLOR_B:
		try
		{
			SetFogColorB(atof(Action.m_Param.data()));
		}catch(...)
		{
			*Consol<<"Enter a float value"<<std::endl;
		}
		break;
				
	case SET_FOG_START_POINT:
		try
		{
			SetStartPoint(atof(Action.m_Param.data()));
		}catch(...)
		{
			*Consol<<"Enter a float value"<<std::endl;
		}
		break;
		
	case SET_FOG_END_POINT:
		try
		{
			SetEndPoint(atof(Action.m_Param.data()));
		}catch(...)
		{
			*Consol<<"Enter a float value"<<std::endl;
		}
		break;

	case SET_FOG_DENSITY:
		try
		{
			SetDensity(atof(Action.m_Param.data()));
		}catch(...)
		{
			*Consol<<"Enter a float value"<<std::endl;
		}
		break;
    
	default:
		*Consol<<"Can not file action in FOG_ACTION_MAP"<<std::endl;
		break;
	}	

	if(Action.m_NextAction){return *Action.m_NextAction;}
	else{return NOTHING;}
UnGuard
}
