//
// Asura_Platform_RenderObjectHierarchy.cpp
//
// Created by KJL - 08/05/2003 15:10:51
//
// Copyright (C) 2003 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

// This file's header.
#include "Rendering/Asura_Platform_RenderObjectHierarchy.h"

// Asura Platform-independent
#include "Animation/Asura_Animation.h"
#include "Animation/Asura_Hierarchy.h"
#include "Animation/Asura_TextureAnimation.h"
#include "Camera/Asura_Camera.h"
#include "Core/Asura_Stream.h"
#include "Core/Asura_Material_System.h"
#include "Core/Asura_MaterialResponse_System.h"
#include "Core/Asura_NameTree.h"
#include "Core/Asura_TextureManagement.h"
#include "Light/Asura_GI_Solution.h"
#include "Mesh/Asura_CollisionMesh.h"
#include "Rendering/Asura_Colour.h"
#include "Rendering/Asura_Fog.h"
#include "Rendering/Asura_Render.h"
#include "Rendering/Asura_SortedRender.h"

#if defined(ASURA_TARGET_SM3)
	#include "Shadows/Asura_Shadow_System.h"
#endif

// Asura PC
#include "Rendering/Asura_Direct3D_Shaders.h"
#include "Rendering/Asura_Direct3D_MaterialResponse.h"

#ifdef ASURA_TARGET_SM3
	#include "Rendering/Asura_Direct3D_Caps.h"
	#include "Rendering/Asura_Direct3D_Effect.h"
	#include "Rendering/Asura_Direct3D_Effects_System.h"
#endif

// Tools
#ifdef ASURA_TOOLS
	#include "Misc/Tools_Render.h"
	#include "PC/Tools_PC_Export.h"
	#include "Tools_System.h"
#endif

// (SB - 20/11/06) Function pointers to set and revert pixel shader
Asura_Direct3D_ObjectHierarchyRenderer::SetupPixelShader* Asura_Direct3D_ObjectHierarchyRenderer::s_pfnSetupPixelShader = NULL;
Asura_Direct3D_ObjectHierarchyRenderer::RevertPixelShader* Asura_Direct3D_ObjectHierarchyRenderer::s_pfnRevertPixelShader = NULL;

// data on current status of drawing
bool									Asura_Direct3D_ObjectHierarchyRenderer::s_bNormalRendering;
bool									Asura_Direct3D_ObjectHierarchyRenderer::s_bShadowRendering;
const Asura_Direct3D_ObjectHierarchy*	Asura_Direct3D_ObjectHierarchyRenderer::s_pxCurrentHierarchyObject;

#ifdef ASURA_TARGET_SM3
bool Asura_Direct3D_ObjectHierarchyRenderer::s_bNewRenderersSupported = false;
bool Asura_Direct3D_ObjectHierarchyRenderer::s_bUseNewRenderers = false;

static Direct3D_VertexDeclaration* g_pxStandardVertexDecl = 0;
static Direct3D_VertexDeclaration* g_pxNormalMapVertexDecl = 0;
#endif //#ifdef ASURA_TARGET_SM3

#define ASURA_MAX_NO_OF_OBJECT_HIERARCHIES 128

static const float fNORMAL_DECOMPRESS[4] = { 2.f, -1.f, 0, 1.f };

static const float fTEXCOORD_DECOMPRESS_MAX		=	10.f;
static const float fTEXCOORD_DECOMPRESS_MIN		=	-10.f;
static const float fTEXCOORD_DECOMPRESS_SCALE	=	(fTEXCOORD_DECOMPRESS_MAX - fTEXCOORD_DECOMPRESS_MIN) / 65535.f;
static const float fTEXCOORD_DECOMPRESS_OFFSET	=	((-32768.f / 65535.f) * (fTEXCOORD_DECOMPRESS_MAX - fTEXCOORD_DECOMPRESS_MIN)) - fTEXCOORD_DECOMPRESS_MIN;
static const float fTEXCOORD_DECOMPRESS[4]		=	{ fTEXCOORD_DECOMPRESS_SCALE, fTEXCOORD_DECOMPRESS_OFFSET, 0.f, 1.f };

#ifdef ASURA_TOOLS
#include "MeshProcessing/Tools_HierarchyProcessor_MultiMaterial.h"
#include "Mesh/Asura_Mesh.h"
#include "Rendering/Asura_Direct3D_Caps.h"

const Asura_Direct3D_ObjectHierarchy* Asura_Direct3D_ObjectHierarchyRender_Handler::InitialiseStripsFromData(const Asura_Hierarchy_Skin* pxSkin)
{
	Asura_Direct3D_ObjectHierarchy* pxStrippedHierarchy = AddHierarchy(pxSkin->Name);

	if(pxStrippedHierarchy)
	{
		Tools_HierarchyProcessor_MultiMaterial::Initialise(pxSkin,false);


		pxStrippedHierarchy->m_uNumberOfStrips = Tools_HierarchyProcessor_MultiMaterial::GetTotalNumberOfStrips();
		pxStrippedHierarchy->m_uTotalNumberOfVertices = Tools_HierarchyProcessor_MultiMaterial::GetTotalNumberOfVertices();
		pxStrippedHierarchy->m_uTotalNumberOfIndices = Tools_HierarchyProcessor_MultiMaterial::GetTotalNumberOfIndices();

		if (pxStrippedHierarchy->m_uTotalNumberOfVertices == 0 || pxStrippedHierarchy->m_uTotalNumberOfIndices == 0  || Tools_HierarchyProcessor_MultiMaterial::s_uTotalNumberOfTriangles==0)
		{
			Tools_HierarchyProcessor_MultiMaterial::Shutdown();
			return pxStrippedHierarchy;
		}


		Asura_Direct3D_ObjectHierarchy_Strip* pxStrip = new Asura_Direct3D_ObjectHierarchy_Strip[pxStrippedHierarchy->m_uNumberOfStrips]; 
		pxStrippedHierarchy->m_pxHierarchyStrip = pxStrip;
		pxStrippedHierarchy->m_ePrimitiveType = D3DPT_TRIANGLELIST;

		u_int uStartIndex = 0;
		u_int uCurrentVertex = 0;

		for(u_int u = 0; u < pxStrippedHierarchy->m_uNumberOfStrips; u++)
		{
			const Tools_HierarchyProcessor_MultiMaterial_Strip& xStrip = *Tools_HierarchyProcessor_MultiMaterial::GetProcessedStrip(u);		

			u_int uLowestVertexUsed = uCurrentVertex;
			u_int uNumberOfVertices = xStrip.m_uNumberOfVertices;

			pxStrip[u].m_uNumberOfTriangles = xStrip.m_uNumberOfTriangles;
			pxStrip[u].m_uStartVertexIndex = uStartIndex;
			pxStrip[u].m_uLowestVertexUsed = uLowestVertexUsed;
			pxStrip[u].m_uNumberOfVertices = uNumberOfVertices;
			pxStrip[u].m_usBoneIndex = xStrip.m_usBoneIndex;

			#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM
				// The old non-normal-mapped hierarchy processor won't be used for processing strips now
				pxStrip[u].m_auMaterialResponseHashID[0] = ASURA_HASH_ID_UNSET;
				pxStrip[u].m_auMaterialResponseHashID[1] = ASURA_HASH_ID_UNSET;
			#else
				pxStrip[u].m_iMaterialIndex = xStrip.m_iMaterialID;
			#endif

			uStartIndex += xStrip.m_uNumberOfIndices;
			uCurrentVertex += xStrip.m_uNumberOfVertices;
		}



		int flags = D3DUSAGE_WRITEONLY;

		if (!Asura_Direct3D_Caps::HasHardwareVertexShaders())
		{
			flags |= D3DUSAGE_SOFTWAREPROCESSING;
		}

		// Create vertex and buffers for the strips
		Asura_Direct3D::D3DDevice->CreateVertexBuffer
			(
			pxStrippedHierarchy->m_uTotalNumberOfVertices * sizeof(Asura_Direct3D_ObjectHierarchy_Vertex),
			flags,
			0, 
			D3DPOOL_MANAGED,
			&(pxStrippedHierarchy->m_pxVertexBuffer),
			0
			);

		// lock, fill in data and unlock
		Asura_Direct3D_ObjectHierarchy_Vertex* pxVertexData;
		pxStrippedHierarchy->m_pxVertexBuffer->Lock
			(
			0,
			sizeof(Asura_Direct3D_ObjectHierarchy_Vertex) * pxStrippedHierarchy->m_uTotalNumberOfVertices,
			(void**)&pxVertexData,
			0
			);

#ifndef ASURA_TARGET_SM3

		bool bAnyOutOfRange = false, bOutOfRange;

		int w=0;
		for( u_int u= 0; u< pxStrippedHierarchy->m_uNumberOfStrips; u++)
		{
			const Tools_HierarchyProcessor_MultiMaterial_Strip& xStrip = *Tools_HierarchyProcessor_MultiMaterial::GetProcessedStrip(u);		

			for (u_int v=0; v<xStrip.m_uNumberOfVertices; v++)
			{
				pxVertexData[w].m_xPosition.x = xStrip.m_pxVertices[v].m_xPosition.x;
				pxVertexData[w].m_xPosition.y = xStrip.m_pxVertices[v].m_xPosition.y;
				pxVertexData[w].m_xPosition.z = xStrip.m_pxVertices[v].m_xPosition.z;

				pxVertexData[w].m_uNormal = Tools_PC_Export::CompressNormalToUByte4(xStrip.m_pxVertices[v].m_xNormal);

				pxVertexData[w].m_sU = Tools_PC_Export::CompressTexCoordToShort(xStrip.m_pxVertices[v].m_fU0, bOutOfRange);
				bAnyOutOfRange |= bOutOfRange;
				pxVertexData[w].m_sV = Tools_PC_Export::CompressTexCoordToShort(xStrip.m_pxVertices[v].m_fV0, bOutOfRange);
				bAnyOutOfRange |= bOutOfRange;

				pxVertexData[w].m_fAlpha = xStrip.m_pxVertices[v].m_fAlpha;

				w++;
			}	
		}

		Asura_Assertf(!bAnyOutOfRange, ("Some texture coordinates in hierarchy %s were out of range and have been clamped", pxSkin->Name));

#else

		int w=0;
		for( u_int u= 0; u< pxStrippedHierarchy->m_uNumberOfStrips; u++)
		{
			const Tools_HierarchyProcessor_MultiMaterial_Strip& xStrip = *Tools_HierarchyProcessor_MultiMaterial::GetProcessedStrip(u);		

			for (u_int v=0; v<xStrip.m_uNumberOfVertices; v++)
			{
				pxVertexData[w].m_fX = xStrip.m_pxVertices[v].m_xPosition.x;
				pxVertexData[w].m_fY = xStrip.m_pxVertices[v].m_xPosition.y;
				pxVertexData[w].m_fZ = xStrip.m_pxVertices[v].m_xPosition.z;

				pxVertexData[w].m_fNX = xStrip.m_pxVertices[v].m_xNormal.x;
				pxVertexData[w].m_fNY = xStrip.m_pxVertices[v].m_xNormal.y;
				pxVertexData[w].m_fNZ = xStrip.m_pxVertices[v].m_xNormal.z;

				pxVertexData[w].m_fU = xStrip.m_pxVertices[v].m_fU0;
				pxVertexData[w].m_fV = xStrip.m_pxVertices[v].m_fV0;

				pxVertexData[w].m_fAlpha = xStrip.m_pxVertices[v].m_fAlpha;

				w++;
			}	
		}

#endif

		pxStrippedHierarchy->m_pxVertexBuffer->Unlock();


		Asura_Direct3D::D3DDevice->CreateIndexBuffer
			(
			pxStrippedHierarchy->m_uTotalNumberOfIndices * sizeof(unsigned short),
			flags,
			D3DFMT_INDEX16,
			D3DPOOL_MANAGED,
			&(pxStrippedHierarchy->m_pxIndexBuffer),
			0
			);

		unsigned short* pusIndexData;
		pxStrippedHierarchy->m_pxIndexBuffer->Lock
			(
			0,
			sizeof(u_short) * pxStrippedHierarchy->m_uTotalNumberOfIndices, 
			(void**)&pusIndexData,
			0
			);

		uCurrentVertex = 0;
		for (u_int s=0; s< pxStrippedHierarchy->m_uNumberOfStrips; s++)
		{
			const Tools_HierarchyProcessor_MultiMaterial_Strip& xStrip = *Tools_HierarchyProcessor_MultiMaterial::GetProcessedStrip(s);

			for (u_int v=0; v<xStrip.m_uNumberOfIndices; v++)
			{
				u_short usIndex = (u_short)(xStrip.m_pusIndices[v]+uCurrentVertex);
				*pusIndexData++ = usIndex;
			}
			uCurrentVertex += xStrip.m_uNumberOfVertices;
		}

		pxStrippedHierarchy->m_pxIndexBuffer->Unlock();

		Tools_HierarchyProcessor_MultiMaterial::Shutdown();
	}

	return pxStrippedHierarchy;
}

#ifdef ASURA_TARGET_SM3
#include "MeshProcessing/Tools_HierarchyProcessor_MultiMaterial_NormalMapped.h"

const Asura_Direct3D_ObjectHierarchy* Asura_Direct3D_ObjectHierarchyRender_Handler::InitialiseNormalMappedStripsFromData(const Asura_Hierarchy_Skin* pxSkin)
{
	Asura_Direct3D_ObjectHierarchy* pxStrippedHierarchy = AddHierarchy(pxSkin->Name);

	if(pxStrippedHierarchy)
	{
		pxStrippedHierarchy->m_bHasNormalMappedStrip = true;
		pxStrippedHierarchy->m_ePrimitiveType = D3DPT_TRIANGLELIST;

		Tools_HierarchyProcessor_MultiMaterial_NormalMapped::Initialise(pxSkin, false);

		pxStrippedHierarchy->m_uNumberOfStrips = Tools_HierarchyProcessor_MultiMaterial_NormalMapped::GetTotalNumberOfStrips();
		pxStrippedHierarchy->m_uTotalNumberOfVertices = Tools_HierarchyProcessor_MultiMaterial_NormalMapped::GetTotalNumberOfVertices();
		pxStrippedHierarchy->m_uTotalNumberOfIndices = Tools_HierarchyProcessor_MultiMaterial_NormalMapped::GetTotalNumberOfIndices();

		if (pxStrippedHierarchy->m_uTotalNumberOfVertices == 0 || pxStrippedHierarchy->m_uTotalNumberOfIndices == 0  || Tools_HierarchyProcessor_MultiMaterial_NormalMapped::s_uTotalNumberOfTriangles==0)
		{
			Tools_HierarchyProcessor_MultiMaterial_NormalMapped::Shutdown();
			return pxStrippedHierarchy;
		}


		Asura_Direct3D_ObjectHierarchy_Strip* pxStrip = new Asura_Direct3D_ObjectHierarchy_Strip[pxStrippedHierarchy->m_uNumberOfStrips]; 
		pxStrippedHierarchy->m_pxHierarchyStrip = pxStrip;

		u_int uStartIndex = 0;
		u_int uCurrentVertex = 0;

		for(u_int u = 0; u < pxStrippedHierarchy->m_uNumberOfStrips; u++)
		{
			const Tools_HierarchyProcessor_MultiMaterial_NormalMapped_Strip& xStrip = *Tools_HierarchyProcessor_MultiMaterial_NormalMapped::GetProcessedStrip(u);		

			u_int uLowestVertexUsed = uCurrentVertex;
			u_int uNumberOfVertices = xStrip.m_uNumberOfVertices;

			pxStrip[u].m_uNumberOfTriangles = xStrip.m_uNumberOfTriangles;
			pxStrip[u].m_uStartVertexIndex = uStartIndex;

			#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM
				pxStrip[u].m_auMaterialResponseHashID[0] = xStrip.m_auMaterialResponseHashID[0];
				pxStrip[u].m_auMaterialResponseHashID[1] = xStrip.m_auMaterialResponseHashID[1];
			#else
				pxStrip[u].m_iMaterialIndex = xStrip.m_iMaterialID;
			#endif

			pxStrip[u].m_uLowestVertexUsed = uLowestVertexUsed;
			pxStrip[u].m_uNumberOfVertices = uNumberOfVertices;
			pxStrip[u].m_usBoneIndex = xStrip.m_usBoneIndex;

			uStartIndex += xStrip.m_uNumberOfIndices;
			uCurrentVertex += xStrip.m_uNumberOfVertices;
		}



		int flags = D3DUSAGE_WRITEONLY;

		if (!Asura_Direct3D_Caps::HasHardwareVertexShaders())
		{
			flags |= D3DUSAGE_SOFTWAREPROCESSING;
		}

		// Create vertex and buffers for the strips
		Asura_Direct3D::D3DDevice->CreateVertexBuffer
			(
			pxStrippedHierarchy->m_uTotalNumberOfVertices * sizeof(Asura_Direct3D_ObjectHierarchy_Vertex_NormalMapped),
			flags,
			0, 
			D3DPOOL_MANAGED,
			&(pxStrippedHierarchy->m_pxVertexBuffer),
			0
			);

		// lock, fill in data and unlock
		Asura_Direct3D_ObjectHierarchy_Vertex_NormalMapped* pxVertexData;
		pxStrippedHierarchy->m_pxVertexBuffer->Lock
			(
			0,
			sizeof(Asura_Direct3D_ObjectHierarchy_Vertex_NormalMapped) * pxStrippedHierarchy->m_uTotalNumberOfVertices,
			(void**)&pxVertexData,
			0
			);

		int w=0;
		for( u_int u= 0; u< pxStrippedHierarchy->m_uNumberOfStrips; u++)
		{
			const Tools_HierarchyProcessor_MultiMaterial_NormalMapped_Strip& xStrip = *Tools_HierarchyProcessor_MultiMaterial_NormalMapped::GetProcessedStrip(u);		

			for (u_int v=0; v<xStrip.m_uNumberOfVertices; v++)
			{
				pxVertexData[w].m_xPosition = xStrip.m_pxVertices[v].m_xPosition;

				pxVertexData[w].m_xNormal = xStrip.m_pxVertices[v].m_xNormal;

				pxVertexData[w].m_fU = xStrip.m_pxVertices[v].m_fU0;
				pxVertexData[w].m_fV = xStrip.m_pxVertices[v].m_fV0;
				pxVertexData[w].m_fU2 = xStrip.m_pxVertices[v].m_fU1;
				pxVertexData[w].m_fV2 = xStrip.m_pxVertices[v].m_fV1;
				pxVertexData[w].m_fAlpha = xStrip.m_pxVertices[v].m_fAlpha;

				pxVertexData[w].m_xBinormal = xStrip.m_pxVertices[v].m_xBinormal;
				pxVertexData[w].m_xTangent = xStrip.m_pxVertices[v].m_xTangent;

				w++;
			}	
		}

		pxStrippedHierarchy->m_pxVertexBuffer->Unlock();


		Asura_Direct3D::D3DDevice->CreateIndexBuffer
			(
			pxStrippedHierarchy->m_uTotalNumberOfIndices * sizeof(unsigned short),
			flags,
			D3DFMT_INDEX16,
			D3DPOOL_MANAGED,
			&(pxStrippedHierarchy->m_pxIndexBuffer),
			0
			);

		unsigned short* pusIndexData;
		pxStrippedHierarchy->m_pxIndexBuffer->Lock
			(
			0,
			sizeof(u_short) * pxStrippedHierarchy->m_uTotalNumberOfIndices, 
			(void**)&pusIndexData,
			0
			);

		uCurrentVertex = 0;
		for (u_int s=0; s< pxStrippedHierarchy->m_uNumberOfStrips; s++)
		{
			const Tools_HierarchyProcessor_MultiMaterial_NormalMapped_Strip& xStrip = *Tools_HierarchyProcessor_MultiMaterial_NormalMapped::GetProcessedStrip(s);

			for (u_int v=0; v<xStrip.m_uNumberOfIndices; v++)
			{
				u_short usIndex = (u_short)(xStrip.m_pusIndices[v]+uCurrentVertex);
				*pusIndexData++ = usIndex;
			}
			uCurrentVertex += xStrip.m_uNumberOfVertices;
		}

		pxStrippedHierarchy->m_pxIndexBuffer->Unlock();

		Tools_HierarchyProcessor_MultiMaterial_NormalMapped::Shutdown();
	}

	return pxStrippedHierarchy;
}
#endif //#ifdef ASURA_TARGET_SM3
#endif


////////////////////////////////////////////////////////////////////////////////
//
// Asura_Direct3D_ObjectHierarchyRender_Handler
//
////////////////////////////////////////////////////////////////////////////////

void Asura_Direct3D_ObjectHierarchyRender_Handler::Reset (void)
{
	m_xHashTree.Reset();
}

const Asura_Direct3D_ObjectHierarchy* Asura_Direct3D_ObjectHierarchyRender_Handler::GetHierarchy(const Asura_Hierarchy_Skin* pxSkin)
{
	const Asura_Hash_ID						uHash				= pxSkin->m_uNameHashID;
	const Asura_Direct3D_ObjectHierarchy*	pxObjectHierarchy	= m_xHashTree.GetDataByHash(uHash);

	if (pxObjectHierarchy == NULL)
	{
#ifdef ASURA_TOOLS
		{
#ifdef ASURA_TARGET_SM3
			if (Tools_HierarchyProcessor_MultiMaterial_NormalMapped::HasHierarchyAnyNormalMappedMaterials(pxSkin))
			{
				pxObjectHierarchy = InitialiseNormalMappedStripsFromData(pxSkin);
			}
			else
#endif //#ifdef ASURA_TARGET_SM3
			{
				pxObjectHierarchy = InitialiseStripsFromData(pxSkin);
			}
			Asura_Assertf(pxObjectHierarchy, ("A hierarchy strip that wasn't loaded as part of an export\ncouldn't be made from existing files either.") );
			return pxObjectHierarchy;
		}
#else
		{
			Asura_Assertf(false, ("No strip data for hierarchy") );
			return 0;
		}
#endif
	}

	return(pxObjectHierarchy);
}

void Asura_Direct3D_ObjectHierarchyRender_Handler::ResetAllLODs(const Asura_Hierarchy_Skin* pxSkin)
{
	while(pxSkin)
	{
		m_xHashTree.DeleteNodeByHash(pxSkin->m_uNameHashID);
		pxSkin = pxSkin->m_pxNextLowerSkin;
	}
}

Asura_Direct3D_ObjectHierarchy* Asura_Direct3D_ObjectHierarchyRender_Handler::AddHierarchy( const Asura_String& xName )
{ 
	bool bDidExist = true;
	Asura_Direct3D_ObjectHierarchy* pxObjHier = m_xHashTree.AddOrFindNode(xName.GetHash(),&bDidExist,true); 
	
	Asura_Assert(pxObjHier,"Out of memory creating new hash tree node");
#if !defined(ASURA_DONT_ASSERT_ON_DUPLICATE_RESOURCE_DATA)
	Asura_Assertf(!(pxObjHier && bDidExist),("Duplicate item %s",xName.GetString()));
#endif	// !defined(ASURA_DONT_ASSERT_ON_DUPLICATE_RESOURCE_DATA)

	if(bDidExist)
	{
		return(NULL);
	}
	else
	{
		return(pxObjHier);
	}
}

/*int Asura_Direct3D_ObjectHierarchyRender_Handler::GetMaterialIndex(const class Asura_Hierarchy_Skin* pxSkin)
{
const Asura_Direct3D_ObjectHierarchy* pxHierarchy = GetHierarchy(pxSkin);
if(!pxHierarchy || !pxHierarchy->m_pxHierarchyStrip)
{
return ASURA_MATERIAL_NONE;
}

//find the first section that has a material , and return that
for(u_int i=0;i<pxHierarchy->m_uNumberOfStrips;i++)
{
if(pxHierarchy->m_pxHierarchyStrip[i].m_iMaterialIndex != ASURA_MATERIAL_NONE)
{
return pxHierarchy->m_pxHierarchyStrip[i].m_iMaterialIndex;
}
}

return ASURA_MATERIAL_NONE;
}*/

bool Asura_Direct3D_ObjectHierarchyRender_Handler::IsAnyMaterialTransparent(const class Asura_Hierarchy_Skin* pxSkin) const
{
	const Asura_Direct3D_ObjectHierarchy* pxHierarchy = m_xHashTree.GetDataByHash(pxSkin->m_uNameHashID);
	if(!pxHierarchy || !pxHierarchy->m_pxHierarchyStrip)
	{
		return false;
	}

	// check all materials
	for(u_int i=0;i<pxHierarchy->m_uNumberOfStrips;i++)
	{
		#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

			const Asura_MaterialResponse* const pxMaterial = Asura_MaterialResponse_System::GetMaterialByHashID( pxHierarchy->m_pxHierarchyStrip[i].m_auMaterialResponseHashID[0] );

			// Materials are opaque as far as the sorted render is concerned if they're flagged as decal-type
			if( pxMaterial && pxMaterial->IsTransparent() ) return true;

		#else // !defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

			if(pxHierarchy->m_pxHierarchyStrip[i].m_iMaterialIndex != ASURA_MATERIAL_NONE)
			{
				if( Asura_Material_System::IsMaterialTransparent( pxHierarchy->m_pxHierarchyStrip[i].m_iMaterialIndex )
				 || Asura_Material_System::IsMaterialPS2AdditiveAlpha( pxHierarchy->m_pxHierarchyStrip[i].m_iMaterialIndex ) )
				{
					return true;
				}
			}

		#endif // !defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM
	}
	// none found
	return false;
}


#ifdef ASURA_TOOLS
bool Asura_Direct3D_ObjectHierarchyRender_Handler::DoesSkinHaveAnyTriangles(const class Asura_Hierarchy_Skin* pxSkin) const
{
	const Asura_Direct3D_ObjectHierarchy* pxHierarchy = m_xHashTree.GetDataByHash(pxSkin->m_uNameHashID);

	if(!pxHierarchy) return false;
	if(!pxHierarchy->m_uTotalNumberOfVertices) return false;
	return true;

}

#endif // ASURA_TOOLS



////////////////////////////////////////////////////////////////////////////////
//
// Asura_Direct3D_ObjectHierarchyRenderer
//
////////////////////////////////////////////////////////////////////////////////

#if defined(ASURA_USE_MULTIPLE_HANDLERS)
Asura_Direct3D_ObjectHierarchyRender_Handler*							Asura_Direct3D_ObjectHierarchyRenderer::s_pxCurrentHandler	= NULL;		// Currently active handler.
Asura_TemplateHashTree<Asura_Direct3D_ObjectHierarchyRender_Handler>	Asura_Direct3D_ObjectHierarchyRenderer::s_xHandlerTree;					// Tree of all of the handlers available.
#else
Asura_Direct3D_ObjectHierarchyRender_Handler							Asura_Direct3D_ObjectHierarchyRenderer::s_xHandler;						// Single static-instance of a zone.
#endif

void Asura_Direct3D_ObjectHierarchyRenderer::Initialise(void)
{
	s_bShadowRendering = false;
	s_bNormalRendering = false;
	s_pxCurrentHierarchyObject = 0;

#ifdef ASURA_TARGET_SM3
	s_bNewRenderersSupported = (Asura_Direct3D_Caps::GetHardwarePixelShaderVersion() >= 2.0f) && (Asura_Direct3D_Caps::GetHardwareVertexShaderVersion() >= 2.0f);
	s_bUseNewRenderers = s_bNewRenderersSupported;

	if( NULL != Asura_Direct3D::D3DDevice)
	{
		{
			Direct3D_VertexElement auVSD[] =
			{
				{	0,	0,	D3DDECLTYPE_FLOAT3,		D3DDECLMETHOD_DEFAULT,	D3DDECLUSAGE_POSITION,	0 },
				{	0,	12,	D3DDECLTYPE_FLOAT3,		D3DDECLMETHOD_DEFAULT,	D3DDECLUSAGE_NORMAL,	0 },
				{	0,	24,	D3DDECLTYPE_FLOAT2,		D3DDECLMETHOD_DEFAULT,	D3DDECLUSAGE_TEXCOORD,	0 },
				{	0,	32,	D3DDECLTYPE_FLOAT1,		D3DDECLMETHOD_DEFAULT,	D3DDECLUSAGE_TEXCOORD,	1 },
				D3DDECL_END()
			};

			#if defined ASURA_ASSERT
				HRESULT hr =
			#endif
				Asura_Direct3D::D3DDevice->CreateVertexDeclaration( auVSD, &(g_pxStandardVertexDecl) );

			Asura_Assert(hr == D3D_OK, "Vertex declaration failed");
		}
		{
			Direct3D_VertexElement auVSD[] =
			{
				{	0,	0,	D3DDECLTYPE_FLOAT3,		D3DDECLMETHOD_DEFAULT,	D3DDECLUSAGE_POSITION,	0 },
				{	0,	12,	D3DDECLTYPE_FLOAT3,		D3DDECLMETHOD_DEFAULT,	D3DDECLUSAGE_NORMAL,	0 },
				{	0,	24,	D3DDECLTYPE_FLOAT2,		D3DDECLMETHOD_DEFAULT,	D3DDECLUSAGE_TEXCOORD,	0 },
				{	0,	32,	D3DDECLTYPE_FLOAT2,		D3DDECLMETHOD_DEFAULT,	D3DDECLUSAGE_TEXCOORD,	1 },
				{	0,	40,	D3DDECLTYPE_FLOAT1,		D3DDECLMETHOD_DEFAULT,	D3DDECLUSAGE_TEXCOORD,	2 },
				{	0,	44,	D3DDECLTYPE_FLOAT3,		D3DDECLMETHOD_DEFAULT,	D3DDECLUSAGE_BINORMAL,	0 },
				{	0,	56,	D3DDECLTYPE_FLOAT3,		D3DDECLMETHOD_DEFAULT,	D3DDECLUSAGE_TANGENT,	0 },
				D3DDECL_END()
			};

			#if defined ASURA_ASSERT
				HRESULT hr =
			#endif
				Asura_Direct3D::D3DDevice->CreateVertexDeclaration( auVSD, &(g_pxNormalMapVertexDecl) );

			Asura_Assert(hr == D3D_OK, "Vertex declaration failed");
		}
	}
#endif //#ifdef ASURA_TARGET_SM3
}

void Asura_Direct3D_ObjectHierarchyRenderer::Reset(void)
{
#if defined(ASURA_USE_MULTIPLE_HANDLERS)
	GetCurrentHandler().Reset();

	s_bNormalRendering = false;
	s_bShadowRendering = false;
	s_pxCurrentHierarchyObject = NULL;
#else
	Shutdown();
	Initialise();
#endif
}

void Asura_Direct3D_ObjectHierarchyRenderer::Shutdown(void)
{
#ifdef ASURA_TARGET_SM3
	if(g_pxStandardVertexDecl)
	{
		g_pxStandardVertexDecl->Release();
		g_pxStandardVertexDecl = NULL;
	}
	if(g_pxNormalMapVertexDecl)
	{
		g_pxNormalMapVertexDecl->Release();
		g_pxNormalMapVertexDecl = NULL;
	}
#endif
#if defined(ASURA_USE_MULTIPLE_HANDLERS)
	s_xHandlerTree.Reset();
	s_pxCurrentHandler	= NULL;
#else
	s_xHandler.Reset();
#endif

	s_bShadowRendering = false;
	s_bNormalRendering = false;
	s_pxCurrentHierarchyObject = 0;
}

#if defined(ASURA_USE_MULTIPLE_HANDLERS)

void Asura_Direct3D_ObjectHierarchyRenderer::ReparentHandler(Asura_Direct3D_ObjectHierarchyRender_Handler& xSourceHandler, const Asura_Hash_ID uNewParentHash)
{
	Asura_Direct3D_ObjectHierarchyRender_Handler*	pxParentHandler	= s_xHandlerTree.GetDataByHash(uNewParentHash);

	if(pxParentHandler != NULL)
	{
		xSourceHandler.m_xHashTree.SetParent(&(pxParentHandler->m_xHashTree));
	}
}

void Asura_Direct3D_ObjectHierarchyRenderer::ReparentHandler(const Asura_Hash_ID uSourceHash, const Asura_Hash_ID uNewParentHash)
{
	Asura_Direct3D_ObjectHierarchyRender_Handler*	pxHandler	= s_xHandlerTree.GetDataByHash(uSourceHash);

	if(pxHandler != NULL)
	{
		ReparentHandler(*pxHandler, uNewParentHash);
	}
}

Asura_Direct3D_ObjectHierarchyRender_Handler* Asura_Direct3D_ObjectHierarchyRenderer::CreateHandler (const Asura_Hash_ID uHash, const Asura_Hash_ID uParentHandlerHash)
{
	Asura_Direct3D_ObjectHierarchyRender_Handler*	pxHandler	= s_xHandlerTree.GetDataByHash(uHash);

	// Do we already have this zone?
	if(pxHandler == NULL)
	{
		// No - create one...
		pxHandler	= s_xHandlerTree.AddNode(uHash);

		if(pxHandler != NULL)
		{
			ReparentHandler(*pxHandler, uParentHandlerHash);
		}
	}
	else
	{
		// Yes - this shouldn't happen...
		Asura_Assert(false, "Already have an object-hierarchy render-handler with this hash-ID.");
	}

	// Return the zone...
	return(pxHandler);
}

bool Asura_Direct3D_ObjectHierarchyRenderer::DestroyHandler (const Asura_Hash_ID uHash)
{
	// Is this the current zone?
	if(s_pxCurrentHandler == s_xHandlerTree.GetDataByHash(uHash))
	{
		s_pxCurrentHandler	= NULL;
	}

	// Call the delete function...
	return(s_xHandlerTree.DeleteNodeByHash(uHash));
}

void Asura_Direct3D_ObjectHierarchyRenderer::WriteHandlerReport(u_int uHandler, Asura_Stream& xLog)
{
	const u_int uLOGBUFFERSIZE = 64;
	char szLogBuffer[uLOGBUFFERSIZE];

	Asura_Direct3D_ObjectHierarchyRender_Handler* pxHandler = s_xHandlerTree.GetDataByHash(uHandler);
	if (pxHandler)
	{
		if (!pxHandler->m_xHashTree.GetNumberOfNodes())
		{
			xLog << "PC ObjHier:\t\t\tNone\n";
		}
		else
		{
			Asura_PrintfToBfr( szLogBuffer, "PSP ObjHier:\t\t\t%d Item(s)\n", uLOGBUFFERSIZE, true, pxHandler->m_xHashTree.GetNumberOfNodes() );
			xLog << szLogBuffer;
		}
	}
	else
	{
		xLog << "PC ObjHier:\t\t\tNo Handler\n";
	}
}

#endif //defined(ASURA_USE_MULTIPLE_HANDLERS)

#if !defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

void Asura_Direct3D_ObjectHierarchyRenderer::BeginRender( const class Asura_Animation* pxAnim, const class Asura_Hierarchy_Skin* pxSkin )
{
	Asura_Direct3D_ObjectHierarchyRender_Handler&	xHandler	= Asura_Direct3D_ObjectHierarchyRenderer::GetCurrentHandler();

	s_bNormalRendering = false;
	s_pxCurrentHierarchyObject = xHandler.GetHierarchy(pxSkin);

	if(s_pxCurrentHierarchyObject == NULL)
	{
		Asura_Assert(0,"no Hierarchy strips to render");
		return;
	}

	if (s_pxCurrentHierarchyObject->m_uTotalNumberOfVertices == 0 || s_pxCurrentHierarchyObject->m_uTotalNumberOfIndices == 0)
	{
		//Assertion removed since it fires on the hierarchies that just exist for particle attachments. RAR 14/02/2005
		//Asura_Assertf(false, ("Hierarchy %s has no polys!", pxSkin ? pxSkin->Name.GetString() : "NULL"));
		return;
	}

	if (s_pxCurrentHierarchyObject->m_pxHierarchyStrip==0)
	{
		Asura_Assert(false, "No strips?");
		return;
	}

	D3DPERFCALL(BeginEvent(0xff837b4a, L"ObjectHierarchy Render"));

	// KJFL - 2004-02-20 11:11:18 - okay, we think we have a valid hierarchy
	s_bNormalRendering = true;

	Asura_Direct3D_Shaders::RequestVertexShader(ASURA_D3D_VS_OBJECT_ORDER2SH_WITHALPHA);

	Asura_Assert(s_pxCurrentHierarchyObject->m_pxVertexBuffer, "No VB");
	Asura_Assert(s_pxCurrentHierarchyObject->m_pxIndexBuffer, "No IB");

#ifdef ASURA_TARGET_SM3
	if (s_pxCurrentHierarchyObject->m_bHasNormalMappedStrip)
	{
		Asura_Direct3D::D3DDevice->SetStreamSource(0, s_pxCurrentHierarchyObject->m_pxVertexBuffer, 0, sizeof(Asura_Direct3D_ObjectHierarchy_Vertex_NormalMapped));
	}
	else
#endif //#ifdef ASURA_TARGET_SM3
	{
		Asura_Direct3D::D3DDevice->SetStreamSource(0, s_pxCurrentHierarchyObject->m_pxVertexBuffer, 0, sizeof(Asura_Direct3D_ObjectHierarchy_Vertex));
	}
	Asura_Direct3D::D3DDevice->SetIndices(s_pxCurrentHierarchyObject->m_pxIndexBuffer);

	Asura_Render::CurrentStates.RequestCullMode(ASURA_CULLMODE_CW);

	// orientate and position object in vertex shader
	D3DXMATRIX xMat;
	D3DXMATRIX xMatView, xMatProj;

	Asura_Direct3D::D3DDevice->GetTransform( D3DTS_VIEW, &xMatView );
	Asura_Direct3D::D3DDevice->GetTransform( D3DTS_PROJECTION, &xMatProj );

    D3DXMatrixMultiply( &xMat, &xMatView, &xMatProj );
    D3DXMatrixTranspose( &xMat, &xMat );

    Asura_Direct3D::D3DDevice->SetVertexShaderConstantF(  0, (float*)&xMat,  4 );

	Asura_Direct3D::D3DDevice->SetVertexShaderConstantF(94, &fNORMAL_DECOMPRESS[0], 1);
	Asura_Direct3D::D3DDevice->SetVertexShaderConstantF(95, &fTEXCOORD_DECOMPRESS[0], 1);

	D3DXMATRIX xReflectiveMat;
	D3DXMATRIX xTransposedView;
	D3DXMatrixTranspose( &xTransposedView, &xMatView );
	xMatView._14 = xMatView._24 = xMatView._34 = 0.0f;
	xMatView._41 = xMatView._42 = xMatView._43 = 0.0f;
	D3DXMatrixInverse( &xMatView,  NULL, &xMatView );

	xReflectiveMat._11 = 0.5f; xReflectiveMat._12 = 0.0f; xReflectiveMat._13 = 0.0f; xReflectiveMat._14 = 0.0f; 
	xReflectiveMat._21 = 0.0f; xReflectiveMat._22 = -0.5f; xReflectiveMat._23 = 0.0f; xReflectiveMat._24 = 0.0f; 
	xReflectiveMat._31 = 0.0f; xReflectiveMat._32 = 0.0f; xReflectiveMat._33 = 1.0f; xReflectiveMat._34 = 0.0f; 
	xReflectiveMat._41 = 0.5f; xReflectiveMat._42 = 0.5f; xReflectiveMat._43 = 0.0f; xReflectiveMat._44 = 1.0f; 

	D3DXMatrixMultiplyTranspose(&xReflectiveMat,&xMatView,&xReflectiveMat);

	Asura_Direct3D::D3DDevice->SetVertexShaderConstantF( 21, (float*)&xTransposedView, 3 );
	Asura_Direct3D::D3DDevice->SetVertexShaderConstantF( 24, (float*)&xReflectiveMat, 3 );

	Asura_Render::CurrentStates.RequestZBufferEnabled(true);
	Asura_Render::CurrentStates.RequestZBufferCompareMode(ASURA_ZBUFFERCMP_LESSEQUAL);
	Asura_Render::CurrentStates.RequestZBufferWriteEnabled(true);

	// (JG - 13.04.2007): Removed redundant lighting setup, as now is done earlier on; 
	// also this call was ignoring the animation / animation attachment render flags
	/*if(pxAnim->GetParent())
	{
		//This is an attachment , so just take lighting from parent.
		//Do it now , since it will be the same for each section RAR 02/04/2004
		pxAnim->UpdateLighting();
	}*/	



	// turn on fog if we have to...
	if (Asura_Fog::IsFogRenderable())
	{
		Asura_Direct3D::D3DDevice->SetRenderState(D3DRS_FOGENABLE, TRUE);
	}


}

void Asura_Direct3D_ObjectHierarchyRenderer::Render( const Asura_Animation* pxAnim,const class Asura_Hierarchy_Skin* pxSkin, const int iSectionDataIndex, const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation, bool bDepthOnly /* = false */)
{
	if (!s_bNormalRendering || !s_pxCurrentHierarchyObject)
	{
		//Assertion removed since it fires on the hierarchies that just exist for particle attachments. RAR 14/02/2005
		//Asura_Assertf( false, ("No object setup for hierarchy %s, will skip", pxSkin ? pxSkin->Name.GetString() : "NULL") );
		return;
	}

	// This is no longer a valid condition because we can have more than one strip per bone
	/*if(s_pxCurrentHierarchyObject->m_uNumberOfStrips <= (u_int) iSectionDataIndex)
	{
		Asura_Assert(0,"number of bones and objects in hierarchy do not match");
		return;
	}*/

	// KJFL - 2004-02-20 12:23:47 - TODO - don't need a 4x4 matrix here - the w component of a transformed vector is just being mapped to 1.0f;
	// can save a constant & possibly a vertex shader instruction
	D3DXMATRIX xMat;
	Asura_Direct3D::SetupD3DMatrix(xMat, xOrientation, xPosition, false);
	Asura_Direct3D::D3DDevice->SetVertexShaderConstantF(  7, (float*)&xMat,  4 );

	float afLights[4*4];
	const Asura_SphericalHarmonics_Order2_RGB &xSH = Asura_GI_Solution::s_xSHForCurrentRender;

	afLights[0] = xSH.m_afRedCoefficients[1]; 
	afLights[1] = xSH.m_afRedCoefficients[2]; 
	afLights[2] = xSH.m_afRedCoefficients[3]; 
	afLights[3] = xSH.m_afRedCoefficients[0]; 

	afLights[4] = xSH.m_afGreenCoefficients[1]; 
	afLights[5] = xSH.m_afGreenCoefficients[2]; 
	afLights[6] = xSH.m_afGreenCoefficients[3]; 
	afLights[7] = xSH.m_afGreenCoefficients[0]; 

	afLights[8] = xSH.m_afBlueCoefficients[1]; 
	afLights[9] = xSH.m_afBlueCoefficients[2];
	afLights[10] = xSH.m_afBlueCoefficients[3];
	afLights[11] = xSH.m_afBlueCoefficients[0];

	Asura_Direct3D::D3DDevice->SetVertexShaderConstantF( 11, afLights, 3 );

	// fog parameters 
	const float afFogValues[4] = { 1.f - Asura_Fog::GetFogDensityAtDistance((xPosition - (*Asura_Camera::GetPosition())).Magnitude()), 0.f, 0.f, pxAnim->GetAlpha() };
	Asura_Direct3D::D3DDevice->SetVertexShaderConstantF( 20, afFogValues, 1);

	for(u_int uStrip = 0; uStrip < s_pxCurrentHierarchyObject->m_uNumberOfStrips; ++uStrip)
	{
		Asura_Direct3D_ObjectHierarchy_Strip* pxStrip = &(s_pxCurrentHierarchyObject->m_pxHierarchyStrip[uStrip]);

		if (pxStrip->m_usBoneIndex != iSectionDataIndex) continue;
		if (pxStrip->m_uNumberOfTriangles==0) continue;

		// UV offsets from texture animation
		Asura_TextureAnimationOutput xTextureAnim;
		Asura_Material_System::GetTextureAnimationState(pxStrip->m_iMaterialIndex,pxAnim->GetTextureAnimController(),&xTextureAnim);
	
		float afUVOffset[4] = {xTextureAnim.m_fUOffset,xTextureAnim.m_fVOffset,0.0f,0.0f};
		Asura_Direct3D::D3DDevice->SetVertexShaderConstantF( 19, afUVOffset, 1);

		// get the strip data
		const int iTextureIndex = (pxAnim->GetAnimTexID() != ASURA_TEXTURE_NONE) ? pxAnim->GetAnimTexID() : Asura_Material_System::GetTextureID(pxStrip->m_iMaterialIndex);
		Asura_Render::CurrentStates.RequestTextureIndex(0,iTextureIndex);

		const bool bShouldRenderTransparent = (pxAnim->GetAlpha() < 1.f);
		const bool b8BitAlpha = (Asura_Texture_Management::GetTextureFlags(iTextureIndex) & AsuraTextureFlag_8BitAlpha) ? true : false;

		if(!bDepthOnly)
		{

			/// Kevin Lea - 07/02/2003 15:33:24 - first off, is texture transparent
			if (Asura_Material_System::IsMaterialSelfIlluminating(pxStrip->m_iMaterialIndex))
			{
		
				Asura_Render::CurrentStates.RequestTextureIndex(1,iTextureIndex);
				Asura_Render::CurrentStates.RequestTranslucencyMode(bShouldRenderTransparent? ASURA_TRANSLUCENCY_NORMAL : ASURA_TRANSLUCENCY_OFF);
				Asura_Render::CurrentStates.RequestAlphaTest(false);
				// self illuminating materials use alpha in their textures
				// we want to prevent it from being blended into the output unless it's also being used for transparency
				Asura_Render::CurrentStates.RequestTextureOpMode(ASURA_TEXTUREOP_SELFILLUMINATE);
				if(!b8BitAlpha || !Asura_Material_System::IsMaterialTransparent(pxStrip->m_iMaterialIndex))
				{
					Asura_Direct3D::D3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2);
					Asura_Render::CurrentStates.RequestZBufferWriteEnabled( true );
				}
				else
				{
					Asura_Render::CurrentStates.RequestZBufferWriteEnabled( false );
				}
			}
			else if (Asura_Material_System::IsMaterialTransparent(pxStrip->m_iMaterialIndex))
			{
				Asura_Render::CurrentStates.RequestTextureOpMode(ASURA_TEXTUREOP_SINGLE_PASS_2X);
				Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_NORMAL);
				Asura_Render::CurrentStates.RequestZBufferWriteEnabled( !b8BitAlpha );
				Asura_Render::CurrentStates.RequestAlphaTest(true);
			}
			else if (Asura_Material_System::IsMaterialPS2AdditiveAlpha(pxStrip->m_iMaterialIndex))
			{
				Asura_Render::CurrentStates.RequestTextureOpMode(ASURA_TEXTUREOP_SINGLE_PASS_2X);

				Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_GLOWING);
				
				Asura_Render::CurrentStates.RequestZBufferWriteEnabled(false);		
				Asura_Render::CurrentStates.RequestAlphaTest(true);
			}
			else if (Asura_Material_System::IsMaterialReflective(pxStrip->m_iMaterialIndex))
			{
				Asura_Direct3D_Shaders::RequestVertexShader(ASURA_D3D_VS_OBJECT_REFLECTIVE_WITHALPHA);
				Asura_Render::CurrentStates.RequestTranslucencyMode(bShouldRenderTransparent? ASURA_TRANSLUCENCY_NORMAL : ASURA_TRANSLUCENCY_OFF);
				if(!Asura_Material_System::IsMaterialTransparent(pxStrip->m_iMaterialIndex))
				{
					Asura_Direct3D_Shaders::RequestPixelShader(ASURA_D3D_PS_OBJECT_REFLECTIVE);
					Asura_Render::CurrentStates.RequestZBufferWriteEnabled( true );
				}
				else
				{
					Asura_Direct3D_Shaders::RequestPixelShader(ASURA_D3D_PS_OBJECT_REFLECTIVE_TEXALPHA);
					Asura_Render::CurrentStates.RequestZBufferWriteEnabled( false );
				}
				Asura_Render::CurrentStates.RequestTextureIndex(1, Asura_Render::GetReflectanceMap());
			}
			else
			{
				Asura_Render::CurrentStates.RequestTextureOpMode(ASURA_TEXTUREOP_SINGLE_PASS_2X);
				Asura_Render::CurrentStates.RequestTranslucencyMode(bShouldRenderTransparent? ASURA_TRANSLUCENCY_NORMAL : ASURA_TRANSLUCENCY_OFF);
				Asura_Render::CurrentStates.RequestAlphaTest(false);
				Asura_Render::CurrentStates.RequestZBufferWriteEnabled( true );
			}
		}
		else
		{
			Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_JUSTSETZ);
			Asura_Render::CurrentStates.RequestTextureOpMode(ASURA_TEXTUREOP_SINGLE_PASS);
			Asura_Render::CurrentStates.RequestAlphaTest(Asura_Material_System::IsMaterialTransparent(pxStrip->m_iMaterialIndex));
			Asura_Render::CurrentStates.RequestZBufferWriteEnabled( true );
		}

		// render strip

		Asura_Assert(pxStrip->m_uLowestVertexUsed+pxStrip->m_uNumberOfVertices <= s_pxCurrentHierarchyObject->m_uTotalNumberOfVertices, "vertices out");
		Asura_Assert(pxStrip->m_uStartVertexIndex + pxStrip->m_uNumberOfTriangles+2 <= s_pxCurrentHierarchyObject->m_uTotalNumberOfIndices, "indices out");
		Asura_Assert(pxStrip->m_uNumberOfTriangles>=1 /*&& pxStrip->m_uNumberOfTriangles <= 4000*/, "tri count suspect");

		// ARC - 05 February 2007 11:57:10 - Moved for SteveB to fix object outlining bug in Simpsons
		// (SB - 16/11/06) Shader override hook
		if (s_pfnSetupPixelShader)
		{
			s_pfnSetupPixelShader(pxStrip);
		}

		Asura_Direct3D::D3DDevice->DrawIndexedPrimitive
							(
								s_pxCurrentHierarchyObject->m_ePrimitiveType,
								0,
								pxStrip->m_uLowestVertexUsed,
								pxStrip->m_uNumberOfVertices,
								pxStrip->m_uStartVertexIndex,
								pxStrip->m_uNumberOfTriangles
							);

		Asura_Render::AddToTrianglesRendered(pxStrip->m_uNumberOfTriangles);

		// (SB - 16/11/06) Shader override hook
		if (s_pfnRevertPixelShader)
		{
			s_pfnRevertPixelShader();
		}

		if(!bDepthOnly && Asura_Material_System::IsMaterialReflective(pxStrip->m_iMaterialIndex))
		{
			// set things back to normal
			Asura_Direct3D_Shaders::RequestVertexShader(ASURA_D3D_VS_OBJECT_ORDER2SH);
			Asura_Direct3D_Shaders::RequestPixelShader(ASURA_D3D_PS_NONE);
		}
	} // for each strip
}

#endif // !defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

#ifdef ASURA_TOOLS
void Asura_Direct3D_ObjectHierarchyRenderer::Render_Outline( const Asura_Animation* pxAnim,const class Asura_Hierarchy_Skin* pxSkin, const int iSectionDataIndex, const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation )
{
	#if 1
	//Render using the Tools_Render function for meshes instead , so that the outline of collision polygons will be visible.
	//RAR 24/04/2009
	Asura_Mesh* pxMesh = pxSkin->SectionData[iSectionDataIndex].Mesh;
	if(pxMesh)
	{
		Tools_Render::RenderMeshOutline(pxMesh,&xPosition,&xOrientation,pxAnim->GetOutlineColour(),true);
	}

	#else
	if (!s_bNormalRendering || !s_pxCurrentHierarchyObject)
	{
		Asura_Assertf( false, ("No object setup for hierarchy %s, will skip", pxSkin ? pxSkin->Name.GetString() : "NULL") );
		return;
	}

	// This is no longer a valid condition because we can have more than one strip per bone (just like the standard render above)
	//if(s_pxCurrentHierarchyObject->m_uNumberOfStrips <= (u_int) iSectionDataIndex)
	//{
	//	Asura_Assert(0,"number of bones and objects in hierarchy do not match");
	//	return;
	//}

	// KJFL - 2004-02-20 12:23:47 - TODO - don't need a 4x4 matrix here - the w component of a transformed vector is just being mapped to 1.0f;
	// can save a constant & possibly a vertex shader instruction
	D3DXMATRIX xMat;
	Asura_Direct3D::SetupD3DMatrix(xMat, xOrientation, xPosition, false);
	Asura_Direct3D::D3DDevice->SetVertexShaderConstantF(  7, (float*)&xMat,  4 );
	

	float afLights[4*4];

	const u_int uColour = pxAnim->GetOutlineColour();
	
	afLights[0] = 0.0f;
	afLights[1] = 0.0f;
	afLights[2] = 0.0f;
	afLights[3] = ((uColour >> 16) & 0xff)/255.0f;

	afLights[4] = 0.0f; 
	afLights[5] = 0.0f; 
	afLights[6] = 0.0f; 
	afLights[7] = ((uColour >> 8) & 0xff)/255.0f; 

	afLights[8] = 0.0f; 
	afLights[9] = 0.0f;
	afLights[10] = 0.0f;
	afLights[11] = ((uColour >> 0) & 0xff)/255.0f;

	Asura_Direct3D::D3DDevice->SetVertexShaderConstantF( 11, afLights, 3 );

	// fog parameters 
	const float afFogValues[4] = { 1.f - Asura_Fog::GetFogDensityAtDistance((xPosition - (*Asura_Camera::GetPosition())).Magnitude()), 0.f, 0.f, 0.f };
	Asura_Direct3D::D3DDevice->SetVertexShaderConstantF( 20, afFogValues, 1);

	// get the strip data
	Asura_Render::CurrentStates.RequestTextureIndex(0, ASURA_TEXTURE_NONE);

	Asura_Render::CurrentStates.RequestTextureOpMode(ASURA_TEXTUREOP_SINGLE_PASS_2X);
	Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_OFF);
	Asura_Render::CurrentStates.RequestAlphaTest(false);

	// render strips

	for(u_int uStrip = 0; uStrip < s_pxCurrentHierarchyObject->m_uNumberOfStrips; ++uStrip)
	{
		Asura_Direct3D_ObjectHierarchy_Strip* pxStrip = &(s_pxCurrentHierarchyObject->m_pxHierarchyStrip[uStrip]);
		if(pxStrip->m_usBoneIndex != iSectionDataIndex) continue;
		if(pxStrip->m_uNumberOfTriangles == 0) continue;

		Asura_Assert(pxStrip->m_uLowestVertexUsed+pxStrip->m_uNumberOfVertices <= s_pxCurrentHierarchyObject->m_uTotalNumberOfVertices, "vertices out");
		Asura_Assert(pxStrip->m_uStartVertexIndex + pxStrip->m_uNumberOfTriangles+2 <= s_pxCurrentHierarchyObject->m_uTotalNumberOfIndices, "indices out");
		Asura_Assert(pxStrip->m_uNumberOfTriangles>=1 /*&& pxStrip->m_uNumberOfTriangles <= 4000*/, "tri count suspect");

		Asura_Render::CurrentStates.RequestWireFrameMode(true);

		Asura_Direct3D::D3DDevice->DrawIndexedPrimitive
							(
								s_pxCurrentHierarchyObject->m_ePrimitiveType,
								0,
								pxStrip->m_uLowestVertexUsed,
								pxStrip->m_uNumberOfVertices,
								pxStrip->m_uStartVertexIndex,
								pxStrip->m_uNumberOfTriangles
							);

		Asura_Render::AddToTrianglesRendered(pxStrip->m_uNumberOfTriangles);

	} // for each strip

	Asura_Render::CurrentStates.RequestWireFrameMode(Asura_Render::GetWireframe());
	#endif
}
#endif

#if !defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

void Asura_Direct3D_ObjectHierarchyRenderer::EndRender(void)
{
	Asura_Render::CurrentStates.RequestAlphaTest(false);
	Asura_Render::CurrentStates.RequestTextureOpMode(ASURA_TEXTUREOP_SINGLE_PASS);
	Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_OFF);

	s_pxCurrentHierarchyObject = 0;
	s_bNormalRendering = false;

	// turn off fog if we have to...
	if (Asura_Fog::IsFogRenderable())
	{
		Asura_Direct3D::D3DDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
	}

	D3DPERFCALL(EndEvent());
}

#endif // !defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

#ifdef ASURA_TARGET_SM3

#if !defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

void Asura_Direct3D_ObjectHierarchyRenderer::BeginRender_EffectsSystem( const class Asura_Animation* pxAnim, const class Asura_Hierarchy_Skin* pxSkin )
{
	Asura_Direct3D_ObjectHierarchyRender_Handler&	xHandler	= GetCurrentHandler();

	s_bNormalRendering = false;
	s_pxCurrentHierarchyObject = xHandler.GetHierarchy(pxSkin);

	if(s_pxCurrentHierarchyObject == NULL)
	{
		Asura_Assert(0,"no Hierarchy strips to render");
		return;
	}

	if (s_pxCurrentHierarchyObject->m_uTotalNumberOfVertices == 0 || s_pxCurrentHierarchyObject->m_uTotalNumberOfIndices == 0)
	{
		//Assertion removed since it fires on the hierarchies that just exist for particle attachments. RAR 14/02/2005
		//Asura_Assertf(false, ("Hierarchy %s has no polys!", pxSkin ? pxSkin->Name.GetString() : "NULL"));
		return;
	}

	if (s_pxCurrentHierarchyObject->m_pxHierarchyStrip==0)
	{
		Asura_Assert(false, "No strips?");
		return;
	}

	D3DPERFCALL(BeginEvent(0xff837b4a, L"ObjectHierarchy Render (Effects System)"));

	// KJFL - 2004-02-20 11:11:18 - okay, we think we have a valid hierarchy
	s_bNormalRendering = true;

	Asura_Assert(s_pxCurrentHierarchyObject->m_pxVertexBuffer, "No VB");
	Asura_Assert(s_pxCurrentHierarchyObject->m_pxIndexBuffer, "No IB");

#ifdef ASURA_TARGET_SM3
	if (s_pxCurrentHierarchyObject->m_bHasNormalMappedStrip)
	{
		Asura_Direct3D::D3DDevice->SetStreamSource(0, s_pxCurrentHierarchyObject->m_pxVertexBuffer, 0, sizeof(Asura_Direct3D_ObjectHierarchy_Vertex_NormalMapped));
	}
	else
#endif //#ifdef ASURA_TARGET_SM3
	{
		Asura_Direct3D::D3DDevice->SetStreamSource(0, s_pxCurrentHierarchyObject->m_pxVertexBuffer, 0, sizeof(Asura_Direct3D_ObjectHierarchy_Vertex));
	}
	Asura_Direct3D::D3DDevice->SetIndices(s_pxCurrentHierarchyObject->m_pxIndexBuffer);

	Asura_Render::CurrentStates.RequestCullMode(ASURA_CULLMODE_CW);

	Asura_Render::CurrentStates.RequestZBufferEnabled(true);
	Asura_Render::CurrentStates.RequestZBufferCompareMode(ASURA_ZBUFFERCMP_LESSEQUAL);
	Asura_Render::CurrentStates.RequestZBufferWriteEnabled(true);

	// (JG - 13.04.2007): Removed redundant lighting setup, as now is done earlier on; 
	// also this call was ignoring the animation / animation attachment render flags
	/*if(pxAnim->GetParent())
	{
		//This is an attachment , so just take lighting from parent.
		//Do it now , since it will be the same for each section RAR 02/04/2004
		pxAnim->UpdateLighting();
	}*/

	// Get an effect so we can set up the values. We'll begin this (or a different one) again when we come to each strip
	Asura_Direct3D_Effect* pxEffect;
	pxEffect = Asura_Direct3D_Effects_System::BeginEffect("Object_TextureAndLight");

#ifndef ASURA_PC_OBJECTHIERARCHY_USEPERSECTIONSH
	// The SH is the same for all sections at the moment, so set the shared values here
	const Asura_SphericalHarmonics_Order2_RGB &xSH = Asura_GI_Solution::s_xSHForCurrentRender;
	Asura_Vector_3 xBrightestLightDirection;
	xSH.GetBrightestDirection(xBrightestLightDirection);
	D3DXVECTOR4 xD3DVector;

	xD3DVector.x = xSH.m_afRedCoefficients[1];
	xD3DVector.y = xSH.m_afRedCoefficients[2];
	xD3DVector.z = xSH.m_afRedCoefficients[3];
	xD3DVector.w = xSH.m_afRedCoefficients[0];
	pxEffect->SetParameterByName("g_xObjectRedSH", xD3DVector);
	xD3DVector.x = xSH.m_afGreenCoefficients[1];
	xD3DVector.y = xSH.m_afGreenCoefficients[2];
	xD3DVector.z = xSH.m_afGreenCoefficients[3];
	xD3DVector.w = xSH.m_afGreenCoefficients[0];
	pxEffect->SetParameterByName("g_xObjectGreenSH", xD3DVector);
	xD3DVector.x = xSH.m_afBlueCoefficients[1];
	xD3DVector.y = xSH.m_afBlueCoefficients[2];
	xD3DVector.z = xSH.m_afBlueCoefficients[3];
	xD3DVector.w = xSH.m_afBlueCoefficients[0];
	pxEffect->SetParameterByName("g_xObjectBlueSH", xD3DVector);
	xD3DVector.x = xBrightestLightDirection.x;
	xD3DVector.y = xBrightestLightDirection.y;
	xD3DVector.z = xBrightestLightDirection.z;
	xD3DVector.w = 0;
	pxEffect->SetParameterByName("g_xObjectBrightestLightDirection", xD3DVector);
#endif //#ifndef ASURA_PC_OBJECTHIERARCHY_USEPERSECTIONSH

	pxEffect->SetParameterByName("g_fObjectAlpha", pxAnim->GetAlpha());
#ifdef ASURA_TOOLS
	pxEffect->SetParameterByName("g_bObjectUseLighting", !Tools_System::IsActive() || Tools_Render::LightingIsOn());
#else
	pxEffect->SetParameterByName("g_bObjectUseLighting", true);
#endif //#ifdef ASURA_TOOLS
}

void Asura_Direct3D_ObjectHierarchyRenderer::Render_EffectsSystem( const Asura_Animation* pxAnim,const class Asura_Hierarchy_Skin* pxSkin, const int iSectionDataIndex, const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation, bool bDepthOnly /* = false */)
{
	if (!s_bNormalRendering || !s_pxCurrentHierarchyObject)
	{
		//Assertion removed since it fires on the hierarchies that just exist for particle attachments. RAR 14/02/2005
		//Asura_Assertf( false, ("No object setup for hierarchy %s, will skip", pxSkin ? pxSkin->Name.GetString() : "NULL") );
		return;
	}

	// KJFL - 2004-02-20 12:23:47 - TODO - don't need a 4x4 matrix here - the w component of a transformed vector is just being mapped to 1.0f;
	// can save a constant & possibly a vertex shader instruction
	D3DXMATRIX xD3DMat;
	xD3DMat._11 = xOrientation.e11;
	xD3DMat._12 = xOrientation.e21;
	xD3DMat._13 = xOrientation.e31;
	xD3DMat._14 = 0;	 
	xD3DMat._21 = xOrientation.e12;
	xD3DMat._22 = xOrientation.e22;
	xD3DMat._23 = xOrientation.e32;
	xD3DMat._24 = 0;	 
	xD3DMat._31 = xOrientation.e13;
	xD3DMat._32 = xOrientation.e23;
	xD3DMat._33 = xOrientation.e33;
	xD3DMat._34 = 0;
	xD3DMat._41 = xPosition.x;
	xD3DMat._42 = xPosition.y;
	xD3DMat._43 = xPosition.z;
	xD3DMat._44 = 1.0f;

	// Get an effect so we can set up the values. We'll begin this (or a different one) again when we come to each strip
	Asura_Direct3D_Effect* pxEffect;
	pxEffect = Asura_Direct3D_Effects_System::BeginEffect("Object_TextureAndLight");

	pxEffect->SetParameterByName("g_xWorldMatrix", xD3DMat);

#ifdef ASURA_PC_OBJECTHIERARCHY_USEPERSECTIONSH
	// Set up the SH for this section

	Asura_SphericalHarmonics_Order2_RGB xSH;
	Asura_GI_Solution::GetTotalIrradiance(xSH, xPosition);
	Asura_Vector_3 xBrightestLightDirection;
	xSH.GetBrightestDirection(xBrightestLightDirection);
	D3DXVECTOR4 xD3DVector;

	xD3DVector.x = xSH.m_afRedCoefficients[1];
	xD3DVector.y = xSH.m_afRedCoefficients[2];
	xD3DVector.z = xSH.m_afRedCoefficients[3];
	xD3DVector.w = xSH.m_afRedCoefficients[0];
	pxEffect->SetParameterByName("g_xObjectRedSH", xD3DVector);
	xD3DVector.x = xSH.m_afGreenCoefficients[1];
	xD3DVector.y = xSH.m_afGreenCoefficients[2];
	xD3DVector.z = xSH.m_afGreenCoefficients[3];
	xD3DVector.w = xSH.m_afGreenCoefficients[0];
	pxEffect->SetParameterByName("g_xObjectGreenSH", xD3DVector);
	xD3DVector.x = xSH.m_afBlueCoefficients[1];
	xD3DVector.y = xSH.m_afBlueCoefficients[2];
	xD3DVector.z = xSH.m_afBlueCoefficients[3];
	xD3DVector.w = xSH.m_afBlueCoefficients[0];
	pxEffect->SetParameterByName("g_xObjectBlueSH", xD3DVector);
	xD3DVector.x = xBrightestLightDirection.x;
	xD3DVector.y = xBrightestLightDirection.y;
	xD3DVector.z = xBrightestLightDirection.z;
	xD3DVector.w = 0;
	pxEffect->SetParameterByName("g_xObjectBrightestLightDirection", xD3DVector);
#else //#ifdef ASURA_PC_OBJECTHIERARCHY_USEPERSECTIONSH
	Asura_Vector_3 xBrightestLightDirection;
	Asura_GI_Solution::s_xSHForCurrentRender.GetBrightestDirection(xBrightestLightDirection);
#endif //#else //#ifdef ASURA_PC_OBJECTHIERARCHY_USEPERSECTIONSH

	for(u_int uStrip = 0; uStrip < s_pxCurrentHierarchyObject->m_uNumberOfStrips; ++uStrip)
	{
		Asura_Direct3D_ObjectHierarchy_Strip* pxStrip = &(s_pxCurrentHierarchyObject->m_pxHierarchyStrip[uStrip]);

		if (pxStrip->m_usBoneIndex != iSectionDataIndex) continue;
		if (pxStrip->m_uNumberOfTriangles==0) continue;

		if (Asura_Material_System::GetNormalMapID(pxStrip->m_iMaterialIndex) != ASURA_TEXTURE_NONE)
		{
			pxEffect = Asura_Direct3D_Effects_System::BeginEffect("Object_TextureAndLight_NormalMap");
			Asura_Direct3D::D3DDevice->SetVertexDeclaration(g_pxNormalMapVertexDecl);
		}
		else
		{
			pxEffect = Asura_Direct3D_Effects_System::BeginEffect("Object_TextureAndLight");
			Asura_Direct3D::D3DDevice->SetVertexDeclaration(g_pxStandardVertexDecl);
		}

		// get the strip data
		pxEffect->SetTextureRenderStates(pxStrip->m_iMaterialIndex);

		// UV offsets from texture animation
		Asura_TextureAnimationOutput xTextureAnim;
		Asura_Material_System::GetTextureAnimationState(pxStrip->m_iMaterialIndex,pxAnim->GetTextureAnimController(),&xTextureAnim);
	
		const bool bIsAdditiveAlpha	= Asura_Material_System::IsMaterialPS2AdditiveAlpha(pxStrip->m_iMaterialIndex);
		const bool bIsTransparent	= Asura_Material_System::IsMaterialTransparent(pxStrip->m_iMaterialIndex);
		D3DXVECTOR4 xD3DVector;
		xD3DVector.x = xTextureAnim.m_fUOffset;
		xD3DVector.y = xTextureAnim.m_fVOffset;
		xD3DVector.z = 1.0f;
		xD3DVector.w = 1.0f;
		pxEffect->SetParameterByName("g_xTextureCoordOffsetAndScale", xD3DVector);

		pxEffect->SetParameterByName("g_bObjectSpecular", (Asura_Material_System::IsMaterialSpecularSharp(pxStrip->m_iMaterialIndex) || Asura_Material_System::IsMaterialSpecularSoft(pxStrip->m_iMaterialIndex)) && (xBrightestLightDirection != Asura_Maths::ZeroVector3));
		pxEffect->SetParameterByName("g_bObjectTextureTransparancy", bIsTransparent || bIsAdditiveAlpha);
		pxEffect->SetParameterByName("g_bSelfIlluminating", Asura_Material_System::IsMaterialSelfIlluminating(pxStrip->m_iMaterialIndex) );

		if ( (pxAnim->GetAlpha() < 1.0f) || bIsTransparent)
		{
			Asura_Render::CurrentStates.RequestTranslucencyMode		(ASURA_TRANSLUCENCY_NORMAL);
			Asura_Render::CurrentStates.RequestZBufferWriteEnabled	(false);

			// (AAM - 23.11.2006) Can't disable blending on the normal-depth RT, so disable writes
			Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_COLORWRITEENABLE1, 0 );
		}

		else if (bIsAdditiveAlpha)
		{
			Asura_Render::CurrentStates.RequestTranslucencyMode		(ASURA_TRANSLUCENCY_GLOWING);
			Asura_Render::CurrentStates.RequestZBufferWriteEnabled	(false);

			Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_COLORWRITEENABLE1, 0 );
		}
		
		else
		{
			Asura_Render::CurrentStates.RequestTranslucencyMode		(ASURA_TRANSLUCENCY_OFF);
			Asura_Render::CurrentStates.RequestZBufferWriteEnabled	(true);

			Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_COLORWRITEENABLE1, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA );
		}
		Asura_Render::CurrentStates.RequestAlphaTest(false);

		// render strip

		// (SB - 16/11/06) Shader override hook
		if (s_pfnSetupPixelShader)
		{
			s_pfnSetupPixelShader(pxStrip);
		}

		Asura_Assert(pxStrip->m_uLowestVertexUsed+pxStrip->m_uNumberOfVertices <= s_pxCurrentHierarchyObject->m_uTotalNumberOfVertices, "vertices out");
		Asura_Assert(pxStrip->m_uStartVertexIndex + pxStrip->m_uNumberOfTriangles+2 <= s_pxCurrentHierarchyObject->m_uTotalNumberOfIndices, "indices out");
		Asura_Assert(pxStrip->m_uNumberOfTriangles>=1 /*&& pxStrip->m_uNumberOfTriangles <= 4000*/, "tri count suspect");

		pxEffect->RenderAllIndexedPrimitivePasses
							(
								s_pxCurrentHierarchyObject->m_ePrimitiveType,
								pxStrip->m_uLowestVertexUsed,
								pxStrip->m_uNumberOfVertices,
								pxStrip->m_uStartVertexIndex,
								pxStrip->m_uNumberOfTriangles,
								NULL
							);
		Asura_Render::AddToTrianglesRendered(pxStrip->m_uNumberOfTriangles);

		// (SB - 16/11/06) Shader override hook
		if (s_pfnRevertPixelShader)
		{
			s_pfnRevertPixelShader();
		}

	} // for each strip

	// Restore normal-depth RT writes in case the last strip was transparent
	Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_COLORWRITEENABLE1, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA );
}

#endif // !defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

#ifdef ASURA_TOOLS
void Asura_Direct3D_ObjectHierarchyRenderer::Render_Outline_EffectsSystem( const Asura_Animation* pxAnim,const class Asura_Hierarchy_Skin* pxSkin, const int iSectionDataIndex, const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation )
{
	#if 1
	//Render using the Tools_Render function for meshes instead , so that the outline of collision polygons will be visible.
	//RAR 24/04/2009
	Asura_Mesh* pxMesh = pxSkin->SectionData[iSectionDataIndex].Mesh;
	if(pxMesh)
	{
		Tools_Render::RenderMeshOutline(pxMesh,&xPosition,&xOrientation,pxAnim->GetOutlineColour(),true);
	}
	#else
	
	if (!s_bNormalRendering || !s_pxCurrentHierarchyObject)
	{
		Asura_Assertf( false, ("No object setup for hierarchy %s, will skip", pxSkin ? pxSkin->Name.GetString() : "NULL") );
		return;
	}

// MGH 13/12/2007: This assert no longer seems to be valid because we can have more than one strip per bone (just like the standard render above)
//	if(s_pxCurrentHierarchyObject->m_uNumberOfStrips <= (u_int) iSectionDataIndex)
//	{
//		Asura_Assert(0,"number of bones and objects in hierarchy do not match");
//		return;
//	}

	// KJFL - 2004-02-20 12:23:47 - TODO - don't need a 4x4 matrix here - the w component of a transformed vector is just being mapped to 1.0f;
	// can save a constant & possibly a vertex shader instruction
	D3DXMATRIX xD3DMat;
	xD3DMat._11 = xOrientation.e11;
	xD3DMat._12 = xOrientation.e21;
	xD3DMat._13 = xOrientation.e31;
	xD3DMat._14 = 0;	 
	xD3DMat._21 = xOrientation.e12;
	xD3DMat._22 = xOrientation.e22;
	xD3DMat._23 = xOrientation.e32;
	xD3DMat._24 = 0;	 
	xD3DMat._31 = xOrientation.e13;
	xD3DMat._32 = xOrientation.e23;
	xD3DMat._33 = xOrientation.e33;
	xD3DMat._34 = 0;
	xD3DMat._41 = xPosition.x;
	xD3DMat._42 = xPosition.y;
	xD3DMat._43 = xPosition.z;
	xD3DMat._44 = 1.0f;

	// Get an effect so we can set up the values. We'll begin this (or a different one) again when we come to each strip.
	// In the outline case, this should be good enough for everything anyway.
	Asura_Direct3D_Effect* pxEffect;
	pxEffect = Asura_Direct3D_Effects_System::BeginEffect("Object_TextureAndLight");

	pxEffect->SetParameterByName("g_xWorldMatrix", xD3DMat);

	const u_int uColour = pxAnim->GetOutlineColour();
	D3DXVECTOR4 xD3DVector;

	xD3DVector.x = 0.0f;
	xD3DVector.y = 0.0f;
	xD3DVector.z = 0.0f;
	xD3DVector.w = ((uColour >> 16) & 0xff)/255.0f;
	pxEffect->SetParameterByName("g_xObjectRedSH", xD3DVector);
	xD3DVector.x = 0.0f; 
	xD3DVector.y = 0.0f; 
	xD3DVector.z = 0.0f; 
	xD3DVector.w = ((uColour >> 8) & 0xff)/255.0f; 
	pxEffect->SetParameterByName("g_xObjectGreenSH", xD3DVector);
	xD3DVector.x = 0.0f; 
	xD3DVector.y = 0.0f;
	xD3DVector.z = 0.0f;
	xD3DVector.w = ((uColour >> 0) & 0xff)/255.0f;
	pxEffect->SetParameterByName("g_xObjectBlueSH", xD3DVector);

	// fog parameters 
//	const float afFogValues[4] = { 1.f - Asura_Fog::GetFogDensityAtDistance((xPosition - (*Asura_Camera::GetPosition())).Magnitude()), 0.f, 0.f, 0.f };
//	Asura_Direct3D::D3DDevice->SetVertexShaderConstantF( 20, afFogValues, 1);

	// get the strip data
	Asura_Render::CurrentStates.RequestTextureIndex(0, ASURA_TEXTURE_NONE);

	Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_OFF);
	Asura_Render::CurrentStates.RequestAlphaTest(false);

	pxEffect->SetParameterByName("g_bObjectSpecular", false);
	pxEffect->SetParameterByName("g_bObjectTextureTransparancy", false);

	pxEffect->SetParameterByName("g_fObjectAlpha", 1.0f);

	// render strips

	for(u_int uStrip = 0; uStrip < s_pxCurrentHierarchyObject->m_uNumberOfStrips; ++uStrip)
	{
		Asura_Direct3D_ObjectHierarchy_Strip* pxStrip = &(s_pxCurrentHierarchyObject->m_pxHierarchyStrip[uStrip]);
		if(pxStrip->m_usBoneIndex != iSectionDataIndex) continue;
		if(pxStrip->m_uNumberOfTriangles == 0) continue;

		Asura_Assert(pxStrip->m_uLowestVertexUsed+pxStrip->m_uNumberOfVertices <= s_pxCurrentHierarchyObject->m_uTotalNumberOfVertices, "vertices out");
		Asura_Assert(pxStrip->m_uStartVertexIndex + pxStrip->m_uNumberOfTriangles+2 <= s_pxCurrentHierarchyObject->m_uTotalNumberOfIndices, "indices out");
		Asura_Assert(pxStrip->m_uNumberOfTriangles>=1 /*&& pxStrip->m_uNumberOfTriangles <= 4000*/, "tri count suspect");

		Asura_Render::CurrentStates.RequestWireFrameMode(true);

		pxEffect->RenderAllIndexedPrimitivePasses
							(
								s_pxCurrentHierarchyObject->m_ePrimitiveType,
								pxStrip->m_uLowestVertexUsed,
								pxStrip->m_uNumberOfVertices,
								pxStrip->m_uStartVertexIndex,
								pxStrip->m_uNumberOfTriangles,
								NULL
							);

		Asura_Render::AddToTrianglesRendered(pxStrip->m_uNumberOfTriangles);

	} // for each strip

	Asura_Render::CurrentStates.RequestWireFrameMode(Asura_Render::GetWireframe());

#ifndef ASURA_PC_OBJECTHIERARCHY_USEPERSECTIONSH
	// The SH needs to be reset to the correct lighting, since we've fiddled with it here
	const Asura_SphericalHarmonics_Order2_RGB &xSH = Asura_GI_Solution::s_xSHForCurrentRender;

	xD3DVector.x = xSH.m_afRedCoefficients[1];
	xD3DVector.y = xSH.m_afRedCoefficients[2];
	xD3DVector.z = xSH.m_afRedCoefficients[3];
	xD3DVector.w = xSH.m_afRedCoefficients[0];
	pxEffect->SetParameterByName("g_xObjectRedSH", xD3DVector);
	xD3DVector.x = xSH.m_afGreenCoefficients[1];
	xD3DVector.y = xSH.m_afGreenCoefficients[2];
	xD3DVector.z = xSH.m_afGreenCoefficients[3];
	xD3DVector.w = xSH.m_afGreenCoefficients[0];
	pxEffect->SetParameterByName("g_xObjectGreenSH", xD3DVector);
	xD3DVector.x = xSH.m_afBlueCoefficients[1];
	xD3DVector.y = xSH.m_afBlueCoefficients[2];
	xD3DVector.z = xSH.m_afBlueCoefficients[3];
	xD3DVector.w = xSH.m_afBlueCoefficients[0];
	pxEffect->SetParameterByName("g_xObjectBlueSH", xD3DVector);
#endif //#ifndef ASURA_PC_OBJECTHIERARCHY_USEPERSECTIONSH

	#endif
}
#endif

#if !defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

void Asura_Direct3D_ObjectHierarchyRenderer::EndRender_EffectsSystem(void)
{
	// Flush any effects we may still be using...
	Asura_Direct3D_Effects_System::FlushEffects	();

	// Turn off any pixel shaders we may have used...
	Asura_Direct3D_Shaders::RequestPixelShader	(ASURA_D3D_PS_NONE);
	Asura_Direct3D::D3DDevice->SetPixelShader	(NULL);

	// Reset ZWriteEnable to true, which is what most of the engine expects it to be
	Asura_Render::CurrentStates.RequestZBufferWriteEnabled	(true);

	s_pxCurrentHierarchyObject = 0;
	s_bNormalRendering = false;

	// turn off fog if we have to...
//	if (Asura_Fog::IsFogRenderable())
//	{
//		Asura_Direct3D::D3DDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
//	}
	D3DPERFCALL(EndEvent());
}

#endif // !defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

#if defined(ASURA_TARGET_SM3)
void Asura_Direct3D_ObjectHierarchyRenderer::RenderShadow_EffectsSystem(const Asura_Animation& xAnim,
																		const Asura_Hierarchy_Skin& xSkin,
																		const Asura_Shadow& xShadow,
																		const float fDistance)
{
	Asura_Direct3D_ObjectHierarchyRender_Handler&	xHandler	= GetCurrentHandler();

	SCOPEDPIXEVENT((0xff58ba34, L"SM3 Object-Hierarchy \"%S\" shadow", xSkin.Name));

	s_bNormalRendering = false;
	s_pxCurrentHierarchyObject = xHandler.GetHierarchy(&xSkin);

	s_bNormalRendering = true;

#ifdef ASURA_TARGET_SM3
	if (s_pxCurrentHierarchyObject->m_bHasNormalMappedStrip)
	{
		Asura_Direct3D::D3DDevice->SetStreamSource(0, s_pxCurrentHierarchyObject->m_pxVertexBuffer, 0, sizeof(Asura_Direct3D_ObjectHierarchy_Vertex_NormalMapped));
		Asura_Direct3D::D3DDevice->SetVertexDeclaration(g_pxNormalMapVertexDecl);
	}
	else
#endif //#ifdef ASURA_TARGET_SM3
	{
		Asura_Direct3D::D3DDevice->SetStreamSource(0, s_pxCurrentHierarchyObject->m_pxVertexBuffer, 0, sizeof(Asura_Direct3D_ObjectHierarchy_Vertex));
		Asura_Direct3D::D3DDevice->SetVertexDeclaration(g_pxStandardVertexDecl);
	}

	Asura_Direct3D::D3DDevice->SetIndices(s_pxCurrentHierarchyObject->m_pxIndexBuffer);

	Asura_Render::CurrentStates.RequestCullMode(ASURA_CULLMODE_CW);
	Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_OFF);
	Asura_Render::CurrentStates.RequestZBufferEnabled(true);
	Asura_Render::CurrentStates.RequestZBufferCompareMode(ASURA_ZBUFFERCMP_LESSEQUAL);
	Asura_Render::CurrentStates.RequestZBufferWriteEnabled(true);

	Asura_Direct3D_Effect* pxEffect;
	pxEffect = Asura_Direct3D_Effects_System::BeginEffect("Object_Shadow");

	D3DXMATRIX xViewProj, xTemp;

	const Asura_Vector_3& xLightPos = xShadow.GetLightPosition();
	D3DXMatrixTranslation( &xViewProj, -xLightPos.x, -xLightPos.y, -xLightPos.z );

	// Light orientation
	Asura_Matrix_3x3 xLightOri;
	xShadow.GetLightOrientation(xLightOri);
	memset( &xTemp, 0, sizeof( D3DXMATRIX ) );
	for( u_int u = 0; u < 3; ++u )
	{
		for( u_int v = 0; v < 3; ++v )
		{
			xTemp.m[u][v] = xLightOri.Element[u][v];
			if( v == 1 )
			{
				xTemp.m[u][v] = -xTemp.m[u][v];
			}
		}
	}
	xTemp._44 = 1.0f;
	xViewProj *= xTemp;

	// Projection
	const float fVerticalFOV = Asura_Maths::DegToRad( xShadow.GetFrustum().GetVerticalFOVInDegrees() );
	D3DXMatrixPerspectiveFovLH( &xTemp, fVerticalFOV, 1.0f, xShadow.GetFrustum().GetNearPlane(), xShadow.GetFrustum().GetFarPlane() );
	xViewProj *= xTemp;

	for(u_int uStrip = 0; uStrip < s_pxCurrentHierarchyObject->m_uNumberOfStrips; ++uStrip)
	{
		SCOPEDPIXEVENT((0xff58ba34, L"SM3 Object-Hierarchy shadow - strip %u", uStrip));

		Asura_Direct3D_ObjectHierarchy_Strip* pxStrip = &(s_pxCurrentHierarchyObject->m_pxHierarchyStrip[uStrip]);
		if(pxStrip->m_uNumberOfTriangles == 0) continue;

		const Asura_Hash_ID uHash = pxStrip->m_auMaterialResponseHashID[0];
		const Asura_MaterialResponse* const pxMaterial =
			Asura_MaterialResponse_System::GetMaterialByHashID( uHash );

		if( pxMaterial && (pxMaterial->GetRenderType() == Asura_MaterialResponse::RENDER_TYPE_RENDER_BUT_DONT_CAST_SHADOW) )
		{
			continue;
		}

		const Asura_Vector_3& xBonePos = Asura_Hierarchy_System::GetWorldspaceBonePos( pxStrip->m_usBoneIndex );
		const Asura_Matrix_3x3& xBoneOri = Asura_Hierarchy_System::GetWorldspaceBoneOri( pxStrip->m_usBoneIndex );

		D3DXMATRIX xWorld;
		// World matrix
		xWorld._11 = xBoneOri.e11;	xWorld._12 = xBoneOri.e21;	xWorld._13 = xBoneOri.e31;	xWorld._14 = 0;	 
		xWorld._21 = xBoneOri.e12;	xWorld._22 = xBoneOri.e22;	xWorld._23 = xBoneOri.e32;	xWorld._24 = 0;	 
		xWorld._31 = xBoneOri.e13;	xWorld._32 = xBoneOri.e23;	xWorld._33 = xBoneOri.e33;	xWorld._34 = 0;
		xWorld._41 = xBonePos.x;	xWorld._42 = xBonePos.y;	xWorld._43 = xBonePos.z;	xWorld._44 = 1.0f;

		pxEffect->SetParameterByName("g_xWorldViewProjectionMatrix", xWorld * xViewProj);

		pxEffect->RenderAllIndexedPrimitivePasses
			(
			s_pxCurrentHierarchyObject->m_ePrimitiveType,
			pxStrip->m_uLowestVertexUsed,
			pxStrip->m_uNumberOfVertices,
			pxStrip->m_uStartVertexIndex,
			pxStrip->m_uNumberOfTriangles,
			NULL
			);

		Asura_Render::AddToTrianglesRendered(pxStrip->m_uNumberOfTriangles);

	} // for each strip

	Asura_Direct3D_Effects_System::FlushEffects();

	// Reset ZWriteEnable to true, which is what most of the engine expects it to be
	Asura_Render::CurrentStates.RequestZBufferWriteEnabled	(true);

	s_pxCurrentHierarchyObject = 0;
	s_bNormalRendering = false;
}
#endif

#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

void Asura_Direct3D_ObjectHierarchyRenderer::BeginRender_MaterialResponse( const Asura_Animation* pxAnim,
																		   const Asura_Hierarchy_Skin* pxSkin )
{
	if( !pxAnim || !pxSkin )
	{
		Asura_Assert( false, "NULL parameter passed to Asura_Direct3D_ObjectHierarchyRenderer::BeginRender_MaterialResponse()." );
		return;
	}

	s_pxCurrentHierarchyObject = GetCurrentHandler().GetHierarchy( pxSkin );
	if( !s_pxCurrentHierarchyObject )
	{
		Asura_Assertf( false, ("Unable to find rendering data for hierarchy %s.", pxSkin->Name.GetString() ));
		return;
	}

	// JAT 07/03/05 - we now have a valid hierarchy
	s_bNormalRendering = true;

	Asura_UnicodeChar wszLabel[256];
	Asura_PrintfToBfr( wszLabel, L"Hierarchy '%S' (material response system)", 256, true, pxSkin->Name.GetString() );
	D3DPERFCALL( BeginEvent( 0xFF837B4A, wszLabel ) );

	{
		SCOPEDPIXEVENT(( 0xFF837B4A, L"Begin hierarchy '%S' (material response system)", pxSkin->Name.GetString() ));

		const bool bTransparentPass = Asura_SortedRender::IsTransparentPass();
		const u_int uTechniqueIndex = bTransparentPass ? 1 : 0;

		Asura_Direct3D_Effect* const pxEffect = Asura_Direct3D_Effects_System::BeginEffect(
			"Object_MaterialResponse", uTechniqueIndex );

		if( !pxEffect || !pxEffect->IsD3DEffectValid() ) return;

		// Set main materials data texture
		{
			pxEffect->SetParameterByName( "g_xMaterialsTexture", Asura_Direct3D_MaterialResponse::GetMaterialsTexture());

			const D3DXVECTOR4 xMaterialProperties( 1.0f / ASURA_MATERIAL_RESPONSE_TEXTURE_WIDTH,
				Asura_Direct3D_MaterialResponse::GetMaterialsTextureScale(), 0.0f, 0.0f );

			pxEffect->SetParameterByName( "g_xMaterialsTextureProperties", xMaterialProperties );
		}

		// Set up streams
		{
			Asura_Direct3D::D3DDevice->SetVertexDeclaration( g_pxNormalMapVertexDecl );
			Asura_Direct3D::D3DDevice->SetStreamSource( 0, s_pxCurrentHierarchyObject->m_pxVertexBuffer, 0, sizeof( Asura_Direct3D_ObjectHierarchy_Vertex_NormalMapped ) );
			Asura_Direct3D::D3DDevice->SetIndices( s_pxCurrentHierarchyObject->m_pxIndexBuffer );
		}

		// Set render states
		{
			Asura_Render::CurrentStates.RequestAlphaTest( false );
			Asura_Render::CurrentStates.RequestCullMode( ASURA_CULLMODE_CW );
			Asura_Render::CurrentStates.RequestDitheringMode( true );
			Asura_Render::CurrentStates.RequestDynamicLights( false );
			Asura_Render::CurrentStates.RequestZBufferCompareMode( ASURA_ZBUFFERCMP_LESSEQUAL );
			Asura_Render::CurrentStates.RequestZBufferEnabled( true );

			// Leave wireframe as it was set elsewhere
		}
	}
}

void Asura_Direct3D_ObjectHierarchyRenderer::Render_MaterialResponse( const Asura_Animation* pxAnim,
																	  const Asura_Hierarchy_Skin* pxSkin,
																	  const int iSectionDataIndex,
																	  const Asura_Vector_3& xPosition,
																	  const Asura_Matrix_3x3& xOrientation,
																	  bool bDepthOnly /*= false*/ )
{
	SCOPEDPIXEVENT(( 0xFF837B4A, L"Hierarchy '%S' section %d (material response system)", pxSkin->Name.GetString(), iSectionDataIndex ));

	if( s_pxCurrentHierarchyObject->m_uTotalNumberOfVertices == 0
	 || s_pxCurrentHierarchyObject->m_uTotalNumberOfIndices == 0
	 || !s_pxCurrentHierarchyObject->m_pxHierarchyStrip )
	{
		return;
	}

	Asura_Direct3D_Effect* const pxEffect = Asura_Direct3D_Effects_System::GetCurrentEffect();

	{
		D3DXMATRIX xWorldViewProj;

		// Rotation
		Asura_Mem::Set( &xWorldViewProj, 0, sizeof( xWorldViewProj ) );
		for( u_int u = 0; u < 3; ++u )
		{
			for( u_int v = 0; v < 3; ++v )
			{
				xWorldViewProj.m[u][v] = xOrientation.Element[v][u];
			}
		}

		xWorldViewProj._44 = 1.0f;

		// Translation
		D3DXMATRIX xTemp;
		D3DXMatrixTranslation( &xTemp, xPosition.x, xPosition.y, xPosition.z );
		xWorldViewProj *= xTemp;

		pxEffect->SetParameterByName( "g_xWorldMatrix", xWorldViewProj );

		// View-projection
		xWorldViewProj *= Asura_Direct3D::GetViewProjectionMatrix();

		pxEffect->SetParameterByName( "g_xWorldViewProjectionMatrix", xWorldViewProj );
	}

	const bool bTransparentPass = Asura_SortedRender::IsTransparentPass();


	if (!bTransparentPass)
	{
		Asura_Direct3D_MaterialResponse::SetFogParameters( false, NULL, *pxEffect );	
	}

	for (int iZPrePassMode = !bTransparentPass ; iZPrePassMode < 2; ++iZPrePassMode)
	{
		for( u_int u = 0; u < s_pxCurrentHierarchyObject->m_uNumberOfStrips; ++u )
		{
			const Asura_Direct3D_ObjectHierarchy_Strip& xStrip = s_pxCurrentHierarchyObject->m_pxHierarchyStrip[u];
			if( xStrip.m_usBoneIndex != iSectionDataIndex || xStrip.m_uNumberOfTriangles == 0 )
			{
				continue;
			}

			const Asura_Hash_ID uMaterialHash1 = xStrip.m_auMaterialResponseHashID[0];
			const Asura_MaterialResponse* pxMaterial1
				= Asura_MaterialResponse_System::GetMaterialByHashID( uMaterialHash1 );

			if( pxMaterial1 )
			{
				if( pxMaterial1->GetDontRender() || (iZPrePassMode == 0 && !pxMaterial1->GetZPrePass()) )
				{
					continue;
				}

				const bool bTransparentStrip = pxMaterial1->IsTransparent();
				if( bTransparentStrip != bTransparentPass )
				{
					continue;
				}
			}

			SCOPEDPIXEVENT(( 0xFF837B4A, L"Strip %u", u ));

			// Set material data
			{
				const Asura_Hash_ID uMaterialHash2 = xStrip.m_auMaterialResponseHashID[1];
				const Asura_MaterialResponse* pxMaterial2 = Asura_MaterialResponse_System::GetMaterialByHashID( uMaterialHash2 );

				Asura_Direct3D_MaterialResponse::SetEffectParameters( pxMaterial1, pxMaterial2,
					pxAnim, *pxEffect );

				Asura_Direct3D_MaterialResponse::SetBlendStates( pxMaterial1 );
				Asura_Direct3D_MaterialResponse::SetSHParameters( pxMaterial1, *pxEffect );

				if (bTransparentPass)
				{
					Asura_Direct3D_MaterialResponse::SetFogParameters( true, pxMaterial1, *pxEffect );	
				}

				if (Asura_MaterialResponse_System::GetMaterialProjectContextCallback())
				{
					Asura_MaterialResponse_System::GetMaterialProjectContextCallback()(pxMaterial1->GetProjectContext(), 
						pxMaterial2 ? pxMaterial2->GetProjectContext() : ASURA_MATERIAL_RESPONSE_PROJECT_CONTEXT_INVALID);
				}

			}
			if (iZPrePassMode == 0)
			{
				Asura_Render::CurrentStates.RequestZBufferWriteEnabled( true );
				Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_COLORWRITEENABLE, 0);
			}

			pxEffect->RenderAllIndexedPrimitivePasses( s_pxCurrentHierarchyObject->m_ePrimitiveType,
													   xStrip.m_uLowestVertexUsed,
													   xStrip.m_uNumberOfVertices,
													   xStrip.m_uStartVertexIndex,
													   xStrip.m_uNumberOfTriangles,
													   NULL );

			Asura_Render::AddToTrianglesRendered( xStrip.m_uNumberOfTriangles );

			if (iZPrePassMode == 0)
			{
				Asura_Direct3D_MaterialResponse::SetBlendStates( pxMaterial1 );
				Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA);
			}

		}
	}
}

void Asura_Direct3D_ObjectHierarchyRenderer::EndRender_MaterialResponse()
{
	{
		SCOPEDPIXEVENT(( 0xFF837B4A, L"End Hierarchy (Material Response System)" ));

		for( u_int u = 0; u < 16; ++u )
		{
			Asura_Direct3D::D3DDevice->SetSamplerState( u, D3DSAMP_SRGBTEXTURE, FALSE );
		}

		const float fDepthBias = 0.0f;
		Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_DEPTHBIAS, *(DWORD*)&fDepthBias );

		Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_COLORWRITEENABLE1, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA );
		Asura_Direct3D_Effects_System::FlushEffects();
	}

	D3DPERFCALL( EndEvent() ); // Hierarchy
}

#endif // defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

#endif //#ifdef ASURA_TARGET_SM3

void Asura_Direct3D_ObjectHierarchyRenderer::BeginShadowRender(const class Asura_Hierarchy_Skin* pxSkin, const Asura_Vector_3& xShadowPosition)
{
	Asura_Direct3D_ObjectHierarchyRender_Handler&	xHandler	= Asura_Direct3D_ObjectHierarchyRenderer::GetCurrentHandler();

	s_bShadowRendering = false;
	s_pxCurrentHierarchyObject = xHandler.GetHierarchy(pxSkin);

	if(s_pxCurrentHierarchyObject == NULL)
	{
		Asura_Assert(0,"no Hierarchy strips to render");
		return;
	}

	if (s_pxCurrentHierarchyObject->m_uTotalNumberOfVertices == 0 || s_pxCurrentHierarchyObject->m_uTotalNumberOfIndices == 0)
	{
		Asura_Assert(false, "This hierarchy has no polys!");
		return;
	}

	if (s_pxCurrentHierarchyObject->m_pxHierarchyStrip==0)
	{
		Asura_Assert(false, "No strips?");
		return;
	}

	// KJFL - 2004-02-20 11:11:18 - okay, we think we have a valid hierarchy
	s_bShadowRendering = true;

	Asura_Direct3D_Shaders::RequestVertexShader(ASURA_D3D_VS_OBJECT_PLANARSHADOW);

	
	Asura_Render::CurrentStates.RequestCullMode(ASURA_CULLMODE_CW);

	// orientate and position object in vertex shader
	D3DXMATRIX xMat;
	D3DXMATRIX xMatView, xMatProj;

	Asura_Direct3D::D3DDevice->GetTransform( D3DTS_VIEW, &xMatView );
	Asura_Direct3D::D3DDevice->GetTransform( D3DTS_PROJECTION, &xMatProj );

    D3DXMatrixMultiply( &xMat, &xMatView, &xMatProj );
    D3DXMatrixTranspose( &xMat, &xMat );

    Asura_Direct3D::D3DDevice->SetVertexShaderConstantF(  0, (float*)&xMat,  4 );

	float fFogDensity = Asura_Fog::GetFogDensityAtDistance((xShadowPosition - (*Asura_Camera::GetPosition())).Magnitude());
	Asura_RGBA xFogColour = Asura_Fog::GetFogColour();
	xFogColour *= fFogDensity;

	float afShadowData[] = 
	{
		// y position and w value
		0.0f, xShadowPosition.y, 0.0f, 1.0f,

		// colour & alpha of shadow
		xFogColour.m_fR, xFogColour.m_fG, xFogColour.m_fB, 0.25f*(1-fFogDensity) + xFogColour.m_fA,
	};

	Asura_Direct3D::D3DDevice->SetVertexShaderConstantF(  6, afShadowData,  2 );

	// set up stencil modes
	Asura_Render::CurrentStates.RequestStencilEnabled(true);
	Asura_Direct3D::D3DDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_INVERT);
	Asura_Direct3D::D3DDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP);
	Asura_Direct3D::D3DDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP);
	Asura_Direct3D::D3DDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL);

	// set to no texture, single pass, normal translucency
	Asura_Render::CurrentStates.RequestTextureIndex(0, ASURA_TEXTURE_NONE);
	Asura_Render::CurrentStates.RequestTextureOpMode(ASURA_TEXTUREOP_SINGLE_PASS);
	Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_NORMAL);
	Asura_Render::CurrentStates.RequestAlphaTest(false);

	// set the vertex and index streams
	Asura_Assert(s_pxCurrentHierarchyObject->m_pxVertexBuffer, "No VB");
	Asura_Assert(s_pxCurrentHierarchyObject->m_pxIndexBuffer, "No IB");
#ifdef ASURA_TARGET_SM3
	if (s_pxCurrentHierarchyObject->m_bHasNormalMappedStrip)
	{
		Asura_Direct3D::D3DDevice->SetStreamSource(0, s_pxCurrentHierarchyObject->m_pxVertexBuffer, 0, sizeof(Asura_Direct3D_ObjectHierarchy_Vertex_NormalMapped));
	}
	else
#endif //#ifdef ASURA_TARGET_SM3
	{
		Asura_Direct3D::D3DDevice->SetStreamSource(0, s_pxCurrentHierarchyObject->m_pxVertexBuffer, 0, sizeof(Asura_Direct3D_ObjectHierarchy_Vertex));
	}
	Asura_Direct3D::D3DDevice->SetIndices(s_pxCurrentHierarchyObject->m_pxIndexBuffer);
}

void Asura_Direct3D_ObjectHierarchyRenderer::RenderShadow(const int iSectionDataIndex, const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation)
{
	if (!s_bShadowRendering || !s_pxCurrentHierarchyObject)
	{
		Asura_Assert( false, "No object setup, will skip");
		return;
	}

	float afTransformationData[] = 
	{
		// x rotation 
		xOrientation.e11, xOrientation.e12, xOrientation.e13, xPosition.x,

		// z rotation
		xOrientation.e31, xOrientation.e32, xOrientation.e33, xPosition.z,
	};
	Asura_Direct3D::D3DDevice->SetVertexShaderConstantF(  4, afTransformationData,  2 );

	for(u_int uStrip = 0; uStrip < s_pxCurrentHierarchyObject->m_uNumberOfStrips; ++uStrip)
	{
		Asura_Direct3D_ObjectHierarchy_Strip* pxStrip = &(s_pxCurrentHierarchyObject->m_pxHierarchyStrip[uStrip]);

		if (pxStrip->m_usBoneIndex != iSectionDataIndex) continue;

		if (pxStrip->m_uNumberOfTriangles==0)
		{
			// KJFL - 2004-02-20 11:12:22 - no triangles in this strip. No assert since some hierarchies may have valid 'dummy' bones.
			continue;
		}

		// render strip
		Asura_Assert(pxStrip->m_uLowestVertexUsed+pxStrip->m_uNumberOfVertices <= s_pxCurrentHierarchyObject->m_uTotalNumberOfVertices, "vertices out");
		Asura_Assert(pxStrip->m_uStartVertexIndex + pxStrip->m_uNumberOfTriangles+2 <= s_pxCurrentHierarchyObject->m_uTotalNumberOfIndices, "indices out");
		Asura_Assert(pxStrip->m_uNumberOfTriangles>=1 /*&& pxStrip->m_uNumberOfTriangles <= 4000*/, "tri count suspect");

		Asura_Direct3D::D3DDevice->DrawIndexedPrimitive
							(
								s_pxCurrentHierarchyObject->m_ePrimitiveType,
								0,
								pxStrip->m_uLowestVertexUsed,
								pxStrip->m_uNumberOfVertices,
								pxStrip->m_uStartVertexIndex,
								pxStrip->m_uNumberOfTriangles
							);

		Asura_Render::AddToTrianglesRendered(pxStrip->m_uNumberOfTriangles);
	}
}

void Asura_Direct3D_ObjectHierarchyRenderer::EndShadowRender(void)
{
	Asura_Render::CurrentStates.RequestStencilEnabled(false);
	Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_OFF);

	s_pxCurrentHierarchyObject = 0;
	s_bShadowRendering = false;
}


/// End of file. ///
