
///////////////////////////////////////////////////////////////////////////////
//
// File   : Tools_FacialAnimation_Export.cpp
// Author : Andy Tate
// Date   : 4-Sep-2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////

#include "Core/Asura.h"

#if defined(ASURA_USE_FACIAL_ANIMATION_SYSTEM)

// This file's header...
#include "Load&Save/LevelExport/Tools_Level_Export.h"

// Asura independent header-files...
#include "Animation/Asura_Animation.h"
#include "ChunkSystem/Asura_Chunk_FacialAnimation.h"
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "FacialAnimation/Asura_FacialAnimation_System.h"

// Tools header-files...
#include "FacialAnimation/Tools_FacialAnimation_System.h"
#include "Load&Save/Tools_ResourceExportLog.h"


////////////////////////////////////////////////////////////////////////////////
// Constant declarations...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Static variable declarations...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Private functions...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Protected functions...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Public functions...
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function     : Tools_Level_Export::AddFaceToExportList
// Author       : Andy Tate
// Date         : 4-Sep-2008
////////////////////////////////////////////////////////////////////////////////

bool Tools_Level_Export::AddFaceToExportList(const char* szFaceName,
											 const Asura_Hash_ID uFaceHash)
{
	FaceContainer*	pxFaceContainer	= This->m_pxFaceContainer;

	if(pxFaceContainer == NULL)
	{
		Asura_Assert(false, "Not in the middle of a file export?");
		return(false);
	}
	else
	{
		const Tools_FacialAnimation_Face*	pxToolsFace	= szFaceName	? Tools_FacialAnimation_System::FindOrLoadFace(szFaceName)
																		: Tools_FacialAnimation_System::FindOrLoadFace(uFaceHash);

		if(pxToolsFace == NULL)
		{
			if(szFaceName)
			{
				Asura_Assertf(false, ("Failed to find Tools face \"%s\" when exporting.", szFaceName ? szFaceName : ""));
			}
			return(false);
		}
		else
		{
			const Asura_FacialAnimation_Face*	pxAsuraFace	= Asura_FacialAnimation_System::FindFace(uFaceHash);

			if(pxAsuraFace == NULL)
			{
				Asura_Assertf(false, ("Failed to find Asura face \"%s\" when exporting.", pxToolsFace->GetName().GetString()));
				return(false);
			}
			else
			{
				if(pxFaceContainer->GetDataByHash(uFaceHash) == NULL)
				{
					TOOLS_RESOURCEEXPORTLOG("Facial-animation face", pxToolsFace->GetName().GetString(), true);
					//pxToolsFace->AddFilesToExportList();
					pxFaceContainer->AddNode(uFaceHash, pxAsuraFace);
				}
				return(true);
			}
		}
	}
}

/// End of function 'Tools_Level_Export::AddFaceToExportList'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Tools_Level_Export::AddFaceAnimationToExportList
// Author       : Andy Tate
// Date         : 4-Sep-2008
////////////////////////////////////////////////////////////////////////////////

bool Tools_Level_Export::AddFaceAnimationToExportList(const char* szFaceAnimationName,
													  const Asura_Hash_ID uFaceAnimationHash,
													  FaceAnimationContainer* pxFaceAnimationContainer)
{
	if(pxFaceAnimationContainer == NULL)
	{
		Asura_Assert(false, "Not in the middle of a file export?");
		return(false);
	}
	else
	{
		const Tools_FacialAnimation_FaceAnimation*	pxToolsFaceAnimation = szFaceAnimationName	? Tools_FacialAnimation_System::FindOrLoadAnimation(szFaceAnimationName)
																								: Tools_FacialAnimation_System::FindOrLoadAnimation(uFaceAnimationHash);

		if(pxToolsFaceAnimation == NULL)
		{
			Asura_Assertf(false, ("Failed to find Tools face-animation \"%s\" when exporting.", szFaceAnimationName ? szFaceAnimationName : ""));
			return(false);
		}
		else
		{
			const Asura_FacialAnimation_FaceAnimation*	pxAsuraFaceAnimation	= Asura_FacialAnimation_System::FindFaceAnimation(uFaceAnimationHash);

			if(pxAsuraFaceAnimation == NULL)
			{
				Asura_Assertf(false, ("Failed to find Asura face-animation \"%s\" when exporting.", pxToolsFaceAnimation->GetName().GetString()));
				return(false);
			}
			else
			{
				if(pxFaceAnimationContainer->GetDataByHash(uFaceAnimationHash) == NULL)
				{
					TOOLS_RESOURCEEXPORTLOG("Facial-animation face-animation", pxToolsFaceAnimation->GetName().GetString(), true);
					pxFaceAnimationContainer->AddNode(uFaceAnimationHash, pxAsuraFaceAnimation);
				}
				return(true);
			}
		}
	}
}

/// End of function 'Tools_Level_Export::AddFaceAnimationToExportList'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Tools_Level_Export::AddFacialAnimationData
// Author       : Andy Tate
// Date         : 5-Sep-2008
////////////////////////////////////////////////////////////////////////////////

bool Tools_Level_Export::AddFacialAnimationData(HANDLE pSaveHandle)
{
	if(m_pxFaceContainer == NULL)
	{
		return(false);
	}
	else
	{
		Asura_Chunk_Memory_Stream	xStream;

		// Add the faces we're using the stream...
		for(FaceConstIterator xIterator(*m_pxFaceContainer); !xIterator.Done(); xIterator.Next())
		{
			Asura_FacialAnimation_Face const* const*	ppxFace	= xIterator.GetCurrent();
			Asura_FacialAnimation_Face const*			pxFace	= (ppxFace == NULL) ? NULL : *ppxFace;

			if(pxFace != NULL)
			{
				//Write out the animations used by the face
				for(u_int i=0; i<pxFace->GetNumMuscleGroups(); i++)
				{
					const Asura_FacialAnimation_MuscleGroup* pxMuscleGroup = pxFace->GetMuscleGroup(i);
					for(u_int j=0; j<pxMuscleGroup->GetNumAnimations(); j++)
					{
						Asura_Hash_ID uAnimHash = pxMuscleGroup->GetAnimationHash(j);
						if(!uAnimHash) continue;

						Asura_Hierarchy_Anim* pxAnim = Asura_Animation_System::GetAnimByHash(uAnimHash);
						if(!pxAnim)
						{
							//May need to seek out some names if this error happens in practice , but for now just stick to reporting it
							AddMessage(MT_ERROR,"Failed to find muscle group animation for face");
							continue;
						}

						AddAnimationToExport(pSaveHandle, pxAnim);
					}
				}
				//and write out a chunk for the face
				const Asura_Hash_ID	uFaceHash	= xIterator.GetCurrentHash();
				Asura_Chunk_FacialAnimation_Face::Create(uFaceHash, *pxFace, xStream);
			}
		}

		// Add the non-localised face-animation to the stream...
		if(m_pxFaceAnimationContainer != NULL)
		{
			// Add the face-animations we're using the the stream...
			for(FaceAnimationConstIterator xIterator(*m_pxFaceAnimationContainer); !xIterator.Done(); xIterator.Next())
			{
				Asura_FacialAnimation_FaceAnimation const* const*	ppxFaceAnimation	= xIterator.GetCurrent();
				Asura_FacialAnimation_FaceAnimation const*			pxFaceAnimation		= (ppxFaceAnimation == NULL) ? NULL : *ppxFaceAnimation;

				if(pxFaceAnimation != NULL)
				{
					const Asura_Hash_ID	uFaceAnimationHash	= xIterator.GetCurrentHash();

					Asura_Chunk_FacialAnimation_FaceAnimation::Create(uFaceAnimationHash, *pxFaceAnimation, xStream);
				}
			}
		}

		// Write the chunk-stream to the save-file...
		return(AddChunkStream(xStream, pSaveHandle));
	}
}

/// End of function 'Tools_Level_Export::AddFacialAnimationData'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Tools_Level_Export::AddLocalisedFacialAnimationData
// Author       : Andy Tate
// Date         : 5-Sep-2008
////////////////////////////////////////////////////////////////////////////////

bool Tools_Level_Export::AddLocalisedFacialAnimationData(HANDLE pSaveHandle,int iLanguage)
{
	if(m_pxLocalisedFaceAnimationContainer == NULL)
	{
		return(false);
	}
	else
	{
		Asura_Chunk_Memory_Stream	xStream;

		// Add the face-animations we're using the the stream...
		// Use SaveIterator to create a balanced tree with same number of nodes
		Asura_TemplateHashTree_SaveIterator	xSaveIterator( m_pxLocalisedFaceAnimationContainer->GetNumberOfNodes() );
		while ( xSaveIterator.Done() == false )
		{
			u_int	uIndex = xSaveIterator.GetCurrent() ;
				
			// Retrieve FaceAnimation from tree using SaveIterator index
			Asura_FacialAnimation_FaceAnimation const* const*	ppxFaceAnimation	= m_pxLocalisedFaceAnimationContainer->GetDataByIndex( uIndex );
			Asura_FacialAnimation_FaceAnimation const*			pxFaceAnimation		= (ppxFaceAnimation == NULL) ? NULL : *ppxFaceAnimation;

			if(pxFaceAnimation != NULL)
			{
				// Retrieve Hash from tree using SaveIterator index
				const Asura_Hash_ID	uFaceAnimationHash	= m_pxLocalisedFaceAnimationContainer->GetHashByIndex( uIndex );
				Asura_Chunk_FacialAnimation_FaceAnimation::Create(uFaceAnimationHash, *pxFaceAnimation, xStream);
			}
			xSaveIterator.Next();
		}

		// Write the chunk-stream to the save-file...
		return(AddChunkStream(xStream, pSaveHandle));
	}
}

/// End of function 'Tools_Level_Export::AddLocalisedFacialAnimationData'. ///

////////////////////////////////////////////////////////////////////////////////
// Function     : Tools_Level_Export::AddFaceAnimsUsedByStandardAnimsToExportList
// Author       : Richard Rice
// Date         : 13-Oct-2008
////////////////////////////////////////////////////////////////////////////////

void Tools_Level_Export::AddFaceAnimsUsedByStandardAnimsToExportList()
{
	//Check all the animation files in the export list , and see if any of those have facial
	//animations associated with them.
	if(m_pxAnimFileList->GetNumberOfNodes())
	{
		const Asura_String** ppxNameList = new const Asura_String*[m_pxAnimFileList->GetNumberOfNodes()];
		m_pxAnimFileList->MakeNameList(ppxNameList);

		for(int i=0;i<m_pxAnimFileList->GetNumberOfNodes() && !IsAbortFlagSet();i++)
		{
			//Find/load the animation
			const Asura_String* pxFilename = ppxNameList[i];
			Asura_String xAnimName;
			pxFilename->SplitFilename(0, &xAnimName, 0);

			if(!Asura_Animation_System::GetAnim(xAnimName.GetString()))
			{
				if(!LoadAsuraFile(pxFilename->GetString()))
				{
					AddMessage(MT_ERROR,"Failed to load %s.",pxFilename->GetString());
					continue;
				}
				if(!Asura_Animation_System::GetAnim(xAnimName.GetString()))
				{
					AddMessage(MT_ERROR,"AddFaceAnimsUsedByStandardAnimsToExportList() failed to find anim %s.",xAnimName.GetString());
					continue;
				}
			}
			Asura_Hierarchy_Anim* pxAnim = Asura_Animation_System::GetAnim(xAnimName.GetString());
			if(pxAnim && pxAnim->HasFacialAnimation())
			{
				//The animation has a facial animation , so add that to the export list
				AddFaceAnimationToExportList(xAnimName.GetString(), xAnimName.GetHash());
			}
		}
		delete [] ppxNameList;
	}

}

/// End of function 'Tools_Level_Export::AddFaceAnimsUsedByStandardAnimsToExportList'. ///

#endif	//defined(ASURA_USE_FACIAL_ANIMATION_SYSTEM)


/// End of file. ///
