/*---------------------------------------------------------------------------* Project: WD demo File: sample.c Copyright 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. $Log: sample.c,v $ Revision 1.5 2006/08/15 03:51:15 yasu Support for PADDING warnings Revision 1.4 2006/07/18 09:25:25 terui Fix appearance Revision 1.3 2006/07/13 13:55:09 terui Adjusted the size of the heap for PAD. Revision 1.2 2006/07/13 12:38:32 terui Fix appearance Revision 1.1 2006/07/13 12:16:23 terui Initial upload $NoKeywords: $ *---------------------------------------------------------------------------*/ #include #include #include #include "sample.h" #include #include #include /*---------------------------------------------------------------------------* Constant Definitions *---------------------------------------------------------------------------*/ #define SAMPLE_FIFO_SIZE ( 256 * 1024 ) #define SAMPLE_XFB_COUNT ( 2 ) #define SAMPLE_PADHEAP_SIZE ( 128 * 1024 ) #define SAMPLE_RAW_COUNT ( 33 + 1 ) #define SAMPLE_COL_COUNT ( 88 ) /*---------------------------------------------------------------------------* Structure definitions *---------------------------------------------------------------------------*/ typedef struct SAMPLECamera { Vec pos; Vec up; Vec target; f32 fovy; f32 aspect; f32 znear; f32 zfar; } SAMPLECamera; /*---------------------------------------------------------------------------* internal variable definitions *---------------------------------------------------------------------------*/ static s32 sampleFrameCount = 0; static s32 sampleFrameCycle; static GXRenderModeObj sampleRend; static u8 sampleFifoBuf[ SAMPLE_FIFO_SIZE ] ATTRIBUTE_ALIGN( 32 ); static void* sampleXFB[ SAMPLE_XFB_COUNT ]; static MEMHeapHandle samplePadHeap; static u8 sampleFontBuf[ OSRoundUp32B( OS_FONT_SIZE_ANSI + OS_FONT_SIZE_SJIS ) ] ATTRIBUTE_ALIGN( 32 ); static OSFontHeader* sampleFont = (OSFontHeader*)( &( sampleFontBuf[ 0 ] ) ); static char sampleString[ SAMPLE_RAW_COUNT ][ 256 ]; static s32 sampleRawIndex; static s32 sampleNextRawIndex; static s32 sampleNextColIndex; static SAMPLECamera sampleCamera; static GXLightObj sampleLight; /*---------------------------------------------------------------------------* internal function prototype *---------------------------------------------------------------------------*/ static void InitString( void ); static void RenderString( void ); static void* AllocFromPadHeap( u32 size ); static u8 FreeToPadHeap( void* ptr ); /*---------------------------------------------------------------------------* Name: SampleInit Description: Performs initialization required for on-screen display. Arguments: None Returns: None *---------------------------------------------------------------------------*/ void SampleInit( void ) { /* Initialize VI */ { const GXRenderModeObj* viConf = &GXNtsc480IntDf; VIInit(); (void)memcpy( &sampleRend, viConf, sizeof( GXRenderModeObj ) ); GXAdjustForOverscan( &sampleRend, &sampleRend, 0, 16 ); sampleFrameCycle = ( ( ( sampleRend.viTVmode >> 2 ) == VI_PAL ) ? 50 : 60 ); VIConfigure( &sampleRend ); } /* Allocate external frame buffer */ { void* arena_s; u32 xfbSize; s32 i; arena_s = OSGetMEM1ArenaLo(); xfbSize = (u32)( VIPadFrameBufferWidth( sampleRend.fbWidth ) * sampleRend.xfbHeight * VI_DISPLAY_PIX_SZ ); for( i = 0; i < SAMPLE_XFB_COUNT; i ++ ) { sampleXFB[ i ] = (void*)OSRoundUp32B( (u32)arena_s ); arena_s = (void*)OSRoundUp32B( (u32)( sampleXFB[ i ] ) + xfbSize ); } OSSetMEM1ArenaLo( arena_s ); } /* Initialize heap for WPAD sampling */ { void* heapAddress; heapAddress = OSGetMEM2ArenaLo(); OSSetMEM2ArenaLo( (void*)OSRoundUp32B( (u32)heapAddress + SAMPLE_PADHEAP_SIZE ) ); samplePadHeap = MEMCreateExpHeap( heapAddress, SAMPLE_PADHEAP_SIZE ); if( samplePadHeap == NULL ) { OSHalt( "Could not create heap.\n" ); } WPADRegisterAllocator( AllocFromPadHeap, FreeToPadHeap ); } /* Initialize controllers */ { KPADStatus status; KPADInit(); while( KPADRead( WPAD_CHAN0, &status, 1 ) ) {} while( KPADRead( WPAD_CHAN1, &status, 1 ) ) {} while( KPADRead( WPAD_CHAN2, &status, 1 ) ) {} while( KPADRead( WPAD_CHAN3, &status, 1 ) ) {} } /* Initialize GX */ { GXFifoObj* gxFifo; f32 yScale; u16 xfbHeight; gxFifo = GXInit( sampleFifoBuf, SAMPLE_FIFO_SIZE ); GXSetViewport( 0.0F, 0.0F, (f32)sampleRend.fbWidth, (f32)sampleRend.efbHeight, 0.0F, 1.0F ); GXSetScissor( 0, 0, (u32)sampleRend.fbWidth, (u32)sampleRend.efbHeight ); yScale = GXGetYScaleFactor( sampleRend.efbHeight, sampleRend.xfbHeight ); xfbHeight = (u16)GXSetDispCopyYScale( yScale ); GXSetDispCopySrc( 0, 0, sampleRend.fbWidth, sampleRend.efbHeight ); GXSetDispCopyDst( sampleRend.fbWidth, xfbHeight ); GXSetCopyFilter( sampleRend.aa, sampleRend.sample_pattern, GX_TRUE, sampleRend.vfilter ); GXSetDispCopyGamma( GX_GM_1_0 ); if( sampleRend.aa ) { GXSetPixelFmt( GX_PF_RGB565_Z16, GX_ZC_LINEAR ); } else { GXSetPixelFmt( GX_PF_RGB8_Z24, GX_ZC_LINEAR ); } GXCopyDisp( sampleXFB[ 0 ], GX_TRUE ); } InitString(); /* Wait for first frame */ { VISetNextFrameBuffer( sampleXFB[ 0 ] ); VISetBlack( FALSE ); VIFlush(); VIWaitForRetrace(); if( (u32)( sampleRend.viTVmode ) & 0x1 ) { VIWaitForRetrace(); } } } /*---------------------------------------------------------------------------* Name: SampleWaitRetrace Description: Wait until V-Blank interrupt is generated. Arguments: None Returns: None *---------------------------------------------------------------------------*/ void SampleWaitRetrace( void ) { RenderString(); GXCopyDisp( sampleXFB[ sampleFrameCount % SAMPLE_XFB_COUNT ], GX_TRUE ); VISetNextFrameBuffer( sampleXFB[ sampleFrameCount % SAMPLE_XFB_COUNT ] ); VIFlush(); VIWaitForRetrace(); sampleFrameCount ++; } /*---------------------------------------------------------------------------* Name: SampleReport Description: Performs debug display of text. Arguments : msg - The character string to be displayed ... - Virtual argument. Returns: None *---------------------------------------------------------------------------*/ void SampleReport( const char* msg, ... ) { va_list vl; char temp[ 256 ]; s32 i; char* p; (void)memset( temp, 0, sizeof( temp ) ); va_start( vl, msg ); (void)vsprintf( temp, msg, vl ); va_end( vl ); OSReport( temp ); p = &temp[ 0 ]; for( i = 0; i < 256; i ++ ) { if( *p == 0x00 ) { sampleString[ sampleNextRawIndex % SAMPLE_RAW_COUNT ][ sampleNextColIndex ] = 0x00; break; } if( *p == 0x0d ) { p ++; continue; } if( *p == 0x0a ) { sampleString[ sampleNextRawIndex % SAMPLE_RAW_COUNT ][ sampleNextColIndex ] = 0x00; sampleNextColIndex = 0; sampleNextRawIndex ++; if( sampleNextRawIndex >= SAMPLE_RAW_COUNT ) { sampleRawIndex = ( sampleRawIndex + 1 ) % SAMPLE_RAW_COUNT; } p ++; continue; } sampleString[ sampleNextRawIndex % SAMPLE_RAW_COUNT ][ sampleNextColIndex ] = *p; if( ( ++ sampleNextColIndex ) > 255 ) { sampleNextColIndex = 0; sampleNextRawIndex ++; if( sampleNextRawIndex >= SAMPLE_RAW_COUNT ) { sampleRawIndex = ( sampleRawIndex + 1 ) % SAMPLE_RAW_COUNT; } } p ++; } } /*---------------------------------------------------------------------------* Name: AllocFromPadHeap Description: Dynamically allocates memory for the WPAD library. Arguments: size - Specifies the amount of memory to be allocated. Returns: void* - Returns the starting address of the allocated memory. *---------------------------------------------------------------------------*/ static void* AllocFromPadHeap( u32 size ) { return MEMAllocFromExpHeap( samplePadHeap, size ); } /*---------------------------------------------------------------------------* Name: FreeToPadHeap Description: Frees memory dynamically allocated for the WPAD library. Arguments: ptr - Specifies the start address of the memory to be freed. Returns: u8 - Returns 0 if attempt to free memory fails. *---------------------------------------------------------------------------*/ static u8 FreeToPadHeap( void* ptr ) { if( ptr == NULL ) { return 0; } MEMFreeToExpHeap( samplePadHeap, ptr ); return 1; } /*---------------------------------------------------------------------------* Name: InitString Description: Performs the necessary initialization for debug display of strings. Arguments: None Returns: None *---------------------------------------------------------------------------*/ static void InitString( void ) { /* Initialize the string buffer*/ (void)memset( sampleString, 0, sizeof( sampleString ) ); sampleRawIndex = 0; sampleNextRawIndex = 0; sampleNextColIndex = 0; /* Load font data */ (void)OSInitFont( sampleFont ); /* Initialize camera */ { sampleCamera.fovy = 33.3f; sampleCamera.aspect = (f32)( 10.0f / 7.0f ); sampleCamera.znear = 0.001f; sampleCamera.zfar = 1023.999f; sampleCamera.pos.x = 0.0f; sampleCamera.pos.y = 0.0f; sampleCamera.pos.z = -20.0f; sampleCamera.up.x = 0.0f; sampleCamera.up.y = 1.0f; sampleCamera.up.z = 0.0f; sampleCamera.target.x = 0.0f; sampleCamera.target.y = 0.0f; sampleCamera.target.z = 0.0f; } /* Initialize lighting */ { const Vec lpos = { 0.0f, 0.0f, 0.0f }; const Vec ldir = { 0.0f, 0.0f, -1.0f }; const GXColor lcol = { 0xff, 0xff, 0xff, 0xff }; GXInitLightPosv( &sampleLight, &lpos ); GXInitLightDirv( &sampleLight, &ldir ); GXInitLightColor( &sampleLight, lcol ); GXInitLightSpot( &sampleLight, 0.03f, GX_SP_COS ); GXInitLightDistAttn( &sampleLight, 3.0f, 0.5f, GX_DA_GENTLE ); } } /*---------------------------------------------------------------------------* Name: RenderString Description: Performs the rendering required for each picture frame in order to perform debug display of strings. Performs rendering. Arguments: None Returns: None *---------------------------------------------------------------------------*/ static void RenderString( void ) { f32 scrWidth = (f32)( sampleRend.fbWidth ); f32 scrHeight = (f32)( sampleRend.efbHeight ); const GXColor ambientCol = { 0xff, 0xff, 0xff, 0xff }; const GXColor strCol = { 0x00, 0x00, 0x00, 0xff }; const GXColor backCol = { 0xff, 0xff, 0xff, 0xff }; /* Rendering preparation */ { Mtx44 projMtx; Mtx posMtx; GXInvalidateTexAll(); /* Viewport settings */ if( (u32)( sampleRend.viTVmode ) & 0x1 ) { GXSetViewportJitter( 0.0f, 0.0f, (f32)( sampleRend.fbWidth ), (f32)( sampleRend.efbHeight ), 0.0f, 1.0f, VIGetNextField() ); } else { GXSetViewport( 0.0f, 0.0f, (f32)( sampleRend.fbWidth ), (f32)( sampleRend.efbHeight ), 0.0f, 1.0f ); } GXSetScissor( 0, 0, (u32)( sampleRend.fbWidth ), (u32)( sampleRend.efbHeight ) ); /* Camera settings */ MTXOrtho( projMtx, 0.0f, scrHeight, 0.0f, scrWidth, sampleCamera.znear, sampleCamera.zfar ); GXSetProjection( projMtx, GX_ORTHOGRAPHIC ); MTXIdentity( posMtx ); GXLoadPosMtxImm( posMtx, GX_PNMTX0 ); GXSetCurrentMtx( GX_PNMTX0 ); GXSetZMode( GX_TRUE, GX_LEQUAL, GX_TRUE ); GXSetBlendMode( GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR ); /* Lighting settings */ GXSetNumChans( 1 ); GXSetChanAmbColor( GX_COLOR0A0, ambientCol ); GXLoadLightObjImm( &sampleLight, GX_LIGHT0 ); GXSetChanCtrl( GX_COLOR0, GX_ENABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT0, GX_DF_NONE, GX_AF_NONE ); GXSetChanCtrl( GX_ALPHA0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT0, GX_DF_NONE, GX_AF_NONE ); } /* Background rendering */ { s16 z = -1023; /* Vertex settings */ GXClearVtxDesc(); GXSetVtxDesc( GX_VA_POS, GX_DIRECT ); GXSetVtxAttrFmt( GX_VTXFMT1, GX_VA_POS, GX_POS_XYZ, GX_S16, 0 ); /* Texture settings */ GXSetNumTexGens( 0 ); GXSetNumTevStages( 1 ); GXSetTevOp( GX_TEVSTAGE0, GX_PASSCLR ); GXSetTevOrder( GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0 ); /* Render quadrangular polygons */ GXSetChanMatColor( GX_COLOR0A0, backCol ); GXBegin( GX_QUADS, GX_VTXFMT1, 4 ); GXPosition3s16( 0, 0, z ); GXPosition3s16( (s16)scrWidth, 0, z ); GXPosition3s16( (s16)scrWidth, (s16)scrHeight, z ); GXPosition3s16( 0, (s16)scrHeight, z ); GXEnd(); } /* Render character strings */ { s32 fx, fy, fw; void* image; char* ptr; s32 i, j; GXTexObj tobj; s16 x, y, z, w, h; Mtx scaleMtx; /* Vertex settings */ GXClearVtxDesc(); GXSetVtxDesc( GX_VA_POS, GX_DIRECT ); GXSetVtxDesc( GX_VA_TEX0, GX_DIRECT ); GXSetVtxAttrFmt( GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 0 ); GXSetVtxAttrFmt( GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S16, 0 ); /* Texture settings */ GXSetNumTexGens( 1 ); MTXScale( scaleMtx, ( 1.0f / sampleFont->sheetWidth ), ( 1.0f / sampleFont->sheetHeight ), 1.0f ); GXLoadTexMtxImm( scaleMtx, GX_TEXMTX0, GX_MTX2x4 ); GXSetTexCoordGen( GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0 ); GXSetNumTevStages( 1 ); GXSetTevOp( GX_TEVSTAGE0, GX_MODULATE ); GXSetTevOrder( GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0 ); /* Draw string buffer */ GXSetChanMatColor( GX_COLOR0A0, strCol ); for( i = 0; i < ( SAMPLE_RAW_COUNT - 1 ); i ++ ) { x = 2; y = (s16)( ( scrHeight * i ) / ( SAMPLE_RAW_COUNT - 1 ) ); z = -1; h = (s16)( scrHeight / ( SAMPLE_RAW_COUNT - 1 ) ); ptr = &( sampleString[ ( sampleRawIndex + i ) % SAMPLE_RAW_COUNT ][ 0 ] ); for( j = 0; j < 256; j ++ ) { if( ( *ptr == 0x00 ) || ( *ptr == 0x0d ) || ( *ptr == 0x0a ) ) { break; } ptr = OSGetFontTexture( ptr, &image, &fx, &fy, &fw ); w = (s16)( ( fw * scrWidth ) / ( 12 * SAMPLE_COL_COUNT ) ); GXInitTexObj( &tobj, image, sampleFont->sheetWidth, sampleFont->sheetHeight, GX_TF_I4, GX_REPEAT, GX_REPEAT, GX_FALSE ); GXLoadTexObj( &tobj, GX_TEXMAP0 ); GXBegin( GX_QUADS, GX_VTXFMT0, 4 ); GXPosition3s16( (s16)( x + 0 ), (s16)( y + 0 ), z ); GXTexCoord2s16( (s16)( fx + 0 ), (s16)( fy + 0 ) ); GXPosition3s16( (s16)( x + w ), (s16)( y + 0 ), z ); GXTexCoord2s16( (s16)( fx + fw ), (s16)( fy + 0 ) ); GXPosition3s16( (s16)( x + w ), (s16)( y + h ), z ); GXTexCoord2s16( (s16)( fx + fw ), (s16)( fy + 24 ) ); GXPosition3s16( (s16)( x + 0 ), (s16)( y + h ), z ); GXTexCoord2s16( (s16)( fx + 0 ), (s16)( fy + 24 ) ); GXEnd(); x += w; if( x >= scrWidth ) { break; } } } } } /*---------------------------------------------------------------------------* End of file *---------------------------------------------------------------------------*/