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