#pragma once

#include "ElementRenderer.hpp"
#include <MLR\MLR.hpp>

namespace ElementRenderer {

	class Element;

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

	class StateChange
		#if defined(_ARMOR)
			: public Stuff::Signature
		#endif
	{
		friend class Element;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Initialization
	//
	public:
		static void
			InitializeClass();
		static void
			TerminateClass();

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Constructors/Destructors
	//
	public:
		StateChange()
			{Check_Pointer(this); m_lights[0] = NULL;}
		StateChange(const StateChange &state)
			{Check_Pointer(this); m_state = state.m_state; m_lights[0] = NULL;}
		StateChange(
			Stuff::MemoryStream *stream,
			int version
		);
		StateChange(
			Stuff::Page *page,
			const Stuff::MString &prefix
		);

		~StateChange()
			{Check_Object(this);}

		void
			Save(Stuff::MemoryStream *stream);
		void
			Load(
				Stuff::MemoryStream *stream,
				int version
			);

		void
			Mix(
				const StateChange &parent,
				const StateChange &child
			)
				{
					Check_Object(this); Check_Object(&parent); Check_Object(&child);
					m_state.Combine(parent.m_state, child.m_state);
				}

		const MidLevelRenderer::MLRState&
			GetMLRState() const
				{Check_Object(this); return m_state;}

		void
			SetMLRState(const MidLevelRenderer::MLRState&state) 
				{Check_Object(this); m_state=state;}

		void*
			operator new(size_t size)
				{
					Verify(size == sizeof(StateChange));
					return s_AllocatedMemory->New();
				}
		void
			operator delete(void *where)
				{s_AllocatedMemory->Delete(where);}

		bool
			operator==(const StateChange &s) const
				{
					Check_Pointer(this);
					return
						m_state == s.m_state;
				}

	protected:
		MidLevelRenderer::MLRState
			m_state;

	private:
		static Stuff::MemoryBlock
			*s_AllocatedMemory;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Testing
	//
	public:
		bool
			IsRealStateChange()
				{
					Check_Object(this);
					return
						(m_state.GetRenderDeltaMask()|m_state.GetProcessDeltaMask()) != 0;
				}
		void
			TestInstance() const
				{}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Blending Mode
	//
	public:
		void
			SetAlphaMode(MidLevelRenderer::MLRState::AlphaMode mode)
				{Check_Object(this); m_state.SetAlphaMode(mode);}
		MidLevelRenderer::MLRState::AlphaMode
			GetAlphaMode()
				{Check_Object(this); return m_state.GetAlphaMode();}

		void
			DisableChildAlphaControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() & ~MidLevelRenderer::MLRState::AlphaMask
					);
				}
		void
			EnableChildAlphaControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() | MidLevelRenderer::MLRState::AlphaMask
					);
				}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Backface control
	//
	public:
		void
			EnableBackfaceCulling()
				{Check_Object(this); m_state.SetBackFaceOn();}
		void
			DisableBackfaceCulling()
				{Check_Object(this); m_state.SetBackFaceOff();}
		bool
			IsBackfaceCullingEnabled()
				{
					Check_Object(this);
					return m_state.GetBackFaceMode()==MidLevelRenderer::MLRState::BackFaceOnMode;
				}

		void
			DisableChildBackfaceControl()
				{
					Check_Object(this);
					m_state.SetProcessPermissionMask(
						m_state.GetProcessPermissionMask() & ~MidLevelRenderer::MLRState::BackFaceMask
					);
				}
		void
			EnableChildBackfaceControl()
				{
					Check_Object(this);
					m_state.SetProcessPermissionMask(
						m_state.GetProcessPermissionMask() | MidLevelRenderer::MLRState::BackFaceMask
					);
				}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Dithering Mode
	//
	public:
		void
			EnableDithering()
				{Check_Object(this); m_state.SetDitherOn();}
		void
			DisableDithering()
				{Check_Object(this); m_state.SetDitherOff();}
		bool
			IsDitheringEnabled()
				{
					Check_Object(this);
					return m_state.GetDitherMode()==MidLevelRenderer::MLRState::DitherOnMode;
				}

		void
			DisableChildDitheringControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() & ~MidLevelRenderer::MLRState::DitherMask
					);
				}
		void
			EnableChildDitheringControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() | MidLevelRenderer::MLRState::DitherMask
					);
				}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// DrawNow control
	//
	public:
		void
			EnableDrawNow()
				{Check_Object(this); m_state.SetDrawNowOn();}
		void
			DisableDrawNow()
				{Check_Object(this); m_state.SetBackFaceOff();}
		bool
			IsDrawNowEnabled()
				{
					Check_Object(this);
					return m_state.GetDrawNowMode()==MidLevelRenderer::MLRState::DrawNowOnMode;
				}

		void
			DisableChildDrawNowControl()
				{
					Check_Object(this);
					m_state.SetProcessPermissionMask(
						m_state.GetProcessPermissionMask() & ~MidLevelRenderer::MLRState::DrawNowMask
					);
				}
		void
			EnableChildDrawNowControl()
				{
					Check_Object(this);
					m_state.SetProcessPermissionMask(
						m_state.GetProcessPermissionMask() | MidLevelRenderer::MLRState::DrawNowMask
					);
				}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Filter Control
	//
	public:
		void
			SetFilterMode(MidLevelRenderer::MLRState::FilterMode mode)
				{Check_Object(this); m_state.SetFilterMode(mode);}
		MidLevelRenderer::MLRState::FilterMode
			GetFilterMode()
				{Check_Object(this); return m_state.GetFilterMode();}

		void
			DisableChildFilterControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() & ~MidLevelRenderer::MLRState::FilterMask
					);
				}
		void
			EnableChildFilterControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() | MidLevelRenderer::MLRState::FilterMask
					);
				}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// FlatColoring Mode
	//
	public:
		void
			EnableFlatColoring()
				{Check_Object(this); m_state.SetFlatColoringOn();}
		void
			DisableFlatColoring()
				{Check_Object(this); m_state.SetFlatColoringOff();}
		bool
			IsFlatColoringEnabled()
				{Check_Object(this); return m_state.GetFlatColoringMode()==MidLevelRenderer::MLRState::FlatColoringOnMode;}

		void
			DisableChildFlatColoringControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() & ~MidLevelRenderer::MLRState::FlatColoringMask
					);
				}
		void
			EnableChildFlatColoringControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() | MidLevelRenderer::MLRState::FlatColoringMask
					);
				}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Fogging Mode
	//
	public:
		enum FogMode {
			DisableFogMode,
			GeneralFogMode,
			LightFogMode,
			CustomFogMode
		};

		void
			SetFogMode(FogMode mode)
				{Check_Object(this); m_state.SetFogMode(mode);}
		FogMode
			GetFogMode()
				{
					Check_Object(this); int mode = m_state.GetFogMode();
					Verify(mode >= 0 && mode <= 3); return static_cast<FogMode>(mode);
				}

		void
			DisableChildFogControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() & ~MidLevelRenderer::MLRState::FogMask
					);
				}
		void
			EnableChildFogControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() | MidLevelRenderer::MLRState::FogMask
					);
				}

		static const Stuff::RGBAColor&
			GetFogColor()
				{return s_fogColor;}
		static void
			SetFogColor(const Stuff::RGBAColor& color)
				{
					s_fogColor = color;
					MidLevelRenderer::MLRState::fogColor = MidLevelRenderer::GOSCopyColor(&color);
				}

	protected:
		static Stuff::RGBAColor
			s_fogColor;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Lighting Control
	//
	public:
		void
			SetLightingMode(int mode)
				{Check_Object(this); m_state.SetLightingMode(mode);}
		int
			GetLightingMode()
				{Check_Object(this); return m_state.GetLightingMode();}

		void
			DisableChildLightingControl()
				{
					Check_Object(this);
					m_state.SetProcessPermissionMask(
						m_state.GetProcessPermissionMask() & ~MidLevelRenderer::MLRState::LightingMask
					);
				}
		void
			EnableChildLightingControl()
				{
					Check_Object(this);
					m_state.SetProcessPermissionMask(
						m_state.GetProcessPermissionMask() | MidLevelRenderer::MLRState::LightingMask
					);
				}

		LightList
			m_lights;

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Perspective correction Mode
	//
	public:
		void
			EnablePerspectiveCorrection()
				{Check_Object(this); m_state.SetTextureCorrectionOn();}
		void
			DisablePerspectiveCorrection()
				{Check_Object(this); m_state.SetTextureCorrectionOff();}
		bool
			IsPerspectiveCorrectionEnabled()
				{
					Check_Object(this);
					return m_state.GetTextureCorrectionMode()==MidLevelRenderer::MLRState::TextureCorrectionOnMode;
				}

		void
			DisableChildPerspectiveCorrectionControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() & ~MidLevelRenderer::MLRState::TextureCorrectionMask
					);
				}
		void
			EnableChildPerspectiveCorrectionControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() | MidLevelRenderer::MLRState::TextureCorrectionMask
					);
				}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Priority control
	//
	public:
		enum RenderPriority {
			DefaultPriority=0,
			DetailPriority,
			AlphaPriority,
			EffectPriority0=4,
			EffectPriority1,
			EffectPriority2,
			EffectPriority3,
			WeatherPriority,
			CagePriority,
			CageEffectsPriority,
			FlarePriority,
			HUDPriority0,
			HUDPriority1,
			HUDPriority2,
			HUDPriority3
		};

		void
			SetRenderPriority(RenderPriority pass)
				{Check_Object(this); m_state.SetPriority(pass);}
		RenderPriority
			GetRenderPriority()
				{Check_Object(this); return static_cast<RenderPriority>(m_state.GetPriority());}

		void
			DisableChildRenderPriorityControl()
				{
					Check_Object(this);
					m_state.SetProcessPermissionMask(
						m_state.GetProcessPermissionMask() & ~MidLevelRenderer::MLRState::PriorityMask
					);
				}
		void
			EnableChildRenderPriorityControl()
				{
					Check_Object(this);
					m_state.SetProcessPermissionMask(
						m_state.GetProcessPermissionMask() | MidLevelRenderer::MLRState::PriorityMask
					);
				}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Specular Mode
	//
	public:
		void
			EnableSpecular()
				{Check_Object(this); m_state.SetSpecularOn();}
		void
			DisableSpecular()
				{Check_Object(this); m_state.SetSpecularOff();}
		bool
			IsSpecularEnabled()
				{
					Check_Object(this);
					return m_state.GetSpecularMode()==MidLevelRenderer::MLRState::SpecularOnMode;
				}

		void
			DisableChildSpecularControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() & ~MidLevelRenderer::MLRState::SpecularMask
					);
				}
		void
			EnableChildSpecularControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() | MidLevelRenderer::MLRState::SpecularMask
					);
				}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Texture control
	//
	public:
		void
			SetTextureHandle(unsigned handle)
				{Check_Object(this); m_state.SetTextureHandle(handle);}
		unsigned
			GetTextureHandle()
				{Check_Object(this); return m_state.GetTextureHandle();}

		void
			DisableChildTextureHandleControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() & ~MidLevelRenderer::MLRState::TextureMask
					);
				}
		void
			EnableChildTextureHandleControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() | MidLevelRenderer::MLRState::TextureMask
					);
				}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// Texture wrap Mode
	//
	public:
		void
			EnableTextureWrap()
				{Check_Object(this); m_state.SetTextureWrapMode(MidLevelRenderer::MLRState::TextureWrap);}
		void
			DisableTextureWrap()
				{Check_Object(this); m_state.SetTextureWrapMode(MidLevelRenderer::MLRState::TextureClamp);}
		bool
			IsTextureWrapEnabled()
				{
					Check_Object(this);
					return m_state.GetTextureWrapMode()==MidLevelRenderer::MLRState::TextureWrap;
				}

		void
			DisableChildTextureWrapControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() & ~MidLevelRenderer::MLRState::TextureWrapMask
					);
				}
		void
			EnableChildTextureWrapControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() | MidLevelRenderer::MLRState::TextureWrapMask
					);
				}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// WireFrame Mode
	//
	public:
		void
			SetWireFrameMode(MidLevelRenderer::MLRState::WireFrameMode mode)
				{Check_Object(this); m_state.SetWireFrameMode(mode);}
		MidLevelRenderer::MLRState::WireFrameMode
			GetWireFrameMode()
				{Check_Object(this); return m_state.GetWireFrameMode();}

		void
			DisableChildWireFrameControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() & ~MidLevelRenderer::MLRState::WireFrameMask
					);
				}
		void
			EnableChildWireFrameControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() | MidLevelRenderer::MLRState::WireFrameMask
					);
				}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// ZBuffer Write Mode
	//
	public:
		void
			EnableZBufferWrite()
				{Check_Object(this); m_state.SetZBufferWriteOn();}
		void
			DisableZBufferWrite()
				{Check_Object(this); m_state.SetZBufferWriteOff();}
		bool
			IsZBufferWriteEnabled()
				{
					Check_Object(this);
					return m_state.GetZBufferWriteMode()==MidLevelRenderer::MLRState::ZBufferWriteOnMode;
				}

		void
			DisableChildZBufferWriteControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() & ~MidLevelRenderer::MLRState::ZBufferWriteMask
					);
				}
		void
			EnableChildZBufferWriteControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() | MidLevelRenderer::MLRState::ZBufferWriteMask
					);
				}

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// ZBuffer Compare Mode
	//
	public:
		void
			EnableZBufferCompare()
				{Check_Object(this); m_state.SetZBufferCompareOn();}
		void
			DisableZBufferCompare()
				{Check_Object(this); m_state.SetZBufferCompareOff();}
		bool
			IsZBufferCompareEnabled()
				{
					Check_Object(this);
					return m_state.GetZBufferCompareMode()==MidLevelRenderer::MLRState::ZBufferCompareOnMode;
				}

		void
			DisableChildZBufferCompareControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() & ~MidLevelRenderer::MLRState::ZBufferCompareMask
					);
				}
		void
			EnableChildZBufferCompareControl()
				{
					Check_Object(this);
					m_state.SetRenderPermissionMask(
						m_state.GetRenderPermissionMask() | MidLevelRenderer::MLRState::ZBufferCompareMask
					);
				}
	};

}
