// **********************************************************************************
// * "l_a3d_v6.c"																	*
// * Written by :	Sébastien Rubens												*
// * Tabulations :	4 char															*
// **********************************************************************************
#define L_A3D_V6_C



// **********************************************************************************
//#define	ShowInfos
//#define	WaitGetChar
#define	Details



// **********************************************************************************
//																	Included files

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

#include "SCR.h"
//#include "LRM.h"

#include "specif\\a3x_pref.h"
#include "structur\\anim_s.h"


#include "a3x_glob.h"
#include "makeanim.h"
#include "l_global_v6.h"
#include "l_a3d_v6.h"
#include "l_Tbl_v6.h"
#include "l_chl_v6.h"
#include "a3x_int.h"
#include "a3x_intb.h"


// **********************************************************************************
#define	NbChannelAlreadyUsed	1000

#define UNKNOW_CHANNEL			0xFFFE

static	unsigned long	ulNoInvalid=	1;		// 0= undefined to graphic, 1= Undefined to empty

static	unsigned short	ax_uwChannelAlreadyUsed[NbChannelAlreadyUsed];

static	signed long		slWaitedStringsTableEntry;
static	signed long		slWaitedVertexesTableEntry;
static	signed long		slWaitedQuaternionsTableEntry;
static	signed long		slWaitedChannelNumber;

static	signed long		slLastFrame, slCurrentFrame, slHierFrame;

static	signed long		slWaitedMax;
//static	signed long		slMaxInChannel;						// Max in channel name le to set ChannelNumber value !!!

static	unsigned short	uwPivotDefined;						// Flag
static	unsigned short	uwOkAnimationFile;					// Flag
static	unsigned short	uwHierDef;							// Flag
static	unsigned short	uwNbReadedKeys;

static	tdstBinA3dAnimationGENERAL	*p_stGENERAL;
static	tdstBinFrame				stReadFrame;

typedef	char	tdString[50];
static	tdString	ax_tdEventType[]=
{	"SOUND_EVENT",	"MECHANIC_EVENT",	"GENERATE_EVENT",	"GENERIC_EVENT"	};
static	tdString	ax_tdMechanicType[]=
{	"NoAction",					"TurnUp",					"TurnDown",					"TurnLeft",
	"TurnRight",				"TurnAbsolute",				"Jump",						"JumpAbsolute",
	"JumpWithoutAddingSpeed",	"Accelerate",				"Pulse",					"Brake",
	"GoRelative",				"GoAbsolute",				"Start",					"Continue",
	"TrackingDirection",		"ActionOnCamera",			"TurnAbsoluteInProgress",	"GoTarget",
	"GoInDirection",			"Fire",						"ReachTarget",				"TurnAround",
	"BePushed"
};

// **********************************************************************************
//								HEADER CALLBACK
// **********************************************************************************
static SCR_tde_Anl_ReturnValue	fn_eA3dHEADERCallBackV6i(	SCR_tdst_File_Description	*_p_stFile,
															char						*_p_szName,
															char						*_ap_SzParam[],
															SCR_tde_Anl_Action			_eAction )
{
	// Section already analysed
	if	(_eAction == SCR_EA_Anl_AlreadyAnalysed)
	{	fprintf( ErrorFile, "%s :  A3dHEADER already analysed\n", AnimationName );
	}

	// Beginning of section
	if	(_eAction == SCR_EA_Anl_BeginSection)
	{
#ifdef	ShowInfos
		fn_v_LogSectionBegin(	D_BINSCR_LogNew,
								"A3dHEADER",
								AnimationName );
#endif
		// No memory allocation for A3dHEADER
		uwNbReadedKeys=	0;
	}

	// We are in the section
	else if	(_eAction == SCR_EA_Anl_Entry)
	{
		// FileType
		if	( !stricmp(_p_szName, "FileType") )
		{	if	( stricmp(_ap_SzParam[0], "Animations") )
			{
				fprintf( ErrorFile, "%s :  A3dHEADER.FileType is not equal to 'Animations' (%s)\n", AnimationName, _ap_SzParam[0] );
				uwOkAnimationFile=	1;
				bValid(&stAnims[uwAnalysedAnim]) = 1;
			}
			else
			{	uwOkAnimationFile=	0;
				//bValid(&stAnims[uwAnalysedAnim]) = 0;
			}
		}

		// VersionNumber
		else if	( (uwOkAnimationFile == 0) && !stricmp(_p_szName, "VersionNumber") )
		{	if	( atoi(_ap_SzParam[0]) != 6 ) {		
				uwOkAnimationFile=	1;
				bValid(&stAnims[uwAnalysedAnim]) = 1;
				
				printf("\nAnimation dans l'ancien format (%s) \n", AnimationName );
				fprintf( ErrorFile, "\nAnimation dans l'ancien format (%s) \n", AnimationName );
			}
			else {
				uwOkAnimationFile=	0;
				//bValid(&stAnims[uwAnalysedAnim]) = 0;
			}

		}

		// Unknown field
		else if (uwOkAnimationFile == 0)
		{	fprintf( ErrorFile, "%s :  Unknown field in A3d file, A3dHEADER (%s)\n", AnimationName, _ap_SzParam[0] );
		}

	}

	// End of section
	else if	(_eAction == SCR_EA_Anl_EndSection)
	{
#ifdef	ShowInfos
		fn_v_LogSectionEnd();
#endif
	}

	return	SCR_ERV_Anl_NormalReturn;
}



// **********************************************************************************
//								STRING TABLE CALLBACK
// **********************************************************************************
SCR_tde_Anl_ReturnValue	fn_eA3dStringsTableCallBackV6i(	SCR_tdst_File_Description	*_p_stFile,
														char						*_p_szName,
														char						*_ap_SzParam[],
														SCR_tde_Anl_Action			_eAction )
{
	// Section already analysed
	if	(_eAction == SCR_EA_Anl_AlreadyAnalysed)
	{	if	(uwOkAnimationFile == 0)
		{	fprintf( ErrorFile, "%s :  A3dStringsTable already analysed\n", AnimationName );
		}
	}

	// Beginning of section
	if	(_eAction == SCR_EA_Anl_BeginSection)
	{
		if	(uwOkAnimationFile == 0)
		{
#ifdef	ShowInfos
			fn_v_LogSectionBegin(	D_BINSCR_LogNew,
									"A3dStringsTable",
									AnimationName );
#endif

			//p_szName contains NumberOfStrings and _ap_SzParam[0] contains nothing ( (nothing) )
			//Allocate memory for StringsTable
			slWaitedMax=	(signed long) atoi(_p_szName);
			fn_v_AllocateOnStack( eStackBinStrings, slWaitedMax );

			slWaitedStringsTableEntry=	0L;
		}
	}

	// We are in the section
	else if	(_eAction == SCR_EA_Anl_Entry)
	{
		if	(uwOkAnimationFile == 0)
		{
			// Add
			if	( !stricmp(_p_szName, "Add") )
			{
				if	( slWaitedStringsTableEntry == ReadSLong(0) )
					strcpy( &ax_xStrings[M_GetStackAlloc(eStackBinStrings)+slWaitedStringsTableEntry][0], _ap_SzParam[1] );
				else
					fprintf( ErrorFile, "%s :  Wrong (first) parameter in A3dStringsTable (%s)\n", AnimationName, _ap_SzParam[0] );
				slWaitedStringsTableEntry++;
			}

			// Unknown field
			else
			{	fprintf( ErrorFile, "%s :  Unknown field in A3d file, A3dStringsTable (%s)\n", AnimationName, _p_szName );
			}
		}
	}

	// End of section
	else if	(_eAction == SCR_EA_Anl_EndSection)
	{
		if	(uwOkAnimationFile == 0)
		{
			if	( slWaitedStringsTableEntry != slWaitedMax )
				fprintf(WarningFile, "%s :  Not enough entries in StringsTable (%d)\n", AnimationName, slWaitedStringsTableEntry );

#ifdef	ShowInfos
			fn_v_LogSectionEnd();
#endif
		}
	}

	return	SCR_ERV_Anl_NormalReturn;
}



// **********************************************************************************
//								VERTEX TABLE CALLBACK
// **********************************************************************************
SCR_tde_Anl_ReturnValue	fn_eA3dVertexesTableCallBackV6i(	SCR_tdst_File_Description	*_p_stFile,
															char						*_p_szName,
															char						*_ap_SzParam[],
															SCR_tde_Anl_Action			_eAction )
{	signed long	slInd;
	SEB_xReal	*p_stVector;

	// Section already analysed
	if	(_eAction == SCR_EA_Anl_AlreadyAnalysed)
	{	if	(uwOkAnimationFile == 0)
		{	fprintf( ErrorFile, "%s :  A3dVertexesTable already analysed\n", AnimationName );
		}
	}

	// Beginning of section
	if	(_eAction == SCR_EA_Anl_BeginSection)
	{
		if	(uwOkAnimationFile == 0)
		{
#ifdef	ShowInfos
			fn_v_LogSectionBegin(	D_BINSCR_LogNew,
									"A3dVertexesTable",
									AnimationName );
#endif

			//Allocate memory for VertexesTable
			slWaitedMax=	(signed long) atoi(_p_szName);
			fn_v_AllocateOnStack( eStackBinVertexes, slWaitedMax );

			slWaitedVertexesTableEntry=	0;
		}
	}

	// We are in the section
	else if	(_eAction == SCR_EA_Anl_Entry)
	{
		if	(uwOkAnimationFile == 0)
		{
			// Add
			if	( !stricmp(_p_szName, "Add") )
			{
				if	( slWaitedVertexesTableEntry == ReadSLong(0) )
				{	slInd=			M_GetStackAlloc(eStackBinVertexes) + slWaitedVertexesTableEntry;
					p_stVector=		&axa3_xVertexes[slInd][0];
					p_stVector[0]=	ReadDouble(1);
					p_stVector[1]=	ReadDouble(2);
					p_stVector[2]=	ReadDouble(3);
					slWaitedVertexesTableEntry++;
				}
				else
				{	fprintf( ErrorFile, "%s :  Wrong (first) parameter in A3dStringsTable (%s)\n", AnimationName, _ap_SzParam[0] );
				}
			}

			// Unknown field
			else
			{	fprintf( ErrorFile, "%s :  Unknown field in A3d file, A3dVertexesTable (%s)\n", AnimationName, _p_szName );
			}
		}
	}

	// End of section
	else if	(_eAction == SCR_EA_Anl_EndSection)
	{
		if	(uwOkAnimationFile == 0)
		{
			if	( slWaitedVertexesTableEntry != slWaitedMax )
				fprintf( ErrorFile, "%s :  Not enough entries in VertexesTable (%d)\n", AnimationName, slWaitedVertexesTableEntry );

#ifdef	ShowInfos
			fn_v_LogSectionEnd();
#endif
		}
	}

	return	SCR_ERV_Anl_NormalReturn;
}



// **********************************************************************************
//								QUATERNIONS TABLE CALLBACK
// **********************************************************************************
SCR_tde_Anl_ReturnValue	fn_eA3dQuaternionsTableCallBackV6i(	SCR_tdst_File_Description	*_p_stFile,
															char						*_p_szName,
															char						*_ap_SzParam[],
															SCR_tde_Anl_Action			_eAction )
{	signed long	slInd;
	SEB_xReal	*p_stQuater;

	// Section already analysed
	if	(_eAction == SCR_EA_Anl_AlreadyAnalysed)
	{	if	(uwOkAnimationFile == 0)
		{	fprintf( ErrorFile, "%s :  A3dQuaternionsTable already analysed\n", AnimationName );
		}
	}

	// Beginning of section
	if	(_eAction == SCR_EA_Anl_BeginSection)
	{	if	(uwOkAnimationFile == 0)
		{
#ifdef	ShowInfos
			fn_v_LogSectionBegin(	D_BINSCR_LogNew,
									"A3dQuaternionsTable",
									AnimationName );
#endif

			//Allocate memory for QuaternionsTable
			slWaitedMax=	atoi(_p_szName);
			fn_v_AllocateOnStack( eStackBinQuaternions, slWaitedMax );

			slWaitedQuaternionsTableEntry=	0L;
		}
	}

	// We are in the section
	else if	(_eAction == SCR_EA_Anl_Entry)
	{	if	(uwOkAnimationFile == 0)
		{
			// Add
			if	( !stricmp(_p_szName, "Add") )
			{
				if	( slWaitedQuaternionsTableEntry == ReadSLong(0) )
				{	slInd=			M_GetStackAlloc(eStackBinQuaternions) + slWaitedQuaternionsTableEntry;
					p_stQuater=		&axa4_xBinQuaternions[slInd][0];
					p_stQuater[0]=	ReadDouble(1);
					p_stQuater[1]=	ReadDouble(2);
					p_stQuater[2]=	ReadDouble(3);
					p_stQuater[3]=	ReadDouble(4);
					slWaitedQuaternionsTableEntry++;
				}
				else
				{	fprintf( ErrorFile, "%s :  Wrong (first) parameter in A3dStringsTable (%s)\n", AnimationName, _ap_SzParam[0] );
				}
			}

			// Unknown field
			else
			{	fprintf( ErrorFile, "%s :  Unknown field in A3d file, A3dQuaternionsTable (%s)\n", AnimationName, _p_szName );
			}
		}
	}

	// End of section
	else if	(_eAction == SCR_EA_Anl_EndSection)
	{
		if	(uwOkAnimationFile == 0)
		{
			if	( slWaitedQuaternionsTableEntry != slWaitedMax )
				fprintf( ErrorFile, "%s :  Not enough entries in QuaternionsTable (%d)\n", AnimationName, slWaitedQuaternionsTableEntry );

#ifdef	ShowInfos
			fn_v_LogSectionEnd();
#endif
		}
	}

	return	SCR_ERV_Anl_NormalReturn;
}



// **********************************************************************************
//								ANIMATION GENERAL CALLBACK
// **********************************************************************************
// Modif 17/08/98 : New Key CameraAngle(do nothing) - Carlos Torres
// Modif 27/08/98 : Supress Morph allocation - Carlos Torres
SCR_tde_Anl_ReturnValue	fn_eA3dAnimationGENERALCallBackV6i(	SCR_tdst_File_Description	*_p_stFile,
															char						*_p_szName,
															char						*_ap_SzParam[],
															SCR_tde_Anl_Action			_eAction )
{
	// Section already analysed
	if	(_eAction == SCR_EA_Anl_AlreadyAnalysed)
	{
		if	(uwOkAnimationFile == 0)
		{
			fprintf( ErrorFile, "%s :  A3dAnimationGENERAL already analysed\n", AnimationName );
		}
	}

	// Beginning of section
	else if	(_eAction == SCR_EA_Anl_BeginSection)
	{
		if (uwOkAnimationFile == 0)
		{
#ifdef	ShowInfos
			fn_v_LogSectionBegin(	D_BINSCR_LogNew,
									"A3dAnimationGENERAL",
									AnimationName );
#endif

			// Set pointer on A3dAnimationGENERAL structure
			p_stGENERAL=	&ax_tdstA3dGENERAL[M_GetStackAlloc(eStackBinA3dGENERAL)];

			p_stGENERAL->uwNumberOfFrames=		0;
			p_stGENERAL->uwNumberOfChannels=	0;
			p_stGENERAL->uwNumberOfVectors=		(unsigned short) (M_GetStackPos(eStackBinVertexes) - M_GetStackAlloc(eStackBinVertexes));
			p_stGENERAL->uwNumberOfQuaternions=	(unsigned short) (M_GetStackPos(eStackBinQuaternions) - M_GetStackAlloc(eStackBinQuaternions));
			p_stGENERAL->uwNumberOfHierarchies=	0;
			p_stGENERAL->uwNumberOfEvents=		0;
			p_stGENERAL->uwNumberOfMorphData=	0;

			p_stGENERAL->slNumOfHierarchies=	M_GetStackPos(eStackBinHierarchies);
			p_stGENERAL->slNumOfVectors=		M_GetStackPos(eStackBinVertexes);
			p_stGENERAL->slNumOfQuaternions=	M_GetStackPos(eStackBinQuaternions);
			p_stGENERAL->slNumOfEvents=			M_GetStackPos(eStackBinEvent);
			p_stGENERAL->slNumOfMorphData=		M_GetStackPos(eStackBinMorphInformation);
			{	unsigned long	ulCnt;

				for	( ulCnt=0 ; ulCnt<NbChannelAlreadyUsed ; ulCnt++ )
					ax_uwChannelAlreadyUsed[ulCnt]=	0;
			}
		}
	}

	// We are in the section
	else if	(_eAction == SCR_EA_Anl_Entry)
	{
		if	(uwOkAnimationFile == 0)
		{
			// Actor
			if	( !stricmp(_p_szName, "Actor") )
			{	// Not used
				// String : Actor's name
			}

			// NumberOfChannels
			else if	( !stricmp(_p_szName, "NumberOfChannels") )
			{	// Integer
				p_stGENERAL->uwNumberOfChannels=	ReadUShort(0);
			}

			// NumberOfFrames
			else if	( !stricmp(_p_szName, "NumberOfFrames") )
			{	// Integer
				p_stGENERAL->uwNumberOfFrames=		ReadUShort(0);
			}

			// CurrentFrame
			else if	( !stricmp(_p_szName, "CurrentFrame") )
			{	// Integer
				// Not used -------
			}

			// AnimationTranslationOffset
			else if ( !stricmp(_p_szName, "AnimationTranslationOffset") )
			{	// Unpacked Vector
				fn_v_CopyVect(	p_stGENERAL->uwAnimationTranslationOffset,
								axa3_xVertexes[M_GetStackAlloc(eStackBinVertexes) + ReadUShort(0)] );
			}

			// AnimationRotationOffset
			else if ( !stricmp(_p_szName, "AnimationRotationOffset") )
			{	// Packed quaternion
				fn_v_CopyQuat(	p_stGENERAL->uwAnimationRotationOffset,
								axa4_xBinQuaternions[M_GetStackAlloc(eStackBinQuaternions) + ReadUShort(0)] );
			}

			// AnimReferenceChannel
			else if	( !stricmp(_p_szName, "AnimReferenceChannel") )
			{	// Integer
				// Not used -------
			}

			// AnimationSpeed
			else if	( !stricmp(_p_szName, "AnimationSpeed") )
			{	// Integer
				p_stGENERAL->uwAnimationSpeed=		ReadUShort(0);
			}

			// CameraAngle
			else if	( !stricmp(_p_szName, "CameraAngle") )
			{	// ???
				// Used by Rayman TV !!!
			}

			// Unknown field
			else
			{	fprintf( ErrorFile, "%s :  Unknown field in A3d, AnimationGENERAL (%s)\n", AnimationName, _p_szName );
			}
		}
	}

	// End of section
	else if	(_eAction == SCR_EA_Anl_EndSection)
	{
		if	(uwOkAnimationFile == 0)
		{	signed long		slCnt;

			// Set pointer on A3dAnimationGENERAL structure
			p_stGENERAL=	&ax_tdstA3dGENERAL[M_GetStackAlloc(eStackBinA3dGENERAL)];

			p_stGENERAL->uwStartFrame=		0;
			p_stGENERAL->uwEndFrame=		0;
			p_stGENERAL->uwFlags=			0;
			p_stGENERAL->uwFakeAnimSpeed=	p_stGENERAL->uwAnimationSpeed;

			// Allocate memory for all Channels structures
			fn_v_AllocateOnStack( eStackBinChannels, p_stGENERAL->uwNumberOfChannels );
			p_stGENERAL->slNumOfChannels=	M_GetStackAlloc(eStackBinChannels);

			// Allocate memory for all OnlyFrame structures
			fn_v_AllocateOnStack( eStackBinOnlyFrames, p_stGENERAL->uwNumberOfFrames );
			p_stGENERAL->slNumOfOnlyFrames=	M_GetStackAlloc(eStackBinOnlyFrames);

			for	( slCnt=0 ; slCnt<p_stGENERAL->uwNumberOfFrames ; slCnt++ )
			{	fn_v_SetIdQuater(	ax_tdstOnlyFrames[p_stGENERAL->slNumOfOnlyFrames + slCnt].tdxAngularSpeedQuat );
				fn_v_SetZeroVector(	ax_tdstOnlyFrames[p_stGENERAL->slNumOfOnlyFrames + slCnt].tdxSpeedVector );
				ax_tdstOnlyFrames[p_stGENERAL->slNumOfOnlyFrames + slCnt].slNumOfAngularSpeedQuat=	0xFFFFFFFF;
				ax_tdstOnlyFrames[p_stGENERAL->slNumOfOnlyFrames + slCnt].slNumOfSpeedVector=		0xFFFFFFFF;
				ax_tdstOnlyFrames[p_stGENERAL->slNumOfOnlyFrames + slCnt].uwHierarchyNbCouples=		0;
				ax_tdstOnlyFrames[p_stGENERAL->slNumOfOnlyFrames + slCnt].slNumOfHierarchyCouples=	p_stGENERAL->slNumOfHierarchies;
			}

			slWaitedChannelNumber=	0;

#ifdef	ShowInfos
			fn_v_LogSectionEnd();
#endif
		}
	}

	return	SCR_ERV_Anl_NormalReturn;
}



// **********************************************************************************
//								CHANNEL CALLBACK
// **********************************************************************************
SCR_tde_Anl_ReturnValue	fn_eChannelCallBackV6i(	SCR_tdst_File_Description	*_p_stFile,
												char						*_p_szName,
												char						*_ap_SzParam[],
												SCR_tde_Anl_Action			_eAction )
{
		// Section already analysed
	if	(_eAction == SCR_EA_Anl_AlreadyAnalysed)
	{
		if	(uwOkAnimationFile == 0)
		{
			fprintf( ErrorFile, "%s :  Channel already analysed (Channel %d)\n", AnimationName, (slWaitedChannelNumber+1) );
		}
	}

	// Beginning of section
	else if	(_eAction == SCR_EA_Anl_BeginSection)
	{
		if	(uwOkAnimationFile == 0)
		{	signed long	slCnt, slNumCHL;

#ifdef	ShowInfos
			fn_v_LogSectionBegin(	D_BINSCR_LogNew,
									"Channel",
									AnimationName );
#endif

			// Verify ChannelNumber
			if	( slWaitedChannelNumber != (signed long) (atoi(_p_szName)-1) )
				fprintf( ErrorFile, "%s :  Wrong (waited) Channel Number (%s)\n", AnimationName, _ap_SzParam[0] );

			// Allocate memory for Frame structures
			fn_v_AllocateOnStack( eStackBinFrames, p_stGENERAL->uwNumberOfFrames );
			ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].slNumOfFrames=	M_GetStackAlloc(eStackBinFrames);

			// Initialize info structure
			fn_v_CopyVect(	ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].a3_xLocalPivotPos, a3_xVector0 );
			uwPivotDefined=	0;

			stReadFrame.swNumberInTable=	-1;
			stReadFrame.uwTypeOfObject=		0;
			stReadFrame.uwFrameNumber=		0;
			stReadFrame.uwMask=				0x0000;
			stReadFrame.uwAttribute=		0;
			stReadFrame.uwTypeOfObject=		TE_EmptyObject;
			stReadFrame.xInterpolationParameter=	0.0;
			fn_v_CopyQuat(	stReadFrame.a4_xQuatOri,		a4_xQuater1 );
			fn_v_CopyQuat(	stReadFrame.a4_xQuatSca,		a4_xQuater1 );
			fn_v_CopyVect(	stReadFrame.a3_xScaleValues,	a3_xVector0 );
			fn_v_CopyVect(	stReadFrame.a3_xPosition,		a3_xVector0 );

			stReadFrame.ucTransparency=0xFF;

			slNumCHL=	ReadUShort(0);
			slCnt=	0;

			// Channel name search is case sensitive !!!
			while ((slCnt < slMaxInChannel) &&
				   (stricmp(ax_xChannelNames[slCnt],ax_xStrings[M_GetStackAlloc(eStackBinStrings) + slNumCHL]))) 
				slCnt++;

			if	(slCnt < slMaxInChannel) {	
				ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].uwChannelNumber=	(unsigned short) slCnt;

				if	(ax_uwChannelAlreadyUsed[slCnt] == 1)
					fprintf( ErrorFile, "%s :  Channel Name (%s) already used in animation (Channel %d) : possible error !!!\n", AnimationName, ax_xChannelNames[slCnt], (slWaitedChannelNumber+1) );
				
				ax_uwChannelAlreadyUsed[slCnt]=	1;
			}
			// unknow channel name
			else 
				ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].uwChannelNumber =	UNKNOW_CHANNEL;

			slLastFrame=	0;
		}
	}

	// We are in the section
	else if	(_eAction == SCR_EA_Anl_Entry)
	{
		if	(uwOkAnimationFile == 0)
		{
			if	( !stricmp(_p_szName, "TrajectorySettings") )
			{	// Editor datas
			}
			else if	( !stricmp(_p_szName, "ActiveStatus") )
			{	// Editor datas
			}
			else if	( !stricmp(_p_szName, "IsCamera") )
			{	// Editor datas
			}
			// Unknown field
			else	fprintf( ErrorFile, "%s :  Unknown field in A3d file (%s) (Channel %d)\n", AnimationName, _p_szName, (slWaitedChannelNumber+1) );
		}
	}

	// End of section
	else if	(_eAction == SCR_EA_Anl_EndSection)
	{	if	(uwOkAnimationFile == 0)
		{	signed long	slCnt;
			tdxMatrix33		a3a3_xScaleMatrix, a3a3_xMtxSca, a3a3_xMtxOri;
			tdxVector3		a3_xTmpVec;

			// Invalid unknow channel channel 
			if (ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].uwChannelNumber == UNKNOW_CHANNEL) 
				ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].uwChannelNumber =	SEB_Invalid;

			slWaitedChannelNumber++;

			// Set other values
			fn_v_QuatToMatrix( a3a3_xMtxSca, stReadFrame.a4_xQuatSca );
			fn_v_QuatToMatrix( a3a3_xMtxOri, stReadFrame.a4_xQuatOri );
			fn_v_InvRotDiaRot( a3a3_xScaleMatrix, a3a3_xMtxSca, stReadFrame.a3_xScaleValues );
			fn_v_MatrixByVector( a3_xTmpVec, a3a3_xScaleMatrix, ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].a3_xLocalPivotPos );
			fn_v_MatrixByVector( stReadFrame.a3_xWorldPivotPosition, a3a3_xMtxOri, a3_xTmpVec  );
			stReadFrame.a3_xWorldPivotPosition[0]+= stReadFrame.a3_xPosition[0];
			stReadFrame.a3_xWorldPivotPosition[1]+= stReadFrame.a3_xPosition[1];
			stReadFrame.a3_xWorldPivotPosition[2]+= stReadFrame.a3_xPosition[2];
			stReadFrame.xDistMaster=	fn_x_VectorLength( stReadFrame.a3_xPosition );
			stReadFrame.uwFrameNumber=	(unsigned short) slCurrentFrame;

			// Copy datas to Table
			stReadFrame.uwMask=			0x0000;
			stReadFrame.uwAttribute=	0;

			// On copie les frames jusqu'à la dernière frame
			ax_tdstFrames[M_GetStackAlloc(eStackBinFrames) + slLastFrame].uwFrameNumber=	(unsigned short) slLastFrame;
			for	( slCnt=slLastFrame+1 ; slCnt<p_stGENERAL->uwNumberOfFrames ; slCnt++ )
			{	ax_tdstFrames[M_GetStackAlloc(eStackBinFrames) + slCnt]=
					ax_tdstFrames[M_GetStackAlloc(eStackBinFrames) + slLastFrame];
				ax_tdstFrames[M_GetStackAlloc(eStackBinFrames) + slCnt].uwAttribute=	0x0000;
				ax_tdstFrames[M_GetStackAlloc(eStackBinFrames) + slCnt].uwFrameNumber=	(unsigned short) slCnt;
			}
			slLastFrame= slCurrentFrame;

#ifdef	ShowInfos
			fn_v_LogSectionEnd();
#endif
			if	(slWaitedChannelNumber == p_stGENERAL->uwNumberOfChannels)
			{
				if	(p_stGENERAL->uwNumberOfFrames > 2)
				{
					if	(uwNbReadedKeys == 0)
						fprintf( WarningFile, "%s :  this animation is optimized ???\n", AnimationName );
				}
			}
		}
	}

	return	SCR_ERV_Anl_NormalReturn;
}



// **********************************************************************************
//								FRAME CALLBACK
// **********************************************************************************
// Modif 27/08/98 : Alloc Morph element and fill new structure - Carlos Torres
SCR_tde_Anl_ReturnValue	fn_eFrameCallBackV6i(	SCR_tdst_File_Description	*_p_stFile,
												char						*_p_szName,
												char						*_ap_SzParam[],
												SCR_tde_Anl_Action			_eAction )
{	static	unsigned short	uwEventType;

	// Section already analysed
	if	(_eAction == SCR_EA_Anl_AlreadyAnalysed)
	{	if	(uwOkAnimationFile == 0)
		{	fprintf( ErrorFile, "%s :  Frame already analysed (Channel %d, Frame %d)\n", AnimationName, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
		}
	}

	// Beginning of section
	else if	(_eAction == SCR_EA_Anl_BeginSection)
	{	if	(uwOkAnimationFile == 0)
		{
			uwEventType=	0;

#ifdef	ShowInfos
			fn_v_LogSectionBegin(	D_BINSCR_LogNew,
									"Frame",
									AnimationName );
#endif

			slCurrentFrame=	(atoi(_p_szName) - 1);
			stReadFrame.uwFrameNumber=	0;
		}
	}

	// We are in the section
	else if	(_eAction == SCR_EA_Anl_Entry)
	{
		if	(uwOkAnimationFile == 0)
		{
			// ObjectType
			if	( !stricmp(_p_szName, "ObjectType") )
			{	// String : Object type
				// No SubAnim

				//	unsigned short	uwTypeOfObject
				if	(( !stricmp(_ap_SzParam[0], "3dObject"))||( !stricmp(_ap_SzParam[0], "Morphed"))) {	
					stReadFrame.uwTypeOfObject=	TE_GraphicObject;
					// check if channel is valid
					if (ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].uwChannelNumber == UNKNOW_CHANNEL) {
						fprintf(ErrorFile,"%s : Channel Name not found (Channel %d)\n",AnimationName,slWaitedChannelNumber+1);
						ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].uwChannelNumber = SEB_Invalid;
					}
				}
				else if	( !stricmp(_ap_SzParam[0], "Light") ) {	
					stReadFrame.uwTypeOfObject=	TE_Light;
					fprintf(ErrorFile,"%s : Light Object isn't suported (Channel %d, Frame %d)\n",AnimationName,slWaitedChannelNumber+1,slCurrentFrame+1);
				}
				else if	( !stricmp(_ap_SzParam[0], "SoundEvent") ) {
					stReadFrame.uwTypeOfObject=	TE_Event;				// Transform to simple event
					uwEventType=	C_ucSOUND_EVENT;
				}
				else if	( !stricmp(_ap_SzParam[0], "CameraEvent") ) {
					stReadFrame.uwTypeOfObject=	TE_Event;				// Transform to simple event
					fprintf(ErrorFile,"%s : Camera Event isn't suported (Channel %d, Frame %d)\n",AnimationName,slWaitedChannelNumber+1,slCurrentFrame+1);
				}
				else if	( !stricmp(_ap_SzParam[0], "GenericEvent") ) {
					stReadFrame.uwTypeOfObject=	TE_Event;				// Transform to simple event
					uwEventType=	C_ucGENERIC_EVENT;
					// check if channel is valid
					if (ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].uwChannelNumber == UNKNOW_CHANNEL) {
						fprintf(ErrorFile,"%s : Channel Name not found (Channel %d)\n",AnimationName,slWaitedChannelNumber+1);
						ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].uwChannelNumber = SEB_Invalid;
					}
				}
				else if	( !stricmp(_ap_SzParam[0], "GenerateEvent") ) {	
					stReadFrame.uwTypeOfObject=	TE_Event;				// Transform to simple event
					uwEventType=				C_ucGENERATE_EVENT;
					// check if channel is valid
					if (ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].uwChannelNumber == UNKNOW_CHANNEL) {
						fprintf(ErrorFile,"%s : Channel Name not found (Channel %d)\n",AnimationName,slWaitedChannelNumber+1);
						ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].uwChannelNumber = SEB_Invalid;
					}
				}
				else if	( !stricmp(_ap_SzParam[0], "MechanicEvent") ) {	
					stReadFrame.uwTypeOfObject=	TE_Event;				// Transform to simple event
					uwEventType=				C_ucMECHANIC_EVENT;
					fprintf(ErrorFile,"%s : Machanic Event isn't supported (Channel %d, Frame %d)\n",AnimationName,slWaitedChannelNumber+1,slCurrentFrame+1);
				}
				else if	( !stricmp(_ap_SzParam[0], "Fake") ) {
					stReadFrame.uwTypeOfObject=		TE_Fake;
					// check if channel is valid
					if (ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].uwChannelNumber == UNKNOW_CHANNEL) {
						fprintf(ErrorFile,"%s : Channel Name not found (Channel %d)\n",AnimationName,slWaitedChannelNumber+1);
						ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].uwChannelNumber = SEB_Invalid;
					}
				}
				else if	( !stricmp(_ap_SzParam[0], "Empty") ) {
					stReadFrame.uwTypeOfObject=		TE_EmptyObject;
					stReadFrame.swNumberInTable=	-1;
				}
				else if	( !stricmp(_ap_SzParam[0], "Undefined") ) {
					stReadFrame.uwTypeOfObject=		TE_Undefined;
					fprintf(WarningFile,"%s : ObjectType is undefined (Channel %d, Frame %d)\n",AnimationName,slWaitedChannelNumber+1,slCurrentFrame+1);
					
				}
				else
				{	stReadFrame.swNumberInTable=	-1;
					stReadFrame.uwTypeOfObject=		TE_EmptyObject;
					fprintf( ErrorFile, "%s :  Unknow type of object (%s) (Channel %d, Frame %d)\n", AnimationName, _ap_SzParam[0], (slWaitedChannelNumber+1), (slCurrentFrame+1) );
				}
			}

			// Bank
			else if	( !stricmp(_p_szName, "Bank") )
			{	// Integer
				// Not used -------
			}

			// Object
			else if	( !stricmp(_p_szName, "Object") )
			{	// Reference to StringsTable (Name of object)
				// Not used
			}

			// NumberInTable
			else if	( !stricmp(_p_szName, "NumberInTable") ) {
				// set number in table and object presence in anim 
				stReadFrame.swNumberInTable=	(signed short)(ReadUShort(0)-1);
				ax_tdstTabTBL[stReadFrame.swNumberInTable].ucFlag |= OBJECT_IN_ANIM;

				if	(stReadFrame.swNumberInTable >= 0)
				{
					// objet non present dans la TBL
					if	(!(ax_tdstTabTBL[stReadFrame.swNumberInTable].ucFlag & OBJECT_IN_TBL))
					{	fprintf( ErrorFile, "%s : NumberInTable #%d not existing in Table of Objects (Channel %d, Frame %d)\n", AnimationName, (stReadFrame.swNumberInTable+1), (slWaitedChannelNumber+1), (slCurrentFrame+1) );
						stReadFrame.uwTypeOfObject=		TE_EmptyObject;
						stReadFrame.swNumberInTable=	-1;
						ax_tdstTabTBL[stReadFrame.swNumberInTable].ucFlag &= ~OBJECT_IN_ANIM;
					}
					// object undefined choose depending on TBL
					else if (stReadFrame.uwTypeOfObject == TE_Undefined) {
						stReadFrame.uwTypeOfObject = (ax_tdstTabTBL[stReadFrame.swNumberInTable].ucIsObject)?TE_GraphicObject:TE_Event;
					}
					// type Object and Event in TBL !! Strange
					else if	((stReadFrame.uwTypeOfObject == TE_GraphicObject) &&
							(!ax_tdstTabTBL[stReadFrame.swNumberInTable].ucIsObject) )
					{	
						stReadFrame.uwTypeOfObject=		TE_Event;
						fprintf( ErrorFile, "%s : 3dObject in A3d, Not a 3dObject in Object Table (NumberInTable %d, Channel %d, Frame %d)\n", AnimationName, (stReadFrame.swNumberInTable+1), (slWaitedChannelNumber+1), (slCurrentFrame+1) );
					}
					// type Event and Object in TBL !! Strange
					else if	((stReadFrame.uwTypeOfObject == TE_Event) &&
							(ax_tdstTabTBL[stReadFrame.swNumberInTable].ucIsObject) )
					{	
						stReadFrame.uwTypeOfObject=		TE_GraphicObject;
						fprintf( ErrorFile, "%s : Event in A3d, 3dObject in Object Table (NumberInTable %d, Channel %d, Frame %d)\n", AnimationName, (stReadFrame.swNumberInTable+1), (slWaitedChannelNumber+1), (slCurrentFrame+1) );
					}
				}
			}

			// IncludingBox
			else if ( !stricmp(_p_szName, "IncludingBox") )
			{	// Reference to vector + reference to vector
				// Not used
			}

			// Position
			else if ( !stricmp(_p_szName, "Position") )
			{	// Reference to vector
				fn_v_CopyVect( stReadFrame.a3_xPosition, axa3_xVertexes[M_GetStackAlloc(eStackBinVertexes) + ReadUShort(0)] );
			}

			// Orientation
			else if	( !stricmp(_p_szName, "Orientation") )
			{	// Reference to quaternion
				fn_v_CopyQuat( stReadFrame.a4_xQuatOri, axa4_xBinQuaternions[M_GetStackAlloc(eStackBinQuaternions) + ReadUShort(0)] );
			}

			// Scale
			else if	( !stricmp(_p_szName, "Scale") )
			{	// Reference to quaternions
				fn_v_CopyQuat( stReadFrame.a4_xQuatSca, axa4_xBinQuaternions[M_GetStackAlloc(eStackBinQuaternions) + ReadUShort(0)] );
				// Reference to vector
				fn_v_CopyVect( stReadFrame.a3_xScaleValues, axa3_xVertexes[M_GetStackAlloc(eStackBinVertexes) + ReadUShort(1)] );
			}

			// PivotPosition
			else if	( !stricmp(_p_szName, "PivotPosition") )
			{	// Reference to vector
				if	( uwPivotDefined == 0 )
				{	uwPivotDefined=	1;
					fn_v_CopyVect(	ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].a3_xLocalPivotPos,
									axa3_xVertexes[M_GetStackAlloc(eStackBinVertexes) + ReadUShort(0)] );
				}
				else
				{	if	( fn_uw_CompVect(	ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].a3_xLocalPivotPos,
											axa3_xVertexes[M_GetStackAlloc(eStackBinVertexes) + ReadUShort(0)] ) != 0 )
						fprintf(WarningFile, "%s :  PivotPosition is changed, changing is ignore (Channel %d, Frame %d)\n", AnimationName, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
				}
			}

			// PivotOrientation
			else if	( !stricmp(_p_szName, "PivotOrientation") )
			{	SEB_xReal	*p_tdxQuat;

				// Reference to quaternion
				// Must be equal to identity in this version !
				p_tdxQuat=	&axa4_xBinQuaternions[M_GetStackAlloc(eStackBinQuaternions) + ReadUShort(0)][0];
				//if ( (p_tdxQuat[0]!=xZero) || (p_tdxQuat[1]!=xZero) || (p_tdxQuat[2]!=xZero) || (p_tdxQuat[3]!=xOne) )
				//	fprintf( ErrorFile, "%s :  PivotOrientation must be equal to Identity (Channel %d, Frame %d)\n", AnimationName, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
				fn_v_CopyQuat( axa4_xBinQuaternions[M_GetStackAlloc(eStackBinQuaternions) + ReadUShort(0)], a4_xQuater1 );
			}

			// Morphing AR980304
			else if	( !stricmp(_p_szName, "Morphing") )
			{
				unsigned short uwTargetObjectNumber=(unsigned short)(ReadUChar(0)-1);
					
				if	(!(ax_tdstTabTBL[uwTargetObjectNumber].ucFlag  & OBJECT_IN_TBL) ||
					 (!ax_tdstTabTBL[uwTargetObjectNumber].ucIsObject) ) 
				{	
					fprintf( ErrorFile, "%s :  Morphing Target #%d not existing in Table of Objects (Channel %d, Frame %d)\n", 
						AnimationName, uwTargetObjectNumber+1, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
				}
				else {
					ax_tdstTabTBL[uwTargetObjectNumber].ucFlag |= OBJECT_IN_ANIM;

				// Add 1 Morphing info
				fn_v_AllocateOnStack(eStackBinMorphInformation,1);
				p_stGENERAL->uwNumberOfMorphData++;

				// Fill the array
				ax_tdstBinMorphInfos[M_GetStackAlloc(eStackBinMorphInformation)].ucTarget=(unsigned char)(ReadUChar(0)-1);
				ax_tdstBinMorphInfos[M_GetStackAlloc(eStackBinMorphInformation)].ucMorphingAmount=ReadUChar(1);
				ax_tdstBinMorphInfos[M_GetStackAlloc(eStackBinMorphInformation)].uwChannelNumber=ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].uwChannelNumber;
				ax_tdstBinMorphInfos[M_GetStackAlloc(eStackBinMorphInformation)].uwFrameNumber=(unsigned short)slCurrentFrame;
			}
			}

			// Transparency
			else if	( !stricmp(_p_szName, "Transparency") ) {
				unsigned short uwTransparency = ReadUShort(0);

				if	(uwTransparency > 255) {
					uwTransparency = 255;
					fprintf( ErrorFile, "%s :  Transparency %d > 255 (Channel %d, Frame %d)\n", AnimationName,uwTransparency, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
				}
				stReadFrame.ucTransparency = (unsigned char)uwTransparency;
			}

			// FakeProperties
			else if ( !stricmp(_p_szName, "FakeProperties") ) {
			} // Nothing To do
			
			// Unknown field
			else {
				fprintf( ErrorFile, "%s :  Unknown field in A3d (%s) (Channel %d, Frame %d)\n", AnimationName, _p_szName, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
			}
		}
	}

	// End of section
	else if	(_eAction == SCR_EA_Anl_EndSection)
	{	if	(uwOkAnimationFile == 0)
		{	signed long		slCnt;
			tdxMatrix33		a3a3_xScaleMatrix, a3a3_xMtxSca, a3a3_xMtxOri;
			tdxVector3		a3_xTmpVec;

			// Copy Event (if we have an event of course !)
			if	((stReadFrame.uwTypeOfObject & 0x00FF) == TE_Event)
			{
				if	(stReadFrame.swNumberInTable < 0)
				{	stReadFrame.uwTypeOfObject=	(stReadFrame.uwTypeOfObject & 0xFF00) | TE_EmptyObject;
					fprintf( ErrorFile, "%s :  NumberInTable #%d not valid for event\n", AnimationName, (stReadFrame.swNumberInTable+1) );
				}
				else
				{	unsigned short	uwNumOfEntry;
					signed long		slEventInd;

					fn_v_AllocateOnStack( eStackBinEvent, 1 );
					slEventInd=		M_GetStackAlloc(eStackBinEvent);
					uwNumOfEntry=	stReadFrame.swNumberInTable;
					ax_tdstEvents[slEventInd].usEventNumberInTBL=	uwNumOfEntry;
					ax_tdstEvents[slEventInd].uwFrameNumber=	(unsigned short) slCurrentFrame;
					ax_tdstEvents[slEventInd].uwChannelNumber=	ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].uwChannelNumber;


					p_stGENERAL->uwNumberOfEvents++;
				}
			}

			// Set other values
			fn_v_QuatToMatrix( a3a3_xMtxSca, stReadFrame.a4_xQuatSca );
			fn_v_QuatToMatrix( a3a3_xMtxOri, stReadFrame.a4_xQuatOri );
			fn_v_InvRotDiaRot( a3a3_xScaleMatrix, a3a3_xMtxSca, stReadFrame.a3_xScaleValues );
			fn_v_MatrixByVector( a3_xTmpVec, a3a3_xScaleMatrix, ax_tdstChannels[p_stGENERAL->slNumOfChannels + slWaitedChannelNumber].a3_xLocalPivotPos );
			fn_v_MatrixByVector( stReadFrame.a3_xWorldPivotPosition, a3a3_xMtxOri, a3_xTmpVec  );
			stReadFrame.a3_xWorldPivotPosition[0]+= stReadFrame.a3_xPosition[0];
			stReadFrame.a3_xWorldPivotPosition[1]+= stReadFrame.a3_xPosition[1];
			stReadFrame.a3_xWorldPivotPosition[2]+= stReadFrame.a3_xPosition[2];
			stReadFrame.xDistMaster=	fn_x_VectorLength( stReadFrame.a3_xPosition );
			stReadFrame.uwFrameNumber=	(unsigned short) slCurrentFrame;

			// Copy datas to Table
			ax_tdstFrames[M_GetStackAlloc(eStackBinFrames) + slCurrentFrame]=	stReadFrame;
			stReadFrame.uwMask=			0x0000;
			stReadFrame.uwAttribute=	0;

			// On copie les frames jusqu'à la dernière frame
			for	( slCnt=slLastFrame+1 ; slCnt<slCurrentFrame ; slCnt++ )
			{	ax_tdstFrames[M_GetStackAlloc(eStackBinFrames) + slCnt]=
					ax_tdstFrames[M_GetStackAlloc(eStackBinFrames) + slLastFrame];
				ax_tdstFrames[M_GetStackAlloc(eStackBinFrames) + slCnt].uwAttribute=	0x0000;
				ax_tdstFrames[M_GetStackAlloc(eStackBinFrames) + slCnt].uwFrameNumber=	(unsigned short) slCnt;
			}
			slLastFrame= slCurrentFrame;

#ifdef	ShowInfos
			fn_v_LogSectionEnd();
#endif
		}
	}

	return	SCR_ERV_Anl_NormalReturn;
}



// **********************************************************************************
//								KEY CALLBACK
// **********************************************************************************
// Modif 27/08/98 : Treat Morphing Entry (do nothing)
// Modif 28/08/98 : Treat Interpolation - type 1 (Non Linear)
SCR_tde_Anl_ReturnValue	fn_eKeyCallBackV6i(	SCR_tdst_File_Description	*_p_stFile,
											char						*_p_szName,
											char						*_ap_SzParam[],
											SCR_tde_Anl_Action			_eAction )
{
	// Section already analysed
	if	(_eAction == SCR_EA_Anl_AlreadyAnalysed)
	{	if	(uwOkAnimationFile == 0)
		{	fprintf( ErrorFile, "%s :  Key already analysed (Channel %d, Frame %d)\n", AnimationName, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
		}
	}

	// Beginning of section
	else if	(_eAction == SCR_EA_Anl_BeginSection)
	{	if	(uwOkAnimationFile == 0)
		{

#ifdef	ShowInfos
			fn_v_LogSectionBegin(	D_BINSCR_LogNew,
									"Key",
									AnimationName );
#endif
			uwNbReadedKeys++;
		}
	}

	// We are in the section
	else if	(_eAction == SCR_EA_Anl_Entry)
	{
		if	(uwOkAnimationFile == 0)
		{
			// Attribute
			if	( !stricmp(_p_szName, "Attribute") )
			{	// Integer
				stReadFrame.uwAttribute=	ReadUShort(0);	// Key type (0= none, 1= simple, 2=double)
			}

			// Mask
			else if ( !stricmp(_p_szName, "Mask") )
			{	unsigned short	uwMask;
				SEB_xReal		*p_tdxVertex;

				// Reference to vector (3 times)
				uwMask=			0L;
				p_tdxVertex=	&axa3_xVertexes[M_GetStackAlloc(eStackBinVertexes) + ReadUShort(0)][0];
				uwMask|=		((signed long) p_tdxVertex[0])<<10;
				uwMask|=		((signed long) p_tdxVertex[1])<<9;
				uwMask|=		((signed long) p_tdxVertex[2])<<8;
				p_tdxVertex=	&axa3_xVertexes[M_GetStackAlloc(eStackBinVertexes) + ReadUShort(1)][0];
				uwMask|=		((signed long) p_tdxVertex[0])<<6;
				uwMask|=		((signed long) p_tdxVertex[1])<<5;
				uwMask|=		((signed long) p_tdxVertex[2])<<4;
				p_tdxVertex=	&axa3_xVertexes[M_GetStackAlloc(eStackBinVertexes) + ReadUShort(2)][0];
				uwMask|=		((signed long) p_tdxVertex[0])<<2;
				uwMask|=		((signed long) p_tdxVertex[1])<<1;
				uwMask|=		((signed long) p_tdxVertex[2]);
				stReadFrame.uwMask=		uwMask;
			}

			// Type (of interpolation, 0= linear)
			else if ( !stricmp(_p_szName, "Type") ) {
				unsigned long	ulInterpolation;
				SEB_xReal		xInterpolation;

				ulInterpolation=	ReadULong(0);
				if	(ulInterpolation == 0)						// Linear interpolation
				{	stReadFrame.xInterpolationParameter=	0.0;
				}
				// Non linear interpolation
				else if	(ulInterpolation == 1) {
					xInterpolation=	axa4_xBinQuaternions[M_GetStackAlloc(eStackBinQuaternions) + ReadULong(2)][0];
					if	(xInterpolation < 0.0) {
						xInterpolation=	0.0;
						fprintf( ErrorFile, "%s :  Interpolation (mode 1) parameter is less than 0, and will set to 0 (Channel %d, Frame %d)\n", AnimationName, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
					}
					else if	(xInterpolation > 1.0) {
						xInterpolation=	1.0;
						fprintf( ErrorFile, "%s :  Interpolation (mode 1) parameter is greater than 1, and will set to 1 (Channel %d, Frame %d)\n", AnimationName, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
					}
					stReadFrame.xInterpolationParameter = (SEB_xReal)(2.0 - (4.0 * xInterpolation));
				}
				else											// Unknow interpolation type
					fprintf( ErrorFile, "%s :  Interpolation type is not equal to 0 (linear) (Channel %d, Frame %d)\n", AnimationName, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
			}

			// Morphing
			else if ( !stricmp(_p_szName, "Morphing") ) {
			} // Nothing To do

			// Unknown field
			else
			{	fprintf( ErrorFile, "%s :  Unknown field in A3d (%s) (Channel %d, Frame %d)\n", AnimationName, _p_szName, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
			}
		}
	}

	// End of section
	else if	(_eAction == SCR_EA_Anl_EndSection)
	{
		if	(uwOkAnimationFile == 0)
		{
#ifdef	ShowInfos
			fn_v_LogSectionEnd();
#endif
		}
	}

	return	SCR_ERV_Anl_NormalReturn;
}



// **********************************************************************************
//								SPEED LIST CALLBACK
// **********************************************************************************
SCR_tde_Anl_ReturnValue	fn_eSpeedsListCallBackV6i(	SCR_tdst_File_Description	*_p_stFile,
													char						*_p_szName,
													char						*_ap_SzParam[],
													SCR_tde_Anl_Action			_eAction )
{
	// Section already analysed
	if	(_eAction == SCR_EA_Anl_AlreadyAnalysed)
	{	if	(uwOkAnimationFile == 0)
		{	fprintf( ErrorFile, "%s :  SpeedsList already analysed (Channel %d, Frame %d)\n", AnimationName, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
		}
	}

	// Beginning of section
	else if	(_eAction == SCR_EA_Anl_BeginSection)
	{
		if	(uwOkAnimationFile == 0)
		{	signed long	slCnt;

#ifdef	ShowInfos
			fn_v_LogSectionBegin(	D_BINSCR_LogNew,
									"SpeedsList",
									AnimationName );
#endif
			// Initialise memory
			fn_v_CopyQuat( ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames)].tdxAngularSpeedQuat,	a4_xQuater1	);
			fn_v_CopyVect( ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames)].tdxSpeedVector,		a3_xVector0	);
			slLastFrame=	0;

			for	( slCnt=0 ; slCnt<p_stGENERAL->uwNumberOfFrames ; slCnt++ )
			{	ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slCnt].slNumOfAngularSpeedQuat=	0xFFFFFFFF;
				ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slCnt].slNumOfSpeedVector=			0xFFFFFFFF;
			}
		}
	}

	// We are in the section
	else if	(_eAction == SCR_EA_Anl_Entry)
	{
		if	(uwOkAnimationFile == 0)
		{
			// Unknown field
			fprintf( ErrorFile, "%s :  Unknown field in A3d file, SpeedsList (%s) (Channel %d, Frame %d)\n", AnimationName, _p_szName, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
		}
	}

	// End of section
	else if	(_eAction == SCR_EA_Anl_EndSection)
	{
		if	(uwOkAnimationFile == 0)
		{	unsigned long	ulFrameNumber, ulLastFrameNumber;

			ulLastFrameNumber=	M_GetStackAlloc(eStackBinOnlyFrames);
			// SpeedQuaternion
			for	( ulFrameNumber=0 ; ulFrameNumber<p_stGENERAL->uwNumberOfFrames ; ulFrameNumber++ )
			{
				if	(ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + ulFrameNumber].slNumOfAngularSpeedQuat != 0xFFFFFFFF)
				{	break;
				}
			}
			if	(ulFrameNumber < p_stGENERAL->uwNumberOfFrames)
			{
				ulLastFrameNumber=	0;
				if	(ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames)].slNumOfAngularSpeedQuat == 0xFFFFFFFF)
				{	fn_v_SetIdQuater( ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames)].tdxAngularSpeedQuat );
					ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames)].slNumOfAngularSpeedQuat=	0;
				}

				// Fill gaps between AngularSpeed changes.
				for	( ulFrameNumber=1 ; ulFrameNumber<p_stGENERAL->uwNumberOfFrames ; ulFrameNumber++ )
				{
					if	(ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + ulFrameNumber].slNumOfAngularSpeedQuat == 0xFFFFFFFF)
					{
						fn_v_CopyQuat(	ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + ulFrameNumber    ].tdxAngularSpeedQuat,
										ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + ulLastFrameNumber].tdxAngularSpeedQuat );
						ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + ulFrameNumber].slNumOfAngularSpeedQuat=	0;
					}
					else
					{	ulLastFrameNumber=	ulFrameNumber;
					}
				}
			}
			else
				printf("Pas de speed\n");

			// SpeedVector
			for	( ulFrameNumber=0 ; ulFrameNumber<p_stGENERAL->uwNumberOfFrames ; ulFrameNumber++ )
			{
				if	(ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + ulFrameNumber].slNumOfSpeedVector != 0xFFFFFFFF)
				{	break;
				}
			}
			if	(ulFrameNumber < p_stGENERAL->uwNumberOfFrames)
			{
				ulLastFrameNumber=	0;
				if	(ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames)].slNumOfSpeedVector == 0xFFFFFFFF)
				{	fn_v_SetIdQuater( ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames)].tdxSpeedVector );
					ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames)].slNumOfSpeedVector=	0;
				}

				// Fill gaps between AngularSpeed changes.
				for	( ulFrameNumber=1 ; ulFrameNumber<p_stGENERAL->uwNumberOfFrames ; ulFrameNumber++ )
				{
					if	(ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + ulFrameNumber].slNumOfSpeedVector == 0xFFFFFFFF)
					{
						fn_v_CopyVect(	ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + ulFrameNumber    ].tdxSpeedVector,
										ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + ulLastFrameNumber].tdxSpeedVector );
						ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + ulFrameNumber].slNumOfSpeedVector=	0;
					}
					else
					{	ulLastFrameNumber=	ulFrameNumber;
					}
				}
			}
			else
				printf("Pas de speed\n");

#ifdef	ShowInfos
			fn_v_LogSectionEnd();
#endif
		}
	}

	return	SCR_ERV_Anl_NormalReturn;
}



// **********************************************************************************
//								SPEED CALLBACK
// **********************************************************************************
SCR_tde_Anl_ReturnValue	fn_eSpeedCallBackV6i(	SCR_tdst_File_Description	*_p_stFile,
												char						*_p_szName,
												char						*_ap_SzParam[],
												SCR_tde_Anl_Action			_eAction )
{
	// Section already analysed
	if	(_eAction == SCR_EA_Anl_AlreadyAnalysed) {	
		if	(uwOkAnimationFile == 0) {	
			fprintf( ErrorFile, "%s :  Speed already analysed (Channel %d, Frame %d)\n", 
				AnimationName, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
		}
	}

	// Beginning of section
	else if	(_eAction == SCR_EA_Anl_BeginSection)
	{	if	(uwOkAnimationFile == 0)
		{
#ifdef	ShowInfos
			fn_v_LogSectionBegin(	D_BINSCR_LogNew,
									"Speed",
									AnimationName );
#endif

			// Readed Frame
			slCurrentFrame=	(atoi(_p_szName) - 1);
		}
	}

	// We are in the section
	else if	(_eAction == SCR_EA_Anl_Entry)
	{	if	(uwOkAnimationFile == 0)
		{
			// RotationSpeed
			if	( !stricmp(_p_szName, "RotationSpeed") )
			{	// Reference to quaternion
				fn_v_CopyQuat(	ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slCurrentFrame].tdxAngularSpeedQuat,
								axa4_xBinQuaternions[M_GetStackAlloc(eStackBinQuaternions) + ReadUShort(0)] );
				ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slCurrentFrame].slNumOfAngularSpeedQuat=	0;
			}

			// TranslationSpeed
			else if ( !stricmp(_p_szName, "TranslationSpeed") )
			{	// Reference to vector
				fn_v_CopyVect(	ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slCurrentFrame].tdxSpeedVector,
								axa3_xVertexes[M_GetStackAlloc(eStackBinVertexes) + ReadUShort(0)] );
				ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slCurrentFrame].slNumOfSpeedVector=	0;
			}

			// Unknown field
			else
			{	fprintf( ErrorFile, "%s :  Unknown field in A3d, SpeedsList, Speed (%s) (Channel %d, Frame %d)\n", AnimationName, _p_szName, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
			}
		}
	}

	// End of section
	else if	(_eAction == SCR_EA_Anl_EndSection)
	{	if	(uwOkAnimationFile == 0)
		{
			slLastFrame=	slCurrentFrame;
#ifdef	ShowInfos
			fn_v_LogSectionEnd();
#endif
		}
	}

	return	SCR_ERV_Anl_NormalReturn;
}



// **********************************************************************************
//								HIERARCHIES LIST CALLBACK
// **********************************************************************************
SCR_tde_Anl_ReturnValue	fn_eHierarchiesListCallBackV6i(	SCR_tdst_File_Description	*_p_stFile,
														char						*_p_szName,
														char						*ap_SzParam[],
														SCR_tde_Anl_Action			_eAction )
{
	// Section already analysed
	if	(_eAction == SCR_EA_Anl_AlreadyAnalysed)
	{	if	(uwOkAnimationFile == 0)
		{	fprintf( ErrorFile, "%s :  HierarchiesList already analysed (Channel %d, Frame %d)\n", AnimationName, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
		}
	}

	// Beginning of section
	else if	(_eAction == SCR_EA_Anl_BeginSection)
	{
		if	(uwOkAnimationFile == 0)
		{
#ifdef	ShowInfos
			fn_v_LogSectionBegin(	D_BINSCR_LogNew,
									"Hierarchy",
									AnimationName );
#endif
			// Initialise memory
			p_stGENERAL->slNumOfHierarchies=	M_GetStackPos(eStackBinHierarchies);
			p_stGENERAL->uwNumberOfHierarchies=	0;
			slLastFrame=	0;
			uwHierDef=		0;
			ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames)].uwHierarchyNbCouples=	0;
		}
	}

	// We are in the section
	else if	(_eAction == SCR_EA_Anl_Entry)
	{	if	(uwOkAnimationFile == 0)
		{
			// Unknown field
			fprintf( ErrorFile, "%s :  Unknown field in A3d file, HierarchiesList (%s) (Channel %d, Frame %d)\n", AnimationName, _p_szName, (slWaitedChannelNumber+1), (slCurrentFrame+1) );
		}
	}

	// End of section
	else if	(_eAction == SCR_EA_Anl_EndSection)
	{	if	(uwOkAnimationFile == 0)
		{	signed long	slCnt;

			// On copie les Hierarchy de la dernière frame jusqu'à celle-ci
			for	( slCnt=slLastFrame+1 ; slCnt<p_stGENERAL->uwNumberOfFrames ; slCnt++ )
			{	ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slCnt].uwHierarchyNbCouples=
					ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slLastFrame].uwHierarchyNbCouples;
				ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slCnt].slNumOfHierarchyCouples=
					ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slLastFrame].slNumOfHierarchyCouples;
			}

			p_stGENERAL->uwNumberOfHierarchies=	(unsigned short) (M_GetStackPos(eStackBinHierarchies) - p_stGENERAL->slNumOfHierarchies);

#ifdef	ShowInfos
			fn_v_LogSectionEnd();
#endif
		}
	}

	return	SCR_ERV_Anl_NormalReturn;
}



// **********************************************************************************
unsigned long	fn_uw_CompareHierarchy(	signed long	slOldFrame,
										signed long	slNewFrame	)
{	signed long	slCnt1, slCnt2, slCnt3;

	if	( ax_tdstOnlyFrames[slOldFrame].uwHierarchyNbCouples == ax_tdstOnlyFrames[slNewFrame].uwHierarchyNbCouples )
	{
		// For all hierarchy couples in CurrentFrame
		for	( slCnt1=0 ; slCnt1<ax_tdstOnlyFrames[slNewFrame].uwHierarchyNbCouples ; slCnt1++ )
		{	// For all hierarchy couples in OldFrame
			slCnt2=	0;
			slCnt3=	0;
			while	( (slCnt2<ax_tdstOnlyFrames[slOldFrame].uwHierarchyNbCouples) && (slCnt3==0) )
			{	if	( (	ax_tdstHierarchies[ ax_tdstOnlyFrames[slNewFrame].slNumOfHierarchyCouples + slCnt1 ].uwChild  ==
						ax_tdstHierarchies[ ax_tdstOnlyFrames[slOldFrame].slNumOfHierarchyCouples + slCnt2 ].uwChild  )	&&
					  (	ax_tdstHierarchies[ ax_tdstOnlyFrames[slNewFrame].slNumOfHierarchyCouples + slCnt1 ].uwFather ==
						ax_tdstHierarchies[ ax_tdstOnlyFrames[slOldFrame].slNumOfHierarchyCouples + slCnt2 ].uwFather )	)
					slCnt3=	1;
				slCnt2++;
			}
			// If not found
			if	( slCnt3==0)
				return	1;
		}
		return	0;
	}
	return	1;
}



signed long		fn_uw_HierarchyIsDefined(	signed long	slFirstFrame,
											signed long	slNewFrame	)
{	signed long	slCnt1, slLastHier;

	// Search hierarchy before this frame
	slLastHier=	SEB_Invalid;
	for	( slCnt1=slFirstFrame ; slCnt1<slNewFrame ; slCnt1++ )
	{	if	( (ax_tdstOnlyFrames[slCnt1].slNumOfHierarchyCouples != slLastHier) && (ax_tdstOnlyFrames[slCnt1].uwHierarchyNbCouples != 0) )
		{	slLastHier=	ax_tdstOnlyFrames[slCnt1].slNumOfHierarchyCouples;
			if	( fn_uw_CompareHierarchy( slCnt1, slNewFrame ) == 0 )
				return	slCnt1;
		}
	}
	return	-1;
}



// **********************************************************************************
//								HIERARCHY CALLBACK
// **********************************************************************************
SCR_tde_Anl_ReturnValue	fn_eA3dHIERARCHYCallBackV6i(	SCR_tdst_File_Description	*_p_stFile,
														char						*_p_szName,
														char						*_ap_SzParam[],
														SCR_tde_Anl_Action			_eAction )
{
	// Section already analysed
	if	(_eAction == SCR_EA_Anl_AlreadyAnalysed)
	{	if	(uwOkAnimationFile == 0)
		{	fprintf( ErrorFile, "%s :  A3dHIERARCHY already analysed (Channel %d, Frame %d)\n", AnimationName, (slWaitedChannelNumber+1), (slHierFrame+1) );
		}
	}

	// Beginning of section
	else if	(_eAction == SCR_EA_Anl_BeginSection)
	{
		if	(uwOkAnimationFile == 0)
		{
#ifdef	ShowInfos
			fn_v_LogSectionBegin(	D_BINSCR_LogNew,
									"A3dHIERARCHY",
									AnimationName );
#endif

			// Readed Frame
			slHierFrame=	(atoi(_p_szName) - 1);

			// Allocate memory for Hierarchy structures
			ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slHierFrame].slNumOfHierarchyCouples=
				M_GetStackPos(eStackBinHierarchies);

			// Number of hierarchy couples equal to 0
			ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slHierFrame].uwHierarchyNbCouples=	0;
		}
	}

	// We are in the section
	else if	(_eAction == SCR_EA_Anl_Entry)
	{
		if	(uwOkAnimationFile == 0)
		{
			// ChannelAndFather
			if	( !stricmp(_p_szName, "ChannelAndFather") )
			{	signed long	slInd;

				uwHierDef=	1;

				// Integer + integer
				ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slHierFrame].uwHierarchyNbCouples++;
				fn_v_AllocateOnStack( eStackBinHierarchies, 1 );
				slInd=	M_GetStackAlloc(eStackBinHierarchies);
				ax_tdstHierarchies[slInd].uwChild=	(ReadUShort(0) - 1);
				ax_tdstHierarchies[slInd].uwFather=	(ReadUShort(1) - 1);

				if	( (ReadUShort(0) <= 0) || (ReadUShort(0) > p_stGENERAL->uwNumberOfChannels) )
					fprintf( ErrorFile, "%s :  Invalid hierarchy channel number (%s) (Channel %d, Frame %d)\n", AnimationName, _p_szName, (slWaitedChannelNumber+1), (slHierFrame+1) );
				if	( (ReadUShort(1) <= 0) || (ReadUShort(1) > p_stGENERAL->uwNumberOfChannels) )
					fprintf( ErrorFile, "%s :  Invalid hierarchy channel number (%s) (Channel %d, Frame %d)\n", AnimationName, _p_szName, (slWaitedChannelNumber+1), (slHierFrame+1) );
			}

			// Unknown field
			else
			{	fprintf( ErrorFile, "%s :  Unknown field in A3d, HierarchiesList, A3dHIERARCHY (%s) (Channel %d, Frame %d)\n", AnimationName, _p_szName, (slWaitedChannelNumber+1), (slHierFrame+1) );
			}
		}
	}

	// End of section
	else if	(_eAction == SCR_EA_Anl_EndSection)
	{	if	(uwOkAnimationFile == 0)
		{	signed long	slInd, slCnt, slRet;

			// On copie les hierarchies de la dernière frame jusqu'à celle-ci
			for	( slCnt=slLastFrame+1 ; slCnt<slHierFrame ; slCnt++ )
			{	ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slCnt].uwHierarchyNbCouples=
					ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slLastFrame].uwHierarchyNbCouples;
				ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slCnt].slNumOfHierarchyCouples=
					ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slLastFrame].slNumOfHierarchyCouples;
			}
			slLastFrame=	slHierFrame;

			slInd=	M_GetStackAlloc(eStackBinOnlyFrames);
			if	(ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slHierFrame].uwHierarchyNbCouples == 0)
			{	if	( uwHierDef == 0 )
						fprintf( WarningFile, "%s :  This hierarchy is empty (can't be change) (Channel %d, Frame %d)\n", AnimationName, (slWaitedChannelNumber+1), (slHierFrame+1) );
				else	ax_tdstOnlyFrames[slInd + slHierFrame].uwHierarchyNbCouples=		0;
			}
			else
			{
				slRet=	fn_uw_HierarchyIsDefined( M_GetStackAlloc(eStackBinOnlyFrames), M_GetStackAlloc(eStackBinOnlyFrames) + slHierFrame );
				// The hierarchy is defined before
				if	( slRet >= 0 ) {
					if (fn_uw_CompareHierarchy( M_GetStackAlloc(eStackBinOnlyFrames) + slHierFrame - 1, M_GetStackAlloc(eStackBinOnlyFrames) + slHierFrame ) == 0 )
						fprintf(WarningFile, "%s :  This hierarchy is duplicated (can be change)   (Channel %d, Frame %d)\n", AnimationName, (slWaitedChannelNumber+1), (slHierFrame+1) );
					fn_v_DeAllocateOnStack(	eStackBinHierarchies, ax_tdstOnlyFrames[slInd + slHierFrame].uwHierarchyNbCouples);
					ax_tdstOnlyFrames[M_GetStackAlloc(eStackBinOnlyFrames) + slHierFrame].slNumOfHierarchyCouples=	
						ax_tdstOnlyFrames[slRet].slNumOfHierarchyCouples;
				}
			}

#ifdef	ShowInfos
			fn_v_LogSectionEnd();
#endif
		}
	}

	return	SCR_ERV_Anl_NormalReturn;
}



// **********************************************************************************
//								A3D FILE CALLBACK
// **********************************************************************************
// Modif 28/10/98 Allocate A3dGeneral - Carlos Torres
// **********************************************************************************
SCR_tde_Anl_ReturnValue	fn_eA3DfileCallBackV6i(	SCR_tdst_File_Description	*_p_stFile,
												char						*_p_szName,
												char						*_ap_SzParam[],
												SCR_tde_Anl_Action			_eAction )
{
	if	(_eAction == SCR_EA_Anl_AlreadyAnalysed)
	{
	}

	else if	(_eAction == SCR_EA_Anl_BeginSection)
	{
		fn_v_LogSectionBegin(	D_BINSCR_LogNew,
								".a3d",
								AnimationName );

		// always allocate A3D General in stack to respect indexing
		fn_v_AllocateOnStack( eStackBinA3dGENERAL, 1 );

	}

	else if	(_eAction == SCR_EA_Anl_Entry)
	{
		fprintf( ErrorFile, "%s :  Unknown field in .a3d (%s)\n", AnimationName, _p_szName );
	}

	else if	(_eAction == SCR_EA_Anl_EndSection) {	
		fn_v_LogSectionEnd();
	}

	return	SCR_ERV_Anl_NormalReturn;
}



// **********************************************************************************
// Modif 28/10/98 init validAnim table -  Carlos Torres
// **********************************************************************************
void	fn_v_InitA3dV6i( void ) {
	// Register CallBack on A3dHeader
	SCR_fn_v_RdL0_RegisterCallback(	"A3dHEADER",
									fn_eA3dHEADERCallBackV6i,
									SCR_CRC_c_RdL0_ForSection );

	// Register CallBack on A3dStringsTable
	SCR_fn_v_RdL0_RegisterCallback(	"A3dStringsTable",
									fn_eA3dStringsTableCallBackV6i,
									SCR_CRC_c_RdL0_ForSection );

	// Register CallBack on A3dVertexesTable
	SCR_fn_v_RdL0_RegisterCallback(	"A3dVertexesTable",
									fn_eA3dVertexesTableCallBackV6i,
									SCR_CRC_c_RdL0_ForSection );

	// Register CallBack on A3dQuaternionsTable
	SCR_fn_v_RdL0_RegisterCallback(	"A3dQuaternionsTable",
									fn_eA3dQuaternionsTableCallBackV6i,
									SCR_CRC_c_RdL0_ForSection );

	// Register CallBack on A3dAnimationGENERAL
	SCR_fn_v_RdL0_RegisterCallback(	"A3dAnimationGENERAL",
									fn_eA3dAnimationGENERALCallBackV6i,
									SCR_CRC_c_RdL0_ForSection );

	// Register CallBack on Channel
	SCR_fn_v_RdL0_RegisterCallback(	"Channel",
									fn_eChannelCallBackV6i,
									SCR_CRC_c_RdL0_ForSection );

	// Register CallBack on Frame
	SCR_fn_v_RdL0_RegisterCallback(	"Frame",
									fn_eFrameCallBackV6i,
									SCR_CRC_c_RdL0_ForSection );

	// Register CallBack on Key
	SCR_fn_v_RdL0_RegisterCallback(	"Key",
									fn_eKeyCallBackV6i,
									SCR_CRC_c_RdL0_ForSection );
		
	// Register CallBack on SpeedsList
	SCR_fn_v_RdL0_RegisterCallback(	"SpeedsList",
									fn_eSpeedsListCallBackV6i,
									SCR_CRC_c_RdL0_ForSection );

	// Register CallBack on Speed
	SCR_fn_v_RdL0_RegisterCallback(	"Speed",
									fn_eSpeedCallBackV6i,
									SCR_CRC_c_RdL0_ForSection );

	// Register CallBack on HierarchiesList
	SCR_fn_v_RdL0_RegisterCallback(	"HierarchiesList",
									fn_eHierarchiesListCallBackV6i,
									SCR_CRC_c_RdL0_ForSection );

	// Register CallBack on A3dHIERARCHY
	SCR_fn_v_RdL0_RegisterCallback(	"A3dHIERARCHY",
									fn_eA3dHIERARCHYCallBackV6i,
									SCR_CRC_c_RdL0_ForSection );

	// Register CallBack on ".a3d"
	SCR_fn_v_RdL0_RegisterCallback(	".a3d",
									fn_eA3DfileCallBackV6i,
									SCR_CRC_c_RdL0_ForFile );
}



// **********************************************************************************
#undef	L_A3D_V6_C
