1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin/Revolution gx demo
3   File:     ind-bump-xyz.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 /******************************************************************************
15  *
16  *   (C) 1999, 2000 ARTX INC..  ALL RIGHTS RESERVED.  UNPUBLISHED -- RIGHTS
17  *   RESERVED UNDER THE COPYRIGHT LAWS OF THE UNITED STATES.  USE OF A
18  *   COPYRIGHT NOTICE IS PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION
19  *   OR DISCLOSURE.
20  *
21  *   THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION AND TRADE SECRETS OF
22  *   ARTX INC..  USE, DISCLOSURE, OR REPRODUCTION IS PROHIBITED WITHOUT
23  *   THE PRIOR EXPRESS WRITTEN PERMISSION OF ARTX INC..
24  *
25  *                   RESTRICTED RIGHTS LEGEND
26  *
27  *   Use, duplication, or disclosure by the Government is subject to
28  *   restrictions as set forth in subparagraph (c)(1)(ii) of the Rights
29  *   in Technical Data and Computer Software clause at DFARS 252.227-7013
30  *   or subparagraphs (c)(1) and (2) of Commercial Computer Software --
31  *   Restricted Rights at 48 CFR 52.227-19, as applicable.
32  *
33  *   ArtX Inc.
34  *   3400 Hillview Ave, Bldg 5
35  *   Palo Alto, CA 94304
36  *
37  *****************************************************************************/
38 
39 // Bump mapping test for bumpXYZ method
40 
41 #include <demo.h>
42 #include <math.h>
43 
44 /*---------------------------------------------------------------------------*
45    Defines
46  *---------------------------------------------------------------------------*/
47 
48 #define TPL_NAME "gxTests/dnt-03.tpl"
49 
50 #define CAM_DIST 4                // Camera's distance from origin.
51 #define LIT_X_ANGLE -55.0f        // Rotation around X for light.
52 #define LIT_Y_ANGLE 45.0f         // Rotation around Y for light.
53 
54 #define LIT_TEX_FMT GX_TF_IA8     // 8-bits each for diffuse and specular.
55 
56 #define PI    3.14159265358979323846f
57 
58 #define NRM_SCALE 0.8f
59 
60 /*---------------------------------------------------------------------------*
61    Rendering parameters
62  *---------------------------------------------------------------------------*/
63 
64 u16 W=640, H=448;                 // Display size
65 u16 IW=256, IH=384;               // Indirect (bump) map size.
66 f32 IS=2.0f/3.0f;                 // Scale parameter for displaying indirect maps
67 u16 TW=64, TH=64;                 // Light map size.
68 u16 TT=32, ST=32;                 // Light map tessellation
69 
70 typedef struct
71 {
72     f32 x, y, z;
73     f32 nx, ny, nz;
74     f32 s, t;
75     u16 tc, pad;
76 } coord;
77 
78 u32 face[9] = { // For each of the 9 cubes, which sides to draw
79     //FRBLUD  Front Right Back Left Up Down sides of cube
80     0x2E, //  101110
81     0x2B, //  101011
82     0x3A, //  111010
83     0x3C, //  111100
84     0x00, //  000000
85     0x3C, //  111100
86     0x2D, //  101101
87     0x2B, //  101011
88     0x39, //  111001
89 };
90 
91 f32 tcoords[12][2] ATTRIBUTE_ALIGN(32) = { // texture coordinate array
92     { 0.0f, 0.0f  }, //  0
93     { 0.5f, 0.0f  }, //  1
94     { 1.0f, 0.0f  }, //  2
95     { 0.0f, 0.25f }, //  3
96     { 0.5f, 0.25f }, //  4
97     { 1.0f, 0.25f }, //  5
98     { 0.0f, 0.50f }, //  6
99     { 0.5f, 0.50f }, //  7
100     { 1.0f, 0.50f }, //  8
101     { 0.0f, 0.75f }, //  9
102     { 0.5f, 0.75f }, // 10
103     { 1.0f, 0.75f }  // 11
104 };
105 
106 coord cube[6][4] ATTRIBUTE_ALIGN(32);
107 
108 void * lightMap;
109 GXTexObj lightMapObj, materialObj, nPtrbObj;
110 
111 Mtx cameraMtx, objectMtx, lightMtx;
112 
113 TPLPalettePtr tpl = NULL;
114 
115 u32 sendNormal, sendIndex, sendCoords;
116 
117 /*---------------------------------------------------------------------------*
118    Forward references
119  *---------------------------------------------------------------------------*/
120 
121 void createCube();
122 void sendVertex(coord *d);
123 void setupMatrices(void);
124 void setupSize(u16 w, u16 h);
125 void commonInit(void);
126 void updateMatrices(u32 id, Mtx obj, Mtx cam);
127 void setLight(GXLightID litID, GXChannelID diffID, GXChannelID specID,
128               Mtx obj, Mtx cam);
129 void bumpMapSetup();
130 void bumpMapSetdown();
131 void lightMapSetup();
132 void renderSetup1();
133 void renderSetup2();
134 void updateDonut(Mtx cam, f32 r1, f32 r2, f32 x, f32 y, f32 z);
135 void drawDonut();
136 void drawHemisphere();
137 void showMaps();
138 void drawScene(Mtx cam, f32 r1, f32 r2);
139 void main(void);
140 static void PrintIntro( void );
141 
142 /*---------------------------------------------------------------------------*
143    Procedures
144  *---------------------------------------------------------------------------*/
145 
146 // Create cube
createCube()147 void createCube()
148 {
149     int i;
150     f32 h, v;
151 
152     for(i=0; i<4; i++)
153     {
154         h = ((i % 3)!=0) - 0.5f;
155         v = - (i / 2) + 0.5f;
156 
157         cube[0][i].x =  h;
158         cube[0][i].y =  v;
159         cube[0][i].z =  0.5f;
160         cube[1][i].x =  0.5f;
161         cube[1][i].y =  v;
162         cube[1][i].z = -h;
163         cube[2][i].x = -h;
164         cube[2][i].y =  v;
165         cube[2][i].z = -0.5f;
166         cube[3][i].x = -0.5f;
167         cube[3][i].y =  v;
168         cube[3][i].z =  h;
169         cube[4][i].x =  h;
170         cube[4][i].y =  0.5f;
171         cube[4][i].z = -v;
172         cube[5][i].x =  h;
173         cube[5][i].y = -0.5f;
174         cube[5][i].z =  v;
175 
176         cube[0][i].nx =  0;
177         cube[0][i].ny =  0;
178         cube[0][i].nz =  1;
179         cube[1][i].nx =  1;
180         cube[1][i].ny =  0;
181         cube[1][i].nz =  0;
182         cube[2][i].nx =  0;
183         cube[2][i].ny =  0;
184         cube[2][i].nz = -1;
185         cube[3][i].nx = -1;
186         cube[3][i].ny =  0;
187         cube[3][i].nz =  0;
188         cube[4][i].nx =  0;
189         cube[4][i].ny =  1;
190         cube[4][i].nz =  0;
191         cube[5][i].nx =  0;
192         cube[5][i].ny = -1;
193         cube[5][i].nz =  0;
194     }
195 
196     cube[0][0].tc = 0;
197     cube[0][1].tc = 1;
198     cube[0][2].tc = 4;
199     cube[0][3].tc = 3;
200 
201     cube[1][0].tc = 1;
202     cube[1][1].tc = 2;
203     cube[1][2].tc = 5;
204     cube[1][3].tc = 4;
205 
206     cube[2][0].tc = 3;
207     cube[2][1].tc = 4;
208     cube[2][2].tc = 7;
209     cube[2][3].tc = 6;
210 
211     cube[3][0].tc = 4;
212     cube[3][1].tc = 5;
213     cube[3][2].tc = 8;
214     cube[3][3].tc = 7;
215 
216     cube[4][0].tc = 6;
217     cube[4][1].tc = 7;
218     cube[4][2].tc = 10;
219     cube[4][3].tc = 9;
220 
221     cube[5][0].tc = 7;
222     cube[5][1].tc = 8;
223     cube[5][2].tc = 11;
224     cube[5][3].tc = 10;
225 }
226 
227 // Send one vertex from the given coordinate structure.
sendVertex(coord * d)228 void sendVertex(coord *d)
229 {
230     GXPosition3f32(d->x, d->y, d->z);
231 
232     if (sendNormal)
233         GXNormal3f32(d->nx, d->ny, d->nz);
234 
235     if (sendIndex)
236         GXTexCoord1x16(d->tc);
237 
238     if (sendCoords)
239         GXTexCoord2f32(d->s, d->t);
240 }
241 
242 // Set up static matrices
setupMatrices(void)243 void setupMatrices(void)
244 {
245     Mtx tempMtx;
246 
247     MTXTrans(cameraMtx, 0, 0, -CAM_DIST);
248 
249     MTXTrans(lightMtx, 0, 0, -1000); // Make light "infinite"
250     MTXRotDeg(tempMtx, 'y', -(LIT_Y_ANGLE));
251     MTXConcat(lightMtx, tempMtx, lightMtx);
252     MTXRotDeg(tempMtx, 'x', -(LIT_X_ANGLE));
253     MTXConcat(lightMtx, tempMtx, lightMtx);
254 
255     MTXIdentity(objectMtx);
256 }
257 
258 // Setup viewport, scissor, copy, etc. based on w/h.
setupSize(u16 w,u16 h)259 void setupSize(u16 w, u16 h)
260 {
261     GXSetViewport(0, 0, w, h, 0, 1);
262     GXSetScissor(0, 0, w, h);
263     GXSetDispCopySrc(0, 0, w, h);
264     GXSetDispCopyDst(w, h);
265     GXSetDispCopyYScale(1);
266     GXSetTexCopySrc(0, 0, w, h);
267     GXSetTexCopyDst(w, h, LIT_TEX_FMT, FALSE);
268 }
269 
270 // Initialization routine common to all my tests.
commonInit(void)271 void commonInit(void)
272 {
273     GXColor black = {0, 0, 0, 0};
274 
275     DEMOInit(NULL);
276     GXInvalidateTexAll();
277     GXSetCopyClear( black, GX_MAX_Z24 );
278 
279     GXSetZMode(TRUE, GX_LEQUAL, TRUE);
280     GXSetZCompLoc(TRUE);
281     GXSetCullMode(GX_CULL_BACK);
282 
283     GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA);
284     GXSetTevSwapModeTable(GX_TEV_SWAP1, GX_CH_RED, GX_CH_RED, GX_CH_RED, GX_CH_ALPHA);
285     GXSetTevSwapModeTable(GX_TEV_SWAP2, GX_CH_GREEN, GX_CH_GREEN, GX_CH_GREEN, GX_CH_ALPHA);
286     GXSetTevSwapModeTable(GX_TEV_SWAP3, GX_CH_BLUE, GX_CH_BLUE, GX_CH_BLUE, GX_CH_ALPHA);
287 
288     setupMatrices();
289 }
290 
291 // Set up position/normal/texture matrices and load.
updateMatrices(u32 id,Mtx obj,Mtx cam)292 void updateMatrices(u32 id, Mtx obj, Mtx cam)
293 {
294     Mtx vertexMtx, normalMtx, bumpnormalMtx;
295     Mtx normalTexMtx, textureMtx, tempMtx;
296     f32 indMtx[2][3];
297 
298     // matrix for transforming vertices from object space to eye space.
299     MTXConcat(cam, obj, vertexMtx);
300 
301     // the normal mtx starts out as the inverse transpose of the vertex mtx
302     if (!MTXInverse(vertexMtx, tempMtx)) {ASSERTMSG(0,"Singular matrix!\n");}
303     MTXTranspose(tempMtx, normalMtx);
304 
305     // matrix for transforming normals from object space to eye space,
306     // scale by NRM_SCALE/2, offset by 0.5,0.5.
307     // the negation in Y is needed since the T axis is opposite of the Y axis
308     MTXScale(tempMtx, NRM_SCALE/2, -NRM_SCALE/2, NRM_SCALE/2);
309     MTXConcat(tempMtx, normalMtx, normalTexMtx);
310     MTXTrans(tempMtx, 0.5f, 0.5f, 0.0f);
311     MTXConcat(tempMtx, normalTexMtx, normalTexMtx);
312 
313     // matrix for transforming bump offsets
314     // take normal mtx, then scale by NRM_SCALE/2
315     // the negation in [1][1] is needed since the T axis is opposite of the Y axis
316     MTXScale(tempMtx, NRM_SCALE/2, NRM_SCALE/2, NRM_SCALE/2);
317     MTXConcat(tempMtx, normalMtx, bumpnormalMtx);
318     indMtx[0][0] =  bumpnormalMtx[0][0];
319     indMtx[0][1] =  bumpnormalMtx[0][1];
320     indMtx[0][2] =  bumpnormalMtx[0][2];
321     indMtx[1][0] =  bumpnormalMtx[1][0];
322     indMtx[1][1] = -bumpnormalMtx[1][1];
323     indMtx[1][2] =  bumpnormalMtx[1][2];
324     // set indirect matrix and scale
325     GXSetIndTexMtx(GX_ITM_0, indMtx, 0);
326 
327     // matrix for specifying material repetitions
328     MTXScale(textureMtx, 1.0f, 1.0f, 1.0f); // no repetitions for this demo
329 
330     GXLoadPosMtxImm(vertexMtx, GX_PNMTX0 + id*3);
331     GXLoadNrmMtxImm(normalMtx, GX_PNMTX0 + id*3);
332     GXLoadTexMtxImm(textureMtx, GX_TEXMTX0, GX_MTX2x4);
333     GXLoadTexMtxImm(normalTexMtx, GX_TEXMTX1 + id*6, GX_MTX2x4);
334 }
335 
336 // Create an infinite light with diffuse and specular components.
setLight(GXLightID litID,GXChannelID diffID,GXChannelID specID,Mtx obj,Mtx cam)337 void setLight(GXLightID litID, GXChannelID diffID, GXChannelID specID,
338               Mtx obj, Mtx cam)
339 {
340     GXLightObj light;
341     Mtx   tempMtx, litMtx;
342     Vec   lPos = {0,0,0}, lDir = {0,0,-1};
343     GXColor color0 = {0x88,0x88,0x88,0xff};
344     GXColor color1 = {0x20,0x20,0x20,0x20};
345     GXColor color2 = {0xff,0xff,0xff,0xff};
346     GXColor color3 = {0x00,0x00,0x00,0x00};
347     GXColor color4 = {0x7f,0x7f,0x7f,0x7f};
348 
349     // Calculate light position and direction.
350     if (!MTXInverse(obj, tempMtx)) {ASSERTMSG(0,"Singular matrix!\n");}
351     MTXConcat(cam, tempMtx, litMtx);
352     MTXMultVec(litMtx, &lPos, &lPos);
353 
354     if (!MTXInverse(litMtx, tempMtx)) {ASSERTMSG(0,"Singular matrix!\n");}
355     MTXTranspose(tempMtx, litMtx);
356     MTXMultVec(litMtx, &lDir, &lDir);
357 
358     // Setup light object.
359     // GXInitLightPos(&light, lPos.x, lPos.y, lPos.z);
360     GXInitSpecularDir(&light, lDir.x, lDir.y, lDir.z);
361     GXInitLightColor(&light, color0 );
362 
363     // Light equation 4x^2 - 3. x=N*H.
364     GXInitLightAttn(&light, -3.0f, 0.0f, 4.0f, 1.0f, 0.0f, 0.0f);
365     GXLoadLightObjImm(&light, litID);
366 
367     // Set material and ambient color.
368     GXSetChanAmbColor(diffID, color1 );
369     GXSetChanMatColor(diffID, color2 );
370     GXSetChanAmbColor(specID, color3 );
371     GXSetChanMatColor(specID, color4 );
372 }
373 
374 // Initial setup for shadowing (setup texture).
bumpMapSetup(void)375 void bumpMapSetup(void)
376 {
377     // Pre-existing textures are in a tpl file.
378     TPLGetPalette(&tpl, TPL_NAME);
379 
380     // Light Map Texture (generated)
381 
382     // Allocate texture in main memory.
383     lightMap = MEMAllocFromAllocator(&DemoAllocator1, GXGetTexBufferSize(TW, TH, LIT_TEX_FMT, FALSE, 0));
384 
385     // Create texture object.
386     GXInitTexObj(&lightMapObj, lightMap, TW, TH, LIT_TEX_FMT,
387                  GX_CLAMP, GX_CLAMP, FALSE);
388 
389     // Load object into hw. Lightmap will be TEXMAP1.
390     GXLoadTexObj(&lightMapObj, GX_TEXMAP1);
391 
392     // Material Texture (pre-existing)
393     //
394     TPLGetGXTexObjFromPalette(tpl, &materialObj, 1);
395     GXLoadTexObj(&materialObj, GX_TEXMAP0); // Material will be TEXMAP0
396 
397     // Normal Perturbation Texture (pre-existing)
398     //
399     TPLGetGXTexObjFromPalette(tpl, &nPtrbObj, 0);
400 
401     // To make the texture coordinates work out as nice fractions of 2,
402     // we pretend the texture is 256x512 instead of 256x384.  We are careful
403     // never to specify a T coordinate larger than 0.75.
404     {
405         void *data = GXGetTexObjData(&nPtrbObj);
406         GXInitTexObj(&nPtrbObj, data, 256, 512, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE);
407     }
408     GXLoadTexObj(&nPtrbObj, GX_TEXMAP2); // Normal perturbation will be TEXMAP2
409 
410     // Set up texgen for rendering. The matrices can be changed per-object,
411     // but the texgen needn't change.
412     GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0);
413     GXSetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_NRM, GX_TEXMTX1);
414 
415     // I will always use position matrix 0 for my geometry.
416     GXSetCurrentMtx(GX_PNMTX0);
417 
418     // Diffuse is color 0, specular is alpha 0.
419     setLight(GX_LIGHT0, GX_COLOR0, GX_ALPHA0, lightMtx, cameraMtx);
420 
421     // Alpha component in frame buffer will be written to.
422     GXSetAlphaUpdate(TRUE);
423 
424     // Make a cube.
425     createCube();
426 }
427 
bumpMapSetdown(void)428 void bumpMapSetdown(void)
429 {
430     TPLReleasePalette(&tpl);
431 
432     MEMFreeToAllocator(&DemoAllocator1, lightMap);
433 }
434 
435 // Per-frame setup for actual render.
renderSetup1(void)436 void renderSetup1(void)
437 {
438     Mtx44 pMtx;
439 
440     // Set the rendering size.
441     setupSize(W, H);
442 
443     // Perspective projection
444     // Note that in this demo, POSITIVE Y is up!
445     MTXFrustum(pMtx, 1, -1, -1, 1, 1, 15);
446     GXSetProjection(pMtx, GX_PERSPECTIVE);
447 
448     // Pixel format
449     GXSetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
450     // We don't need to clear the display again
451 
452     // Disable lights
453     GXSetChanCtrl(GX_COLOR0, FALSE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT0,
454                   GX_DF_NONE, GX_AF_NONE);
455     GXSetChanCtrl(GX_ALPHA0, FALSE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT0,
456                   GX_DF_NONE, GX_AF_NONE);
457 }
458 
renderSetup2(void)459 void renderSetup2(void)
460 {
461     // Two tev stages, one Bump stage.
462     GXSetNumTevStages(2);
463 
464     GXSetNumIndStages(1);
465 
466     // Two texture coordinates, no colors.
467     GXSetNumTexGens(2);
468     GXSetNumChans(0);
469 
470     // Indirect Stage 0 -- Sample normal perturbation map
471     GXSetIndTexOrder(GX_INDTEXSTAGE0, GX_TEXCOORD0, GX_TEXMAP2);
472     GXSetIndTexCoordScale(GX_INDTEXSTAGE0, GX_ITS_1, GX_ITS_1);
473 
474     // Stage 0 -- Save material texture
475     //
476     // TEVPREV = TEXC/TEXA
477     //
478     GXSetTevDirect(GX_TEVSTAGE0);
479     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
480     GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0); // RGBA
481     GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
482 
483     // Set up the indirect bump calculation for Stage 1
484     //
485     GXSetTevIndBumpXYZ(GX_TEVSTAGE1, GX_INDTEXSTAGE0, GX_ITM_0);
486 
487     // Stage 1 -- Add source normal in Bump. Index lightmap with result of
488     //            perturbation. Apply diffuse and specular components.
489     //
490     // TEVPREVC = PREVC * TEXC + TEXA
491     // TEVPREVA = PREVA
492     //
493     GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD1, GX_TEXMAP1, GX_COLOR_NULL);
494     GXSetTevColorIn(GX_TEVSTAGE1,
495                     GX_CC_ZERO, GX_CC_CPREV, GX_CC_TEXC, GX_CC_TEXA);
496     GXSetTevAlphaIn(GX_TEVSTAGE1,
497                     GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_APREV);
498     GXSetTevColorOp(GX_TEVSTAGE1,
499                     GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, TRUE, GX_TEVPREV);
500     GXSetTevAlphaOp(GX_TEVSTAGE1,
501                     GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, TRUE, GX_TEVPREV);
502 
503 
504     // Vertex packet specification -- Position, normal,
505     //                                and one pair of texture coordinates.
506     GXClearVtxDesc();
507     GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
508     GXSetVtxDesc(GX_VA_NRM, GX_DIRECT);
509     GXSetVtxDesc(GX_VA_TEX0, GX_INDEX16);
510     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
511     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
512     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
513 
514     GXSetArray(GX_VA_TEX0, (void *) tcoords, 2*sizeof(f32));
515 
516     sendNormal = TRUE;
517     sendIndex  = TRUE;
518     sendCoords = FALSE;
519 }
520 
521 // Per-frame setup for light map.
lightMapSetup(void)522 void lightMapSetup(void)
523 {
524     Mtx44 pMtx;
525     Mtx   idMtx;
526 
527     // Set the rendering size.
528     setupSize(TW, TH);
529 
530     // Orthographic projection
531     MTXOrtho(pMtx, 1, -1, -1, 1, 1, 15);
532     GXSetProjection(pMtx, GX_ORTHOGRAPHIC);
533 
534     // Pixel format
535     GXSetPixelFmt(GX_PF_RGBA6_Z24, GX_ZC_LINEAR);
536     // don't need to re-clear, since we will overwrite everything we use
537 
538     // Enable diffuse and specular lights.
539     // COLOR0 = diffuse
540     // ALPHA0 = specular
541     GXSetChanCtrl(GX_COLOR0, TRUE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT0,
542                   GX_DF_CLAMP, GX_AF_NONE);
543     GXSetChanCtrl(GX_ALPHA0, TRUE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT0,
544                   GX_DF_NONE, GX_AF_SPEC);
545 
546     // One tev stage.
547     GXSetNumTevStages(1);
548 
549     // No textures, one color.
550     GXSetNumTexGens(0);
551     GXSetNumChans(1);
552     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
553 
554     // Stage 0 -- Send out rasterized color.
555     //
556     // TEVPREV = RAS
557     //
558     GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
559 
560     // Vertex packet specification -- Position and normal.
561     GXClearVtxDesc();
562     GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
563     GXSetVtxDesc(GX_VA_NRM, GX_DIRECT);
564     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
565     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0);
566 
567     sendNormal = TRUE;
568     sendIndex  = FALSE;
569     sendCoords = FALSE;
570 
571     // Identity matrices for object and matrix.
572     MTXIdentity(idMtx);
573     updateMatrices(0, idMtx, idMtx);
574 }
575 
576 // Prepare for donut drawing.
updateDonut(Mtx cam,f32 r1,f32 r2,f32 x,f32 y,f32 z)577 void updateDonut(Mtx cam, f32 r1, f32 r2, f32 x, f32 y, f32 z)
578 {
579     Mtx donutMtx, tempMtx;
580 
581     // update object matrix for this donut.
582     MTXRotDeg(tempMtx, 'x', -r2);
583     MTXConcat(tempMtx, objectMtx, objectMtx);
584     MTXRotDeg(tempMtx, 'y', r1);
585     MTXConcat(tempMtx, objectMtx, objectMtx);
586     MTXTrans(tempMtx, x, y, z);
587     MTXConcat(tempMtx, objectMtx, donutMtx);
588 
589     // Create all other matrices derived from this object matrix.
590     updateMatrices(0, donutMtx, cam);
591 }
592 
593 // Draw a donut.
drawDonut()594 void drawDonut()
595 {
596     int c, f, v;
597     f32 x, y;
598 
599     GXBegin(GX_QUADS, GX_VTXFMT0, (6-2)*4*8 ); // each cube is missing 2 faces; 8 cubes
600 
601     for(c=0; c<9; c++) // for each cube
602     {
603         if (c==4) continue; // middle cube not drawn
604 
605         x = (c % 3) - 1; // compute cube offset
606         y = 1 - (c / 3);
607 
608         for(f=0; f<6; f++) // for each face
609         {
610             if (!(face[c] & ((1<<5)>>f))) continue;
611 
612             for(v=0; v<4; v++) // for each vertex
613             {
614                 cube[f][v].x += x; // offset vertex
615                 cube[f][v].y += y;
616 
617                 sendVertex(&cube[f][v]); // draw it
618 
619                 cube[f][v].x -= x; // put it back
620                 cube[f][v].y -= y;
621             }
622         }
623     }
624 
625     GXEnd();
626 }
627 
628 // Draw a tesselated square, with normals that make it look like a hemisphere.
drawHemisphere()629 void drawHemisphere()
630 {
631     u32 i, j;
632     coord c;
633 
634     for (i=0; i<ST; i++)
635     {
636         GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT0, (u16) (TT*2 + 2));
637 
638         for (j=0; j<=TT; j++)
639         {
640             c.x = ((f32) 2.0f*(i+1)/ST) - 1.0f;
641             c.y = ((f32) 2.0f*j/TT) - 1.0f;
642             c.z = -2.0f;
643             c.nx = c.x / NRM_SCALE;
644             c.ny = c.y / NRM_SCALE;
645             c.nz = c.x*c.x + c.y*c.y;
646             c.nz = c.nz < 1 ? sqrtf(1 - c.nz) : 0;
647             sendVertex(&c);
648 
649             c.x = ((f32) 2.0f*(i+0)/ST) - 1.0f;
650             c.nx = c.x / NRM_SCALE;
651             c.nz = c.x*c.x + c.y*c.y;
652             c.nz = c.nz < 1 ? sqrtf(1 - c.nz) : 0;
653             sendVertex(&c);
654         }
655 
656         GXEnd();
657     }
658 }
659 
660 // Draw the full scene from a specific camera.
drawScene(Mtx cam,f32 rot1,f32 rot2)661 void drawScene(Mtx cam, f32 rot1, f32 rot2)
662 {
663     // Draw one donut, centered at 0,0,0, rotating at normal speed.
664     updateDonut(cam, rot1, rot2, 0.0f, 0.0f, 0.0f);
665     drawDonut();
666 }
667 
668 //  Show the generated light maps in the corner of the screen
showMaps()669 void showMaps()
670 {
671     Mtx   idMtx;
672     coord c;
673 
674     // GXSetCullMode(GX_CULL_NONE); // sanity check
675 
676     // One tev stage.
677     GXSetNumTevStages(1);
678     GXSetNumIndStages(0);
679 
680     // One texture, no color.
681     GXSetNumTexGens(1);
682     GXSetNumChans(0);
683     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP1, GX_COLOR_NULL);
684 
685     // Stage 0 -- Send out texture color.
686     //
687     // TEVPREV = TEXC
688     //
689     GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
690     GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0); // RGBA
691     GXSetTevAlphaIn(GX_TEVSTAGE0,GX_CA_ZERO,GX_CA_ZERO,GX_CA_ZERO,GX_CA_ONE);
692 
693     // Vertex packet specification -- Position and normal.
694     GXClearVtxDesc();
695     GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
696     GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
697     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
698     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
699 
700     sendNormal = FALSE;
701     sendIndex  = FALSE;
702     sendCoords = TRUE;
703 
704     // Identity matrices for object and matrix.
705     MTXIdentity(idMtx);
706     GXLoadPosMtxImm(idMtx, GX_PNMTX0);
707     GXLoadTexMtxImm(idMtx, GX_TEXMTX0, GX_MTX2x4);
708 
709     GXBegin(GX_QUADS, GX_VTXFMT0, 4);
710     c.x = -1.0f;
711     c.y =  1.0f;
712     c.z = -1.0f;
713     c.s =  0.0f;
714     c.t =  0.0f;
715     sendVertex(&c);
716     c.x += (f32) TW/W*2;
717     c.s  = 1.0f;
718     sendVertex(&c);
719     c.y -= (f32) TH/H*2;
720     c.t  = 1.0f;
721     sendVertex(&c);
722     c.x -= (f32) TW/W*2;
723     c.s  = 0.0f;
724     sendVertex(&c);
725     GXEnd();
726 
727     // Now show alpha (specular) map
728     GXSetTevColorIn(GX_TEVSTAGE0,GX_CC_ZERO,GX_CC_ZERO,GX_CC_ZERO,GX_CC_TEXA);
729 
730     GXBegin(GX_QUADS, GX_VTXFMT0, 4);
731     c.x = -1.0f;
732     c.y = -1.0f;
733     c.z = -1.0f;
734     c.s =  0.0f;
735     c.t =  1.0f;
736     sendVertex(&c);
737     c.y += (f32) TH/H*2;
738     c.t  = 0.0f;
739     sendVertex(&c);
740     c.x += (f32) TW/W*2;
741     c.s  = 1.0f;
742     sendVertex(&c);
743     c.y -= (f32) TH/H*2;
744     c.t  = 1.0f;
745     sendVertex(&c);
746     GXEnd();
747 
748     // Now show the X component of the bump map
749     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP2, GX_COLOR_NULL);
750     GXSetTevColorIn(GX_TEVSTAGE0,GX_CC_ZERO,GX_CC_ZERO,GX_CC_ZERO,GX_CC_TEXA);
751 
752     GXBegin(GX_QUADS, GX_VTXFMT0, 4);
753     c.x =  1.0f;
754     c.y =  1.0f;
755     c.z = -1.0f;
756     c.s =  1.0f;
757     c.t =  0.0f;
758     sendVertex(&c);
759     c.y -= (f32) IH/H*IS;
760     c.t  = 0.75f;
761     sendVertex(&c);
762     c.x -= (f32) IW/W*IS;
763     c.s  = 0.0f;
764     sendVertex(&c);
765     c.y += (f32) IH/H*IS;
766     c.t  = 0.0f;
767     sendVertex(&c);
768     GXEnd();
769 
770     // Now show the Y component of the bump map
771     GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP3); // BBB
772     GXSetTevColorIn(GX_TEVSTAGE0,GX_CC_ZERO,GX_CC_ZERO,GX_CC_ZERO,GX_CC_TEXC);
773 
774     GXBegin(GX_QUADS, GX_VTXFMT0, 4);
775     c.y -= (f32) IH/H*IS + (64.0f/H);
776     sendVertex(&c);
777     c.x += (f32) IW/W*IS;
778     c.s  = 1.0f;
779     sendVertex(&c);
780     c.y -= (f32) IH/H*IS;
781     c.t  = 0.75f;
782     sendVertex(&c);
783     c.x -= (f32) IW/W*IS;
784     c.s  = 0.0f;
785     sendVertex(&c);
786     GXEnd();
787 
788     // Now show the Z component of the bump map
789     GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP2); // GGG
790     GXSetTevColorIn(GX_TEVSTAGE0,GX_CC_ZERO,GX_CC_ZERO,GX_CC_ZERO,GX_CC_TEXC);
791 
792     GXBegin(GX_QUADS, GX_VTXFMT0, 4);
793     c.y -= (f32) 64.0f/H;
794     c.t  = 0.0f;
795     sendVertex(&c);
796     c.x += (f32) IW/W*IS;
797     c.s  = 1.0f;
798     sendVertex(&c);
799     c.y -= (f32) IH/H*IS;
800     c.t  = 0.75f;
801     sendVertex(&c);
802     c.x -= (f32) IW/W*IS;
803     c.s  = 0.0f;
804     sendVertex(&c);
805     GXEnd();
806 }
807 
808 /*---------------------------------------------------------------------------*
809    Application main loop
810  *---------------------------------------------------------------------------*/
811 
main(void)812 void main(void)
813 {
814     f32 rot1=0.0f;
815     f32 rot2=0.0f;
816 
817     commonInit();  // Same init for all tests.
818 
819     bumpMapSetup(); // Setup texture objects and all other static things.
820 
821     // This is only done once in this test since the camera and light never
822     // change direction with respect to one another. If they ever do, the
823     // lightmap must be regenerated.
824     lightMapSetup();  // Setup for lightmap render.
825     drawHemisphere(); // Render hemisphere lightmap
826 
827     GXCopyTex(lightMap, FALSE); // Copy to texture.
828     GXPixModeSync();
829 
830     PrintIntro();
831 
832     while(!(DEMOPadGetButton(0) & PAD_BUTTON_MENU))
833     {
834         DEMOPadRead();
835 
836         rot1 = DEMOPadGetStickX(0)/10;
837         rot2 = DEMOPadGetStickY(0)/10;
838         DEMOBeforeRender();
839 
840         renderSetup1();   // Setup for actual render, part 1.
841 
842         showMaps();       // Show the lightmaps used
843 
844         renderSetup2();   // Setup for actual render, part 2.
845 
846         drawScene(cameraMtx, rot1, rot2);
847 
848         DEMODoneRender();
849     }
850 
851     bumpMapSetdown(); // Free memory and such.
852 
853     OSHalt("End of demo");
854 }
855 
856 /*---------------------------------------------------------------------------*
857     Name:           PrintIntro
858 
859     Description:    Prints the directions on how to use this demo.
860 
861     Arguments:      none
862 
863     Returns:        none
864  *---------------------------------------------------------------------------*/
PrintIntro(void)865 static void PrintIntro( void )
866 {
867     OSReport("\n\n");
868     OSReport("************************************************\n");
869     OSReport("ind-bump-xyz: demonstrate bumpXYZ method\n");
870     OSReport("************************************************\n");
871     OSReport("to quit hit the start button\n");
872     OSReport("\n");
873     OSReport("  Stick X/Y    : rotate model\n");
874     OSReport("************************************************\n\n");
875 }
876 
877