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