//
// Tools_VertexCacheOptimiser.h
//
// Created by KJFL - 30 March 2009
//
// Copyright (C) 2009 Rebellion, All Rights Reserved.
//

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#ifndef __TOOLS_VERTEXCACHEOPTIMISER_H__
#define __TOOLS_VERTEXCACHEOPTIMISER_H__

class Tools_VCO_Triangle;
class Tools_VCO_Vertex;

// KJFL - 31 March 2009 - Tools_VertexCacheOptimiser
//
// This class is designed to be used as an instance in local scope. The constructor does all the necessary work to
// optimise the passed in data, and there are access methods to get the optimised output. 
// 
// *NOTE* The buffers returned by these access methods will be automatically deleted when the class instance 
// goes out of scope. This is intended to give a very clean interface and reduce the chances of memory leaks etc.
//
// The class constructor takes in a triangle list, i.e. an array of vertex indices, with three indices per triangle.
// It then rearranges the triangles to improve vertex caching on final hardware. This new index list can be retrieved
// by the GetNewIndexList() method.
//
// As well as reordering the triangles and thus the index list, there is also the option to renumber the indices so 
// that the vertex buffer can be reordered so that it is more likely to be read from in a sequential manner. This 
// gives two potential speed increases - improved vertex caching and improved memory access to the vertex buffer.
// This is turned on by the bReorderVertices parameter (which defaults to false). You can retrieve the new vertex
// order via the GetNewVertexOrder() method, and GetNumberOfUsedVertices() provides the size of this array. (Only
// vertices used by the triangles are included - the original vertex buffer passed in may have been larger.)
//
class Tools_VertexCacheOptimiser
{
	public:
		
		Tools_VertexCacheOptimiser( u_int uNumberOfTriangles, u_int uNumberOfVertices, const u_short* pusIndexList, bool bReorderVertices = false );

		// Index list of vertices used in the triangles - three indices per triangle
		const u_short* GetNewIndexList( void ) const { return m_pusIndexList; }
	
		// If bReorderVertices==true then the following methods provide the new order
		// of the vertices in the vertex buffer to match the above indices.
		const u_int GetNumberOfUsedVertices( void ) const { return m_uNumberOfUsedVertices; }
		const u_short* GetNewVertexOrder( void ) const { return m_pusVertexOrder; }

		~Tools_VertexCacheOptimiser();

	private:

		u_short*			m_pusIndexList;
		u_short*			m_pusVertexOrder;
		u_int				m_uNumberOfUsedVertices;

		Tools_VCO_Triangle* m_pxTriangles;
		Tools_VCO_Vertex*	m_pxVertices;

		u_int				m_uCurrentCache;
		u_int*				m_apuLRUCache[2];
		u_int				m_uNumberOfVerticesInCache;

};


class Tools_VCO_Triangle
{
	public:

		// 12 bytes in size
		// Could use u_int instead of u_short for the vertex indices,
		// which might be faster and still 16 bytes if we hide the 
		// "AddedToDrawList" in the score somehow.
		int		m_iScore;
		u_short m_usVertices[3];
		u_short m_bAddedToDrawList :1;
};

class Tools_VCO_Vertex
{
	public:

		Tools_VCO_Vertex()
		: m_iScore(0)
		, m_uTotalNumberOfTris(0)
		, m_uNumberOfTrisOutstanding(0)
		, m_puTriangles(0)
		{
		}

		~Tools_VCO_Vertex()
		{
		}

		// 16 bytes in size for cache friendliness
		int			m_iScore;
		u_int		m_uTotalNumberOfTris;
		u_int		m_uNumberOfTrisOutstanding;
		u_int*		m_puTriangles;
};

#endif//__TOOLS_VERTEXCACHEOPTIMISER_H__

