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