/***************************************************
 *
 * AGO : Animations Graphiques Optimisées pour Ray2
 ***************************************************
 *
 * A ultra-simple multi-purpose particle system
 * for animation optimizations
 * (to reduce PlayAnim & IA use)
 *
 ***************************************************
 *
 * Version 2.0 : Francois 'FX' Queinnec
 *
 ***************************************************/
 
#include <stdlib.h>	/* Needed for rand() function and constants */
 
#ifdef U64
#include <ultra.h>
#include <gbi.h>
#endif /* U64*/
 
#include "GLD.h"
#include "GMT.h"
 
#include "AGO.h"
 

#ifndef U64

#define INFODESIGN_RESEARCH

#endif
 
/*****************************************
 * MAXIMUM NUMBER OF AGOS AT A TIME      *
 *****************************************
 *
 * PC can handle more than that, but
 * we should keep this value for the
 * editor... To let designers really
 * see what's gonna happen.
 *
 ***************************************/
#define AGO_MAX_NUMBER_OF_AGOS		150
 
 
/***************************************/
/* INTERNAL IDENTIFICATION CONSTANTS ***/
/***************************************/
 
/* Part behavior*/
#define AGO_TYPEMASK		0x000000FF
#define AGO_STILL			0x00000000
#define AGO_FALLING			0x00000001
#define AGO_SINUSING		0x00000002
#define AGO_MOVING			0x00000003
#define AGO_GEISER			0x00000004
#define AGO_FALLING_SLOW	0x00000005
#define AGO_ROTATING_SLOW	0x00000006
#define AGO_MOVINGSINXY		0x00000007
#define AGO_SPIRALE			0x00000008
#define AGO_MOVING_AND_SLOWING 0x00000009
#define AGO_GOINGTO			0x0000000A
#define AGO_MOVINGSINXYUP	0x0000000B
#define AGO_2DSPIRALE		0x0000000C
#define AGO_FASEGOINGTO		0x0000000E
#define AGO_FIREWORKS		0x0000000F
#define AGO_FALLING_MEGAFAST 0x00000010
#define AGO_FRAME			0x00000011
#define AGO_GOTO			0x00000012
 
#define AGO_GOTO_STEP		9.0f
 
/* Scaling Behavior*/
#define AGO_SCALEMASK			0x00000F00
#define AGO_SCALING_SLOW		0x00000100
#define AGO_SCALING_MID			0x00000200
#define AGO_SCALING_FAST		0x00000300
#define AGO_SCALING_FASTEST		0x00000400
#define AGO_UNSCALING_FAST		0x00000500
#define AGO_UNSCALING_SLOW		0x00000600
#define AGO_UNSCALING_FASTEST	0x00000700
#define AGO_SCALING_MEGASLOW	0x00000800
#define AGO_SCALING_MEGAFASTY	0x00000900
#define AGO_SCALING_XTOY		0x00000A00
#define AGO_SCALING_YTOX		0x00000B00
#define AGO_SCALING_YTOX2		0x00000D00
#define AGO_BIG_RANDOM_SCALE	0x00000E00
#define AGO_SMALL_RANDOM_SCALE	0x00000F00

 
/* Shading Behavior*/
#define AGO_SHADEMASK		0x0000F000
#define AGO_SHADE_SLOW		0x00001000
#define AGO_SHADE_MID 		0x00002000
#define AGO_SHADE_FAST		0x00003000
#define AGO_SHADE_FASTEST   0x00004000
#define AGO_SHADE_MEGAFAST  0x00005000
#define AGO_SHADE_TWOFRAMES	0x00006000
#define AGO_APPEAR			0x00007000
#define AGO_WAIT			0x00008000
#define AGO_RANDOM_SHADE	0x00009000
#define AGO_UNSHADE			0x0000A000
 
/* Part death & misc flags:*/
#define AGO_TIMELIMITED		0x00010000
#define AGO_ENDASPLOUF		0x00020000
#define AGO_ZLIMITED		0x00040000
#define AGO_ZELDA			0x00080000
#define AGO_MUSTDIE			0x01000000
#define AGO_FOLLOWZ			0x02000000
#define AGO_LOOPANIM		0x04000000
#define AGO_BASEDSCALE		0x08000000
 
 
#define AGO_GEOMETRY_TYPE_MASK	0xF0000000
#define AGO_XYPLAN				0x10000000
#define AGO_ORTHOPLAN			0x20000000
#define AGO_ORIENTEDXYPLAN		0x30000000
#define AGO_REMANANCE			0x40000000
#define AGO_REMANANCE2			0x50000000
#define AGO_REMANANCE3			0x60000000
 
 
 
/*********************/
/* Gravity constant*/
/*********************/
#define AGO_G				9.81f
#define AGO_G_SLOW			3.50f
/*********************/
 
 
/***********************************************/
/* Predefined types*/
/***********************************************/

#define AGO_RAYMAN_PLOUF (AGO_STILL | AGO_XYPLAN | AGO_SCALING_FAST /*EST*/ |  AGO_SHADE_FAST)
#define AGO_RAYMAN_SMALL_PLOUF (AGO_STILL | AGO_XYPLAN | AGO_SCALING_SLOW |  AGO_SHADE_FAST)
 
#define AGO_RAYMAN_PLOUF_SKI (AGO_STILL | AGO_ORIENTEDXYPLAN | AGO_SCALING_SLOW |  AGO_SHADE_MEGAFAST)
#define AGO_NAISSANCE_OBUS (AGO_MOVING | AGO_SCALING_SLOW | AGO_SHADE_SLOW)
#define AGO_APPARITION_FUMEE (AGO_MOVING | AGO_SCALING_FAST | AGO_SHADE_FAST)
/************************************************/
 
 
 
 
/*************************************/
/* MAIN AGO STRUCTURE*/
/*************************************/
typedef struct AGO_Part_
{
	unsigned long ulType;			/* Type of the animation*/
	unsigned long AnimTime;			/* Texture Animation timebase*/
	float fCreationTime;			/* 'Creation time'*/
	float a3_fInitialPosition[3];	/* Initial Position of the part*/
	float a3_fPosition[3];			/* Position of the part*/
	float a3_fDirection[3];			/* Direction Vector*/
	float fScale[2];				/* Sizes (X and Y)*/
	float fAnimTimeScale;			/* Texture animation time multiplier*/
	union
	{	float f_ZLimit;				/* Z limitation from the initial position*/
		float fTimeLimit;			/* Time limitation*/
	} LimitParam;
	void *VisualMaterial;			/* Visual material for the sprite*/
	float Transparency;				/* Alpha value for this part*/
} AGO_Part;
/**************************************/


/* */
/* ATTENTION ! SUR PC, CETTE CONSTANTE NE DOIT JAMAIS ETRE DEFINIE !!!*/
/* Elle me sert uniquement pour forcer des valeurs en dur lors de mes tests*/
/**/
#ifdef U64
/* #define AGO_TEMP_SETTINGS */
#endif /* U64*/

#ifdef U64
extern char g_bWeirdWaterEffect;
extern char g_bWeirdFireEffect;
#endif
 
 
/***************************************/
/* MAIN GLOBAL DATA*/
/***************************************/
unsigned long g_ulNumberOfAgos=0;	/* Number of AGOs currently used      */

AGO_Part g_AGO[AGO_MAX_NUMBER_OF_AGOS+1];		/* THE AGO array !!                   */
int g_AGO_MustReinitStaticVars=1;			/* This is important to allow re-init */
											/* of static vars...                  */
 
int AGO_g_OddFrame=0;						/* Variable for displaying only on odd or even frames*/
 
float g_AGO_AnimTimeScale;					/* Global time multiplier for texture animation*/
											/* GLI uses it to desynchronize multiple AGOs that*/
											/* were launched at the same time*/
 
float AGO_gExtraParameter1[3];
float AGO_gExtraParameter2[3];
/* XB 10/06/99 */
#ifdef INFODESIGN_RESEARCH
float AGO_gExtraFloatParameter;
#endif /* INFODESIGN_RESEARCH */
/* End XB 10/06/99 */
void *g_AGO_PloufMaterial=NULL;
void *AGO_gExtraMaterial=NULL;

unsigned char g_bUsingMapMondeAGOs=0;
 

#ifndef _FIRE_DEADCODE_U64_ 
static float g_OldPloufDirection[3]={0.0f, 0.0f, 0.0f}; /* Used to remember the last direction*/
														/* of Rayman Ski*/
#endif
 
/* This is for nuclear explosions*/
char g_bForceWhiteFog=0;
char g_DoSmallPlouf=0;
 
 
/*****************************************/
/* (Real) Time values*/
/*****************************************/
float g_ffFrameTime=0.0f;		/* The current frame timestamp*/
float g_ffLastFrameTime=0.0f;	/* The last frame timestamp*/
float g_fTimeDifference=0.0f;	/* time elapsed between this frame */
								/* and the former one */
 
 
/****************************************/
/* VARIOUS SPECIFIC vars*/
/****************************************/
#ifdef U64
	void *AGO_g_LastMaterialUsed=NULL;	/* Used for "SendMaterialToViewport"*/
	unsigned char AGO_SkipMaterial=0;	/* optimizations...*/
	char g_bLoopAnim=0;	/* Boolean to tell GLI functions to loop the texture animations*/
	extern unsigned long g_ulVBLTime;	/* Timebase for texture animation*/
	void GLI_vPrepareViewPort(void);	/* Function to prepare the viewport for Sprite Display*/
	/* Sprite optimization globals*/
	extern char g_GLI_DontReinitSprites;
	extern char g_GLI_DontInitSprites;
	extern char g_GLI_SpritesUsed;
	extern int g_iCurrentPlanarSprite;
	extern char g_ulUseAntiAliasing;
#else /**********************************/
 
	extern MTH_tdxReal gs_fCoefOfMultiplicationForAnimatedTexture; /* Timebase for texture animation*/
 
#endif /* U64 */
 
 
 
/****************************************/
 
/****************************************/
/* ZELDA EFFECT vars*/
/****************************************/
#define MAX_NUMBER_OF_ZELDA_AGOS	35
int g_NumberOfZeldaAgos=0;
/****************************************/
 
 
/*****************************************/
/* FLOAT_RANGED_RANDOM macro :*/
/**/
/* returns a float value between x and y*/
/*****************************************/
#ifdef U64
	/* As a function, we save 1.5KB of memory !!!*/
	/* Of course, it's a bit slower.. but not THAT slower anyway*/
	float FLOAT_RANGED_RANDOM(float x, float y)
	{
		return (((((float)rand()) * ((y) - (x))) /((float)RAND_MAX) ) + (x) );
	}

	void GLI_vExtendedFarClipping(int b);
#else
	#define FLOAT_RANGED_RANDOM(x,y) (((((float)rand()) * ((y) - (x))) /((float)RAND_MAX) ) + (x) )
#endif
 
 
 
 
 
/***********************************/
/* Time limiter for AGOs !       ***/
/***********************************/
/**/
/* Used to limit the time between 2 AGOs of the same type.*/
/**/
/***********************************/

float g_fNextPlouf=0.0f;

#define LIMIT_AGO_TO_EVERY(timelimit) \
{ \
	static float NextBubble=0.0f;					 \
	g_ffFrameTime=AGO_fGetTimeInSeconds();			 \
	if ((g_AGO_MustReinitStaticVars) || (NextBubble==0.0f)) NextBubble=g_ffFrameTime;	 \
	if (NextBubble>g_ffFrameTime) return;			 \
	NextBubble=g_ffFrameTime+timelimit;				 \
}
 
 
/********************************************/
/* Copies a float[3] or a MTH3D_tdstVector*/
/* into a float[3] or a MTH3D_tdstVector*/
/********************************************/
 

#ifndef U64 

#define Copy_a3f_Array(dest,src) \
{ \
	register float *p1=(float *)(dest); \
	register float *p2=(float *)(src); \
	*(p1++)=*(p2++); \
	*(p1++)=*(p2++); \
	*(p1)=*(p2); \
}

#else /* U64 */



void Internal_Copy_a3f_Array(float *dest,float *src)
{
	register float *p1=(float *)(dest);
	register float *p2=(float *)(src);
	*(p1++)=*(p2++);
	*(p1++)=*(p2++);
	*(p1)=*(p2);
}

#define Copy_a3f_Array(dest,src) Internal_Copy_a3f_Array(((float *)(dest)),((float *)(src)))

#endif
 
 
/*****************************************/
/* Various functions prototypes*/
/*****************************************/
void AGO_vInit(void);
AGO_Part *AGO_vCreatePart(unsigned long parm_ulType, float *parm_a3_fPosition, float *parm_a3_fDirection, float TimeLimit, float fScaleX, float fScaleY, void *pVisualMaterial);
void AGO_vDestroyPart(unsigned long ulPartNumber);
void AGO_vProcessPart(unsigned long ulPartNumber,GLD_tdstViewportAttributes *_p_stViewport);
void AGO_vProcessAllParts(GLD_tdstViewportAttributes *_p_stViewport);
void AGO_vTestNewParts(void);
void AGO_vAddParticle(unsigned long PartType,
					  MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter);
void AGO_Define_OrthogonalVectors(MTH3D_tdstVector *p_stDirection,MTH3D_tdstVector *p_stV1,MTH3D_tdstVector *p_stV2);
void AGO_vDisplayPart(unsigned long ulPartNumber, GLD_tdstViewportAttributes *_p_stViewport);
void InitGauges(void);
void InitIcones(void);


#ifdef INFODESIGN_RESEARCH

			void AGO_vTrianglesInit(void);

			void AGO_vDisplayTriangles(GLD_tdstViewportAttributes *p_stVpt);

			void AGO_vCreateTriangle(float c1[3], float c2[3], float c3[3], void *VisualMat, 
						 float U1, float V1, 
						 float U2, float V2,
						 float U3, float V3,
						 float DelayTime,
						 unsigned long Parameter);

			void GLI_vDisplayWorldTriangle(
						GLD_tdstViewportAttributes *p_stVpt,
						float coordinates[3][3],
						float uvs[3][2],
						void *VisualMaterial);
 
			

#endif /* INFODESIGN_RESEARCH */



void JFFTXT_vInit(void);
void JFFTXT_vAffiche(GLD_tdstViewportAttributes *p_stVpt);

 
/********************************************/
/************** CUSTOM LOGOS ****************/
/********************************************/
void *LogoMaterials[6*3];
float g_LogoTransparency=0;
float g_LogoPosition[4];
void AGO_vAddLogoPart(float parameter, void *hVisualMaterial);
void AGO_vActivateLogoDisplay(float *p_stPosition, float *p_stDirection, float parameter);
void AGO_vDisplayLogo(GLD_tdstViewportAttributes *p_stVpt);
/*********************************************/


extern ACP_tdxBool  g_bInGameMenu;
 
/******************************************************/
/* SINUS and COSINUS FUNCTIONS*/
/******************************************************/
#ifdef U64
 
	/* Defining an external look-up table for the N64 version*/
	#define COSTABLESIZE			128
	#define COSTABLEMASK			(COSTABLESIZE-1)
	#define COS_PI					3.1415927f
	#define COS_2PI					(2.0f*COS_PI)
	#define COS_FLOAT2_TABLEINDEX	((float)COSTABLESIZE/(float)COS_2PI)
	extern float g_pfCosTable[COSTABLESIZE];
	#define COSINUS(f)	(g_pfCosTable[((long)((f)*COS_FLOAT2_TABLEINDEX)) & COSTABLEMASK])
	#define SINUS(f)	(g_pfCosTable[((long)((f)*COS_FLOAT2_TABLEINDEX)+32) & COSTABLEMASK])


	extern char FON_fn_cRefreshCache(unsigned char *_szString);
 
 
#else /*************************************************/
 
	/* PC version uses MTH macros instead (hopin' they're optimized !)*/
	#define SINUS(f)	MTH_M_xSin(f)
	#define COSINUS(f)	MTH_M_xCos(f)
 
#endif	/* U64*/
/******************************************************/
 
 
/*****************************************************************/
/* Initialization function... Once per map change or re-init*/
/***************************************************************/


void AGO_vInit(void)
{
	g_ulNumberOfAgos=0;
	g_bUsingMapMondeAGOs=0;
	g_ffLastFrameTime=0.0f;
	g_NumberOfZeldaAgos=0;
	g_AGO_MustReinitStaticVars=1;
	g_AGO_PloufMaterial=NULL;
	g_fNextPlouf=0.0f;
	g_DoSmallPlouf=0;
	g_LogoTransparency=0;
#ifdef U64
	g_bWeirdFireEffect=0;
#endif
	InitGauges();
	InitIcones();
	JFFTXT_vInit();

#ifdef INFODESIGN_RESEARCH

	AGO_vTrianglesInit();

#endif /* INFODESIGN_RESEARCH */ 
}
 
/***********************************************************/
/**/
/* returns time in seconds*/
/**/
/***********************************************************/
 
#include "lst.h" 
#include "fil.h"
#include "pcs.h"
#include "geo.h"
#include "mec.h"
#include "sct.h"
#include "prt.h"
#include "gam.h"
#include "gli.h"
#include "gli\object.h"
 
#ifdef U64

void fn_vFadeIn(void);
void fn_vBlackScreenForNFrames(int);
void GLI_vSaveCenteringParameters(void);
 
float AGO_fGetTimeInSeconds(void)
{
	return ((float)OS_CYCLES_TO_USEC(osGetTime()))/1000000.0f;
}
 
#else /****************************************************/
 
float AGO_fGetTimeInSeconds(void) 
{
	return ((float)g_stEngineStructure.stEngineTimer.ulCurrentTimerCount)*0.001f;
}
 
#endif /* U64*/
 
 
 
/******************************************************/
/* EXTERNAL AGO DRAWING FUNCTIONS*/
/******************************************************/
/* Draws a sprite using a world-coordinated-position, and 2 scales*/
int GLI_vDrawWorldSprite(float *a3_fPosition,
						 void *pVisualMaterial,
						 float fscaleX,
						 float fscaleY, 
						 GLD_tdstViewportAttributes *_p_stViewport, 
						 unsigned long AnimTime);
/*****************************/
/* Draws a planar sprite (XY-planar rectangle)*/
int GLI_vDrawWorldPlanarSprite(float *a3_fPosition,
							   void *pVisualMaterial,
							   float fscaleX,
							   float fscaleY, 
							   GLD_tdstViewportAttributes *_p_stViewport, 
							   unsigned long AnimTime);
/*****************************/
/* Draws an oriented rectangle according to the given 2 vectors*/
int GLI_vDrawWorldOrthoPlanarSprite(float *a3_fPosition,
									void *pVisualMaterial,
									float fscaleX,
									float fscaleY, 
									GLD_tdstViewportAttributes *_p_stViewport, 
									unsigned long AnimTime, 
									MTH3D_tdstVector *p_stV1, 
									MTH3D_tdstVector *p_stV2, 
									int FollowZ); /* This parameter is ignored right now...*/
 

/***************************************/
/* Draws a black transparent rectangle */
/***************************************/

void GLI_vDisplayFrame(float *a3_fPosition, /* X,Y in percent of screen size (Z is ignored) of UpperLeft */
					  float *a3_fDirection, /* X,Y in percent of screen size (Z is ignored) of LowerRight*/
					  float Transparency, /* Opacity of the black frame */
					  GLD_tdstViewportAttributes *_p_stViewport
					  );

 
void  GLI_vSetGlobalAlpha(float f);
float GLI_vGetGlobalAlpha(void);
 
 
 
long AGO_ulGetElderOne(void)
{
	register unsigned long i;
	register unsigned long ulOldestIndex;
	register float fOldestTime;
	
	ulOldestIndex=0;
	fOldestTime=g_AGO[0].fCreationTime;

	i=0;
	while ((g_AGO[i].ulType != AGO_STILL | AGO_REMANANCE3) && (i<AGO_MAX_NUMBER_OF_AGOS)) i++;
	if (i>=AGO_MAX_NUMBER_OF_AGOS-1) return -1;
	
	ulOldestIndex=i;
	fOldestTime=g_AGO[i].fCreationTime;
	i++;
	
	for(;i<AGO_MAX_NUMBER_OF_AGOS;i++)
	{
		if ((g_AGO[i].fCreationTime<fOldestTime) && 
			(g_AGO[i].ulType != AGO_STILL | AGO_REMANANCE3))
		{
			ulOldestIndex=i;
			fOldestTime=g_AGO[i].fCreationTime;
		}
	}
	return ulOldestIndex;
}
 
/******************************************************/
/* ************************************************ ***/
/* AGO_vCreatePart : AGO Creation Function			***/
/* ************************************************ ***/
/******************************************************/
AGO_Part *AGO_vCreatePart(unsigned long parm_ulType, float *parm_a3_fPosition, float *parm_a3_fDirection, float TimeLimit, float fScaleX, float fScaleY, void *pVisualMaterial)
{
	register AGO_Part *p;
 
 
	/* We also check for Zelda effect*/
	if ((parm_ulType & AGO_ZELDA) && (g_ulNumberOfAgos!=AGO_MAX_NUMBER_OF_AGOS))
	{
		if (g_NumberOfZeldaAgos==MAX_NUMBER_OF_ZELDA_AGOS) return NULL;
		g_NumberOfZeldaAgos++;
	}
 
	/**/
	/* New : If we reached the max amount of AGOs, we 'kill' the elder one, */
	/* to be able to create a new one :-)*/
	/* */
	if (g_ulNumberOfAgos==AGO_MAX_NUMBER_OF_AGOS)
	{
		long i;
		i=AGO_ulGetElderOne();
		if (i!=-1) AGO_vDestroyPart(i); else return NULL;
	}
 
	/* We take the next available AGO*/
	p=&(g_AGO[g_ulNumberOfAgos++]);
 
 
	p->ulType=parm_ulType;
	Copy_a3f_Array(p->a3_fPosition,parm_a3_fPosition);
	Copy_a3f_Array(p->a3_fInitialPosition,parm_a3_fPosition);
	if (parm_a3_fDirection!=NULL) { Copy_a3f_Array(p->a3_fDirection,parm_a3_fDirection); }
 
 
	g_ffFrameTime=AGO_fGetTimeInSeconds();
	p->fCreationTime=g_ffFrameTime;
 
	/* We copy the given scale*/
	p->fScale[0]=fScaleX; p->fScale[1]=fScaleY;
 
	/* The 'time limit' may also be the Z limit */
	/* or anything else according to the given type*/
	p->LimitParam.fTimeLimit=TimeLimit;
 
	/* We copy the visual material*/
	p->VisualMaterial=pVisualMaterial;
 
	/* We record the creation time, to allow texture animation start at the begining*/
#ifdef U64
	p->AnimTime=g_ulVBLTime;
#else
	p->AnimTime = (long)gs_fCoefOfMultiplicationForAnimatedTexture ;
#endif /* U64*/
 
	/* External desynchro parameter*/
	p->fAnimTimeScale=g_AGO_AnimTimeScale;
 
	/* The default transparency is 255 except for some special cases*/
	p->Transparency=255.0f;
	if ((parm_ulType == AGO_RAYMAN_PLOUF) && (parm_a3_fDirection!=NULL))
		p->Transparency=parm_a3_fDirection[0];
	if (( parm_ulType & AGO_SHADEMASK) ==AGO_APPEAR)
		p->Transparency=5.0f;
 
 
	/* Special cases for magical effect*/
	if ((parm_ulType & AGO_TYPEMASK) == AGO_ROTATING_SLOW)
	{
		/* Center is Direction*/
		/* Angles are in parm_a3_fPosition*/
		/* Radius = p->LimitParam.fTimeLimit*/
		p->a3_fInitialPosition[0]=FLOAT_RANGED_RANDOM(-3.5f,3.5f);
		p->a3_fInitialPosition[1]=FLOAT_RANGED_RANDOM(-3.5f,3.5f);
		p->a3_fInitialPosition[2]=FLOAT_RANGED_RANDOM(-3.5f,3.5f);
	}
 
	if (((parm_ulType & AGO_TYPEMASK) == AGO_MOVINGSINXY) || ((parm_ulType & AGO_TYPEMASK) == AGO_MOVINGSINXYUP))
	{
		if (parm_ulType & AGO_ZELDA)
		{
			/* Sinus amplitude*/
			p->a3_fInitialPosition[0]=FLOAT_RANGED_RANDOM(-1.5f,1.5f);
			/* Time multiplier for the sinus effect*/
			p->a3_fInitialPosition[2]=FLOAT_RANGED_RANDOM(1.0f,4.0f);
		}
		else
		{
			/* Sinus amplitude*/
			p->a3_fInitialPosition[0]=FLOAT_RANGED_RANDOM(-0.5f,0.5f);
			/* Time multiplier for the sinus effect*/
			p->a3_fInitialPosition[2]=FLOAT_RANGED_RANDOM(1.0f,2.0f);
		}
 
		
	}
 
	if ((parm_ulType & AGO_TYPEMASK) == AGO_SPIRALE)
	{
		/* Sinus amplitude*/
		p->a3_fInitialPosition[0]=FLOAT_RANGED_RANDOM(0.0f,0.005f);
		p->a3_fInitialPosition[1]=FLOAT_RANGED_RANDOM(-0.05f,0.05f);
		/* Time multiplier for the sinus effect*/
		p->a3_fInitialPosition[2]=FLOAT_RANGED_RANDOM(5.0f,6.0f);
		p->Transparency=200.0f;
	}

	if ((parm_ulType & AGO_TYPEMASK) == AGO_GOTO) 
	{
		register int i;
		p->LimitParam.fTimeLimit=0.0f;

		for(i=0;i<3;i++)
		{
			p->a3_fInitialPosition[i]=(p->a3_fDirection[i]-p->a3_fPosition[i])/AGO_GOTO_STEP;
		}
	}
 
	if ((parm_ulType & AGO_TYPEMASK) == AGO_2DSPIRALE)
	{
		MTH3D_tdstVector V1,V2;
		float Sin1,Cos1,Angle;

		Copy_a3f_Array(p->a3_fInitialPosition,parm_a3_fPosition);
		/*p->a3_fInitialPosition[0]=parm_a3_fPosition[0];
		p->a3_fInitialPosition[1]=parm_a3_fPosition[1];
		p->a3_fInitialPosition[2]=parm_a3_fPosition[2];*/
		AGO_Define_OrthogonalVectors((MTH3D_tdstVector *)parm_a3_fDirection,&V1,&V2);
		Angle=FLOAT_RANGED_RANDOM(0.0f,7.0f);
		p->fAnimTimeScale=Angle;
 
		*((float *)(&p->AnimTime))=FLOAT_RANGED_RANDOM(0.5f,1.0f);
 
		Sin1=SINUS(Angle)*TimeLimit;
		Cos1=COSINUS(Angle)*TimeLimit;
		p->a3_fPosition[0]=parm_a3_fPosition[0]+V1.xX*Sin1+V2.xX*Cos1;
		p->a3_fPosition[1]=parm_a3_fPosition[1]+V1.xY*Sin1+V2.xY*Cos1;
		p->a3_fPosition[2]=parm_a3_fPosition[2]+V1.xZ*Sin1+V2.xZ*Cos1;
	}

	return p; 
}
 
 
/******************************************************/
/* ************************************************ ***/
/* AGO_vDestroyPart : Destroys the given AGO		***/
/* ************************************************ ***/
/******************************************************/
void AGO_vDestroyPart(unsigned long ulPartNumber)
{
	register unsigned long i;
	register AGO_Part *psrc, *pdst;
 
	pdst=&(g_AGO[ulPartNumber]);
	psrc=pdst+1;
 
	if (pdst->ulType & AGO_ZELDA)
		g_NumberOfZeldaAgos--;
 
	for(i=ulPartNumber+1; i<g_ulNumberOfAgos;i++)
	{
		memcpy(pdst,psrc,sizeof(AGO_Part));
		psrc++;
		pdst++;
	}
	g_ulNumberOfAgos--;
}
 








/*******************************************************************************/
/*	NEW PART FOR MISC DISPLAYING											   */
/*		GAUGES & ICONS														   */
/*******************************************************************************/


typedef struct AGO_Gauge_
{
	float Coords[4];
	void *EmptyMaterial;
	void *FullMaterial;
	float Position;
	int Transparency;
} AGO_Gauge;

typedef struct AGO_Icone_
{
	float Coords[4];
	void *Material;
	int Transparency;
} AGO_Icone;
 
#define MAX_ICONES 35
#define MAX_GAUGES 8

AGO_Icone	g_TheIcones[MAX_ICONES];
AGO_Gauge	g_TheGauges[MAX_GAUGES];

/* 
	This function draws a sprite 
	With "percent of the screen" coordinates
	And uses global transparency level.
*/
void GLI_vDraw2DSpriteWithPercent(	GLD_tdstViewportAttributes *p_stVpt,
						float XMin,
						float YMin,
						float XMax,
						float YMax,
						ACP_tdxHandleOfMaterial hMaterial );

#ifdef U64
    #define M_vSetZValueForSprites(Z)
#else /* U64 */
    /* On PC, we need to set different Z value for icones and texts. */
    extern float GLI_g_fZValueForSprite;
    #define M_vSetZValueForSprites(Z) GLI_g_fZValueForSprite = Z;
#endif /* U64 */


void InitGauges(void)
{
	int i;
	for(i=0;i<MAX_GAUGES;i++) 
	{
		g_TheGauges[i].Transparency=0;
		g_TheGauges[i].Position=0;
	}
}

void InitIcones(void)
{
	int i;
	for(i=0;i<MAX_ICONES;i++) 
	{
		g_TheIcones[i].Transparency=0;
	}
}


void AddGauge(float *V1, float *V2, float Num, void *EmptyMat, void *FullMat)
{
	int i=(int)Num;

	g_TheGauges[i].Coords[0]=V1[0];
	g_TheGauges[i].Coords[1]=V1[1];
	g_TheGauges[i].Coords[2]=V2[0];
	g_TheGauges[i].Coords[3]=V2[1];
	g_TheGauges[i].EmptyMaterial=EmptyMat;
	g_TheGauges[i].FullMaterial=FullMat;
	g_TheGauges[i].Position=V1[2];
	g_TheGauges[i].Transparency=V2[2];
}


void AddIcone(float *V1, float *V2, float Num, void *Mat)
{
	int i=(int)Num;

	
	g_TheIcones[i].Coords[0]=V1[0];
	g_TheIcones[i].Coords[1]=V1[1];
	g_TheIcones[i].Coords[2]=V2[0];
	g_TheIcones[i].Coords[3]=V2[1];
	g_TheIcones[i].Material=Mat;
	g_TheIcones[i].Transparency=V2[2];
}

void AGO_vDisplayIcones(GLD_tdstViewportAttributes *p_stVpt)
{
	int i;

	for(i=0;i<MAX_ICONES;i++)
	{
		if ((!g_stEngineStructure.bEngineFrozen) || ((i>14) && (i<25)))
		if (g_TheIcones[i].Transparency>0)
		{
			GLI_vSetGlobalAlpha(g_TheIcones[i].Transparency);
			GLI_vDraw2DSpriteWithPercent(	p_stVpt, 
								g_TheIcones[i].Coords[0],
								g_TheIcones[i].Coords[1],
								g_TheIcones[i].Coords[2],
								g_TheIcones[i].Coords[3],
								g_TheIcones[i].Material);
		}
	}
}


void AGO_vDisplayGAUGES(GLD_tdstViewportAttributes *p_stVpt)
{
	int i;

#ifdef U64
	/* We re-init for N64*/

	AGO_g_LastMaterialUsed=NULL;
	g_GLI_SpritesUsed=0;
	g_GLI_DontInitSprites=0;
	g_GLI_DontReinitSprites=0;
	AGO_SkipMaterial=0;
	GLI_vPrepareViewPort();
#endif /* U64*/


	for(i=0;i<MAX_GAUGES;i++)
	{
		

#ifdef U64
	   if (((!g_stEngineStructure.bEngineFrozen) && (i<MAX_GAUGES-2)) ||
			((g_stEngineStructure.bEngineFrozen) && (i>=MAX_GAUGES-2)))
#endif

		if (g_TheGauges[i].Transparency>0)
		{
			float diffx,diffy;
			float position;

			diffx=g_TheGauges[i].Coords[2]-g_TheGauges[i].Coords[0];
			diffy=g_TheGauges[i].Coords[3]-g_TheGauges[i].Coords[1];

			if (diffx>diffy) /* horizontal gauge */
			{
				position=g_TheGauges[i].Coords[0]+(g_TheGauges[i].Position*diffx/100.0f);
				GLI_vSetGlobalAlpha(g_TheGauges[i].Transparency);

				GLI_vDraw2DSpriteWithPercent(	p_stVpt, 
									g_TheGauges[i].Coords[0],
									g_TheGauges[i].Coords[1],
									position,
									g_TheGauges[i].Coords[3],
									g_TheGauges[i].FullMaterial);

				if (g_TheGauges[i].Position<100.0f)
				{
					GLI_vDraw2DSpriteWithPercent(	p_stVpt, 
										position,
										g_TheGauges[i].Coords[1],
										g_TheGauges[i].Coords[2],
										g_TheGauges[i].Coords[3],
										g_TheGauges[i].EmptyMaterial);
				}

			}
			else /* vertical gauge */
			{
				position=g_TheGauges[i].Coords[3]-(g_TheGauges[i].Position*diffy/100.0f);
				GLI_vSetGlobalAlpha(g_TheGauges[i].Transparency);

				GLI_vDraw2DSpriteWithPercent(	p_stVpt, 
									g_TheGauges[i].Coords[0],
									position,
									g_TheGauges[i].Coords[2],
									g_TheGauges[i].Coords[3],
									g_TheGauges[i].FullMaterial);

				if (g_TheGauges[i].Position<100.0f)
				{
					GLI_vDraw2DSpriteWithPercent(	p_stVpt, 
										g_TheGauges[i].Coords[0],
										g_TheGauges[i].Coords[1],
										g_TheGauges[i].Coords[2],
										position,
										g_TheGauges[i].EmptyMaterial);
				}
			}
		}
	}

	M_vSetZValueForSprites( 0.998f );

	AGO_vDisplayIcones(p_stVpt);

	if (g_LogoTransparency>0.01f)
	{
		M_vSetZValueForSprites( 0.999f );
		AGO_vDisplayLogo(p_stVpt);
	}

	M_vSetZValueForSprites( 1.0f );

	JFFTXT_vAffiche(p_stVpt);
}

 
/***************************************************************/
/**/
/* Main AGO function :	Processes all the parts, destroys them */
/*						When limits have been reached ...*/
/**/
/***************************************************************/
 

void AGO_vProcessAllParts(GLD_tdstViewportAttributes *_p_stViewport)
{
	register AGO_Part *p;
	register unsigned long i;
	register unsigned long MustDestroy;
	register unsigned long Type;
	float AlphaTemp;
	static int LastFrozen=0;


	g_ffFrameTime=AGO_fGetTimeInSeconds();
	if (g_ffLastFrameTime!=0.0f)
	{
		g_fTimeDifference=g_ffFrameTime - g_ffLastFrameTime;
		g_ffLastFrameTime=g_ffFrameTime;
	}
	else
	{
		/* Dummy value for the first time.. who cares ;-) */
		g_fTimeDifference=0.0f;
		g_ffLastFrameTime=g_ffFrameTime;
		return;
	}

	if ((g_bInGameMenu) && (!LastFrozen) && (g_bUsingMapMondeAGOs==0))
	{
		LastFrozen=1;
		g_ulNumberOfAgos=0;
		g_NumberOfZeldaAgos=0;
	}
	else
	if ((!g_bInGameMenu) && (LastFrozen)  && (g_bUsingMapMondeAGOs==0))
	{
		LastFrozen=0;
		g_ulNumberOfAgos=0;
		g_NumberOfZeldaAgos=0;
	}

 
	if (g_bForceWhiteFog)
	{
		g_bForceWhiteFog++;
		if (g_bForceWhiteFog==3)
		{
			g_bForceWhiteFog=0;
		}
	}
 
	/* If no AGO, we simply return ;-)*/
	/* But we must display the jauges !! */
	if (g_ulNumberOfAgos==0) 
	{
			/* AGO_vDisplayGAUGES(_p_stViewport); */

#ifdef INFODESIGN_RESEARCH
	AGO_vDisplayTriangles(_p_stViewport);
#endif /* INFODESIGN_RESEARCH */

		return;
	}
 
	/* Simply for alternate display*/
	AGO_g_OddFrame=(AGO_g_OddFrame)?0:1;
 
	/* Various N64 initializations*/
 
#ifdef U64
	AGO_g_LastMaterialUsed=NULL;
	g_GLI_SpritesUsed=0;
	g_GLI_DontInitSprites=0;
	g_GLI_DontReinitSprites=0;
	AGO_SkipMaterial=0;
	g_iCurrentPlanarSprite=0;
	GLI_vPrepareViewPort();
#endif /* U64*/
 
	/* We save the original global transparency*/
	AlphaTemp = GLI_vGetGlobalAlpha();
 
	i=0;
	/********************************/
	/* First we kill the particles*/
	/* that must die !*/
	/********************************/
	while(i<g_ulNumberOfAgos)
	{
 
		p=&(g_AGO[i]);
		Type=p->ulType;
		MustDestroy=0;
 
		if (Type & AGO_TIMELIMITED)
		{
			if (g_ffFrameTime-p->fCreationTime>p->LimitParam.fTimeLimit) MustDestroy=1;
		}
		if (Type & AGO_ZLIMITED)
		{
			if (p->a3_fPosition[2] > p->LimitParam.f_ZLimit) MustDestroy=1;
		}
 
		if (p->Transparency<=0.0f)
		{
			MustDestroy=1;
		}
		
		
 
		if ((MustDestroy) || (p->ulType & AGO_MUSTDIE))
		{
			if (p->ulType & AGO_ENDASPLOUF) 
			if (p->ulType & AGO_ZELDA)
			{
				if (FLOAT_RANGED_RANDOM(-6.0f,1.0f)>0.0f)
				{
					AGO_vAddParticle(68, 
							(MTH3D_tdstVector *)p->a3_fPosition,
							(MTH3D_tdstVector *)p->a3_fDirection,
							p->VisualMaterial,
							1.0f);
				}
			}
			AGO_vDestroyPart(i); 
		}
		else  
		{ 
			i++; 
		}
	}
 
	i=0;
 
	/* Now we can process and display every remaining AGO*/
	while(i<g_ulNumberOfAgos)
	{
		AGO_vProcessPart(i, _p_stViewport);
		i++;
	};

	
 
#ifdef U64
	/* We re-init for N64*/
 
	AGO_g_LastMaterialUsed=NULL;
	g_GLI_SpritesUsed=0;
	g_GLI_DontInitSprites=0;
	g_GLI_DontReinitSprites=0;
	AGO_SkipMaterial=0;
	GLI_vPrepareViewPort();
#endif /* U64*/

	/*AGO_vDisplayGAUGES(_p_stViewport); */
 
#ifdef INFODESIGN_RESEARCH
	AGO_vDisplayTriangles(_p_stViewport);
#endif /* INFODESIGN_RESEARCH */

 
	GLI_vSetGlobalAlpha(AlphaTemp);
 
	g_AGO_MustReinitStaticVars=0;
}
 
#ifndef U64
void AGO_vReDisplayAllParts(GLD_tdstViewportAttributes *_p_stViewport)
{
	register unsigned long i;
	float AlphaTemp;
 
 
	/* If no AGO, we simply return ;-)*/
	if (g_ulNumberOfAgos==0) return;
 
	/* Various N64 initializations*/
 
	/* We save the original global transparency*/
	AlphaTemp = GLI_vGetGlobalAlpha();
 
	i=0;
 
	/* Now we can process and display every remaining AGO*/
	while(i<g_ulNumberOfAgos)
	{
		AGO_vDisplayPart(i, _p_stViewport);
		i++;
	};
 
	GLI_vSetGlobalAlpha(AlphaTemp);
}
 
#endif

void AGO_vDisplayPart(unsigned long ulPartNumber, GLD_tdstViewportAttributes *_p_stViewport)
{
	register AGO_Part *p;
	register unsigned long ulTemp;
	float AddX=0.0f;
	float AddY=0.0f;
	float AddZ=0.0f;
 
	p=&(g_AGO[ulPartNumber]);
 
	ulTemp=(p->ulType & AGO_TYPEMASK);
 
	switch(ulTemp)
	{
		/* If the part is still, no need for any calculation*/
		case AGO_STILL: break;
		case AGO_MOVINGSINXYUP:
		case AGO_MOVINGSINXY:
			{
				float timet=p->a3_fInitialPosition[2]*(g_ffFrameTime-p->fCreationTime);
				float *pp2=p->a3_fPosition;
				AddX=p->a3_fInitialPosition[0]*SINUS(timet);
				AddY=p->a3_fInitialPosition[0]*COSINUS(timet);
				pp2[0]+=AddX;
				pp2[1]+=AddY;
				pp2[2]+=AddX+AddY;
			}
			break;
 
		case AGO_SPIRALE:
			{
				float *pp=p->a3_fInitialPosition;
				float *pp2=p->a3_fPosition;
				float timet=p->a3_fInitialPosition[2]*(g_ffFrameTime-p->fCreationTime)+p->a3_fDirection[2];
 
				AddX=pp[0]*SINUS(timet);
				AddY=pp[0]*COSINUS(timet);
				AddX+=pp[1]*COSINUS(timet);
				AddZ=pp[1]*SINUS(timet);
				pp2[0]+=AddX;
				pp2[1]+=AddY;
				pp2[2]+=AddZ;
			}
			break;
 
		default: break;
 
	};
	
 
#ifdef U64
	/* determine if there must be an anim loop*/
	if (p->ulType & AGO_LOOPANIM) g_bLoopAnim=1; else g_bLoopAnim=0;
#endif
 
	/* Setting the "Used By GLI" variable */
	/* for texture animation desynchro*/
 
	if ((p->ulType & AGO_TYPEMASK) == AGO_2DSPIRALE)
	{
		g_AGO_AnimTimeScale=1.0f;
	}
	else
	{
		g_AGO_AnimTimeScale=p->fAnimTimeScale;
	}
 
	
	/* This allows a better transparency handling*/
	if (p->Transparency>=255.0f)  
		GLI_vSetGlobalAlpha(255.0f);
	else
		GLI_vSetGlobalAlpha(p->Transparency);
 
 
	/* Drawing the AGO :*/
	if (p->VisualMaterial!=NULL)
	{
		if ((p->ulType & AGO_TYPEMASK) == AGO_FRAME)
		{
			GLI_vDisplayFrame(p->a3_fPosition, p->a3_fDirection, p->Transparency,_p_stViewport);
			p->ulType |= AGO_MUSTDIE;
		}
		else
		if ((p->ulType & AGO_GEOMETRY_TYPE_MASK)==AGO_ORIENTEDXYPLAN)
		{
			/***************************************************************/
			/* This is an XY "sprite" that is oriented along X and Y axes*/
			/* The a3_fDirection represent the main direction of the sprite*/
			/***************************************************************/
			MTH3D_tdstVector stV1, stV2;
			float fNorm;
			stV2.xX=-p->a3_fDirection[0];
			stV2.xY=-p->a3_fDirection[1];
			stV2.xZ=0.0f;
			fNorm=MTH_M_xSqrt(stV2.xX*stV2.xX+stV2.xY*stV2.xY);
			if (fNorm>=0.01f)
			{
				fNorm=1.0f/fNorm;
				stV1.xX=-p->a3_fDirection[1]*fNorm;
				stV1.xY=p->a3_fDirection[0]*fNorm;
				stV1.xZ=0.0f;
				stV2.xX*=fNorm;
				stV2.xY*=fNorm;
				if (GLI_vDrawWorldOrthoPlanarSprite(p->a3_fPosition,(void *)p->VisualMaterial,p->fScale[0],p->fScale[1],_p_stViewport,p->AnimTime,&stV1, &stV2,0))
				{
						/* This means it has finished the texture animation*/
						p->ulType |= AGO_MUSTDIE;
				}
			}
			else { p->ulType |= AGO_MUSTDIE; }
		}
		else
		if (((p->ulType & AGO_GEOMETRY_TYPE_MASK)==AGO_REMANANCE) || ((p->ulType & AGO_GEOMETRY_TYPE_MASK)==AGO_REMANANCE2) || ((p->ulType & AGO_GEOMETRY_TYPE_MASK)==AGO_REMANANCE3))
		{
			MTH3D_tdstVector stV1, stV2, stV3;
			register float Val1, Val2;
			float TempPos[3];
 
			/***************************************************************/
			/* This is an orthogonal-to-a-given-vector surface... We draw a */
			/* half-cross that is inverted once every frame, giving a weird*/
			/* manga-like blinking effect, and also reduces the number */
			/* of drawn polygons by a factor of 2 !*/
			/***************************************************************/

			/* initial vector  */
			stV1.xX=p->a3_fPosition[0]-p->a3_fInitialPosition[0];
			stV1.xY=p->a3_fPosition[1]-p->a3_fInitialPosition[1];
			stV1.xZ=p->a3_fPosition[2]-p->a3_fInitialPosition[2];

			if ((p->ulType & AGO_GEOMETRY_TYPE_MASK)==AGO_REMANANCE3) stV1.xZ=0.0f;
 
			/* center position */
			TempPos[0]=p->a3_fInitialPosition[0]+stV1.xX*0.5f;
			TempPos[1]=p->a3_fInitialPosition[1]+stV1.xY*0.5f;
			TempPos[2]=p->a3_fInitialPosition[2]+stV1.xZ*0.5f;
 
			stV2.xX=-stV1.xY;
			stV2.xY=stV1.xZ;
			stV2.xZ=0;

			if ((p->ulType & AGO_GEOMETRY_TYPE_MASK)==AGO_REMANANCE3) stV2.xY=stV1.xX;

 
			Val1=stV1.xX*stV1.xX+stV1.xY*stV1.xY;
 
			if (Val1>=0.05f)
			{
 
				Val2=stV1.xZ*stV1.xZ+Val1;
		
				p->fScale[0]=MTH_M_xSqrt(Val2)*0.5f;
		
				Val1=MTH_M_xInvSqrt(Val1);
				Val2=MTH_M_xInvSqrt(Val2);
 
				stV2.xX*=Val1; stV2.xY*=Val1; 
				stV1.xX*=Val2; stV1.xY*=Val2; stV1.xZ*=Val2;
 
				if ((p->ulType & AGO_GEOMETRY_TYPE_MASK)==AGO_REMANANCE3)
				{
					if (!g_bInGameMenu)
						GLI_vDrawWorldOrthoPlanarSprite(TempPos,(void *)p->VisualMaterial,0.4f,p->fScale[0],_p_stViewport,p->AnimTime,&stV2, &stV1,0);
				}
				else
				if ((p->ulType & AGO_GEOMETRY_TYPE_MASK)==AGO_REMANANCE2)
				{
					GLI_vDrawWorldOrthoPlanarSprite(TempPos,(void *)p->VisualMaterial,0.3f,p->fScale[0],_p_stViewport,p->AnimTime,&stV2, &stV1,0);
					stV3.xX=stV1.xY*stV2.xZ - stV1.xZ*stV2.xY;
					stV3.xY=stV1.xZ*stV2.xX - stV1.xX*stV2.xZ;
					stV3.xZ=stV1.xX*stV2.xY - stV1.xY*stV2.xX;
					GLI_vDrawWorldOrthoPlanarSprite(TempPos,(void *)p->VisualMaterial,0.3f,p->fScale[0],_p_stViewport,p->AnimTime,&stV3, &stV1,0);
				}
				else
				if (AGO_g_OddFrame)
					GLI_vDrawWorldOrthoPlanarSprite(TempPos,(void *)p->VisualMaterial,0.1f,p->fScale[0],_p_stViewport,p->AnimTime,&stV2, &stV1,0);
				else
				{
					/* we cross product the V1 and V2 to make the other part of the cross-polygons*/
 
					stV3.xX=stV1.xY*stV2.xZ - stV1.xZ*stV2.xY;
					stV3.xY=stV1.xZ*stV2.xX - stV1.xX*stV2.xZ;
					stV3.xZ=stV1.xX*stV2.xY - stV1.xY*stV2.xX;
 
					GLI_vDrawWorldOrthoPlanarSprite(TempPos,(void *)p->VisualMaterial,0.1f,p->fScale[0],_p_stViewport,p->AnimTime,&stV3, &stV1,0);
				}
			}
		}
		else
		if ((p->ulType & AGO_GEOMETRY_TYPE_MASK)==AGO_ORTHOPLAN)
		{
			MTH3D_tdstVector stV1, stV2;
			MTH3D_tdstVector *p1,*p2;
 
			/***************************************************************/
			/* This is an "sprite" that is defined by a point and a normal vector*/
			/* to its surface (stored in the direction vector).*/
			/***************************************************************/
 
			/* We get 2 vectors that define the orthogonal planar surface*/
			AGO_Define_OrthogonalVectors((MTH3D_tdstVector *)p->a3_fDirection,&stV1,&stV2);
 
			if ((p->ulType & AGO_FOLLOWZ) == AGO_FOLLOWZ)  
			{
				/* The texture MUST be upside down*/
				if (stV1.xZ>stV2.xZ) 
					{ p1=&stV2; p2=&stV1; }
				else 
					{ p1=&stV1; p2=&stV2; }
			}
			else { p1=&stV1; p2=&stV2; }
 
			if (GLI_vDrawWorldOrthoPlanarSprite(p->a3_fPosition,(void *)p->VisualMaterial,p->fScale[0],p->fScale[1],_p_stViewport,p->AnimTime, p1, p2,0))
			{
				/* This means it has finished the texture animation*/
				p->ulType |= AGO_MUSTDIE;
			}
		}
		else
		if ((p->ulType & AGO_GEOMETRY_TYPE_MASK)==AGO_XYPLAN)
		{
			/***************************************************************/
			/* This is an simple XY "sprite" that is not oriented... */
			/* like "ploufs"*/
			/***************************************************************/
			if (GLI_vDrawWorldPlanarSprite(p->a3_fPosition,(void *)p->VisualMaterial,p->fScale[0],p->fScale[1],_p_stViewport,p->AnimTime))
			{
					/* This means it has finished the texture animation*/
					p->ulType |= AGO_MUSTDIE;
			}
		}
		else
		{
#ifdef U64
			char aamode=g_ulUseAntiAliasing;
			if ((p->ulType & (AGO_ZELDA | AGO_MOVINGSINXYUP))== (AGO_ZELDA | AGO_MOVINGSINXYUP))
			{
				g_ulUseAntiAliasing=3;
			}
#endif
			/***************************************************************/
			/* Then it's a simple 2D sprite :-)*/
			/***************************************************************/
 
			/* if this sprite is "based scale", it means that the sprite doesn't scale around its center,*/
			/* but around it's base...*/
			/* That's why we have to shift its position before displaying it*/
			if (p->ulType & AGO_BASEDSCALE) p->a3_fPosition[2]+=p->fScale[1];
 
			
 
			if (GLI_vDrawWorldSprite(p->a3_fPosition,(void *)p->VisualMaterial,p->fScale[0],p->fScale[1],_p_stViewport,p->AnimTime))
			{
					/* This means it has finished the texture animation*/
					p->ulType |= AGO_MUSTDIE;
			}
 
			/* And we restore it after...*/
			if (p->ulType & AGO_BASEDSCALE) p->a3_fPosition[2]-=p->fScale[1]; 
 
#ifdef U64
			if ((p->ulType & (AGO_ZELDA | AGO_MOVINGSINXYUP))== (AGO_ZELDA | AGO_MOVINGSINXYUP))
			{
				g_ulUseAntiAliasing=aamode;
			}
#endif
 
		}
 
 
 
		/* We restore original values for those types :*/
		
		if (((p->ulType & AGO_TYPEMASK) == AGO_MOVINGSINXY) || ((p->ulType & AGO_TYPEMASK) == AGO_MOVINGSINXYUP))
		{
			p->a3_fPosition[0]-=AddX;
			p->a3_fPosition[1]-=AddY;
			p->a3_fPosition[2]-=(AddY+AddX);
		}
 
		if ((p->ulType & AGO_TYPEMASK) == AGO_SPIRALE)
		{
			p->a3_fPosition[0]-=AddX;
			p->a3_fPosition[1]-=AddY;
			p->a3_fPosition[2]-=AddZ;
		}
 
	}
	else
	{
#ifdef U64
		osSyncPrintf("Null visual material in particles !!!\n");
#endif
	}
 
}
 

void AGO_vVectorMulAddInternal(float *pfdest, float *pfsrc, float mul)
{
	int i;

	for(i=0;i<3;i++)
	{
		pfdest[i]+=pfsrc[i]*mul;
	}
}

#define AGO_vVectorMulAdd(pfdest, pfsrc, mul) AGO_vVectorMulAddInternal((float *)(pfdest), (float *)(pfsrc), (float)(mul))



/***************************************************************/
/**/
/* Processes coordinates for a single part and displays it*/
/**/
/***************************************************************/
void AGO_vProcessPart(unsigned long ulPartNumber, GLD_tdstViewportAttributes *_p_stViewport)
{
	register AGO_Part *p;
	register unsigned long ulTemp;
	float TempValue;
 
	p=&(g_AGO[ulPartNumber]);
 
	ulTemp=(p->ulType & AGO_TYPEMASK);
 
	switch(ulTemp)
	{
		/* If the part is still, no need for any calculation*/
		case AGO_STILL: break;
 
		/* If the part is falling we must calculate this falling*/
 
		case AGO_FALLING_MEGAFAST:
				p->a3_fDirection[2]+=-AGO_G*g_fTimeDifference*4.0f;
		case AGO_GEISER: 
		/* NO BREAK HERE ON PURPOSE !*/
		case AGO_FALLING: 
				p->a3_fDirection[2]+=-AGO_G_SLOW*g_fTimeDifference;
		/* NO BREAK HERE ON PURPOSE !*/
		case AGO_FALLING_SLOW:
				p->a3_fDirection[2]+=-AGO_G_SLOW*g_fTimeDifference;
		/* NO BREAK HERE ON PURPOSE !*/
		case AGO_MOVING:
			{

				AGO_vVectorMulAdd(p->a3_fPosition,p->a3_fDirection,g_fTimeDifference);

				/* p->a3_fPosition[0]+=p->a3_fDirection[0]*g_fTimeDifference;
				p->a3_fPosition[1]+=p->a3_fDirection[1]*g_fTimeDifference;
				p->a3_fPosition[2]+=p->a3_fDirection[2]*g_fTimeDifference; */
			}
			break;
 
		case AGO_FASEGOINGTO:
			{
				register float Val1, Val2;
				register int Finished=0;
				register int i;
				
				for(i=0;i<3;i++)
				{
					Val1=(p->a3_fDirection[i]-p->a3_fPosition[i]);
					if ((MTH_M_xAbs(Val1)<=0.1f)) Finished++;
					else 
					{
						p->a3_fInitialPosition[i]=p->a3_fPosition[i];
						Val2=6.5f*Val1*g_fTimeDifference;
						if (MTH_M_xAbs(Val2)>=MTH_M_xAbs(Val1))
						{
							Finished++;
							p->a3_fPosition[i]=p->a3_fDirection[i];
						}
						else
							p->a3_fPosition[i]+=Val2;
					}
				}
				if (Finished) p->ulType |= AGO_MUSTDIE;
			}
		break;
 
		case AGO_GOINGTO:
			{
				register float Val1, Val2;
				register int Finished=0;
				register int i;
				
				for(i=0;i<3;i++)
				{
					Val1=(p->a3_fDirection[i]-p->a3_fPosition[i]);
					if ((MTH_M_xAbs(Val1)<=0.1f)) Finished++;
					else 
					{
						p->a3_fInitialPosition[i]=p->a3_fPosition[i];
						Val2=1.5f*Val1*g_fTimeDifference;
						if (MTH_M_xAbs(Val2)>=MTH_M_xAbs(Val1))
						{
							Finished++;
							p->a3_fPosition[i]=p->a3_fDirection[i];
						}
						else
							p->a3_fPosition[i]+=Val2;
					}
				}
				if (Finished) p->ulType |= AGO_MUSTDIE;
			}
		break;
 
		case AGO_GOTO:
			{
				register int i;
				for(i=0;i<3;i++)
				{
					p->a3_fPosition[i]+=p->a3_fInitialPosition[i];
				}
				p->LimitParam.fTimeLimit+=1.0f;
				if (p->LimitParam.fTimeLimit>=AGO_GOTO_STEP - 1.0f) p->ulType |= AGO_MUSTDIE;

			}
		break;
 
		case AGO_MOVING_AND_SLOWING:
			{
				float *pp=p->a3_fDirection;
				float *pp2=p->a3_fPosition;
				TempValue=-1.6f*g_fTimeDifference;
				pp[0]+=TempValue;
				pp[1]+=TempValue;
				pp[2]+=TempValue;

				AGO_vVectorMulAdd(pp2,pp,g_fTimeDifference);
				/* pp2[0]+=pp[0]*g_fTimeDifference;
				pp2[1]+=pp[1]*g_fTimeDifference;
				pp2[2]+=pp[2]*g_fTimeDifference; */
			}
			break;
 
		case AGO_MOVINGSINXYUP:
		case AGO_MOVINGSINXY:
			{
				/* float *pp=p->a3_fDirection;
				float *pp2=p->a3_fPosition; */

				AGO_vVectorMulAdd(((float *)(p->a3_fPosition)),((float *)(p->a3_fDirection)),g_fTimeDifference);

				/*pp2[0]+=pp[0]*g_fTimeDifference;
				pp2[1]+=pp[1]*g_fTimeDifference;
				pp2[2]+=pp[2]*g_fTimeDifference; */
			}
			break;
 
		
		
		case AGO_SPIRALE:
			{
				float *pp=p->a3_fInitialPosition;
 
				if (pp[0]<0.25f)
				{
					pp[0]*=1.51f;
					pp[1]*=1.1f;
				}
				else
				if (pp[0]<0.5f)
				{
					pp[0]*=1.1f;
					pp[1]*=1.01f;
				}
				else
				{
					pp[0]*=0.9f;
					pp[1]*=0.98f;
				}
			}
 
			break;
 
		case AGO_2DSPIRALE:
		{
			MTH3D_tdstVector V1,V2;
			float Sin1,Cos1,Angle;
 
			p->fAnimTimeScale+=g_fTimeDifference*6.5f*(*((float *)(&p->AnimTime)));
 
			(*((float *)(&p->AnimTime)))+=g_fTimeDifference*0.20f;
			p->LimitParam.fTimeLimit-=g_fTimeDifference*1.00f;
			if (p->LimitParam.fTimeLimit<=0.01f)
			{
				p->ulType |= AGO_MUSTDIE;
			}
 
			Angle=p->fAnimTimeScale;
			Sin1=SINUS(Angle)*p->LimitParam.fTimeLimit;
			Cos1=COSINUS(Angle)*p->LimitParam.fTimeLimit;
 
			AGO_Define_OrthogonalVectors((MTH3D_tdstVector *)p->a3_fDirection,&V1,&V2);			
			p->a3_fPosition[0]=p->a3_fInitialPosition[0]+V1.xX*Sin1+V2.xX*Cos1;
			p->a3_fPosition[1]=p->a3_fInitialPosition[1]+V1.xY*Sin1+V2.xY*Cos1;
			p->a3_fPosition[2]=p->a3_fInitialPosition[2]+V1.xZ*Sin1+V2.xZ*Cos1;
/*
			Angle=g_fTimeDifference*2.0f;
			Sin1=SINUS(Angle);
			Cos1=COSINUS(Angle);
			xx=p->a3_fDirection[0]*Cos1-p->a3_fDirection[1]*Sin1;
			yy=p->a3_fDirection[0]*Sin1+p->a3_fDirection[1]*Cos1;
			p->a3_fDirection[0]=xx;
			p->a3_fDirection[1]=yy;
 
			Angle=g_fTimeDifference*1.5f;
			Sin1=SINUS(Angle);
			Cos1=COSINUS(Angle);
			xx=p->a3_fDirection[0]*Cos1-p->a3_fDirection[2]*Sin1;
			yy=p->a3_fDirection[0]*Sin1+p->a3_fDirection[2]*Cos1;
			p->a3_fDirection[0]=xx;
			p->a3_fDirection[2]=yy;
*/
		}
		break;
		
 
		case AGO_ROTATING_SLOW:
		{
			register float cosx, sinx, cosy,siny,cosz, sinz;
			register float X,Y,Z;
			register float pos0,pos1,pos2;
 
			X=0.707f;
			Y=0.50f;
			Z=0.50f;
 
			/* Center is Direction*/
			/* Angles are in parm_a3_fPosition*/
			/* Radius = p->LimitParam.fTimeLimit*/
			pos0=p->a3_fInitialPosition[0]*g_ffFrameTime;
			pos1=p->a3_fInitialPosition[1]*g_ffFrameTime;
			pos2=p->a3_fInitialPosition[2]*g_ffFrameTime;
 
			cosx=COSINUS(pos0); sinx=SINUS(pos0);
			cosy=COSINUS(pos1); siny=SINUS(pos1);
			cosz=COSINUS(pos2); sinz=SINUS(pos2);
 
			/* We rotate the part around its own axis and add the translation*/
			p->a3_fPosition[0]=p->a3_fDirection[0]+(p->LimitParam.fTimeLimit)*(
				(cosy*cosz)*X + 
				(-siny*cosx*cosz - cosx*sinz)*Y + 
				(-siny*cosx*cosz + sinx /*+*/ * sinz)*Z
				);
			p->a3_fPosition[1]=p->a3_fDirection[1]+(p->LimitParam.fTimeLimit)*(
				(cosy*sinz)*X +
				(-sinz*siny*sinx+cosx*cosz)*Y +
				(-sinz*siny*cosx-sinx*cosz)*Z 
				);
			p->a3_fPosition[2]=p->a3_fDirection[2]+(p->LimitParam.fTimeLimit)*(
				(siny)*X +
				(sinx*siny)*Y +
				(cosx*cosy)*Z 
				);
 
			p->LimitParam.fTimeLimit-=4.5f*g_fTimeDifference;
			if (p->LimitParam.fTimeLimit<=0.01f)
				p->ulType |= AGO_MUSTDIE;
		}
		break;
 
		default: break;
 
	};
 
 
	if ((p->ulType & AGO_ENDASPLOUF) && (g_AGO_PloufMaterial!=NULL) && (!(p->ulType & AGO_ZELDA)))
	{
		if (p->a3_fPosition[2]<=p->LimitParam.fTimeLimit)
		{
			/* Must transform this AGO into a Plouf AGO !*/
			p->a3_fPosition[2]=p->LimitParam.fTimeLimit;
			p->ulType=AGO_RAYMAN_SMALL_PLOUF;
			p->fScale[0]=0.1f;
			p->fScale[1]=0.1f;
			p->fCreationTime=g_ffFrameTime;
			p->Transparency=250.0f;
			p->VisualMaterial=g_AGO_PloufMaterial;
		}
	}
	
 
	TempValue=0.0f;
 
	/********************************/
	/* Scale processing*/
	/********************************/
	switch (p->ulType & AGO_SCALEMASK)
	{
		case AGO_SCALING_MEGAFASTY:
			p->fScale[0]+=5.3f*g_fTimeDifference;
			p->fScale[1]+=20.5f*g_fTimeDifference;
			break;
 
#define EXPLOSION_SPEED 3.0f
		case AGO_SCALING_XTOY:
			p->fScale[0]+=EXPLOSION_SPEED*20.0f*g_fTimeDifference;
			p->fScale[1]-=EXPLOSION_SPEED*5.5f*g_fTimeDifference;
			if (p->fScale[0]>=5.0f)
			{
				p->ulType &= (~AGO_SCALEMASK);
				p->ulType |= AGO_SCALING_YTOX;
			}
			break;
		case AGO_SCALING_YTOX:
			p->fScale[0]-=EXPLOSION_SPEED*20.0f*g_fTimeDifference;
			/* p->fScale[1]+=EXPLOSION_SPEED*10.5f*g_fTimeDifference;*/
			if (p->fScale[0]<=1.0f)
			{
				p->fScale[0]=2.0f;
				p->ulType &= (~AGO_SCALEMASK);
				p->ulType |= AGO_SCALING_YTOX2;
			}
			break;
		case AGO_SCALING_YTOX2:
			p->fScale[0]-=EXPLOSION_SPEED*5.5f*g_fTimeDifference;
			p->fScale[1]+=EXPLOSION_SPEED*20.5f*g_fTimeDifference;
			if (p->fScale[1]>=10.0f)
			{
				p->ulType |= AGO_MUSTDIE;
			}
			break;
		case AGO_SCALING_MEGASLOW:
			TempValue=0.05f;
			break;
		case AGO_SCALING_SLOW:
			TempValue=1.3f;
			break;
		case AGO_SCALING_MID:
			TempValue=3.7f;
			break;
		case AGO_SCALING_FAST:
			TempValue=6.5f;
			break;
		case AGO_SCALING_FASTEST:
			TempValue=9.5f;
			break;
		case AGO_UNSCALING_FAST:
			TempValue=-0.5f;
			break;
		case AGO_UNSCALING_FASTEST:
			TempValue=-3.5f;
			break;
		case AGO_UNSCALING_SLOW:
			TempValue=-0.2f;
			break;
		default:
			break;
	}
 
	if (TempValue!=0.0f)
	{
		TempValue*=g_fTimeDifference;
		p->fScale[0]+=TempValue; p->fScale[1]+=TempValue;
	}

	if ( (p->ulType & AGO_SCALEMASK) == AGO_BIG_RANDOM_SCALE)
	{
		p->fScale[1]=p->fScale[0]=FLOAT_RANGED_RANDOM(0.0f,1.0f);
	}
	else if ( (p->ulType & AGO_SCALEMASK) == AGO_SMALL_RANDOM_SCALE)
	{
		p->fScale[1]=p->fScale[0]=FLOAT_RANGED_RANDOM(0.2f,0.6f);
	}
 
	if (p->fScale[0]<=0.0f) 
	{
		p->fScale[0]=0.01f;
		p->ulType |= AGO_MUSTDIE;
	}
	if (p->fScale[1]<=0.0f) 
	{
		p->fScale[1]=0.01f;
		p->ulType |= AGO_MUSTDIE;
	}
 
 
	/********************************/
	/* Shade processing*/
	/********************************/
	switch (p->ulType & AGO_SHADEMASK)
	{
		case AGO_WAIT:
			if (g_ffFrameTime-p->fCreationTime>p->LimitParam.fTimeLimit) 
			{
				p->ulType&=~AGO_SHADEMASK;
				p->ulType|=AGO_SHADE_FAST;
				
			}
			break;
		case AGO_APPEAR:
			p->Transparency+=350.0f*g_fTimeDifference;
			if (p->Transparency>=255.0f) 
			{
				p->Transparency=255.0f;
				p->ulType&=~AGO_SHADEMASK;
				p->ulType|=AGO_WAIT;
				p->fCreationTime=g_ffFrameTime;
			}
			break;
		case AGO_SHADE_SLOW:
			p->Transparency-=100.0f*g_fTimeDifference;
			break;
		case AGO_SHADE_MID:
			p->Transparency-=160.0f*g_fTimeDifference;
			break;
		case AGO_SHADE_FAST:
			p->Transparency-=260.0f*g_fTimeDifference;
			break;
		case AGO_SHADE_FASTEST:
			p->Transparency-=350.0f*g_fTimeDifference;
			break;
		case AGO_SHADE_MEGAFAST:
			p->Transparency-=850.0f*g_fTimeDifference;
			break;
		case AGO_SHADE_TWOFRAMES:
			p->Transparency-=2500.0f*g_fTimeDifference;
			break;
		case AGO_RANDOM_SHADE:
			p->Transparency=FLOAT_RANGED_RANDOM(100.0f,255.0f);
			break;
		case AGO_UNSHADE:
			p->Transparency+=100.0f*g_fTimeDifference;
			break;
 
		default:
			break;
	}
 
	if ((p->Transparency<0.0f) && ((p->ulType & AGO_SHADEMASK)!=AGO_APPEAR))
	{
		p->ulType |= AGO_MUSTDIE;
		p->Transparency=0.0f;
	}
 
	AGO_vDisplayPart(ulPartNumber, _p_stViewport);
}
 
 
void CreateType5AGO(  MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3];
 
	p_stPosition->xZ+=0.6f;
 
	g_AGO_AnimTimeScale=FLOAT_RANGED_RANDOM(0.7f,2.0f);
	Pos[0]=p_stPosition->xX; Pos[1]=p_stPosition->xY+0.5f; Pos[2]=p_stPosition->xZ+0.8f;
	Direction[0]=1.0f; Direction[1]=0.56f; Direction[2]=-0.53f;
	AGO_vCreatePart( AGO_NAISSANCE_OBUS ,  Pos,  Direction,  parameter, 0.8f, 0.8f, hVisualMaterial );
 
	g_AGO_AnimTimeScale=FLOAT_RANGED_RANDOM(0.7f,2.0f);
	Pos[0]=p_stPosition->xX; Pos[1]=p_stPosition->xY-0.5f; Pos[2]=p_stPosition->xZ+1.5f;
	Direction[0]=-0.50f; Direction[1]=-0.98f; Direction[2]=0.23f;
	AGO_vCreatePart( AGO_NAISSANCE_OBUS  ,  Pos,  Direction,  parameter, 0.5f, 0.6f, hVisualMaterial );
 
	g_AGO_AnimTimeScale=FLOAT_RANGED_RANDOM(0.7f,2.0f);
	Pos[0]=p_stPosition->xX; Pos[1]=p_stPosition->xY+0.5f; Pos[2]=p_stPosition->xZ-0.5f;
	Direction[0]=0.5f; Direction[1]=0.16f; Direction[2]=0.13f;
	AGO_vCreatePart( AGO_NAISSANCE_OBUS ,  Pos,  Direction,  parameter, 0.3f, 0.3f, hVisualMaterial );
 
	g_AGO_AnimTimeScale=FLOAT_RANGED_RANDOM(0.7f,2.0f);
	Pos[0]=p_stPosition->xX; Pos[1]=p_stPosition->xY-0.5f; Pos[2]=p_stPosition->xZ;
	Direction[0]=1.0f; Direction[1]=-0.29f; Direction[2]=-0.63f;
	AGO_vCreatePart( AGO_NAISSANCE_OBUS ,  Pos,  Direction,  parameter, 1.0f, 1.0f, hVisualMaterial );
}

void CreateType8AGO(  MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3];
	float Pos2[3];
	float fNorm;
	register float vx,vy;
 
	Copy_a3f_Array(Pos,p_stPosition);
	Pos[2]+=0.2f;
	Copy_a3f_Array(Pos2,Pos);
	Copy_a3f_Array(Direction,p_stDirection);
 
	vx=-Direction[1]; vy=Direction[0];
	fNorm=MTH_M_xSqrt(vx*vx+vy*vy);
	if (fNorm>=0.01f)
	{
		fNorm=0.4f/fNorm;
		vx*=fNorm; vy*=fNorm;
 
		fNorm=FLOAT_RANGED_RANDOM(-0.9f,0.0f); 
 
		Pos[0]+=-vx+fNorm*Direction[0];
		Pos[1]+=-vy+fNorm*Direction[1];
 
		fNorm=FLOAT_RANGED_RANDOM(-0.9f,0.0f); 
		Pos2[0]+=vx+fNorm*Direction[0];
		Pos2[1]+=vy+fNorm*Direction[1];
 
		AGO_vCreatePart( AGO_RAYMAN_PLOUF_SKI ,  Pos,   Direction, 200.0f, 0.2f, 0.8f, hVisualMaterial );
		AGO_vCreatePart( AGO_RAYMAN_PLOUF_SKI ,  Pos2,  Direction, 200.0f, 0.2f, 0.8f, hVisualMaterial );
	}
}




void CreateType16AGO(  MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{

#ifndef _FIRE_DEADCODE_U64_ 
	float Pos[3];
	float Direction[3];
	float Pos2[3];
	MTH3D_tdstVector stV2;
	float fNorm, PloufDirect;
	float scale;
 
	/* Direction[0]=p_stDirection->xX; Direction[1]=p_stDirection->xY; Direction[2]=p_stDirection->xZ;*/
	Copy_a3f_Array(Direction,p_stDirection);
 
	Direction[0]-=g_OldPloufDirection[0];
	Direction[1]-=g_OldPloufDirection[1];
 
	g_OldPloufDirection[0]=p_stDirection->xX;
	g_OldPloufDirection[1]=p_stDirection->xY;
 
	fNorm=Direction[0]*Direction[0]+Direction[1]*Direction[1];
 
	if (fNorm<0.000400f) return;
 
	scale=fNorm;
 
	if ((fNorm*Direction[0]+fNorm*Direction[1])<0.0f) PloufDirect=0; else PloufDirect=1;
 
	Copy_a3f_Array(Pos,p_stPosition);
	Pos[2]+=0.2f;
	Copy_a3f_Array(Pos2,Pos);
	Copy_a3f_Array(Direction,p_stDirection);
 
	stV2.xX=-Direction[1]; stV2.xY=Direction[0];
	fNorm=MTH_M_xSqrt(stV2.xX*stV2.xX+stV2.xY*stV2.xY);
	if (fNorm>=0.01f)
	{
		stV2.xX*=fNorm; stV2.xY*=fNorm;
 
		fNorm=FLOAT_RANGED_RANDOM(0.0f,1.5f); 
 
		Pos[0]+=-0.4f*stV2.xX+fNorm*Direction[0];
		Pos[1]+=-0.4f*stV2.xY+fNorm*Direction[1];
 
		fNorm=FLOAT_RANGED_RANDOM(0.0f,1.3f);  
		Pos2[0]+=0.4f*stV2.xX+fNorm*Direction[0];
		Pos2[1]+=0.4f*stV2.xY+fNorm*Direction[1];
 
		Pos[0]-=0.4f*stV2.xX;
		Pos[1]-=0.4f*stV2.xY;
		Pos2[0]+=0.4f*stV2.xX;
		Pos2[1]+=0.4f*stV2.xY;
		
 
#define ZVALUEFORSIDEPLOUFS 0.6f
 
		stV2.xZ=ZVALUEFORSIDEPLOUFS;
 
		/* We determine the normal vector using cross product :*/
 
 
		Direction[0]=-stV2.xZ*p_stDirection->xY;
		Direction[1]=stV2.xZ*p_stDirection->xX;
		Direction[2]=stV2.xX*p_stDirection->xY-stV2.xY*p_stDirection->xX;
	
		if (PloufDirect)
		{
			Direction[2]=-Direction[2];
			AGO_vCreatePart( (AGO_STILL | AGO_ORTHOPLAN | AGO_FOLLOWZ | AGO_SCALING_FAST |  AGO_SHADE_MEGAFAST),  Pos,   Direction, 200.0f, scale, scale, hVisualMaterial );
		}
		else
		{
			AGO_vCreatePart( (AGO_STILL | AGO_ORTHOPLAN | AGO_FOLLOWZ | AGO_SCALING_FAST |  AGO_SHADE_MEGAFAST),  Pos2,  Direction,  200.0f, scale, scale, hVisualMaterial );
		}
 
#undef ZVALUEFORSIDEPLOUFS
	}
#endif /* _FIRE_DEADCODE_U64_  */
}
 
 
 
void CreateType72AGO( MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3];
	int i;
	float scale;
	
	/* Copy_a3f_Array(Pos,p_stPosition); */
	Copy_a3f_Array(Direction,p_stDirection);
 
	for(i=0;i<3;i++)
	{
		float f;
 
		f=FLOAT_RANGED_RANDOM(0.05f,0.95f);
		Pos[0]=p_stPosition->xX+f*(p_stDirection->xX-p_stPosition->xX);
		Pos[1]=p_stPosition->xY+f*(p_stDirection->xY-p_stPosition->xY);
		Pos[2]=p_stPosition->xZ+f*(p_stDirection->xZ-p_stPosition->xZ);
		scale=FLOAT_RANGED_RANDOM(0.2f,1.0f);
		AGO_vCreatePart( AGO_STILL | AGO_SHADE_MEGAFAST  | AGO_SCALING_FASTEST,  Pos,  Direction,  parameter, scale, scale, hVisualMaterial );
	} 
}
 
void CreateType52AGO( MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3];
	float scale;
	int i;
 
	Copy_a3f_Array(Pos,p_stPosition);
	Copy_a3f_Array(Direction,p_stDirection);
 
	for(i=0;i<3;i++)
	{
		Pos[i]=((float *)p_stPosition)[i]+4.0f*((float *)p_stDirection)[i]+FLOAT_RANGED_RANDOM(-4.0f,4.0f)+0.3f*AGO_gExtraParameter1[i];
		Direction[i]=FLOAT_RANGED_RANDOM(-0.2f,0.2f)+AGO_gExtraParameter1[i];

		/*
		Pos[1]=p_stPosition->xY+4.0f*p_stDirection->xY+FLOAT_RANGED_RANDOM(-4.0f,4.0f)+0.3f*AGO_gExtraParameter1[1];
		Pos[2]=p_stPosition->xZ+4.0f*p_stDirection->xZ+FLOAT_RANGED_RANDOM(-4.0f,4.0f)+0.3f*AGO_gExtraParameter1[2];
		
		Direction[1]=FLOAT_RANGED_RANDOM(-0.2f,0.2f)+AGO_gExtraParameter1[1];
		Direction[2]=FLOAT_RANGED_RANDOM(-0.2f,0.2f)+AGO_gExtraParameter1[2];
		*/
	}

	scale=FLOAT_RANGED_RANDOM(0.40f,0.45f);
	AGO_vCreatePart( AGO_ZELDA |  AGO_MOVING |  AGO_TIMELIMITED,  Pos, Direction,  1.0f , scale, scale, hVisualMaterial );
}
 
 
void CreateType60AGO( MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3];
	int i;
	float scale;
 
	if (g_DoSmallPlouf) return;

	Copy_a3f_Array(Pos,p_stPosition);
	Copy_a3f_Array(Direction,p_stDirection);
 
	/*
	for(i=0;i<10;i++)
	{
		float a,b,c;
		a=FLOAT_RANGED_RANDOM(-0.2f,0.2f);
		b=FLOAT_RANGED_RANDOM(-0.4f,0.4f);
		c=FLOAT_RANGED_RANDOM(-0.4f,0.4f);
		Pos[1]+=b; Pos[0]+=c; Pos[2]+=a;
		scale=FLOAT_RANGED_RANDOM(0.2f,0.5f);
		** AGO_FALLING_SLOW
		AGO_vCreatePart( AGO_STILL | AGO_SHADE_FASTEST  | AGO_SCALING_SLOW,  Pos,  Direction,  parameter, scale, scale, hVisualMaterial );
		Pos[2]-=a; Pos[1]-=b; Pos[0]-=c;
	}
	*/
 
	for(i=0;i<10;i++)
	{
		Direction[0]=FLOAT_RANGED_RANDOM(-3.0f,3.0f);
		Direction[1]=FLOAT_RANGED_RANDOM(-3.0f,3.0f);
		Direction[2]=FLOAT_RANGED_RANDOM(2.0f,6.0f);
		scale=FLOAT_RANGED_RANDOM(0.03f,0.05f);
		AGO_vCreatePart( AGO_FALLING | AGO_SHADE_SLOW | AGO_ENDASPLOUF,  Pos,  Direction,  Pos[2], scale, scale, hVisualMaterial );
	}
 
}
 
void CreateType62AGO( MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3];
	int i;
	float scale;
	float time;
 
	Copy_a3f_Array(Pos,p_stPosition);
	Copy_a3f_Array(Direction,p_stDirection);
 
	for(i=0;i<10;i++)
	{
		Direction[0]=FLOAT_RANGED_RANDOM(-1.0f,1.0f);
		Direction[1]=FLOAT_RANGED_RANDOM(-1.0f,1.0f);
		Direction[2]=0.0f;
		scale=FLOAT_RANGED_RANDOM(0.01f,0.10f);
		if (g_DoSmallPlouf)
		{
			time=FLOAT_RANGED_RANDOM(0.2f,1.0f);
		}
		else
		{
			time=FLOAT_RANGED_RANDOM(1.0f,3.0f);
		}


		AGO_vCreatePart( AGO_MOVING | AGO_TIMELIMITED,  Pos,  Direction,  time, scale, scale, hVisualMaterial );
	}
}
 
 
void CreateType35AGO(  MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3];
	MTH3D_tdstVector stV1,stV2,stV3;
	float Mul1,Mul2;
	float cos1,sin1;
 
	/******************************/
	/* */
 
	stV3.xX=p_stPosition->xX-p_stDirection->xX;
	stV3.xY=p_stPosition->xY-p_stDirection->xY;
	stV3.xZ=p_stPosition->xZ-p_stDirection->xZ;

	Mul1=stV3.xX*stV3.xX+stV3.xY*stV3.xY+stV3.xZ*stV3.xZ;
	Mul1=MTH_M_xInvSqrt(Mul1);
	stV3.xX*=Mul1;
	stV3.xY*=Mul1;
	stV3.xZ*=Mul1;

	AGO_Define_OrthogonalVectors(&stV3, &stV1, &stV2);

	Mul1=FLOAT_RANGED_RANDOM(-6.28f,6.28f);

	cos1=COSINUS(Mul1);
	sin1=SINUS(Mul1);

	stV3.xX=cos1*stV1.xX + sin1*stV2.xX;
	stV3.xY=cos1*stV1.xY + sin1*stV2.xY;
	stV3.xZ=cos1*stV1.xZ + sin1*stV2.xZ;

	Mul2=stV3.xX*stV3.xX+stV3.xY*stV3.xY+stV3.xZ*stV3.xZ;
	if ((Mul2<1.0f) && (AGO_g_OddFrame))
	{
		Mul2*=parameter;
	}
	else
	{
		Mul2=MTH_M_xInvSqrt(Mul2)*parameter;
	}
	Pos[0]=p_stDirection->xX+Mul2*stV3.xX; 
	Pos[1]=p_stDirection->xY+Mul2*stV3.xY; 
	Pos[2]=p_stDirection->xZ+Mul2*stV3.xZ;
	Direction[0]=p_stPosition->xX; Direction[1]=p_stPosition->xY; Direction[2]=p_stPosition->xZ;

	AGO_vCreatePart( AGO_REMANANCE | AGO_GOINGTO ,  Pos,  Direction,  2.0f , 0.9f, 0.9f, hVisualMaterial );
 
 
}
 
void CreateType15AGO(  MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3], scale;
	int i,j;
	float offset,offset2;
	for(i=8;i;i--)
	{
		g_AGO_AnimTimeScale=FLOAT_RANGED_RANDOM(0.2f,3.0f);
		offset=FLOAT_RANGED_RANDOM(-0.5f,0.8f);
		offset2=FLOAT_RANGED_RANDOM(0.5f,2.2f)*parameter;
		scale=FLOAT_RANGED_RANDOM(0.8f,1.5f);
		/*
		Direction[0]=p_stDirection->xX*offset2; 
		Direction[1]=p_stDirection->xY*offset2; 
		Direction[2]=p_stDirection->xZ*offset2;
		Pos[0]=p_stPosition->xX+offset*p_stDirection->xX;
		Pos[1]=p_stPosition->xY+offset*p_stDirection->xY;
		Pos[2]=p_stPosition->xZ+offset*p_stDirection->xZ;
		*/

		for(j=0;j<3;j++)
		{
			Direction[j]=((float *)p_stDirection)[j]*offset2;
			Pos[j]=((float *)p_stPosition)[j]+offset*((float *)p_stDirection)[j];
		}

		AGO_vCreatePart( AGO_MOVING_AND_SLOWING | AGO_SHADE_FAST,  Pos,  Direction,  offset2 , scale, scale, hVisualMaterial );
	}
}


void CreateType158AGO(  MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3], scale;
	int i, j;
	float offset2;

	/*p_stPosition->xZ+=2.0f; */
	/* parameter=0.3f; */
	
	for(i=8;i;i--)
	{
		g_AGO_AnimTimeScale=FLOAT_RANGED_RANDOM(0.2f,3.0f);
		offset2=FLOAT_RANGED_RANDOM(4.0f,6.5f);
		scale=parameter;

		/*
		Direction[0]=p_stDirection->xX*offset2+p_stDirection->xX*FLOAT_RANGED_RANDOM(-1.5f,1.5f);
		Direction[1]=p_stDirection->xY*offset2+p_stDirection->xY*FLOAT_RANGED_RANDOM(-1.5f,1.5f);
		Direction[2]=p_stDirection->xZ*offset2+p_stDirection->xZ*FLOAT_RANGED_RANDOM(-1.5f,1.5f);
		Pos[0]=p_stPosition->xX+FLOAT_RANGED_RANDOM(0.0f,0.3f)*p_stDirection->xZ;
		Pos[1]=p_stPosition->xY+FLOAT_RANGED_RANDOM(0.0f,0.3f)*p_stDirection->xY;
		Pos[2]=p_stPosition->xZ+FLOAT_RANGED_RANDOM(0.0f,0.3f)*p_stDirection->xZ;
		*/

		for(j=0;j<3;j++)
		{
			Direction[j]=((float *)p_stDirection)[j]*offset2+((float *)p_stDirection)[j]*FLOAT_RANGED_RANDOM(-1.5f,1.5f);
			Pos[j]=((float *)p_stPosition)[j]+FLOAT_RANGED_RANDOM(0.0f,0.3f)*((float *)p_stDirection)[j];
		}

		AGO_vCreatePart( AGO_MOVING /*_AND_SLOWING */ | AGO_SHADE_MID | AGO_SCALING_SLOW,  Pos,  Direction,  offset2 , scale, scale, hVisualMaterial );
	}
}

 
void CreateType21AGO(  MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
 
{
	float Pos[3];
	float Direction[3];
	int i;
	int j;
	static float Offset=0.0f;
	float fTemp;

	fTemp=1.0f/parameter;

	for(j=0;j<3;j++)
	{
		Direction[j]=(((float *)p_stDirection)[j]-((float *)p_stPosition)[j])*fTemp;
	}
	for(i=0;i<parameter;i++)
	{
		AGO_Part *p;
		
		for(j=0;j<3;j++)
		{
			Pos[j]=((float *)p_stPosition)[j]+((float)i+Offset)*Direction[j];
		}
		p=AGO_vCreatePart( AGO_STILL |  AGO_SHADE_TWOFRAMES,  Pos,  NULL,  2.0f , 0.7f, 0.7f, hVisualMaterial);
		if (p) p->Transparency=400.0f;
	}
	Offset+=6.123456f*g_fTimeDifference;
	while (Offset>=1.0f) Offset-=1.0f;
}
 
 
#ifdef __CETTE_FONCTION_N_EST_QU_UN_PROTO_KI_SERT_A_RIEN__
 
void CreateTypeXAGO(  MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3];
 
	Copy_a3f_Array(Pos,p_stPosition);
	Copy_a3f_Array(Direction,p_stDirection);
 
	AGO_vCreatePart( AGO_STILL |  AGO_SHADE_TWOFRAMES,  Pos,  NULL,  2.0f , 0.7f, 0.7f, hVisualMaterial);
}
 
#endif /* __CETTE_FONCTION_N_EST_QU_UN_PROTO_KI_SERT_A_RIEN__ */
 
void CreateType65AGO(  MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3];
	float scale;
 
	/* LIMIT_AGO_TO_EVERY(0.01f);*/
 
	Copy_a3f_Array(Pos,p_stPosition);
	Copy_a3f_Array(Direction,p_stDirection);
 
	Direction[0]=0.0f;
	Direction[1]=1.0f;
	Direction[2]=0.0f;
 
	/* scale=FLOAT_RANGED_RANDOM(0.030f,0.110f);*/
	/*scale=FLOAT_RANGED_RANDOM(0.150f,0.250f);*/
	scale=FLOAT_RANGED_RANDOM(0.100f,0.150f);
 
	AGO_vCreatePart( AGO_2DSPIRALE,  Pos,  Direction,  3.0f*parameter , scale, scale, hVisualMaterial);
}
 
/* Heat Effet + Holbe*/
void CreateType28AGO(  MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3];
	float scale;
 
	LIMIT_AGO_TO_EVERY(0.05f);
	Pos[0]=p_stPosition->xX+8.0f*p_stDirection->xX+FLOAT_RANGED_RANDOM(-4.0f,4.0f);
	Pos[1]=p_stPosition->xY+8.0f*p_stDirection->xY+FLOAT_RANGED_RANDOM(-4.0f,4.0f);
	Pos[2]=p_stPosition->xZ+8.0f*p_stDirection->xZ+FLOAT_RANGED_RANDOM(-5.0f,-4.0f);
	/*scale=FLOAT_RANGED_RANDOM(0.12f,0.19f);*/
	/* parameter=2.0f; */
	scale=FLOAT_RANGED_RANDOM(parameter*0.20f,parameter*0.25f);
	Direction[0]=FLOAT_RANGED_RANDOM(-0.2f,0.2f);
	Direction[1]=FLOAT_RANGED_RANDOM(-0.2f,0.2f);
	Direction[2]=FLOAT_RANGED_RANDOM(2.5f,4.5f);
	AGO_vCreatePart( AGO_ZELDA |  AGO_MOVINGSINXYUP |  AGO_APPEAR,  Pos,  Direction,  0.5f , scale, scale, hVisualMaterial );
 
}
 
void CreateType67AGO(  MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3];
	float scale;
 
	LIMIT_AGO_TO_EVERY(0.05f);
	Pos[0]=p_stPosition->xX+8.0f*p_stDirection->xX+2.0f*FLOAT_RANGED_RANDOM(-4.0f,4.0f);
	Pos[1]=p_stPosition->xY+8.0f*p_stDirection->xY+2.0f*FLOAT_RANGED_RANDOM(-4.0f,4.0f);
	Pos[2]=p_stPosition->xZ+8.0f*p_stDirection->xZ+2.0f*FLOAT_RANGED_RANDOM(-5.0f,-4.0f);
	/*scale=FLOAT_RANGED_RANDOM(0.12f,0.19f);*/
	/* parameter=2.0f;*/
	scale=FLOAT_RANGED_RANDOM(parameter*0.10f,parameter*0.15f);
	Direction[0]=FLOAT_RANGED_RANDOM(-0.2f,0.2f);
	Direction[1]=FLOAT_RANGED_RANDOM(-0.2f,0.2f);
	Direction[2]=FLOAT_RANGED_RANDOM(2.5f,4.5f);
	AGO_vCreatePart( AGO_ENDASPLOUF | AGO_ZELDA |  AGO_MOVINGSINXYUP |  AGO_APPEAR,  Pos,  Direction,  0.5f , scale, scale, hVisualMaterial );
 
}

void CreateType83AGO(  MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3];
	float scale;
 
	LIMIT_AGO_TO_EVERY(0.05f);
	Pos[0]=p_stPosition->xX+5.0f*p_stDirection->xX+2.0f*FLOAT_RANGED_RANDOM(-2.0f,2.0f);
	Pos[1]=p_stPosition->xY+5.0f*p_stDirection->xY+2.0f*FLOAT_RANGED_RANDOM(-2.0f,2.0f);
	Pos[2]=p_stPosition->xZ+5.0f*p_stDirection->xZ-4.0f;
	/*scale=FLOAT_RANGED_RANDOM(0.12f,0.19f);*/
	/* parameter=2.0f;*/
	scale=FLOAT_RANGED_RANDOM(parameter*0.20f,parameter*0.25f);
	Direction[0]=FLOAT_RANGED_RANDOM(-0.2f,0.2f);
	Direction[1]=FLOAT_RANGED_RANDOM(-0.2f,0.2f);
	Direction[2]=FLOAT_RANGED_RANDOM(2.5f,4.5f);
	AGO_vCreatePart( AGO_ZELDA |  AGO_MOVINGSINXY |  AGO_APPEAR,  Pos,  Direction,  0.5f , scale, scale, hVisualMaterial );
 
}


void CreateType104AGO( MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3];
	int i;
 
	Copy_a3f_Array(Pos,p_stPosition);
	Copy_a3f_Array(Direction,p_stDirection);
 
	for(i=0;i<10;i++)
	{
		Direction[0]=FLOAT_RANGED_RANDOM(-1.0f,1.0f);
		Direction[1]=FLOAT_RANGED_RANDOM(-1.0f,1.0f);
		Direction[2]=0.0f;
		AGO_vCreatePart( AGO_FALLING | AGO_TIMELIMITED,  Pos,  Direction,  FLOAT_RANGED_RANDOM(1.0f,3.0f), 0.0f, 0.0f, hVisualMaterial );
	}
 
}



int AGO_CompareVector(float *v1, float *v2)
{
	int i;

	for(i=0;i<3;i++)
	{
		if (v1[i]!=v2[i]) return 0;
	}
	return 1;
}
 
void AGO_vTransformHandVector(float *Position, float *Direction)
{
	float other[3];
	Position[0]+=Direction[0]*0.13f;
	Position[1]+=Direction[1]*0.13f;
	Position[2]+=Direction[2]*0.1f+0.2f;
 
	
	other[0]=Direction[1];
	other[1]=-Direction[0];
	other[2]=0.0f;
	Position[0]+=0.3f*other[0];
	Position[1]+=0.3f*other[1];
	
}



void AGO_vAddParticleContd(unsigned long PartType,
					  MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter);



void AGO_vAddParticle(unsigned long PartType,
					  MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3];
	int i;
	float scale;

	g_AGO_AnimTimeScale=1.0f;
 
	Copy_a3f_Array(Pos,p_stPosition);
	Copy_a3f_Array(Direction,p_stDirection);

	switch(PartType)
	{

		/************************************************/
		/* Nuage de fumée simple                        */
		/* LanceAGO(1,Position, rien, Materiau, Taille) */
		/************************************************/
		case 1: 
			parameter+=1.0f;
			AGO_vCreatePart( AGO_STILL |  AGO_TIMELIMITED,  Pos,  NULL,  2.0f , parameter, parameter, hVisualMaterial );
		break;

		case 2: 
			parameter+=1.0f;
			AGO_vCreatePart( AGO_STILL |  AGO_TIMELIMITED,  Pos,  NULL,  Direction[0] , parameter, parameter, hVisualMaterial );
		break;
 
 
		/***************************************************************/
		/* Nuages de fumée pour la naissance de l'obus                 */
		/* LanceAGO(5,Position Obus, rien, "AGO_Fumee", 1.0)           */
		/***************************************************************/
		case 5:
			CreateType5AGO(p_stPosition,p_stDirection,hVisualMaterial,parameter);
		break;
 
		/*************************************************************************/
		/* Ondes (ploufs) de raymond 1                                           */
		/* Petite astuce : Direction->xX = Transparence initiale (0.0 -> 255.0)  */
		/* Petite astuce : Direction->xZ = Taille (Par défaut : 1.0)             */
		/*************************************************************************/
		case 7:
			g_AGO_PloufMaterial=hVisualMaterial;

			{
				g_ffFrameTime=AGO_fGetTimeInSeconds();
				if (g_fNextPlouf==0.0f) g_fNextPlouf=g_ffFrameTime;
				if (g_fNextPlouf>g_ffFrameTime) return;
				g_fNextPlouf=g_ffFrameTime+0.2f;
			}

			/* LIMIT_AGO_TO_EVERY(0.2f); */
 
			if (Direction[0]>300) Direction[0]=250;

			if (g_DoSmallPlouf)
			{
				AGO_vCreatePart( AGO_RAYMAN_SMALL_PLOUF ,  Pos,  Direction,  Direction[0], Direction[2], Direction[2], hVisualMaterial);		
			}
			else
			{
				AGO_vCreatePart( AGO_RAYMAN_PLOUF ,  Pos,  Direction,  Direction[0], Direction[2], Direction[2], hVisualMaterial);		
			}
		break;
		/***************************************************************/
 
		/***************************************************************/
		/* Ondes du ski nautique                                       */
		/* Vecteur Position                                            */
		/* Vecteur Directeur                                           */
		/***************************************************************/
		case 8:
			CreateType8AGO(p_stPosition,p_stDirection,hVisualMaterial,parameter);
		break;
		/***************************************************************/
 
 
		/***************************************************************/
		/* REBOND DU POINT*/
		/***************************************************************/
		case 9:
		{
			scale=FLOAT_RANGED_RANDOM(0.5f,0.8f);
			AGO_vCreatePart( AGO_STILL | AGO_SHADE_FASTEST | AGO_UNSCALING_FAST,  Pos,  NULL,  parameter, scale, scale, hVisualMaterial );
			for(i=8;i;i--)
			{
				Direction[0]=FLOAT_RANGED_RANDOM(-2.0f,2.0f); 
				Direction[1]=FLOAT_RANGED_RANDOM(-2.0f,2.0f); 
				Direction[2]=FLOAT_RANGED_RANDOM(-0.2f,6.0f);
				scale=FLOAT_RANGED_RANDOM(0.19f,0.35f);
				AGO_vCreatePart( AGO_FALLING | AGO_SHADE_FAST,  Pos,  Direction,  parameter, scale, scale, hVisualMaterial );
			}
		}
		break;
		/***************************************************************/

		
		
 
 
		/***************************************************************/
		/* TRAINEE DU POINT*/
		/***************************************************************/
		case 10:
		{
			LIMIT_AGO_TO_EVERY(0.1f);
			Direction[0]=0.0f;  Direction[1]=0.0f;  Direction[2]=0.0f;
			scale=0.40f;
			AGO_vCreatePart( AGO_FALLING_SLOW | AGO_UNSCALING_SLOW | AGO_SHADE_SLOW ,  Pos,  Direction, parameter, scale, scale, hVisualMaterial );
		}
		break;
		/***************************************************************/
 
 
 
		/***************************************************************/
		/* Nuages circulaires de fumée pour une apparition (Explosion)*/
		/***************************************************************/
		/**/
		/* Arg1 = position*/
		/* Arg2 = Vecteur -> [0] = Rayon, [1] = Nb Particules*/
		/**/
		case 11:
			{
				float fRadius= p_stDirection->xX;
				float cos1,sin1;
				int Number= (int)p_stDirection->xY;
 
				for(i=0;i<Number;i++)
				{
					float angle=((float)i)*6.28f/((float)Number);
 
					cos1=COSINUS(angle);
					sin1=SINUS(angle);
					g_AGO_AnimTimeScale=FLOAT_RANGED_RANDOM(0.2f,3.0f);
					Pos[0]=p_stPosition->xX+fRadius*cos1; Pos[1]=p_stPosition->xY+fRadius*sin1; Pos[2]=p_stPosition->xZ;
					Direction[0]=fRadius*cos1; Direction[1]=fRadius*sin1; Direction[2]=1.53f;
					scale=FLOAT_RANGED_RANDOM(0.2f,1.2f); 
					AGO_vCreatePart( AGO_APPARITION_FUMEE ,  Pos,  Direction,  parameter, scale, scale, hVisualMaterial );
				}
			}
		break;
		/***************************************************************/
 
 
		/***************************************************************/
		/* "Bouche à Feu" (Mic Janod)*/
		/***************************************************************/
		/**/
		/* Arg1 = position*/
		/* Arg2 = Vecteur Directeur*/
		/* Arg3 = Materiau*/
		/* Arg4 = Vitesse*/
		/**/
		case 15:
			{
				CreateType15AGO(p_stPosition,p_stDirection,hVisualMaterial,parameter);
			}
		break;
		/***************************************************************/

		/***************************************************************/
		/* Gerbes du Ski nautique*/
		/* Memes parametres que le type 8*/
		/***************************************************************/
		case 16:
			CreateType16AGO(p_stPosition,p_stDirection,hVisualMaterial,parameter);
		break;
		/***************************************************************/

 
		/***************************************************************/
		/* MEGA-TIR*/
		/* Arg1 = position*/
		/* Arg2 = Vecteur Directeur du tir*/
		/* Arg3 = Materiau*/
		/* Arg4 = unused*/
		/***************************************************************/
		case 19:
		{
			float fNorm;
			/* Test if normal vector is null*/
			fNorm=p_stDirection->xX*p_stDirection->xX+p_stDirection->xY*p_stDirection->xY+p_stDirection->xZ*p_stDirection->xZ;
			if (fNorm<=0.001f) return;
			fNorm=MTH_M_xInvSqrt(fNorm);
			p_stDirection->xX*=fNorm; p_stDirection->xY*=fNorm; p_stDirection->xZ*=fNorm;
			/* Direction = normal vector*/
			Copy_a3f_Array(Direction,p_stDirection);
			scale=0.5f;
			AGO_vCreatePart( AGO_STILL | AGO_ORTHOPLAN | AGO_SCALING_SLOW | AGO_SHADE_MID ,  Pos,  Direction, parameter, scale, scale, hVisualMaterial );
		}
		break;
		/***************************************************************/
 
		/***************************************************************/
		/* MEGA-TIR TRES RAPIDE (BOSS_RHOP)*/
		/* Arg1 = position*/
		/* Arg2 = Vecteur Directeur du tir*/
		/* Arg3 = Materiau*/
		/* Arg4 = unused*/
		/***************************************************************/
		case 20:
		{
			float fNorm;
			/* Test if normal vector is null*/
			fNorm=p_stDirection->xX*p_stDirection->xX+p_stDirection->xY*p_stDirection->xY+p_stDirection->xZ*p_stDirection->xZ;
			if (fNorm<=0.001f) return;
			fNorm=MTH_M_xInvSqrt(fNorm);
			p_stDirection->xX*=fNorm; p_stDirection->xY*=fNorm; p_stDirection->xZ*=fNorm;
			/* Direction = normal vector*/
			Copy_a3f_Array(Direction,p_stDirection);
			scale=0.5f;
			AGO_vCreatePart( AGO_STILL | AGO_ORTHOPLAN | AGO_SCALING_FASTEST | AGO_SHADE_MEGAFAST ,  Pos,  Direction, parameter, scale, scale, hVisualMaterial );
		}
		break;
		/***************************************************************/
 
		/***************************************************************/
		/* Faisceau*/
		/***************************************************************/
		/* Arg2 = Position Rayman*/
		/* Arg3 = Position Lumsx*/
		/* Arg5 = Number of particles*/
		/***************************************************************/
		case 21:
		{
				CreateType21AGO(p_stPosition,p_stDirection,hVisualMaterial,parameter);
		}
		break;
 
 
		/***************************************************************/
		/* Magic*/
		/***************************************************************/
		/* Arg2 = Position centre*/
		/* Arg5 = Rayon*/
		/***************************************************************/
 
		case 23:
		{
			/* LIMIT_AGO_TO_EVERY(0.05f);*/
			/* We save the center in the direction*/
 
			AGO_vTransformHandVector(Pos,Direction);
			Copy_a3f_Array(Direction,p_stPosition);
			/* We define the position randomly according to the Rotation Angles*/
			
			scale=FLOAT_RANGED_RANDOM(0.10f,0.15f);
			/* AGO_vCreatePart( AGO_ROTATING_SLOW |  AGO_SHADE_SLOW,  Pos,  Direction,  parameter , scale, scale, hVisualMaterial);*/
			/* AGO_vCreatePart( AGO_ROTATING_SLOW |  AGO_SHADE_SLOW  | AGO_APPEAR  ,  Pos,  Direction,  parameter, scale, scale, hVisualMaterial);*/

			for(i=0;i<3;i++) Pos[i]=Direction[i]+FLOAT_RANGED_RANDOM(-1.0f,1.0f);

			/*
				Pos[0]=Direction[0]+FLOAT_RANGED_RANDOM(-1.0f,1.0f);
				Pos[1]=Direction[1]+FLOAT_RANGED_RANDOM(-1.0f,1.0f);
				Pos[2]=Direction[2]+FLOAT_RANGED_RANDOM(-1.0f,1.0f);
			*/
 
			AGO_vCreatePart( AGO_FASEGOINGTO ,  Pos,  Direction,  parameter , scale, scale, hVisualMaterial);
			
 
			break;
		}
		break;

		/***************************************************************/
		/* ZLimited "Bubbles"*/
		/***************************************************************/
		/**/
		/* Arg1 = position*/
		/* Arg2 = Vecteur Directeur*/
		/* Arg3 = Materiau*/
		/* Arg4 = Z limit */
		/**/
		case 26:
			{
				LIMIT_AGO_TO_EVERY(FLOAT_RANGED_RANDOM(0.0f,0.5f));

				if (Pos[2]<parameter) return;
 
				if (Pos[2]-parameter>20.0f) parameter=Pos[2]+20.0f;

				scale=FLOAT_RANGED_RANDOM(0.02f,0.1f);
				Direction[0]=FLOAT_RANGED_RANDOM(-1.0f,1.0f);
				Direction[1]=FLOAT_RANGED_RANDOM(-1.0f,1.0f);
				Direction[2]=FLOAT_RANGED_RANDOM(1.0f,4.0f);
				AGO_vCreatePart( AGO_MOVINGSINXY |  AGO_ZLIMITED | AGO_SCALING_MEGASLOW,  Pos,  Direction,  parameter , scale, scale, hVisualMaterial );
 
				/* more bubbles by Christophe giraud...*/
				Pos[1]+=0.2f; Pos[2]+=0.2f;
				if (Pos[2]<parameter)
					AGO_vCreatePart( AGO_MOVINGSINXY |  AGO_ZLIMITED | AGO_SCALING_MEGASLOW,  Pos,  Direction,  parameter , scale, scale, hVisualMaterial );
                Pos[1]-=0.5f; Pos[2]+=0.1f;
				if (Pos[2]<parameter)
					AGO_vCreatePart( AGO_MOVINGSINXY |  AGO_ZLIMITED | AGO_SCALING_MEGASLOW,  Pos,  Direction,  parameter , scale, scale, hVisualMaterial );
				/* end more bubbles by Christophe giraud...*/
				
			}
		break;
		/***************************************************************/

		/***************************************************************/
		/* "Bubbles"*/
		/***************************************************************/
		/**/
		/* Arg1 = position*/
		/* Arg2 = Vecteur Directeur*/
		/* Arg3 = Materiau*/
		/* Arg4 = Duree*/
		/**/
		case 27:
			{
				LIMIT_AGO_TO_EVERY(FLOAT_RANGED_RANDOM(0.0f,0.5f));

				if (parameter>7.0f) parameter=7.0f;
 
				scale=FLOAT_RANGED_RANDOM(0.02f,0.1f);
				Direction[0]=FLOAT_RANGED_RANDOM(-1.0f,1.0f);
				Direction[1]=FLOAT_RANGED_RANDOM(-1.0f,1.0f);
				Direction[2]=FLOAT_RANGED_RANDOM(2.0f,4.0f);
				AGO_vCreatePart( AGO_MOVINGSINXY |  AGO_TIMELIMITED | AGO_SCALING_MEGASLOW,  Pos,  Direction,  parameter , scale, scale, hVisualMaterial );
 
				/* more bubbles by Christophe giraud...*/
				Pos[1]+=0.2f; Pos[2]+=0.2f;
                AGO_vCreatePart( AGO_MOVINGSINXY |  AGO_TIMELIMITED | AGO_SCALING_MEGASLOW,  Pos,  Direction,  parameter , scale, scale, hVisualMaterial );
                Pos[1]-=0.5f; Pos[2]+=0.1f;
                AGO_vCreatePart( AGO_MOVINGSINXY |  AGO_TIMELIMITED | AGO_SCALING_MEGASLOW,  Pos,  Direction,  parameter , scale, scale, hVisualMaterial );
				/* end more bubbles by Christophe giraud...*/
				
			}
		break;
		/***************************************************************/
 
		/***************************************************************/
		/* "Plancton" (Zelda effect moving up !)*/
		/***************************************************************/
		/**/
		case 28:
			{
				CreateType28AGO(p_stPosition,p_stDirection,hVisualMaterial,parameter);
			}
		break;
		/***************************************************************/
 
 
		/***************************************************************/
		/* "Plancton" (Zelda effect)*/
		/***************************************************************/
		/**/
		case 29:
			{
				for(i=0;i<3;i++)
				{
					Pos[i]=((float *)p_stPosition)[i]+8.0f*((float *)p_stDirection)[i]+FLOAT_RANGED_RANDOM(-4.0f,4.0f);
					Direction[i]=FLOAT_RANGED_RANDOM(-0.5f,0.5f);
				}

				/*
				Pos[0]=p_stPosition->xX+8.0f*p_stDirection->xX+FLOAT_RANGED_RANDOM(-4.0f,4.0f);
				Pos[1]=p_stPosition->xY+8.0f*p_stDirection->xY+FLOAT_RANGED_RANDOM(-4.0f,4.0f);
				Pos[2]=p_stPosition->xZ+8.0f*p_stDirection->xZ+FLOAT_RANGED_RANDOM(-4.0f,4.0f);
				
				Direction[0]=FLOAT_RANGED_RANDOM(-0.5f,0.5f);
				Direction[1]=FLOAT_RANGED_RANDOM(-0.5f,0.5f);
				Direction[2]=FLOAT_RANGED_RANDOM(-0.5f,0.5f);
				*/

				scale=FLOAT_RANGED_RANDOM(0.12f,0.19f);
				AGO_vCreatePart( AGO_ZELDA |  AGO_MOVINGSINXY |  AGO_APPEAR,  Pos,  Direction,  0.5f , scale, scale, hVisualMaterial );
			}
		break;
		/***************************************************************/
 
	
		/***************************************************************/
		/* Seat effect*/
		/* Seat Position*/
		/* rien, ... , nombre de particules*/
		/***************************************************************/
		case 30:
		{
			scale=FLOAT_RANGED_RANDOM(0.5f,0.8f);
			AGO_vCreatePart( AGO_STILL | AGO_SHADE_FASTEST | AGO_UNSCALING_FAST,  Pos,  NULL,  parameter, scale, scale, hVisualMaterial );
			for(i=parameter;i;i--)
			{
				Direction[0]=FLOAT_RANGED_RANDOM(-2.0f,2.0f); 
				Direction[1]=FLOAT_RANGED_RANDOM(-2.0f,2.0f); 
				Direction[2]=FLOAT_RANGED_RANDOM(-0.2f,3.0f);
				scale=FLOAT_RANGED_RANDOM(0.10f,0.15f);
				AGO_vCreatePart( AGO_FALLING | AGO_SHADE_FAST,  Pos,  Direction,  parameter, scale, scale, hVisualMaterial );
			}
		}
		break;
 
 
		/***************************************************************/
		/* Spiral effect*/
		/* Position*/
		/***************************************************************/
		case 31:
		{
			LIMIT_AGO_TO_EVERY(0.5f);
 
			Direction[0]=FLOAT_RANGED_RANDOM(-2.0f,2.0f); 
			Direction[1]=FLOAT_RANGED_RANDOM(-2.0f,2.0f); 
			Direction[2]=FLOAT_RANGED_RANDOM(0.0f,6.0f);
			scale=FLOAT_RANGED_RANDOM(0.35f,0.65f);
			AGO_vCreatePart( AGO_SPIRALE | AGO_SHADE_SLOW,  Pos,  Direction,  parameter, scale, scale, hVisualMaterial );			
		}
		break;
 
		/***************************************************************/
		/* FireWall effect (too slow to be used)*/
		/* Position*/
		/* Normal*/
		/* GMT*/
		/* Size*/
		/***************************************************************/
		case 33:
		{
			scale=FLOAT_RANGED_RANDOM(-parameter,parameter);
			Pos[0]-=scale*p_stDirection->xY;
			Pos[1]+=scale*p_stDirection->xX;
			AGO_vCreatePart( AGO_STILL |  AGO_SHADE_FAST,  Pos,  NULL,  2.0f , 2.0f, 2.0f, hVisualMaterial );
		}
		break;
 
		/***************************************************************/
		/* Aspiration effect*/
		/* Position (destination)*/
		/* Center of the Origin*/
		/* GMT*/
		/* Size of the origin circle*/
		/***************************************************************/
		case 35:
		{
			CreateType35AGO(p_stPosition,p_stDirection,hVisualMaterial,parameter);
		}
		break;
 
		/**/
		/* Plouf gerbe*/
		/**/
		case 39:
			{
				scale=p_stDirection->xY*0.5f;
				/* scale=0.8f;*/
				/*AGO_vCreatePart( AGO_STILL | AGO_SCALING_MEGAFASTY   | AGO_BASEDSCALE | AGO_SHADE_FAST,  Pos,  NULL,  0.01f , scale, scale, hVisualMaterial );*/
				AGO_vCreatePart( AGO_STILL | AGO_SCALING_SLOW | AGO_BASEDSCALE | AGO_SHADE_SLOW,  Pos,  NULL,  0.01f , scale, scale, hVisualMaterial );
			}
			break;
 
		/**/
		/* GAZ TOXIQUE*/
		/**/
		case 42:
			{
				g_AGO_AnimTimeScale=FLOAT_RANGED_RANDOM(0.7f,1.8f);
				scale=FLOAT_RANGED_RANDOM(0.2f,0.8f);
				Pos[0]+=FLOAT_RANGED_RANDOM(-1.0f,1.0f);
				Pos[1]+=FLOAT_RANGED_RANDOM(-1.0f,1.0f);
				Direction[0]=FLOAT_RANGED_RANDOM(-0.2f,0.2f);
				Direction[1]=FLOAT_RANGED_RANDOM(-0.2f,0.2f);
				Direction[2]=FLOAT_RANGED_RANDOM(1.0f,2.0f);
				AGO_vCreatePart( AGO_MOVING | AGO_SCALING_SLOW,  Pos,  Direction,  0.01f , scale, scale, hVisualMaterial );
			}
			break;
 
		/***************************************************/
		/* Explosion : Particles*/
		/***************************************************/
		case 45: 
			{
 				for(i=9;i;i--)
				{
					Direction[0]=FLOAT_RANGED_RANDOM(-2.0f*parameter,2.0f*parameter);
					Direction[1]=FLOAT_RANGED_RANDOM(-2.0f*parameter,2.0f*parameter);
					Direction[2]=FLOAT_RANGED_RANDOM(-0.2f*parameter,6.0f*parameter);
					scale=FLOAT_RANGED_RANDOM(0.8f*parameter,0.16f*parameter);
					AGO_vCreatePart( AGO_FALLING | AGO_SHADE_MID  | AGO_UNSCALING_FAST ,  Pos,  Direction,  parameter, scale, scale, hVisualMaterial );
				}
			}
			break;
 
		/***************************************************/
		/* Explosion : Smoke*/
		/***************************************************/
		case 46:
			{
 				g_AGO_AnimTimeScale=0.7f;
				AGO_vCreatePart( AGO_STILL | AGO_SCALING_SLOW,  Pos,  NULL,  0.01f , 0.5f*parameter, 0.5f*parameter, hVisualMaterial );
				Pos[0]+=FLOAT_RANGED_RANDOM(-2.0f*parameter,2.0f*parameter);
				Pos[1]+=FLOAT_RANGED_RANDOM(-2.0f*parameter,2.0f*parameter);
				g_AGO_AnimTimeScale=1.25f;
				AGO_vCreatePart( AGO_STILL | AGO_SCALING_SLOW,  Pos,  NULL,  0.01f , 0.5f*parameter, 0.5f*parameter, hVisualMaterial );
 
			}
			break;
 
		/***************************************************/
		/* Explosion : Big explosion*/
		/***************************************************/
		case 47:
			{
 				AGO_vCreatePart( AGO_STILL | AGO_SCALING_FASTEST | AGO_SHADE_TWOFRAMES,  Pos,  NULL,  0.01f , parameter, parameter, hVisualMaterial );
 			}
			break;
 
		/***************************************************/
		/* Explosion : Nuclear effect*/
		/***************************************************/
		case 48:
			{
				if (parameter>=9.0f)
				{
					AGO_vCreatePart( AGO_STILL | AGO_XYPLAN | AGO_SCALING_FASTEST |  AGO_SHADE_MID,  Pos,  NULL,  0.1f , parameter*0.7f, parameter*0.7f, hVisualMaterial );
				}
				else
				{
					AGO_vCreatePart( AGO_STILL | AGO_XYPLAN | AGO_SCALING_FASTEST |  AGO_SHADE_FAST,  Pos,  NULL,  0.1f , 0.05f*parameter, 0.05f*parameter, hVisualMaterial );
				}
				// g_bForceWhiteFog=1;
 
			}
			break;
 
		/* Explosion Manga (PAF)*/
		case 49:
			{
				AGO_Part *p;
				/* if (g_ulNumberOfAgos==AGO_MAX_NUMBER_OF_AGOS) return; */
				// p=&(g_AGO[g_ulNumberOfAgos]);
				p=AGO_vCreatePart( AGO_STILL | AGO_SCALING_XTOY | AGO_SHADE_MEGAFAST,  Pos,  NULL,  255.0f , 0.7f*parameter, 0.7f*parameter, hVisualMaterial );
				if (p) p->Transparency=300.0f;
			}
			break;
 
		case 50:
			{
				Copy_a3f_Array(AGO_gExtraParameter1,Pos);
				Copy_a3f_Array(AGO_gExtraParameter2,Direction);
/* XB 10/06/99 */
#ifdef INFODESIGN_RESEARCH
				AGO_gExtraFloatParameter=parameter;
#endif /* INFODESIGN_RESEARCH */
/* End XB 10/06/99 */

				AGO_gExtraMaterial=hVisualMaterial;
			}
		break;
 
		/* Lasers*/
		case 51:
			{
				AGO_Part *p; 
				p=AGO_vCreatePart(AGO_STILL | AGO_REMANANCE2 | AGO_SHADE_MEGAFAST,  Pos,  NULL,  0.1f , 1.0f, 1.0f, hVisualMaterial );
				if (p) for(i=0;i<3;i++) p->a3_fInitialPosition[i]=Direction[i];
			}
			break;
 
		
 
		/***************************************************************/
		/* "Gone with the Wind"                                        */
		/* LanceAGO(50,Direction du vent, ..)
		/* LanceAGO(52,Pos Camera, Direct Camera, Mat, ....)
		/***************************************************************/
		case 52:
			{
				CreateType52AGO(p_stPosition,p_stDirection,hVisualMaterial,parameter);
			}
		break;
 
		/**************************************************************/
		/* etoile : Particules qui partent dans toutes les directions */
		/*										                      */
		/* parameter = vitesse (1.0)                                  */
		/* Direction[0] = taille (1.0)                                */
		/* Direction[1] = Nombre                                      */
		/**************************************************************/
		case 55:
			{
				int j;
				scale=Direction[0];
				i=((int)Direction[1])+1;
				for(;i;i--)
				{
					for(j=0;j<3;j++) Direction[j]=FLOAT_RANGED_RANDOM(-parameter,parameter);
					AGO_vCreatePart( AGO_MOVING |  AGO_SHADE_FAST,  Pos, Direction,  1.0f , scale, scale, hVisualMaterial );
				}
			}
		break;
 
		/*************************************************/
		/* Gouttes d'eau qui font des ploufs             */
		/* LanceAGO(60, Position, ....)                  */
		/*************************************************/
		case 60:
			{
				CreateType60AGO(p_stPosition,p_stDirection,hVisualMaterial,parameter);
			}
		break;
 
		/*************************************************/
		/* Bulles du ploufs								 */
		/*************************************************/
		case 62:
			{
				CreateType62AGO(p_stPosition,p_stDirection,hVisualMaterial,parameter);
			}
		break;
 

		/*************************************************/
		/* Spirale vers mapmonde (TEST)					 */
		/* Position = Position du centre				 */
		/* Direction = Normale au plan					 */
		/* Parameter = Rayon							 */
		/*************************************************/
		case 65:
			{
				CreateType65AGO(p_stPosition,p_stDirection,hVisualMaterial,parameter);
			}
		break;

		/***************************************************************/
		/* Plum_10 Zelda effect :									   */
		/*		Zelda effect, with random sparks					   */
		/***************************************************************/
		case 67:
			{
				CreateType67AGO(p_stPosition,p_stDirection,hVisualMaterial,parameter);
			}
		break;

		
		default: 
			AGO_vAddParticleContd(PartType,p_stPosition,p_stDirection,hVisualMaterial,parameter);
			break;
	};
}


void AGO_vAddParticleContd(unsigned long PartType,
					  MTH3D_tdstVector *p_stPosition,
					  MTH3D_tdstVector *p_stDirection,
					  void *hVisualMaterial,
					  float parameter)
{
	float Pos[3];
	float Direction[3];
	int i;
	float scale;

	g_AGO_AnimTimeScale=1.0f;
 
	Copy_a3f_Array(Pos,p_stPosition);
	Copy_a3f_Array(Direction,p_stDirection);

	switch(PartType)
	{

		/***************************************************************/
		/* sparks*/
		/***************************************************************/
		case 68:
		{
			for(i=6;i;i--)
			{
				Direction[0]=FLOAT_RANGED_RANDOM(-1.0f,1.0f); 
				Direction[1]=FLOAT_RANGED_RANDOM(-1.0f,1.0f); 
				Direction[2]=FLOAT_RANGED_RANDOM(-0.2f,4.0f);
				scale=FLOAT_RANGED_RANDOM(0.05f,0.12f);
				AGO_vCreatePart( AGO_FALLING_SLOW | AGO_SHADE_FAST,  Pos,  Direction,  parameter, scale, scale, hVisualMaterial );
			}
		}
		break;

		/*****************************************************/
		/* Super-shoot flashs								 */
		/*****************************************************/
		case 69:
			{
				AGO_Part *p;
				int j;
				
				AGO_vTransformHandVector(Pos,Direction);

				for(j=0;j<3;j++)
				{
					for(i=0;i<3;i++) Direction[i]=Pos[i]+FLOAT_RANGED_RANDOM(-1.5f,1.5f);
					p=AGO_vCreatePart(AGO_STILL | AGO_REMANANCE2 | AGO_SHADE_TWOFRAMES,  Pos,  NULL,  0.1f , 5.0f, 5.0f, hVisualMaterial );
					if (p) for(i=0;i<3;i++) p->a3_fInitialPosition[i]=Direction[i];
				}
			}
			break;

 
		/***************************************************************/
		/* Poing qui grossi!										   */
		/***************************************************************/
		case 71:
			{
				AGO_Part *p;
				AGO_vTransformHandVector(Pos,Direction);
				scale=FLOAT_RANGED_RANDOM(0.3f*parameter,0.3f*parameter);
			 	p=AGO_vCreatePart(AGO_STILL | AGO_SHADE_TWOFRAMES,  Pos,  NULL,  0.1f , scale, scale, hVisualMaterial );
				if (p) p->Transparency=500.0f;
			}
		break;

		/***************************************************************/
		/* bouillon sous la cascade !								   */
		/* Ca a un peu tendance à ramer !							   */
		/***************************************************************/
		case 72:
			{
				CreateType72AGO(p_stPosition,p_stDirection,hVisualMaterial,parameter);
			}
		break;
 
		/***************************************************************/
		/* AGOs du Menu (effet Zelda) !								   */
		/***************************************************************/
		case 83:
			{
				CreateType83AGO(p_stPosition,p_stDirection,hVisualMaterial,parameter);
			}
		break;


		/***************************************************************/
		/* REBOND DU POINT version 2 */
		/***************************************************************/
		case 99:
		{

			scale=FLOAT_RANGED_RANDOM(0.5f,0.8f);
			AGO_vCreatePart( AGO_STILL | AGO_SHADE_FASTEST | AGO_UNSCALING_FAST,  Pos,  NULL,  parameter, scale, scale, hVisualMaterial );
			
			for(i=(int)(4+4*parameter);i;i--)
			{
				Direction[0]=FLOAT_RANGED_RANDOM(-2.0f,2.0f); 
				Direction[1]=FLOAT_RANGED_RANDOM(-2.0f,2.0f); 
				Direction[2]=FLOAT_RANGED_RANDOM(-0.2f,6.0f);
				scale=FLOAT_RANGED_RANDOM(0.19f,0.35f);
				AGO_vCreatePart( AGO_FALLING | AGO_SHADE_FAST,  Pos,  Direction,  parameter, scale, scale, hVisualMaterial );
			}
		}
		break;
		/***************************************************************/


		/*****************************************************/
		/* Fire Effect										 */
		/* Enables or disables sinus on camera parameters	 */
		/*****************************************************/
		case 100:
			{
#ifdef U64
				g_bWeirdFireEffect=1;
#endif
			}
			break;

		case 101:
			{
#ifdef U64
				g_bWeirdFireEffect=0;
#endif
			}
			break;

		/*****************************************************/
		/* Clipping											 */
		/* Enables or disables far clipping					 */
		/*****************************************************/
		case 102:
#ifdef U64
			GLI_vExtendedFarClipping(1);
#endif
			break;

		case 103:
#ifdef U64
			GLI_vExtendedFarClipping(0);
#endif
			break;

		/*****************************************************/
		/* FireWorks										 */
		/* For the Credit Map								 */
		/*****************************************************/
		case 104:
			CreateType104AGO(p_stPosition,p_stDirection,hVisualMaterial,parameter);
			break;

		case 105:
			{
				int j;
				scale=Direction[0];
				i=((int)Direction[1])+1;
				for(;i;i--)
				{
					for(j=0;j<3;j++) Direction[j]=FLOAT_RANGED_RANDOM(-parameter,parameter);
					AGO_vCreatePart( AGO_FALLING_MEGAFAST | AGO_BIG_RANDOM_SCALE | AGO_SHADE_FAST,  Pos, Direction,  1.0f , scale, scale, hVisualMaterial );
				}
			}
		break;

		case 110: 
			{
				AGO_Part *p;
				p=AGO_vCreatePart( AGO_FRAME,  Pos, Direction,  parameter, 1.0f, 1.0f, hVisualMaterial );
				if (p) p->Transparency=parameter;
			}
			break;

			/********************************/
			/* GAUGE                        */
			/********************************/
		case 120:
			{
				AddGauge(Pos, Direction, parameter, AGO_gExtraMaterial, hVisualMaterial);
			}
			break;

		case 125:
			{
				AddIcone(Pos, Direction, parameter, hVisualMaterial);
			}
			break;


			/***********************************/
			/* TEST	(spirale bizarre aura)	   */
			/***********************************/
		case 132:
			{
#ifndef _FIRE_DEAD_CODE_N64_
				static float XAngle=0.0f;
				static float YAngle=0.0f;
				static float ZAngle=0.0f;
#define VECT_132_VALUE 0.5773502691896f
				float Norm;

				/* scale=FLOAT_RANGED_RANDOM(0.9f*parameter,0.9f*parameter); */
				scale=FLOAT_RANGED_RANDOM(0.6f*parameter,0.8f*parameter);

				Direction[0]=VECT_132_VALUE*COSINUS(XAngle)-VECT_132_VALUE*SINUS(YAngle);
				Direction[1]=VECT_132_VALUE*SINUS(XAngle)+VECT_132_VALUE*COSINUS(YAngle)+VECT_132_VALUE*COSINUS(ZAngle)-VECT_132_VALUE*SINUS(XAngle);
				Direction[2]=VECT_132_VALUE*COSINUS(XAngle)-VECT_132_VALUE*COSINUS(YAngle)+VECT_132_VALUE*SINUS(ZAngle)-VECT_132_VALUE*COSINUS(YAngle);

				XAngle+=g_fTimeDifference*1.0f;
				YAngle+=g_fTimeDifference*6.9f;
				ZAngle+=g_fTimeDifference*3.1564f;

				Norm=Direction[0]*Direction[0]+Direction[1]*Direction[1]+Direction[2]*Direction[2];
				Norm=MTH_M_xInvSqrt(Norm);

				Direction[0]*=Norm;
				Direction[1]*=Norm;
				Direction[2]*=Norm;

				AGO_vCreatePart(AGO_ORTHOPLAN | AGO_STILL | AGO_SHADE_FASTEST,  Pos,  Direction,  0.1f , scale, scale, hVisualMaterial );

				Pos[0]+=p_stDirection->xX;
				Pos[1]+=p_stDirection->xY;
				Pos[2]+=p_stDirection->xZ;
				Norm=Direction[0];
				Direction[0]=Direction[2];
				Direction[2]=Norm;

				AGO_vCreatePart(AGO_ORTHOPLAN | AGO_STILL | AGO_SHADE_FASTEST,  Pos,  Direction,  0.1f , scale, scale, hVisualMaterial );
#endif
			}
			break;

			/************************/
			/* DEFILEMENT D'ETOILES */
			/* Fred Houde			*/
			/************************/
		case 151:
			{
				AGO_Part *p;
				scale=FLOAT_RANGED_RANDOM(0.1f,0.5f);
				p=AGO_vCreatePart(AGO_MOVING | AGO_TIMELIMITED | AGO_UNSHADE,  Pos,  Direction,  parameter , scale, scale, hVisualMaterial );
				if (p) p->Transparency=0.01f;
			}
			break;

		/**************************************************************/
		/* etoile : Particules qui partent dans toutes les directions */
		/*										                      */
		/* parameter = vitesse (1.0)                                  */
		/* Direction[0] = taille (1.0)                                */
		/* Direction[1] = Nombre                                      */
		/**************************************************************/
		case 155:
			{
				int j;
				scale=Direction[0];
				i=((int)Direction[1])+1;
				for(;i;i--)
				{
					for(j=0;j<3;j++) Direction[j]=FLOAT_RANGED_RANDOM(-parameter,parameter);
					AGO_vCreatePart( AGO_MOVING |  AGO_SHADE_MEGAFAST,  Pos, Direction,  1.0f , scale, scale, hVisualMaterial );
				}
			}
		break;


		/************************************************/
		/* Nuage de fumée simple                        */
		/* LanceAGO(1,Position, rien, Materiau, Taille) */
		/************************************************/
		case 156: 
			parameter+=1.0f;
			g_AGO_AnimTimeScale=0.3333333f;
			AGO_vCreatePart( AGO_STILL |  AGO_TIMELIMITED,  Pos,  NULL,  2.0f , parameter, parameter, hVisualMaterial );
		break;

		/************************************************/
		/* OmbroSol										*/
		/* LanceAGO(157,Position, rien, Materiau, Taille) */
		/************************************************/
		case 157:
			AGO_vCreatePart( AGO_STILL | AGO_XYPLAN | AGO_SHADE_TWOFRAMES,  Pos,  NULL,  2.0f , parameter, parameter, hVisualMaterial );
		break;

		case 158:
			CreateType158AGO(p_stPosition,p_stDirection,hVisualMaterial,parameter);
		break;

		/* LanceAGO(163,Position1, Position2, "AGO_Laser",1.0) */
		/* Faisceau mapmonde */
		case 163:
			{
				AGO_Part *p;
				int i;

				for(i=0;i<g_ulNumberOfAgos;i++)
				{
					p=&(g_AGO[i]);
					if (p->ulType == AGO_STILL | AGO_REMANANCE3)
					{
						if ((AGO_CompareVector(p->a3_fInitialPosition, Pos)) && 
							(AGO_CompareVector(p->a3_fPosition, Direction))) return;
						if ((AGO_CompareVector(p->a3_fInitialPosition, Direction)) && 
							(AGO_CompareVector(p->a3_fPosition, Pos))) return;
					}
				}

				p=&(g_AGO[g_ulNumberOfAgos]);
				AGO_vCreatePart(AGO_STILL | AGO_REMANANCE3,  Pos,  NULL,  0.1f , 1.0f, 1.0f, hVisualMaterial );
 
				for(i=0;i<3;i++)
					p->a3_fInitialPosition[i]=Direction[i];

				g_bUsingMapMondeAGOs=1;
			}
		break;

		case 167:
			{
				if (parameter<=0.01f) g_DoSmallPlouf=0;
				else g_DoSmallPlouf=1;
			}
		break;
 
		case 170:
			{
				AGO_vAddLogoPart(parameter, hVisualMaterial);
			}
		break;

		case 171:
			{
				AGO_vActivateLogoDisplay((float *)p_stPosition,(float *)p_stDirection,parameter);
			}
		break;


		/* Hole Aspiration effect */
		case 175:
			{
				int j;
				float fNorm1=0.0f;
				float V1[3],V2[3],V3[3],V4[3];

				if (parameter==0.0f) return;

				parameter*=0.5f;

				for(i=0;i<3;i++)
				{
					V4[i]=Direction[i];
					Direction[i]-=Pos[i];
					fNorm1+=Direction[i]*Direction[i];
				}
				if (fNorm1!=0.0f)
				{

					fNorm1=MTH_M_xInvSqrt(fNorm1);
					for(i=0;i<3;i++) Direction[i]*=fNorm1;

					AGO_Define_OrthogonalVectors((MTH3D_tdstVector *)Direction,(MTH3D_tdstVector *)&V1,(MTH3D_tdstVector *)&V2);
					
					for(j=0;j<12;j++)
					{
						fNorm1=0.0f;
						for(i=0;i<3;i++)
						{
							V3[i]=V1[i]*FLOAT_RANGED_RANDOM(-8.0f,8.0f)+V2[i]*FLOAT_RANGED_RANDOM(-8.0f,8.0f);
							fNorm1+=V3[i]*V3[i];
						}

						if (fNorm1!=0.0f)
						{
							fNorm1=MTH_M_xInvSqrt(fNorm1)*parameter;
							for(i=0;i<3;i++) V3[i]=V4[i]+V3[i]*fNorm1;
						}

						scale=FLOAT_RANGED_RANDOM(0.05f,0.3f);
						AGO_vCreatePart( AGO_GOTO /*| AGO_APPEAR */,  V3,  Pos,  2.0f , scale, scale, hVisualMaterial );
					}
				}
			}
		break;

		case 260:
			{
#ifdef U64
				fn_vFadeIn();
#endif /* U64 */
			}
			break;

			case 261:
			{
#ifdef U64
				fn_vBlackScreenForNFrames((int)parameter);
#endif /* U64 */
			}
			break;


			case 300:
			{
#ifdef U64
				GLI_vSaveCenteringParameters();
#endif /* U64 */
			}
		break;


		case 500:
			{
#ifdef INFODESIGN_RESEARCH
				unsigned long IntParam=(int)parameter;

				/*
					TEMPORARY SETTING !!
					JUST FOR TEST PURPOSE !!!

				Direction[2]=0.0f;
				Direction[0]=-Pos[1];
				Direction[1]=Pos[0];
				
				Pos[0]=AGO_gExtraParameter1[0]+Direction[0];
				Pos[1]=AGO_gExtraParameter1[1]+Direction[1];
				Pos[2]=AGO_gExtraParameter1[2]+Direction[2]+0.5f;

			DO NOT REMOVE THIS COMMENT !!!

			;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
			Procedure(Proc_SetAGO,1)
				Constant(50,2)
				Operator(Operator_VectorPlusVector,2)
					Field(Position,2)
					Vector(Unused,2)
						Real("0.0",3)
						Real("0.0",3)
						Real("2.0",3)
				Operator(Operator_VectorPlusVector,2)
					Operator(Operator_VectorPlusVector,3)
						Field(Position,4)
						Vector(Unused,4)
							Real("0.0",5)
							Real("0.0",5)
							Real("2.0",5)
					Function(Func_GetPersoSighting,3)
				GameMaterialRef("AGOs\AGOs.gmt^GameMaterial:AGO_etincelle_bleue",2)
				Real("1.00000",2)
			Procedure(Proc_SetAGO,1)
				Constant(500,2)
				Function(Func_GetPersoSighting,2)
				Function(Func_GetPersoSighting,2)
				GameMaterialRef("AGOs\AGOs.gmt^GameMaterial:AGO_etincelle_bleue",2)
				Real("0.00000",2)
			;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


					END OF TEMPORARY SETTING !
				*/
								
				AGO_vCreateTriangle(
					AGO_gExtraParameter1,
					AGO_gExtraParameter2,
					Pos,
					AGO_gExtraMaterial,
					0.0f,0.0f,
					1.0f,0.0f,
					1.0f,1.0f,
					AGO_gExtraFloatParameter,
					IntParam);

				
				if (IntParam & 1)
				{
					AGO_vCreateTriangle(
						Direction,
						AGO_gExtraParameter1,
						Pos,
						AGO_gExtraMaterial,
						0.0f,1.0f,
						0.0f,0.0f,
						1.0f,1.0f,
						AGO_gExtraFloatParameter,
						IntParam);
			}
#endif

			}
		break;

 
		case 0:
		default: 
			AGO_vCreatePart( AGO_STILL |  AGO_TIMELIMITED | AGO_LOOPANIM,  Pos,  NULL,  2.0f , 1.0f, 1.0f, hVisualMaterial );
			break;
	};
}
 
 
 
/*****************************************************************************/
/*                                                                           */
/* AGO_Define_OrthogonalVectors                                              */
/*																			 */
/*****************************************************************************/
/* Given one NORMAL 3D vector, this function returns 2 orthogonal vectors    */
/* that define the orthogonal planar surface.								 */
/*****************************************************************************/
void AGO_Define_OrthogonalVectors(MTH3D_tdstVector *p_stDirection,MTH3D_tdstVector *p_stV1,MTH3D_tdstVector *p_stV2)
{
	register MTH3D_tdstVector stV1, stV2, stV3;
	register float fNorm1,fNorm2,fNorm3;
 
	/* The first normal vector is easy to find */
	/* For better accuracy, we take the 3 possibilities */
	/* and then get the biggest one */
	stV1.xX=-p_stDirection->xY; stV1.xY=p_stDirection->xX; stV1.xZ=0.0f;
	stV2.xX=-p_stDirection->xZ; stV2.xY=0.0f; stV2.xZ=p_stDirection->xX;
	stV3.xX=0.0f; stV3.xY=-p_stDirection->xZ; stV3.xZ=p_stDirection->xY;
 
	/* So we calculate ||Vx||² */
	fNorm1=stV1.xX*stV1.xX+stV1.xY*stV1.xY+stV1.xZ+stV1.xZ;
	fNorm2=stV2.xX*stV2.xX+stV2.xY*stV2.xY+stV2.xZ+stV2.xZ;
	fNorm3=stV3.xX*stV3.xX+stV3.xY*stV3.xY+stV3.xZ+stV3.xZ;
 
	/* To avoid problems, we choose the greatest size */
	if (fNorm3>fNorm1) { stV1.xX=stV3.xX; stV1.xY=stV3.xY; stV1.xZ=stV3.xZ; fNorm1=fNorm3; }
	if (fNorm2>fNorm1) { stV1.xX=stV2.xX; stV1.xY=stV2.xY; stV1.xZ=stV2.xZ; fNorm1=fNorm2; }
 
	fNorm1=MTH_M_xInvSqrt(fNorm1);
 
	/* Now, we can normalize the choosen vector */
	stV1.xX*=fNorm1; stV1.xY*=fNorm1; stV1.xZ*=fNorm1;
 
	/* Now stV1 is the greatest normal */
	/* Now we use a cross product to get the second orthogonal vector */
 
	p_stV2->xX=p_stDirection->xY*stV1.xZ - p_stDirection->xZ*stV1.xY;
	p_stV2->xY=p_stDirection->xZ*stV1.xX - p_stDirection->xX*stV1.xZ;
	p_stV2->xZ=p_stDirection->xX*stV1.xY - p_stDirection->xY*stV1.xX;
 
	/* So now, we have stV1 & stV2 that define the */
	/* orthogonal surface to the given direction vector */
	p_stV1->xX=stV1.xX; p_stV1->xY=stV1.xY; p_stV1->xZ=stV1.xZ;
}
 
 

/*
void *LogoMaterials[6*3];
unsigned char g_LogoTransparency=0;
float g_LogoPosition[4];
*/
void AGO_vAddLogoPart(float parameter, void *hVisualMaterial)
{
	LogoMaterials[(int)parameter]=hVisualMaterial;
}

void AGO_vActivateLogoDisplay(float *p_stPosition, float *p_stDirection, float parameter)
{
	/*
	g_LogoPosition[0]=p_stPosition[0];
	g_LogoPosition[1]=p_stPosition[1];
	g_LogoPosition[2]=p_stDirection[0];
	g_LogoPosition[3]=p_stDirection[1];
	*/
	g_LogoPosition[0]=15.0f; /* Finally I decided to force the correct values */
	g_LogoPosition[1]=20.0f;
	g_LogoPosition[2]=85.0f;
	g_LogoPosition[3]=60.0f;
	g_LogoTransparency=parameter;
}
 
 
extern int SCREEN_WD;
extern int SCREEN_HT;

void AGO_vDisplayLogo(GLD_tdstViewportAttributes *p_stVpt)
{
	int i,j;
	float x,y;
	float dx,dy;
	float dx2,dy2;

	if (g_stEngineStructure.bEngineFrozen)
		return;

	x=g_LogoPosition[0];
	y=g_LogoPosition[1];

	dx2=dx=(g_LogoPosition[2]-g_LogoPosition[0])/6.0f;
	dy2=dy=(g_LogoPosition[3]-g_LogoPosition[1])/3.0f;

	

#ifdef U64

	if (SCREEN_WD==300)
	{
		dx2-=3*0.20f;
		dy2-=4*0.20f;

		dx+=14*0.01f;
		dy+=10*0.01f;
	}
	else
	{
		dx2-=3.0f*0.2f+4.0f*0.05f;
		dy2-=3.0f*0.2f+6.0f*0.05f;

		dx-=0.18f;
		dy-=0.22f;
	}

#else /* U64 */ 
	dy2-=(220.0f)/(float)p_stVpt->dwBottomInPix;
	dx2-=(220.0f)/(float)p_stVpt->dwRightInPix;
#endif /* U64 */

	GLI_vSetGlobalAlpha(g_LogoTransparency);

	for(i=0;i<6;i++)
	{
		y=g_LogoPosition[1];
		for(j=0;j<3;j++)
		{
			GLI_vDraw2DSpriteWithPercent(	p_stVpt, 
								x,
								y,
								x+dx,
								y+dy,
								LogoMaterials[j+3*i]);
			y+=dy2;
		}
		x+=dx2;
	}

}
 
 
/***************************************************************************************/
/**                                                                                   **/
/** SIMPLE TEXT DRAWING                                                               **/
/**                                                                                   **/
/***************************************************************************************/

/*
	
	Number of strings per dsg :

    YAM : 10
    SDZ : 2
	ARG : 2
	GRP : 2

	And because I'm sure they'll ask for more ;-)
	EXTRA : 20

*/

#define MAX_JFFTXT	50

#define JFFTXT_FADEIN	0x01
#define JFFTXT_FADEOUT	0x02
#define JFFTXT_SELECTED		0x04
#define JFFTXT_AUTOFRAME	0x08
#define JFFTXT_FORCED_COLOR	0x10


typedef struct _JFFTXT_
{
	unsigned char *	pString;
	float			a3_Pos[3];
	unsigned char	ucTransparency;
	unsigned char   bFrozenDisplay;
	unsigned char	bWaveEffect;
	unsigned char	bOther;
	int				EffectParameter;
	unsigned char	ucForcedColor;
} tdst_JFFTXT;


/* THE GLOBAL ARRAY */
tdst_JFFTXT g_JFFTXT[MAX_JFFTXT];



/* PROTOs */

void JFFTXT_vInit(void);
void JFFTXT_vAffiche(GLD_tdstViewportAttributes *p_stVpt);
void JFFTXT_vDrawString(GLD_tdstViewportAttributes *p_stVpt, tdst_JFFTXT *p);
void JFFTXT_vAddText(int StringNumber, MTH3D_tdstVector *p_stPosition, unsigned char *pszString, float xParameter);
void JFFTXT_vExtendText(int StringNumber, int ID, float xParameter);
void JFFTXT_vGetStringExtents(tdst_JFFTXT *p,float *x1,float *x2);

void *GLI_pGetVisualMaterialForLetter(unsigned int Offset);
extern char g_GLI_bForceAAAColor;
extern unsigned char g_GLI_ForcedAAAColor[3];



#ifdef U64

extern unsigned char g_JFFTXT_DrawingText;
extern unsigned char g_JFFTXT_DrawingTextFirstChar;
// extern unsigned char g_JFFTXT_DrawingTextLastChar;

#endif /* U64 */


/* END OF PROTOs */



void JFFTXT_vInit(void)
{
	int i;

	for(i=0;i<MAX_JFFTXT;i++)
	{
		g_JFFTXT[i].pString=NULL;
		g_JFFTXT[i].ucTransparency=0;
		g_JFFTXT[i].bFrozenDisplay=0;
		g_JFFTXT[i].bWaveEffect=0;
		g_JFFTXT[i].bOther=0;
		g_JFFTXT[i].EffectParameter=0;
	}
	
	/* TEST : DECOMMENTER CES LIGNES POUR TESTER :  */

	/*
	
	g_JFFTXT[1].pString="/c:/o180:Ceci l'est, un test !/l:Et on verifie que ca/l:marche !";
	g_JFFTXT[1].ucTransparency=1;
	g_JFFTXT[1].bFrozenDisplay=0;
	g_JFFTXT[1].a3_Pos[0]=500;
	g_JFFTXT[1].a3_Pos[1]=300;
	g_JFFTXT[1].a3_Pos[2]=14;
	g_JFFTXT[1].bWaveEffect=0;
	g_JFFTXT[1].bOther= JFFTXT_AUTOFRAME | JFFTXT_FADEIN; */

/*
	// g_JFFTXT[0].pString="/c:CECI EST /o180:UN 0;50/c:/l:ET CA MaRchE/o240: BIEN/o0:/l:Ben evidemment je sais/c:/l:pas quoi dire !";
	g_JFFTXT[0].pString="/C:/O300:g                 f                 h/O240:";
	g_JFFTXT[0].ucTransparency=255;
	g_JFFTXT[0].bFrozenDisplay=0;
	g_JFFTXT[0].a3_Pos[0]=500;
	g_JFFTXT[0].a3_Pos[1]=155;
	g_JFFTXT[0].a3_Pos[2]=15;
	g_JFFTXT[0].bWaveEffect=0;
	g_JFFTXT[0].bOther=JFFTXT_AUTOFRAME;
	g_JFFTXT[0].EffectParameter=0;

	
*/	

//	g_JFFTXT[6].pString="/c:/o240:use /o300:j/o240: to swim/L:press /o300:z/o240: to dive/L:press /o300:a/o240: to come back up";
	/* g_JFFTXT[36].pString="/c:ICI = ùò !";
	g_JFFTXT[36].ucTransparency=155;
	g_JFFTXT[36].bFrozenDisplay=0;
	g_JFFTXT[36].a3_Pos[0]=500;
	g_JFFTXT[36].a3_Pos[1]=200;
	g_JFFTXT[36].a3_Pos[2]=15;
	g_JFFTXT[36].bWaveEffect=0;
	g_JFFTXT[36].bOther= JFFTXT_AUTOFRAME | JFFTXT_FADEIN; */

	/* TEST */
}

#ifdef U64
void JFFTXT_vCheckStringValidity(unsigned char *pString)
{
	int i;

	if (pString==NULL) return;

	for(i=0;i<MAX_JFFTXT;i++)
	{
		if (g_JFFTXT[i].pString==pString)
		{
#ifndef FINAL_VERSION
			g_JFFTXT[i].pString="STRING KICKED FROM CACHE !";
#else
			g_JFFTXT[i].pString=" ";
#endif /* FINAL_VERSION */
			g_JFFTXT[i].a3_Pos[2]=13;
		}
	}
}
#endif /* U64 */
 
 
void JFFTXT_vAddText(int StringNumber, MTH3D_tdstVector *p_stPosition, unsigned char *pszString, float xParameter)
{
	
	tdst_JFFTXT *p;
/*
	if (pszString)
		osSyncPrintf("Adding %s\n",pszString);
	else
		osSyncPrintf("Adding NULL STRING\n");

*/

	if (StringNumber<MAX_JFFTXT)
	{
		p=&(g_JFFTXT[StringNumber]);
		p->pString=pszString;
		p->ucTransparency=(unsigned char)xParameter;
		p->bFrozenDisplay=0;
		p->a3_Pos[0]=p_stPosition->xX;
		p->a3_Pos[1]=p_stPosition->xY;
		p->a3_Pos[2]=p_stPosition->xZ;
		p->bWaveEffect=0;
		p->bOther=0;
	}
}
 
void JFFTXT_vExtendText(int StringNumber, int ID, float xParameter)
{
	tdst_JFFTXT *p;
 
	if (StringNumber<MAX_JFFTXT)
	{
		p=&(g_JFFTXT[StringNumber]);
 
		switch(ID)
		{
			case 0:
				p->ucTransparency=(unsigned char)xParameter;
				break;
			case 1:
				p->bWaveEffect=((unsigned char)xParameter)?1:0;
				break;
			case 2:
				p->bOther=JFFTXT_FADEIN;
				if (p->ucTransparency==0) p->ucTransparency=1;
				break;
			case 3:
				p->bOther=JFFTXT_FADEOUT;
				break;
			case 4:
				p->a3_Pos[2]=xParameter;
				break;
			case 5:
				if ((int)xParameter==0)
				{
					p->bOther&=~JFFTXT_SELECTED;
				}
				else
				{
					p->bOther|=JFFTXT_SELECTED;
					p->EffectParameter=xParameter;
				}
				break;
			case 6:
				if (xParameter==1.0f)
				{
					p->bOther|=JFFTXT_AUTOFRAME;
				}
				else
				{
					p->bOther&=~JFFTXT_AUTOFRAME;
				}
				break;
			case 7:
				{
					switch ((int)xParameter)
					{
						case 0: 
							p->bOther&=~JFFTXT_FORCED_COLOR;
							p->ucForcedColor=0;
							break;
						case 1:
							p->bOther|=JFFTXT_FORCED_COLOR;
							p->ucForcedColor=1;
							break;
						case 2:
							p->bOther|=JFFTXT_FORCED_COLOR;
							p->ucForcedColor=2;
							break;
						case 3:
							p->bOther|=JFFTXT_FORCED_COLOR;
							p->ucForcedColor=3;
							break;
					}
				}
				break;
		};
	}
}

void JFFTXT_vModifyCaracter(int StringNumber, int Position, int newcar)
{
	tdst_JFFTXT *p;

	if (StringNumber<MAX_JFFTXT)
	{
		p=&(g_JFFTXT[StringNumber]);

		if (p->pString!=NULL)
		{
			p->pString[Position]=newcar;
		}
	}
}



void JFFTXT_vAffiche(GLD_tdstViewportAttributes *p_stVpt)
{
	tdst_JFFTXT *p;
	int i;

#ifdef U64

	g_JFFTXT_DrawingText=1;
	g_JFFTXT_DrawingTextFirstChar=1;

#endif /* U64 */


	for(i=0;i<MAX_JFFTXT;i++)
	{
		p=&(g_JFFTXT[i]);

		/* This is a valid Text */
		if ((p->ucTransparency!=0) && (p->pString!=NULL))
		{
#ifdef U64
			FON_fn_cRefreshCache(p->pString);
#endif
			if ((i<15) || (!g_stEngineStructure.bEngineFrozen))
			{


			if (p->bOther & JFFTXT_FADEIN)
			{
				int trsp;
				trsp=p->ucTransparency;
					trsp+=g_fTimeDifference*200.0f;
				if (trsp>=255) 
				{
					trsp=255;
					p->bOther &= ~JFFTXT_FADEIN;
					/* p->bOther |= JFFTXT_FADEOUT; */
				}
				p->ucTransparency=(unsigned char)trsp;
			}
			else if (p->bOther & JFFTXT_FADEOUT)
			{
				int trsp;
				trsp=p->ucTransparency;
					trsp-=g_fTimeDifference*200.0f;
				if (trsp<=0) 
				{
					trsp=0;
					p->bOther &= ~JFFTXT_FADEOUT;
					/* trsp=1;
					p->bOther |= JFFTXT_FADEIN; */
				}
				p->ucTransparency=(unsigned char)trsp;
			}

			if (p->bOther & JFFTXT_AUTOFRAME)
			{
				float x1[3];
				float x2[3];

				JFFTXT_vGetStringExtents(p,x1,x2);

				GLI_vDisplayFrame(	x1,
									x2,
									(int)((((float)p->ucTransparency)*0.7f)),
									p_stVpt);

			}

			JFFTXT_vDrawString(p_stVpt,p);
		}
	}
	}
	g_GLI_bForceAAAColor=0;

#ifdef U64
	GLI_vReinitRDPAfterDisplayingLetters();
	g_JFFTXT_DrawingText=0;
#endif
	
}


#define FLOAT(x) ((float)(x))



unsigned int JFFTXT_toupper(unsigned int c)
{
	if ((c>='a') && (c<='z'))
	{
		c=c-'a'+'A';
	}
	return c;
}


int JFFTXT_iGetStringLength(unsigned char *pt, int dx)
{
	int i=0;
	int Length=0;
	unsigned char c;

	c=pt[i];

	while (c!=0)
	{
		if (c=='/')
		{
			c=JFFTXT_toupper(pt[++i]);
			if (c=='L') return Length;
			
			while (c!=':')
			{
				c=pt[++i];
			};
		}
		else
		{
			if (c==32)
			{
				Length+=(int)(FLOAT(dx)*0.6f);
			}
			else
			{
				Length+=dx;
			}
		}
		c=pt[++i];
	};

	return (Length);
}

void JFFTXT_GetSizeValues(float size, int *dx, int *dy, int *cx, int *cy)
{
	/* osSyncPrintf("%f\n",size); */

/* 	if (size==35.0f) */
	{
	size-=15.0f;
	*cy=(int)(38.0f+size*2.5f);
	size*=2.0f;
	*dx=(int)(32.0f+size);
	*cx=(int)(32.0f+size);
	*dy=(int)(46.0f+size*2.0f);
	}
	/* else
	{
		size-=15.0f;
		*cy=(int)(38.0f+size*1.0f);
		size*=2.0f;
		*dx=(int)(32.0f+size);
		*cx=(int)(32.0f+size);
		*dy=(int)(46.0f+size*1.0f);
	}*/


}


#define FRAME_BORDER_X 10
#define FRAME_BORDER_Y 10

void JFFTXT_vGetStringExtents(tdst_JFFTXT *p,float *x1,float *x2)
{
	int i=0;
	unsigned char *pt;
	char c;
	float x,y;	/* screen position */
	int dx,dy;	/* next character deltas */
	int cx,cy;	/* character sizes */
	int bCentering=0;

	pt=p->pString;

	x=p->a3_Pos[0];
	y=p->a3_Pos[1];

	x2[0]=x1[0]=x;
	x2[1]=x1[1]=y;

	JFFTXT_GetSizeValues(p->a3_Pos[2], &dx, &dy, &cx, &cy);

	c=JFFTXT_toupper(pt[i]);

	while(c!=0)
	{
		if (c=='/')
		{
			c=JFFTXT_toupper(pt[++i]);
			if (!c) return;

			if (c=='L') /* LINE SKIP */
			{
				c=pt[++i];
				if (!c) return;
				if (c==':')
				{
					if (bCentering)
						x=(1000-JFFTXT_iGetStringLength(&pt[i+1], dx))>>1;
					else
						x=p->a3_Pos[0];
					if (x<x1[0]) x1[0]=x;
					y+=dy;
					if (y>x2[1]) x2[1]=y;
				} else return;
			}
			else if (c=='O') /* OFFSET */
			{
				c=pt[++i];
				if (!c) return;

				while(c!=':')
				{
					c=pt[++i];
					if (!c) return;
				}
			}
			else if (c=='C') /* CENTERING */
			{
				c=pt[++i];
				if (!c) return;
				if (c==':')
				{
					bCentering^=1;
					if (bCentering)
					{
						x=(1000-JFFTXT_iGetStringLength(&pt[i+1], dx))>>1;
						if (x<x1[0]) x1[0]=x;
						if (x>x2[0]) x2[0]=x;
					}
				} else return;
			}
		}
		else if (c==32)
		{
			x+=(int)(FLOAT(dx)*0.6f);
		}
		else /* Not a control character, we display the letter */
		{
			x+=dx;
		}

		if (x>x2[0]) x2[0]=x;

		c=JFFTXT_toupper(pt[++i]);
	}

	x1[0]=(x1[0]-10.0f)*0.1f;
	x1[1]=(x1[1]-10.0f)*0.1f;

	x2[0]=(x2[0]+10.0f)*0.1f;
	x2[1]=(x2[1]+dy+10.0f)*0.1f;
}


#define BLUE_R 110
#define BLUE_G 190
#define BLUE_B 255

#define RED_R  250
#define RED_G	70
#define RED_B	70

#define YELLOW_R 255
#define YELLOW_G 255
#define YELLOW_B 120


void JFFTXT_vDrawString(GLD_tdstViewportAttributes *p_stVpt, tdst_JFFTXT *p)
{
	int i=0;
	unsigned char *pt;
	unsigned int c;
	float x,y;	/* screen position */
	int dx,dy;	/* next character deltas */
	int cx,cy;	/* character sizes */
	void *hVisualMaterial;
	unsigned int CurrentOffset=0;
	int bCentering=0;
	float Waveeffect=0.0f;
	int RealChar=1;

	g_GLI_bForceAAAColor=1;


	pt=p->pString;

	if (p->bOther & JFFTXT_FORCED_COLOR)
	{
		switch(p->ucForcedColor)
		{
			case 1:
				g_GLI_ForcedAAAColor[0]=BLUE_R;
				g_GLI_ForcedAAAColor[1]=BLUE_G;
				g_GLI_ForcedAAAColor[2]=BLUE_B;
				break;
			case 2:
				g_GLI_ForcedAAAColor[0]=RED_R;
				g_GLI_ForcedAAAColor[1]=RED_G;
				g_GLI_ForcedAAAColor[2]=RED_B;
				break;
			case 3:
				g_GLI_ForcedAAAColor[0]=YELLOW_R;
				g_GLI_ForcedAAAColor[1]=YELLOW_G;
				g_GLI_ForcedAAAColor[2]=YELLOW_B;
				break;
		}
	}
	else
	{
		g_GLI_ForcedAAAColor[0]=BLUE_R;
		g_GLI_ForcedAAAColor[1]=BLUE_G;
		g_GLI_ForcedAAAColor[2]=BLUE_B;
	}


	if (p->bWaveEffect)
	{
		Waveeffect=7.0f*SINUS(g_ffFrameTime*5.0f);
	}
	

	x=p->a3_Pos[0];
	y=p->a3_Pos[1];

	JFFTXT_GetSizeValues(p->a3_Pos[2], &dx, &dy, &cx, &cy);

	GLI_vSetGlobalAlpha(FLOAT(p->ucTransparency));

	c=JFFTXT_toupper(pt[i]);

	while(c!=0)
	{
		if (c=='/')
		{
			c=JFFTXT_toupper(pt[++i]);
			if (!c) return;

			if (c=='L') /* LINE SKIP */
			{
				c=pt[++i];
				if (!c) return;
				if (c==':')
				{
					if (bCentering)
					{
						x=(1000-JFFTXT_iGetStringLength(&pt[i+1], dx))>>1;
					}
					else
					{
						x=p->a3_Pos[0];
					}
					y+=dy;
				} else return;
			}
			else if (c=='O') /* OFFSET */
			{
				/*
					/o0:	Blue
					/o600:	Blue
					/o200:	Red
					/o400:	Yellow
					/o800:	Pad signs
				*/

				CurrentOffset=0;

				c=pt[++i];
				if (!c) return;

				while(c!=':')
				{
					CurrentOffset*=10;
					CurrentOffset+=c-'0';
					c=pt[++i];
					if (!c) return;
				}

				if ((CurrentOffset==0) || (CurrentOffset==600))
				{
					g_GLI_ForcedAAAColor[0]=BLUE_R;
					g_GLI_ForcedAAAColor[1]=BLUE_G;
					g_GLI_ForcedAAAColor[2]=BLUE_B;
				}
				else if (CurrentOffset==200)
				{
					g_GLI_ForcedAAAColor[0]=RED_R;
					g_GLI_ForcedAAAColor[1]=RED_G;
					g_GLI_ForcedAAAColor[2]=RED_B;
				}
				else if (CurrentOffset==400)
				{
					g_GLI_ForcedAAAColor[0]=YELLOW_R;
					g_GLI_ForcedAAAColor[1]=YELLOW_G;
					g_GLI_ForcedAAAColor[2]=YELLOW_B;
				}
			}
			else if (c=='C') /* CENTERING */
			{
				c=pt[++i];
				if (!c) return;
				if (c==':')
				{
					bCentering^=1;
					if (bCentering)
					{
						x=(float)((1000-JFFTXT_iGetStringLength(&pt[i+1], dx))>>1);
					}

				} else return;
			}
		}
		else if (c==32)
		{
			x+=(int)(FLOAT(dx)*0.6f);
			RealChar++;
		}
		else /* Not a control character, we display the letter */
		{
			unsigned int c2;
			float ftempy;

			c2=(unsigned int)(c);
			if (c>160) c2-=32;
			c2-=32;
			
			hVisualMaterial=(void *)GLI_pGetVisualMaterialForLetter(c2+CurrentOffset);
			
			if (hVisualMaterial!=NULL)
			{
				if (CurrentOffset>=800) g_GLI_bForceAAAColor=0;

				if (p->bOther & JFFTXT_SELECTED)
				{
					if (RealChar==p->EffectParameter)
					{
						GLI_vSetGlobalAlpha(FLOAT(p->ucTransparency>>1));
						Waveeffect=7.0f*SINUS(g_ffFrameTime*5.0f);
					}
					else
					{
						GLI_vSetGlobalAlpha(FLOAT(p->ucTransparency));
						Waveeffect=0.0f;
					}
				}

				ftempy=(float)y;

				if (c=='.') 
				{
					ftempy+=(cy>>2);
				}
				else if (c==',')
				{
					ftempy+=(cy>>1);
				}
				else if (c=='\'')
				{
					ftempy-=(cy>>2);
				}
				
				
				GLI_vDraw2DSpriteWithPercent( p_stVpt, 
					FLOAT(x)*0.1f,
				(ftempy-Waveeffect)*0.1f,
					FLOAT(x+cx)*0.1f,
				(FLOAT(ftempy+cy)+Waveeffect)*0.1f,
					hVisualMaterial);
#ifdef U64
				g_JFFTXT_DrawingTextFirstChar=0;
#endif

				g_GLI_bForceAAAColor=1;
			}

			x+=dx;
			RealChar++;
		}

		c=JFFTXT_toupper(pt[++i]);
	}
}








/******************************************************************************
**
**				TRIANGLE GENERATION FOR INFO-DESIGN RESEARCH
**
*******************************************************************************/


#ifdef INFODESIGN_RESEARCH


#define MAX_AGO_TRIANGLES	200

#define AGO_TRI_FADE 0x00002

typedef struct AGO_Triangles_
{
	float c[3][3];
	float uv[3][2];
	void *VisualMaterial;
	unsigned long DelayTime;
	unsigned long type;
	float fTransparency;
	unsigned long CreationTime;

} AGO_Triangles;


AGO_Triangles	g_pAGO_Triangles[MAX_AGO_TRIANGLES];
unsigned long   g_NbAGO_Triangles=0;
unsigned long g_AGO_NbEngineFramesSinceStart=0;

void AGO_vTrianglesInit(void)
{
	g_NbAGO_Triangles=0;
}

void AGO_vCreateTriangle(float c1[3], float c2[3], float c3[3], void *VisualMat, 
			 float U1, float V1, 
			 float U2, float V2,
			 float U3, float V3,
			 float DelayTime,
			 unsigned long Parameter)
{
	AGO_Triangles *p;
	int i;

	if (g_NbAGO_Triangles==MAX_AGO_TRIANGLES)
	{
		unsigned long Least;
		int LeastIndex=0;

		Least=g_pAGO_Triangles[0].CreationTime;

		for(i=0;i<MAX_AGO_TRIANGLES;i++)
		{
			if (g_pAGO_Triangles[i].CreationTime<Least)
			{
				Least=g_pAGO_Triangles[i].CreationTime;
				LeastIndex=i;
			}
		}
		p=&(g_pAGO_Triangles[LeastIndex]);
	}
	else
	{
		p=&(g_pAGO_Triangles[g_NbAGO_Triangles++]);
	}

	p->CreationTime=g_AGO_NbEngineFramesSinceStart;

	for(i=0;i<3;i++)
	{
		p->c[0][i]=c1[i];
		p->c[1][i]=c2[i];
		p->c[2][i]=c3[i];
	}
	p->uv[0][0]=U1; p->uv[0][1]=V1;
	p->uv[1][0]=U2; p->uv[1][1]=V2;
	p->uv[2][0]=U3; p->uv[2][1]=V3;

	p->fTransparency=255.0f;

	p->VisualMaterial=VisualMat;
	p->DelayTime=(unsigned long)DelayTime;

	p->type=0;

	if (Parameter & 0x02) p->type|=AGO_TRI_FADE;
		
}


void AGO_vDisplayTriangles(GLD_tdstViewportAttributes *p_stVpt)
{
	AGO_Triangles *p;
	int i;

	g_AGO_NbEngineFramesSinceStart++;

	for(i=0;i<g_NbAGO_Triangles;i++)
	{
		p=&(g_pAGO_Triangles[i]);

		if (p->type & AGO_TRI_FADE)
		{
			p->fTransparency=255.0f-255.0f*FLOAT(g_AGO_NbEngineFramesSinceStart-p->CreationTime-1)/FLOAT(p->DelayTime);
		}

		GLI_vSetGlobalAlpha(p->fTransparency);

		GLI_vDisplayWorldTriangle(
			p_stVpt,
			p->c,
			p->uv,
			p->VisualMaterial);

		if (g_AGO_NbEngineFramesSinceStart-p->CreationTime>=p->DelayTime)
		{
			p->type|=0x80000000;
		}
	}

	i=0;
	while(i<g_NbAGO_Triangles)
	{
		p=&(g_pAGO_Triangles[i]);

		if (p->type & 0x80000000)
		{
			int j;
			AGO_Triangles *p1;
			AGO_Triangles *p2;

			for(j=i+1;j<g_NbAGO_Triangles;j++)
			{
				p1=&(g_pAGO_Triangles[j-1]);
				p2=&(g_pAGO_Triangles[j]);
				memcpy(p1,p2,sizeof(AGO_Triangles));
			}

			g_NbAGO_Triangles--;
	}
		else i++;
}
}


#endif /* INFODESIGN_RESEARCH */


















 
 
