///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	This file contains the controller-related exported structures.
 *	\file		FLX_AddController.h
 *	\author		Pierre Terdiman
 *	\date		April, 4, 2000
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __FLX_ADDCONTROLLER_H__
#define __FLX_ADDCONTROLLER_H__

	class Key
	{
		public:
		// Constructor/Destructor
										Key()	{ mTime=0; mFlags=0;	}
										~Key()	{}

				sdword					mTime;
				udword					mFlags;
	};

	// TCB keys
	class TCBKey : public Key
	{
		public:
		// Constructor/Destructor
										TCBKey()	{}
										~TCBKey()	{}

				float					mTens;
				float					mCont;
				float					mBias;
				float					mEaseIn;
				float					mEaseOut;
	};

	class TCBFloatKey : public TCBKey
	{
		public:
		// Constructor/Destructor
										TCBFloatKey()	{}
										~TCBFloatKey()	{}

				float					mVal;
	};

	class TCBPointKey : public TCBKey
	{
		public:
		// Constructor/Destructor
										TCBPointKey()	{}
										~TCBPointKey()	{}

				MAXPoint				mVal;		
	};

	class TCBRotKey : public TCBKey
	{
		public:
		// Constructor/Destructor
										TCBRotKey()		{}
										~TCBRotKey()	{}

				MAXQuat					mVal;
	};




	enum ControllerType{
		CTRL_UNKNOWN		= 0,			//!< Unknown type
		CTRL_FLOAT			= 1,			//!< A single float value
		CTRL_VECTOR			= 2,			//!< A point/vector (x,y,z, 3 floats)
		CTRL_QUAT			= 3,			//!< A quaternion (x,y,z,w, 4 floats)
		CTRL_PR				= 4,			//!< A PR structure (Position, Rotation = vector, quat = 7 floats)
		CTRL_PRS			= 5,			//!< A PRS structure (Position, Rotation, Scale = vector, quat, vector = 10 floats)
		CTRL_VERTEXCLOUD	= 6,			//!< A list of vectors
		CTRL_FORCE_DWORD	= 0x7fffffff
	};

	// Handy helper structures.
	struct CtrlFloat	{ float Value;									};
	struct CtrlVector	{ float x, y, z;								};
	struct CtrlQuat		{ float x, y, z, w;								};
	struct CtrlPR		{ float tx, ty, tz, qx, qy, qz, qw;				};
	struct CtrlPRS		{ float tx, ty, tz, qx, qy, qz, qw, sx, sy, sz;	};

	enum ControllerMode{
		CTRL_SAMPLES		= 1,			//!< Sampling mode
		CTRL_KEYFRAMES		= 2,			//!< Keyframing mode
		CTRL_DWORD			= 0x7fffffff
	};

	enum InterpScheme{
		SCHEME_UNKNOWN		= 0,			//!< Unknown interpolation scheme
		SCHEME_LINEAR		= 1,			//!< Linear interpolation
		SCHEME_TCB			= 2,			//!< TCB interpolation
		SCHEME_BEZIER		= 3,			//!< Bezier interpolation
		SCHEME_FORCE_DWORD	= 0x7fffffff
	};

	// ControllerData: this is the base class for all controlled values.
	// The base information is:
	// - the ControllerType, which gives the type of data beeing controlled (from a single float to a vertex cloud)
	// - the ControllerMode, which gives the way the type is beeing controlled (by keyframes? Samples?)

	struct ControllerDataCreate
	{
		ControllerType		Type;
		ControllerMode		Mode;
	};

	// Base class
	class ControllerData
	{
		public:
		// Constructor/Destructor
										ControllerData();
		virtual							~ControllerData();

		// Initialize
		virtual	bool					Init(ControllerDataCreate* create)	= 0;

		public:
				ControllerType			mType;					//!< Type of data handled by the controller
				ControllerMode			mMode;					//!< Data are saved as samples, keyframes, etc
				udword					mFlags;					//!< Possible flags [not used yet]
	};

	// SampleData: this is the class to handle sampled data.
	// The extra information is:
	// - NbSamples, which gives the number of samples (one sample beeing one 'type' value. Ex: a Vector is 3 floats, but still one sample)
	// - the sampling rate

	struct SampleDataCreate : ControllerDataCreate
	{
		udword				NbSamples;
		udword				SamplingRate;
	};

	// A sample container.
	class SampleData : public ControllerData
	{
		public:
		// Constructor/Destructor

										SampleData();
		virtual							~SampleData();

		virtual			bool			Init(ControllerDataCreate* create);

		public:
						udword			mNbSamples;				//!< Number of samples
						udword			mSamplingRate;			//!< Sampling rate
						void*			mSamples;				//!< List of mNbSamples samples, whose type is mType
	};

	// KeyframeData: this is the class to handle keyframed data
	// The extra information is:
	// - the number of keyframes
	// - the interpolation scheme

	struct KeyframeDataCreate : ControllerDataCreate
	{
		udword				NbKeyframes;
		InterpScheme		Scheme;
	};

	// A keyframe container.
	class KeyframeData : public ControllerData
	{
		public:
		// Constructor/Destructor

										KeyframeData();
		virtual							~KeyframeData();

		virtual			bool			Init(ControllerDataCreate* create);

		public:
						udword			mNbKeyframes;			//!< Number of keyframes
						InterpScheme	mScheme;				//!< Interpolation scheme
						void*			mKeyframes;				//!< List of mNbKeyframes keyframes, whose type is mType
	};

	// MorphData: this is the class to handle morphing data.
	// Morphing is handled by sampling only, since individual vertex transformations may not be trivial, and different for each vertex.
	// The extra information is just the number of controlled vertices. One sample here is a list of NbVertices vectors.

	struct MorphDataCreate : SampleDataCreate
	{
		udword				NbVertices;
	};

	// Morphing data
	class MorphData : public SampleData
	{
		public:
		// Constructor/Destructor

										MorphData();
		virtual							~MorphData();

		virtual			bool			Init(ControllerDataCreate* create);

		public:
						udword			mNbVertices;			//!< Number of morphed vertices
	};

	//! The controller information class.
	class ControllerDescriptor
	{
		public:
		// Constructor/Destructor
										ControllerDescriptor();
		virtual							~ControllerDescriptor();

		// Database management
						String			mField;					//!< Controlled field
						sdword			mObjectID;				//!< Controller's ID
						sdword			mOwnerID;				//!< Owner object's ID
						ObjType			mOwnerType;				//!< Owner object's type
		// NB: that way I added the animation controllers without breaking the old format.

		// Animation data
						ControllerData*	mData;					//!< Actual animation data
	};

	ControllerType	GetControllerType(udword ctrlid);
	InterpScheme	GetControllerScheme(udword ctrlid);

#endif // __FLX_ADDCONTROLLER_H__
