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