/*---------------------------------------------------------------------------* Project: Dolphin/Revolution gx demo File: tg-emboss.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 #include #include "cmn-model.h" #define SCREEN_DEPTH 128.0f #define SCREEN_ZNEAR 0.0f // near plane Z in screen coordinates #define SCREEN_ZFAR 1.0f // far plane Z in screen coordinates #define ZBUFFER_MAX 0x00ffffff /*---------------------------------------------------------------------------* Typedefs *---------------------------------------------------------------------------*/ typedef struct { Camera* camera; ViewPort* viewport; GXColor* bgcolor; } Scene; /*---------------------------------------------------------------------------* Forward references *---------------------------------------------------------------------------*/ void SceneDraw ( Scene* ); void SceneControl ( Scene*, DEMOPadStatus* ); void myInitModel ( void ); void myAnimeModel ( Scene*, DEMOPadStatus* ); void myDrawModel ( Scene* ); void myInfoModel ( Scene* ); static void PrintIntro( void ); /*---------------------------------------------------------------------------* Rendering parameters *---------------------------------------------------------------------------*/ Camera myCamera = { { 0.0f,-300.0f, 0.0f }, // position { 0.0f, 0.0f, 0.0f }, // target { 0.0f, 0.0f, 1.0f }, // upVec 33.3f, // fovy 16.0f, // near plane Z in camera coordinates 1024.0f, // far plane Z in camera coordinates }; ViewPort myViewPort = { 0, 0, 0, 0 }; GXColor myBgColor = { 32, 32, 255, 255}; Scene myScene = { &myCamera, &myViewPort, &myBgColor }; /*---------------------------------------------------------------------------* Application main loop *---------------------------------------------------------------------------*/ void main ( void ) { GXRenderModeObj *rmp; // initialize render settings and set clear color for first frame DEMOInit(NULL); OSReport("\n\n"); OSReport("**********************************************\n"); OSReport("tg-emboss: Emboss Texture demo\n"); OSReport("**********************************************\n"); OSReport("To quit hit the start button.\n"); OSReport("\n"); OSReport("Main stick moves light position.\n"); OSReport("A button changes the indicated parameter.\n"); OSReport("B/X buttons move the parameter cursor.\n"); OSReport("**********************************************\n"); OSReport("\n\n"); GXInvalidateTexAll( ); GXSetCopyClear( *(myScene.bgcolor), GX_MAX_Z24 ); // Dummy copy operation to clear the eFB by specified color GXCopyDisp( DEMOGetCurrentBuffer(), GX_TRUE ); rmp = DEMOGetRenderModeObj(); myViewPort.width = (s16) rmp->fbWidth; myViewPort.height = (s16) rmp->efbHeight; myInitModel( ); while ( ! ( DEMOPadGetButton(0) & PAD_BUTTON_MENU ) ) { // get pad status DEMOPadRead( ); // General control & model animation SceneControl( &myScene, &DemoPad[0] ); myAnimeModel( &myScene, &DemoPad[0] ); // Draw scene DEMOBeforeRender( ); SceneDraw( &myScene ); DEMODoneRender( ); } OSHalt("End of demo"); } /*---------------------------------------------------------------------------* Functions *---------------------------------------------------------------------------*/ //============================================================================ // Scene //============================================================================ /*---------------------------------------------------------------------------* Name: SceneControl Description: user interface for paramter control Arguments: Returns: none *---------------------------------------------------------------------------*/ void SceneControl( Scene* s, DEMOPadStatus* pad ) { #pragma unused( s, pad ) return; } /*---------------------------------------------------------------------------* Name: SceneDraw Description: Draw model Arguments: Scene* s Returns: none *---------------------------------------------------------------------------*/ void SceneDraw( Scene* s ) { Camera* c = s->camera; ViewPort* v = s->viewport; float aspect = (float) (4.0 / 3.0); // Set projection matrix MTXPerspective ( c->projMtx, c->fovy, aspect, c->znear, c->zfar ); GXSetProjection( c->projMtx, GX_PERSPECTIVE ); // Set CameraView matrix MTXLookAt( c->viewMtx, &c->position, &c->up, &c->target ); // Set Viewport GXSetViewport( (f32)v->xorg, (f32)v->yorg, (f32)v->width, (f32)v->height, SCREEN_ZNEAR, SCREEN_ZFAR ); GXSetScissor ( v->xorg, v->yorg, v->width, v->height ); // Set rendering mode GXSetCullMode ( GX_CULL_BACK ); // Draw objects myDrawModel( s ); // draw information myInfoModel( s ); return; } //============================================================================ // Model // Rectangles //============================================================================ typedef struct { GXColor color; Point3d pos; // in world space f32 dist; GXLightObj obj; } MyLight; typedef struct { Mtx modelMtx; u8 bumpScale; // 0-128 on Emulator, 0-255 on HW s32 invNrmScale; s32 blendSteps; u32 texNo; GXTexObj texObj; } MyModel; typedef struct { s32 cursor; s32 animation; GXTexCoordID coord, coord1; // to show all tex coord pairs work } MyControl; MyLight myLight; MyModel myModel; MyControl myControl; TPLPalettePtr texPalette = 0; #ifndef M_SQRT3 #define M_SQRT3 1.732050808f #endif /*---------------------------------------------------------------------------* Name: myDrawModel Description: draw model Arguments: Camera *c Returns: none *---------------------------------------------------------------------------*/ void myInitModel( void ) { Vec axis = { 1.0f, 0.0f, 1.0f }; //------------------------------------------------------------------------ // MODEL //------------------------------------------------------------------------ // Matrix MTXRotAxisDeg( myModel.modelMtx, &axis, -150.0f ); // Texture myModel.texNo = 1; TPLGetPalette( &texPalette, "gxTests/tg-02.tpl" ); TPLGetGXTexObjFromPalette( texPalette, &myModel.texObj, myModel.texNo-1 ); // Bump Mapping myModel.bumpScale = 128; myModel.blendSteps = 3; myModel.invNrmScale = 48; //------------------------------------------------------------------------ // LIGHT //------------------------------------------------------------------------ // Light color myLight.color.r = 32; myLight.color.g = 64; myLight.color.b = 96; // Light position in world space myLight.dist = 100.0f; myLight.pos.x = - myLight.dist * 1.0f / M_SQRT3; myLight.pos.y = - myLight.dist * 1.0f / M_SQRT3; myLight.pos.z = + myLight.dist * 1.0f / M_SQRT3; // Set white light with no attenuation GXInitLightSpot ( &myLight.obj, 0.0f, GX_SP_OFF ); GXInitLightDistAttn( &myLight.obj, 0.0f, 0.0f, GX_DA_OFF ); //------------------------------------------------------------------------ // CONTROL //------------------------------------------------------------------------ myControl.cursor = 0; myControl.animation = 1; myControl.coord = GX_TEXCOORD0; myControl.coord1 = GX_TEXCOORD1; } /*---------------------------------------------------------------------------* Name: myAnimeModel Description: animate model Arguments: Scene *s Returns: none *---------------------------------------------------------------------------*/ void myAnimeModel( Scene* s, DEMOPadStatus* pad ) { # pragma unused(s) f32 r2, y2, scale; Mtx tmp; Vec axis; //--------------------------------------------------------------------- // Move cursor //--------------------------------------------------------------------- if ( pad->buttonDown & PAD_BUTTON_X ) { myControl.cursor ++; } if ( pad->buttonDown & PAD_BUTTON_B ) { myControl.cursor += 4; } myControl.cursor %= 5; //--------------------------------------------------------------------- // Cycle though all texture coordinates //--------------------------------------------------------------------- if ( pad->buttonDown & PAD_BUTTON_Y ) { myControl.coord++; if (myControl.coord > GX_TEXCOORD6) myControl.coord = GX_TEXCOORD0; myControl.coord1 = (GXTexCoordID)(myControl.coord + 1); OSReport("Using texture coord %d and %d\n", myControl.coord, myControl.coord1); } //--------------------------------------------------------------------- // Change item //--------------------------------------------------------------------- if ( pad->buttonDown & PAD_BUTTON_A ) { switch ( myControl.cursor ) { case 0: // Texture myModel.texNo %= 3; myModel.texNo ++; TPLGetGXTexObjFromPalette( texPalette, &myModel.texObj, myModel.texNo-1 ); break; case 1: // Animation myControl.animation ^= 1; break; case 2: // Bump scale myModel.bumpScale = (u8)( ( myModel.bumpScale < 128 ) ? myModel.bumpScale + 32 : 0 ); break; case 3: // Normal scale ( 8 - 96 ) myModel.invNrmScale %= 96; myModel.invNrmScale += 8; break; case 4: // Show step of blending myModel.blendSteps %= 3; myModel.blendSteps ++; break; } } //--------------------------------------------------------------------- // Animation //--------------------------------------------------------------------- if ( myControl.animation ) { axis.x = 1.0f; axis.y = 2.0f; axis.z = 0.5f; MTXRotAxisDeg( tmp, &axis, 1.0f ); MTXConcat( myModel.modelMtx, tmp, myModel.modelMtx ); } //--------------------------------------------------------------------- // Change light position //--------------------------------------------------------------------- if ( pad->dirs & DEMO_STICK_LEFT ) myLight.pos.x -= 2.0f; if ( pad->dirs & DEMO_STICK_RIGHT ) myLight.pos.x += 2.0f; if ( pad->dirs & DEMO_STICK_UP ) myLight.pos.z += 2.0f; if ( pad->dirs & DEMO_STICK_DOWN ) myLight.pos.z -= 2.0f; r2 = myLight.pos.x * myLight.pos.x + myLight.pos.z * myLight.pos.z; y2 = myLight.dist * myLight.dist - r2; if ( y2 < 0 ) { scale = myLight.dist / sqrtf(r2); myLight.pos.x *= scale; myLight.pos.z *= scale; myLight.pos.y = 0.0f; } else { myLight.pos.y = - sqrtf(y2); } } /*---------------------------------------------------------------------------* Name: myDrawModel Description: draw model Arguments: Scene *c Returns: none *---------------------------------------------------------------------------*/ void myDrawModel( Scene* s ) { Camera* c = s->camera; Mtx mvmtx, posMtx, nrmMtx; Point3d lpos; f32 nrmScale = 1.0f / (f32)myModel.invNrmScale; GXColor color1 = {255,64,64,255}; // set a light object MTXMultVec( c->viewMtx, &myLight.pos, &lpos ); GXInitLightPos ( &myLight.obj, lpos.x, lpos.y, lpos.z ); GXInitLightColor ( &myLight.obj, myLight.color ); GXLoadLightObjImm( &myLight.obj, GX_LIGHT0 ); // set modelview matrix GXSetCurrentMtx( GX_PNMTX0 ); // Load ModelView matrix for pos/nrm into view space // Note: mvmtx is uniform transformation here, then (mvmtx)^(-T) = mvmtx // With bump mapping, normal must be scaled to match texel size in // texture space. MTXConcat ( c->viewMtx, myModel.modelMtx, mvmtx ); MTXScale ( posMtx, 75.0f, 75.0f, 75.0f ); MTXConcat ( mvmtx, posMtx, posMtx ); GXLoadPosMtxImm( posMtx, GX_PNMTX0 ); MTXScale ( nrmMtx, nrmScale, nrmScale, nrmScale ); MTXConcat ( mvmtx, nrmMtx, nrmMtx ); GXLoadNrmMtxImm( nrmMtx, GX_PNMTX0 ); // Set texture GXLoadTexObj( &myModel.texObj, GX_TEXMAP0 ); // Render mode for Box GXClearVtxDesc( ); // z update for 1st stage GXSetZMode ( GX_TRUE, GX_LESS, GX_TRUE ); //------------------------------------------------------------------------ // Actual code for bump mapping on dolphin HW. //------------------------------------------------------------------------ { GXColor bumpScale; u32 i; GXColor white = {255,255,255,255}; GXColor grey = {128,128,128,128}; // Vertex component GXClearVtxDesc(); GXSetVtxDesc( GX_VA_POS, GX_DIRECT ); GXSetVtxDesc( GX_VA_NBT, GX_DIRECT ); GXSetVtxDesc( GX_VA_TEX0, GX_DIRECT ); // Light 0 for bump mapping GXSetNumChans(1); // GX_COLOR0A0 GXSetChanCtrl( GX_COLOR0, GX_ENABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT0, GX_DF_CLAMP, GX_AF_NONE ); GXSetChanCtrl( GX_ALPHA0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_NONE ); GXSetChanMatColor( GX_COLOR0A0, white ); GXSetChanAmbColor( GX_COLOR0A0, grey ); // clear out unused tex gens for (i = 0; i < myControl.coord; i++) GXSetTexCoordGen( (GXTexCoordID)i, GX_TG_MTX2x4, GX_TG_POS, GX_IDENTITY ); // Tex Gen // GX_TEXCOORD0: Base texcoord of bump mapping // GX_TEXCOORD1: Tex gen by bump mapping GXSetNumTexGens((u8)(myControl.coord1+1)); // coord1 is always the max coord GXSetTexCoordGen( myControl.coord, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY ); GXSetTexCoordGen( myControl.coord1, GX_TG_BUMP0, (GXTexGenSrc)((u32)myControl.coord + GX_TG_TEXCOORD0), GX_IDENTITY ); // Tev Order // GX_TEVSTAGE0: send base texture + diffuse color // GX_TEVSTAGE1: send shifted texture GXSetTevOrder( GX_TEVSTAGE0, myControl.coord, GX_TEXMAP0, GX_COLOR0A0 ); GXSetTevOrder( GX_TEVSTAGE1, myControl.coord1, GX_TEXMAP0, GX_COLOR_NULL ); // Tev Register // GX_TEVREG0: ( X, X, X, bumpScale ) bumpScale.a = myModel.bumpScale; GXSetTevColor( GX_TEVREG0, bumpScale ); // // In many case, bump mapping needs 3 tev stage, but here, // use only 2 tev stages, since no material texture map // GXSetNumTevStages( 2 ); // // Tev stage0 // Color: BumpTexture * bumpScale + DiffuseColor => R // Alpha: Not used // GXSetTevColorIn( GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, /* Bump Texture */ GX_CC_A0, /* BumpScale */ GX_CC_RASC /* Diffuse color */ ); GXSetTevColorOp( GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_DISABLE, GX_TEVPREV /* To next stage */ ); GXSetTevAlphaIn( GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO ); GXSetTevAlphaOp( GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_DISABLE, GX_TEVPREV ); // // Tev stage1 // Color: ShiftTexture * bumpScale * (-1) + R => R // Alpha: Not used // GXSetTevColorIn( GX_TEVSTAGE1, GX_CC_ZERO, GX_CC_TEXC, /* Shift Texture */ GX_CC_A0, /* BumpScale */ GX_CC_CPREV /* Last stage out */ ); GXSetTevColorOp( GX_TEVSTAGE1, GX_TEV_SUB, /* mult (-1) */ GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV ); GXSetTevAlphaIn( GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO ); GXSetTevAlphaOp( GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_DISABLE, GX_TEVPREV ); //------------------------------------------------- // Draw objects //------------------------------------------------- GXDrawCube( ); } //------------------------------------------------- // Draw light direction //------------------------------------------------- // Shade mode GXSetChanCtrl ( GX_COLOR0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_NONE ); GXSetChanMatColor( GX_COLOR0, color1 ); GXSetNumTexGens ( 0 ); // Tev mode GXSetNumTevStages( 1 ); GXSetTevOrder ( GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0 ); GXSetTevOp ( GX_TEVSTAGE0, GX_PASSCLR ); // Render mode GXSetBlendMode ( GX_BM_BLEND, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR ); GXSetZMode ( GX_TRUE, GX_LESS, GX_TRUE ); // Draw lines GXClearVtxDesc ( ); GXSetVtxDesc ( GX_VA_POS, GX_DIRECT ); GXSetVtxAttrFmt ( GX_VTXFMT1, GX_VA_POS, GX_POS_XYZ, GX_F32, 0 ); GXLoadPosMtxImm ( c->viewMtx, GX_PNMTX0 ); GXBegin( GX_LINES, GX_VTXFMT1, 2 ); GXPosition3f32( 0.0f, 0.0f, 0.0f ); GXPosition3f32( myLight.pos.x, myLight.pos.y, myLight.pos.z ); GXEnd( ); GXBegin( GX_LINESTRIP, GX_VTXFMT1, 5 ); GXPosition3f32( myLight.pos.x+2.0f, myLight.pos.y, myLight.pos.z+2.0f ); GXPosition3f32( myLight.pos.x+2.0f, myLight.pos.y, myLight.pos.z-2.0f ); GXPosition3f32( myLight.pos.x-2.0f, myLight.pos.y, myLight.pos.z-2.0f ); GXPosition3f32( myLight.pos.x-2.0f, myLight.pos.y, myLight.pos.z+2.0f ); GXPosition3f32( myLight.pos.x+2.0f, myLight.pos.y, myLight.pos.z+2.0f ); GXEnd( ); return; } /*---------------------------------------------------------------------------* Name: ModelDrawInfo Description: Draw scene information Arguments: Returns: none *---------------------------------------------------------------------------*/ void myInfoModel( Scene* s ) { ViewPort* v = s->viewport; // Z mode for drawing captions GXSetZMode( GX_TRUE, GX_ALWAYS, GX_TRUE ); // Draw paramters to the window DEMOInitCaption( DM_FT_XLU, v->width, v->height ); DEMOPuts ( 10, (s16)(myControl.cursor*8+10), 0, "\x7f" ); DEMOPrintf( 18, 10, 0, "Texture %d", myModel.texNo ); DEMOPrintf( 18, 18, 0, "Animation %s", myControl.animation ? "ON" : "OFF" ); DEMOPrintf( 18, 26, 0, "Bump scale %d", myModel.bumpScale ); DEMOPrintf( 18, 34, 0, "Normal scale 1/%d", myModel.invNrmScale ); DEMOPrintf( 18, 42, 0, "Blend steps %d", myModel.blendSteps ); return; } /*---------------------------------------------------------------------------* Name: PrintIntro Description: Prints the directions on how to use this demo. Arguments: none Returns: none *---------------------------------------------------------------------------*/ static void PrintIntro( void ) { OSReport("\n\n"); OSReport("**********************************************\n"); OSReport("tg-emboss: demonstrate bump mapping using the \n"); OSReport(" embossing technique. \n"); OSReport("**********************************************\n"); OSReport("to quit hit the start button\n"); OSReport("\n"); OSReport("Main Stick : Move Light Position\n"); OSReport("Sub Stick : Rotate the Model\n"); OSReport("X/B Buttons : Select parameter\n"); OSReport("A Button : Change selected parameter\n"); OSReport("Y Button : Change texture coordinate\n"); OSReport("**********************************************\n"); } /*======== End of tg-emboss.c ========*/