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