/*---------------------------------------------------------------------------* Project: KPAD Sample Program File: main.c Programmer: Keizo Ohta HIRATSU Daisuke Haruki Tojo Copyright 2005-2008 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 #include #include #include "main.h" #include "kfont.h" #include "sample.h" /*************************************************************** GXFIFO ***************************************************************/ #define GX_FIFO_SIZE ( 1 * 1024*1024 ) // Large enough (the smaller the FIFO, the greater the chance of having to wait for space to open when a command is issued) static void *gx_fifo_p ; // Pointer to buffer static GXFifoObj *gx_fifo_obj ; // Management structure /*************************************************************** Frame Buffer ***************************************************************/ GXRenderModeObj *rmode_p ; // Pointer to the rendering mode static u8 vfilter[ 7 ] = { 0,8, 16,16,16, 8,0 } ; static void *xfb_p[ 2 ] ; // Pointer to double buffer static s32 draw_xfb_idx ; // XFB being rendered by GX static s32 disp_xfb_idx ; // XFB being displayed by VI /*************************************************************** Working buffer ***************************************************************/ KPADUnifiedWpadStatus uniRingBufs[ WPAD_MAX_CONTROLLERS * KPAD_BUF_SIZE ] ; /*************************************************************** Controllers ***************************************************************/ KPADStatus kpads[ WPAD_MAX_CONTROLLERS ][ KPAD_BUF_SIZE * 2 ] ; s32 kpad_reads ; s32 kpad_err ; PADStatus pads[ PAD_MAX_CONTROLLERS ] ; PADStatus padsTmp[ PAD_MAX_CONTROLLERS ] ; PADStatus padsTrig[ PAD_MAX_CONTROLLERS ] ; /******************************************************************************* Memory initialization *******************************************************************************/ static void init_memory( void ) { void *arenaLo, *arenaHi ; OSHeapHandle heap ; //----- Check available memory arenaLo = OSGetArenaLo() ; arenaHi = OSGetArenaHi() ; //----- Declare the creation of a single heap that takes up all available memory arenaLo = OSInitAlloc( arenaLo, arenaHi, 1 ) ; OSSetArenaLo( arenaLo ) ; // Reset because the available memory changes //----- Create a heap that takes up all available memory and set it as the current heap heap = OSCreateHeap( arenaLo, arenaHi ) ; (void)OSSetCurrentHeap( heap ) ; //----- Make it clear ahead of time that available memory has been all consumed arenaLo = arenaHi ; OSSetArenaLo( arenaLo ) ; } /******************************************************************************* Initialize memory (MEM2) *******************************************************************************/ static MEMAllocator s_mem2Allocator ; static MEMHeapHandle s_handle ; static void init_memory2( void ) { void *lo = OSGetMEM2ArenaLo() ; void *hi = OSGetMEM2ArenaHi() ; s_handle = MEMCreateFrmHeap( lo, (u32)hi - (u32)lo ) ; if ( s_handle == MEM_HEAP_INVALID_HANDLE ) { OSHalt("MEM2 heap allocation error.\n") ; } else { OSSetMEM2ArenaLo(hi) ; MEMInitAllocatorForFrmHeap( &s_mem2Allocator, s_handle, 32 ) ; // Buffer requires 32-byte alignment. } } void* alloc32( u32 size ) { return MEMAllocFromAllocator( &s_mem2Allocator, size ) ; } u8 free32( void *addr ) { MEMFreeToAllocator( &s_mem2Allocator, addr ) ; return 1 ; } /******************************************************************************* Display device-related initialization *******************************************************************************/ static void init_display( void ) { u32 xfb_size ; //----- Select rendering mode rmode_p = &GXNtsc480IntDf ; //----- Allocate frame buffer xfb_size = VIPadFrameBufferWidth(rmode_p->fbWidth) * rmode_p->xfbHeight * (u32)VI_DISPLAY_PIX_SZ ; xfb_p[ 0 ] = OSAlloc( xfb_size ) ; xfb_p[ 1 ] = OSAlloc( xfb_size ) ; //----- Decide a rendering buffer and display buffer draw_xfb_idx = 0 ; disp_xfb_idx = 1 ; //----- Initialize VI VIConfigure( rmode_p ) ; VISetNextFrameBuffer( xfb_p[ disp_xfb_idx ] ) ; VIFlush() ; VIWaitForRetrace() ; // In order to enable Configure, you need to wait two cycles VIWaitForRetrace() ; // } /******************************************************************************* GX-related initialization *******************************************************************************/ static void init_gx( void ) { GXColor clear_clr = { 0,0,0, 0 } ; //----- Create GXFIFO gx_fifo_p = OSAlloc( GX_FIFO_SIZE ) ; gx_fifo_obj = GXInit( gx_fifo_p, GX_FIFO_SIZE ) ; //----- Determine pixel format GXSetPixelFmt( GX_PF_RGB8_Z24, GX_ZC_LINEAR ) ; GXSetDither( GX_DISABLE ) ; //----- Initialize settings for copying from EFB to XFB GXSetDispCopySrc( 0, 0, rmode_p->fbWidth, rmode_p->efbHeight ) ; GXSetDispCopyDst( rmode_p->fbWidth, rmode_p->xfbHeight ) ; (void)GXSetDispCopyYScale( (f32)(rmode_p->xfbHeight) / (f32)(rmode_p->efbHeight) ) ; GXSetDispCopyGamma( GX_GM_1_0 ) ; GXSetCopyFilter( rmode_p->aa, rmode_p->sample_pattern, GX_ENABLE, vfilter ) ; GXSetCopyClear( clear_clr, 0x00FFFFFF ) ; //----- Initialize EFB rendering area GXSetViewport( 0.0f, 0.0f, (f32)(rmode_p->fbWidth), (f32)(rmode_p->efbHeight), 0.0f, 1.0f ) ; GXSetScissor( 0, 0, (u32)rmode_p->fbWidth, (u32)rmode_p->efbHeight ) ; //----- Clear EFB and XFB GXCopyDisp( xfb_p[ 0 ], GX_ENABLE ) ; // The EFB is cleared and garbage is placed in XFB[0] GXCopyDisp( xfb_p[ 0 ], GX_DISABLE ) ; // The cleared EFB is placed in XFB[0] GXCopyDisp( xfb_p[ 1 ], GX_DISABLE ) ; // The cleared EFB is placed in XFB[1] GXDrawDone() ; } /*************************************************************** KPAD callback ***************************************************************/ static void work_callback( s32 chan, s32 reason, int idx ) { #pragma unused(chan) u32 i ; u32 smallest = MY_START_COUNT_DEFAULT ; u32 smallestIdx = 0 ; for (i = 0; i < MY_START_COUNTS_MAX; i++) { if ( MyCallbackStatusBuf[ idx ][ i ].count == 0 ) { break ; } else { if (smallest > MyCallbackStatusBuf[ idx ][ i ].count) { smallest = MyCallbackStatusBuf[ idx ][ i ].count ; smallestIdx = i ; } } } if ( i == MY_START_COUNTS_MAX ) { i = smallestIdx ; } MyCallbackStatusBuf[ idx ][ i ].count = MY_START_COUNT_DEFAULT ; MyCallbackStatusBuf[ idx ][ i ].reason = reason ; MyCallbackLatestIdx[ idx ] = (s32)i ; } void dpd_callback( s32 chan, s32 reason ) { work_callback( chan, reason, 0 ); } void mpls_callback( s32 chan, s32 reason ) { work_callback( chan, reason, 1 ); } void sampling_callback( s32 chan ) { #pragma unused(chan) MySamplingCount++ ; } static void read_pad( s32 chan ) { padsTrig[ chan ] = pads[ chan ] ; PADRead( padsTmp ) ; if ( padsTmp[ chan ].err == PAD_ERR_NONE ) { pads[ chan ] = padsTmp[ chan ] ; } padsTrig[ chan ].button = (u16)( (padsTrig[ chan ].button ^ pads[ chan ].button) & pads[ chan ].button ) ; } /******************************************************************************* Main *******************************************************************************/ void main( void ) { /*********************************************************************** Initialization ***********************************************************************/ //----- Highest-priority hardware initialization VIInit() ; //----- Other high-priority initializations init_memory() ; // Enable allocation and release of memory init_memory2() ; init_display() ; // Display device-related init_gx() ; // GX-related //----- Initialize application init_kfont_texture() ; init_sample() ; // Initialize KPAD //----- Screen display ON VISetBlack( FALSE ) ; VIFlush() ; PADInit(); /*********************************************************************** Main loop ***********************************************************************/ while ( 1 ) { //----- Get GameCube controller data read_pad( 0 ) ; /*************************************************************** First, perform calculations by the CPU Find coordinates based on controller input, and prepare the data necessary to issue a GX command. ***************************************************************/ //----- Get KPAD data (and miscellaneous processing) work_kpad() ; //----- Various calculations work_sample() ; /*************************************************************** Issue GX command and go on rendering to EFB ***************************************************************/ //-----Hocus-pocus here to start issuing the command GXInvalidateVtxCache() ; GXInvalidateTexAll() ; //----- Issue various commands draw_sample() ; //----- Finally, copy from EFB to XFB GXCopyDisp( xfb_p[ draw_xfb_idx ], GX_ENABLE ) ; GXDrawDone() ; /*************************************************************** Switch the XFB just copied so that it can display on the TV ***************************************************************/ disp_xfb_idx = draw_xfb_idx ; VISetNextFrameBuffer( xfb_p[ disp_xfb_idx ] ) ; VIFlush() ; //----- Wait for it to actually switch VIWaitForRetrace() ; //----- Switch to the no-longer-displayed XFB ahead of time for the next render destination draw_xfb_idx ^= 1 ; } }