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