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