/* ***********************************************************************************/
/* * "a3x_intn.c"																	**/
/* * Written by :	Sébastien Rubens												**/
/* * Tabulations :	4 char															**/
/* ***********************************************************************************/
#define	A3X_INTN_C
 
 
 
/* ***********************************************************************************/
/*																	Included files*/
 
#include <math.h>
 
/*#define LST2_StaticIsOptimised*/
#include "ACP_Base.h"
#include "cpa_std.h"
#include "TOOLSCPA.h"
 
#include "STRUCTUR/Anim_s.h"
#define D_ObjsTbls_Define
#include "STRUCTUR/ObjsTbls.h"
#include "MTH.h"
#include "POS.h"
#include "PlayAnim/Interpol/specif/a3x_pref.h"
#include "chanlist.h"
#include "PlayAnim/Interpol/a3x_glob.h"
#include "PlayAnim/Interpol/a3x_int.h"
#include "PlayAnim/Interpol/a3x_intn.h"
#include "PlayAnim/Interpol/a3x_mem.h"
#include "PlayAnim/Interpol/a3x_cach.h"
#include "PlayAnim/PlayEvts.h"
 
/* for allocation*/
#include "ZeMem.h"
#define	M_Abs( x )			\
	( ((x) > xZero) ? (x) : -(x) )              
 
/* temp*/
extern SEB_xReal xEps;
extern SEB_xReal xOneSubEps;
 
/*AR9902 To be cleaned...*/
extern tdstA3dHeader* p_stA3dHeaders;
 
/* ***********************************************************************************/
void	fn_v_InterpolBetweenKeys(	tdstKeyFrame			*_p_stKey1,
									tdstKeyFrame			*_p_stKey2,
									tdstChannel				*_p_stChannel,
									POS_tdxHandleToPosition	_p_stCompletePosition,
									register unsigned short	_uwInterpolated,
									register SEB_xReal		_xT	)
{	tdxMatrix33				a3a3_xMtxOri, a3a3_xMtxTra;
	tdxVector3				a3_xPosition;
	static tdxQuater4		a4_xQuatI, a4_xQuatS1, a4_xQuatS2;
	static tdxMatrix33		a3a3_xMtxOriSca, a3a3_xMtxSca;
	static tdxVector3		a3_xVecSca;
	register SEB_xReal		xSinOmega;
	register SEB_xReal		xCoef1, xCoef2;
/*	register SEB_xReal		xOmega, xCosOmega, xTbyOmega;*/
	register tdxVector3		*p_Vect1, *p_Vect2;
	register signed short	swOmega, swCosOmega, swTbyOmega;
 
#ifdef ANIM_DEBUG
	if(_p_stCompletePosition==NULL)
	{
		osSyncPrintf("Position is null in fn_v_InterpolBetweenKeys\n");
		ASM_BREAK;
	}
#endif
 
	POS_fn_vSetIdentityMatrix(_p_stCompletePosition);
 
	MTH3D_M_vSetIdentityMatrix((MTH3D_tdstMatrix*)&a3a3_xMtxOri);
	MTH3D_M_vSetIdentityMatrix((MTH3D_tdstMatrix*)&a3a3_xMtxTra);
	MTH3D_M_vNullVector((MTH3D_tdstVector*)&a3_xPosition);
 
 
	/* -- Interpolation of orientation -------*/
	if	( (_xT == xZero) || ((_p_stKey1->uwMask & SEB_xMaskQuatOri) != 0x0000) )
	{	/* We are on the first KeyFrame or we have a non interpolated quaternion*/
		if	((_p_stKey1->uwMask & SEB_xMaskIdQuatOri) == 0x0000)
		{	/* Copy of first (KeyFrame) quaternion*/
			fn_v_ExpandQuat( a4_xQuatI, p_a4_xQuaternions[_p_stKey1->uwNumOfQuatOri] );
			fn_v_QuatToMatrix( a3a3_xMtxOri, a4_xQuatI );
			POS_fn_vSetRotationMatrix( _p_stCompletePosition , (MTH3D_tdstVector*)a3a3_xMtxOri[0], (MTH3D_tdstVector*)a3a3_xMtxOri[1] , (MTH3D_tdstVector*)a3a3_xMtxOri[2] );
		}
	}
	else
	{	/* Interpolation of orientation*/
		fn_v_ExpandQuat( a4_xQuatS1, p_a4_xQuaternions[_p_stKey1->uwNumOfQuatOri] );
		fn_v_ExpandQuat( a4_xQuatS2, p_a4_xQuaternions[_p_stKey2->uwNumOfQuatOri] );
		fn_v_InterpolQuatWithOmega( a4_xQuatI, a4_xQuatS1, a4_xQuatS2, _xT, _p_stKey1->uwAngQuatOri );
		fn_v_QuatToMatrix( a3a3_xMtxOri, a4_xQuatI );
		POS_fn_vSetRotationMatrix( _p_stCompletePosition , (MTH3D_tdstVector*)a3a3_xMtxOri[0], (MTH3D_tdstVector*)a3a3_xMtxOri[1] , (MTH3D_tdstVector*)a3a3_xMtxOri[2] );
	}
 
	/* -- Linear interpolation of ScaleValues -------*/
	if	(	((_p_stKey1->uwMask & (SEB_xMaskScaleValues|SEB_xMaskIdScaleValues)) == (SEB_xMaskScaleValues|SEB_xMaskIdScaleValues))
		||	((_xT==xZero) && ((_p_stKey1->uwMask & SEB_xMaskIdScaleValues) != 0x0000)) )
	{	/* Identity vector (we don't use scale)*/
		MTH3D_M_vCopyMatrix((MTH3D_tdstMatrix*)&a3a3_xMtxTra,(MTH3D_tdstMatrix*)&a3a3_xMtxOri);
	}
	/*else we have a non "identity" scale vector*/
 
 
	/* -- Interpolation of whole scale -------*/
	/* -- and creation of TransformMatrix -------*/
	else
	{	/* Interpolated of ScaleValues*/
		fn_v_InterpolVect( a3_xVecSca,	p_a3_xVectors[_p_stKey1->uwNumOfScaleValues],
										p_a3_xVectors[_p_stKey2->uwNumOfScaleValues], _xT );
 
		if	( (_xT == xZero) || ((_p_stKey1->uwMask & SEB_xMaskQuatSca) != 0x0000) )
		{	/* We are on the first KeyFrame or we have a non interpolated quaternion*/
			if	((_p_stKey1->uwMask & SEB_xMaskIdQuatSca) != 0x0000)
			{	/* Identity quaternion*/
				/* Create final Transform matrix*/
				/* Final matrix= [scale dir. matrix]*[values scale matrix]*[scale dir. matrix]^-1*/
				if(MTH_M_bEqualWithEpsilon(a3_xVecSca[0],a3_xVecSca[1],MTH_M_xFloatToReal(0.01)) &&
				   MTH_M_bEqualWithEpsilon(a3_xVecSca[0],a3_xVecSca[2],MTH_M_xFloatToReal(0.01)))
				{
					POS_fn_vSetZoomMatrix( _p_stCompletePosition , (MTH_tdxReal)a3_xVecSca[0] );
					POS_fn_vGetTransformMatrix( _p_stCompletePosition , (MTH3D_tdstVector*)a3a3_xMtxTra[0], (MTH3D_tdstVector*)a3a3_xMtxTra[1] , (MTH3D_tdstVector*)a3a3_xMtxTra[2] );
				}
				else
				{
					fn_v_MatrixByDia( a3a3_xMtxTra, a3a3_xMtxOri, a3_xVecSca );
					POS_fn_vSetTransformMatrix( _p_stCompletePosition , (MTH3D_tdstVector*)a3a3_xMtxTra[0], (MTH3D_tdstVector*)a3a3_xMtxTra[1] , (MTH3D_tdstVector*)a3a3_xMtxTra[2] );
				}
			}
			else
			{	/* Copy of first (KeyFrame) quaternion*/
				fn_v_ExpandQuat( a4_xQuatI, p_a4_xQuaternions[_p_stKey1->uwNumOfQuatSca] );
				fn_v_QuatToMatrix( a3a3_xMtxOriSca, a4_xQuatI );
 
				/* Create final scale matrix*/
				/* Final matrix= [scale dir. matrix]*[values scale matrix]*[scale dir. matrix]^-1*/
				if(MTH_M_bEqualWithEpsilon(a3_xVecSca[0],a3_xVecSca[1],MTH_M_xFloatToReal(0.01)) &&
				   MTH_M_bEqualWithEpsilon(a3_xVecSca[0],a3_xVecSca[2],MTH_M_xFloatToReal(0.01)))
				{
					POS_fn_vSetZoomMatrix( _p_stCompletePosition , (MTH_tdxReal)a3_xVecSca[0] );
					POS_fn_vGetTransformMatrix( _p_stCompletePosition , (MTH3D_tdstVector*)a3a3_xMtxTra[0], (MTH3D_tdstVector*)a3a3_xMtxTra[1] , (MTH3D_tdstVector*)a3a3_xMtxTra[2] );
				}
				else
				{
					fn_v_InvRotDiaRot( a3a3_xMtxSca, a3a3_xMtxOriSca, a3_xVecSca );
 
					/* Create final Transform matrix*/
					fn_v_MultMatrix( a3a3_xMtxTra, a3a3_xMtxOri, a3a3_xMtxSca );
					POS_fn_vSetTransformMatrix( _p_stCompletePosition , (MTH3D_tdstVector*)a3a3_xMtxTra[0], (MTH3D_tdstVector*)a3a3_xMtxTra[1] , (MTH3D_tdstVector*)a3a3_xMtxTra[2] );
				}
			}
		}
		else
		{	/* Interpolation of scale direction*/
			fn_v_ExpandQuat( a4_xQuatS1, p_a4_xQuaternions[_p_stKey1->uwNumOfQuatSca] );
			fn_v_ExpandQuat( a4_xQuatS2, p_a4_xQuaternions[_p_stKey2->uwNumOfQuatSca] );
			fn_v_InterpolQuatWithOmega( a4_xQuatI, a4_xQuatS1, a4_xQuatS2, _xT, _p_stKey1->uwAngQuatSca );
			fn_v_QuatToMatrix( a3a3_xMtxOriSca, a4_xQuatI );
 
			/* Create final scale matrix*/
			/* Final matrix= [scale dir. matrix]*[values scale matrix]*[scale dir. matrix]^-1*/
			if(MTH_M_bEqualWithEpsilon(a3_xVecSca[0],a3_xVecSca[1],MTH_M_xFloatToReal(0.01)) &&
			   MTH_M_bEqualWithEpsilon(a3_xVecSca[0],a3_xVecSca[2],MTH_M_xFloatToReal(0.01)))
			{
				POS_fn_vSetZoomMatrix( _p_stCompletePosition , (MTH_tdxReal)a3_xVecSca[0] );
				POS_fn_vGetTransformMatrix( _p_stCompletePosition , (MTH3D_tdstVector*)a3a3_xMtxTra[0], (MTH3D_tdstVector*)a3a3_xMtxTra[1] , (MTH3D_tdstVector*)a3a3_xMtxTra[2] );
			}
			else
			{
				fn_v_InvRotDiaRot( a3a3_xMtxSca, a3a3_xMtxOriSca, a3_xVecSca );
 
				/* Create final Transform matrix*/
				fn_v_MultMatrix( a3a3_xMtxTra, a3a3_xMtxOri, a3a3_xMtxSca );
				POS_fn_vSetTransformMatrix( _p_stCompletePosition , (MTH3D_tdstVector*)a3a3_xMtxTra[0], (MTH3D_tdstVector*)a3a3_xMtxTra[1] , (MTH3D_tdstVector*)a3a3_xMtxTra[2] );
			}
		}
	}
 
 
	/* -- Interpolation of position -------*/
	if	( (_xT == xZero) || (_p_stKey1->uwMask & SEB_xMaskPosition) != 0x0000 )
	{	register SEB_xReal	r_xDistMaster;
 
		p_Vect1=	&p_a3_xVectors[_p_stKey1->uwNumOfPosition];
		r_xDistMaster=	_p_stKey1->xDistMaster;
		a3_xPosition[0]=	(*p_Vect1)[0] * r_xDistMaster;
		a3_xPosition[1]=	(*p_Vect1)[1] * r_xDistMaster;
		a3_xPosition[2]=	(*p_Vect1)[2] * r_xDistMaster;
		POS_fn_vSetTranslationVector( _p_stCompletePosition , (MTH3D_tdstVector*)a3_xPosition );
	}
	else
	{
		if	( _uwInterpolated == 0x0000 )
		{
		/* Interpolation with the pivot*/
			/* Rotate pivot (local to object)*/
			fn_v_MatrixByVector( a3_xVecSca, a3a3_xMtxTra, p_a3_xVectors[_p_stChannel->uwNumOfLocalPivotPos] );
 
			/* Pivot (linear) interpolation in world axes*/
			fn_v_InterpolVect( a3_xPosition, _p_stKey1->a3_xWorldPivotPosition, _p_stKey2->a3_xWorldPivotPosition, _xT );
 
			/* Computes the interpolated position*/
			a3_xPosition[0]-=	a3_xVecSca[0];
			a3_xPosition[1]-=	a3_xVecSca[1];
			a3_xPosition[2]-=	a3_xVecSca[2];
			POS_fn_vSetTranslationVector( _p_stCompletePosition , (MTH3D_tdstVector*)a3_xPosition );
		}
		else
		{
		/* Interpolation with Hierarchy*/
			if	( (_p_stKey1->xDistMaster > xEps) || (_p_stKey2->xDistMaster > xEps) )
			{
				p_Vect1=	&p_a3_xVectors[_p_stKey1->uwNumOfPosition];
 
				if	((_p_stKey1->uwMask & SEB_xMaskZeroAngCentre) != 0x0000)
				{
					/* Linear interpolation of vector length*/
					xCoef1=	( _p_stKey2->xDistMaster - _p_stKey1->xDistMaster ) * _xT
							+ _p_stKey1->xDistMaster;
 
					/* Computes the interpolated position*/
					a3_xPosition[0]=	xCoef1 * (*p_Vect1)[0];
					a3_xPosition[1]=	xCoef1 * (*p_Vect1)[1];
					a3_xPosition[2]=	xCoef1 * (*p_Vect1)[2];
					POS_fn_vSetTranslationVector( _p_stCompletePosition , (MTH3D_tdstVector*)a3_xPosition );
				}
				else
				{
					p_Vect2=	&p_a3_xVectors[_p_stKey2->uwNumOfPosition];
					swOmega=	_p_stKey1->uwAngObjCentre;
 
					/* Computes values for "Geodesic" interpolation*/
					swCosOmega=	ax_SinTab[ swOmega ];
					if	( swCosOmega != 0 )
					{	xSinOmega=	xOne / swCosOmega;
						swTbyOmega=	(signed short) (_xT * swOmega);		/* Always 0 < slTbyOmega < _slOmega*/
						xCoef1=		ax_SinTab[ swOmega - swTbyOmega ] * xSinOmega;
						xCoef2=		ax_SinTab[ swTbyOmega ] * xSinOmega;
					}
					else
					{	xCoef1=		xOne - _xT;
						xCoef2=		_xT;
					}
 
					/* Linear interpolation of vector length*/
					xSinOmega=	( _p_stKey2->xDistMaster - _p_stKey1->xDistMaster ) * _xT
								+ _p_stKey1->xDistMaster;
					xCoef1*=	xSinOmega;
					xCoef2*=	xSinOmega;
 
					/* Computes the interpolated position*/
					a3_xPosition[0]=	xCoef1 * (*p_Vect1)[0] + xCoef2 * (*p_Vect2)[0];
					a3_xPosition[1]=	xCoef1 * (*p_Vect1)[1] + xCoef2 * (*p_Vect2)[1];
					a3_xPosition[2]=	xCoef1 * (*p_Vect1)[2] + xCoef2 * (*p_Vect2)[2];
					POS_fn_vSetTranslationVector( _p_stCompletePosition , (MTH3D_tdstVector*)a3_xPosition );
				}
			}
		}
	}
}
 
 
 
/* ***********************************************************************************/
#ifdef	A3X_CUT
unsigned short	fn_uw_GetNumOfA3dGENERAL(	unsigned short	_uwNumOfA3dGENERAL,
											unsigned short	_uwT )
{	register unsigned short	uwNumOfA3dGENERAL;
 
	uwNumOfA3dGENERAL=	_uwNumOfA3dGENERAL;
	while	( _uwT >= p_stCuttedAnim[uwNumOfA3dGENERAL].uwEndFrame )
	{	uwNumOfA3dGENERAL=							p_stCuttedAnim[uwNumOfA3dGENERAL].uwNextAnim;
 
		if	(uwNumOfA3dGENERAL == 0xFFFF)
		{
#ifdef ANIM_DEBUG
			osSyncPrintf("Cut anim not found\n");
			osSyncPrintf("Anim = %d, Frame = %d\n",_uwNumOfA3dGENERAL,_uwT);
			ASM_BREAK; /* temporary*/
#endif
			return	0xFFFF;
		}
	}
	p_uwLastA3dGENERAL[_uwNumOfA3dGENERAL]=		uwNumOfA3dGENERAL;
	return	uwNumOfA3dGENERAL;
}
#endif
 
 
/* ***********************************************************************************/
tdstEvent	*fn_p_GetEventsAddress(	tdstAnim3d		*_p_stAnim3d,
									unsigned long	_ulFrame,
									tdxHandleToObjectsTablesList _h_ObjectsTablesListElement)
{
#ifdef U64
	int i;
	tdstEvent * p_stEvent, * p_stEventNeverPlay;
 
	if	( _p_stAnim3d->uwNumOfA3dGENERAL != C_uwAnimNotInterpolated )
	{	/* Animation is a interpolated animation*/
	
			/* Set Events*/
		if	( _p_stAnim3d->ucNumberOfEvents == 0 )
				_p_stAnim3d->d_stAnimEvent=	NULL;
		else
		{	tdstA3dGENERAL	*p_stCurrentA3dGENERAL;
 
#ifndef FORCE_REAL_TIME_LOAD
			if(g_bRealTimeAnimationLoad)
#endif
				p_stCurrentA3dGENERAL=	fn_p_GetA3dGENERAL(p_uwLastA3dGENERAL[_p_stAnim3d->uwNumOfA3dGENERAL], _ulFrame);
#ifndef FORCE_REAL_TIME_LOAD
			else
				p_stCurrentA3dGENERAL=	fn_p_GetA3dGENERAL(_p_stAnim3d->uwNumOfA3dGENERAL, _ulFrame );
#endif
 
			_p_stAnim3d->d_stAnimEvent=	&p_stEvents[ p_stCurrentA3dGENERAL->uwNumOfFirstEvent ];
				
			/* Update event pointer with sort*/
			for(i=0,p_stEvent=NULL,p_stEventNeverPlay=_p_stAnim3d->d_stAnimEvent;i<_p_stAnim3d->ucNumberOfEvents;++i,p_stEventNeverPlay++) 
			{
				if(p_stEventNeverPlay->p_stfEventInTBL==NULL)
				{
					/* set the tbl event*/
					p_stEventNeverPlay->p_stfEventInTBL=
						(tdstEventInTable*)_h_ObjectsTablesListElement->d_stObjectsTable[p_stEventNeverPlay->usEventNumberInTBL].h_Target;
 
					/* found first non never play event*/
#ifdef ANIM_DEBUG
					if(p_stEventNeverPlay->p_stfEventInTBL==NULL)
					{
						osSyncPrintf("Probleme d'evenements : p_stfEventInTBL==NULL\n");
						osSyncPrintf("Anim = %d, Frame = %d, number in table = %d\n",_p_stAnim3d->uwNumOfA3dGENERAL,_ulFrame,p_stEventNeverPlay->usEventNumberInTBL);
					}
#endif
					if (!p_stEvent && (GAM_fn_ucGetFirstCallOfEvent(p_stEventNeverPlay) != C_ucNeverPlay))
						p_stEvent = p_stEventNeverPlay;
			
					/* found a never play */
					else if (GAM_fn_ucGetFirstCallOfEvent(p_stEventNeverPlay) == C_ucNeverPlay) 
					{
						/* set the frame & channel to 0*/
						p_stEventNeverPlay->uwChannelNumber = p_stEventNeverPlay->uwFrameNumber = 0;
 
						/* there is a non never play before*/
						if (p_stEvent) 
						{
							tdstEvent * p_stTmpEvent;
							/* we move up the never play event until the first non never play*/
							for(p_stTmpEvent = p_stEventNeverPlay-1;p_stTmpEvent >= p_stEvent;p_stTmpEvent--) 
							{
								/* permute Event*/
								tdstEvent stEvent = *(p_stTmpEvent+1);
								*(p_stTmpEvent+1) = *p_stTmpEvent;
								*p_stTmpEvent = stEvent;
							}
 
							/* now the fisrt non never play has moved 1 place down*/
							p_stEvent++;
						}
					}
				}
			}
		}
 
	}
#endif /*U64*/
 
	return	_p_stAnim3d->d_stAnimEvent;
}
 
 
 
/* ***********************************************************************************/
void fn_v_CalculateGeneral(tdstAnim3d * _p_stAnim3d,unsigned long _ulFrame ) {
#ifndef FORCE_REAL_TIME_LOAD
	tdstA3dGENERAL		*p_stCurrentA3dGENERAL;
/*	tdxQuater4			a4_xQuat;*/
/*	tdxMatrix33			a3x3_Matrix;*/
 
	if(!g_bRealTimeAnimationLoad)
	{
		p_stCurrentA3dGENERAL =	fn_p_GetA3dGENERAL(_p_stAnim3d->uwNumOfA3dGENERAL,_ulFrame);
		
		_p_stAnim3d->uwNumberOfFrames = p_stCurrentA3dGENERAL->uwNumberOfFrames;
		_p_stAnim3d->ucFrameRate=			(unsigned char) p_stCurrentA3dGENERAL->uwAnimationSpeed;
		_p_stAnim3d->ucMaxNumberOfElements=	(unsigned char) p_stCurrentA3dGENERAL->uwNumberOfChannels;
		_p_stAnim3d->ucNumberOfEvents=		(unsigned char) p_stCurrentA3dGENERAL->uwNumberOfEvents;
		
		if	(	(p_a3_xVectors[p_stCurrentA3dGENERAL->uwNumOfAnimationTranslationOffset][0] != xZero) ||
			(p_a3_xVectors[p_stCurrentA3dGENERAL->uwNumOfAnimationTranslationOffset][1] != xZero) ||
			(p_a3_xVectors[p_stCurrentA3dGENERAL->uwNumOfAnimationTranslationOffset][2] != xZero)
			)
		{
/*			POS_fn_vSetTranslationVector( &(_p_stAnim3d->stOffsetMatrix) , (MTH3D_tdstVector*)p_a3_xVectors[p_stCurrentA3dGENERAL->uwNumOfAnimationTranslationOffset] );*/
			memcpy(&(_p_stAnim3d->stOffsetMatrix),(MTH3D_tdstVector*)p_a3_xVectors[p_stCurrentA3dGENERAL->uwNumOfAnimationTranslationOffset],sizeof(MTH3D_tdstVector));
		}
		else
			memset(&_p_stAnim3d->stOffsetMatrix,0,sizeof(MTH3D_tdstVector)); /*AR9811*/
		
/*		if	(	(p_a4_xQuaternions[p_stCurrentA3dGENERAL->uwNumOfAnimationRotationOffset][0] != 0) ||
			(p_a4_xQuaternions[p_stCurrentA3dGENERAL->uwNumOfAnimationRotationOffset][1] != 0) ||
			(p_a4_xQuaternions[p_stCurrentA3dGENERAL->uwNumOfAnimationRotationOffset][2] != 0) ||
			(p_a4_xQuaternions[p_stCurrentA3dGENERAL->uwNumOfAnimationRotationOffset][3] != lOne)
			)
		{
			fn_v_ExpandQuat(	a4_xQuat, p_a4_xQuaternions[p_stCurrentA3dGENERAL->uwNumOfAnimationRotationOffset] );
			fn_v_QuatToMatrix( a3x3_Matrix , a4_xQuat );
			POS_fn_vSetRotationMatrix( &(_p_stAnim3d->stOffsetMatrix) , (MTH3D_tdstVector*)a3x3_Matrix[0] , (MTH3D_tdstVector*)a3x3_Matrix[1] , (MTH3D_tdstVector*)a3x3_Matrix[2] );
		} */
		
		/* Set Events*/
		if	( _p_stAnim3d->ucNumberOfEvents == 0 )
			_p_stAnim3d->d_stAnimEvent=	NULL;
		else
			_p_stAnim3d->d_stAnimEvent=	&p_stEvents[p_stCurrentA3dGENERAL->uwNumOfFirstEvent];
		
		/* Set Morph table*/
		if	( p_stCurrentA3dGENERAL->uwNumberOfMorphData == 0 )
			_p_stAnim3d->d_stMorphDataArray = NULL;
		else
			_p_stAnim3d->d_stMorphDataArray = &p_stMorphData[p_stCurrentA3dGENERAL->uwNumOfFirstMorphData];
		
	}
	else
	{
#endif
#ifdef	A3X_CUT
		/* If we are in realtime load system, we don't need to load the entire animations, here.*/
		register	tdstShortA3dGENERAL		*p_stShortA3dGENERAL;
		
		p_stShortA3dGENERAL=	fn_p_ReadShortAnimFromROM(_p_stAnim3d->uwNumOfA3dGENERAL);
		
		_p_stAnim3d->uwNumberOfFrames=		p_stShortA3dGENERAL->uwNumberOfFrames;
		_p_stAnim3d->ucFrameRate=			p_stShortA3dGENERAL->uwFrameRate;
		_p_stAnim3d->ucMaxNumberOfElements=	p_stShortA3dGENERAL->uwMaxNumberOfElements;
		_p_stAnim3d->ucNumberOfEvents=		p_stShortA3dGENERAL->uwNumberOfEvents;
		
		if((p_stShortA3dGENERAL->a3_xAnimationTranslationOffset[0] != xZero)||
			(p_stShortA3dGENERAL->a3_xAnimationTranslationOffset[1] != xZero)||
			(p_stShortA3dGENERAL->a3_xAnimationTranslationOffset[2] != xZero))
/*			POS_fn_vSetTranslationVector(&(_p_stAnim3d->stOffsetMatrix) , (MTH3D_tdstVector*)p_stShortA3dGENERAL->a3_xAnimationTranslationOffset );*/
			memcpy(&(_p_stAnim3d->stOffsetMatrix),(MTH3D_tdstVector*)p_stShortA3dGENERAL->a3_xAnimationTranslationOffset,sizeof(MTH3D_tdstVector)); /*AR9811*/
		else
			memset(&_p_stAnim3d->stOffsetMatrix,0,sizeof(MTH3D_tdstVector)); /*AR9811*/

		
/*		if	((p_stShortA3dGENERAL->a4_uwAnimationRotationOffset[0] != 0) ||
			(p_stShortA3dGENERAL->a4_uwAnimationRotationOffset[1] != 0) ||
			(p_stShortA3dGENERAL->a4_uwAnimationRotationOffset[2] != 0) ||
			(p_stShortA3dGENERAL->a4_uwAnimationRotationOffset[3] != lOne)
			)
		{
			fn_v_ExpandQuat(a4_xQuat, p_stShortA3dGENERAL->a4_uwAnimationRotationOffset );
			fn_v_QuatToMatrix( a3x3_Matrix , a4_xQuat );
			POS_fn_vSetRotationMatrix( &(_p_stAnim3d->stOffsetMatrix) , (MTH3D_tdstVector*)a3x3_Matrix[0] , (MTH3D_tdstVector*)a3x3_Matrix[1] , (MTH3D_tdstVector*)a3x3_Matrix[2] );
		} */
		
		/* Set Events*/
		if	( _p_stAnim3d->ucNumberOfEvents == 0 )
			_p_stAnim3d->d_stAnimEvent=	NULL;
		else
			_p_stAnim3d->d_stAnimEvent=	(struct tdstEvent_ *)0xCCCCCCCC; /* Updated later*/
		
		/* Set Morph table*/
		if	( p_stShortA3dGENERAL->uwNumberOfMorphData == 0 )
			_p_stAnim3d->d_stMorphDataArray = NULL;
		else
			_p_stAnim3d->d_stMorphDataArray = (struct stMorphData *)0xCCCCCCCC; /* Updated later*/
#endif
#ifndef FORCE_REAL_TIME_LOAD
	}
#endif
}
 
 
 
/* ****************************************************************** fn_vUpdateFrame*/
/* Update Frame structure if it wasn't - but matrix isn't update*/
/*		Set Linear and Angular Speed (Alloc or Free Matrix)*/
/*		Set Hierarchy*/
/*		Fill Element3D Array : ElementNuber,ElementType,ActiveStatus,ChannelNumber*/
/**/
/* 17/07/98 - Carlos Torres*/
/* ***********************************************************************************/
void fn_vUpdateFrame(void * _p_stSuperObject,tdstFrame3d * _p_stFrame,tdstAnim3d * _p_stAnim3d,unsigned short _uwFrame) 
{
	tdstA3dGENERAL * p_stCurrentA3dGENERAL;
	tdstOnlyFrame * p_stCurrentOnlyFrame;
	tdstChannel * p_stCurrentChannel;
	unsigned short	uwT_NTTO;
	unsigned short uwCnt1,uwNumOfA3dGENERAL;
	tdstElement3d * p_stCurrentElement3d;
	unsigned short uwCorrectedFrame;
	ACP_tdxBool bMustTest=TRUE;
 
	/* AR9902*/
	/* Before returning, we must be sure that the animation is still loaded into the animation cache*/
	/* and that it is loaded into the same cache entry*/
	/* ----------------------------------------------------------------------------------*/
	/* Get A3D General Info*/
#ifdef	A3X_N64
#ifndef FORCE_REAL_TIME_LOAD
	if(g_bRealTimeAnimationLoad)
#endif
		uwNumOfA3dGENERAL=	fn_uw_GetNumOfA3dGENERAL(_p_stAnim3d->uwNumOfA3dGENERAL, _uwFrame);
#ifndef FORCE_REAL_TIME_LOAD
	else
#endif
#endif
#ifndef FORCE_REAL_TIME_LOAD
		uwNumOfA3dGENERAL=	_p_stAnim3d->uwNumOfA3dGENERAL;
#endif
 
#ifdef	A3X_N64
	if((p_stA3dHeaders[uwNumOfA3dGENERAL].uwNumOfCacheEntry == SEB_Invalid)
		||(_p_stFrame->ucCacheEntry!=(unsigned char)p_stA3dHeaders[uwNumOfA3dGENERAL].uwNumOfCacheEntry))
	{	
		/* Animation isn't loaded*/
		/* We must load it and fill again the _p_stFrame because the old values aren't valid anymore*/
		bMustTest=FALSE;
	}
	else
#endif /*A3X_N64*/
		bMustTest=TRUE;
 
	if(bMustTest)
	{
		/* if uwFrame>uwNumberOfFrames, no update*/
		if	( _uwFrame >= _p_stAnim3d->uwNumberOfFrames )
			return; /* Can occur sometimes... AR9808*/
 
		/* check if the frame is already updated*/
		if ((_p_stFrame->p_stAnim == _p_stAnim3d) && (_p_stFrame->uwFrameNumber == _uwFrame))
			return;
	}
	else
	{
		if	( _uwFrame >= _p_stAnim3d->uwNumberOfFrames )
			_uwFrame = ( unsigned short ) ( _p_stAnim3d->uwNumberOfFrames - 1 ) ; /*last valid frame*/
	}
 
	/* ----------------------------------------------------------------------------------*/
	/* set ref of the frame*/
	_p_stFrame->p_stAnim = _p_stAnim3d;
	_p_stFrame->uwFrameNumber = _uwFrame;
	_p_stFrame->ucMatrixUpdated = FALSE;
 
	/* Here, we load the animation in cache again*/
	p_stCurrentA3dGENERAL = fn_p_GetA3dGENERAL(uwNumOfA3dGENERAL,_uwFrame);
	/* ----------------------------------------------------------------------------------*/
	/* check if anim cutting is well done*/
#if defined(A3X_N64) && defined(ANIM_DEBUG)
	if ((_uwFrame < p_stCurrentA3dGENERAL->uwStartFrame) ||
		(_uwFrame >= p_stCurrentA3dGENERAL->uwEndFrame) )
	{
		osSyncPrintf("Probleme decoupage d'animation (anim= %d, Frame= %d, StartFrame= %d, EndFrame= %d)\n", uwNumOfA3dGENERAL, _uwFrame, p_stCurrentA3dGENERAL->uwStartFrame, p_stCurrentA3dGENERAL->uwEndFrame);
		ASM_BREAK;
 
	}
#endif /* ANIM_DEBUG */
 
#ifdef	A3X_N64
	if(!bMustTest)
	{
		/*Here, the anim has been loaded and we can updade the number of the cache entry into the frame structure*/
		_p_stFrame->ucCacheEntry=(unsigned char)p_stA3dHeaders[uwNumOfA3dGENERAL].uwNumOfCacheEntry;
	}
	/* End of AR9902*/
#endif /*A3X_N64*/
 
	uwCorrectedFrame = (unsigned short) (_uwFrame - p_stCurrentA3dGENERAL->uwStartFrame);
 
	/* ----------------------------------------------------------------------------------*/
	/* Get information to update frame info*/
	p_stCurrentChannel = &p_stChannels [p_stCurrentA3dGENERAL->uwNumOfFirstChannel];
	p_stCurrentOnlyFrame = &p_stOnlyFrames[p_stCurrentA3dGENERAL->uwNumOfFirstOnlyFrame + uwCorrectedFrame];
	uwT_NTTO = p_stCurrentOnlyFrame->uwNumOfSavedFrame;
 
	/* ----------------------------------------------------------------------------------*/
	/* Set Angular Speed Matrix if exist*/
#ifndef U64
	if	(p_stCurrentOnlyFrame->uwNumOfAngularSpeedQuat == SEB_Invalid) 
	{
		/* free matrix if allocated*/
		if (_p_stFrame->p_stAngularSpeedMatrix)
		{
            MMG_fn_vAddMemoryInfo( MMG_C_lTypeInterpol , MMG_C_lSubTypeSpeedMatrix , 0 );
			TMP_M_Free(_p_stFrame->p_stAngularSpeedMatrix);
        }
		_p_stFrame->p_stAngularSpeedMatrix=	NULL;
	}
	else 
	{
		tdxQuater4 a4_xQuatOri;
 
		/* allocate matrix if it wasn't*/
		if (!_p_stFrame->p_stAngularSpeedMatrix)
		{
            MMG_fn_vAddMemoryInfo( MMG_C_lTypeInterpol , MMG_C_lSubTypeSpeedMatrix , 0 );
			_p_stFrame->p_stAngularSpeedMatrix = TMP_M_p_Malloc(sizeof(MTH3D_tdstMatrix));
        }
		fn_v_ExpandQuat(a4_xQuatOri,p_a4_xQuaternions[p_stCurrentOnlyFrame->uwNumOfAngularSpeedQuat]);
		fn_v_QuatToMatrix(*((tdxMatrix33 *) (_p_stFrame->p_stAngularSpeedMatrix)),a4_xQuatOri);
	}
 
	/* ----------------------------------------------------------------------------------*/
	/* Set Linear Speed Vector if exist*/
	if	(p_stCurrentOnlyFrame->uwNumOfSpeedVector == SEB_Invalid) 
	{
		_p_stFrame->p_stLinearSpeedVector = NULL;
	}
	else 
	{
		_p_stFrame->p_stLinearSpeedVector = (MTH3D_tdstVector *) &p_a3_xVectors[p_stCurrentOnlyFrame->uwNumOfSpeedVector];
	}
#endif
 
	/* ---------------------------------------------------------------------------------- */
	/* Set Hierarchy */
	if (p_stCurrentOnlyFrame->uwHierarchyNbCouples)
	{
#ifdef U64
		/* Begin AR9902 Copy hierarchy instead of pointing it */
		if(_p_stFrame->stHierarchy.d_stCouples!=NULL)
		{
			if((memcmp(_p_stFrame->stHierarchy.d_stCouples,
				&p_stHierarchies[p_stCurrentOnlyFrame->uwNumOfFirstHierarchyCouple],
				sizeof(tdstCouple)*p_stCurrentOnlyFrame->uwHierarchyNbCouples)!=0) ||
				(p_stCurrentOnlyFrame->uwHierarchyNbCouples != _p_stFrame->stHierarchy.ulNbOfCouples))
			{
				/* hierarchy is different */
				MMG_fn_vAddMemoryInfo( MMG_C_lTypeInterpol , MMG_C_lSubTypeHierarchies , 0 );
				_p_stFrame->stHierarchy.d_stCouples = TMP_M_p_Malloc(sizeof(tdstCouple)*p_stCurrentOnlyFrame->uwHierarchyNbCouples);
				memcpy(_p_stFrame->stHierarchy.d_stCouples,
					&p_stHierarchies[p_stCurrentOnlyFrame->uwNumOfFirstHierarchyCouple],
					sizeof(tdstCouple)*p_stCurrentOnlyFrame->uwHierarchyNbCouples);
				/* The old hierarchy is freed into the anim player (PLA_fn_vInitAllChildInHeapNewAnim) */
			}
		}
		else
		{
			/* no previous hierarchy */
			MMG_fn_vAddMemoryInfo( MMG_C_lTypeInterpol , MMG_C_lSubTypeHierarchies , 0 );
			_p_stFrame->stHierarchy.d_stCouples = TMP_M_p_Malloc(sizeof(tdstCouple)*p_stCurrentOnlyFrame->uwHierarchyNbCouples);
			memcpy(_p_stFrame->stHierarchy.d_stCouples,
					&p_stHierarchies[p_stCurrentOnlyFrame->uwNumOfFirstHierarchyCouple],
					sizeof(tdstCouple)*p_stCurrentOnlyFrame->uwHierarchyNbCouples);
		}
		/* End AR9902 */
#else
		_p_stFrame->stHierarchy.d_stCouples = (tdstCouple *) &p_stHierarchies[p_stCurrentOnlyFrame->uwNumOfFirstHierarchyCouple];
#endif
	}
	else
		_p_stFrame->stHierarchy.d_stCouples = NULL;
	_p_stFrame->stHierarchy.ulNbOfCouples = p_stCurrentOnlyFrame->uwHierarchyNbCouples;
 
	/* ----------------------------------------------------------------------------------*/
	/* Set Frame Info - don't compute matrix*/
	for	(uwCnt1=0,p_stCurrentElement3d=_p_stFrame->p_stArrayOfElts3d;uwCnt1<p_stCurrentA3dGENERAL->uwNumberOfChannels;uwCnt1++) 
	{
		tdstFrame * p_stCurrentFrame;
 
		/* Get Current Frame info*/
		p_stCurrentFrame = &p_stFrames[p_stCurrentChannel->uwNumOfFirstFrame + uwT_NTTO];
 
		/* ----------------------------------------------------------------------------------*/
		/* Fill element 3D structure*/
		if(p_stCurrentFrame->uwNumOfNTTO!=(unsigned short)0xFFFF) /* empty object AR9810*/
		{
		/* Element Number in TBL*/
			p_stCurrentElement3d->wElement = p_stNTTO[p_stCurrentFrame->uwNumOfNTTO].ucNumberInTable;
		/* Channel Number*/
		p_stCurrentElement3d->ucChannelNumber = (unsigned char)(p_stCurrentChannel->uwChannelNumber);
		/* Active Status*/
		p_stCurrentElement3d->bf1ActiveStatus = TRUE;
		/* Type Of Element*/
		p_stCurrentElement3d->eTypeOfElement = (tdeTypeOfElement)(p_stNTTO[p_stCurrentFrame->uwNumOfNTTO].uwTypeOfObject & 0x00FF);
		/* ucTransparency*/
		p_stCurrentElement3d->ucTransparency=	p_stNTTO[ p_stCurrentFrame->uwNumOfNTTO ].ucTransparency;
		}
		else
		{
			/* XB 05/05/99 : typeof(wElement)=unsigned char on N64 !! */
#ifndef U64
			p_stCurrentElement3d->wElement = (unsigned short) -1; 
#else
			p_stCurrentElement3d->wElement = (unsigned char) -1;
#endif
			/* End XB 05/05/99 */
			p_stCurrentElement3d->ucChannelNumber = (unsigned char)(p_stCurrentChannel->uwChannelNumber);
			p_stCurrentElement3d->bf1ActiveStatus = TRUE;
			p_stCurrentElement3d->eTypeOfElement = TE_EmptyObject;
			p_stCurrentElement3d->ucTransparency = 0;
		}
 
		p_stCurrentChannel++;
		p_stCurrentElement3d++;
	}
}
 
/* ************************************************************ fn_vUpdateFrameMatrix*/
/* Update Frame if it wasn't update*/
/* Update Matrix in Channel Array*/
/*		if they weren't updated*/
/*		or if bolean ForceUpdate is TRUE*/
/**/
/* 17/07/98 - Carlos Torres*/
/* ***********************************************************************************/
void fn_vUpdateFrameMatrix(void * _p_stSuperObject,tdstFrame3d * _p_stFrame,tdstAnim3d * _p_stAnim3d,
						   unsigned short _uwFrame,unsigned char ucForceUpdate,tdstAChannel * d_stChannelArray) {
	tdstA3dGENERAL * p_stCurrentA3dGENERAL;
	tdstChannel * p_stCurrentChannel;
	unsigned short	uwT_NTTO;
	unsigned short uwCnt1,uwNumOfA3dGENERAL;
	unsigned short uwCorrectedFrame;
	ACP_tdxBool bHierarchized;
 
	/* ----------------------------------------------------------------------------------*/
	/* update frame*/
	fn_vUpdateFrame(_p_stSuperObject,_p_stFrame,_p_stAnim3d,_uwFrame);
 
	/* ----------------------------------------------------------------------------------*/
	/* check if the frame matrix is already updated*/
	if (_p_stFrame->ucMatrixUpdated && !ucForceUpdate)
		return;
 
	/* ----------------------------------------------------------------------------------*/
	/* set ref of the frame*/
	_p_stFrame->ucMatrixUpdated = TRUE;
 
	/* ----------------------------------------------------------------------------------*/
	/* Get A3D General Info*/
#ifdef	A3X_N64
#ifndef FORCE_REAL_TIME_LOAD
	if(g_bRealTimeAnimationLoad)
#endif
		uwNumOfA3dGENERAL=	fn_uw_GetNumOfA3dGENERAL(_p_stAnim3d->uwNumOfA3dGENERAL, _uwFrame);
#ifndef FORCE_REAL_TIME_LOAD
	else
#endif
#endif
#ifndef FORCE_REAL_TIME_LOAD
		uwNumOfA3dGENERAL=	_p_stAnim3d->uwNumOfA3dGENERAL;
#endif
 
	p_stCurrentA3dGENERAL = fn_p_GetA3dGENERAL(uwNumOfA3dGENERAL,_uwFrame);
 
#ifdef	A3X_N64
	/* ----------------------------------------------------------------------------------*/
	/* check if anim cutting is well done*/
#ifdef ANIM_DEBUG
	if ((_uwFrame < p_stCurrentA3dGENERAL->uwStartFrame) ||
		(_uwFrame >= p_stCurrentA3dGENERAL->uwEndFrame) )
	{
		osSyncPrintf("Probleme decoupage d'animation (anim= %d, frame= %d, StartFrame= %d, EndFrame= %d)\n", uwNumOfA3dGENERAL, _uwFrame, p_stCurrentA3dGENERAL->uwStartFrame, p_stCurrentA3dGENERAL->uwEndFrame);
		osSyncPrintf("Numéro original d'anim : %d\n",_p_stAnim3d->uwNumOfA3dGENERAL);
		ASM_BREAK;
	}
#endif /* ANIM_DEBUG */
#endif
	uwCorrectedFrame = (unsigned short) (_uwFrame - p_stCurrentA3dGENERAL->uwStartFrame);
 
	/* ----------------------------------------------------------------------------------*/
	/* Get information to update frame info*/
	p_stCurrentChannel = &p_stChannels [p_stCurrentA3dGENERAL->uwNumOfFirstChannel];
	uwT_NTTO = p_stOnlyFrames[p_stCurrentA3dGENERAL->uwNumOfFirstOnlyFrame + uwCorrectedFrame].uwNumOfSavedFrame;
 
	/* ----------------------------------------------------------------------------------*/
	/* Interpolate all channels Matrix*/
	for	(uwCnt1=0;uwCnt1<p_stCurrentA3dGENERAL->uwNumberOfChannels;uwCnt1++) {
		tdstFrame * p_stCurrentFrame;
		tdstFrameKF	* p_stCurrentFrameKF;
		tdstKeyFrame * p_stCurrentKeyFrame, * p_stOldKeyFrame;
		register SEB_xReal xDT=	xZero;
 
		/* TEMP ANTI BUG - to avoid crash with bad Anim*/
		/* Later replace by an assert in debuf version*/
		if ((p_stCurrentChannel->uwChannelNumber != SEB_Invalid) &&
			(!d_stChannelArray[p_stCurrentChannel->uwChannelNumber].bControlledChannel))
		{
			/* Get Current frame information*/
			p_stCurrentFrame = &p_stFrames[p_stCurrentChannel->uwNumOfFirstFrame + uwT_NTTO];
			p_stCurrentFrameKF = &p_stFramesKF[p_stCurrentChannel->ulNumOfFirstFrameKF + uwCorrectedFrame];
			p_stOldKeyFrame = &p_stKeyFrames[p_stCurrentFrameKF->uwNumOfKeyFrame];
 
			/* get key frame for interpolation*/
			if ((p_stOldKeyFrame->uwMask & SEB_xMaskLastKey) != 0x0000)
			{
				if	((p_stOldKeyFrame->uwMask & SEB_xTypeWrapLastKey) != 0x0000)
				{
					p_stCurrentKeyFrame=	&p_stKeyFrames[ p_stFramesKF[p_stCurrentChannel->ulNumOfFirstFrameKF].uwNumOfKeyFrame ];
					xDT=	((SEB_xReal) (_uwFrame - p_stOldKeyFrame->uwFrameNumber)) / ((SEB_xReal) (p_stCurrentA3dGENERAL->uwNumberOfFrames + p_stCurrentKeyFrame->uwFrameNumber - p_stOldKeyFrame->uwFrameNumber));
				}
				else
				{	
				p_stCurrentKeyFrame = p_stOldKeyFrame;
				xDT = xZero;
			}
			}
			else {
				p_stCurrentKeyFrame = p_stOldKeyFrame + 1;
				if (p_stCurrentKeyFrame->uwFrameNumber == p_stOldKeyFrame->uwFrameNumber)
					xDT = xZero;
				else
					xDT = ((SEB_xReal)(_uwFrame - p_stOldKeyFrame->uwFrameNumber)) / ((SEB_xReal)(p_stCurrentKeyFrame->uwFrameNumber - p_stOldKeyFrame->uwFrameNumber));
			}
 
			/* InterpolationParameter*/
			if	( (p_stOldKeyFrame->swInterpolationParameter != 0x0000) && (xDT != xZero) )
			{	register	SEB_xReal	xTmp;
				xTmp=	p_stCurrentKeyFrame->swInterpolationParameter * ((SEB_xReal) (1.0f / 8192.0f));
				xDT=	xDT * (xDT * xTmp + xOne - xTmp);
			} 
 
			if(p_stNTTO[p_stCurrentFrame->uwNumOfNTTO].uwTypeOfObject!=(unsigned short)0xFFFF)
				bHierarchized=(ACP_tdxBool)(p_stNTTO[p_stCurrentFrame->uwNumOfNTTO].uwTypeOfObject & SEB_xTypeHierarchized);
			else
				bHierarchized=FALSE;
 
			/* Interpolate channel matrix*/
			fn_v_InterpolBetweenKeys(
				p_stOldKeyFrame,
				p_stCurrentKeyFrame,
				p_stCurrentChannel,
				d_stChannelArray[p_stCurrentChannel->uwChannelNumber].hSupObject->hLocalMatrix,
				bHierarchized,
				xDT);
		}
 
		p_stCurrentChannel++;
	}
}
 
 
/* ****************************************************** fn_p_stGetLinearSpeedVector*/
/* Return the Linear Speed Vector*/
/* the vector returned is a reference so*/
/*		DON'T Modify it or Free it*/
/* if there is no speed, return NULL*/
/* reference remain valid until animation is free*/
/**/
/* 20/07/98 - Carlos Torres*/
/* ***********************************************************************************/
MTH3D_tdstVector *  fn_p_stGetLinearSpeedVector(tdstAnim3d * _p_stAnim3d,unsigned short _uwFrame) {
	unsigned short uwNumOfA3dGENERAL;
	tdstA3dGENERAL * p_stCurrentA3dGENERAL;
	tdstOnlyFrame * p_stCurrentOnlyFrame;
 
	if	( _uwFrame >= _p_stAnim3d->uwNumberOfFrames )
		return	NULL; /* Can occur sometimes... AR9808*/
 
	/* ----------------------------------------------------------------------------------*/
	/* Get A3D General Info*/
#ifdef	A3X_N64
#ifndef FORCE_REAL_TIME_LOAD
	if(g_bRealTimeAnimationLoad)
#endif
		uwNumOfA3dGENERAL=	fn_uw_GetNumOfA3dGENERAL(_p_stAnim3d->uwNumOfA3dGENERAL, _uwFrame);
#ifndef FORCE_REAL_TIME_LOAD
	else
#endif
#endif
#ifndef FORCE_REAL_TIME_LOAD
		uwNumOfA3dGENERAL=	_p_stAnim3d->uwNumOfA3dGENERAL;
#endif 
	p_stCurrentA3dGENERAL = fn_p_GetA3dGENERAL(uwNumOfA3dGENERAL,_uwFrame);
 
#ifdef	A3X_N64
	/* ----------------------------------------------------------------------------------*/
	/* check if anim cutting is well done*/
#ifdef ANIM_DEBUG
	if ((_uwFrame < p_stCurrentA3dGENERAL->uwStartFrame) ||
		(_uwFrame >= p_stCurrentA3dGENERAL->uwEndFrame) )
	{
		osSyncPrintf("Probleme decoupage d'animation (anim= %d, Frame= %d, StartFrame= %d, EndFrame= %d)\n", uwNumOfA3dGENERAL, _uwFrame, p_stCurrentA3dGENERAL->uwStartFrame, p_stCurrentA3dGENERAL->uwEndFrame);
		osSyncPrintf("Numero original d'anim : %d\n",_p_stAnim3d->uwNumOfA3dGENERAL);
		ASM_BREAK;
 
	}
#endif /* ANIM_DEBUG */
#endif
 
#ifndef U64
#pragma warning(disable:4244)
#endif
	_uwFrame -= p_stCurrentA3dGENERAL->uwStartFrame;
#ifndef U64
#pragma warning(default:4244)
#endif
 
	/* ----------------------------------------------------------------------------------*/
	/* Get information to update frame info*/
	p_stCurrentOnlyFrame = &p_stOnlyFrames[p_stCurrentA3dGENERAL->uwNumOfFirstOnlyFrame + _uwFrame];
 
 
	/* ----------------------------------------------------------------------------------*/
	/* Set Linear Speed Vector if exist*/
	if	(p_stCurrentOnlyFrame->uwNumOfSpeedVector == SEB_Invalid) {
		return NULL;
	}
	else {
		return (MTH3D_tdstVector *) &p_a3_xVectors[p_stCurrentOnlyFrame->uwNumOfSpeedVector];
	}
}
 
/* ***************************************************** fn_p_stGetAngularSpeedMatrix*/
/* Return the Angular Speed Matrix*/
/* Fill the Matrix if exist and return pointer*/
/* If no angular speed return NULL*/
/*		The matrix pass in parameter must be allocate by the calling function*/
/**/
/* 20/07/98 - Carlos Torres*/
/* ***********************************************************************************/
MTH3D_tdstMatrix *  fn_p_stGetAngularSpeedMatrix(tdstAnim3d * _p_stAnim3d,unsigned short _uwFrame,MTH3D_tdstMatrix * p_stMatrix) {
	unsigned short uwNumOfA3dGENERAL;
	tdstA3dGENERAL * p_stCurrentA3dGENERAL;
	tdstOnlyFrame * p_stCurrentOnlyFrame;
 
	if	( _uwFrame >= _p_stAnim3d->uwNumberOfFrames )
		return	NULL; /* Can occur sometimes... AR9808*/
 
	/* ----------------------------------------------------------------------------------*/
	/* Get A3D General Info*/
#ifdef	A3X_N64
#ifndef FORCE_REAL_TIME_LOAD
	if(g_bRealTimeAnimationLoad)
#endif
		uwNumOfA3dGENERAL=	fn_uw_GetNumOfA3dGENERAL(_p_stAnim3d->uwNumOfA3dGENERAL, _uwFrame);
#ifndef FORCE_REAL_TIME_LOAD
	else
#endif
#endif
#ifndef FORCE_REAL_TIME_LOAD
		uwNumOfA3dGENERAL=	_p_stAnim3d->uwNumOfA3dGENERAL;
#endif
 
	p_stCurrentA3dGENERAL = fn_p_GetA3dGENERAL(uwNumOfA3dGENERAL,_uwFrame);
 
#ifdef	A3X_N64
	/* ----------------------------------------------------------------------------------*/
	/* check if anim cutting is well done*/
#ifdef ANIM_DEBUG
	if ((_uwFrame < p_stCurrentA3dGENERAL->uwStartFrame) ||
		(_uwFrame >= p_stCurrentA3dGENERAL->uwEndFrame) )
	{
		osSyncPrintf("Probleme decoupage d'animation (anim= %d, Frame= %d, StartFrame= %d, EndFrame= %d)\n", uwNumOfA3dGENERAL, _uwFrame, p_stCurrentA3dGENERAL->uwStartFrame, p_stCurrentA3dGENERAL->uwEndFrame);
		osSyncPrintf("Animation originelle : %d\n",_p_stAnim3d->uwNumOfA3dGENERAL);
		ASM_BREAK;
 
	}
#endif /* ANIM_DEBUG */
#endif /*A3X_N64*/
 
#ifndef U64
#pragma warning(disable:4244)
#endif
	_uwFrame -= p_stCurrentA3dGENERAL->uwStartFrame;
#ifndef U64
#pragma warning(default:4244)
#endif
 
	/* ----------------------------------------------------------------------------------*/
	/* Get information to update frame info*/
	p_stCurrentOnlyFrame = &p_stOnlyFrames[p_stCurrentA3dGENERAL->uwNumOfFirstOnlyFrame + _uwFrame];
 
 
	/* ----------------------------------------------------------------------------------*/
	/* Set Angular Speed Matrix if exist*/
	if	(p_stCurrentOnlyFrame->uwNumOfAngularSpeedQuat == SEB_Invalid) {
		return NULL;
	}
	else {
		tdxQuater4 a4_xQuatOri;
 
		fn_v_ExpandQuat(a4_xQuatOri,p_a4_xQuaternions[p_stCurrentOnlyFrame->uwNumOfAngularSpeedQuat]);
/*		if	(_uwFrame != 1)
			fn_v_InterpolQuatWithOmega( a4_xQuatOri, a4_xQuater1, a4_xQuatOri, (SEB_xReal)_uwFrame, p_stCurrentOnlyFrame->uwAngSpeedQuat ); */
		fn_v_QuatToMatrix(*((tdxMatrix33 *) (p_stMatrix)),a4_xQuatOri);
 
		return p_stMatrix;
	}
}
 

#undef	A3X_INTN_C
