/*---------------------------------------------------------------------------* Project: Dolphin/Revolution gx demo File: tf-clip-bug.c Copyright 1998-2006 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. *---------------------------------------------------------------------------*/ #include // This demo illustrates the color clipping bug. // It also shows the properties of the various Z-buffer modes. // // It draws 2 rectangles in perspective on either side of the screen. // The left rectangle gets darker further away from the viewer, while // the right rectangle gets brighter further away from the viewer. // When the rectangles get near-clipped, the colors can flip around! // // In the middle are shown tags with different Z depths, with a red // tag drawn a certain spacing behind each green tag. // You should normally not be able to see any of the red tags, but // this will change depending upon the Z-buffer mode and the tag spacing. // It also changes greatly depending upon the near-plane distance! // // Of course, the near-plane distance also affects the clipping bug, // so that is why we show the effects on the Z-buffering. // // Please refer to the HTML man page for this demo for more details. /*---------------------------------------------------------------------------* Model Data *---------------------------------------------------------------------------*/ // Notes on vertex layout: // // The rectangle below represents the model being drawn. // It is just a rectangle, but it can be tessellated into vertical strips. // Lines 1 and 10 label the quad's corner vertex drawing order. // Lines 3 and 8 label all the vertex positions. // // 1: 3 0 // 2: | . : . ; . : . | // 3: 16 14 12 10 8 6 4 2 0 // 4: +-----------------------+ // 5: | | // 6: | | // 7: +-----------------------+ // 8: 17 15 13 11 9 7 5 3 1 // 9: | . : . ; . : . | // 10: 2 1 // // The above is for a single rectangle. We actually draw 2 // rectangles on the right and left sides, so we have twice as // many vertices as that. // indices for verts for drawing order at tessellation = 1, 2, 4, 8 static u8 ivert[4][32] = { { 0, 1, 17, 16 }, { 0, 1, 9, 8, 8, 9, 17, 16 }, { 0, 1, 5, 4, 4, 5, 9, 8, 8, 9, 13, 12, 12, 13, 17, 16 }, { 0, 1, 3, 2, 2, 3, 5, 4, 4, 5, 7, 6, 6, 7, 9, 8, 8, 9, 11, 10, 10, 11, 13, 12, 12, 13, 15, 14, 14, 15, 17, 16 } }; #define IHALF 18 // verts static s16 Vert_s16[] ATTRIBUTE_ALIGN(32) = { // left wall: -10, 100, 100, // 0 0 0 0 0 -10, -100, 100, // 1 1 1 1 1 -10, 100, 75, // 3 4 2 -10, -100, 75, // 2 5 3 -10, 100, 50, // 3 4 7 8 4 -10, -100, 50, // 2 5 6 9 5 -10, 100, 25, // 11 12 6 -10, -100, 25, // 10 13 7 -10, 100, 0, // 3 4 7 8 15 16 8 -10, -100, 0, // 2 5 6 9 14 17 9 -10, 100, -25, // 20 19 10 -10, -100, -25, // 21 18 11 -10, 100, -50, // 11 12 24 23 12 -10, -100, -50, // 10 13 25 22 13 -10, 100, -75, // 28 27 14 -10, -100, -75, // 29 26 15 -10, 100, -100, // 3 7 15 31 16 -10, -100, -100, // 2 6 14 30 17 // right wall: 10, 100, 100, // 0 0 0 0 18 10, -100, 100, // 1 1 1 1 19 10, 100, 75, // 3 4 20 10, -100, 75, // 2 5 21 10, 100, 50, // 3 4 7 8 22 10, -100, 50, // 2 5 6 9 23 10, 100, 25, // 11 12 24 10, -100, 25, // 10 13 25 10, 100, 0, // 3 4 7 8 15 16 26 10, -100, 0, // 2 5 6 9 14 17 27 10, 100, -25, // 20 19 28 10, -100, -25, // 21 18 29 10, 100, -50, // 11 12 24 23 30 10, -100, -50, // 10 13 25 22 31 10, 100, -75, // 28 27 32 10, -100, -75, // 29 26 33 10, 100, -100, // 3 7 15 31 34 10, -100, -100, // 2 6 14 30 35 }; // colors // Left wall is brighter closer to the eye, // darker further from the eye. // Right wall is darker closer to the eye, // brighter further from the eye. // Due to the clipping bug, they may appear the opposite way around. static u32 Colors_u32[] ATTRIBUTE_ALIGN(32) = { // left wall: // r g b a 0xc0c0c0ff, // 0 0 0xa0a0c0ff, // 1 1 0xb4b4c0ff, // 1/8 0-3 2 0x9c9cc0ff, // 1/8 1-2 3 0xa8a8c0ff, // 1/4 0-3 4 0x9898c0ff, // 1/4 1-2 5 0x9c9cc0ff, // 3/8 0-3 6 0x9494c0ff, // 3/8 1-2 7 0x9090c0ff, // 1/2 0-3 8 0x9090c0ff, // 1/2 1-2 9 0x8484c0ff, // 5/8 0-3 10 0x8c8cc0ff, // 5/8 1-2 11 0x7878c0ff, // 3/4 0-3 12 0x8888c0ff, // 3/4 1-2 13 0x6c6cc0ff, // 7/8 0-3 14 0x8484c0ff, // 7/8 1-2 15 0x8080c0ff, // 2 16 0x6060c0ff, // 3 17 // right wall: // r g b a 0x2020c0ff, // 0 18 0x4040c0ff, // 1 19 0x2c2cc0ff, // 1/8 0-3 20 0x4444c0ff, // 1/8 1-2 21 0x3838c0ff, // 1/4 0-3 22 0x4848c0ff, // 1/4 1-2 23 0x4444c0ff, // 3/8 0-3 24 0x4c4cc0ff, // 3/8 1-2 25 0x5050c0ff, // 1/2 0-3 26 0x5050c0ff, // 1/2 1-2 27 0x5c5cc0ff, // 5/8 0-3 28 0x5454c0ff, // 5/8 1-2 29 0x6868c0ff, // 3/4 0-3 30 0x5858c0ff, // 3/4 1-2 31 0x7474c0ff, // 7/8 0-3 32 0x5c5cc0ff, // 7/8 1-2 33 0x6060c0ff, // 2 34 0x8080c0ff, // 3 35 }; /*---------------------------------------------------------------------------* Application main loop *---------------------------------------------------------------------------*/ void main ( void ) { u16 button, down; // button return codes Mtx44 pm; // projection matrix Mtx cm; // camera matrix Mtx vm; // view matrix Mtx sm; // scale matrix Mtx ym; // yet another view matrix s16 i; // loop variable s16 j; // loop variable u8 tess = 0; // tessellation factor u8 mode = 0; // AA/zbuffer mode Vec vTmp = {0.0F, 0.0F, 0.0F}; // camera position Vec at = {0.0F, 0.0F, -6000.0F}; // look at position Vec up = {0.0F, 1.0F, 0.0F}; // camera up vector f32 fovy = 90.0F; // FOV in Y direction f32 near = 5.0f; // near plane distance char nums[100]; // number string GXColor green = { 0, 255, 0, 255 }; GXColor red = { 255, 0, 0, 255 }; s16 spacing = 5; // interplanar distance for Z tags s16 xp, yp, zp; // Z tag position f32 fi; // fractional i for distance calculation //---------------------------------------------------------------------- // We use GXNtsc240Int since that makes it easy to change // between 16-bit (AA) and 24-bit framebuffer modes. DEMOInit(&GXNtsc240Int); // Init os, pad, gx, vi GXSetCullMode(GX_CULL_NONE); GXSetArray(GX_VA_POS, Vert_s16, 3*sizeof(s16)); GXSetArray(GX_VA_CLR0, Colors_u32, 1*sizeof(u32)); GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_POS, GX_POS_XYZ, GX_S16, 0); GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); DEMOLoadFont( GX_TEXMAP0, GX_TEXMTX0, DMTF_POINTSAMPLE ); MTXIdentity(sm); OSReport("\n\n********************************\n"); OSReport("Running...\n\n"); OSReport("********************************\n"); OSReport("This demo shows the properties of the color clipping bug.\n"); OSReport("It also shows the properties of the various Z-buffer modes.\n"); OSReport("\n"); OSReport("It draws 2 rectangles in perspective on either side of the screen.\n"); OSReport("The left rectangle gets darker further away from the viewer, while\n"); OSReport("the right rectangle gets brighter further away from the viewer.\n"); OSReport("When the rectangles get near-clipped, the colors can flip around!\n"); OSReport("\n"); OSReport("In the middle are shown tags with different Z depths, with a red\n"); OSReport("tag drawn a certain spacing behind each green tag.\n"); OSReport("You should normally not be able to see any of the red tags, but\n"); OSReport("this will change depending upon the Z-buffer mode and the tag spacing.\n"); OSReport("It also changes greatly depending upon the near-plane distance!\n"); OSReport("\n"); OSReport("Of course, the near-plane distance also affects the clipping bug,\n"); OSReport("so that is why we show the effects on the Z-buffering.\n"); OSReport("\n"); OSReport("Please refer to the HTML man page for this demo for more details.\n"); OSReport("\n"); OSReport("Main stick - move camera\n"); OSReport("Sub stick - move camera in Z\n"); OSReport("L trigger - hold to adjust FOV with A/B buttons\n"); OSReport("R trigger - hold to adjust tessellation with X/Y buttons\n"); OSReport("A/B buttons - adjust near plane or FOV\n"); OSReport("X/Y buttons - adjust Z tag interplanar dist or tessellation\n"); OSReport("Start button - toggle 16/24-bit mode\n"); OSReport("********************************\n"); while(1) { DEMOPadRead(); down = DEMOPadGetButtonDown(0); button = DEMOPadGetButton(0); vTmp.x -= DEMOPadGetStickX(0) / 100.0f; vTmp.y -= DEMOPadGetStickY(0) / 100.0f; vTmp.z += DEMOPadGetSubStickY(0) / 100.0f; if (button & PAD_TRIGGER_R) { if (down & PAD_BUTTON_X) { if (tess > 0) tess--; } if (down & PAD_BUTTON_Y) { if (tess < 3) tess++; } } else { if (down & PAD_BUTTON_X) { spacing += 1; if (spacing > 10) spacing = 10; } if (down & PAD_BUTTON_Y) { spacing -= 1; if (spacing < 1) spacing = 1; } } if (button & PAD_TRIGGER_L) { if (button & PAD_BUTTON_A) { fovy += 1.0F; if (fovy > 179.0F) fovy = 179.0F; } if (button & PAD_BUTTON_B) { fovy -= 1.0F; if (fovy < 1.0F) fovy = 1.0F; } } else { if (button & PAD_BUTTON_A) { near += 0.1F; if (near > 10.0F) near = 10.0F; } if (button & PAD_BUTTON_B) { near -= 0.1F; if (near < 0.1F) near = 0.1F; } } if (down & PAD_BUTTON_MENU) { mode++; if (mode == 5) mode = 0; } if (mode) { GXSetPixelFmt( GX_PF_RGB565_Z16, (GXZFmt16)(mode - 1) ); } else { GXSetPixelFmt( GX_PF_RGB8_Z24, GX_ZC_LINEAR ); } DEMOBeforeRender(); // Cancel out changes done by DEMOInitCaption (below) GXSetZMode( GX_ENABLE, GX_LEQUAL, GX_TRUE); GXSetNumChans(1); // Set up projection, matrices MTXPerspective(pm, fovy, 4.0F/3.0F, near, 10000); GXSetProjection(pm, GX_PERSPECTIVE); // Set up camera/view matrices MTXLookAt(cm, &vTmp, &up, &at); // If you want any viewing transforms, put them here MTXCopy(cm, vm); GXLoadPosMtxImm(vm, GX_PNMTX0); // Set up for drawing walls GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_INDEX8); GXSetVtxDesc(GX_VA_CLR0, GX_INDEX8); // Use vertex colors GXSetChanCtrl( GX_COLOR0A0, GX_DISABLE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE ); GXSetNumTexGens(0); GXSetTevOrder( GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0 ); GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR); // Draw the walls GXBegin(GX_QUADS, GX_VTXFMT1, (u16) ((1<9) ? -16 : -12); yp = (s16) -8; zp = (s16) (-i * 100); // scale signs larger as they get further away sm[0][0] = i * (5.0F / 12.0F); sm[1][1] = i * (5.0F / 12.0F); MTXConcat(vm, sm, ym); // position signs up and down in vertical FOV ym[1][3] = - i * 100 + i * i * (10.0F / 3.0F); GXLoadPosMtxImm(ym, GX_PNMTX0); // Draw green sign GXSetChanMatColor(GX_COLOR0A0, green); DEMOPuts( xp, yp, zp, nums ); // Adjust for red sign zp -= spacing; fi = i + spacing / 100.0F; ym[1][3] = - fi * 100 + fi * fi * (10.0F / 3.0F); GXLoadPosMtxImm(ym, GX_PNMTX0); // Draw red sign GXSetChanMatColor(GX_COLOR0A0, red); DEMOPuts( xp, yp, zp, nums ); } // Draw the control panel DEMOInitCaption(DM_FT_OPQ, 640, 480); sprintf(nums, "camera= [%g, %g, %g]", vTmp.x, vTmp.y, vTmp.z); DEMOPuts( 24, 20, 0, nums ); sprintf(nums, "fovy = %g", fovy); DEMOPuts( 24, 28, 0, nums ); sprintf(nums, "near = %g", near); DEMOPuts( 24, 36, 0, nums ); sprintf(nums, "tess = %d", 1 << tess); DEMOPuts( 24, 44, 0, nums ); sprintf(nums, "Z spacing = %d", spacing); DEMOPuts( 24, 52, 0, nums ); switch (mode) { case 0: sprintf(nums, "24-bit linear mode"); break; case 1: sprintf(nums, "16-bit linear mode"); break; case 2: sprintf(nums, "16-bit near mode"); break; case 3: sprintf(nums, "16-bit mid mode"); break; case 4: sprintf(nums, "16-bit far mode"); break; } DEMOPuts( 24, 60, 0, nums ); DEMODoneRender(); } OSHalt("End of demo"); } /*===========================================================================*/