1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin/Revolution gx demo
3   File:     ind-warp.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 #include <demo.h>
15 #include <math.h>
16 #define PI 3.1415926535f
17 
18 /*---------------------------------------------------------------------------*
19   Defines
20  *---------------------------------------------------------------------------*/
21 
22 #define WIDTH_LYR1         64
23 #define HSHIFT_LYR1         6
24 #define HEIGHT_LYR1        64
25 
26 #define ASPECT (10.0f/7.0f)
27 
28 typedef struct
29 {
30     f32 val, min, max, step;
31     char *name;
32 } Param;
33 
34 /*---------------------------------------------------------------------------*
35    Forward references
36  *---------------------------------------------------------------------------*/
37 
38 void        main          ( void );
39 static void ParameterInit ( void );
40 static void TexInit       ( void );
41 static void TexUpdate     ( f32 phase, f32 freq, f32 amp, f32 ang, u8 func );
42 static void DrawInit      ( void );
43 static void DrawTick      ( u8 model );
44 static void AnimTick      ( void );
45 static void PrintIntro    ( void );
46 
47 /*---------------------------------------------------------------------------*
48    Global variables
49  *---------------------------------------------------------------------------*/
50 
51 // Modeling parameters for the object that is drawn
52 
53 Mtx objMtx;
54 f32 scale = 1.5f;
55 f32 xp = 0.0f;
56 f32 yp = 0.0f;
57 f32 zp = -5.0f;
58 
59 // Parameters for the indirect texture creation function
60 
61 f32 phase = 0.0f;
62 
63 #define P_FUNC  0
64 #define P_MODEL 1
65 #define P_FREQ  2
66 #define P_AMPL  3
67 #define P_VANG  4
68 #define P_ROTA  5
69 #define P_LAST  5
70 
71 Param parm[P_LAST+1] = {
72     { 1.0f, 1.0f,  3.0f, 1.0f,  "Function"  },
73     { 1.0f, 1.0f,  4.0f, 1.0f,  "Model" },
74     { 5.0f, 0.1f, 30.0f, 0.05f, "Frequency" },
75     { 0.5f, 0.01f, 1.0f, 0.01f, "Amplitude" },
76     { 0.0f, 0.0f,  0.0f, 2.0f,  "Vector Angle" },
77     { 0.0f, 0.0f,  0.0f, 0.02f, "Rotation (F3)"  }, // for function 3 only
78 };
79 
80 u8  select = 0;
81 
82 // Texture data
83 
84 static TPLPalettePtr tpl = NULL;
85 
86 static GXTexObj imageTexObj;
87 static GXTexObj indTexObj;
88 
89 static u8 tmap1[WIDTH_LYR1 * HEIGHT_LYR1 * 2] ATTRIBUTE_ALIGN(32);
90 
91 /*---------------------------------------------------------------------------*
92    Application main loop
93  *---------------------------------------------------------------------------*/
main(void)94 void main ( void )
95 {
96     DEMOInit(NULL);
97 
98     PrintIntro();       // Print demo directions
99 
100     TexInit();          // Set up textures
101 
102     ParameterInit();    // Set up misc. parameters
103 
104     DEMOPadRead();      // Read the joystick for this frame
105 
106     DrawInit();         // Set up drawing state
107 
108     while(1)
109     {
110         DEMOPadRead();  // Read the joystick for this frame
111 
112         AnimTick();     // Do animation based on input
113 
114         // Update the indirect texture
115         TexUpdate(phase,
116                   parm[P_FREQ].val,
117                   parm[P_AMPL].val,
118                   parm[P_ROTA].val,
119                   (u8) parm[P_FUNC].val);
120 
121         DEMOBeforeRender();
122 
123         DrawTick((u8) parm[P_MODEL].val);     // Draw the model.
124 
125         DEMODoneRender();
126     }
127 
128     OSHalt("End of demo");
129 }
130 
131 /*---------------------------------------------------------------------------*
132    Functions
133  *---------------------------------------------------------------------------*/
134 
135 /*---------------------------------------------------------------------------*
136     Name:           ParameterInit
137 
138     Description:    Initialize parameters for single frame display
139 
140     Arguments:      none
141 
142     Returns:        none
143  *---------------------------------------------------------------------------*/
ParameterInit(void)144 static void ParameterInit( void )
145 {
146     MTXIdentity(objMtx);
147 }
148 
149 /*---------------------------------------------------------------------------*
150     Name:           TexInit
151 
152     Description:    Sets up the texture state.
153 
154     Arguments:      none
155 
156     Returns:        none
157  *---------------------------------------------------------------------------*/
TexInit(void)158 static void TexInit( void )
159 {
160     // Get image texture from tpl
161 
162     TPLGetPalette(&tpl, "gxTests/tex-01.tpl");
163 
164     TPLGetGXTexObjFromPalette(tpl, &imageTexObj, 3);
165     // Override LOD information
166     GXInitTexObjLOD( &imageTexObj,              // texture object
167                      GX_LINEAR, GX_LINEAR,      // min/mag filter
168                      0.0F, 0.0F,                // min/max LOD
169                      0.0F,                      // LOD bias
170                      GX_FALSE,                  // bias clamp
171                      GX_FALSE,                  // do edge LOD
172                      GX_ANISO_1 );              // max anisotropy
173 
174 
175     // Set up indirect texture for bilinear interpolation
176 
177     // Indirect texture data will be created later.
178     // Right now, we only need the pointer to where it will be.
179 
180     GXInitTexObj(&indTexObj,            // texture object
181                  (void*) &tmap1,        // data
182                  WIDTH_LYR1,            // width
183                  HEIGHT_LYR1,           // height
184                  GX_TF_IA8,             // format
185                  GX_REPEAT,             // wrap s
186                  GX_REPEAT,             // wrap t
187                  GX_FALSE);             // mipmap
188 
189     GXInitTexObjLOD( &indTexObj,                // texture object
190                      GX_LINEAR, GX_LINEAR,      // min/mag filter
191                      0.0F, 0.0F,                // min/max LOD
192                      0.0F,                      // LOD bias
193                      GX_FALSE,                  // bias clamp
194                      GX_FALSE,                  // do edge LOD
195                      GX_ANISO_1 );              // max anisotropy
196 }
197 
198 /*---------------------------------------------------------------------------*
199     Name:           TexUpdate
200 
201     Description:    Updates the indirect texture map.
202 
203     Arguments:      phase, frequency, amplitude, rotation, function select
204 
205     Returns:        none
206  *---------------------------------------------------------------------------*/
TexUpdate(f32 phase,f32 freq,f32 amp,f32 rot,u8 func)207 static void TexUpdate( f32 phase, f32 freq, f32 amp, f32 rot, u8 func )
208 {
209     s32 nJ, nI, off;
210     u8  nS, nT;
211     f32 dx, dy, di, id;
212 
213     // Create indirect texture
214 
215     for (nJ=0; nJ<HEIGHT_LYR1; nJ++)
216     {
217         for (nI=0; nI<WIDTH_LYR1; nI++)
218         {
219             // compute the direction vector
220             if (func <= 2)
221             {
222                 dx = ((f32) nI / WIDTH_LYR1) - 0.5f;
223                 dy = ((f32) nJ / HEIGHT_LYR1) - 0.5f;
224             } else {
225                 dx = (f32) nI / WIDTH_LYR1  * cosf(rot);
226                 dy = (f32) nJ / HEIGHT_LYR1 * sinf(rot);
227             }
228 
229             // normalize the vector
230             if (dx != 0.0f || dy != 0.0f)
231             {
232                 di = sqrtf(dx*dx+dy*dy);
233                 id = 1.0f/di;
234                 dx *= id;
235                 dy *= id;
236             } else {
237                 di = id = 0.0f;
238             }
239 
240             // use inverse distance for function 2
241             if (func == 2)
242             {
243                 di = id * 0.1f;
244             }
245 
246             // compute magnitude based upon sin function of distance, phase
247             di = sinf(di * freq + phase);
248 
249             // compute the actual indirect offsets
250             nS = (u8) ((dx * di) * amp * 127.0f + 128.0f);
251             nT = (u8) ((dy * di) * amp * 127.0f + 128.0f);
252 
253             // This offset calculation works for map widths that are
254             // powers of 2
255             off = ((nI & 3) | ((nI >> 2) << 4) | ((nJ & 3) << 2) |
256                    ((nJ >> 2) << (4+(HSHIFT_LYR1-2)))) * 2;
257 
258             tmap1[off+0] = nS;
259             tmap1[off+1] = nT;
260         }
261     }
262 
263     // Important! We must flush the texture data from the CPU cache
264     DCFlushRange((void *) tmap1, WIDTH_LYR1 * HEIGHT_LYR1 * 2);
265 }
266 
267 /*---------------------------------------------------------------------------*
268     Name:           DrawInit
269 
270     Description:    Sets up the graphics state.
271 
272     Arguments:      none
273 
274     Returns:        none
275  *---------------------------------------------------------------------------*/
DrawInit(void)276 static void DrawInit( void )
277 {
278     Mtx   idtMtx;
279     Mtx44 prjMtx;
280 
281     // Misc setup
282     GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
283     GXSetCullMode(GX_CULL_BACK);
284 
285     // Set up textures
286     GXLoadTexObj(&imageTexObj, GX_TEXMAP0);
287     GXLoadTexObj(&indTexObj, GX_TEXMAP1);
288 
289     // Set up texgen
290     GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0);
291 
292     // Set up TEV and such...
293     GXSetNumTevStages(1);
294     GXSetNumIndStages(1);
295 
296     // One texture coordinate, no colors.
297     GXSetNumTexGens(1);
298     GXSetNumChans(0);
299 
300     // Indirect Stage 0 -- Lookup indirect map
301     GXSetIndTexOrder(GX_INDTEXSTAGE0, GX_TEXCOORD0, GX_TEXMAP1);
302 
303     // The image map is four times bigger than the indirect map
304     GXSetIndTexCoordScale(GX_INDTEXSTAGE0, GX_ITS_4, GX_ITS_4);
305 
306     // Stage 0 -- Output texture color
307     //
308     // TEVPREV = TEXC/TEXA
309 
310     GXSetTevIndWarp(GX_TEVSTAGE0,       // tev stage
311                     GX_INDTEXSTAGE0,    // indirect stage
312                     GX_TRUE,            // signed offsets?
313                     GX_FALSE,           // replace mode?
314                     GX_ITM_0);          // ind matrix select
315 
316     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
317     GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
318 
319     GXClearVtxDesc();
320     GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
321     GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
322     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
323     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
324 
325     MTXIdentity(idtMtx);
326     GXLoadPosMtxImm(idtMtx, GX_PNMTX0);
327     GXLoadTexMtxImm(idtMtx, GX_TEXMTX0, GX_MTX2x4);
328 
329     MTXFrustum(prjMtx, 0.25f, -0.25f, -0.25f*ASPECT, 0.25f*ASPECT, 1.0f, 15.0f);
330     GXSetProjection(prjMtx, GX_PERSPECTIVE);
331 }
332 
333 /*---------------------------------------------------------------------------*
334     Name:           DrawTick
335 
336     Description:    Draw the current model once.
337 
338     Arguments:      which model
339 
340     Returns:        none
341  *---------------------------------------------------------------------------*/
DrawTick(u8 model)342 static void DrawTick( u8 model )
343 {
344     Mtx txMtx;
345 
346     MTXIdentity(txMtx);
347 
348     switch(model)
349     {
350       case 1:
351         // Draw one copy of the texture per cube side
352         GXLoadTexMtxImm(txMtx, GX_TEXMTX0, GX_MTX2x4);
353         GXDrawCube();
354         break;
355       case 2:
356         // Draw nine copies of the texture per cube side
357         txMtx[0][0] = 3.0f;
358         txMtx[1][1] = 3.0f;
359         GXLoadTexMtxImm(txMtx, GX_TEXMTX0, GX_MTX2x4);
360         GXDrawCube();
361         break;
362       case 3:
363         // Draw two copies of the texture on a sphere
364         txMtx[0][0] = 2.0f;
365         GXLoadTexMtxImm(txMtx, GX_TEXMTX0, GX_MTX2x4);
366         GXDrawSphere(12, 20);
367         break;
368       case 4:
369         // Draw two copies of the texture on a torus
370         txMtx[1][1] = 2.0f;
371         GXLoadTexMtxImm(txMtx, GX_TEXMTX0, GX_MTX2x4);
372         GXDrawTorus(0.3f, 12, 20);
373         break;
374     }
375 }
376 
377 /*---------------------------------------------------------------------------*
378     Name:           AnimTick
379 
380     Description:    Animate the scene.
381 
382     Arguments:      none
383 
384     Returns:        none
385  *---------------------------------------------------------------------------*/
AnimTick(void)386 static void AnimTick( void )
387 {
388     Mtx tmpMtx;
389     Mtx posMtx;
390     f32 indMtx[2][3];
391     f32 rAng1, rAng2, rAng3;
392     u8  act = 0;
393     u8  show = 0;
394     static u8 first = 1;
395     u16 press = DEMOPadGetButton(0);
396     u16 down = DEMOPadGetButtonDown(0);
397 
398     if (first == 1)
399     {
400         first = 0;
401         show = 1;
402     }
403 
404     if (down & PAD_BUTTON_X)
405     {
406         select = (u8) ((select == P_LAST) ? 0 : select + 1);
407         show = 1;
408     }
409     else if (down & PAD_BUTTON_Y)
410     {
411         select = (u8) ((select == 0) ? P_LAST : select - 1);
412         show = 1;
413     }
414 
415     if (show)
416     {
417         OSReport("%s select\n", parm[select].name);
418     }
419 
420     if (select == P_FUNC || select == P_MODEL)
421     {
422         if (down & PAD_BUTTON_A)
423             act = 1;
424         else if (down & PAD_BUTTON_B)
425             act = 2;
426     } else {
427         if (press & PAD_BUTTON_A)
428             act = 1;
429         else if (press & PAD_BUTTON_B)
430             act = 2;
431     }
432 
433     if (act == 1)
434     {
435         parm[select].val += parm[select].step;
436         if (parm[select].max != 0.0f && parm[select].val > parm[select].max)
437             parm[select].val = parm[select].max;
438     }
439     else if (act == 2)
440     {
441         parm[select].val -= parm[select].step;
442         if (parm[select].min != 0.0f && parm[select].val < parm[select].min)
443             parm[select].val = parm[select].min;
444     }
445 
446     if (act)
447     {
448         OSReport("%s = %f\n", parm[select].name, parm[select].val);
449     }
450 
451     rAng1 = - DEMOPadGetTriggerR(0) / 100.0f
452             + DEMOPadGetTriggerL(0) / 100.0f;
453     rAng2  =  DEMOPadGetStickX(0) / 10.0f;
454     rAng3  = -DEMOPadGetStickY(0) / 10.0f;
455 
456     scale +=  DEMOPadGetSubStickY(0)/1000.0f;
457     if (scale < 0.01f)
458         scale = 0.01f;
459     else if (scale > 100.0f)
460         scale = 100.0f;
461 
462     // Compute rotations...
463     MTXRotDeg(tmpMtx, 'x', rAng3);
464     MTXConcat(tmpMtx, objMtx, objMtx);
465     MTXRotDeg(tmpMtx, 'y', rAng2);
466     MTXConcat(tmpMtx, objMtx, objMtx);
467     MTXRotDeg(tmpMtx, 'z', rAng1);
468     MTXConcat(tmpMtx, objMtx, objMtx);
469 
470     // Compute the rest...
471     MTXTrans(tmpMtx, xp, yp, zp);
472     MTXConcat(tmpMtx, objMtx, posMtx);
473     MTXScale(tmpMtx, scale, scale, scale);
474     MTXConcat(posMtx, tmpMtx, posMtx);
475 
476     GXLoadPosMtxImm(posMtx, GX_PNMTX0);
477 
478     // Set indirect matrix (vector angle)
479 
480     MTXRotDeg(tmpMtx, 'z', parm[P_VANG].val);
481 
482     indMtx[0][0] = tmpMtx[0][0]*0.5f;
483     indMtx[0][1] = tmpMtx[0][1]*0.5f;
484     indMtx[0][2] = 0.0f;
485     indMtx[1][0] = tmpMtx[1][0]*0.5f;
486     indMtx[1][1] = tmpMtx[1][1]*0.5f;
487     indMtx[1][2] = 0.0f;
488 
489     GXSetIndTexMtx(GX_ITM_0, indMtx, 1);
490 
491     // Phase
492 
493     if (!(DEMOPadGetButton(0) & PAD_BUTTON_MENU))
494     {
495         phase += 0.02f;
496     }
497 }
498 
499 /*---------------------------------------------------------------------------*
500     Name:           PrintIntro
501 
502     Description:    Prints the directions on how to use this demo.
503 
504     Arguments:      none
505 
506     Returns:        none
507  *---------------------------------------------------------------------------*/
PrintIntro(void)508 static void PrintIntro( void )
509 {
510     OSReport("\n\n");
511     OSReport("************************************************\n");
512     OSReport("ind-tile-test: tiled texture map using indirect textures\n");
513     OSReport("************************************************\n");
514     OSReport("to quit hit the start button\n");
515     OSReport("main stick   : rotates object X/Y\n");
516     OSReport("sub stick    : scales object\n");
517     OSReport("l/r triggers : rotates object Z\n");
518     OSReport("A/B buttons  : changes paramter value\n");
519     OSReport("X/Y buttons  : selects parameter\n");
520     OSReport("\n");
521     OSReport("************************************************\n\n");
522 }
523