1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin/Revolution gx demo
3   File:     frb-aa-full.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 
17 
18 #define OCT_DEPTH_MIN  1 // min octahedron recursion depth
19 #define OCT_DEPTH_MAX  6 // max octahedron recursion depth
20 
21 // The viewing frustum parameters
22 #define PROJ_RIGHT   0.050F
23 #define PROJ_TOP     0.0375F
24 #define PROJ_ZNEAR   0.1F
25 #define PROJ_ZFAR    10.0F
26 
27 // Octahedron vertices
28 static f32 vertNorth[] = { 0.0f, 0.0f, 1.0f };
29 static f32 vertSouth[] = { 0.0f, 0.0f, -1.0f };
30 static f32 vertEquator[] =
31 {
32     1.0f, 0.0f, 0.0f,
33     0.0f, 1.0f, 0.0f,
34     -1.0f, 0.0f, 0.0f,
35     0.0f, -1.0f, 0.0f
36 };
37 
38 // An alternate sample pattern & filter to try out
39 static u8  mySamples[12][2] = {
40     3,  3, 10,  5,  5, 10,
41     7,  2,  2,  7,  9,  9,
42     7,  2,  2,  7,  9,  9,
43     3,  3, 10,  5,  5, 10,
44 };
45 
46 static u8  myFilter[7] = {
47     4, 11, 11, 12, 11, 11, 4
48 };
49 
50 static u32 Ticks    = 0;  // time counter
51 static u8  animMode = 1;  // whether animation is going or stopped
52 static u8  drawMode = 0;  // which pattern to draw
53 static u8  aaMode   = 0;  // which filters to use
54 
55 static u32 octDepth = 3;
56 
57 // The following items are necessary for full-frame AA mode
58 
59 GXRenderModeObj *rMode;     // pointer to the render mode struct
60 
61 #define COPY_OVERLAP 2
62 static u16 copyLines;       // number of scan lines to copy for bottom
63 static u32 bufferOffset;    // offset into external frame buffer
64                             // for copying bottom half of buffer
65 
66 // Buffer space for 2 lines of video
67 // This is needed to clear out the overlap lines in f.f. AA mode
68 static u8 garbage[640*2*VI_DISPLAY_PIX_SZ] ATTRIBUTE_ALIGN(32);
69 
70 /*---------------------------------------------------------------------------*
71    Forward references
72  *---------------------------------------------------------------------------*/
73 
74 void        main        ( void );
75 static void CopyBottom  ( void );
76 static void CameraInit  ( Mtx v );
77 static void DrawInit    ( void );
78 static void DrawTick    ( Mtx v );
79 static void AnimTick    ( void );
80 static void PrintIntro  ( void );
81 static void Tri         (f32 *v0, f32 *v1, f32 *v2, u8 color, u32 depth);
82 
83 /*---------------------------------------------------------------------------*
84    Application main loop
85  *---------------------------------------------------------------------------*/
86 
main(void)87 void main ( void )
88 {
89     Mtx         v;   // view matrix
90     u32         width;
91     u32         half_ht;
92 
93     rMode = &GXNtsc480IntAa;
94 
95     DEMOInit(rMode);    // Init os, pad, gx, vi
96 
97     // The overlap for the rendering passes is 2 scan lines.
98     // Store away some framebuffer values to make it easy to change scissor.
99     width = rMode->fbWidth;
100     half_ht = (u16) (rMode->xfbHeight / 2);
101 
102     // Calculate copy parameters for bottom half of the screen
103     copyLines    = (u16) (rMode->efbHeight - COPY_OVERLAP);
104     bufferOffset = VIPadFrameBufferWidth(rMode->fbWidth) * copyLines *
105                    (u32) VI_DISPLAY_PIX_SZ;
106 
107     // Y scale is miscalculated in DEMOInit.  Set it to 1.0
108     GXSetDispCopyYScale((f32) 1.0);
109 
110     // You typically want to turn on dither in 16-bit mode
111     GXSetDither(GX_ENABLE);
112 
113 
114     CameraInit(v); // Initialize the camera.
115     DrawInit();    // Define my vertex formats and set array pointers.
116 
117     PrintIntro(); // Print demo directions
118 
119     while(!(DEMOPadGetButton(0) & PAD_BUTTON_MENU))
120     {
121         DEMOBeforeRender();
122 
123         // Viewport setting done by DEMOBeforeRender is not appropriate
124         // for full-frame AA mode. Override it by correct setting.
125         GXSetViewport(0.0F, 0.0F,
126                       (f32)rMode->fbWidth, (f32)rMode->xfbHeight,
127                       0.0F, 1.0F);
128 
129 
130         // Draw the top half of the screen
131         // Set scissor box and offset to top half
132         GXSetScissor(0, 0, width, half_ht+2);
133         GXSetScissorBoxOffset(0, 0);
134 
135         DrawTick(v);        // Draw the model.
136 
137         // Copy out (and clear) the top half
138         GXCopyDisp(DEMOGetCurrentBuffer(), GX_TRUE);
139 
140         // Draw the bottom half of the screen
141         // Set scissor box and offset for bottom half
142         GXSetScissor(0, half_ht-2, width, half_ht+2);
143         GXSetScissorBoxOffset(0, (s32) half_ht-2);
144 
145         DrawTick(v);        // Draw the model.
146 
147         // Copy out (and clear) the bottom half
148         CopyBottom();
149 
150         // Wait for retrace and swap buffers.
151         GXDrawDone();
152         DEMOSwapBuffers();
153 
154         DEMOPadRead();
155         AnimTick();         // Update animation.
156     }
157 
158     OSHalt("End of test");
159 }
160 
161 
162 /*---------------------------------------------------------------------------*
163    Functions
164  *---------------------------------------------------------------------------*/
165 
166 /*---------------------------------------------------------------------------*
167     Name:           CopyBottom
168 
169     Description:    Copies the bottom half of the frame buffer correctly.
170 
171     Arguments:      none
172 
173     Returns:        none
174  *---------------------------------------------------------------------------*/
CopyBottom(void)175 static void CopyBottom( void )
176 {
177     // This first copy copies out the lines we want to display.
178     // We want to omit the first two lines from the copy, but one of
179     // these lines is used for the vertical filter.  We must adjust
180     // the clamp mode to allow for this (turn off top clamping).
181     GXSetCopyClamp(GX_CLAMP_BOTTOM); // not TOP
182     GXSetDispCopySrc(0, COPY_OVERLAP, rMode->fbWidth, copyLines);
183     GXCopyDisp((void *)((u32)DEMOGetCurrentBuffer()+bufferOffset), GX_TRUE);
184 
185     // This second copy is to clear out the two lines that we didn't copy.
186     // We also must return the clamp mode back to normal.
187     GXSetCopyClamp((GXFBClamp)(GX_CLAMP_TOP | GX_CLAMP_BOTTOM));
188     GXSetDispCopySrc(0, 0, rMode->fbWidth, COPY_OVERLAP);
189     GXCopyDisp((void *)garbage, GX_TRUE);
190 
191     // Finally, return the display copy source back to the default.
192     // This makes sure the top half will get copied correctly.
193     GXSetDispCopySrc(0, 0, rMode->fbWidth, rMode->efbHeight);
194 }
195 
196 /*---------------------------------------------------------------------------*
197     Name:           CameraInit
198 
199     Description:    Initialize the projection matrix and load into hardware.
200                     Initialize the view matrix.
201 
202     Arguments:      v       view matrix
203 
204     Returns:        none
205  *---------------------------------------------------------------------------*/
CameraInit(Mtx v)206 static void CameraInit ( Mtx v )
207 {
208     Vec     up      = {0.0F, 0.0F, 1.0F};
209     Vec     camLoc  = {0.25F, 3.0F, 0.5F};
210     Vec     objPt   = {0.0F, 0.0F, 0.0F};
211 
212     MTXLookAt(v, &camLoc, &up, &objPt);
213 }
214 
215 /*---------------------------------------------------------------------------*
216     Name:           DrawInit
217 
218     Description:    Initializes the vertex attribute format 0, and sets
219                     the array pointers and strides for the indexed data.
220 
221     Arguments:      none
222 
223     Returns:        none
224  *---------------------------------------------------------------------------*/
DrawInit(void)225 static void DrawInit( void )
226 {
227     Mtx44       p;   // projection matrix
228     GXColor blue = {0, 0, 255, 0};
229 
230     // The clear Z is always specified in 24-bit format
231     GXSetCopyClear(blue, GX_MAX_Z24);
232 
233     // Need to clear background by specified color
234     // since the clear color is different than DEMOInit default
235     // The clear operation can be done by dummy display copy
236     GXCopyDisp(DEMOGetCurrentBuffer(), GX_TRUE);
237 
238     // Set current vertex descriptor to enable position and color0.
239     // Both use 8b index to access their data arrays.
240     GXClearVtxDesc();
241     GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
242     GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
243 
244     // Position has 3 elements (x,y,z), each of type f32
245     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
246 
247     // Color 0 has 4 components (r, g, b, a), each component is 8b.
248     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
249 
250     // Initialize lighting, texgen, and tev parameters
251     GXSetNumChans(1); // default, color = vertex color
252     GXSetNumTexGens(0); // no texture in this demo
253     GXSetNumTevStages( 1 );
254     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
255     GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
256 
257     // Set the projection matrix.
258     // Not needed here for Rev. A, actually.
259     MTXFrustum(p, PROJ_TOP,  -PROJ_TOP,
260                -PROJ_RIGHT, PROJ_RIGHT,
261                PROJ_ZNEAR, PROJ_ZFAR);
262     GXSetProjection(p, GX_PERSPECTIVE);
263 }
264 
265 /*---------------------------------------------------------------------------*
266     Name:           Tri
267 
268     Description:    Recursively draw a triangle while alternating colors.
269 
270     Arguments:      v0        vertex 0
271                     v1        vertex 1
272                     v2        vertex 2
273                     color     color of triangle
274                     depth     recursion depth
275 
276     Returns:        none
277  *---------------------------------------------------------------------------*/
Tri(f32 * v0,f32 * v1,f32 * v2,u8 color,u32 depth)278 static void Tri (f32 *v0, f32 *v1, f32 *v2, u8 color, u32 depth)
279 {
280     f32 vertMid01[3];  // midpoint between v0 and v1
281     f32 vertMid12[3];  // midpoint between v1 and v2
282     f32 vertMid20[3];  // midpoint between v2 and v0
283 
284     // if more recursion depth to go, ...
285     if (depth > 0)
286     {
287         // compute triangle midpoints on unit spheres
288         VECAdd((VecPtr) v0, (VecPtr) v1, (VecPtr) vertMid01);
289         VECScale((VecPtr) vertMid01, (VecPtr) vertMid01, 0.5f);
290         VECNormalize((VecPtr) vertMid01, (VecPtr) vertMid01);
291 
292         VECAdd((VecPtr) v1, (VecPtr) v2, (VecPtr) vertMid12);
293         VECScale((VecPtr) vertMid12, (VecPtr) vertMid12, 0.5f);
294         VECNormalize((VecPtr) vertMid12, (VecPtr) vertMid12);
295 
296         VECAdd((VecPtr) v2, (VecPtr) v0, (VecPtr) vertMid20);
297         VECScale((VecPtr) vertMid20, (VecPtr) vertMid20, 0.5f);
298         VECNormalize((VecPtr) vertMid20, (VecPtr) vertMid20);
299 
300         // draw three outer triangles in same color as parent
301         Tri(v0, vertMid01, vertMid20, color, depth - 1);
302         Tri(v1, vertMid12, vertMid01, color, depth - 1);
303         Tri(v2, vertMid20, vertMid12, color, depth - 1);
304 
305         // draw inner triangle in complementary color
306         Tri(vertMid01, vertMid12, vertMid20, (u8) ~color, depth - 1);
307     }
308     else // at bottom of recursion
309     {
310         // draw the triangle
311         GXBegin(GX_TRIANGLES, GX_VTXFMT0, 3);
312             // vertex 0
313             GXPosition3f32( v0[0], v0[1], v0[2] );
314             GXColor4u8( color, color, color, 255 );
315 
316             // vertex 1
317             GXPosition3f32( v1[0], v1[1], v1[2] );
318             GXColor4u8( color, color, color, 255 );
319 
320             // vertex 2
321             GXPosition3f32( v2[0], v2[1], v2[2] );
322             GXColor4u8( color, color, color, 255 );
323         GXEnd();
324     }
325 }
326 
327 /*---------------------------------------------------------------------------*
328     Name:           DrawTick
329 
330     Description:    Draw the model once.
331 
332     Arguments:      v       view matrix
333 
334     Returns:        none
335  *---------------------------------------------------------------------------*/
DrawTick(Mtx v)336 static void DrawTick( Mtx v )
337 {
338     Mtx m;  // Model matrix.
339     Mtx mv; // Modelview matrix.
340 
341     switch(aaMode)
342     {
343       case 0:
344         GXSetCopyFilter(GX_TRUE, rMode->sample_pattern,
345                         GX_TRUE, rMode->vfilter);
346         break;
347       case 1:
348         GXSetCopyFilter(GX_TRUE, mySamples,
349                         GX_TRUE, myFilter);
350         break;
351       case 2:
352         GXSetCopyFilter(GX_FALSE, NULL,
353                         GX_TRUE, rMode->vfilter);
354         break;
355       case 3:
356         GXSetCopyFilter(GX_FALSE, NULL,
357                         GX_FALSE, NULL);
358         break;
359       default:
360         OSHalt("bad aaMode case");
361     }
362 
363     // model has a rotation about z axis
364     MTXRotDeg(m, 'z', Ticks);
365     MTXConcat(v, m, mv);
366     GXLoadPosMtxImm(mv, GX_PNMTX0);
367 
368     if (drawMode == 0)
369     {
370         // draw octahedron to recursion depth of octDepth
371         // draw northern hemisphere
372         Tri(&vertEquator[3], &vertEquator[0], vertNorth, 0,   octDepth);
373         Tri(&vertEquator[6], &vertEquator[3], vertNorth, 255, octDepth);
374         Tri(&vertEquator[9], &vertEquator[6], vertNorth, 0,   octDepth);
375         Tri(&vertEquator[0], &vertEquator[9], vertNorth, 255, octDepth);
376 
377         // draw southern hemisphere
378         Tri(&vertEquator[0], &vertEquator[3], vertSouth, 255, octDepth);
379         Tri(&vertEquator[3], &vertEquator[6], vertSouth, 0,   octDepth);
380         Tri(&vertEquator[6], &vertEquator[9], vertSouth, 255, octDepth);
381         Tri(&vertEquator[9], &vertEquator[0], vertSouth, 0,   octDepth);
382     }
383     if (drawMode == 1)
384     {
385         int i;
386         f32 x, y;
387 
388         GXBegin(GX_LINES, GX_VTXFMT0, 30*2);
389         for(i=0; i<30; i++)
390         {
391             x = cosf(i/15.0F * 3.1415926535F);
392             y = sinf(i/15.0F * 3.1415926535F);
393 
394             // vertex 0
395             GXPosition3f32( 0.0F, 0.0F, 0.0F );
396             GXColor4u8( 255, 255, 255, 255 );
397 
398             // vertex 1
399             GXPosition3f32( x, y, 0.0F );
400             GXColor4u8( 255, 255, 255, 255 );
401         }
402         GXEnd();
403     }
404 }
405 
406 /*---------------------------------------------------------------------------*
407     Name:           AnimTick
408 
409     Description:    Computes next time step.
410 
411     Arguments:      none
412 
413     Returns:        none
414  *---------------------------------------------------------------------------*/
AnimTick(void)415 static void AnimTick( void )
416 {
417     u8  oldaaMode = aaMode;
418     u16 down = DEMOPadGetButtonDown(0);
419 
420     if (down & PAD_BUTTON_X)
421     {
422         animMode = ! animMode;
423     }
424 
425     if (down & PAD_BUTTON_Y)
426     {
427         drawMode = ! drawMode;
428     }
429 
430     if (DEMOPadGetButton(0) & PAD_BUTTON_A)
431     {
432         aaMode |= 1;
433     }
434     else
435     {
436         aaMode &= ~1;
437     }
438 
439     if (down & PAD_BUTTON_B)
440     {
441         aaMode+=2;
442         if (aaMode > 3)
443             aaMode = 0;
444     }
445 
446     if (down & PAD_TRIGGER_R)
447     {
448     	octDepth++;
449         if (octDepth > OCT_DEPTH_MAX)
450             octDepth = OCT_DEPTH_MAX;
451     }
452 
453     if (down & PAD_TRIGGER_L)
454     {
455     	octDepth--;
456         if (octDepth < OCT_DEPTH_MIN)
457             octDepth = OCT_DEPTH_MIN;
458     }
459 
460     if (animMode)
461     {
462         Ticks++;
463     }
464 
465     if (aaMode != oldaaMode)
466     {
467         switch(aaMode)
468         {
469           case 0:  OSReport("Regular filter\n"); break;
470           case 1:  OSReport("Modified filter\n"); break;
471           case 2:  OSReport("AA off, deflicker on\n"); break;
472           case 3:  OSReport("AA off, deflicker off\n"); break;
473           default: OSHalt("bad aaMode case\n");
474         }
475     }
476 }
477 
478 /*---------------------------------------------------------------------------*
479     Name:           PrintIntro
480 
481     Description:    Prints the directions on how to use this demo.
482 
483     Arguments:      none
484 
485     Returns:        none
486  *---------------------------------------------------------------------------*/
PrintIntro(void)487 static void PrintIntro( void )
488 {
489     OSReport("\n\n*************************************************\n");
490     OSReport("frb-aa-full: demonstrate full-frame antialiasing\n");
491     OSReport("*************************************************\n");
492     OSReport("Button A - hold to show alternate AA mode\n");
493     OSReport("Button B - press to toggle AA on/off\n\n");
494     OSReport("Button X - press to toggle animation on/off\n");
495     OSReport("Button Y - press to toggle drawing mode\n");
496     OSReport("Triggers - press to change levels of recursive subdivision\n");
497     OSReport("\nTo quit:\n");
498     OSReport("     press the start button\n");
499     OSReport("\n\n*************************************************\n");
500 }
501