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