/*
	Trig Wars.
	Copyright (c) 2008, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//=====================================================================================================================
/// @brief		Class representing a buffered line renderer. The buffered line renderer allows for lines to be 
///				rendered in a batch, rather than one by one as with the primitives renderer.
//=====================================================================================================================

#include "Precompiled.h"
#include "Graphics\BufferedLineRenderer.h"
#include "Graphics\Display.h"

using namespace Game;

//=====================================================================================================================
/// @brief		Creates the buffered line renderer
/// @param		display - display the renderer is using
/// @param		vsmgr - vertex shader manager to use for loading resources
/// @param		psmgr - pixel shader manager to use for loading resources
/// @pre		Display cannot be null
/// @pre		Display must be valid
/// @pre		Vertex shader manager must not be null
/// @pre		Pixel shader manager must not be null
/// @pre		Game must have a vertex shader manager
//=====================================================================================================================

BufferedLineRenderer::BufferedLineRenderer( Display * display , VertexShaderManager * vsmgr , PixelShaderManager * psmgr )
{
	// Make sure ok

	ENSURE( display != 0		, "Display cannot be null"					);
	ENSURE( display->IsValid()	, "Display must be valid"					);
	ENSURE( vsmgr != 0			, "Vertex shader manager must not be null"	);
	ENSURE( psmgr != 0			, "Pixel shader manager must not be null"	);

	// Load our vertex and pixel shaders

	m_vs = vsmgr->GetVertexShader( "Shaders\\Colored.vsh.bin" );
	m_ps = psmgr->GetPixelShader( "Shaders\\Colored.psh.bin" );

	// Vertex format elements

	VertexFormat::ElementUsage vf_usages[] =
	{
		VertexFormat::VF_USAGE_POSITION	,
		VertexFormat::VF_USAGE_COLOR
	};

	// Vertex format types

	VertexFormat::ElementType vf_types[] =
	{
		VertexFormat::VF_TYPE_FLOAT3	,
		VertexFormat::VF_TYPE_COLOR
	};

	// Create our vertex format 

	m_vf = VertexFormat
	(
		display		,
		2			,
		vf_usages	,
		vf_types
	);

	// Load our shader uniform:

	if ( m_vs.IsValid() )
	{
		m_u_transform = m_vs.GetUniform("Transform");
	}

	// See if valid:

	if ( m_vf.IsValid() && m_ps.IsValid() && m_vs.IsValid() && m_u_transform.IsValid() )
	{
		// All valid:

		m_is_valid = true;
	}
	else
	{
		// Invalid:

		m_is_valid = false;
	}

	// Save a reference to the directx device:

	m_device = display->GetDevice(); m_device->AddRef();
}

//=====================================================================================================================
/// @brief		Destroys the buffered line renderer
//=====================================================================================================================

BufferedLineRenderer::~BufferedLineRenderer()
{
	// Release the device

	m_device->Release();
}

//=====================================================================================================================
/// @brief		Annouces the type name for this object.
/// @returns	Type name of this object
//=====================================================================================================================

const char * BufferedLineRenderer::GetTypeName() const
{
	return "BufferedLineRenderer";
}

//=====================================================================================================================
/// @brief		Sets up the state for the buffered point renderer
/// @param		transform - transform to use
/// @pre		Renderer must be in a valid state and setup correctly
//=====================================================================================================================

void BufferedLineRenderer::SetupRenderState( const Matrix4f & transform )
{
	ENSURE( m_is_valid , "Renderer must be in a valid state and setup correctly" );

	// Apply our vertex format and pixel shaders

	m_vf.Apply();
	m_vs.Apply();
	m_ps.Apply();

	// Set the transform on the vertex shader

	m_u_transform.SetMatrix(transform);
}

//=====================================================================================================================
/// @brief		Draws a set of lines specified in the given stack. See details for format of data on the stack
/// @param		transform - transform matrix to use to transform the points
/// @param		count - the number of points to draw
/// @param		stack - a stack containing all of lines to draw.
/// @pre		Count must be at least 1
/// @remarks	Lines must be pushed onto the stack in the following order:
///				1 - Vec3f		position 1
///				2 - unsigned	color 1
///				2 - Vec3f		position 2
///				2 - unsigned	color 2
/// @remarks	Lines are specified in list format. I.E connected lines must specify duplicate points.
/// @remarks	To get the most benefit from this function, batch up loads of lines before the call.
//=====================================================================================================================

void BufferedLineRenderer::Draw( const Matrix4f & transform , unsigned count , Stack & stack )
{
	// Make sure this is ok:

	ENSURE( count > 0 , "Count must be at least 1" );

	// Move the stack pointer back to where the data starts

	stack.Offset( -((int)(( sizeof(Vec3f) + sizeof(unsigned) ) * count * 2 )) );

	// If invalid state then abort

	if ( m_is_valid == false ) return;

	// Apply all our vertex and pixel shaders etc:

	SetupRenderState(transform);

	// Begin drawing:

	m_device->DrawPrimitiveUP
	(
		D3DPT_LINELIST					,
		count							,
		stack.GetPointer()			,
		sizeof(Vec3f) + sizeof(unsigned)
	);
}
