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