#include "MW4Headers.hpp"

#include "MWVideoRenderer.hpp"
#include "MWGUIManager.hpp"
#include "Objective.hpp"
#include "MWApplication.hpp"
#include "GUILightAmp.hpp"
#include "GUIStaticView.hpp"

#include <Adept\GUITextManager.hpp>
#include <Adept\CameraComponent.hpp>
#include <ElementRenderer\CameraElement.hpp>
#include <Adept\Tool.hpp>
#include <MLR\MLRTexturePool.hpp>
#include <Adept\Application.hpp>

char g_SkinSet = g_SkinSignal;
int g_PilotDecal = 0;
int g_TeamDecal = 0;

static const char* Skinner(const char* old_skin)
{
	//
	//-------------------------------------------------------------------
	// If the skin name starts with an underscore, replace the underscore
	//-------------------------------------------------------------------
	//
	Verify(old_skin[1] != g_SkinSignal);
	static char Skin_Name[255];
	if (*old_skin == '_')
	{
		Str_Copy(Skin_Name, old_skin, sizeof(Skin_Name));
		*Skin_Name = g_SkinSet;
		return Skin_Name;
	}

	//
	//--------------------------------------------------------------------
	// If the skin name starts with the compositing signal, pre-append the
	// skin letter to the detail texture name
	//--------------------------------------------------------------------
	//
	if (*old_skin == g_SkinSignal)
	{
		if (!stricmp(old_skin, "@pilot"))
			return MWApplication::GetInstance()->GetDecalName(g_PilotDecal);
		if (!stricmp(old_skin, "@team"))
			return MWApplication::GetInstance()->GetDecalName(g_TeamDecal);
		*Skin_Name = g_SkinSet;
		Str_Copy(Skin_Name+1, old_skin, sizeof(Skin_Name)-1);
		return Skin_Name;
	}

	//
	//--------------------------------
	// Otherwise, the name is ok as is
	//--------------------------------
	//
	return old_skin;
}

//#############################################################################
// Shared Data Support
//
MWVideoRenderer::ClassData*
	MWVideoRenderer::DefaultData = NULL;

DECLARE_TIMER(static, GUITime);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWVideoRenderer::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			MWVideoRendererClassID,
			"MechWarrior4::MWVideoRenderer",
			VideoRenderer::DefaultData,
			0,
			NULL
		);
	Register_Object(DefaultData);

	Initialize_Timer(GUITime, "GUI Time");
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWVideoRenderer::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWVideoRenderer::MWVideoRenderer(bool display_gui):
	VideoRenderer(DefaultData)
{
	Check_Pointer(this);

	Verify(!MWGUIManager::GetInstance());
	Verify(Adept::Application::GetInstance() != NULL);

	if (display_gui)
	{
		GlobalPointers::AddGlobalPointer( new MWGUIManager(), MWGUIManagerGlobalPointerIndex);
		Register_Object(MWGUIManager::GetInstance());
	}

	Verify(!ObjectiveRenderer::Instance);
	ObjectiveRenderer::Instance = new ObjectiveRenderer();
	Register_Object(ObjectiveRenderer::Instance);

	fadeLevel = 0.0f;
	drawCinemaScope = false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWVideoRenderer::~MWVideoRenderer()
{
	if (MWGUIManager::GetInstance())
	{
		Unregister_Object(MWGUIManager::GetInstance());
		delete MWGUIManager::GetInstance();
		GlobalPointers::ClearPointer(MWGUIManagerGlobalPointerIndex);
	}

	Unregister_Object(ObjectiveRenderer::Instance);
	delete ObjectiveRenderer::Instance;
	ObjectiveRenderer::Instance = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

int static black_render_counter = 5;


void MWVideoRenderer::SetDrawBlack()
{
	black_render_counter = 0;
}

void
	MWVideoRenderer::ExecuteImplementation(Time target_render_time)
{



	//
	//-----------------------------------
	// Execute the executeable components
	//-----------------------------------
	//
	gos_PushCurrentHeap(Heap);
	VideoRenderer::ExecuteImplementation(target_render_time);

	RENDER("HUD");
	Start_Timer(GUITime);
	if (MWGUIManager::GetInstance())
	{
		Check_Object(MWGUIManager::GetInstance());
		MWGUIManager::GetInstance()->Execute();
	}

	Check_Object(GUITextManager::GetInstance());
	GUITextManager::GetInstance()->Execute();

	if (MW4AI::DebugRenderer::GetInstance() != 0)
	{
		MW4AI::DebugRenderer::GetInstance()->Execute();
	}

	m_DebugHelper.Execute();


	if (fadeLevel > 0.0f)
		DrawFade();

	if (drawCinemaScope)
		DrawCinemaScope();


	if (Application::GetInstance()->GetApplicationState() == ApplicationStateEngine::RunningGameState)
	{	
		if (black_render_counter < 4)
		{
			Scalar temp_fade_level = fadeLevel;
			fadeLevel = 1.0f;
			DrawFade();
			fadeLevel = temp_fade_level;
			black_render_counter++;
		}
	}
	

	Stop_Timer(GUITime);
	gos_PopCurrentHeap();

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWVideoRenderer::EntityIsInteresting(
		Entity *entity,
		bool render_me
	)
{
	Check_Object(this);
	Check_Object(entity);
	VIDEO_LOAD("EntityIsInteresting");

	//
	//----------------------------------------------------------------------
	// If this object already has a web, we just have to turn the web on/off
	//----------------------------------------------------------------------
	//
	VideoComponentWeb *web =
		static_cast<VideoComponentWeb*>(entity->GetComponentWeb(rendererType));
	Element* node = entity->GetElement();
	Check_Object(node);
	if (web)
	{
		Check_Object(web);
		web->SetInterest(render_me);
		if (!render_me)
			return;
	}

	//
	//--------------------------------------
	// Create a component web for the entity
	//--------------------------------------
	//
	else
	{
		VIDEO_LOAD("EntityIsInteresting::Web");
		const ResourceID &resources =
			entity->GetRendererDataResourceID(rendererType);

		//
		//---------------------------------------------------------------------
		// If there are no resources, or if we aren't to be rendered, just sync
		// the matrices
		//---------------------------------------------------------------------
		//
		if (!resources || !render_me)
		{
			entity->NeedMatrixSync();
			if (!node->AreBoundsLocked())
				node->NeedNewBounds();
			entity->SyncMatrices(true);
			return;
		}

		//
		//---------------------------------
		// Set up the options for the skins
		//---------------------------------
		//
		MidLevelRenderer::MLRTexturePool::Skinner old_skinner =
			MidLevelRenderer::MLRTexturePool::Instance->GetSkinner();
		MidLevelRenderer::MLRTexturePool::Instance->SetSkinner(Skinner);

		//
		//----------------------------------------------------------------------
		// We will be building a web, so allocate it and attach it to the entity
		//----------------------------------------------------------------------
		//
		gos_PushCurrentHeap(s_Heap);
		web =
			new VideoComponentWeb(
				VideoComponentWeb::DefaultData,
   				entity,
   				this,
   				resources,
   				NULL
   			);
		Register_Object(web);
		entity->SetComponentWeb(rendererType, web);

		//
		//-------------------------------------------------
		// Now, load up the web from the specified resource
		//-------------------------------------------------
		//
		Resource script(resources);
		web->LoadFromStream(&script);

		//
		//----------------------------------------------------------------------
		// Now, spin through and hook up the specified components to the locator
		//----------------------------------------------------------------------
		//
		ComponentID component_id;
		component_id.scriptResourceID = resources;
		script >> component_id.componentNumber;
		while (component_id.componentNumber != -1)
		{
			Component *component = web->FindComponent(component_id);
			Check_Object(component);
			VideoComponent *child = Cast_Object(VideoComponent*, component);
			Element *child_node = child->GetElement();
			Check_Object(child_node);
			node->AttachChild(child_node);
			script >> component_id.componentNumber;
		}
		gos_PopCurrentHeap();
		MidLevelRenderer::MLRTexturePool::Instance->SetSkinner(old_skinner);
	}

	//
	//-----------------------
	// Execute the components
	//-----------------------
	//
	{
		VIDEO_LOAD("EntityIsInteresting::Sync & Execute");
		entity->NeedMatrixSync();
		entity->SyncMatrices(true);
		web->ExecuteWatcherComponents();
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void MWVideoRenderer::DrawCinemaScope(void)
{

	gos_SetRenderState( gos_State_Texture, 0 );
	gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_OneZero );
	gos_SetRenderState( gos_State_Clipping, 0 );
	gos_SetRenderState( gos_State_ZWrite, 0 );
	gos_SetRenderState( gos_State_Filter, gos_FilterNone );
	gos_SetRenderState( gos_State_ZCompare, 0 );
	gos_SetRenderState( gos_State_WireframeMode, 0 );
	gos_SetRenderState( gos_State_Specular, 0 );
	gos_SetRenderState( gos_State_Dither, 0 );
	gos_SetRenderState( gos_State_ShadeMode, gos_ShadeFlat );
	gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );
	gos_SetRenderState( gos_State_AlphaTest, 0 );
	gos_SetRenderState( gos_State_Fog, 0 );
	//First we need to Draw the Quad for the Window
	gos_VERTEX quad_verticies[4];


	RGBAColor color(0.0f, 0.0f, 0.0f, 0.0f);

	
	Stuff::Scalar wide_screen_height = (float)Environment.screenWidth / cinemaScopeRatio;

	Stuff::Scalar half = (float)Environment.screenHeight * 0.5f;

	Stuff::Scalar top_half_border = half - (wide_screen_height*0.5f);
	Stuff::Scalar bottom_half_border = half + (wide_screen_height*0.5f);



	quad_verticies[0].rhw	= 1.0;
	quad_verticies[1].rhw	= 1.0;
	quad_verticies[2].rhw	= 1.0;
	quad_verticies[3].rhw	= 1.0;

	quad_verticies[0].x		= 0.0f;
	quad_verticies[0].y		= 0.0f;
	quad_verticies[0].z		= 0.9f;
	quad_verticies[0].argb	= MidLevelRenderer::GOSCopyColor(&color);

	quad_verticies[1].x		= (float)Environment.screenWidth;
	quad_verticies[1].y		= 0.0f;
	quad_verticies[1].z		= 0.9f;
	quad_verticies[1].argb	= MidLevelRenderer::GOSCopyColor(&color);

	quad_verticies[2].x		= (float)Environment.screenWidth;
	quad_verticies[2].y		= top_half_border;
	quad_verticies[2].z		= 0.9f;
	quad_verticies[2].argb	= MidLevelRenderer::GOSCopyColor(&color);

	quad_verticies[3].x		= 0.0f;
	quad_verticies[3].y		= top_half_border;
	quad_verticies[3].z		= 0.9f;
	quad_verticies[3].argb	= MidLevelRenderer::GOSCopyColor(&color);

	gos_DrawQuads(quad_verticies, 4);



	quad_verticies[0].x		= 0.0f;
	quad_verticies[0].y		= bottom_half_border;
	quad_verticies[0].z		= 0.9f;
	quad_verticies[0].argb	= MidLevelRenderer::GOSCopyColor(&color);

	quad_verticies[1].x		= (float)Environment.screenWidth;
	quad_verticies[1].y		= bottom_half_border;
	quad_verticies[1].z		= 0.9f;
	quad_verticies[1].argb	= MidLevelRenderer::GOSCopyColor(&color);

	quad_verticies[2].x		= (float)Environment.screenWidth;
	quad_verticies[2].y		= (float)Environment.screenHeight;
	quad_verticies[2].z		= 0.9f;
	quad_verticies[2].argb	= MidLevelRenderer::GOSCopyColor(&color);

	quad_verticies[3].x		= 0.0f;
	quad_verticies[3].y		= (float)Environment.screenHeight;
	quad_verticies[3].z		= 0.9f;
	quad_verticies[3].argb	= MidLevelRenderer::GOSCopyColor(&color);

	gos_DrawQuads(quad_verticies, 4);


}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWVideoRenderer::DrawFade(void)
{
	gos_SetRenderState( gos_State_Texture, 0 );
	gos_SetRenderState( gos_State_AlphaMode, gos_Alpha_AlphaInvAlpha );
	gos_SetRenderState( gos_State_Clipping, 0 );
	gos_SetRenderState( gos_State_ZWrite, 0 );
	gos_SetRenderState( gos_State_Filter, gos_FilterNone );
	gos_SetRenderState( gos_State_ZCompare, 0 );
	gos_SetRenderState( gos_State_WireframeMode, 0 );
	gos_SetRenderState( gos_State_Specular, 0 );
	gos_SetRenderState( gos_State_Dither, 0 );
	gos_SetRenderState( gos_State_ShadeMode, gos_ShadeFlat );
	gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );
	gos_SetRenderState( gos_State_AlphaTest, 0 );
	gos_SetRenderState( gos_State_Fog, 0 );
	//First we need to Draw the Quad for the Window
	gos_VERTEX quad_verticies[4];


	RGBAColor color(fadeColor.red, fadeColor.blue, fadeColor.green, fadeLevel);


	quad_verticies[0].rhw	= 1.0;
	quad_verticies[1].rhw	= 1.0;
	quad_verticies[2].rhw	= 1.0;
	quad_verticies[3].rhw	= 1.0;

	quad_verticies[0].x		= 0.0f;
	quad_verticies[0].y		= 0.0f;
	quad_verticies[0].z		= 0.9f;
	quad_verticies[0].argb	= MidLevelRenderer::GOSCopyColor(&color);

	quad_verticies[1].x		= (float)Environment.screenWidth;
	quad_verticies[1].y		= 0.0f;
	quad_verticies[1].z		= 0.9f;
	quad_verticies[1].argb	= MidLevelRenderer::GOSCopyColor(&color);

	quad_verticies[2].x		= (float)Environment.screenWidth;
	quad_verticies[2].y		= (float)Environment.screenHeight;
	quad_verticies[2].z		= 0.9f;
	quad_verticies[2].argb	= MidLevelRenderer::GOSCopyColor(&color);

	quad_verticies[3].x		= 0.0f;
	quad_verticies[3].y		= (float)Environment.screenHeight;
	quad_verticies[3].z		= 0.9f;
	quad_verticies[3].argb	= MidLevelRenderer::GOSCopyColor(&color);

	gos_DrawQuads(quad_verticies, 4);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWVideoRenderer::SetCamera(CameraComponent *camera)
{
	Check_Object(this);

	if (camera != NULL)
	{
		MWGUIManager *gui;
		gui = MWGUIManager::GetInstance ();

		if(gui)
		{
		gui->lightAmp->AdoptCamera (camera->GetElement());
//		GUILightAmp::AdoptCamera(camera->GetElement());
		GUIStaticView::AdoptCamera(camera->GetElement());
		}
	}
	else
	{
		MWGUIManager *gui;
		gui = MWGUIManager::GetInstance ();
		if(gui)
		{
		gui->lightAmp->RemoveCamera ();
//		GUILightAmp::RemoveCamera();
		GUIStaticView::RemoveCamera();
		}
	}

	VideoRenderer::SetCamera(camera);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	MWVideoRenderer::TestInstance() const
{
	Verify(IsDerivedFrom(DefaultData));
}
