#include "MW4Headers.hpp"

#include "GUILightAmp.hpp"

#include <ElementRenderer\StateChange.hpp>
#include <ElementRenderer\ScreenQuadsElement.hpp>
#include <ElementRenderer\CameraElement.hpp>

#include <MLR\MLRTexture.hpp>
#include <MLR\MLRTexturePool.hpp>

using MidLevelRenderer::MLRTexturePool;
using MidLevelRenderer::MLRTexture;


//ElementRenderer::CameraElement *GUILightAmp::s_Camera = NULL;
//bool GUILightAmp::s_MarkForAttach = false;

//#######################################################################
//###########################    GUIWeaponManager   #####################
//#######################################################################

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
GUILightAmp::GUILightAmp() :
	Plug(Plug::DefaultData),
	m_screenTiles(NULL),
	s_Camera(NULL)
{
	
	s_MarkForAttach = false;
	m_CurrentMod = 0;
	m_numTiles = 0;
	isShown = false;
	m_LastScreenX = 0;
	m_LastScreenY = 0;

	ChangeResolution();
	Hide();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
GUILightAmp::~GUILightAmp()
{
	if(m_screenTiles.GetCurrent())
	{
		delete m_screenTiles.GetCurrent();
		m_screenTiles.Remove();
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	GUILightAmp::Initialize()
{
	Check_Object(this);

	s_MarkForAttach = false;
	m_numTiles = 0;
	isShown = false;
	ChangeResolution();
	Hide();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void GUILightAmp::SetModifier (Stuff::Scalar mod)
{
	m_CurrentMod = mod;
	SetupTiles ();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void GUILightAmp::SetupTiles (void)
{
	Scalar left,right;
	Scalar top;

	left = m_CurrentMod * 16.0f;
	left = (Scalar) floor (left);
	Clamp (left,0,15);
	right = left + 1;
	left *= 0.0625f;
	right *= 0.0625f;
	top = 0;
	
	Scalar TOffset=gos_GetMachineInformation(gos_Info_TextureOffset) ? 0.0f : 0.5f;

	for(int i=0; i<m_numTiles; i++,top+=256.0f)
	{
		//Pointers into the screen quad
		Vector4D *poly_corners;
		RGBAColor *poly_colors;
		Vector2DOf<Scalar> *poly_UVs;
		bool *poly_status;

		Vector4D corners[4];
		RGBAColor colors[4];
		Vector2DOf<Scalar> UVs[4];

		m_screenTiles.GetCurrent()->GetQuadData(
			i,
			&poly_corners,
			&poly_colors,
			&poly_UVs,
			&poly_status
		);

		colors[0].red = colors[1].red = colors[2].red = colors[3].red = 1.0f;
		colors[0].green = colors[1].green = colors[2].green = colors[3].green = 1.0f;
		colors[0].blue = colors[1].blue = colors[2].blue = colors[3].blue = 1.0f;
		colors[0].alpha = colors[1].alpha = colors[2].alpha = colors[3].alpha = 1.0f;

		Mem_Copy(poly_colors, colors, 4 * sizeof(RGBAColor), 4 * sizeof(RGBAColor));

		UVs[0].x = left;
		UVs[0].y = 0.0f;

		UVs[1].x = right;
		UVs[1].y = 0.0f;

		UVs[2].x = right;
		if((i + 1) <m_numTiles)
			UVs[2].y = 1.0f;
		else
			UVs[2].y = m_Left_Over / 256.0f;

		UVs[3].x = left;
		UVs[3].y = UVs[2].y;

		if( 0.0f==TOffset )
		{
			float TexOffset=0.0625f/256.0f;			//   0.0625/texture size.

			UVs[0].x +=TexOffset;
			UVs[0].y +=TexOffset;
			UVs[1].x +=TexOffset;
			UVs[1].y +=TexOffset;
			UVs[2].x +=TexOffset;
			UVs[2].y +=TexOffset;
			UVs[3].x +=TexOffset;
			UVs[3].y +=TexOffset;
		}

		Mem_Copy(poly_UVs, UVs, 4 * sizeof(Vector2DOf<Scalar>), 4 * sizeof(Vector2DOf<Scalar>));
	
		corners[0].x = 0.0f;
		if(i > 0)
			corners[0].y = ((top-TOffset) / Environment.screenHeight);
		else
			corners[0].y = 0.0f;

		corners[1].x = 1.0f;
		corners[1].y = corners[0].y;

		corners[2].x = 1.0f;
		if((i + 1) <m_numTiles)
			corners[2].y = ((top+256.0f-TOffset) / Environment.screenHeight);
		else
			corners[2].y = 1.0f;

		corners[3].x = 0.0f;
		corners[3].y = corners[2].y;

		corners[0].z = 0.0f;
		corners[0].w = 1.0f;
		corners[1].z = 0.0f;
		corners[1].w = 1.0f;
		corners[2].z = 0.0f;
		corners[2].w = 1.0f;
		corners[3].z = 0.0f;
		corners[3].w = 1.0f;

		Mem_Copy(poly_corners, corners, 4 * sizeof(Vector4D), 4 * sizeof(Vector4D));

		*poly_status = IsOn();
	}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void GUILightAmp::NewVehicle()
{
	m_LastScreenX = 0;
	m_LastScreenY = 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void GUILightAmp::ChangeResolution()
{
	Check_Object(this);

	if ((m_LastScreenX == Environment.screenWidth) && (m_LastScreenY == Environment.screenHeight))
		return;

	m_LastScreenX = Environment.screenWidth;
	m_LastScreenY = Environment.screenHeight;

	if(m_screenTiles.GetCurrent())
	{
		delete m_screenTiles.GetCurrent();
		m_screenTiles.Remove();
	}


	Scalar ratio = 255.0f / Environment.screenHeight;
	int left_over = Environment.screenHeight % 256;

	m_Ratio = ratio;

	m_numTiles = (Environment.screenHeight / 256) + 1;
	m_Left_Over = (left_over);//+m_numTiles-1);
	if (m_Left_Over >= 256)
	{
		m_Left_Over -= 256;
		m_numTiles++;
	}

	gos_PushCurrentHeap(ElementRenderer::ScreenQuadsElement::s_Heap);
	ElementRenderer::ScreenQuadsElement *screen_tiles = new ElementRenderer::ScreenQuadsElement(m_numTiles);

	m_screenTiles.Add(screen_tiles);


	gos_PopCurrentHeap();

	SetupTiles ();

	ElementRenderer::StateChange *state_change = new ElementRenderer::StateChange();
	Check_Object(MLRTexturePool::Instance);
	MLRTexture *quad_texture = (*MLRTexturePool::Instance)("LI", 0);
	if(!quad_texture)
	{
		quad_texture = MLRTexturePool::Instance->Add("LI", 0);
	}
	Check_Object(quad_texture);
	state_change->SetTextureHandle(quad_texture->GetTextureHandle());
//	state_change->SetAlphaMode(ElementRenderer::StateChange::AlphaInvAlphaMode);
//	state_change->SetAlphaMode(MidLevelRenderer::MLRState::OneOneMode);
	state_change->SetAlphaMode(MidLevelRenderer::MLRState::OneInvAlphaMode);
	
	state_change->SetRenderPriority(ElementRenderer::StateChange::HUDPriority0);

	state_change->DisableBackfaceCulling();
	state_change->DisableChildBackfaceControl();

	state_change->SetFogMode(ElementRenderer::StateChange::DisableFogMode);
	state_change->DisableChildFogControl();

	state_change->DisableZBufferWrite();
	state_change->DisableChildZBufferWriteControl();

	state_change->DisableZBufferCompare();
	state_change->DisableChildZBufferCompareControl();

	state_change->DisableTextureWrap();
	state_change->DisableChildTextureWrapControl();
	state_change->DisableChildFilterControl ();
	state_change->SetFilterMode (MidLevelRenderer::MLRStateBase::NoFilterMode);

	screen_tiles->AdoptStateChange(state_change);


	if(s_Camera.GetCurrent() && m_screenTiles.GetCurrent ())
	{
		s_Camera.GetCurrent()->AttachChild(m_screenTiles.GetCurrent());
		m_screenTiles.GetCurrent()->Sync();
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	GUILightAmp::Hide()
{
	Check_Object(this);

	for(int i=0; i<m_numTiles; i++)
	{
		if (m_screenTiles.GetCurrent ())
		{
			m_screenTiles.GetCurrent()->SetQuadStatus(i, false);
		}
	}
	isShown = false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	GUILightAmp::Show()
{
	Check_Object(this);

	if (!m_screenTiles.GetCurrent ())
	{
		ChangeResolution ();
	}
	if (m_screenTiles.GetCurrent ())
	{
		for(int i=0; i<m_numTiles; i++)
		{
			m_screenTiles.GetCurrent()->SetQuadStatus(i, true);
		}
		if(s_MarkForAttach)
		{
			s_Camera.GetCurrent()->AttachChild(m_screenTiles.GetCurrent());
			m_screenTiles.GetCurrent()->Sync();
			s_MarkForAttach = false;
		}
	}

	isShown = true;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	GUILightAmp::AdoptCamera(ElementRenderer::CameraElement *camera)
{
	Check_Pointer(camera);

	if (s_Camera.GetCurrent())
	{
		Verify (s_Camera.GetCurrent () == camera);
		return;
	}


	s_Camera.Add(camera);
	s_MarkForAttach = true;
	
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	GUILightAmp::RemoveCamera()
{
	if (s_Camera.GetCurrent())
	{
		s_Camera.Remove();
	}
	s_MarkForAttach = false;
}