//
// Asura_Chunk_Hierarchy.h
//
// Created by Kevin Lea - 12/06/2001 11:18:30
// 
// Copyright (C) 2001 Rebellion, All Rights Reserved.
//

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef __ASURA_CHUNK_HIERARCHY_H__
#define __ASURA_CHUNK_HIERARCHY_H__

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

#include "ChunkSystem/Asura_Chunk_Loaders.h"

// F O R W A R D   D E C L A R A T I O N S ///////////////////////////////////

class Asura_Hierarchy_Anim;
class Asura_Hierarchy_Bone_KeyFrame;
class Asura_Hierarchy_Skin;
class Asura_SaveBlock;
class Asura_String;
class Asura_Chunk_Stream;

#ifdef ASURA_TOOLS
class Asura_Mesh;
template<typename T> class List;
#endif

// C L A S S E S /////////////////////////////////////////////////////////////

#define ASURA_CHUNK_HIERARCHY_ANIM_VERSION 16

class Asura_Chunk_Hierarchy_Anim : public Asura_Chunk_Header
{
public:
#ifdef ASURA_TOOLS
	static void Create( const Asura_Hierarchy_Anim* pxAnim, Asura_SaveBlock* pxSaveBlock);
	static void Create( const Asura_Hierarchy_Anim* pxAnim , Asura_Chunk_Stream& xStream);

	static void Create( const Asura_Hierarchy_Anim* pxAnim , char* pcChunkBuffer , int iChunkSize);
	static int GetChunkBufferSize( const Asura_Hierarchy_Anim* pxAnim);

#endif
	bool Process(Asura_Handle fileHandle) const;

#ifdef ASURA_TOOLS
	//Processes a chunk that has already been completely loaded and returns a pointer
	//to an animation. ('this' is a pointer to the start of a buffer containing the whole chunk)
	//This animation isn't put in Asura_Animation_System , so should be deallocated
	//with delete. RAR 06/03/03
	Asura_Hierarchy_Anim* Process() const;
#endif



	enum ChunkFlags
	{
		ChunkFlag_HasBoneLengths = 0x00000001,
		ChunkFlag_DeltaAnimation = 0x00000002,
		ChunkFlag_DontRemoveKeyframes = 0x00000004,
		ChunkFlag_HasBoundingBox = 0x00000008,
		ChunkFlag_HasMovementData = 0x00000010,
		ChunkFlag_DontCompressKeyframes = 0x00000020,
		ChunkFlag_HasHierarchyData = 0x00000040,//indicates anim has parent bone and bone name arrays
		ChunkFlag_HasSkinExportTransforms = 0x00000080,
		ChunkFlag_SharedAnimDeltaPos = 0x00000100,
		ChunkFlag_SharedAnimDeltaOrient = 0x00000200,
		ChunkFlag_HasBoneRestPose = 0x00000400,
		ChunkFlag_HasBoneDeltaPose = 0x00000800,
		ChunkFlag_HasFacialAnimation = 0x00001000,
	};

private :

	
	//main process function used by the other ones
	bool Process(Asura_Chunk_Stream& xStream, const char* szFilename, Asura_Hierarchy_Anim* pxPreAllocatedAnim) const;

};

class Asura_Chunk_Hierarchy_CompressedAnim : public Asura_Chunk_Header
{
	public:
#ifdef ASURA_TOOLS
		static int GetChunkBufferSize(const Asura_Hierarchy_Anim* pxAnim);
		static void Create(const Asura_Hierarchy_Anim* pxAnim, char* pcChunkBuffer);
#endif

		bool Process(Asura_Handle fileHandle) const;

	private:
		// KJL - 23/06/2003 16:33:06 - any data whose size is known can be added to the chunk
		// (only things like arrays of variable size need to be read separately)
		u_int	m_uNumberOfBones;
		float	m_fDuration;
		float	m_fSpeed;
		float	m_fDirection;
        u_int	m_uTotalNumberOfKeyFrames;
		u_int	m_uTotalNumberOfBoneOffsets;
		u_int	m_uNumberOfAnimationFlags;

		
		enum ChunkFlags
		{
			ChunkFlag_HasBoneLengths				= 0x00000001,
			ChunkFlag_DeltaAnimation				= 0x00000002,
			ChunkFlag_HasBoundingBox				= 0x00000008,
			ChunkFlag_HasMovementData				= 0x00000010,
			ChunkFlag_CompressedBoneDataStructure	= 0x00000020,
			ChunkFlag_SharedAnimDeltaPos			= 0x00000200,
			ChunkFlag_SharedAnimDeltaOrient			= 0x00000400,
			ChunkFlag_HasFacialAnimation			= 0x00000800,
		};
};

#define ASURA_CHUNK_HIERARCHY_SKIN_VERSION (9)

// Version history:
//
//     (KJL - 15.08.2001) -  2 - Added bone parent and positional data.
//
//     (RAR - 06.12.2002) -  3 - Added collision mesh stuff for hierarchical
//                               skins.
//
//     (MP  - 12.02.2003) -  4 - Max weightings per vertex reduced from 8 to
//                               4.
//
//     (RAR - 27.06.2003) -  5 - Added collision bounding box
//                               
//
//     (RAR - 22.09.2003) -  6 - Added collision mesh
//                               
//                               
//     (RAR - 17.10.2006) -  7 - Added mirrored bone array
//
//                               
//     (RAR - 09.11.2006) -  8 - Added initial rest pose
//
//
//     (RAR - 26.01.2007) -  9 - Added bone sort key
//

class Asura_Chunk_Hierarchy_Skin : public Asura_Chunk_Header
{
public:
#ifdef ASURA_TOOLS
	static void Create( Asura_SaveBlock* pxSaveBlock, Asura_Hierarchy_Skin* pxSkin, const List<Asura_Mesh*>* pxMeshList, bool bCreateLODChunks );
	static void Create( Asura_Chunk_Stream& xStream, Asura_Hierarchy_Skin* pxSkin, const List<Asura_Mesh*>* pxMeshList, bool bCreateLODChunks );
#endif									 
	bool Process(Asura_Handle fileHandle) const;
	//If pxPreAllocatedSkin is non-zero then it will be filled in instead of allocating a skin
	//in the animation system
	Asura_Hierarchy_Skin* Process(Asura_Chunk_Stream& xStream, Asura_Hierarchy_Skin* pxPreAllocatedSkin, bool bConvertMaterialIDs = true) const;

	int NumberOfVertices;
	int NumberOfBones;

	enum ChunkFlags
	{
		ChunkFlag_HasSectionArray = 	  0x00000001,
		ChunkFlag_HasCollisionBB = 		  0x00000002,
		ChunkFlag_HasCollisionMesh = 	  0x00000004,
		ChunkFlag_ManualLOD =		      0x00000008,
		ChunkFlag_HasInitialRestPose =	  0x00000010,
		ChunkFlag_HasBoneSortKey =		  0x00000020,
		ChunkFlag_NoIndependentSkinData = 0x00000040,
	};
	
	// Kevin Lea - 10/08/2001 17:21:11 - data packet contains
	//
	// Name (padded to 4byte multiple)
	// Vertex data (Asura_Hierarchy_Skin_Vertex * NumberOfVertices)
	// Bone Parent data (int * NumberOfBones)
	// Bone data (Asura_Hierarchy_Bone_RestFrame * NumberOfBones)


};

class Asura_Chunk_Hierarchy_SkinLOD : public Asura_Chunk_Header
{
public:
	enum ChunkFlags
	{
		ChunkFlag_NoIndependentSkinData = 0x00000001,
	};

#ifdef ASURA_TOOLS
	static void Create( Asura_Chunk_Stream& xStream, const Asura_Hierarchy_Skin* pxSkin, const Asura_String& xRootSkinName);
#endif
	bool Process(Asura_Handle iFileHandle) const;
	//If pxPreAllocatedSkin is passed in , then it will be filled in instead of allocating a new skin in the animation system.
	//Only the data from the chunk will be taken in this case. The skin won't get data copied from the parent.
	bool Process(Asura_Chunk_Stream& xStream, Asura_Hierarchy_Skin* pxPreAllocatedSkin = 0, Asura_String* pxOutputRootSkinName = 0) const;

};

class Asura_Chunk_Hierarchy_MarkerPoints : public Asura_Chunk_Header
{
public:
#ifdef ASURA_TOOLS
	static void Create( const Asura_Hierarchy_Skin* pxSkin, const Asura_String& xSkinName, Asura_SaveBlock* pxSaveBlock);
	static void Create( const Asura_Hierarchy_Skin* pxSkin, const Asura_String& xSkinName, Asura_Chunk_Stream& xStream);
#endif
	bool Process(Asura_Handle fileHandle) const;

	int NumberOfMarkerPoints;
	//followed by...
	//Skin Name
	//And then each of the marker points in turn
	
};

class Asura_Chunk_Hierarchy_SectionBBs : public Asura_Chunk_Header
{

    public:

#ifdef ASURA_TOOLS
        static bool Create( const Asura_Hierarchy_Skin* pxSkin, const Asura_String& xSkinName, Asura_SaveBlock* pxSaveBlock );
#endif
        bool Process( Asura_Handle iFileHandle ) const;



};

#ifdef ASURA_TOOLS
class Asura_Chunk_Hierarchy_ManualSectionBBs : public Asura_Chunk_Header
{

    public:

        static void Create( const Asura_Hierarchy_Skin* pxSkin, Asura_SaveBlock* pxSaveBlock );
        static void Create( const Asura_Hierarchy_Skin* pxSkin, Asura_Chunk_Stream& xStream );
        bool Process( Asura_Handle iFileHandle ) const;
		//process from chunk buffer)
		bool Process( Asura_Hierarchy_Skin* pxSkin) const;

};
#endif // ASURA_TOOLS



class Asura_Chunk_Hierarchy_Sounds : public Asura_Chunk_Header
{

    public:

#ifdef ASURA_TOOLS
        static void Create( const Asura_Hierarchy_Skin* pxSkin, Asura_SaveBlock* pxSaveBlock );
        static void Create( const Asura_Hierarchy_Anim* pxAnim, Asura_SaveBlock* pxSaveBlock );
        static void Create( const Asura_Hierarchy_Skin* pxSkin, Asura_Chunk_Stream& xStream );
        static void Create( const Asura_Hierarchy_Anim* pxAnim, Asura_Chunk_Stream& xStream );
		static void Create(int iNumberOfSoundDefns,const class Asura_Hierarchy_Sound* pxSoundDefns,const Asura_String* pxName,bool bAnim, Asura_SaveBlock* pxSaveBlock);
		static void Create(int iNumberOfSoundDefns,const class Asura_Hierarchy_Sound* pxSoundDefns,const Asura_String* pxName,bool bAnim, Asura_Chunk_Stream& xStream);
#endif
        bool Process( Asura_Handle iFileHandle ) const;

#ifdef ASURA_TOOLS
	//processes a chunk from chunkbuffer
		bool Process(int* piNumberOfSoundDefns,class Asura_Hierarchy_Sound** ppxSoundDefns, Asura_String* pxName = 0) const;
#endif
		enum ChunkFlags
		{
			ChunkFlag_AnimSounds = 0x00000001,//sounds are for anim instead of skin
		};

private :
		bool Process(Asura_Chunk_Stream& xStream,bool bApplyToSkinOrAnim,int* piNumberOfSoundDefns,class Asura_Hierarchy_Sound** ppxSoundDefns, Asura_String* pxName) const;


		int m_iNumberOfSoundDefns;


};


#endif//__ASURA_CHUNK_HIERARCHY_H__
