/************************************************************************************
	ISL PSX LIBRARY	(c) 1999 Interactive Studios Ltd.

	actor.h			Skinned model control routines

************************************************************************************/


#ifndef __ACTOR_H__
#define __ACTOR_H__

#define ANIM_MAX_QUEUE_SIZE			(8)
#define ANIMSHIFT					(8)

// actorAnimate return codes

// OK
#define ANIMATE_OK					(0)

// all these not OK
#define ANIMATE_STILLBLENDING		(1)
#define ANIMATE_NOANIMATIONS		(2)
#define ANIMATE_INVALIDANIMATION	(3)
#define ANIMATE_QUEUEFULL			(4)


#define ACTORFRAME_BADRANGE			(-1)
#define ACTORFRAME_AT				(0)
#define ACTORFRAME_BEFORE			(1)
#define ACTORFRAME_AFTER			(2)


typedef struct
{
	int scaledStartFrame;
	int scaledAnimLength;
	int actualStartFrame;
	int actualAnimLength;
}ANIM_SEGMENT;

typedef struct
{
	short		segment;			// CPW: current animation segment (-1 if none)
	short		speed;				// CPW: anim frames per poll (*256)
	long		scaledFrameOffset;	// CPW: offset of current anim frame (*256)
	short		actualFrame;		// CPW: actual frame number, segment start having been added
	short		loop;				// CPW: loop this animation
	short		reachedEnd;			// CPW: flags whether or not we've reached the end of this anim
	short		pad;
}ANIM_DATA;

typedef struct
{
// CPW: 	short		blendEnable;		// CPW: allow blending to take place
	short		blendCounter;		// CPW: 0 = fully old anim, 4096 = fully current (new) anim
	short		endOfCurrentAnim;	// CPW: current (new) anim has finished playing
	short		numSegments;		// CPW: number of animation ranges in model
	short		blendSpeed;			// CPW: blend speed
	short		numFrames;			// CPW: total number of frames
	short		queueSize;			// CPW: number of items in queue
	ANIM_SEGMENT	*pSegments;		// CPW: list of animation segment info, first & last frame, etc

	PSIOBJECT	*throw_root;
	short		throwCounter;
	short		throwSegStart;
	short		throwSegLen;

	// CPW: subscripts:	0 = current
	// CPW: 			1 = old
	ANIM_DATA	animData[2];
	ANIM_DATA	animQueue[ANIM_MAX_QUEUE_SIZE];
}ANIM_ANIMATION;

/*
// Actor animation data structure
typedef struct
{
	short		numAnimations;
	short		currentAnimation;
	short		oldAnimation;
	short		pad;

	UBYTE		reachedEndOfAnimation;
	UBYTE		loopAnimation;
	short 		numberQueued;

	long		animationSpeed;
	long		oldAnimationSpeed;

	short		queueAnimation[ANIM_QUEUE_LENGTH];
	UBYTE		queueLoopAnimation[ANIM_QUEUE_LENGTH];
	long		queueAnimationSpeed[ANIM_QUEUE_LENGTH];
	long		animTime;
	long		baseTime;	// CPW:
	long		oldTime;	// CPW:

	short		frame;
	UBYTE 		exclusive;
	UBYTE 		blendEnable;

	int			blendCounter;
} ACTOR_ANIMATION;
*/

// bounding box data structure
typedef struct
{

	long	minX,maxX;
	long	minY,maxY;
	long	minZ,maxZ;

} BOUNDINGBOX;


// Actor data structure
typedef struct _ACTOR
{

	struct _ACTOR	*next,*prev;
// CPW: 	USHORT			animFrames;				// number of animation frames
// CPW: 	USHORT			*animSegments;			// list of start-end frames (shorts)
// CPW: 	ACTOR_ANIMATION	animation;
	ANIM_ANIMATION	animation;
	VECTOR			oldPosition;	//
	VECTOR			accumulator;	// for animation movement;
	VECTOR			position;		// real position
   	VECTOR			size;
	ULONG			radius;
	BOUNDINGBOX		bounding;
	PSIDATA			psiData;

} ACTOR;


typedef struct
{
	short animStart;
	short animEnd;
} ANIMATION;

// CPW: added by chris
typedef struct tagOVERRIDE
{
	PSIOBJECT	*pPSI;
	MATRIX		matrix;
}OVERRIDE;


// linked list of actors
typedef struct 
{

	ACTOR	head;
	int	 	numEntries;

}	ACTORLIST;

extern ACTORLIST	actorList;


// macros

// return TRUE if still blending
#define actorBlending(A)				(A->animation.blendCounter!=-1)
#define actorReachedEndOfAnimation(A)	(A->animation.reachedEndOfAnimation)

// functions


void actorInitialise();

void actorAdd(ACTOR *actor);

void actorSub(ACTOR *actor);

void actorFree(ACTOR *actor);

ACTOR *actorCreate(PSIMODEL *psiModel);

void actorInitAnim(ACTOR *actor);

void actorFlushQueue(ACTOR *actor);

void actorMaintainAnimation(ACTOR *pActor);

void actorSetAnimSpeed(ACTOR *pActor, int speed);

void actorAdjustPosition(ACTOR *actor);

// queue = 0 for play right now, and delete all queued stuff
// queue = 1 for queue the anim
// queue = 2 for play right now, but leave the queue intact (used when the queue itself wants to start the int actorAnimate(ACTOR *pActor, int animNum, char loop, char queue, int actualSpeed, char skipendframe, int blend)
int actorAnimate(ACTOR *actor, int animNum, char loop, char queue, int speed, char offset, int blend);

void actorSetAnimationSpeed(ACTOR *actor, int speed);

void actorUpdateAnimations(ACTOR *actor);

void actorDrawAll();

void actorMove(ACTOR *actor);

void actorDraw(ACTOR *actor);

void actorDraw2(ACTOR *actor);

void actorDrawBones(ACTOR *actor);

void actorRotate(short angx, short angy, short angz, long movex, long movey, long movez, VECTOR *result);

void actorSetAnimation(ACTOR *actor, ULONG frame);

void actorSetAnimation2(ACTOR *actor, ULONG frame0, ULONG frame1, ULONG blend);

int actorCalcSegments(ACTOR *actor);

void actorSetBoundingRotated(ACTOR *actor,int frame,int rotX,int rotY, int rotZ);

void actorSetBounding(ACTOR *actor,int frame);

UBYTE actorIsVisible(ACTOR *actor);

int actorNearEndOfAnimation(ACTOR *, int, int);

int actorReachedFrame(ACTOR *pActor, int animRange, int checkFrame);
int actorReachedFrameRatio(ACTOR *pActor, int animRange, int checkRatio);

#define ACTORGETANIMFRAMESTART(actor,anim)	(actor)->animSegments[ (anim)*2]

#define ACTORGETANIMFRAMEEND(actor,anim)		(actor)->animSegments[((anim)*2)+1]

void actorGetBonePosition(ACTOR *actor, PSIOBJECT *obj, int frame, VECTOR *pos);

void actorSetupForThrowing(ACTOR *actor, PSIOBJECT *throw_root, int anim_segment);
void actorStartThrow(ACTOR *actor);

#endif //__ACTOR_H__
