1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin/Revolution gx demo
3   File:     lit-prelit.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-prelit
15      Vertex lighting with a prelit color
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_FAKELIGHTS   8
31 #define WALL_SIZE        64
32 #define WALL_ARRAY_SIZE  ( WALL_SIZE * WALL_SIZE * 3 )
33 
34 #define ALL_LIGHTS   \
35     ( GX_LIGHT0 | GX_LIGHT1 | GX_LIGHT2 | GX_LIGHT3 )
36 
37 /*---------------------------------------------------------------------------*
38   Structure definitions
39  *---------------------------------------------------------------------------*/
40 // for camera
41 typedef struct
42 {
43     Vec    location;
44     Vec    up;
45     Vec    target;
46     f32    left;
47     f32    top;
48     f32    znear;
49     f32    zfar;
50 } CameraConfig;
51 
52 typedef struct
53 {
54     CameraConfig  cfg;
55     Mtx           view;
56     Mtx44         proj;
57 } MyCameraObj;
58 
59 // for lighting
60 typedef struct
61 {
62     GXLightObj  lobj;
63     s32         theta;
64     s32         velocity;
65     u32         color;
66 } MyLightObj;
67 
68 // for pre-lighting
69 typedef struct
70 {
71     f32  xpos;
72     f32  ypos;
73     f32  zpos;
74     f32  vx;
75     f32  vy;
76     u32  color;
77 } MyFakeLightObj;
78 
79 // for entire scene control
80 typedef struct
81 {
82     MyCameraObj    cam;
83     MyFakeLightObj fakeLight[NUM_FAKELIGHTS];
84     u8*            preLitColor;
85     MyLightObj     lightCtrl[4];
86     GXColorSrc     ambSrc;
87     GXColorSrc     matSrc;
88 } MySceneCtrlObj;
89 
90 /*---------------------------------------------------------------------------*
91    Forward references
92  *---------------------------------------------------------------------------*/
93 void        main            ( void );
94 static void DrawInit        ( MySceneCtrlObj* sc );
95 static void DrawTick        ( MySceneCtrlObj* sc );
96 static void AnimTick        ( MySceneCtrlObj* sc );
97 static void DrawWall        ( void );
98 static void SetCamera       ( MyCameraObj* cam );
99 static void SetLight        ( MySceneCtrlObj* sc );
100 static void PreLighting     ( MySceneCtrlObj* sc );
101 static void PrintIntro      ( void );
102 static void StatusMessage   ( MySceneCtrlObj* sc );
103 
104 /*---------------------------------------------------------------------------*
105   Model and Lighting data
106  *---------------------------------------------------------------------------*/
107 #define REG_MATERIAL     MyColors[12]
108 #define REG_AMBIENT      MyColors[13]
109 
110 static GXColor MyColors[] ATTRIBUTE_ALIGN(32) =
111 {
112     {0xc0, 0xc0, 0xc0, 0xff},  // white
113     {0xc0, 0xc0, 0x00, 0xff},  // yellow
114     {0x00, 0xc0, 0xc0, 0xff},  // cyan
115     {0xc0, 0x00, 0xc0, 0xff},  // magenta
116 
117     {0xc0, 0x00, 0x00, 0xff},  // red
118     {0x00, 0xc0, 0x00, 0xff},  // green
119     {0x00, 0x00, 0xc0, 0xff},  // blue
120     {0xc0, 0x60, 0x00, 0xff},  // orange
121     {0xc0, 0x60, 0x90, 0xff},  // pink
122     {0x70, 0xc0, 0x40, 0xff},  // olive green
123     {0xc0, 0xa0, 0x70, 0xff},  // beige
124     {0x40, 0x00, 0xc0, 0xff},  // indigo
125 
126     {0xe0, 0xe0, 0xe0, 0xff},  // material reg.
127     {0x40, 0x40, 0x40, 0xff},  // ambient reg.
128 };
129 
130 static f32 FixedNormal[] ATTRIBUTE_ALIGN(32) =
131 { 0.0F, 0.0F, 1.0F };
132 
133 static s16 LightPos[4][3] =
134 {
135     {  400,  400, 400 },
136     {  400, -400, 400 },
137     { -400, -400, 400 },
138     { -400,  400, 400 }
139 };
140 
141 static Vec LightRotAxis[4] =
142 {
143     { -1.0F,   1.0F, 0.0F },
144     {  1.0F,   1.0F, 0.0F },
145     {  1.0F,  -1.0F, 0.0F },
146     { -1.0F,  -1.0F, 0.0F }
147 };
148 
149 static MyFakeLightObj DefaultFakeLightStatus[NUM_FAKELIGHTS] =
150 {
151     // xpos  ypos   zpos   vx     vy    color
152     { 24.0F, 24.0F, 4.0F,  0.4F,  0.8F, 4  },
153     { 24.0F, 40.0F, 4.5F, -0.6F,  0.2F, 5  },
154     { 40.0F, 24.0F, 5.0F, -0.5F,  0.4F, 6  },
155     { 40.0F, 40.0F, 5.5F, -0.2F, -0.7F, 7  },
156     { 32.0F,  8.0F, 6.0F,  0.3F,  0.5F, 8  },
157     {  8.0F, 32.0F, 6.5F, -0.8F, -0.2F, 9  },
158     { 56.0F, 32.0F, 7.0F,  0.4F,  0.4F, 10 },
159     { 32.0F, 56.0F, 7.5F, -0.5F,  0.0F, 11 }
160 };
161 
162 #define ANGLE_ATN0   -99.0F
163 #define ANGLE_ATN1   100.0F
164 #define ANGLE_ATN2     0.0F
165 
166 /*---------------------------------------------------------------------------*
167    Camera configuration
168  *---------------------------------------------------------------------------*/
169 static CameraConfig DefaultCamera =
170 {
171     { 0.0F, 0.0F, 1200.0F }, // location
172     { 0.0F, 1.0F,    0.0F }, // up
173     { 0.0F, 0.0F,    0.0F }, // target
174     -320.0F, // left
175     240.0F,  // top
176     500.0F,  // near
177     2000.0F  // far
178 };
179 
180 /*---------------------------------------------------------------------------*
181   Global variables
182  *---------------------------------------------------------------------------*/
183 static MySceneCtrlObj SceneCtrl;    // scene control parameters
184 
185 /*---------------------------------------------------------------------------*
186    Application main loop
187  *---------------------------------------------------------------------------*/
main(void)188 void main ( void )
189 {
190     DEMOInit(NULL);    // Initialize the OS, game pad, graphics and video.
191 
192     DrawInit(&SceneCtrl);       // Initialize vertex formats, arrays, lights, etc.
193 
194     PrintIntro();               // Print demo directions
195 
196     StatusMessage(&SceneCtrl);      // Print current status
197     while(!(DEMOPadGetButton(0) & PAD_BUTTON_MENU))
198     {
199         DEMOBeforeRender();
200         DrawTick(&SceneCtrl);    // Draw the model.
201         DEMODoneRender();
202         DEMOPadRead();           // Update pad status.
203         AnimTick(&SceneCtrl);    // Update animation.
204     }
205 
206     OSHalt("End of demo");
207 }
208 
209 
210 /*---------------------------------------------------------------------------*
211    Functions
212  *---------------------------------------------------------------------------*/
213 /*---------------------------------------------------------------------------*
214     Name:           DrawInit
215 
216     Description:    Initializes the vertex attribute, the array pointers
217                     and strides for the indexed data and lighting parameters.
218                     This function also set up modelview matrix.
219 
220     Arguments:      sc : pointer to the structure of scene control parameters
221 
222     Returns:        none
223  *---------------------------------------------------------------------------*/
DrawInit(MySceneCtrlObj * sc)224 static void DrawInit( MySceneCtrlObj* sc )
225 {
226     Mtx  ms, mt, mv, mvi;
227     f32  scaling;
228     u32  i;
229 
230     // sets vertex attributes
231     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_U8, 0);
232     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
233     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGB, GX_RGB8, 0);
234 
235     // sets array pointers
236     sc->preLitColor = MEMAllocFromAllocator(&DemoAllocator1,  WALL_ARRAY_SIZE );
237     ASSERTMSG(sc->preLitColor != 0, "Memory allocation failed.");
238 
239     GXSetArray(GX_VA_CLR0, sc->preLitColor, 3*sizeof(u8));
240     GXSetArray(GX_VA_NRM, FixedNormal, 3*sizeof(f32));
241 
242 
243     // initialize scene control parameters
244 
245     // camera
246     sc->cam.cfg = DefaultCamera;
247     SetCamera(&sc->cam);   // never changes in this test
248 
249     // set hardware light parameters
250     for ( i = 0 ; i < 4 ; ++i )
251     {
252         sc->lightCtrl[i].theta    = 70;
253         sc->lightCtrl[i].velocity = 2;
254         sc->lightCtrl[i].color    = i;
255     }
256 
257     // copy default fake light parameters
258     for ( i = 0 ; i < NUM_FAKELIGHTS ; ++i )
259     {
260         sc->fakeLight[i] = DefaultFakeLightStatus[i];
261     }
262 
263     // channel color source control
264     sc->ambSrc = GX_SRC_VTX;
265     sc->matSrc = GX_SRC_REG;
266 
267 
268     // modelview matrix is never changed in this test.
269      scaling = 800.0F / WALL_SIZE;
270     MTXScale(ms, scaling, scaling, 1.0F);  // scale
271     MTXTrans(mt, -400.0F, -400.0F, 0.0F);  // translation
272     MTXConcat(sc->cam.view, mt, mv);
273     MTXConcat(mv, ms, mv);
274     GXLoadPosMtxImm(mv, GX_PNMTX0);
275     MTXInverse(mv, mvi);
276     MTXTranspose(mvi, mv);
277     GXLoadNrmMtxImm(mv, GX_PNMTX0);
278 }
279 
280 /*---------------------------------------------------------------------------*
281     Name:           DrawTick
282 
283     Description:    Draw the model once.
284                     GXInit makes GX_PNMTX0 the default matrix.
285 
286     Arguments:      sc : pointer to the structure of scene control parameters
287 
288     Returns:        none
289  *---------------------------------------------------------------------------*/
DrawTick(MySceneCtrlObj * sc)290 static void DrawTick( MySceneCtrlObj* sc )
291 {
292     // render mode = one color / no texture
293     GXSetNumTexGens(0);
294     GXSetNumChans(1);
295     GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
296     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
297 
298     // pre-lighting
299     PreLighting(sc);
300 
301     // hardware lights and channel control
302     SetLight(sc);
303 
304     // sets preloaded modelview matrix and draws wall
305     GXSetCurrentMtx(GX_PNMTX0);
306     DrawWall();
307 }
308 
309 /*---------------------------------------------------------------------------*
310     Name:           AnimTick
311 
312     Description:    Moves light objects and controls scene by using pad status.
313 
314     Arguments:      sc : pointer to the structure of scene control parameters
315 
316     Returns:        none
317  *---------------------------------------------------------------------------*/
AnimTick(MySceneCtrlObj * sc)318 static void AnimTick( MySceneCtrlObj* sc )
319 {
320     u16  down = DEMOPadGetButtonDown(0);
321     u32  i;
322 
323     // changes channel source setting
324     if ( down & PAD_BUTTON_A )
325     {
326         sc->ambSrc = ( sc->ambSrc == GX_SRC_REG ) ? GX_SRC_VTX : GX_SRC_REG;
327 
328         if ( sc->ambSrc == GX_SRC_REG )
329         {
330             sc->matSrc = ( sc->matSrc == GX_SRC_REG ) ? GX_SRC_VTX : GX_SRC_REG;
331         }
332 
333         StatusMessage(sc);
334     }
335 
336     // moves fake lights
337     for ( i = 0 ; i < NUM_FAKELIGHTS ; ++i )
338     {
339         sc->fakeLight[i].xpos += sc->fakeLight[i].vx;
340         sc->fakeLight[i].ypos += sc->fakeLight[i].vy;
341 
342         if ( sc->fakeLight[i].xpos < 0.0F || sc->fakeLight[i].xpos > WALL_SIZE )
343         {
344             sc->fakeLight[i].vx = - sc->fakeLight[i].vx;
345         }
346         if ( sc->fakeLight[i].ypos < 0.0F || sc->fakeLight[i].ypos > WALL_SIZE )
347         {
348             sc->fakeLight[i].vy = - sc->fakeLight[i].vy;
349         }
350     }
351 
352     // moves hardware lights
353     for ( i = 0 ; i < 4 ; ++i )
354     {
355         sc->lightCtrl[i].theta += sc->lightCtrl[i].velocity;
356         if ( sc->lightCtrl[i].theta < 0 || sc->lightCtrl[i].theta > 90 )
357         {
358             sc->lightCtrl[i].velocity = - sc->lightCtrl[i].velocity;
359         }
360     }
361 
362 }
363 
364 /*---------------------------------------------------------------------------*
365     Name:           DrawWall
366 
367     Description:    Draws a tessellated wall
368 
369     Arguments:      none
370 
371     Returns:        none
372  *---------------------------------------------------------------------------*/
DrawWall(void)373 static void DrawWall( void )
374 {
375     u32 x, y, i;
376 
377     // sets up vertex descriptors
378     GXClearVtxDesc();
379     GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
380     GXSetVtxDesc(GX_VA_NRM, GX_INDEX8);
381     GXSetVtxDesc(GX_VA_CLR0, GX_INDEX16);
382 
383     for ( y = 0 ; y < WALL_SIZE - 1 ; ++y )
384     {
385         i = y * WALL_SIZE;
386         GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, WALL_SIZE * 2);
387             for ( x = 0 ; x < WALL_SIZE ; ++x )
388             {
389                 GXPosition3u8((u8)x, (u8)y, 0);
390                 GXNormal1x8(0);
391                 GXColor1x16((u16)(i+x));
392                 GXPosition3u8((u8)x, (u8)(y+1), 0);
393                 GXNormal1x8(0);
394                 GXColor1x16((u16)(i+x+WALL_SIZE));
395             }
396         GXEnd();
397     }
398 }
399 
400 /*---------------------------------------------------------------------------*
401     Name:           SetCamera
402 
403     Description:    Sets view matrix and loads projection matrix into hardware
404 
405     Arguments:      cam : pointer to the MyCameraObj structure
406 
407     Returns:        none
408  *---------------------------------------------------------------------------*/
SetCamera(MyCameraObj * cam)409 static void SetCamera( MyCameraObj* cam )
410 {
411     MTXLookAt(
412         cam->view,
413         &cam->cfg.location,
414         &cam->cfg.up,
415         &cam->cfg.target );
416 
417     MTXFrustum(
418         cam->proj,
419         cam->cfg.top,
420         - (cam->cfg.top),
421         cam->cfg.left,
422         - (cam->cfg.left),
423         cam->cfg.znear,
424         cam->cfg.zfar );
425     GXSetProjection(cam->proj, GX_PERSPECTIVE);
426 }
427 
428 /*---------------------------------------------------------------------------*
429     Name:           SetLight
430 
431     Description:    Sets hardware light objects and color channels
432 
433     Arguments:      sc : pointer to the structure of scene control parameters
434 
435     Returns:        none
436  *---------------------------------------------------------------------------*/
SetLight(MySceneCtrlObj * sc)437 void SetLight( MySceneCtrlObj* sc )
438 {
439     Mtx mr;
440     u32 i;
441 
442     for ( i = 0 ; i < 4 ; ++i )
443     {
444         Vec ldir = { 0.0F, 0.0F, -1.0F };
445         Vec lpos, laxis;
446 
447         // Light direction
448         laxis = LightRotAxis[i];
449         MTXRotAxisDeg(mr, &laxis, (f32)sc->lightCtrl[i].theta);
450         MTXMultVec(mr, &ldir, &ldir);
451         // convert direction into view space
452         MTXMultVecSR(sc->cam.view, &ldir, &ldir);
453 
454         // Light position
455         lpos.x = (f32)LightPos[i][0];
456         lpos.y = (f32)LightPos[i][1];
457         lpos.z = (f32)LightPos[i][2];
458         // convert position into view space
459         MTXMultVec(sc->cam.view, &lpos, &lpos);
460 
461         GXInitLightDirv(&sc->lightCtrl[i].lobj, &ldir);
462         GXInitLightPosv(&sc->lightCtrl[i].lobj, &lpos);
463         GXInitLightAttn(
464             &sc->lightCtrl[i].lobj,
465             ANGLE_ATN0,
466             ANGLE_ATN1,
467             ANGLE_ATN2,
468             1.0F,
469             0.0F,
470             0.0F );
471         GXInitLightColor(
472             &sc->lightCtrl[i].lobj,
473             MyColors[sc->lightCtrl[i].color] );
474     }
475 
476     // loads each light object
477     GXLoadLightObjImm(&sc->lightCtrl[0].lobj, GX_LIGHT0);
478     GXLoadLightObjImm(&sc->lightCtrl[1].lobj, GX_LIGHT1);
479     GXLoadLightObjImm(&sc->lightCtrl[2].lobj, GX_LIGHT2);
480     GXLoadLightObjImm(&sc->lightCtrl[3].lobj, GX_LIGHT3);
481 
482     // color channel setting
483     GXSetNumChans(1); // number of color channels
484     GXSetChanCtrl(
485         GX_COLOR0,
486         GX_ENABLE,   // enable channel
487         sc->ambSrc,  // amb source
488         sc->matSrc,  // mat source
489         ALL_LIGHTS,  // light mask
490         GX_DF_CLAMP, // diffuse function
491         GX_AF_SPOT);
492     GXSetChanCtrl(
493         GX_ALPHA0,
494         GX_DISABLE,  // disable channel
495         GX_SRC_REG,  // amb source
496         GX_SRC_REG,  // mat source
497         0,           // light mask
498         GX_DF_NONE,  // diffuse function
499         GX_AF_NONE);
500     // set up material and ambient register
501     GXSetChanMatColor(GX_COLOR0A0, REG_MATERIAL);
502     GXSetChanAmbColor(GX_COLOR0A0, REG_AMBIENT);
503 
504 }
505 
506 /*---------------------------------------------------------------------------*
507     Name:           PreLighting
508 
509     Description:    Creates an array of pre-lighted vertex color by
510                     using fake lights.
511 
512     Arguments:      sc : pointer to the structure of scene control parameters
513 
514     Returns:        none
515  *---------------------------------------------------------------------------*/
PreLighting(MySceneCtrlObj * sc)516 static void PreLighting( MySceneCtrlObj* sc )
517 {
518     f32 x, y, z, r, g, b, dx, dy, bri;
519     u32 iv, il, col;
520 
521     // calculates colors on each vertex
522     iv = 0;
523     for ( y = 0.0F ; y < (f32)WALL_SIZE ; y += 1.0F )
524     {
525         for ( x = 0.0F ; x < (f32)WALL_SIZE ; x += 1.0F )
526         {
527             r = g = b = 0.0F;
528 
529             for ( il = 0 ; il < NUM_FAKELIGHTS ; ++il )
530             {
531                 col = sc->fakeLight[il].color;
532                 dx  = sc->fakeLight[il].xpos - x;
533                 dy  = sc->fakeLight[il].ypos - y;
534                 z   = sc->fakeLight[il].zpos * sc->fakeLight[il].zpos;
535 
536                 bri = z / ( dx * dx + dy * dy + z );
537                 r += bri * MyColors[col].r;
538                 g += bri * MyColors[col].g;
539                 b += bri * MyColors[col].b;
540             }
541 
542             sc->preLitColor[iv]   = (u8)(( r > 255.0F ) ? 255 : r);
543             sc->preLitColor[iv+1] = (u8)(( g > 255.0F ) ? 255 : g);
544             sc->preLitColor[iv+2] = (u8)(( b > 255.0F ) ? 255 : b);
545             iv += 3;
546         }
547     }
548 
549     // flushes all data existing in D-cache into main memory
550     DCFlushRange(sc->preLitColor, WALL_ARRAY_SIZE);
551     // invalidates previous data existing in vertex cache
552     GXInvalidateVtxCache();
553 }
554 
555 /*---------------------------------------------------------------------------*
556     Name:           PrintIntro
557 
558     Description:    Prints the directions on how to use this demo.
559 
560     Arguments:      none
561 
562     Returns:        none
563  *---------------------------------------------------------------------------*/
PrintIntro(void)564 static void PrintIntro( void )
565 {
566     OSReport("\n\n");
567     OSReport("*****************************************\n");
568     OSReport("lit-prelit: prelit vertex lighting test\n");
569     OSReport("*****************************************\n");
570     OSReport("to quit hit the start button\n");
571     OSReport("\n");
572     OSReport("A Button     : Change channel sources\n");
573     OSReport("*****************************************\n");
574     OSReport("\n");
575 }
576 
577 /*---------------------------------------------------------------------------*
578     Name:           StatusMessage
579 
580     Description:    Prints the current status of scene control.
581 
582     Arguments:      sc : pointer to the structure of scene control parameters
583 
584     Returns:        none
585  *---------------------------------------------------------------------------*/
StatusMessage(MySceneCtrlObj * sc)586 static void StatusMessage( MySceneCtrlObj* sc )
587 {
588     if ( sc->ambSrc == GX_SRC_VTX )
589         OSReport("Ambient:Vertex  ");
590     else
591         OSReport("Ambient:Register");
592 
593     if ( sc->matSrc == GX_SRC_VTX )
594         OSReport("  Material:Vertex  ");
595     else
596         OSReport("  Material:Register");
597 
598     OSReport("\n");
599 }
600 
601 /*============================================================================*/
602