1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin/Revolution gx demo
3   File:     lit-spot.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    lit-spot
15      Spot light angle attenuation test
16  *---------------------------------------------------------------------------*/
17 
18 
19 /*---------------------------------------------------------------------------*
20    Header files
21  *---------------------------------------------------------------------------*/
22 #include <demo.h>
23 #include <math.h>
24 
25 /*---------------------------------------------------------------------------*
26    Macro definitions
27  *---------------------------------------------------------------------------*/
28 #define PI                3.14159265358979323846F
29 #define NUM_LIGHTS        4
30 #define NUM_PANELTYPE     6
31 #define PANEL_ARRAY_SIZE  ( 16 * 16 * 3 )
32 
33 #define Clamp(val,min,max) \
34     ((val) = (((val)<(min)) ? (min) : ((val)>(max)) ? (max) : (val)))
35 
36 /*---------------------------------------------------------------------------*
37   Structure definitions
38  *---------------------------------------------------------------------------*/
39 // for camera
40 typedef struct
41 {
42     Vec    location;
43     Vec    up;
44     Vec    target;
45     f32    left;
46     f32    top;
47     f32    znear;
48     f32    zfar;
49 } CameraConfig;
50 
51 typedef struct
52 {
53     CameraConfig  cfg;
54     Mtx           view;
55     Mtx44         proj;
56 } MyCameraObj;
57 
58 // for lighting
59 typedef struct
60 {
61     f32         a0;
62     f32         a1;
63     f32         a2;
64 } AngleAttn;
65 
66 typedef struct
67 {
68     GXLightObj  lobj;
69     Vec         pos;
70     s32         theta;
71     s32         phi;
72     u32         colorIdx;
73     u32         attnType;
74     u32         enable;
75 } MyLightObj;
76 
77 typedef struct
78 {
79     MyLightObj  light[NUM_LIGHTS];
80     GXAttnFn    attnFunc;
81 } MyLightEnvObj;
82 
83 // for model object
84 typedef struct
85 {
86     u32         type;
87     f32*        posArray;
88     f32*        normArray;
89 } MyTessPanelObj;
90 
91 // for entire scene control
92 typedef struct
93 {
94     MyCameraObj     cam;
95     MyLightEnvObj   lightEnv;
96     MyTessPanelObj  panel;
97     u32             cur;
98     u32             mode;
99     u32             mark;
100 } MySceneCtrlObj;
101 
102 /*---------------------------------------------------------------------------*
103    Forward references
104  *---------------------------------------------------------------------------*/
105 void        main            ( void );
106 static void DrawInit        ( MySceneCtrlObj* sc );
107 static void DrawTick        ( MySceneCtrlObj* sc );
108 static void AnimTick        ( MySceneCtrlObj* sc );
109 static void CreateTessPanel ( MyTessPanelObj* pnl );
110 static void DrawTessPanel   ( MyTessPanelObj* pnl );
111 static void DrawLightMark   ( MyLightObj* light );
112 static void SetCamera       ( MyCameraObj* cam );
113 static void SetLight        ( MyLightEnvObj* le, Mtx view );
114 static void DisableLight    ( void );
115 static void PrintIntro      ( void );
116 static void StatusMessage   ( MyLightObj* light );
117 
118 /*---------------------------------------------------------------------------*
119   Lighting and model parameters
120  *---------------------------------------------------------------------------*/
121 #define BLACK        MyColors[4]
122 #define REG_MATERIAL MyColors[5]
123 #define REG_AMBIENT  MyColors[6]
124 
125 static GXColor MyColors[] ATTRIBUTE_ALIGN(32) =
126 {
127     {0xff, 0xff, 0xff, 0xff},  // white
128     {0xff, 0x00, 0x00, 0xff},  // red
129     {0x00, 0xff, 0x00, 0xff},  // green
130     {0x00, 0x00, 0xff, 0xff},  // blue
131 
132     {0x00, 0x00, 0x00, 0x00},  // black
133     {0xc0, 0xc0, 0xc0, 0xff},  // material
134     {0x10, 0x10, 0x10, 0xff}   // ambient
135 };
136 
137 static Vec DefaultLightPos[4] =
138 {
139     {  200,  200, 450 },
140     {  200, -200, 450 },
141     { -200, -200, 450 },
142     { -200,  200, 450 }
143 };
144 
145 #define NUM_OF_ATTNS    20
146 static AngleAttn LightAttnSamples[NUM_OF_ATTNS] =
147 {
148     {  -9.0F,  10.0F,   0.0F  },
149     { -24.0F,  25.0F,   0.0F  },
150     { -49.0F,  50.0F,   0.0F  },
151     {  -4.0F,   5.0F,   0.0F  },
152     { -18.5F,  20.0F,   0.0F  },
153     { -47.0F,  50.0F,   0.0F  },
154     {-299.0F, 200.0F, 100.0F  },
155     { -74.0F,  50.0F,  25.0F  },
156     { -26.0F,  18.0F,   9.0F  },
157     {  -2.0F,   2.0F,   1.0F  },
158     {-297.0F, 200.0F, 100.0F  },
159     { -72.5F,  50.0F,  25.0F  },
160     {   0.5F,   0.5F,   0.25F },
161     {  -0.5F,   2.0F,   1.0F  },
162     {   1.0F,  -2.0F,   1.0F  },
163     {  38.5F, -40.0F,   0.0F  },
164     { -17.0F,  48.0F, -32.0F  },
165     {  -3.0F,   8.0F,  -4.0F  },
166     {   0.0F,   1.0F,   0.0F  },
167     {   0.5F,   0.0F,   0.0F  }
168 };
169 
170 /*---------------------------------------------------------------------------*
171    Camera configuration
172  *---------------------------------------------------------------------------*/
173 static CameraConfig DefaultCamera =
174 {
175     { 0.0F, 0.0F, 1200.0F }, // location
176     { 0.0F, 1.0F, 0.0F },    // up
177     { 0.0F, 0.0F, 0.0F },    // target
178     -320.0F,  // left
179     240.0F,   // top
180     500.0F,   // near
181     2000.0F   // far
182 };
183 
184 /*---------------------------------------------------------------------------*
185    Strings for messages
186  *---------------------------------------------------------------------------*/
187 static char* CtrlMsg[] =
188 {
189     "White Light",
190     "Red Light",
191     "Green Light",
192     "Blue Light"
193 };
194 
195 static char* ModeMsg[] =
196 {
197     "Direction & attenuation control",
198     "Position control",
199     "Camera control"
200 };
201 
202 /*---------------------------------------------------------------------------*
203    Global variables
204  *---------------------------------------------------------------------------*/
205 static MySceneCtrlObj  SceneCtrl;
206 
207 /*---------------------------------------------------------------------------*
208    Application main loop
209  *---------------------------------------------------------------------------*/
main(void)210 void main ( void )
211 {
212     DEMOInit(NULL);
213 
214     DrawInit(&SceneCtrl);       // Initialize vertex formats, array
215                                 // and default scene settings
216 
217     PrintIntro(); // Print demo directions
218 
219     while(!(DEMOPadGetButton(0) & PAD_BUTTON_MENU))
220     {
221         DEMOBeforeRender();
222         DrawTick(&SceneCtrl);    // Draw the model.
223         DEMODoneRender();
224         DEMOPadRead();           // Update pad status.
225         AnimTick(&SceneCtrl);    // Update animation.
226     }
227 
228     OSHalt("End of demo");
229 }
230 
231 /*---------------------------------------------------------------------------*
232    Functions
233  *---------------------------------------------------------------------------*/
234 /*---------------------------------------------------------------------------*
235     Name:           DrawInit
236 
237     Description:    Initializes the vertex attribute format and allocates
238                     the array memory for the indexed data.
239                     This function also initializes scene control parameters.
240 
241     Arguments:      sc : pointer to the structure of scene control parameters
242 
243     Returns:        none
244  *---------------------------------------------------------------------------*/
DrawInit(MySceneCtrlObj * sc)245 static void DrawInit( MySceneCtrlObj* sc )
246 {
247     u32 i;
248 
249     // vertex attribute
250     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
251     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
252     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
253 
254 
255     // Default scene control parameter settings
256 
257     // camera
258     sc->cam.cfg = DefaultCamera;
259 
260     // light parameters
261     for ( i = 0 ; i < 4 ; ++i )
262     {
263         sc->lightEnv.light[i].pos      = DefaultLightPos[i];
264         sc->lightEnv.light[i].theta    = 0;
265         sc->lightEnv.light[i].phi      = 0;
266         sc->lightEnv.light[i].attnType = 0;
267         sc->lightEnv.light[i].enable   = TRUE;
268         sc->lightEnv.light[i].colorIdx = i;
269     }
270     sc->lightEnv.attnFunc = GX_AF_SPOT;
271 
272     // allocate arrays
273     sc->panel.posArray = MEMAllocFromAllocator(&DemoAllocator1, PANEL_ARRAY_SIZE * sizeof(f32));
274     ASSERT( sc->panel.posArray != 0 );
275     sc->panel.normArray = MEMAllocFromAllocator(&DemoAllocator1, PANEL_ARRAY_SIZE * sizeof(f32));
276     ASSERT( sc->panel.normArray != 0 );
277     sc->panel.type = 0;
278 
279     // create default panel
280     CreateTessPanel(&sc->panel);
281 
282     //  current control object and control mode
283     sc->cur  = 0;
284     sc->mode = 0;
285     sc->mark = 1;
286 }
287 
288 /*---------------------------------------------------------------------------*
289     Name:           DrawTick
290 
291     Description:    Draw models specified by given scene control parameters.
292 
293     Arguments:      sc : pointer to the structure of scene control parameters
294 
295     Returns:        none
296  *---------------------------------------------------------------------------*/
DrawTick(MySceneCtrlObj * sc)297 static void DrawTick( MySceneCtrlObj* sc )
298 {
299     Mtx  ms;  // Scale matrix.
300     Mtx  mt;  // Translation matrix
301     Mtx  mv;  // Modelview matrix.
302     Mtx  mvi; // Modelview matrix.
303     s32  ix, iy;
304 
305     // render mode = one color / no texture
306     GXSetNumTexGens(0);
307     GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
308     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
309 
310     // set camera
311     SetCamera(&sc->cam);
312 
313     // set lighting
314     SetLight(&sc->lightEnv, sc->cam.view);
315 
316     // draw 2x2=4 panels as a wall
317     MTXScale(ms, 400.0F, 400.0F, 120.0F);
318     for ( iy = 0 ; iy < 2 ; ++iy )
319     {
320         for ( ix = 0 ; ix < 2 ; ++ix )
321         {
322             MTXTrans(mt, ix * 400.0F - 400.0F, iy * 400.0F - 400.0F, 0.0F);
323 
324             MTXConcat(sc->cam.view, mt, mv);
325             MTXConcat(mv, ms, mv);
326 
327             GXLoadPosMtxImm(mv, GX_PNMTX0);
328             MTXInverse(mv, mvi);
329             MTXTranspose(mvi, mv);
330             GXLoadNrmMtxImm(mv, GX_PNMTX0);
331 
332             DrawTessPanel(&sc->panel);
333         }
334     }
335 
336     // turn off lighting
337     DisableLight();
338 
339     // draw a light mark
340     MTXCopy(sc->cam.view, mv);
341     GXLoadPosMtxImm(mv, GX_PNMTX0);
342     MTXInverse(mv, mvi);
343     MTXTranspose(mvi, mv);
344     GXLoadNrmMtxImm(mv, GX_PNMTX0);
345 
346     if ( sc->mark == 1 && sc->cur < NUM_LIGHTS )
347     {
348         DrawLightMark(&sc->lightEnv.light[sc->cur]);
349     }
350 
351 }
352 
353 /*---------------------------------------------------------------------------*
354     Name:           AnimTick
355 
356     Description:    Changes scene control parameters by using pad input.
357 
358     Arguments:      sc : pointer to the structure of scene control parameters.
359 
360     Returns:        none
361  *---------------------------------------------------------------------------*/
AnimTick(MySceneCtrlObj * sc)362 static void AnimTick( MySceneCtrlObj* sc )
363 {
364     static u16  counter = 0;
365     u32  i;
366     MyLightObj* lo = sc->lightEnv.light;
367 
368 
369     // Frame counter
370     ++counter;
371 
372     // Light Blinking Control
373     for ( i = 0 ; i < NUM_LIGHTS ; ++i )
374     {
375         lo[i].enable = TRUE;
376     }
377 
378     if ( ( counter % 32 ) > 28 )
379     {
380         lo[sc->cur].enable = FALSE;
381     }
382 
383     // Each light control mode
384     if ( sc->cur < NUM_LIGHTS )
385     {
386         // Direction
387         lo[sc->cur].theta += ( DEMOPadGetStickX(0) / 32 );
388         Clamp(lo[sc->cur].theta, -60, 60);
389         lo[sc->cur].phi += ( DEMOPadGetStickY(0) / 32 );
390         Clamp(lo[sc->cur].phi, -60, 60);
391 
392         // Position X/Y
393         lo[sc->cur].pos.x += ( DEMOPadGetSubStickX(0) / 16 );
394         Clamp(lo[sc->cur].pos.x, -320, 320);
395         lo[sc->cur].pos.y += ( DEMOPadGetSubStickY(0) / 16 );
396         Clamp(lo[sc->cur].pos.y, -240, 240);
397 
398         // Position Z
399         lo[sc->cur].pos.z += ( DEMOPadGetTriggerR(0) / 16 )
400                            - ( DEMOPadGetTriggerL(0) / 16 );
401         Clamp(lo[sc->cur].pos.z, 50, 600);
402 
403         // Attenuation parameter change
404         if ( DEMOPadGetButtonDown(0) & PAD_BUTTON_X )
405         {
406             lo[sc->cur].attnType =
407                 ( lo[sc->cur].attnType + 1 ) % NUM_OF_ATTNS;
408             StatusMessage(&lo[sc->cur]);
409         }
410         if ( DEMOPadGetButtonDown(0) & PAD_BUTTON_Y )
411         {
412             lo[sc->cur].attnType =
413                 ( lo[sc->cur].attnType + NUM_OF_ATTNS - 1 ) % NUM_OF_ATTNS;
414             StatusMessage(&lo[sc->cur]);
415         }
416     }
417     // General / camera control mode
418     else
419     {
420         // Camera calculation
421         Vec* cloc = &sc->cam.cfg.location;
422 
423         cloc->x += ( DEMOPadGetStickX(0) / 16 ) * 2;
424         Clamp(cloc->x, -480, 480);
425 
426         cloc->y += ( DEMOPadGetStickY(0) / 16 ) * 2;
427         Clamp(cloc->y, -320, 320);
428 
429         cloc->z =
430             sqrtf( 1200 * 1200 - cloc->y * cloc->y - cloc->x * cloc->x );
431 
432 
433         // Spotlight attenuation ON/OFF
434         if ( DEMOPadGetButtonDown(0) & PAD_BUTTON_X )
435         {
436             sc->lightEnv.attnFunc = GX_AF_NONE;
437             OSReport("GX_AF_NONE\n");
438         }
439         if ( DEMOPadGetButtonDown(0) & PAD_BUTTON_Y )
440         {
441             sc->lightEnv.attnFunc = GX_AF_SPOT;
442             OSReport("GX_AF_SPOT\n");
443         }
444 
445         // Tesselated wall type Select
446         if ( DEMOPadGetButtonDown(0) & PAD_TRIGGER_R )
447         {
448             sc->panel.type += 1;
449             sc->panel.type %= NUM_PANELTYPE;
450             CreateTessPanel(&sc->panel);
451         }
452         if ( DEMOPadGetButtonDown(0) & PAD_TRIGGER_L )
453         {
454             sc->panel.type += NUM_PANELTYPE - 1;
455             sc->panel.type %= NUM_PANELTYPE;
456             CreateTessPanel(&sc->panel);
457         }
458     }
459 
460 
461     // Hide light mark
462     sc->mark = (u32)(( DEMOPadGetButton(0) & PAD_BUTTON_A ) ? 0 : 1);
463 
464     // Select light / camera mode
465     if ( DEMOPadGetButtonDown(0) & PAD_BUTTON_B )
466     {
467         sc->cur = ( sc->cur + 1 ) % ( NUM_LIGHTS + 1 );
468 
469         if ( sc->cur < NUM_LIGHTS )
470         {
471             StatusMessage(&sc->lightEnv.light[sc->cur]);
472         }
473         else
474         {
475             OSReport("Camera mode\n");
476         }
477     }
478 }
479 
480 /*---------------------------------------------------------------------------*
481     Name:           CreateTessPanel
482 
483     Description:    Creates tesselated vertex data
484 
485     Arguments:      pnl : pointer to a MyTessPanelObj structure
486 
487     Returns:        none
488  *---------------------------------------------------------------------------*/
CreateTessPanel(MyTessPanelObj * pnl)489 static void CreateTessPanel( MyTessPanelObj* pnl )
490 {
491     u8  ix, iy;
492     u32 in;
493     f32 px, py, pz, nx, ny, nz;
494     f32 theta, phi, s;
495 
496     in = 0;
497 
498     for ( iy = 0 ; iy <= 15 ; ++iy )
499     {
500         py = (f32)iy / 15.0F;
501 
502         for ( ix = 0 ; ix <= 15 ; ++ix )
503         {
504             px = (f32)ix / 15.0F;
505 
506             switch(pnl->type)
507             {
508                 case 0 :    // Z = 0
509                 {
510                     pz = 0.0F;
511                     nx = 0.0F;
512                     ny = 0.0F;
513                     nz = 1.0F;
514                 } break;
515                 case 1 :    // Z = sinX
516                 {
517                     theta = (f32)ix * 2.0F * PI / 15.0F;
518                     s = sqrtf( 1.0F + cosf(theta) * cosf(theta) );
519                     pz = sinf(theta);
520                     nx = - cosf(theta) / s;
521                     ny = 0.0F;
522                     nz = 1.0F / s;
523                 } break;
524                 case 2 :    // Z = sin2X
525                 {
526                     theta = (f32)ix * 4.0F * PI / 15.0F;
527                     s = sqrtf( 1.0F + cosf(theta) * cosf(theta) );
528                     pz = sinf(theta);
529                     nx = - cosf(theta) / s;
530                     ny = 0.0F;
531                     nz = 1.0F / s;
532                 } break;
533                 case 3 :    // Z = cos2X * sinY
534                 {
535                     theta = (f32)ix * 4.0F * PI / 15.0F;
536                     phi   = (f32)iy * 2.0F * PI / 15.0F;
537                     s = sqrtf( 1.0F + cosf(theta) * cosf(theta) * sinf(phi) * sinf(phi) )
538                       * sqrtf( 1.0F + sinf(theta) * sinf(theta) * cosf(phi) * cosf(phi) );
539                     pz = cosf(theta) * cosf(phi);
540                     nx = sinf(theta) * cosf(phi) / s;
541                     ny = cosf(theta) * sinf(phi) / s;
542                     nz = 1.0F / s;
543                 } break;
544                 case 4 :    // Z = (X - 0.5)^2
545                 {
546                     theta = (f32)ix / 15.0F - 0.5F;
547                     pz = 4.0F * theta * theta;
548                     s  = sqrtf( 1.0F + 64.0F * theta * theta );
549                     nx = - (f32)theta * 8.0F / s;
550                     ny = 0.0F;
551                     nz = 1.0F / s;
552                 } break;
553                 case 5 :    // Z = - (Y - 0.5)^2
554                 {
555                     theta = (f32)iy / 15.0F - 0.5F;
556                     pz = 0.25F - 4.0F * theta * theta;
557                     s  = sqrtf( 1.0F + 64.0F * theta * theta );
558                     nx = 0.0F;
559                     ny = (f32)theta * 8.0F / s;
560                     nz = 1.0F / s;
561                 } break;
562             }
563 
564             pnl->posArray[in]    = px;
565             pnl->posArray[in+1]  = py;
566             pnl->posArray[in+2]  = pz;
567             pnl->normArray[in]   = nx;
568             pnl->normArray[in+1] = ny;
569             pnl->normArray[in+2] = nz;
570 
571             in += 3;
572         }
573     }
574 
575     // flushes all data into main memory from D-cache
576     DCFlushRange(pnl->posArray,  PANEL_ARRAY_SIZE * sizeof(f32));
577     DCFlushRange(pnl->normArray, PANEL_ARRAY_SIZE * sizeof(f32));
578     // invalidates previous data existing in vertex cache
579     GXInvalidateVtxCache();
580 
581 }
582 
583 /*---------------------------------------------------------------------------*
584     Name:           DrawTessPanel
585 
586     Description:    Draws panel by using tesselated vertices
587 
588     Arguments:      pnl : pointer to a MyTessPanelObj structure
589 
590     Returns:        none
591  *---------------------------------------------------------------------------*/
DrawTessPanel(MyTessPanelObj * pnl)592 static void DrawTessPanel( MyTessPanelObj* pnl )
593 {
594     u32 i, x, y;
595 
596     // set up vertex descriptors
597     // since GX_INDEX8 can handle up to 255 (not 256) vertices,
598     // GX_INDEX16 is used here.
599     GXClearVtxDesc();
600     GXSetVtxDesc(GX_VA_POS, GX_INDEX16);
601     GXSetVtxDesc(GX_VA_NRM, GX_INDEX16);
602 
603     // set up array pointers and strides
604     GXSetArray(GX_VA_POS, pnl->posArray,  3 * sizeof(f32));
605     GXSetArray(GX_VA_NRM, pnl->normArray, 3 * sizeof(f32));
606 
607     for ( y = 0 ; y < 15 ; ++y )
608     {
609         i = y * 16;
610 
611         GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, 32);
612             for ( x = 0 ; x < 16 ; ++x )
613             {
614                 GXPosition1x16((u16)i);
615                 GXNormal1x16((u16)i);
616                 GXPosition1x16((u16)(i+16));
617                 GXNormal1x16((u16)(i+16));
618                 ++i;
619             }
620         GXEnd();
621     }
622 }
623 
624 /*---------------------------------------------------------------------------*
625     Name:           DrawLightMark
626 
627     Description:    Draws a mark which shows light position and direction.
628 
629     Arguments:      light: pointer to a MyLightObj structure
630 
631     Returns:        none
632  *---------------------------------------------------------------------------*/
DrawLightMark(MyLightObj * light)633 static void DrawLightMark( MyLightObj* light )
634 {
635     f32 theta, phi, len;
636     Vec ldir;
637 
638     theta = (f32)light->theta * PI / 180.0F;
639     phi   = (f32)light->phi   * PI / 180.0F;
640     ldir.x = sinf(theta);
641     ldir.y = sinf(phi) * cosf(theta);
642     ldir.z = cosf(phi) * cosf(theta);
643 
644     len = fabsf(light->pos.z / ldir.z);
645     ldir.x = light->pos.x + ldir.x * len;
646     ldir.y = light->pos.y + ldir.y * len;
647     ldir.z = 0;
648 
649     // set up vertex descriptors
650     GXClearVtxDesc();
651     GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
652     GXSetVtxDesc(GX_VA_CLR0, GX_INDEX8);
653 
654     // set up array pointers and strides
655     GXSetArray(GX_VA_CLR0, MyColors, 4 * sizeof(u8));
656 
657     GXBegin(GX_LINES, GX_VTXFMT0, 8);
658         GXPosition3f32(light->pos.x, light->pos.y, 700.0F);
659         GXColor1x8((u8)light->colorIdx);
660         GXPosition3f32(light->pos.x, light->pos.y, 0.0F);
661         GXColor1x8((u8)light->colorIdx);
662 
663         GXPosition3f32(light->pos.x, -480.0F, light->pos.z);
664         GXColor1x8((u8)light->colorIdx);
665         GXPosition3f32(light->pos.x,  480.0F, light->pos.z);
666         GXColor1x8((u8)light->colorIdx);
667 
668         GXPosition3f32(-640.0F, light->pos.y, light->pos.z);
669         GXColor1x8((u8)light->colorIdx);
670         GXPosition3f32( 640.0F, light->pos.y, light->pos.z);
671         GXColor1x8((u8)light->colorIdx);
672 
673         GXPosition3f32(light->pos.x, light->pos.y, light->pos.z);
674         GXColor1x8((u8)light->colorIdx);
675         GXPosition3f32(ldir.x, ldir.y, ldir.z);
676         GXColor1x8((u8)light->colorIdx);
677     GXEnd();
678 }
679 
680 /*---------------------------------------------------------------------------*
681     Name:           SetCamera
682 
683     Description:    set view matrix and load projection matrix into hardware
684 
685     Arguments:      cam : pointer to the MyCameraObj structure
686 
687     Returns:        none
688  *---------------------------------------------------------------------------*/
SetCamera(MyCameraObj * cam)689 static void SetCamera( MyCameraObj* cam )
690 {
691     MTXLookAt(
692         cam->view,
693         &cam->cfg.location,
694         &cam->cfg.up,
695         &cam->cfg.target );
696 
697     MTXFrustum(
698         cam->proj,
699         cam->cfg.top,
700         - (cam->cfg.top),
701         cam->cfg.left,
702         - (cam->cfg.left),
703         cam->cfg.znear,
704         cam->cfg.zfar );
705     GXSetProjection(cam->proj, GX_PERSPECTIVE);
706 }
707 
708 /*---------------------------------------------------------------------------*
709     Name:           SetLight
710 
711     Description:    Sets light objects and color channels
712 
713     Arguments:      le   : pointer to a MyLightEnvObj structure
714                     view : view matrix.
715 
716     Returns:        none
717  *---------------------------------------------------------------------------*/
SetLight(MyLightEnvObj * le,Mtx view)718 static void SetLight( MyLightEnvObj* le, Mtx view )
719 {
720     f32 theta, phi;
721     Vec ldir, lpos;
722     AngleAttn attn;
723     u32 i;
724     u32 lmask = 0;
725 
726     for ( i = 0 ; i < NUM_LIGHTS ; ++i )
727     {
728         // direction
729         theta = (f32)le->light[i].theta * PI / 180.0F;
730         phi   = (f32)le->light[i].phi   * PI / 180.0F;
731         ldir.x = sinf(theta);
732         ldir.y = sinf(phi) * cosf(theta);
733         ldir.z = - cosf(phi) * cosf(theta);
734 
735         // convert direction into view space
736         MTXMultVecSR(view, &ldir, &ldir);
737 
738         // convert position into view space
739         lpos = le->light[i].pos;
740         MTXMultVec(view, &lpos, &lpos);
741 
742         // angular attenuation parameters
743         attn = LightAttnSamples[le->light[i].attnType];
744 
745         // set parameters for one light
746         GXInitLightDirv(&le->light[i].lobj, &ldir);
747         GXInitLightPosv(&le->light[i].lobj, &lpos);
748         GXInitLightColor(&le->light[i].lobj, MyColors[le->light[i].colorIdx]);
749         GXInitLightAttn(
750             &le->light[i].lobj,
751             attn.a0,
752             attn.a1,
753             attn.a2,
754             1.0F,
755             0.0F,
756             0.0F );
757     }
758 
759     // loads each light object
760     GXLoadLightObjImm(&le->light[0].lobj, GX_LIGHT0);
761     GXLoadLightObjImm(&le->light[1].lobj, GX_LIGHT1);
762     GXLoadLightObjImm(&le->light[2].lobj, GX_LIGHT2);
763     GXLoadLightObjImm(&le->light[3].lobj, GX_LIGHT3);
764 
765     // light mask control
766     lmask = le->light[0].enable ? ( lmask | GX_LIGHT0 ) : lmask;
767     lmask = le->light[1].enable ? ( lmask | GX_LIGHT1 ) : lmask;
768     lmask = le->light[2].enable ? ( lmask | GX_LIGHT2 ) : lmask;
769     lmask = le->light[3].enable ? ( lmask | GX_LIGHT3 ) : lmask;
770 
771     // channel setting
772     GXSetNumChans(1);     // number of active color channels
773     GXSetChanCtrl(
774         GX_COLOR0,
775         GX_ENABLE,        // enable channel
776         GX_SRC_REG,       // amb source
777         GX_SRC_REG,       // mat source
778         lmask,            // light mask
779         GX_DF_CLAMP,      // diffuse function
780         le->attnFunc);    // attenuation function
781     GXSetChanCtrl(
782         GX_ALPHA0,
783         GX_DISABLE,       // disable channel
784         GX_SRC_REG,       // amb source
785         GX_SRC_REG,       // mat source
786         0,                // light mask
787         GX_DF_NONE,       // diffuse function
788         GX_AF_NONE);      // attenuation function
789     // set up ambient color
790     GXSetChanAmbColor(GX_COLOR0A0, REG_AMBIENT);
791     // set up material color
792     GXSetChanMatColor(GX_COLOR0A0, REG_MATERIAL);
793 }
794 
795 /*---------------------------------------------------------------------------*
796     Name:           DisableLight
797 
798     Description:    Disables lighting
799 
800     Arguments:      none
801 
802     Returns:        none
803  *---------------------------------------------------------------------------*/
DisableLight(void)804 static void DisableLight( void )
805 {
806     GXSetNumChans(1);
807     GXSetChanCtrl(
808         GX_COLOR0A0,
809         GX_DISABLE,  // disable channel
810         GX_SRC_VTX,  // amb source
811         GX_SRC_VTX,  // mat source
812         0,           // light mask
813         GX_DF_NONE,  // diffuse function
814         GX_AF_NONE);
815 }
816 
817 /*---------------------------------------------------------------------------*
818     Name:           PrintIntro
819 
820     Description:    Prints the directions on how to use this demo.
821 
822     Arguments:      none
823 
824     Returns:        none
825  *---------------------------------------------------------------------------*/
PrintIntro(void)826 static void PrintIntro( void )
827 {
828     OSReport("\n\n");
829     OSReport("******************************************************\n");
830     OSReport("lit-spot: spot light angle attenuation test\n");
831     OSReport("******************************************************\n");
832     OSReport("to quit hit the start button\n");
833     OSReport("\n");
834     OSReport("B Button     : Select a light or camera\n");
835     OSReport("    [each light control mode]\n");
836     OSReport("Main Stick   : Change direction of selected light\n");
837     OSReport("Sub Stick    : Change XY-position of selected light\n");
838     OSReport("L/R Triggers : Change Z-position of selected light\n");
839     OSReport("X/Y Buttons  : Change the spotlight shape\n");
840     OSReport("    [camera control mode]\n");
841     OSReport("Main Stick   : Move the camera location\n");
842     OSReport("X/Y Buttons  : Enable/Disable spot function\n");
843     OSReport("L/R Triggers : Change the wall shape\n");
844     OSReport("******************************************************\n");
845     OSReport("\n");
846 }
847 
848 /*---------------------------------------------------------------------------*
849     Name:           StatusMessage
850 
851     Description:    Prints current status.
852  *---------------------------------------------------------------------------*/
StatusMessage(MyLightObj * light)853 static void StatusMessage(MyLightObj* light)
854 {
855     u32 i;
856     OSReport("%s ", CtrlMsg[light->colorIdx]);
857 
858     i = light->attnType;
859     OSReport(" a0 = %f ", LightAttnSamples[i].a0);
860     OSReport(" a1 = %f ", LightAttnSamples[i].a1);
861     OSReport(" a2 = %f ", LightAttnSamples[i].a2);
862 
863     OSReport("\n");
864 }
865 
866 /*============================================================================*/
867