1 /*---------------------------------------------------------------------------*
2   Project:  hbm
3   File:     homebutton.cpp
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 /* Use MEMHeap, which is inside DEMOInit */
15 #define DEMO_USE_MEMLIB
16 
17 /* Definitions for changing the number of buttons */
18 /* #define BTN_NUM_3 */
19 
20 /* Save confirmation on/off */
21 /* #define HBM_NO_SAVE */
22 
23 #include <Revolution.h>
24 #include <revolution/kpad.h>
25 #include <revolution/sc.h>
26 
27 #include <demo.h>
28 
29 #include <string.h>
30 #include <math.h>
31 
32 #include <revolution/hbm.h>
33 
34 enum
35 {
36     OFF = 0,
37     ON
38 };
39 
40 enum
41 {
42     eAlphaInIcon = 0,
43     ePauseIcon,
44     eAlphaOutIcon
45 };
46 
47 static const f32 scStickMoveCoe =  2048.0f/72.0f; /* Amount-of-movement coefficient of the analog stick */
48 static KPADStatus sKpads[ WPAD_MAX_CONTROLLERS ][ KPAD_MAX_READ_BUFS ];
49 static KPADStatus sKpadToHBM[ WPAD_MAX_CONTROLLERS ];
50 
51 static TPLPalettePtr sIconTpl;
52 
53 /* Allocate a buffer for sounds */
54 u8* sound_buf;
55 /* Read destination for the sound data from the optical disc */
56 u8* sound_data;
57 
58 // Reset/Power Callback
59 static void ResetCallback();
60 static void PowerCallback();
61 static bool reset_called,power_called;
62 
63 // NTSC / PAL
64 int sTvmode;
65 
66 // Frame buffer size
67 static const u16 sFbWidth = 608;
68 static const u16 sFbHeight = 456;
69 
70 // VI size
71 static const u16 viWidth = 670;
72 static const u16 viWidthWide = 686;
73 static const u16 viWidthWide_Pal = 682;
74 
75 static const u16 viHeight = 456;
76 static const u16 viHeight_Pal = 542;
77 
78 #ifdef  ENABLE_BALANCE_BOARD
79 static u8  workarea[WPAD_BLCINT_WORK_LEN] ATTRIBUTE_ALIGN(32);
80 #endif // ENABLE_BALANCE_BOARD
81 /* RenderMode */
82 static GXRenderModeObj sRMObj[2] =
83 {
84     /* NTSC 4:3 */
85     {
86         VI_TVMODE_NTSC_INT,
87         sFbWidth,
88         sFbHeight,
89         viHeight,
90         (u16)((VI_MAX_WIDTH_NTSC - viWidth)/2),
91         (u16)((VI_MAX_HEIGHT_NTSC - viHeight)/2),
92         viWidth,
93         viHeight,
94         VI_XFBMODE_DF,
95         GX_FALSE,
96         GX_FALSE,
97         6, 6, 6, 6, 6, 6,
98         6, 6, 6, 6, 6, 6,
99         6, 6, 6, 6, 6, 6,
100         6, 6, 6, 6, 6, 6,
101         8, 8,
102         10, 12, 10,
103         8, 8,
104     },
105     /* PAL 4:3 */
106     {
107         VI_TVMODE_PAL_INT,
108         sFbWidth,
109         sFbHeight,
110         viHeight_Pal,
111         (u16)((VI_MAX_WIDTH_PAL - viWidth)/2),
112         (u16)((VI_MAX_HEIGHT_PAL - viHeight_Pal)/2),
113         viWidth,
114         viHeight_Pal,
115         VI_XFBMODE_DF,
116         GX_FALSE,
117         GX_FALSE,
118         6, 6, 6, 6, 6, 6,
119         6, 6, 6, 6, 6, 6,
120         6, 6, 6, 6, 6, 6,
121         6, 6, 6, 6, 6, 6,
122         8, 8,
123         10, 12, 10,
124         8, 8,
125     }
126 };
127 
128 static GXRenderModeObj sRMObjWide[2] =
129 {
130     /* NTSC 16:9 */
131     {
132         VI_TVMODE_NTSC_INT,
133         sFbWidth,
134         sFbHeight,
135         viHeight,
136         (u16)((VI_MAX_WIDTH_NTSC - viWidthWide)/2),
137         (u16)((VI_MAX_HEIGHT_NTSC - viHeight)/2),
138         viWidthWide,
139         viHeight,
140         VI_XFBMODE_DF,
141         GX_FALSE,
142         GX_FALSE,
143         6, 6, 6, 6, 6, 6,
144         6, 6, 6, 6, 6, 6,
145         6, 6, 6, 6, 6, 6,
146         6, 6, 6, 6, 6, 6,
147         8, 8,
148         10, 12, 10,
149         8, 8,
150     },
151     /* PAL 16:9 */
152     {
153         VI_TVMODE_PAL_INT,
154         sFbWidth,
155         sFbHeight,
156         viHeight_Pal,
157         (u16)((VI_MAX_WIDTH_PAL - viWidthWide_Pal)/2),
158         (u16)((VI_MAX_HEIGHT_PAL - viHeight_Pal)/2),
159         viWidthWide_Pal,
160         viHeight_Pal,
161         VI_XFBMODE_DF,
162         GX_FALSE,
163         GX_FALSE,
164         6, 6, 6, 6, 6, 6,
165         6, 6, 6, 6, 6, 6,
166         6, 6, 6, 6, 6, 6,
167         6, 6, 6, 6, 6, 6,
168         8, 8,
169         10, 12, 10,
170         8, 8,
171     }
172 };
173 
allocMem1(u32 size)174 static void* allocMem1( u32 size )
175 {
176     return MEMAllocFromAllocator( &DemoAllocator1, size );
177 }
178 
freeMem1(void * ptr)179 static u8 freeMem1( void* ptr )
180 {
181     MEMFreeToAllocator( &DemoAllocator1, ptr );
182     return 1;
183 }
184 
allocMem2(u32 size)185 static void* allocMem2( u32 size )
186 {
187     return MEMAllocFromAllocator( &DemoAllocator2, size );
188 }
189 
freeMem2(void * ptr)190 static u8 freeMem2( void* ptr )
191 {
192     MEMFreeToAllocator( &DemoAllocator2, ptr );
193     return 1;
194 }
195 
196 /* Event/sound callback function */
SoundCallback(int evt,int arg)197 static int SoundCallback( int evt, int arg )
198 {
199     OSReport( "SoundCallback: %d, %d\n", evt, arg );
200     return HBMSEV_RET_NONE;
201 }
202 
ResetCallback()203 static void ResetCallback()
204 {
205     reset_called = true;
206 }
207 
PowerCallback()208 static void PowerCallback()
209 {
210     power_called = true;
211 }
212 
213 /* Load file */
ReadDvdFile(const char * fileName,MEMAllocator * mem,u32 * fileSize)214 static void* ReadDvdFile(
215     const char*     fileName,
216     MEMAllocator*   mem,
217     u32* fileSize
218 )
219 {
220     u32 fileLen, fileLenUp32;
221     void* readBuf;
222     s32 readBytes;
223 
224     DVDFileInfo fileInfo;
225     if (! DVDOpen(fileName, &fileInfo))
226     {
227         return NULL;
228     }
229 
230     fileLen     = DVDGetLength(&fileInfo);
231     if( (fileLen % 32) != 0 )
232     {
233         fileLenUp32 = fileLen + (32 - (fileLen % 32));
234     }
235     else
236     {
237         fileLenUp32 = fileLen;
238     }
239     readBuf = MEMAllocFromAllocator(mem, fileLenUp32);
240     readBytes = DVDRead(&fileInfo, readBuf, (s32)(fileLenUp32), 0);
241     ASSERT(readBytes > 0);
242     if( fileSize )
243         *fileSize   = fileLen;
244     DVDClose(&fileInfo);
245 
246     return readBuf;
247 }
248 
249 
250 /* Initial settings */
Init()251 static void Init()
252 {
253     #ifdef BTN_NUM_3
254     char dirName[] = "hbm/HomeButton3";
255     #else
256     char dirName[] = "hbm/HomeButton2";
257     #endif
258     char nameBuf[32];
259 
260     VIInit();
261     switch (VIGetTvFormat())
262     {
263         case VI_NTSC:
264              sTvmode = 0;
265              break;
266         case VI_PAL:
267              sTvmode = 1;
268              break;
269         default:
270              OSHalt("VIGetTvFormat()t: invalid TV format\n");
271              break;
272     }
273 
274     DEMOInit(&sRMObj[sTvmode]);
275 
276     SCInit();
277     while ( SC_STATUS_OK != SCCheckStatus() ) {} /* Wait for completion of SCInit() */
278     DVDInit();
279     OSInitFastCast();
280 
281 #ifdef  ENABLE_BALANCE_BOARD
282     WPADRegisterBLCWorkarea( workarea );
283 #endif // ENABLE_BALANCE_BOARD
284     WPADRegisterAllocator( allocMem2, freeMem2 );
285 
286     PADInit();
287     KPADInit();
288 
289      /* Load icon */
290     strcpy( nameBuf, dirName );
291     strcat( nameBuf, "/homeBtnIcon.tpl" );
292     sIconTpl = ( TPLPalettePtr )ReadDvdFile( nameBuf, &DemoAllocator1, NULL );
293     TPLBind( sIconTpl );
294 
295     /* Power switch and reset switch callbacks */
296     OSSetResetCallback(ResetCallback);
297     OSSetPowerCallback(PowerCallback);
298 
299     reset_called = false;
300     power_called = false;
301 }
302 
303 
304 /* Projection settings */
SetProjection(int wideflag)305 static void SetProjection( int wideflag )
306 {
307     Mtx44 projMtx;
308 
309 
310     if( !wideflag )
311     {
312         DEMOReInit(&sRMObj[sTvmode]);
313         f32 viRateX = sRMObj[sTvmode].viWidth  / 670.f;
314         f32 viRateY = sRMObj[sTvmode].viHeight / 456.f;
315         MTXOrtho(projMtx, viRateY * 228.0f, -viRateY * 228.0f, -viRateX * 304.0f, viRateX * 304.0f, 0.0f, 500.0f);
316     }
317     else
318     {
319         DEMOReInit(&sRMObjWide[sTvmode]);
320         f32 viRateX = sRMObjWide[sTvmode].viWidth  / 682.f;
321         f32 viRateY = sRMObjWide[sTvmode].viHeight / 456.f;
322         MTXOrtho(projMtx, viRateY * 228.0f, -viRateY * 228.0f, -viRateX * 416.0f, viRateX * 416.0f, 0.0f, 500.0f);
323     }
324 
325     GXSetProjection(projMtx, GX_ORTHOGRAPHIC);
326 }
327 
328 /* Initialize GX */
InitGX()329 static void InitGX()
330 {
331     GXClearVtxDesc();
332 
333     GXSetVtxAttrFmt(GX_VTXFMT4, GX_VA_POS,  GX_POS_XY,  GX_F32, 0);
334     GXSetVtxAttrFmt(GX_VTXFMT4, GX_VA_CLR0, GX_CLR_RGB, GX_RGB8, 0);
335     GXSetVtxDesc(GX_VA_POS,  GX_DIRECT);
336     GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
337 
338     GXSetNumChans(1);
339     GXSetNumTexGens(0);
340     GXSetNumTevStages(1);
341     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
342     GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
343 
344     GXSetBlendMode(GX_BM_NONE, GX_BL_ZERO, GX_BL_ZERO, GX_LO_CLEAR);
345     GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
346     GXSetCurrentMtx( GX_PNMTX1 );
347 }
348 
349 /* Render the "Prohibited" icon */
DrawBanIcon(u8 alpha)350 static void DrawBanIcon( u8 alpha )
351 {
352     GXTexObj texObj;
353     Mtx      view_mtx ;
354     // mtx
355     MTXIdentity( view_mtx ) ;
356     GXLoadPosMtxImm( view_mtx, GX_PNMTX1 ) ;
357     GXSetCurrentMtx( GX_PNMTX1 ) ;
358 
359     GXClearVtxDesc();
360 
361     GXSetVtxAttrFmt(GX_VTXFMT5, GX_VA_POS,  GX_POS_XY,  GX_S16, 0);
362     GXSetVtxAttrFmt(GX_VTXFMT5, GX_VA_TEX0, GX_TEX_ST, GX_S16, 0);
363     GXSetVtxDesc(GX_VA_POS,  GX_DIRECT);
364     GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
365 
366     GXSetNumChans(1);
367     GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_VTX, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE);
368 
369     GXSetNumTexGens(1);
370     GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
371 
372     GXSetNumTevStages(1);
373     GXSetTevColor(GX_TEVREG0, (GXColor){255, 255, 255, alpha});
374     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
375     GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC);
376     GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
377     GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_A0, GX_CA_TEXA, GX_CA_ZERO);
378     GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
379 
380     GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
381     GXSetZMode(GX_FALSE, GX_LEQUAL, GX_FALSE);
382 
383     TPLGetGXTexObjFromPalette( sIconTpl, &texObj, 0 );
384     GXLoadTexObj( &texObj, GX_TEXMAP0 );
385 
386     /* The rendering position may be anywhere inside the safe frame. */
387     GXBegin( GX_QUADS, GX_VTXFMT5, 4 );
388     GXPosition2s16( -256 + 0, 188 - 56 );
389     GXTexCoord2s16( 0, 1 );
390     GXPosition2s16( -256 + 0, 188 + 0 );
391     GXTexCoord2s16( 0, 0 );
392     GXPosition2s16( -256 + 56, 188 + 0 );
393     GXTexCoord2s16( 1, 0 );
394     GXPosition2s16( -256 + 56, 188 - 56 );
395     GXTexCoord2s16( 1, 1 );
396     GXEnd();
397 }
398 
InitHomeButtonInfo(HBMDataInfo * pHbmInfo)399 static void InitHomeButtonInfo( HBMDataInfo* pHbmInfo )
400 {
401 #ifdef BTN_NUM_3
402     char dirName[] = "hbm/HomeButton3";
403 #else
404     char dirName[] = "hbm/HomeButton2";
405 #endif
406 
407     char nameBuf[32];
408 
409     /* Create filename */
410     strcpy( nameBuf, dirName );
411     /* Switching as necessary according to the language setting */
412     pHbmInfo->region=SCGetLanguage();
413     switch (pHbmInfo->region)
414     {
415     case SC_LANG_JAPANESE:
416         strcat( nameBuf, "/homeBtn.arc" );
417         break;
418     case SC_LANG_ENGLISH:
419         strcat( nameBuf, "/homeBtn_ENG.arc" );
420         break;
421     case SC_LANG_GERMAN:
422         strcat( nameBuf, "/homeBtn_GER.arc" );
423         break;
424     case SC_LANG_FRENCH:
425         strcat( nameBuf, "/homeBtn_FRA.arc" );
426         break;
427     case SC_LANG_SPANISH:
428         strcat( nameBuf, "/homeBtn_SPA.arc" );
429         break;
430     case SC_LANG_ITALIAN:
431         strcat( nameBuf, "/homeBtn_ITA.arc" );
432         break;
433     case SC_LANG_DUTCH:
434         strcat( nameBuf, "/homeBtn_NED.arc" );
435         break;
436     case SC_LANG_SIMP_CHINESE:
437         strcat( nameBuf, "/homeBtn_CHN.arc" );
438         break;
439     case SC_LANG_KOREAN:
440         strcat( nameBuf, "/homeBtn_KOR.arc" );
441         break;
442     default:
443         pHbmInfo->region=SC_LANG_JAPANESE;
444         strcat( nameBuf, "/homeBtn.arc" );
445         break;
446     }
447     pHbmInfo->layoutBuf = ReadDvdFile( nameBuf, &DemoAllocator1, NULL );
448 
449     strcpy( nameBuf, dirName );
450     strcat( nameBuf, "/SpeakerSe.arc" );
451     pHbmInfo->spkSeBuf = ReadDvdFile( nameBuf, &DemoAllocator1, NULL );
452 
453     strcpy( nameBuf, dirName );
454 #ifdef HBM_NO_SAVE
455     strcat( nameBuf, "/home_nosave.csv" );
456 #else
457     strcat( nameBuf, "/home.csv" );
458 #endif
459     pHbmInfo->msgBuf = ReadDvdFile( nameBuf, &DemoAllocator1, NULL );
460 
461     strcpy( nameBuf, dirName );
462     strcat( nameBuf, "/config.txt" );
463     pHbmInfo->configBuf = ReadDvdFile( nameBuf, &DemoAllocator1, &pHbmInfo->configBufSize );
464 
465     pHbmInfo->sound_callback = SoundCallback;
466     pHbmInfo->backFlag       = OFF;
467     pHbmInfo->cursor         = 0;
468     pHbmInfo->adjust.x       = 1.0f;
469     pHbmInfo->adjust.y       = 1.0f;
470     pHbmInfo->frameDelta     = 1.0f;
471 
472     /* Memory allocation settings */
473     pHbmInfo->mem = allocMem1( HBM_MEM_SIZE );
474     pHbmInfo->memSize = HBM_MEM_SIZE;
475     pHbmInfo->pAllocator = NULL;
476 
477     /* Change the exit message each time the HOME menu is started */
478     pHbmInfo->messageFlag++;
479     pHbmInfo->messageFlag &= 0x3;
480 }
481 
482 /* Initialize sounds */
InitSound()483 static void InitSound()
484 {
485     #ifdef BTN_NUM_3
486         char dirName[] = "hbm/HomeButton3";
487     #else
488         char dirName[] = "hbm/HomeButton2";
489     #endif
490 
491     char nameBuf[32];
492 
493     /* Create filename */
494     strcpy( nameBuf, dirName );
495     strcat( nameBuf, "/HomeButtonSe.arc" );
496 
497     /* Load sound data for AX use */
498     sound_data = (u8*)ReadDvdFile( nameBuf, &DemoAllocator1, NULL );
499     /* Allocate a buffer for sounds */
500     sound_buf = (u8*)allocMem1( HBM_MEM_SIZE_SOUND );
501     HBMCreateSound( sound_data, sound_buf, HBM_MEM_SIZE_SOUND );
502 }
503 
504 /* Cursor position initialization */
InitControllerData(HBMControllerData * pConData)505 static void InitControllerData( HBMControllerData* pConData )
506 {
507     int i;
508     for( i = 0; i < WPAD_MAX_CONTROLLERS; i++ )
509     {
510         pConData->wiiCon[i].pos.x = 0.f;
511         pConData->wiiCon[i].pos.y = 0.f;
512         pConData->wiiCon[i].use_devtype = WPAD_DEV_CORE;
513     }
514 }
515 
516 /* Absolute value clamp */
AbsClamp(f32 val,f32 max)517 static f32 AbsClamp( f32 val, f32 max )
518 {
519     return ( ( val > max ) ? max : ( val < -max ) ? -max : val );
520 }
521 
522 /* Cursor movement processing for analog stick */
calcAnalogCursorPos(f32 stickX,f32 stickY,Vec2 * pos)523 static int calcAnalogCursorPos( f32 stickX, f32 stickY, Vec2* pos )
524 {
525     f32 x,y;
526     x = ( stickX / scStickMoveCoe );
527     y = ( stickY / scStickMoveCoe );
528     x = AbsClamp( x, 1.0f );
529     y = AbsClamp( y, 1.0f );
530     if( x == 0.0f && y == 0.0f ) return FALSE;
531     pos->x = AbsClamp( pos->x + x, 1.0f );
532     pos->y = AbsClamp( pos->y - y, 1.0f );
533     return TRUE;
534 }
535 
536 /* Cursor movement processing when using +Control key */
calcDigitalCursorPos(u32 button,Vec2 * pos)537 static int calcDigitalCursorPos( u32 button, Vec2* pos )
538 {
539     const float spd =1.0f / scStickMoveCoe;
540     const float spd2= spd * 0.7071f;
541 
542     button&=KPAD_CL_BUTTON_UP|KPAD_CL_BUTTON_LEFT|KPAD_CL_BUTTON_DOWN|KPAD_CL_BUTTON_RIGHT;
543     switch (button)
544     {
545     case KPAD_CL_BUTTON_UP:     pos->y-=spd; break;
546     case KPAD_CL_BUTTON_LEFT:   pos->x-=spd; break;
547     case KPAD_CL_BUTTON_DOWN:   pos->y+=spd; break;
548     case KPAD_CL_BUTTON_RIGHT:  pos->x+=spd; break;
549     case KPAD_CL_BUTTON_UP  |KPAD_CL_BUTTON_LEFT:   pos->y-=spd2; pos->x-=spd2; break;
550     case KPAD_CL_BUTTON_UP  |KPAD_CL_BUTTON_RIGHT:  pos->y-=spd2; pos->x+=spd2; break;
551     case KPAD_CL_BUTTON_DOWN|KPAD_CL_BUTTON_LEFT:   pos->y+=spd2; pos->x-=spd2; break;
552     case KPAD_CL_BUTTON_DOWN|KPAD_CL_BUTTON_RIGHT:  pos->y+=spd2; pos->x+=spd2; break;
553     default: return FALSE;
554     }
555     pos->x = AbsClamp( pos->x, 1.0f );
556     pos->y = AbsClamp( pos->y, 1.0f );
557     return TRUE;
558 }
559 
560 
561 /* Change the adjust value depending on the display mode */
SetAdjustValue(HBMDataInfo * pHbmInfo,int wideflag)562 static void SetAdjustValue( HBMDataInfo* pHbmInfo, int wideflag )
563 {
564     if( !wideflag )
565     {
566         /* 4:3 */
567         pHbmInfo->adjust.x       = 1.0f;
568         pHbmInfo->adjust.y       = 1.0f;
569     }
570     else
571     {
572         /* 16:9 */
573         pHbmInfo->adjust.x       = 832.f / 608.f;
574         pHbmInfo->adjust.y       = 1.0f;
575     }
576 
577     if(sTvmode == 0)
578     {
579         /* NTSC: 60Hz */
580         pHbmInfo->frameDelta     = 1.0f;
581     }
582     else
583     {
584         /* PAL: 50Hz */
585         pHbmInfo->frameDelta     = 1.2f;
586     }
587 }
588 
589 /* Main function */
main()590 void main()
591 {
592     Mtx mv;
593     HBMDataInfo hbmInfo;
594     HBMControllerData conData;
595     int homeBtnSwitch  = OFF;   /* HOME button switch */
596     int drawModeFlag   = OFF;   /* Flag for toggling between 4:3 and 16:9 displays */
597     int banIconSwitch  = OFF;   /* HOME button prohibited icon */
598     s8  banIconMode    = 0;     /* 0: AlphaIn, 1: Pause, 2: AlphaOut */
599     OSTick banIconTime = 0;
600     u8  banIconAlpha   = 0;
601     s32 wpad_result[WPAD_MAX_CONTROLLERS];
602     u32 pad_type[WPAD_MAX_CONTROLLERS];
603     Vec2 pos[WPAD_MAX_CONTROLLERS];/* Position of the Pointer */
604     int input_classic;
605     int i;
606 
607     s32 kpad_read[WPAD_MAX_CONTROLLERS];
608     GXRenderModeObj* pRm;
609 
610     Init();
611 
612     /* Viewport settings */
613     pRm = DEMOGetRenderModeObj();
614     MTXIdentity(mv);
615     GXLoadPosMtxImm(mv, GX_PNMTX1);
616     SetProjection( drawModeFlag );
617     /* No culling */
618     GXSetCullMode( GX_CULL_NONE );
619 
620     /* Display the operation method on the console */
621     OSReport( "------------------------------\n" );
622     OSReport( "HOME Button Menu Sample\n\n" );
623     OSReport( "+ : Show Icon\n" );
624     OSReport( "2 : Switch Video Mode\n" );
625     OSReport( "------------------------------\n" );
626 
627     OSReport("Mem1Free = %d\n", MEMGetTotalFreeSizeForExpHeap((MEMHeapHandle)DemoAllocator1.pHeap) );
628     OSReport("Mem2Free = %d\n", MEMGetTotalFreeSizeForExpHeap((MEMHeapHandle)DemoAllocator2.pHeap) );
629 
630     memset(&sKpadToHBM[0], 0, sizeof(KPADStatus)*WPAD_MAX_CONTROLLERS);
631     while( 1 )
632     {
633         /* Wii controllers */
634         for( int i = 0; i < WPAD_MAX_CONTROLLERS; i++ )
635         {
636             wpad_result[i] = WPADProbe( i, &pad_type[i] );
637             conData.wiiCon[i].use_devtype = pad_type[i];
638             kpad_read[i] = KPADRead( i, &sKpads[i][0], KPAD_MAX_READ_BUFS );
639             if( kpad_read[i] )
640             	memcpy( &sKpadToHBM[i], &sKpads[i][0], sizeof(KPADStatus) );
641 
642             switch( wpad_result[i] )
643             {
644             /* In the following error states, the value gotten by KPADRead is applied as is. */
645             case WPAD_ERR_BUSY:
646             case WPAD_ERR_TRANSFER:
647             case WPAD_ERR_INVALID:
648             case WPAD_ERR_CORRUPTED:
649             case WPAD_ERR_NONE:
650                 conData.wiiCon[i].kpad = &sKpadToHBM[i];
651 
652                 {
653                     input_classic = calcDigitalCursorPos(
654                         conData.wiiCon[i].kpad->ex_status.cl.hold,
655                         &conData.wiiCon[i].pos );
656 
657                     input_classic = input_classic | calcAnalogCursorPos(
658                         conData.wiiCon[i].kpad->ex_status.cl.lstick.x,
659                         conData.wiiCon[i].kpad->ex_status.cl.lstick.y,
660                         &conData.wiiCon[i].pos );
661 
662                     if( !input_classic && conData.wiiCon[i].kpad->dpd_valid_fg > 0)
663                     {
664                         conData.wiiCon[i].pos.x = conData.wiiCon[i].kpad->pos.x;
665                         conData.wiiCon[i].pos.y = conData.wiiCon[i].kpad->pos.y;
666                     }
667                 }
668 
669                 /* Change the rendering mode */
670                 if( !homeBtnSwitch && sKpadToHBM[i].trig == KPAD_BUTTON_2 )
671                 {
672                     drawModeFlag = !drawModeFlag;
673                     SetProjection( drawModeFlag );
674                     SetAdjustValue( &hbmInfo, drawModeFlag );
675                     pRm = DEMOGetRenderModeObj();
676                 }
677 
678                 if( sKpadToHBM[i].trig == KPAD_BUTTON_1 )
679                 {
680                     VISetBlack(FALSE);
681                     VIFlush();
682                 }
683 
684                 if ( !homeBtnSwitch && !banIconSwitch && sKpadToHBM[i].trig == KPAD_BUTTON_PLUS )
685                 {
686                     banIconMode   = eAlphaInIcon;
687                     banIconSwitch = ON;
688                     banIconTime   = OSGetTick();
689                     banIconAlpha  = 0;
690                 }
691                 break;
692             /* Apply NULL in the following error states. */
693             case WPAD_ERR_NO_CONTROLLER:
694             default:
695                 conData.wiiCon[i].kpad = NULL;
696                 memset(&sKpadToHBM[i], 0, sizeof(KPADStatus));
697                 break;
698             }
699         }
700         if( !homeBtnSwitch && !banIconSwitch )
701         {
702             BOOL press_home = FALSE;
703 
704             for ( int i = 0; i < WPAD_MAX_CONTROLLERS; i++ )
705             {
706                  if ( WPAD_ERR_NONE != wpad_result[i] ) continue;
707 
708                  /* When HOME is pressed on the Wii Remote or Classic Controller */
709                  if ( sKpadToHBM[i].trig == KPAD_BUTTON_HOME ||
710                       sKpadToHBM[i].ex_status.cl.trig==KPAD_CL_BUTTON_HOME )
711                  {
712                      press_home = TRUE;
713                      homeBtnSwitch = ON;
714                      break;
715                  }
716             }
717             if ( press_home )
718             {
719                 InitControllerData( &conData );
720                 InitHomeButtonInfo( &hbmInfo );
721                 /* Set the adjust value depending on the screen mode */
722                 SetAdjustValue( &hbmInfo, drawModeFlag );
723 
724                 /* HBM initialization */
725                 HBMCreate( &hbmInfo );
726                 HBMInit();
727                 /* Adjust ON */
728                 HBMSetAdjustFlag( TRUE );
729 
730                 /* Load sounds */
731                 InitSound();
732 
733                 OSReport("Mem1Free = %d\n", MEMGetTotalFreeSizeForExpHeap((MEMHeapHandle)DemoAllocator1.pHeap) );
734                 OSReport("Mem2Free = %d\n", MEMGetTotalFreeSizeForExpHeap((MEMHeapHandle)DemoAllocator2.pHeap) );
735             }
736         }
737 
738         if( homeBtnSwitch )
739         {
740             /* Update SE (sound effect) */
741             HBMUpdateSound();
742 
743             /* Update the HOME Menu */
744             if( HBMCalc( &conData ) >= HBM_SELECT_HOMEBTN )
745             {
746                 /* The number of the decided-upon button is returned */
747                 OSReport("Select Btn:%d\n", HBMGetSelectBtnNum());
748                 OSReport("Reassigned:%d\n", HBMIsReassignedControllers());
749 
750 
751                 /* Process executed when returning from the HOME Menu */
752                 switch( HBMGetSelectBtnNum() )
753                 {
754                 case HBM_SELECT_HOMEBTN:
755                     break;
756                 /* Move to the Wii Menu */
757                 case HBM_SELECT_BTN1:
758                     OSReport( "Return to WiiMenu.\n" );
759                     OSReturnToMenu();
760                     break;
761                 /* Reset */
762                 case HBM_SELECT_BTN2:
763                     OSReport( "Reset.\n" );
764                     OSRestart( 0 );
765                     break;
766                 case 3:
767 
768                     break;
769                 default:
770                     break;
771                 }
772                 /* Release various items */
773                 HBMDelete( );
774                 HBMDeleteSound();
775 
776                 freeMem1( sound_buf );
777                 freeMem1( sound_data );
778                 freeMem1( hbmInfo.mem );
779                 freeMem1( hbmInfo.layoutBuf );
780                 freeMem1( hbmInfo.spkSeBuf );
781                 freeMem1( hbmInfo.msgBuf );
782                 freeMem1( hbmInfo.configBuf );
783 
784                 homeBtnSwitch = OFF;
785 
786                 OSReport("Mem1Free = %d\n", MEMGetTotalFreeSizeForExpHeap((MEMHeapHandle)DemoAllocator1.pHeap) );
787                 OSReport("Mem2Free = %d\n", MEMGetTotalFreeSizeForExpHeap((MEMHeapHandle)DemoAllocator2.pHeap) );
788             }
789 
790         }
791 
792         /* Calculate the Pointer position */
793         for( i = 0; i < PAD_MAX_CONTROLLERS; i++ )
794         {
795             /* For Wii */
796             if ( WPAD_ERR_NONE == wpad_result[i] &&
797                  0 < kpad_read[i] &&
798                  conData.wiiCon[i].kpad )
799             {
800                 if( !homeBtnSwitch )
801                 {
802                     if( sKpads[i]->dev_type == WPAD_DEV_CLASSIC )
803                     {
804                         pos[i].x = conData.wiiCon[i].pos.x;
805                         pos[i].y = conData.wiiCon[i].pos.y;
806                     }
807                     else
808                     {
809                         pos[i].x = conData.wiiCon[i].kpad->pos.x;
810                         pos[i].y = conData.wiiCon[i].kpad->pos.y;
811                     }
812 
813                     pos[i].x *= pRm->fbWidth * 0.5f;
814                     pos[i].y *= pRm->xfbHeight * 0.5f;
815 
816                     if( drawModeFlag )
817                     {
818                         pos[i].x *= hbmInfo.adjust.x;
819                         pos[i].y *= hbmInfo.adjust.y;
820                     }
821                 }
822             }
823         }
824 
825         DEMOBeforeRender();
826         {
827             InitGX();
828             if( homeBtnSwitch )
829             {
830                 /* Render the HOME Menu */
831                 HBMDraw();
832             }
833             /* Render the specified cursor inside the HOME Menu */
834             if( !homeBtnSwitch )
835             {
836                 for( i = 0; i < PAD_MAX_CONTROLLERS; i++ )
837                 {
838                     if( conData.wiiCon[i].kpad )
839                     {
840                         /* Render the Wii Pointer */
841                         GXBegin( GX_QUADS, GX_VTXFMT4, 4 );
842                         GXPosition2f32( -10 + pos[i].x, -10 - pos[i].y );
843                         GXColor3u8( 255, 255, 255 );
844                         GXPosition2f32( -10 + pos[i].x,  10 - pos[i].y );
845                         GXColor3u8( 255, 255, 255 );
846                         GXPosition2f32(  10 + pos[i].x,  10 - pos[i].y );
847                         GXColor3u8( 255, 255, 255 );
848                         GXPosition2f32(  10 + pos[i].x, -10 - pos[i].y );
849                         GXColor3u8( 255, 255, 255 );
850                         GXEnd();
851                     }
852                 }
853 
854                 /* Render the HOME Menu prohibited icon */
855                 if ( banIconSwitch )
856                 {
857                     f32 elapse = OSTicksToMilliseconds( OSDiffTick( OSGetTick(), banIconTime ) );
858 
859                     switch ( banIconMode )
860                     {
861                     case eAlphaInIcon: /* AlphaIn (250ms) */
862                         banIconAlpha = ( u8 )( 255.9f * ( elapse / 250.f ) );
863                         if ( elapse >= 250.f )
864                         {
865                             banIconTime  = OSGetTick();
866                             banIconMode  = ePauseIcon;
867                             banIconAlpha = 255;
868                         }
869                         break;
870                     case ePauseIcon: /* Pause (1000ms) */
871                         if ( elapse >= 1000.f )
872                         {
873                             banIconTime = OSGetTick();
874                             banIconMode = eAlphaOutIcon;
875                         }
876                         break;
877                     case eAlphaOutIcon: /* AlphaOut (250ms) */
878                         banIconAlpha = ( u8 )( 255.9f * ( ( 250.f - elapse ) / 250.f ) );
879                         if ( elapse >= 250.f )
880                         {
881                             banIconAlpha  = 0;
882                             banIconSwitch = OFF;
883                         }
884                         break;
885                     }
886 
887                     DrawBanIcon( banIconAlpha );
888                 }
889             }
890         }
891         DEMODoneRender();
892 
893         /* Process executed when the RESET or Power Button is pressed */
894         if(reset_called)
895         {
896             /*When other than the HOME Menu, go straight on to reset */
897             if( homeBtnSwitch == OFF )
898             {
899                 OSRestart(0);
900             }
901             /* If the HOME Menu is running, reset after black-out */
902             else
903             {
904                 HBMStartBlackOut();
905             }
906             reset_called = false;
907         }
908 
909         if(power_called)
910         {
911             OSReturnToMenu();
912         }
913     }
914 }
915 
916