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