1 /*---------------------------------------------------------------------------*
2 Project: rsodemo
3 File: rsomodule.c
4
5 Copyright 2006-2008 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
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 default:
319 pHbmInfo->region=SC_LANG_JAPANESE;
320 strcat( nameBuf, "/homeBtn.arc" );
321 break;
322 }
323 pHbmInfo->layoutBuf = ReadDvdFile( nameBuf, NULL );
324
325 strcpy( nameBuf, dirName );
326 strcat( nameBuf, "/SpeakerSe.arc" );
327 pHbmInfo->spkSeBuf = ReadDvdFile( nameBuf, NULL );
328
329 strcpy( nameBuf, dirName );
330 #ifdef HBM_NO_SAVE
331 strcat( nameBuf, "/home_nosave.csv" );
332 #else
333 strcat( nameBuf, "/home.csv" );
334 #endif
335 pHbmInfo->msgBuf = ReadDvdFile( nameBuf, NULL );
336
337 strcpy( nameBuf, dirName );
338 strcat( nameBuf, "/config.txt" );
339 pHbmInfo->configBuf = ReadDvdFile( nameBuf, &pHbmInfo->configBufSize );
340 pHbmInfo->sound_callback = g_callback;
341 pHbmInfo->backFlag = OFF;
342 pHbmInfo->cursor = 0;
343 pHbmInfo->adjust.x = 832.f / 608.f;
344 pHbmInfo->adjust.y = 1.0f;
345 pHbmInfo->frameDelta = 1.0f;
346
347
348 }
349
350 /* Change the adjust value depending on the display mode */
SetAdjustValue(HBMDataInfo * pHbmInfo,int wideflag)351 static void SetAdjustValue( HBMDataInfo* pHbmInfo, int wideflag )
352 {
353 int tvMode;
354
355 if( !wideflag )
356 {
357 /* 4:3 */
358 pHbmInfo->adjust.x = 1.0f;
359 pHbmInfo->adjust.y = 1.0f;
360 }
361 else
362 {
363 /* 16:9 */
364 pHbmInfo->adjust.x = 832.f / 608.f;
365 pHbmInfo->adjust.y = 1.0f;
366 }
367
368 /* NTSC or PAL ? */
369 switch (VIGetTvFormat())
370 {
371 case VI_NTSC:
372 tvMode = 0;
373 break;
374 case VI_PAL:
375 tvMode = 1;
376 break;
377 default:
378 OSHalt("DEMOInit: invalid TV format\n");
379 break;
380 }
381
382 /* setting frameDelta */
383 if(tvMode == 0)
384 {
385 // NTSC: 60Hz
386 pHbmInfo->frameDelta = 1.0f;
387 }
388 else
389 {
390 // PAL: 50Hz
391 pHbmInfo->frameDelta = 1.2f;
392 }
393 }
394
395 /* Initialize sound */
InitSound()396 static void InitSound()
397 {
398 #ifdef BTN_NUM_3
399 char dirName[] = "hbm/HomeButton3";
400 #else
401 char dirName[] = "hbm/HomeButton2";
402 #endif
403
404 char nameBuf[32];
405
406
407 /* Create file name */
408 strcpy( nameBuf, dirName );
409 strcat( nameBuf, "/HomeButtonSe.arc" );
410
411 /* Load sound data for AX use */
412 sound_data = ReadDvdFile( nameBuf, NULL );
413
414 /* Allocates a buffer for sound */
415 sound_buf = allocMem( HBM_MEM_SIZE_DVD );
416
417 HBMCreateSound( sound_data, sound_buf, HBM_MEM_SIZE_SOUND );
418 }
419
420 /* Cursor position initialization */
InitControllerData(HBMControllerData * pConData)421 static void InitControllerData( HBMControllerData* pConData )
422 {
423 int i;
424 for( i = 0; i < WPAD_MAX_CONTROLLERS; i++ )
425 {
426 pConData->wiiCon[i].pos.x = 0.f;
427 pConData->wiiCon[i].pos.y = 0.f;
428 pConData->wiiCon[i].use_devtype = WPAD_DEV_CORE;
429 }
430 }
431
432 /* Absolute value clamp */
AbsClamp(f32 val,f32 max)433 static f32 AbsClamp( f32 val, f32 max )
434 {
435 return ( ( val > max ) ? max : ( val < -max ) ? -max : val );
436 }
437
438 /* Cursor movement processing for analog stick */
calcAnalogCursorPos(f32 stickX,f32 stickY,Vec2 * pos)439 static int calcAnalogCursorPos( f32 stickX, f32 stickY, Vec2* pos )
440 {
441 f32 x,y;
442 x = ( stickX / scStickMoveCoe );
443 y = ( stickY / scStickMoveCoe );
444 x = AbsClamp( x, 1.0f );
445 y = AbsClamp( y, 1.0f );
446 if( x == 0.0f && y == 0.0f ) return FALSE;
447 pos->x = AbsClamp( pos->x + x, 1.0f );
448 pos->y = AbsClamp( pos->y - y, 1.0f );
449 return TRUE;
450 }
451
452 /* Cursor movement processing when using +Control key */
calcDigitalCursorPos(u32 button,Vec2 * pos)453 static int calcDigitalCursorPos( u32 button, Vec2* pos )
454 {
455 const float spd =1.0f / scStickMoveCoe;
456 const float spd2= spd * 0.7071f;
457
458 button&=KPAD_CL_BUTTON_UP|KPAD_CL_BUTTON_LEFT|KPAD_CL_BUTTON_DOWN|KPAD_CL_BUTTON_RIGHT;
459 switch (button)
460 {
461 case KPAD_CL_BUTTON_UP: pos->y-=spd; break;
462 case KPAD_CL_BUTTON_LEFT: pos->x-=spd; break;
463 case KPAD_CL_BUTTON_DOWN: pos->y+=spd; break;
464 case KPAD_CL_BUTTON_RIGHT: pos->x+=spd; break;
465 case KPAD_CL_BUTTON_UP |KPAD_CL_BUTTON_LEFT: pos->y-=spd2; pos->x-=spd2; break;
466 case KPAD_CL_BUTTON_UP |KPAD_CL_BUTTON_RIGHT: pos->y-=spd2; pos->x+=spd2; break;
467 case KPAD_CL_BUTTON_DOWN|KPAD_CL_BUTTON_LEFT: pos->y+=spd2; pos->x-=spd2; break;
468 case KPAD_CL_BUTTON_DOWN|KPAD_CL_BUTTON_RIGHT: pos->y+=spd2; pos->x+=spd2; break;
469 default: return FALSE;
470 }
471 pos->x = AbsClamp( pos->x, 1.0f );
472 pos->y = AbsClamp( pos->y, 1.0f );
473 return TRUE;
474 }
475
476 __declspec(export) void
InitHomebutton(void)477 InitHomebutton(void)
478 {
479 /* Return if this is the Home Menu, or if icon has already appeared */
480 if( homebutton ) return;
481
482 InitControllerData( &conData );
483 InitHomeButtonInfo( &hbmInfo );
484
485 /* Memory allocation settings */
486 hbmInfo.mem = allocMem( HBM_MEM_SIZE );
487 hbmInfo.memSize = HBM_MEM_SIZE;
488 hbmInfo.pAllocator = NULL;
489 hbmInfo.messageFlag = 0;
490
491 /* Set the adjust value depending on the screen mode */
492 SetAdjustValue( &hbmInfo, g_drawModeFlag );
493
494 /* No culling */
495 GXSetCullMode( GX_CULL_NONE );
496
497 /* HBM initialization */
498 HBMCreate( &hbmInfo );
499 HBMInit();
500 HBMSetAdjustFlag( TRUE );
501
502 /* Load sound */
503 InitSound();
504
505 /* Set up callback functions */
506 OldResetCallback = OSSetResetCallback(ResetCallback);
507 OldPowerCallback = OSSetPowerCallback(PowerCallback);
508 reset_called = FALSE;
509 power_called = FALSE;
510
511 /* Flag setting */
512 homebutton = ON;
513 }
514
515 __declspec(export) void
EndHomebutton(void)516 EndHomebutton(void)
517 {
518 /* Release various and sundry items */
519 HBMDelete();
520 HBMDeleteSound();
521
522 freeMem( sound_buf );
523 freeMem( sound_data );
524 freeMem( hbmInfo.mem );
525 freeMem( hbmInfo.layoutBuf );
526 freeMem( hbmInfo.spkSeBuf );
527 freeMem( hbmInfo.msgBuf );
528 freeMem( hbmInfo.configBuf );
529
530 /* Set up callback functions */
531 OSSetResetCallback(OldResetCallback);
532 OSSetPowerCallback(OldPowerCallback);
533
534 /* Flag setting */
535 homebutton = OFF;
536 }
537
538 __declspec(export) void
getCursorPos(int no,Vec2 * result)539 getCursorPos(int no, Vec2 *result)
540 {
541 result->x = conData.wiiCon[no].pos.x;
542 result->y = conData.wiiCon[no].pos.y;
543 }
544
545 __declspec(export) void
setCursorPos(int no,Vec2 result)546 setCursorPos(int no, Vec2 result)
547 {
548 conData.wiiCon[no].pos.x = result.x;
549 conData.wiiCon[no].pos.y = result.y;
550 }
551
552
553 /*---------------------------------------------------------------------------*
554 Name: HomebuttonMain
555
556 Description: This is an RSO module test function.
557
558 Arguments: None.
559
560 Returns: None.
561 *---------------------------------------------------------------------------*/
562
563 __declspec(export) int
HomebuttonMain(void)564 HomebuttonMain(void)
565 {
566 s32 wpad_result[WPAD_MAX_CONTROLLERS];
567 u32 pad_type[WPAD_MAX_CONTROLLERS];
568 s32 kpad_read[WPAD_MAX_CONTROLLERS];
569 int input_classic;
570 int i;
571
572 if( homebutton )
573 {
574 HBMSetAdjustFlag( g_drawModeFlag );
575
576 /* Wii controllers */
577 for( i = 0; i < WPAD_MAX_CONTROLLERS; i++ )
578 {
579 wpad_result[i] = WPADProbe( i, &pad_type[i] );
580 conData.wiiCon[i].use_devtype = pad_type[i];
581 kpad_read[i] =
582 KPADRead( i, &sKpads[i][0], KPAD_MAX_READ_BUFS );
583
584 switch( wpad_result[i] )
585 {
586 /* In the following error states, the value gotten by KPADRead is applied as-is. */
587 case WPAD_ERR_BUSY:
588 case WPAD_ERR_TRANSFER:
589 case WPAD_ERR_INVALID:
590 case WPAD_ERR_CORRUPTED:
591 case WPAD_ERR_NONE:
592 conData.wiiCon[i].kpad = &sKpads[i][0];
593 conData.wiiCon[i].kpad->horizon.x = sKpads[i][0].horizon.x;
594 conData.wiiCon[i].kpad->horizon.y = sKpads[i][0].horizon.y;
595 {
596 /*
597 According to guidelines, if there is input from a Classic Controller, that input is prioritized and inherits DPD coordinates.
598
599 Specify the DPD absolute coordinates when there is no Classic Controller input.
600 */
601
602 input_classic = calcDigitalCursorPos(
603 conData.wiiCon[i].kpad->ex_status.cl.hold,
604 &conData.wiiCon[i].pos );
605
606
607 input_classic = input_classic | calcAnalogCursorPos(
608 conData.wiiCon[i].kpad->ex_status.cl.lstick.x,
609 conData.wiiCon[i].kpad->ex_status.cl.lstick.y,
610 &conData.wiiCon[i].pos );
611
612 if( !input_classic && conData.wiiCon[i].kpad->dpd_valid_fg > 0)
613 {
614 conData.wiiCon[i].pos.x = conData.wiiCon[i].kpad->pos.x;
615 conData.wiiCon[i].pos.y = conData.wiiCon[i].kpad->pos.y;
616 }
617 }
618 break;
619 /* Apply NULL in the following error states. */
620 case WPAD_ERR_NO_CONTROLLER:
621 default:
622 conData.wiiCon[i].kpad = NULL;
623 break;
624 }
625 }
626
627 {
628
629 /* Update the HOME Menu */
630 if( HBMCalc( &conData ) >= HBM_SELECT_HOMEBTN )
631 {
632 /* The number of the decided-upon button is returned */
633 OSReport("Select Btn:%d\n", HBMGetSelectBtnNum());
634 OSReport("Reassigned:%d\n", HBMIsReassignedControllers());
635
636
637 /* Process executed when returning from the HOME Menu */
638 switch( HBMGetSelectBtnNum() )
639 {
640 case HBM_SELECT_HOMEBTN:
641 break;
642 /* Move to the Wii Menu */
643 case HBM_SELECT_BTN1:
644 OSReport( "Return to WiiMenu.\n" );
645 OSReturnToMenu();
646 break;
647 /* Reset */
648 case HBM_SELECT_BTN2:
649 OSReport( "Reset.\n" );
650 OSRestart( 0 );
651 break;
652 case 3:
653
654 break;
655 default:
656
657 break;
658 }
659 homebutton = OFF;
660 EndHomebutton();
661 /* Notification that the Home Menu has completed */
662 return HOMEBUTTON_END;
663 }
664 /* Update SE (sound effect) */
665 HBMUpdateSound();
666 }
667 DEMOBeforeRender();
668
669 /* Set GX configuration */
670 InitGX();
671 /* Render the HOME Menu */
672 HBMDraw();
673
674 DEMODoneRender();
675
676 /* Process executed when the RESET or Power Button is pressed */
677 if(reset_called)
678 {
679 HBMStartBlackOut();
680 reset_called = FALSE;
681 }
682
683 if(power_called)
684 {
685 OSReturnToMenu();
686 }
687
688 return HOMEBUTTON_ALIVE;
689 }
690
691 return HOMEBUTTON_NOERROR;
692 }
693
694
695