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