/*---------------------------------------------------------------------------* Project: rsodemo File: rsomodule.c Copyright 2006-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. *---------------------------------------------------------------------------*/ #pragma force_active on // Set use_lmw_stmw to on, for the time being. #pragma use_lmw_stmw on #pragma section code_type ".text" data_mode=far_abs code_mode=far_abs #pragma section RX ".init" ".init" data_mode=far_abs code_mode=far_abs #include #include #include #include #include #include #include #include "revolution/hbm.h" /* define for changing the number of buttons */ /* #define BTN_NUM_3 */ /* Save confirmation on/off */ /* #define HBM_NO_SAVE */ #pragma section code_type ".text" data_mode=far_abs code_mode=pc_rel #pragma section RX ".init" ".init" data_mode=far_abs code_mode=pc_rel #include "rsomodule.h" #ifdef __cplusplus extern "C" { #endif typedef void (*voidfunctionptr) (void); /* ptr to function returning void */ __declspec(section ".init") extern voidfunctionptr _ctors[]; __declspec(section ".init") extern voidfunctionptr _dtors[]; enum { OFF = 0, ON }; // Wide? int g_drawModeFlag = OFF; // Allocator MEMAllocator* g_alloc; // Default callback function static int SoundCallback( int evt, int arg ); // Callback HBMSoundCallback g_callback = SoundCallback; int homebutton = OFF; void _prolog(void); void _epilog(void); void _unresolved(void); #ifdef __cplusplus } #endif static const f32 scStickMoveCoe = 2048.0f/72.0f; /* Distance-moved coefficient of the analog stick */ static KPADStatus sKpads[ WPAD_MAX_CONTROLLERS ][ KPAD_MAX_READ_BUFS ]; HBMDataInfo hbmInfo; HBMControllerData conData; // Reset/Power Callback static void ResetCallback(); static void PowerCallback(); int reset_called = FALSE; int power_called = FALSE; OSResetCallback OldResetCallback; OSPowerCallback OldPowerCallback; // Sound buffer for HBM void *sound_buf; /* Sound data for AX use */ u8* sound_data; static void* allocMem( u32 size ) { return MEMAllocFromAllocator( g_alloc, size ); } static u8 freeMem( void* ptr ) { MEMFreeToAllocator( g_alloc, ptr ); return 1; } // "Wide flag" setting function __declspec(export) void setWideMode(int mode) { g_drawModeFlag = mode; } // Allocator setting function __declspec(export) void setAllocator(MEMAllocator* allocator) { g_alloc = allocator; } // Callback setting function __declspec(export) void setSoundCallback(HBMSoundCallback callback) { g_callback = callback; } static void ResetCallback() { reset_called = TRUE; } static void PowerCallback() { power_called = TRUE; } /* Event/sound callback function */ static int SoundCallback( int evt, int arg ) { OSReport( "SoundCallback: %d, %d\n", evt, arg ); return HBMSEV_RET_NONE; } /* Load file */ static void* ReadDvdFile( const char* fileName, u32* fileSize ) { u32 fileLen, fileLenUp32; void* readBuf; s32 readBytes; DVDFileInfo fileInfo; if (! DVDOpen(fileName, &fileInfo)) { return NULL; } fileLen = DVDGetLength(&fileInfo); if( (fileLen % 32) != 0 ) { fileLenUp32 = fileLen + (32 - (fileLen % 32)); } else { fileLenUp32 = fileLen; } readBuf = allocMem(fileLenUp32); readBytes = DVDRead(&fileInfo, readBuf, (s32)(fileLenUp32), 0); ASSERT(readBytes > 0); if( fileSize ) *fileSize = fileLen; DVDClose(&fileInfo); return readBuf; } /*---------------------------------------------------------------------------* Name: _prolog Description: Pre-processes (initializes) an RSO module. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ __declspec(export) void _prolog(void) { voidfunctionptr *constructor; /* * call static initializers */ // for (constructor = _ctors; *constructor; constructor++) { (*constructor)(); } } /*---------------------------------------------------------------------------* Name: _epilog Description: Post-processes an RSO module. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ __declspec(export) void _epilog(void) { voidfunctionptr *destructor; /* * call destructors */ for (destructor = _dtors; *destructor; destructor++) { (*destructor)(); } } /*---------------------------------------------------------------------------* Name: _unresolved Description: Called when the link to a function that is referenced from an RSO module has not been resolved. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ __declspec(export) void _unresolved(void) { u32 i; u32* p; OSReport("\nError: A called an unlinked function.\n"); OSReport("Address: Back Chain LR Save\n"); for (i = 0, p = (u32*) OSGetStackPointer(); // get current sp p && (u32) p != 0xffffffff && i++ < 16; p = (u32*) *p) // Get caller sp { OSReport("0x%08x: 0x%08x 0x%08x\n", p, p[0], p[1]); } OSReport("\n"); } /* Initialize GX */ static void InitGX() { GXClearVtxDesc(); GXSetVtxAttrFmt(GX_VTXFMT4, GX_VA_POS, GX_POS_XY, GX_F32, 0); GXSetVtxAttrFmt(GX_VTXFMT4, GX_VA_CLR0, GX_CLR_RGB, GX_RGB8, 0); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT); GXSetNumChans(1); GXSetNumTexGens(0); GXSetNumTevStages(1); GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR); GXSetBlendMode(GX_BM_NONE, GX_BL_ZERO, GX_BL_ZERO, GX_LO_CLEAR); GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); GXSetCurrentMtx( GX_PNMTX1 ); } static void InitHomeButtonInfo( HBMDataInfo* pHbmInfo ) { #ifdef BTN_NUM_3 char dirName[] = "hbm/HomeButton3"; #else char dirName[] = "hbm/HomeButton2"; #endif char nameBuf[32]; /* Create file name */ strcpy( nameBuf, dirName ); /* Switching as necessary according to the language setting */ pHbmInfo->region=SCGetLanguage(); switch (pHbmInfo->region) { case SC_LANG_JAPANESE: strcat( nameBuf, "/homeBtn.arc" ); break; case SC_LANG_ENGLISH: strcat( nameBuf, "/homeBtn_ENG.arc" ); break; case SC_LANG_GERMAN: strcat( nameBuf, "/homeBtn_GER.arc" ); break; case SC_LANG_FRENCH: strcat( nameBuf, "/homeBtn_FRA.arc" ); break; case SC_LANG_SPANISH: strcat( nameBuf, "/homeBtn_SPA.arc" ); break; case SC_LANG_ITALIAN: strcat( nameBuf, "/homeBtn_ITA.arc" ); break; case SC_LANG_DUTCH: strcat( nameBuf, "/homeBtn_NED.arc" ); break; default: pHbmInfo->region=SC_LANG_JAPANESE; strcat( nameBuf, "/homeBtn.arc" ); break; } pHbmInfo->layoutBuf = ReadDvdFile( nameBuf, NULL ); strcpy( nameBuf, dirName ); strcat( nameBuf, "/SpeakerSe.arc" ); pHbmInfo->spkSeBuf = ReadDvdFile( nameBuf, NULL ); strcpy( nameBuf, dirName ); #ifdef HBM_NO_SAVE strcat( nameBuf, "/home_nosave.csv" ); #else strcat( nameBuf, "/home.csv" ); #endif pHbmInfo->msgBuf = ReadDvdFile( nameBuf, NULL ); strcpy( nameBuf, dirName ); strcat( nameBuf, "/config.txt" ); pHbmInfo->configBuf = ReadDvdFile( nameBuf, &pHbmInfo->configBufSize ); pHbmInfo->sound_callback = g_callback; pHbmInfo->backFlag = OFF; pHbmInfo->cursor = 0; pHbmInfo->adjust.x = 832.f / 608.f; pHbmInfo->adjust.y = 1.0f; pHbmInfo->frameDelta = 1.0f; } /* Change the adjust value depending on the display mode */ static void SetAdjustValue( HBMDataInfo* pHbmInfo, int wideflag ) { int tvMode; if( !wideflag ) { /* 4:3 */ pHbmInfo->adjust.x = 1.0f; pHbmInfo->adjust.y = 1.0f; } else { /* 16:9 */ pHbmInfo->adjust.x = 832.f / 608.f; pHbmInfo->adjust.y = 1.0f; } /* NTSC or PAL ? */ switch (VIGetTvFormat()) { case VI_NTSC: tvMode = 0; break; case VI_PAL: tvMode = 1; break; default: OSHalt("DEMOInit: invalid TV format\n"); break; } /* setting frameDelta */ if(tvMode == 0) { // NTSC: 60Hz pHbmInfo->frameDelta = 1.0f; } else { // PAL: 50Hz pHbmInfo->frameDelta = 1.2f; } } /* Initialize sound */ static void InitSound() { #ifdef BTN_NUM_3 char dirName[] = "hbm/HomeButton3"; #else char dirName[] = "hbm/HomeButton2"; #endif char nameBuf[32]; /* Create file name */ strcpy( nameBuf, dirName ); strcat( nameBuf, "/HomeButtonSe.arc" ); /* Load sound data for AX use */ sound_data = ReadDvdFile( nameBuf, NULL ); /* Allocates a buffer for sound */ sound_buf = allocMem( HBM_MEM_SIZE_DVD ); HBMCreateSound( sound_data, sound_buf, HBM_MEM_SIZE_SOUND ); } /* Cursor position initialization */ static void InitControllerData( HBMControllerData* pConData ) { int i; for( i = 0; i < WPAD_MAX_CONTROLLERS; i++ ) { pConData->wiiCon[i].pos.x = 0.f; pConData->wiiCon[i].pos.y = 0.f; pConData->wiiCon[i].use_devtype = WPAD_DEV_CORE; } } /* Absolute value clamp */ static f32 AbsClamp( f32 val, f32 max ) { return ( ( val > max ) ? max : ( val < -max ) ? -max : val ); } /* Cursor movement processing for analog stick */ static int calcAnalogCursorPos( f32 stickX, f32 stickY, Vec2* pos ) { f32 x,y; x = ( stickX / scStickMoveCoe ); y = ( stickY / scStickMoveCoe ); x = AbsClamp( x, 1.0f ); y = AbsClamp( y, 1.0f ); if( x == 0.0f && y == 0.0f ) return FALSE; pos->x = AbsClamp( pos->x + x, 1.0f ); pos->y = AbsClamp( pos->y - y, 1.0f ); return TRUE; } /* Cursor movement processing when using +Control key */ static int calcDigitalCursorPos( u32 button, Vec2* pos ) { const float spd =1.0f / scStickMoveCoe; const float spd2= spd * 0.7071f; button&=KPAD_CL_BUTTON_UP|KPAD_CL_BUTTON_LEFT|KPAD_CL_BUTTON_DOWN|KPAD_CL_BUTTON_RIGHT; switch (button) { case KPAD_CL_BUTTON_UP: pos->y-=spd; break; case KPAD_CL_BUTTON_LEFT: pos->x-=spd; break; case KPAD_CL_BUTTON_DOWN: pos->y+=spd; break; case KPAD_CL_BUTTON_RIGHT: pos->x+=spd; break; case KPAD_CL_BUTTON_UP |KPAD_CL_BUTTON_LEFT: pos->y-=spd2; pos->x-=spd2; break; case KPAD_CL_BUTTON_UP |KPAD_CL_BUTTON_RIGHT: pos->y-=spd2; pos->x+=spd2; break; case KPAD_CL_BUTTON_DOWN|KPAD_CL_BUTTON_LEFT: pos->y+=spd2; pos->x-=spd2; break; case KPAD_CL_BUTTON_DOWN|KPAD_CL_BUTTON_RIGHT: pos->y+=spd2; pos->x+=spd2; break; default: return FALSE; } pos->x = AbsClamp( pos->x, 1.0f ); pos->y = AbsClamp( pos->y, 1.0f ); return TRUE; } __declspec(export) void InitHomebutton(void) { /* Return if this is the Home Menu, or if icon has already appeared */ if( homebutton ) return; InitControllerData( &conData ); InitHomeButtonInfo( &hbmInfo ); /* Memory allocation settings */ hbmInfo.mem = allocMem( HBM_MEM_SIZE ); hbmInfo.memSize = HBM_MEM_SIZE; hbmInfo.pAllocator = NULL; hbmInfo.messageFlag = 0; /* Set the adjust value depending on the screen mode */ SetAdjustValue( &hbmInfo, g_drawModeFlag ); /* No culling */ GXSetCullMode( GX_CULL_NONE ); /* HBM initialization */ HBMCreate( &hbmInfo ); HBMInit(); HBMSetAdjustFlag( TRUE ); /* Load sound */ InitSound(); /* Set up callback functions */ OldResetCallback = OSSetResetCallback(ResetCallback); OldPowerCallback = OSSetPowerCallback(PowerCallback); reset_called = FALSE; power_called = FALSE; /* Flag setting */ homebutton = ON; } __declspec(export) void EndHomebutton(void) { /* Release various and sundry items */ HBMDelete(); HBMDeleteSound(); freeMem( sound_buf ); freeMem( sound_data ); freeMem( hbmInfo.mem ); freeMem( hbmInfo.layoutBuf ); freeMem( hbmInfo.spkSeBuf ); freeMem( hbmInfo.msgBuf ); freeMem( hbmInfo.configBuf ); /* Set up callback functions */ OSSetResetCallback(OldResetCallback); OSSetPowerCallback(OldPowerCallback); /* Flag setting */ homebutton = OFF; } __declspec(export) void getCursorPos(int no, Vec2 *result) { result->x = conData.wiiCon[no].pos.x; result->y = conData.wiiCon[no].pos.y; } __declspec(export) void setCursorPos(int no, Vec2 result) { conData.wiiCon[no].pos.x = result.x; conData.wiiCon[no].pos.y = result.y; } /*---------------------------------------------------------------------------* Name: HomebuttonMain Description: This is an RSO module test function. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ __declspec(export) int HomebuttonMain(void) { s32 wpad_result[WPAD_MAX_CONTROLLERS]; u32 pad_type[WPAD_MAX_CONTROLLERS]; s32 kpad_read[WPAD_MAX_CONTROLLERS]; int input_classic; int i; if( homebutton ) { HBMSetAdjustFlag( g_drawModeFlag ); /* Wii controllers */ for( i = 0; i < WPAD_MAX_CONTROLLERS; i++ ) { wpad_result[i] = WPADProbe( i, &pad_type[i] ); conData.wiiCon[i].use_devtype = pad_type[i]; kpad_read[i] = KPADRead( i, &sKpads[i][0], KPAD_MAX_READ_BUFS ); switch( wpad_result[i] ) { /* In the following error states, the value gotten by KPADRead is applied as-is. */ case WPAD_ERR_BUSY: case WPAD_ERR_TRANSFER: case WPAD_ERR_INVALID: case WPAD_ERR_CORRUPTED: case WPAD_ERR_NONE: conData.wiiCon[i].kpad = &sKpads[i][0]; conData.wiiCon[i].kpad->horizon.x = sKpads[i][0].horizon.x; conData.wiiCon[i].kpad->horizon.y = sKpads[i][0].horizon.y; { /* According to guidelines, if there is input from a Classic Controller, that input is prioritized and inherits DPD coordinates. Specify the DPD absolute coordinates when there is no Classic Controller input. */ input_classic = calcDigitalCursorPos( conData.wiiCon[i].kpad->ex_status.cl.hold, &conData.wiiCon[i].pos ); input_classic = input_classic | calcAnalogCursorPos( conData.wiiCon[i].kpad->ex_status.cl.lstick.x, conData.wiiCon[i].kpad->ex_status.cl.lstick.y, &conData.wiiCon[i].pos ); if( !input_classic && conData.wiiCon[i].kpad->dpd_valid_fg > 0) { conData.wiiCon[i].pos.x = conData.wiiCon[i].kpad->pos.x; conData.wiiCon[i].pos.y = conData.wiiCon[i].kpad->pos.y; } } break; /* Apply NULL in the following error states. */ case WPAD_ERR_NO_CONTROLLER: default: conData.wiiCon[i].kpad = NULL; break; } } { /* Update the HOME Menu */ if( HBMCalc( &conData ) >= HBM_SELECT_HOMEBTN ) { /* The number of the decided-upon button is returned */ OSReport("Select Btn:%d\n", HBMGetSelectBtnNum()); OSReport("Reassigned:%d\n", HBMIsReassignedControllers()); /* Process executed when returning from the HOME Menu */ switch( HBMGetSelectBtnNum() ) { case HBM_SELECT_HOMEBTN: break; /* Move to the Wii Menu */ case HBM_SELECT_BTN1: OSReport( "Return to WiiMenu.\n" ); OSReturnToMenu(); break; /* Reset */ case HBM_SELECT_BTN2: OSReport( "Reset.\n" ); OSRestart( 0 ); break; case 3: break; default: break; } homebutton = OFF; EndHomebutton(); /* Notification that the Home Menu has completed */ return HOMEBUTTON_END; } /* Update SE (sound effect) */ HBMUpdateSound(); } DEMOBeforeRender(); /* Set GX configuration */ InitGX(); /* Render the HOME Menu */ HBMDraw(); DEMODoneRender(); /* Process executed when the RESET or Power Button is pressed */ if(reset_called) { HBMStartBlackOut(); reset_called = FALSE; } if(power_called) { OSReturnToMenu(); } return HOMEBUTTON_ALIVE; } return HOMEBUTTON_NOERROR; }