#include "ElementRendererHeaders.hpp"

#include <MLR\MLRTexturePool.hpp>

//############################################################################
//#############################  StateChange  ################################
//############################################################################

Stuff::MemoryBlock*
	ElementRenderer::StateChange::s_AllocatedMemory = NULL;
Stuff::RGBAColor
	ElementRenderer::StateChange::s_fogColor;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::StateChange::InitializeClass()
{
	Verify(!s_AllocatedMemory);
	s_AllocatedMemory =
		new Stuff::MemoryBlock(
			sizeof(StateChange),
			100,
			100,
			"StateChange",
			g_LibraryHeap
		);
	Register_Object(s_AllocatedMemory);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::StateChange::TerminateClass()
{
	Unregister_Object(s_AllocatedMemory);
	delete s_AllocatedMemory;
	s_AllocatedMemory = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::StateChange::StateChange(
	Stuff::MemoryStream *stream,
	int version
)
{
	Check_Pointer(this);
	Check_Object(stream);

	version = (version > 3) ? MidLevelRenderer::ReadMLRVersion(stream) : version;
	m_lights[0] = NULL;
	m_state.Load(stream, version);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::StateChange::StateChange(
	Stuff::Page *page,
	const Stuff::MString &prefix
)
{
	Check_Pointer(this);
	Check_Object(&prefix);
	Check_Object(page);

	//
	//------------------------------
	// Look for the backface control
	//------------------------------
	//
	memset(m_lights, 0, sizeof(m_lights));
	bool backfacing;
	if (page->GetEntry(prefix+"BackfaceCulling", &backfacing))
	{
		if (backfacing)
			EnableBackfaceCulling();
		else
			DisableBackfaceCulling();
		if (
			page->GetEntry(
				prefix+"ChildBackfaceCullingControl",
				&backfacing
			)
		)
		{
			if (backfacing)
				EnableChildBackfaceControl();
			else
				DisableChildBackfaceControl();
		}
	}

	//
	//------------------------------
	// Look for the DrawNow control
	//------------------------------
	//
	bool drawNow;
	if (page->GetEntry(prefix+"DrawNow", &drawNow))
	{
		if (drawNow)
			EnableDrawNow();
		else
			DisableDrawNow();
		if (
			page->GetEntry(
				prefix+"ChildDrawNowControl",
				&backfacing
			)
		)
		{
			if (drawNow)
				EnableChildDrawNowControl();
			else
				DisableChildDrawNowControl();
		}
	}

	//
	//----------------------------------------------------------------------
	// Look for the various blending modes.  We will be initially supporting
	// both naming conventions
	//----------------------------------------------------------------------
	//
	const char* alpha = NULL;
	page->GetEntry(prefix+"Alpha", &alpha);

	//
	//------------------------------------------------------
	// The new syntax takes precedence, so look for it first
	//------------------------------------------------------
	//
	if (alpha)
	{
		Check_Pointer(alpha);
		if (!_stricmp(alpha, "OneZero"))
			SetAlphaMode(MidLevelRenderer::MLRState::OneZeroMode);
		else if (!_stricmp(alpha, "KeyedAlpha"))
			SetAlphaMode(MidLevelRenderer::MLRState::KeyedAlphaMode);
		else if (!_stricmp(alpha, "OneOne"))
			SetAlphaMode(MidLevelRenderer::MLRState::OneOneMode);
		else if (!_stricmp(alpha, "AlphaOne"))
			SetAlphaMode(MidLevelRenderer::MLRState::AlphaOneMode);
		else if (!_stricmp(alpha, "OneAlpha"))
			SetAlphaMode(MidLevelRenderer::MLRState::OneAlphaMode);
		else if (!_stricmp(alpha, "AlphaInvAlpha"))
			SetAlphaMode(MidLevelRenderer::MLRState::AlphaInvAlphaMode);
		else if (!_stricmp(alpha, "OneInvAlpha"))
			SetAlphaMode(MidLevelRenderer::MLRState::OneInvAlphaMode);
		else
			STOP(("Bad alpha mode"));

		bool permission;
		if (page->GetEntry(prefix+"ChildAlphaControl", &permission))
		{
			if (permission)
				EnableChildAlphaControl();
			else
				DisableChildAlphaControl();
		}
	}

	//
	//-------------------------------
	// Look for the dithering control
	//-------------------------------
	//
	bool dithering;
	if (page->GetEntry(prefix+"Dithering", &dithering))
	{
		if (dithering)
			EnableDithering();
		else
			DisableDithering();
		if (page->GetEntry(prefix+"ChildDitheringControl", &dithering))
		{
			if (dithering)
				EnableChildDitheringControl();
			else
				DisableChildDitheringControl();
		}
	}

	//
	//--------------------------
	// Look for the filter modes
	//--------------------------
	//
	const char* filter = NULL;
	if (page->GetEntry(prefix+"Filter", &filter))
	{
		Check_Pointer(filter);
		if (!_stricmp(filter, "PointSample"))
			SetFilterMode(MidLevelRenderer::MLRState::NoFilterMode);
		else if (!_stricmp(filter, "Bilinear"))
			SetFilterMode(MidLevelRenderer::MLRState::BiLinearFilterMode);
		else if (!_stricmp(filter, "Trilinear"))
			SetFilterMode(MidLevelRenderer::MLRState::TriLinearFilterMode);
		else
			STOP(("Bad filter mode"));

		bool permission;
		if (page->GetEntry(prefix+"ChildFilterControl", &permission))
		{
			if (permission)
				EnableChildFilterControl();
			else
				DisableChildFilterControl();
		}
	}

	//
	//-------------------------------
	// Look for the flat_coloring control
	//-------------------------------
	//
	bool flat_coloring;
	if (page->GetEntry(prefix+"FlatColoring", &flat_coloring))
	{
		if (flat_coloring)
			EnableFlatColoring();
		else
			DisableFlatColoring();
		if (page->GetEntry(prefix+"ChildFlatColoringControl", &flat_coloring))
		{
			if (flat_coloring)
				EnableChildFlatColoringControl();
			else
				DisableChildFlatColoringControl();
		}
	}

	//
	//-------------------------
	// Look for the fog control
	//-------------------------
	//
	const char* fog = NULL;
	if (page->GetEntry(prefix+"Fog", &fog))
	{
		Check_Pointer(fog);
		if (!_stricmp(fog, "General") || !_stricmp(fog, "Yes"))
			SetFogMode(ElementRenderer::StateChange::GeneralFogMode);
		else if (!_stricmp(fog, "Light"))
			SetFogMode(ElementRenderer::StateChange::LightFogMode);
		else if (!_stricmp(fog, "Custom"))
			SetFogMode(ElementRenderer::StateChange::CustomFogMode);
		else if (!_stricmp(fog, "Disable") || !_stricmp(fog, "No"))
			SetFogMode(ElementRenderer::StateChange::DisableFogMode);
		else
			STOP(("Bad fog mode"));

		bool permission;
		if (page->GetEntry(prefix+"ChildFogControl", &permission))
		{
			if (permission)
				EnableChildFogControl();
			else
				DisableChildFogControl();
		}
	}

	//
	//----------------------------
	// Look for the lighting modes
	//----------------------------
	//
	bool any_lighting = false;
	bool lighting = false;
	int light_mode = 0;
	if (page->GetEntry(prefix+"LightMapLighting", &lighting))
	{
		any_lighting = true;
		if (lighting)
			light_mode |= MidLevelRenderer::MLRState::LightMapLightingMode;
	}
	if (page->GetEntry(prefix+"VertexLighting", &lighting))
	{
		any_lighting = true;
		if (lighting)
			light_mode |= MidLevelRenderer::MLRState::VertexLightingMode;
	}
	if (page->GetEntry(prefix+"LookupLighting", &lighting))
	{
		any_lighting = true;
		if (lighting)
			light_mode |= MidLevelRenderer::MLRState::LookupLightingMode;
	}
	if (page->GetEntry(prefix+"FaceLighting", &lighting))
	{
		any_lighting = true;
		if (lighting)
			light_mode |= MidLevelRenderer::MLRState::FaceLightingMode;
	}
	if (any_lighting)
		SetLightingMode(light_mode);

	bool permission;
	if (page->GetEntry(prefix+"ChildLightingControl", &permission))
	{
		if (permission)
			EnableChildLightingControl();
		else
			DisableChildLightingControl();
	}

	//
	//--------------------------------------------
	// Look for the perspective correction control
	//--------------------------------------------
	//
	bool correction;
	if (page->GetEntry(prefix+"PerspectiveCorrection", &correction))
	{
		if (correction)
			EnablePerspectiveCorrection();
		else
			DisablePerspectiveCorrection();
		if (
			page->GetEntry(
				prefix+"ChildPerspectiveCorrectionControl",
				&correction
			)
		)
		{
			if (correction)
				EnableChildPerspectiveCorrectionControl();
			else
				DisableChildPerspectiveCorrectionControl();
		}
	}

	//
	//-------------------------
	// Look for the render pass
	//-------------------------
	//
	const char* pass = NULL;
	if (page->GetEntry(prefix+"Priority", &pass))
	{
		Check_Pointer(pass);
		if (!_stricmp(pass, "DefaultPriority"))
			SetRenderPriority(ElementRenderer::StateChange::DefaultPriority);
		else if (!_stricmp(pass, "DetailPriority"))
			SetRenderPriority(ElementRenderer::StateChange::DetailPriority);
		else if (!_stricmp(pass, "AlphaPriority"))
			SetRenderPriority(ElementRenderer::StateChange::AlphaPriority);
		else if (!_stricmp(pass, "EffectPriority0"))
			SetRenderPriority(ElementRenderer::StateChange::EffectPriority0);
		else if (!_stricmp(pass, "EffectPriority1"))
			SetRenderPriority(ElementRenderer::StateChange::EffectPriority1);
		else if (!_stricmp(pass, "EffectPriority2"))
			SetRenderPriority(ElementRenderer::StateChange::EffectPriority2);
		else if (!_stricmp(pass, "EffectPriority3"))
			SetRenderPriority(ElementRenderer::StateChange::EffectPriority3);
		else if (!_stricmp(pass, "WeatherPriority"))
			SetRenderPriority(ElementRenderer::StateChange::WeatherPriority);
		else if (!_stricmp(pass, "CagePriority"))
			SetRenderPriority(ElementRenderer::StateChange::CagePriority);
		else if (!_stricmp(pass, "CageDashPriority"))
			SetRenderPriority(ElementRenderer::StateChange::CageEffectsPriority);
		else if (!_stricmp(pass, "CageEffectsPriority"))
			SetRenderPriority(ElementRenderer::StateChange::FlarePriority);
		else if (!_stricmp(pass, "FlarePriority"))
			SetRenderPriority(ElementRenderer::StateChange::FlarePriority);
		else if (!_stricmp(pass, "HUDPriority0"))
			SetRenderPriority(ElementRenderer::StateChange::HUDPriority0);
		else if (!_stricmp(pass, "HUDPriority1"))
			SetRenderPriority(ElementRenderer::StateChange::HUDPriority1);
		else if (!_stricmp(pass, "HUDPriority2"))
			SetRenderPriority(ElementRenderer::StateChange::HUDPriority2);
		else if (!_stricmp(pass, "HUDPriority3"))
			SetRenderPriority(ElementRenderer::StateChange::HUDPriority3);
		else
			STOP(("Bad priority"));

		bool permission;
		if (page->GetEntry(prefix+"ChildPriorityControl", &permission))
		{
			if (permission)
				EnableChildRenderPriorityControl();
			else
				DisableChildRenderPriorityControl();
		}
	}
	else if (page->GetEntry(prefix+"RenderPass", &pass))
	{
		Check_Pointer(pass);
		if (!_stricmp(pass, "DefaultPass") || !_stricmp(pass, "DefaultPriority"))
			SetRenderPriority(ElementRenderer::StateChange::DefaultPriority);
		else if (!_stricmp(pass, "DetailPriority"))
			SetRenderPriority(ElementRenderer::StateChange::DetailPriority);
		else if (!_stricmp(pass, "AlphaPass") || !_stricmp(pass, "AlphaPriority"))
			SetRenderPriority(ElementRenderer::StateChange::AlphaPriority);
		else if (!_stricmp(pass, "EffectPriority0"))
			SetRenderPriority(ElementRenderer::StateChange::EffectPriority0);
		else if (!_stricmp(pass, "EffectPriority1"))
			SetRenderPriority(ElementRenderer::StateChange::EffectPriority1);
		else if (!_stricmp(pass, "EffectPriority2"))
			SetRenderPriority(ElementRenderer::StateChange::EffectPriority2);
		else if (!_stricmp(pass, "EffectPriority3"))
			SetRenderPriority(ElementRenderer::StateChange::EffectPriority3);
		else if (!_stricmp(pass, "WeatherPriority"))
			SetRenderPriority(ElementRenderer::StateChange::WeatherPriority);
		else if (!_stricmp(pass, "CagePriority"))
			SetRenderPriority(ElementRenderer::StateChange::CagePriority);
		else if (!_stricmp(pass, "CageDashPriority"))
			SetRenderPriority(ElementRenderer::StateChange::CageEffectsPriority);
		else if (!_stricmp(pass, "CageEffectsPriority"))
			SetRenderPriority(ElementRenderer::StateChange::FlarePriority);
		else if (!_stricmp(pass, "FlarePriority"))
			SetRenderPriority(ElementRenderer::StateChange::FlarePriority);
		else if (!_stricmp(pass, "HUDPriority0") || !_stricmp(pass, "PostPass2"))
			SetRenderPriority(ElementRenderer::StateChange::HUDPriority0);
		else if (!_stricmp(pass, "HUDPriority1"))
			SetRenderPriority(ElementRenderer::StateChange::HUDPriority1);
		else if (!_stricmp(pass, "HUDPriority2"))
			SetRenderPriority(ElementRenderer::StateChange::HUDPriority2);
		else if (!_stricmp(pass, "HUDPriority3"))
			SetRenderPriority(ElementRenderer::StateChange::HUDPriority3);
		else
			STOP(("Bad render pass"));

		bool permission;
		if (page->GetEntry(prefix+"ChildRenderPriorityControl", &permission))
		{
			if (permission)
				EnableChildRenderPriorityControl();
			else
				DisableChildRenderPriorityControl();
		}
	}

	//
	//------------------------------
	// Look for the specular control
	//------------------------------
	//
	bool specular;
	if (page->GetEntry(prefix+"Specular", &specular))
	{
		if (specular)
			EnableSpecular();
		else
			DisableSpecular();
		if (
			page->GetEntry(
				prefix+"ChildSpecularControl",
				&specular
			)
		)
		{
			if (specular)
				EnableChildSpecularControl();
			else
				DisableChildSpecularControl();
		}
	}

	//
	//----------------------------
	// Look for the texture handle
	//----------------------------
	//
	const char* texture_name = NULL;
	if (page->GetEntry(prefix+"Texture", &texture_name))
	{
		Check_Object(MidLevelRenderer::MLRTexturePool::Instance);
		MidLevelRenderer::MLRTexture* texture =
			(*MidLevelRenderer::MLRTexturePool::Instance)(texture_name);
		if (!texture)
			texture = MidLevelRenderer::MLRTexturePool::Instance->Add(texture_name);
		Check_Object(texture);
		int handle = texture->GetTextureHandle();
		SetTextureHandle(handle);
		bool permission;
		if (page->GetEntry(prefix+"ChildTextureControl", &permission))
		{
			if (permission)
				EnableChildTextureHandleControl();
			else
				DisableChildTextureHandleControl();
		}
	}

	//
	//----------------------------------
	// Look for the texture wrap control
	//----------------------------------
	//
	bool wrap;
	if (page->GetEntry(prefix+"TextureWrap", &wrap))
	{
		if (wrap)
			EnableTextureWrap();
		else
			DisableTextureWrap();
		if (
			page->GetEntry(
				prefix+"ChildTextureWrapControl",
				&wrap
			)
		)
		{
			if (wrap)
				EnableChildTextureWrapControl();
			else
				DisableChildTextureWrapControl();
		}
	}

	//
	//-------------------------------------
	// Look for the various Wireframe modes
	//-------------------------------------
	//
	const char* wireframe = NULL;
	if (page->GetEntry(prefix+"WireFrame", &wireframe))
	{
		Check_Pointer(wireframe);
		if (!_stricmp(wireframe, "Solid"))
			SetWireFrameMode(MidLevelRenderer::MLRState::WireFrameOffMode);
		else if (!_stricmp(wireframe, "Wire"))
			SetWireFrameMode(MidLevelRenderer::MLRState::WireFrameOnlyMode);
		else if (!_stricmp(wireframe, "SolidAndWire"))
			SetWireFrameMode(MidLevelRenderer::MLRState::WireFrameAddMode);
		else
			STOP(("Bad wireframe mode"));

		bool permission;
		if (page->GetEntry(prefix+"ChildWireFrameControl", &permission))
		{
			if (permission)
				EnableChildWireFrameControl();
			else
				DisableChildWireFrameControl();
		}
	}

	//
	//-----------------------------------
	// Look for the Zbuffer write control
	//-----------------------------------
	//
	bool write;
	if (page->GetEntry(prefix+"ZBufferWrite", &write))
	{
		if (write)
			EnableZBufferWrite();
		else
			DisableZBufferWrite();
		if (
			page->GetEntry(
				prefix+"ChildZBufferWriteControl",
				&write
			)
		)
		{
			if (write)
				EnableChildZBufferWriteControl();
			else
				DisableChildZBufferWriteControl();
		}
	}

	//
	//-------------------------------------
	// Look for the Zbuffer compare control
	//-------------------------------------
	//
	bool compare;
	if (page->GetEntry(prefix+"ZBufferCompare", &compare))
	{
		if (compare)
			EnableZBufferCompare();
		else
			DisableZBufferCompare();
		if (
			page->GetEntry(
				prefix+"ChildZBufferCompareControl",
				&compare
			)
		)
		{
			if (compare)
				EnableChildZBufferCompareControl();
			else
				DisableChildZBufferCompareControl();
		}
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::StateChange::Load(
		Stuff::MemoryStream *stream,
		int version
	)
{
	Check_Object(this);
	Check_Object(stream);

	version = (version > 3) ? MidLevelRenderer::ReadMLRVersion(stream) : version;
	m_state.Load(stream, version);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::StateChange::Save(Stuff::MemoryStream *stream)
{
	Check_Object(this);
	Check_Object(stream);

	MidLevelRenderer::WriteMLRVersion(stream);
	m_state.Save(stream);
}
