#include "ElementRendererHeaders.hpp"
#include <gosFX\EffectLibrary.hpp>

//############################################################################
//############################  gosFXElement  ################################
//############################################################################

HGOSHEAP
	ElementRenderer::gosFXElement::s_Heap = NULL;

ElementRenderer::gosFXElement::ClassData*
	ElementRenderer::gosFXElement::DefaultData = NULL;

ElementRenderer::Element::DrawMethod
	ElementRenderer::gosFXElement::DrawMethods[DrawStateCount]=
{
	//
	// No billboarding
	//
	DRAW_METHOD(gosFXElement,	Inherit),
	DRAW_METHOD(gosFXElement,	Override)
};

bool Hide_Effects=false;

static bool
	__stdcall CheckHideEffects()
{
	return Hide_Effects;
}

static void
	__stdcall EnableHideEffects()
{
	Hide_Effects = !Hide_Effects;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::gosFXElement::InitializeClass()
{
	Verify(!s_Heap);
	s_Heap = gos_CreateMemoryHeap("gosFX", 0, g_LibraryHeap);
	Check_Pointer(s_Heap);

	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			gosFXElementClassID,
			"ElementRenderer::gosFXElement",
			BaseClass::DefaultData,
			reinterpret_cast<Factory>(&Make)
		);
	Register_Object(DefaultData);

	AddDebuggerMenuItem("Libraries\\ElementRenderer\\Hide Effects", CheckHideEffects, EnableHideEffects, 0 );
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::gosFXElement::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;

	Check_Pointer(s_Heap);
	gos_DestroyMemoryHeap(s_Heap);
	s_Heap = NULL;
}

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

	unsigned index = (m_state>>DrawStateBit) & DrawStateMask;
	Verify(index < DrawStateCount);
	m_draw = DrawMethods[index];

	//
	//---------------------------------
	// Create the shape from the stream
	//---------------------------------
	//
	unsigned flags;
	*stream >> index >> flags;
#if 0
	Check_Object(gosFX::EffectLibrary::Instance);
	m_effect = gosFX::EffectLibrary::Instance->MakeEffect(index, flags);
	Register_Object(m_effect);
#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::gosFXElement::gosFXElement(gosFX::Effect *effect):
	Element(DefaultData)
{
	Check_Pointer(this);
	Check_Object(effect);

	unsigned index = (m_state>>DrawStateBit) & DrawStateMask;
	Verify(index < DrawStateCount);
	m_draw = DrawMethods[index];

	//
	//---------------------------------
	// Create the shape from the stream
	//---------------------------------
	//
	m_effect = effect;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::gosFXElement::~gosFXElement()
{
	Check_Object(this);
	Unregister_Object(m_effect);
	delete m_effect;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::gosFXElement*
	ElementRenderer::gosFXElement::Make(
		Stuff::MemoryStream *stream,
		int version,
		ShapeHolder shapes
	)
{
	Check_Object(stream);
	gos_PushCurrentHeap(s_Heap);
	gosFXElement *element = new gosFXElement(stream, version);
	gos_PopCurrentHeap();
	return element;
}

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

	//
	//-----------------------------
	// Save the shape to the stream
	//-----------------------------
	//
	SPEW(("jmalbert", "JM!!! gosFX states are not saved properly"));
	Check_Object(m_effect);
	gosFX::Effect::Specification *spec = m_effect->GetSpecification();
	Check_Object(spec);
	*stream << spec->m_effectID << m_effect->GetSimulationFlags();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::gosFXElement::TestInstance()
{
	Verify(IsDerivedFrom(DefaultData));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::gosFXElement::AttachChild(Element *child)
{
	Check_Object(this);
	Check_Object(child);
	STOP(("FX elements can't have children!"));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::gosFXElement::DetachChild(Element *child)
{
	Check_Object(this);
	Check_Object(child);
	STOP(("FX elements can't have children!"));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	ElementRenderer::gosFXElement::CastCulledRay(CollisionQuery *query)
{
	Check_Object(this);
	Check_Object(query);

	STOP(("FX is not collidable!"));
	return false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::Element*
	ElementRenderer::gosFXElement::FindSmallestElementContainingCulled(SphereTest *test)
{
	Check_Object(this);
	Check_Object(test);

	STOP(("FX is not collidable!"));
	return NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::gosFXElement::SetDrawState()
{
	Check_Object(this);
	unsigned index = (m_state>>DrawStateBit) & DrawStateMask;
	Verify(index < DrawStateCount);
	m_draw = DrawMethods[index];
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::gosFXElement::InheritDrawMethod(
		CameraElement *camera,
		const StateChange *inherited_state,
		int culling_state
	)
{
	Check_Object(this);
	Check_Object(inherited_state);
	Check_Object(camera);
	Verify(culling_state != -1);
	#if defined(_ARMOR)
		if (!culling_state)
			Verify(!Cull(camera));
	#endif

	//
	//--------------------------------------
	// Draw our bounds if we are supposed to
	//--------------------------------------
	//
	#if defined(LAB_ONLY)
		if (Hide_Effects)
			return;
		Callback *callback = GetCallbackSet();
		unsigned index = GetCallbackIndex();
		if (callback && callback[index])
		{
			Check_Pointer(callback[index]);
			(*callback[index])(camera, inherited_state, culling_state, this);
		}
	#endif

	//
	//----------------------------
	// Set up the draw information
	//----------------------------
	//
	gosFX::Effect::DrawInfo info;
	info.m_clippingFlags.SetClippingState(culling_state);
	info.m_parentToWorld = &m_localToWorld;
	info.m_state = inherited_state->GetMLRState();
	info.m_clipper = camera->GetClipper();
	Check_Object(info.m_clipper);
	Check_Object(m_effect);

	Stop_Timer(Graph_Traversal);
	ELEMENT_RENDER("Culling::gosFX::Inherited");
	Start_Timer(gosFX::Draw_Time);
	m_effect->Draw(&info);
	Stop_Timer(gosFX::Draw_Time);
	Start_Timer(Graph_Traversal);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::gosFXElement::OverrideDrawMethod(
		CameraElement *camera,
		const StateChange *inherited_state,
		int culling_state
	)
{
	Check_Object(this);
	Check_Object(inherited_state);
	Check_Object(camera);
	Verify(culling_state != -1);
	#if defined(_ARMOR)
		if (!culling_state)
			Verify(!Cull(camera));
	#endif

	//
	//-------------------
	// Mix the properties
	//-------------------
	//
	Check_Object(m_stateChange);
	StateChange mixed;
	mixed.Mix(*inherited_state, *m_stateChange);

	//
	//--------------------------------------
	// Draw our bounds if we are supposed to
	//--------------------------------------
	//
	#if defined(LAB_ONLY)
		if (Hide_Effects)
			return;
		Callback *callback = GetCallbackSet();
		unsigned index = GetCallbackIndex();
		if (callback && callback[index])
		{
			Check_Pointer(callback[index]);
			(*callback[index])(camera, inherited_state, culling_state, this);
		}
	#endif
	//
	//----------------------------
	// Set up the draw information
	//----------------------------
	//
	gosFX::Effect::DrawInfo info;
	info.m_clippingFlags.SetClippingState(culling_state);
	info.m_parentToWorld = &m_localToWorld;
	info.m_state = mixed.GetMLRState();
	info.m_clipper = camera->GetClipper();
	Check_Object(info.m_clipper);
	Check_Object(m_effect);

	Stop_Timer(Graph_Traversal);
	ELEMENT_RENDER("Culling::gosFX::Overridden");
	Start_Timer(gosFX::Draw_Time);
	m_effect->Draw(&info);
	Stop_Timer(gosFX::Draw_Time);
	Start_Timer(Graph_Traversal);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	ElementRenderer::gosFXElement::CountTriangles()
{
	Check_Object(this);
	STOP(("Not implemented"));
	return 0;
}
