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