1 /*---------------------------------------------------------------------------*
2 Project: Virtual Console Manual Viewer Shell Program
3 File: vcmv_test.c
4
5 Copyright 1998-2009 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 // This program should be adapted to each Virtual Console game engine
14
15 *---------------------------------------------------------------------------*/
16
17 /*---------------------------------------------------------------------------*
18 Macro definitions
19 *---------------------------------------------------------------------------*/
20
21 #if 0
22 #define verbose(s); s
23 #else
24 #define verbose(s);
25 #endif
26
27 #define USE_FOR_MANUAL
28 #define HOME_BUTTON_MENU_3 1
29 #define PAL_MODE 0
30 #define PAL_MODE_SUPPORTS_PROGRESSIVE 0 // Set to 1 if the game supports 60Hz in PAL region (Most VC titles do not)
31 #define GAME_SUPPORTS_NON_INTERLACE 1
32
33 #define USE_MEMORY_PROTOCOL 1 // Determines whether to keep the html contents in memory, or copy to NAND /tmp directory
34 #define INITIALIZE_IN_THREAD 1
35 #define GAME_HARDWARE_WIDTH 256 // Choose from: 256, 320, 336, 512
36 #define GAME_HARDWARE_HEIGHT 224 // Choose from: 224, 240
37 #define GAME_TEXTURE_HEIGHT GAME_HARDWARE_HEIGHT
38 #define SIMULATE_GAME_MEMORY_USAGE 0
39 #define MANUALLY_ADJUSTED_TWEAK 0
40 #define TEST_BAN_ICON 0
41
42 #if defined REGION_KOR
43 #define IGNORE_TV_ASPECT_RATIO 1
44 #else
45 #define IGNORE_TV_ASPECT_RATIO 0
46 #endif
47
48 #define GAME_USES_NW4R 0
49 #define BROWSER_RSO_CIDX 2
50 #define FONT_CIDX 3
51
52 #define GX_FIFO_SIZE (1024 * 1024)
53 #define FILTER_KPAD 1
54
55 /*---------------------------------------------------------------------------*
56 Header files
57 *---------------------------------------------------------------------------*/
58
59 #include "vcmv.h"
60 #include <revolution.h>
61 #include <revolution/sc.h>
62 #include <revolution/vi.h>
63 #include <revolution/wpad.h>
64 #include <revolution/ax.h>
65 #include <revolution/mix.h>
66 #include <revolution/kpad.h>
67 #include <revolution/cx.h>
68 #include <revolution/tpl.h>
69 #include <revolution/nand.h>
70 #include <string.h>
71 #include <stdio.h>
72 #if GAME_USES_NW4R
73 #include <nw4r/snd.h>
74 #endif
75
76 /*---------------------------------------------------------------------------*
77 Game Hardware definitions and data
78 *---------------------------------------------------------------------------*/
79
80 typedef struct {
81 s32 nGameXFB;
82 s32 nGameVI;
83 s32 nCurrentXFB;
84 s32 nCurrentVI;
85 f32 rTweakR;
86 } TweakEntry;
87
88 #if ( GAME_HARDWARE_WIDTH == 256 )
89 #define GAME_TEXTURE_WIDTH 256
90 #define GAME_EFB_WIDTH_FULL 512
91 #define GAME_XFB_WIDTH_FULL 512
92 #define GAME_VI_WIDTH_FULL 640
93 #define GAME_EFB_WIDTH_SQUASH 512
94 #define GAME_XFB_WIDTH_SQUASH 512
95 #define GAME_VI_WIDTH_SQUASH 512
96 TweakEntry aTweakTbl[] = {
97 { 512, 512, 512, 512, 0.0 },
98 { 512, 512, 608, 670, 0.9 },
99 { 512, 512, 608, 672, 0.7 },
100 { 512, 512, 640, 686, 0.3 },
101 { 512, 512, 640, 688, 1.3 },
102 { 512, 640, 608, 670, 0.6 },
103 { 512, 640, 608, 672, 0.2 },
104 { 512, 640, 640, 686, 0.1 },
105 { 512, 640, 640, 688, 0.9 },
106 };
107
108 #elif ( GAME_HARDWARE_WIDTH == 320 )
109 #define GAME_TEXTURE_WIDTH 320
110 #define GAME_EFB_WIDTH_FULL 640
111 #define GAME_XFB_WIDTH_FULL 640
112 #define GAME_VI_WIDTH_FULL 640
113 #define GAME_EFB_WIDTH_SQUASH 320
114 #define GAME_XFB_WIDTH_SQUASH 320
115 #define GAME_VI_WIDTH_SQUASH 480
116 TweakEntry aTweakTbl[] = {
117 { 320, 480, 512, 512, -0.9 },
118 { 320, 480, 608, 670, 0.7 },
119 { 320, 480, 608, 672, 0.4 },
120 { 320, 480, 640, 686, -0.2 },
121 { 320, 480, 640, 688, 1.2 },
122 { 640, 640, 608, 670, 0.9 },
123 { 640, 640, 608, 672, 0.7 },
124 { 640, 640, 640, 686, 0.3 },
125 { 640, 640, 640, 688, 1.2 },
126 };
127
128 #elif ( GAME_HARDWARE_WIDTH == 336 )
129 #define GAME_TEXTURE_WIDTH 336
130 #define GAME_EFB_WIDTH_FULL 336
131 #define GAME_XFB_WIDTH_FULL 336
132 #define GAME_VI_WIDTH_FULL 672 // Maybe 640? 672 Assumes 336 resolution of original hardware was designed to eliminate L/R borders
133 #define GAME_EFB_WIDTH_SQUASH 336
134 #define GAME_XFB_WIDTH_SQUASH 336
135 #define GAME_VI_WIDTH_SQUASH 504 // Maybe 480? 504 Assumes 336 resolution of original hardware was designed to eliminate L/R borders
136 TweakEntry aTweakTbl[] = {
137 { 336, 504, 512, 512, -0.7 },
138 { 336, 504, 608, 670, 0.8 },
139 { 336, 504, 608, 672, 0.0 },
140 { 336, 504, 640, 686, -0.4 },
141 { 336, 504, 640, 688, 1.0 },
142 { 336, 670, 608, 670, -0.5 },
143 { 336, 672, 608, 670, 1.0 },
144 { 336, 672, 608, 672, 0.6 },
145 { 336, 672, 640, 686, 0.2 },
146 { 336, 672, 640, 688, 1.2 },
147 };
148
149 #elif ( GAME_HARDWARE_WIDTH == 512 )
150 #define GAME_TEXTURE_WIDTH 512
151 #define GAME_EFB_WIDTH_FULL 512
152 #define GAME_XFB_WIDTH_FULL 512
153 #define GAME_VI_WIDTH_FULL 640
154 #define GAME_EFB_WIDTH_SQUASH 512
155 #define GAME_XFB_WIDTH_SQUASH 512
156 #define GAME_VI_WIDTH_SQUASH 512
157 TweakEntry aTweakTbl[] = {
158 { 512, 512, 512, 512, 0.0 },
159 { 512, 512, 608, 670, 2.0 },
160 { 512, 512, 608, 672, 0.8 },
161 { 512, 512, 640, 686, 0.3 },
162 { 512, 512, 640, 688, 2.5 },
163 { 512, 640, 608, 670, 1.1 },
164 { 512, 640, 608, 672, 0.1 },
165 { 512, 640, 640, 686, 0.1 },
166 { 512, 640, 640, 688, 1.7 },
167 };
168 #endif
169
170 /*---------------------------------------------------------------------------*
171 TV Mode definitions
172 *---------------------------------------------------------------------------*/
173
174 #define BLACKOUT_TIME 3
175
176 #if PAL_MODE
177 #define GAME_VI_HEIGHT 542
178 #define HBM_VI_HEIGHT 542
179 #define MANUAL_VI_HEIGHT 542
180 #define PROG_MODE VI_TVMODE_EURGB60_PROG
181 #define INT_MODE VI_TVMODE_PAL_INT
182 #define DS_MODE VI_TVMODE_PAL_DS
183 #define VI_MAX_WIDTH VI_MAX_WIDTH_PAL
184 #define VI_MAX_HEIGHT VI_MAX_HEIGHT_PAL
185 #else
186 #define GAME_VI_HEIGHT (GAME_HARDWARE_HEIGHT<<1)
187 #define HBM_VI_HEIGHT 456
188 #define MANUAL_VI_HEIGHT 456
189 #define PROG_MODE VI_TVMODE_NTSC_PROG
190 #define INT_MODE VI_TVMODE_NTSC_INT
191 #define DS_MODE VI_TVMODE_NTSC_DS
192 #define VI_MAX_WIDTH VI_MAX_WIDTH_NTSC
193 #define VI_MAX_HEIGHT VI_MAX_HEIGHT_NTSC
194 #endif
195
196 #define HBM_EFB_WIDTH_WIDE 640 // 16:9 mode
197 #define HBM_EFB_WIDTH_NORMAL 608 // 4:3 mode
198 #define HBM_EFB_HEIGHT 456
199 #define HBM_VI_WIDTH_WIDE 688 // Multiple of 16, may be better than 686 for VI resampling
200 #define HBM_VI_WIDTH_NORMAL 672 // Multiple of 16, may be better than 670 for VI resampling
201 #define MANUAL_FB_HEIGHT 456
202 #define BROWSER_FB_HEIGHT 456
203
204 // Widescreen TV with 16:9 aspect ratio. TV should be set to display "Full" signal.
205 #define W_BROWSER_FB_WIDTH 808
206 #define W_MANUAL_FB_WIDTH_FULL 640
207 #define W_MANUAL_FB_WIDTH_SQUASH 640
208 #define W_MANUAL_VI_WIDTH_FULL 640
209 #define W_MANUAL_VI_WIDTH_SQUASH 640
210
211 // Normal TV with 4:3 aspect ratio
212 #define BROWSER_FB_WIDTH 608
213 #define MANUAL_FB_WIDTH_FULL 608
214 #define MANUAL_VI_WIDTH_FULL 672 // Multiple of 16, may be better than 670 for VI resampling
215 #define MANUAL_FB_WIDTH_SQUASH 512
216 #define MANUAL_VI_WIDTH_SQUASH 512
217
218 /*---------------------------------------------------------------------------*
219 Simulate Game memory definitions and variables
220 *---------------------------------------------------------------------------*/
221
222 #if SIMULATE_GAME_MEMORY_USAGE
223 // For simulating game memory usage
224 #define GAME_MEM1_SIZE (16 * 1024 * 1024)
225 #define GAME_MEM2_SIZE (40 * 1024 * 1024)
226
227 u8 *pGameMem1 = 0;
228 u8 *pGameMem2 = 0;
229 s32 nGameMem1Idx = 0;
230 s32 nGameMem2Idx = 0;
231 #endif
232
233 /*---------------------------------------------------------------------------*
234 Render Mode definitions and data
235 *---------------------------------------------------------------------------*/
236 //-------------------
237 // For Game
238 //-------------------
239 static const GXRenderModeObj C_aRmGame[6] = {
240 // Game Interlaced, 4:3 or 16:9 Stretched
241 {
242 // Settings for progressive mode should be similar to interlaced settings
243 INT_MODE, // viTVmode
244 GAME_XFB_WIDTH_FULL, // fbWidth
245 GAME_HARDWARE_HEIGHT, // efbHeight
246 GAME_VI_HEIGHT, // xfbHeight
247 (VI_MAX_WIDTH - GAME_VI_WIDTH_FULL)/2, // viXOrigin
248 (VI_MAX_HEIGHT - GAME_VI_HEIGHT)/2, // viYOrigin
249 GAME_VI_WIDTH_FULL, // viWidth
250 GAME_VI_HEIGHT, // viHeight
251 VI_XFBMODE_DF, // xFBmode
252 GX_FALSE, // field_rendering
253 GX_FALSE, // aa
254 6, 6, 6, 6, 6, 6, // sample_pattern
255 6, 6, 6, 6, 6, 6,
256 6, 6, 6, 6, 6, 6,
257 6, 6, 6, 6, 6, 6,
258 8, 8, // vfilter
259 10, 12, 10,
260 8, 8,
261 },
262
263 // Game Interlaced, 16:9 Squashed
264 {
265 // Settings for progressive mode should be similar to interlaced settings
266 INT_MODE, // viTVmode
267 GAME_XFB_WIDTH_SQUASH, // fbWidth
268 GAME_HARDWARE_HEIGHT, // efbHeight
269 GAME_VI_HEIGHT, // xfbHeight
270 (VI_MAX_WIDTH - GAME_VI_WIDTH_SQUASH)/2, // viXOrigin
271 (VI_MAX_HEIGHT - GAME_VI_HEIGHT)/2, // viYOrigin
272 GAME_VI_WIDTH_SQUASH, // viWidth
273 GAME_VI_HEIGHT, // viHeight
274 VI_XFBMODE_DF, // xFBmode
275 GX_FALSE, // field_rendering
276 GX_FALSE, // aa
277 6, 6, 6, 6, 6, 6, // sample_pattern
278 6, 6, 6, 6, 6, 6,
279 6, 6, 6, 6, 6, 6,
280 6, 6, 6, 6, 6, 6,
281 8, 8, // vfilter
282 10, 12, 10,
283 8, 8,
284 },
285
286 // Game Progressive, 4:3 or 16:9 Stretched
287 {
288 PROG_MODE, // viTVmode
289 GAME_XFB_WIDTH_FULL, // fbWidth
290 GAME_HARDWARE_HEIGHT, // efbHeight
291 GAME_VI_HEIGHT, // xfbHeight
292 (VI_MAX_WIDTH - GAME_VI_WIDTH_FULL)/2, // viXOrigin
293 (VI_MAX_HEIGHT - GAME_VI_HEIGHT)/2, // viYOrigin
294 GAME_VI_WIDTH_FULL, // viWidth
295 GAME_VI_HEIGHT, // viHeight
296 VI_XFBMODE_SF, // xFBmode
297 GX_FALSE, // field_rendering
298 GX_FALSE, // aa
299 6, 6, 6, 6, 6, 6, // sample_pattern
300 6, 6, 6, 6, 6, 6,
301 6, 6, 6, 6, 6, 6,
302 6, 6, 6, 6, 6, 6,
303 0, 0, // vfilter
304 21, 22, 21,
305 0, 0,
306 },
307
308 // Game Progressive, 16:9 Squashed
309 {
310 PROG_MODE, // viTVmode
311 GAME_XFB_WIDTH_SQUASH, // fbWidth
312 GAME_HARDWARE_HEIGHT, // efbHeight
313 GAME_VI_HEIGHT, // xfbHeight
314 (VI_MAX_WIDTH - GAME_VI_WIDTH_SQUASH)/2, // viXOrigin
315 (VI_MAX_HEIGHT - GAME_VI_HEIGHT)/2, // viYOrigin
316 GAME_VI_WIDTH_SQUASH, // viWidth
317 GAME_VI_HEIGHT, // viHeight
318 VI_XFBMODE_SF, // xFBmode
319 GX_FALSE, // field_rendering
320 GX_FALSE, // aa
321 6, 6, 6, 6, 6, 6, // sample_pattern
322 6, 6, 6, 6, 6, 6,
323 6, 6, 6, 6, 6, 6,
324 6, 6, 6, 6, 6, 6,
325 0, 0, // vfilter
326 21, 22, 21,
327 0, 0,
328 },
329
330 // Game Non-interlaced, 4:3 or 16:9 Stretched
331 {
332 DS_MODE, // viDisplayMode
333 GAME_XFB_WIDTH_FULL, // fbWidth
334 GAME_HARDWARE_HEIGHT, // efbHeight
335 (GAME_VI_HEIGHT/2), // xfbHeight
336 (VI_MAX_WIDTH - GAME_VI_WIDTH_FULL)/2, // viXOrigin
337 (VI_MAX_HEIGHT - GAME_VI_HEIGHT)/4, // viYOrigin
338 GAME_VI_WIDTH_FULL, // viWidth
339 GAME_VI_HEIGHT, // viHeight
340 VI_XFBMODE_SF, // xFBmode
341 GX_FALSE, // field_rendering
342 GX_FALSE, // aa
343 6, 6, 6, 6, 6, 6, // sample_pattern
344 6, 6, 6, 6, 6, 6,
345 6, 6, 6, 6, 6, 6,
346 6, 6, 6, 6, 6, 6,
347 0, 0, // vfilter
348 21, 22, 21,
349 0, 0,
350 },
351
352 // Game Non-interlaced, 16:9 Squashed
353 {
354 DS_MODE, // viDisplayMode
355 GAME_XFB_WIDTH_SQUASH, // fbWidth
356 GAME_HARDWARE_HEIGHT, // efbHeight
357 (GAME_VI_HEIGHT/2), // xfbHeight
358 (VI_MAX_WIDTH - GAME_VI_WIDTH_SQUASH)/2, // viXOrigin
359 (VI_MAX_HEIGHT - GAME_VI_HEIGHT)/4, // viYOrigin
360 GAME_VI_WIDTH_SQUASH, // viWidth
361 GAME_VI_HEIGHT, // viHeight
362 VI_XFBMODE_SF, // xFBmode
363 GX_FALSE, // field_rendering
364 GX_FALSE, // aa
365 6, 6, 6, 6, 6, 6, // sample_pattern
366 6, 6, 6, 6, 6, 6,
367 6, 6, 6, 6, 6, 6,
368 6, 6, 6, 6, 6, 6,
369 0, 0, // vfilter
370 21, 22, 21,
371 0, 0,
372 }
373 };
374
375 //-------------------
376 // For HBM
377 //-------------------
378 static const GXRenderModeObj C_aRmHBM[4] = {
379 // HBM Interlaced, 4:3
380 {
381 INT_MODE, // viTVmode
382 HBM_EFB_WIDTH_NORMAL, // fbWidth
383 HBM_EFB_HEIGHT, // efbHeight
384 HBM_VI_HEIGHT, // xfbHeight
385 (VI_MAX_WIDTH - HBM_VI_WIDTH_NORMAL)/2, // viXOrigin
386 (VI_MAX_HEIGHT - HBM_VI_HEIGHT)/2, // viYOrigin
387 HBM_VI_WIDTH_NORMAL, // viWidth
388 HBM_VI_HEIGHT, // viHeight
389 VI_XFBMODE_DF, // xFBmode
390 GX_FALSE, // field_rendering
391 GX_FALSE, // aa
392 6, 6, 6, 6, 6, 6, // sample_pattern
393 6, 6, 6, 6, 6, 6,
394 6, 6, 6, 6, 6, 6,
395 6, 6, 6, 6, 6, 6,
396 8, 8, // vfilter
397 10, 12, 10,
398 8, 8,
399 },
400
401 // HBM Interlaced, 16:9
402 {
403 INT_MODE, // viTVmode
404 HBM_EFB_WIDTH_WIDE, // fbWidth
405 HBM_EFB_HEIGHT, // efbHeight
406 HBM_VI_HEIGHT, // xfbHeight
407 (VI_MAX_WIDTH - HBM_VI_WIDTH_WIDE)/2, // viXOrigin
408 (VI_MAX_HEIGHT - HBM_VI_HEIGHT)/2, // viYOrigin
409 HBM_VI_WIDTH_WIDE, // viWidth
410 HBM_VI_HEIGHT, // viHeight
411 VI_XFBMODE_DF, // xFBmode
412 GX_FALSE, // field_rendering
413 GX_FALSE, // aa
414 6, 6, 6, 6, 6, 6, // sample_pattern
415 6, 6, 6, 6, 6, 6,
416 6, 6, 6, 6, 6, 6,
417 6, 6, 6, 6, 6, 6,
418 8, 8, // vfilter
419 10, 12, 10,
420 8, 8,
421 },
422
423 // HBM Progressive, 4:3
424 {
425 PROG_MODE, // viTVmode
426 HBM_EFB_WIDTH_NORMAL, // fbWidth
427 HBM_EFB_HEIGHT, // efbHeight
428 HBM_VI_HEIGHT, // xfbHeight
429 (VI_MAX_WIDTH - HBM_VI_WIDTH_NORMAL)/2, // viXOrigin
430 (VI_MAX_HEIGHT - HBM_VI_HEIGHT)/2, // viYOrigin
431 HBM_VI_WIDTH_NORMAL, // viWidth
432 HBM_VI_HEIGHT, // viHeight
433 VI_XFBMODE_SF, // xFBmode
434 GX_FALSE, // field_rendering
435 GX_FALSE, // aa
436 6, 6, 6, 6, 6, 6, // sample_pattern
437 6, 6, 6, 6, 6, 6,
438 6, 6, 6, 6, 6, 6,
439 6, 6, 6, 6, 6, 6,
440 8, 8, // vfilter
441 10, 12, 10,
442 8, 8,
443 },
444
445 // HBM Progressive, 16:9
446 {
447 PROG_MODE, // viTVmode
448 HBM_EFB_WIDTH_WIDE, // fbWidth
449 HBM_EFB_HEIGHT, // efbHeight
450 HBM_VI_HEIGHT, // xfbHeight
451 (VI_MAX_WIDTH - HBM_VI_WIDTH_WIDE)/2, // viXOrigin
452 (VI_MAX_HEIGHT - HBM_VI_HEIGHT)/2, // viYOrigin
453 HBM_VI_WIDTH_WIDE, // viWidth
454 HBM_VI_HEIGHT, // viHeight
455 VI_XFBMODE_SF, // xFBmode
456 GX_FALSE, // field_rendering
457 GX_FALSE, // aa
458 6, 6, 6, 6, 6, 6, // sample_pattern
459 6, 6, 6, 6, 6, 6,
460 6, 6, 6, 6, 6, 6,
461 6, 6, 6, 6, 6, 6,
462 8, 8, // vfilter
463 10, 12, 10,
464 8, 8,
465 },
466 };
467
468
469 //-------------------
470 // For Manual
471 //-------------------
472 static const GXRenderModeObj C_aRmManual[4] = {
473 // Manual Interlaced, 4:3 or 16:9 Stretched
474 {
475 INT_MODE, // viTVmode
476 MANUAL_FB_WIDTH_FULL, // fbWidth
477 MANUAL_FB_HEIGHT, // efbHeight
478 MANUAL_VI_HEIGHT, // xfbHeight
479 (VI_MAX_WIDTH - MANUAL_VI_WIDTH_FULL)/2, // viXOrigin
480 (VI_MAX_HEIGHT - MANUAL_VI_HEIGHT)/2, // viYOrigin
481 MANUAL_VI_WIDTH_FULL, // viWidth
482 MANUAL_VI_HEIGHT, // viHeight
483 VI_XFBMODE_DF, // xFBmode
484 GX_FALSE, // field_rendering
485 GX_FALSE, // aa
486 6, 6, 6, 6, 6, 6, // sample_pattern
487 6, 6, 6, 6, 6, 6,
488 6, 6, 6, 6, 6, 6,
489 6, 6, 6, 6, 6, 6,
490 8, 8, // vfilter
491 10, 12, 10,
492 8, 8,
493 },
494
495 // Manual Interlaced, 16:9 Squashed
496 {
497 INT_MODE, // viTVmode
498 W_MANUAL_FB_WIDTH_SQUASH, // fbWidth
499 MANUAL_FB_HEIGHT, // efbHeight
500 MANUAL_VI_HEIGHT, // xfbHeight
501 (VI_MAX_WIDTH - W_MANUAL_VI_WIDTH_SQUASH)/2,// viXOrigin
502 (VI_MAX_HEIGHT - MANUAL_VI_HEIGHT)/2, // viYOrigin
503 W_MANUAL_VI_WIDTH_SQUASH, // viWidth
504 MANUAL_VI_HEIGHT, // viHeight
505 VI_XFBMODE_DF, // xFBmode
506 GX_FALSE, // field_rendering
507 GX_FALSE, // aa
508 6, 6, 6, 6, 6, 6, // sample_pattern
509 6, 6, 6, 6, 6, 6,
510 6, 6, 6, 6, 6, 6,
511 6, 6, 6, 6, 6, 6,
512 8, 8, // vfilter
513 10, 12, 10,
514 8, 8,
515 },
516
517 // Manual Progressive, 4:3 or 16:9 Stretched
518 {
519 PROG_MODE, // viTVmode
520 MANUAL_FB_WIDTH_FULL, // fbWidth
521 MANUAL_FB_HEIGHT, // efbHeight
522 MANUAL_VI_HEIGHT, // xfbHeight
523 (VI_MAX_WIDTH - MANUAL_VI_WIDTH_FULL)/2, // viXOrigin
524 (VI_MAX_HEIGHT - MANUAL_VI_HEIGHT)/2, // viYOrigin
525 MANUAL_VI_WIDTH_FULL, // viWidth
526 MANUAL_VI_HEIGHT, // viHeight
527 VI_XFBMODE_SF, // xFBmode
528 GX_FALSE, // field_rendering
529 GX_FALSE, // aa
530 6, 6, 6, 6, 6, 6, // sample_pattern
531 6, 6, 6, 6, 6, 6,
532 6, 6, 6, 6, 6, 6,
533 6, 6, 6, 6, 6, 6,
534 8, 8, // vfilter
535 10, 12, 10,
536 8, 8,
537 },
538
539 // Manual Progressive, 16:9 Squashed
540 {
541 PROG_MODE, // viTVmode
542 W_MANUAL_FB_WIDTH_SQUASH, // fbWidth
543 MANUAL_FB_HEIGHT, // efbHeight
544 MANUAL_VI_HEIGHT, // xfbHeight
545 (VI_MAX_WIDTH - W_MANUAL_VI_WIDTH_SQUASH)/2,// viXOrigin
546 (VI_MAX_HEIGHT - MANUAL_VI_HEIGHT)/2, // viYOrigin
547 W_MANUAL_VI_WIDTH_SQUASH, // viWidth
548 MANUAL_VI_HEIGHT, // viHeight
549 VI_XFBMODE_SF, // xFBmode
550 GX_FALSE, // field_rendering
551 GX_FALSE, // aa
552 6, 6, 6, 6, 6, 6, // sample_pattern
553 6, 6, 6, 6, 6, 6,
554 6, 6, 6, 6, 6, 6,
555 6, 6, 6, 6, 6, 6,
556 8, 8, // vfilter
557 10, 12, 10,
558 8, 8,
559 },
560 };
561
562 enum {
563 E_InGame = 0,
564 E_InGamePlusBanIcon,
565 E_GameToHbmTransition1,
566 E_GameToHbmTransition2,
567 E_InHbm,
568 E_HbmToGameTransition,
569 E_HbmToVcmvTransition,
570 E_InVcmv,
571 E_FadeInGameTransition,
572
573 E_BlackOutTransition,
574 E_ResartGameAfterResetTransition
575 };
576
577 /*---------------------------------------------------------------------------*
578 Global variables
579 *---------------------------------------------------------------------------*/
580 typedef struct { f32 left, top, right, bottom; } RectF32;
581
582 //-----------------------
583 // For NW4R
584 //-----------------------
585 #if GAME_USES_NW4R
586 #include <nw4r/snd.h>
587 static const OSPriority SOUND_THREAD_PRIORITY = 4;
588 static const OSPriority DVD_THREAD_PRIORITY = 3;
589 #endif
590
591 //-----------------------
592 // For Memory
593 //-----------------------
594 MEMAllocator Allocator1;
595 MEMAllocator Allocator2;
596
597 //-----------------------
598 // For File read
599 //-----------------------
600 CNTHandle hCnt4, hCnt5;
601 #if HOME_BUTTON_MENU_3
602 CNTHandle hCnt6;
603 #endif
604
605 //-----------------------
606 // For Rendering
607 //-----------------------
608 const u32 C_nNumTweakEntries = sizeof(aTweakTbl)/sizeof(TweakEntry);
609
610 const GXRenderModeObj *pRmGame;
611 const GXRenderModeObj *pRmHBM;
612 const GXRenderModeObj *pRmManual;
613 const GXRenderModeObj *pRmManualNormal;
614 const GXRenderModeObj *pRmManualWide;
615 const GXRenderModeObj *pCurrentRenderMode;
616 const GXRenderModeObj *pPreviousRenderMode;
617
618 BOOL bProgressiveFlag;
619 BOOL bNonInterlaceFlag;
620 BOOL bSquashFlag;
621
622 Mtx44 mGameProjectionMtx;
623
624 s32 nGameEfbWidth;
625 s32 nGameXfbWidth;
626 s32 nGameXfbStride;
627 s32 nGameViWidth;
628 s32 nHbmEfbWidth;
629 s32 nHbmXfbStride;
630 s32 nHbmViWidth;
631 s32 nCurrentEfbRenderWidth;
632 f32 rHbmGxHalfWidth;
633 u32 nMaxXfbSize;
634 u8 nTVAspectRatio;
635 u8 nHbmAspectRatio;
636
637 f32 rGlobalAdjustRightCoord = 0.0f;
638
639 static void *pGXFifoBuffer;
640 static GXFifoObj *pGXFifoObj;
641
642 static void *apXFB[2];
643 static s32 nDisplayXFB;
644
645 GXTexObj toSample;
646 void *pSampleTextureData = NULL;
647
648 RectF32 rectGameEfb;
649 RectF32 rectScreen;
650
651 //-----------------------
652 // For Man viewer
653 //-----------------------
654 void *pManualData;
655
656 BOOL bAnyHomeButtonPressed;
657 BOOL bHomeButtonMenu;
658
659 const char *pCurrentURL;
660 char pTopPageURL[100];
661 char *pTopPage;
662
663 volatile s32 nSum;
664 u8 nInitialFocusController;
665
666 //-----------------------
667 // For Home Button Menu
668 //-----------------------
669 HBMDataInfo hbmInfo;
670
671 int nGameToHbmTransition1MaxFrame;
672 int nGameToHbmTransition2MaxFrame;
673 int nHbmToGameTransitionMaxFrame;
674 int nFadeInGameTransitionMaxFrame;
675 int nHbmVcmvState;
676 int nTransitionFrame;
677
678 u8 nGameFadeBrightnessLevel;
679
680 // The VCMV initialization routines do not require a large stack size
681 const int C_nVcmvInitThreadStackSize = 64*1024;
682
683 BOOL bTmpFilesCreated = FALSE;
684 void *pMyVcmvInitThreadStack = 0;
685 void *pHbmSoundInstanceBuf = 0;
686
687 #if HOME_BUTTON_MENU_3
688 u8* sound_data_ptr = NULL;
689 #endif
690
691 enum {
692 eAlphaInIcon = 0,
693 ePauseIcon,
694 eAlphaOutIcon
695 };
696
697 typedef struct {
698 TPLPalette *pTpl;
699 BOOL bOnFlag;
700 OSTick nTime;
701 s8 nState; // 0:AlphaIn, 1:Pause, 2:AlphaOut
702 u8 nAlpha;
703 } OverlayIconStruct;
704
705 OverlayIconStruct sBanHbmIcon; // Icon to indicate when HBM temporarily unavailable.
706
707 //-----------------------
708 // For Reset Function
709 //-----------------------
710 volatile BOOL bCalledHBMBlackOut;
711 volatile BOOL bResetButtonPressed = FALSE;
712 volatile BOOL bPowerButtonPressed = FALSE;
713
714 /*---------------------------------------------------------------------------*
715 Function Declaration
716 *---------------------------------------------------------------------------*/
717 //-----------------------
718 // MEMORY
719 //-----------------------
720 void MyInitAllocators(void);
721 void *MyAllocMem1(u32 size);
722 void *MyAllocMem2(u32 size);
723 u8 MyFreeMem1(void *addr);
724 u8 MyFreeMem2(void *addr);
725
726 //-----------------------
727 // FILE READ
728 //-----------------------
729 u32 MyContentReadFile(CNTHandle *phCnt, const char *pFileName, void **ppBuffer, MEMAllocator *pAlloc1, MEMAllocator *pAlloc2);
730
731 //-----------------------
732 // AUDIO
733 //-----------------------
734 void MyInitAudio(void);
735
736 //-----------------------
737 // RENDERING
738 //-----------------------
739 void ClearYUV(void *pPtr, u32 nSizeInBytes);
740 void ClearBorderYUV(void *pPtr);
741 void MyInitGX(void);
742 void MyUpdateRenderModes();
743 void MyInitDisplayMode(void);
744 void LoadTexture();
745 void MyDrawInit();
746 void SetupTexture(const GXTexObj *pTexObj, GXColor clr);
747 void DrawAxisAlignedRect(const RectF32 *pRect);
748 void SetupColorOnly(GXColor clr);
749 void DrawColorRect(const RectF32 *pRect);
750 void DrawTexture(const RectF32 *pRect, const GXTexObj *pTexObj, GXColor color);
751 void CompensateForModeChange(void);
752 void GameDrawTick(void);
753 void MyDrawDone(void);
754
755 //-------------------------
756 // MANUAL VIEWER
757 //-------------------------
758 void MyLoadManualData(void);
759 void MyVcmvDoneRenderCallback(u8 nFadeIn, const GXRenderModeObj *pRm);
760 void UpdateInitialFocusController(void);
761 void MyInitializeManualViewer(void *);
762 void MyCloseManualViewer(void);
763 void RunManualViewer(void);
764
765 //-------------------------------
766 // HOME BUTTON BAN ICON
767 //--------------------------------
768 void ActivateBanIcon(void);
769 void DrawBanIcon(void);
770
771 //------------------------------------
772 // HOME BUTTON MENU RELATED
773 //------------------------------------
774 static int MyHBMSoundCallback(int evt, int arg);
775 void MyInitHomeButtonMenu(void);
776 void SetupHbmGX(void);
777 void DrawBoxCursors(void);
778
779 //-----------------------
780 // RESET
781 //-----------------------
782 void ResetGame();
783 void MyPowerButtonCallback(void);
784 void MyResetButtonCallback(void);
785
786 //-----------------------
787 // CONTROLLER FUNCTIONS
788 //-----------------------
789 void MyReadControllers(void);
790
791 //-----------------------
792 // MAIN PROGRAM
793 //-----------------------
794 void Test(void);
795
796
797 /*---------------------------------------------------------------------------*
798 Functions
799 *---------------------------------------------------------------------------*/
800 //=============================================================================
801 // MEMORY FUNCTIONS
802 //=============================================================================
803 /*---------------------------------------------------------------------------*
804 Name: MyInitAllocators
805 *---------------------------------------------------------------------------*/
MyInitAllocators(void)806 void MyInitAllocators(void)
807 {
808 void *arenaLo, *arenaHi;
809 MEMHeapHandle heapHandle;
810
811 // Memory allocation managed by MEM library
812 arenaLo = OSGetMEM1ArenaLo();
813 arenaHi = OSGetMEM1ArenaHi();
814 heapHandle = MEMCreateExpHeap(arenaLo, (u32)arenaHi - (u32)arenaLo);
815 verbose(OSReport("MEMCreateExpHeap(%p, %p)\n", arenaLo, (u32)arenaHi - (u32)arenaLo););
816
817 if (heapHandle == MEM_HEAP_INVALID_HANDLE) {
818 OSHalt("MEM1 heap allocation error.\n");
819 }
820
821 OSSetMEM1ArenaLo(arenaHi);
822 MEMInitAllocatorForExpHeap(&Allocator1, heapHandle, 32);
823
824 // Heap on MEM2
825 arenaLo = OSGetMEM2ArenaLo();
826 arenaHi = OSGetMEM2ArenaHi();
827 heapHandle = MEMCreateExpHeap(arenaLo, (u32)arenaHi - (u32)arenaLo);
828 verbose(OSReport("MEMCreateExpHeap(%p, %p)\n", arenaLo, (u32)arenaHi - (u32)arenaLo););
829
830 if (heapHandle == MEM_HEAP_INVALID_HANDLE) {
831 OSHalt("MEM2 heap allocation error.\n");
832 }
833
834 OSSetMEM2ArenaLo(arenaHi);
835 MEMInitAllocatorForExpHeap(&Allocator2, heapHandle, 32);
836 }
837
838 /*---------------------------------------------------------------------------*
839 Name: MyAllocMem1
840 *---------------------------------------------------------------------------*/
MyAllocMem1(u32 size)841 void *MyAllocMem1(u32 size)
842 {
843 void *addr = MEMAllocFromAllocator(&Allocator1, size);
844 verbose(OSReport("MyAllocMem1 %d bytes @ 0x%08x\n", size, addr););
845
846 return addr;
847 }
848
849 /*---------------------------------------------------------------------------*
850 Name: MyFreeMem1
851 *---------------------------------------------------------------------------*/
MyFreeMem1(void * addr)852 u8 MyFreeMem1(void *addr)
853 {
854
855 MEMFreeToAllocator(&Allocator1, addr);
856 verbose(OSReport("MyFreeMem1 @ 0x%08x\n", addr););
857
858 return TRUE;
859 }
860
861 /*---------------------------------------------------------------------------*
862 Name: MyAllocMem2
863 *---------------------------------------------------------------------------*/
864
MyAllocMem2(u32 size)865 void *MyAllocMem2(u32 size)
866 {
867 void *addr = MEMAllocFromAllocator(&Allocator2, size);
868 verbose(OSReport("MyAllocMem2 %d bytes @ 0x%08x\n", size, addr););
869
870 return addr;
871 }
872
873 /*---------------------------------------------------------------------------*
874 Name: MyFreeMem2
875 --------------------------------------------------*/
MyFreeMem2(void * addr)876 u8 MyFreeMem2(void *addr)
877 {
878 MEMFreeToAllocator(&Allocator2, addr);
879 verbose(OSReport("MyFreeMem2 @ 0x%08x\n", addr););
880
881 return TRUE;
882 }
883
884 //============================================================================
885 // FILE READ FUNCTIONS
886 //============================================================================
887 /*---------------------------------------------------------------------------*
888 Name: MyContentReadFile
889 *---------------------------------------------------------------------------*/
MyContentReadFile(CNTHandle * phCnt,const char * pFileName,void ** ppBuffer,MEMAllocator * pAlloc1,MEMAllocator * pAlloc2)890 u32 MyContentReadFile(CNTHandle *phCnt, const char *pFileName, void **ppBuffer, MEMAllocator *pAlloc1, MEMAllocator *pAlloc2)
891 {
892 CNTFileInfo cfi;
893 u32 nSize, nRoundedUpSize;
894 u8 nCompression = 0;
895 s32 nResult;
896
897 nResult = CNTOpen(phCnt, pFileName, &cfi);
898 verbose(OSReport("CNTOpen(%p, \"%s\", %p) returned %d\n", phCnt, pFileName, (u32)&cfi, nResult););
899
900 if (nResult != CNT_RESULT_OK) {
901 return 0;
902 }
903
904 nSize = CNTGetLength(&cfi);
905 nRoundedUpSize = OSRoundUp32B(nSize);
906
907 if (strstr(pFileName, "/LZ77")) {
908 nCompression = CX_COMPRESSION_LZ;
909 } else if (strstr(pFileName, "/Huf8")) {
910 nCompression = CX_COMPRESSION_HUFFMAN;
911 }
912
913 verbose(OSReport("Compression=%d\n", nCompression););
914
915 if (nCompression) {
916 void *pTempBuf=0;
917 VCMVAllocIfNecessary(&pTempBuf, nRoundedUpSize, pAlloc1, pAlloc2);
918
919 if (pTempBuf) {
920 verbose(OSReport("Reading %p Bytes from %s to %p\n", nRoundedUpSize, pFileName, pTempBuf););
921
922 CNTRead(&cfi, pTempBuf, nRoundedUpSize);
923 nSize = CXGetUncompressedSize(pTempBuf);
924 nRoundedUpSize = OSRoundUp32B(nSize);
925 VCMVAllocIfNecessary(ppBuffer, nRoundedUpSize, pAlloc1, pAlloc2);
926 verbose(OSReport("Decompressing %p Bytes to %p\n", nRoundedUpSize, *ppBuffer););
927
928 if (*ppBuffer) {
929 if (nCompression==CX_COMPRESSION_LZ) {
930 CXUncompressLZ(pTempBuf, *ppBuffer);
931 } else {
932 CXUncompressHuffman(pTempBuf, *ppBuffer);
933 }
934 } else {
935 nSize = 0;
936 }
937
938 VCMVFreeAndClearPointer(&pTempBuf);
939 } else {
940 nSize = 0;
941 }
942 } else {
943 verbose(OSReport("VCMVAllocIfNecessary(%p, %d, %p %p)\n", *ppBuffer, nRoundedUpSize, pAlloc1, pAlloc2););
944 VCMVAllocIfNecessary(ppBuffer, nRoundedUpSize, pAlloc1, pAlloc2);
945 verbose(OSReport("ppBuffer=%p\n", *ppBuffer););
946
947 if (*ppBuffer) {
948
949 verbose(OSReport("Reading %p Bytes from %s to %p\n", nRoundedUpSize, pFileName, *ppBuffer););
950 CNTRead(&cfi, *ppBuffer, nRoundedUpSize);
951 } else {
952 nSize = 0;
953 }
954 }
955
956 CNTClose(&cfi);
957
958 return nSize;
959 }
960
961 //============================================================================
962 // AUDIO FUNCTION
963 //============================================================================
964 /*---------------------------------------------------------------------------*
965 Name: MyInitAudio
966 *---------------------------------------------------------------------------*/
MyInitAudio(void)967 void MyInitAudio(void)
968 {
969 static u8 bInitAX = TRUE;
970
971 if (bInitAX) {
972 AIInit(NULL);
973 AXInit();
974 AXSetMode(AX_MODE_STEREO);
975 #if GAME_USES_NW4R
976 nw4r::snd::SoundSystem::InitSoundSystem(SOUND_THREAD_PRIORITY, DVD_THREAD_PRIORITY);
977 #else
978 MIXInit();
979 MIXSetSoundMode(MIX_SOUND_MODE_STEREO);
980 #endif
981 bInitAX=FALSE;
982 }
983 }
984
985
986 //============================================================================
987 // RENDERING FUNCTIONS
988 //============================================================================
989 /*---------------------------------------------------------------------------*
990 Name: ClearYUV
991 *---------------------------------------------------------------------------*/
ClearYUV(void * pPtr,u32 nSizeInBytes)992 void ClearYUV(void *pPtr, u32 nSizeInBytes)
993 {
994 u32 *pPtrYUV = (u32*)pPtr;
995 u32 *pPtrEnd = (u32*)((u32)pPtr + nSizeInBytes);
996
997 verbose(OSReport("ClearYUV(%p, %d)\n", pPtr, nSizeInBytes););
998
999 while (pPtrYUV<pPtrEnd) {
1000 *pPtrYUV++ = 0x800080;
1001 }
1002
1003 DCFlushRange(pPtr, nSizeInBytes);
1004 }
1005
1006 /*---------------------------------------------------------------------------*
1007 Name: ClearBorderYUV
1008 *---------------------------------------------------------------------------*/
ClearBorderYUV(void * pPtr)1009 void ClearBorderYUV(void *pPtr)
1010 {
1011 u32 nBlackYUV = 0x800080;
1012 u32 *pPtrYUV = (u32*)pPtr;
1013 s32 nBorderSize = (pCurrentRenderMode->fbWidth - nCurrentEfbRenderWidth)>>1;
1014 s32 nEfbWidthInU32 = nCurrentEfbRenderWidth>>1;
1015 s32 nX, nY;
1016
1017 if (nBorderSize < 0) {
1018 OSHalt(".");
1019 }
1020
1021 for(nX=0; nX<(nBorderSize>>1); nX++) {
1022 *pPtrYUV++ = nBlackYUV;
1023 }
1024
1025 pPtrYUV += nEfbWidthInU32;
1026
1027 for(nY=1; nY<pCurrentRenderMode->viHeight; nY++) {
1028
1029 for(nX=0; nX<nBorderSize; nX++) {
1030 *pPtrYUV++ = nBlackYUV;
1031 }
1032
1033 pPtrYUV += nEfbWidthInU32;
1034 }
1035
1036 for(nX=0; nX<nBorderSize>>1; nX++) {
1037 *pPtrYUV++ = nBlackYUV;
1038 }
1039
1040 {
1041 u32 nSize = (u32)pPtrYUV - (u32)pPtr;
1042 DCFlushRange(pPtr, nSize);
1043 }
1044 }
1045
1046 /*---------------------------------------------------------------------------*
1047 Name: MyInitGX
1048 *---------------------------------------------------------------------------*/
MyInitGX(void)1049 void MyInitGX(void)
1050 {
1051 GXColor clear_clr = { 0,0,0,0 };
1052
1053 if (pGXFifoBuffer==0) {
1054 pGXFifoBuffer = MyAllocMem1(GX_FIFO_SIZE);
1055 pGXFifoObj = GXInit(pGXFifoBuffer, GX_FIFO_SIZE);
1056 }
1057
1058 // Set Pixel Format
1059 GXSetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
1060 GXSetDither(GX_DISABLE);
1061
1062 // Initialize parameters of EFB->XFB Copy-out
1063 GXSetDispCopySrc(0, 0, pCurrentRenderMode->fbWidth, pCurrentRenderMode->efbHeight);
1064 GXSetDispCopyDst(pCurrentRenderMode->fbWidth, pCurrentRenderMode->xfbHeight);
1065 GXSetCopyFilter(pCurrentRenderMode->aa, pCurrentRenderMode->sample_pattern, GX_TRUE, pCurrentRenderMode->vfilter);
1066 GXSetDispCopyYScale(GXGetYScaleFactor(pCurrentRenderMode->efbHeight, pCurrentRenderMode->xfbHeight));
1067 GXSetDispCopyGamma(GX_GM_1_0);
1068
1069 GXSetCopyClear(clear_clr, 0x00FFFFFF);
1070
1071 // Initialize EFB Rendering Area
1072 GXSetViewport(0.0f, 0.0f, (f32)pCurrentRenderMode->fbWidth, (f32)pCurrentRenderMode->efbHeight, 0.0f, 1.0f);
1073 GXSetScissor(0, 0, (u32)pCurrentRenderMode->fbWidth, (u32)pCurrentRenderMode->efbHeight);
1074
1075 // Clear EFB and XFB
1076 GXCopyDisp(apXFB[0], GX_ENABLE);
1077 GXDrawDone();
1078 }
1079
1080 /*---------------------------------------------------------------------------*
1081 Name: MyUpdateRenderModes
1082 *---------------------------------------------------------------------------*/
MyUpdateRenderModes()1083 void MyUpdateRenderModes()
1084 {
1085 // This function should be called after VCMVRun finishes
1086 #if ((PAL_MODE==0) || (PAL_MODE_SUPPORTS_PROGRESSIVE))
1087 bProgressiveFlag = (VIGetDTVStatus() && (SCGetProgressiveMode()==SC_PROGRESSIVE_MODE_ON));
1088 #else
1089 bProgressiveFlag = 0;
1090 #endif
1091 bNonInterlaceFlag = (~bProgressiveFlag) & VCMVGetNonInterlaceFlag() & GAME_SUPPORTS_NON_INTERLACE;
1092
1093 #if 0
1094 bSquashFlag = nTVAspectRatio & VCMVGetSquashFlag();
1095 #else
1096 bSquashFlag = nTVAspectRatio;
1097 #endif
1098
1099 verbose(
1100 OSReport("bProgressiveFlag = %d\n", bProgressiveFlag);
1101 OSReport("bNonInterlaceFlag = %d\n", bNonInterlaceFlag);
1102 OSReport("bSquashFlag = %d\n", bSquashFlag);
1103 );
1104
1105 pRmGame = &C_aRmGame[(4*bNonInterlaceFlag)+(2*bProgressiveFlag)+bSquashFlag];
1106 pRmHBM = &C_aRmHBM[(2*bProgressiveFlag)+nHbmAspectRatio];
1107 pRmManual = &C_aRmManual[(2*bProgressiveFlag)+bSquashFlag];
1108 pRmManualNormal = &C_aRmManual[2*bProgressiveFlag];
1109 pRmManualWide = &C_aRmManual[(2*bProgressiveFlag)+1];
1110
1111 if (bNonInterlaceFlag) {
1112 nGameToHbmTransition1MaxFrame = 10;
1113 nGameToHbmTransition2MaxFrame = 10;
1114 nHbmToGameTransitionMaxFrame = 45;
1115 nFadeInGameTransitionMaxFrame = 12;
1116 } else {
1117 nGameToHbmTransition1MaxFrame = 1;
1118 nGameToHbmTransition2MaxFrame = -BLACKOUT_TIME;
1119 nHbmToGameTransitionMaxFrame = 1;
1120 nFadeInGameTransitionMaxFrame = -BLACKOUT_TIME;
1121 }
1122
1123 if (bSquashFlag) {
1124 nGameEfbWidth = GAME_EFB_WIDTH_SQUASH;
1125 nGameXfbWidth = GAME_XFB_WIDTH_SQUASH;
1126 nGameViWidth = GAME_VI_WIDTH_SQUASH;
1127 } else {
1128 nGameEfbWidth = GAME_EFB_WIDTH_FULL;
1129 nGameXfbWidth = GAME_XFB_WIDTH_FULL;
1130 nGameViWidth = GAME_VI_WIDTH_FULL;
1131 }
1132
1133 if (nHbmAspectRatio) {
1134 nHbmEfbWidth = HBM_EFB_WIDTH_WIDE;
1135 } else {
1136 nHbmEfbWidth = HBM_EFB_WIDTH_NORMAL;
1137 }
1138
1139 verbose(OSReport("pRmHBM->viWidth=%d\n", pRmHBM->viWidth););
1140
1141 nGameXfbStride = VIPadFrameBufferWidth(nGameXfbWidth);
1142 nHbmXfbStride = VIPadFrameBufferWidth(nHbmEfbWidth);
1143 }
1144
1145 /*---------------------------------------------------------------------------*
1146 Name: MyInitDisplayMode
1147 *---------------------------------------------------------------------------*/
MyInitDisplayMode(void)1148 void MyInitDisplayMode(void)
1149 {
1150 s32 nI;
1151 nTVAspectRatio = SCGetAspectRatio();
1152 #if IGNORE_TV_ASPECT_RATIO
1153 nTVAspectRatio = 0;
1154 #endif
1155 nHbmAspectRatio = nTVAspectRatio;
1156 //nHbmAspectRatio = 0;
1157 MyUpdateRenderModes();
1158 nCurrentEfbRenderWidth = nGameEfbWidth;
1159
1160 // Allocate a double buffered XFB
1161 // First determine the maximum size required by the Game, HBM or Manual Viewer.
1162 // Allocate the maximum size so that the buffer does not need to be resized each
1163 // time the mode is changed.
1164 nMaxXfbSize = 0;
1165
1166 for(nI=0; nI<6; nI++) {
1167 u32 nSize = (u32)(VIPadFrameBufferWidth(C_aRmGame[nI].fbWidth) * C_aRmGame[nI].viHeight * VI_DISPLAY_PIX_SZ);
1168
1169 if (nMaxXfbSize < nSize) {
1170 nMaxXfbSize = nSize;
1171 }
1172 }
1173 for(nI=0; nI<4; nI++) {
1174 u32 nSize = (u32)(VIPadFrameBufferWidth(C_aRmHBM[nI].fbWidth) * C_aRmHBM[nI].viHeight * VI_DISPLAY_PIX_SZ);
1175
1176 if (nMaxXfbSize < nSize) {
1177 nMaxXfbSize = nSize;
1178 }
1179
1180 nSize = (u32)(VIPadFrameBufferWidth(C_aRmManual[nI].fbWidth) * C_aRmManual[nI].viHeight * VI_DISPLAY_PIX_SZ);
1181
1182 if (nMaxXfbSize < nSize) {
1183 nMaxXfbSize = nSize;
1184 }
1185
1186 }
1187 apXFB[0] = MyAllocMem2(nMaxXfbSize);
1188 apXFB[1] = MyAllocMem2(nMaxXfbSize);
1189 nDisplayXFB = 0;
1190
1191 verbose(OSReport("VIGetDTVStatus()=%d, SCGetProgressiveMode()=%d bSquashFlag=%d\n", VIGetDTVStatus(), SCGetProgressiveMode(), bSquashFlag););
1192 verbose(OSReport("nGameViWidth=%d, nGameXfbWidth=%d, nGameXfbStride=%d\n", nGameViWidth, nGameXfbWidth, nGameXfbStride););
1193
1194 // Clear EFB area in advance for HBM
1195 pCurrentRenderMode = pRmHBM;
1196 MyInitGX();
1197
1198 pCurrentRenderMode = pRmGame;
1199 MyInitGX();
1200
1201 // Clear XFB
1202 ClearYUV(apXFB[0], nMaxXfbSize);
1203 ClearYUV(apXFB[1], nMaxXfbSize);
1204
1205 // Initialize VI
1206 VIConfigure(pCurrentRenderMode);
1207 VISetNextFrameBuffer(apXFB[nDisplayXFB]);
1208 VIFlush();
1209
1210 // Wait 2 frames for new VI settings to take effect
1211 VIWaitForRetrace();
1212 VIWaitForRetrace();
1213 }
1214
1215 /*---------------------------------------------------------------------------*
1216 Name: LoadTexture
1217 *---------------------------------------------------------------------------*/
LoadTexture()1218 void LoadTexture()
1219 {
1220 char sFileName[64];
1221
1222 sprintf(sFileName, "sample%dx%d.rgb565", GAME_TEXTURE_WIDTH, GAME_TEXTURE_HEIGHT);
1223 verbose(OSReport("Loading %s\n", sFileName););
1224
1225 MyContentReadFile(&hCnt5, sFileName, &pSampleTextureData, &Allocator2, &Allocator1);
1226 GXInitTexObj (&toSample, pSampleTextureData, GAME_TEXTURE_WIDTH, GAME_TEXTURE_HEIGHT, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE);
1227 GXInitTexObjLOD(&toSample, GX_NEAR, GX_NEAR, 0, 0, 0, GX_FALSE, GX_FALSE, GX_ANISO_1);
1228 }
1229
1230 /*---------------------------------------------------------------------------*
1231 Name: MyDrawInit
1232 *---------------------------------------------------------------------------*/
MyDrawInit()1233 void MyDrawInit()
1234 {
1235 Mtx44 proj;
1236 GXColor clrBlack = { 0, 0, 0, 255 };
1237
1238 verbose(OSReport("MyDrawInit\n"););
1239 GXSetProjection(proj, GX_ORTHOGRAPHIC);
1240
1241 // Vertex Attribute
1242 GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_POS, GX_POS_XYZ, GX_S16, 0);
1243 GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_TEX0, GX_TEX_ST, GX_S16, 8);
1244 GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
1245 // Z compare, pixel format and background color
1246 GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
1247
1248 GXSetAlphaUpdate(GX_ENABLE);
1249 // Set number of tev stages, tex coord generators and color channels
1250 GXSetNumTevStages(1);
1251 GXSetNumTexGens(1);
1252 GXSetNumChans(0); // 1, Done
1253 GXSetCopyClear(clrBlack, 0x00FFFFFF);
1254 }
1255
1256 /*---------------------------------------------------------------------------*
1257 Name: SetupTexture
1258 *---------------------------------------------------------------------------*/
SetupTexture(const GXTexObj * pTexObj,GXColor clr)1259 void SetupTexture(const GXTexObj *pTexObj, GXColor clr)
1260 {
1261 GXClearVtxDesc();
1262 GXInvalidateVtxCache();
1263 GXInvalidateTexAll();
1264 GXSetVtxDesc(GX_VA_POS , GX_DIRECT);
1265 GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
1266 GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS , GX_POS_XYZ, GX_F32, 0);
1267 GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST , GX_U8 , 0);
1268 GXSetNumChans(0);
1269 GXSetNumTexGens(1);
1270 GXSetNumIndStages(0);
1271 GXSetNumTevStages(1);
1272 GXSetTevDirect( GX_TEVSTAGE0);
1273 GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO , GX_CC_C0 , GX_CC_TEXC , GX_CC_ZERO);
1274 GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO , GX_CA_A0 , GX_CA_TEXA , GX_CA_ZERO);
1275 GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD , GX_TB_ZERO , GX_CS_SCALE_1 , GX_TRUE , GX_TEVPREV);
1276 GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD , GX_TB_ZERO , GX_CS_SCALE_1 , GX_TRUE , GX_TEVPREV);
1277 GXSetTevOrder( GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0 , GX_COLOR_NULL);
1278 GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0 , GX_IDENTITY);
1279 GXSetColorUpdate(GX_ENABLE);
1280 GXSetAlphaUpdate(GX_ENABLE);
1281 GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_SET);
1282 GXSetZMode(GX_FALSE, GX_ALWAYS, GX_FALSE);
1283 GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
1284 GXSetCullMode(GX_CULL_NONE);
1285 GXSetClipMode(GX_CLIP_ENABLE);
1286 GXLoadTexObj(pTexObj, GX_TEXMAP0);
1287 GXSetTevColor(GX_TEVREG0, clr);
1288 }
1289
1290 /*---------------------------------------------------------------------------*
1291 Name: DrawAxisAlignedRect
1292 *---------------------------------------------------------------------------*/
DrawAxisAlignedRect(const RectF32 * pRect)1293 void DrawAxisAlignedRect(const RectF32 *pRect)
1294 {
1295 GXBegin(GX_QUADS, GX_VTXFMT0 , 4);
1296 GXPosition3f32(pRect->left , pRect->top , 0); GXTexCoord2u8(0, 0);
1297 GXPosition3f32(pRect->left , pRect->bottom, 0); GXTexCoord2u8(0, 1);
1298 GXPosition3f32(pRect->right, pRect->bottom, 0); GXTexCoord2u8(1, 1);
1299 GXPosition3f32(pRect->right, pRect->top , 0); GXTexCoord2u8(1, 0);
1300 GXEnd();
1301 }
1302
1303 /*---------------------------------------------------------------------------*
1304 Name: SetupColorOnly
1305 *---------------------------------------------------------------------------*/
SetupColorOnly(GXColor clr)1306 void SetupColorOnly(GXColor clr)
1307 {
1308 GXClearVtxDesc();
1309 GXInvalidateVtxCache();
1310 GXInvalidateTexAll();
1311 GXSetVtxDesc(GX_VA_POS , GX_DIRECT);
1312 GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
1313 GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS , GX_POS_XYZ , GX_F32 , 0);
1314 GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
1315
1316 GXSetNumChans(1);
1317 GXSetNumTexGens(0);
1318 GXSetNumIndStages(0);
1319 GXSetNumTevStages(1);
1320
1321 GXSetTevDirect( GX_TEVSTAGE0);
1322 GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_C0, GX_CC_RASC, GX_CC_ZERO);
1323 GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_A0, GX_CA_RASA, GX_CA_ZERO);
1324 GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
1325 GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
1326 GXSetTevOrder( GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
1327
1328 GXSetChanCtrl(GX_COLOR0A0, GX_DISABLE, GX_SRC_VTX, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_NONE);
1329
1330 GXSetColorUpdate(GX_ENABLE);
1331 GXSetAlphaUpdate(GX_ENABLE);
1332 GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_SET);
1333 GXSetZMode(GX_FALSE, GX_ALWAYS, GX_FALSE);
1334 GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
1335
1336 GXSetCullMode(GX_CULL_NONE);
1337 GXSetClipMode(GX_CLIP_ENABLE);
1338
1339 GXSetTevColor(GX_TEVREG0, clr);
1340 }
1341
1342 /*---------------------------------------------------------------------------*
1343 Name: DrawColorRect
1344 *---------------------------------------------------------------------------*/
DrawColorRect(const RectF32 * pRect)1345 void DrawColorRect(const RectF32 *pRect)
1346 {
1347 GXBegin(GX_QUADS, GX_VTXFMT0, 4);
1348 GXPosition3f32(pRect->left , pRect->top , 0); GXColor1u32(0xffffffff);
1349 GXPosition3f32(pRect->left , pRect->bottom, 0); GXColor1u32(0xffffffff);
1350 GXPosition3f32(pRect->right, pRect->bottom, 0); GXColor1u32(0xffffffff);
1351 GXPosition3f32(pRect->right, pRect->top , 0); GXColor1u32(0xffffffff);
1352 GXEnd();
1353 }
1354
1355 /*---------------------------------------------------------------------------*
1356 Name: DrawTexture
1357 *---------------------------------------------------------------------------*/
DrawTexture(const RectF32 * pRect,const GXTexObj * pTexObj,GXColor color)1358 void DrawTexture(const RectF32 *pRect, const GXTexObj *pTexObj, GXColor color)
1359 {
1360 SetupTexture(pTexObj, color);
1361 DrawAxisAlignedRect(pRect);
1362 }
1363
1364 /*---------------------------------------------------------------------------*
1365 Name: CompensateForModeChange
1366 *---------------------------------------------------------------------------*/
CompensateForModeChange(void)1367 void CompensateForModeChange(void)
1368 {
1369 // This function is used to ensure the game always covers the same part of the screen even when
1370 // the render mode is changed, as happens during HBM display and the fade out of VCMV.
1371 f32 rExpandX = 0.5f * (((f32)(pCurrentRenderMode->viWidth * nCurrentEfbRenderWidth * GAME_HARDWARE_WIDTH) / (f32)(nGameViWidth * pCurrentRenderMode->fbWidth)) - (f32)GAME_HARDWARE_WIDTH);
1372 f32 rExpandY = (f32)((pCurrentRenderMode->viHeight - GAME_VI_HEIGHT) * GAME_HARDWARE_HEIGHT) / (f32)(2 * GAME_VI_HEIGHT);
1373
1374 GXSetViewport(0.0f, 0.0f, (f32)nCurrentEfbRenderWidth, (f32)pCurrentRenderMode->efbHeight, 0.0f, 1.0f);
1375 GXSetScissor(0, 0, (u32)nCurrentEfbRenderWidth, (u32)pCurrentRenderMode->efbHeight);
1376
1377 verbose(
1378 if (pPreviousRenderMode != pCurrentRenderMode) {
1379 OSReport("\n");
1380 OSReport("pCurrentRenderMode->viWidth=%d\n", pCurrentRenderMode->viWidth);
1381 OSReport("nCurrentEfbRenderWidth=%d\n", nCurrentEfbRenderWidth);
1382 OSReport("pCurrentRenderMode->fbWidth=%d\n", pCurrentRenderMode->fbWidth);
1383 OSReport("pCurrentRenderMode->viHeight=%d\n", pCurrentRenderMode->viHeight);
1384 OSReport("GAME_VI_HEIGHT=%d\n", GAME_VI_HEIGHT);
1385 OSReport("GAME_HARDWARE_HEIGHT=%d\n", GAME_HARDWARE_HEIGHT);
1386 OSReport("\n");
1387 OSReport(" %3d %3d\n", pCurrentRenderMode->viWidth, nCurrentEfbRenderWidth);
1388 OSReport("rExpandX = ( --- x --- - 1.0 ) * %3d * 0.5 == %.1f\n", GAME_HARDWARE_WIDTH, rExpandX);
1389 OSReport(" %3d %3d\n", nGameViWidth, pCurrentRenderMode->fbWidth);
1390 OSReport("\n");
1391 OSReport(" %3d\n", GAME_HARDWARE_HEIGHT);
1392 OSReport("rExpandY = --- x ( %3d - %3d ) * 0.5 == %.1f\n", pCurrentRenderMode->viHeight, GAME_VI_HEIGHT, rExpandY);
1393 OSReport(" %3d\n", GAME_VI_HEIGHT);
1394 OSReport("\n");
1395 OSReport("GXSetViewport(0, 0, %d, %d, 0, 1)\n", nCurrentEfbRenderWidth, pCurrentRenderMode->efbHeight);
1396 OSReport("GXSetScissor(0, 0, %d, %d)\n", (u32)nCurrentEfbRenderWidth, (u32)pCurrentRenderMode->efbHeight);
1397 }
1398 );
1399
1400 rectGameEfb.top = -rExpandY;
1401 rectGameEfb.bottom = rExpandY + GAME_HARDWARE_HEIGHT;
1402
1403 rectGameEfb.left = -rExpandX;
1404 rectGameEfb.right = rExpandX + GAME_HARDWARE_WIDTH;
1405
1406 if (pCurrentRenderMode != pRmGame) {
1407 s32 nTweakIdx=0;
1408
1409 for(; nTweakIdx<C_nNumTweakEntries; nTweakIdx++) {
1410 TweakEntry *te = &aTweakTbl[nTweakIdx];
1411 if ((te->nGameXFB == pRmGame->fbWidth) &&
1412 (te->nGameVI == pRmGame->viWidth) &&
1413 (te->nCurrentXFB == pCurrentRenderMode->fbWidth) &&
1414 (te->nCurrentVI == pCurrentRenderMode->viWidth))
1415 {
1416 verbose(OSReport("Using Tweak: %.1f + GlobalAdjust:%.1f\n", te->rTweakR, rGlobalAdjustRightCoord););
1417 rectGameEfb.right -= te->rTweakR + rGlobalAdjustRightCoord;
1418
1419 goto Done;
1420 }
1421 }
1422
1423 verbose(OSReport("Using GlobalAdjust: %.1f\n", rGlobalAdjustRightCoord););
1424 rectGameEfb.right -= rGlobalAdjustRightCoord;
1425 }
1426
1427 Done:
1428 MTXOrtho(mGameProjectionMtx, rectGameEfb.top, rectGameEfb.bottom, rectGameEfb.left, rectGameEfb.right, 0.0f, -1.0f);
1429 }
1430
1431 /*---------------------------------------------------------------------------*
1432 Name: GameDrawTick
1433 *---------------------------------------------------------------------------*/
GameDrawTick(void)1434 void GameDrawTick(void)
1435 {
1436 GXColor clrGrey;
1437 GXColor clrBlack = { 0, 0, 0, 255 };
1438
1439 RectF32 rectGame = { 0, 0, GAME_HARDWARE_WIDTH, GAME_HARDWARE_HEIGHT };
1440 // Adjust the left and right coordinates of the game display area to compensate
1441 // for the display width changing while displaying the HBM / Manual Viewer
1442 GXInvalidateVtxCache();
1443 GXInvalidateTexAll();
1444
1445 if (pPreviousRenderMode != pCurrentRenderMode) {
1446 CompensateForModeChange();
1447 verbose(OSReport("MTXOrtho(proj, %.1f, %.1f, %.1f, %.1f, 0.0f, -1.0f)\n",
1448 rectGameEfb.top, rectGameEfb.bottom, rectGameEfb.left, rectGameEfb.right);
1449 );
1450 GXSetDispCopySrc(0, 0, (u16)nCurrentEfbRenderWidth, pCurrentRenderMode->efbHeight);
1451 GXSetDispCopyDst(pCurrentRenderMode->fbWidth, pCurrentRenderMode->xfbHeight);
1452 GXSetDispCopyYScale(GXGetYScaleFactor(pCurrentRenderMode->efbHeight, pCurrentRenderMode->xfbHeight));
1453 GXSetCopyFilter(pCurrentRenderMode->aa, pCurrentRenderMode->sample_pattern, GX_TRUE, pCurrentRenderMode->vfilter);
1454 GXSetCopyClear(clrBlack, 0x00FFFFFF); // Ensure the borders around the game image are black
1455 GXCopyDisp(apXFB[nDisplayXFB^1], GX_ENABLE); // Clear the EFB when the resolution changes
1456 pPreviousRenderMode = pCurrentRenderMode;
1457 *((u32*)apXFB[0]) = 0x12345678; // Magic number used to indicate XFB needs to be cleared before copyout
1458 *((u32*)apXFB[1]) = 0x12345678;
1459 verbose(
1460 OSReport("GXSetDispCopySrc(0, 0, %d, %d)\n", nCurrentEfbRenderWidth, pCurrentRenderMode->efbHeight);
1461 OSReport("GXSetDispCopyDst(%d, %d)\n", pCurrentRenderMode->fbWidth, pCurrentRenderMode->xfbHeight);
1462 OSReport("pCurrentRenderMode->Width = %d\n", pCurrentRenderMode->fbWidth);
1463 );
1464 }
1465
1466 GXSetProjection(mGameProjectionMtx, GX_ORTHOGRAPHIC);
1467
1468 // Perform the normal game rendering here
1469 GXSetNumTexGens(1); // Generate 1 texture coordinate for TEV: GX_TEXCOORD0
1470 GXSetNumChans(0); // Generate 0 color channels
1471 GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX3x4, GX_TG_TEX0, GX_IDENTITY);
1472
1473 GXSetNumTevStages(1);
1474 GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
1475 GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
1476
1477 GXClearVtxDesc();
1478 GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
1479 GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
1480
1481 clrGrey.r = clrGrey.g = clrGrey.b = nGameFadeBrightnessLevel;
1482 clrGrey.a = 255;
1483 DrawTexture(&rectGame, &toSample, clrGrey);
1484 }
1485
1486 /*---------------------------------------------------------------------------*
1487 Name: MyDrawDone
1488 *---------------------------------------------------------------------------*/
MyDrawDone(void)1489 void MyDrawDone(void)
1490 {
1491 s32 nXFBLeftOffset = (s32)(pCurrentRenderMode->fbWidth - nCurrentEfbRenderWidth);
1492
1493 if (nXFBLeftOffset&15) {
1494 OSHalt(".");
1495 }
1496
1497 nDisplayXFB ^= 1;
1498
1499 if (*((u32*)apXFB[nDisplayXFB]) == 0x12345678) {
1500 ClearYUV(apXFB[nDisplayXFB],nMaxXfbSize);
1501 //ClearBorderYUV(apXFB[nDisplayXFB]); // Clear the XFB after a mode change
1502 }
1503
1504 GXCopyDisp((void*)((u32)apXFB[nDisplayXFB] + nXFBLeftOffset), GX_ENABLE);
1505 GXDrawDone();
1506 // VI Configure is done here to ensure there is no garbled frame when switching between
1507 // the HBM / Manual Viewer resolution and the Game resolution.
1508 VIConfigure(pCurrentRenderMode);
1509 VISetNextFrameBuffer(apXFB[nDisplayXFB]);
1510 VIFlush();
1511 //verbose(OSReport("VBL(%d) ", nGameFadeBrightnessLevel););
1512 VIWaitForRetrace();
1513 }
1514
1515 //============================================================================
1516 // MANUAL VIEWER FUNCTIONS
1517 //============================================================================
1518 /*---------------------------------------------------------------------------*
1519 Name: MyLoadManualData
1520 *---------------------------------------------------------------------------*/
MyLoadManualData(void)1521 void MyLoadManualData(void)
1522 {
1523 const char * const ARC_PATH =
1524 #if defined REGION_JPN
1525 "html/JPN.arc";
1526 #elif defined REGION_EUR
1527 "html/EUR.arc";
1528 #elif defined REGION_KOR
1529 "html/KOR.arc";
1530 #elif defined REGION_CHN
1531 "html/CHN.arc";
1532 #else
1533 "html/USA.arc";
1534 #endif
1535
1536 u32 nSize = MyContentReadFile(&hCnt5, ARC_PATH, &pManualData, &Allocator2, &Allocator1);
1537
1538 #if USE_MEMORY_PROTOCOL
1539 VCMVSetMemoryContentsArcAddress(pManualData);
1540 #else
1541 // Write out html.arc to nand flash /tmp/html.arc
1542 NANDFileInfo nfi;
1543 NANDCreate("/tmp/html.arc", NAND_PERM_OWNER_READ|NAND_PERM_OWNER_WRITE, 0);
1544 NANDOpen("/tmp/html.arc", &nfi, NAND_ACCESS_WRITE);
1545 NANDWrite(&nfi, pManualData, nSize);
1546 NANDClose(&nfi);
1547 MyFreeMem2(pManualData);
1548 #endif
1549 }
1550
1551 /*---------------------------------------------------------------------------*
1552 Name: MyVcmvDoneRenderCallback
1553 *---------------------------------------------------------------------------*/
MyVcmvDoneRenderCallback(u8 nFadeIn,const GXRenderModeObj * pRm)1554 void MyVcmvDoneRenderCallback(u8 nFadeIn, const GXRenderModeObj *pRm)
1555 {
1556 #if GAME_SUPPORTS_NON_INTERLACE
1557 if (bNonInterlaceFlag != (BOOL)((~bProgressiveFlag) & VCMVGetNonInterlaceFlag())) {
1558 // User toggled Non-Interlace flag during VCMV
1559 verbose(OSReport("bNonInterlaceFlag changed: %d->%d\n", (s32)bNonInterlaceFlag, (s32)((~bProgressiveFlag)&VCMVGetNonInterlaceFlag())););
1560 MyUpdateRenderModes();
1561 }
1562 #endif
1563
1564 pCurrentRenderMode = pRm;
1565
1566 if (pPreviousRenderMode != pCurrentRenderMode) {
1567 // The user has changed the 16:9 stretch/squash mode during VCMV (Nunchuck 'Z' + Wii Remote 'A' + 'B')
1568 verbose(OSReport("pPreviousRenderMode: %p!=%p\n", pPreviousRenderMode, pCurrentRenderMode););
1569 MyUpdateRenderModes();
1570 nCurrentEfbRenderWidth = pCurrentRenderMode->fbWidth;
1571 CompensateForModeChange();
1572 GXSetDispCopySrc(0, 0, pCurrentRenderMode->fbWidth, pCurrentRenderMode->efbHeight);
1573 GXSetDispCopyDst(pCurrentRenderMode->fbWidth, pCurrentRenderMode->xfbHeight);
1574 GXSetDispCopyYScale(GXGetYScaleFactor(pCurrentRenderMode->efbHeight, pCurrentRenderMode->xfbHeight));
1575 GXSetCopyFilter(pCurrentRenderMode->aa, pCurrentRenderMode->sample_pattern, GX_TRUE, pCurrentRenderMode->vfilter);
1576 pPreviousRenderMode = pCurrentRenderMode;
1577 *((u32*)apXFB[0]) = 0x12345678; // Magic Number
1578 *((u32*)apXFB[1]) = 0x12345678;
1579 verbose(
1580 OSReport("GXSetDispCopySrc(0, 0, %d, %d)\n", nCurrentEfbRenderWidth, pCurrentRenderMode->efbHeight);
1581 OSReport("GXSetDispCopyDst(%d, %d)\n", pCurrentRenderMode->fbWidth, pCurrentRenderMode->xfbHeight);
1582 OSReport("pCurrentRenderMode->Width = %d\n", pCurrentRenderMode->fbWidth);
1583 );
1584 }
1585
1586 if (nFadeIn) {
1587 // FadeIn ramps from 0->255 as the Manual Viewer closes
1588 GXColor clrBlackAlpha;
1589 clrBlackAlpha.r = clrBlackAlpha.g = clrBlackAlpha.b = 0; clrBlackAlpha.a = nFadeIn;
1590 verbose(OSReport("nFadeIn=%d\n", (s32)nFadeIn););
1591 GXSetProjection(mGameProjectionMtx, GX_ORTHOGRAPHIC);
1592
1593 if (bNonInterlaceFlag) {
1594 // Fade out the VCMV by blending the EFB with a Black rectangle using the Alpha value
1595 RectF32 rect;
1596 rect.left = -150;
1597 rect.top = -150;
1598 rect.right = GAME_HARDWARE_WIDTH+150;
1599 rect.bottom = GAME_HARDWARE_HEIGHT+150;
1600 SetupColorOnly(clrBlackAlpha);
1601 DrawColorRect(&rect);
1602 } else {
1603 // Fade in the game by blending the game texture with the EFB using the Alpha value
1604 RectF32 rect;
1605 GXColor clrGreyAlpha;
1606 clrGreyAlpha.r = clrGreyAlpha.g = clrGreyAlpha.b = nGameFadeBrightnessLevel; clrGreyAlpha.a = nFadeIn;
1607 rect.left=0; rect.right=GAME_HARDWARE_WIDTH; rect.top=0; rect.bottom=GAME_HARDWARE_HEIGHT;
1608 DrawTexture(&rect, &toSample, clrGreyAlpha);
1609 // Fade out the borders around the game by blending with Black rectangles using the Alpha value
1610 SetupColorOnly(clrBlackAlpha);
1611 rect.left=-150; rect.right=GAME_HARDWARE_WIDTH+150; rect.top=-150; rect.bottom=0;
1612 DrawColorRect(&rect);
1613 rect.left=-150; rect.right=0; rect.top=0; rect.bottom=GAME_HARDWARE_HEIGHT;
1614 DrawColorRect(&rect);
1615 rect.left=GAME_HARDWARE_WIDTH; rect.right=GAME_HARDWARE_WIDTH+150; rect.top=-150; rect.bottom=GAME_HARDWARE_HEIGHT;
1616 DrawColorRect(&rect);
1617 rect.left=-150; rect.right=GAME_HARDWARE_WIDTH+150; rect.top=GAME_HARDWARE_HEIGHT; rect.bottom=GAME_HARDWARE_HEIGHT+150;
1618 DrawColorRect(&rect);
1619 }
1620 }
1621
1622 // Copy out, and switch VI to display the new XFB
1623 GXSetDispCopySrc(0, 0, pCurrentRenderMode->fbWidth, pCurrentRenderMode->efbHeight);
1624 GXSetDispCopyDst(pCurrentRenderMode->fbWidth, pCurrentRenderMode->xfbHeight);
1625 GXSetDispCopyYScale(GXGetYScaleFactor(pCurrentRenderMode->efbHeight, pCurrentRenderMode->xfbHeight));
1626 nDisplayXFB ^= 1;
1627 GXCopyDisp((void*)((u32)apXFB[nDisplayXFB]), GX_ENABLE);
1628 GXDrawDone();
1629 VIConfigure(pCurrentRenderMode);
1630 VISetNextFrameBuffer(apXFB[nDisplayXFB]);
1631 VIFlush();
1632 VIWaitForRetrace(); // Render thread will yield during this call
1633 }
1634
1635 /*---------------------------------------------------------------------------*
1636 Name: UpdateInitialFocusController
1637 *---------------------------------------------------------------------------*/
UpdateInitialFocusController(void)1638 void UpdateInitialFocusController(void)
1639 {
1640 u8 nI;
1641
1642 for(nI=0; nI<WPAD_MAX_CONTROLLERS; nI++) {
1643
1644 if (VCMV_HBMControllerData.wiiCon[nI].kpad) {
1645
1646 if (VCMV_HBMControllerData.wiiCon[nI].use_devtype == WPAD_DEV_CORE) {
1647 if (VCMV_HBMControllerData.wiiCon[nI].kpad->trig & KPAD_BUTTON_A) {
1648 nInitialFocusController = nI;
1649 }
1650 } else {
1651 if (VCMV_HBMControllerData.wiiCon[nI].kpad->ex_status.cl.trig & KPAD_CL_BUTTON_A) {
1652 nInitialFocusController = nI;
1653 }
1654 }
1655 }
1656 }
1657 }
1658
1659 /*---------------------------------------------------------------------------*
1660 Name: RunManualViewer
1661 *---------------------------------------------------------------------------*/
RunManualViewer(void)1662 void RunManualViewer(void)
1663 {
1664 s32 nHeapSize = 20 * 1024 * 1024;
1665
1666 if (pCurrentURL==0) {
1667 pCurrentURL = pTopPageURL;
1668 }
1669
1670 pCurrentRenderMode = pRmManual;
1671 nCurrentEfbRenderWidth = pCurrentRenderMode->fbWidth;
1672 VIConfigure(pCurrentRenderMode);
1673 VIFlush();
1674
1675 #if IGNORE_TV_ASPECT_RATIO
1676 VCMVSetRenderModes(pRmManualNormal, pRmManualNormal, GAME_SUPPORTS_NON_INTERLACE & ~bProgressiveFlag);
1677 VCMVAllocateRenderingBuffers(BROWSER_FB_WIDTH, BROWSER_FB_HEIGHT);
1678 #else
1679 if (nTVAspectRatio == SC_ASPECT_RATIO_4x3) {
1680 VCMVSetRenderModes(pRmManualNormal, pRmManualNormal, GAME_SUPPORTS_NON_INTERLACE & ~bProgressiveFlag);
1681 VCMVAllocateRenderingBuffers(BROWSER_FB_WIDTH, BROWSER_FB_HEIGHT);
1682 } else {
1683 VCMVSetRenderModes(pRmManualWide, pRmManualWide, GAME_SUPPORTS_NON_INTERLACE & ~bProgressiveFlag);
1684 VCMVAllocateRenderingBuffers(W_BROWSER_FB_WIDTH, BROWSER_FB_HEIGHT);
1685 }
1686 #endif
1687
1688 VCMVSetScrollBarWidth(12);
1689
1690 for(;nHeapSize>0; nHeapSize-=1024*1024) {
1691 if (VCMVAllocateHeap((u32)nHeapSize)) {
1692 break;
1693 }
1694 }
1695
1696 verbose(OSReport("HeapSize = %p\n", nHeapSize););
1697
1698 if (nHeapSize <= 0) {
1699 OSHalt(".");
1700 }
1701
1702 VCMVSetTopPageURL(pTopPageURL);
1703
1704 verbose(
1705 OSReport("FreeMem Mem1=%p Mem2=%p\n",
1706 MEMGetAllocatableSizeForExpHeapEx((MEMHeapHandle)Allocator1.pHeap, 32),
1707 MEMGetAllocatableSizeForExpHeapEx((MEMHeapHandle)Allocator2.pHeap, 32));
1708 );
1709
1710 verbose(OSReport("VCMVRun(\"%s\", %d)\n", pCurrentURL, nInitialFocusController););
1711
1712 pCurrentURL = VCMVRun(MyVcmvDoneRenderCallback, pCurrentURL, nInitialFocusController);
1713 MyUpdateRenderModes();
1714 nCurrentEfbRenderWidth = nGameEfbWidth;
1715 verbose(OSReport("Final URL: \"%s\"\n", pCurrentURL););
1716
1717 verbose(
1718 OSReport("FreeMem Mem1=%p Mem2=%p\n",
1719 MEMGetAllocatableSizeForExpHeapEx((MEMHeapHandle)Allocator1.pHeap, 32),
1720 MEMGetAllocatableSizeForExpHeapEx((MEMHeapHandle)Allocator2.pHeap, 32));
1721 );
1722 }
1723
1724 /*---------------------------------------------------------------------------*
1725 Name: MyInitializeManualViewer
1726 *---------------------------------------------------------------------------*/
MyInitializeManualViewer(void *)1727 void MyInitializeManualViewer(void *)
1728 {
1729 // This function can be registered as the idle function in order to
1730 // load initialize the Manual Viewer in the background.
1731 verbose(OSReport("MyInitializeManualViewer\n"););
1732 VCMVAllocateAndLoadBrowserComponent(BROWSER_RSO_CIDX, FONT_CIDX);
1733 MyLoadManualData();
1734 }
1735
1736 /*---------------------------------------------------------------------------*
1737 Name: MyCloseManualViewer
1738 *---------------------------------------------------------------------------*/
MyCloseManualViewer(void)1739 void MyCloseManualViewer(void)
1740 {
1741 verbose(OSReport("MyCloseManualViewer\n"););
1742 VCMVFreeRenderingBuffers();
1743 VCMVFreeHeap();
1744 #if USE_MEMORY_PROTOCOL
1745 VCMVFreeAndClearPointer(&pManualData);
1746 #endif
1747 VCMVCloseAndFreeBrowserComponent();
1748 verbose(OSReport("MyCloseManualViewer finished\n"););
1749 }
1750
1751
1752 //============================================================================
1753 // HOME BUTTON BAN ICON FUNCTIONS
1754 //============================================================================
1755 /*---------------------------------------------------------------------------*
1756 Name: ActivateBanIcon
1757 *---------------------------------------------------------------------------*/
ActivateBanIcon(void)1758 void ActivateBanIcon(void)
1759 {
1760 sBanHbmIcon.nState = eAlphaInIcon;
1761 sBanHbmIcon.bOnFlag = TRUE;
1762 sBanHbmIcon.nTime = OSGetTick();
1763 sBanHbmIcon.nAlpha = 0;
1764 }
1765
1766 /*---------------------------------------------------------------------------*
1767 Name: DrawBanIcon
1768 *---------------------------------------------------------------------------*/
DrawBanIcon(void)1769 void DrawBanIcon(void)
1770 {
1771 // �֎~�A�C�R���̕`��
1772 // Update & Draw HOME Button Menu "Ban Icon" (== temporarily unavailable icon)
1773 GXTexObj texObj;
1774 f32 elapse = OSTicksToMilliseconds(OSDiffTick(OSGetTick(), sBanHbmIcon.nTime));
1775
1776 switch (sBanHbmIcon.nState) {
1777 case eAlphaInIcon: // AlphaIn(250ms)
1778 sBanHbmIcon.nAlpha = (u8)(255.9f * (elapse / 250.f));
1779
1780 if (elapse >= 250.f) {
1781 sBanHbmIcon.nTime = OSGetTick();
1782 sBanHbmIcon.nState = ePauseIcon;
1783 sBanHbmIcon.nAlpha = 255;
1784 }
1785
1786 break;
1787 case ePauseIcon: // Pause(1000ms)
1788
1789 if (elapse >= 1000.f) {
1790 sBanHbmIcon.nTime = OSGetTick();
1791 sBanHbmIcon.nState = eAlphaOutIcon;
1792 }
1793
1794 break;
1795 case eAlphaOutIcon: // AlphaOut(250ms)
1796 sBanHbmIcon.nAlpha = (u8)(255.9f * ((250.f - elapse) / 250.f));
1797
1798 if (elapse >= 250.f) {
1799 sBanHbmIcon.nAlpha = 0;
1800 sBanHbmIcon.bOnFlag = FALSE;
1801 }
1802
1803 break;
1804 }
1805
1806 GXClearVtxDesc();
1807 GXSetVtxAttrFmt(GX_VTXFMT5, GX_VA_POS, GX_POS_XY, GX_S16, 0);
1808 GXSetVtxAttrFmt(GX_VTXFMT5, GX_VA_TEX0, GX_TEX_ST, GX_S16, 0);
1809 GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
1810 GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
1811 GXSetNumChans(1);
1812 GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_VTX, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE);
1813 GXSetNumTexGens(1);
1814 GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
1815 GXSetNumTevStages(1);
1816 GXSetTevColor(GX_TEVREG0, (GXColor){255, 255, 255, sBanHbmIcon.nAlpha});
1817 GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
1818 GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC);
1819 GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
1820 GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_A0, GX_CA_TEXA, GX_CA_ZERO);
1821 GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
1822 GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
1823 GXSetZMode(GX_FALSE, GX_LEQUAL, GX_FALSE);
1824 GXSetCurrentMtx(GX_PNMTX1);
1825 TPLGetGXTexObjFromPalette(sBanHbmIcon.pTpl, &texObj, 0);
1826 GXLoadTexObj(&texObj, GX_TEXMAP0);
1827
1828 // The display position can be anywhere inside the guaranteed visible screen area (safety frame).
1829 // �`��ʒu�͈��S�t���[�����Ȃ�ǂ��ł��ǂ�
1830 {
1831 s16 nL = (s16)(( 48 * GAME_HARDWARE_WIDTH) / 608);
1832 s16 nR = (s16)((104 * GAME_HARDWARE_WIDTH) / 608);
1833 s16 nT = (s16)(( 40 * GAME_HARDWARE_HEIGHT) / 456);
1834 s16 nB = (s16)(( 96 * GAME_HARDWARE_HEIGHT) / 456);
1835 GXBegin(GX_QUADS, GX_VTXFMT5, 4);
1836 GXPosition2s16(nL, nB); GXTexCoord2s16(0, 1);
1837 GXPosition2s16(nL, nT); GXTexCoord2s16(0, 0);
1838 GXPosition2s16(nR, nT); GXTexCoord2s16(1, 0);
1839 GXPosition2s16(nR, nB); GXTexCoord2s16(1, 1);
1840 GXEnd();
1841 }
1842 }
1843
1844 //============================================================================
1845 // RESET FUNCTIONS
1846 //============================================================================
1847 /*---------------------------------------------------------------------------*
1848 Name: ResetGame
1849 *---------------------------------------------------------------------------*/
ResetGame()1850 void ResetGame()
1851 {
1852 // Note: The screen should already be BLACK when this function is called
1853 // ** TODO: Perform game soft reset here. **
1854 verbose(OSReport("GAME RESET.\n"););
1855 pCurrentRenderMode = pRmGame;
1856 nCurrentEfbRenderWidth = nGameEfbWidth;
1857 bResetButtonPressed = FALSE;
1858 }
1859
1860 /*---------------------------------------------------------------------------*
1861 Name: MyPowerButtonCallback
1862 *---------------------------------------------------------------------------*/
MyPowerButtonCallback(void)1863 void MyPowerButtonCallback(void)
1864 {
1865 bCalledHBMBlackOut = FALSE;
1866 bPowerButtonPressed = TRUE;
1867
1868 if (nHbmVcmvState == E_InVcmv) {
1869 VCMVBlackOutAndQuit(30);
1870 nGameFadeBrightnessLevel=0; // To ensure VCMV fades out to Black in progressive mode
1871 }
1872 }
1873
1874 /*---------------------------------------------------------------------------*
1875 Name: MyResetButtonCallback
1876 *---------------------------------------------------------------------------*/
MyResetButtonCallback(void)1877 void MyResetButtonCallback(void)
1878 {
1879 bCalledHBMBlackOut = FALSE;
1880 bResetButtonPressed = TRUE;
1881
1882 if (nHbmVcmvState == E_InVcmv) {
1883 VCMVBlackOutAndQuit(30);
1884 nGameFadeBrightnessLevel=0; // To ensure VCMV fades out to Black in progressive mode
1885 }
1886 }
1887
1888 //============================================================================
1889 // CONTROLLER FUNCTIONS
1890 //============================================================================
1891 /*---------------------------------------------------------------------------*
1892 Name: MyReadControllers
1893 *---------------------------------------------------------------------------*/
MyReadControllers(void)1894 void MyReadControllers(void)
1895 {
1896 u8 nI;
1897 #if FILTER_KPAD
1898 static u32 aOldHoldClassic[4][2];
1899 for(nI=0; nI<WPAD_MAX_CONTROLLERS; nI++) {
1900 KPADStatus *kps = VCMV_HBMControllerData.wiiCon[nI].kpad;
1901
1902 if (kps) {
1903 // Replace the original KPAD so kpad.a can't tell we changed it
1904 kps->ex_status.cl.hold = aOldHoldClassic[nI][1];
1905 }
1906 }
1907 #endif
1908 VCMVReadControllersForHBM();
1909 bAnyHomeButtonPressed = FALSE;
1910
1911 for(nI=0; nI<WPAD_MAX_CONTROLLERS; nI++) {
1912 KPADStatus *kps = VCMV_HBMControllerData.wiiCon[nI].kpad;
1913
1914 if (kps) {
1915 #if IGNORE_TV_ASPECT_RATIO
1916 // Important Bug Fix! This is necessary otherwise the cursor X position will be
1917 // scaled incorrectly within the HBM in the case where IGNORE_TV_ASPECT_RATIO and
1918 // VCMVGetSquashFlag are both set. HBM Version 3.0.1 makes this problem more
1919 // noticable because the cursor cannot reach the edge of the screen.
1920 // The behaviour can be tested by using the vcmvmenu_*.wad tool to set the squash flag.
1921 if (VCMVGetSquashFlag()) {
1922 VCMV_HBMControllerData.wiiCon[nI].pos.x *= 1.3333;
1923 kps->pos.x *= 1.3333;
1924 }
1925 #endif
1926 #if FILTER_KPAD
1927 // Filter KPAD release signal to delay Home Button Release by one frame
1928 aOldHoldClassic[nI][1] = kps->ex_status.cl.hold;
1929 kps->ex_status.cl.hold |= kps->ex_status.cl.release & KPAD_CL_BUTTON_HOME;
1930 kps->ex_status.cl.trig = kps->ex_status.cl.hold & ~aOldHoldClassic[nI][0];
1931 kps->ex_status.cl.release = ~kps->ex_status.cl.hold & aOldHoldClassic[nI][0];
1932 aOldHoldClassic[nI][0] = kps->ex_status.cl.hold;
1933 #endif
1934 #if MANUALLY_ADJUSTED_TWEAK
1935
1936 if (kps->trig & KPAD_BUTTON_RIGHT) {
1937 rGlobalAdjustRightCoord += 0.1f;
1938 OSReport("rGlobalAdjustRightCoord = %0.1f\n", rGlobalAdjustRightCoord);
1939 } else if (kps->trig & KPAD_BUTTON_LEFT) {
1940 rGlobalAdjustRightCoord -= 0.1f;
1941 OSReport("rGlobalAdjustRightCoord = %0.1f\n", rGlobalAdjustRightCoord);
1942 }
1943 #endif
1944 // Wait for KPAD_BUTTON_1 after reset button is pressed. Then fade-in start screen again.
1945 if ((kps->trig==KPAD_BUTTON_1)&&(nHbmVcmvState==E_BlackOutTransition)&&(bResetButtonPressed==FALSE)) {
1946 VISetBlack(FALSE);
1947 VIFlush();
1948 nHbmVcmvState = E_ResartGameAfterResetTransition;
1949 OSSetResetCallback(MyResetButtonCallback);
1950 }
1951
1952 #if TEST_BAN_ICON
1953 if ((nHbmVcmvState==E_InGame) && !sBanHbmIcon.bOnFlag && (kps->trig==KPAD_BUTTON_PLUS)) {
1954 nHbmVcmvState = E_InGamePlusBanIcon;
1955 ActivateBanIcon();
1956 }
1957 #endif
1958 if ((kps->trig&KPAD_BUTTON_HOME) ||
1959 ((kps->dev_type==WPAD_DEV_CLASSIC) && (kps->ex_status.cl.trig&KPAD_CL_BUTTON_HOME))) {
1960 bAnyHomeButtonPressed = TRUE;
1961 nInitialFocusController = nI;
1962 }
1963 }
1964 }
1965 }
1966
1967
1968 //============================================================================
1969 // HOME BUTTON MENU RELATED
1970 //============================================================================
1971 /*---------------------------------------------------------------------------*
1972 Name: MyHBMSoundCallback
1973 *---------------------------------------------------------------------------*/
MyHBMSoundCallback(int evt,int arg)1974 static int MyHBMSoundCallback(int evt, int arg)
1975 {
1976 #if GAME_INTERACED
1977 #pragma unused(arg)
1978 #else
1979 if ((evt == HBMSEV_PLAY_SOUND) && (arg == HBMSE_RETURN_APP)) {
1980 // If the game is using non-interlace mode, we need to fade to black before switching
1981 // back to non-interlace mode. In order to minimise the number of screen transitions,
1982 // we start fading to black at the same time as the user exits the home button menu.
1983 nTransitionFrame = 0;
1984 nHbmVcmvState = E_HbmToGameTransition;
1985 }
1986 #endif
1987 //verbose(OSReport("SoundCallback: %d, %d\n", evt, arg););
1988 #if INITIALIZE_IN_THREAD
1989 if (evt == HBMSEV_BEGIN_BLACKOUT_TO_MANUAL) {
1990 // Start initializing the manual viewer in the background
1991 verbose(OSReport("Starting Manual Viewer Initialization Thread\n"););
1992 VCMVAllocIfNecessary(&pMyVcmvInitThreadStack, C_nVcmvInitThreadStackSize, &Allocator1, &Allocator2);
1993 OSSetIdleFunction(MyInitializeManualViewer, 0, (void*)((u32)pMyVcmvInitThreadStack+C_nVcmvInitThreadStackSize),
1994 C_nVcmvInitThreadStackSize);
1995 }
1996 #endif
1997 return HBMSEV_RET_NONE;
1998 }
1999
2000 /*---------------------------------------------------------------------------*
2001 Name: MyInitHomeButtonMenu
2002 *---------------------------------------------------------------------------*/
MyInitHomeButtonMenu(void)2003 void MyInitHomeButtonMenu(void)
2004 {
2005 #if HOME_BUTTON_MENU_3
2006 const char *pNandSoundFullPath = "/tmp/HBMSE.arc";
2007 char aSeFullPath[32] = "HomeButtonSe/";
2008 char *pSeFileName = &aSeFullPath[strlen(aSeFullPath)];
2009 #else
2010 const char *pNandSoundFullPath = "/tmp/HBMSE.brsar";
2011 #endif
2012 const char *pOperaIniFilesFullPath = "/tmp/opera.arc";
2013 char aFullPath[32] = "HomeButton3/";
2014 char *pFileName = &aFullPath[strlen(aFullPath)];
2015
2016 CNTInitHandle(4, &hCnt4, &Allocator2);
2017
2018 #if HOME_BUTTON_MENU_3
2019 CNTInitHandle(6, &hCnt6, &Allocator2);
2020 #endif
2021 if (!bTmpFilesCreated) {
2022 // The first time this function is run, copy the sound effects file to the NAND /tmp directory
2023 // where it can be accessed by the Home Button Menu library
2024 NANDFileInfo nfi;
2025 void *pTempBuf=0; // VCMVAllocFrame
2026 u32 nSize;
2027 s32 nResult;
2028 bTmpFilesCreated = TRUE;
2029 #if HOME_BUTTON_MENU_3
2030 strcpy(pSeFileName, "Huf8_HomeButtonSe.arc");
2031 nSize = MyContentReadFile(&hCnt6, aSeFullPath, (void **)&sound_data_ptr, &Allocator2, &Allocator1);
2032 #else
2033 strcpy(pFileName, "Huf8_HomeButtonSe.brsar");
2034 nSize = MyContentReadFile(&hCnt4, aFullPath, &pTempBuf, &Allocator2, &Allocator1);
2035 nResult = NANDCreate(pNandSoundFullPath, NAND_PERM_OWNER_READ|NAND_PERM_OWNER_WRITE, 0);
2036 verbose(OSReport("NANDCreate: %d\n", nResult););
2037 nResult = NANDOpen(pNandSoundFullPath, &nfi, NAND_ACCESS_WRITE);
2038 verbose(OSReport("NANDOpen: %d\n", nResult););
2039 nResult = NANDWrite(&nfi, pTempBuf, nSize);
2040 verbose(OSReport("NANDWrite: %d\n", nResult););
2041 nResult = NANDClose(&nfi);
2042 verbose(OSReport("NANDClose: %d\n", nResult););
2043 VCMVFreeAndClearPointer(&pTempBuf);
2044 #endif
2045
2046 nSize = MyContentReadFile(&hCnt5, "Opera.arc", &pTempBuf, &Allocator2, &Allocator1);
2047 nResult = NANDCreate(pOperaIniFilesFullPath, NAND_PERM_OWNER_READ|NAND_PERM_OWNER_WRITE, 0);
2048 verbose(OSReport("NANDCreate: %d\n", nResult););
2049 nResult = NANDOpen(pOperaIniFilesFullPath, &nfi, NAND_ACCESS_WRITE);
2050 verbose(OSReport("NANDOpen: %d\n", nResult););
2051 nResult = NANDWrite(&nfi, pTempBuf, nSize);
2052 verbose(OSReport("NANDWrite: %d\n", nResult););
2053 nResult = NANDClose(&nfi);
2054 verbose(OSReport("NANDClose: %d\n", nResult););
2055 VCMVFreeAndClearPointer(&pTempBuf);
2056 }
2057
2058
2059 #if USE_MEMORY_PROTOCOL
2060 strcpy(pTopPageURL, "arc:/html/");
2061 #else
2062 strcpy(pTopPageURL, "file:/flash/tmp/html.arc/html/");
2063 #endif
2064 pTopPage = &pTopPageURL[strlen(pTopPageURL)];
2065
2066
2067 #if defined REGION_JPN
2068
2069 // For JAPANESE releases:
2070 hbmInfo.region=SCGetLanguage();
2071
2072 switch (hbmInfo.region) {
2073 case SC_LANG_KOREAN:
2074 OSHalt("Warning: Wrong Language Setting! \n");
2075 break;
2076 case SC_LANG_SIMP_CHINESE:
2077 OSHalt("Warning: Wrong Language Setting! \n");
2078 break;
2079 default:
2080 case SC_LANG_JAPANESE:
2081 strcpy(pFileName, "LZ77_homeBtn.arc");
2082 strcpy(pTopPage, "index/index_Frameset.html");
2083 break;
2084 }
2085
2086 #elif defined REGION_EUR
2087
2088 // For EUROPEAN releases:
2089 hbmInfo.region=SCGetLanguage();
2090 switch (hbmInfo.region) {
2091 case SC_LANG_GERMAN:
2092 strcpy(pFileName, "LZ77_homeBtn_GER.arc");
2093 strcpy(pTopPage, "startup_noe.html");
2094 break;
2095 case SC_LANG_FRENCH:
2096 strcpy(pFileName, "LZ77_homeBtn_FRA.arc");
2097 strcpy(pTopPage, "startup_fra.html");
2098 break;
2099 case SC_LANG_SPANISH:
2100 strcpy(pFileName, "LZ77_homeBtn_SPA.arc");
2101 strcpy(pTopPage, "startup_esp.html");
2102 break;
2103 case SC_LANG_ITALIAN:
2104 strcpy(pFileName, "LZ77_homeBtn_ITA.arc");
2105 strcpy(pTopPage, "startup_ita.html");
2106 break;
2107 case SC_LANG_DUTCH:
2108 strcpy(pFileName, "LZ77_homeBtn_NED.arc");
2109 strcpy(pTopPage, "startup_hol.html");
2110 break;
2111 case SC_LANG_KOREAN:
2112 OSHalt("Warning: Wrong Language Setting! \n");
2113 break;
2114 case SC_LANG_SIMP_CHINESE:
2115 OSHalt("Warning: Wrong Language Setting! \n");
2116 break;
2117 default:
2118 case SC_LANG_ENGLISH:
2119 strcpy(pFileName, "LZ77_homeBtn_ENG.arc");
2120 strcpy(pTopPage, "startup.html");
2121 break;
2122 }
2123
2124 #elif defined REGION_KOR
2125
2126 // For KOREAN releases:
2127 hbmInfo.region=SCGetLanguage();
2128
2129 switch (hbmInfo.region) {
2130 case SC_LANG_KOREAN:
2131 strcpy(pFileName, "LZ77_homeBtn_KOR.arc");
2132 strcpy(pTopPage, "index/index_Frameset.html");
2133 break;
2134 default:
2135 OSHalt("Warning: Wrong Language Setting! \n");
2136 }
2137
2138 #elif defined REGION_CHN
2139
2140 // For CHINESE releases:
2141 hbmInfo.region=SCGetLanguage();
2142
2143 switch (hbmInfo.region) {
2144 case SC_LANG_SIMP_CHINESE:
2145 strcpy(pFileName, "LZ77_homeBtn_CHN.arc");
2146 strcpy(pTopPage, "startup.html");
2147 break;
2148 case SC_LANG_TRAD_CHINESE:
2149 strcpy(pFileName, "LZ77_homeBtn_CHN.arc");
2150 strcpy(pTopPage, "startup.html");
2151 break;
2152 default:
2153 OSHalt("Warning: Wrong Language Setting! \n");
2154 }
2155
2156 #else
2157 //#elif defined REGION_USA
2158
2159 // For US releases:
2160 hbmInfo.region=SCGetLanguage();
2161 switch (hbmInfo.region) {
2162 case SC_LANG_FRENCH:
2163 strcpy(pFileName, "LZ77_homeBtn_FRA.arc");
2164 strcpy(pTopPage, "startup_fra.html");
2165 break;
2166 case SC_LANG_SPANISH:
2167 strcpy(pFileName, "LZ77_homeBtn_SPA.arc");
2168 strcpy(pTopPage, "startup_esp.html");
2169 break;
2170 case SC_LANG_KOREAN:
2171 OSHalt("Warning: Wrong Language Setting! \n");
2172 break;
2173 case SC_LANG_SIMP_CHINESE:
2174 OSHalt("Warning: Wrong Language Setting! \n");
2175 break;
2176 default:
2177 case SC_LANG_ENGLISH:
2178 strcpy(pFileName, "LZ77_homeBtn_ENG.arc");
2179 strcpy(pTopPage, "startup.html");
2180 break;
2181 }
2182
2183 #endif
2184
2185 verbose(OSReport("Language = %d\n", hbmInfo.region););
2186 MyContentReadFile(&hCnt4, aFullPath, &hbmInfo.layoutBuf, &Allocator2, &Allocator1);
2187 strcpy(pFileName, "Huf8_SpeakerSe.arc");
2188 MyContentReadFile(&hCnt4, aFullPath, &hbmInfo.spkSeBuf, &Allocator2, &Allocator1);
2189 #ifdef HBM_NO_SAVE
2190 strcpy(pFileName, "home_nosave.csv");
2191 #else
2192 strcpy(pFileName, "home.csv");
2193 #endif
2194
2195 MyContentReadFile(&hCnt5, pFileName, &hbmInfo.msgBuf, &Allocator2, &Allocator1);
2196 strcpy(pFileName, "config.txt");
2197 hbmInfo.configBufSize = MyContentReadFile(&hCnt4, aFullPath, &hbmInfo.configBuf, &Allocator2, &Allocator1);
2198 hbmInfo.sound_callback = MyHBMSoundCallback;
2199 hbmInfo.backFlag = 0; // Make background half transparent, so the game pause screen can be seen through it
2200 hbmInfo.cursor = 0;
2201 hbmInfo.adjust.x = 832.f / 608.f;
2202 hbmInfo.adjust.y = 1.0f;
2203 hbmInfo.frameDelta = 1.0f;
2204
2205 strcpy(pFileName, "homeBtnIcon.tpl");
2206 MyContentReadFile(&hCnt4, aFullPath, (void **)&sBanHbmIcon.pTpl, &Allocator2, &Allocator1);
2207 TPLBind(sBanHbmIcon.pTpl);
2208
2209 hbmInfo.memSize = HBM_MEM_SIZE;
2210 VCMVAllocIfNecessary(&hbmInfo.mem, HBM_MEM_SIZE, &Allocator2, &Allocator1);
2211 hbmInfo.pAllocator = NULL;
2212 hbmInfo.messageFlag = 0; // Set to HBMMSG_NOSAVE_WIIMENU if the game supports the Suspend feature.
2213
2214 verbose(
2215 OSReport("HBMCreate(&hbmInfo)\n");
2216 OSReport("hbmInfo.layoutBuf = %p\n", hbmInfo.layoutBuf);
2217 OSReport("hbmInfo.spkSeBuf = %p\n", hbmInfo.spkSeBuf);
2218 OSReport("hbmInfo.msgBuf = %p\n", hbmInfo.msgBuf);
2219 OSReport("hbmInfo.configBuf = %p\n", hbmInfo.configBuf);
2220 OSReport("hbmInfo.mem = %p\n", hbmInfo.mem);
2221 OSReport("hbmInfo.sound_callback = %p\n", hbmInfo.sound_callback);
2222 OSReport("hbmInfo.backFlag = %p\n", hbmInfo.backFlag);
2223 OSReport("hbmInfo.region = %p\n", hbmInfo.region);
2224 OSReport("hbmInfo.cursor = %p\n", hbmInfo.cursor);
2225 OSReport("hbmInfo.memSize = %p\n", hbmInfo.memSize);
2226 OSReport("hbmInfo.frameDelta= %.1f\n", hbmInfo.frameDelta);
2227 OSReport("hbmInfo.adjust.x = %.1f\n", hbmInfo.adjust.x);
2228 OSReport("hbmInfo.adjust.y = %.1f\n", hbmInfo.adjust.y);
2229 OSReport("hbmInfo.pAllocator= %p\n", hbmInfo.pAllocator);
2230 );
2231
2232 VCMVSetHbmInfo(&hbmInfo);
2233 HBMCreate(&hbmInfo);
2234 verbose(OSReport("HBMCreateNandSound()\n"););
2235 #if HOME_BUTTON_MENU_3
2236 VCMVAllocIfNecessary(&pHbmSoundInstanceBuf, HBM_MEM_SIZE_SOUND, &Allocator2, &Allocator1);
2237 HBMCreateSound(sound_data_ptr, pHbmSoundInstanceBuf, HBM_MEM_SIZE_SOUND);
2238 CNTReleaseHandle(&hCnt6);
2239 #else
2240 VCMVAllocIfNecessary(&pHbmSoundInstanceBuf, HBM_MEM2_SIZE_NAND, &Allocator2, &Allocator1);
2241 HBMCreateNandSound(pNandSoundFullPath, pHbmSoundInstanceBuf, HBM_MEM2_SIZE_NAND);
2242 #endif
2243 CNTReleaseHandle(&hCnt4);
2244 }
2245
2246 /*---------------------------------------------------------------------------*
2247 Name: SetupHbmGX
2248 *---------------------------------------------------------------------------*/
SetupHbmGX(void)2249 void SetupHbmGX(void)
2250 {
2251 // GX Initialization for the box cursors and Ban icon
2252 GXClearVtxDesc();
2253 GXSetVtxAttrFmt(GX_VTXFMT4, GX_VA_POS, GX_POS_XY, GX_F32, 0);
2254 GXSetVtxAttrFmt(GX_VTXFMT4, GX_VA_CLR0, GX_CLR_RGB, GX_RGB8, 0);
2255 GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
2256 GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
2257 GXSetNumChans(1);
2258 GXSetNumTexGens(0);
2259 GXSetNumTevStages(1);
2260 GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
2261 GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
2262 GXSetBlendMode(GX_BM_NONE, GX_BL_ZERO, GX_BL_ZERO, GX_LO_CLEAR);
2263 GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
2264 GXSetCurrentMtx(GX_PNMTX1);
2265 }
2266
2267 /*---------------------------------------------------------------------------*
2268 Name: DrawBoxCursors
2269 *---------------------------------------------------------------------------*/
DrawBoxCursors(void)2270 void DrawBoxCursors(void)
2271 {
2272 // Draw simple box cursors.
2273 s32 nI;
2274 for(nI=0; nI<PAD_MAX_CONTROLLERS; nI++) {
2275 if (VCMV_HBMControllerData.wiiCon[nI].kpad) {
2276 f32 rX = VCMV_HBMControllerData.wiiCon[nI].pos.x * 0.5f * nHbmEfbWidth;
2277 f32 rY = VCMV_HBMControllerData.wiiCon[nI].pos.y * 0.5f * HBM_EFB_HEIGHT;
2278 u8 nC = nGameFadeBrightnessLevel;
2279 GXBegin(GX_QUADS, GX_VTXFMT4, 4);
2280 GXPosition2f32(-6+rX, -6-rY); GXColor3u8(nC, nC, nC);
2281 GXPosition2f32(-6+rX, 6-rY); GXColor3u8(nC, nC, nC);
2282 GXPosition2f32( 6+rX, 6-rY); GXColor3u8(nC, nC, nC);
2283 GXPosition2f32( 6+rX, -6-rY); GXColor3u8(nC, nC, nC);
2284 GXEnd();
2285 }
2286 }
2287 }
2288
2289 //===========================================================================
2290 // MAIN PROGRAM
2291 //===========================================================================
Test(void)2292 void Test(void)
2293 {
2294 // Initialize
2295 VIInit();
2296 SCInit();
2297 while (SC_STATUS_OK!=SCCheckStatus()) {} // Wait for SCInit() to complete
2298 OSInitFastCast(); // Used by the Home Button Menu
2299 OSSetResetCallback(MyResetButtonCallback);
2300 OSSetPowerCallback(MyPowerButtonCallback);
2301 MyInitAllocators();
2302 WPADRegisterAllocator(MyAllocMem2, MyFreeMem2);
2303 VCMVRegisterAllocators(&Allocator1, &Allocator2);
2304 MyInitAudio();
2305 VISetBlack(TRUE);
2306 VIFlush();
2307
2308 // Manual Viewer uses KPAD. Game application may or may not use KPAD.
2309 verbose(OSReport("KPADInit()\n"););
2310
2311 KPADInit();
2312 {
2313 s32 nI;
2314 for(nI=0; nI<WPAD_MAX_CONTROLLERS; nI++) {
2315 KPADEnableAimingMode(nI);
2316 }
2317 }
2318
2319 verbose(OSReport("PADInit()\n"););
2320 PADInit();
2321 MyInitDisplayMode();
2322 verbose(OSReport("MyInitGX()\n"););
2323 MyInitGX();
2324 VISetBlack(FALSE);
2325 VIFlush();
2326
2327 #ifdef NANDAPP
2328 verbose(OSReport("CNTInit() - NANDAPP\n"););
2329 #else
2330 verbose(OSReport("CNTInit() - DVDAPP\n"););
2331 #endif
2332
2333 CNTInit();
2334 CNTInitHandle(5, &hCnt5, &Allocator2);
2335 LoadTexture();
2336 MyDrawInit();
2337
2338 bHomeButtonMenu = FALSE;
2339 sBanHbmIcon.bOnFlag = FALSE;
2340
2341 nHbmVcmvState = E_InGame;
2342
2343 verbose(OSReport("MyInitHomeButtonMenu()\n"););
2344 MyInitHomeButtonMenu();
2345
2346 {
2347 Mtx mv;
2348 MTXIdentity(mv);
2349 GXLoadPosMtxImm(mv, GX_PNMTX1);
2350 }
2351
2352 if (nHbmAspectRatio) {
2353 HBMSetAdjustFlag(1); // 16:9
2354 rHbmGxHalfWidth = 416.0;
2355 nHbmViWidth = HBM_VI_WIDTH_WIDE;
2356 } else {
2357 HBMSetAdjustFlag(0); // 4:3
2358 rHbmGxHalfWidth = 304.0;
2359 nHbmViWidth = HBM_VI_WIDTH_NORMAL;
2360 }
2361
2362 GXSetCullMode(GX_CULL_NONE);
2363
2364 GXSetZMode(GX_FALSE, GX_ALWAYS, GX_FALSE);
2365
2366 nGameFadeBrightnessLevel = 255;
2367 pCurrentRenderMode = pRmGame;
2368
2369 while(1) {
2370 MyReadControllers();
2371
2372 if (bResetButtonPressed || bPowerButtonPressed) {
2373 switch(nHbmVcmvState) {
2374 case E_GameToHbmTransition2:
2375 case E_HbmToGameTransition:
2376 case E_InHbm: {
2377
2378 if (!bCalledHBMBlackOut) {
2379 bCalledHBMBlackOut = TRUE;
2380 HBMStartBlackOut();
2381 }
2382
2383 break;
2384 }
2385 default:
2386 nHbmVcmvState = E_BlackOutTransition;
2387 break;
2388 }
2389 }
2390
2391 switch(nHbmVcmvState) {
2392
2393 case E_InGamePlusBanIcon:
2394 ASSERT(nHbmVcmvState == E_InGamePlusBanIcon);
2395 verbose(OSReport("E_InGamePlusBanIcon\n"););
2396
2397 if (sBanHbmIcon.bOnFlag==FALSE) {
2398 nHbmVcmvState = E_InGame;
2399 }
2400
2401 break;
2402
2403 FadeInGameTransition:
2404 case E_FadeInGameTransition:
2405 ASSERT(nHbmVcmvState == E_FadeInGameTransition);
2406 verbose(OSReport("E_FadeInGameTransition: %d/%d\n", nTransitionFrame, nFadeInGameTransitionMaxFrame););
2407 nTransitionFrame++;
2408 nGameFadeBrightnessLevel = (u8)(nTransitionFrame * 255 / nFadeInGameTransitionMaxFrame);
2409
2410 if (nTransitionFrame < nFadeInGameTransitionMaxFrame) {
2411 // Fade back up to normal brightness after switching to interlace mode
2412 // Note: If the game is using interlace or progressive mode, set nFadeInGameTransitionMaxFrame=0
2413 if (nTransitionFrame<=0) {
2414 nGameFadeBrightnessLevel=0;
2415
2416 if (VIGetNextField()==VI_FIELD_ABOVE) {
2417 pCurrentRenderMode = pRmGame;
2418 nCurrentEfbRenderWidth = nGameEfbWidth;
2419 }
2420 }
2421 break;
2422 }
2423 pCurrentRenderMode = pRmGame;
2424 nCurrentEfbRenderWidth = nGameEfbWidth;
2425 nTransitionFrame = 0;
2426 nHbmVcmvState = E_InGame;
2427 verbose(OSReport("E_InGame\n"););
2428 GXInitTexObjLOD(&toSample, GX_NEAR, GX_NEAR, 0, 0, 0, GX_FALSE, GX_FALSE, GX_ANISO_1);
2429 // no break, intentional fall-through
2430
2431 case E_InGame:
2432 ASSERT(nHbmVcmvState == E_InGame);
2433 #if SIMULATE_GAME_MEMORY_USAGE
2434 VCMVAllocIfNecessary((void**)&pGameMem1, GAME_MEM1_SIZE, &Allocator1, &Allocator1);
2435 VCMVAllocIfNecessary((void**)&pGameMem2, GAME_MEM2_SIZE, &Allocator2, &Allocator2);
2436 {
2437 // Simulate some game code overwriting memory
2438 int nI;
2439 for(nI=0; nI<100000; nI++) {
2440 pGameMem1[nGameMem1Idx]++;
2441 pGameMem2[nGameMem2Idx]++;
2442 nGameMem1Idx = (nGameMem1Idx+1)%GAME_MEM1_SIZE;
2443 nGameMem2Idx = (nGameMem2Idx+1)%GAME_MEM2_SIZE;
2444 }
2445 }
2446 #endif
2447 nGameFadeBrightnessLevel = 255;
2448
2449 if (!bAnyHomeButtonPressed) {
2450 break;
2451 }
2452
2453 nTransitionFrame = 0;
2454 #if SIMULATE_GAME_MEMORY_USAGE
2455 VCMVFreeAndClearPointer((void**)&pGameMem1);
2456 VCMVFreeAndClearPointer((void**)&pGameMem2);
2457 #endif
2458 nHbmVcmvState = E_GameToHbmTransition1;
2459 GXInitTexObjLOD(&toSample, GX_LINEAR, GX_LINEAR, 0, 0, 0, GX_FALSE, GX_FALSE, GX_ANISO_1);
2460 // no break, intentional fall-through
2461
2462 case E_GameToHbmTransition1:
2463 ASSERT(nHbmVcmvState == E_GameToHbmTransition1);
2464 verbose(OSReport("E_GameToHbmTransition1: %d/%d\n", nTransitionFrame, nGameToHbmTransition1MaxFrame););
2465 nTransitionFrame++;
2466 nGameFadeBrightnessLevel = (u8)(255 - (nTransitionFrame * 255 / nGameToHbmTransition1MaxFrame));
2467
2468 if (nTransitionFrame < nGameToHbmTransition1MaxFrame) {
2469 // Fade to black before switching from non-interlace mode to interlace mode
2470 // Note: If the game is using interlace or progressive mode, set nGameToHbmTransition1MaxFrame=0
2471 break;
2472 }
2473
2474 HBMInit();
2475 bHomeButtonMenu = TRUE;
2476 nTransitionFrame = -BLACKOUT_TIME;
2477 nHbmVcmvState = E_GameToHbmTransition2;
2478 // no break, intentional fall-through
2479
2480 case E_GameToHbmTransition2:
2481 ASSERT(nHbmVcmvState == E_GameToHbmTransition2);
2482 verbose(OSReport("E_GameToHbmTransition2: %d/%d\n", nTransitionFrame, nGameToHbmTransition2MaxFrame););
2483 nTransitionFrame++;
2484 nGameFadeBrightnessLevel = (u8)(nTransitionFrame * 255 / nGameToHbmTransition2MaxFrame);
2485
2486 if (nTransitionFrame < nGameToHbmTransition2MaxFrame) {
2487 // Fade back up to normal brightness after switching to interlace mode
2488 // Note: If the game is using interlace or progressive mode, set nGameToHbmTransition2MaxFrame=0
2489 if (nTransitionFrame<=0) {
2490 nGameFadeBrightnessLevel=0;
2491 if (VIGetNextField()==VI_FIELD_ABOVE) {
2492 pCurrentRenderMode = pRmHBM;
2493 nCurrentEfbRenderWidth = nHbmEfbWidth;
2494 }
2495 }
2496 // no break, intentional fall-through
2497 } else {
2498 nGameFadeBrightnessLevel = 255;
2499 pCurrentRenderMode = pRmHBM;
2500 nCurrentEfbRenderWidth = nHbmEfbWidth;
2501 nTransitionFrame = 0;
2502 nHbmVcmvState = E_InHbm;
2503 // no break, intentional fall-through
2504 }
2505
2506 InHbm:
2507 case E_InHbm:
2508 UpdateInitialFocusController();
2509
2510 // Update Home Button Menu. HOME�{�^�����j���[�X�V
2511 if (HBMCalc(&VCMV_HBMControllerData) == HBM_SELECT_NULL) {
2512 HBMUpdateSound();
2513 break;
2514 } else {
2515 s32 nI;
2516 verbose(OSReport("HBM finished: %d\n", HBMGetSelectBtnNum()););
2517 for(nI=0; nI<WPAD_MAX_CONTROLLERS; nI++) {
2518 WPADStopMotor(nI);
2519 }
2520 bHomeButtonMenu = FALSE;
2521
2522 switch(HBMGetSelectBtnNum()) {
2523
2524 case HBM_SELECT_BTN1:
2525 goto ReturnToMenu;
2526 case HBM_SELECT_BTN2:
2527 nGameFadeBrightnessLevel=0; // HBM has already finished the BlackOut
2528 bResetButtonPressed=TRUE;
2529 #if INITIALIZE_IN_THREAD
2530 if (OSGetIdleFunction()) {
2531 // This can happen if the user presses RESET after clicking the User-Manual button,
2532 // and before the HBM has fully faded out.
2533 goto ContinueVcmvInitialization;
2534 }
2535 #endif
2536 goto BlackOutTransition;
2537 case HBM_SELECT_BTN3:
2538 // Initialize and Run the manual viewer
2539 nHbmVcmvState = E_HbmToVcmvTransition;
2540 #if INITIALIZE_IN_THREAD
2541 verbose(OSReport("Waiting for Manual Viewer initialization to finish..\n"););
2542 // The screen is already black at this point
2543
2544 ContinueVcmvInitialization:
2545 while (OSGetIdleFunction()) {
2546 VIWaitForRetrace(); // Yields this thread to allow the initialization thread to continue
2547 }
2548
2549 VCMVFreeAndClearPointer(&pMyVcmvInitThreadStack);
2550 #else
2551 MyInitializeManualViewer(0);
2552 #endif
2553 OSDisableInterrupts();
2554
2555 if (!(bResetButtonPressed || bPowerButtonPressed)) {
2556 verbose(OSReport("Running Manual Viewer\n"););
2557 nHbmVcmvState = E_InVcmv;
2558 RunManualViewer();
2559 verbose(OSReport("Manual Viewer Finished\n"););
2560 } else {
2561 verbose(OSReport("Reset/Power pressed during VCMV Initialization\n"););
2562 }
2563
2564 MyCloseManualViewer();
2565 OSEnableInterrupts();
2566 bHomeButtonMenu = FALSE;
2567
2568 // NOTE: We don't want the compiler to optimize this part, so bResetButtonPressed
2569 // and bPowerButtonPressed are declared as volatile
2570 if (bResetButtonPressed || bPowerButtonPressed) {
2571 goto BlackOutTransition;
2572 }
2573
2574 nTransitionFrame = -BLACKOUT_TIME;
2575 nHbmVcmvState = E_FadeInGameTransition;
2576 goto FadeInGameTransition;
2577 case HBM_SELECT_HOMEBTN:
2578 break;
2579 }
2580 nTransitionFrame = -BLACKOUT_TIME;
2581 nHbmVcmvState = E_FadeInGameTransition;
2582 goto FadeInGameTransition;
2583 }
2584 // no break, intentional fall-through
2585
2586 case E_HbmToGameTransition:
2587 ASSERT(nHbmVcmvState == E_HbmToGameTransition);
2588 verbose(OSReport("E_HbmToGameTransition: %d/%d\n", nTransitionFrame, nHbmToGameTransitionMaxFrame););
2589 nTransitionFrame++;
2590
2591 if (nTransitionFrame > nHbmToGameTransitionMaxFrame) {
2592 nTransitionFrame = nHbmToGameTransitionMaxFrame;
2593 }
2594
2595 if (nTransitionFrame < 10) {
2596 nGameFadeBrightnessLevel = 255;
2597 } else {
2598 nGameFadeBrightnessLevel = (u8)(255 - ((nTransitionFrame-10) * 255 / (nHbmToGameTransitionMaxFrame-10)));
2599 }
2600
2601 goto InHbm;
2602
2603 case E_HbmToVcmvTransition:
2604 ASSERT(nHbmVcmvState == E_HbmToVcmvTransition);
2605 break;
2606
2607 BlackOutTransition:
2608 nHbmVcmvState = E_BlackOutTransition;
2609 case E_BlackOutTransition:
2610 ASSERT(nHbmVcmvState == E_BlackOutTransition);
2611 verbose(OSReport("E_BlackOutTransition: %d\n", nGameFadeBrightnessLevel););
2612
2613 if (nGameFadeBrightnessLevel > 0) {
2614 nGameFadeBrightnessLevel = (u8)((nGameFadeBrightnessLevel-4)&0xF8); // Fadeout in steps of 8, not 4
2615 } else {
2616 if (bPowerButtonPressed) {
2617 goto ReturnToMenu;
2618 }
2619 if (bResetButtonPressed) {
2620 ResetGame();
2621 break;
2622 }
2623 }
2624
2625 break;
2626
2627 case E_ResartGameAfterResetTransition:
2628 ASSERT(nHbmVcmvState == E_ResartGameAfterResetTransition);
2629
2630 if (nGameFadeBrightnessLevel < 255) {
2631 nGameFadeBrightnessLevel = (u8)((nGameFadeBrightnessLevel+4)|0x7); // Fadein in steps of 8, not 4
2632 } else {
2633 nHbmVcmvState = E_InGame;
2634 }
2635
2636 break;
2637
2638 default:
2639 verbose(OSReport("Warning: unexpected nHbmVcmvState (%d)\n", nHbmVcmvState););
2640 break;
2641 }
2642
2643 GXInvalidateVtxCache();
2644 GXInvalidateTexAll();
2645
2646 GameDrawTick();
2647
2648 if (sBanHbmIcon.bOnFlag) {
2649 DrawBanIcon();
2650 }
2651
2652 {
2653 Mtx44 projMtx;
2654 MTXOrtho(projMtx, HBM_EFB_HEIGHT*0.5f, -HBM_EFB_HEIGHT*0.5f, -rHbmGxHalfWidth, rHbmGxHalfWidth, 0.0f, 500.0f);
2655 GXSetProjection(projMtx, GX_ORTHOGRAPHIC);
2656 GXSetCullMode(GX_CULL_NONE);
2657 SetupHbmGX();
2658
2659 if (bHomeButtonMenu) {
2660 HBMDraw();
2661 }
2662
2663 if (!bHomeButtonMenu) {
2664 f32 rHalfWidth = (f32)(pCurrentRenderMode->viWidth * nHbmEfbWidth) / (f32)(nHbmViWidth * 2);
2665 f32 rHalfHeight = (f32)(pCurrentRenderMode->viHeight * HBM_EFB_HEIGHT) / (f32)(HBM_VI_HEIGHT * 2);
2666
2667 verbose(
2668 {
2669 static u8 bFirst=1;
2670
2671 if (bFirst) {
2672 bFirst=0;
2673 OSReport("nGameViWidth=%d, nHbmEfbWidth=%d, nHbmViWidth=%d\n", nGameViWidth, nHbmEfbWidth, nHbmViWidth);
2674 OSReport("pCurrentRenderMode->efbHeight=%d, viHeight=%d, HBM_EFB_HEIGHT=%d\n", pCurrentRenderMode->efbHeight, pCurrentRenderMode->viHeight, HBM_EFB_HEIGHT);
2675 OSReport("nGameXfbWidth=%d, pCurrentRenderMode->fbWidth=%d\n", nGameXfbWidth, pCurrentRenderMode->fbWidth);
2676 OSReport("rHalfWidth=%.1f, rHalfHeight=%.1f\n", rHalfWidth, rHalfHeight);
2677 }
2678 }
2679 );
2680
2681 MTXOrtho(projMtx, rHalfHeight, -rHalfHeight, -rHalfWidth, rHalfWidth, 0.0f, 500.0f);
2682 GXSetProjection(projMtx, GX_ORTHOGRAPHIC);
2683 DrawBoxCursors();
2684 }
2685 }
2686 MyDrawDone();
2687 }
2688
2689 ReturnToMenu:
2690 VCMVFreeAndClearPointer(&hbmInfo.mem);
2691 CNTReleaseHandle(&hCnt5);
2692 MyFreeMem2(apXFB[1]);
2693 MyFreeMem2(apXFB[0]);
2694 OSReport("End of VCMV + HBM Sample\n");
2695 OSReturnToMenu();
2696
2697 {
2698 ARCHandle ah;
2699 ARCDir dir;
2700 ARCOpenDir(&ah, ".", &dir);
2701 }
2702 }
2703
main(void)2704 void main(void) { Test(); }
2705
2706