//*******************************************************************
// File: Asura_Direct3D_MaterialResponse.cpp
//
// Created: 02 March 2007 DLH
//
// Description: 
//
//*******************************************************************

#include "Core/Asura.h"

#if defined( ASURA_USE_MATERIAL_RESPONSE_SYSTEM)

// main header
#include "Rendering/Asura_Direct3D_MaterialResponse.h"

// Asura platform-independent
#include "Animation/Asura_Animation.h"
#include "Animation/Asura_TextureAnimation.h"
#include "Core/Asura_FixedArray.h"
#include "Core/Asura_MaterialResponse_System.h"
#include "Core/Asura_Maths.h"
#include "Debugging/Asura_Debug_Timers.h"
#include "Interface/Asura_CommandConsole.h"
#include "Light/Asura_GI_Solution.h"
#include "Rendering/Asura_DeferredShading.h"
#include "Rendering/Asura_Fog.h"
#include "Rendering/Asura_Render.h"

#ifdef ASURA_USE_NEW_VISIBILITY_SYSTEM
#include "Visibility/Asura_Visibility_System.h"
#endif

// Asura PC
#include "Rendering/Asura_Direct3D_Effect.h"
#include "Rendering/Asura_Direct3D_EffectParameterBlock.h"
#include "Rendering/Asura_Direct3D_Effects_System.h"
#include "Rendering/Asura_Direct3D_UserOptions.h"
#include "Rendering/Asura_Direct3D_Fog.h"
#if defined(ASURA_USE_MATERIAL_RESPONSE_SYSTEM) && (((ASURA_LOAD_EFFECT_FILES == 1) && !defined( ASURA_NO_LOAD_EFFECTS_FILES_FROM_FILES)) || defined(ASURA_TOOLS))
#include "Rendering/Asura_Direct3D_MRPShaderCompile.h"
#endif

// Tools
#if defined( ASURA_TOOLS )
	#include "Materials/Tools_MaterialResponse_System.h"
	#include "Misc/Tools_Render.h"
	#include "Misc/Tools_Timed_Messages.h"
	#include "Texturing/Tools_Texturing_MaterialResponse.h"
	#include "Tools_System.h"
#endif // #if defined( ASURA_TOOLS )

extern void Asura_PC_MaterialResponse_UpdateTexture();

//*******************************************************************
// Local Classes
//*******************************************************************

struct MaterialTextureFormatDesc
{
public:
	D3DFORMAT m_eFormat;
	float m_fScale;
};

//*******************************************************************
// Local Data
//*******************************************************************

bool Asura_Direct3D_MaterialResponse::s_bMaterialsTextureValid = false;	
Direct3D_Texture* Asura_Direct3D_MaterialResponse::s_pxMaterialsTexture = NULL;
D3DFORMAT Asura_Direct3D_MaterialResponse::s_eMaterialsTextureFormat = D3DFMT_A16B16G16R16F;
float Asura_Direct3D_MaterialResponse::s_fMaterialsTextureScale = 1.0f;

Asura_TemplateHashTree< Asura_Direct3D_MRPShader* > Asura_Direct3D_MaterialResponse::s_xPSTree;

static const MaterialTextureFormatDesc g_axPossibleFormats[] = 
{
	{ D3DFMT_A16B16G16R16F, 1.0f / 1.0f},
	{ D3DFMT_A16B16G16R16, 2.0f / 1.0f },
	{ D3DFMT_A8R8G8B8, 2.0f / 1.0f }
};

#if defined(ASURA_SUPPORT_COMMAND_CONSOLE) 
#if defined( ASURA_TOOLS)
static u_int g_uMaterialsTextureFormat = 0;
static u_int g_uMaterialsTextureFormatLast = 0;
static const u_int g_uMaterialsTextureFormatMax = (sizeof( g_axPossibleFormats) / sizeof( g_axPossibleFormats[0])) - 1;
#endif
#endif

DEBUGVAR float	dbg_fDirect3DMaterialResponseDepthBias	= -0.0001f;


//*******************************************************************
// Function Definitions
//*******************************************************************

Asura_Direct3D_MRPShader::Asura_Direct3D_MRPShader( const void* const pShader )
	: m_pxShader( NULL )
{
	for( u_int u = 0; u < m_aiSamplers.GetSize(); ++u )
	{
		// Use -1 to indicate unset
		m_aiSamplers[u] = -1;
	}

	const DWORD* const puFunction = static_cast< const DWORD* >( pShader );

	HRESULT xResult;
	ID3DXConstantTable* pxConstantTable = NULL;

	if( puFunction )
	{
		// Create a pixel shader object from the compiled token array

		xResult = Asura_Direct3D::D3DDevice->CreatePixelShader( puFunction, &m_pxShader );

		Asura_Assert( SUCCEEDED( xResult ) && m_pxShader,
			"Failed to create material response pixel shader." );

		// Cache the sampler register to which each texture should be bound

		xResult = D3DXGetShaderConstantTableEx( puFunction, D3DXCONSTTABLE_LARGEADDRESSAWARE,
			&pxConstantTable );

		if( SUCCEEDED( xResult ) && pxConstantTable )
		{
			const char* const szSAMPLER_NAMES[] =
			{
				"g_xAlbedoSampler",              "g_xAlbedo2Sampler",
				"g_xNormalMapSampler",           "g_xNormalMap2Sampler",
				"g_xSpecularMapSampler",         "g_xSpecularMap2Sampler",
				"g_xTransparencyMapSampler",     "g_xTransparencyMap2Sampler",
				"g_xSelfIlluminationMapSampler", "g_xSelfIlluminationMap2Sampler",
				"g_xEnvironmentMapSampler",      "g_xEnvironmentMap2Sampler",
				"g_xReflectivityMaskSampler",    "g_xReflectivityMask2Sampler",
				"g_xParallaxMapSampler",         "g_xParallaxMap2Sampler",
				"g_xAlbedoDetailMapSampler",     "g_xAlbedoDetailMap2Sampler",
				"g_xNormalDetailMapSampler",     "g_xNormalDetailMap2Sampler",
			};

			const u_int uArraySize = sizeof( szSAMPLER_NAMES ) / sizeof( szSAMPLER_NAMES[0] );
			const u_int uNumSlots = Asura_MaterialResponse::NUMBER_OF_TEXTURE_SLOTS * 2;

			ASURA_STATIC_ASSERT( uArraySize == uNumSlots );

			for( u_int u = 0; u < uArraySize; ++u )
			{
				const D3DXHANDLE xHandle =
					pxConstantTable->GetConstantByName( NULL, szSAMPLER_NAMES[u] );

				if( xHandle )
				{
					m_aiSamplers[u] = pxConstantTable->GetSamplerIndex( xHandle );
				}
			}
		}
		else
		{
			Asura_Assert( false, "Failed to access pixel shader constant table." );
		}
	}

	SAFE_RELEASE( pxConstantTable );
}

Asura_Direct3D_MRPShader::~Asura_Direct3D_MRPShader()
{
	SAFE_RELEASE( m_pxShader );
}

void Asura_Direct3D_MaterialResponse::MakeTexture()
{
	HRESULT xResult;
	
	SAFE_RELEASE( s_pxMaterialsTexture);
	
	xResult = Asura_Direct3D::D3DDevice->CreateTexture( ASURA_MATERIAL_RESPONSE_TEXTURE_WIDTH,
		ASURA_PC_MATERIALS_TEXTURE_HEIGHT, 1, 0, s_eMaterialsTextureFormat, D3DPOOL_MANAGED,
		&s_pxMaterialsTexture, NULL );

	ASURA_D3D_OK( xResult);
	
	Asura_Assert( NULL != s_pxMaterialsTexture, "Failed to create material response system texture." );
}

void Asura_Direct3D_MaterialResponse::Initialise()
{
	HRESULT xResult;
	
	if( !Asura_Direct3D::D3DDevice )
	{
		//Asura_Assert( false, "Trying to initialise material response system before D3D." );
		return;
	}

	ASURA_CPU_PROFILE_SCOPED_TIMER( "Asura_Direct3D_MaterialResponse::Initialise");
	
#if defined(ASURA_SUPPORT_COMMAND_CONSOLE) 
	#if defined( ASURA_TOOLS)
		Asura_CommandConsole::AddVar( L"Render.Material Response.Graph Texture Format", &(g_uMaterialsTextureFormat), 0, g_uMaterialsTextureFormatMax, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	#endif
#endif
	{	
		// DLH - 12 June 2007 16:23:45 - Find the texture that supports filtering
 		const Asura_Direct3D_UserOptions::Options& xOptions = Asura_Direct3D_UserOptions::GetCurrentOptions();
		static const u_int uPossibleFormatsSize = sizeof( g_axPossibleFormats) / sizeof( g_axPossibleFormats[0]);
		const MaterialTextureFormatDesc* pxFoundDesc = NULL;
		
		for( u_int uPossibleFormatIndex = 0; uPossibleFormatIndex < uPossibleFormatsSize; uPossibleFormatIndex += 1)
		{
			const MaterialTextureFormatDesc& xPossibleFormat = g_axPossibleFormats[ uPossibleFormatIndex];
			D3DFORMAT eTestFormat = xPossibleFormat.m_eFormat;
			
			xResult = Asura_Direct3D::D3DObject->CheckDeviceFormat( xOptions.m_uAdapterIndex, xOptions.m_eDevType, xOptions.m_eFrontBufferFormat, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, eTestFormat);
			if( xResult)
			{
				continue;
			}
			
			pxFoundDesc = &xPossibleFormat;
			break;
		}
		
		if( NULL != pxFoundDesc)
		{
#if defined(ASURA_SUPPORT_COMMAND_CONSOLE) 
	#if defined( ASURA_TOOLS)
			g_uMaterialsTextureFormat = pxFoundDesc - g_axPossibleFormats;
			g_uMaterialsTextureFormatLast = g_uMaterialsTextureFormat;
	#endif
#endif
			s_eMaterialsTextureFormat = pxFoundDesc->m_eFormat;
			s_fMaterialsTextureScale = pxFoundDesc->m_fScale;
		}
	}

	MakeTexture();
}

void Asura_Direct3D_MaterialResponse::Reset()
{
	// Remove pixel shaders. TODO: we're going to have problems with global materials, but not an
	// issue for the moment since we're only doing this for the environment

#if defined(ASURA_USE_MATERIAL_RESPONSE_SYSTEM) && (((ASURA_LOAD_EFFECT_FILES == 1) && !defined( ASURA_NO_LOAD_EFFECTS_FILES_FROM_FILES)) || defined(ASURA_TOOLS))
	Asura_Direct3D_MRPShaderCompile::ResetLoadedShaderList();
#endif

	Asura_TemplateHashTree_Iterator< Asura_Direct3D_MRPShader* > xIter( s_xPSTree );
	while( !xIter.Done() )
	{
		const Asura_Hash_ID uNameHash = xIter.GetCurrentHash();
		Asura_Direct3D_MRPShader** const ppxShader = xIter.GetCurrent();

		xIter.Next();

		delete *ppxShader;
		s_xPSTree.DeleteNodeByHash( uNameHash );
	}
}

void Asura_Direct3D_MaterialResponse::Shutdown()
{
	SAFE_RELEASE( s_pxMaterialsTexture);
}

void Asura_Direct3D_MaterialResponse::SetMaterialsTextureValid( const bool bValid)
{
	s_bMaterialsTextureValid = bValid;
}

Direct3D_Texture* Asura_Direct3D_MaterialResponse::GetMaterialsTexture( const bool bUpdate /* = true */)
{
#if defined( ASURA_TOOLS)
	#if defined(ASURA_SUPPORT_COMMAND_CONSOLE) 
	if( g_uMaterialsTextureFormat != g_uMaterialsTextureFormatLast)
	{
		const MaterialTextureFormatDesc* pxFoundDesc = &(g_axPossibleFormats[ g_uMaterialsTextureFormat]);
		
		s_eMaterialsTextureFormat = pxFoundDesc->m_eFormat;
		s_fMaterialsTextureScale = pxFoundDesc->m_fScale;
		
		g_uMaterialsTextureFormatLast = g_uMaterialsTextureFormat;
		
		MakeTexture();
		
		s_bMaterialsTextureValid = false;
	}
	#endif
	if( true == bUpdate && false == s_bMaterialsTextureValid)
	{
		Asura_PC_MaterialResponse_UpdateTexture();
	}
#endif
	return( s_pxMaterialsTexture);
}

void Asura_Direct3D_MaterialResponse::SetBlendStates( const Asura_MaterialResponse* const pxMaterial )
{
#ifdef ASURA_USE_NEW_VISIBILITY_SYSTEM
	if ( Asura_Visibility_System::ShouldRenderInXRayMode() )
	{
		SCOPEDPIXEVENT(( 0xFF884499, L"Set blend mode (additive)" ));

		Asura_Render::CurrentStates.RequestZBufferWriteEnabled( false );
		Asura_Render::CurrentStates.RequestTranslucencyMode( ASURA_TRANSLUCENCY_GLOWING );
		return;
	}
#endif

	const Asura_MaterialResponse::BLEND_MODE eBlendMode = pxMaterial
														? pxMaterial->GetBlendMode()
														: Asura_MaterialResponse::BLEND_MODE_OPAQUE;

	switch( eBlendMode )
	{
		default:
		case Asura_MaterialResponse::BLEND_MODE_OPAQUE:
		{
			SCOPEDPIXEVENT(( 0xFF884499, L"Set blend mode (opaque)" ))

			Asura_Render::CurrentStates.RequestZBufferWriteEnabled( true );
			Asura_Render::CurrentStates.RequestTranslucencyMode( ASURA_TRANSLUCENCY_OFF );

			break;
		}

		case Asura_MaterialResponse::BLEND_MODE_ADDITIVE:
		{
			SCOPEDPIXEVENT(( 0xFF884499, L"Set blend mode (additive)" ));

			Asura_Render::CurrentStates.RequestZBufferWriteEnabled( false );
			Asura_Render::CurrentStates.RequestTranslucencyMode( ASURA_TRANSLUCENCY_GLOWING );

			break;
		}

		case Asura_MaterialResponse::BLEND_MODE_BACKGROUNDBLEND:
		{
			SCOPEDPIXEVENT(( 0xFF884499, L"Set blend mode (background)" ));

			Asura_Render::CurrentStates.RequestZBufferWriteEnabled( false );
			Asura_Render::CurrentStates.RequestTranslucencyMode( ASURA_TRANSLUCENCY_NORMAL );

			break;
		}
	}

	if( pxMaterial && pxMaterial->GetIsDecal() )
	{
		// Apply depth bias so these can display above coplanar geometry
		Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_DEPTHBIAS, *(DWORD*)&dbg_fDirect3DMaterialResponseDepthBias );

		if( eBlendMode != Asura_MaterialResponse::BLEND_MODE_OPAQUE )
		{
			// Need to disable writes to the normal-depth buffer and material ID channel
			Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_COLORWRITEENABLE1, 0 );
			Asura_Direct3D::D3DDevice->SetRenderState( D3DRS_COLORWRITEENABLE2, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE );
		}
	}
	else
	{
		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::D3DDevice->SetRenderState( D3DRS_COLORWRITEENABLE2, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA );
	}
}

void Asura_Direct3D_MaterialResponse::SetEffectParameters(
	const Asura_MaterialResponse* const pxMaterial1,
	const Asura_MaterialResponse* const pxMaterial2, const Asura_Animation* const pxAnim,
	Asura_Direct3D_Effect& xEffect )
{
	SCOPEDPIXEVENT(( 0xFFFFFFFF, L"Set material parameters" ));

	const Asura_TextureAnimationController* const pxTextureAnimationController =
		(pxAnim ? pxAnim->GetTextureAnimController() : NULL);

	xEffect.SetParameterByHash( "g_xMaterialsTexture", 0xfc009a0f, GetMaterialsTexture() );

	// Set materials texture properties
	{
		D3DXVECTOR4 xProperties;

		xProperties.x = 1.0f / ASURA_MATERIAL_RESPONSE_TEXTURE_WIDTH;
		xProperties.y = GetMaterialsTextureScale();
		xProperties.z = 0.0f;
		xProperties.w = 0.0f;

		xEffect.SetParameterByHash( "g_xMaterialsTextureProperties", 0x11bc2082, xProperties );
	}

	if( pxMaterial1 )
	{
		// Set texture usage flags
		{
#if defined( ASURA_TOOLS )
			const bool bEnableTexturing = Tools_Render::TexturingIsOn();
#else // #if defined( ASURA_TOOLS )
			const bool bEnableTexturing = true;
#endif // #if defined( ASURA_TOOLS )
			xEffect.SetParameterByHash( "g_bUseAlbedo", 0xd55e83b6, ( pxMaterial1->GetTexture( Asura_MaterialResponse::ALBEDO_TEXTURE ) != ASURA_TEXTURE_NONE ) && bEnableTexturing );
			xEffect.SetParameterByHash( "g_bUseNormalMap", 0x1cbefcf8, pxMaterial1->GetTexture( Asura_MaterialResponse::NORMAL_MAP ) != ASURA_TEXTURE_NONE );
			xEffect.SetParameterByHash( "g_bUseSpecularMap", 0x50ca6c5c, pxMaterial1->GetTexture( Asura_MaterialResponse::SPECULAR_MAP ) != ASURA_TEXTURE_NONE );
			xEffect.SetParameterByHash( "g_bUseTransparencyMap", 0xa0ccd6a7, pxMaterial1->GetTexture( Asura_MaterialResponse::TRANSPARENCY_MAP ) != ASURA_TEXTURE_NONE );
			xEffect.SetParameterByHash( "g_bUseSelfIlluminationMap", 0x1d9db684, pxMaterial1->GetTexture( Asura_MaterialResponse::SELFILLUMINATION_MAP ) != ASURA_TEXTURE_NONE );
			xEffect.SetParameterByHash( "g_bUseEnvironmentMap", 0x8e2dfa66, ( pxMaterial1->GetTexture( Asura_MaterialResponse::ENVIRONMENT_MAP ) != ASURA_TEXTURE_NONE ) && bEnableTexturing );
			xEffect.SetParameterByHash( "g_bUseReflectivityMask", 0x9c03556d, pxMaterial1->GetTexture( Asura_MaterialResponse::REFLECTIVITY_MASK ) != ASURA_TEXTURE_NONE );
			xEffect.SetParameterByHash( "g_bUseParallaxMap", 0x1d70a188, pxMaterial1->GetTexture( Asura_MaterialResponse::PARALLAX_MAP ) != ASURA_TEXTURE_NONE );
			
			xEffect.SetParameterByHash( "g_bDualAlbedo", 0x5a40683f, ( pxMaterial2 && pxMaterial2->GetTexture( Asura_MaterialResponse::ALBEDO_TEXTURE ) != ASURA_TEXTURE_NONE ) && bEnableTexturing );
			xEffect.SetParameterByHash( "g_bDualNormalMap", 0xc820dfcf, pxMaterial2 && pxMaterial2->GetTexture( Asura_MaterialResponse::NORMAL_MAP ) != ASURA_TEXTURE_NONE );
			xEffect.SetParameterByHash( "g_bDualSpecularMap", 0xab3ef573, pxMaterial2 && pxMaterial2->GetTexture( Asura_MaterialResponse::SPECULAR_MAP ) != ASURA_TEXTURE_NONE );
			xEffect.SetParameterByHash( "g_bDualTransparencyMap", 0x2d18fc3e, pxMaterial2 && pxMaterial2->GetTexture( Asura_MaterialResponse::TRANSPARENCY_MAP ) != ASURA_TEXTURE_NONE );
			xEffect.SetParameterByHash( "g_bDualSelfIlluminationMap", 0xb59f389b, pxMaterial2 && pxMaterial2->GetTexture( Asura_MaterialResponse::SELFILLUMINATION_MAP ) != ASURA_TEXTURE_NONE );
			xEffect.SetParameterByHash( "g_bDualParallaxMap", 0x77e52a9f, pxMaterial2 && pxMaterial2->GetTexture( Asura_MaterialResponse::PARALLAX_MAP ) != ASURA_TEXTURE_NONE );
		}

		// Set textures
		{
			xEffect.SetParameterByHash( "g_xAlbedo", 0xabaa2959, Asura_Direct3D::GetDirect3DTextureByIndex( pxMaterial1->GetTexture( Asura_MaterialResponse::ALBEDO_TEXTURE ) ) );
			xEffect.SetParameterByHash( "g_xNormalMap", 0xe9df5075, Asura_Direct3D::GetDirect3DTextureByIndex( pxMaterial1->GetTexture( Asura_MaterialResponse::NORMAL_MAP ) ) );
			xEffect.SetParameterByHash( "g_xSpecularMap", 0x5723d499, Asura_Direct3D::GetDirect3DTextureByIndex( pxMaterial1->GetTexture( Asura_MaterialResponse::SPECULAR_MAP ) ) );
			xEffect.SetParameterByHash( "g_xTransparencyMap", 0x8f8dd864, Asura_Direct3D::GetDirect3DTextureByIndex( pxMaterial1->GetTexture( Asura_MaterialResponse::TRANSPARENCY_MAP ) ) );
			xEffect.SetParameterByHash( "g_xSelfIlluminationMap", 0xdc5d91c1, Asura_Direct3D::GetDirect3DTextureByIndex( pxMaterial1->GetTexture( Asura_MaterialResponse::SELFILLUMINATION_MAP ) ) );
			xEffect.SetParameterByHash( "g_xEnvironmentMap", 0x6c974d09, Asura_Direct3D::GetDirect3DTextureByIndex( pxMaterial1->GetTexture( Asura_MaterialResponse::ENVIRONMENT_MAP ) ) );
			xEffect.SetParameterByHash( "g_xReflectivityMask", 0x85628b50, Asura_Direct3D::GetDirect3DTextureByIndex( pxMaterial1->GetTexture( Asura_MaterialResponse::REFLECTIVITY_MASK ) ) );
			xEffect.SetParameterByHash( "g_xParallaxMap", 0x23ca09c5, Asura_Direct3D::GetDirect3DTextureByIndex( pxMaterial1->GetTexture( Asura_MaterialResponse::PARALLAX_MAP ) ) );

			if(pxMaterial2)
			{
				xEffect.SetParameterByHash( "g_xAlbedo2", 0xc99b01f9, Asura_Direct3D::GetDirect3DTextureByIndex( pxMaterial2->GetTexture( Asura_MaterialResponse::ALBEDO_TEXTURE ) ) );
				xEffect.SetParameterByHash( "g_xNormalMap2", 0x520abe5d, Asura_Direct3D::GetDirect3DTextureByIndex( pxMaterial2->GetTexture( Asura_MaterialResponse::NORMAL_MAP ) ) );
				xEffect.SetParameterByHash( "g_xSpecularMap2", 0x8d56beb9, Asura_Direct3D::GetDirect3DTextureByIndex( pxMaterial2->GetTexture( Asura_MaterialResponse::SPECULAR_MAP ) ) );
				xEffect.SetParameterByHash( "g_xTransparencyMap2", 0x622d344e, Asura_Direct3D::GetDirect3DTextureByIndex( pxMaterial2->GetTexture( Asura_MaterialResponse::TRANSPARENCY_MAP ) ) );
				xEffect.SetParameterByHash( "g_xSelfIlluminationMap2", 0xaf54a691, Asura_Direct3D::GetDirect3DTextureByIndex( pxMaterial2->GetTexture( Asura_MaterialResponse::SELFILLUMINATION_MAP ) ) );
				xEffect.SetParameterByHash( "g_xParallaxMap2", 0x55772f0d, Asura_Direct3D::GetDirect3DTextureByIndex( pxMaterial2->GetTexture( Asura_MaterialResponse::PARALLAX_MAP ) ) );
			}
			else
			{
				xEffect.SetParameterByHash( "g_xAlbedo2", 0xc99b01f9, Asura_Direct3D::GetDirect3DTextureByIndex(ASURA_TEXTURE_NONE));
				xEffect.SetParameterByHash( "g_xNormalMap2", 0x520abe5d, Asura_Direct3D::GetDirect3DTextureByIndex(ASURA_TEXTURE_NONE));
				xEffect.SetParameterByHash( "g_xSpecularMap2", 0x8d56beb9, Asura_Direct3D::GetDirect3DTextureByIndex(ASURA_TEXTURE_NONE));
				xEffect.SetParameterByHash( "g_xTransparencyMap2", 0x622d344e, Asura_Direct3D::GetDirect3DTextureByIndex(ASURA_TEXTURE_NONE));
				xEffect.SetParameterByHash( "g_xSelfIlluminationMap2", 0xaf54a691, Asura_Direct3D::GetDirect3DTextureByIndex(ASURA_TEXTURE_NONE));
				xEffect.SetParameterByHash( "g_xParallaxMap2", 0x55772f0d, Asura_Direct3D::GetDirect3DTextureByIndex(ASURA_TEXTURE_NONE) );
			}
		}

		// Set misc packed properties
		{
			D3DXVECTOR4 xProperties;

			xProperties.x = (static_cast< float >( pxMaterial1->GetMaterialIndex() ) + 0.5f) / ASURA_PC_MATERIALS_TEXTURE_HEIGHT;
			xProperties.y = pxMaterial1->GetReflectivity();

			// Set parallax bias to half the scale for now, centres effect on the polygon position
			xProperties.z = pxMaterial1->GetParallaxScale();
			xProperties.w = -xProperties.z * 0.5f;

			xEffect.SetParameterByHash( "g_xMaterialProperties", 0x46b5143a, xProperties );
		}

		// Set self-illumination parameters
		{
			float fSelfIlluminationAmount;
			float fSelfIlluminationColourise;
			Asura_RGBA xSelfIlluminationColour;
			pxMaterial1->GetSelfIllumination(pxTextureAnimationController, fSelfIlluminationAmount, fSelfIlluminationColourise, xSelfIlluminationColour);


			D3DXVECTOR4 xSelfIlluminationParameters( xSelfIlluminationColour.m_fR, xSelfIlluminationColour.m_fG, xSelfIlluminationColour.m_fB, 0.0f );
			xSelfIlluminationParameters *= fSelfIlluminationAmount * fSelfIlluminationColourise;
			xSelfIlluminationParameters.w = fSelfIlluminationAmount * (1.0f - fSelfIlluminationColourise);

			xEffect.SetParameterByHash( "g_xSelfIlluminationParameters", 0x43d109e5, xSelfIlluminationParameters );
		}

		// Set texture animation
		{
			// Grab the texture anim UV offsets for both channels
			Asura_TextureAnimationOutput xTexAnim1, xTexAnim2;

			Asura_TextureAnimation_System::GetAnimationState( pxMaterial1->GetTextureAnim(), pxTextureAnimationController, &xTexAnim1 );
			Asura_TextureAnimation_System::GetAnimationState( pxMaterial2 ? pxMaterial2->GetTextureAnim() : 0, pxTextureAnimationController, &xTexAnim2 );

			const D3DXVECTOR4 xTexCoordOffset( xTexAnim1.m_fUOffset, xTexAnim1.m_fVOffset, xTexAnim2.m_fUOffset, xTexAnim2.m_fVOffset );
			xEffect.SetParameterByHash( "g_xUV_Offsets", 0xca387942, xTexCoordOffset );
		}

		// Albedo modifier
		{
			Asura_RGBA xAlbedoModifier( 1.0f, 1.0f, 1.0f, 1.0f );

			if( Asura_MaterialResponse_System::GetAlbedoModifierCallback() )
			{
				Asura_MaterialResponse_System::GetAlbedoModifierCallback()( pxAnim,
					pxMaterial1->GetProjectContext(), xAlbedoModifier );
			}

			const D3DXVECTOR4 xVec( &xAlbedoModifier.m_fR );
			xEffect.SetParameterByHash( "g_xAlbedoModifier", 0xBE8BC330, xVec );
		}

		// Misc
		{
			const bool bBlendIntoAlbedo = (pxMaterial1->GetBlendMode() != Asura_MaterialResponse::BLEND_MODE_OPAQUE)
										&& pxMaterial1->GetIsDecal();

			xEffect.SetParameterByName( "g_bBlendIntoAlbedo", bBlendIntoAlbedo );
		}
	}
	else
	{
		// Set texture usage flags
		{
			xEffect.SetParameterByHash( "g_bUseAlbedo", 0xd55e83b6, false );
 			xEffect.SetParameterByHash( "g_bUseNormalMap", 0x1cbefcf8, false );
			xEffect.SetParameterByHash( "g_bUseSpecularMap", 0x50ca6c5c, false );
			xEffect.SetParameterByHash( "g_bUseTransparencyMap", 0xa0ccd6a7, false );
			xEffect.SetParameterByHash( "g_bUseSelfIlluminationMap", 0x1d9db684, false );
			xEffect.SetParameterByHash( "g_bUseEnvironmentMap", 0x8e2dfa66, false );
			xEffect.SetParameterByHash( "g_bUseReflectivityMask", 0x9c03556d, false );
			xEffect.SetParameterByHash( "g_bUseParallaxMap", 0x1d70a188, false );
		}

		// Set self-illumination parameters
		{
			const D3DXVECTOR4 xSelfIlluminationParameters( 0.0f, 0.0f, 0.0f, 0.0f );
			xEffect.SetParameterByHash( "g_xSelfIlluminationParameters", 0x43d109e5, xSelfIlluminationParameters );
		}

		// Zero the uv offsets
		{
			const D3DXVECTOR4 xTexCoordOffset( 0.0f, 0.0f, 0.0f, 0.0f );
			xEffect.SetParameterByHash( "g_xUV_Offsets", 0xca387942, xTexCoordOffset );
		}

		// Identity albedo modifier
		{
			const D3DXVECTOR4 xAlbedoModifier( 1.0f, 1.0f, 1.0f, 1.0f );
			xEffect.SetParameterByHash( "g_xAlbedoModifier", 0xBE8BC330, xAlbedoModifier );
		}

		// Misc
		{
			// Just use the first material's responses
			const D3DXVECTOR4 xProperties( 0.5f, 0.0f, 0.0f, 0.0f );
			xEffect.SetParameterByHash( "g_xMaterialProperties", 0x46b5143a, xProperties );
			xEffect.SetParameterByName( "g_bBlendIntoAlbedo", false );
		}
	}
}

void Asura_Direct3D_MaterialResponse::SetSHParameters( const Asura_MaterialResponse* const pxMaterial,
													   Asura_Direct3D_Effect& xEffect )
{
	SCOPEDPIXEVENT(( 0xFFFFFFFF, L"Set SH parameters" ));

	Asura_SphericalHarmonics_Order2_RGB xSH;

	if( pxMaterial )
	{
		// Set SH lighting by considering static and dynamic components separately

		xSH = Asura_GI_Solution::s_xStaticSHForCurrentRender;

		Asura_RGBA xColour = pxMaterial->GetAmbientColour();

		const float fPrelightingColourise = pxMaterial->GetPrelightingColourise();
		xSH.Colourise( xColour.m_fR, xColour.m_fG, xColour.m_fB, fPrelightingColourise );

		const float fAmbientContribution = pxMaterial->GetAmbientContribution();
		xSH.Scale( fAmbientContribution );

		if( pxMaterial->IsTransparent() )
		{	
			xSH += Asura_GI_Solution::s_xDynamicSHForCurrentRender;
		}
	}
	else
	{
		// send through basic SH
		xSH = Asura_GI_Solution::s_xSHForCurrentRender;
	}

	// Set effect parameters

	const D3DXVECTOR4 xRedSH( xSH.m_afRedCoefficients[1], xSH.m_afRedCoefficients[2],
							  xSH.m_afRedCoefficients[3], xSH.m_afRedCoefficients[0] );

	const D3DXVECTOR4 xGreenSH( xSH.m_afGreenCoefficients[1], xSH.m_afGreenCoefficients[2],
								xSH.m_afGreenCoefficients[3], xSH.m_afGreenCoefficients[0] );

	const D3DXVECTOR4 xBlueSH( xSH.m_afBlueCoefficients[1], xSH.m_afBlueCoefficients[2],
							   xSH.m_afBlueCoefficients[3], xSH.m_afBlueCoefficients[0] );

	xEffect.SetParameterByName( "g_xRedSH", xRedSH );
	xEffect.SetParameterByName( "g_xGreenSH", xGreenSH );
	xEffect.SetParameterByName( "g_xBlueSH", xBlueSH );

	// Now we've scaled the SH, calculate the related light properties for transparent render
	if( pxMaterial && pxMaterial->IsTransparent() )
	{
		// Find the brightest direction

		Asura_Vector_3 xLightDirection_Asura;
		xSH.GetBrightestDirection( xLightDirection_Asura );

		if( xLightDirection_Asura.ApproximatelyEquals( Asura_Maths::ZeroVector3 ) )
		{
			// If there are no lights, we'll get a zero direction. Not much we can do here,
			// might as well consider the light as coming from above
			xLightDirection_Asura.y = -1.0f;
		}

		const D3DXVECTOR4 xLightDirection_D3DX( xLightDirection_Asura.x,
												xLightDirection_Asura.y,
												xLightDirection_Asura.z,
												1.0f );

		// Evaluate the colour in that direction

		D3DXVECTOR4 xLightColour;
		{
			xLightColour.x = D3DXVec4Dot( &xLightDirection_D3DX, &xRedSH );
			xLightColour.y = D3DXVec4Dot( &xLightDirection_D3DX, &xGreenSH );
			xLightColour.z = D3DXVec4Dot( &xLightDirection_D3DX, &xBlueSH );
			xLightColour.w = 0.0f;

			const D3DXVECTOR4 xZero( 0.0f, 0.0f, 0.0f, 0.0f );
			D3DXVec4Maximize( &xLightColour, &xLightColour, &xZero );
		}

		// Use the same method to calculate light brightness as the photon shaders. Should
		// probably use standard luminance calculation instead
		const D3DXVECTOR4 xAveragingVector( 0.333f, 0.333f, 0.333f, 0.0f );

		// Store the result in the w component to minimise number of constant registers used
		xLightColour.w = D3DXVec4Dot( &xLightColour, &xAveragingVector );

		xEffect.SetParameterByName( "g_xSHLightDirection", xLightDirection_D3DX );
		xEffect.SetParameterByName( "g_xSHLightColour", xLightColour );
	}
}


void Asura_Direct3D_MaterialResponse::SetFogParameters(bool bIsForwardPass, const Asura_MaterialResponse* const pxMaterial, Asura_Direct3D_Effect& xEffect )
{	
	if (!bIsForwardPass)
	{
		xEffect.SetParameterByHash("g_bFogEnabled", 0xDBC836CD, false);
	}
	else if (pxMaterial)
	{
		xEffect.SetParameterByHash("g_bFogEnabled", 0xDBC836CD, Asura_Fog::IsFogEnabled());

		if (Asura_Fog::IsFogEnabled())
		{
			xEffect.SetParameterTextureByHash("g_xFogTexture", 0xB2DDDD3D,
				Asura_Direct3D_Fog::GetTexture());

			const D3DXVECTOR4 xFogData(Asura_Fog::GetFogNearPlane(),
				Asura_Fog::GetOneOverFogPlaneSeparation(), 0.0f, 0.0f);

			xEffect.SetParameterByHash("g_xFogParams", 0x06F86524, xFogData);

			D3DXVECTOR4 xCol;

			if (pxMaterial->GetBlendMode() == Asura_MaterialResponse::BLEND_MODE_ADDITIVE)
			{
				// Additive-blended materials fog out to black, not the fog colour
				xCol.x = 0;
				xCol.y = 0;
				xCol.z = 0;
			}
			else
			{
				
				xCol.x = Asura_Fog::GetFogColour().m_fR;
				xCol.y = Asura_Fog::GetFogColour().m_fG;
				xCol.z = Asura_Fog::GetFogColour().m_fB;
			}	

			xEffect.SetParameterByHash("g_xFogColour", 0xF18C296A, xCol);
		}
	}
}

Asura_Direct3D_MRPShader* Asura_Direct3D_MaterialResponse::AddPixelShader(
	const Asura_Hash_ID uHash, const void* const pData )
{
	Asura_Direct3D_MRPShader* pxShader = new Asura_Direct3D_MRPShader( pData );
	Asura_Assert( pxShader, "Failed to allocate material response pixel shader." );

	if( !s_xPSTree.AddNode( uHash, pxShader ) )
	{
		#if !defined ASURA_DONT_ASSERT_ON_DUPLICATE_RESOURCE_DATA
			// Might actually be out of memory, or during a tree traversal etc, but those are
			// covered by separate asserts
			Asura_Assertf( false, ("Pixel shader 0x%X already loaded.", uHash) );
		#endif

		delete pxShader;
		pxShader = NULL;
	}

	return pxShader;
}

Asura_Direct3D_MRPShader* Asura_Direct3D_MaterialResponse::ReplacePixelShader(
	const Asura_Hash_ID uHash, const void* const pData )
{
	Asura_Direct3D_MRPShader* const pxShader = new Asura_Direct3D_MRPShader( pData );
	Asura_Assert( pxShader, "Failed to allocate material response pixel shader." );

	if (pxShader)
	{
		bool bDidExist;
		Asura_Direct3D_MRPShader** ppxOldShader = s_xPSTree.AddOrFindNode( uHash, &bDidExist );

		if (bDidExist)
		{
			delete *ppxOldShader;
		}
		*ppxOldShader = pxShader;
	}

	return pxShader;
}


Asura_Direct3D_MRPShader* Asura_Direct3D_MaterialResponse::GetPixelShader( const Asura_Hash_ID uHash )
{
	Asura_Direct3D_MRPShader** const ppxResult = s_xPSTree.GetDataByHash( uHash );

	#if defined ASURA_TOOLS

		if( ppxResult )
		{
			return *ppxResult;
		}
		else
		{
			// Not come across this shader before, so compile it now

			// At most 32 macros from the bitfield, plus NOT_EFFECT, ASURA_TOOLS, NULL terminator
			Asura_FixedArray< D3DXMACRO, 35 > axMacros;

			bool bSkin, bDeferred;
			if( !Asura_Direct3D_MRPShaderCompile::GetMRPSMacrosFromHash( uHash, &axMacros[0],
				bSkin, bDeferred ) )
			{
				Tools_Timed_Message_System::AddMessage( Tools_Timed_Message_System::COLOUR_ERROR,
					"Too many texture slots required by pixel shader." );
			}

			// In Tools builds, add the extra options

			for( u_int u = 0; u < axMacros.GetSize(); u++ )
			{
				if( !axMacros[u].Name && !axMacros[u].Definition )
				{
					axMacros[u].Name = "ASURA_TOOLS";
					axMacros[u].Definition = NULL;

					axMacros[u+1].Name = NULL;
					axMacros[u+1].Definition = NULL;

					break;
				}
			}

			ID3DXBuffer* pxBuffer =
				Asura_Direct3D_MRPShaderCompile::CompileMRPShader( &axMacros[0], bSkin, bDeferred );

			const void* const pCompiledData = (pxBuffer ? pxBuffer->GetBufferPointer() : NULL);

			Asura_Direct3D_MRPShader* const pxShader = AddPixelShader( uHash, pCompiledData );

			SAFE_RELEASE( pxBuffer );

			return pxShader;
		}

	#else
		Asura_Assertf( ppxResult, ("Failed to get pixel shader with hash ID 0x%X.", uHash) );
		return ppxResult ? *ppxResult : NULL;
	#endif
}

void Asura_Direct3D_MaterialResponse::SetMaterialConstants( const Asura_Hash_ID uPSHash,
	const Asura_MaterialResponse* const pxMaterial1,
	const Asura_MaterialResponse* const pxMaterial2, const Asura_Animation* const pxAnim )
{
	Direct3D_Device* const pxDevice = Asura_Direct3D::D3DDevice;

	const Asura_TextureAnimationController* const pxTextureAnimController
		= (pxAnim ? pxAnim->GetTextureAnimController() : NULL);

	Asura_Hash_ID uModifiedHash = uPSHash;

	#if defined ASURA_TOOLS

		if( !Tools_Render::TexturingIsOn() )
		{
			// Disable the bits for albedo textures & environment maps

			u_int uDisabledBits = 1 << (2 * Asura_MaterialResponse::ALBEDO_TEXTURE);
			uDisabledBits |= 1 << (2 * Asura_MaterialResponse::ALBEDO_TEXTURE + 1);
			uDisabledBits |= 1 << (2 * Asura_MaterialResponse::DETAIL_MAP);
			uDisabledBits |= 1 << (2 * Asura_MaterialResponse::DETAIL_MAP + 1);
			uDisabledBits |= 1 << (2 * Asura_MaterialResponse::ENVIRONMENT_MAP);
			uDisabledBits |= 1 << (2 * Asura_MaterialResponse::ENVIRONMENT_MAP + 1);

			uModifiedHash &= ~uDisabledBits;
		}

		// Set "Disable lighting" and "Show normals" Tools options

		// Hack to work around HLSL compiler issue. We need to upload these to both bool and float
		// constants, because it won't let us force them into bools if it wants to optimise them
		// into floats, and we can't force floats because then we can't sample textures inside
		// the resulting dynamic branch...

		Asura_FixedArray< BOOL, 2 > abToolsBools;
		abToolsBools[0] = !Tools_Render::LightingIsOn();
		abToolsBools[1] = Tools_Render::ShowPerPixelNormalsIsOn();

		Asura_FixedArray< D3DXVECTOR4, 2 > axToolsFloats;
		axToolsFloats[0].x = (Tools_Render::LightingIsOn() ? 0.0f : 1.0f);
		axToolsFloats[0].y = axToolsFloats[0].z = axToolsFloats[0].w = 0.0f;
		axToolsFloats[1].x = (Tools_Render::ShowPerPixelNormalsIsOn() ? 1.0f : 0.0f);
		axToolsFloats[1].y = axToolsFloats[1].z = axToolsFloats[1].w = 0.0f;

		pxDevice->SetPixelShaderConstantB( 0, &abToolsBools[0], abToolsBools.GetSize() );
		pxDevice->SetPixelShaderConstantF( 222, axToolsFloats[0], axToolsFloats.GetSize() );

	#endif // defined ASURA_TOOLS

	// Set the strip's pixel shader
	Asura_Direct3D_MRPShader* const pxShader = GetPixelShader( uModifiedHash );
	pxDevice->SetPixelShader( pxShader ? pxShader->GetShader() : NULL );

	// Set constants based on the materials

	Asura_FixedArray< const Asura_MaterialResponse*, 2 > apxMaterials;

	apxMaterials[0] = pxMaterial1;
	apxMaterials[1] = pxMaterial2;

	Asura_FixedArray< D3DXVECTOR4, 6 > axConstants;

	// Material properties
	if( apxMaterials[0] )
	{
		axConstants[0].x = (apxMaterials[0]->GetMaterialIndex() + 0.5f) / ASURA_PC_MATERIALS_TEXTURE_HEIGHT;
		axConstants[0].y = apxMaterials[0]->GetReflectivity();
		axConstants[0].z = apxMaterials[0]->GetParallaxScale();
		axConstants[0].w = -axConstants[0].z * 0.5f;
	}
	else
	{
		axConstants[0].x = 0.5f / ASURA_PC_MATERIALS_TEXTURE_HEIGHT;
		axConstants[0].y = axConstants[0].z = axConstants[0].w = 0.0f;
	}

	// Material response texture properties
	axConstants[1].x = 1.0f / ASURA_MATERIAL_RESPONSE_TEXTURE_WIDTH;
	axConstants[1].y = GetMaterialsTextureScale();
	axConstants[1].z = axConstants[1].w = 0.0f;

	// Detail map 1 parameters
	if( apxMaterials[0] )
	{
		axConstants[2].x = apxMaterials[0]->GetAlbedoDetailMapUVScale();
		axConstants[2].y = apxMaterials[0]->GetAlbedoDetailMapValueScale();
		axConstants[2].z = apxMaterials[0]->GetNormalDetailMapUVScale();
		axConstants[2].w = apxMaterials[0]->GetNormalDetailMapValueScale();
	}
	else
	{
		axConstants[2].x = axConstants[2].y = axConstants[2].z = axConstants[2].w = 0.0f;
	}

	// Detail map 2 parameters
	if( apxMaterials[1] )
	{
		axConstants[3].x = apxMaterials[1]->GetAlbedoDetailMapUVScale();
		axConstants[3].y = apxMaterials[1]->GetAlbedoDetailMapValueScale();
		axConstants[3].z = apxMaterials[1]->GetNormalDetailMapUVScale();
		axConstants[3].w = apxMaterials[1]->GetNormalDetailMapValueScale();
	}
	else
	{
		axConstants[3].x = axConstants[3].y = axConstants[3].z = axConstants[3].w = 0.0f;
	}

	// Self-illumination values
	{
		float fAmount = 0.0f;
		float fColourise = 0.0f;
		Asura_RGBA xColour(0);

		if( apxMaterials[0] )
		{
			apxMaterials[0]->GetSelfIllumination( pxTextureAnimController, fAmount, fColourise,
				xColour );
		}

		axConstants[4].x = fAmount * xColour.m_fR * fColourise;
		axConstants[4].y = fAmount * xColour.m_fG * fColourise;
		axConstants[4].z = fAmount * xColour.m_fB * fColourise;
		axConstants[4].w = fAmount * (1.0f - fColourise);
	}

	// Albedo modifier
	{
		Asura_RGBA xAlbedoModifier( 1.0f, 1.0f, 1.0f, 1.0f );

		Asura_MaterialResponse_System::AlbedoModifierCallback pfnCallback =
			Asura_MaterialResponse_System::GetAlbedoModifierCallback();

		if( pfnCallback )
		{
			const u_int uContext = (apxMaterials[0] ? apxMaterials[0]->GetProjectContext() :
				ASURA_MATERIAL_RESPONSE_PROJECT_CONTEXT_INVALID);

			pfnCallback( pxAnim, uContext, xAlbedoModifier );
		}

		axConstants[5].x = xAlbedoModifier.m_fR;
		axConstants[5].y = xAlbedoModifier.m_fG;
		axConstants[5].z = xAlbedoModifier.m_fB;
		axConstants[5].w = 0.0f;
	}

	pxDevice->SetPixelShaderConstantF( 0, axConstants[0], 6 );

	// Also need to set texture animation constants for the vertex shader
	{
		// Grab the texture anim UV offsets for both channels
		Asura_TextureAnimationOutput xTexAnim1, xTexAnim2;

		const Asura_Hash_ID uAnim1 =
			(apxMaterials[0] ? apxMaterials[0]->GetTextureAnim() : ASURA_HASH_ID_UNSET);
		const Asura_Hash_ID uAnim2 =
			(apxMaterials[1] ? apxMaterials[1]->GetTextureAnim() : ASURA_HASH_ID_UNSET);

		Asura_TextureAnimation_System::GetAnimationState( uAnim1, pxTextureAnimController,
			&xTexAnim1 );
		Asura_TextureAnimation_System::GetAnimationState( uAnim2, pxTextureAnimController,
			&xTexAnim2 );

		const float afTexCoordOffset[4] = { xTexAnim1.m_fUOffset, xTexAnim1.m_fVOffset,
			xTexAnim2.m_fUOffset, xTexAnim2.m_fVOffset };

		pxDevice->SetVertexShaderConstantF( 1, afTexCoordOffset, 1 );
	}

	// Bind textures
	{
		// Clamp the materials texture, but wrap the artist-selected ones
		pxDevice->SetTexture( 0, GetMaterialsTexture() );
		pxDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP );
		pxDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP );
		pxDevice->SetSamplerState( 0, D3DSAMP_SRGBTEXTURE, false );

		u_int uTextureSlot = 0;
		Direct3D_BaseTexture* pxTexture;

		for( u_int u = 0; u < Asura_MaterialResponse::NUMBER_OF_TEXTURE_SLOTS; ++u )
		{
			for( u_int v = 0; v < 2; ++v )
			{
				const int iRegister = (pxShader ? pxShader->GetSamplerRegister( uTextureSlot ) : 0);
				++uTextureSlot;

				const Asura_MaterialResponse::TEXTURE_SLOT_ID eTexture =
					static_cast< Asura_MaterialResponse::TEXTURE_SLOT_ID >(u);

				const int iTexID = (apxMaterials[v] ? apxMaterials[v]->GetTexture( eTexture ) :
					ASURA_TEXTURE_NONE);

				if( iTexID == ASURA_TEXTURE_NONE || iRegister < 0 ) continue;

				pxTexture = Asura_Direct3D::GetDirect3DTextureByIndex( iTexID );
				pxDevice->SetTexture( iRegister, pxTexture );

				pxDevice->SetSamplerState( iRegister, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP );
				pxDevice->SetSamplerState( iRegister, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP );

				// Colour textures are stored in sRGB space, so we need to convert them on sample
				bool bSRGB = eTexture == Asura_MaterialResponse::ALBEDO_TEXTURE
						  || eTexture == Asura_MaterialResponse::ENVIRONMENT_MAP;

				bSRGB = bSRGB && Asura_Direct3D::UseGammaCorrection();

				pxDevice->SetSamplerState( iRegister, D3DSAMP_SRGBTEXTURE, bSRGB );
			}
		}
	}
}

Asura_Direct3D_MaterialResponse_ShaderData::Asura_Direct3D_MaterialResponse_ShaderData()
{
	this->Clear();
}

Asura_Direct3D_MaterialResponse_ShaderData_Env::Asura_Direct3D_MaterialResponse_ShaderData_Env()
{
	this->Clear();
}

Asura_Direct3D_MaterialResponse_ShaderData_Parallax::Asura_Direct3D_MaterialResponse_ShaderData_Parallax()
{
	this->Clear();
}

void Asura_Direct3D_MaterialResponse_ShaderData::Clear_AllUseMaps()
{
	this->m_bUseAlbedo = false;
	this->m_bUseNormalMap = false;
	this->m_bUseSpecularMap = false;
	this->m_bUseTransparencyMap = false;
	this->m_bUseSelfIlluminationMap = false;
	this->m_bUseEnvironmentMap = false;
	this->m_bUseReflectivityMask = false;
}

void Asura_Direct3D_MaterialResponse_ShaderData::Clear_AllDual()
{
	this->m_bDualAlbedo = false;
	this->m_bDualNormalMap = false;
	this->m_bDualSpecularMap = false;
	this->m_bDualTransparencyMap = false;
	this->m_bDualSelfIlluminationMap = false;
}

void Asura_Direct3D_MaterialResponse_ShaderData::Clear()
{
	this->m_pxAlbedoMap = NULL;
	this->m_pxNormalMap = NULL;
	this->m_pxSpecularMap = NULL;
	this->m_pxTransparencyMap = NULL;
	this->m_pxSelfIlluminationMap = NULL;
	this->m_pxEnvironmentMap = NULL;
	this->m_pxReflectivityMask = NULL;

	this->m_pxAlbedoMap2 = NULL;
	this->m_pxNormalMap2 = NULL;
	this->m_pxSpecularMap2 = NULL;
	this->m_pxTransparencyMap2 = NULL;
	this->m_pxSelfIlluminationMap2 = NULL;

	this->m_pxMaterialsTexture = NULL;

	this->m_afMaterialProperties[0] = 0.0f;
	this->m_afMaterialProperties[1] = 0.0f;
	this->m_afMaterialProperties[2] = 0.0f;
	this->m_afMaterialProperties[3] = 0.0f;

	this->m_afMaterialsTextureProperties[0] = 1.0f;
	this->m_afMaterialsTextureProperties[1] = 1.0f;

	this->Clear_AllUseMaps();
	this->Clear_AllDual();
	
	this->m_afUV_Offsets[0] = 0;
	this->m_afUV_Offsets[1] = 0;
	this->m_afUV_Offsets[2] = 0;
	this->m_afUV_Offsets[3] = 0;

	this->m_xSelfIlluminationParameters = D3DXVECTOR4( 0, 0, 0, 0);

	this->m_afAlbedoModifier[0] = this->m_afAlbedoModifier[1] = this->m_afAlbedoModifier[2] = 1.0f;

	this->m_bBlendIntoAlbedo = false;
}

void Asura_Direct3D_MaterialResponse_ShaderData_Env::Clear()
{
	this->m_xPrelightingColourVector = D3DXVECTOR4( 1.0f, 1.0f, 1.0f, 0.0f);
}

void Asura_Direct3D_MaterialResponse_ShaderData_Parallax::Clear()
{
	this->m_pxParallaxMap = NULL;
	this->m_pxParallaxMap2 = NULL;
	this->m_bUseParallaxMap = false;
	this->m_bDualParallaxMap = false;
}

bool Asura_Direct3D_MaterialResponse_ShaderData::AddDataToParameterBlock( Asura_Direct3D_EffectParameterBlock* pxParameterBlock)
{
	pxParameterBlock->AddDynamicParameter<Direct3D_BaseTexture*> ( "g_xAlbedo", &this->m_pxAlbedoMap);
	pxParameterBlock->AddDynamicParameter<Direct3D_BaseTexture*> ( "g_xNormalMap", &this->m_pxNormalMap);
	pxParameterBlock->AddDynamicParameter<Direct3D_BaseTexture*> ( "g_xSpecularMap", &this->m_pxSpecularMap);
	pxParameterBlock->AddDynamicParameter<Direct3D_BaseTexture*> ( "g_xTransparencyMap", &this->m_pxTransparencyMap);
	pxParameterBlock->AddDynamicParameter<Direct3D_BaseTexture*> ( "g_xSelfIlluminationMap", &this->m_pxSelfIlluminationMap);
	pxParameterBlock->AddDynamicParameter<Direct3D_BaseTexture*> ( "g_xEnvironmentMap", &this->m_pxEnvironmentMap);
	pxParameterBlock->AddDynamicParameter<Direct3D_BaseTexture*> ( "g_xReflectivityMask", &this->m_pxReflectivityMask);
	pxParameterBlock->AddDynamicParameter<Direct3D_BaseTexture*> ( "g_xAlbedo2", &this->m_pxAlbedoMap2);
	pxParameterBlock->AddDynamicParameter<Direct3D_BaseTexture*> ( "g_xNormalMap2", &this->m_pxNormalMap2);
	pxParameterBlock->AddDynamicParameter<Direct3D_BaseTexture*> ( "g_xSpecularMap2", &this->m_pxSpecularMap2);
	pxParameterBlock->AddDynamicParameter<Direct3D_BaseTexture*> ( "g_xTransparencyMap2", &this->m_pxTransparencyMap2);
	pxParameterBlock->AddDynamicParameter<Direct3D_BaseTexture*> ( "g_xSelfIlluminationMap2", &this->m_pxSelfIlluminationMap2);
	pxParameterBlock->AddDynamicParameter<Direct3D_BaseTexture*> ( "g_xMaterialsTexture", &this->m_pxMaterialsTexture);
	pxParameterBlock->AddDynamicParameter<float> ( "g_xMaterialProperties", this->m_afMaterialProperties, 4);
	pxParameterBlock->AddDynamicParameter<float> ( "g_xMaterialsTextureProperties", this->m_afMaterialsTextureProperties, 2);
	pxParameterBlock->AddDynamicParameter<bool> ( "g_bUseAlbedo", &this->m_bUseAlbedo);
	pxParameterBlock->AddDynamicParameter<bool> ( "g_bUseNormalMap", &this->m_bUseNormalMap);
	pxParameterBlock->AddDynamicParameter<bool> ( "g_bUseSpecularMap", &this->m_bUseSpecularMap);
	pxParameterBlock->AddDynamicParameter<bool> ( "g_bUseTransparencyMap", &this->m_bUseTransparencyMap);
	pxParameterBlock->AddDynamicParameter<bool> ( "g_bUseSelfIlluminationMap", &this->m_bUseSelfIlluminationMap);
	pxParameterBlock->AddDynamicParameter<bool> ( "g_bUseEnvironmentMap", &this->m_bUseEnvironmentMap);
	pxParameterBlock->AddDynamicParameter<bool> ( "g_bUseReflectivityMask", &this->m_bUseReflectivityMask);
	pxParameterBlock->AddDynamicParameter<bool> ( "g_bDualAlbedo", &this->m_bDualAlbedo);
	pxParameterBlock->AddDynamicParameter<bool> ( "g_bDualNormalMap", &this->m_bDualNormalMap);
	pxParameterBlock->AddDynamicParameter<bool> ( "g_bDualSpecularMap", &this->m_bDualSpecularMap);
	pxParameterBlock->AddDynamicParameter<bool> ( "g_bDualTransparencyMap", &this->m_bDualTransparencyMap);
	pxParameterBlock->AddDynamicParameter<bool> ( "g_bDualSelfIlluminationMap", &this->m_bDualSelfIlluminationMap);
	pxParameterBlock->AddDynamicParameter<float> ( "g_xUV_Offsets", this->m_afUV_Offsets, 4);
	pxParameterBlock->AddDynamicParameter<float> ( "g_xAlbedoModifier", this->m_afAlbedoModifier, 3);

	pxParameterBlock->AddDynamicParameter<D3DXVECTOR4> ( "g_xSelfIlluminationParameters", &this->m_xSelfIlluminationParameters);

	pxParameterBlock->AddDynamicParameter<bool> ( "g_bBlendIntoAlbedo", &this->m_bBlendIntoAlbedo);

	return( true);
}

bool Asura_Direct3D_MaterialResponse_ShaderData_Env::AddDataToParameterBlock( Asura_Direct3D_EffectParameterBlock* pxParameterBlock)
{
	pxParameterBlock->AddDynamicParameter<D3DXVECTOR4> ( "g_xPrelightingColourFilter", &this->m_xPrelightingColourVector);
	return( false);	
}

bool Asura_Direct3D_MaterialResponse_ShaderData_Parallax::AddDataToParameterBlock( Asura_Direct3D_EffectParameterBlock* pxParameterBlock)
{
	pxParameterBlock->AddDynamicParameter<Direct3D_BaseTexture*> ( "g_xParallaxMap", &this->m_pxParallaxMap);
	pxParameterBlock->AddDynamicParameter<Direct3D_BaseTexture*> ( "g_xParallaxMap2", &this->m_pxParallaxMap2);
	pxParameterBlock->AddDynamicParameter<bool> ( "g_bUseParallaxMap", &this->m_bUseParallaxMap);
	pxParameterBlock->AddDynamicParameter<bool> ( "g_bDualParallaxMap", &this->m_bDualParallaxMap);
	
	return( true);
}

bool Asura_Direct3D_MaterialResponse_ShaderData::SetupCommon()
{
	this->m_pxMaterialsTexture = Asura_Direct3D_MaterialResponse::GetMaterialsTexture();
	this->m_afMaterialsTextureProperties[0] = 1.0f / ASURA_MATERIAL_RESPONSE_TEXTURE_WIDTH;
	this->m_afMaterialsTextureProperties[1] = Asura_Direct3D_MaterialResponse::GetMaterialsTextureScale();

	return( true);
}

bool Asura_Direct3D_MaterialResponse_ShaderData::Setup_SelfIlluminating( const Asura_MaterialResponse* pxMaterialResponse, const Asura_TextureAnimationController* pxTextureAnimationController)
{
	float fSelfIlluminationAmount;
	float fSelfIlluminationColourise;
	Asura_RGBA xSelfIlluminationColour;
	pxMaterialResponse->GetSelfIllumination(pxTextureAnimationController, fSelfIlluminationAmount, fSelfIlluminationColourise, xSelfIlluminationColour);


	this->m_xSelfIlluminationParameters = D3DXVECTOR4( xSelfIlluminationColour.m_fR, xSelfIlluminationColour.m_fG, xSelfIlluminationColour.m_fB, 0.0f );
	this->m_xSelfIlluminationParameters *= fSelfIlluminationAmount * fSelfIlluminationColourise;
	this->m_xSelfIlluminationParameters.w = fSelfIlluminationAmount * (1.0f - fSelfIlluminationColourise);
	
	return( true);
}

#if 0
bool Asura_Direct3D_MaterialResponse_ShaderData::Setup_Parallax( const Asura_MaterialResponse* pxMaterialResponse)
{
	D3DXVECTOR2 xParallaxParameters = this->m_xParallaxParameters;

	// Set bias to half the scale for now, centres the effect on the polygon position
	xParallaxParameters.x = pxMaterialResponse->GetParallaxScale();
	xParallaxParameters.y = -xParallaxParameters.x * 0.5f;

	return( true);
}
#endif

bool Asura_Direct3D_MaterialResponse_ShaderData::Setup_TextureAnimation( const Asura_MaterialResponse* pxMaterialResponse1, const Asura_MaterialResponse* pxMaterialResponse2)
{
	Asura_TextureAnimationOutput xTexAnim1, xTexAnim2;

	Asura_TextureAnimation_System::GetAnimationState( pxMaterialResponse1 ? pxMaterialResponse1->GetTextureAnim() : 0, NULL, &xTexAnim1 );
	Asura_TextureAnimation_System::GetAnimationState( pxMaterialResponse2 ? pxMaterialResponse2->GetTextureAnim() : 0, NULL, &xTexAnim2 );

	this->m_afUV_Offsets[ 0] = xTexAnim1.m_fUOffset;
	this->m_afUV_Offsets[ 1] = xTexAnim1.m_fVOffset;
	this->m_afUV_Offsets[ 2] = xTexAnim2.m_fUOffset;
	this->m_afUV_Offsets[ 3] = xTexAnim2.m_fVOffset;
	
	return( false);
}

#define SETUP_TEXTURE_DUAL( SRC_TEXTURE1, SRC_TEXTURE2, DST_TEXTURE1, DST_TEXTURE2, DST_USE, DST_DUAL) \
{	\
	const int iTexture1 = SRC_TEXTURE1;	\
	const int iTexture2 = SRC_TEXTURE2;	\
	\
	DST_USE = (ASURA_TEXTURE_NONE != iTexture1);	\
	DST_DUAL = (ASURA_TEXTURE_NONE != iTexture2);	\
	\
	Direct3D_BaseTexture* pxTexture1 = Asura_Direct3D::GetDirect3DTextureByIndex( iTexture1); \
	DST_TEXTURE1 = pxTexture1;	\
	\
	Direct3D_BaseTexture* pxTexture2 = Asura_Direct3D::GetDirect3DTextureByIndex( iTexture2); \
	DST_TEXTURE2 = pxTexture2;	\
}

#define SETUP_TEXTURE_SINGLE( SRC_TEXTURE1, DST_TEXTURE1, DST_USE) \
{	\
	const int iTexture1 = SRC_TEXTURE1;	\
	\
	DST_USE = (ASURA_TEXTURE_NONE != iTexture1);	\
	\
	Direct3D_BaseTexture* pxTexture1 = Asura_Direct3D::GetDirect3DTextureByIndex( iTexture1); \
	DST_TEXTURE1 = pxTexture1;	\
}

bool Asura_Direct3D_MaterialResponse_ShaderData::Setup( const Asura_MaterialResponse* pxMaterialResponse1, const Asura_MaterialResponse* pxMaterialResponse2, const Asura_TextureAnimationController* pxTextureAnimationController)
{
	Asura_Assert(pxMaterialResponse1, "Expecting first material response to be valid");

	const int iAlbedoTexture2 = pxMaterialResponse2 ? pxMaterialResponse2->GetTexture( Asura_MaterialResponse::ALBEDO_TEXTURE ) : ASURA_TEXTURE_NONE;
	const int iNormalMap2 = pxMaterialResponse2 ? pxMaterialResponse2->GetTexture( Asura_MaterialResponse::NORMAL_MAP ) : ASURA_TEXTURE_NONE;
	const int iSpecularMap2 = pxMaterialResponse2 ? pxMaterialResponse2->GetTexture( Asura_MaterialResponse::SPECULAR_MAP ) : ASURA_TEXTURE_NONE;
	const int iTransparencyMap2 = pxMaterialResponse2 ? pxMaterialResponse2->GetTexture( Asura_MaterialResponse::TRANSPARENCY_MAP ) : ASURA_TEXTURE_NONE;
	const int iSelfIlluminationMap2 = pxMaterialResponse2 ? pxMaterialResponse2->GetTexture( Asura_MaterialResponse::SELFILLUMINATION_MAP ) : ASURA_TEXTURE_NONE;

	SETUP_TEXTURE_DUAL( pxMaterialResponse1->GetTexture( Asura_MaterialResponse::ALBEDO_TEXTURE ),			iAlbedoTexture2,		this->m_pxAlbedoMap, this->m_pxAlbedoMap2, this->m_bUseAlbedo, this->m_bDualAlbedo);
	SETUP_TEXTURE_DUAL( pxMaterialResponse1->GetTexture( Asura_MaterialResponse::NORMAL_MAP ),				iNormalMap2,			this->m_pxNormalMap, this->m_pxNormalMap2, this->m_bUseNormalMap, this->m_bDualNormalMap);
	SETUP_TEXTURE_DUAL( pxMaterialResponse1->GetTexture( Asura_MaterialResponse::SPECULAR_MAP ),			iSpecularMap2,			this->m_pxSpecularMap, this->m_pxSpecularMap2, this->m_bUseSpecularMap, this->m_bDualSpecularMap);
	SETUP_TEXTURE_DUAL( pxMaterialResponse1->GetTexture( Asura_MaterialResponse::TRANSPARENCY_MAP ),		iTransparencyMap2,		this->m_pxTransparencyMap, this->m_pxTransparencyMap2, this->m_bUseTransparencyMap, this->m_bDualTransparencyMap);
	SETUP_TEXTURE_DUAL( pxMaterialResponse1->GetTexture( Asura_MaterialResponse::SELFILLUMINATION_MAP ),	iSelfIlluminationMap2,	this->m_pxSelfIlluminationMap, this->m_pxSelfIlluminationMap2, this->m_bUseSelfIlluminationMap, this->m_bDualSelfIlluminationMap);

	SETUP_TEXTURE_SINGLE( pxMaterialResponse1->GetTexture( Asura_MaterialResponse::ENVIRONMENT_MAP ), this->m_pxEnvironmentMap, this->m_bUseEnvironmentMap);
	SETUP_TEXTURE_SINGLE( pxMaterialResponse1->GetTexture( Asura_MaterialResponse::REFLECTIVITY_MASK ), this->m_pxReflectivityMask, this->m_bUseReflectivityMask);

	#if defined ASURA_TOOLS
		const bool bEnableTexturing = Tools_Render::TexturingIsOn();
		this->m_bUseAlbedo &= bEnableTexturing;
		this->m_bDualAlbedo &= bEnableTexturing;
	#endif

	this->m_afMaterialProperties[0] = (static_cast< float>( pxMaterialResponse1->GetMaterialIndex()) + 0.5f) / ASURA_PC_MATERIALS_TEXTURE_HEIGHT;
	this->m_afMaterialProperties[1] = pxMaterialResponse1->GetReflectivity();

	// Set parallax mapping parameters
	{
		// Set bias to half the scale for now, centres the effect on the polygon position
		this->m_afMaterialProperties[2] = pxMaterialResponse1->GetParallaxScale();
		this->m_afMaterialProperties[3] = -this->m_afMaterialProperties[2] * 0.5f;
	}

	this->Setup_TextureAnimation( pxMaterialResponse1, pxMaterialResponse2);
	this->Setup_SelfIlluminating( pxMaterialResponse1, pxTextureAnimationController);

	// Set albedo modifier
	{
		Asura_RGBA xColour( 1.0f, 1.0f, 1.0f, 1.0f);

		if( Asura_MaterialResponse_System::GetAlbedoModifierCallback() )
		{
			const u_int uContext = pxMaterialResponse1->GetProjectContext();
			Asura_MaterialResponse_System::GetAlbedoModifierCallback()( NULL, uContext, xColour);
		}

		this->m_afAlbedoModifier[0] = xColour.m_fR;
		this->m_afAlbedoModifier[1] = xColour.m_fG;
		this->m_afAlbedoModifier[2] = xColour.m_fB;
	}

	this->m_bBlendIntoAlbedo
		= (pxMaterialResponse1->GetBlendMode() != Asura_MaterialResponse::BLEND_MODE_OPAQUE)
		&& pxMaterialResponse1->GetIsDecal();

	return( true);
}

bool Asura_Direct3D_MaterialResponse_ShaderData::Setup_SingleMapsOnly( const Asura_MaterialResponse* pxMaterialResponse, const Asura_TextureAnimationController* pxTextureAnimationController)
{
	SETUP_TEXTURE_DUAL( pxMaterialResponse->GetTexture( Asura_MaterialResponse::ALBEDO_TEXTURE ),       ASURA_TEXTURE_NONE, this->m_pxAlbedoMap, this->m_pxAlbedoMap2, this->m_bUseAlbedo, this->m_bDualAlbedo);
	SETUP_TEXTURE_DUAL( pxMaterialResponse->GetTexture( Asura_MaterialResponse::NORMAL_MAP ),           ASURA_TEXTURE_NONE, this->m_pxNormalMap, this->m_pxNormalMap2, this->m_bUseNormalMap, this->m_bDualNormalMap);
	SETUP_TEXTURE_DUAL( pxMaterialResponse->GetTexture( Asura_MaterialResponse::SPECULAR_MAP ),         ASURA_TEXTURE_NONE, this->m_pxSpecularMap, this->m_pxSpecularMap2, this->m_bUseSpecularMap, this->m_bDualSpecularMap);
	SETUP_TEXTURE_DUAL( pxMaterialResponse->GetTexture( Asura_MaterialResponse::TRANSPARENCY_MAP ),     ASURA_TEXTURE_NONE, this->m_pxTransparencyMap, this->m_pxTransparencyMap2, this->m_bUseTransparencyMap, this->m_bDualTransparencyMap);
	SETUP_TEXTURE_DUAL( pxMaterialResponse->GetTexture( Asura_MaterialResponse::SELFILLUMINATION_MAP ), ASURA_TEXTURE_NONE, this->m_pxSelfIlluminationMap, this->m_pxSelfIlluminationMap2, this->m_bUseSelfIlluminationMap, this->m_bDualSelfIlluminationMap);

	SETUP_TEXTURE_SINGLE( pxMaterialResponse->GetTexture( Asura_MaterialResponse::ENVIRONMENT_MAP ), this->m_pxEnvironmentMap, this->m_bUseEnvironmentMap);
	SETUP_TEXTURE_SINGLE( pxMaterialResponse->GetTexture( Asura_MaterialResponse::REFLECTIVITY_MASK ), this->m_pxReflectivityMask, this->m_bUseReflectivityMask);

	#if defined ASURA_TOOLS
		const bool bEnableTexturing = Tools_Render::TexturingIsOn();
		this->m_bUseAlbedo &= bEnableTexturing;
		this->m_bDualAlbedo &= bEnableTexturing;
	#endif

	this->m_afMaterialProperties[0] = (static_cast< float>( pxMaterialResponse->GetMaterialIndex()) + 0.5f) / ASURA_PC_MATERIALS_TEXTURE_HEIGHT;
	this->m_afMaterialProperties[1] = pxMaterialResponse->GetReflectivity();

	// Set parallax mapping parameters
	{
		// Set bias to half the scale for now, centres the effect on the polygon position
		this->m_afMaterialProperties[2] = pxMaterialResponse->GetParallaxScale();
		this->m_afMaterialProperties[3] = -this->m_afMaterialProperties[2] * 0.5f;
	}

	this->Setup_TextureAnimation( pxMaterialResponse, 0);
	this->Setup_SelfIlluminating( pxMaterialResponse, pxTextureAnimationController);

	// Set albedo modifier
	{
		Asura_RGBA xColour( 1.0f, 1.0f, 1.0f, 1.0f);

		if( Asura_MaterialResponse_System::GetAlbedoModifierCallback() )
		{
			const u_int uContext = pxMaterialResponse->GetProjectContext();
			Asura_MaterialResponse_System::GetAlbedoModifierCallback()( NULL, uContext, xColour);
		}

		this->m_afAlbedoModifier[0] = xColour.m_fR;
		this->m_afAlbedoModifier[1] = xColour.m_fG;
		this->m_afAlbedoModifier[2] = xColour.m_fB;
	}

	this->m_bBlendIntoAlbedo
		= (pxMaterialResponse->GetBlendMode() != Asura_MaterialResponse::BLEND_MODE_OPAQUE)
		&& pxMaterialResponse->GetIsDecal();

	return( true);
}

bool Asura_Direct3D_MaterialResponse_ShaderData_Env::Setup( const Asura_MaterialResponse* pxMaterialResponse1, const Asura_MaterialResponse* pxMaterialResponse2)
{
	Asura_RGBA xPrelightingColour = pxMaterialResponse1->GetAmbientColour();
	xPrelightingColour *= pxMaterialResponse1->GetAmbientContribution();

	this->m_xPrelightingColourVector = D3DXVECTOR4( xPrelightingColour.m_fR, xPrelightingColour.m_fG, xPrelightingColour.m_fB, 0.0f );
	
	return( true);
}

bool Asura_Direct3D_MaterialResponse_ShaderData_Parallax::Setup( const Asura_MaterialResponse* pxMaterialResponse1, const Asura_MaterialResponse* pxMaterialResponse2)
{
	Asura_Assert(pxMaterialResponse1, "Expecting first material response to be valid");

	const int iParallaxMap2 = pxMaterialResponse2 ? pxMaterialResponse2->GetTexture( Asura_MaterialResponse::PARALLAX_MAP ) : ASURA_TEXTURE_NONE;

	SETUP_TEXTURE_DUAL( pxMaterialResponse1->GetTexture( Asura_MaterialResponse::PARALLAX_MAP ), iParallaxMap2, this->m_pxParallaxMap, this->m_pxParallaxMap2, this->m_bUseParallaxMap, this->m_bDualParallaxMap);

	return( true);
}

bool Asura_Direct3D_MaterialResponse_ShaderData::SetParameterByName( Asura_Direct3D_Effect* pxD3DEffect) const 
{
	pxD3DEffect->SetParameterTextureByName( "g_xAlbedo", this->m_pxAlbedoMap);
	pxD3DEffect->SetParameterTextureByName( "g_xNormalMap", this->m_pxNormalMap);
	pxD3DEffect->SetParameterTextureByName( "g_xSpecularMap", this->m_pxSpecularMap);
	pxD3DEffect->SetParameterTextureByName( "g_xTransparencyMap", this->m_pxTransparencyMap);
	pxD3DEffect->SetParameterTextureByName( "g_xSelfIlluminationMap", this->m_pxSelfIlluminationMap);
	pxD3DEffect->SetParameterTextureByName( "g_xEnvironmentMap", this->m_pxEnvironmentMap);
	pxD3DEffect->SetParameterTextureByName( "g_xReflectivityMask", this->m_pxReflectivityMask);
	pxD3DEffect->SetParameterTextureByName( "g_xAlbedo2", this->m_pxAlbedoMap2);
	pxD3DEffect->SetParameterTextureByName( "g_xNormalMap2", this->m_pxNormalMap2);
	pxD3DEffect->SetParameterTextureByName( "g_xSpecularMap2", this->m_pxSpecularMap2);
	pxD3DEffect->SetParameterTextureByName( "g_xTransparencyMap2", this->m_pxTransparencyMap2);
	pxD3DEffect->SetParameterTextureByName( "g_xSelfIlluminationMap2", this->m_pxSelfIlluminationMap2);
	pxD3DEffect->SetParameterTextureByName( "g_xMaterialsTexture", this->m_pxMaterialsTexture);
	
	pxD3DEffect->SetParameterByName( "g_xMaterialProperties", this->m_afMaterialProperties, sizeof( this->m_afMaterialProperties));
	pxD3DEffect->SetParameterByName( "g_xMaterialsTextureProperties", this->m_afMaterialsTextureProperties, sizeof( this->m_afMaterialsTextureProperties));

	pxD3DEffect->SetParameterByName( "g_bUseAlbedo", this->m_bUseAlbedo);
	pxD3DEffect->SetParameterByName( "g_bUseNormalMap", this->m_bUseNormalMap);
	pxD3DEffect->SetParameterByName( "g_bUseSpecularMap", this->m_bUseSpecularMap);
	pxD3DEffect->SetParameterByName( "g_bUseTransparencyMap", this->m_bUseTransparencyMap);
	pxD3DEffect->SetParameterByName( "g_bUseSelfIlluminationMap", this->m_bUseSelfIlluminationMap);
	pxD3DEffect->SetParameterByName( "g_bUseEnvironmentMap", this->m_bUseEnvironmentMap);
	pxD3DEffect->SetParameterByName( "g_bUseReflectivityMask", this->m_bUseReflectivityMask);
	pxD3DEffect->SetParameterByName( "g_bDualAlbedo", this->m_bDualAlbedo);
	pxD3DEffect->SetParameterByName( "g_bDualNormalMap", this->m_bDualNormalMap);
	pxD3DEffect->SetParameterByName( "g_bDualSpecularMap", this->m_bDualSpecularMap);
	pxD3DEffect->SetParameterByName( "g_bDualTransparencyMap", this->m_bDualTransparencyMap);
	pxD3DEffect->SetParameterByName( "g_bDualSelfIlluminationMap", this->m_bDualSelfIlluminationMap);
	pxD3DEffect->SetParameterByName( "g_xUV_Offsets", D3DXVECTOR4( this->m_afUV_Offsets));
	
	pxD3DEffect->SetParameterByName( "g_xSelfIlluminationParameters", this->m_xSelfIlluminationParameters );

	return( true);
}

bool Asura_Direct3D_MaterialResponse_ShaderData_Env::SetParameterByName( Asura_Direct3D_Effect* pxD3DEffect) const 
{
	pxD3DEffect->SetParameterByName( "g_xPrelightingColourFilter", this->m_xPrelightingColourVector );

	return( true);
}

bool Asura_Direct3D_MaterialResponse_ShaderData_Parallax::SetParameterByName( Asura_Direct3D_Effect* pxD3DEffect) const 
{
	pxD3DEffect->SetParameterTextureByName( "g_xParallaxMap", this->m_pxParallaxMap);
	pxD3DEffect->SetParameterTextureByName( "g_xParallaxMap2", this->m_pxParallaxMap2);

	pxD3DEffect->SetParameterByName( "g_bUseParallaxMap", this->m_bUseParallaxMap);
	pxD3DEffect->SetParameterByName( "g_bDualParallaxMap", this->m_bDualParallaxMap);

	return( true);
}

//*******************************************************************
//
// (c) 2006 Rebellion
//
// Warning: This computer program is protected by copyright law and 
// international treaties. Unauthorized reproduction or distribution
// of this program, or any portion of it, may result in severe civil and
// criminal penalties, and will be prosecuted to the maximum extent 
// possible under the law.
//
//*******************************************************************

#endif //defined( ASURA_USE_MATERIAL_RESPONSE_SYSTEM)
