frontend: Wiz/Caanoo tweaks + banner image from darklight1138
[pcsx_rearmed.git] / frontend / menu.c
CommitLineData
69af03a2 1/*
201c21e2 2 * (C) GraÅžvydas "notaz" Ignotas, 2010-2011
69af03a2 3 *
4 * This work is licensed under the terms of any of these licenses
5 * (at your option):
6 * - GNU GPL, version 2 or later.
7 * - GNU LGPL, version 2.1 or later.
8 * See the COPYING file in the top-level directory.
9 */
10
11#include <stdio.h>
12#include <string.h>
3c70c47b 13#include <errno.h>
bbd837c6 14#include <dlfcn.h>
61363062 15#include <zlib.h>
69af03a2 16
c5061935 17#include "main.h"
3c70c47b 18#include "menu.h"
69af03a2 19#include "config.h"
201c21e2 20#include "plugin.h"
69af03a2 21#include "plugin_lib.h"
22#include "omap.h"
55b0eeea 23#include "plat.h"
c22b95ab 24#include "pcnt.h"
a80ae4a0 25#include "cspace.h"
69af03a2 26#include "common/plat.h"
ef94866c 27#include "common/input.h"
28#include "linux/in_evdev.h"
69af03a2 29#include "../libpcsxcore/misc.h"
1df403c5 30#include "../libpcsxcore/cdrom.h"
799b0b87 31#include "../libpcsxcore/psemu_plugin_defs.h"
dc990066 32#include "../libpcsxcore/new_dynarec/new_dynarec.h"
4c08b9e7 33#include "../plugins/dfinput/main.h"
3c70c47b 34#include "revision.h"
69af03a2 35
69af03a2 36#define array_size(x) (sizeof(x) / sizeof(x[0]))
37
38typedef enum
39{
40 MA_NONE = 1,
41 MA_MAIN_RESUME_GAME,
42 MA_MAIN_SAVE_STATE,
43 MA_MAIN_LOAD_STATE,
44 MA_MAIN_RESET_GAME,
45 MA_MAIN_LOAD_ROM,
1df403c5 46 MA_MAIN_SWAP_CD,
e16a7e51 47 MA_MAIN_RUN_BIOS,
51f77282 48 MA_MAIN_RUN_EXE,
69af03a2 49 MA_MAIN_CONTROLS,
50 MA_MAIN_CREDITS,
51 MA_MAIN_EXIT,
52 MA_CTRL_PLAYER1,
53 MA_CTRL_PLAYER2,
54 MA_CTRL_EMU,
55 MA_CTRL_DEV_FIRST,
56 MA_CTRL_DEV_NEXT,
55b0eeea 57 MA_CTRL_NUBS_BTNS,
58 MA_CTRL_DEADZONE,
69af03a2 59 MA_CTRL_DONE,
60 MA_OPT_SAVECFG,
61 MA_OPT_SAVECFG_GAME,
62 MA_OPT_CPU_CLOCKS,
3c70c47b 63 MA_OPT_FILTERING,
55b0eeea 64 MA_OPT_DISP_OPTS,
69af03a2 65} menu_id;
66
3c70c47b 67enum {
68 SCALE_1_1,
69 SCALE_4_3,
a185be70 70 SCALE_4_3v2,
3c70c47b 71 SCALE_FULLSCREEN,
72 SCALE_CUSTOM,
73};
69af03a2 74
bd6267e6 75static int last_psx_w, last_psx_h, last_psx_bpp;
ea4a16e7 76static int scaling, filter, cpu_clock, cpu_clock_st, volume_boost, frameskip;
69af03a2 77static char rom_fname_reload[MAXPATHLEN];
78static char last_selected_fname[MAXPATHLEN];
4c08b9e7 79static int warned_about_bios, region, in_type_sel1, in_type_sel2;
2573466a 80static int psx_clock;
51f77282 81static int memcard1_sel, memcard2_sel;
221be40d 82int g_opts;
83int analog_deadzone; // for Caanoo
bd6267e6 84
67d399b0 85#ifdef __ARM_ARCH_7A__
86#define DEFAULT_PSX_CLOCK 57
87#define DEFAULT_PSX_CLOCK_S "57"
88#else
2573466a 89#define DEFAULT_PSX_CLOCK 50
90#define DEFAULT_PSX_CLOCK_S "50"
67d399b0 91#endif
2573466a 92
bd6267e6 93// sound plugin
94extern int iUseReverb;
95extern int iUseInterpolation;
96extern int iXAPitch;
97extern int iSPUIRQWait;
98extern int iUseTimer;
9e7a7352 99extern int iVolume;
bd6267e6 100
e6eb2066 101static const char *bioses[24];
bbd837c6 102static const char *gpu_plugins[16];
103static const char *spu_plugins[16];
51f77282 104static const char *memcards[32];
e6eb2066 105static int bios_sel, gpu_plugsel, spu_plugsel;
bbd837c6 106
bd6267e6 107
108static int min(int x, int y) { return x < y ? x : y; }
109static int max(int x, int y) { return x > y ? x : y; }
69af03a2 110
111void emu_make_path(char *buff, const char *end, int size)
112{
113 int pos, end_len;
114
115 end_len = strlen(end);
116 pos = plat_get_root_dir(buff, size);
117 strncpy(buff + pos, end, size - pos);
118 buff[size - 1] = 0;
119 if (pos + end_len > size - 1)
120 printf("Warning: path truncated: %s\n", buff);
121}
122
123static int emu_check_save_file(int slot)
124{
8f892648 125 int ret = emu_check_state(slot);
3c70c47b 126 return ret == 0 ? 1 : 0;
69af03a2 127}
128
8f892648 129static int emu_save_load_game(int load, int unused)
69af03a2 130{
3c70c47b 131 int ret;
132
33f56da1 133 if (load) {
8f892648 134 ret = emu_load_state(state_slot);
33f56da1 135
136 // reflect hle/bios mode from savestate
137 if (Config.HLE)
138 bios_sel = 0;
139 else if (bios_sel == 0 && bioses[1] != NULL)
140 // XXX: maybe find the right bios instead
141 bios_sel = 1;
142 }
3c70c47b 143 else
8f892648 144 ret = emu_save_state(state_slot);
3c70c47b 145
146 return ret;
69af03a2 147}
148
907b1e90 149// propagate menu settings to the emu vars
150static void menu_sync_config(void)
151{
ef94866c 152 static int allow_abs_only_old;
153
907b1e90 154 Config.PsxAuto = 1;
155 if (region > 0) {
156 Config.PsxAuto = 0;
157 Config.PsxType = region - 1;
158 }
2573466a 159 cycle_multiplier = 10000 / psx_clock;
160
4c08b9e7 161 switch (in_type_sel1) {
162 case 1: in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
163 case 2: in_type1 = PSE_PAD_TYPE_GUNCON; break;
164 default: in_type1 = PSE_PAD_TYPE_STANDARD;
165 }
166 switch (in_type_sel2) {
167 case 1: in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
168 case 2: in_type2 = PSE_PAD_TYPE_GUNCON; break;
169 default: in_type2 = PSE_PAD_TYPE_STANDARD;
170 }
ef94866c 171 if (in_evdev_allow_abs_only != allow_abs_only_old) {
55b0eeea 172 plat_rescan_inputs();
ef94866c 173 allow_abs_only_old = in_evdev_allow_abs_only;
174 }
907b1e90 175
9e7a7352 176 iVolume = 768 + 128 * volume_boost;
ea4a16e7 177 pl_rearmed_cbs.frameskip = frameskip - 1;
76f7048e 178 pl_timing_prepare(Config.PsxType);
907b1e90 179}
180
3c70c47b 181static void menu_set_defconfig(void)
182{
33400707 183 emu_set_default_config();
184
bce6b056 185 g_opts = 0;
3c70c47b 186 scaling = SCALE_4_3;
9e7a7352 187 volume_boost = 0;
ea4a16e7 188 frameskip = 0;
bab59f00 189 analog_deadzone = 50;
2573466a 190 psx_clock = DEFAULT_PSX_CLOCK;
bd6267e6 191
907b1e90 192 region = 0;
4c08b9e7 193 in_type_sel1 = in_type_sel2 = 0;
ef94866c 194 in_evdev_allow_abs_only = 0;
907b1e90 195
196 menu_sync_config();
3c70c47b 197}
198
4f3639fa 199#define CE_CONFIG_STR(val) \
200 { #val, 0, Config.val }
201
202#define CE_CONFIG_VAL(val) \
203 { #val, sizeof(Config.val), &Config.val }
204
205#define CE_STR(val) \
206 { #val, 0, val }
207
208#define CE_INTVAL(val) \
209 { #val, sizeof(val), &val }
210
e64dc4c5 211#define CE_INTVAL_P(val) \
212 { #val, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
213
cdb31c95 214// 'versioned' var, used when defaults change
215#define CE_INTVAL_V(val, ver) \
216 { #val #ver, sizeof(val), &val }
217
ea4a16e7 218#define CE_INTVAL_PV(val, ver) \
219 { #val #ver, sizeof(pl_rearmed_cbs.val), &pl_rearmed_cbs.val }
220
4f3639fa 221static const struct {
222 const char *name;
223 size_t len;
224 void *val;
225} config_data[] = {
226 CE_CONFIG_STR(Bios),
227 CE_CONFIG_STR(Gpu),
228 CE_CONFIG_STR(Spu),
33716956 229// CE_CONFIG_STR(Cdr),
4f3639fa 230 CE_CONFIG_VAL(Xa),
231 CE_CONFIG_VAL(Sio),
232 CE_CONFIG_VAL(Mdec),
4f3639fa 233 CE_CONFIG_VAL(Cdda),
234 CE_CONFIG_VAL(Debug),
235 CE_CONFIG_VAL(PsxOut),
236 CE_CONFIG_VAL(SpuIrq),
237 CE_CONFIG_VAL(RCntFix),
238 CE_CONFIG_VAL(VSyncWA),
239 CE_CONFIG_VAL(Cpu),
4feed8d3 240 CE_CONFIG_VAL(CdrReschedule),
907b1e90 241 CE_INTVAL(region),
a185be70 242 CE_INTVAL_V(scaling, 2),
cd6e8d0f 243 CE_INTVAL(g_layer_x),
244 CE_INTVAL(g_layer_y),
245 CE_INTVAL(g_layer_w),
246 CE_INTVAL(g_layer_h),
4f3639fa 247 CE_INTVAL(filter),
248 CE_INTVAL(state_slot),
249 CE_INTVAL(cpu_clock),
250 CE_INTVAL(g_opts),
4c08b9e7 251 CE_INTVAL(in_type_sel1),
252 CE_INTVAL(in_type_sel2),
55b0eeea 253 CE_INTVAL(analog_deadzone),
ea4a16e7 254 CE_INTVAL_V(frameskip, 2),
e64dc4c5 255 CE_INTVAL_P(gpu_peops.iUseDither),
256 CE_INTVAL_P(gpu_peops.dwActFixes),
17a54a4a 257 CE_INTVAL_P(gpu_unai.abe_hack),
258 CE_INTVAL_P(gpu_unai.no_light),
259 CE_INTVAL_P(gpu_unai.no_blend),
ffdbda29 260 CE_INTVAL_V(iUseReverb, 3),
261 CE_INTVAL_V(iXAPitch, 3),
262 CE_INTVAL_V(iUseInterpolation, 3),
263 CE_INTVAL_V(iSPUIRQWait, 3),
264 CE_INTVAL_V(iUseTimer, 3),
4f5a1b2a 265 CE_INTVAL(warned_about_bios),
ef94866c 266 CE_INTVAL(in_evdev_allow_abs_only),
9e7a7352 267 CE_INTVAL(volume_boost),
2573466a 268 CE_INTVAL(psx_clock),
0ff8c62c 269 CE_INTVAL(new_dynarec_hacks),
4f3639fa 270};
271
1bd9ee68 272static char *get_cd_label(void)
cd6e8d0f 273{
1bd9ee68 274 static char trimlabel[33];
cd6e8d0f 275 int j;
276
277 strncpy(trimlabel, CdromLabel, 32);
278 trimlabel[32] = 0;
279 for (j = 31; j >= 0; j--)
280 if (trimlabel[j] == ' ')
281 trimlabel[j] = 0;
282
1bd9ee68 283 return trimlabel;
284}
285
286static void make_cfg_fname(char *buf, size_t size, int is_game)
287{
cd6e8d0f 288 if (is_game)
1bd9ee68 289 snprintf(buf, size, "." PCSX_DOT_DIR "cfg/%.32s-%.9s.cfg", get_cd_label(), CdromId);
cd6e8d0f 290 else
bbd837c6 291 snprintf(buf, size, "." PCSX_DOT_DIR "%s", cfgfile_basename);
cd6e8d0f 292}
293
43bca6fb 294static void keys_write_all(FILE *f);
295
3c70c47b 296static int menu_write_config(int is_game)
297{
4f3639fa 298 char cfgfile[MAXPATHLEN];
299 FILE *f;
300 int i;
301
cd6e8d0f 302 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
4f3639fa 303 f = fopen(cfgfile, "w");
304 if (f == NULL) {
bbd837c6 305 printf("menu_write_config: failed to open: %s\n", cfgfile);
4f3639fa 306 return -1;
307 }
308
309 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
310 fprintf(f, "%s = ", config_data[i].name);
311 switch (config_data[i].len) {
312 case 0:
313 fprintf(f, "%s\n", (char *)config_data[i].val);
314 break;
315 case 1:
316 fprintf(f, "%x\n", *(u8 *)config_data[i].val);
317 break;
318 case 2:
319 fprintf(f, "%x\n", *(u16 *)config_data[i].val);
320 break;
321 case 4:
322 fprintf(f, "%x\n", *(u32 *)config_data[i].val);
323 break;
324 default:
325 printf("menu_write_config: unhandled len %d for %s\n",
326 config_data[i].len, config_data[i].name);
327 break;
328 }
329 }
330
331 if (!is_game)
332 fprintf(f, "lastcdimg = %s\n", last_selected_fname);
333
43bca6fb 334 keys_write_all(f);
4f3639fa 335 fclose(f);
43bca6fb 336
4f3639fa 337 return 0;
338}
339
340static void parse_str_val(char *cval, const char *src)
341{
342 char *tmp;
343 strncpy(cval, src, MAXPATHLEN);
344 cval[MAXPATHLEN - 1] = 0;
345 tmp = strchr(cval, '\n');
346 if (tmp == NULL)
347 tmp = strchr(cval, '\r');
348 if (tmp != NULL)
349 *tmp = 0;
3c70c47b 350}
351
43bca6fb 352static void keys_load_all(const char *cfg);
353
3c70c47b 354static int menu_load_config(int is_game)
69af03a2 355{
4f3639fa 356 char cfgfile[MAXPATHLEN];
357 int i, ret = -1;
358 long size;
359 char *cfg;
360 FILE *f;
361
cd6e8d0f 362 make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
4f3639fa 363 f = fopen(cfgfile, "r");
364 if (f == NULL) {
bbd837c6 365 printf("menu_load_config: failed to open: %s\n", cfgfile);
cbd45cda 366 goto fail;
4f3639fa 367 }
368
369 fseek(f, 0, SEEK_END);
370 size = ftell(f);
371 if (size <= 0) {
372 printf("bad size %ld: %s\n", size, cfgfile);
373 goto fail;
374 }
375
376 cfg = malloc(size + 1);
377 if (cfg == NULL)
378 goto fail;
379
380 fseek(f, 0, SEEK_SET);
381 if (fread(cfg, 1, size, f) != size) {
382 printf("failed to read: %s\n", cfgfile);
383 goto fail_read;
384 }
385 cfg[size] = 0;
386
387 for (i = 0; i < ARRAY_SIZE(config_data); i++) {
388 char *tmp, *tmp2;
389 u32 val;
390
391 tmp = strstr(cfg, config_data[i].name);
392 if (tmp == NULL)
393 continue;
394 tmp += strlen(config_data[i].name);
395 if (strncmp(tmp, " = ", 3) != 0)
396 continue;
397 tmp += 3;
398
399 if (config_data[i].len == 0) {
400 parse_str_val(config_data[i].val, tmp);
401 continue;
402 }
403
404 tmp2 = NULL;
405 val = strtoul(tmp, &tmp2, 16);
406 if (tmp2 == NULL || tmp == tmp2)
407 continue; // parse failed
408
409 switch (config_data[i].len) {
410 case 1:
411 *(u8 *)config_data[i].val = val;
412 break;
413 case 2:
414 *(u16 *)config_data[i].val = val;
415 break;
416 case 4:
417 *(u32 *)config_data[i].val = val;
418 break;
419 default:
420 printf("menu_load_config: unhandled len %d for %s\n",
421 config_data[i].len, config_data[i].name);
422 break;
423 }
424 }
425
426 if (!is_game) {
427 char *tmp = strstr(cfg, "lastcdimg = ");
428 if (tmp != NULL) {
429 tmp += 12;
430 parse_str_val(last_selected_fname, tmp);
431 }
432 }
433
cbd45cda 434 keys_load_all(cfg);
435 ret = 0;
436fail_read:
437 free(cfg);
438fail:
439 if (f != NULL)
440 fclose(f);
441
907b1e90 442 menu_sync_config();
443
bbd837c6 444 // sync plugins
e6eb2066 445 for (i = bios_sel = 0; bioses[i] != NULL; i++)
446 if (strcmp(Config.Bios, bioses[i]) == 0)
447 { bios_sel = i; break; }
448
bbd837c6 449 for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
450 if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
451 { gpu_plugsel = i; break; }
452
453 for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
454 if (strcmp(Config.Spu, spu_plugins[i]) == 0)
455 { spu_plugsel = i; break; }
456
4f3639fa 457 return ret;
69af03a2 458}
459
9564e73d 460// rrrr rggg gggb bbbb
461static unsigned short fname2color(const char *fname)
462{
bab59f00 463 static const char *cdimg_exts[] = { ".bin", ".img", ".mdf", ".iso", ".cue", ".z",
464 ".bz", ".znx", ".pbp", ".cbn" };
465 static const char *other_exts[] = { ".ccd", ".toc", ".mds", ".sub",
466 ".table", ".index", ".sbi" };
9564e73d 467 const char *ext = strrchr(fname, '.');
468 int i;
469
470 if (ext == NULL)
471 return 0xffff;
472 for (i = 0; i < array_size(cdimg_exts); i++)
473 if (strcasecmp(ext, cdimg_exts[i]) == 0)
474 return 0x7bff;
475 for (i = 0; i < array_size(other_exts); i++)
476 if (strcasecmp(ext, other_exts[i]) == 0)
477 return 0xa514;
478 return 0xffff;
479}
480
61363062 481static void draw_savestate_bg(int slot);
482
f246f461 483static const char *filter_exts[] = {
484 ".mp3", ".MP3", ".txt", ".htm", "html", ".jpg", ".pnd"
485};
486
bd6267e6 487#define MENU_ALIGN_LEFT
55b0eeea 488#ifdef __ARM_ARCH_7A__ // assume hires device
489#define MENU_X2 1
490#else
491#define MENU_X2 0
492#endif
493
3c70c47b 494#define menu_init menu_init_common
69af03a2 495#include "common/menu.c"
3c70c47b 496#undef menu_init
69af03a2 497
61363062 498// a bit of black magic here
499static void draw_savestate_bg(int slot)
500{
61363062 501 static const int psx_widths[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
502 int x, y, w, h;
503 char fname[MAXPATHLEN];
504 GPUFreeze_t *gpu;
505 u16 *s, *d;
506 gzFile f;
507 int ret;
508 u32 tmp;
509
510 ret = get_state_filename(fname, sizeof(fname), slot);
511 if (ret != 0)
512 return;
513
514 f = gzopen(fname, "rb");
515 if (f == NULL)
516 return;
517
518 if (gzseek(f, 0x29933d, SEEK_SET) != 0x29933d) {
519 fprintf(stderr, "gzseek failed\n");
520 gzclose(f);
521 return;
522 }
523
524 gpu = malloc(sizeof(*gpu));
525 if (gpu == NULL) {
526 gzclose(f);
527 return;
528 }
529
530 ret = gzread(f, gpu, sizeof(*gpu));
531 gzclose(f);
532 if (ret != sizeof(*gpu)) {
533 fprintf(stderr, "gzread failed\n");
534 goto out;
535 }
536
537 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
538
ff847a2e 539 if (gpu->ulStatus & 0x800000)
540 goto out; // disabled
61363062 541
542 x = gpu->ulControl[5] & 0x3ff;
543 y = (gpu->ulControl[5] >> 10) & 0x1ff;
ff847a2e 544 s = (u16 *)gpu->psxVRam + y * 1024 + (x & ~1);
61363062 545 w = psx_widths[(gpu->ulStatus >> 16) & 7];
546 tmp = gpu->ulControl[7];
547 h = ((tmp >> 10) & 0x3ff) - (tmp & 0x3ff);
548 if (gpu->ulStatus & 0x80000) // doubleheight
549 h *= 2;
550
551 x = max(0, g_menuscreen_w - w) & ~3;
552 y = max(0, g_menuscreen_h / 2 - h / 2);
553 w = min(g_menuscreen_w, w);
554 h = min(g_menuscreen_h, h);
555 d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
556
55b0eeea 557 for (; h > 0; h--, d += g_menuscreen_w, s += 1024) {
ff847a2e 558 if (gpu->ulStatus & 0x200000)
559 bgr888_to_rgb565(d, s, w * 3);
560 else
561 bgr555_to_rgb565(d, s, w * 2);
55b0eeea 562#ifndef __ARM_ARCH_7A__
563 // better darken this on small screens
564 menu_darken_bg(d, d, w * 2, 0);
565#endif
566 }
61363062 567
568out:
569 free(gpu);
570}
571
55b0eeea 572// ---------- XXX: pandora specific -----------
3c70c47b 573
574static const char pnd_script_base[] = "sudo -n /usr/pandora/scripts";
575static char **pnd_filter_list;
576
3c70c47b 577static void apply_filter(int which)
578{
4f3639fa 579 static int old = -1;
3c70c47b 580 char buf[128];
581 int i;
582
4f3639fa 583 if (pnd_filter_list == NULL || which == old)
3c70c47b 584 return;
585
586 for (i = 0; i < which; i++)
587 if (pnd_filter_list[i] == NULL)
588 return;
589
590 if (pnd_filter_list[i] == NULL)
591 return;
592
593 snprintf(buf, sizeof(buf), "%s/op_videofir.sh %s", pnd_script_base, pnd_filter_list[i]);
594 system(buf);
4f3639fa 595 old = which;
3c70c47b 596}
597
cefe86b7 598static void apply_lcdrate(int pal)
599{
600 static int old = -1;
601 char buf[128];
602
603 if (pal == old)
604 return;
605
606 snprintf(buf, sizeof(buf), "%s/op_lcdrate.sh %d",
607 pnd_script_base, pal ? 50 : 60);
608 system(buf);
609 old = pal;
610}
611
3c70c47b 612static menu_entry e_menu_gfx_options[];
613
614static void pnd_menu_init(void)
615{
616 struct dirent *ent;
617 int i, count = 0;
618 char **mfilters;
1bd9ee68 619 char buff[64];
3c70c47b 620 DIR *dir;
621
55b0eeea 622 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
3c70c47b 623
624 dir = opendir("/etc/pandora/conf/dss_fir");
625 if (dir == NULL) {
626 perror("filter opendir");
627 return;
628 }
629
630 while (1) {
631 errno = 0;
632 ent = readdir(dir);
633 if (ent == NULL) {
634 if (errno != 0)
635 perror("readdir");
636 break;
637 }
1bd9ee68 638
639 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
640 continue;
641
642 count++;
3c70c47b 643 }
644
645 if (count == 0)
646 return;
647
648 mfilters = calloc(count + 1, sizeof(mfilters[0]));
649 if (mfilters == NULL)
650 return;
651
652 rewinddir(dir);
653 for (i = 0; (ent = readdir(dir)); ) {
654 size_t len;
655
1bd9ee68 656 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
657 continue;
658
659 len = strlen(ent->d_name);
660
661 // skip pre-HF5 extra files
662 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v3") == 0)
663 continue;
664 if (len >= 3 && strcmp(ent->d_name + len - 3, "_v5") == 0)
3c70c47b 665 continue;
666
1bd9ee68 667 // have to cut "_up_h" for pre-HF5
668 if (len > 5 && strcmp(ent->d_name + len - 5, "_up_h") == 0)
669 len -= 5;
670
3c70c47b 671 if (len > sizeof(buff) - 1)
672 continue;
673
674 strncpy(buff, ent->d_name, len);
675 buff[len] = 0;
676 mfilters[i] = strdup(buff);
677 if (mfilters[i] != NULL)
678 i++;
679 }
680 closedir(dir);
681
682 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
683 e_menu_gfx_options[i].data = (void *)mfilters;
684 pnd_filter_list = mfilters;
69af03a2 685}
686
201c21e2 687void menu_finish(void)
688{
55b0eeea 689 plat_cpu_clock_apply(cpu_clock_st);
201c21e2 690}
691
69af03a2 692// -------------- key config --------------
693
694me_bind_action me_ctrl_actions[] =
695{
696 { "UP ", 1 << DKEY_UP},
697 { "DOWN ", 1 << DKEY_DOWN },
698 { "LEFT ", 1 << DKEY_LEFT },
699 { "RIGHT ", 1 << DKEY_RIGHT },
700 { "TRIANGLE", 1 << DKEY_TRIANGLE },
22a8a805 701 { "CIRCLE ", 1 << DKEY_CIRCLE },
69af03a2 702 { "CROSS ", 1 << DKEY_CROSS },
703 { "SQUARE ", 1 << DKEY_SQUARE },
704 { "L1 ", 1 << DKEY_L1 },
705 { "R1 ", 1 << DKEY_R1 },
706 { "L2 ", 1 << DKEY_L2 },
707 { "R2 ", 1 << DKEY_R2 },
43bca6fb 708 { "L3 ", 1 << DKEY_L3 },
709 { "R3 ", 1 << DKEY_R3 },
69af03a2 710 { "START ", 1 << DKEY_START },
711 { "SELECT ", 1 << DKEY_SELECT },
712 { NULL, 0 }
713};
714
715me_bind_action emuctrl_actions[] =
716{
8f892648 717 { "Save State ", 1 << SACTION_SAVE_STATE },
718 { "Load State ", 1 << SACTION_LOAD_STATE },
719 { "Prev Save Slot ", 1 << SACTION_PREV_SSLOT },
720 { "Next Save Slot ", 1 << SACTION_NEXT_SSLOT },
721 { "Toggle Frameskip ", 1 << SACTION_TOGGLE_FSKIP },
29a8c4f3 722 { "Take Screenshot ", 1 << SACTION_SCREENSHOT },
8f892648 723 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
4c08b9e7 724 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
725 { "Gun A button ", 1 << SACTION_GUN_A },
726 { "Gun B button ", 1 << SACTION_GUN_B },
727 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
221be40d 728#ifndef __ARM_ARCH_7A__ /* XXX */
729 { "Volume Up ", 1 << SACTION_VOLUME_UP },
730 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
731#endif
69af03a2 732 { NULL, 0 }
733};
734
43bca6fb 735static char *mystrip(char *str)
736{
737 int i, len;
738
739 len = strlen(str);
740 for (i = 0; i < len; i++)
741 if (str[i] != ' ') break;
742 if (i > 0) memmove(str, str + i, len - i + 1);
743
744 len = strlen(str);
745 for (i = len - 1; i >= 0; i--)
746 if (str[i] != ' ') break;
747 str[i+1] = 0;
748
749 return str;
750}
751
752static void get_line(char *d, size_t size, const char *s)
753{
754 const char *pe;
755 size_t len;
756
757 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
758 ;
759 len = pe - s;
760 if (len > size - 1)
761 len = size - 1;
762 strncpy(d, s, len);
763 d[len] = 0;
764
765 mystrip(d);
766}
767
768static void keys_write_all(FILE *f)
769{
770 int d;
771
772 for (d = 0; d < IN_MAX_DEVS; d++)
773 {
774 const int *binds = in_get_dev_binds(d);
775 const char *name = in_get_dev_name(d, 0, 0);
776 int k, count = 0;
777
778 if (binds == NULL || name == NULL)
779 continue;
780
781 fprintf(f, "binddev = %s\n", name);
782 in_get_config(d, IN_CFG_BIND_COUNT, &count);
783
784 for (k = 0; k < count; k++)
785 {
786 int i, kbinds, mask;
787 char act[32];
788
789 act[0] = act[31] = 0;
790 name = in_get_key_name(d, k);
791
792 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
793 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
794 mask = me_ctrl_actions[i].mask;
795 if (mask & kbinds) {
796 strncpy(act, me_ctrl_actions[i].name, 31);
797 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
798 kbinds &= ~mask;
799 }
800 mask = me_ctrl_actions[i].mask << 16;
801 if (mask & kbinds) {
802 strncpy(act, me_ctrl_actions[i].name, 31);
803 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
804 kbinds &= ~mask;
805 }
806 }
807
808 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
221be40d 809 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
43bca6fb 810 mask = emuctrl_actions[i].mask;
811 if (mask & kbinds) {
812 strncpy(act, emuctrl_actions[i].name, 31);
813 fprintf(f, "bind %s = %s\n", name, mystrip(act));
814 kbinds &= ~mask;
815 }
816 }
817 }
818 }
819}
820
821static int parse_bind_val(const char *val, int *type)
822{
823 int i;
824
825 *type = IN_BINDTYPE_NONE;
826 if (val[0] == 0)
827 return 0;
828
829 if (strncasecmp(val, "player", 6) == 0)
830 {
831 int player, shift = 0;
832 player = atoi(val + 6) - 1;
833
834 if ((unsigned int)player > 1)
835 return -1;
836 if (player == 1)
837 shift = 16;
838
839 *type = IN_BINDTYPE_PLAYER12;
840 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
841 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
842 return me_ctrl_actions[i].mask << shift;
843 }
844 }
845 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
846 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
847 *type = IN_BINDTYPE_EMU;
848 return emuctrl_actions[i].mask;
849 }
850 }
851
852 return -1;
853}
854
855static void keys_load_all(const char *cfg)
856{
857 char dev[256], key[128], *act;
858 const char *p;
859 int bind, bindtype;
860 int dev_id;
861
862 p = cfg;
863 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
864 p += 10;
865
866 get_line(dev, sizeof(dev), p);
867 dev_id = in_config_parse_dev(dev);
868 if (dev_id < 0) {
869 printf("input: can't handle dev: %s\n", dev);
870 continue;
871 }
872
873 in_unbind_all(dev_id, -1, -1);
874 while ((p = strstr(p, "bind"))) {
875 if (strncmp(p, "binddev = ", 10) == 0)
876 break;
877
878 p += 4;
879 if (*p != ' ') {
880 printf("input: parse error: %16s..\n", p);
881 continue;
882 }
883
884 get_line(key, sizeof(key), p);
885 act = strchr(key, '=');
886 if (act == NULL) {
887 printf("parse failed: %16s..\n", p);
888 continue;
889 }
890 *act = 0;
891 act++;
892 mystrip(key);
893 mystrip(act);
894
895 bind = parse_bind_val(act, &bindtype);
896 if (bind != -1 && bind != 0) {
8f892648 897 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
43bca6fb 898 in_config_bind_key(dev_id, key, bind, bindtype);
899 }
900 else
901 lprintf("config: unhandled action \"%s\"\n", act);
902 }
903 }
ef94866c 904 in_clean_binds();
43bca6fb 905}
906
69af03a2 907static int key_config_loop_wrap(int id, int keys)
908{
909 switch (id) {
910 case MA_CTRL_PLAYER1:
911 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
912 break;
913 case MA_CTRL_PLAYER2:
914 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
915 break;
916 case MA_CTRL_EMU:
917 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
918 break;
919 default:
920 break;
921 }
922 return 0;
923}
924
925static const char *mgn_dev_name(int id, int *offs)
926{
927 const char *name = NULL;
928 static int it = 0;
929
930 if (id == MA_CTRL_DEV_FIRST)
931 it = 0;
932
933 for (; it < IN_MAX_DEVS; it++) {
934 name = in_get_dev_name(it, 1, 1);
935 if (name != NULL)
936 break;
937 }
938
939 it++;
940 return name;
941}
942
943static const char *mgn_saveloadcfg(int id, int *offs)
944{
945 return "";
946}
947
cd6e8d0f 948static int mh_savecfg(int id, int keys)
69af03a2 949{
cd6e8d0f 950 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
951 me_update_msg("config saved");
952 else
953 me_update_msg("failed to write config");
69af03a2 954
955 return 1;
956}
957
ef94866c 958static int mh_input_rescan(int id, int keys)
959{
960 //menu_sync_config();
55b0eeea 961 plat_rescan_inputs();
ef94866c 962 me_update_msg("rescan complete.");
963
964 return 0;
965}
966
4c08b9e7 967static const char *men_in_type_sel[] = {
968 "Standard (SCPH-1080)",
969 "Analog (SCPH-1150)",
970 "GunCon",
971 NULL
972};
ef94866c 973static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
4c08b9e7 974static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
799b0b87 975
69af03a2 976static menu_entry e_menu_keyconfig[] =
977{
4c08b9e7 978 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
979 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
980 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
799b0b87 981 mee_label (""),
4c08b9e7 982 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
983 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
55b0eeea 984 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
985 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
4c08b9e7 986 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
799b0b87 987 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
988 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
ef94866c 989 mee_handler ("Rescan devices", mh_input_rescan),
69af03a2 990 mee_label (""),
991 mee_label ("Input devices:"),
992 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
993 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
994 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
995 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
996 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
997 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
998 mee_label_mk (MA_CTRL_DEV_NEXT, mgn_dev_name),
999 mee_end,
1000};
1001
1002static int menu_loop_keyconfig(int id, int keys)
1003{
1004 static int sel = 0;
1005
e16a7e51 1006// me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
51f77282 1007 me_loop(e_menu_keyconfig, &sel);
69af03a2 1008 return 0;
1009}
1010
69af03a2 1011// ------------ gfx options menu ------------
1012
a185be70 1013static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
3c70c47b 1014static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1015 "using d-pad or move it using R+d-pad";
1016static const char *men_dummy[] = { NULL };
1017
1018static int menu_loop_cscaler(int id, int keys)
1019{
1020 unsigned int inp;
1021
1022 scaling = SCALE_CUSTOM;
1023
1024 omap_enable_layer(1);
3c70c47b 1025
1026 for (;;)
1027 {
1028 menu_draw_begin(0);
201c21e2 1029 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1030 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1031 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
3c70c47b 1032 menu_draw_end();
1033
1034 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_R|PBTN_MOK|PBTN_MBACK, 40);
1035 if (inp & PBTN_UP) g_layer_y--;
1036 if (inp & PBTN_DOWN) g_layer_y++;
1037 if (inp & PBTN_LEFT) g_layer_x--;
1038 if (inp & PBTN_RIGHT) g_layer_x++;
1039 if (!(inp & PBTN_R)) {
1040 if (inp & PBTN_UP) g_layer_h += 2;
1041 if (inp & PBTN_DOWN) g_layer_h -= 2;
1042 if (inp & PBTN_LEFT) g_layer_w += 2;
1043 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1044 }
1045 if (inp & (PBTN_MOK|PBTN_MBACK))
1046 break;
1047
1048 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1049 if (g_layer_x < 0) g_layer_x = 0;
1050 if (g_layer_x > 640) g_layer_x = 640;
1051 if (g_layer_y < 0) g_layer_y = 0;
1052 if (g_layer_y > 420) g_layer_y = 420;
1053 if (g_layer_w < 160) g_layer_w = 160;
1054 if (g_layer_h < 60) g_layer_h = 60;
1055 if (g_layer_x + g_layer_w > 800)
1056 g_layer_w = 800 - g_layer_x;
1057 if (g_layer_y + g_layer_h > 480)
1058 g_layer_h = 480 - g_layer_y;
1059 omap_enable_layer(1);
1060 }
1061 }
1062
1063 omap_enable_layer(0);
1064
1065 return 0;
1066}
1067
69af03a2 1068static menu_entry e_menu_gfx_options[] =
1069{
3c70c47b 1070 mee_enum ("Scaler", 0, scaling, men_scaler),
1071 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1072// mee_onoff ("Vsync", 0, vsync, 1),
1073 mee_cust_h ("Setup custom scaler", 0, menu_loop_cscaler, NULL, h_cscaler),
69af03a2 1074 mee_end,
1075};
1076
1077static int menu_loop_gfx_options(int id, int keys)
1078{
1079 static int sel = 0;
1080
51f77282 1081 me_loop(e_menu_gfx_options, &sel);
69af03a2 1082
1083 return 0;
1084}
1085
bd6267e6 1086// ------------ bios/plugins ------------
1087
17a54a4a 1088static menu_entry e_menu_plugin_gpu_unai[] =
1089{
1090 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1091 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1092 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1093 mee_end,
1094};
1095
1096static int menu_loop_plugin_gpu_unai(int id, int keys)
1097{
1098 int sel = 0;
1099 me_loop(e_menu_plugin_gpu_unai, &sel);
1100 return 0;
1101}
1102
bd6267e6 1103static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
bd6267e6 1104static const char h_gpu_0[] = "Needed for Chrono Cross";
1105static const char h_gpu_1[] = "Capcom fighting games";
1106static const char h_gpu_2[] = "Black screens in Lunar";
1107static const char h_gpu_3[] = "Compatibility mode";
1108static const char h_gpu_6[] = "Pandemonium 2";
1109static const char h_gpu_7[] = "Skip every second frame";
1110static const char h_gpu_8[] = "Needed by Dark Forces";
1111static const char h_gpu_9[] = "better g-colors, worse textures";
1112static const char h_gpu_10[] = "Toggle busy flags after drawing";
1113
17a54a4a 1114static menu_entry e_menu_plugin_gpu_peops[] =
bd6267e6 1115{
e64dc4c5 1116 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
1117 mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
1118 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1119 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1120 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1121 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
1122 mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
1123 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1124 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1125 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
bd6267e6 1126 mee_end,
1127};
1128
17a54a4a 1129static int menu_loop_plugin_gpu_peops(int id, int keys)
bd6267e6 1130{
1131 static int sel = 0;
17a54a4a 1132 me_loop(e_menu_plugin_gpu_peops, &sel);
bd6267e6 1133 return 0;
1134}
1135
bd6267e6 1136static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
9e7a7352 1137static const char h_spu_volboost[] = "Large values cause distortion";
cdb31c95 1138static const char h_spu_irq_wait[] = "Wait for CPU (recommended set to ON)";
1bd9ee68 1139static const char h_spu_thread[] = "Run sound emulation in main thread (recommended)";
bd6267e6 1140
1141static menu_entry e_menu_plugin_spu[] =
1142{
9e7a7352 1143 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
381ea103 1144 mee_onoff ("Reverb", 0, iUseReverb, 2),
bd6267e6 1145 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1146 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
1147 mee_onoff_h ("SPU IRQ Wait", 0, iSPUIRQWait, 1, h_spu_irq_wait),
1bd9ee68 1148 mee_onoff_h ("Sound in main thread", 0, iUseTimer, 2, h_spu_thread),
bd6267e6 1149 mee_end,
1150};
1151
1152static int menu_loop_plugin_spu(int id, int keys)
1153{
1154 static int sel = 0;
51f77282 1155 me_loop(e_menu_plugin_spu, &sel);
bd6267e6 1156 return 0;
1157}
1158
55b0eeea 1159static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1160 "savestates and can't be changed there. Must save\n"
1161 "config and reload the game for change to take effect";
bbd837c6 1162static const char h_plugin_xpu[] = "Must save config and reload the game\n"
1163 "for plugin change to take effect";
17a54a4a 1164static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
1165static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
e6eb2066 1166static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
bbd837c6 1167
bd6267e6 1168static menu_entry e_menu_plugin_options[] =
1169{
e6eb2066 1170 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
bbd837c6 1171 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_xpu),
1172 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_xpu),
17a54a4a 1173 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
1174 mee_handler_h ("Configure PCSX4ALL GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
bd6267e6 1175 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1176 mee_end,
1177};
1178
51f77282 1179static menu_entry e_menu_main2[];
e16a7e51 1180
bd6267e6 1181static int menu_loop_plugin_options(int id, int keys)
1182{
1183 static int sel = 0;
51f77282 1184 me_loop(e_menu_plugin_options, &sel);
bbd837c6 1185
e6eb2066 1186 // sync BIOS/plugins
1187 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
bbd837c6 1188 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1189 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
51f77282 1190 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
bbd837c6 1191
bd6267e6 1192 return 0;
1193}
1194
1195// ------------ adv options menu ------------
1196
0ff8c62c 1197static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n";
bab59f00 1198static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
0ff8c62c 1199static const char h_cfg_gteunn[] = "May cause graphical glitches";
1200static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1201
1202static menu_entry e_menu_speed_hacks[] =
1203{
1204 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1205 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1206 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1207 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1208 mee_end,
1209};
1210
1211static int menu_loop_speed_hacks(int id, int keys)
1212{
1213 static int sel = 0;
1214 me_loop(e_menu_speed_hacks, &sel);
1215 return 0;
1216}
1217
4feed8d3 1218static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
8f892648 1219static const char h_cfg_cpul[] = "Shows CPU usage in %";
90f1d26c 1220static const char h_cfg_spu[] = "Shows active SPU channels\n"
1221 "(green: normal, red: fmod, blue: noise)";
1bd9ee68 1222static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
bd6267e6 1223static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1224static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1225 "(proper .cue/.bin dump is needed otherwise)";
4feed8d3 1226static const char h_cfg_sio[] = "You should not need this, breaks games";
1227static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1228static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1229 "(timing hack, breaks other games)";
1230static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1231 "(timing hack, breaks other games)";
0ff8c62c 1232static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
b5e7e49a 1233static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1234 "Might be useful to overcome some dynarec bugs";
0ff8c62c 1235static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1236 "must reload game for any change to take effect";
bd6267e6 1237
1238static menu_entry e_menu_adv_options[] =
1239{
fba06457 1240 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
90f1d26c 1241 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
bce6b056 1242 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
bd6267e6 1243 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1244 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1245 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1246 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
b1be1eee 1247 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
bd6267e6 1248 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
4feed8d3 1249 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
b5e7e49a 1250 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
0ff8c62c 1251 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
bd6267e6 1252 mee_end,
1253};
1254
1255static int menu_loop_adv_options(int id, int keys)
1256{
1257 static int sel = 0;
51f77282 1258 me_loop(e_menu_adv_options, &sel);
bd6267e6 1259 return 0;
1260}
1261
69af03a2 1262// ------------ options menu ------------
1263
69af03a2 1264static int mh_restore_defaults(int id, int keys)
1265{
3c70c47b 1266 menu_set_defconfig();
69af03a2 1267 me_update_msg("defaults restored");
1268 return 1;
1269}
1270
907b1e90 1271static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
ea4a16e7 1272static const char *men_frameskip[] = { "Auto", "Off", "1", NULL };
bd6267e6 1273/*
69af03a2 1274static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1275static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1276 "loading state or both";
bd6267e6 1277*/
1278static const char h_restore_def[] = "Switches back to default / recommended\n"
1279 "configuration";
9f4a4237 1280static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
69af03a2 1281
1282static menu_entry e_menu_options[] =
1283{
bd6267e6 1284// mee_range ("Save slot", 0, state_slot, 0, 9),
1285// mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
ea4a16e7 1286 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
bd6267e6 1287 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
907b1e90 1288 mee_enum ("Region", 0, region, men_region),
3c70c47b 1289 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
55b0eeea 1290 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
bd6267e6 1291 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
69af03a2 1292 mee_handler ("[Advanced]", menu_loop_adv_options),
cd6e8d0f 1293 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1294 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
bd6267e6 1295 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
69af03a2 1296 mee_end,
1297};
1298
1299static int menu_loop_options(int id, int keys)
1300{
1301 static int sel = 0;
1302 int i;
1303
1304 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
3c70c47b 1305 e_menu_options[i].enabled = cpu_clock != 0 ? 1 : 0;
e16a7e51 1306 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
69af03a2 1307
51f77282 1308 me_loop(e_menu_options, &sel);
69af03a2 1309
1310 return 0;
1311}
1312
1313// ------------ debug menu ------------
1314
72bb6fdd 1315static void draw_frame_debug(GPUFreeze_t *gpuf)
69af03a2 1316{
72bb6fdd 1317 int w = min(g_menuscreen_w, 1024);
1318 int h = min(g_menuscreen_h, 512);
1319 u16 *d = g_menuscreen_ptr;
1320 u16 *s = (u16 *)gpuf->psxVRam;
1321 char buff[64];
1322 int ty = 1;
1323
1324 gpuf->ulFreezeVersion = 1;
1325 if (GPU_freeze != NULL)
1326 GPU_freeze(1, gpuf);
1327
1328 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1329 bgr555_to_rgb565(d, s, w * 2);
1330
3c70c47b 1331 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
72bb6fdd 1332 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1333 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1334 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1335 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
69af03a2 1336}
1337
1338static void debug_menu_loop(void)
1339{
72bb6fdd 1340 GPUFreeze_t *gpuf;
69af03a2 1341 int inp;
1342
72bb6fdd 1343 gpuf = malloc(sizeof(*gpuf));
1344 if (gpuf == NULL)
1345 return;
1346
69af03a2 1347 while (1)
1348 {
72bb6fdd 1349 menu_draw_begin(0);
1350 draw_frame_debug(gpuf);
69af03a2 1351 menu_draw_end();
1352
1353 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
1354 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, 70);
1355 if (inp & PBTN_MBACK)
72bb6fdd 1356 break;
69af03a2 1357 }
72bb6fdd 1358
1359 free(gpuf);
69af03a2 1360}
1361
51f77282 1362// --------- memcard manager ---------
1363
1364static void draw_mc_icon(int dx, int dy, const u16 *s)
1365{
1366 u16 *d;
1367 int x, y, l, p;
1368
1369 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1370
1371 for (y = 0; y < 16; y++, s += 16) {
1372 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1373 for (x = 0; x < 16; x++) {
1374 p = s[x];
1375 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1376 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1377 }
1378 }
1379 }
1380}
1381
1382static void draw_mc_bg(void)
1383{
1384 McdBlock *blocks1, *blocks2;
1385 int maxicons = 15;
1386 int i, y, row2;
1387
1388 blocks1 = malloc(15 * sizeof(blocks1[0]));
1389 blocks2 = malloc(15 * sizeof(blocks1[0]));
1390 if (blocks1 == NULL || blocks2 == NULL)
1391 goto out;
1392
1393 for (i = 0; i < 15; i++) {
1394 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1395 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1396 }
1397
1398 menu_draw_begin(1);
1399
1400 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1401
1402 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1403 if (y < 0) {
1404 // doesn't fit..
1405 y = 0;
1406 maxicons = g_menuscreen_h / 32;
1407 }
1408
1409 row2 = g_menuscreen_w / 2;
1410 for (i = 0; i < maxicons; i++) {
1411 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1412 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1413
1414 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1415 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1416 }
1417
1418 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1419
1420 menu_draw_end();
1421out:
1422 free(blocks1);
1423 free(blocks2);
1424}
1425
1426static void handle_memcard_sel(void)
1427{
1428 Config.Mcd1[0] = 0;
1429 if (memcard1_sel != 0)
1430 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1431 Config.Mcd2[0] = 0;
1432 if (memcard2_sel != 0)
1433 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1434 LoadMcds(Config.Mcd1, Config.Mcd2);
1435 draw_mc_bg();
1436}
1437
1438static menu_entry e_memcard_options[] =
1439{
1440 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1441 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1442 mee_end,
1443};
1444
1445static int menu_loop_memcards(int id, int keys)
1446{
1447 static int sel = 0;
1448 char *p;
1449 int i;
1450
1451 memcard1_sel = memcard2_sel = 0;
1452 p = strrchr(Config.Mcd1, '/');
1453 if (p != NULL)
1454 for (i = 0; memcards[i] != NULL; i++)
1455 if (strcmp(p + 1, memcards[i]) == 0)
1456 { memcard1_sel = i; break; }
1457 p = strrchr(Config.Mcd2, '/');
1458 if (p != NULL)
1459 for (i = 0; memcards[i] != NULL; i++)
1460 if (strcmp(p + 1, memcards[i]) == 0)
1461 { memcard2_sel = i; break; }
1462
1463 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1464
1465 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1466
1467 return 0;
1468}
1469
1470// --------- main menu help ----------
69af03a2 1471
4f5a1b2a 1472static void menu_bios_warn(void)
1473{
1474 int inp;
1475 static const char msg[] =
cbd45cda 1476 "You don't seem to have copied any BIOS\n"
1477 "files to\n"
1478#ifdef __ARM_ARCH_7A__ // XXX
4f5a1b2a 1479 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
cbd45cda 1480#else
1481 "pcsx_rearmed/bios/\n\n"
1482#endif
1483 "While many games work fine with fake\n"
1484 "(HLE) BIOS, others (like MGS and FF8)\n"
1485 "require BIOS to work.\n"
1486 "After copying the file, you'll also need\n"
1487 "to select it in the emu's menu:\n"
1488 "options->[BIOS/Plugins]\n\n"
1489 "The file is usually named SCPH1001.BIN,\n"
1490 "but other not compressed files can be\n"
1491 "used too.\n\n"
4f5a1b2a 1492 "Press (B) or (X) to continue";
1493
1494 while (1)
1495 {
4f5a1b2a 1496 draw_menu_message(msg, NULL);
4f5a1b2a 1497
1498 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1499 if (inp & (PBTN_MBACK|PBTN_MOK))
1500 return;
1501 }
1502}
1503
1504// ------------ main menu ------------
1505
bd6267e6 1506void OnFile_Exit();
1507
1bd9ee68 1508static void draw_frame_main(void)
1509{
65092fd8 1510 struct tm *tmp;
1511 time_t ltime;
1512 char ltime_s[16];
1513 char buff[64];
1514
1bd9ee68 1515 if (CdromId[0] != 0) {
c22b95ab 1516 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1517 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1518 Config.HLE ? "HLE" : "BIOS");
1bd9ee68 1519 smalltext_out16(4, 1, buff, 0x105f);
1520 }
65092fd8 1521
1522 if (ready_to_go) {
1523 ltime = time(NULL);
1524 tmp = localtime(&ltime);
1525 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
55b0eeea 1526 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, plat_get_bat_capacity());
65092fd8 1527 smalltext_out16(4, 1 + me_sfont_h, buff, 0x105f);
1528 }
1bd9ee68 1529}
1530
1531static void draw_frame_credits(void)
1532{
1533 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
1534}
1535
4f5a1b2a 1536static const char credits_text[] =
1537 "PCSX-ReARMed\n\n"
1538 "(C) 1999-2003 PCSX Team\n"
1539 "(C) 2005-2009 PCSX-df Team\n"
1540 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
1541 "GPU and SPU code by Pete Bernert\n"
1542 " and the P.E.Op.S. team\n"
1543 "ARM recompiler (C) 2009-2011 Ari64\n"
1544 "PCSX4ALL plugins by PCSX4ALL team\n"
1545 " Chui, Franxis, Unai\n\n"
1546 "integration, optimization and\n"
1547 " frontend (C) 2010-2011 notaz\n";
69af03a2 1548
e16a7e51 1549static int reset_game(void)
1550{
1551 // sanity check
1552 if (bios_sel == 0 && !Config.HLE)
1553 return -1;
1554
1555 ClosePlugins();
1556 OpenPlugins();
1557 SysReset();
1558 if (CheckCdrom() != -1) {
1559 LoadCdrom();
1560 }
1561 return 0;
1562}
1563
51f77282 1564static int reload_plugins(const char *cdimg)
e16a7e51 1565{
76f7048e 1566 pl_vout_buf = NULL;
e16a7e51 1567
1568 ClosePlugins();
51f77282 1569
1570 set_cd_image(cdimg);
e16a7e51 1571 LoadPlugins();
c22b95ab 1572 pcnt_hook_plugins();
e16a7e51 1573 NetOpened = 0;
1574 if (OpenPlugins() == -1) {
1575 me_update_msg("failed to open plugins");
1576 return -1;
1577 }
1578 plugin_call_rearmed_cbs();
1579
1580 CdromId[0] = '\0';
1581 CdromLabel[0] = '\0';
1582
51f77282 1583 return 0;
1584}
1585
1586static int run_bios(void)
1587{
1588 if (bios_sel == 0)
1589 return -1;
1590
1591 ready_to_go = 0;
1592 if (reload_plugins(NULL) != 0)
1593 return -1;
e16a7e51 1594 SysReset();
1595
1596 ready_to_go = 1;
1597 return 0;
1598}
1599
51f77282 1600static int run_exe(void)
69af03a2 1601{
51f77282 1602 const char *fname;
1603
1604 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1605 if (fname == NULL)
1606 return -1;
1607
69af03a2 1608 ready_to_go = 0;
51f77282 1609 if (reload_plugins(NULL) != 0)
1610 return -1;
69af03a2 1611
51f77282 1612 SysReset();
1613 if (Load(fname) != 0) {
1614 me_update_msg("exe load failed, bad file?");
1615 printf("meh\n");
bbd837c6 1616 return -1;
69af03a2 1617 }
51f77282 1618
1619 ready_to_go = 1;
1620 return 0;
1621}
1622
1623static int run_cd_image(const char *fname)
1624{
1625 ready_to_go = 0;
1626 reload_plugins(fname);
69af03a2 1627
76d63edf 1628 // always autodetect, menu_sync_config will override as needed
1629 Config.PsxAuto = 1;
1630
69af03a2 1631 if (CheckCdrom() == -1) {
1632 // Only check the CD if we are starting the console with a CD
1633 ClosePlugins();
1634 me_update_msg("unsupported/invalid CD image");
bbd837c6 1635 return -1;
69af03a2 1636 }
1637
bbd837c6 1638 SysReset();
1639
69af03a2 1640 // Read main executable directly from CDRom and start it
1641 if (LoadCdrom() == -1) {
1642 ClosePlugins();
1643 me_update_msg("failed to load CD image");
bbd837c6 1644 return -1;
69af03a2 1645 }
1646
1647 ready_to_go = 1;
bbd837c6 1648 return 0;
69af03a2 1649}
1650
bbd837c6 1651static int romsel_run(void)
69af03a2 1652{
bbd837c6 1653 int prev_gpu, prev_spu;
51f77282 1654 const char *fname;
bbd837c6 1655
1656 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1657 if (fname == NULL)
1658 return -1;
69af03a2 1659
bbd837c6 1660 printf("selected file: %s\n", fname);
1661
dc990066 1662 new_dynarec_clear_full();
1663
bbd837c6 1664 if (run_cd_image(fname) != 0)
1665 return -1;
1666
1667 prev_gpu = gpu_plugsel;
1668 prev_spu = spu_plugsel;
1669 if (menu_load_config(1) != 0)
1670 menu_load_config(0);
1671
1672 // check for plugin changes, have to repeat
1673 // loading if game config changed plugins to reload them
1674 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1675 printf("plugin change detected, reloading plugins..\n");
1676 if (run_cd_image(fname) != 0)
1677 return -1;
1678 }
1679
bab59f00 1680 if (Config.HLE)
1681 printf("note: running without BIOS, expect compatibility problems\n");
1682
bbd837c6 1683 strcpy(last_selected_fname, rom_fname_reload);
1684 return 0;
1685}
1686
1df403c5 1687static int swap_cd_image(void)
1688{
1689 char *fname;
1690
1691 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1692 if (fname == NULL)
1693 return -1;
1694
1695 printf("selected file: %s\n", fname);
1696
1697 CdromId[0] = '\0';
1698 CdromLabel[0] = '\0';
1699
1700 set_cd_image(fname);
1701 if (ReloadCdromPlugin() < 0) {
1702 me_update_msg("failed to load cdr plugin");
1703 return -1;
1704 }
1705 if (CDR_open() < 0) {
1706 me_update_msg("failed to open cdr plugin");
1707 return -1;
1708 }
1709
1710 SetCdOpenCaseTime(time(NULL) + 2);
1711 LidInterrupt();
1712
1713 strcpy(last_selected_fname, rom_fname_reload);
1714 return 0;
1715}
1716
bbd837c6 1717static int main_menu_handler(int id, int keys)
1718{
69af03a2 1719 switch (id)
1720 {
1721 case MA_MAIN_RESUME_GAME:
3c70c47b 1722 if (ready_to_go)
1723 return 1;
69af03a2 1724 break;
1725 case MA_MAIN_SAVE_STATE:
1726 if (ready_to_go)
1727 return menu_loop_savestate(0);
1728 break;
1729 case MA_MAIN_LOAD_STATE:
1730 if (ready_to_go)
1731 return menu_loop_savestate(1);
1732 break;
1733 case MA_MAIN_RESET_GAME:
e16a7e51 1734 if (ready_to_go && reset_game() == 0)
3c70c47b 1735 return 1;
69af03a2 1736 break;
1737 case MA_MAIN_LOAD_ROM:
bbd837c6 1738 if (romsel_run() == 0)
69af03a2 1739 return 1;
1740 break;
1df403c5 1741 case MA_MAIN_SWAP_CD:
1742 if (swap_cd_image() == 0)
1743 return 1;
1744 break;
e16a7e51 1745 case MA_MAIN_RUN_BIOS:
1746 if (run_bios() == 0)
1747 return 1;
1748 break;
51f77282 1749 case MA_MAIN_RUN_EXE:
1750 if (run_exe() == 0)
1751 return 1;
1752 break;
69af03a2 1753 case MA_MAIN_CREDITS:
4f5a1b2a 1754 draw_menu_message(credits_text, draw_frame_credits);
69af03a2 1755 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1756 break;
1757 case MA_MAIN_EXIT:
bd6267e6 1758 OnFile_Exit();
1759 break;
69af03a2 1760 default:
1761 lprintf("%s: something unknown selected\n", __FUNCTION__);
1762 break;
1763 }
1764
1765 return 0;
1766}
1767
51f77282 1768static menu_entry e_menu_main2[] =
1769{
1770 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1771 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
1772 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
1773 mee_handler ("Memcard manager", menu_loop_memcards),
1774 mee_end,
1775};
1776
1777static int main_menu2_handler(int id, int keys)
1778{
1779 static int sel = 0;
1780
1781 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
1782 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
1783
1784 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
1785}
1786
1787static const char h_extra[] = "Change CD, manage memcards..\n";
1788
69af03a2 1789static menu_entry e_menu_main[] =
1790{
1791 mee_label (""),
1792 mee_label (""),
1793 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
1794 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
1795 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
1796 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
1797 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
1798 mee_handler ("Options", menu_loop_options),
1799 mee_handler ("Controls", menu_loop_keyconfig),
51f77282 1800 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
69af03a2 1801 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
1802 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
1803 mee_end,
1804};
1805
3c70c47b 1806// ----------------------------
1807
bd6267e6 1808static void menu_leave_emu(void);
1809
69af03a2 1810void menu_loop(void)
1811{
1812 static int sel = 0;
1813
bd6267e6 1814 menu_leave_emu();
69af03a2 1815
4f5a1b2a 1816 if (bioses[1] == NULL && !warned_about_bios) {
1817 menu_bios_warn();
1818 warned_about_bios = 1;
1819 }
1820
69af03a2 1821 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
e16a7e51 1822 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
1823 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
69af03a2 1824 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
1825
69af03a2 1826 in_set_config_int(0, IN_CFG_BLOCKING, 1);
1827
1828 do {
51f77282 1829 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
69af03a2 1830 } while (!ready_to_go);
1831
1832 /* wait until menu, ok, back is released */
1833 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
1834 ;
1835
1836 in_set_config_int(0, IN_CFG_BLOCKING, 0);
1837
3c70c47b 1838 menu_prepare_emu();
1839}
1840
51f77282 1841static int qsort_strcmp(const void *p1, const void *p2)
1842{
1843 char * const *s1 = (char * const *)p1;
1844 char * const *s2 = (char * const *)p2;
1845 return strcasecmp(*s1, *s2);
1846}
1847
e6eb2066 1848static void scan_bios_plugins(void)
bbd837c6 1849{
1850 char fname[MAXPATHLEN];
1851 struct dirent *ent;
51f77282 1852 int bios_i, gpu_i, spu_i, mc_i;
bbd837c6 1853 char *p;
1854 DIR *dir;
1855
e6eb2066 1856 bioses[0] = "HLE";
bbd837c6 1857 gpu_plugins[0] = "builtin_gpu";
1858 spu_plugins[0] = "builtin_spu";
51f77282 1859 memcards[0] = "(none)";
1860 bios_i = gpu_i = spu_i = mc_i = 1;
e6eb2066 1861
1862 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
1863 dir = opendir(fname);
1864 if (dir == NULL) {
1865 perror("scan_bios_plugins bios opendir");
1866 goto do_plugins;
1867 }
1868
1869 while (1) {
1870 struct stat st;
1871
1872 errno = 0;
1873 ent = readdir(dir);
1874 if (ent == NULL) {
1875 if (errno != 0)
1876 perror("readdir");
1877 break;
1878 }
1879
1880 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1881 continue;
1882
1883 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
1884 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
1885 printf("bad BIOS file: %s\n", ent->d_name);
1886 continue;
1887 }
1888
1889 if (bios_i < ARRAY_SIZE(bioses) - 1) {
1890 bioses[bios_i++] = strdup(ent->d_name);
1891 continue;
1892 }
1893
1894 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
1895 }
1896
1897 closedir(dir);
bbd837c6 1898
e6eb2066 1899do_plugins:
bbd837c6 1900 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
1901 dir = opendir(fname);
1902 if (dir == NULL) {
51f77282 1903 perror("scan_bios_plugins plugins opendir");
1904 goto do_memcards;
bbd837c6 1905 }
1906
1907 while (1) {
1908 void *h, *tmp;
1909
1910 errno = 0;
1911 ent = readdir(dir);
1912 if (ent == NULL) {
1913 if (errno != 0)
1914 perror("readdir");
1915 break;
1916 }
1917 p = strstr(ent->d_name, ".so");
1918 if (p == NULL)
1919 continue;
1920
1921 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
1922 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
1923 if (h == NULL) {
1924 fprintf(stderr, "%s\n", dlerror());
1925 continue;
1926 }
1927
1928 // now what do we have here?
1929 tmp = dlsym(h, "GPUinit");
1930 if (tmp) {
1931 dlclose(h);
1932 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
1933 gpu_plugins[gpu_i++] = strdup(ent->d_name);
1934 continue;
1935 }
1936
1937 tmp = dlsym(h, "SPUinit");
1938 if (tmp) {
1939 dlclose(h);
1940 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
1941 spu_plugins[spu_i++] = strdup(ent->d_name);
1942 continue;
1943 }
1944
1945 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
1946 dlclose(h);
1947 }
1948
1949 closedir(dir);
51f77282 1950
1951do_memcards:
1952 dir = opendir("." MEMCARD_DIR);
1953 if (dir == NULL) {
1954 perror("scan_bios_plugins memcards opendir");
1955 return;
1956 }
1957
1958 while (1) {
1959 struct stat st;
1960
1961 errno = 0;
1962 ent = readdir(dir);
1963 if (ent == NULL) {
1964 if (errno != 0)
1965 perror("readdir");
1966 break;
1967 }
1968
1969 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
1970 continue;
1971
1972 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
1973 if (stat(fname, &st) != 0) {
1974 printf("bad memcard file: %s\n", ent->d_name);
1975 continue;
1976 }
1977
1978 if (mc_i < ARRAY_SIZE(memcards) - 1) {
1979 memcards[mc_i++] = strdup(ent->d_name);
1980 continue;
1981 }
1982
1983 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
1984 }
1985
1986 if (mc_i > 2)
1987 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
1988
1989 closedir(dir);
bbd837c6 1990}
1991
3c70c47b 1992void menu_init(void)
1993{
4f3639fa 1994 char buff[MAXPATHLEN];
1995
1996 strcpy(last_selected_fname, "/media");
1997
e6eb2066 1998 scan_bios_plugins();
4f3639fa 1999 pnd_menu_init();
2000 menu_init_common();
2001
3c70c47b 2002 menu_set_defconfig();
2003 menu_load_config(0);
3c70c47b 2004 last_psx_w = 320;
2005 last_psx_h = 240;
bd6267e6 2006 last_psx_bpp = 16;
2007
4f3639fa 2008 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2009 if (g_menubg_src_ptr == NULL)
2010 exit(1);
2011 emu_make_path(buff, "skin/background.png", sizeof(buff));
2012 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
55b0eeea 2013
2014#ifndef __ARM_ARCH_7A__ /* XXX */
2015 me_enable(e_menu_options, MA_OPT_DISP_OPTS, 0);
2016 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2017#else
2018 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2019#endif
3c70c47b 2020}
2021
bd6267e6 2022void menu_notify_mode_change(int w, int h, int bpp)
3c70c47b 2023{
a185be70 2024 float mult;
2025 int imult;
2026
3c70c47b 2027 last_psx_w = w;
2028 last_psx_h = h;
bd6267e6 2029 last_psx_bpp = bpp;
3c70c47b 2030
a185be70 2031 switch (scaling) {
2032 case SCALE_1_1:
3c70c47b 2033 g_layer_w = w; g_layer_h = h;
a185be70 2034 break;
2035
a185be70 2036 case SCALE_4_3v2:
fb005d87 2037 if (h > g_menuscreen_h || (240 < h && h <= 360))
2038 goto fractional_4_3;
2039
a185be70 2040 // 4:3 that prefers integer scaling
2041 imult = g_menuscreen_h / h;
2042 g_layer_w = w * imult;
2043 g_layer_h = h * imult;
2044 mult = (float)g_layer_w / (float)g_layer_h;
2045 if (mult < 1.25f || mult > 1.666f)
2046 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2047 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2048 break;
2049
fb005d87 2050 fractional_4_3:
2051 case SCALE_4_3:
2052 mult = 240.0f / (float)h * 4.0f / 3.0f;
2053 if (h > 256)
2054 mult *= 2.0f;
2055 g_layer_w = mult * (float)g_menuscreen_h;
2056 g_layer_h = g_menuscreen_h;
2057 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2058 break;
2059
a185be70 2060 case SCALE_FULLSCREEN:
2061 g_layer_w = g_menuscreen_w;
2062 g_layer_h = g_menuscreen_h;
2063 break;
2064
2065 default:
2066 break;
3c70c47b 2067 }
a185be70 2068
2069 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2070 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2071 if (g_layer_x < 0) g_layer_x = 0;
2072 if (g_layer_y < 0) g_layer_y = 0;
2073 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2074 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
3c70c47b 2075}
2076
bd6267e6 2077static void menu_leave_emu(void)
2078{
6d1a1ac2 2079 if (GPU_close != NULL) {
2080 int ret = GPU_close();
2081 if (ret)
2082 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2083 }
bd6267e6 2084
55b0eeea 2085 plat_video_menu_enter(ready_to_go);
2086
4f3639fa 2087 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
76f7048e 2088 if (pl_vout_buf != NULL && ready_to_go && last_psx_bpp == 16) {
bd6267e6 2089 int x = max(0, g_menuscreen_w - last_psx_w);
2090 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2091 int w = min(g_menuscreen_w, last_psx_w);
2092 int h = min(g_menuscreen_h, last_psx_h);
4f3639fa 2093 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
76f7048e 2094 u16 *s = pl_vout_buf;
bd6267e6 2095
2096 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w)
4f3639fa 2097 menu_darken_bg(d, s, w, 0);
bd6267e6 2098 }
fba06457 2099
1bd9ee68 2100 if (ready_to_go)
55b0eeea 2101 cpu_clock = plat_cpu_clock_get();
bd6267e6 2102}
2103
3c70c47b 2104void menu_prepare_emu(void)
2105{
b5e7e49a 2106 R3000Acpu *prev_cpu = psxCpu;
2107
fba06457 2108 plat_video_menu_leave();
2109
a185be70 2110 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
bd6267e6 2111
b5e7e49a 2112 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2113 if (psxCpu != prev_cpu)
2114 // note that this does not really reset, just clears drc caches
2115 psxCpu->Reset();
2116
bd6267e6 2117 // core doesn't care about Config.Cdda changes,
2118 // so handle them manually here
2119 if (Config.Cdda)
2120 CDR_stop();
6d1a1ac2 2121
907b1e90 2122 menu_sync_config();
cefe86b7 2123 apply_lcdrate(Config.PsxType);
2124 apply_filter(filter);
55b0eeea 2125 plat_cpu_clock_apply(cpu_clock);
fba06457 2126
e64dc4c5 2127 // push config to GPU plugin
2128 plugin_call_rearmed_cbs();
2129
6d1a1ac2 2130 if (GPU_open != NULL) {
6d1a1ac2 2131 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2132 if (ret)
2133 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2134 }
384f5f43 2135
4c08b9e7 2136 dfinput_activate();
69af03a2 2137}
2138
2139void me_update_msg(const char *msg)
2140{
2141 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2142 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2143
2144 menu_error_time = plat_get_ticks_ms();
2145 lprintf("msg: %s\n", menu_error_msg);
2146}
2147