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



// **********************************************************************************
//                                                                     Included files
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

#include "SCR.h"

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


#include "a3x_glob.h"
#include "makeanim.h"
#include "l_Tbl_v6.h"
#include "l_global_v6.h"
#include "l_optim_v6.h"
#include "a3x_int.h"
#include "a3x_intb.h"

// **********************************************************************************
//                                                                  define Files Path
#define ERROR_DIR		"MakeAnim\\ErrorFile"
#define WARNING_DIR		"MakeAnim\\WarningFile"
#define SIZEOF_DIR		"MakeAnim\\SizeOf"
#define EVENT_DIR		"MakeAnim\\EventIn"

#define	A3xDebug
//#define	MoveEvent

#define	SeuilAngCentre	4

// parametrable variables
extern SEB_xReal xEps;
extern SEB_xReal xOneSubEps;

// Frequence of forced KeyFrame
int iKeyFreq = 1;

// **********************************************************************************
unsigned short	a100_TabNbElt[100];

static	unsigned long	ulSToMem0, ulSToKeyFrame0, ulSToFrame0, ulSToChannel0, ulSToOnlyFrame0, ulSToHierarchy0, ulSToGeneral0, ulSToEvents0;
static	unsigned long	ulSToMem1, ulSToKeyFrame1, ulSToFrame1, ulSToChannel1, ulSToOnlyFrame1, ulSToHierarchy1, ulSToGeneral1, ulSToEvents1;
static	unsigned long	ulSToMem2, ulSToKeyFrame2, ulSToFrame2, ulSToChannel2, ulSToOnlyFrame2, ulSToHierarchy2, ulSToGeneral2, ulSToEvents2;
static	unsigned long	ulTotMem0, ulTotKeyFrame0, ulTotFrame0, ulTotChannel0, ulTotOnlyFrame0, ulTotHierarchy0, ulTotGeneral0, ulTotEvents0;
static	unsigned long	ulTotMem1, ulTotKeyFrame1, ulTotFrame1, ulTotChannel1, ulTotOnlyFrame1, ulTotHierarchy1, ulTotGeneral1, ulTotEvents1;
static	unsigned long	ulTotMem2, ulTotKeyFrame2, ulTotFrame2, ulTotChannel2, ulTotOnlyFrame2, ulTotHierarchy2, ulTotGeneral2, ulTotEvents2;
static	signed long		slNbTotVect, slNbTotQuat;
static	unsigned long	ulNbVect1, ulNbQuat1;			// Total number of quaternions equals to identity
SEB_xReal				fSToTime2, fTotTime2;

static	signed short	uwOrder, uwCalc;
static	signed short	swReadedWord;
static	signed long		slReadedLong;
static	float			fReadedFloat;

static	unsigned long	ulTotNbAnims=	0;
static	unsigned long	ax_MemSizes[2000], ax_RomSizes[2000];

static	unsigned short	ax_uwTabSavedChannels[500];
static	unsigned short	ax_uwTabSavedFrames[500];
static	unsigned short	ax_uwTabChannelWithOnlyEvents[500];
static	unsigned short	ax_uwTabMoveEventToChannel[500];
//static	signed short	ax_swUsedChannelForHierarchy[1000];

#ifdef	A3xDebug
static	unsigned short	uwA3xDebug=		1;
#else
static	unsigned short	uwA3xDebug=		0;
#endif

static	unsigned short	uwDirectory=	1;		// Animation in directory



// **********************************************************************************
void	fn_v_ShowVect( FILE *out, tdxVector3 _p_a3_xVect )
{
	fprintf( out, "(%3.8f, %3.8f, %3.8f)\n",	_p_a3_xVect[0],
												_p_a3_xVect[1],
												_p_a3_xVect[2] );
}



void	fn_v_ShowQuat( FILE *out, tdxQuater4 _p_a4_xQuat )
{
	fprintf( out, "(%3.8f, %3.8f, %3.8f, %3.8f)\n",	_p_a4_xQuat[0],
													_p_a4_xQuat[1],
													_p_a4_xQuat[2],
													_p_a4_xQuat[3] );
}


// **********************************************************************************
// Modif 23/07/98 Kill couple when a channel have invalid channel number - Carlos Torres
void	fn_v_VerifyAnimationV6i(	unsigned short	uwNbAnims )
{	signed long		uwCnt1, uwCnt2, uwCnt3, uwCnt4, uwMax1, uwMax2;
	signed long		slNumOfVector, slNumOfQuaternion;
	signed long		slNumOfOnlyFrames, slNumOfChannels;
	signed long		slNumOfFrames, slNumOfHierarchyCouples, slNumOfHierarchyCouples2;
	signed long		uwInterpol, uwLastAttribute, uwLastKeyFrame;
	signed short	uwEmpty;
	unsigned short	uwLastSavedChannel;
	tdxMatrix33		a3a3_xMtxOri, a3a3_xMtxSca, a3a3_xScaleMatrix;
	tdxVector3		a3_xTmpVec;
#ifdef	MoveEvent
	signed long		uwCnt5, slNumChannel, slNumOfEvents, slNumOfFrames2;
	signed short	uwEmpty, uwEmptyEvent, uwMove1, uwMove2;
#endif

	printf("Verifications  ------------------\n");

	for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ ) {
		// bad anim --> skip it
		if	(bValid(&stAnims[uwCnt1]))
			continue;
		else {
			xEps = xPrecision(&stAnims[uwCnt1]);
			xOneSubEps = (SEB_xReal)(1.0 - xEps);
		}
		
		slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=	ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		// For each Channel
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;
			ax_tdstChannels[slNumOfChannels + uwCnt2].uwUsedChannel=		1;
			ax_tdstChannels[slNumOfChannels + uwCnt2].uwGenerateChannel=	0;

			for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
				ax_tdstFrames[slNumOfFrames + uwCnt3].uwChildrenInHierarchy=	0;
		}
	}

	// Kill empty (or only with sound) channels	-------------------------------------
#ifdef	KillChannels
	for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ ) {
		// bad anim --> skip it
		if	(bValid(&stAnims[uwCnt1]))
			continue;
		else {
			xEps = xPrecision(&stAnims[uwCnt1]);
			xOneSubEps = (SEB_xReal)(1.0 - xEps);
		}

		slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=	ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		// For each Channel
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;


			// For each Frame
			uwEmpty=		0;	// Not used !
			ax_uwTabChannelWithOnlyEvents[uwCnt2]=	1;
			for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
			{	
				if	( (ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject & 0x00FF) == TE_Event )
				{	// If we have an event
					if	( (ax_tdstTabTBL[ ax_tdstFrames[slNumOfFrames + uwCnt3].swNumberInTable ].ucTypeOfEvent == C_ucMECHANIC_EVENT) ||
						  (ax_tdstTabTBL[ ax_tdstFrames[slNumOfFrames + uwCnt3].swNumberInTable ].ucTypeOfEvent == C_ucSOUND_EVENT) )
					{	// If we have a mechanic ou a sound event -> transform it to empty object
						ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject=	(ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject & 0xFF00) | TE_EmptyObject;
						ax_tdstFrames[slNumOfFrames + uwCnt3].swNumberInTable=	-1;

					}
					// GENERATE
					if	(ax_tdstTabTBL[ ax_tdstFrames[slNumOfFrames + uwCnt3].swNumberInTable ].ucTypeOfEvent == C_ucGENERATE_EVENT)
					{	ax_tdstChannels[slNumOfChannels + uwCnt2].uwGenerateChannel=	1;
						uwEmpty=	1;
					}
					// GENERIC
					else if (ax_tdstTabTBL[ ax_tdstFrames[slNumOfFrames + uwCnt3].swNumberInTable ].ucTypeOfEvent == C_ucGENERIC_EVENT)
						uwEmpty=	1;
				}
				else
				{	// We don't have an event
					if	(	((ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject & 0x00FF) != TE_EmptyObject) )
					{	// We don't have (an EmptyObject or an UndefinedObject)
						ax_uwTabChannelWithOnlyEvents[uwCnt2]=	0;
						uwEmpty=	1;		// Object is not empty => no empty channel
					}
				}

			}
			ax_tdstChannels[slNumOfChannels + uwCnt2].uwUsedChannel=	uwEmpty;
		//	if	(uwEmpty == 1)
		//		fprintf( WarningFile, "Empty channel (%d) : %s\n", uwCnt2+1, szAnimName(&stAnims[uwCnt1]) );
		}

#ifdef	MoveEvent
		// Reduce number of channels events
		// For each Channel
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			// If we have a channel only with events
			if	( (ax_uwTabChannelWithOnlyEvents[uwCnt2] == 1) &&
				  (ax_tdstChannels[slNumOfChannels + uwCnt2].uwUsedChannel == 1) )
			{	uwMove1=	0;
				// For each frames
				for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
				{	// If we have an event
					if	( (ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject & 0x00FF) == TE_Event )
					{	ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute=	eDoubleKey;

						uwMove2=	0;
						// For all the rest of channels
						for	( uwCnt4=(uwCnt2+1) ; uwCnt4<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt4++ )
						{	slNumOfFrames2=	ax_tdstChannels[slNumOfChannels + uwCnt4].slNumOfFrames;
							// If we have a channel only with events
							if	( (ax_uwTabChannelWithOnlyEvents[uwCnt4] == 1) &&
								  (ax_tdstChannels[slNumOfChannels + uwCnt4].uwUsedChannel == 1) )
							{	// If we have an event
								if	( (ax_tdstFrames[slNumOfFrames2 + uwCnt3].uwTypeOfObject & 0x00FF) == TE_EmptyObject )
								{	// We can move the event
									ax_uwTabMoveEventToChannel[uwCnt2]=	(unsigned short) uwCnt4;
									uwMove2=	1;
								}
							}
						}
						if	( uwMove2 == 0 )
							uwMove1=	1;		// We can't move channel
					}
				}
				// Move the event infos if possible
				if	( uwMove1 == 0 )
				{	ax_tdstChannels[slNumOfChannels + uwCnt2].uwUsedChannel=	0;
					slNumOfFrames2=	ax_tdstChannels[slNumOfChannels + ax_uwTabMoveEventToChannel[uwCnt2]].slNumOfFrames;
					for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
					{	// If we have an event
						if	( (ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject & 0x00FF) == TE_Event )
						{	ax_tdstFrames[slNumOfFrames + uwCnt3].swNumberInTable=	ax_tdstFrames[slNumOfFrames2 + uwCnt3].swNumberInTable;
							ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject=	ax_tdstFrames[slNumOfFrames2 + uwCnt3].uwTypeOfObject;
							ax_tdstFrames[slNumOfFrames + uwCnt3].uwFrameNumber=	ax_tdstFrames[slNumOfFrames2 + uwCnt3].uwFrameNumber;
							ax_tdstFrames[slNumOfFrames + uwCnt3].xDistMaster=		ax_tdstFrames[slNumOfFrames2 + uwCnt3].xDistMaster;
							ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask=			ax_tdstFrames[slNumOfFrames2 + uwCnt3].uwMask;
							ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute=		ax_tdstFrames[slNumOfFrames2 + uwCnt3].uwAttribute;
							fn_v_CopyQuat( ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatOri, ax_tdstFrames[slNumOfFrames2 + uwCnt3].a4_xQuatOri );
							fn_v_CopyQuat( ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatSca, ax_tdstFrames[slNumOfFrames2 + uwCnt3].a4_xQuatSca );
							fn_v_CopyVect( ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xScaleValues, ax_tdstFrames[slNumOfFrames2 + uwCnt3].a3_xScaleValues );
							fn_v_CopyVect( ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xPosition, ax_tdstFrames[slNumOfFrames2 + uwCnt3].a3_xPosition );
							fn_v_CopyVect( ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xWorldPivotPosition, ax_tdstFrames[slNumOfFrames2 + uwCnt3].a3_xWorldPivotPosition );
						}
					}
					// Change channel references
					uwCnt4=	ax_tdstChannels[slNumOfChannels + uwCnt2].uwChannelNumber;
					uwCnt5=	ax_tdstChannels[slNumOfChannels + ax_uwTabMoveEventToChannel[uwCnt2]].uwChannelNumber;
					slNumOfEvents=	ax_tdstA3dGENERAL[uwCnt1].slNumOfEvents;
					for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfEvents ; uwCnt3++ )
					{	if	( (ax_tdstEvents[slNumOfEvents + uwCnt3].uwTypeOfEvent == C_ucGENERIC_EVENT) ||
							  (ax_tdstEvents[slNumOfEvents + uwCnt3].uwTypeOfEvent == C_ucGENERATE_EVENT) )
						{	slNumChannel=	(ax_tdstEvents[slNumOfEvents + uwCnt3].ulValue & 0x00FFFF00) >> 8;
							if	( (unsigned short) slNumChannel == uwCnt4 )
							{	ax_tdstEvents[slNumOfEvents + uwCnt3].ulValue&=	0x000000FF;
								ax_tdstEvents[slNumOfEvents + uwCnt3].ulValue|=	(uwCnt5 << 8);
							}
						}
					}
				}
			}
		}
#endif

		// Rebuild hierarchy for killed channels
		uwLastSavedChannel=	0;
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	ax_uwTabSavedChannels[uwCnt2]=	uwLastSavedChannel;
			if	( ax_tdstChannels[slNumOfChannels + uwCnt2].uwUsedChannel == 1 )
				uwLastSavedChannel++;
		}

		// Kill unused hierarchies
		// For channel unused
		// For bad channal with undefined channel number
		slNumOfHierarchyCouples=	ax_tdstA3dGENERAL[uwCnt1].slNumOfHierarchies;
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfHierarchies ; uwCnt2++ ) {	
			if ((ax_tdstChannels[slNumOfChannels + ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt2].uwChild].uwUsedChannel == 0) ||
				(ax_tdstChannels[slNumOfChannels + ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt2].uwChild].uwChannelNumber == SEB_Invalid) ||
				(ax_tdstChannels[slNumOfChannels + ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt2].uwFather].uwUsedChannel == 0) ||
				(ax_tdstChannels[slNumOfChannels + ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt2].uwFather].uwChannelNumber == SEB_Invalid) )
			{
				// bad child
				if ((ax_tdstChannels[slNumOfChannels + ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt2].uwChild].uwUsedChannel == 0) ||
					(ax_tdstChannels[slNumOfChannels + ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt2].uwChild].uwChannelNumber == SEB_Invalid) )
				{
					// channel killed
					if (ax_tdstChannels[slNumOfChannels + ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt2].uwChild].uwUsedChannel == 0)
						fprintf(ErrorFile, "Hierarchy Couple suppressed : An unused channel (%d) is Child of hierarchy !!! (%s)\n",ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt2].uwChild+1,szAnimName(&stAnims[uwCnt1]));
					// bad channel number
					else
						fprintf(ErrorFile, "Hierarchy Couple suppressed : channel %d with Bad name is Child of hierarchy !!! (%s)\n",ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt2].uwChild+1,szAnimName(&stAnims[uwCnt1]));

					ax_tdstHierarchies[ slNumOfHierarchyCouples + uwCnt2 ].uwChild=		SEB_Invalid;
				}
				// bad father
				if ((ax_tdstChannels[slNumOfChannels + ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt2].uwFather].uwUsedChannel == 0) ||
					(ax_tdstChannels[slNumOfChannels + ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt2].uwFather].uwChannelNumber == SEB_Invalid) )
				{
					// channel killed
					if (ax_tdstChannels[slNumOfChannels + ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt2].uwFather].uwUsedChannel == 0)
						fprintf(ErrorFile, "Hierarchy Couple suppressed : An unused channel (%d) is Father of hierarchy !!! (%s)\n",ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt2].uwFather,szAnimName(&stAnims[uwCnt1]));
					// bad channel number
					else
						fprintf(ErrorFile, "Hierarchy Couple suppressed : channel %d with Bad name is Father of hierarchy !!! (%s)\n",ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt2].uwFather,szAnimName(&stAnims[uwCnt1]));
					
					ax_tdstHierarchies[ slNumOfHierarchyCouples + uwCnt2 ].uwFather=	SEB_Invalid;
				}
			}
		}

		// For only frames, count used hierarchies
		slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=	ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt2++ )
		{	slNumOfHierarchyCouples=	ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt2].slNumOfHierarchyCouples;
			uwCnt4=	ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt2].uwHierarchyNbCouples;
			for	( uwCnt3=0 ; uwCnt3<ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt2].uwHierarchyNbCouples ; uwCnt3++ )
			{
				if	(	(ax_tdstHierarchies[ slNumOfHierarchyCouples + uwCnt3 ].uwChild  == SEB_Invalid) ||
						(ax_tdstHierarchies[ slNumOfHierarchyCouples + uwCnt3 ].uwFather == SEB_Invalid) )
				{	
					uwCnt4--;
				}
			}
			ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt2].uwHierarchyNbCouples=	(unsigned short) uwCnt4;
			// Calculate new hierachy indice in table
			slNumOfHierarchyCouples=	ax_tdstA3dGENERAL[uwCnt1].slNumOfHierarchies;
			uwCnt4=						slNumOfHierarchyCouples;
			for	( uwCnt3=slNumOfHierarchyCouples ; uwCnt3<ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt2].slNumOfHierarchyCouples ; uwCnt3++ )
			{	if	(	(ax_tdstHierarchies[ uwCnt3 ].uwChild  != SEB_Invalid) &&
						(ax_tdstHierarchies[ uwCnt3 ].uwFather != SEB_Invalid) )
				{	uwCnt4++;

				}
			}
			ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt2].slNumOfHierarchyCouples=	uwCnt4;
		}

		// Calculate new hierarchy indice in table and total number of hierarchies
		uwCnt3=	0;
		slNumOfHierarchyCouples=	ax_tdstA3dGENERAL[uwCnt1].slNumOfHierarchies;
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfHierarchies ; uwCnt2++ )
		{	if	(	(ax_tdstHierarchies[ slNumOfHierarchyCouples + uwCnt2 ].uwChild  != SEB_Invalid) &&
					(ax_tdstHierarchies[ slNumOfHierarchyCouples + uwCnt2 ].uwFather != SEB_Invalid) )
			{	ax_tdstHierarchies[ slNumOfHierarchyCouples + uwCnt3 ].uwChild=		ax_tdstHierarchies[ slNumOfHierarchyCouples + uwCnt2 ].uwChild;
				ax_tdstHierarchies[ slNumOfHierarchyCouples + uwCnt3 ].uwFather=	ax_tdstHierarchies[ slNumOfHierarchyCouples + uwCnt2 ].uwFather;
				uwCnt3++;
			}
		}
		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfHierarchies=	(unsigned short) uwCnt3;

	// To avoid problem with zero channel animation after simplification
		// For each Channel
		slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=	ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		uwCnt3=	0;
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	uwCnt3+=	ax_tdstChannels[slNumOfChannels + uwCnt2].uwUsedChannel;
		}

		if	(uwCnt3 == 0)
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels].slNumOfFrames;

			fprintf(WarningFile, "Zero channels in animation %s\n",szAnimName(&stAnims[uwCnt1]));

			// First elements of vector table and quaternion table
			slNumOfVector=		ax_tdstA3dGENERAL[uwCnt1].slNumOfVectors;
			slNumOfQuaternion=	ax_tdstA3dGENERAL[uwCnt1].slNumOfQuaternions;
			fn_v_SetZeroVector( axa3_xVertexes[slNumOfVector] );
			fn_v_SetIdQuater( axa4_xBinQuaternions[slNumOfQuaternion] );

			// New first channel infos
			ax_tdstChannels[slNumOfChannels].uwUsedChannel=			1;		// Channel is used
			ax_tdstChannels[slNumOfChannels].uwNumberOfKeys=		1;
			ax_tdstChannels[slNumOfChannels].uwGenerateChannel=		0;
			ax_tdstChannels[slNumOfChannels].slNumOfLocalPivotPos=	slNumOfVector;
			fn_v_SetZeroVector( ax_tdstChannels[slNumOfChannels].a3_xLocalPivotPos );

			// For all frame
			for	( uwCnt3=1 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
			{	ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject=	TE_EmptyObject;
				ax_tdstFrames[slNumOfFrames + uwCnt3].swNumberInTable=	-1;
				fn_v_SetIdQuater( ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatOri );
				fn_v_SetIdQuater( ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatSca );
				fn_v_SetZeroVector( ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xScaleValues );
				fn_v_SetZeroVector( ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xPosition );
				fn_v_SetZeroVector( ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xWorldPivotPosition );
				ax_tdstFrames[slNumOfFrames + uwCnt3].xDistMaster=			xOne;
				ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask=				0x0000;
				ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute=			eNoKey;
				ax_tdstFrames[slNumOfFrames + uwCnt3].slNumOfQuatOri=		slNumOfQuaternion;
				ax_tdstFrames[slNumOfFrames + uwCnt3].slNumOfQuatSca=		slNumOfQuaternion;
				ax_tdstFrames[slNumOfFrames + uwCnt3].slNumOfScaleValues=	slNumOfVector;
				ax_tdstFrames[slNumOfFrames + uwCnt3].slNumOfPosition=		slNumOfVector;
			}

			// For first frame
			ax_tdstFrames[slNumOfFrames + 0].uwMask=	(SEB_xMaskLastKey|SEB_xMaskIdScaleValues|SEB_xMaskIdQuatSca|SEB_xMaskIdQuatOri|SEB_xMaskAllLow);
		}
	}
#endif

	// Test for empty module with ChildrenInHierarchy
	for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ ) {
		// bad anim --> skip it
		if	(bValid(&stAnims[uwCnt1]))
			continue;
		else {
			xEps = xPrecision(&stAnims[uwCnt1]);
			xOneSubEps = (SEB_xReal)(1.0 - xEps);
		}
		
		slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=	ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt2++ )
		{	slNumOfHierarchyCouples=	ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt2].slNumOfHierarchyCouples;

			for	( uwCnt3=0 ; uwCnt3<ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt2].uwHierarchyNbCouples ; uwCnt3++ )
			{	ax_tdstFrames[	ax_tdstChannels[slNumOfChannels + ax_tdstHierarchies[ slNumOfHierarchyCouples + uwCnt3 ].uwFather
								].slNumOfFrames + uwCnt2 ].uwChildrenInHierarchy=	1;
			}
		}
	}


	// Test for (intro) bug of hierarchy and CHL	---------------------------------
	/*for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ ) {
		// bad anim --> skip it
		if	(TabValidAnimations[uwCnt1] == 1)
			continue;
		
		slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=	ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt2++ )
		{	slNumOfHierarchyCouples=	ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt2].slNumOfHierarchyCouples;

			for	( uwCnt3=0 ; uwCnt3<1000 ; uwCnt3++ )
				ax_swUsedChannelForHierarchy[uwCnt3]=	-1;

			for	( uwCnt3=0 ; uwCnt3<ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt2].uwHierarchyNbCouples ; uwCnt3++ )
			{
				uwCnt4=	ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt3].uwChild;
				if	(ax_tdstChannels[slNumOfChannels + uwCnt4].uwChannelNumber == SEB_Invalid)
				{	fprintf( ErrorFile, "(Child) Channel %d without a name is hierarchized , frame %d (%s)\n", (uwCnt4+1), (uwCnt2+1), szAnimName(&stAnims[uwCnt1]) );
				}
				else
				{
					if	(ax_swUsedChannelForHierarchy[ ax_tdstChannels[slNumOfChannels + uwCnt4].uwChannelNumber ] < 0)
					{	ax_swUsedChannelForHierarchy[ ax_tdstChannels[slNumOfChannels + uwCnt4].uwChannelNumber ]=	(signed short) uwCnt4;
					}
					else
					{
						if	(ax_swUsedChannelForHierarchy[ ax_tdstChannels[slNumOfChannels + uwCnt4].uwChannelNumber ] != uwCnt4)
							fprintf( ErrorFile, "CHL / Hierarchy (child) problem on channel %d, frame %d (%s)\n", (ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt3].uwChild+1), (uwCnt2+1), szAnimName(&stAnims[uwCnt1]) );
					}
				}

				uwCnt4=	ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt3].uwFather;
				if	(ax_tdstChannels[slNumOfChannels + uwCnt4].uwChannelNumber == SEB_Invalid)
				{	fprintf( ErrorFile, "(Father) Channel %d without a name is hierarchized , frame %d (%s)\n", (uwCnt4+1), (uwCnt2+1), szAnimName(&stAnims[uwCnt1]) );
				}
				else
				{
					if	(ax_swUsedChannelForHierarchy[ ax_tdstChannels[slNumOfChannels + uwCnt4].uwChannelNumber ] < 0)
					{	ax_swUsedChannelForHierarchy[ ax_tdstChannels[slNumOfChannels + uwCnt4].uwChannelNumber ]=	(signed short) uwCnt4;
					}
					else
					{
						if	(ax_swUsedChannelForHierarchy[ ax_tdstChannels[slNumOfChannels + uwCnt4].uwChannelNumber ] != uwCnt4)
							fprintf( ErrorFile, "CHL / Hierarchy (father) problem on channel %d, frame %d (%s)\n", (ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt3].uwFather+1), (uwCnt2+1), szAnimName(&stAnims[uwCnt1]) );
					}
				}
			}
		}
	}*/

	// Verify keys and reset interpolation mask	-------------------------------------
	for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ ) {
		// bad anim --> skip it
		if	(bValid(&stAnims[uwCnt1]))
			continue;
		else {
			xEps = xPrecision(&stAnims[uwCnt1]);
			xOneSubEps = (SEB_xReal)(1.0 - xEps);
		}
		
		slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=	ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		// For each Channel
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	static	unsigned long	ulLastMask;
			int iNextKeyFrame = 1;	// first forced key frame always on the first frame

			slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			// For each Frame
			uwInterpol=			0;			// Datas is non interpolated
			uwLastAttribute=	0;
			ulLastMask=			0;			// Last interpolation mask
			for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
			{
				if	( ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute == eNoKey )			// If we have no Key
				{
					// If (we are not interpolated) or (we are interpolated and the mask is incomplete)
					if	(	(uwInterpol == 0) ||
							((uwInterpol != 0) && (ulLastMask != 0x00000777)) )
					{

						if	((uwInterpol != 0) && (ulLastMask != 0x00000777))
						{	fprintf( WarningFile, "Channel %d, frame %d, mask is incomplete in %s\n", (uwCnt2+1), (uwCnt3+1), szAnimName(&stAnims[uwCnt1]) );
						}

						// Force a Key for non-optimized anim 
						if (!(--iNextKeyFrame) || (uwCnt3 == (ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames - 1))) {
							ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute = eDoubleKey;	// We set a Key
							iNextKeyFrame = iKeyFreq;
						}

						if	((ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject & 0x00FF) == TE_EmptyObject)
						{	// Reset datas because we have an empty object
							if	(	(ax_tdstChannels[slNumOfChannels + uwCnt2].uwGenerateChannel == 0) &&
									(ax_tdstFrames[slNumOfFrames + uwCnt3].uwChildrenInHierarchy == 0) )
							{
								fn_v_CopyVect( ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xPosition, a3_xVector0 );
								fn_v_CopyQuat( ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatOri, a4_xQuater1 );
								fn_v_CopyQuat( ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatSca, a4_xQuater1 );
								fn_v_CopyVect( ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xScaleValues, a3_xVector1 );
								ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute= eDoubleKey;
							}
						//	else
						//	{
						//		printf("%s (channel %d , frame %d)\n", szAnimName(&stAnims[uwCnt1]), uwCnt2+1, uwCnt3+1);
						//	}
							// Reset other values
							fn_v_QuatToMatrix( a3a3_xMtxSca, ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatSca );
							fn_v_QuatToMatrix( a3a3_xMtxOri, ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatOri );
							fn_v_InvRotDiaRot( a3a3_xScaleMatrix, a3a3_xMtxSca, ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xScaleValues );
							fn_v_MatrixByVector( a3_xTmpVec, a3a3_xScaleMatrix, ax_tdstChannels[slNumOfChannels + uwCnt2].a3_xLocalPivotPos );
							fn_v_MatrixByVector( ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xWorldPivotPosition, a3a3_xMtxOri, a3_xTmpVec  );
							ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xWorldPivotPosition[0]+= ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xPosition[0];
							ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xWorldPivotPosition[1]+= ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xPosition[1];
							ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xWorldPivotPosition[2]+= ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xPosition[2];
							ax_tdstFrames[slNumOfFrames + uwCnt3].xDistMaster=		fn_x_VectorLength( ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xPosition );
						}
					}
				}
				else if	( ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute == eSimpleKey )
				{	if	(uwInterpol == 0)													// If we have a simple key
							uwInterpol=	1;														// We begin interpolation
					else	uwInterpol=	0;													// Else We stop interpolation
					ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute= eDoubleKey;
					uwLastAttribute=	eSimpleKey;
					ulLastMask=			ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask;
					uwLastKeyFrame=		uwCnt3;
				}
				else //if	( tdstFrames[slNumOfFrames + uwCnt3].uwAttribute == eDoubleKey )
				{	uwInterpol=	1;															// Begin interpolation
					uwLastAttribute=	eDoubleKey;
					uwLastKeyFrame=		uwCnt3;
					ulLastMask=			ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask;
				}
				ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask=	0x0000;
			}
			if	( (uwInterpol == 1) && (uwLastAttribute == eDoubleKey) )
				fprintf( WarningFile, "Channel %d terminated by a double key in %s\n", (uwCnt2+1), szAnimName(&stAnims[uwCnt1]) );

			if	(uwLastAttribute != eNoKey)
			{	for	( uwCnt3=uwLastKeyFrame+1; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
					if	( (ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject & 0x00FF) != TE_EmptyObject )
						ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute= eDoubleKey;
			}
		}
	}


	// Set hierarchies bit	---------------------------------------------------------
	for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ ) {
		// bad anim --> skip it
		if	(bValid(&stAnims[uwCnt1]))
			continue;
		else {
			xEps = xPrecision(&stAnims[uwCnt1]);
			xOneSubEps = (SEB_xReal)(1.0 - xEps);
		}
		
		slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=	ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt2++ )
		{	slNumOfHierarchyCouples=	ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt2].slNumOfHierarchyCouples;

			// SEB_xTypeHierarchized
			for	( uwCnt3=0 ; uwCnt3<ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt2].uwHierarchyNbCouples ; uwCnt3++ )
			{	ax_tdstFrames[	ax_tdstChannels[slNumOfChannels + ax_tdstHierarchies[ slNumOfHierarchyCouples + uwCnt3 ].uwChild
								].slNumOfFrames + uwCnt2 ].uwTypeOfObject |= SEB_xTypeHierarchized;
			}

			// SEB_xTypeChangeOfHierarchy
			uwMax1=	ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt2].uwHierarchyNbCouples;
			if	(uwCnt2 == (ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames-1))
					uwMax2=	ax_tdstOnlyFrames[slNumOfOnlyFrames].uwHierarchyNbCouples;
			else	uwMax2=	ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt2 + 1].uwHierarchyNbCouples;

			slNumOfHierarchyCouples=	ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt2].slNumOfHierarchyCouples;
			if	(uwCnt2 == (ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames-1))
					slNumOfHierarchyCouples2=	ax_tdstOnlyFrames[slNumOfOnlyFrames].slNumOfHierarchyCouples;
			else	slNumOfHierarchyCouples2=	ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt2 + 1].slNumOfHierarchyCouples;

			for	( uwCnt3=0 ; uwCnt3<uwMax1 ; uwCnt3++ )
			{	register	unsigned short	uwFlag;

				uwFlag=	0;
				for	( uwCnt4=0 ; uwCnt4<uwMax2 ; uwCnt4++ )
				{
					if	( (ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt3].uwChild  == ax_tdstHierarchies[slNumOfHierarchyCouples2 + uwCnt4].uwChild ) &&
						  (ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt3].uwFather == ax_tdstHierarchies[slNumOfHierarchyCouples2 + uwCnt4].uwFather) )
					{	uwFlag=	1;
						break;
					}
				}
				if	(uwFlag == 0)
				{	register	signed long	slTmp;

					uwCnt4=		ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt3].uwChild;
					slTmp=		ax_tdstChannels[slNumOfChannels + uwCnt4].slNumOfFrames + uwCnt2;
					ax_tdstFrames[slTmp].uwTypeOfObject |= SEB_xTypeChangeOfHierarchy;
					if	( ax_tdstFrames[slTmp + 1].uwAttribute == eNoKey )
					{	fprintf( ErrorFile, "Change of hierarchy (type 1) not on KeyFrame (%s, channel #%d, frame #%d)\n", szAnimName(&stAnims[uwCnt1]), uwCnt4+1, uwCnt2+2 );
					}
				}
			}

			for	( uwCnt4=0 ; uwCnt4<uwMax2 ; uwCnt4++ )
			{	register	unsigned short	uwFlag;

				uwFlag=	0;
				for	( uwCnt3=0 ; uwCnt3<uwMax1 ; uwCnt3++ )
				{
					if	( (ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt3].uwChild  == ax_tdstHierarchies[slNumOfHierarchyCouples2 + uwCnt4].uwChild ) &&
						  (ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt3].uwFather == ax_tdstHierarchies[slNumOfHierarchyCouples2 + uwCnt4].uwFather) )
					{	uwFlag=	1;
						break;
					}
				}
				if	(uwFlag == 0)
				{	register	signed long	slTmp;

					uwCnt3=		ax_tdstHierarchies[slNumOfHierarchyCouples2 + uwCnt4].uwChild;
					slTmp=		ax_tdstChannels[slNumOfChannels + uwCnt3].slNumOfFrames + uwCnt2;
					ax_tdstFrames[slTmp].uwTypeOfObject |= SEB_xTypeChangeOfHierarchy;
					if	( ax_tdstFrames[slTmp + 1].uwAttribute == eNoKey )
					{	fprintf( ErrorFile, "Change of hierarchy (type 2) not on KeyFrame (%s, channel #%d, frame #%d)\n", szAnimName(&stAnims[uwCnt1]), uwCnt3+1, uwCnt2+2 );
					}
				}
			}

		}

		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
			{
				// SEB_xTypeChangeOfHierarchy ("Object" frame t, Empty frame t+1)
				if	(uwCnt3 < (ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames - 1))
				{
					if	(	((ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject & 0x00FF) != TE_EmptyObject) &&
							((ax_tdstFrames[slNumOfFrames + uwCnt3 + 1].uwTypeOfObject & 0x00FF) == TE_EmptyObject) )
					{	ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject |= SEB_xTypeChangeOfHierarchy;
					//	if	( ax_tdstFrames[slNumOfFrames + uwCnt3 + 1].uwAttribute == eNoKey )
					//	{	fprintf( ErrorFile, "Change of hierarchy (type 3) not on KeyFrame (%s, channel #%d, frame #%d)\n", szAnimName(&stAnims[uwCnt1]), uwCnt2+1, uwCnt3+1 );
					//	}
					}
				}
			}
		}
	}


	// Calcule number of key frame --------------------------------------------------
	//printf("Number of key frames       NumberOfChannels * NumberOfFrames     Total channel\n");
	ulTotGeneral0=		uwNbAnims;
	ulTotMem0=			0;
	ulTotKeyFrame0=		0;
	ulTotFrame0=		0;
	ulTotChannel0=		0;
	ulTotOnlyFrame0=	0;
	ulTotHierarchy0=	0;
	ulTotEvents0=		0;

	fprintf( SizeOut, "Après chargement du fichier\n" );
	fprintf( SizeOut, "KeyFrame    Frame   Channel   OnlyFrame   Hierarchy   General   Events   Place Memoire\n" );
	for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ ) {
		// bad anim --> skip it
		if	(bValid(&stAnims[uwCnt1]))
			continue;
		else {
			xEps = xPrecision(&stAnims[uwCnt1]);
			xOneSubEps = (SEB_xReal)(1.0 - xEps);
		}
		
		slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=		ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		ulSToGeneral0=		1;
		ulSToKeyFrame0=		0;
		ulSToHierarchy0=	ax_tdstA3dGENERAL[uwCnt1].uwNumberOfHierarchies;
		ulSToOnlyFrame0=	ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames;
		ulSToChannel0=		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels;
		ulSToEvents0=		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfEvents;
		ulSToFrame0=		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels * ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames;

		// For each Channel
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			// For each key frame
			uwCnt4=	0;
			for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
			{	// If we have a KeyFrame
				if	( ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute != eNoKey )
					uwCnt4++;
			}
			ulSToKeyFrame0+=	uwCnt4;
			ax_tdstChannels[slNumOfChannels + uwCnt2].uwNumberOfKeys=	(unsigned short) uwCnt4;
		}
		ulSToMem0=	ulSToGeneral0 * 64L + ulSToChannel0 * 16L + ulSToOnlyFrame0 * 6L +
					ulSToKeyFrame0 * 32L + ulSToHierarchy0 * 4L + ulSToFrame0 * 4L +
					ulSToOnlyFrame0 * (8+12);	// + quaternions et vecteurs speed !!!

		fprintf( SizeOut, "%8d   %6d   %7d   %9d   %9d   %7d   %6d   %13d   %s\n",
					ulSToKeyFrame0, ulSToFrame0, ulSToChannel0, ulSToOnlyFrame0, ulSToHierarchy0, ulSToGeneral0,
					ulSToEvents0, ulSToMem0, szAnimName(&stAnims[uwCnt1]) );

		ulTotMem0+=			ulSToMem0;
		ulTotKeyFrame0+=	ulSToKeyFrame0;
		ulTotFrame0+=		ulSToFrame0;
		ulTotChannel0+=		ulSToChannel0;
		ulTotOnlyFrame0+=	ulSToOnlyFrame0;
		ulTotHierarchy0+=	ulSToHierarchy0;
		ulTotEvents0+=		ulSToEvents0;

	}
	fprintf( SizeOut, "Totaux\n" );
	fprintf( SizeOut, "%8d   %6d   %7d   %9d   %9d   %7d   %6d   %10d\n",
				ulTotKeyFrame0, ulTotFrame0, ulTotChannel0, ulTotOnlyFrame0, ulTotHierarchy0, ulTotGeneral0, ulTotEvents0, ulTotMem0 );
	fprintf( SizeOut, "\n" );

	printf("ulTotKeyFrame0=  %d\n", ulTotKeyFrame0	);
	printf("ulTotFrame0=     %d\n", ulTotFrame0		);
	printf("ulTotChannel0=   %d\n", ulTotChannel0	);
	printf("ulTotOnlyFrame0= %d\n", ulTotOnlyFrame0	);
	printf("ulTotHierarchy0= %d\n", ulTotHierarchy0	);
	printf("ulTotGeneral0=   %d\n", ulTotGeneral0	);
	printf("ulTotEvents0=    %d\n", ulTotEvents0 );

	printf("Memoire utilisee  %d\n\n",	ulTotMem0 );
}


#define Inv_128		0.0078125	
#define Inv_256		0.00390625

// **********************************************************************************
void	fn_v_DiscretizeScal(	tdxVector3	_a3_xVect ) {
	if ((fabs(_a3_xVect[0]) < Inv_256)  && (fabs(_a3_xVect[0]) > xEps)) 
		_a3_xVect[0] =  Inv_128;
	else
		_a3_xVect[0]=	(SEB_xReal)(((signed long) (_a3_xVect[0]*128.0+0.5)) / 128.0);

	if ((fabs(_a3_xVect[1]) < Inv_256)  && (fabs(_a3_xVect[1]) > xEps)) 
		_a3_xVect[1] =  Inv_128;
	else
		_a3_xVect[1]=	(SEB_xReal)(((signed long) (_a3_xVect[1]*128.0+0.5)) / 128.0);

	if ((fabs(_a3_xVect[2]) < Inv_256)  && (fabs(_a3_xVect[2]) > xEps)) 
		_a3_xVect[2] =  Inv_128;
	else
		_a3_xVect[2]=	(SEB_xReal)(((signed long) (_a3_xVect[2]*128.0+0.5)) / 128.0);
}



void	fn_v_ClassicVector(	tdxVector3	_a3_xVect )
{	unsigned short	uwCnt;

	for	( uwCnt=0 ; uwCnt<3 ; uwCnt++ )
		if	( fabs(_a3_xVect[uwCnt]) < xEps )
			_a3_xVect[uwCnt]=	xZero;

	for	( uwCnt=0 ; uwCnt<3 ; uwCnt++ )
		if	( fabs(xOne - _a3_xVect[uwCnt]) < xEps )
			_a3_xVect[uwCnt]=	xOne;
}

void	fn_v_ClassicQuaternion(	tdxQuater4	_a4_xQuat )
{	tdxQuater4		a4_xQuatTest;
	unsigned short	uwCnt;

	for	( uwCnt=0 ; uwCnt<4 ; uwCnt++ )
	{	fn_v_CopyQuat( a4_xQuatTest, a4_xQuater0 );
		a4_xQuatTest[uwCnt]=	xOne;
		if	( fn_uw_AreSameQuat( _a4_xQuat, a4_xQuatTest ) == 0 )
		{	_a4_xQuat[0]=		xZero;
			_a4_xQuat[1]=		xZero;
			_a4_xQuat[2]=		xZero;
			_a4_xQuat[3]=		xZero;
			_a4_xQuat[uwCnt]=	xOne;
			return;
		}
		a4_xQuatTest[uwCnt]=	-xOne;
		if	( fn_uw_AreSameQuat( _a4_xQuat, a4_xQuatTest ) == 0 )
		{	_a4_xQuat[0]=		xZero;
			_a4_xQuat[1]=		xZero;
			_a4_xQuat[2]=		xZero;
			_a4_xQuat[3]=		xZero;
			_a4_xQuat[uwCnt]=	-xOne;
			return;
		}
	}
}



// **********************************************************************************
SEB_xReal	fn_uw_BinAngleBetweenVect(	tdxVector3	_a3_xVec1,
										tdxVector3	_a3_xVec2 )
{	register SEB_xReal	xAngle;

	xAngle= (SEB_xReal) acos(	_a3_xVec1[0] * _a3_xVec2[0] +
								_a3_xVec1[1] * _a3_xVec2[1] +
								_a3_xVec1[2] * _a3_xVec2[2] );
	return	xAngle;
}


SEB_xReal	fn_uw_BinAngleBetweenQuat(	tdxQuater4	_a4_xQuat1,
										tdxQuater4	_a4_xQuat2 )
{	register SEB_xReal	xAngle;

	xAngle=	(SEB_xReal) acos(	_a4_xQuat1[eQX] * _a4_xQuat2[eQX] +
								_a4_xQuat1[eQY] * _a4_xQuat2[eQY] +
								_a4_xQuat1[eQZ] * _a4_xQuat2[eQZ] +
								_a4_xQuat1[eQW] * _a4_xQuat2[eQW] );
	return	xAngle;
}



// **********************************************************************************
void	fn_v_OptimiseAnimationV6i(	unsigned short	uwNbAnims )
{	signed long	uwCnt1, uwCnt2, uwCnt3, uwCnt4, uwCnt5, uwCnt6;
	signed long	slNumOfOnlyFrames, slNumOfChannels, slNumOfHierarchyCouples;
	signed long	slNumOfFrames;
	tdxQuater4		a4_xQuatOri, a4_xQuatSca;
	tdxMatrix33		a3a3_xMtxOri, a3a3_xMtxSca;
	tdxVector3		a3_xPosition, a3_xVecSca;

	printf("Optimisations  ------------------\n");

	// use default precision for classic vector
	xEps = xDefaultEps;
	xOneSubEps = (SEB_xReal)(1.0 - xEps);

	// Set classic quaternions and vectors	-----------------------------------------
	// In StackVertexes
	for	( uwCnt1=0 ; uwCnt1<M_GetStackPos(eStackBinVertexes) ; uwCnt1++ )
		fn_v_ClassicVector( axa3_xVertexes[uwCnt1] );
	// In StackQuaternions
	for	( uwCnt1=0 ; uwCnt1<M_GetStackPos(eStackBinQuaternions) ; uwCnt1++ )
		fn_v_ClassicQuaternion( axa4_xBinQuaternions[uwCnt1] );
	// In StackChannels
	for	( uwCnt1=0 ; uwCnt1<M_GetStackPos(eStackBinChannels) ; uwCnt1++ )
		fn_v_ClassicVector( ax_tdstChannels[uwCnt1].a3_xLocalPivotPos );
	// In StackOnlyFrames
	for	( uwCnt1=0 ; uwCnt1<M_GetStackPos(eStackBinOnlyFrames) ; uwCnt1++ )
	{	fn_v_ClassicQuaternion( ax_tdstOnlyFrames[uwCnt1].tdxAngularSpeedQuat );
		fn_v_ClassicVector( ax_tdstOnlyFrames[uwCnt1].tdxSpeedVector );
	}
	// In StackFrames
	for	( uwCnt1=0 ; uwCnt1<M_GetStackPos(eStackBinFrames) ; uwCnt1++ )
	{	fn_v_ClassicQuaternion( ax_tdstFrames[uwCnt1].a4_xQuatOri );
		fn_v_ClassicQuaternion( ax_tdstFrames[uwCnt1].a4_xQuatSca );
		fn_v_ClassicVector( ax_tdstFrames[uwCnt1].a3_xScaleValues );
		fn_v_ClassicVector( ax_tdstFrames[uwCnt1].a3_xPosition );
		fn_v_DiscretizeScal( ax_tdstFrames[uwCnt1].a3_xScaleValues );
	}


	// Reset pivot positions  -------------------------------------------------------
	for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ ) {
		// bad anim --> skip it
		if	(bValid(&stAnims[uwCnt1]))
			continue;
		else {
			xEps = xPrecision(&stAnims[uwCnt1]);
			xOneSubEps = (SEB_xReal)(1.0 - xEps);
		}
		
		slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=	ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		// For each Channel
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			uwCnt5=	1;
			for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
			{	
				// If we don't have a hierarchized objet
				if	( (ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject & SEB_xTypeHierarchized) == 0x0000 )
					uwCnt5=	0;
			}
			if	(uwCnt5 == 1)
				fn_v_SetZeroVector( ax_tdstChannels[slNumOfChannels + uwCnt2].a3_xLocalPivotPos );
		}
	}


	// Reset scale quaternion -------------------------------------------------------
	for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ ) {
		// bad anim --> skip it
		if	(bValid(&stAnims[uwCnt1]))
			continue;
		else {
			xEps = xPrecision(&stAnims[uwCnt1]);
			xOneSubEps = (SEB_xReal)(1.0 - xEps);
		}
		
		slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=	ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		// For each Channel
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
			{	// If we have a KeyFrame
				if	( ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute != eNoKey )
				{	tdxMatrix33	a3a3_xMtxOriSca, a3a3_xMtxSca;

					// We have a diagonal matrix ?
					fn_v_QuatToMatrix( a3a3_xMtxOriSca, ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatSca );
					fn_v_InvRotDiaRot( a3a3_xMtxSca, a3a3_xMtxOriSca, ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xScaleValues );
					if	( fn_uw_IsDiagonale(a3a3_xMtxSca) == 0 )
						fn_v_SetIdQuater(ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatSca);

					// Search next KeyFrame (k+1)
					uwCnt4=	uwCnt3 + 1;
					while	( (uwCnt4<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames) && (ax_tdstFrames[slNumOfFrames + uwCnt4].uwAttribute==eNoKey) )
						uwCnt4++;

					if	( uwCnt4<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames )
					{	// Set scale quaternion
						if	( (fn_uw_AreSameVect(ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xScaleValues, a3_xVector1) == 0) &&
							  (fn_uw_AreSameVect(ax_tdstFrames[slNumOfFrames + uwCnt4].a3_xScaleValues, a3_xVector1) == 0) )
						{	// Copy identity vector and quaternion for all keys
							for	( uwCnt5=uwCnt3 ; uwCnt5<=uwCnt4 ; uwCnt5++ )
							{	fn_v_CopyVect( ax_tdstFrames[slNumOfFrames + uwCnt5].a3_xScaleValues, a3_xVector1 );
								fn_v_CopyQuat( ax_tdstFrames[slNumOfFrames + uwCnt5].a4_xQuatSca,     a4_xQuater1 );
							}
						}
					}
					else
					{	// Set last scale quaternion on last KeyFrame
						if	( fn_uw_AreSameVect(ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xScaleValues, a3_xVector1) == 0 )
						{	fn_v_CopyVect( ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xScaleValues, a3_xVector1 );
							fn_v_CopyQuat( ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatSca,     a4_xQuater1 );
						}
					}
					uwCnt3=	uwCnt4-1;
				}
			}
		}
	}


	// Optimize KeyFrames	---------------------------------------------------------
	for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ ) {
		// bad anim --> skip it
		if	(bValid(&stAnims[uwCnt1]))
			continue;
		else {
			xEps = xPrecision(&stAnims[uwCnt1]);
			xOneSubEps = (SEB_xReal)(1.0 - xEps);
		}
		
		slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=	ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		// For each Channel
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			//if	(ax_tdstChannels[slNumOfChannels + uwCnt2].uwUsedChannel == 1)
			if	(	(ax_tdstChannels[slNumOfChannels + uwCnt2].uwUsedChannel == 1) &&
					(ax_tdstChannels[slNumOfChannels + uwCnt2].uwGenerateChannel == 0) )		// We are not on GenerateChannel
			{
				// For each KeyFrame
				for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
				{	// If we have a KeyFrame
					if	( ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute != eNoKey )
					{	signed long	uwCntZ, uwFlag;
						signed long	uwFather3, uwFather4, uwFather5;

						// Search next KeyFrame (k+1)
						uwCnt4=	uwCnt3 + 1;
						while	( (uwCnt4<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames) && (ax_tdstFrames[slNumOfFrames + uwCnt4].uwAttribute==eNoKey))
							uwCnt4++;

						// Search next next KeyFrame (k+2)
						uwCnt5=	uwCnt4 + 1;
						while	( (uwCnt5<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames) && (ax_tdstFrames[slNumOfFrames + uwCnt5].uwAttribute==eNoKey))
							uwCnt5++;

						if	(	(uwCnt4 < ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames) &&
								(uwCnt5 < ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames) )
						{
							uwFather3=	-1;
							uwFather4=	-1;
							uwFather5=	-1;

							slNumOfHierarchyCouples=	ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt3].slNumOfHierarchyCouples;
							for	( uwCnt6=0 ; uwCnt6<ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt3].uwHierarchyNbCouples ; uwCnt6++ )
							{
								if	(ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt6].uwChild == uwCnt2)
								{	uwFather3=	ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt6].uwFather;
									break;
								}
							}
							slNumOfHierarchyCouples=	ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt4].slNumOfHierarchyCouples;
							for	( uwCnt6=0 ; uwCnt6<ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt3].uwHierarchyNbCouples ; uwCnt6++ )
							{
								if	(ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt6].uwChild == uwCnt2)
								{	uwFather4=	ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt6].uwFather;
									break;
								}
							}
							slNumOfHierarchyCouples=	ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt5].slNumOfHierarchyCouples;
							for	( uwCnt6=0 ; uwCnt6<ax_tdstOnlyFrames[slNumOfOnlyFrames + uwCnt3].uwHierarchyNbCouples ; uwCnt6++ )
							{
								if	(ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt6].uwChild == uwCnt2)
								{	uwFather5=	ax_tdstHierarchies[slNumOfHierarchyCouples + uwCnt6].uwFather;
									break;
								}
							}


							// Test the hierarchy
							if	((uwFather3 == uwFather4) && (uwFather4 == uwFather5))
							{
								// Optimize EmptyObject KeyFrames
								uwFlag=	0;
								for	( uwCntZ=uwCnt3+1 ; uwCntZ<uwCnt5 ; uwCntZ++ ) {
									if	(	((ax_tdstFrames[slNumOfFrames + uwCntZ].uwTypeOfObject & 0x00FF) != TE_EmptyObject) ||
											(ax_tdstFrames[slNumOfFrames + uwCnt3].uwChildrenInHierarchy == 1) )
										uwFlag=	1;
								}
								// All objects equal to EmptyObject
								if	(uwFlag == 0)
								{
									if	((ax_tdstFrames[slNumOfFrames + uwCnt5].uwTypeOfObject & 0x00FF) != TE_EmptyObject)
									{	ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	(SEB_xMaskQuatOri|SEB_xMaskQuatSca|SEB_xMaskScaleValues|SEB_xMaskPosition);
									}
									ax_tdstFrames[slNumOfFrames + uwCnt4].uwAttribute=	eNoKey;
									uwCnt3--;
								}
								else
								{
									if	(ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask != (SEB_xMaskQuatOri|SEB_xMaskQuatSca|SEB_xMaskScaleValues|SEB_xMaskPosition))
									{
										fn_v_BinInterpolBetweenKeys(	&ax_tdstFrames[slNumOfFrames + uwCnt3],
																		&ax_tdstFrames[slNumOfFrames + uwCnt5],
																		a3a3_xMtxOri,
																		a3a3_xMtxSca,
																		a3_xPosition,
																		(uwCnt4-uwCnt3)/(SEB_xReal)(uwCnt5-uwCnt3),
																		ax_tdstChannels[slNumOfChannels + uwCnt2].a3_xLocalPivotPos,
																		a4_xQuatOri,
																		a4_xQuatSca,
																		a3_xVecSca
																	);
										if	( (fn_uw_AreSameQuat(ax_tdstFrames[slNumOfFrames + uwCnt4].a4_xQuatOri , a4_xQuatOri ) == 0) &&
											  (fn_uw_AreSameQuat(ax_tdstFrames[slNumOfFrames + uwCnt4].a4_xQuatSca , a4_xQuatSca ) == 0) &&
											  (fn_uw_AreSameVect(ax_tdstFrames[slNumOfFrames + uwCnt4].a3_xScaleValues, a3_xVecSca) == 0) &&
											  (fn_uw_AreSameVect(ax_tdstFrames[slNumOfFrames + uwCnt4].a3_xPosition, a3_xPosition) == 0) )
										{		ax_tdstFrames[slNumOfFrames + uwCnt4].uwAttribute=	eNoKey;		// Delete KeyFrame
												uwCnt3--;														// Dont change first KeyFrame
										}
										else
												uwCnt3=	uwCnt4 - 1;												// Change of KeyFrame
									}
									else
										uwCnt3=	uwCnt4 - 1;
								}
							}
							else
							{	uwCnt3=	uwCnt4 - 1;
							}
						}
						else
						{	if	(uwCnt4 < ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames)
							{
								uwFlag=	0;
								for	( uwCntZ=uwCnt3+1 ; uwCntZ<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCntZ++ ) {
									if	(	((ax_tdstFrames[slNumOfFrames + uwCntZ].uwTypeOfObject & 0x00FF) != TE_EmptyObject) ||
										(ax_tdstFrames[slNumOfFrames + uwCnt3].uwChildrenInHierarchy == 1) )
										uwFlag=	1;
								}
								// All objects equal to EmptyObject
								if	( uwFlag == 0 )
									ax_tdstFrames[slNumOfFrames + uwCnt4].uwAttribute=	eNoKey;
							}
							uwCnt3=	ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames;
						}
					}
				}
			}
		}
	}


	// Optimize KeyFrames	---------------------------------------------------------
/*	for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ )
	{	slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=	ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		// For each Channel
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			if	(ax_tdstChannels[slNumOfChannels + uwCnt2].uwUsedChannel == 0)
			{
				// For each KeyFrame
				for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
				{	// If we have a KeyFrame
					if	( ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute != eNoKey )
					{	signed long	uwCntZ, uwFlag;

						// Search next KeyFrame (k+1)
						uwCnt4=	uwCnt3 + 1;
						while	( (uwCnt4<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames) && (ax_tdstFrames[slNumOfFrames + uwCnt4].uwAttribute==eNoKey))
							uwCnt4++;
						// Search next next KeyFrame (k+2)
						uwCnt5=	uwCnt4 + 1;
						while	( (uwCnt5<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames) && (ax_tdstFrames[slNumOfFrames + uwCnt5].uwAttribute==eNoKey))
							uwCnt5++;

						// Optimize EmptyObject KeyFrames
						if	(	(uwCnt4 < ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames) &&
								(uwCnt5 < ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames) )
						{
							uwFlag=	0;
							for	( uwCntZ=uwCnt3+1 ; uwCntZ<uwCnt5 ; uwCntZ++ )
							{	if	((ax_tdstFrames[slNumOfFrames + uwCntZ].uwTypeOfObject & 0x00FF) != TE_EmptyObject)
									uwFlag=	1;
							}
							// All objects equal to EmptyObject
							if	(uwFlag == 0)
							{
								if	((ax_tdstFrames[slNumOfFrames + uwCnt5].uwTypeOfObject & 0x00FF) != TE_EmptyObject)
								{	ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	(SEB_xMaskQuatOri|SEB_xMaskQuatSca|SEB_xMaskScaleValues|SEB_xMaskPosition);
								}
								ax_tdstFrames[slNumOfFrames + uwCnt4].uwAttribute=	eNoKey;
								uwCnt3--;
							}
							else
							{
								fn_v_BinInterpolBetweenKeys(	&ax_tdstFrames[slNumOfFrames + uwCnt3],
																&ax_tdstFrames[slNumOfFrames + uwCnt5],
																a3a3_xMtxOri,
																a3a3_xMtxSca,
																a3_xPosition,
																(uwCnt4-uwCnt3)/(SEB_xReal)(uwCnt5-uwCnt3),
																ax_tdstChannels[slNumOfChannels + uwCnt2].a3_xLocalPivotPos,
																a4_xQuatOri,
																a4_xQuatSca,
																a3_xVecSca
															);
								if	( (fn_uw_AreSameQuat(ax_tdstFrames[slNumOfFrames + uwCnt4].a4_xQuatOri , a4_xQuatOri ) == 0) &&
									  (fn_uw_AreSameQuat(ax_tdstFrames[slNumOfFrames + uwCnt4].a4_xQuatSca , a4_xQuatSca ) == 0) &&
									  (fn_uw_AreSameVect(ax_tdstFrames[slNumOfFrames + uwCnt4].a3_xScaleValues, a3_xVecSca) == 0) &&
									  (fn_uw_AreSameVect(ax_tdstFrames[slNumOfFrames + uwCnt4].a3_xPosition, a3_xPosition) == 0) )
								{		ax_tdstFrames[slNumOfFrames + uwCnt4].uwAttribute=	eNoKey;		// Delete KeyFrame
										uwCnt3--;														// Dont change first KeyFrame
								}
								else	uwCnt3=	uwCnt4 - 1;												// Change of KeyFrame
							}
						}
						else
						{	if	(uwCnt4 < ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames)
							{
								uwFlag=	0;
								for	( uwCntZ=uwCnt3+1 ; uwCntZ<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCntZ++ )
								{	if	( (ax_tdstFrames[slNumOfFrames + uwCntZ].uwTypeOfObject & 0x00FF) != TE_EmptyObject )
										uwFlag=	1;
								}
								// All objects equal to EmptyObject
								if	( uwFlag == 0 )
									ax_tdstFrames[slNumOfFrames + uwCnt4].uwAttribute=	eNoKey;
							}
							uwCnt3=	ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames;
						}

					}

				}
			}
		}
	}*/


	// Sort hierarchy couples	-----------------------------------------------------
		// A tester mais certainement pas plus rapide

	// Set interpolation mask	-----------------------------------------------------
	for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ ) {
		// bad anim --> skip it
		if	(bValid(&stAnims[uwCnt1]))
			continue;
		else {
			xEps = xPrecision(&stAnims[uwCnt1]);
			xOneSubEps = (SEB_xReal)(1.0 - xEps);
		}
		
		slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=	ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		// For each Channel
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
			{	// If we have a KeyFrame
				if	( ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute != eNoKey )
				{	// Search next key
					uwCnt4=	uwCnt3 + 1;
					while	( (uwCnt4<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames) && (ax_tdstFrames[slNumOfFrames + uwCnt4].uwAttribute==eNoKey))
						uwCnt4++;

					if	( uwCnt4<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames )
					{	tdxVector3	a3_xPosition1, a3_xPosition2;

						// To avoid problems with interpolation between "normal" key and empty "key"
						if	( (uwCnt4 == (uwCnt3+1)) && ((ax_tdstFrames[slNumOfFrames + uwCnt4].uwTypeOfObject & 0x00FF)== TE_EmptyObject))
						{
							ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskQuatOri;
							ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskQuatSca;
							ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskScaleValues;
							ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskPosition;
						}
						else
						{
							//ax_tdstFrames[slNumOfFrames + uwCnt4].uwMask=		0x0000;
							if	( fn_uw_AreSameQuat(	ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatOri,
														ax_tdstFrames[slNumOfFrames + uwCnt4].a4_xQuatOri ) == 0 )
								ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskQuatOri;
							if	( fn_uw_AreSameQuat(	ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatSca,
														ax_tdstFrames[slNumOfFrames + uwCnt4].a4_xQuatSca ) == 0 )
								ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskQuatSca;
							if	( fn_uw_AreSameVect(	ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xScaleValues,
														ax_tdstFrames[slNumOfFrames + uwCnt4].a3_xScaleValues ) == 0 )
								ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskScaleValues;
							if	( fn_uw_AreSameVect(	ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xPosition,
														ax_tdstFrames[slNumOfFrames + uwCnt4].a3_xPosition ) == 0 )
								ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskPosition;
						}

						fn_v_CopyVect( a3_xPosition1, ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xPosition );
						fn_v_CopyVect( a3_xPosition2, ax_tdstFrames[slNumOfFrames + uwCnt4].a3_xPosition );
						fn_v_NormalizeVector( a3_xPosition1 );
						fn_v_NormalizeVector( a3_xPosition2 );
						uwCnt5=	fn_uw_AngleBetweenVect( a3_xPosition1, a3_xPosition2 );
					//	if	(uwCnt5 < SeuilAngCentre)
					//		ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskZeroAngCentre;
					}
					else
					{	// Set Mask between last and first key
						if	( fn_uw_AreSameQuat(	ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatOri,
													ax_tdstFrames[slNumOfFrames         ].a4_xQuatOri ) == 0 )
							ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskQuatOri;
						if	( fn_uw_AreSameQuat(	ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatSca,
													ax_tdstFrames[slNumOfFrames         ].a4_xQuatSca ) == 0 )
							ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskQuatSca;
						if	( fn_uw_AreSameVect(	ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xScaleValues,
													ax_tdstFrames[slNumOfFrames         ].a3_xScaleValues ) == 0 )
							ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskScaleValues;
						if	( fn_uw_AreSameVect(	ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xPosition,
													ax_tdstFrames[slNumOfFrames         ].a3_xPosition ) == 0 )
							ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskPosition;

						{	tdxVector3	a3_xPosition1, a3_xPosition2;

							fn_v_CopyVect( a3_xPosition1, ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xPosition );
							fn_v_CopyVect( a3_xPosition2, ax_tdstFrames[slNumOfFrames         ].a3_xPosition );
							fn_v_NormalizeVector( a3_xPosition1 );
							fn_v_NormalizeVector( a3_xPosition2 );
							uwCnt5=	fn_uw_AngleBetweenVect( a3_xPosition1, a3_xPosition2 );
						//	if	(uwCnt5 < SeuilAngCentre)
						//		ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskZeroAngCentre;
						}
						// Set mask (SEB_xTypeWrapLastKey) for wrapping animations
					/*	{	register	SEB_xReal	xCompX, xCompY, xCompZ, xAngleOri, xAngleSca, xScaleVal, xDistance;

							xAngleOri=	fn_uw_BinAngleBetweenQuat(	ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatOri,
																	ax_tdstFrames[slNumOfFrames         ].a4_xQuatOri );
							xAngleSca=	fn_uw_BinAngleBetweenQuat(	ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatSca,
																	ax_tdstFrames[slNumOfFrames         ].a4_xQuatSca );
							xCompX=	ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xPosition[0] - ax_tdstFrames[slNumOfFrames].a3_xPosition[0];
							xCompY=	ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xPosition[1] - ax_tdstFrames[slNumOfFrames].a3_xPosition[1];
							xCompZ=	ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xPosition[2] - ax_tdstFrames[slNumOfFrames].a3_xPosition[2];
							xScaleVal=	xCompX*xCompX + xCompY*xCompY + xCompZ*xCompZ;
							xCompX=	ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xScaleValues[0] - ax_tdstFrames[slNumOfFrames].a3_xScaleValues[0];
							xCompY=	ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xScaleValues[1] - ax_tdstFrames[slNumOfFrames].a3_xScaleValues[1];
							xCompZ=	ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xScaleValues[2] - ax_tdstFrames[slNumOfFrames].a3_xScaleValues[2];
							xDistance=	xCompX*xCompX + xCompY*xCompY + xCompZ*xCompZ;
							if	(	(xAngleOri < 0.005) &&
									(xAngleSca < 0.005) &&
									(xScaleVal < 0.005) &&
									(xDistance < 0.005) )
							{	ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xTypeWrapLastKey;
							}
						}*/
					}
					uwCnt3=	uwCnt4-1;
				}
			}
		}
	}

	// Kill extra KeyFrames	---------------------------------------------------------
	for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ ) {
		// bad anim --> skip it
		if	(bValid(&stAnims[uwCnt1]))
			continue;
		else {
			xEps = xPrecision(&stAnims[uwCnt1]);
			xOneSubEps = (SEB_xReal)(1.0 - xEps);
		}

		slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=	ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		// For each Channel
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			if	(ax_tdstChannels[slNumOfChannels + uwCnt2].uwUsedChannel == 1)
			{
				// Search Last KeyFrame
				uwCnt3=	ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames - 1;
				while	( (uwCnt3>=0) && (ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute==eNoKey) )
					uwCnt3--;
				// Search Last Last KeyFrame
				uwCnt4=	uwCnt3 - 1;
				while	( (uwCnt4>=0) && (ax_tdstFrames[slNumOfFrames + uwCnt4].uwAttribute==eNoKey) )
					uwCnt4--;

				// Optimize same KeyFrames
				if	(	((uwCnt3>=0) && ((ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask & SEB_xMaskAllLow) == SEB_xMaskAllLow)) &&
						((uwCnt4>=0) && ((ax_tdstFrames[slNumOfFrames + uwCnt4].uwMask & SEB_xMaskAllLow) == SEB_xMaskAllLow)) &&
						( fn_uw_AreSameQuat(	ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatOri,
												ax_tdstFrames[slNumOfFrames         ].a4_xQuatOri ) == 0 )			&&
						( fn_uw_AreSameQuat(	ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatSca,
												ax_tdstFrames[slNumOfFrames         ].a4_xQuatSca ) == 0 )			&&
						( fn_uw_AreSameVect(	ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xScaleValues,
												ax_tdstFrames[slNumOfFrames         ].a3_xScaleValues ) == 0 )		&&
						( fn_uw_AreSameVect(	ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xPosition,
												ax_tdstFrames[slNumOfFrames         ].a3_xPosition ) == 0 )			)
				{	ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute=	eNoKey;		// NoKey
				}
			}
		}
	}


	// Calculate number of KeyFrame	-------------------------------------------------
	for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ ) {
		// bad anim --> skip it
		if	(bValid(&stAnims[uwCnt1]))
			continue;
		else {
			xEps = xPrecision(&stAnims[uwCnt1]);
			xOneSubEps = (SEB_xReal)(1.0 - xEps);
		}
		
		slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=	ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		// For each Channel
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			// For each KeyFrame
			uwCnt4=	0;
			for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
			{	// If we have a KeyFrame
				if	( ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute != eNoKey )
					uwCnt4++;
			}
			ax_tdstChannels[slNumOfChannels + uwCnt2].uwNumberOfKeys=	(unsigned short) uwCnt4;
		}
	}


	// Clear Events -----------------------------------------------------------------
	for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ ) {
		// bad anim --> skip it
		if	(bValid(&stAnims[uwCnt1]))
			continue;
		else {
			xEps = xPrecision(&stAnims[uwCnt1]);
			xOneSubEps = (SEB_xReal)(1.0 - xEps);
		}

		slNumOfChannels=	ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		// For each Channel
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			// With channel killing !
			if	( ax_tdstChannels[slNumOfChannels + uwCnt2].uwUsedChannel == 1 )
			{
				// For each Frame
				for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
				{	if	( (ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject & 0x00FF) == TE_Event )
					{	ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject=	(ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject & 0xFF00) | TE_EmptyObject;
						ax_tdstFrames[slNumOfFrames + uwCnt3].swNumberInTable=	-1;
					}
				}
			}
		}
	}


	//printf("Number of key frames       NumberOfChannels * NumberOfFrames     Total channel\n");
	ulTotGeneral1=		uwNbAnims;
	ulTotMem1=			0;
	ulTotKeyFrame1=		0;
	ulTotFrame1=		0;
	ulTotChannel1=		0;
	ulTotOnlyFrame1=	0;
	ulTotHierarchy1=	0;
	ulTotEvents1=		0;

	fprintf( SizeOut, "Optimisations niveau 1\n" );
	fprintf( SizeOut, "KeyFrame    Frame   Channel   OnlyFrame   Hierarchy   General   Events   Place Memoire\n" );
	for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ ) {
		// bad anim --> skip it
		if	(bValid(&stAnims[uwCnt1]))
			continue;
		else {
			xEps = xPrecision(&stAnims[uwCnt1]);
			xOneSubEps = (SEB_xReal)(1.0 - xEps);
		}
		
		slNumOfOnlyFrames=	ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=		ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		ulSToGeneral1=		1;
		ulSToKeyFrame1=		0;
		ulSToHierarchy1=	ax_tdstA3dGENERAL[uwCnt1].uwNumberOfHierarchies;
		ulSToOnlyFrame1=	ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames;
		ulSToChannel1=		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels;
		ulSToEvents1=		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfEvents;
		ulSToFrame1=		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels * ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames;

		ulSToKeyFrame1=		0;
		// For each Channel
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
			ulSToKeyFrame1+=	ax_tdstChannels[slNumOfChannels + uwCnt2].uwNumberOfKeys;

		ulSToMem1=	ulSToGeneral1 * 64L + ulSToChannel1 * 16L + ulSToOnlyFrame1 * 6L +
					ulSToKeyFrame1 * 32L + ulSToHierarchy1 * 4L + ulSToFrame1 * 4L +
					ulSToOnlyFrame1 * (8+12);	// + quaternions et vecteurs speed !!!

		fprintf( SizeOut, "%8d   %6d   %7d   %9d   %9d   %7d   %6d   %13d   %s\n",
					ulSToKeyFrame1, ulSToFrame1, ulSToChannel1, ulSToOnlyFrame1, ulSToHierarchy1, ulSToGeneral1,
					ulSToEvents1, ulSToMem1, szAnimName(&stAnims[uwCnt1]) );

		ulTotMem1+=			ulSToMem1;
		ulTotKeyFrame1+=	ulSToKeyFrame1;
		ulTotFrame1+=		ulSToFrame1;
		ulTotChannel1+=		ulSToChannel1;
		ulTotOnlyFrame1+=	ulSToOnlyFrame1;
		ulTotHierarchy1+=	ulSToHierarchy1;
		ulTotEvents1+=		ulSToEvents1;
	}
	fprintf( SizeOut, "Totaux\n" );
	fprintf( SizeOut, "%8d   %6d   %7d   %9d   %9d   %7d   %6d   %10d\n",
				ulTotKeyFrame1, ulTotFrame1, ulTotChannel1, ulTotOnlyFrame1, ulTotHierarchy1, ulTotGeneral1, ulTotEvents1, ulTotMem1 );
	fprintf( SizeOut, "\n" );

	printf("ulTotKeyFrame1=  %d\n", ulTotKeyFrame1);
	printf("ulTotFrame1=     %d\n", ulTotFrame1);
	printf("ulTotChannel1=   %d\n", ulTotChannel1);
	printf("ulTotOnlyFrame1= %d\n", ulTotOnlyFrame1);
	printf("ulTotHierarchy1= %d\n", ulTotHierarchy1);
	printf("ulTotGeneral1=   %d\n", ulTotGeneral1);
	printf("ulTotEvents1=    %d\n", ulTotEvents1);

	printf("Memoire utilisee  %d\n\n",	ulTotMem1 );
}



// **********************************************************************************
unsigned long	fn_uw_InsertVector(	signed long	_slStackStart,
									tdxVector3	_tdxVect )
{	signed long	slCnt1;

	if	( fn_uw_CompVect( _tdxVect, a3_xVector1 ) == 0 )
		ulNbVect1++;

	for	( slCnt1=_slStackStart ; slCnt1<M_GetStackPos(eStackSavedVertexes) ; slCnt1++ )
	{
		if	( fn_uw_AreSameVect( ax_tdxSavedVertexes[slCnt1], _tdxVect ) == 0 )
			return	slCnt1;
	}
	fn_v_AllocateOnStack( eStackSavedVertexes, 1 );
	fn_v_CopyVect( ax_tdxSavedVertexes[ M_GetStackAlloc(eStackSavedVertexes) ], _tdxVect );

	return	slCnt1;
}



unsigned long	fn_uw_InsertQuater(	signed long	_slStackStart,
									tdxQuater4	_tdxQuat )
{	signed long	slCnt1;

	if	( fn_uw_CompQuat( _tdxQuat, a4_xQuater1 ) == 0 )
		ulNbQuat1++;

	for	( slCnt1=_slStackStart ; slCnt1<M_GetStackPos(eStackSavedQuaternions) ; slCnt1++ )
	{
		if	( fn_uw_AreSameQuat( ax_tdxSavedQuaternions[slCnt1], _tdxQuat ) == 0 )
			return	slCnt1;
	}
	fn_v_AllocateOnStack( eStackSavedQuaternions, 1 );
	fn_v_CopyQuat( ax_tdxSavedQuaternions[ M_GetStackAlloc(eStackSavedQuaternions) ], _tdxQuat );
	return	slCnt1;
}



unsigned long	fn_uw_InsertNTTO(	signed long		_slStackStart,
									signed short	_swNumberInTable,
									unsigned short	_uwTypeOfObject,
									unsigned char	_ucTransparency )
{	signed long	slCnt1;

	for	( slCnt1=_slStackStart ; slCnt1<M_GetStackPos(eStackSavedNTTO) ; slCnt1++ )
	{
		if	(	(ax_tdstSavedNTTO[slCnt1].ucNumberInTable == _swNumberInTable) &&
				(ax_tdstSavedNTTO[slCnt1].uwTypeOfObject == _uwTypeOfObject) &&
				(ax_tdstSavedNTTO[slCnt1].ucTransparency == _ucTransparency) )
			return	slCnt1;
	}
	fn_v_AllocateOnStack( eStackSavedNTTO, 1 );
	ax_tdstSavedNTTO[ M_GetStackAlloc(eStackSavedNTTO) ].ucNumberInTable=	_swNumberInTable;
	ax_tdstSavedNTTO[ M_GetStackAlloc(eStackSavedNTTO) ].uwTypeOfObject=	_uwTypeOfObject;
	ax_tdstSavedNTTO[ M_GetStackAlloc(eStackSavedNTTO) ].ucTransparency=	_ucTransparency;
	return	slCnt1;
}



/* comparison function for qsorting events on frame number */

static int fn_iCmpEventsOnFrameAndChannel(const void *va, const void *vb)
{
	tdstBinEvent *a, *b;

	a=(tdstBinEvent *)va;
	b=(tdstBinEvent *)vb;

	if(a->uwFrameNumber>b->uwFrameNumber)
		return 1;
	else if(a->uwFrameNumber<b->uwFrameNumber)
		return -1;
	else if(a->uwChannelNumber>b->uwChannelNumber)
		return 1;
	else if(a->uwChannelNumber<b->uwChannelNumber)
		return -1;
	else 
		return 0;
}

// **********************************************************************************
void	fn_v_OptimiseAnimation2V6i(	unsigned short	uwNbAnims )
{	signed long		uwCnt1, uwCnt2, uwCnt3;
	signed long		slNumOfOnlyFrames, slNumOfChannels, slNumOfFrames;
	signed long		uwMinInVectors, uwMinInQuaternions, uwMinOfPositions, uwMinInNTTO;
	signed long		uwNumOfLastFrame, uwFlagChangeFrame;
	signed long		ulTotVectors2, ulTotQuaternions2;

	printf("Optimisations2 ----------------\n");

	// Kill duplicated vectors and quaternions	-------------------------------------
	ulTotGeneral2=		uwNbAnims;
	ulTotMem2=			0;
	ulTotKeyFrame2=		0;
	ulTotFrame2=		0;
	ulTotChannel2=		0;
	ulTotOnlyFrame2=	0;
	ulTotHierarchy2=	0;
	ulTotEvents2=		0;
	ulTotVectors2=		0;
	ulTotQuaternions2=	0;
	fTotTime2=			xZero;

	ulNbQuat1= 0;
	ulNbVect1= 0;

	fprintf( SizeOut, "Optimisations niveau 2\n" );
	fprintf( SizeOut, "KeyFrame    Vectors    Quaternions   VectorsOpt  QuaternionsOpt   Place Memoire   Temps\n" );
	for	( uwCnt1=0 ; uwCnt1<uwNbAnims ; uwCnt1++ ) {
		// bad anim --> skip it
		if	(bValid(&stAnims[uwCnt1]))
			continue;
		else {
			xEps = xPrecision(&stAnims[uwCnt1]);
			xOneSubEps = (SEB_xReal)(1.0 - xEps);
		}

		ax_tdstA3dGENERAL[uwCnt1].slNumOfSavedVectors=		M_GetStackPos(eStackSavedVertexes);
		ax_tdstA3dGENERAL[uwCnt1].slNumOfSavedQuaternions=	M_GetStackPos(eStackSavedQuaternions);
		ax_tdstA3dGENERAL[uwCnt1].slNumOfSavedNTTO=			M_GetStackPos(eStackSavedNTTO);

		slNumOfOnlyFrames=		ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=		ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;

		uwMinInVectors=			M_GetStackPos(eStackSavedVertexes);
		uwMinInQuaternions=		M_GetStackPos(eStackSavedQuaternions);
		uwMinInNTTO=			M_GetStackPos(eStackSavedNTTO);

		ulSToGeneral2=		1;
		ulSToKeyFrame2=		0;
		ulSToHierarchy2=	ax_tdstA3dGENERAL[uwCnt1].uwNumberOfHierarchies;
		ulSToOnlyFrame2=	ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames;
		ulSToChannel2=		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels;
		ulSToEvents2=		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfEvents;
		ulSToFrame2=		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels * ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames;
		slNbTotVect+=		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfVectors;
		slNbTotQuat+=		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfQuaternions;

		// Insert zero vector and identity quaternion
		//fn_uw_InsertVector( uwMinInVectors, a3_xVector0 );
		//fn_uw_InsertQuater( uwMinInQuaternions, a4_xQuater0 );

		// If the channel is used
		ax_tdstA3dGENERAL[uwCnt1].slNumOfAnimationTranslationOffset=	fn_uw_InsertVector( uwMinInVectors, ax_tdstA3dGENERAL[uwCnt1].uwAnimationTranslationOffset );
		ax_tdstA3dGENERAL[uwCnt1].slNumOfAnimationRotationOffset=		fn_uw_InsertQuater( uwMinInQuaternions, ax_tdstA3dGENERAL[uwCnt1].uwAnimationRotationOffset );

		// For each (only) frame
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt2++ )
		{
			if	(ax_tdstOnlyFrames[uwCnt2 + slNumOfOnlyFrames].slNumOfAngularSpeedQuat != 0xFFFFFFFF)
				ax_tdstOnlyFrames[uwCnt2 + slNumOfOnlyFrames].slNumOfAngularSpeedQuat=	fn_uw_InsertQuater( uwMinInQuaternions, ax_tdstOnlyFrames[uwCnt2 + slNumOfOnlyFrames].tdxAngularSpeedQuat );
			if	(ax_tdstOnlyFrames[uwCnt2 + slNumOfOnlyFrames].slNumOfSpeedVector != 0xFFFFFFFF)
				ax_tdstOnlyFrames[uwCnt2 + slNumOfOnlyFrames].slNumOfSpeedVector=		fn_uw_InsertVector( uwMinInVectors, ax_tdstOnlyFrames[uwCnt2 + slNumOfOnlyFrames].tdxSpeedVector );
		}

		// For each Channel
		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfKeyFrames=	0;
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			// With channel killing !
			if	( ax_tdstChannels[slNumOfChannels + uwCnt2].uwUsedChannel == 1 )
			{
				ulSToKeyFrame2+=	ax_tdstChannels[slNumOfChannels + uwCnt2].uwNumberOfKeys;
				ax_tdstChannels[uwCnt2 + slNumOfChannels].slNumOfLocalPivotPos=	fn_uw_InsertVector( uwMinInVectors, ax_tdstChannels[slNumOfChannels + uwCnt2].a3_xLocalPivotPos );

				// For each frame
				for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
				{
					if	( ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute != eNoKey )
					{
						ax_tdstFrames[slNumOfFrames + uwCnt3].slNumOfQuatOri=		fn_uw_InsertQuater( uwMinInQuaternions, ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatOri );
						ax_tdstFrames[slNumOfFrames + uwCnt3].slNumOfQuatSca=		fn_uw_InsertQuater( uwMinInQuaternions, ax_tdstFrames[slNumOfFrames + uwCnt3].a4_xQuatSca );
						ax_tdstFrames[slNumOfFrames + uwCnt3].slNumOfScaleValues=	fn_uw_InsertVector( uwMinInVectors, ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xScaleValues );
						ax_tdstA3dGENERAL[uwCnt1].uwNumberOfKeyFrames++;
						if	( fn_uw_CompQuat(ax_tdxSavedQuaternions[ ax_tdstFrames[slNumOfFrames + uwCnt3].slNumOfQuatOri ], a4_xQuater1) == 0 )
							ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskIdQuatOri;
						if	( fn_uw_CompQuat(ax_tdxSavedQuaternions[ ax_tdstFrames[slNumOfFrames + uwCnt3].slNumOfQuatSca ], a4_xQuater1) == 0 )
							ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskIdQuatSca;
						if	( fn_uw_CompVect(ax_tdxSavedVertexes   [ ax_tdstFrames[slNumOfFrames + uwCnt3].slNumOfScaleValues ], a3_xVector1) == 0 )
							ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask|=	SEB_xMaskIdScaleValues;
					}
				}
			}
		}


		// Set SEB_xMaskLastKey flag
		// For each Channel
		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfKeyFrames=	0;
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			// With channel killing !
			if	( ax_tdstChannels[slNumOfChannels + uwCnt2].uwUsedChannel == 1 )
			{
				ax_tdstChannels[uwCnt2 + slNumOfChannels].slNumOfLocalPivotPos=	fn_uw_InsertVector( uwMinInVectors, ax_tdstChannels[slNumOfChannels + uwCnt2].a3_xLocalPivotPos );

				// For each frame
				uwNumOfLastFrame=	0;
				for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
				{
					if	( ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute != eNoKey )
					{	uwNumOfLastFrame=	uwCnt3;
					}
				}
				ax_tdstFrames[slNumOfFrames + uwNumOfLastFrame].uwMask|=	SEB_xMaskLastKey;
			}
		}

		// Copy of Positions in Vertexes Stack
		uwMinOfPositions=							M_GetStackPos(eStackSavedVertexes);
		ax_tdstA3dGENERAL[uwCnt1].slNumOfPositions=	uwMinOfPositions;

		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			// With channel killing !
			if	( ax_tdstChannels[slNumOfChannels + uwCnt2].uwUsedChannel == 1 )
			{
				// For each frame
				for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
				{	if	( ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute != eNoKey )
						ax_tdstFrames[slNumOfFrames + uwCnt3].slNumOfPosition=	fn_uw_InsertVector( uwMinOfPositions, ax_tdstFrames[slNumOfFrames + uwCnt3].a3_xPosition );

					// Insert uwFrameNumber and uwTypeOfObject
					ax_tdstFrames[slNumOfFrames + uwCnt3].slNumOfNTTO=	fn_uw_InsertNTTO( uwMinInNTTO,	ax_tdstFrames[slNumOfFrames + uwCnt3].swNumberInTable,
																										ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject,
																										ax_tdstFrames[slNumOfFrames + uwCnt3].ucTransparency );
				}
			}
		}

		// Optimise Frames redondancy
		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedFrames=		1;
		uwNumOfLastFrame=										0;
		ax_tdstOnlyFrames[slNumOfOnlyFrames].uwNumOfSavedFrame=	ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedFrames - 1;

		for	( uwCnt2=1 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt2++ )
		{	// For each frame after the first
			uwFlagChangeFrame=	0;

			for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt3++ )
			{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt3].slNumOfFrames;

				// With channel killing !
				if	( ax_tdstChannels[slNumOfChannels + uwCnt3].uwUsedChannel == 1 )
				{
					if	( (ax_tdstFrames[slNumOfFrames + uwNumOfLastFrame].swNumberInTable != ax_tdstFrames[slNumOfFrames + uwCnt2].swNumberInTable) ||
						  (ax_tdstFrames[slNumOfFrames + uwNumOfLastFrame].uwTypeOfObject  != ax_tdstFrames[slNumOfFrames + uwCnt2].uwTypeOfObject ) ||
						  (ax_tdstFrames[slNumOfFrames + uwNumOfLastFrame].ucTransparency  != ax_tdstFrames[slNumOfFrames + uwCnt2].ucTransparency ) )
						uwFlagChangeFrame=	1;
				}
			}

			if	( uwFlagChangeFrame != 0 )
			{	uwNumOfLastFrame=	uwCnt2;
				ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedFrames++;
			}
			ax_tdstOnlyFrames[uwCnt2 + slNumOfOnlyFrames].uwNumOfSavedFrame=	ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedFrames - 1;
		}

		//-------------------------------
		// Sort Events on FrameNumbers (and, on second key, on channel number)
		qsort(&ax_tdstEvents[ax_tdstA3dGENERAL[uwCnt1].slNumOfEvents], ax_tdstA3dGENERAL[uwCnt1].uwNumberOfEvents, sizeof(tdstBinEvent), fn_iCmpEventsOnFrameAndChannel);
		//-------------------------------


		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedVectors=		(unsigned short) (M_GetStackPos(eStackSavedVertexes) - uwMinInVectors);
		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedQuaternions=	(unsigned short) (M_GetStackPos(eStackSavedQuaternions) - uwMinInQuaternions);
		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedNTTO=			(unsigned short) (M_GetStackPos(eStackSavedNTTO) - uwMinInNTTO);


		fSToTime2=	(SEB_xReal) ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames / (SEB_xReal) ax_tdstA3dGENERAL[uwCnt1].uwAnimationSpeed;
		ulSToMem2=	ulSToGeneral2 * sizeof(tdstFileA3dAnimationGENERAL) +
					ulSToChannel2 * sizeof(tdstFileChannel) +
					ulSToOnlyFrame2 * sizeof(tdstFileOnlyFrame) +
					ulSToKeyFrame2 * sizeof(tdstFileKeyFrame) +
					ulSToHierarchy2 * sizeof(tdstHierarchy) +
					ulSToFrame2 * sizeof(tdstFileFrame) +
					ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedVectors * sizeof(tdxVector3) +
					ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedQuaternions * sizeof(tdxSShortQuater4);

		fprintf( SizeOut, "%8d   %7d    %11d   %10d   %14d   %13d   %4.2f sec   %s\n",
					ulSToKeyFrame2, ax_tdstA3dGENERAL[uwCnt1].uwNumberOfVectors, ax_tdstA3dGENERAL[uwCnt1].uwNumberOfQuaternions,
					ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedVectors, ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedQuaternions,
					ulSToMem2, fSToTime2, szAnimName(&stAnims[uwCnt1]) );

		ulTotMem2+=			ulSToMem2;
		ulTotKeyFrame2+=	ulSToKeyFrame2;
		ulTotFrame2+=		ulSToFrame2;
		ulTotChannel2+=		ulSToChannel2;
		ulTotOnlyFrame2+=	ulSToOnlyFrame2;
		ulTotHierarchy2+=	ulSToHierarchy2;
		ulTotEvents2+=		ulSToEvents2;
		ulTotVectors2+=		ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedVectors;
		ulTotQuaternions2+=	ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedQuaternions;
		fTotTime2+=			fSToTime2;
	}
	fprintf( SizeOut, "Totaux\n" );
	fprintf( SizeOut, "%8d   %7d    %11d   %10d   %14d   %13d   %4.2f sec   %s\n",
				ulTotKeyFrame2, slNbTotVect, slNbTotQuat,
				ulTotVectors2, ulTotQuaternions2, ulTotMem2, fTotTime2, szAnimName(&stAnims[uwCnt1]) );
	fprintf( SizeOut, "\n" );

	printf("ulTotKeyFrame2=  %d\n", ulTotKeyFrame2);
	printf("ulTotFrame2=     %d\n", ulTotFrame2);
	printf("ulTotChannel2=   %d\n", ulTotChannel2);
	printf("ulTotOnlyFrame2= %d\n", ulTotOnlyFrame2);
	printf("ulTotHierarchy2= %d\n", ulTotHierarchy2);
	printf("ulTotGeneral2=   %d\n", ulTotGeneral2);
	printf("ulTotEvents2=    %d\n", ulTotEvents2);

	ulTotMem2=	ulTotGeneral2 * sizeof(tdstFileA3dAnimationGENERAL) +
				ulTotChannel2 * sizeof(tdstFileChannel) +
				ulTotOnlyFrame2 * sizeof(tdstFileOnlyFrame) +
				ulTotKeyFrame2 * sizeof(tdstFileKeyFrame) +
				ulTotHierarchy2 * sizeof(tdstHierarchy) +
				ulTotFrame2 * sizeof(tdstFileFrame) +
				ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedVectors * sizeof(tdxVector3) +
				ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedQuaternions * sizeof(tdxSShortQuater4);
	printf("Memoire utilisee  %d\n\n",	ulTotMem2 );

	printf( "ulNbQuat1= %8d\n", ulNbQuat1 );
	printf( "ulNbVect1= %8d\n", ulNbVect1 );
}



// **********************************************************************************
unsigned short	fn_uw_SwapWord(	unsigned short	x )
{
#ifdef	A3X_PC
	if	( uwOrder == 0 )
#else
	if	( uwOrder != 0 )
#endif
			return	( ((x<<8)&0xFF00) | ((x>>8)&0x00FF) );
	else	return	x;
}



// ----------------------------------------------------------------------------------
unsigned long	fn_ul_SwapLong(	unsigned long	x )
{
#ifdef	A3X_PC
	if	( uwOrder == 0 )
#else
	if	( uwOrder != 0 )
#endif
			return	( ((x<<24)&0xFF000000L) | ((x<<8)&0x00FF0000L) | ((x>>24)&0x000000FFL) | ((x>>8)&0x0000FF00L) );
	else	return	x;
}



// **********************************************************************************
unsigned long	fn_v_WriteHunk(	char			HunkName[4],
								char			*Buffer,
								unsigned long	ulSize,
								unsigned long	ulCount,
								FILE			*Stream )
{	unsigned long		ulSavedSize;

	ulSavedSize=	fn_ul_SwapLong(ulSize*ulCount);
	if	( uwA3xDebug ==	1 )
	{	fwrite(	HunkName    , 4, 1, Stream );
		fwrite(	&ulSavedSize, 4, 1, Stream );
	}
	if (fwrite(Buffer,ulSize,ulCount,Stream) != ulCount) {
		fprintf(ErrorFile, "Anim Save FAIL, write in file error\n");
		//assert(FALSE);
	}

	ulSavedSize=	ulSize*ulCount;
	return	ulSavedSize;
}



// **********************************************************************************
void	fn_v_Verify(	char			*sText,
						unsigned short	uwMax,
						unsigned short	uwNum )
{	if	( (uwNum) > (uwMax) )
	{	printf("Erreur sauvegarde : %s", sText);
	}
}



// **********************************************************************************
// Modif : 16/07/98 Replace Element number by channel number before saving - Carlos Torres
// Modif : 20/07/98 Sort channel by channel number - Carlos Torres
// Modif : 30/07/98 Add a Save Dir aprameter - Carlos 
// Modif : 27/08/98 Fill the new morph struct - Carlos 
// Modif : 28/08/98 Save A3i Version a tthe beginning of the A3i - Carlos 
// Modif : 06/09/98 Change alignement before event - Carlos 
void	fn_v_WriteAnimationV6i(unsigned short uwCnt1,char * p_szSaveDir)
{	signed long		uwCnt2, uwCnt3;
	signed long		slNumOfOnlyFrames, slNumOfChannels;
	signed long		slNumOfSavedVectors, slNumOfSavedQuaternions, slNumOfHierarchies, slNumOfSavedNTTO, slNumOfFramesNTTO, slNumOfEvents, slNumOfFrames, slNumOfMorphData;
	signed long		uwFileNumOfFrames, uwFileNumOfChannel, uwFileNumOfKeyFrames;
	signed long		ulRealNumOfChannel, ulRealNumOfFrame;
	unsigned short	uwRealNumberOfChannels, uwRealNumberOfKeyFrames, uwAlign= 0;
	unsigned long	ulSavedSize, ulSizeOfAnim;
	signed long		slNumOfRealFrame, uwLastChangeFrame, uwLastRealFrame;
	char			FileName[500];
	FILE			*Out;
	short			wVersion = A3i_Version;

	// Output Directory Name
	sprintf(FileName,"%s\\%s",p_szSaveDir,szAnimName(&stAnims[uwCnt1]));

	if	( uwOrder == 0 )
			FileName[ strlen(FileName) - 1 ]=	'm';	// Motorola order
	else	FileName[ strlen(FileName) - 1 ]=	'i';	// Intel order

	if	( uwA3xDebug == 0 )
			FileName[ strlen(FileName) - 3 ]=	'A';	// A3x normal mode
	else	FileName[ strlen(FileName) - 3 ]=	'D';	// Debug mode


	if	(!bValid(&stAnims[uwCnt1]))
	{
		if	( uwA3xDebug == 0 )
		{	if	( uwOrder == 0 )
					printf("Save *.a3m : %s\n", FileName);		// Motorola order
			else	printf("Save *.a3i : %s\n", FileName);		// Intel order
		}
		else
		{	if	( uwOrder == 0 )
					printf("Save *.d3m : %s\n", FileName);		// Motorola order
			else	printf("Save *.d3i : %s\n", FileName);		// Intel order
		}


		slNumOfOnlyFrames=			ax_tdstA3dGENERAL[uwCnt1].slNumOfOnlyFrames;
		slNumOfChannels=			ax_tdstA3dGENERAL[uwCnt1].slNumOfChannels;
		slNumOfSavedVectors=		ax_tdstA3dGENERAL[uwCnt1].slNumOfSavedVectors;
		slNumOfSavedQuaternions=	ax_tdstA3dGENERAL[uwCnt1].slNumOfSavedQuaternions;
		slNumOfHierarchies=			ax_tdstA3dGENERAL[uwCnt1].slNumOfHierarchies;
		slNumOfSavedNTTO=			ax_tdstA3dGENERAL[uwCnt1].slNumOfSavedNTTO;
		slNumOfFramesNTTO=			ax_tdstA3dGENERAL[uwCnt1].slNumOfFramesNTTO;
		slNumOfEvents=				ax_tdstA3dGENERAL[uwCnt1].slNumOfEvents;
		slNumOfMorphData=			ax_tdstA3dGENERAL[uwCnt1].slNumOfMorphData;

		// With channel killing !
		uwRealNumberOfChannels=		0;
		uwRealNumberOfKeyFrames=	0;
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			if	( ax_tdstChannels[slNumOfChannels + uwCnt2].uwUsedChannel == 1 )
			{	uwRealNumberOfChannels++;

				for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
					if	( ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute != eNoKey )
						uwRealNumberOfKeyFrames++;
			}
		}

		// ------------------------------------------------------------------------------
		// change Hierarchies 
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfHierarchies ; uwCnt2++ ) {
			// Replace Element number by channel number
			ax_tdstHierarchies[slNumOfHierarchies+uwCnt2].uwChild =  
				ax_tdstChannels[slNumOfChannels+ax_tdstHierarchies[slNumOfHierarchies+uwCnt2].uwChild].uwChannelNumber;
			ax_tdstHierarchies[slNumOfHierarchies+uwCnt2].uwFather = 
				ax_tdstChannels[slNumOfChannels+ax_tdstHierarchies[slNumOfHierarchies+uwCnt2].uwFather].uwChannelNumber;
		}

		// ------------------------------------------------------------------------------
		// sort channel
		{
			int iNbChannelUnsorted,iLeftToPermute;

			// sort channel
			for (iNbChannelUnsorted=ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels-1;iNbChannelUnsorted;iNbChannelUnsorted--) 
			{
				int bPermuteDone=0;
				tdstBinChannel * p_stChannel, * p_stNextChannel,tdstTempChannel;

				p_stChannel = &ax_tdstChannels[slNumOfChannels];
				p_stNextChannel = p_stChannel+1;

				for (iLeftToPermute=0;iLeftToPermute<iNbChannelUnsorted;iLeftToPermute++,p_stChannel=p_stNextChannel,p_stNextChannel++) 
				{
					// permutation to have ascendant channel number
					if (p_stChannel->uwChannelNumber > p_stNextChannel->uwChannelNumber) {
						tdstTempChannel=*p_stChannel;
						*p_stChannel=*p_stNextChannel;
						*p_stNextChannel=tdstTempChannel;
						bPermuteDone=1;
					}
				}
				
				// If no permutation channels is sorted
				if (!bPermuteDone)
					break;
			}
		}

		// Copy GENERAL
		swReadedWord=											ax_tdstA3dGENERAL[uwCnt1].uwAnimationSpeed;				// uwAnimationSpeed
		ax_tdstFileA3dGENERAL[uwCnt1].uwAnimationSpeed=			fn_uw_SwapWord( swReadedWord );

		swReadedWord=											ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedVectors;		// uwNumberOfVectors
		ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfVectors=		fn_uw_SwapWord( swReadedWord );
		swReadedWord=											ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedQuaternions;	// uwNumberOfQuaternions
		ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfQuaternions=	fn_uw_SwapWord( swReadedWord );
		swReadedWord=											ax_tdstA3dGENERAL[uwCnt1].uwNumberOfHierarchies;		// uwNumberOfHierarchies
		ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfHierarchies=	fn_uw_SwapWord( swReadedWord );
		swReadedWord=											ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedNTTO;			// uwNumberOfSavedNTTO
		ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfSavedNTTO=		fn_uw_SwapWord( swReadedWord );

		//swReadedWord=											ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels;			// uwNumberOfChannels
		//ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfChannels=		fn_uw_SwapWord( swReadedWord );
		ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfChannels=		fn_uw_SwapWord( uwRealNumberOfChannels );
		swReadedWord=											ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames;				// uwNumberOfFrames
		ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfFrames=			fn_uw_SwapWord( swReadedWord );
		//swReadedWord=											ax_tdstA3dGENERAL[uwCnt1].uwNumberOfKeyFrames;			// uwNumberOfKeyFrames
		//ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfKeyFrames=		fn_uw_SwapWord( swReadedWord );
		ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfKeyFrames=		fn_uw_SwapWord( uwRealNumberOfKeyFrames );
		swReadedWord=											ax_tdstA3dGENERAL[uwCnt1].uwNumberOfEvents;				// uwNumberOfEvents
		ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfEvents=			fn_uw_SwapWord( swReadedWord );

		swReadedWord=	(signed short)																					// uwNumOfAnimationTranslationOffset
						(ax_tdstA3dGENERAL[uwCnt1].slNumOfAnimationTranslationOffset - slNumOfSavedVectors);
		ax_tdstFileA3dGENERAL[uwCnt1].uwNumOfAnimationTranslationOffset=	fn_uw_SwapWord( swReadedWord );
		swReadedWord=	(signed short)																					// uwNumOfAnimationRotationOffset
						(ax_tdstA3dGENERAL[uwCnt1].slNumOfAnimationRotationOffset -	slNumOfSavedQuaternions);
		ax_tdstFileA3dGENERAL[uwCnt1].uwNumOfAnimationRotationOffset=		fn_uw_SwapWord( swReadedWord );
		swReadedWord=	(signed short)
						(ax_tdstA3dGENERAL[uwCnt1].slNumOfPositions - slNumOfSavedVectors);
		ax_tdstFileA3dGENERAL[uwCnt1].uwNumOfFirstPosition=					fn_uw_SwapWord( swReadedWord );
		swReadedWord=												ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedFrames;	// uwNumberOfSavedFrames
		ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfSavedFrames=				fn_uw_SwapWord( swReadedWord );

		swReadedWord=ax_tdstA3dGENERAL[uwCnt1].uwNumberOfMorphData;	
		ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfMorphData=			fn_uw_SwapWord( swReadedWord );

		ax_tdstFileA3dGENERAL[uwCnt1].uwStartFrame=				fn_uw_SwapWord( 0 );
		ax_tdstFileA3dGENERAL[uwCnt1].uwEndFrame=				fn_uw_SwapWord( ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames );
		ax_tdstFileA3dGENERAL[uwCnt1].uwFlags=					fn_uw_SwapWord( ax_tdstA3dGENERAL[uwCnt1].uwFlags );
		ax_tdstFileA3dGENERAL[uwCnt1].uwFakeAnimSpeed=			fn_uw_SwapWord( ax_tdstA3dGENERAL[uwCnt1].uwFakeAnimSpeed );
	//	ax_tdstFileA3dGENERAL[uwCnt1].uwAlign=	0x0000;

		// Copy vertexes
		assert(MaxInFileVertexesTab > ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedVectors);
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedVectors ; uwCnt2++ )
		{
			fReadedFloat=					(float) ax_tdxSavedVertexes[uwCnt2 + slNumOfSavedVectors][0];
			slReadedLong=					*( (signed long *) &fReadedFloat );
			ax_tdxFileVertexes[uwCnt2][0]=	fn_ul_SwapLong( slReadedLong );
			fReadedFloat=					(float) ax_tdxSavedVertexes[uwCnt2 + slNumOfSavedVectors][1];
			slReadedLong=					*( (signed long *) &fReadedFloat );
			ax_tdxFileVertexes[uwCnt2][1]=	fn_ul_SwapLong( slReadedLong );
			fReadedFloat=					(float) ax_tdxSavedVertexes[uwCnt2 + slNumOfSavedVectors][2];
			slReadedLong=					*( (signed long *) &fReadedFloat );
			ax_tdxFileVertexes[uwCnt2][2]=	fn_ul_SwapLong( slReadedLong );
		}

		// Copy quaternions
		assert(MaxInFileQuaternionsTab > ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedQuaternions);
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedQuaternions ; uwCnt2++ )
		{	swReadedWord=						(signed short) (ax_tdxSavedQuaternions[uwCnt2 + slNumOfSavedQuaternions][0] * xCompactValue);
			ax_tdxFileQuaternions[uwCnt2][0]=	fn_uw_SwapWord( swReadedWord );
			swReadedWord=						(signed short) (ax_tdxSavedQuaternions[uwCnt2 + slNumOfSavedQuaternions][1] * xCompactValue);
			ax_tdxFileQuaternions[uwCnt2][1]=	fn_uw_SwapWord( swReadedWord );
			swReadedWord=						(signed short) (ax_tdxSavedQuaternions[uwCnt2 + slNumOfSavedQuaternions][2] * xCompactValue);
			ax_tdxFileQuaternions[uwCnt2][2]=	fn_uw_SwapWord( swReadedWord );
			swReadedWord=						(signed short) (ax_tdxSavedQuaternions[uwCnt2 + slNumOfSavedQuaternions][3] * xCompactValue);
			ax_tdxFileQuaternions[uwCnt2][3]=	fn_uw_SwapWord( swReadedWord );
		}

		// Copy hierarchies
		assert(MaxInFileHierarchyTab > ax_tdstA3dGENERAL[uwCnt1].uwNumberOfHierarchies);
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfHierarchies ; uwCnt2++ )
		{	swReadedWord=							(signed short) ax_tdstHierarchies[uwCnt2 + slNumOfHierarchies].uwChild;
			ax_tdstFileHierarchy[uwCnt2].uwChild=	fn_uw_SwapWord( swReadedWord );
			swReadedWord=							(signed short) ax_tdstHierarchies[uwCnt2 + slNumOfHierarchies].uwFather;
			ax_tdstFileHierarchy[uwCnt2].uwFather=	fn_uw_SwapWord( swReadedWord );
		}

		// Copy NTTO
		assert(MaxInFileNTTOTab > ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedNTTO);
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedNTTO ; uwCnt2++ ) {
				swReadedWord = ax_tdstTabTBL[ax_tdstSavedNTTO[uwCnt2 + slNumOfSavedNTTO].ucNumberInTable].swNewObjectNumber;
			ax_tdstFileNTTO[uwCnt2].ucNumberInTable=	fn_uw_SwapWord( swReadedWord );
			swReadedWord=								(signed short) ax_tdstSavedNTTO[uwCnt2 + slNumOfSavedNTTO].uwTypeOfObject;
			ax_tdstFileNTTO[uwCnt2].uwTypeOfObject=		fn_uw_SwapWord( swReadedWord );
			swReadedWord=								(signed short) ax_tdstSavedNTTO[uwCnt2 + slNumOfSavedNTTO].ucTransparency;
			ax_tdstFileNTTO[uwCnt2].ucTransparency=		(unsigned char)fn_uw_SwapWord( swReadedWord );
		}


		// Copy OnlyFrames infos

		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt2++ )
		{	swReadedWord=										ax_tdstOnlyFrames[uwCnt2 + slNumOfOnlyFrames].uwHierarchyNbCouples;
			ax_tdstFileOnlyFrame[uwCnt2].uwHierarchyNbCouples=	fn_uw_SwapWord( swReadedWord );
			swReadedWord=										(signed short)
																(ax_tdstOnlyFrames[uwCnt2 + slNumOfOnlyFrames].slNumOfHierarchyCouples - slNumOfHierarchies);
			ax_tdstFileOnlyFrame[uwCnt2].uwNumOfHierarchyCouples=	fn_uw_SwapWord( swReadedWord );
			swReadedWord=										(signed short)
																(ax_tdstOnlyFrames[uwCnt2 + slNumOfOnlyFrames].uwNumOfSavedFrame);
			ax_tdstFileOnlyFrame[uwCnt2].uwNumOfSavedFrame=		fn_uw_SwapWord( swReadedWord );
			if	(ax_tdstOnlyFrames[uwCnt2 + slNumOfOnlyFrames].slNumOfAngularSpeedQuat != 0xFFFFFFFF)
			{	swReadedWord=	(signed short)
								(ax_tdstOnlyFrames[uwCnt2 + slNumOfOnlyFrames].slNumOfAngularSpeedQuat - slNumOfSavedQuaternions);
				ax_tdstFileOnlyFrame[uwCnt2].uwNumOfAngularSpeedQuat=	fn_uw_SwapWord( swReadedWord );
			}
			else
			{	swReadedWord=	(signed short) SEB_Invalid;
			}
			ax_tdstFileOnlyFrame[uwCnt2].uwNumOfAngularSpeedQuat=	fn_uw_SwapWord( swReadedWord );
			if	(ax_tdstOnlyFrames[uwCnt2 + slNumOfOnlyFrames].slNumOfSpeedVector != 0xFFFFFFFF)
			{	swReadedWord=	(signed short)
								(ax_tdstOnlyFrames[uwCnt2 + slNumOfOnlyFrames].slNumOfSpeedVector - slNumOfSavedVectors);
			}
			else
			{	swReadedWord=	(signed short) SEB_Invalid;
			}
			ax_tdstFileOnlyFrame[uwCnt2].uwNumOfSpeedVector=	fn_uw_SwapWord( swReadedWord );
		}


// ----------------------
		ax_uwTabSavedFrames[0]=	ax_tdstOnlyFrames[slNumOfOnlyFrames].uwNumOfSavedFrame;
		uwLastChangeFrame=		0;
		uwLastRealFrame=		0;

		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt2++ )
		{
			if	( ax_tdstOnlyFrames[uwCnt2 + slNumOfOnlyFrames].uwNumOfSavedFrame != ax_tdstOnlyFrames[uwLastChangeFrame + slNumOfOnlyFrames].uwNumOfSavedFrame )
			{	uwLastChangeFrame=	uwCnt2;
				uwLastRealFrame++;
				ax_uwTabSavedFrames[uwLastRealFrame]=	(unsigned short) uwCnt2;
			}
		}

// ----------------------

		// Copy Channels, Frames and KeyFrames
		// For each Channel
		uwFileNumOfFrames=		0;
		uwFileNumOfChannel=		0;
		uwFileNumOfKeyFrames=	0;
		assert(MaxInFileChannelTab > ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels);
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
		{	slNumOfFrames=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

			// With channel killing !
			if	( ax_tdstChannels[slNumOfChannels + uwCnt2].uwUsedChannel == 1 )
			{
				// Copy Channel
				swReadedWord=													ax_tdstChannels[uwCnt2 + slNumOfChannels].uwNumberOfKeys;
				ax_tdstFileChannel[uwFileNumOfChannel].uwNumberOfKeys=			fn_uw_SwapWord( swReadedWord );
				swReadedWord=													ax_tdstChannels[uwCnt2 + slNumOfChannels].uwChannelNumber;
				ax_tdstFileChannel[uwFileNumOfChannel].uwChannelNumber=			fn_uw_SwapWord( swReadedWord );
				swReadedWord=													(unsigned short)
									(ax_tdstChannels[uwCnt2 + slNumOfChannels].slNumOfLocalPivotPos - slNumOfSavedVectors);
				ax_tdstFileChannel[uwFileNumOfChannel].uwNumOfLocalPivotPos=	fn_uw_SwapWord( swReadedWord );

				// For each SavedFrames
				assert(MaxInFileFrameTab > (uwFileNumOfFrames + ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedFrames));
				for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedFrames ; uwCnt3++ )
				{
					slNumOfRealFrame=										ax_uwTabSavedFrames[uwCnt3];
					swReadedWord=											(unsigned short) (ax_tdstFrames[slNumOfFrames + slNumOfRealFrame].slNumOfNTTO - slNumOfSavedNTTO);
					ax_tdstFileFrame[uwFileNumOfFrames].uwNumOfNTTO=		fn_uw_SwapWord( swReadedWord );
					uwFileNumOfFrames++;
				}

				// For each Frames
				assert(MaxInFileKeyFrameTab > (uwFileNumOfKeyFrames + ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames));
				for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt3++ )
				{
					// Copy Frame
				//	swReadedWord=											ax_tdstFrames[slNumOfFrames + uwCnt3].swNumberInTable;
				//	ax_tdstFileFrame[uwFileNumOfFrames].swNumberInTable=	fn_uw_SwapWord( swReadedWord );
				//	swReadedWord=											ax_tdstFrames[slNumOfFrames + uwCnt3].uwTypeOfObject;
				//	ax_tdstFileFrame[uwFileNumOfFrames].uwTypeOfObject=		fn_uw_SwapWord( swReadedWord );
				//	uwFileNumOfFrames++;

					// Copy KeyFrame
					if	( ax_tdstFrames[slNumOfFrames + uwCnt3].uwAttribute != eNoKey )
					{
						swReadedWord=													ax_tdstFrames[slNumOfFrames + uwCnt3].uwFrameNumber;
						ax_tdstFileKeyFrame[uwFileNumOfKeyFrames].uwFrameNumber=		fn_uw_SwapWord( swReadedWord );
						swReadedWord=													ax_tdstFrames[slNumOfFrames + uwCnt3].uwMask;
						ax_tdstFileKeyFrame[uwFileNumOfKeyFrames].uwMask=				fn_uw_SwapWord( swReadedWord );
						swReadedWord=		(unsigned short)
											(ax_tdstFrames[slNumOfFrames + uwCnt3].slNumOfQuatOri - slNumOfSavedQuaternions);
						ax_tdstFileKeyFrame[uwFileNumOfKeyFrames].uwNumOfQuatOri=		fn_uw_SwapWord( swReadedWord );
						swReadedWord=		(unsigned short)
											(ax_tdstFrames[slNumOfFrames + uwCnt3].slNumOfQuatSca - slNumOfSavedQuaternions);
						ax_tdstFileKeyFrame[uwFileNumOfKeyFrames].uwNumOfQuatSca=		fn_uw_SwapWord( swReadedWord );
						swReadedWord=		(unsigned short)
											(ax_tdstFrames[slNumOfFrames + uwCnt3].slNumOfScaleValues - slNumOfSavedVectors);
						ax_tdstFileKeyFrame[uwFileNumOfKeyFrames].uwNumOfScaleValues=	fn_uw_SwapWord( swReadedWord );
						swReadedWord=		(unsigned short)
											(ax_tdstFrames[slNumOfFrames + uwCnt3].slNumOfPosition - slNumOfSavedVectors);
						ax_tdstFileKeyFrame[uwFileNumOfKeyFrames].uwNumOfPosition=		fn_uw_SwapWord( swReadedWord );
						swReadedWord=		(signed short)
											(ax_tdstFrames[slNumOfFrames + uwCnt3].xInterpolationParameter * 8192.0);
						ax_tdstFileKeyFrame[uwFileNumOfKeyFrames].swInterpolationParameter=	fn_uw_SwapWord( swReadedWord );
						uwFileNumOfKeyFrames++;
					}
				}
				uwFileNumOfChannel++;
			}
		}

		// Copy Events
		assert(MaxInFileEventTab > ax_tdstA3dGENERAL[uwCnt1].uwNumberOfEvents);
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfEvents ; uwCnt2++ )
		{
			ax_tdstFileEvent[uwCnt2].uwFrameNumber =	  ax_tdstEvents[slNumOfEvents + uwCnt2].uwFrameNumber;
			ax_tdstFileEvent[uwCnt2].usEventNumberInTBL=ax_tdstTabTBL[ax_tdstEvents[slNumOfEvents + uwCnt2].usEventNumberInTBL].swNewObjectNumber;
			ax_tdstFileEvent[uwCnt2].uwChannelNumber =    ax_tdstEvents[slNumOfEvents + uwCnt2].uwChannelNumber;
		}

		// Copy and optimize morphing data with compact modifications
		assert(MaxInFileMorphTab > ax_tdstA3dGENERAL[uwCnt1].uwNumberOfMorphData);
		for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfMorphData ; uwCnt2++ )
		{
			ax_tdstFileMorphInfos[uwCnt2].ucTarget= (unsigned char)
				ax_tdstTabTBL[ax_tdstBinMorphInfos[slNumOfMorphData+uwCnt2].ucTarget].swNewObjectNumber;
			ax_tdstFileMorphInfos[uwCnt2].ucMorphingAmount=
				ax_tdstBinMorphInfos[slNumOfMorphData+uwCnt2].ucMorphingAmount;
			ax_tdstFileMorphInfos[uwCnt2].uwChannelNumber=
				ax_tdstBinMorphInfos[slNumOfMorphData+uwCnt2].uwChannelNumber;
			ax_tdstFileMorphInfos[uwCnt2].uwFrameNumber=
				ax_tdstBinMorphInfos[slNumOfMorphData+uwCnt2].uwFrameNumber;
		}


// ----------------------------------------------------------------------------------
		// Verify animation
#ifdef	A3X_PC
		if	( uwOrder != 0 )
#else
		if	( uwOrder == 0 )
#endif
		{
			if	( uwCalc == 1 )
			{
				ulSizeOfAnim=		sizeof(tdstA3dGENERAL) +
									12						* (unsigned long) ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfVectors +
									sizeof(tdxSShortQuater4)* (unsigned long) ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfQuaternions +
									sizeof(tdstHierarchy)	* (unsigned long) ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfHierarchies +
									sizeof(tdstNTTO)		* (unsigned long) ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfSavedNTTO +
									sizeof(tdstOnlyFrame)	* (unsigned long) ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfFrames +
									sizeof(tdstChannel)		* (unsigned long) uwFileNumOfChannel +
									sizeof(tdstFrame)		* (unsigned long) ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfSavedFrames *
															  (unsigned long) uwFileNumOfChannel +
									sizeof(tdstFrameKF)		* (unsigned long) ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfFrames *
															  (unsigned long) uwFileNumOfChannel;
				if	( ((ulSizeOfAnim) & 0x0002) != 0x0000 )
					ulSizeOfAnim+=	2;
				ulSizeOfAnim+=		sizeof(tdstKeyFrame)	* (unsigned long) uwFileNumOfKeyFrames +
									sizeof(tdstEvent)		* (unsigned long) ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfEvents;
				ax_MemSizes[ulTotNbAnims]=	ulSizeOfAnim;
				if	( (ulSizeOfAnim & 0x03FF) == 0 )				// mod 1024
						ulSizeOfAnim=	(ulSizeOfAnim >> 10) - 1;	// div 1024 - 1
				else	ulSizeOfAnim=	(ulSizeOfAnim >> 10);		// div 1024
				a100_TabNbElt[ ulSizeOfAnim ]++;
			}


			// A3dGENERAL
			fn_v_Verify( "A3dGENERAL", ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfVectors, ax_tdstFileA3dGENERAL[uwCnt1].uwNumOfAnimationTranslationOffset );
			fn_v_Verify( "A3dGENERAL", ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfQuaternions, ax_tdstFileA3dGENERAL[uwCnt1].uwNumOfAnimationRotationOffset );

			// Hierarchies 
			/*for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfHierarchies ; uwCnt2++ )
			{	
				fn_v_Verify( "Hierarchies (Child)",  ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfChannels, ax_tdstFileHierarchy[uwCnt2].uwChild );
				fn_v_Verify( "Hierarchies (Father)", ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfChannels, ax_tdstFileHierarchy[uwCnt2].uwFather );

			}*/

			// NTTO

			// OnlyFrames
			for	( uwCnt2=0 ; uwCnt2<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames ; uwCnt2++ )
			{
				if	(ax_tdstFileOnlyFrame[uwCnt2].uwNumOfAngularSpeedQuat != SEB_Invalid)
					fn_v_Verify( "OnlyFrames (Angular speed)", ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfQuaternions, ax_tdstFileOnlyFrame[uwCnt2].uwNumOfAngularSpeedQuat );
				if	(ax_tdstFileOnlyFrame[uwCnt2].uwNumOfSpeedVector != SEB_Invalid)
					fn_v_Verify( "OnlyFrames (Translation speed)", ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfVectors, ax_tdstFileOnlyFrame[uwCnt2].uwNumOfSpeedVector );
				//fn_v_Verify( "OnlyFrames (hierarchy)", ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfHierarchies, ax_tdstFileOnlyFrame[uwCnt2].uwNumOfHierarchyCouples );
				//fn_v_Verify( "OnlyFrames (hierarchy)", ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfHierarchies, ax_tdstFileOnlyFrame[uwCnt2].uwNumOfHierarchyCouples + ax_tdstFileOnlyFrame[uwCnt2].uwHierarchyNbCouples );
				fn_v_Verify( "OnlyFrames (hierarchy)", ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfHierarchies, ax_tdstFileOnlyFrame[uwCnt2].uwHierarchyNbCouples );
				fn_v_Verify( "OnlyFrames (FrameNTTO)", ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfSavedFrames, ax_tdstFileOnlyFrame[uwCnt2].uwNumOfSavedFrame );
				if	( (uwCnt2>0) && (ax_tdstFileOnlyFrame[uwCnt2].uwNumOfSavedFrame < ax_tdstFileOnlyFrame[uwCnt2 - 1].uwNumOfSavedFrame) )
							{	printf("Erreur sauvegarde : SavedFrame (rupture accroissement frame #%d (%d), frame #%d (%d))",
											uwCnt2-1, ax_tdstFileOnlyFrame[uwCnt2].uwNumOfSavedFrame, uwCnt2, ax_tdstFileOnlyFrame[uwCnt2 - 1].uwNumOfSavedFrame );
							}
			}

			// Channels, Frames and KeyFrames
			// For each Channel
			uwFileNumOfFrames=		0;
			uwFileNumOfChannel=		0;
			uwFileNumOfKeyFrames=	0;
			ulRealNumOfChannel=		0;
			for	( uwCnt2=0 ; uwCnt2<ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfChannels ; uwCnt2++ )
			{	slNumOfFrames=		ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;
				ulRealNumOfFrame=	ax_tdstChannels[slNumOfChannels + uwCnt2].slNumOfFrames;

				while	( ax_tdstChannels[slNumOfChannels + ulRealNumOfChannel].uwUsedChannel == 0 )
					ulRealNumOfChannel++;

				// Channel
				fn_v_Verify( "Channels", ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfVectors, ax_tdstFileChannel[uwFileNumOfChannel].uwNumOfLocalPivotPos );

				// For each Frames (NTTO)
				for	( uwCnt3=0 ; uwCnt3<ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedFrames ; uwCnt3++ )
				{	fn_v_Verify( "bad NTTO", ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedNTTO, ax_tdstFileFrame[uwFileNumOfFrames].uwNumOfNTTO );
					uwFileNumOfFrames++;
				}

				// For each KeyFrames
				for	( uwCnt3=0 ; uwCnt3<ax_tdstFileChannel[uwFileNumOfChannel].uwNumberOfKeys ; uwCnt3++ )
				{
					fn_v_Verify( "KeyFrame (FrameNumber)", ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfFrames, ax_tdstFileKeyFrame[uwFileNumOfKeyFrames].uwFrameNumber );
					fn_v_Verify( "KeyFrame (QuatOri)", ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfQuaternions, ax_tdstFileKeyFrame[uwFileNumOfKeyFrames].uwNumOfQuatOri );
					fn_v_Verify( "KeyFrame (QuatSca)", ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfQuaternions, ax_tdstFileKeyFrame[uwFileNumOfKeyFrames].uwNumOfQuatSca );
					fn_v_Verify( "KeyFrame (ScaleValues)", ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfVectors, ax_tdstFileKeyFrame[uwFileNumOfKeyFrames].uwNumOfScaleValues );
					fn_v_Verify( "KeyFrame (NumOfPosition)", ax_tdstFileA3dGENERAL[uwCnt1].uwNumberOfVectors, ax_tdstFileKeyFrame[uwFileNumOfKeyFrames].uwNumOfPosition );
					// We are on the last key
					if	( uwCnt3 < (ax_tdstFileChannel[uwFileNumOfChannel].uwNumberOfKeys - 1) )
					{	if	( (ax_tdstFileKeyFrame[uwFileNumOfKeyFrames].uwMask & SEB_xMaskLastKey) == SEB_xMaskLastKey )
						{	printf( "KeyFrame (is not SEB_xMaskLastKey), channel #%d, keyframe #%d (/%d)", uwCnt2, uwCnt3, ax_tdstFileChannel[uwFileNumOfChannel].uwNumberOfKeys );
					}
					}
					else
					{	if	( (ax_tdstFileKeyFrame[uwFileNumOfKeyFrames].uwMask & SEB_xMaskLastKey) != SEB_xMaskLastKey )
						{	printf( "KeyFrame (must be SEB_xMaskLastKey), channel #%d, keyframe #%d (/%d)", uwCnt2, uwCnt3, ax_tdstFileChannel[uwFileNumOfChannel].uwNumberOfKeys );
						}
					}
					uwFileNumOfKeyFrames++;
				}
				ulRealNumOfChannel++;
				uwFileNumOfChannel++;
			}
		}



// ----------------------------------------------------------------------------------
		Out=	fopen( FileName, "wb+" );

		// Put Version
		fwrite(&wVersion,2,1,Out);

			// Save GENERAL
		ulSavedSize=	fn_v_WriteHunk(	"GENE",
										(char *) &ax_tdstFileA3dGENERAL[uwCnt1],
										sizeof(tdstFileA3dAnimationGENERAL),
										1,
										Out );
			// Save vertexes
		ulSavedSize+=	fn_v_WriteHunk(	"VERT",
										(char *) ax_tdxFileVertexes,
										sizeof(signed long)*3,
										ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedVectors,
										Out );
			// Save quaternions
		ulSavedSize+=	fn_v_WriteHunk(	"QUAT",
										(char *) ax_tdxFileQuaternions,
										sizeof(signed short)*4,
										ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedQuaternions,
										Out );
			// Save hierarchies
		ulSavedSize+=	fn_v_WriteHunk(	"HIER",
										(char *) ax_tdstFileHierarchy,
										sizeof(tdstFileHierarchy),
										ax_tdstA3dGENERAL[uwCnt1].uwNumberOfHierarchies,
										Out );
			// Save NTTO (NumberInTable and TypeOfObject Table)
		ulSavedSize+=	fn_v_WriteHunk(	"NTTO",
										(char *) ax_tdstFileNTTO,
										sizeof(tdstNTTO),
										ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedNTTO,
										Out );
			// Save OnlyFrames infos
		ulSavedSize+=	fn_v_WriteHunk(	"OFRM",
										(char *) ax_tdstFileOnlyFrame,
										sizeof(tdstFileOnlyFrame),
										ax_tdstA3dGENERAL[uwCnt1].uwNumberOfFrames,
										Out );
			// Save Channels
		ulSavedSize+=	fn_v_WriteHunk(	"CHAN",
										(char *) ax_tdstFileChannel,
										sizeof(tdstFileChannel),
										uwFileNumOfChannel,
										Out );
			// Save Frames
		ulSavedSize+=	fn_v_WriteHunk(	"FRMS",
										(char *) ax_tdstFileFrame,
										sizeof(tdstFileFrame),
										uwFileNumOfChannel * ax_tdstA3dGENERAL[uwCnt1].uwNumberOfSavedFrames,
										Out );
			// Save KeyFrames
		ulSavedSize+=	fn_v_WriteHunk(	"KFRM",
										(char *) ax_tdstFileKeyFrame,
										sizeof(tdstFileKeyFrame),
										uwFileNumOfKeyFrames,
										Out );
		// align data
		while( (ulSavedSize % 4) != 0 )
			ulSavedSize+=	fwrite( &uwAlign, 1, 1, Out );

		// Save Events
		ulSavedSize+=	fn_v_WriteHunk(	"EVNT",
										(char *) ax_tdstFileEvent,
										sizeof(tdstFileEvent),
										ax_tdstA3dGENERAL[uwCnt1].uwNumberOfEvents,
										Out );

		//align data
		while( (ulSavedSize % 4) != 0 )
			ulSavedSize+=	fwrite( &uwAlign, 1, 1, Out );

		// Save Morphing array
		ulSavedSize+=	fn_v_WriteHunk(	"MORP",
										(char *) ax_tdstFileMorphInfos,
										sizeof(tdstFileMorphData),
										ax_tdstA3dGENERAL[uwCnt1].uwNumberOfMorphData,
										Out );

		fclose( Out );

#ifdef	A3X_PC
		if	( uwOrder != 0 )
#else
		if	( uwOrder == 0 )
#endif
		{
			if	( uwCalc == 1 )
			{
				ax_RomSizes[ulTotNbAnims]=	ulSavedSize;
				ulTotNbAnims++;
			}
		}
	}
	else
	{	printf("Don't save (not animation) : %s\n", FileName);
	}
}



// **********************************************************************************
// Modif 30/07/98 : Anims are located in two dir 
//					Save Binary anim in good directory - Carlos Torres
// Modif 17/08/98 : Generalized function -> Save N Anims beginning at anim uwNbFirstAnims - Carlos Torres
void fn_v_SaveAnimationV6i(unsigned short uwNbFirstAnim,unsigned short uwNbAnims,char * p_szSaveDir)
{	unsigned short	uwCnt1;

	printf("Sauvegarde des animations...\n");
	uwCalc=	0;

	// For each animation
	for	( uwCnt1=uwNbFirstAnim;uwCnt1<uwNbFirstAnim+uwNbAnims;uwCnt1++ ) {
		// bad anim --> skip it
		if	(bValid(&stAnims[uwCnt1]))
			continue;
		else {
			xEps = xPrecision(&stAnims[uwCnt1]);
			xOneSubEps = (SEB_xReal)(1.0 - xEps);
		}
		
		uwCalc=	1;
		uwA3xDebug=	0;								// A3x Normal mode
//			uwOrder=	0;								// Motorola order
//				fn_v_WriteAnimationV6i( uwCnt1 );
			uwOrder=	1;							// Intel order

			fn_v_WriteAnimationV6i(uwCnt1,p_szSaveDir);
//	uwCalc=	0;
//		uwA3xDebug=	1;								// A3x Debug mode
//			uwOrder=	0;								// Motorola order
//				fn_v_WriteAnimationV6i( uwCnt1 );
//			uwOrder=	1;								// Intel order
//				fn_v_WriteAnimationV6i( uwCnt1 );
	}

	printf("End of saving\n\n");
}



// ***************************************************************** fn_v_StartA3dV6i
// Open files to make Log
//		Error File
//		SizeOf File
//		Event File
// If file cannot be open, use stdout
//
// Sebastien Rubens
// Modif 16/10/98 Add Warning File - Carlos Torres
// **********************************************************************************
void fn_v_StartA3dV6i( void ) {	
	char FileName[200];

	slNbTotVect = 0;
	slNbTotQuat = 0;
	fn_v_ResetStacks();

	// Open Error File
	sprintf(FileName,"%s\\%s.txt",ERROR_DIR,szFamilyName);
	ErrorFile =	fopen(FileName,"w+");
	if (ErrorFile == NULL)
		ErrorFile =	stdout;

	// Open Warning File
	sprintf(FileName,"%s\\%s.txt",WARNING_DIR,szFamilyName);
	WarningFile = fopen(FileName,"w+");
	if (WarningFile == NULL)
		WarningFile =	stdout;

	// Open SizeOf File
	sprintf(FileName,"%s\\%s.txt",SIZEOF_DIR,szFamilyName);
	SizeOut = fopen(FileName,"w+");
	if (SizeOut == NULL)
		SizeOut = stdout;

	// Open Event File
	sprintf(FileName,"%s\\%s.txt",EVENT_DIR,szFamilyName);
	EventFile = fopen(FileName,"w+");
	if (EventFile == NULL)
		EventFile = stdout;
}



// ******************************************************************* fn_v_EndA3dV6i
// Close Log if use (not stdout)
//		Error File
//		SizeOf File
//		Event File
//
// Sebastien Rubens
// Modif 23/07/98 Remove Empty Error File - Carlos Torres
// Modif 16/10/98 Add Warning File - Carlos Torres
// **********************************************************************************
void fn_v_EndA3dV6i(void) {
	// Close Error File
	if (ErrorFile != stdout) {
		// get position in file
		int bError = ftell(ErrorFile);

		fclose(ErrorFile);

		// remove file if no error
		if (!bError) {
			char szFileName[200];

			sprintf(szFileName,"%s\\%s.txt",ERROR_DIR,szFamilyName);
			remove(szFileName);
		}
	}

	// Close Warning File
	if (WarningFile != stdout) {
		// get position in file
		int bWarning = ftell(WarningFile);

		fclose(WarningFile);

		// remove file if no warning
		if (!bWarning) {
			char szFileName[200];

			sprintf(szFileName,"%s\\%s.txt",WARNING_DIR,szFamilyName);
			remove(szFileName);
		}
	}

	// Close SizeOf File
	if (SizeOut != stdout)
		fclose(SizeOut);

	// Close Event File
	if (EventFile != stdout)
		fclose(EventFile);
}

// ******************************************************************** fn_bIsNewAnim
// Check if an anim name is allready in the general table
//
// Carlos Torres
// **********************************************************************************
int fn_bIsNewAnim(char * szAnimName) {
	int i;

	for(i=0;i<g_uwTotalNumOfAnim;i++) {
		if (!stricmp(szAnimName,szAnimName(&stAnims[i])))
			return FALSE;
	}

	return TRUE;
}

// ****************************************************************** fn_uw_GetDirV6i
// Fill a table with all anim file name found in the actor Dir
// Return the number of anim found
//
// Sebastien Rubens
// Modif 30/07/98 : Add anim name table in parameter - Carlos Torres
// Modif 25/08/98 : Get all anim found or just new name - Carlos Torres
// **********************************************************************************
unsigned short fn_uw_GetDirV6i(char * LongActorName,unsigned char bTreatAll) {	
	FILE			*Directory;
	char			ExecCommand[500];
	unsigned short  uwAnimNumber;

	// Get all A3D files of the directory in DIR.A3D file
	sprintf(ExecCommand,"DIR %s\\*.A3D /B /ON > %s\\A3D.DIR",LongActorName,LongActorName);
	system(ExecCommand);

	// Read all A3D files for perso
	sprintf(LongFileName,"%s\\A3D.DIR",LongActorName);
	Directory = fopen(LongFileName,"r");

	// Fill table with anim name and default value
	// Default
	//		General precision 
	//		set anim valid
	uwAnimNumber = 0;
	if (Directory) {
		while (fgets(szAnimName(&stAnims[g_uwTotalNumOfAnim]),50,Directory)) {
			// suppress last char (EOL)
			szAnimName(&stAnims[g_uwTotalNumOfAnim])[strlen(szAnimName(&stAnims[g_uwTotalNumOfAnim]))-1] = NULL;

			// keep anim if treat all or if it is a new name
			if (bTreatAll || fn_bIsNewAnim(szAnimName(&stAnims[g_uwTotalNumOfAnim]))) {
				uwAnimNumber++;
				g_uwTotalNumOfAnim++;

				xPrecision(&stAnims[g_uwTotalNumOfAnim])	= xDefaultEps;
				bValid(&stAnims[g_uwTotalNumOfAnim])		= 0;

				assert(g_uwTotalNumOfAnim<NombreDanimationsParDirectory);
			}
		}

		fclose(Directory);
	}

	return uwAnimNumber;
}

// ******************************************************** fn_v_InitSaveAnimationV6i
// **********************************************************************************
void fn_v_InitSaveAnimationV6i(void) {	
	unsigned short	uwCnt;

	// Reset Table
	for	( uwCnt=0 ; uwCnt<100 ; uwCnt++ )
		a100_TabNbElt[uwCnt] = 0;
}

// **********************************************************************************
void	fn_v_EndSaveAnimationV6i( void )
{	unsigned short	uwCnt;
	double			xMemMoy, xRomMoy, xMemEcart, xRomEcart, xMaxMem, xMaxRom;
	/*FILE			*stream;

	stream=	fopen( "D:\\sizes.txt", "w+" );
	fprintf( stream, "Nombre d'animations inferieures ou egales a :\n");
	for	( uwCnt=0 ; uwCnt<100 ; uwCnt++ )
	{	if	((uwCnt % 10) == 0)
			fprintf( stream, "\n" );
		fprintf( stream, "%3d Ko : %d\n", (uwCnt+1), a100_TabNbElt[uwCnt] );
	}
	fclose(stream);*/


	// ------------------------------------------------------------------------------
	xMemMoy=	0.0;
	xRomMoy=	0.0;
	xMemEcart=	0.0;
	xRomEcart=	0.0;

	// Calcul des moyennes et de "la variance"
	xMaxMem=	0;
	xMaxRom=	0;
	for	( uwCnt=0 ; uwCnt<ulTotNbAnims ; uwCnt++ )
	{	xMemMoy+=	ax_MemSizes[uwCnt];
		xRomMoy+=	ax_RomSizes[uwCnt];
		xMemEcart+=	ax_MemSizes[uwCnt] * ax_MemSizes[uwCnt];
		xRomEcart+=	ax_RomSizes[uwCnt] * ax_RomSizes[uwCnt];
		if	( ax_MemSizes[uwCnt] > xMaxMem )
			xMaxMem=	ax_MemSizes[uwCnt];
		if	( ax_RomSizes[uwCnt] > xMaxRom )
			xMaxRom=	ax_RomSizes[uwCnt];
	}
	xMemMoy/=	ulTotNbAnims;					// E[x]
	xRomMoy/=	ulTotNbAnims;
	xMemEcart/=	ulTotNbAnims;					// E[x²]
	xRomEcart/=	ulTotNbAnims;

	xMemEcart=	xMemEcart - xMemMoy * xMemMoy;	// V= E[x²] - E[x]²
	xRomEcart=	xRomEcart - xRomMoy * xRomMoy;

	xMemEcart=	sqrt( xMemEcart );				// Ecart type
	xRomEcart=	sqrt( xRomEcart );

	printf("\n");
	printf("Nombre total d'animations : %d\n", ulTotNbAnims);
	printf("Moyenne    MEM : %10.4f\n", xMemMoy );
	printf("Moyenne    ROM : %10.4f\n", xRomMoy );
	printf("Ecart type MEM : %10.4f\n", xMemEcart );
	printf("Ecart type ROM : %10.4f\n", xRomEcart );
	printf("Taille max MEM : %10.4f\n", xMaxMem );
	printf("Taille max ROM : %10.4f\n", xMaxRom );
}



// **********************************************************************************
#undef	L_OPTIM_V6_C
