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