//===========================================================================//
// File:	AnimFormat.hpp                                                 
// Project: MechWarrior 4
// Contents: 
//			This is the base animation format header file.
//			This file defines Keyframes and Animation Player classes
//			PLEASE NOTE!!!!  THIS FILE IS USED BY THE PLUGIN :
//				3dsplugins/AnimationExport
//			If you change this you must also change the plugin!!!!
//			
//			THIS IS A THREAT!  
//			All the animations that have been exported rely on this format
//			If you change this format, you better know what you are doing!
//			If you don't support multiple versions when you change this
//			Then you HAVE TO EXPORT ALL THE ANIMATIONS AGAIN!!!!!
//			The max plugin environment allows for this.
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 05/15/98  JSE  Initial coding, 
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Fasa Interactive, Inc.
// All Rights reserved worldwide
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL
//===========================================================================//


#pragma once

// Animation file format
// The animation file format is designed to be quickly loaded and have only a 
// small amount of overhead.
// Basicly the file format is binary compatable with the memory format.
// The only section that isn't binary compatable is the header block
// and that is so that it can actualy point to the blocks of memory
//

#define MAJOR_ANIM_VERSION_2_1 2
#define MINOR_ANIM_VERSION_2_1 1

#define MAJOR_ANIM_VERSION_2_0 2
#define MINOR_ANIM_VERSION_2_0 0
 
#define MAJOR_ANIM_VERSION_1_0 1
#define MINOR_ANIM_VERSION_1_0 0

#define COMPRESS_JOINT_COUNT 47

	#include <MW4\MW4AnimationSystem.hpp>
	#include <Adept\Resource.hpp>

namespace MW4Animation {

	// Pack all this
	#pragma pack( push, anim_pack, 4 )


	//
	//===========================================================================//
	//  This is the basic keyframe data holders
	//  This is binary compatable to the file format 
	//  so casting is all that is required to 
	//  create them from the file


	//===========================================================================//
	// Class BaseKeyframe
	// Only holds the time
	// all iteration uses this base class
	class BaseKeyframeTime
	{
	public:
		Stuff::Scalar timeOfFrame;

	};

	//===========================================================================//

	class BaseKeyframe
	{
	public:
	
	};

	//===========================================================================//

	class Point3DLinearKey :
		public BaseKeyframe
	{
	public:
		Stuff::Point3D
			valueOfKey;
	};

	//===========================================================================//

	class QuaternionLinearKey :
		public BaseKeyframe
	{
	public:
		Stuff::UnitQuaternion
			valueOfKey;
	};

	//===========================================================================//

	class TriggerLinearKey :
		public BaseKeyframe
	{
	public:
		int 
			valueOfKey;
	};

	//===========================================================================//

	class VelocityLinearKey :
		public BaseKeyframe
	{
	public:
		Stuff::Point3D
			valueOfKey;
		Stuff::Point3D
			velocityOfKey;
	};

	//===========================================================================//

	class AngularVelocityLinearKey :
		public BaseKeyframe
	{
	public:
		Stuff::UnitQuaternion
			valueOfKey;
		Stuff::Vector3D
			velocityOfKey;
	};

	//===========================================================================//


	class JointAnimData
	{
	public:

		enum {
			
			Point3DLinearKeyType,
			QuaternionLinearKeyType,
			TriggerLinearKeyType,
			VelocityLinearKeyType,
			AngularVelocityLinearKeyType,
			KeyTypeCount
		};

		JointAnimData(){};
		~JointAnimData(){};

		
		size_t offsetToName;
		int	firstChannel;
		BYTE	channelsUsed;

		const char *GetName(const char *name_block)
		{
			return name_block + offsetToName;
		}
	};

	//===========================================================================//

	class ChannelAnimData
	{
	public:
		enum {
			VelocityChannelType,
			PositionChannelType,
			RotationChannelType,
			TriggerChannelType,
			AngularVelocityChannelType
		};

		
		size_t sizeOfOneKey;
		size_t offsetToKeyData;
		size_t offsetToKeyTimeData;

		BYTE keyframeCount;
		BYTE channelType;
		BYTE keyType;
		BYTE jointNumber;

	};

	//===========================================================================//

	class AnimHeader
	{
	public:
		
		AnimHeader(){};
		~AnimHeader(){};


		int majorVersion;
		int minorVersion;
		Stuff::Scalar startTime;
		Stuff::Scalar endTime;
		
		size_t totalSizeOfAnimation;
		size_t offsetToHeaderBlock;
		size_t offsetToJointBlock;
		size_t offsetToNameBlock;
		size_t offsetToKeyBlock;
		size_t offsetToKeyTimeBlock;
		size_t offsetToChannelBlock;

		// these are last for packing reasons.
		char animationName[56];
	};

	//===========================================================================//

	// This is the only thing that has to be dynamicly allocated once the binary 
	// of the animation has been transfered to memory.  The rest is pointer math!
	class AnimData
	{
	public:

		AnimData();
		~AnimData();

		// if we made a copy of the memory
		BYTE *startOfBlocks;

		AnimHeader *animHeaderBlock;
		size_t animHeaderBlockSize;

		JointAnimData *animJointBlock;
		size_t animJointBlockSize;

		char *animNameBlock;
		size_t animNameBlockSize;

		void *animKeyBlock;
		size_t animKeyBlockSize;

		void *animKeyTimeBlock;
		size_t animKeyTimeBlockSize;

		ChannelAnimData *animChannelBlock;
		size_t animChannelBlockSize;

		BYTE GetJointCount();
		int GetChannelCount();

		size_t GetSize();

		bool Save(const char *file_name);
		bool Save(Stuff::FileStream *stream);
		bool Save(Stuff::MemoryStream *stream);
		
		bool Load(const char *file_name);       // this makes a local copy of the data
		bool Load(Stuff::FileStream *stream);   // this makes a local copy of the data
		bool Load_1_0(Stuff::MemoryStream *stream); // this just refrences the data
		bool Load_2_0(Stuff::MemoryStream *stream);
		bool Load_2_1(Stuff::MemoryStream *stream);
		bool Load(Adept::Resource *res);

		bool CopyAndLoad(Stuff::MemoryStream *stream);	// this will make a copy of the data
	};

	#pragma pack( pop, anim_pack)

	inline BYTE
		AnimData::GetJointCount(void)
	{
		return (BYTE)(animJointBlockSize / sizeof(JointAnimData));
	}

	inline int 
		AnimData::GetChannelCount(void)
	{
		return animChannelBlockSize / sizeof(ChannelAnimData);
	}

	inline size_t
		AnimData::GetSize(void)
	{
		return animHeaderBlockSize + 
				animJointBlockSize + 
				animNameBlockSize +
				animKeyBlockSize + 
				animKeyTimeBlockSize +
				animChannelBlockSize + 1; // one is the null byte

	}
	


	int CompressName(const char *source, Stuff::MString &dest);
	int UncompressName(const char *source, Stuff::MString &dest);

}

