1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin/Revolution gx demo
3   File:     geo-particle.c
4 
5   Copyright 1998-2006 Nintendo.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12  *---------------------------------------------------------------------------*/
13 
14 #include <demo.h>
15 #include <math.h>
16 #include <stdio.h>
17 
18 /*---------------------------------------------------------------------------*
19    Defines
20  *---------------------------------------------------------------------------*/
21 
22 #define HEIGHT              20
23 #define WIDTH               12
24 
25 #define WIDTH_SAMPLES       32
26 #define HEIGHT_SAMPLES      32
27 #define TOTAL_SAMPLES       (WIDTH_SAMPLES * HEIGHT_SAMPLES)
28 
29 #define MAX_PARTICLES       1600
30 #define MAX_EMISSION_RATE   50
31 #define EMMISION_RATE       5.0F
32 
33 #define LIFESPAN_MEAN       125.0F
34 #define LIFESPAN_STDDEV     25.0F
35 #define SIZE_MEAN           200.0F
36 #define SIZE_MAX            640.0F
37 #define SIZE_STDDEV         40.0F
38 
39 #define PARTICLE_SPEED      4.0F
40 #define GRAVITY             -0.03F
41 #define EVENT_TIME          160
42 
43 #define ACTIVE_LIST         MAX_PARTICLES
44 #define FREE_LIST           (MAX_PARTICLES + 1)
45 
46 #define LINE_SEGMENT        0x0001
47 #define PARTICLE_HAS_SIZE   0x0002
48 #define ANIMATE_SIZE        0x0004
49 #define INVERSE_ANIMATE     0x0008
50 #define TEXTURE_PARTICLE    0x0010
51 #define TEXWIDE_PARTICLE    0x0020
52 
53 /*---------------------------------------------------------------------------*
54    Local Typedefs
55  *---------------------------------------------------------------------------*/
56 
57 // Emitter State
58 typedef struct
59 {
60     Mtx     mModel;             // modeling matrix (orientation)
61     Vec     vPos;               // position of emitter
62     Vec     vLinVel;            // linear velocity per tick
63     Vec     vAngVel;            // angular velocity per tick
64     f32     rEmitted;           // counts particles emitted
65     f32     rEmissionRate;      // number of particles emitted per tick
66     f32     rLifespanMean;      // average lifespan of emitted particles
67     f32     rLifespanStdDev;    // standard deviation of lifespan of emitted particles
68     f32     rSizeMean;          // average size of emitted particles
69     f32     rSizeStdDev;        // standard deviation of size of emitted particles
70     u32     nType;              // type of particles emitted
71     GXTexOffset offset;         // texture offset for texture particles
72 }
73 Emitter;
74 
75 // Particle State
76 typedef struct
77 {
78     u32     nNext;          // singularly linked list for sequential access + add/delete
79     Vec     vPos;           // position
80     Vec     vVel;           // velocity per tick
81     s32     nLifespan;      // number of ticks of life left
82     u32     nType;          // defines point/line and Lifespan->{size, color, texture} mappings
83     s32     nSize;          // Size of Particle (only when PARTICLE_HAS_SIZE)
84     f32     tex_s, tex_t;   // Texture coordinates
85 }
86 Particle;
87 
88 typedef struct
89 {
90     Vec vPos;
91     Vec vUp;
92     VecPtr vpTarget;
93 }
94 Camera;
95 
96 /*---------------------------------------------------------------------------*
97    Forward references
98  *---------------------------------------------------------------------------*/
99 
100 void        main            ( void );
101 
102 static void CameraInit      ( void );
103 static void CameraUpdate    (s8 stickX, s8 stickY);
104 static void DrawInit        ( void );
105 static void DrawTick        ( void );
106 
107 static void AnimTick        ( void );
108 
109 static void PrintIntro          ( void );
110 
111 static void SetupTransforms     ( void );
112 static void DrawParticles       ( void );
113 static void DrawEmitter         ( void );
114 
115 static double BoxMuller         ( void );
116 static void TextureParticlesInit( void );
117 static void ParticleInit        ( void );
118 static void ParticleEmit        ( Particle *prt, Emitter *em );
119 static void EmitterEmit         ( Emitter *em);
120 static void ParticleUpdate      ( void );
121 static void EmitterInit         ( Emitter *em );
122 static void EmitterUpdate       ( Emitter *em, s8 rotX, s8 rotY );
123 
124 static void SendEmitterVertex   ( u8 posIndex, u8 normalIndex,
125                                   u8 colorIndex, u8 texCoordIndex );
126 static void SendParticlePoint   ( Vec *vPoint, u8 colorIndex );
127 static void SendParticleLine    ( Vec *vPoint1, Vec *vDelta, u8 colorIndex );
128 
129 static u32 rndi( void );
130 static void srnd( u32 x );
131 static double rndf( void );
132 
133 /*---------------------------------------------------------------------------*
134    Global variables
135  *---------------------------------------------------------------------------*/
136 
137 #define ULONG_MAX 4294967295
138 static u32 seed = 1;        // Arbitrary
139 
140 Emitter emMain;             // Particle emitter
141 Camera  cam;
142 
143 Particle ParticleData[MAX_PARTICLES + 2];
144 u32 nNumActiveParticles;
145 
146 u8          clrRGBA[4];     // color of particle
147 
148 Mtx v;
149 
150 TPLPalettePtr tpl = 0;
151 float FloatVert[] ATTRIBUTE_ALIGN(32) =
152 {
153     -WIDTH, HEIGHT, -WIDTH,
154     -WIDTH, HEIGHT, WIDTH,
155     -WIDTH, -HEIGHT, WIDTH,
156     -WIDTH, -HEIGHT, -WIDTH,
157     WIDTH, HEIGHT, -WIDTH,
158     WIDTH, -HEIGHT, -WIDTH,
159     WIDTH, -HEIGHT, WIDTH,
160     WIDTH, HEIGHT, WIDTH
161 };
162 
163 u8  ColorRGBA8[] ATTRIBUTE_ALIGN(32) =
164 {
165     144,  48,   0,   0,
166     160,  64,   0,  16,
167     176,  80,   0,  32,
168     192,  96,   0,  48,
169     208, 112,   0,  64,
170     224, 128,   0,  80,
171     240, 144,  16,  96,
172     255, 160,  32, 112,
173     255, 176,  48, 128,
174     255, 192,  64, 144,
175     255, 208,  80, 160,
176     255, 224,  96, 176,
177     255, 240, 128, 192,
178     255, 255, 160, 208,
179     255, 255, 192, 224,
180     255, 255, 224, 240,
181     255, 255, 255, 255,
182     240, 255, 255, 255,
183     224, 255, 255, 255,
184     208, 255, 255, 255,
185     192, 240, 255, 255,
186     176, 224, 255, 255,
187     160, 208, 255, 255,
188     144, 192, 255, 255,
189 };  //GX_RGBA8
190 
191 u8 EmitterColorRGBA8[] ATTRIBUTE_ALIGN(32) =
192 {
193       0,   0,   0, 255,
194      72,  72, 255, 255,
195     140,  60, 140, 255,
196     80,  128,   0, 255,
197       0, 140, 160, 255,
198     255, 255, 255, 255,
199 };  //GX_RGBA8
200 
201 f32 FloatTex[] ATTRIBUTE_ALIGN(32) =
202 {   0.0F, 0.0F,
203     1.0F, 0.0F,
204     1.0F, 1.0F,
205     0.0F, 1.0F,
206     0.5F, 0.5F
207 };
208 
209 f32 FloatNorm[] ATTRIBUTE_ALIGN(32) =
210 {
211     -1.0F, 0.0F, 0.0F,
212     1.0F, 0.0F, 0.0F,
213     0.0F, -1.0F, 0.0F,
214     0.0F, 1.0F, 0.0F,
215     0.0F, 0.0F, -1.0F,
216     0.0F, 0.0F, 1.0F
217 };
218 
219 u8 MyPointTexture[4*8] ATTRIBUTE_ALIGN(32) =
220 {
221       0xaf, 0x0f, 0xf0, 0xf0,
222       0xff, 0x0f, 0xf0, 0xff,
223       0x00, 0x0f, 0xf0, 0x00,
224       0xff, 0xff, 0xff, 0xff,
225       0xff, 0xff, 0xff, 0xff,
226       0x00, 0x0f, 0xf0, 0x00,
227       0xff, 0x0f, 0xf0, 0xff,
228       0x0f, 0x0f, 0xf0, 0xf0
229 };  //GX_TF_I4
230 
231 
232 u32 CurrentControl = 0;
233 u32 TypeControl = 0;
234 u32 SizeAnimationControl = 0;
235 u32 NormalControl = 0;
236 u32 TexCoordControl = 0;
237 
238 u8  PositionShift = 0;
239 u8  NormalShift = 0;
240 u8  TexCoordShift = 0;
241 s32 FrameNumber;
242 
243 s16 GridOrder[TOTAL_SAMPLES];
244 
245 /*---------------------------------------------------------------------------*
246    Application main loop
247  *---------------------------------------------------------------------------*/
main(void)248 void main ( void )
249 {
250     DEMOInit(NULL);
251 
252     ParticleInit();
253     EmitterInit( &emMain );
254     DrawInit();         // Define my vertex formats and set array pointers.
255     PrintIntro();
256 
257     DEMOPadRead();      // Read the joystick for this frame
258 
259     // While the quit button is not pressed
260     while(!(DEMOPadGetButton(0) & PAD_BUTTON_MENU))
261     {
262         DEMOPadRead();  // Read the joystick for this frame
263 
264         AnimTick();     // Do animation based on input
265         DEMOBeforeRender();
266 
267         DrawTick();     // Draw the model.
268 
269         DEMODoneRender();
270     }
271 
272     OSHalt("End of test");
273 }
274 
275 /*---------------------------------------------------------------------------*
276    Functions
277  *---------------------------------------------------------------------------*/
278 
279 /*---------------------------------------------------------------------------*
280     Name:           TextureParticlesInit
281 
282     Description:    Initialize parameters for texture particles
283 
284     Arguments:      none
285 
286     Returns:        none
287  *---------------------------------------------------------------------------*/
TextureParticlesInit()288 static void TextureParticlesInit()
289 {
290     u32 nI, nJ, nK;
291     s16 nT;
292 
293     nJ=1;
294     for(nI=0; nI<TOTAL_SAMPLES; nI++)
295     {
296         //GridOrder[nI] = (s16)nI;
297         nJ = ((nJ*17)+19) % TOTAL_SAMPLES;
298         GridOrder[nI] = (s16)nJ;
299     }
300 
301     // Make a number of shuffles
302     for(nI=0; nI<511; nI++)
303     {
304         nJ = rndi() % TOTAL_SAMPLES;
305         nK = rndi() % TOTAL_SAMPLES;
306 
307         nT = GridOrder[nJ];
308         GridOrder[nJ] = GridOrder[nK];
309         GridOrder[nK] = nT;
310     }
311 }
312 
313 
314 #define LINE_SEGMENT        0x0001
315 #define PARTICLE_HAS_SIZE   0x0002
316 #define ANIMATE_SIZE        0x0004
317 #define INVERSE_ANIMATE     0x0008
318 /*---------------------------------------------------------------------------*
319     Name:           CameraInit
320 
321     Description:    Initialize the projection matrix and load into hardware.
322 
323     Arguments:      none
324     Returns:        none
325  *---------------------------------------------------------------------------*/
CameraInit(void)326 static void CameraInit      ( void )
327 {
328     Mtx44 p;
329     Vec camPt = {0.0F, 0.0F, 650.0F};
330     Vec up = {0.0F, 1.0F, 0.0F};
331 
332     MTXFrustum(p, 240, -240, -320, 320, 500, 2000);
333 
334     GXSetProjection(p, GX_PERSPECTIVE);
335 
336     cam.vPos = camPt;
337     cam.vUp = up;
338     cam.vpTarget = &emMain.vPos;
339 
340     MTXIdentity(v);
341 }
342 
343 /*---------------------------------------------------------------------------*
344     Name:           CameraUpdate
345 
346     Description:    Updates the camera object based on the joystick's state.
347 
348     Arguments:      s8 stickX, stickY    joystick direction (-127..+127, -127..+127)
349 
350     Returns:        none
351  *---------------------------------------------------------------------------*/
CameraUpdate(s8 stickX,s8 stickY)352 static void CameraUpdate(s8 stickX, s8 stickY)
353 {
354     Vec vVertical;
355     Vec vHorizontal;
356     Mtx m;
357 
358     vVertical.x = v[0][1];
359     vVertical.y = v[1][1];
360     vVertical.z = v[2][1];
361 
362     vHorizontal.x = v[0][0];
363     vHorizontal.y = v[1][0];
364     vHorizontal.z = v[2][0];
365 
366     MTXRotAxisDeg(m, &vHorizontal, (float)stickY * 0.01F);
367     MTXMultVec(m, &cam.vPos, &cam.vPos);
368     MTXRotAxisDeg(m, &vVertical, (float)stickX * 0.01F);
369     MTXMultVec(m, &cam.vPos, &cam.vPos);
370     MTXLookAt(v, &cam.vPos, &vVertical, cam.vpTarget);
371 }
372 
373 /*---------------------------------------------------------------------------*
374     Name:           DrawInit
375 
376     Description:    Calls the correct initialization function for the current
377                     model.
378 
379     Arguments:      none
380 
381     Returns:        none
382  *---------------------------------------------------------------------------*/
DrawInit(void)383 static void DrawInit( void )
384 {
385 
386     GXTexObj to;
387 
388     TPLGetPalette(&tpl, "gxTests/geo-00.tpl");
389 
390     TPLGetGXTexObjFromPalette(tpl, &to, 0);
391 
392     GXLoadTexObj(&to, GX_TEXMAP0);
393 
394     // init my point texture
395     GXInitTexObj(
396             &to,
397             MyPointTexture,
398             8, 8, // wd, ht
399             GX_TF_I4,
400             GX_CLAMP, GX_CLAMP,
401             GX_FALSE);
402 
403     GXLoadTexObj(&to, GX_TEXMAP1);
404 
405     CameraInit();   // Initialize the camera.
406 
407     GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA,
408         GX_LO_CLEAR);
409     GXSetZMode(FALSE, GX_ALWAYS, FALSE);
410 }
411 
412 /*---------------------------------------------------------------------------*
413     Name:           Options
414 
415     Description:    Selects test options
416 
417     Arguments:      u16 buttons     button status
418 
419     Returns:        none
420  *---------------------------------------------------------------------------*/
Options(u16 buttons)421 static void Options ( u16 buttons )
422 {
423     if (buttons & PAD_BUTTON_X)
424     {
425         CurrentControl = (CurrentControl + 1) % 3;
426 
427         switch(CurrentControl)
428         {
429             case 0:
430                 OSReport("\nParticle Type Control\n");
431                 break;
432             case 1:
433                 OSReport("\nPoint Size Animation Control\n");
434                 break;
435         }
436     }
437 
438     if (CurrentControl == 0)
439     {
440         if(buttons & PAD_BUTTON_B)
441         {
442             TypeControl = (TypeControl + 1) % 13;
443 
444             switch(TypeControl)
445             {
446                 case 0:
447                     OSReport("Particle Type - Points\n");
448                     emMain.nType &= ~LINE_SEGMENT;
449                     emMain.nType &= ~TEXTURE_PARTICLE;
450                     break;
451                 case 1:
452                     OSReport("Particle Type - Lines\n");
453                     emMain.nType |= LINE_SEGMENT;
454                     emMain.nType &= ~TEXTURE_PARTICLE;
455                     break;
456                 case 2:
457                     OSReport("Particle Type - Texture Points GX_TO_ZERO\n");
458                     emMain.nType &= ~LINE_SEGMENT;
459                     emMain.nType |= TEXTURE_PARTICLE;
460                     emMain.offset = GX_TO_ZERO;
461                     FrameNumber = -16;
462                     break;
463                 case 3:
464                     OSReport("Particle Type - Texture Points GX_TO_SIXTEENTH\n");
465                     emMain.nType &= ~LINE_SEGMENT;
466                     emMain.nType |= TEXTURE_PARTICLE;
467                     emMain.offset = GX_TO_SIXTEENTH;
468                     FrameNumber = -16;
469                     break;
470                 case 4:
471                     OSReport("Particle Type - Texture Points GX_TO_EIGHTH\n");
472                     emMain.nType &= ~LINE_SEGMENT;
473                     emMain.nType |= TEXTURE_PARTICLE;
474                     emMain.offset = GX_TO_EIGHTH;
475                     FrameNumber = -16;
476                     break;
477                 case 5:
478                     OSReport("Particle Type - Texture Points GX_TO_FOURTH\n");
479                     emMain.nType &= ~LINE_SEGMENT;
480                     emMain.nType |= TEXTURE_PARTICLE;
481                     emMain.offset = GX_TO_FOURTH;
482                     FrameNumber = -16;
483                     break;
484                 case 6:
485                     OSReport("Particle Type - Texture Points GX_TO_HALF\n");
486                     emMain.nType &= ~LINE_SEGMENT;
487                     emMain.nType |= TEXTURE_PARTICLE;
488                     emMain.offset = GX_TO_HALF;
489                     FrameNumber = -16;
490                     break;
491                 case 7:
492                     OSReport("Particle Type - Texture Points GX_TO_ONE\n");
493                     emMain.nType &= ~LINE_SEGMENT;
494                     emMain.nType |= TEXTURE_PARTICLE;
495                     emMain.offset = GX_TO_ONE;
496                     FrameNumber = -16;
497                     break;
498                 case 8: // bubble texture
499                     OSReport("Particle Type - Bubble Points GX_TO_ONE\n");
500                     emMain.nType &= ~LINE_SEGMENT;
501                     emMain.nType |= TEXTURE_PARTICLE;
502                     emMain.offset = GX_TO_ONE;
503                     FrameNumber = -16;
504                     break;
505                 case 9: // bubble texture
506                     OSReport("Particle Type - Bubble Points GX_TO_HALF\n");
507                     emMain.nType &= ~LINE_SEGMENT;
508                     emMain.nType |= TEXTURE_PARTICLE;
509                     emMain.offset = GX_TO_HALF;
510                     FrameNumber = -16;
511                     break;
512                 case 10: // bubble texture
513                     OSReport("Particle Type - Bubble Points GX_TO_FOURTH\n");
514                     emMain.nType &= ~LINE_SEGMENT;
515                     emMain.nType |= TEXTURE_PARTICLE;
516                     emMain.offset = GX_TO_FOURTH;
517                     FrameNumber = -16;
518                     break;
519                 case 11: // bubble texture
520                     OSReport("Particle Type - Bubble Points GX_TO_EIGHTH\n");
521                     emMain.nType &= ~LINE_SEGMENT;
522                     emMain.nType |= TEXTURE_PARTICLE;
523                     emMain.offset = GX_TO_EIGHTH;
524                     FrameNumber = -16;
525                     break;
526                 case 12: // bubble texture
527                     OSReport("Particle Type - Bubble Points GX_TO_SIXTEENTH\n");
528                     emMain.nType &= ~LINE_SEGMENT;
529                     emMain.nType |= TEXTURE_PARTICLE;
530                     emMain.offset = GX_TO_SIXTEENTH;
531                     FrameNumber = -16;
532                     break;
533             }
534         }
535     }
536     else if (CurrentControl == 1)
537     {
538         if (buttons & PAD_BUTTON_B)
539         {
540             SizeAnimationControl = (SizeAnimationControl + 1) % 3;
541 
542             switch (SizeAnimationControl)
543             {
544                 case 0:
545                     OSReport("Point Size - Constant per particle\n");
546                     emMain.nType &= ~ANIMATE_SIZE;
547                     break;
548                 case 1:
549                     OSReport("Point Size - Animated  per particle - Grow smaller\n");
550                     emMain.nType |= ANIMATE_SIZE;
551                     emMain.nType &= ~INVERSE_ANIMATE;
552                     break;
553                 case 2:
554                     OSReport("Point Size - Animated  per particle - Grow larger\n");
555                     emMain.nType |= ANIMATE_SIZE;
556                     emMain.nType |= INVERSE_ANIMATE;
557                     break;
558             }
559         }
560     }
561 
562 
563     if (buttons & PAD_TRIGGER_L) {
564         emMain.rSizeMean -= 10.0F;
565     }
566     if (buttons & PAD_TRIGGER_R) {
567         emMain.rSizeMean += 10.0F;
568     }
569 
570     if (emMain.rSizeMean < SIZE_MEAN)
571         emMain.rSizeMean = SIZE_MEAN;
572     if (emMain.rSizeMean > SIZE_MAX)
573         emMain.rSizeMean = SIZE_MAX;
574 
575     if (buttons & PAD_TRIGGER_L) {
576         OSReport("average size is %5.2f\n", emMain.rSizeMean*0.10F);
577     }
578     if (buttons & PAD_TRIGGER_R) {
579         OSReport("average size is %5.2f\n", emMain.rSizeMean*0.10F);
580     }
581 }
582 
srnd(u32 x)583 static void srnd( u32 x )
584 {
585     seed = x;
586 }
587 
rndi(void)588 static u32 rndi( void )
589 {
590 
591     seed = (seed * 1592653589UL) + 453816691UL;
592     return seed;
593 }
594 
rndf(void)595 static double rndf( void )  // 0 <= rndf() < 1
596 {
597     return (1.0 / (ULONG_MAX + 1.0)) * rndi();
598 }
599 
600 /*---------------------------------------------------------------------------*
601     Name:           Box Muller
602 
603     Description:    Generates normal random variants
604                     via the Box-Muller transform
605 
606     Arguments:      none
607 
608     Returns:        normal variant with mean 0 and standard deviation 1
609  *---------------------------------------------------------------------------*/
BoxMuller(void)610 static double BoxMuller( void )
611 {
612     double x1, x2, w, y1;
613     static double y2;
614     static int use_last = 0;
615 
616     if (use_last)                   // use value from previous call
617     {
618         y1 = y2;
619         use_last = 0;
620     }
621     else
622     {
623         do
624         {
625             x1 = 2.0 * rndf() - 1.0;
626             x2 = 2.0 * rndf() - 1.0;
627             w = (x1 * x1) + (x2 * x2);
628         } while ( w > 1.0 );
629 
630         w = sqrt( (-2.0 * log( w ) ) / w );
631         y1 = x1 * w;
632         y2 = x2 * w;
633         use_last = 1;
634     }
635     return y1;
636 }
637 
638 /*---------------------------------------------------------------------------*
639     Name:           ParticleInit
640 
641     Description:    Initializes the particle list pointers
642 
643     Arguments:      none
644 
645     Returns:        none
646  *---------------------------------------------------------------------------*/
ParticleInit(void)647 static void ParticleInit( void )
648 {
649     u32 nI;
650 
651     for(nI=1; nI<(MAX_PARTICLES+2); nI++)
652     {
653         ParticleData[nI-1].nNext = nI;
654     }
655     ParticleData[nI-1].nNext = 0;
656 
657     nNumActiveParticles = 0;
658 
659     TextureParticlesInit();
660 }
661 
662 /*---------------------------------------------------------------------------*
663     Name:           TextureParticleEmit
664 
665     Description:    Emits a texture particle, fixing its initial velocity so
666                     that it hits the target spot at a specified time
667 
668     Arguments:      Particle *prt   Pointer to the particle to be emitted
669                     Emitter *em     Pointer to the Emitter
670                     s16 nOrder
671 
672     Returns:        none
673  *---------------------------------------------------------------------------*/
TextureParticleEmit(Particle * prt,Emitter * em,s16 nOrder)674 static void TextureParticleEmit(Particle *prt, Emitter *em, s16 nOrder)
675 {
676     s32 nX = ((nOrder >> 4) & 0x3e) - 31;
677     s32 nY = ((nOrder << 1) & 0x3e) - 31;
678     s32 nT;
679     f32 rRT;     // Reciprocal of target time
680     Vec vDest;
681 
682     prt->nLifespan = 200;
683 
684     vDest.x = nX * 5.0F;
685     vDest.z = nY * 5.0F;
686     vDest.y = 200.0F;
687 
688     MTXMultVec(em->mModel, &vDest, &vDest);
689 
690     nT = EVENT_TIME - FrameNumber;
691     rRT = 1.0F / nT;
692 
693     prt->vVel.x = vDest.x * rRT;
694     prt->vVel.y = (vDest.y * rRT) - (GRAVITY * 0.5F * (nT - 1));
695     prt->vVel.z = vDest.z * rRT;
696 
697     prt->vPos.x = 0.0F;
698     prt->vPos.y = 0.0F;
699     prt->vPos.z = 0.0F;
700 
701     prt->tex_s = (nX * 0.015625F) + 0.5F;
702     prt->tex_t = (nY * -0.015625F) + 0.5F;
703 
704     prt->nType = em->nType;
705 
706     if (em->nType & PARTICLE_HAS_SIZE)
707     {
708         prt->nSize = (s32)((float)em->rSizeMean +
709         ((float)BoxMuller() * em->rSizeStdDev));
710     }
711 }
712 
713 /*---------------------------------------------------------------------------*
714     Name:           ParticleEmit
715 
716 
717     Description:    Emits a single particle, setting up its initial parameters
718 
719     Arguments:      Particle *prt   Pointer to the particle to be emitted
720                     Emitter *em     Pointer to the Emitter
721 
722     Returns:        none
723  *---------------------------------------------------------------------------*/
ParticleEmit(Particle * prt,Emitter * em)724 static void ParticleEmit(Particle *prt, Emitter *em)
725 {
726     float rW;
727 
728     // Normally distributed life spans
729     prt->nLifespan = (s32)((float)em->rLifespanMean +
730         ((float)BoxMuller() * em->rLifespanStdDev));
731 
732     do
733     {
734         prt->vVel.x = (float)(2 * rndf())-1;
735         prt->vVel.z = (float)(2 * rndf())-1;
736         rW = (prt->vVel.x * prt->vVel.x) +
737              (prt->vVel.z * prt->vVel.z);
738     }
739     while (rW > 1.0F);
740 
741     prt->vVel.x *= 0.5;
742     prt->vVel.z *= 0.5;
743     rW *= 0.25;
744 
745     prt->vVel.y = (float) sqrt( 1.0F - rW );
746 
747     VECScale(&prt->vVel, &prt->vVel, PARTICLE_SPEED);
748     MTXMultVec(em->mModel, &prt->vVel, &prt->vVel);
749 
750     VECScale(&prt->vVel, &prt->vPos, 2.5F);
751     VECAdd(&em->vPos, &prt->vPos, &prt->vPos);
752 
753     prt->nType = em->nType;
754 
755     if (em->nType & PARTICLE_HAS_SIZE)
756     {
757         prt->nSize = (s32)((float)em->rSizeMean +
758         ((float)BoxMuller() * em->rSizeStdDev));
759     }
760 }
761 
762 /*---------------------------------------------------------------------------*
763     Name:           EmitterEmit
764 
765     Description:    Emits one timestep's worth of particles
766 
767     Arguments:      Emitter *em     Pointer to the emitter
768 
769     Returns:        none
770  *---------------------------------------------------------------------------*/
EmitterEmit(Emitter * em)771 static void EmitterEmit(Emitter *em)
772 {
773     u32 nPrt, nI, nN, nTmp;
774 
775     nN = (u32)em->rEmitted;
776     em->rEmitted += em->rEmissionRate;
777     nN = (u32)em->rEmitted - nN;
778 
779 
780     if (em->nType & TEXTURE_PARTICLE)
781     {
782         FrameNumber++;
783 
784         if (FrameNumber > 250)
785         {
786             FrameNumber = 0;
787         }
788         else if ((FrameNumber < 0) || (FrameNumber > 128))
789         {
790             return;
791         }
792         nN = 8;
793     }
794 
795     nNumActiveParticles += nN;
796 
797     if (nNumActiveParticles > MAX_PARTICLES)
798     {
799         nN -= (nNumActiveParticles - MAX_PARTICLES);
800         nNumActiveParticles = MAX_PARTICLES;
801         OSReport("Particles Maxed Out!\n");
802     }
803 
804     if (nN == 0)
805     {
806         return;
807     }
808 
809     nPrt = FREE_LIST;
810 
811     if (em->nType & TEXTURE_PARTICLE)
812     {
813         for(nI=0; nI<nN; nI++)
814         {
815             nPrt = ParticleData[nPrt].nNext;
816             TextureParticleEmit(&ParticleData[nPrt], em,
817                 GridOrder[(FrameNumber<<3) + nI]);
818         }
819     }
820     else
821     {
822         for(nI=0; nI<nN; nI++)
823         {
824             nPrt = ParticleData[nPrt].nNext;
825             ParticleEmit(&ParticleData[nPrt], em);
826         }
827     }
828 
829     nTmp = ParticleData[ACTIVE_LIST].nNext;
830     ParticleData[ACTIVE_LIST].nNext = ParticleData[FREE_LIST].nNext;
831     ParticleData[FREE_LIST].nNext = ParticleData[nPrt].nNext;
832     ParticleData[nPrt].nNext = nTmp;
833 }
834 
835 /*---------------------------------------------------------------------------*
836     Name:           ParticleUpdate
837 
838     Description:    Updates the positions of all particles
839 
840     Arguments:      none
841 
842     Returns:        none
843  *---------------------------------------------------------------------------*/
ParticleUpdate(void)844 static void ParticleUpdate( void )
845 {
846     /*  The particles are stored in a list
847      *  Sequentially step through the list.
848      *  Decrement lifespan by 1 and if it becomes <0, remove the particle.
849      *  Update the position of remaining particles by adding velocity to position
850      *  Update the velocity of particles due to any force fields such as gravity
851      */
852 
853     u32 nPrt, *pPrev;
854     Particle *prt;
855 
856     pPrev = &ParticleData[ACTIVE_LIST].nNext;
857     nPrt = *pPrev;
858     for(; nPrt!=FREE_LIST; nPrt=*pPrev)
859     {
860         prt = &ParticleData[nPrt];
861         prt->nLifespan --;
862 
863         if (prt->nLifespan < 0)
864         {
865             // Remove particle from active list and add to head of free list
866 
867             *pPrev = prt->nNext;
868             prt->nNext = ParticleData[FREE_LIST].nNext;
869             ParticleData[FREE_LIST].nNext = nPrt;
870 
871             nNumActiveParticles--;
872         }
873         else
874         {
875             // Update particle
876 
877             VECAdd(&prt->vPos, &prt->vVel, &prt->vPos);
878             prt->vVel.y += GRAVITY;
879             pPrev = &prt->nNext;
880         }
881     }
882 }
883 
884 /*---------------------------------------------------------------------------*/
SendParticlePoint(Vec * vPoint,u8 colorIndex)885 static inline void SendParticlePoint( Vec *vPoint, u8 colorIndex )
886 {
887     GXPosition3f32(vPoint->x, vPoint->y, vPoint->z);
888     GXColor1x8(colorIndex);
889     GXTexCoord2f32( 0.5F, 0.5F ); //texCoordIndex);
890 }
891 
892 /*---------------------------------------------------------------------------*/
SendParticleLine(Vec * vPoint1,Vec * vDelta,u8 colorIndex)893 static inline void SendParticleLine( Vec *vPoint1, Vec *vDelta, u8 colorIndex )
894 {
895     GXPosition3f32(vPoint1->x - vDelta->x * 2,
896                    vPoint1->y - vDelta->y * 2,
897                    vPoint1->z - vDelta->z * 2);
898     GXColor1x8(colorIndex);
899     GXTexCoord2f32( 0.0F, 0.0F ); //texCoordIndex);
900 
901     GXPosition3f32(vPoint1->x + vDelta->x * 2,
902                    vPoint1->y + vDelta->y * 2,
903                    vPoint1->z + vDelta->z * 2);
904     GXColor1x8(colorIndex);
905     GXTexCoord2f32( 0.0F, 1.0F ); //texCoordIndex);
906 }
907 
908 /*---------------------------------------------------------------------------*/
SendTexturePoint(Vec * vPoint,f32 s,f32 t)909 static inline void SendTexturePoint( Vec *vPoint, f32 s, f32 t )
910 {
911     GXPosition3f32(vPoint->x, vPoint->y, vPoint->z);
912     GXColor1x8(16);
913     GXTexCoord2f32(s, t);
914 }
915 
916 /*---------------------------------------------------------------------------*
917     Name:           DrawParticles
918 
919     Description:    Draws the particles
920 
921     Arguments:      none
922 
923     Returns:        none
924  *---------------------------------------------------------------------------*/
DrawParticles(void)925 static void DrawParticles( void )
926 {
927     Mtx mv;
928     u32 nPrt;
929     Particle *prt;
930 
931     GXClearVtxDesc();
932 
933     // Set Position Params
934 
935     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, PositionShift);
936     GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
937     GXSetArray(GX_VA_POS, &ParticleData[0].vPos, sizeof(Particle));
938 
939     // Set Color Params
940 
941     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
942     GXSetVtxDesc(GX_VA_CLR0, GX_INDEX8);
943     GXSetArray(GX_VA_CLR0, ColorRGBA8, 4);
944 
945     GXSetNumChans(1);
946     GXSetChanCtrl(
947         GX_COLOR0,
948         GX_FALSE,   // enable channel
949         GX_SRC_VTX, // amb source
950         GX_SRC_VTX, // mat source
951         GX_LIGHT0,  // light mask
952         GX_DF_CLAMP,// diffuse function
953         GX_AF_NONE);
954     GXSetChanCtrl(
955         GX_ALPHA0,
956         GX_FALSE,   // enable channel
957         GX_SRC_VTX, // amb source
958         GX_SRC_VTX, // mat source
959         GX_LIGHT0,  // light mask
960         GX_DF_CLAMP,// diffuse function
961         GX_AF_NONE);
962 
963     // Set Tex Coord Params
964     GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
965 
966     // 8-bit indexed floating point texture coordinates
967     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, TexCoordShift);
968     GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
969 
970     // Setup Transforms
971 
972     MTXCopy(v, mv);
973     GXLoadPosMtxImm(mv, GX_PNMTX0);
974     MTXInverse(mv, mv);
975     MTXTranspose(mv, mv);
976     GXLoadNrmMtxImm(mv, GX_PNMTX0);
977 
978     nPrt = ParticleData[ACTIVE_LIST].nNext;
979 
980     //GXBegin(GX_POINTS, GX_VTXFMT0, (u16)nNumActiveParticles);
981     for(; nPrt!=FREE_LIST; nPrt=prt->nNext)
982     {
983         prt = &ParticleData[nPrt];
984 
985         if (prt->nType & TEXTURE_PARTICLE)
986         {
987             GXSetNumTexGens(1); // Use one texture coord
988             // undocumented function
989             GXEnableTexOffsets(GX_TEXCOORD0, GX_FALSE, GX_TRUE);
990 
991             if (TypeControl >= 8 && TypeControl <= 12) // Bubble texture
992             {
993                 GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP1, GX_COLOR0A0);
994                 GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
995             }
996             else
997             {
998                 GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
999                 GXSetTevOp(GX_TEVSTAGE0, GX_MODULATE);
1000             }
1001 
1002             if (prt->nType & ANIMATE_SIZE)
1003             {
1004                 if (prt->nType & INVERSE_ANIMATE)
1005                 {
1006                     GXSetPointSize((u8)((prt->nSize + 200 - prt->nLifespan)*0.10), emMain.offset);
1007                 }
1008                 else
1009                 {
1010                     GXSetPointSize((u8)((prt->nSize + prt->nLifespan)*0.10), emMain.offset);
1011                 }
1012             }
1013             else
1014             {
1015                 GXSetPointSize((u8)(prt->nSize*0.10), emMain.offset);
1016             }
1017             GXBegin(GX_POINTS, GX_VTXFMT0, 1);
1018             if (TypeControl >= 8 && TypeControl <= 12)
1019                 SendTexturePoint( &prt->vPos, 0.0F, 0.0F );
1020             else
1021                 SendTexturePoint( &prt->vPos, prt->tex_s, prt->tex_t );
1022             GXEnd();
1023             continue;
1024         }
1025 
1026         GXSetNumTexGens(0);  // Use no texture (coord)
1027         GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
1028         GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
1029 
1030         if (prt->nType & LINE_SEGMENT)
1031         {
1032             if (prt->nType & PARTICLE_HAS_SIZE)
1033             {
1034                 if (prt->nType & ANIMATE_SIZE)
1035                 {
1036                     if (prt->nType & INVERSE_ANIMATE)
1037                     {
1038                         GXSetLineWidth((u8)((prt->nSize + 200 - prt->nLifespan)*0.05), GX_TO_ZERO);
1039                     }
1040                     else
1041                     {
1042                         GXSetLineWidth((u8)((prt->nSize + prt->nLifespan)*0.05), GX_TO_ZERO);
1043                     }
1044                 }
1045                 else
1046                 {
1047                     GXSetLineWidth((u8)(prt->nSize*0.06), GX_TO_ZERO);
1048                 }
1049             }
1050 
1051             GXBegin(GX_LINES, GX_VTXFMT0, 2);
1052             SendParticleLine(&prt->vPos, &prt->vVel, (u8)(prt->nLifespan>>3));
1053             GXEnd();
1054         }
1055         else
1056         {
1057             if (prt->nType & PARTICLE_HAS_SIZE)
1058             {
1059                 if (prt->nType & ANIMATE_SIZE)
1060                 {
1061                     if (prt->nType & INVERSE_ANIMATE)
1062                     {
1063                         GXSetPointSize((u8)((prt->nSize + 200 - prt->nLifespan)*0.10), GX_TO_ZERO);
1064                     }
1065                     else
1066                     {
1067                         GXSetPointSize((u8)((prt->nSize + prt->nLifespan)*0.10), GX_TO_ZERO);
1068                     }
1069                 }
1070                 else
1071                 {
1072                     GXSetPointSize((u8)(prt->nSize*0.12), GX_TO_ZERO);
1073                 }
1074             }
1075             GXBegin(GX_POINTS, GX_VTXFMT0, 1);
1076             SendParticlePoint(&prt->vPos, (u8)(prt->nLifespan>>3));
1077             GXEnd();
1078         }
1079     }
1080     //GXEnd();
1081 }
1082 
1083 /*---------------------------------------------------------------------------*
1084     Name:           EmitterInit
1085 
1086     Description:    Initializes an emitter
1087 
1088     Arguments:      Emitter *em     Pointer to the emitter
1089 
1090     Returns:        none
1091  *---------------------------------------------------------------------------*/
EmitterInit(Emitter * em)1092 static void EmitterInit( Emitter *em )
1093 {
1094     MTXIdentity( em->mModel );
1095     em->vLinVel.x = em->vLinVel.y = em->vLinVel.z = 0.0F;
1096     em->vAngVel = em->vLinVel;
1097     em->rEmitted = 0.0F;
1098     em->rEmissionRate   = EMMISION_RATE;
1099     em->rLifespanMean   = LIFESPAN_MEAN;
1100     em->rLifespanStdDev = LIFESPAN_STDDEV;
1101     em->rSizeMean       = SIZE_MEAN;
1102     em->rSizeStdDev     = SIZE_STDDEV;
1103     em->nType           = PARTICLE_HAS_SIZE;
1104 }
1105 
1106 /*---------------------------------------------------------------------------*
1107     Name:           EmitterUpdate
1108 
1109     Description:    Emits one timestep's worth of particles
1110 
1111     Arguments:      Emitter *em     Pointer to the emitter
1112                     s8 rotX         amount to rotate about vertical
1113                     s8 rotY         amount to rotate about horizontal
1114 
1115     Returns:        none
1116  *---------------------------------------------------------------------------*/
EmitterUpdate(Emitter * em,s8 rotX,s8 rotY)1117 static void EmitterUpdate(Emitter *em, s8 rotX, s8 rotY)
1118 {
1119     Vec vVertical;
1120     Vec vHorizontal;
1121     Mtx m;
1122 
1123     vVertical.x = v[0][1];
1124     vVertical.y = v[1][1];
1125     vVertical.z = v[2][1];
1126 
1127     vHorizontal.x = v[0][0];
1128     vHorizontal.y = v[1][0];
1129     vHorizontal.z = v[2][0];
1130 
1131     MTXRotAxisDeg(m, &vHorizontal, (float)rotY * 0.01F);
1132     MTXConcat(m, em->mModel, em->mModel);
1133     MTXRotAxisDeg(m, &vVertical, (float)rotX * 0.01F);
1134     MTXConcat(m, em->mModel, em->mModel);
1135 }
1136 
1137 /*---------------------------------------------------------------------------*/
SendEmitterVertex(u8 posIndex,u8 normalIndex,u8 colorIndex,u8 texCoordIndex)1138 static void SendEmitterVertex ( u8 posIndex, u8 normalIndex,
1139                                 u8 colorIndex, u8 texCoordIndex )
1140 {
1141     GXPosition1x8(posIndex);
1142     GXNormal1x8(normalIndex);
1143     GXColor1x8(colorIndex);
1144     GXTexCoord1x8(texCoordIndex);
1145 }
1146 
1147 /*---------------------------------------------------------------------------*
1148     Name:           DrawEmitter
1149 
1150     Description:    Draws the emitter
1151 
1152     Arguments:      none
1153 
1154     Returns:        none
1155  *---------------------------------------------------------------------------*/
DrawEmitter(void)1156 static void DrawEmitter( void )
1157 {
1158     Mtx mv;
1159 
1160     GXClearVtxDesc();
1161 
1162     // Set Position Params
1163 
1164     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, PositionShift);
1165     GXSetVtxDesc(GX_VA_POS, GX_INDEX8);
1166     GXSetArray(GX_VA_POS, FloatVert, 12);
1167 
1168     // Set Normal Params
1169 
1170     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, NormalShift);
1171     GXSetVtxDesc(GX_VA_NRM, GX_INDEX8);
1172     GXSetArray(GX_VA_NRM, FloatNorm, 12);
1173     /*
1174     GXSetChanCtrl(
1175         GX_COLOR0,
1176         GX_FALSE,   // enable channel
1177         GX_SRC_VTX, // amb source
1178         GX_SRC_VTX, // mat source
1179         GX_LIGHT0,  // light mask
1180         GX_DF_CLAMP,// diffuse function
1181         GX_AF_NONE);
1182     */
1183 
1184     // Set Color Params
1185 
1186     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
1187     GXSetVtxDesc(GX_VA_CLR0, GX_INDEX8);
1188     GXSetArray(GX_VA_CLR0, EmitterColorRGBA8, 4);
1189 
1190     GXSetNumChans(1);
1191     GXSetChanCtrl(
1192         GX_COLOR0,
1193         GX_FALSE,   // enable channel
1194         GX_SRC_VTX, // amb source
1195         GX_SRC_VTX, // mat source
1196         GX_LIGHT0,  // light mask
1197         GX_DF_CLAMP,// diffuse function
1198         GX_AF_NONE);
1199     GXSetChanCtrl(
1200         GX_ALPHA0,
1201         GX_FALSE,   // enable channel
1202         GX_SRC_REG, // amb source
1203         GX_SRC_VTX, // mat source
1204         GX_LIGHT0,  // light mask
1205         GX_DF_CLAMP,// diffuse function
1206         GX_AF_NONE);
1207 
1208     // Set Tex Coord Params
1209     GXSetNumTexGens( 1 );
1210     GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
1211     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
1212     GXSetTevOp(GX_TEVSTAGE0, GX_MODULATE); //GX_REPLACE);
1213 
1214 
1215     // 8-bit indexed floating point texture coordinates
1216     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, TexCoordShift);
1217     GXSetVtxDesc(GX_VA_TEX0, GX_INDEX8);
1218     GXSetArray(GX_VA_TEX0, FloatTex, 8);
1219 
1220     // Setup Transforms
1221 
1222     MTXConcat(v, emMain.mModel, mv);
1223     emMain.mModel[0][3] = emMain.vPos.x;
1224     emMain.mModel[1][3] = emMain.vPos.y;
1225     emMain.mModel[2][3] = emMain.vPos.z;
1226     GXLoadPosMtxImm(mv, GX_PNMTX0);
1227     MTXInverse(mv, mv);
1228     MTXTranspose(mv, mv);
1229     GXLoadNrmMtxImm(mv, GX_PNMTX0);
1230 
1231     // Send Geometry
1232 
1233     GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, 4);
1234 
1235         SendEmitterVertex(1, 0, 2, 1);
1236         SendEmitterVertex(2, 0, 2, 2);
1237         SendEmitterVertex(0, 0, 1, 0);
1238         SendEmitterVertex(3, 0, 1, 3);
1239 
1240     GXEnd();
1241 
1242     GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, 4);
1243 
1244         SendEmitterVertex(5, 1, 3, 1);
1245         SendEmitterVertex(6, 1, 4, 2);
1246         SendEmitterVertex(4, 1, 3, 0);
1247         SendEmitterVertex(7, 1, 4, 3);
1248 
1249     GXEnd();
1250 
1251     GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, 4);
1252 
1253         SendEmitterVertex(6, 2, 0, 1);
1254         SendEmitterVertex(5, 2, 0, 2);
1255         SendEmitterVertex(2, 2, 0, 0);
1256         SendEmitterVertex(3, 2, 0, 3);
1257 
1258     GXEnd();
1259 
1260     GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, 4);
1261 
1262         SendEmitterVertex(0, 3, 5, 1);
1263         SendEmitterVertex(4, 3, 5, 2);
1264         SendEmitterVertex(1, 3, 5, 0);
1265         SendEmitterVertex(7, 3, 5, 3);
1266 
1267     GXEnd();
1268 
1269     GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, 4);
1270 
1271         SendEmitterVertex(4, 4, 3, 1);
1272         SendEmitterVertex(0, 4, 1, 2);
1273         SendEmitterVertex(5, 4, 3, 0);
1274         SendEmitterVertex(3, 4, 1, 3);
1275 
1276     GXEnd();
1277 
1278     GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, 4);
1279 
1280         SendEmitterVertex(2, 5, 2, 1);
1281         SendEmitterVertex(1, 5, 2, 2);
1282         SendEmitterVertex(6, 5, 4, 0);
1283         SendEmitterVertex(7, 5, 4, 3);
1284 
1285     GXEnd();
1286 }
1287 
1288 /*---------------------------------------------------------------------------*
1289     Name:           AnimTick
1290 
1291     Description:    Updates the objects in the world by one timestep
1292 
1293     Arguments:      none
1294 
1295     Returns:        none
1296  *---------------------------------------------------------------------------*/
AnimTick(void)1297 static void AnimTick ( void )
1298 {
1299     u16 buttons = DEMOPadGetButton(0);
1300     u16 down    = DEMOPadGetButtonDown(0);
1301     s8 stickX = DEMOPadGetStickX(0);
1302     s8 stickY = DEMOPadGetStickY(0);
1303 
1304     EmitterUpdate(&emMain, stickX, stickY);
1305 
1306     if (!(buttons & PAD_BUTTON_A))
1307     {
1308         EmitterEmit(&emMain);
1309         ParticleUpdate();
1310     }
1311 
1312     CameraUpdate(0, 0);
1313     Options(down);
1314 }
1315 
1316 /*---------------------------------------------------------------------------*
1317     Name:           DrawTick
1318 
1319     Description:    Draw the current model once.
1320 
1321     Arguments:      v       view matrix
1322                     m       model matrix
1323 
1324     Returns:        none
1325  *---------------------------------------------------------------------------*/
DrawTick(void)1326 static void DrawTick( void )
1327 {
1328     DrawEmitter();
1329     DrawParticles();
1330 }
1331 
1332 /*---------------------------------------------------------------------------*
1333     Name:           PrintIntro
1334 
1335     Description:    Prints the directions on how to use this demo.
1336 
1337     Arguments:      none
1338 
1339     Returns:        none
1340  *---------------------------------------------------------------------------*/
PrintIntro(void)1341 static void PrintIntro( void )
1342 {
1343     OSReport("\n\n****************************************************\n");
1344     OSReport(" geo-particle - demonstrate paritcle effects\n");
1345     OSReport("****************************************************\n");
1346     OSReport("BUTTON X:  Particle Type/Particle Animation control mode\n");
1347     OSReport("BUTTON B:  Select a type or animation\n");
1348     OSReport("BUTTON A:  Pause animation\n");
1349     OSReport("\n");
1350     OSReport("TRIGGER R: Increase average size of points\n");
1351     OSReport("TRIGGER L: Decrease average size of points\n");
1352     OSReport("\n");
1353     OSReport("to quit hit the menu button\n");
1354     OSReport("*******************************************************\n");
1355     OSReport("\n\n");
1356 }
1357 
1358 
1359