//
// Asura_Chunk_TextureAnimation.h
//
// Created by Richard Rice - 16/05/2005
// 
// Copyright (C) 2005 Rebellion, All Rights Reserved.
//


#include "Core/Asura.h"
#include "ChunkSystem/Asura_Chunk_TextureAnimation.h"

#include "Animation/Asura_TextureAnimation.h"
#include "ChunkSystem/Asura_Chunk_Macros.h"
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "ChunkSystem/Asura_SaveBlock.h"
#include "Core/Memory/Asura_ResourceAllocator.h"
#include "Debugging/Asura_Logfile.h"
#include "FileAccess/Asura_FileAccess.h"


#define ASURA_CHUNK_TEXTUREANIMATION_VERSION 2

bool Asura_Chunk_TextureAnimation::Process(Asura_Handle iFileHandle) const
{
	Asura_ResourcePushType(ASURA_RESOURCE_TEXTURE_ANIMATION);
	{
		Asura_Assert(Version<=ASURA_CHUNK_TEXTUREANIMATION_VERSION,"Unknown chunk version");

		//get the name
		const char* pszAnimName = Asura_FileAccess::ReadString(iFileHandle);

#if ASURA_LOG_FILE_CONTENTS
		Asura_SimpleLogfileOutput((ASURA_FILE_CONTENTS_LOGFILE,"Texture Animation : %s\n",pszAnimName));
#endif

		//create a new anim
		Asura_TextureAnimation* pxAnim;
		if(!Asura_TextureAnimation_System::NewAnimation(pszAnimName,pxAnim))
		{
			//anim already exists (or too many anims)
			if(!pxAnim)
			{
				Asura_ResourcePopType();
				return false;
			}

			if(stricmp(pszAnimName,pxAnim->GetName()))
			{
				//animation with different name , but same hash.. not so good
				Asura_Assertf(0,("Texture animations '%s' and '%s' share the same hash ID.\nOne of these will need to have their names changed.",pszAnimName,pxAnim->GetName()));
				Asura_ResourcePopType();
				return false;
			}
			//Loading an animation with the same name.
			//In this case we need to overwrite the existing animation. This is needed to allow
			//animations that are used on shapes flagged as merge into environment to be updated
			//properly when their shape files get updated.

			//However... I think we will only need to be doing this in tools
			//(hopefully in level exports the anims will be up to date , or at any rate , the 
			//correct one will come first)
#ifdef ASURA_TOOLS
			Asura_ResourceDeallocateArray(pxAnim->m_pxSequences);
			pxAnim->m_pxSequences = 0;
			pxAnim->m_uNumberOfSequences = 0;
#else
			Asura_ResourcePopType();
			return false;
#endif
		}

		//get number of sequences , and allocate
		ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxAnim->m_uNumberOfSequences,pxAnim->m_uNumberOfSequences);
		Asura_ResourceAllocateArray(pxAnim->m_pxSequences, pxAnim->m_uNumberOfSequences);

		//read in each sequence
		Asura_TextureAnimationSequence* pxSeq = pxAnim->m_pxSequences;
		for(u_int uSeq=0;uSeq<pxAnim->m_uNumberOfSequences;uSeq++,pxSeq++)
		{
			ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxSeq->m_fDuration,float);
			ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxSeq->m_uFlags,u_int);

			//get the frames
			ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxSeq->m_uNumberOfFrames,u_int);
			Asura_Assert(pxSeq->m_uNumberOfFrames,"Texture animation sequences should contain at least one frame");

			Asura_ResourceAllocateArray(pxSeq->m_pxFrames, pxSeq->m_uNumberOfFrames);

			Asura_TextureAnimationFrame* pxFrame = pxSeq->m_pxFrames;
			for(u_int uFrame=0;uFrame<pxSeq->m_uNumberOfFrames;uFrame++,pxFrame++)
			{
				ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxFrame->m_fU,float);			
				ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxFrame->m_fV,float);			
				ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxFrame->m_fTime,float);
				if(Version>=1)
				{
					ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxFrame->m_uAddedMaterialFlags,u_int);
					ASURA_CHUNK_FILEEXTRACT(iFileHandle,pxFrame->m_uRemovedMaterialFlags,u_int);			
				}
				if(Version<2)
				{
					pxFrame->m_uAddedMaterialFlags = 0;
					pxFrame->m_uRemovedMaterialFlags = 0;
				}
			}			
		}
	}
	Asura_ResourcePopType();
	return true;
}

#if defined ASURA_TOOLS

void Asura_Chunk_TextureAnimation::Create (Asura_Chunk_Stream& xStream, const Asura_TextureAnimation* pxAnim)
{
	// Write the data...
	xStream.WriteChunk_Start	(ASURA_CHUNK_TEXTUREANIMATION, ASURA_CHUNK_TEXTUREANIMATION_VERSION, 0);

	xStream << pxAnim->m_xName;
	xStream << pxAnim->m_uNumberOfSequences;

	// Write each sequence in-turn...
	for (u_int s = 0; s < pxAnim->m_uNumberOfSequences; s++)
	{
		const Asura_TextureAnimationSequence&		xSequence	= pxAnim->m_pxSequences [s];

		Asura_WriteToStream_Bitfield_Wrapper<u_int>	xFlagsBitfield (xSequence.m_uFlags);

		// Create the bitfields...
		xFlagsBitfield.Add	(xSequence.m_bLoop,				1);
		xFlagsBitfield.Add	(xSequence.m_bInterpolate,		1);
		xFlagsBitfield.Add	(xSequence.m_bRandom,			1);
		xFlagsBitfield.Add	(xSequence.m_bLoopBackAndForth,	1);

		// Write this sequence...
		xStream << xSequence.m_fDuration;
		xStream << xFlagsBitfield;
		xStream << xSequence.m_uNumberOfFrames;

		// Write each frame in-turn
		for (u_int f = 0; f < xSequence.m_uNumberOfFrames; f++)
		{
			const Asura_TextureAnimationFrame&	xFrame	= xSequence.m_pxFrames [f];

			// Write this frame...
			xStream << xFrame.m_fU;
			xStream << xFrame.m_fV;
			xStream << xFrame.m_fTime;
			xStream << xFrame.m_uAddedMaterialFlags;
			xStream << xFrame.m_uRemovedMaterialFlags;
		}			
	}

	// End the data...
	xStream.WriteChunk_End	();
}

void Asura_Chunk_TextureAnimation::Create(Asura_SaveBlock* pxSaveBlock,const class Asura_TextureAnimation* pxAnim)
{
	Asura_Chunk_SaveBlock_Stream	xStream (pxSaveBlock);

	// Call the other function...
	Create	(xStream, pxAnim);
}

#endif
