1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin/Revolution gx demo
3   File:     lit-specular.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-specular
15      specular lighting 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 
30 #define NUM_RENDER_MODES  4
31 
32 #define Clamp(val,min,max) \
33     ((val) = (((val) < (min)) ? (min) : ((val) > (max)) ? (max) : (val)))
34 
35 /*---------------------------------------------------------------------------*
36    Structure definitions
37  *---------------------------------------------------------------------------*/
38 // for camera
39 typedef struct
40 {
41     Vec    location;
42     Vec    up;
43     Vec    target;
44     f32    left;
45     f32    top;
46     f32    znear;
47     f32    zfar;
48 } CameraConfig;
49 
50 typedef struct
51 {
52     CameraConfig  cfg;
53     Mtx           view;
54     Mtx44         proj;
55 } MyCameraObj;
56 
57 // for lighting
58 typedef struct
59 {
60     GXLightObj     lobj;
61     s32            theta;
62     s32            phi;
63     f32            shininess;
64 } MyLightEnvObj;
65 
66 // for entire scene control
67 typedef struct
68 {
69     MyCameraObj    cam;
70     MyLightEnvObj  lightEnv;
71     Mtx            modelCtrl;
72     u32            modelType;
73     u32            renderMode;
74 } MySceneCtrlObj;
75 
76 /*---------------------------------------------------------------------------*
77    Forward references
78  *---------------------------------------------------------------------------*/
79 void        main            ( void );
80 static void DrawInit        ( MySceneCtrlObj* sc );
81 static void DrawTick        ( MySceneCtrlObj* sc );
82 static void AnimTick        ( MySceneCtrlObj* sc );
83 static void DrawModel       ( u32 model );
84 static void DrawLightMark   ( void );
85 static void SetCamera       ( MyCameraObj* cam );
86 static void SetLight        ( MyLightEnvObj* le, Mtx view );
87 static void DisableLight    ( void );
88 static void PrintIntro      ( void );
89 
90 /*---------------------------------------------------------------------------*
91    Model and color data
92  *---------------------------------------------------------------------------*/
93 #define SPHERE      0
94 #define CYLINDER    1
95 #define TORUS       2
96 #define ICOSA       3
97 #define DODECA      4
98 
99 #define MODELS      5
100 
101 
102 #define REG_AMBIENT0   MyColors[0]
103 #define REG_MATERIAL0  MyColors[1]
104 #define REG_AMBIENT1   MyColors[2]
105 #define REG_MATERIAL1  MyColors[3]
106 #define LIGHT_COLOR0   MyColors[4]
107 
108 static GXColor MyColors[] =
109 {
110     { 0x40, 0x40, 0x40, 0x40 }, // Ambient  for channel 0
111     { 0x50, 0x20, 0x10, 0xFF }, // Material for channel 0
112     { 0x00, 0x00, 0x00, 0x00 }, // Ambient  for channel 1
113     { 0xE0, 0xE0, 0xE0, 0xE0 }, // Material for channel 1
114     { 0xFF, 0xFF, 0xFF, 0xFF }  // Light color
115 };
116 
117 /*---------------------------------------------------------------------------*
118    Strings for messages
119  *---------------------------------------------------------------------------*/
120 static char* RenModeStr[] =
121 {
122     "Specular channel only",
123     "Diffuse channel only",
124     "Specular/Diffuse added",
125     "Specular/Diffuse blended"
126 };
127 
128 /*---------------------------------------------------------------------------*
129    Camera configuration
130  *---------------------------------------------------------------------------*/
131 static CameraConfig DefaultCamera =
132 {
133     { 0.0F, 0.0F, 900.0F }, // location
134     { 0.0F, 1.0F,   0.0F }, // up
135     { 0.0F, 0.0F,   0.0F }, // target
136     -320.0F, // left
137     240.0F,  // top
138     400.0F,  // znear
139     2000.0F  // zfar
140 };
141 
142 /*---------------------------------------------------------------------------*
143    Global variables
144  *---------------------------------------------------------------------------*/
145 static MySceneCtrlObj  SceneCtrl;    // scene control parameters
146 
147 /*---------------------------------------------------------------------------*
148    Application main loop
149  *---------------------------------------------------------------------------*/
main(void)150 void main ( void )
151 {
152     DEMOInit(NULL);
153 
154     DrawInit(&SceneCtrl);       // Initialize vertex formats and scene parameters.
155 
156     PrintIntro();  // Print demo directions
157 
158     while(!(DEMOPadGetButton(0) & PAD_BUTTON_MENU))
159     {
160         DEMOBeforeRender();
161         DrawTick(&SceneCtrl);    // Draw the model.
162         DEMODoneRender();
163         DEMOPadRead();           // Update pad status.
164         AnimTick(&SceneCtrl);    // Update animation.
165     }
166 
167     OSHalt("End of demo");
168 }
169 
170 /*---------------------------------------------------------------------------*
171    Functions
172  *---------------------------------------------------------------------------*/
173 /*---------------------------------------------------------------------------*
174     Name:           DrawInit
175 
176     Description:    Initializes the vertex attribute format and
177                     sets up default scene parameters.
178 
179     Arguments:      sc : pointer to the structure of scene control parameters
180 
181     Returns:        none
182  *---------------------------------------------------------------------------*/
DrawInit(MySceneCtrlObj * sc)183 static void DrawInit( MySceneCtrlObj* sc )
184 {
185     // set up a vertex attribute
186     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
187     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
188     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
189     GXSetNumTexGens(0);
190 
191     // Z compare mode
192     GXSetZMode(GX_ENABLE, GX_LEQUAL, GX_ENABLE);
193 
194 
195     // Default scene parameter settings
196 
197     // camera
198     sc->cam.cfg = DefaultCamera;
199     SetCamera(&sc->cam);   // never changes in this test
200 
201     // light parameters
202     sc->lightEnv.theta      = 0;
203     sc->lightEnv.phi        = 0;
204     sc->lightEnv.shininess  = 16.0F;
205 
206     // model control matrix
207     MTXScale(sc->modelCtrl, 300.0F, 300.0F, 300.0F);
208     sc->modelType = 0;
209 
210     // rendering mode
211     sc->renderMode = 0;
212 }
213 
214 /*---------------------------------------------------------------------------*
215     Name:           DrawTick
216 
217     Description:    Draws the model by using given scene parameters
218 
219     Arguments:      sc : pointer to the structure of scene control parameters
220 
221     Returns:        none
222  *---------------------------------------------------------------------------*/
223 /*---------------------------------------------------------------------------*
224     In the MAC emulator, we can't configure Tev to blend two color channels.
225     So this test draws the object twice with using pixel blending.
226  *---------------------------------------------------------------------------*/
DrawTick(MySceneCtrlObj * sc)227 static void DrawTick( MySceneCtrlObj* sc )
228 {
229     Mtx  mv, mr, mvi;
230 
231     // enable lighting
232     SetLight(&sc->lightEnv, sc->cam.view);
233 
234     // set tev mode
235     switch ( sc->renderMode )
236     {
237       case 0:
238         {
239             // Output = COLOR1
240             GXSetNumTevStages(1);
241             GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
242             GXSetTevOrder(
243                 GX_TEVSTAGE0,
244                 GX_TEXCOORD_NULL,
245                 GX_TEXMAP_NULL,
246                 GX_COLOR1A1 );
247         } break;
248       case 1:
249         {
250             // Output = COLOR0
251             GXSetNumTevStages(1);
252             GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
253             GXSetTevOrder(
254                 GX_TEVSTAGE0,
255                 GX_TEXCOORD_NULL,
256                 GX_TEXMAP_NULL,
257                 GX_COLOR0A0 );
258         } break;
259       case 2:
260         {
261             // Output = COLOR0 + COLOR1
262             GXSetNumTevStages(2);
263             GXSetTevOrder(
264                 GX_TEVSTAGE0,
265                 GX_TEXCOORD_NULL,
266                 GX_TEXMAP_NULL,
267                 GX_COLOR0A0 );
268             GXSetTevOrder(
269                 GX_TEVSTAGE1,
270                 GX_TEXCOORD_NULL,
271                 GX_TEXMAP_NULL,
272                 GX_COLOR1A1 );
273             GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
274             GXSetTevColorOp(
275                 GX_TEVSTAGE1,
276                 GX_TEV_ADD,    // operator
277                 GX_TB_ZERO,    // bias
278                 GX_CS_SCALE_1, // scale
279                 GX_ENABLE,     // clamp
280                 GX_TEVPREV );  // output
281             GXSetTevColorIn(
282                 GX_TEVSTAGE1,
283                 GX_CC_ZERO,    // a
284                 GX_CC_RASC,    // b
285                 GX_CC_ONE,     // c
286                 GX_CC_CPREV ); // d
287         } break;
288       case 3:
289         {
290             // Output = ( 1 - COLOR1 ) * COLOR0 + COLOR1
291             GXSetNumTevStages(2);
292             GXSetTevOrder(
293                 GX_TEVSTAGE0,
294                 GX_TEXCOORD_NULL,
295                 GX_TEXMAP_NULL,
296                 GX_COLOR0A0 );
297             GXSetTevOrder(
298                 GX_TEVSTAGE1,
299                 GX_TEXCOORD_NULL,
300                 GX_TEXMAP_NULL,
301                 GX_COLOR1A1 );
302             GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
303             GXSetTevColorOp(
304                 GX_TEVSTAGE1,
305                 GX_TEV_ADD,    // operator
306                 GX_TB_ZERO,    // bias
307                 GX_CS_SCALE_1, // scale
308                 GX_ENABLE,     // clamp
309                 GX_TEVPREV );  // output
310             GXSetTevColorIn(
311                 GX_TEVSTAGE1,
312                 GX_CC_CPREV,   // a
313                 GX_CC_ONE,     // b
314                 GX_CC_RASC,    // c
315                 GX_CC_ZERO );  // d
316         } break;
317     }
318 
319     // draw the model
320     MTXConcat(sc->cam.view, sc->modelCtrl, mv);
321     GXLoadPosMtxImm(mv, GX_PNMTX0);
322     MTXInverse(mv, mvi);
323     MTXTranspose(mvi, mv);
324     GXLoadNrmMtxImm(mv, GX_PNMTX0);
325 
326     DrawModel(sc->modelType);
327 
328 
329     // Draw light direction mark
330     DisableLight();
331     GXSetNumTevStages(1);
332     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
333 
334     MTXRotDeg(mr, 'y', sc->lightEnv.theta);
335     MTXConcat(sc->cam.view, mr, mv);
336     MTXRotDeg(mr, 'x', - sc->lightEnv.phi);
337     MTXConcat(mv, mr, mv);
338     GXLoadPosMtxImm(mv, GX_PNMTX0);
339     DrawLightMark();
340 }
341 
342 /*---------------------------------------------------------------------------*
343     Name:           AnimTick
344 
345     Description:    Changes scene parameters according to the pad status.
346 
347     Arguments:      sc : pointer to the structure of scene control parameters
348 
349     Returns:        none
350  *---------------------------------------------------------------------------*/
AnimTick(MySceneCtrlObj * sc)351 static void AnimTick( MySceneCtrlObj* sc )
352 {
353     static u32  cursor = 0;
354     u16  button, down;
355     Mtx  mrx, mry;
356 
357     // PAD
358     button = DEMOPadGetButton(0);
359     down   = DEMOPadGetButtonDown(0);
360 
361     // Light Position Calculation
362     sc->lightEnv.theta += ( DEMOPadGetStickX(0) / 32 );
363     sc->lightEnv.theta = sc->lightEnv.theta % 360;
364     sc->lightEnv.phi += ( DEMOPadGetStickY(0) / 32 );
365     Clamp(sc->lightEnv.phi, -90, 90);
366 
367 
368     // Model Rotation Calculation
369     MTXRotDeg(mry, 'x', -(DEMOPadGetSubStickY(0) / 32));
370     MTXRotDeg(mrx, 'y', (DEMOPadGetSubStickX(0) / 32));
371     MTXConcat(mry, sc->modelCtrl, sc->modelCtrl);
372     MTXConcat(mrx, sc->modelCtrl, sc->modelCtrl);
373 
374 
375     // Shininess parameter control
376     if ( button & PAD_TRIGGER_L )
377     {
378         sc->lightEnv.shininess -= 4.0F;
379     }
380     if ( button & PAD_TRIGGER_R )
381     {
382         sc->lightEnv.shininess += 4.0F;
383     }
384     Clamp(sc->lightEnv.shininess, 4.0F, 256.0F);
385 
386     // Render mode
387     if ( down & PAD_BUTTON_Y )
388     {
389         sc->renderMode = ( sc->renderMode + 1 ) % NUM_RENDER_MODES;
390         OSReport("%s\n", RenModeStr[sc->renderMode]);
391     }
392 
393     // Model Select
394     if ( down & PAD_BUTTON_B )
395     {
396         sc->modelType = ( sc->modelType + 1 ) % MODELS;
397     }
398 
399 }
400 
401 /*---------------------------------------------------------------------------*
402     Name:           DrawModel
403 
404     Description:    Draws specified model
405 
406     Arguments:      model : specifies which model is to be displayed
407 
408     Returns:        none
409  *---------------------------------------------------------------------------*/
DrawModel(u32 model)410 static void DrawModel( u32 model )
411 {
412     // sets up vertex descriptors
413     GXClearVtxDesc();
414     GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
415     GXSetVtxDesc(GX_VA_NRM, GX_DIRECT);
416 
417     // draws a GXDraw model
418     switch(model)
419     {
420         case CYLINDER :
421             GXDrawCylinder(64);
422             break;
423         case TORUS :
424             GXDrawTorus(0.25F, 24, 32);
425             break;
426         case SPHERE :
427             GXDrawSphere1(3);
428             break;
429         case ICOSA :
430             GXDrawIcosahedron();
431             break;
432         case DODECA :
433             GXDrawDodeca();
434             break;
435     }
436 }
437 
438 /*---------------------------------------------------------------------------*
439     Name:           DrawLightMark
440 
441     Description:    Draws a mark which shows position of the light.
442 
443     Arguments:      none
444 
445     Returns:        none
446  *---------------------------------------------------------------------------*/
DrawLightMark(void)447 static void DrawLightMark( void )
448 {
449     // sets up vertex descriptors
450     GXClearVtxDesc();
451     GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
452     GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
453 
454     GXBegin(GX_LINES, GX_VTXFMT0, 10);
455         GXPosition3f32(0.0F, 0.0F, 350.0F);
456         GXColor4u8(0, 255, 255, 255);
457         GXPosition3f32(0.0F, 0.0F, 0.0F);
458         GXColor4u8(0, 255, 255, 255);
459 
460         GXPosition3f32(20.0F, 20.0F, 450.0F);
461         GXColor4u8(0, 255, 255, 255);
462         GXPosition3f32(0.0F, 0.0F, 350.0F);
463         GXColor4u8(0, 255, 255, 255);
464 
465         GXPosition3f32(-20.0F, 20.0F, 450.0F);
466         GXColor4u8(0, 255, 255, 255);
467         GXPosition3f32(0.0F, 0.0F, 350.0F);
468         GXColor4u8(0, 255, 255, 255);
469 
470         GXPosition3f32(-20.0F, -20.0F, 450.0F);
471         GXColor4u8(0, 255, 255, 255);
472         GXPosition3f32(0.0F, 0.0F, 350.0F);
473         GXColor4u8(0, 255, 255, 255);
474 
475         GXPosition3f32(20.0F, -20.0F, 450.0F);
476         GXColor4u8(0, 255, 255, 255);
477         GXPosition3f32(0.0F, 0.0F, 350.0F);
478         GXColor4u8(0, 255, 255, 255);
479     GXEnd();
480 }
481 
482 /*---------------------------------------------------------------------------*
483     Name:           SetCamera
484 
485     Description:    Sets view matrix and loads projection matrix into hardware
486 
487     Arguments:      cam : pointer to the MyCameraObj structure
488 
489     Returns:        none
490  *---------------------------------------------------------------------------*/
SetCamera(MyCameraObj * cam)491 static void SetCamera( MyCameraObj* cam )
492 {
493     MTXLookAt(
494         cam->view,
495         &cam->cfg.location,
496         &cam->cfg.up,
497         &cam->cfg.target );
498 
499     MTXFrustum(
500         cam->proj,
501         cam->cfg.top,
502         - (cam->cfg.top),
503         cam->cfg.left,
504         - (cam->cfg.left),
505         cam->cfg.znear,
506         cam->cfg.zfar );
507     GXSetProjection(cam->proj, GX_PERSPECTIVE);
508 }
509 
510 /*---------------------------------------------------------------------------*
511     Name:           SetLight
512 
513     Description:    Sets up lights and lighting channel parameters
514 
515     Arguments:      le   : pointer to a MyLightEnvObj structure
516                     view : view matrix
517 
518     Returns:        none
519  *---------------------------------------------------------------------------*/
SetLight(MyLightEnvObj * le,Mtx view)520 static void SetLight( MyLightEnvObj* le, Mtx view )
521 {
522     GXDiffuseFn  dfunc[2];
523     GXAttnFn     afunc[2];
524     Vec  ldir;
525     f32  theta, phi;
526 
527     // attenuation setting
528     dfunc[0] = GX_DF_CLAMP;
529     afunc[0] = GX_AF_NONE;
530     dfunc[1] = GX_DF_NONE;
531     afunc[1] = GX_AF_SPEC;
532 
533     // Light position
534     theta = (f32)le->theta * PI / 180.0F;
535     phi   = (f32)le->phi   * PI / 180.0F;
536     ldir.x = - 1.0F * cosf(phi) * sinf(theta);
537     ldir.y = - 1.0F * sinf(phi);
538     ldir.z = - 1.0F * cosf(phi) * cosf(theta);
539 
540     // Convert light position into view space
541     MTXMultVecSR(view, &ldir, &ldir);
542 
543     // Set up light parameters
544 
545     // This API can calculate infinite light position
546     // and half-angle vector internally.
547     GXInitSpecularDirv(&le->lobj, &ldir);
548 
549     GXInitLightShininess(&le->lobj, le->shininess);
550     GXInitLightColor(&le->lobj, LIGHT_COLOR0);
551     GXLoadLightObjImm(&le->lobj, GX_LIGHT0);
552 
553     // Lighting channel
554     GXSetNumChans(2);    // use two color channels
555     GXSetChanCtrl(
556         GX_COLOR0,
557         GX_ENABLE,       // enable channel
558         GX_SRC_REG,      // amb source
559         GX_SRC_REG,      // mat source
560         GX_LIGHT0,       // light mask
561         dfunc[0],        // diffuse function
562         afunc[0]);       // attenuation
563     GXSetChanCtrl(
564         GX_COLOR1,
565         GX_ENABLE,       // enable channel
566         GX_SRC_REG,      // amb source
567         GX_SRC_REG,      // mat source
568         GX_LIGHT0,       // light mask
569         dfunc[1],        // diffuse function
570         afunc[1]);       // attenuation
571     GXSetChanCtrl(
572         GX_ALPHA0,
573         GX_DISABLE,      // disable channel
574         GX_SRC_REG,      // amb source
575         GX_SRC_REG,      // mat source
576         GX_LIGHT_NULL,   // light mask
577         GX_DF_NONE,      // diffuse function
578         GX_AF_NONE);
579     GXSetChanCtrl(
580         GX_ALPHA1,
581         GX_DISABLE,      // disable channel
582         GX_SRC_REG,      // amb source
583         GX_SRC_REG,      // mat source
584         GX_LIGHT_NULL,   // light mask
585         GX_DF_NONE,      // diffuse function
586         GX_AF_NONE);
587 
588     // set up ambient color
589     GXSetChanAmbColor(GX_COLOR0, REG_AMBIENT0);
590     GXSetChanAmbColor(GX_COLOR1, REG_AMBIENT1);
591     // set up material color
592     GXSetChanMatColor(GX_COLOR0, REG_MATERIAL0);
593     GXSetChanMatColor(GX_COLOR1, REG_MATERIAL1);
594 
595 }
596 
597 /*---------------------------------------------------------------------------*
598     Name:           DisableLight
599 
600     Description:    Disables lighting
601 
602     Arguments:      none
603 
604     Returns:        none
605  *---------------------------------------------------------------------------*/
DisableLight(void)606 static void DisableLight( void )
607 {
608     // use only one color channel to avoid wasting performance.
609     GXSetNumChans(1);
610 
611     GXSetChanCtrl(
612         GX_COLOR0A0,
613         GX_DISABLE,    // disable channel
614         GX_SRC_VTX,    // amb source
615         GX_SRC_VTX,    // mat source
616         GX_LIGHT_NULL, // light mask
617         GX_DF_NONE,    // diffuse function
618         GX_AF_NONE);
619     GXSetChanCtrl(
620         GX_COLOR1A1,
621         GX_DISABLE,    // disable channel
622         GX_SRC_VTX,    // amb source
623         GX_SRC_VTX,    // mat source
624         GX_LIGHT_NULL, // light mask
625         GX_DF_NONE,    // diffuse function
626         GX_AF_NONE);
627 }
628 
629 /*---------------------------------------------------------------------------*
630     Name:           PrintIntro
631 
632     Description:    Prints the directions on how to use this demo.
633 
634     Arguments:      none
635 
636     Returns:        none
637  *---------------------------------------------------------------------------*/
PrintIntro(void)638 static void PrintIntro( void )
639 {
640     OSReport("\n\n");
641     OSReport("************************************************\n");
642     OSReport("lit-specular: specular lighting test\n");
643     OSReport("************************************************\n");
644     OSReport("to quit hit the start button\n");
645     OSReport("\n");
646     OSReport("Main Stick   : Move Light Direction\n");
647     OSReport("Sub  Stick   : Rotate the model\n");
648     OSReport("L/R Triggers : Change shininess parameter\n");
649     OSReport("Y Button     : Change rendering mode\n");
650     OSReport("B Button     : Change Model\n");
651     OSReport("************************************************\n\n");
652 }
653 
654 /*============================================================================*/
655