//
// Asura_GX_Hierarchy.h
//
// Created by KOR - 09 October 2006
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#ifndef __ASURA_GX_HIERARCHY_H__
#define __ASURA_GX_HIERARCHY_H__

#include "Core/Asura_HashTree.h"
#include "Rendering/Asura_GX_DisplayList.h"

//////////////////////////////////////////////////////////////////////////
// Hierarchy objects
//////////////////////////////////////////////////////////////////////////
struct Asura_GX_Hierarchy_Normal_Vertex
{
	// 10 fractional bits gives 64m range and millimetre accuracy
	short			m_sX;				// 2
	short			m_sY;				// 2
	short			m_sZ;				// 2
	// Normal could be chars, but a 13 byte vertex is 'orrible. 14 fractional bits.
	short			m_sNX;				// 2
	short			m_sNY;				// 2
	short			m_sNZ;				// 2

	short			m_sU;				// 2
	short			m_sV;				// 2
										// 16
};

struct Asura_GX_Hierarchy_Colour_Vertex
{
	// 10 fractional bits gives 64m range and millimetre accuracy
	short			m_sX;				// 2
	short			m_sY;				// 2
	short			m_sZ;				// 2

	short			m_pad;				// 2

	// Colour in standard 4 bytes argb format
	u_int			m_uARGBColour;       // 4


	short			m_sU;				// 2
	short			m_sV;				// 2
	// 16
};


struct Asura_GX_Hierarchy_Strip
{
	int		m_iMaterialID;
	u_int	m_uNumTris;
	u_short	m_usBoneIndex;
	// Room for a couple of bytes of flags here if necessary.
	Asura_GX_DisplayList m_xDisplayList;
};


class Asura_GX_Hierarchy
{
public:
	Asura_GX_Hierarchy();
	~Asura_GX_Hierarchy();
	void LoadFromChunk(Asura_Handle fileHandle, int iChunkVersion);
	void BeginRender() const;
	void Render(u_int uCamVisFlags, bool bDepthOnly = false, float fAlpha = 1.f) const;
	int GetMaterialID(u_int uStrip) const { return m_pxStrips[uStrip].m_iMaterialID; }

	const void* GetVertices() const { return m_pxVertices; }
	u_int GetNumStrips() const { return m_uNumberOfStrips; }
	u_int GetNumVertices() const { return m_uNumberOfVertices; }

	bool CheckExportFlag(u_int uFlagToCheck) const
	{
		return (m_uHierarchyExportFlags & uFlagToCheck) == uFlagToCheck;
	}
	u_int GetExportFlags() const
	{
		return m_uHierarchyExportFlags;
	}
	int GetVertexSize() const 
	{
		return m_iVertexSize;
	}
	int GetVertexNormalOffset() const 
	{
		return m_iNormalOffset;
	}
	int GetVertexColourOffset() const 
	{
		return m_iColourOffset;
	}
	int GetVertexUV1Offset() const 
	{
		return m_iUVOffset;
	}
	Asura_GX_Hierarchy_Strip *GetStrips()
	{
		return m_pxStrips;
	}
	const Asura_GX_Hierarchy_Strip *GetStrips() const
	{
		return m_pxStrips;
	}
private:
	u_int m_uHierarchyExportFlags;
	u_int m_uNumberOfStrips;
	Asura_GX_Hierarchy_Strip* m_pxStrips;
	//u_int m_uTotalIndices;
	u_int m_uNumberOfVertices;
	void* m_pxVertices;
	//u_short* m_pusIndices;
	int m_iVertexSize;
	int m_iNormalOffset;
	int m_iColourOffset;
	int m_iAlphaOffset;
	int m_iUVOffset;
	u_int m_uFractionalBits;

	Asura_GX_DisplayListBlock m_xDisplayListBlock;

};

class Asura_GX_HierarchyRenderer
{
public:
	static void Initialise();
	static void Reset();
	static void Shutdown();
	static bool AddHierarchy(Asura_Handle fileHandle, int iChunkVersion);
	static void RenderHierarchy(Asura_Hash_ID uHashID, u_int uCamVisFlags, float fAlpha = 1.f);
	static int  GetMaterialIndex(Asura_Hash_ID uHashID);
	static bool IsSkinOpaque(Asura_Hash_ID uHashID);
	static const Asura_GX_Hierarchy* GetHierarchy(Asura_Hash_ID uHashID);
private:
	static Asura_TemplateHashTree<Asura_GX_Hierarchy> s_xHashTree;
};

#endif//__ASURA_GX_HIERARCHY_H__