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