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