#include "OpenGLUtils.h"
#include "Color.h"
#include "glu.h"

#include <assert.h>
#include <stdexcept>

//////////////////////////////////////////////////////////////
namespace Dubious {
namespace Renderer {

////////////////////////////////////////////////////////////////////////////////////
void OpenGLUtils::ClearColor( const Color& C )
{
	glClearColor( C.Red(), C.Green(), C.Blue(), C.Alpha() );
}

////////////////////////////////////////////////////////////////////////////////////
void OpenGLUtils::LightPosition( int Light, const Math::Vector& Position )
{
	float LightParams[4];
	LightParams[0] = Position.X();
	LightParams[1] = Position.Y();
	LightParams[2] = Position.Z();
	LightParams[3] = 0.0f;	// Directional light (like the sun)
	glLightfv( Light, GL_POSITION, LightParams );

}

////////////////////////////////////////////////////////////////////////////////////
void OpenGLUtils::LightColor( int Light, int Type, const Color& Color )
{
	float LightParams[4];
	LightParams[0] = Color.Red();
	LightParams[1] = Color.Green();
	LightParams[2] = Color.Blue();
	LightParams[3] = Color.Alpha();
	glLightfv( Light, Type, LightParams );
}

//////////////////////////////////////////////////////////////
void OpenGLUtils::Material( int Light, const Color& C )
{
	float RawColour[4];
	RawColour[0] = C.Red();
	RawColour[1] = C.Green();
	RawColour[2] = C.Blue();
	RawColour[3] = C.Alpha();
	// In OpenGL ES you must use the same material for
	// front and back.
	glMaterialfv( GL_FRONT_AND_BACK, Light, RawColour );
}

//////////////////////////////////////////////////////////////
void OpenGLUtils::Perspective( float FOVY, float Aspect, float Near, float Far )
{
	gluPerspective( FOVY, Aspect, Near, Far );
}

//////////////////////////////////////////////////////////////
void OpenGLUtils::Ortho( const Math::RectangleYDown& Rect )
{
	// This function will set up the screen for windowing, ie with the
	// to left being (0,0)
	glOrthof( Rect.Origin().X(), Rect.Dimensions().X()-Rect.Origin().X(),
			  Rect.Dimensions().Y()-Rect.Origin().Y(), Rect.Origin().Y(), 0, 1 );
}

//////////////////////////////////////////////////////////////
void OpenGLUtils::LookAt( const Math::Vector& Position, const Math::Vector& Target,
							const Math::Vector& Up )
{
	gluLookAt( Position.X(), Position.Y(), Position.Z(),
			   Target.X(), Target.Y(), Target.Z(),
			   Up.X(), Up.Y(), Up.Z() );
}

//////////////////////////////////////////////////////////////
void OpenGLUtils::Unproject( const Math::Point& Position, float ModelMatrix[16],
							   float ProjectionMatrix[16],	int Viewport[4], Math::Vector& V )
{
	float X, Y, Z;
	gluUnProject( Position.X(), Position.Y(), 0, ModelMatrix, ProjectionMatrix, Viewport, &X, &Y, &Z );
	V = Math::Vector( X, Y, Z );
}

}
}
