#include "ElementRendererHeaders.hpp"

//############################################################################
//############################  ScreenQuadsElement  ################################
//############################################################################

HGOSHEAP
	ElementRenderer::ScreenQuadsElement::s_Heap = NULL;

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

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

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

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

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

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

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

	m_sync = &Element::NoneSyncMethod;
	m_cameraCull = &Element::NeverCullMethod;
	m_rayCull = &Element::AlwaysRayCullMethod;
	unsigned index = (m_state>>DrawStateBit) & DrawStateMask;
	Verify(index < DrawStateCount);
	m_draw = DrawMethods[index];
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::ScreenQuadsElement::ScreenQuadsElement(unsigned count):
	Element(DefaultData)
{
	Check_Pointer(this);

	m_sync = &Element::NoneSyncMethod;
	m_cameraCull = &Element::NeverCullMethod;
	m_rayCull = &Element::AlwaysRayCullMethod;
	unsigned index = (m_state>>DrawStateBit) & DrawStateMask;
	Verify(index < DrawStateCount);
	m_draw = DrawMethods[index];

	m_status.SetLength(count);
	for (unsigned i=0; i<count; ++i)
		m_status[i] = false;

	count *= 4;
	m_corners.SetLength(count);
	m_colors.SetLength(count);
	m_UVs.SetLength(count);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::ScreenQuadsElement::~ScreenQuadsElement()
{
	Check_Object(this);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ElementRenderer::ScreenQuadsElement*
	ElementRenderer::ScreenQuadsElement::Make(
		Stuff::MemoryStream *stream,
		int version,
		ShapeHolder shapes
	)
{
	Check_Object(stream);

	gos_PushCurrentHeap(s_Heap);
	ScreenQuadsElement *element = new ScreenQuadsElement(stream, version);
	gos_PopCurrentHeap();

	return element;
}

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

	//
	//-----------------------------
	// Save the shape to the stream
	//-----------------------------
	//
#if 0
	Check_Object(mlrScreenQuads);
	mlrScreenQuads->Save(stream);
#endif
}

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

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

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::ScreenQuadsElement::GetQuadData(
		unsigned quad,
		Stuff::Vector4D **corners,
		Stuff::RGBAColor **colors,
		Stuff::Vector2DOf<Stuff::Scalar> **uvs,
		bool **status
	)
{
	Check_Object(this);
	Verify(quad < m_status.GetLength());
	Check_Pointer(corners);
	Check_Pointer(colors);
	Check_Pointer(uvs);
	Check_Pointer(status);

	*status = &m_status[quad];
	quad *= 4;
	*corners = &m_corners[quad];
	*colors = &m_colors[quad];
	*uvs = &m_UVs[quad];
}

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

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

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

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::ScreenQuadsElement::SetSyncState()
{
	Check_Object(this);
	m_state &= ~MatrixDirtyBit;
	m_sync = &Element::NoneSyncMethod;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::ScreenQuadsElement::SetCullState()
{
	Check_Object(this);

	if (GetCullMode() == AlwaysCullMode)
	{
		m_cameraCull = &Element::AlwaysCullMethod;
		m_rayCull = &Element::AlwaysRayCullMethod;
	}
	else
	{
		m_cameraCull = &Element::NeverCullMethod;
		m_rayCull = &Element::AlwaysRayCullMethod;
	}
}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::ScreenQuadsElement::InheritDrawMethod(
		CameraElement *camera,
		const StateChange *inherited_state,
		int culling_state
	)
{
	Check_Object(this);
	Check_Object(inherited_state);
	Check_Object(camera);
	Verify(culling_state != -1);

	//
	//--------------------------------------
	// Draw our bounds if we are supposed to
	//--------------------------------------
	//
	#if defined(LAB_ONLY)
		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
	//----------------------------
	//
	MidLevelRenderer::DrawScreenQuadsInformation info;
	info.nrOfQuads = m_status.GetLength();
	info.currentNrOfQuads = 0;
	info.state = inherited_state->GetMLRState();
	info.coords = &m_corners[0];
	info.colors = &m_colors[0];
	info.texCoords = &m_UVs[0];
	info.onOrOff = &m_status[0];

	//
	//---------------
	// Draw the shape
	//---------------
	//
	MidLevelRenderer::MLRClipper *clipper = camera->GetClipper();
	Check_Object(clipper);

	Stop_Timer(Graph_Traversal);
	ELEMENT_RENDER("Culling::Quads::Inherited");
	Start_Timer(Draw_Quads);
	clipper->DrawScreenQuads(&info);
	Stop_Timer(Draw_Quads);
	Start_Timer(Graph_Traversal);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ElementRenderer::ScreenQuadsElement::OverrideDrawMethod(
		CameraElement *camera,
		const StateChange *inherited_state,
		int culling_state
	)
{
	Check_Object(this);
	Check_Object(inherited_state);
	Check_Object(camera);
	Verify(culling_state != -1);

	//
	//-------------------
	// 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)
		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
	//----------------------------
	//
	MidLevelRenderer::DrawScreenQuadsInformation info;
	info.nrOfQuads = m_status.GetLength();
	info.currentNrOfQuads = 0;
	info.state = mixed.GetMLRState();
	info.coords = &m_corners[0];
	info.colors = &m_colors[0];
	info.texCoords = &m_UVs[0];
	info.onOrOff = &m_status[0];

	//
	//---------------
	// Draw the shape
	//---------------
	//
	MidLevelRenderer::MLRClipper *clipper = camera->GetClipper();
	Check_Object(clipper);

	Stop_Timer(Graph_Traversal);
	ELEMENT_RENDER("Culling::Quads::Overridden");
	Start_Timer(Draw_Quads);
	clipper->DrawScreenQuads(&info);
	Stop_Timer(Draw_Quads);
	Start_Timer(Graph_Traversal);
}

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