/////////////////////////////////////////////////////////////////////////////////////////
//
//	FILE:			Asura_Platform_Shape.cpp
//
//	DESCRIPTION:	The PC version of both the Asura_Shape_CollisionData and
//					Asura_Shape_RenderData concrete classes
//
//	AUTHOR:			Richard M. Smith (8 August 2002)
//
/////////////////////////////////////////////////////////////////////////////////////////


//////////////
// INCLUDES //
//////////////
#include "Core/Asura.h"

#include "Shapes/Asura_Shapes.h"
#include "Shapes/Asura_Platform_Shape.h"

#include "ChunkSystem/Asura_Chunk_Loaders.h"
#include "ChunkSystem/Asura_Chunk_Macros.h"
#include "Core/Asura_Material_System.h"
#include "Core/Asura_MaterialResponse_System.h"
#include "Mesh/Asura_Mesh_System.h"
#include "Mesh/Asura_Mesh.h"

#ifdef ASURA_TOOLS
#include "Shapes/Tools_Shapes.h"
#endif ASURA_TOOLS


////////////////////
// STATIC MEMBERS //
////////////////////
bool	Asura_Platform_Shape_RenderData::s_bLoadingShape = false;


#ifdef ASURA_TOOLS
static bool ChunkLoadFilter_LoadShapeDataOnly(enum ASURA_CHUNKID eChunkID)
{
	return eChunkID == ASURA_CHUNK_SHAPEDATA;
}

#endif //ASURA_TOOLS


/////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION		Asura_Platform_Shape_RenderData::Asura_Platform_Shape_RenderData (Constructor)
// PARAMETERS	Filename and mesh name
// RETURNS		Default (Constructor)
// DESCRIPTION	Initialises a new PC shape render data class
// AUTHOR		Richard M. Smith (8 August 2002)
/////////////////////////////////////////////////////////////////////////////////////////
Asura_Platform_Shape_RenderData::Asura_Platform_Shape_RenderData( const char* szFilename,
																	const char* szMeshName )
:m_pxTheMesh(NULL)
{
#ifdef ASURA_TOOLS
	//mesh already loaded?
	m_pxTheMesh = Asura_Mesh_System::GetMesh( szMeshName );
	
	//Need to load the file regardless of whether the mesh exists to retrieve the shape data.
	//However , if the mesh is already loaded ,set a filter so that we don't
	//process all the mesh chunks and get annoying asserts from them.
	//RAR 03/05/2006	
	if(m_pxTheMesh)
	{
		Asura_ChunkLoading_System::SetChunkLoadFilter(ChunkLoadFilter_LoadShapeDataOnly);
	}
	
	bool	bSuccess;

	s_bLoadingShape = true;
	bSuccess = LoadAsuraFile( (char*)szFilename );
	s_bLoadingShape = false;

	//reset filter
	Asura_ChunkLoading_System::SetChunkLoadFilter(0);

	Asura_Assert( true == bSuccess, "(RMS) Failed with file" );

	if(!m_pxTheMesh) m_pxTheMesh = Asura_Mesh_System::GetMesh( szMeshName );
	

	strcpy( m_xFilename.m_szFilename, szFilename );

#endif

} // End Function 'Asura_Platform_Shape_RenderData::Asura_Platform_Shape_RenderData (Constructor)'





/////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION		Asura_Platform_Shape_RenderData::Asura_Platform_Shape_RenderData (Constructor)
// PARAMETERS	Chunk buffer
// RETURNS		Default (Constructor)
// DESCRIPTION	Creates a new Platform render data object based on the data in the chunk
//				buffer
// AUTHOR		Richard M. Smith (8 August 2002)
/////////////////////////////////////////////////////////////////////////////////////////
Asura_Platform_Shape_RenderData::Asura_Platform_Shape_RenderData( const char*& pcChunkBuffer )
:m_pxTheMesh(NULL)
{
#ifdef ASURA_TOOLS
	ASURA_CHUNK_EXTRACT( pcChunkBuffer, m_xFilename, MY_TEMP_FILENAME );
#else
	pcChunkBuffer += sizeof(MY_TEMP_FILENAME);
#endif

// RICHARDS		bool	bSuccess;
// RICHARDS		
// RICHARDS		bSuccess = LoadAsuraFile( m_xFilename.m_szFilename );
// RICHARDS	
// RICHARDS		Asura_Assert( true == bSuccess, "(RMS) Failed with file" );
// RICHARDS	
// RICHARDS		Asura_String	xMeshName = m_xFilename.m_szFilename;
// RICHARDS	
// RICHARDS		m_pxTheMesh = Asura_Mesh_System::GetMesh( xMeshName );
// RICHARDS	
// RICHARDS		Asura_Assert( NULL != m_pxTheMesh, "(RMS) Failed with mesh" );


} // End Function 'Asura_Platform_Shape_RenderData::Asura_Platform_Shape_RenderData (Constructor)'


Asura_Platform_Shape_RenderData::Asura_Platform_Shape_RenderData( Asura_Mesh* pxMesh )
:m_pxTheMesh(pxMesh)
{
#ifdef ASURA_TOOLS
	//use the mesh name for the 'filename'
	strcpy(m_xFilename.m_szFilename,pxMesh->Name.GetString());
#endif
}


/////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION		Asura_Platform_Shape_RenderData::Render
// PARAMETERS	Position to render the mesh at
//				Orientation to render the mesh in
// RETURNS		None
// DESCRIPTION	
// AUTHOR		Richard M. Smith (8 August 2002)
/////////////////////////////////////////////////////////////////////////////////////////

/// Kevin Lea - 18/12/2002 10:46:30 - tying in the PC object renderer
#include "Rendering/Asura_PlatformRenderObject.h"
#include "Camera/Asura_Camera.h"
#include "Rendering/Asura_Render.h"
void Asura_Platform_Shape_RenderData::Render( const Asura_Vector_3& xPos, const Asura_Matrix_3x3& xOri, const unsigned int uAmbientRGBA, unsigned int uFlags, const unsigned uCamVisFlags)
{
} // End Function 'Asura_Platform_Shape_RenderData::Render'





/////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION		Asura_Platform_Shape_RenderData::GetChunkBufferSize
// PARAMETERS	None
// RETURNS		Size in bytes of the chunk buffer needed to save this mesh
// DESCRIPTION	
// AUTHOR		Richard M. Smith (8 August 2002)
/////////////////////////////////////////////////////////////////////////////////////////
int Asura_Platform_Shape_RenderData::GetChunkBufferSize( void )
{
// (RMS) For a quick "hacky" method I am just going to save out the filename of the mesh
	return sizeof(MY_TEMP_FILENAME);
}




/////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION		Asura_Platform_Shape_RenderData::FillInChunkBuffer
// PARAMETERS	Pointer to the chunk buffer
// RETURNS		None
// DESCRIPTION	
// AUTHOR		Richard M. Smith (8 August 2002)
/////////////////////////////////////////////////////////////////////////////////////////
void Asura_Platform_Shape_RenderData::FillInChunkBuffer( char*& pcChunkBuffer )
{
#ifdef ASURA_TOOLS
	ASURA_CHUNK_FILL( pcChunkBuffer, m_xFilename, MY_TEMP_FILENAME );
#endif 

} // End Function 'Asura_Platform_Shape_RenderData::FillInChunkBuffer'





void Asura_Platform_Shape_RenderData::Load( Asura_Hash_ID uShapeHash )
{
#ifdef ASURA_TOOLS
	// (MH - 28.08.2002) first check to see if mesh is already loaded
	Asura_String	xFileName = m_xFilename.m_szFilename;
	Asura_String	xMeshName;
	xFileName.SplitFilename( NULL, &xMeshName, NULL );
		
	m_pxTheMesh = Asura_Mesh_System::GetMesh( xMeshName );
	bool bHasObjectStrip = Asura_Direct3D_ObjectRenderer::DoesObjectStripExist(uShapeHash); 
	
    if (!m_pxTheMesh && !bHasObjectStrip)
    {
        bool	bSuccess;
    	s_bLoadingShape = true;
	    bSuccess = LoadAsuraFile( m_xFilename.m_szFilename );
    	s_bLoadingShape = false;

	    Asura_Assertf( bSuccess, ("(RMS) Failed with file %s", m_xFilename.m_szFilename) );
        m_pxTheMesh = Asura_Mesh_System::GetMesh( xMeshName );
    }

	if( NULL != m_pxTheMesh )
	{
		if (!m_pxTheMesh->BoundingBoxDataValid)
        {
            m_pxTheMesh->CalculateBoundingBox();
        }
        if (!m_pxTheMesh->AreNormalsValid())
        {
            m_pxTheMesh->CreateNormals();
        }
	}

	Asura_Assertf( (NULL != m_pxTheMesh) || bHasObjectStrip, ("(RMS) Failed with mesh %s", xMeshName.GetString()) );
#endif
}

/////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION		Asura_Shape_Instance::Platform_SetAmbientARGB
// PARAMETERS	components of colour in one 32 bit value (RGBA)
// RETURNS		None
// DESCRIPTION	
// AUTHOR		Neil Massey (13th Sept. 2002)
/////////////////////////////////////////////////////////////////////////////////////////
void Asura_Shape_Instance::Platform_SetAmbientARGB( const unsigned int uARGB )
{
	// PC implementation - just copy
	m_uAmbientARGB = uARGB;
	m_uFlags &= ~ASURA_SHAPE_INSTANCE_USES_DEFAULT_AMBIENT;
}

/////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION		Asura_Shape_Instance::Platform_SetAmbientRGB
// PARAMETERS	components of colour in four 8 bit value (RGBA)
// RETURNS		None
// DESCRIPTION	
// AUTHOR		Neil Massey (13th Sept. 2002)
/////////////////////////////////////////////////////////////////////////////////////////

void Asura_Shape_Instance::Platform_SetAmbientRGB( const unsigned char ucR, const unsigned char ucG, const unsigned char ucB, const unsigned char ucA)
{
	// Just generate as a bit field for PC
	m_uAmbientARGB = (ucA << 24) | (ucR << 16) | (ucG << 8) | ucB;
	m_uFlags &= ~ASURA_SHAPE_INSTANCE_USES_DEFAULT_AMBIENT;
}

/////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION		Asura_Shape_Instance::Platform_SetDefaultAmbientRGB
// PARAMETERS	None
// RETURNS		None
// DESCRIPTION	
// AUTHOR		Richard M. Smith (9 August 2002)
// MODIFIED     Mike Healey (26.9.02) now calling the appropriate function to set up
//                          ambient to correct values for each platform.
// MODIFIED		Andrew Weinkove (01.03.04) Now just set a flag to say it uses default ambient
/////////////////////////////////////////////////////////////////////////////////////////
void Asura_Shape_Instance::Platform_SetDefaultAmbientRGB( void )
{
	m_uFlags |= ASURA_SHAPE_INSTANCE_USES_DEFAULT_AMBIENT;
} 

#ifdef ASURA_TOOLS
void Asura_Platform_Shape_RenderData::GetShapeFilename( char* szString, unsigned int uMaxLen )
{
	strncpy( szString, m_xFilename.m_szFilename, uMaxLen );
}

void Asura_Platform_Shape_RenderData::GetShapeName( char* szString, unsigned int uMaxLen )
{
	Asura_String	xFileName = m_xFilename.m_szFilename;
	Asura_String	xMeshName;
	xFileName.SplitFilename( NULL, &xMeshName, NULL );

	strncpy( szString, xMeshName.GetString(), uMaxLen );
}
#endif ASURA_TOOLS




void Asura_Platform_Shape_RenderData::GetFragmentHashFromMesh(Asura_Hash_ID& xOutputHash) const
{
#ifdef ASURA_TOOLS
	if(m_pxTheMesh) xOutputHash = m_pxTheMesh->m_uFragmentHash;
#endif
}

int Asura_Shape::Platform_GetMaterialIdx( void ) const
{
    return Asura_Direct3D_ObjectRenderer::GetMaterialIdx( *this );
}

bool Asura_Shape::Platform_IsOpaque( void ) const
{
	#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

		const Asura_Hash_ID uMaterialHash = GetMaterialIdx();
		const Asura_MaterialResponse* const pxMaterial = Asura_MaterialResponse_System::GetMaterialByHashID( uMaterialHash );

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

	#else // !defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

		const int iMaterialIndex = GetMaterialIdx();
		return !(Asura_Material_System::IsMaterialTransparent( iMaterialIndex ) || Asura_Material_System::IsMaterialPS2AdditiveAlpha( iMaterialIndex ));

	#endif // !defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM
}

void Asura_Shape::Platform_Render( const Asura_Shape_Instance* pxShapeInst, u_int uAmbientARGB, u_int uCamVisFlags ) const
{
	Asura_Guid guid = ASURA_GUID_UNREGISTERED;
	for( int iCam = Asura_Camera::GetNumberOfCameras(); iCam--; )
	{
		if( (1 << iCam) & uCamVisFlags )
		{
			Asura_Camera::SetCameraIndex( iCam );
			if (Asura_Camera::IsCameraActive() && 
				(Asura_Camera::GetEntityToIgnore() != guid) )
			{
				Asura_Render::ApplyCameraSettings();

				Asura_Direct3D_ObjectRenderer::Render( this, pxShapeInst, uAmbientARGB );
			}
		}
	}
}

void Asura_Shape::Platform_RenderShadow( const Asura_Shape_Instance* pxShapeInst, const Asura_Shadow& xShadow, u_int uCamVisFlags ) const
{
#if defined(ASURA_TARGET_SM3)
	Asura_Direct3D_ObjectRenderer::RenderShadow( *this, *pxShapeInst, xShadow );
#endif
}

////////////////////////////////////// End of file //////////////////////////////////////
