1 /*---------------------------------------------------------------------------*
2   Project:  3D sound demo for AX
3   File:     axart3ddemo.c
4 
5   Copyright (C)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   $Log: axart3ddemo.c,v $
14   Revision 1.11  2006/11/21 08:14:48  aka
15   Removed the zero buffer.
16 
17   Revision 1.10  2006/10/23 02:05:52  aka
18   Changed from AXInit() to AXInitSpecifyMem().
19   Changed from MIXInit() to MIXInitSpecifyMem().
20   Changed from SYNInit() to SYNInitSpecifyMem().
21 
22   Revision 1.9  2006/10/10 08:30:06  aka
23   Revised AXInit(), MIXInit() and SYNInit().
24 
25   Revision 1.8  2006/03/06 09:59:03  kawaset
26   Eliminated warnings.
27 
28   Revision 1.7  2006/02/21 01:04:15  mitu
29   modified am.h path.
30 
31   Revision 1.6  2006/02/20 04:13:07  mitu
32   changed include path from dolphin/ to revolution/.
33 
34   Revision 1.5  2006/02/02 07:44:31  aka
35   Modified using MEM functions instead of OSAlloc()/OSFree().
36 
37   Revision 1.4  2006/02/01 07:59:03  aka
38   Added #ifndef(#ifdef) HOLLYWOOD_REV - #else - #endif.
39 
40   Revision 1.3  2006/02/01 04:26:20  aka
41   Added cast from u32 to u8* in relation to changing API around ARAM.
42 
43   Revision 1.2  2005/11/08 02:55:02  aka
44   Changed suiting to Revolution's audio spec.
45 
46   Revision 1.1  2005/11/04 05:01:39  aka
47   Imported from dolphin tree.
48 
49     9     03/04/24 11:43 Suzuki
50     Changed the effect from reverbHiDpl2 to reverbHi(This part is commented
51     out).
52 
53     8     03/04/09 15:23 Suzuki
54     shift AuxA and AuxB volume left by 16bit.
55 
56     7     03/04/01 16:19 Sak
57     murakami: modify to use atan2f in place of atan
58 
59     7     02/10/23 3:13p Suzuki
60     replaced the turn of AXARTServiceSounds and MIXUpdateSettings.
61 
62     5     4/11/02 1:59p Billyjack
63 
64     4     1/08/02 6:42p Billyjack
65     - Added DPL2 support
66 
67     3     9/05/01 4:33p Eugene
68     Updated AM API.
69 
70     2     8/29/01 1:52p Billyjack
71 
72     1     8/20/01 6:05p Billyjack
73     created
74 
75     1     7/06/01 11:50a Billyjack
76     created
77   $NoKeywords: $
78 
79  *---------------------------------------------------------------------------*/
80 
81 #include <math.h>
82 #include <string.h>
83 #include <demo.h>
84 #include <revolution/mix.h>
85 #include <revolution/axart.h>
86 #include <revolution/sp.h>
87 #include <revolution/mem.h>
88 
89 #include "axartdemo.h"  // symbols from sndconv
90 
91 /*---------------------------------------------------------------------------*
92  * Exp Heap
93  *---------------------------------------------------------------------------*/
94 
95 static MEMHeapHandle hExpHeap;
96 
97 /*---------------------------------------------------------------------------*
98     local type used for 3D sound object
99  *---------------------------------------------------------------------------*/
100 typedef struct
101 {
102 
103     AXVPB               *voice;
104     SPSoundEntry        *sound;
105     AXART_SOUND         axartSound;
106     AXART_3D            axart3d;
107     AXART_PITCH         axartPitch;     // additional pitch cents
108     AXART_VOLUME        axartVolume;    // additional attenuation
109     AXART_AUXA_VOLUME   axartAuxAVolume;// set volume for aux A
110     AXART_AUXB_VOLUME   axartAuxBVolume;// set volume for aux B
111     AXART_AUXC_VOLUME   axartAuxCVolume;// set volume for aux C
112 
113 } soundObject;
114 
115 // two sound objects used by demo
116 static soundObject  helicopter;
117 static soundObject  cube;
118 
119 // additonal articulators for making LFO effects with cube
120 static AXART_PITCH_MOD  cubePitchMod[2];
121 static AXART_VOLUME_MOD cubeVolumeMod[2];
122 
123 static u8           *soundSamples;
124 static SPSoundTable *soundTable;
125 
126 /*---------------------------------------------------------------------------*
127     Callback for AX audio frames, for this demo we need to tell AX3D to update
128     sound sources then run the mixer as AX3D will apply setting to the mixer
129  *---------------------------------------------------------------------------*/
callbackAudioFrame(void)130 static void callbackAudioFrame(void)
131 {
132     AXARTServiceSounds();
133     MIXUpdateSettings();
134 }
135 
136 
137 /*---------------------------------------------------------------------------*
138     Some stuff for video
139  *---------------------------------------------------------------------------*/
140 // Constants
141 #define GRID_LENGTH   95
142 #define GRID_SEGS     19
143 
144 // Local structures
145 typedef struct
146 {
147     Vec        xAxis;
148     Vec        yAxis;
149     Vec        zAxis;
150     Vec        translate;
151 
152     f32        fov;
153     f32        aspect;
154     f32        near;
155     f32        far;
156 
157     Mtx        viewMtx;
158 
159 } CameraObj;
160 
161 // Forward references
162 void            main            ( void );
163 
164 static void     DrawInit        ( void );
165 static void     DrawTick        ( void );
166 static void     AnimTick        ( void );
167 
168 static void     CameraLoad      ( CameraObj *newCam );
169 static void     CameraUpdate    ( CameraObj *camera );
170 
171 static void     DrawGrid        ( void );
172 static void     DrawUI          ( void );
173 
174 // Global variables
175 CameraObj DefaultCamera =
176 {
177     {1.0f, 0.0f, 0.0f},
178     {0.0f, 0.0f, 1.0f},
179     {0.0f,-1.0f, 0.0f},
180     {0.0f, 0.0f, 2.0f},
181     45.0f,
182     4.0f / 3.0f,
183     0.1f,
184     1024.0f
185 };
186 
187 u32              Quit = 0;
188 CameraObj        Camera;
189 GXLightObj       Light;
190 
191 Vec              WorldXAxis = { 1, 0, 0 };
192 Vec              WorldYAxis = { 0, 1, 0 };
193 Vec              WorldZAxis = { 0, 0, 1 };
194 
195 Vec              BallPosition = { 40, 0, 0 };
196 f32              BallRotation = 0.0f;
197 Mtx              ModelMtx;
198 
199 Vec              CubePosition = { 0, 0, 0 };
200 
201 f32              CubeRadius = 5.0f;
202 
203 GXRenderModeObj *RenderMode;
204 
205 /*---------------------------------------------------------------------------*
206  *---------------------------------------------------------------------------*/
voiceDrop(void * p)207 static void voiceDrop(void *p)
208 {
209     // if a voice is dropped we need to get rid of references to it so it is
210     // no longer serviced for that instance of soundObject...
211     // we stored the pointer to the soundObject in the voice for just such an
212     // occation
213     soundObject *so = (soundObject*)(((AXVPB*)p)->userContext);
214 
215     if (so)
216     {
217         // we are using the so->voice as a flag to service the axart3D
218         so->voice = NULL;
219 
220         // remove the sound from AXART
221         AXARTRemoveSound(&so->axartSound);
222     }
223 }
224 
225 
226 /*---------------------------------------------------------------------------*
227     Name:           startSound
228 
229     Description:    start halicopter and cube sound
230 
231     Arguments:      so  , pointer to static soundObject
232                     st  , pointer to sound table
233                     i   , index of sound to start
234 
235     Returns:        none
236  *---------------------------------------------------------------------------*/
startSound(soundObject * so,SPSoundTable * st,u32 i)237 static void startSound(soundObject *so, SPSoundTable *st, u32 i)
238 {
239     // allocate voice for sound object
240     so->voice = AXAcquireVoice(15, &voiceDrop, (u32)so);
241 
242     if (so->voice)
243     {
244         // get sound entry
245         so->sound = SPGetSoundEntry(st, i);
246 
247         if (so->sound)
248         {
249             // prepare the sound addressing
250             SPPrepareSound(so->sound, so->voice, 0);
251 
252             // initialize the AXART_SOUND
253             AXARTInitSound      (&so->axartSound, so->voice, so->sound->sampleRate);
254 
255             // initialize articulators
256             AXARTInitArt3D          (&so->axart3d);
257             AXARTInitArtPitch       (&so->axartPitch);
258             AXARTInitArtVolume      (&so->axartVolume);
259             AXARTInitArtAuxAVolume  (&so->axartAuxAVolume);
260             AXARTInitArtAuxBVolume  (&so->axartAuxBVolume);
261             AXARTInitArtAuxCVolume  (&so->axartAuxCVolume);
262 
263             // turn the Aux sends to 0
264             so->axartAuxAVolume.attenuation = -904 << 16;
265             so->axartAuxBVolume.attenuation = -904 << 16;
266             so->axartAuxCVolume.attenuation = -904 << 16;
267 
268             // add articulators to sound
269             AXARTAddArticulator (&so->axartSound, (AXART_ART*)&so->axart3d);
270             AXARTAddArticulator (&so->axartSound, (AXART_ART*)&so->axartPitch);
271             AXARTAddArticulator (&so->axartSound, (AXART_ART*)&so->axartVolume);
272             AXARTAddArticulator (&so->axartSound, (AXART_ART*)&so->axartAuxAVolume);
273             AXARTAddArticulator (&so->axartSound, (AXART_ART*)&so->axartAuxBVolume);
274             AXARTAddArticulator (&so->axartSound, (AXART_ART*)&so->axartAuxCVolume);
275 
276             // add sound to sound list
277             AXARTAddSound(&so->axartSound);
278 
279             // start the sound
280             AXSetVoiceState(so->voice, AX_PB_STATE_RUN);
281         }
282         else
283         {
284             // free the voice if we are not going to use it
285             AXFreeVoice(so->voice);
286         }
287     }
288 }
289 
290 
291 /*---------------------------------------------------------------------------*
292  *---------------------------------------------------------------------------*/
addModToCube(void)293 static void addModToCube(void)
294 {
295     // adjust volume on cube using volume articulator alreadt installed
296 //    cube.axartVolume.attenuation = -960 << 16;
297     cube.axartVolume.attenuation = -150 << 16;
298 //    cube.axartPitch.cents = -1200 << 16;
299 
300     // initialize articulators
301     AXARTInitArtPitchMod(&cubePitchMod[0]);
302     AXARTInitArtPitchMod(&cubePitchMod[1]);
303     AXARTInitArtVolumeMod(&cubeVolumeMod[0]);
304     AXARTInitArtVolumeMod(&cubeVolumeMod[1]);
305 
306     // initialize LFOs
307     AXARTInitLfo(&cubePitchMod[0].lfo, AXARTSine, AXART_SINE_SAMPLES, (0.3f * AXART_SINE_SAMPLES) / 200);
308     AXARTInitLfo(&cubePitchMod[1].lfo, AXARTSine, AXART_SINE_SAMPLES, (5.0f * AXART_SINE_SAMPLES) / 200);
309     AXARTInitLfo(&cubeVolumeMod[0].lfo, AXARTSaw, AXART_SAW_SAMPLES, (1.0f * AXART_SAW_SAMPLES) / 200);
310     AXARTInitLfo(&cubeVolumeMod[1].lfo, AXARTSine, AXART_SINE_SAMPLES, (3.0f * AXART_SINE_SAMPLES) / 200);
311 
312     // assigne pitch and attenuation for articulators
313     cubePitchMod[0].cents = -500 << 16;
314     cubePitchMod[1].cents = 500 << 16;
315     cubeVolumeMod[0].attenuation = -30 << 16;
316     cubeVolumeMod[1].attenuation = 30 << 16;
317 
318     // add articulators to sound
319     AXARTAddArticulator(&cube.axartSound, (AXART_ART*)&cubePitchMod[0]);
320     AXARTAddArticulator(&cube.axartSound, (AXART_ART*)&cubePitchMod[1]);
321     AXARTAddArticulator(&cube.axartSound, (AXART_ART*)&cubeVolumeMod[0]);
322     AXARTAddArticulator(&cube.axartSound, (AXART_ART*)&cubeVolumeMod[1]);
323 }
324 
325 
326 /*---------------------------------------------------------------------------*
327  *---------------------------------------------------------------------------*/
killSound(soundObject * so)328 static void killSound(soundObject *so)
329 {
330     if (so->voice)
331     {
332         // remove the sound from AXART
333         AXARTRemoveSound(&so->axartSound);
334 
335         // free tyhe voice
336         AXFreeVoice(so->voice);
337 
338         // we are using the so->voice as a flag to service the axart3D
339         so->voice = NULL;
340     }
341 }
342 
343 
344 /*---------------------------------------------------------------------------*
345  *---------------------------------------------------------------------------*/
LoadFileIntoRam(char * path)346 static void* LoadFileIntoRam(char *path)
347 {
348     DVDFileInfo handle;
349     u32         round_length;
350     s32         read_length;
351     void        *buffer;
352 
353     // Open File
354     if (!DVDOpen(path, &handle))
355     {
356         OSReport("WARNING! Failed to open %s\n", path);
357         return NULL;
358     }
359 
360     // Make sure file length is not 0
361     if (DVDGetLength(&handle) == 0)
362     {
363         OSReport("WARNING! File length is 0\n");
364         return NULL;
365     }
366 
367     round_length = OSRoundUp32B(DVDGetLength(&handle));
368     buffer       = MEMAllocFromExpHeapEx(hExpHeap, round_length,  32);
369 
370     // Make sure we got a buffer
371     if (buffer == NULL)
372     {
373         OSReport("WARNING! Unable to allocate buffer\n");
374         return NULL;
375     }
376 
377     // Read Files
378     read_length = DVDRead(&handle, buffer, (s32)(round_length), 0);
379 
380     // Make sure we read the file correctly
381     if (read_length <= 0)
382     {
383         OSReport("WARNING! File lenght is wrong\n");
384         return NULL;
385     }
386 
387     return buffer;
388 }
389 
390 
391 /*---------------------------------------------------------------------------*
392     Name:           main
393 
394     Description:    The main application loop
395 
396     Arguments:      none
397 
398     Returns:        none
399  *---------------------------------------------------------------------------*/
main(void)400 void main (void)
401 {
402     void       *arenaMem2Lo;
403     void       *arenaMem2Hi;
404     void       *axBuffer;
405     void       *mixBuffer;
406 
407     DEMOInit( NULL );
408     DrawInit();
409 
410     // initialize Exp Heap on MEM2
411     arenaMem2Lo = OSGetMEM2ArenaLo();
412     arenaMem2Hi = OSGetMEM2ArenaHi();
413     hExpHeap    = MEMCreateExpHeap(arenaMem2Lo, (u32)arenaMem2Hi - (u32) arenaMem2Lo);
414 
415     // initialize AI subsystem
416     AIInit(NULL);
417 
418     // initialize AX, MIXer and AXART
419     axBuffer  = MEMAllocFromExpHeapEx(hExpHeap, AXGetMemorySize(AX_MAX_VOICES), 32);
420     mixBuffer = MEMAllocFromExpHeap(hExpHeap, MIXGetMemorySize(AX_MAX_VOICES));
421 
422     AXInitSpecifyMem(AX_MAX_VOICES, axBuffer);
423     MIXInitSpecifyMem(mixBuffer);
424     AXARTInit();
425 
426     // start the system in stereo mode
427     AXSetMode(AX_MODE_STEREO);
428     MIXSetSoundMode(MIX_SOUND_MODE_STEREO);
429 
430     AXARTSet3DDopplerScale(20.0f);
431     AXARTSet3DDistanceScale(40.0f);
432 
433     AXRegisterCallback(&callbackAudioFrame);
434 
435     // push sound samples into ARAM
436     soundSamples = LoadFileIntoRam("/axdemo/axart/axartdemo.spd");
437 
438     // load sound table into main memory
439     soundTable   = LoadFileIntoRam("/axdemo/axart/axartdemo.spt");
440 
441     // initialize the sound table
442     SPInitSoundTable(soundTable, soundSamples, NULL);
443 
444     // start sounds
445     startSound(&helicopter, soundTable, SND_HELICOPTER);
446     startSound(&cube, soundTable, SND_CUBE);
447     addModToCube();
448 
449     while( !Quit )
450     {
451         // Get input and animate
452         AnimTick();
453 
454         DEMOBeforeRender();
455 
456         // Draw the scene
457         DrawTick();
458 
459         DEMODoneRender();
460     }
461 
462     killSound(&helicopter);
463     killSound(&cube);
464 
465     AXARTQuit();
466     MIXQuit();
467     AXQuit();
468 
469     OSReport( "End of demo.\n" );
470 }
471 
472 
473 /*---------------------------------------------------------------------------*
474     Name:           DrawInit
475 
476     Description:    Initialize
477 
478     Arguments:      none
479 
480     Returns:        none
481  *---------------------------------------------------------------------------*/
482 static void
DrawInit(void)483 DrawInit( void )
484 {
485     GXColor black     = {0,0,0,0};
486 
487     RenderMode = DEMOGetRenderModeObj();
488 
489     // Set background color
490     GXSetCopyClear( black, GX_MAX_Z24 );
491 
492     // Initialize the camera
493     Camera = DefaultCamera;
494 }
495 
496 
497 static GXColor change = { 0,  64, 128, 255 };
498 static BOOL delta_r = 1;
499 static BOOL delta_g = 1;
500 static BOOL delta_b = 1;
501 
502 
503 /*---------------------------------------------------------------------------*
504     Name:           DrawTick
505 
506     Description:    Draw the current scene.
507 
508     Arguments:      none
509 
510     Returns:        none
511  *---------------------------------------------------------------------------*/
512 static void
DrawTick()513 DrawTick ( )
514 {
515     GXColor green = { 0, 255, 0,  100 };
516     GXColor red   = { 255, 0, 0, 255 };
517     GXColor lightGrey = { 220, 220, 220, 255 };
518     GXColor darkGrey  = {  35,  35,  35, 255 };
519     Mtx     mv, scale;
520 
521     // Load up the camera
522     CameraLoad( &Camera );
523 
524     // Set the blend mode for transparencies
525     GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
526     GXSetAlphaCompare(GX_GREATER, 0, GX_AOP_AND, GX_GREATER, 0);
527     GXSetZCompLoc(GX_FALSE);
528 
529     // Pass register color in TEV
530     GXSetTevOrder( GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0 );
531     GXSetTevOp( GX_TEVSTAGE0, GX_PASSCLR );
532     GXSetNumTexGens( 0 );
533     GXSetNumTevStages( 1 );
534     GXSetNumChans( 1 );
535 
536     // Enable lighting
537     GXSetChanCtrl( GX_COLOR0A0, GX_ENABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT0, GX_DF_CLAMP, GX_AF_NONE );
538     GXSetChanAmbColor( GX_COLOR0A0, darkGrey );
539 
540     // Initialize light w/ pre-lighting
541     GXInitLightPos( &Light, 0, 0, 1024.0f );
542     GXInitLightColor( &Light, lightGrey );
543     GXLoadLightObjImm( &Light, GX_LIGHT0 );
544 
545     // Load in the modelview matrix for sphere
546     MTXConcat( Camera.viewMtx, ModelMtx, mv );
547     GXLoadPosMtxImm( mv, GX_PNMTX0 );
548     GXSetCurrentMtx( GX_PNMTX0 );
549 
550     // Draw unit sphere with model matrix
551     GXSetChanMatColor( GX_COLOR0A0, red );
552     GXDrawSphere( 20, 20 );
553 
554     // draw cube
555     MTXScale(scale, CubeRadius, CubeRadius, CubeRadius);
556     MTXConcat(Camera.viewMtx, scale, mv);
557     GXLoadPosMtxImm(mv, GX_PNMTX0);
558     GXSetCurrentMtx( GX_PNMTX0 );
559     GXSetChanMatColor( GX_COLOR0A0, change );
560     GXDrawCube();
561 
562 
563     if (delta_r)
564     {
565         change.r++;
566         if (255 == change.r)
567         {
568             delta_r = 0;
569         }
570     }
571     else
572     {
573         change.r--;
574         if (0 == change.r)
575         {
576             delta_r = 1;
577         }
578     }
579 
580     if (delta_g)
581     {
582         change.g++;
583         if (255 == change.g)
584         {
585             delta_g = 0;
586         }
587     }
588     else
589     {
590         change.g--;
591         if (0 == change.g)
592         {
593             delta_g = 1;
594         }
595     }
596 
597     if (delta_b)
598     {
599         change.b++;
600         if (255 == change.b)
601         {
602             delta_b = 0;
603         }
604     }
605     else
606     {
607         change.b--;
608         if (0 == change.b)
609         {
610             delta_b = 1;
611         }
612     }
613 
614 
615     // Disable lighting
616     GXSetChanCtrl( GX_COLOR0A0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE );
617 
618     // Load in the modelview matrix for grid
619     // Assume identity model matrix
620     GXLoadPosMtxImm( Camera.viewMtx, GX_PNMTX0 );
621 
622     // Draw green grid (transparent so draw last )
623     GXSetChanMatColor( GX_COLOR0A0, green );
624     DrawGrid();
625 
626     // Draw text, do this last since it clobbers lots of GX state
627     DrawUI();
628 }
629 
toggleAxMode(void)630 static void toggleAxMode(void)
631 {
632 
633     switch (AXGetMode())
634     {
635     case AX_MODE_STEREO:
636 
637         AXSetMode(AX_MODE_SURROUND);
638         MIXSetSoundMode(MIX_SOUND_MODE_SURROUND);
639 
640         break;
641 
642     case AX_MODE_SURROUND:
643 
644         AXSetMode(AX_MODE_DPL2);
645         MIXSetSoundMode(MIX_SOUND_MODE_DPL2);
646 
647         break;
648 
649     case AX_MODE_DPL2:
650 
651         AXSetMode(AX_MODE_STEREO);
652         MIXSetSoundMode(MIX_SOUND_MODE_STEREO);
653 
654         break;
655     }
656 
657 }
658 
659 static int buttonDown = FALSE;
660 /*---------------------------------------------------------------------------*
661     Name:           AnimTick
662 
663     Description:    Animates the scene
664 
665     Arguments:      none
666 
667     Returns:        none
668  *---------------------------------------------------------------------------*/
669 static void
AnimTick(void)670 AnimTick ( void )
671 {
672     u16        buttons;
673     u16        buttonsDown;
674     s8         stickX;
675     s8         stickY;
676     s8         subStickX;
677     s8         subStickY;
678     u8         triggerL;
679     u8         triggerR;
680     Mtx        rot;
681     static f32 digAYBtnScale;
682 
683 
684     // Get the pad status
685     DEMOPadRead();
686     buttons     = DEMOPadGetButton(0);
687     buttonsDown = DEMOPadGetButtonDown(0);
688     stickX      = DEMOPadGetStickX(0);
689     stickY      = DEMOPadGetStickY(0);
690     subStickX   = DEMOPadGetSubStickX(0);
691     subStickY   = DEMOPadGetSubStickY(0);
692     triggerL    = DEMOPadGetTriggerL(0);
693     triggerR    = DEMOPadGetTriggerR(0);
694 
695 
696     // Quit
697     if(buttonsDown & PAD_BUTTON_MENU)
698     {
699         Quit = 1;
700     }
701 
702     // toggle AX mode
703     if (buttons & PAD_BUTTON_X)
704     {
705         if (buttonDown == FALSE)
706         {
707             buttonDown = TRUE;
708             toggleAxMode();
709         }
710     }
711     else
712     {
713         buttonDown = FALSE;
714     }
715 
716     // Reset Camera
717     if(buttonsDown & PAD_TRIGGER_L)
718     {
719         Camera = DefaultCamera;
720     }
721 
722     // Shift button
723     if( buttons & PAD_TRIGGER_R )
724     {
725         // Roll the camera about its z axis
726         if(stickX != 0)
727         {
728             MTXRotAxis(rot, &Camera.zAxis, -stickX * 5.0f / 128.0f);
729             MTXMultVec(rot, &Camera.xAxis, &Camera.xAxis);
730             MTXMultVec(rot, &Camera.yAxis, &Camera.yAxis);
731         }
732     }
733     else
734     {
735         // Zoom camera
736         if( buttons & (PAD_BUTTON_Y | PAD_BUTTON_A) )
737         {
738             if( buttonsDown & (PAD_BUTTON_Y | PAD_BUTTON_A) )
739             {
740                 digAYBtnScale = 0.05f;
741             }
742 
743             // If Y button, reverse the direction of zoom
744             if( buttons & PAD_BUTTON_Y )
745                 digAYBtnScale = -digAYBtnScale;
746 
747             Camera.translate.x += digAYBtnScale * Camera.zAxis.x;
748             Camera.translate.y += digAYBtnScale * Camera.zAxis.y;
749             Camera.translate.z += digAYBtnScale * Camera.zAxis.z;
750 
751             // Restore the scale
752             if( buttons & PAD_BUTTON_Y )
753                 digAYBtnScale = -digAYBtnScale;
754 
755             digAYBtnScale += 0.05f;
756             if( digAYBtnScale > 5.0f )
757                 digAYBtnScale = 5.0f;
758         }
759 
760         if(stickX != 0)
761         {
762             // Rotate camera about world Z Axis
763             MTXRotAxis(rot, &WorldZAxis, -stickX * 5.0f / 128.0f);
764             MTXMultVec(rot, &Camera.xAxis, &Camera.xAxis);
765             MTXMultVec(rot, &Camera.yAxis, &Camera.yAxis);
766             MTXMultVec(rot, &Camera.zAxis, &Camera.zAxis);
767         }
768         if(stickY != 0)
769         {
770             // Rotate camera about camera x axis
771             MTXRotAxis(rot, &Camera.xAxis, -stickY * 5.0f / 128.0f);
772             MTXMultVec(rot, &Camera.yAxis, &Camera.yAxis);
773             MTXMultVec(rot, &Camera.zAxis, &Camera.zAxis);
774         }
775 
776         if( subStickX != 0 )
777         {
778             // Dolly the camera relative to camera x axis
779             f32 translate = subStickX * 5.0f / 128.0f;
780             Camera.translate.x += translate * Camera.xAxis.x;
781             Camera.translate.y += translate * Camera.xAxis.y;
782             Camera.translate.z += translate * Camera.xAxis.z;
783         }
784         if( subStickY != 0 )
785         {
786             // Dolly the camera relative to camera y axis
787             f32 translate = subStickY * 5.0f / 128.0f;
788             Camera.translate.x += translate * Camera.yAxis.x;
789             Camera.translate.y += translate * Camera.yAxis.y;
790             Camera.translate.z += translate * Camera.yAxis.z;
791         }
792     }
793 
794     if (!(buttons & PAD_TRIGGER_Z))
795     {
796         MTXRotDeg( rot, 'z', 1.5f );
797         MTXMultVec( rot, &BallPosition, &BallPosition );
798         MTXTrans( ModelMtx, BallPosition.x, BallPosition.y, BallPosition.z );
799     }
800 
801     // Update any changes to the camera
802     CameraUpdate( &Camera );
803 }
804 
805 
806 /*---------------------------------------------------------------------------*
807     Name:           CameraLoad
808 
809     Description:    Initialize the projection matrix and load into hardware.
810 
811     Arguments:      newCam - camera to switch projection to
812 
813     Returns:        none
814  *---------------------------------------------------------------------------*/
815 static void
CameraLoad(CameraObj * newCam)816 CameraLoad( CameraObj *newCam )
817 {
818     Mtx44 p;
819 
820     MTXPerspective( p, newCam->fov, newCam->aspect, newCam->near, newCam->far );
821     GXSetProjection(p, GX_PERSPECTIVE);
822 }
823 
824 
825 /*---------------------------------------------------------------------------*
826     Name:           CameraUpdate
827 
828     Description:    Updates the camera's view matrix.
829 
830     Arguments:      camera - camera's view matrix to update
831 
832     Returns:        none
833  *---------------------------------------------------------------------------*/
834 static void
CameraUpdate(CameraObj * camera)835 CameraUpdate ( CameraObj *camera )
836 {
837     Mtx transMtx;
838 
839     VECNormalize( &camera->xAxis, &camera->xAxis );
840     VECNormalize( &camera->yAxis, &camera->yAxis );
841     VECNormalize( &camera->zAxis, &camera->zAxis );
842 
843     MTXRowCol(camera->viewMtx,0,0) = camera->xAxis.x;
844     MTXRowCol(camera->viewMtx,0,1) = camera->xAxis.y;
845     MTXRowCol(camera->viewMtx,0,2) = camera->xAxis.z;
846     MTXRowCol(camera->viewMtx,0,3) = 0.0F;
847 
848     MTXRowCol(camera->viewMtx,1,0) = camera->yAxis.x;
849     MTXRowCol(camera->viewMtx,1,1) = camera->yAxis.y;
850     MTXRowCol(camera->viewMtx,1,2) = camera->yAxis.z;
851     MTXRowCol(camera->viewMtx,1,3) = 0.0F;
852 
853     MTXRowCol(camera->viewMtx,2,0) = camera->zAxis.x;
854     MTXRowCol(camera->viewMtx,2,1) = camera->zAxis.y;
855     MTXRowCol(camera->viewMtx,2,2) = camera->zAxis.z;
856     MTXRowCol(camera->viewMtx,2,3) = 0.0F;
857 
858     MTXTrans(transMtx, -camera->translate.x, -camera->translate.y, -camera->translate.z);
859     MTXConcat(camera->viewMtx, transMtx, camera->viewMtx);
860 
861     if (helicopter.voice)
862     {
863         f32 oldDist, newDist, hAngle, vAngle;
864         int old;
865         Vec ballPosInCamera;
866 
867         // Find position of ball in camera space
868         MTXMultVec( Camera.viewMtx, &BallPosition, &ballPosInCamera );
869 
870         // Compute horizontal and vertical angle
871 		if (ballPosInCamera.x > 0)
872 			hAngle = -atan2f( ballPosInCamera.x, ballPosInCamera.z ) + 3.14f;
873 		else
874 			hAngle = -atan2f( ballPosInCamera.x, ballPosInCamera.z ) - 3.14f;
875 
876 		if (ballPosInCamera.y > 0)
877 			vAngle = -atan2f( ballPosInCamera.y, ballPosInCamera.z ) + 3.14f;
878 		else
879 			vAngle = -atan2f( ballPosInCamera.y, ballPosInCamera.z ) - 3.14f;
880 
881         oldDist = helicopter.axart3d.dist;
882         newDist = sqrtf(((ballPosInCamera.x * ballPosInCamera.x) +
883                         (ballPosInCamera.y * ballPosInCamera.y) +
884                         (ballPosInCamera.z * ballPosInCamera.z)));
885 
886         old = OSDisableInterrupts();
887 
888         helicopter.axart3d.hAngle       = hAngle;
889         helicopter.axart3d.vAngle       = vAngle;
890         helicopter.axart3d.dist         = newDist;
891         helicopter.axart3d.closingSpeed = oldDist - newDist;
892         helicopter.axart3d.update       = TRUE;
893 
894         OSRestoreInterrupts(old);
895     }
896 
897     if (cube.voice)
898     {
899         f32 oldDist, newDist, hAngle, vAngle;
900         int old;
901         Vec cubePosInCamera;
902 
903         // Find position of cube in camera space
904         MTXMultVec( Camera.viewMtx, &CubePosition, &cubePosInCamera );
905 
906         // Compute horizontal and vertical angle
907 		if (cubePosInCamera.x > 0)
908 			hAngle = -atan2f( cubePosInCamera.x, cubePosInCamera.z ) + 3.14f;
909 		else
910 			hAngle = -atan2f( cubePosInCamera.x, cubePosInCamera.z ) - 3.14f;
911 
912 		if (cubePosInCamera.y > 0)
913 			vAngle = -atan2f( cubePosInCamera.y, cubePosInCamera.z ) + 3.14f;
914 		else
915 			vAngle = -atan2f( cubePosInCamera.y, cubePosInCamera.z ) - 3.14f;
916 
917         oldDist = cube.axart3d.dist;
918         newDist = sqrtf(((cubePosInCamera.x * cubePosInCamera.x) +
919                         (cubePosInCamera.y * cubePosInCamera.y) +
920                         (cubePosInCamera.z * cubePosInCamera.z)));
921 
922         old = OSDisableInterrupts();
923 
924         cube.axart3d.hAngle       = hAngle;
925         cube.axart3d.vAngle       = vAngle;
926         cube.axart3d.dist         = newDist;
927         cube.axart3d.closingSpeed = oldDist - newDist;
928         cube.axart3d.update       = TRUE;
929 
930         OSRestoreInterrupts(old);
931     }
932 }
933 
934 
935 /*---------------------------------------------------------------------------*
936     Name:           DrawGrid
937 
938     Description:    Draws a square grid of length GRID_LENGTH centered about
939                     the origin lying on the XY world plane.  GRID_SEGS is the
940                     number of vertices per side.
941 
942     Arguments:      none
943 
944     Returns:        none
945  *---------------------------------------------------------------------------*/
946 static void
DrawGrid()947 DrawGrid ( )
948 {
949     u32     i, j;
950     f32     position[2];
951     f32     increment;
952 
953     // Draw grid
954     GXClearVtxDesc();
955     GXSetVtxDesc( GX_VA_POS, GX_DIRECT );
956     GXSetVtxAttrFmt( GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0 );
957 
958     increment = ((f32)GRID_LENGTH) / GRID_SEGS;
959 
960     position[1] = -GRID_LENGTH * 0.5f;
961     for( i = 0; i < GRID_SEGS; i++ )
962     {
963         position[0] = -GRID_LENGTH * 0.5f;
964         GXBegin( GX_LINESTRIP, GX_VTXFMT0, GRID_SEGS );
965         for( j = 0; j < GRID_SEGS; j++ )
966         {
967             GXPosition3f32( position[0], position[1], 0 );
968             position[0] += increment;
969         }
970         position[1] += increment;
971         GXEnd();
972     }
973 
974     position[0] = -GRID_LENGTH * 0.5f;
975     for( i = 0; i < GRID_SEGS; i++ )
976     {
977         position[1] = -GRID_LENGTH * 0.5f;
978         GXBegin( GX_LINESTRIP, GX_VTXFMT0, GRID_SEGS );
979         for( j = 0; j < GRID_SEGS; j++ )
980         {
981             GXPosition3f32( position[0], position[1], 0 );
982             position[1] += increment;
983         }
984         position[0] += increment;
985         GXEnd();
986     }
987 }
988 
989 /*---------------------------------------------------------------------------*
990     Name:           DrawUI
991 
992     Description:    Draw text onto the scene
993 
994     Arguments:      none
995 
996     Returns:        none
997  *---------------------------------------------------------------------------*/
998 static void
DrawUI()999 DrawUI ()
1000 {
1001     s16   textX = 20;
1002     s16   textY = 20;
1003 
1004     // Initialize GX for drawing text
1005     DEMOInitCaption( DM_FT_OPQ, RenderMode->fbWidth, RenderMode->xfbHeight );
1006 
1007     switch (AXGetMode())
1008     {
1009     case AX_MODE_STEREO:
1010 
1011         DEMOPrintf( textX, textY, 0, "AX mode:                         AX_MODE_STEREO");
1012 
1013         break;
1014 
1015     case AX_MODE_SURROUND:
1016 
1017         DEMOPrintf( textX, textY, 0, "AX mode:                         AX_MODE_SURROUND");
1018 
1019         break;
1020 
1021     case AX_MODE_DPL2:
1022 
1023         DEMOPrintf( textX, textY, 0, "AX mode:                         AX_MODE_DPL2");
1024 
1025         break;
1026     }
1027     textY += 20;
1028     DEMOPrintf( textX, textY, 0, "helicopter.voice:                %.8xh", helicopter.voice);
1029     textY += 10;
1030     DEMOPrintf( textX, textY, 0, "helicopter.sound.sampleRate:     %dHz", helicopter.sound->sampleRate);
1031     textY += 20;
1032     DEMOPrintf( textX, textY, 0, "helicopter.axart3d.hAngle:       %f", helicopter.axart3d.hAngle);
1033     textY += 10;
1034     DEMOPrintf( textX, textY, 0, "helicopter.axart3d.vAngle:       %f", helicopter.axart3d.vAngle);
1035     textY += 10;
1036     DEMOPrintf( textX, textY, 0, "helicopter.axart3d.dist:         %f", helicopter.axart3d.dist);
1037     textY += 10;
1038     DEMOPrintf( textX, textY, 0, "helicopter.axart3d.closingSpeed: %f", helicopter.axart3d.closingSpeed);
1039 }
1040