1 /*---------------------------------------------------------------------------*
2 Project: rsodemo
3 File: rsomodule.c
4
5 Copyright 2006-2009 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12 *---------------------------------------------------------------------------*/
13
14 #pragma force_active on
15 // Set use_lmw_stmw to on, for the time being.
16 #pragma use_lmw_stmw on
17
18 #pragma section code_type ".text" data_mode=far_abs code_mode=far_abs
19 #pragma section RX ".init" ".init" data_mode=far_abs code_mode=far_abs
20
21 #include <revolution.h>
22
23 #include <Revolution.h>
24 #include <revolution/kpad.h>
25 #include <revolution/sc.h>
26 #include <demo.h>
27 #include <string.h>
28 #include <math.h>
29
30 #include "revolution/hbm.h"
31
32 /* define for changing the number of buttons */
33 /* #define BTN_NUM_3 */
34
35 /* Save confirmation on/off */
36 /* #define HBM_NO_SAVE */
37
38 #pragma section code_type ".text" data_mode=far_abs code_mode=pc_rel
39 #pragma section RX ".init" ".init" data_mode=far_abs code_mode=pc_rel
40
41 #include "rsomodule.h"
42
43 #ifdef __cplusplus
44 extern "C" {
45 #endif
46
47 typedef void (*voidfunctionptr) (void); /* ptr to function returning void */
48 __declspec(section ".init") extern voidfunctionptr _ctors[];
49 __declspec(section ".init") extern voidfunctionptr _dtors[];
50
51 enum
52 {
53 OFF = 0,
54 ON
55 };
56
57
58 // Wide?
59 int g_drawModeFlag = OFF;
60 // Allocator
61 MEMAllocator* g_alloc;
62 // Default callback function
63 static int SoundCallback( int evt, int arg );
64 // Callback
65 HBMSoundCallback g_callback = SoundCallback;
66
67 int homebutton = OFF;
68
69 void _prolog(void);
70 void _epilog(void);
71 void _unresolved(void);
72
73 #ifdef __cplusplus
74 }
75 #endif
76
77 static const f32 scStickMoveCoe = 2048.0f/72.0f; /* Distance-moved coefficient of the analog stick */
78 static KPADStatus sKpads[ WPAD_MAX_CONTROLLERS ][ KPAD_MAX_READ_BUFS ];
79 static KPADStatus sKpadToHBM[ WPAD_MAX_CONTROLLERS ];
80
81 HBMDataInfo hbmInfo;
82 HBMControllerData conData;
83
84 // Reset/Power Callback
85 static void ResetCallback();
86 static void PowerCallback();
87 int reset_called = FALSE;
88 int power_called = FALSE;
89 OSResetCallback OldResetCallback;
90 OSPowerCallback OldPowerCallback;
91
92 // Sound buffer for HBM
93 void *sound_buf;
94 /* Sound data for AX use */
95 u8* sound_data;
96
allocMem(u32 size)97 static void* allocMem( u32 size )
98 {
99 return MEMAllocFromAllocator( g_alloc, size );
100 }
101
freeMem(void * ptr)102 static u8 freeMem( void* ptr )
103 {
104 MEMFreeToAllocator( g_alloc, ptr );
105 return 1;
106 }
107
108 // "Wide flag" setting function
109 __declspec(export) void
setWideMode(int mode)110 setWideMode(int mode)
111 {
112 g_drawModeFlag = mode;
113 }
114
115
116 // Allocator setting function
117 __declspec(export) void
setAllocator(MEMAllocator * allocator)118 setAllocator(MEMAllocator* allocator)
119 {
120 g_alloc = allocator;
121 }
122
123 // Callback setting function
124 __declspec(export) void
setSoundCallback(HBMSoundCallback callback)125 setSoundCallback(HBMSoundCallback callback)
126 {
127 g_callback = callback;
128 }
129
130
ResetCallback()131 static void ResetCallback()
132 {
133 reset_called = TRUE;
134 }
135
PowerCallback()136 static void PowerCallback()
137 {
138 power_called = TRUE;
139 }
140
141 /* Event/sound callback function */
SoundCallback(int evt,int arg)142 static int SoundCallback( int evt, int arg )
143 {
144 OSReport( "SoundCallback: %d, %d\n", evt, arg );
145 return HBMSEV_RET_NONE;
146 }
147
148 /* Load file */
ReadDvdFile(const char * fileName,u32 * fileSize)149 static void* ReadDvdFile(
150 const char* fileName,
151 u32* fileSize
152 )
153 {
154 u32 fileLen, fileLenUp32;
155 void* readBuf;
156 s32 readBytes;
157
158 DVDFileInfo fileInfo;
159 if (! DVDOpen(fileName, &fileInfo))
160 {
161 return NULL;
162 }
163
164 fileLen = DVDGetLength(&fileInfo);
165 if( (fileLen % 32) != 0 )
166 {
167 fileLenUp32 = fileLen + (32 - (fileLen % 32));
168 }
169 else
170 {
171 fileLenUp32 = fileLen;
172 }
173 readBuf = allocMem(fileLenUp32);
174 readBytes = DVDRead(&fileInfo, readBuf, (s32)(fileLenUp32), 0);
175 ASSERT(readBytes > 0);
176 if( fileSize )
177 *fileSize = fileLen;
178 DVDClose(&fileInfo);
179
180 return readBuf;
181 }
182
183
184 /*---------------------------------------------------------------------------*
185 Name: _prolog
186
187 Description: Pre-processes (initializes) an RSO module.
188
189 Arguments: None.
190
191 Returns: None.
192 *---------------------------------------------------------------------------*/
193 __declspec(export) void
_prolog(void)194 _prolog(void)
195 {
196 voidfunctionptr *constructor;
197
198 /*
199 * call static initializers
200 */
201 //
202
203
204 for (constructor = _ctors; *constructor; constructor++) {
205 (*constructor)();
206 }
207 }
208
209
210 /*---------------------------------------------------------------------------*
211 Name: _epilog
212
213 Description: Post-processes an RSO module.
214
215 Arguments: None.
216
217 Returns: None.
218 *---------------------------------------------------------------------------*/
219 __declspec(export) void
_epilog(void)220 _epilog(void)
221 {
222 voidfunctionptr *destructor;
223
224 /*
225 * call destructors
226 */
227 for (destructor = _dtors; *destructor; destructor++) {
228 (*destructor)();
229 }
230 }
231
232
233 /*---------------------------------------------------------------------------*
234 Name: _unresolved
235
236 Description: Called when the link to a function that is referenced from an RSO module has not been resolved.
237
238
239 Arguments: None.
240
241 Returns: None.
242 *---------------------------------------------------------------------------*/
243 __declspec(export) void
_unresolved(void)244 _unresolved(void)
245 {
246 u32 i;
247 u32* p;
248
249 OSReport("\nError: A called an unlinked function.\n");
250 OSReport("Address: Back Chain LR Save\n");
251 for (i = 0, p = (u32*) OSGetStackPointer(); // get current sp
252 p && (u32) p != 0xffffffff && i++ < 16;
253 p = (u32*) *p) // Get caller sp
254 {
255 OSReport("0x%08x: 0x%08x 0x%08x\n", p, p[0], p[1]);
256 }
257 OSReport("\n");
258 }
259
260 /* Initialize GX */
InitGX()261 static void InitGX()
262 {
263 GXClearVtxDesc();
264
265 GXSetVtxAttrFmt(GX_VTXFMT4, GX_VA_POS, GX_POS_XY, GX_F32, 0);
266 GXSetVtxAttrFmt(GX_VTXFMT4, GX_VA_CLR0, GX_CLR_RGB, GX_RGB8, 0);
267 GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
268 GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
269
270 GXSetNumChans(1);
271 GXSetNumTexGens(0);
272 GXSetNumTevStages(1);
273 GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
274 GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
275
276 GXSetBlendMode(GX_BM_NONE, GX_BL_ZERO, GX_BL_ZERO, GX_LO_CLEAR);
277 GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
278 GXSetCurrentMtx( GX_PNMTX1 );
279 }
280
InitHomeButtonInfo(HBMDataInfo * pHbmInfo)281 static void InitHomeButtonInfo( HBMDataInfo* pHbmInfo )
282 {
283 #ifdef BTN_NUM_3
284 char dirName[] = "hbm/HomeButton3";
285 #else
286 char dirName[] = "hbm/HomeButton2";
287 #endif
288
289 char nameBuf[32];
290
291 /* Create file name */
292 strcpy( nameBuf, dirName );
293 /* Switching as necessary according to the language setting */
294 pHbmInfo->region=SCGetLanguage();
295 switch (pHbmInfo->region)
296 {
297 case SC_LANG_JAPANESE:
298 strcat( nameBuf, "/homeBtn.arc" );
299 break;
300 case SC_LANG_ENGLISH:
301 strcat( nameBuf, "/homeBtn_ENG.arc" );
302 break;
303 case SC_LANG_GERMAN:
304 strcat( nameBuf, "/homeBtn_GER.arc" );
305 break;
306 case SC_LANG_FRENCH:
307 strcat( nameBuf, "/homeBtn_FRA.arc" );
308 break;
309 case SC_LANG_SPANISH:
310 strcat( nameBuf, "/homeBtn_SPA.arc" );
311 break;
312 case SC_LANG_ITALIAN:
313 strcat( nameBuf, "/homeBtn_ITA.arc" );
314 break;
315 case SC_LANG_DUTCH:
316 strcat( nameBuf, "/homeBtn_NED.arc" );
317 break;
318 case SC_LANG_SIMP_CHINESE:
319 strcat( nameBuf, "/homeBtn_CHN.arc" );
320 break;
321 case SC_LANG_KOREAN:
322 strcat( nameBuf, "/homeBtn_KOR.arc" );
323 break;
324 default:
325 pHbmInfo->region=SC_LANG_JAPANESE;
326 strcat( nameBuf, "/homeBtn.arc" );
327 break;
328 }
329 pHbmInfo->layoutBuf = ReadDvdFile( nameBuf, NULL );
330
331 strcpy( nameBuf, dirName );
332 strcat( nameBuf, "/SpeakerSe.arc" );
333 pHbmInfo->spkSeBuf = ReadDvdFile( nameBuf, NULL );
334
335 strcpy( nameBuf, dirName );
336 #ifdef HBM_NO_SAVE
337 strcat( nameBuf, "/home_nosave.csv" );
338 #else
339 strcat( nameBuf, "/home.csv" );
340 #endif
341 pHbmInfo->msgBuf = ReadDvdFile( nameBuf, NULL );
342
343 strcpy( nameBuf, dirName );
344 strcat( nameBuf, "/config.txt" );
345 pHbmInfo->configBuf = ReadDvdFile( nameBuf, &pHbmInfo->configBufSize );
346 pHbmInfo->sound_callback = g_callback;
347 pHbmInfo->backFlag = OFF;
348 pHbmInfo->cursor = 0;
349 pHbmInfo->adjust.x = 1.0f;
350 pHbmInfo->adjust.y = 1.0f;
351 pHbmInfo->frameDelta = 1.0f;
352 pHbmInfo->messageFlag = HBMMSG_NOSAVE_DEFAULT;
353 }
354
355 /* Change the adjust value depending on the display mode */
SetAdjustValue(HBMDataInfo * pHbmInfo,int wideflag)356 static void SetAdjustValue( HBMDataInfo* pHbmInfo, int wideflag )
357 {
358 int tvMode;
359
360 if( !wideflag )
361 {
362 /* 4:3 */
363 pHbmInfo->adjust.x = 1.0f;
364 pHbmInfo->adjust.y = 1.0f;
365 }
366 else
367 {
368 /* 16:9 */
369 pHbmInfo->adjust.x = 832.f / 608.f;
370 pHbmInfo->adjust.y = 1.0f;
371 }
372
373 /* NTSC or PAL ? */
374 switch (VIGetTvFormat())
375 {
376 case VI_NTSC:
377 tvMode = 0;
378 break;
379 case VI_PAL:
380 tvMode = 1;
381 break;
382 default:
383 OSHalt("DEMOInit: invalid TV format\n");
384 break;
385 }
386
387 /* setting frameDelta */
388 if(tvMode == 0)
389 {
390 // NTSC: 60Hz
391 pHbmInfo->frameDelta = 1.0f;
392 }
393 else
394 {
395 // PAL: 50Hz
396 pHbmInfo->frameDelta = 1.2f;
397 }
398 }
399
400 /* Initialize sound */
InitSound()401 static void InitSound()
402 {
403 #ifdef BTN_NUM_3
404 char dirName[] = "hbm/HomeButton3";
405 #else
406 char dirName[] = "hbm/HomeButton2";
407 #endif
408
409 char nameBuf[32];
410
411
412 /* Create file name */
413 strcpy( nameBuf, dirName );
414 strcat( nameBuf, "/HomeButtonSe.arc" );
415
416 /* Load sound data for AX use */
417 sound_data = ReadDvdFile( nameBuf, NULL );
418
419 /* Allocates a buffer for sound */
420 sound_buf = allocMem( HBM_MEM_SIZE_DVD );
421
422 HBMCreateSound( sound_data, sound_buf, HBM_MEM_SIZE_SOUND );
423 }
424
425 /* Cursor position initialization */
InitControllerData(HBMControllerData * pConData)426 static void InitControllerData( HBMControllerData* pConData )
427 {
428 int i;
429 for( i = 0; i < WPAD_MAX_CONTROLLERS; i++ )
430 {
431 pConData->wiiCon[i].pos.x = 0.f;
432 pConData->wiiCon[i].pos.y = 0.f;
433 pConData->wiiCon[i].use_devtype = WPAD_DEV_CORE;
434 }
435 memset(&sKpadToHBM[0], 0, sizeof(KPADStatus)*WPAD_MAX_CONTROLLERS);
436 }
437
438 /* Absolute value clamp */
AbsClamp(f32 val,f32 max)439 static f32 AbsClamp( f32 val, f32 max )
440 {
441 return ( ( val > max ) ? max : ( val < -max ) ? -max : val );
442 }
443
444 /* Cursor movement processing for analog stick */
calcAnalogCursorPos(f32 stickX,f32 stickY,Vec2 * pos)445 static int calcAnalogCursorPos( f32 stickX, f32 stickY, Vec2* pos )
446 {
447 f32 x,y;
448 x = ( stickX / scStickMoveCoe );
449 y = ( stickY / scStickMoveCoe );
450 x = AbsClamp( x, 1.0f );
451 y = AbsClamp( y, 1.0f );
452 if( x == 0.0f && y == 0.0f ) return FALSE;
453 pos->x = AbsClamp( pos->x + x, 1.0f );
454 pos->y = AbsClamp( pos->y - y, 1.0f );
455 return TRUE;
456 }
457
458 /* Cursor movement processing when using +Control key */
calcDigitalCursorPos(u32 button,Vec2 * pos)459 static int calcDigitalCursorPos( u32 button, Vec2* pos )
460 {
461 const float spd =1.0f / scStickMoveCoe;
462 const float spd2= spd * 0.7071f;
463
464 button&=KPAD_CL_BUTTON_UP|KPAD_CL_BUTTON_LEFT|KPAD_CL_BUTTON_DOWN|KPAD_CL_BUTTON_RIGHT;
465 switch (button)
466 {
467 case KPAD_CL_BUTTON_UP: pos->y-=spd; break;
468 case KPAD_CL_BUTTON_LEFT: pos->x-=spd; break;
469 case KPAD_CL_BUTTON_DOWN: pos->y+=spd; break;
470 case KPAD_CL_BUTTON_RIGHT: pos->x+=spd; break;
471 case KPAD_CL_BUTTON_UP |KPAD_CL_BUTTON_LEFT: pos->y-=spd2; pos->x-=spd2; break;
472 case KPAD_CL_BUTTON_UP |KPAD_CL_BUTTON_RIGHT: pos->y-=spd2; pos->x+=spd2; break;
473 case KPAD_CL_BUTTON_DOWN|KPAD_CL_BUTTON_LEFT: pos->y+=spd2; pos->x-=spd2; break;
474 case KPAD_CL_BUTTON_DOWN|KPAD_CL_BUTTON_RIGHT: pos->y+=spd2; pos->x+=spd2; break;
475 default: return FALSE;
476 }
477 pos->x = AbsClamp( pos->x, 1.0f );
478 pos->y = AbsClamp( pos->y, 1.0f );
479 return TRUE;
480 }
481
482 __declspec(export) void
InitHomebutton(void)483 InitHomebutton(void)
484 {
485 /* Return if this is the Home Menu, or if icon has already appeared */
486 if( homebutton ) return;
487
488 InitControllerData( &conData );
489 InitHomeButtonInfo( &hbmInfo );
490
491 /* Memory allocation settings */
492 hbmInfo.mem = allocMem( HBM_MEM_SIZE );
493 hbmInfo.memSize = HBM_MEM_SIZE;
494 hbmInfo.pAllocator = NULL;
495
496 /* Set the adjust value depending on the screen mode */
497 SetAdjustValue( &hbmInfo, g_drawModeFlag );
498
499 /* No culling */
500 GXSetCullMode( GX_CULL_NONE );
501
502 /* HBM initialization */
503 HBMCreate( &hbmInfo );
504 HBMInit();
505 HBMSetAdjustFlag( TRUE );
506
507 /* Load sound */
508 InitSound();
509
510 /* Set up callback functions */
511 OldResetCallback = OSSetResetCallback(ResetCallback);
512 OldPowerCallback = OSSetPowerCallback(PowerCallback);
513 reset_called = FALSE;
514 power_called = FALSE;
515
516 /* Flag setting */
517 homebutton = ON;
518 }
519
520 __declspec(export) void
EndHomebutton(void)521 EndHomebutton(void)
522 {
523 /* Release various and sundry items */
524 HBMDelete();
525 HBMDeleteSound();
526
527 freeMem( sound_buf );
528 freeMem( sound_data );
529 freeMem( hbmInfo.mem );
530 freeMem( hbmInfo.layoutBuf );
531 freeMem( hbmInfo.spkSeBuf );
532 freeMem( hbmInfo.msgBuf );
533 freeMem( hbmInfo.configBuf );
534
535 /* Set up callback functions */
536 OSSetResetCallback(OldResetCallback);
537 OSSetPowerCallback(OldPowerCallback);
538
539 /* Flag setting */
540 homebutton = OFF;
541 }
542
543 __declspec(export) void
getCursorPos(int no,Vec2 * result)544 getCursorPos(int no, Vec2 *result)
545 {
546 result->x = conData.wiiCon[no].pos.x;
547 result->y = conData.wiiCon[no].pos.y;
548 }
549
550 __declspec(export) void
setCursorPos(int no,Vec2 result)551 setCursorPos(int no, Vec2 result)
552 {
553 conData.wiiCon[no].pos.x = result.x;
554 conData.wiiCon[no].pos.y = result.y;
555 }
556
557
558 /*---------------------------------------------------------------------------*
559 Name: HomebuttonMain
560
561 Description: This is an RSO module test function.
562
563 Arguments: None.
564
565 Returns: None.
566 *---------------------------------------------------------------------------*/
567
568 __declspec(export) int
HomebuttonMain(void)569 HomebuttonMain(void)
570 {
571 s32 wpad_result[WPAD_MAX_CONTROLLERS];
572 u32 pad_type[WPAD_MAX_CONTROLLERS];
573 s32 kpad_read[WPAD_MAX_CONTROLLERS];
574 int input_classic;
575 int i;
576
577 if( homebutton )
578 {
579 HBMSetAdjustFlag( g_drawModeFlag );
580
581 /* Wii controllers */
582 for( i = 0; i < WPAD_MAX_CONTROLLERS; i++ )
583 {
584 wpad_result[i] = WPADProbe( i, &pad_type[i] );
585 conData.wiiCon[i].use_devtype = pad_type[i];
586 kpad_read[i] =
587 KPADRead( i, &sKpads[i][0], KPAD_MAX_READ_BUFS );
588 if( kpad_read[i] )
589 memcpy( &sKpadToHBM[i], &sKpads[i][0], sizeof(KPADStatus) );
590
591 switch( wpad_result[i] )
592 {
593 /* In the following error states, the value gotten by KPADRead is applied as-is. */
594 case WPAD_ERR_BUSY:
595 case WPAD_ERR_TRANSFER:
596 case WPAD_ERR_INVALID:
597 case WPAD_ERR_CORRUPTED:
598 case WPAD_ERR_NONE:
599 conData.wiiCon[i].kpad = &sKpadToHBM[i];
600 {
601 /*
602 According to guidelines, if there is input from a Classic Controller, that input is prioritized and inherits DPD coordinates.
603
604 Specify the DPD absolute coordinates when there is no Classic Controller input.
605 */
606
607 input_classic = calcDigitalCursorPos(
608 conData.wiiCon[i].kpad->ex_status.cl.hold,
609 &conData.wiiCon[i].pos );
610
611
612 input_classic = input_classic | calcAnalogCursorPos(
613 conData.wiiCon[i].kpad->ex_status.cl.lstick.x,
614 conData.wiiCon[i].kpad->ex_status.cl.lstick.y,
615 &conData.wiiCon[i].pos );
616
617 if( !input_classic && conData.wiiCon[i].kpad->dpd_valid_fg > 0)
618 {
619 conData.wiiCon[i].pos.x = conData.wiiCon[i].kpad->pos.x;
620 conData.wiiCon[i].pos.y = conData.wiiCon[i].kpad->pos.y;
621 }
622 }
623 break;
624 /* Apply NULL in the following error states. */
625 case WPAD_ERR_NO_CONTROLLER:
626 default:
627 conData.wiiCon[i].kpad = NULL;
628 memset(&sKpadToHBM[i], 0, sizeof(KPADStatus));
629 break;
630 }
631 }
632
633 {
634
635 /* Update the HOME Menu */
636 if( HBMCalc( &conData ) >= HBM_SELECT_HOMEBTN )
637 {
638 /* The number of the decided-upon button is returned */
639 OSReport("Select Btn:%d\n", HBMGetSelectBtnNum());
640 OSReport("Reassigned:%d\n", HBMIsReassignedControllers());
641
642
643 /* Process executed when returning from the HOME Menu */
644 switch( HBMGetSelectBtnNum() )
645 {
646 case HBM_SELECT_HOMEBTN:
647 break;
648 /* Move to the Wii Menu */
649 case HBM_SELECT_BTN1:
650 OSReport( "Return to WiiMenu.\n" );
651 OSReturnToMenu();
652 break;
653 /* Reset */
654 case HBM_SELECT_BTN2:
655 OSReport( "Reset.\n" );
656 OSRestart( 0 );
657 break;
658 case 3:
659
660 break;
661 default:
662
663 break;
664 }
665 homebutton = OFF;
666 EndHomebutton();
667 /* Notification that the Home Menu has completed */
668 return HOMEBUTTON_END;
669 }
670 /* Update SE (sound effect) */
671 HBMUpdateSound();
672 }
673 DEMOBeforeRender();
674
675 /* Set GX configuration */
676 InitGX();
677 /* Render the HOME Menu */
678 HBMDraw();
679
680 DEMODoneRender();
681
682 /* Process executed when the RESET or Power Button is pressed */
683 if(reset_called)
684 {
685 HBMStartBlackOut();
686 reset_called = FALSE;
687 }
688
689 if(power_called)
690 {
691 OSReturnToMenu();
692 }
693
694 return HOMEBUTTON_ALIVE;
695 }
696
697 return HOMEBUTTON_NOERROR;
698 }
699
700
701