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