//////////////////////////////////////////////////////////////////////
//
//	Crytek Source code 
//	Copyright (c) Crytek 2001-2004
// 
//	File: 
//
//  Description:  
//
//	History:
//
//////////////////////////////////////////////////////////////////////

#ifndef _CRYTEK_CONTROLLER_HEADER_
#define _CRYTEK_CONTROLLER_HEADER_

#include "StringUtils.h"
#include "CryHeaders.h"

//////////////////////////////////////////////////////////////////////////////////////////
// interface IController  
// Describes the position and orientation of an object, changing in time.
// Responsible for loading itself from a binary file, calculations
//////////////////////////////////////////////////////////////////////////////////////////
class IController: public _reference_target_t
{
public:

	// each controller has an ID, by which it is identifiable
	virtual unsigned GetID () const = 0;

	// returns the orientation of the controller at the given time
	virtual CryQuat GetOrientation (float t) = 0;

	// returns the orientation of the controller at the given time, in logarithmic space
	virtual Vec3 GetOrientation2 (float t) = 0;

	// returns position of the controller at the given time
	virtual Vec3 GetPosition (float t) = 0;

	// returns scale of the controller at the given time
	virtual Vec3 GetScale (float t) = 0;
	
	// retrieves the position and orientation within one call
	// may be optimal in some applications
	virtual void GetValue (float t, CryQuat& q, Vec3 &p) = 0;

	// retrieves the position and orientation (in the logarithmic space, i.e. instead of quaternion, its logarithm is returned)
	// may be optimal for motion interpolation
	struct PQLog
	{
		Vec3 vPos;
		Vec3 vRotLog; // logarithm of the rotation

		string toString()const {return "{pos:" + CryStringUtils::toString(vPos)+", rot="+CryStringUtils::toString (vRotLog) + "}";}

		// returns the rotation quaternion
		CryQuat getOrientation()const;
		// resets the state to zero
		void reset ();
		// blends the pqSource[0] and pqSource[1] with weights 1-fBlend and fBlend into pqResult
		void blendPQ (const PQLog* pqSource, float fBlend);
		// blends the pqFrom and pqTo with weights 1-fBlend and fBlend into pqResult
		void blendPQ (const PQLog& pqFrom, const PQLog& pqTo, float fBlend);
		// builds the matrix out of the position and orientation stored in this PQLog
		void buildMatrix(Matrix44& mat)const;
		// a special version of the buildMatrix that adds a rotation to the rotation of this PQLog
		void buildMatrixPlusRot(Matrix44& mat, const CryQuat& qRotPlus) const;
		// returns the equivalent rotation in logarithmic space (the quaternion of which is negative the original)
		Vec3 getComplementaryRotLog() const;
		// constructs the position/rotation from the given matrix
		void assignFromMatrix (const Matrix44& mat);

		PQLog operator * (float f)const
		{
			PQLog res;
			res.vPos = this->vPos * f;
			res.vRotLog = this->vRotLog * f;
			return res;
		}

		const PQLog& operator += (const PQLog& pq)
		{
			this->vPos += pq.vPos;
			this->vRotLog += pq.vRotLog;
			return *this;
		}
	};
	virtual void GetValue2 (float t, PQLog& pq) = 0;

	// returns the start time
	virtual float GetTimeStart () = 0;

	// returns the end time
	virtual float GetTimeEnd() = 0;

	virtual size_t sizeofThis () const = 0;

	virtual bool IsLooping() const { return false; };
};

TYPEDEF_AUTOPTR(IController);
//typedef IController*IController_AutoPtr;

// adjusts the rotation of these PQs: if necessary, flips them or one of them (effectively NOT changing the whole rotation,but
// changing the rotation angle to Pi-X and flipping the rotation axis simultaneously)
// this is needed for blending between animations represented by quaternions rotated by ~PI in quaternion space
// (and thus ~2*PI in real space)
extern void AdjustLogRotations (Vec3& vRotLog1, Vec3& vRotLog2);
extern void AdjustLogRotationTo (const Vec3& vRotLog1, Vec3& vRotLog2);
extern void AdjustLogRotation(Vec3& vRotLog);


//////////////////////////////////////////////////////////////////////////
// This class is a non-trivial predicate used for sorting an
// ARRAY OF smart POINTERS  to IController's. That's why I need a separate
// predicate class for that. Also, to avoid multiplying predicate classes,
// there are a couple of functions that are also used to find a IController
// in a sorted by ID array of IController* pointers, passing only ID to the
// lower_bound function instead of creating and passing a dummy IController*
class AnimCtrlSortPred
{
public:
	bool operator() (const IController_AutoPtr& a, const IController_AutoPtr& b) {assert (a!=(IController*)NULL && b != (IController*)NULL); return a->GetID() < b->GetID();}
	bool operator() (const IController_AutoPtr& a, unsigned nID) {assert (a != (IController*)NULL);return a->GetID() < nID;}
};


#endif