1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin/Revolution gx demo
3   File:     tf-clip-bug.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 
16 // This demo illustrates the color clipping bug.
17 // It also shows the properties of the various Z-buffer modes.
18 //
19 // It draws 2 rectangles in perspective on either side of the screen.
20 // The left rectangle gets darker further away from the viewer, while
21 // the right rectangle gets brighter further away from the viewer.
22 // When the rectangles get near-clipped, the colors can flip around!
23 //
24 // In the middle are shown tags with different Z depths, with a red
25 // tag drawn a certain spacing behind each green tag.
26 // You should normally not be able to see any of the red tags, but
27 // this will change depending upon the Z-buffer mode and the tag spacing.
28 // It also changes greatly depending upon the near-plane distance!
29 //
30 // Of course, the near-plane distance also affects the clipping bug,
31 // so that is why we show the effects on the Z-buffering.
32 //
33 // Please refer to the HTML man page for this demo for more details.
34 
35 /*---------------------------------------------------------------------------*
36   Model Data
37  *---------------------------------------------------------------------------*/
38 
39 // Notes on vertex layout:
40 //
41 // The rectangle below represents the model being drawn.
42 // It is just a rectangle, but it can be tessellated into vertical strips.
43 // Lines 1 and 10 label the quad's corner vertex drawing order.
44 // Lines 3 and 8 label all the vertex positions.
45 //
46 //  1:	    3                       0
47 //  2:	    |  .  :  .  ;  .  :  .  |
48 //  3:	   16 14 12 10  8  6  4  2  0
49 //  4:	    +-----------------------+
50 //  5:	    |                       |
51 //  6:	    |                       |
52 //  7:	    +-----------------------+
53 //  8:	   17 15 13 11  9  7  5  3  1
54 //  9:	    |  .  :  .  ;  .  :  .  |
55 // 10:	    2                       1
56 //
57 // The above is for a single rectangle.  We actually draw 2
58 // rectangles on the right and left sides, so we have twice as
59 // many vertices as that.
60 
61 // indices for verts for drawing order at tessellation = 1, 2, 4, 8
62 
63 static u8 ivert[4][32] =
64 {
65     { 0,  1, 17, 16 },
66     { 0,  1,  9,  8,  8,  9, 17, 16 },
67     { 0,  1,  5,  4,  4,  5,  9,  8,  8,  9, 13, 12, 12, 13, 17, 16 },
68     { 0,  1,  3,  2,  2,  3,  5,  4,  4,  5,  7,  6,  6,  7,  9, 8,
69       8,  9, 11, 10, 10, 11, 13, 12, 12, 13, 15, 14, 14, 15, 17, 16 }
70 };
71 
72 #define IHALF 18
73 
74 // verts
75 
76 static s16 Vert_s16[] ATTRIBUTE_ALIGN(32) =
77 {
78 // left wall:
79    -10,  100,  100,  // 0 0   0         0             0
80    -10, -100,  100,  // 1 1   1         1             1
81    -10,  100,   75,  //                 3 4           2
82    -10, -100,   75,  //                 2 5           3
83    -10,  100,   50,  //       3 4         7 8         4
84    -10, -100,   50,  //       2 5         6 9         5
85    -10,  100,   25,  //                    11 12      6
86    -10, -100,   25,  //                    10 13      7
87    -10,  100,    0,  //   3 4   7 8           15 16   8
88    -10, -100,    0,  //   2 5   6 9           14 17   9
89    -10,  100,  -25,  //                       20 19   10
90    -10, -100,  -25,  //                       21 18   11
91    -10,  100,  -50,  //          11 12     24 23      12
92    -10, -100,  -50,  //          10 13     25 22      13
93    -10,  100,  -75,  //                 28 27         14
94    -10, -100,  -75,  //                 29 26         15
95    -10,  100, -100,  // 3   7       15  31            16
96    -10, -100, -100,  // 2   6       14  30            17
97 // right wall:
98     10,  100,  100,  // 0 0   0         0             18
99     10, -100,  100,  // 1 1   1         1             19
100     10,  100,   75,  //                 3 4           20
101     10, -100,   75,  //                 2 5           21
102     10,  100,   50,  //       3 4         7 8         22
103     10, -100,   50,  //       2 5         6 9         23
104     10,  100,   25,  //                    11 12      24
105     10, -100,   25,  //                    10 13      25
106     10,  100,    0,  //   3 4   7 8           15 16   26
107     10, -100,    0,  //   2 5   6 9           14 17   27
108     10,  100,  -25,  //                       20 19   28
109     10, -100,  -25,  //                       21 18   29
110     10,  100,  -50,  //          11 12     24 23      30
111     10, -100,  -50,  //          10 13     25 22      31
112     10,  100,  -75,  //                 28 27         32
113     10, -100,  -75,  //                 29 26         33
114     10,  100, -100,  // 3   7       15  31            34
115     10, -100, -100,  // 2   6       14  30            35
116 };
117 
118 // colors
119 
120 // Left wall is  brighter closer to the eye,
121 //               darker further from the eye.
122 // Right wall is darker closer to the eye,
123 //               brighter further from the eye.
124 
125 // Due to the clipping bug, they may appear the opposite way around.
126 
127 static u32 Colors_u32[] ATTRIBUTE_ALIGN(32) =
128 {
129 // left wall:
130 //    r g b a
131     0xc0c0c0ff, // 0        0
132     0xa0a0c0ff, // 1        1
133     0xb4b4c0ff, // 1/8 0-3  2
134     0x9c9cc0ff, // 1/8 1-2  3
135     0xa8a8c0ff, // 1/4 0-3  4
136     0x9898c0ff, // 1/4 1-2  5
137     0x9c9cc0ff, // 3/8 0-3  6
138     0x9494c0ff, // 3/8 1-2  7
139     0x9090c0ff, // 1/2 0-3  8
140     0x9090c0ff, // 1/2 1-2  9
141     0x8484c0ff, // 5/8 0-3  10
142     0x8c8cc0ff, // 5/8 1-2  11
143     0x7878c0ff, // 3/4 0-3  12
144     0x8888c0ff, // 3/4 1-2  13
145     0x6c6cc0ff, // 7/8 0-3  14
146     0x8484c0ff, // 7/8 1-2  15
147     0x8080c0ff, // 2        16
148     0x6060c0ff, // 3        17
149 // right wall:
150 //    r g b a
151     0x2020c0ff, // 0        18
152     0x4040c0ff, // 1        19
153     0x2c2cc0ff, // 1/8 0-3  20
154     0x4444c0ff, // 1/8 1-2  21
155     0x3838c0ff, // 1/4 0-3  22
156     0x4848c0ff, // 1/4 1-2  23
157     0x4444c0ff, // 3/8 0-3  24
158     0x4c4cc0ff, // 3/8 1-2  25
159     0x5050c0ff, // 1/2 0-3  26
160     0x5050c0ff, // 1/2 1-2  27
161     0x5c5cc0ff, // 5/8 0-3  28
162     0x5454c0ff, // 5/8 1-2  29
163     0x6868c0ff, // 3/4 0-3  30
164     0x5858c0ff, // 3/4 1-2  31
165     0x7474c0ff, // 7/8 0-3  32
166     0x5c5cc0ff, // 7/8 1-2  33
167     0x6060c0ff, // 2        34
168     0x8080c0ff, // 3        35
169 };
170 
171 /*---------------------------------------------------------------------------*
172    Application main loop
173  *---------------------------------------------------------------------------*/
174 
main(void)175 void main ( void )
176 {
177     u16 button, down;   // button return codes
178 
179     Mtx44   pm;         // projection matrix
180     Mtx     cm;         // camera matrix
181     Mtx     vm;         // view matrix
182     Mtx     sm;         // scale matrix
183     Mtx     ym;         // yet another view matrix
184 
185     s16      i;         // loop variable
186     s16      j;         // loop variable
187     u8    tess = 0;     // tessellation factor
188     u8    mode = 0;     // AA/zbuffer mode
189 
190     Vec   vTmp = {0.0F, 0.0F, 0.0F};     // camera position
191     Vec   at   = {0.0F, 0.0F, -6000.0F}; // look at position
192     Vec   up   = {0.0F, 1.0F, 0.0F};     // camera up vector
193     f32   fovy = 90.0F; // FOV in Y direction
194     f32   near = 5.0f;  // near plane distance
195 
196     char  nums[100];    // number string
197     GXColor green = { 0, 255, 0, 255 };
198     GXColor red   = { 255, 0, 0, 255 };
199     s16   spacing = 5;  // interplanar distance for Z tags
200     s16   xp, yp, zp;   // Z tag position
201     f32   fi;           // fractional i for distance calculation
202 
203     //----------------------------------------------------------------------
204 
205     // We use GXNtsc240Int since that makes it easy to change
206     // between 16-bit (AA) and 24-bit framebuffer modes.
207 
208     DEMOInit(&GXNtsc240Int);    // Init os, pad, gx, vi
209 
210     GXSetCullMode(GX_CULL_NONE);
211 
212     GXSetArray(GX_VA_POS,  Vert_s16, 3*sizeof(s16));
213     GXSetArray(GX_VA_CLR0, Colors_u32, 1*sizeof(u32));
214 
215     GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_POS,  GX_POS_XYZ,  GX_S16,   0);
216     GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
217 
218     DEMOLoadFont( GX_TEXMAP0, GX_TEXMTX0, DMTF_POINTSAMPLE );
219 
220     MTXIdentity(sm);
221 
222     OSReport("\n\n********************************\n");
223     OSReport("Running...\n\n");
224     OSReport("********************************\n");
225     OSReport("This demo shows the properties of the color clipping bug.\n");
226     OSReport("It also shows the properties of the various Z-buffer modes.\n");
227     OSReport("\n");
228     OSReport("It draws 2 rectangles in perspective on either side of the screen.\n");
229     OSReport("The left rectangle gets darker further away from the viewer, while\n");
230     OSReport("the right rectangle gets brighter further away from the viewer.\n");
231     OSReport("When the rectangles get near-clipped, the colors can flip around!\n");
232     OSReport("\n");
233     OSReport("In the middle are shown tags with different Z depths, with a red\n");
234     OSReport("tag drawn a certain spacing behind each green tag.\n");
235     OSReport("You should normally not be able to see any of the red tags, but\n");
236     OSReport("this will change depending upon the Z-buffer mode and the tag spacing.\n");
237     OSReport("It also changes greatly depending upon the near-plane distance!\n");
238     OSReport("\n");
239     OSReport("Of course, the near-plane distance also affects the clipping bug,\n");
240     OSReport("so that is why we show the effects on the Z-buffering.\n");
241     OSReport("\n");
242     OSReport("Please refer to the HTML man page for this demo for more details.\n");
243     OSReport("\n");
244 
245     OSReport("Main stick   - move camera\n");
246     OSReport("Sub stick    - move camera in Z\n");
247     OSReport("L trigger    - hold to adjust FOV with A/B buttons\n");
248     OSReport("R trigger    - hold to adjust tessellation with X/Y buttons\n");
249     OSReport("A/B buttons  - adjust near plane or FOV\n");
250     OSReport("X/Y buttons  - adjust Z tag interplanar dist or tessellation\n");
251     OSReport("Start button - toggle 16/24-bit mode\n");
252     OSReport("********************************\n");
253     while(1)
254     {
255         DEMOPadRead();
256 
257         down   = DEMOPadGetButtonDown(0);
258         button = DEMOPadGetButton(0);
259 
260         vTmp.x -= DEMOPadGetStickX(0) / 100.0f;
261         vTmp.y -= DEMOPadGetStickY(0) / 100.0f;
262         vTmp.z += DEMOPadGetSubStickY(0) / 100.0f;
263 
264         if (button & PAD_TRIGGER_R)
265         {
266             if (down & PAD_BUTTON_X)
267             {
268                 if (tess > 0)
269                     tess--;
270             }
271             if (down & PAD_BUTTON_Y)
272             {
273                 if (tess < 3)
274                     tess++;
275             }
276         } else {
277             if (down & PAD_BUTTON_X)
278             {
279                 spacing += 1;
280                 if (spacing > 10)
281                     spacing = 10;
282             }
283             if (down & PAD_BUTTON_Y)
284             {
285                 spacing  -= 1;
286                 if (spacing < 1)
287                     spacing = 1;
288             }
289         }
290 
291 
292         if (button & PAD_TRIGGER_L)
293         {
294             if (button & PAD_BUTTON_A)
295             {
296                 fovy += 1.0F;
297                 if (fovy > 179.0F)
298                     fovy = 179.0F;
299             }
300             if (button & PAD_BUTTON_B)
301             {
302                 fovy -= 1.0F;
303                 if (fovy < 1.0F)
304                     fovy = 1.0F;
305             }
306         } else {
307             if (button & PAD_BUTTON_A)
308             {
309                 near += 0.1F;
310                 if (near > 10.0F)
311                     near = 10.0F;
312             }
313             if (button & PAD_BUTTON_B)
314             {
315                 near -= 0.1F;
316                 if (near < 0.1F)
317                     near = 0.1F;
318             }
319         }
320 
321         if (down & PAD_BUTTON_MENU)
322         {
323             mode++;
324             if (mode == 5)
325                 mode = 0;
326         }
327 
328 
329         if (mode)
330         {
331             GXSetPixelFmt( GX_PF_RGB565_Z16, (GXZFmt16)(mode - 1) );
332         } else {
333             GXSetPixelFmt( GX_PF_RGB8_Z24, GX_ZC_LINEAR );
334         }
335 
336         DEMOBeforeRender();
337 
338         // Cancel out changes done by DEMOInitCaption (below)
339         GXSetZMode( GX_ENABLE, GX_LEQUAL, GX_TRUE);
340         GXSetNumChans(1);
341 
342         // Set up projection, matrices
343         MTXPerspective(pm, fovy, 4.0F/3.0F, near, 10000);
344         GXSetProjection(pm, GX_PERSPECTIVE);
345 
346         // Set up camera/view matrices
347         MTXLookAt(cm, &vTmp, &up, &at);
348 
349         // If you want any viewing transforms, put them here
350         MTXCopy(cm, vm);
351         GXLoadPosMtxImm(vm, GX_PNMTX0);
352 
353         // Set up for drawing walls
354         GXClearVtxDesc();
355         GXSetVtxDesc(GX_VA_POS,  GX_INDEX8);
356         GXSetVtxDesc(GX_VA_CLR0, GX_INDEX8);
357 
358         // Use vertex colors
359         GXSetChanCtrl(
360             GX_COLOR0A0,
361             GX_DISABLE,
362             GX_SRC_REG,
363             GX_SRC_VTX,
364             GX_LIGHT_NULL,
365             GX_DF_NONE,
366             GX_AF_NONE );
367 
368         GXSetNumTexGens(0);
369         GXSetTevOrder( GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0 );
370         GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
371 
372         // Draw the walls
373         GXBegin(GX_QUADS, GX_VTXFMT1, (u16) ((1<<tess)*4*2));
374         for (i = 0; i < (1<<tess); i++)
375         {
376             for(j=0; j<4; j++)  // left wall
377             {
378                 GXPosition1x8( (u8) ivert[tess][i*4+j]);
379                 GXColor1x8( (u8) ivert[tess][i*4+j]);
380             }
381             for(j=0; j<4; j++)  // right wall
382             {
383                 GXPosition1x8( (u8) (ivert[tess][i*4+j]+IHALF));
384                 GXColor1x8( (u8) (ivert[tess][i*4+j]+IHALF));
385             }
386         }
387         GXEnd();
388 
389         // Set up for drawing signs
390         vm[1][1] = - vm[1][1];
391 
392         // Use register colors
393         GXSetChanCtrl(
394             GX_COLOR0A0,
395             GX_DISABLE,
396             GX_SRC_REG,
397             GX_SRC_REG,
398             GX_LIGHT_NULL,
399             GX_DF_NONE,
400             GX_AF_NONE );
401 
402         GXSetNumTexGens(1);
403         GXSetTevOrder( GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0 );
404         GXSetTevOp(GX_TEVSTAGE0, GX_BLEND);
405 
406         // Draw the signs
407         for (i = 1; i < 60; i++)
408         {
409             sprintf( nums, "%d00", i );
410 
411             xp = (s16) ((i>9) ? -16 : -12);
412             yp = (s16) -8;
413             zp = (s16) (-i * 100);
414 
415             // scale signs larger as they get further away
416             sm[0][0] = i * (5.0F / 12.0F);
417             sm[1][1] = i * (5.0F / 12.0F);
418             MTXConcat(vm, sm, ym);
419             // position signs up and down in vertical FOV
420             ym[1][3] = - i * 100 + i * i * (10.0F / 3.0F);
421             GXLoadPosMtxImm(ym, GX_PNMTX0);
422 
423             // Draw green sign
424             GXSetChanMatColor(GX_COLOR0A0, green);
425             DEMOPuts( xp, yp, zp, nums );
426 
427             // Adjust for red sign
428             zp -= spacing;
429             fi  = i + spacing / 100.0F;
430             ym[1][3] = - fi * 100 + fi * fi * (10.0F / 3.0F);
431             GXLoadPosMtxImm(ym, GX_PNMTX0);
432 
433             // Draw red sign
434             GXSetChanMatColor(GX_COLOR0A0, red);
435             DEMOPuts( xp, yp, zp, nums );
436         }
437 
438         // Draw the control panel
439         DEMOInitCaption(DM_FT_OPQ, 640, 480);
440 
441         sprintf(nums, "camera= [%g, %g, %g]", vTmp.x, vTmp.y, vTmp.z);
442         DEMOPuts( 24, 20, 0, nums );
443         sprintf(nums, "fovy = %g", fovy);
444         DEMOPuts( 24, 28, 0, nums );
445         sprintf(nums, "near = %g", near);
446         DEMOPuts( 24, 36, 0, nums );
447         sprintf(nums, "tess = %d", 1 << tess);
448         DEMOPuts( 24, 44, 0, nums );
449         sprintf(nums, "Z spacing = %d", spacing);
450         DEMOPuts( 24, 52, 0, nums );
451 
452         switch (mode)
453         {
454           case 0: sprintf(nums, "24-bit linear mode"); break;
455           case 1: sprintf(nums, "16-bit linear mode"); break;
456           case 2: sprintf(nums, "16-bit near mode"); break;
457           case 3: sprintf(nums, "16-bit mid mode"); break;
458           case 4: sprintf(nums, "16-bit far mode"); break;
459         }
460 
461         DEMOPuts( 24, 60, 0, nums );
462 
463         DEMODoneRender();
464     }
465     OSHalt("End of demo");
466 }
467 
468 /*===========================================================================*/
469