1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin/Revolution gx demo
3   File:     tg-dual.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    tg-dual
15      A simple demo of dual transform texgen feature
16  *---------------------------------------------------------------------------*
17      NOTE: This feature is only available on HW2 (or MAC2)
18  *---------------------------------------------------------------------------*/
19 
20 
21 /*---------------------------------------------------------------------------*
22    Header files
23  *---------------------------------------------------------------------------*/
24 #include <demo.h>
25 #include <math.h>
26 
27 /*---------------------------------------------------------------------------*
28    Macro definitions
29  *---------------------------------------------------------------------------*/
30 #define PI          3.14159265358979323846F
31 
32 #define MODE_POS    0
33 #define MODE_NRM    1
34 #define NUM_MODES   2
35 
36 #define Clamp(val,min,max) \
37     ((val) = (((val) < (min)) ? (min) : ((val) > (max)) ? (max) : (val)))
38 
39 /*---------------------------------------------------------------------------*
40    Structure definitions
41  *---------------------------------------------------------------------------*/
42 // for camera
43 typedef struct
44 {
45     Vec    location;
46     Vec    up;
47     Vec    target;
48     f32    left;
49     f32    top;
50     f32    znear;
51     f32    zfar;
52 } CameraConfig;
53 
54 typedef struct
55 {
56     CameraConfig  cfg;
57     Mtx           view;
58     Mtx44         proj;
59     s32           theta;
60     s32           phi;
61     f32           distance;
62 } MyCameraObj;
63 
64 typedef struct
65 {
66     GXLightObj      lobj;
67     MyCameraObj     cam;
68 } MyLightObj;
69 
70 // for entire scene control
71 typedef struct
72 {
73     MyCameraObj     cam;
74     MyLightObj      light;
75     GXTexObj        texture[NUM_MODES];
76     Mtx             modelCtrl;
77     u32             mode;
78 } MySceneCtrlObj;
79 
80 /*---------------------------------------------------------------------------*
81    Forward references
82  *---------------------------------------------------------------------------*/
83 void        main            ( void );
84 
85 static void DrawInit        ( MySceneCtrlObj* sc );
86 static void DrawTick        ( MySceneCtrlObj* sc );
87 static void AnimTick        ( MySceneCtrlObj* sc );
88 static void SetCamera       ( MyCameraObj* cam );
89 static void DrawLightMark   ( MyLightObj* light );
90 static void SetLight        ( MyLightObj* light, Mtx view );
91 static void DisableLight    ( void );
92 static void SetTexGenPos    ( MySceneCtrlObj* sc );
93 static void SetTexGenNrm    ( MySceneCtrlObj* sc );
94 static void PrintIntro      ( void );
95 
96 /*---------------------------------------------------------------------------*
97    Lighting parameters
98  *---------------------------------------------------------------------------*/
99 #define COL_LIGHT       (GXColor){ 0xA0, 0xA0, 0xA0, 0xA0 }
100 #define COL_AMBIENT     (GXColor){ 0x60, 0x60, 0x60, 0x60 }
101 #define COL_MATERIAL    (GXColor){ 0x80, 0xFF, 0x40, 0xFF }
102 
103 /*---------------------------------------------------------------------------*
104    Camera configuration
105  *---------------------------------------------------------------------------*/
106 static CameraConfig DefaultCamera =
107 {
108     { 0.0F, 0.0F, 10.0F }, // location (actually not used)
109     { 0.0F, 1.0F,  0.0F }, // up
110     { 0.0F, 0.0F,  0.0F }, // target
111     -160.0F, // left
112      120.0F, // top
113      500.0F, // near
114     5000.0F  // far
115 };
116 
117 static CameraConfig DefaultLightCamera =
118 {
119     { 10.0F, 10.0F, 10.0F }, // location (actually not used)
120     {  0.0F,  1.0F,  0.0F }, // up
121     {  0.0F,  0.0F,  0.0F }, // target
122     -32.0F,   // left
123      32.0F,   // top
124     300.0F,   // near
125    5000.0F    // far
126 };
127 
128 /*---------------------------------------------------------------------------*
129    Global variables
130  *---------------------------------------------------------------------------*/
131 static MySceneCtrlObj  SceneCtrl;    // scene control parameters
132 static TPLPalettePtr   MyTplObj = NULL;
133 
134 /*---------------------------------------------------------------------------*
135    Application main loop
136  *---------------------------------------------------------------------------*/
main(void)137 void main ( void )
138 {
139     DEMOInit(NULL);    // Init the OS, game pad, graphics and video.
140 
141     DrawInit(&SceneCtrl);       // Initialize vertex formats and scene parameters.
142     PrintIntro();               // Print demo directions
143 
144     while(!(DEMOPadGetButton(0) & PAD_BUTTON_MENU))
145     {
146         DEMOBeforeRender();
147         DrawTick(&SceneCtrl);   // Draw the model.
148         DEMODoneRender();
149         DEMOPadRead();          // Update pad status.
150         AnimTick(&SceneCtrl);   // Update animation.
151     }
152 
153     OSHalt("End of test");
154 }
155 
156 /*---------------------------------------------------------------------------*
157    Functions
158  *---------------------------------------------------------------------------*/
159 /*---------------------------------------------------------------------------*
160     Name:           DrawInit
161 
162     Description:    Initializes the vertex attribute format, texture and
163                     default scene parameters.
164 
165     Arguments:      sc : pointer to the structure of scene control parameters
166 
167     Returns:        none
168  *---------------------------------------------------------------------------*/
DrawInit(MySceneCtrlObj * sc)169 static void DrawInit( MySceneCtrlObj* sc )
170 {
171     TPLDescriptorPtr tdp;
172     u32     i;
173 
174     GXSetCopyClear((GXColor){ 0x40, 0x40, 0x40, 0xFF}, 0xFFFFFF);
175 
176     // set up a vertex attribute
177     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
178     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
179     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
180 
181     // textures
182     TPLGetPalette(&MyTplObj, "gxTests/tg-dual.tpl");
183     for ( i = 0 ; i < NUM_MODES ; ++i )
184     {
185         tdp = TPLGet(MyTplObj, i);
186         GXInitTexObj(
187             &sc->texture[i],
188             tdp->textureHeader->data,
189             tdp->textureHeader->width,
190             tdp->textureHeader->height,
191             (GXTexFmt)tdp->textureHeader->format,
192             GX_CLAMP, // s
193             GX_CLAMP, // t
194             GX_FALSE );
195     }
196 
197 
198     // Default scene parameter settings
199 
200     // camera
201     sc->cam.cfg      = DefaultCamera;
202     sc->cam.theta    = 0;
203     sc->cam.phi      = 0;
204     sc->cam.distance = 2000.0F;
205 
206     // light parameters
207     sc->light.cam.cfg      = DefaultLightCamera;
208     sc->light.cam.theta    = 0;
209     sc->light.cam.phi      = 60;
210     sc->light.cam.distance = 1000.0F;
211 
212     // mode
213     sc->mode = 0;
214 
215     // model control matrix
216     MTXIdentity(sc->modelCtrl);
217 }
218 
219 /*---------------------------------------------------------------------------*
220     Name:           DrawTick
221 
222     Description:    Draws the model by using given scene parameters
223 
224     Arguments:      sc : pointer to the structure of scene control parameters
225 
226     Returns:        none
227  *---------------------------------------------------------------------------*/
DrawTick(MySceneCtrlObj * sc)228 static void DrawTick( MySceneCtrlObj* sc )
229 {
230     s32  i;
231     Mtx  mv, mvi, mr, ms, mm;
232 
233     // camera
234     SetCamera(&sc->cam);
235     GXSetProjection(sc->cam.proj, GX_PERSPECTIVE);
236 
237     // lighting
238     SetLight(&sc->light, sc->cam.view);
239 
240     // set texture
241     GXLoadTexObj(&sc->texture[sc->mode], GX_TEXMAP0);
242     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
243 
244     // set up texture coord generation and TEV operation
245     switch( sc->mode )
246     {
247       case MODE_POS :
248         SetTexGenPos(sc);
249         GXSetTevOp(GX_TEVSTAGE0, GX_DECAL);
250         break;
251       case MODE_NRM :
252         SetTexGenNrm(sc);
253         GXSetTevOp(GX_TEVSTAGE0, GX_MODULATE);
254         break;
255     }
256 
257     // draw models
258     MTXConcat(sc->cam.view, sc->modelCtrl, mm);
259     MTXScale(ms, 150.0F, 150.0F, 150.0F);
260     MTXConcat(mm, ms, mm);
261     for ( i = 0 ; i < 5 ; ++i )
262     {
263         MTXTrans(ms, i-2, 0.0F, 0.0F);
264         MTXRotDeg(mr, 'x', i*90);
265         MTXConcat(ms, mr, mv);
266         MTXConcat(mm, mv, mv);
267         GXLoadPosMtxImm(mv, GX_PNMTX0);
268 
269         MTXInverse(mv, mvi);
270         MTXTranspose(mvi, mv);
271         GXLoadNrmMtxImm(mv, GX_PNMTX0);
272         if ( sc->mode == MODE_NRM )
273         {
274             // A copy of normal transform matrix
275             GXLoadTexMtxImm(mv, GX_TEXMTX0, GX_MTX3x4);
276         }
277 
278         GXDrawTorus(0.25F, 12, 16);
279     }
280 
281     // light mark
282     if ( sc->mode == MODE_POS )
283     {
284         // disable lighting
285         DisableLight();
286         // set texture environments
287         GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
288         GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
289 
290         // transform matrix
291         MTXRotDeg(mr, 'y', sc->light.cam.theta);
292         MTXConcat(sc->cam.view, mr, mv);
293         MTXRotDeg(mr, 'x', - sc->light.cam.phi);
294         MTXConcat(mv, mr, mv);
295         GXLoadPosMtxImm(mv, GX_PNMTX0);
296 
297         // draw a light mark
298         DrawLightMark(&sc->light);
299     }
300 }
301 
302 /*---------------------------------------------------------------------------*
303     Name:           AnimTick
304 
305     Description:    Changes scene parameters according to the pad status.
306 
307     Arguments:      sc : pointer to the structure of scene control parameters
308 
309     Returns:        none
310  *---------------------------------------------------------------------------*/
AnimTick(MySceneCtrlObj * sc)311 static void AnimTick( MySceneCtrlObj* sc )
312 {
313     Mtx  mrx, mry;
314     u16  button, down;
315     u32  pr = 0;
316 
317     // PAD
318     button = DEMOPadGetButton(0);
319     down   = DEMOPadGetButtonDown(0);
320 
321     // Light position
322     sc->light.cam.theta += ( DEMOPadGetSubStickX(0) / 24 );
323     if ( sc->light.cam.theta > 360 )
324     {
325         sc->light.cam.theta -= 360;
326     }
327     if ( sc->light.cam.theta < 0 )
328     {
329         sc->light.cam.theta += 360;
330     }
331     sc->light.cam.phi += ( DEMOPadGetSubStickY(0) / 24 );
332     Clamp(sc->light.cam.phi, -85, 85);
333 
334     // Model Rotation Calculation
335     MTXRotDeg(mry, 'x', -(f32)DEMOPadGetStickY(0) / 24.0F);
336     MTXRotDeg(mrx, 'y', (f32)DEMOPadGetStickX(0) / 24.0F);
337     MTXConcat(mry, sc->modelCtrl, sc->modelCtrl);
338     MTXConcat(mrx, sc->modelCtrl, sc->modelCtrl);
339 
340     // Projection control
341     sc->light.cam.cfg.znear +=
342         ( DEMOPadGetTriggerR(0) - DEMOPadGetTriggerL(0) ) / 16;
343     Clamp(sc->light.cam.cfg.znear, 200.0F, 600.0F);
344 
345     // change mode
346     if ( down & PAD_BUTTON_A )
347     {
348         sc->mode = ( sc->mode + 1 ) % NUM_MODES;
349         switch(sc->mode)
350         {
351           case MODE_POS :
352             OSReport("Position based projection\n");
353             break;
354           case MODE_NRM :
355             OSReport("Normal based environment mapping\n");
356             break;
357         }
358     }
359 
360 }
361 
362 /*---------------------------------------------------------------------------*
363     Name:           DrawLightMark
364 
365     Description:    Draws a mark which shows position of the light.
366 
367     Arguments:      light: light object
368 
369     Returns:        none
370  *---------------------------------------------------------------------------*/
DrawLightMark(MyLightObj * light)371 static void DrawLightMark( MyLightObj* light )
372 {
373     f32  dst, wd;
374 
375     // sets up vertex descriptors
376     GXClearVtxDesc();
377     GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
378     GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
379 
380     dst = light->cam.distance;
381     wd  = 64.0F * dst / light->cam.cfg.znear;
382 
383     GXBegin(GX_LINES, GX_VTXFMT0, 8);
384         GXPosition3f32(wd, wd, -dst);
385         GXColor4u8(0, 255, 255, 255);
386         GXPosition3f32(0.0F, 0.0F, dst);
387         GXColor4u8(0, 255, 255, 255);
388 
389         GXPosition3f32(wd, -wd, -dst);
390         GXColor4u8(0, 255, 255, 255);
391         GXPosition3f32(0.0F, 0.0F, dst);
392         GXColor4u8(0, 255, 255, 255);
393 
394         GXPosition3f32(-wd, wd, -dst);
395         GXColor4u8(0, 255, 255, 255);
396         GXPosition3f32(0.0F, 0.0F, dst);
397         GXColor4u8(0, 255, 255, 255);
398 
399         GXPosition3f32(-wd, -wd, -dst);
400         GXColor4u8(0, 255, 255, 255);
401         GXPosition3f32(0.0F, 0.0F, dst);
402         GXColor4u8(0, 255, 255, 255);
403     GXEnd();
404 }
405 
406 /*---------------------------------------------------------------------------*
407     Name:           SetCamera
408 
409     Description:    Sets view matrix and loads projection matrix into hardware
410 
411     Arguments:      cam : pointer to the MyCameraObj structure
412 
413     Returns:        none
414  *---------------------------------------------------------------------------*/
SetCamera(MyCameraObj * cam)415 static void SetCamera( MyCameraObj* cam )
416 {
417     f32  r_theta, r_phi;
418 
419     r_theta = (f32)cam->theta * PI / 180.0F;
420     r_phi   = (f32)cam->phi   * PI / 180.0F;
421 
422     cam->cfg.location.x =
423         cam->distance * sinf(r_theta) * cosf(r_phi);
424     cam->cfg.location.y =
425         cam->distance * sinf(r_phi);
426     cam->cfg.location.z =
427         cam->distance * cosf(r_theta) * cosf(r_phi);
428 
429     MTXLookAt(
430         cam->view,
431         &cam->cfg.location,
432         &cam->cfg.up,
433         &cam->cfg.target );
434 
435     MTXFrustum(
436         cam->proj,
437         cam->cfg.top,
438         - (cam->cfg.top),
439         cam->cfg.left,
440         - (cam->cfg.left),
441         cam->cfg.znear,
442         cam->cfg.zfar );
443 }
444 
445 /*---------------------------------------------------------------------------*
446     Name:           SetLight
447 
448     Description:    Sets up lights and lighting channel parameters
449 
450     Arguments:      light: pointer to a MyLightObj structure
451                     view : view matrix
452 
453     Returns:        none
454  *---------------------------------------------------------------------------*/
SetLight(MyLightObj * light,Mtx view)455 static void SetLight( MyLightObj* light, Mtx view )
456 {
457     Vec lpos;
458 
459     // Light Position
460     SetCamera(&light->cam);
461     lpos = light->cam.cfg.location;
462 
463     // Convert light position into view space
464     MTXMultVec(view, &lpos, &lpos);
465 
466     GXInitLightPos(&light->lobj, lpos.x, lpos.y, lpos.z);
467     GXInitLightColor(&light->lobj, COL_LIGHT);
468     GXLoadLightObjImm(&light->lobj, GX_LIGHT0);
469 
470     // Lighting channel
471     GXSetNumChans(1);
472     GXSetChanCtrl(
473         GX_COLOR0A0,
474         GX_ENABLE,   // enable channel
475         GX_SRC_REG,  // amb source
476         GX_SRC_REG,  // mat source
477         GX_LIGHT0,   // light mask
478         GX_DF_CLAMP, // diffuse function
479         GX_AF_NONE);
480     // set up ambient color
481     GXSetChanAmbColor(GX_COLOR0A0, COL_AMBIENT);
482     // set up material color
483     GXSetChanMatColor(GX_COLOR0A0, COL_MATERIAL);
484 
485 }
486 
487 /*---------------------------------------------------------------------------*
488     Name:           DisableLight
489 
490     Description:    Disables lighting
491 
492     Arguments:      none
493 
494     Returns:        none
495  *---------------------------------------------------------------------------*/
DisableLight(void)496 static void DisableLight( void )
497 {
498     GXSetChanCtrl(
499         GX_COLOR0A0,
500         GX_DISABLE,     // disable channel
501         GX_SRC_VTX,     // amb source
502         GX_SRC_VTX,     // mat source
503         GX_LIGHT_NULL,  // light mask
504         GX_DF_NONE,     // diffuse function
505         GX_AF_NONE );
506 }
507 
508 /*---------------------------------------------------------------------------*
509     Name:           SetTexGenPos
510 
511     Description:    Set up texgen for position based projection
512                     (by dual-transform)
513 
514     Arguments:      sc : a pointer to MySceneCtrlObj structure
515 
516     Returns:        none
517  *---------------------------------------------------------------------------*/
518 /*---------------------------------------------------------------------------*
519     Position transform matrix usually contains transformation as:
520 
521         Cv * Mv (where Cv = camera view, Mv = model view.)
522 
523     Now, texture projection requires the transformation like:
524 
525         Lp * Lv * Mv (where Lv = light view, Lp = projection.)
526 
527     In such case, if we set the matrix:
528 
529         Lp * Lv * Inv(Cv)
530 
531     for the second texgen transform matrix, we can re-use position matrix
532     directly for the first texgen transform. This method allows us to do
533     texgen matrix setting only once at the beginning. This is useful for
534     doing projection on skinned surfaces too.
535  *---------------------------------------------------------------------------*/
SetTexGenPos(MySceneCtrlObj * sc)536 static void SetTexGenPos( MySceneCtrlObj* sc )
537 {
538     Mtx  proj;
539     Mtx  mci, mp, mv;
540 
541     MTXLightFrustum(
542         proj,
543         - (sc->light.cam.cfg.top),
544         sc->light.cam.cfg.top,
545         sc->light.cam.cfg.left,
546         - (sc->light.cam.cfg.left),
547         sc->light.cam.cfg.znear,
548         0.5F,
549         0.5F,
550         0.5F,
551         0.5F );
552 
553     MTXInverse(sc->cam.view, mci);
554     MTXConcat(sc->light.cam.view, mci, mv);
555     MTXConcat(proj, mv, mp);
556 
557     // Load as second texgen transform matrix
558     GXLoadTexMtxImm(mp, GX_PTTEXMTX0, GX_MTX3x4);
559 
560     GXSetNumTexGens(1);
561     GXSetTexCoordGen2(
562         GX_TEXCOORD0,   // Output tex coord id
563         GX_TG_MTX3x4,   // Texgen function type
564         GX_TG_POS,      // Texgen source
565         GX_PNMTX0,      // 1st. transform matrix ( re-use position matrix )
566         GX_FALSE,       // normalization
567         GX_PTTEXMTX0 ); // 2nd. transform matrix
568 }
569 
570 /*---------------------------------------------------------------------------*
571     Name:           SetTexGenNrm
572 
573     Description:    Set up texgen for normal based environment mapping
574                     (by dual-transform)
575 
576     Arguments:      sc : a pointer to MySceneCtrlObj structure
577 
578     Returns:        none
579  *---------------------------------------------------------------------------*/
580 /*---------------------------------------------------------------------------*
581     Dual transform texgen is also useful for environment mapping.
582 
583     Unfortunately we can't access normal transform matrices for texgen directly.
584     So this demo should load the same matrix into (first) texgen matrix space.
585 
586     But still there are some advantages because dual texgen can perform
587     normalization after the first transform. It can allow non-normalized
588     vertex normal sources or non-uniform scale transformations. And it
589     saves additional matrix concatenations that should be done by the CPU.
590  *---------------------------------------------------------------------------*/
SetTexGenNrm(MySceneCtrlObj * sc)591 static void SetTexGenNrm( MySceneCtrlObj* sc )
592 {
593 #pragma unused(sc)
594 
595     Mtx  mt, ms;
596 
597     // Just scaling and bias to adjust sphere map
598     // Third row simply returns 1 for q coordinate
599     MTXScale(ms, 0.50F, 0.50F, 0.0F);
600     MTXTrans(mt, 0.50F, 0.50F, 1.0F);
601     MTXConcat(mt, ms, ms);
602 
603     // Load as second texgen transform matrix
604     GXLoadTexMtxImm(ms, GX_PTTEXMTX1, GX_MTX3x4);
605 
606     GXSetNumTexGens(1);
607     GXSetTexCoordGen2(
608         GX_TEXCOORD0,   // Output tex coord id
609         GX_TG_MTX3x4,   // Texgen function type
610         GX_TG_NRM,      // Texgen source
611         GX_TEXMTX0,     // 1st. transform matrix
612         GX_TRUE,        // normalization
613         GX_PTTEXMTX1 ); // 2nd. transform matrix
614 }
615 
616 /*---------------------------------------------------------------------------*
617     Name:           PrintIntro
618 
619     Description:    Prints the directions on how to use this demo.
620 
621     Arguments:      none
622 
623     Returns:        none
624  *---------------------------------------------------------------------------*/
PrintIntro(void)625 static void PrintIntro( void )
626 {
627     OSReport("\n\n");
628     OSReport("**********************************************\n");
629     OSReport("tg-dual : HW2 dual transform texgen demo\n");
630     OSReport("**********************************************\n");
631     OSReport("to quit hit the menu button\n");
632     OSReport("\n");
633     OSReport("Main stick   : Rotate Models\n");
634     OSReport("Sub stick    : Move Light Location\n");
635     OSReport("L/R Triggers : Control Light Frustum\n");
636     OSReport("A Button     : Change texgen mode\n");
637     OSReport("**********************************************\n");
638 }
639 
640 /*---------------------------------------------------------------------------*/
641 
642 /*============================================================================*/
643