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