//*******************************************************************
// File: Asura_Chunk_ResourceFile_PC_MaterialResponse.cpp
//
// Created: 12 March 2007 DLH
//
// Description: 
//
//*******************************************************************

// system libraries
#include "Core/Asura.h"

#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

// main header
#include "ChunkSystem/Asura_Chunk_ResourceFile_PC_MaterialResponse.h"

// other libraries
#include "Core/Asura_HalfFloat.h"
#include "Core/Asura_MaterialResponse_System.h"
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "Rendering/Asura_Direct3D.h"
#include "Rendering/Asura_Direct3D_MaterialResponse.h"

// internal dependencies

//*******************************************************************
// Constants
//*******************************************************************


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


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


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

#if 0
static void Convert( Asura_Chunk_Stream& xStream, Asura_HalfFloat& xStore )
{
	float f;
	xStream >> f;
	xStore = (Asura_HalfFloat)f;
}
#endif

template< class TPixelType>
static void Convert( Asura_Chunk_Stream& xStream, TPixelType& xStore, float fScale)
{
	float fValue;
	xStream >> fValue;
	
	float fScaledValue = fScale * fValue;
	TPixelType tScaledValue = static_cast< TPixelType>( fScaledValue);
	
	xStore = tScaledValue;
}

template< class TPixelType>
bool Asura_Chunk_ResourceFile_PC_MaterialResponse::Process_Fill( const char* szFilename, Asura_Chunk_Stream& xStream,  const float fTypeRange, const u_int uOffsetR, const u_int uOffsetG, const u_int uOffsetB, const u_int uOffsetA)
{
	// JAT 16/05/07 this version number is common to PC, 360, PS3 exports
	const u_int uCURRENT_VERSION = Asura_MaterialResponse_System::EXPORTED_TEXTURE_VERSION;
	if ( Version < uCURRENT_VERSION )
	{
		Asura_Assert( false, "Bad version re-export the level to fix this" );
		return false;
	}

	Direct3D_Texture* pxMaterialsTexture = Asura_Direct3D_MaterialResponse::GetMaterialsTexture();
	if( !pxMaterialsTexture )
	{
		Asura_Assert( false, "Trying to update material response texture, but it doesn't exist." );
		return false;
	}
	
	const float fMaterialTextureScale = Asura_Direct3D_MaterialResponse::GetMaterialsTextureScale();
	const float fMaterialTextureTypeScale = fTypeRange / fMaterialTextureScale;

	D3DLOCKED_RECT xLockedRect;
	const HRESULT xResult = pxMaterialsTexture->LockRect( 0, &xLockedRect, NULL, 0 );
	if( FAILED( xResult ) )
	{
		Asura_Assert( false, "Failed to lock material response texture." );
		return false;
	}

	u_int uNumberOfMaterials;
	xStream >> uNumberOfMaterials;

	// Format is ABGR, but we'll write little-endian floats
	TPixelType* pxData = static_cast< TPixelType* >( xLockedRect.pBits );

	// Pitch is specified in bytes for non-DXT formats
	const u_int uNumLines = Asura_MaterialResponse_System::GetNumMaterialsTextureLines();
	pxData += uNumLines * ( xLockedRect.Pitch / sizeof( TPixelType ) );
	Asura_MaterialResponse_System::SetNumMaterialsTextureLines( uNumLines + uNumberOfMaterials );

	Asura_Assert( uNumLines + uNumberOfMaterials <= ASURA_PC_MATERIALS_TEXTURE_HEIGHT,
				  "Too many material responses. Data texture needs to be enlarged." );

	for ( u_int uMaterial=0; uMaterial<uNumberOfMaterials; ++uMaterial )
	{
		// First we'll have the graphs, one in each colour channel
		u_int uElement=0;

		for ( ; uElement< (4*ASURA_MATERIAL_RESPONSE_GRAPH_WIDTH);  )
		{
			// m_xDiffuseGraph.GetValueAtTime( fTime ) / 100.0f;
			Convert(xStream, pxData[ uElement+uOffsetR], fMaterialTextureTypeScale);
			// m_xSpecularGraph.GetValueAtTime( fTime ) / 100.0f;
			Convert(xStream, pxData[ uElement+uOffsetG], fMaterialTextureTypeScale);
			// m_xTransparencyGraph.GetValueAtTime( fTime ) / 100.0f;
			Convert(xStream, pxData[ uElement+uOffsetB], fMaterialTextureTypeScale);
			// 0.0f;
			Convert(xStream, pxData[ uElement+uOffsetA], fMaterialTextureTypeScale);
			uElement += 4;
		}

		// Then the rest of the material's properties

		// m_xAmbientColour.m_fR;
		// m_xAmbientColour.m_fG;
		// m_xAmbientColour.m_fB;
		// m_fColouriseAmbient / 100.0f;
		Convert(xStream, pxData[ uElement+uOffsetR], fMaterialTextureTypeScale);
		Convert(xStream, pxData[ uElement+uOffsetG], fMaterialTextureTypeScale);
		Convert(xStream, pxData[ uElement+uOffsetB], fMaterialTextureTypeScale);
		Convert(xStream, pxData[ uElement+uOffsetA], fMaterialTextureTypeScale);
		uElement += 4;

		// m_xDiffuseColour.m_fR;
		// m_xDiffuseColour.m_fG;
		// m_xDiffuseColour.m_fB;
		// m_fColouriseDiffuse / 100.0f;
		Convert(xStream, pxData[ uElement+uOffsetR], fMaterialTextureTypeScale);
		Convert(xStream, pxData[ uElement+uOffsetG], fMaterialTextureTypeScale);
		Convert(xStream, pxData[ uElement+uOffsetB], fMaterialTextureTypeScale);
		Convert(xStream, pxData[ uElement+uOffsetA], fMaterialTextureTypeScale);
		uElement += 4;

		// m_xSpecularColour.m_fR;
		// m_xSpecularColour.m_fG;
		// m_xSpecularColour.m_fB;
		// m_fColouriseSpecular / 100.0f;
		Convert(xStream, pxData[ uElement+uOffsetR], fMaterialTextureTypeScale);
		Convert(xStream, pxData[ uElement+uOffsetG], fMaterialTextureTypeScale);
		Convert(xStream, pxData[ uElement+uOffsetB], fMaterialTextureTypeScale);
		Convert(xStream, pxData[ uElement+uOffsetA], fMaterialTextureTypeScale);
		uElement += 4;

		// m_fAmbientContribution / 100.0f;
		// m_fMetalicity / 100.0f;
		// 0.0f;
		// 0.0f;
		Convert(xStream, pxData[ uElement+uOffsetR], fMaterialTextureTypeScale);
		Convert(xStream, pxData[ uElement+uOffsetG], fMaterialTextureTypeScale);
		Convert(xStream, pxData[ uElement+uOffsetB], fMaterialTextureTypeScale);
		Convert(xStream, pxData[ uElement+uOffsetA], fMaterialTextureTypeScale);
		uElement += 4;

		// Pitch is specified in bytes for non-DXT formats
		pxData += xLockedRect.Pitch / sizeof( TPixelType );
	}

	pxMaterialsTexture->UnlockRect(0);

	return true;
}

bool Asura_Chunk_ResourceFile_PC_MaterialResponse::Process( const char* szFilename, Asura_Chunk_Stream& xStream )
{
	const D3DFORMAT eMaterialTextureFormat = Asura_Direct3D_MaterialResponse::GetMaterialsTextureFormat();
	
	switch( eMaterialTextureFormat)
	{
		case D3DFMT_A16B16G16R16F:	return this->Process_Fill<Asura_HalfFloat>( szFilename, xStream , 1.0f, 0, 1, 2, 3);
		case D3DFMT_A16B16G16R16:	return this->Process_Fill<uint16>( szFilename, xStream , 0xFFFF, 0, 1, 2, 3);
		case D3DFMT_A8R8G8B8:		return this->Process_Fill<uint8>( szFilename, xStream , 0xFF, 2, 1, 0, 3);
		default: Asura_Assert( false, "Unknown Format for MaterialsTexture"); return false;
	}
}

//*******************************************************************
//
// (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
