/*---------------------------------------------------------------------------* Project: KPAD sample program File: main.c Programmer: Keizo Ohta HIRATSU Daisuke Copyright 2005-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 #include #include #include "main.h" #include "kfont.h" #include "sample.h" static void dpd_callback( s32 chan, s32 reason ) ; static void sampling_callback( s32 chan ) ; /*************************************************************** GXFIFO ***************************************************************/ #define GX_FIFO_SIZE ( 1 * 1024*1024 ) // Large enough (The smaller the FIFO, the larger the chance of waiting 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 drawn 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 one heap that takes up all available memory arenaLo = OSInitAlloc( arenaLo, arenaHi, 1 ) ; OSSetArenaLo( arenaLo ) ; // Reset because the available memory changes //----- Create a heap which 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 utilized 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 32byte alignment. } } static void* alloc32( u32 size ) { return MEMAllocFromAllocator( &s_mem2Allocator, size ) ; } static u8 free32( void *addr ) { MEMFreeToAllocator( &s_mem2Allocator, addr ) ; return 1 ; } /******************************************************************************* Initialize relationship with display device *******************************************************************************/ static void init_display( void ) { u32 xfb_size ; //----- Select drawing 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 ) ; //----- Select a drawing 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, VIWaitForRetrace() ; // you need to wait two times. } /******************************************************************************* Initialize GX relationship *******************************************************************************/ 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 ) ; //----- Select 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 drawing area GXSetViewport( 0.0f, 0.0f, rmode_p->fbWidth, 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 DPD callback ***************************************************************/ static void dpd_callback( s32 chan, s32 reason ) { #pragma unused(chan) u32 i ; u32 smallest = MY_DPD_START_COUNT_DEFAULT ; u32 smallestIdx = 0 ; for (i = 0; i < MY_DPD_START_COUNTS_MAX; i++) { if ( MyDpdCallbackStatusBuf[ i ].count == 0 ) { break ; } else { if (smallest > MyDpdCallbackStatusBuf[i].count) { smallest = MyDpdCallbackStatusBuf[i].count ; smallestIdx = i ; } } } if ( i == MY_DPD_START_COUNTS_MAX ) { i = smallestIdx ; } MyDpdCallbackStatusBuf[ i ].count = MY_DPD_START_COUNT_DEFAULT ; MyDpdCallbackStatusBuf[ i ].reason = reason ; MyDpdCallbackLatestIdx = (s32)i ; } static void sampling_callback( s32 chan ) { #pragma unused(chan) MySamplingCount++ ; } /******************************************************************************* Main *******************************************************************************/ void main( void ) { int rev = 0 ; int init = 0 ; u8 btn = KPAD_BUTTON_PROC_MODE_LOOSE ; /*********************************************************************** Initialization processing ***********************************************************************/ //----- Highest-priority hardware initialization VIInit() ; //----- Other priority initializations init_memory() ; // Enable allocation and release of memory init_memory2() ; init_display() ; // Display device-related init_gx() ; // GX-related WPADRegisterAllocator( alloc32, free32 ) ; KPADInit() ; // Controllers KPADSetControlDpdCallback( 0, dpd_callback ) ; KPADSetSamplingCallback( 0, sampling_callback ) ; //----- Initialize application init_kfont_texture() ; init_sample() ; //----- Screen display ON VISetBlack( FALSE ) ; VIFlush() ; PADInit(); /*********************************************************************** Main loop ***********************************************************************/ while ( 1 ) { padsTrig[ 0 ] = pads[ 0 ] ; PADRead( padsTmp ) ; if ( padsTmp[ 0 ].err == PAD_ERR_NONE ) { pads[ 0 ] = padsTmp[ 0 ] ; } padsTrig[ 0 ].button = (u16)( (padsTrig[ 0 ].button ^ pads[ 0 ].button) & pads[ 0 ].button ) ; /*************************************************************** First, perform calculations by the CPU Find coordinates based on controller input, and prepare the data necessary to issue a GX command ***************************************************************/ //----- Load controller if ( padsTrig[ 0 ].button & PAD_BUTTON_A ) { OSReport("KPADReset() from main()\n") ; KPADReset() ; } if ( pads[ 0 ].button & PAD_BUTTON_B ) { kpad_reads = 0 ; } else { kpad_reads = KPADReadEx( 0, &kpads[ 0 ][ 0 ], (u32)( KPAD_BUF_SIZE * ( init + 1 ) ), &kpad_err ) ; if ( kpad_reads == 0 && kpad_err == KPAD_READ_ERR_NO_DATA ) { // Only the last piece of data is preserved kpad_reads = 1 ; } } if ( padsTrig[ 0 ].button & PAD_BUTTON_X ) { rev = ( rev ) ? 0 : 1 ; KPADSetReviseMode( 0, rev ) ; } if ( padsTrig[ 0 ].button & PAD_BUTTON_Y ) { if ( kpad_err == KPAD_READ_ERR_INIT ) { init = ( init ) ? 0 : 1 ; if ( init ) { KPADInitEx( uniRingBufs, sizeof(uniRingBufs)/sizeof(KPADUnifiedWpadStatus) ) ; } else { KPADInit() ; } KPADSetControlDpdCallback( 0, dpd_callback ) ; KPADSetSamplingCallback( 0, sampling_callback ) ; } else { KPADShutdown() ; } } if ( padsTrig[ 0 ].button & PAD_TRIGGER_Z ) { btn = (u8)( ( btn == KPAD_BUTTON_PROC_MODE_LOOSE ) ? KPAD_BUTTON_PROC_MODE_TIGHT : KPAD_BUTTON_PROC_MODE_LOOSE ) ; KPADSetButtonProcMode( 0, btn ) ; } //----- Various calculations work_sample() ; /*************************************************************** Issue GX command and go on drawing to EFB ***************************************************************/ //----- Cast spell 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() ; /*************************************************************** The XFB copied here can be selected for display on the TV ***************************************************************/ disp_xfb_idx = draw_xfb_idx ; VISetNextFrameBuffer( xfb_p[ disp_xfb_idx ] ) ; VIFlush() ; //----- Wait for the display to actually switch VIWaitForRetrace() ; //----- Switch to the no longer displayed XFB ahead of time for the next drawing draw_xfb_idx ^= 1 ; } }