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