//
// Asura_Chunk_Material.cpp
//
// Created by Richard Rice - 11/02/03
// 
// Copyright (C) 2003 Rebellion, All Rights Reserved.
//

// I N C L U D E S ///////////////////////////////////////////////////////////

#include "Core/Asura.h"

// This file's header.
#include "ChunkSystem/Asura_Chunk_Material.h"

// Engine independent.
#include "ChunkSystem/Asura_Chunk_Macros.h"
#ifdef ASURA_TOOLS
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "ChunkSystem/Asura_SaveBlock.h"
#endif
#include "Core/Asura_Material_System.h"
#include "Core/Asura_TextureManagement.h"
#include "Debugging/Asura_Assert.h"

// C L A S S   I M P L E M E N T A T I O N S /////////////////////////////////

/*----------------------**
** Asura_Chunk_Material **
**----------------------*/

#if ASURA_MATERIAL_MAXTEXTURES != 2
#error Loaders need to be updated if number of textures per material changes
#endif

// (AW - 30.11.2004) - IMPORTANT! New chunk versions MUST be handled in Tools_Level_Export::ModifyChunkBeforeOutput
#define ASURA_CHUNK_MATERIAL_VERSION 6

//Version 5 - Added specular map ID's
// VGP 09Feb2006
//Version 4 - Added texture animation ID
//  RAR 16/05/05
//Version 3 - Added normal map texture IDs
//	KOR 26/11/04
//Version 2 - Added second texture ID
//	RAR 13/05/04

bool Asura_Chunk_Material::Process(Asura_Handle iFileHandle) const
{
	Asura_Assert(Version<=ASURA_CHUNK_MATERIAL_VERSION,"Unknown chunk version");
	Asura_Material_System::NewConversionList(m_iNumberOfMaterials);
	
	Asura_Assertf( static_cast< u_int>( m_iNumberOfMaterials) <= Asura_Material_System::GetFreeMaterialCount(), ("Not enough Material Slots. %d needed. %d free. %d used", this->m_iNumberOfMaterials, Asura_Material_System::GetFreeMaterialCount(), Asura_Material_System::GetActiveMaterialCount()));

	for(int i=0;i<m_iNumberOfMaterials;i++)
	{
		//create a new material
		int iMaterialIndex = Asura_Material_System::CreateMaterial(i);
		if(iMaterialIndex == ASURA_MATERIAL_NONE) return false;

		//and get it
		Asura_Material* pxMaterial = Asura_Material_System::GetMaterial(iMaterialIndex);
		Asura_Assert(pxMaterial,"");

		int iNumTextures = (Version >= 2) ? 2 : 1;
		for(int iTexture = 0; iTexture < iNumTextures; ++iTexture)
		{
			ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxMaterial->m_iTextureID[iTexture],int);
			// KOR - 26/11/2004 - load normal map texture ID
			if(Version >= 3)
			{
				ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxMaterial->m_iNormalMapID[iTexture],int);
			}

			// VGP - 9Feb2006 - load specular map texture ID
			if(Version >= 5)
			{
				ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxMaterial->m_iSpecularMapID[iTexture],int);
			}
		}
		ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxMaterial->m_uMaterialFlags,unsigned int);
		if (Version < 1)
		{
			pxMaterial->m_uProjectFlags = 0;
		}
		else
		{
			ASURA_CHUNK_FILEEXTRACT(iFileHandle, pxMaterial->m_uProjectFlags, unsigned);
		}

		if (Version < 4)
		{
			pxMaterial->m_uAnimHash = ASURA_HASH_ID_UNSET;
		}
		else
		{
			ASURA_CHUNK_FILEEXTRACT(iFileHandle, pxMaterial->m_uAnimHash, Asura_Hash_ID);
		}

		if(Version < 6)
		{
			pxMaterial->m_uSpecularColour = 0xffffffff;
		}
		else
		{
			ASURA_CHUNK_FILEEXTRACT(iFileHandle, pxMaterial->m_uSpecularColour, u_int);
		}


		//convert the texture indices
		for(int j=0;j<ASURA_MATERIAL_MAXTEXTURES;j++)
		{
			if(pxMaterial->m_iTextureID[j] != ASURA_TEXTURE_NONE)
			{
				pxMaterial->m_iTextureID[j] = Asura_Texture_Management::ConvertIndex(pxMaterial->m_iTextureID[j]);
			}
			if(pxMaterial->m_iNormalMapID[j] != ASURA_TEXTURE_NONE)
			{
				pxMaterial->m_iNormalMapID[j] = Asura_Texture_Management::ConvertIndex(pxMaterial->m_iNormalMapID[j]);
			}

			// VGP 9Feb2006
			if(pxMaterial->m_iSpecularMapID[j] != ASURA_TEXTURE_NONE)
			{
				pxMaterial->m_iSpecularMapID[j] = Asura_Texture_Management::ConvertIndex(pxMaterial->m_iSpecularMapID[j]);
			}

		}
		#ifdef ASURA_DISABLE_VERTEX_ALPHA
		//set the second texture to none
		pxMaterial->m_iTextureID[1] = ASURA_TEXTURE_NONE;
		pxMaterial->m_iNormalMapID[1] = ASURA_TEXTURE_NONE;
		pxMaterial->m_iSpecularMapID[1] = ASURA_TEXTURE_NONE;
		#endif


		//flag the textures according to how they are being used. RAR 08/05/2006
		#ifdef ASURA_TOOLS
		for(int j=0;j<ASURA_MATERIAL_MAXTEXTURES;j++)
		{
			if(pxMaterial->m_iTextureID[j] != ASURA_TEXTURE_NONE)
			{
				int iFlags = Asura_Texture_Management::GetTextureFlags(pxMaterial->m_iTextureID[j]);
				iFlags |= AsuraTextureFlag_DiffuseMap;
				Asura_Texture_Management::SetTextureFlags(pxMaterial->m_iTextureID[j],iFlags);
			
			}
			if(pxMaterial->m_iNormalMapID[j] != ASURA_TEXTURE_NONE)
			{
				int iFlags = Asura_Texture_Management::GetTextureFlags(pxMaterial->m_iNormalMapID[j]);
				iFlags |= AsuraTextureFlag_NormalMap;
				Asura_Texture_Management::SetTextureFlags(pxMaterial->m_iNormalMapID[j],iFlags);
			}

			if(pxMaterial->m_iSpecularMapID[j] != ASURA_TEXTURE_NONE)
			{
				int iFlags = Asura_Texture_Management::GetTextureFlags(pxMaterial->m_iSpecularMapID[j]);
				iFlags |= AsuraTextureFlag_SpecularMap;
				Asura_Texture_Management::SetTextureFlags(pxMaterial->m_iSpecularMapID[j],iFlags);
			}
		}
		#endif //ASURA_TOOLS

		Asura_ChunkLoading_System::YieldBackgroundProcessing();
	}
	return true;
}

#ifdef ASURA_TOOLS
void Asura_Chunk_Material::Create(int iNumberOfMaterials,const Asura_Material* pxMaterials,Asura_SaveBlock* pxSaveBlock)
{
    Asura_Chunk_SaveBlock_Stream xStream( pxSaveBlock );
	Create(iNumberOfMaterials, pxMaterials, xStream);
}

void Asura_Chunk_Material::Create(int iNumberOfMaterials,const Asura_Material* pxMaterials,Asura_Chunk_Stream& xStream)
{
    //Create this chunk even if there are no materials , since it makes adding the PS2 untextured material
    //easier during level export. There should be no harm in doing this , since the only time that a level
    //wouldn't have any materials would be at early stages of construction. RAR 15/01/04
    //if(!iNumberOfMaterials) return;

    Asura_Assert( pxMaterials, "" );
    
#if defined( ASURA_MAX_NO_OF_MATERIALS_GAME)
	Asura_Assertf( iNumberOfMaterials <= ASURA_MAX_NO_OF_MATERIALS_GAME, ("Not enough material handles in the game. Need %d total %d.", iNumberOfMaterials, ASURA_MAX_NO_OF_MATERIALS_GAME));
#endif

    xStream.WriteChunk_Start( ASURA_CHUNK_MATERIAL, ASURA_CHUNK_MATERIAL_VERSION, 0 );
    xStream << iNumberOfMaterials;

    const Asura_Material* pxMaterial = pxMaterials;
    for(int i=0;i<iNumberOfMaterials;i++,pxMaterial++)
    {
        for(int j=0;j<ASURA_MATERIAL_MAXTEXTURES;j++)
        {
            xStream << pxMaterial->m_iTextureID[j];
            xStream << pxMaterial->m_iNormalMapID[j];
            xStream << pxMaterial->m_iSpecularMapID[j];
        }

        xStream << pxMaterial->m_uMaterialFlags;
        Project_WriteProjectFlags( xStream, pxMaterial->m_uProjectFlags );
        xStream << pxMaterial->m_uAnimHash;
		xStream << pxMaterial->m_uSpecularColour;
    }

    xStream.WriteChunk_End();
}

#endif //ASURA_TOOLS


//////////////////////////////////////////////////////////////////////////////////////////////////
/*---------------------------**
** Asura_Chunk_MaterialNames **
**---------------------------*/
#define ASURA_CHUNK_MATERIALNAMES_VERSION 0

bool Asura_Chunk_MaterialNames::Process(Asura_Handle iFileHandle) const
{
	#ifdef ASURA_TOOLS
	Asura_Assert(Version<=ASURA_CHUNK_MATERIALNAMES_VERSION,"Unknown chunk version");
	for(int i=0;i<m_iNumberOfNamedMaterials;i++)
	{
		int iMaterialID;
		ASURA_CHUNK_FILEEXTRACT(iFileHandle,iMaterialID,int);
		//convert the index ,and get the material
		iMaterialID = Asura_Material_System::ConvertIndex(iMaterialID);
		Asura_Material* pxMaterial = Asura_Material_System::GetMaterial(iMaterialID);
		if(!pxMaterial) return false;

		//read in the material name
		ASURA_CHUNK_FILEEXTRACT_STRING(iFileHandle,pxMaterial->m_xMaterialName);
		
	}
	return true;
	#else
	//just skip this chunk if we come across it in a non-tools build
	return false;
	#endif
}

#ifdef ASURA_TOOLS
void Asura_Chunk_MaterialNames::Create(int iNumberOfMaterials,const Asura_Material* pxMaterials,Asura_SaveBlock* pxSaveBlock)
{
	if(!iNumberOfMaterials) return;

	Asura_Chunk_SaveBlock_Stream xStream(pxSaveBlock);
	Create	(iNumberOfMaterials,pxMaterials,xStream);
}


void Asura_Chunk_MaterialNames::Create(int iNumberOfMaterials,const Asura_Material* pxMaterials,Asura_Chunk_Stream& xStream)
{
	if(!iNumberOfMaterials) return;
	Asura_Assert(pxMaterials,"");

	

	//Determine the number of materials with names
	int iNumberOfNamedMaterials = 0;

	for(int i=0;i<iNumberOfMaterials;i++)
	{
		if(!pxMaterials[i].m_xMaterialName.IsBlank())
		{
			iNumberOfNamedMaterials++;
		}
	}

	if(!iNumberOfNamedMaterials) return;//no point in writing chunk if none were named

	u_int uChunkFlags = 0;
	xStream.WriteChunk_Start(ASURA_CHUNK_MATERIALNAMES, ASURA_CHUNK_MATERIALNAMES_VERSION, uChunkFlags);


	xStream << iNumberOfNamedMaterials;

	const Asura_Material* pxMaterial = pxMaterials;
	for(int i=0;i<iNumberOfMaterials;i++,pxMaterial++)
	{
		if(!pxMaterial->m_xMaterialName.IsBlank())
		{
			xStream << i;
			xStream << pxMaterial->m_xMaterialName;
		}
	}
	xStream.WriteChunk_End();
}

#endif //ASURA_TOOLS
