add support for software-enhanced rendering
[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 },
8f892648 666 { "Enter Menu ", 1 << SACTION_ENTER_MENU },
a805c855 667#ifdef __ARM_ARCH_7A__ /* XXX */
668 { "Minimize ", 1 << SACTION_MINIMIZE },
669#endif
4c08b9e7 670 { "Gun Trigger ", 1 << SACTION_GUN_TRIGGER },
671 { "Gun A button ", 1 << SACTION_GUN_A },
672 { "Gun B button ", 1 << SACTION_GUN_B },
673 { "Gun Offscreen Trigger", 1 << SACTION_GUN_TRIGGER2 },
221be40d 674#ifndef __ARM_ARCH_7A__ /* XXX */
675 { "Volume Up ", 1 << SACTION_VOLUME_UP },
676 { "Volume Down ", 1 << SACTION_VOLUME_DOWN },
677#endif
69af03a2 678 { NULL, 0 }
679};
680
43bca6fb 681static char *mystrip(char *str)
682{
683 int i, len;
684
685 len = strlen(str);
686 for (i = 0; i < len; i++)
687 if (str[i] != ' ') break;
688 if (i > 0) memmove(str, str + i, len - i + 1);
689
690 len = strlen(str);
691 for (i = len - 1; i >= 0; i--)
4ea086f6 692 if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
43bca6fb 693 str[i+1] = 0;
694
695 return str;
696}
697
698static void get_line(char *d, size_t size, const char *s)
699{
700 const char *pe;
701 size_t len;
702
703 for (pe = s; *pe != '\r' && *pe != '\n' && *pe != 0; pe++)
704 ;
705 len = pe - s;
706 if (len > size - 1)
707 len = size - 1;
708 strncpy(d, s, len);
709 d[len] = 0;
710
711 mystrip(d);
712}
713
714static void keys_write_all(FILE *f)
715{
716 int d;
717
718 for (d = 0; d < IN_MAX_DEVS; d++)
719 {
720 const int *binds = in_get_dev_binds(d);
721 const char *name = in_get_dev_name(d, 0, 0);
722 int k, count = 0;
723
724 if (binds == NULL || name == NULL)
725 continue;
726
727 fprintf(f, "binddev = %s\n", name);
728 in_get_config(d, IN_CFG_BIND_COUNT, &count);
729
730 for (k = 0; k < count; k++)
731 {
732 int i, kbinds, mask;
733 char act[32];
734
735 act[0] = act[31] = 0;
736 name = in_get_key_name(d, k);
737
738 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_PLAYER12)];
739 for (i = 0; kbinds && i < ARRAY_SIZE(me_ctrl_actions) - 1; i++) {
740 mask = me_ctrl_actions[i].mask;
741 if (mask & kbinds) {
742 strncpy(act, me_ctrl_actions[i].name, 31);
743 fprintf(f, "bind %s = player1 %s\n", name, mystrip(act));
744 kbinds &= ~mask;
745 }
746 mask = me_ctrl_actions[i].mask << 16;
747 if (mask & kbinds) {
748 strncpy(act, me_ctrl_actions[i].name, 31);
749 fprintf(f, "bind %s = player2 %s\n", name, mystrip(act));
750 kbinds &= ~mask;
751 }
752 }
753
754 kbinds = binds[IN_BIND_OFFS(k, IN_BINDTYPE_EMU)];
221be40d 755 for (i = 0; kbinds && emuctrl_actions[i].name != NULL; i++) {
43bca6fb 756 mask = emuctrl_actions[i].mask;
757 if (mask & kbinds) {
758 strncpy(act, emuctrl_actions[i].name, 31);
759 fprintf(f, "bind %s = %s\n", name, mystrip(act));
760 kbinds &= ~mask;
761 }
762 }
763 }
1b0c5139 764
765 for (k = 0; k < array_size(in_adev); k++)
766 {
767 if (in_adev[k] == d)
768 fprintf(f, "bind_analog = %d\n", k);
769 }
43bca6fb 770 }
771}
772
773static int parse_bind_val(const char *val, int *type)
774{
775 int i;
776
777 *type = IN_BINDTYPE_NONE;
778 if (val[0] == 0)
779 return 0;
780
781 if (strncasecmp(val, "player", 6) == 0)
782 {
783 int player, shift = 0;
784 player = atoi(val + 6) - 1;
785
786 if ((unsigned int)player > 1)
787 return -1;
788 if (player == 1)
789 shift = 16;
790
791 *type = IN_BINDTYPE_PLAYER12;
792 for (i = 0; me_ctrl_actions[i].name != NULL; i++) {
793 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0)
794 return me_ctrl_actions[i].mask << shift;
795 }
796 }
797 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
798 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
799 *type = IN_BINDTYPE_EMU;
800 return emuctrl_actions[i].mask;
801 }
802 }
803
804 return -1;
805}
806
807static void keys_load_all(const char *cfg)
808{
809 char dev[256], key[128], *act;
810 const char *p;
811 int bind, bindtype;
1b0c5139 812 int ret, dev_id;
43bca6fb 813
814 p = cfg;
815 while (p != NULL && (p = strstr(p, "binddev = ")) != NULL) {
816 p += 10;
817
818 get_line(dev, sizeof(dev), p);
819 dev_id = in_config_parse_dev(dev);
820 if (dev_id < 0) {
821 printf("input: can't handle dev: %s\n", dev);
822 continue;
823 }
824
825 in_unbind_all(dev_id, -1, -1);
826 while ((p = strstr(p, "bind"))) {
827 if (strncmp(p, "binddev = ", 10) == 0)
828 break;
829
1b0c5139 830 if (strncmp(p, "bind_analog", 11) == 0) {
831 ret = sscanf(p, "bind_analog = %d", &bind);
832 p += 11;
833 if (ret != 1) {
834 printf("input: parse error: %16s..\n", p);
835 continue;
836 }
837 if ((unsigned int)bind >= array_size(in_adev)) {
838 printf("input: analog id %d out of range\n", bind);
839 continue;
840 }
841 in_adev[bind] = dev_id;
842 continue;
843 }
844
43bca6fb 845 p += 4;
846 if (*p != ' ') {
847 printf("input: parse error: %16s..\n", p);
848 continue;
849 }
850
851 get_line(key, sizeof(key), p);
852 act = strchr(key, '=');
853 if (act == NULL) {
854 printf("parse failed: %16s..\n", p);
855 continue;
856 }
857 *act = 0;
858 act++;
859 mystrip(key);
860 mystrip(act);
861
862 bind = parse_bind_val(act, &bindtype);
863 if (bind != -1 && bind != 0) {
8f892648 864 //printf("bind #%d '%s' %08x (%s)\n", dev_id, key, bind, act);
43bca6fb 865 in_config_bind_key(dev_id, key, bind, bindtype);
866 }
867 else
868 lprintf("config: unhandled action \"%s\"\n", act);
869 }
870 }
ef94866c 871 in_clean_binds();
43bca6fb 872}
873
69af03a2 874static int key_config_loop_wrap(int id, int keys)
875{
876 switch (id) {
877 case MA_CTRL_PLAYER1:
878 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 0);
879 break;
880 case MA_CTRL_PLAYER2:
881 key_config_loop(me_ctrl_actions, array_size(me_ctrl_actions) - 1, 1);
882 break;
883 case MA_CTRL_EMU:
884 key_config_loop(emuctrl_actions, array_size(emuctrl_actions) - 1, -1);
885 break;
886 default:
887 break;
888 }
889 return 0;
890}
891
1b0c5139 892static const char *adevnames[IN_MAX_DEVS + 2];
893static int stick_sel[2];
894
895static menu_entry e_menu_keyconfig_analog[] =
896{
897 mee_enum ("Left stick (L3)", 0, stick_sel[0], adevnames),
898 mee_range(" X axis", 0, in_adev_axis[0][0], 0, 7),
899 mee_range(" Y axis", 0, in_adev_axis[0][1], 0, 7),
900 mee_enum ("Right stick (R3)", 0, stick_sel[1], adevnames),
901 mee_range(" X axis", 0, in_adev_axis[1][0], 0, 7),
902 mee_range(" Y axis", 0, in_adev_axis[1][1], 0, 7),
903 mee_end,
904};
905
906static int key_config_analog(int id, int keys)
907{
908 int i, d, count, sel = 0;
909 int sel2dev_map[IN_MAX_DEVS];
910
911 memset(adevnames, 0, sizeof(adevnames));
912 memset(sel2dev_map, 0xff, sizeof(sel2dev_map));
913 memset(stick_sel, 0, sizeof(stick_sel));
914
915 adevnames[0] = "None";
916 i = 1;
917 for (d = 0; d < IN_MAX_DEVS; d++)
918 {
919 const char *name = in_get_dev_name(d, 0, 1);
920 if (name == NULL)
921 continue;
922
923 count = 0;
924 in_get_config(d, IN_CFG_ABS_AXIS_COUNT, &count);
925 if (count == 0)
926 continue;
927
928 if (in_adev[0] == d) stick_sel[0] = i;
929 if (in_adev[1] == d) stick_sel[1] = i;
930 sel2dev_map[i] = d;
931 adevnames[i++] = name;
932 }
933 adevnames[i] = NULL;
934
935 me_loop(e_menu_keyconfig_analog, &sel);
936
937 in_adev[0] = sel2dev_map[stick_sel[0]];
938 in_adev[1] = sel2dev_map[stick_sel[1]];
939
940 return 0;
941}
942
69af03a2 943static const char *mgn_dev_name(int id, int *offs)
944{
945 const char *name = NULL;
946 static int it = 0;
947
948 if (id == MA_CTRL_DEV_FIRST)
949 it = 0;
950
951 for (; it < IN_MAX_DEVS; it++) {
952 name = in_get_dev_name(it, 1, 1);
953 if (name != NULL)
954 break;
955 }
956
957 it++;
958 return name;
959}
960
961static const char *mgn_saveloadcfg(int id, int *offs)
962{
963 return "";
964}
965
cd6e8d0f 966static int mh_savecfg(int id, int keys)
69af03a2 967{
cd6e8d0f 968 if (menu_write_config(id == MA_OPT_SAVECFG_GAME ? 1 : 0) == 0)
969 me_update_msg("config saved");
970 else
971 me_update_msg("failed to write config");
69af03a2 972
973 return 1;
974}
975
ef94866c 976static int mh_input_rescan(int id, int keys)
977{
978 //menu_sync_config();
9b4bd105 979 in_probe();
ef94866c 980 me_update_msg("rescan complete.");
981
982 return 0;
983}
984
4c08b9e7 985static const char *men_in_type_sel[] = {
986 "Standard (SCPH-1080)",
987 "Analog (SCPH-1150)",
988 "GunCon",
989 NULL
990};
ef94866c 991static const char h_nub_btns[] = "Experimental, keep this OFF if unsure. Select rescan after change.";
b944a30e 992static const char h_notsgun[] = "Don't trigger (shoot) when touching screen in gun games.";
993static const char h_vibration[]= "Must select analog above and enable this ingame too.";
799b0b87 994
69af03a2 995static menu_entry e_menu_keyconfig[] =
996{
4c08b9e7 997 mee_handler_id("Player 1", MA_CTRL_PLAYER1, key_config_loop_wrap),
998 mee_handler_id("Player 2", MA_CTRL_PLAYER2, key_config_loop_wrap),
1b0c5139 999 mee_handler_id("Analog controls", MA_CTRL_ANALOG, key_config_analog),
4c08b9e7 1000 mee_handler_id("Emulator/Gun controls", MA_CTRL_EMU, key_config_loop_wrap),
799b0b87 1001 mee_label (""),
4c08b9e7 1002 mee_enum ("Port 1 device", 0, in_type_sel1, men_in_type_sel),
1003 mee_enum ("Port 2 device", 0, in_type_sel2, men_in_type_sel),
55b0eeea 1004 mee_onoff_h ("Nubs as buttons", MA_CTRL_NUBS_BTNS, in_evdev_allow_abs_only, 1, h_nub_btns),
b944a30e 1005 mee_onoff_h ("Vibration", MA_CTRL_VIBRATION, in_enable_vibration, 1, h_vibration),
55b0eeea 1006 mee_range ("Analog deadzone", MA_CTRL_DEADZONE, analog_deadzone, 1, 99),
4c08b9e7 1007 mee_onoff_h ("No TS Gun trigger", 0, g_opts, OPT_TSGUN_NOTRIGGER, h_notsgun),
799b0b87 1008 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1009 mee_cust_nosave("Save cfg for loaded game", MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
1b0c5139 1010 mee_handler ("Rescan devices:", mh_input_rescan),
69af03a2 1011 mee_label (""),
69af03a2 1012 mee_label_mk (MA_CTRL_DEV_FIRST, mgn_dev_name),
1013 mee_label_mk (MA_CTRL_DEV_NEXT, 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_end,
1020};
1021
1022static int menu_loop_keyconfig(int id, int keys)
1023{
1024 static int sel = 0;
1025
e16a7e51 1026// me_enable(e_menu_keyconfig, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
51f77282 1027 me_loop(e_menu_keyconfig, &sel);
69af03a2 1028 return 0;
1029}
1030
69af03a2 1031// ------------ gfx options menu ------------
1032
a185be70 1033static const char *men_scaler[] = { "1x1", "scaled 4:3", "integer scaled 4:3", "fullscreen", "custom", NULL };
3c70c47b 1034static const char h_cscaler[] = "Displays the scaler layer, you can resize it\n"
1035 "using d-pad or move it using R+d-pad";
1036static const char *men_dummy[] = { NULL };
1037
1038static int menu_loop_cscaler(int id, int keys)
1039{
1040 unsigned int inp;
1041
9e5ac38f 1042 g_scaler = SCALE_CUSTOM;
3c70c47b 1043
ab423939 1044 plat_gvideo_open(Config.PsxType);
3c70c47b 1045
1046 for (;;)
1047 {
1048 menu_draw_begin(0);
201c21e2 1049 memset(g_menuscreen_ptr, 4, g_menuscreen_w * g_menuscreen_h * 2);
1050 text_out16(2, 2, "%d,%d", g_layer_x, g_layer_y);
1051 text_out16(2, 480 - 18, "%dx%d | d-pad: resize, R+d-pad: move", g_layer_w, g_layer_h);
3c70c47b 1052 menu_draw_end();
1053
61f97bb0 1054 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT
1055 |PBTN_R|PBTN_MOK|PBTN_MBACK, NULL, 40);
3c70c47b 1056 if (inp & PBTN_UP) g_layer_y--;
1057 if (inp & PBTN_DOWN) g_layer_y++;
1058 if (inp & PBTN_LEFT) g_layer_x--;
1059 if (inp & PBTN_RIGHT) g_layer_x++;
1060 if (!(inp & PBTN_R)) {
1061 if (inp & PBTN_UP) g_layer_h += 2;
1062 if (inp & PBTN_DOWN) g_layer_h -= 2;
1063 if (inp & PBTN_LEFT) g_layer_w += 2;
1064 if (inp & PBTN_RIGHT) g_layer_w -= 2;
1065 }
1066 if (inp & (PBTN_MOK|PBTN_MBACK))
1067 break;
1068
1069 if (inp & (PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT)) {
1070 if (g_layer_x < 0) g_layer_x = 0;
1071 if (g_layer_x > 640) g_layer_x = 640;
1072 if (g_layer_y < 0) g_layer_y = 0;
1073 if (g_layer_y > 420) g_layer_y = 420;
1074 if (g_layer_w < 160) g_layer_w = 160;
1075 if (g_layer_h < 60) g_layer_h = 60;
1076 if (g_layer_x + g_layer_w > 800)
1077 g_layer_w = 800 - g_layer_x;
1078 if (g_layer_y + g_layer_h > 480)
1079 g_layer_h = 480 - g_layer_y;
6469a8c4 1080 // resize the layer
ab423939 1081 plat_gvideo_open(Config.PsxType);
3c70c47b 1082 }
1083 }
1084
6469a8c4 1085 plat_gvideo_close();
3c70c47b 1086
1087 return 0;
1088}
1089
69af03a2 1090static menu_entry e_menu_gfx_options[] =
1091{
9e5ac38f 1092 mee_enum ("Scaler", MA_OPT_SCALER, g_scaler, men_scaler),
a72ac803 1093 mee_onoff ("Software Scaling", MA_OPT_SCALER2, soft_scaling, 1),
3c70c47b 1094 mee_enum ("Filter", MA_OPT_FILTERING, filter, men_dummy),
1095// mee_onoff ("Vsync", 0, vsync, 1),
a72ac803 1096 mee_cust_h ("Setup custom scaler", MA_OPT_SCALER_C, menu_loop_cscaler, NULL, h_cscaler),
69af03a2 1097 mee_end,
1098};
1099
1100static int menu_loop_gfx_options(int id, int keys)
1101{
1102 static int sel = 0;
1103
51f77282 1104 me_loop(e_menu_gfx_options, &sel);
69af03a2 1105
1106 return 0;
1107}
1108
ab423939 1109// XXX
1110void menu_set_filter_list(void *filters)
1111{
1112 int i;
1113
1114 i = me_id2offset(e_menu_gfx_options, MA_OPT_FILTERING);
1115 e_menu_gfx_options[i].data = filters;
1116 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, filters != NULL);
1117}
1118
bd6267e6 1119// ------------ bios/plugins ------------
1120
5440b88e 1121#ifdef __ARM_NEON__
1122
1123static const char h_gpu_neon[] = "Configure built-in NEON GPU plugin";
0b02eb77 1124static const char h_gpu_neon_enhanced[] = "Renders in double resolution at the cost of lower performance";
1125static const char h_gpu_neon_enhanced_hack[] = "Speed hack for above option (glitches some games)";
5440b88e 1126static const char *men_gpu_interlace[] = { "Off", "On", "Auto", NULL };
1127
1128static menu_entry e_menu_plugin_gpu_neon[] =
1129{
1130 mee_enum ("Enable interlace mode", 0, pl_rearmed_cbs.gpu_neon.allow_interlace, men_gpu_interlace),
0b02eb77 1131 mee_onoff_h ("Enhanced resolution (slow)", 0, pl_rearmed_cbs.gpu_neon.enhancement_enable, 1, h_gpu_neon_enhanced),
1132 mee_onoff_h ("Enhanced res. speed hack", 0, pl_rearmed_cbs.gpu_neon.enhancement_no_main, 1, h_gpu_neon_enhanced_hack),
5440b88e 1133 mee_end,
1134};
1135
1136static int menu_loop_plugin_gpu_neon(int id, int keys)
1137{
0b02eb77 1138 static int sel = 0;
5440b88e 1139 me_loop(e_menu_plugin_gpu_neon, &sel);
1140 return 0;
1141}
1142
1143#endif
1144
17a54a4a 1145static menu_entry e_menu_plugin_gpu_unai[] =
1146{
89c0de42 1147 mee_onoff ("Skip every 2nd line", 0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
17a54a4a 1148 mee_onoff ("Abe's Odyssey hack", 0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
1149 mee_onoff ("Disable lighting", 0, pl_rearmed_cbs.gpu_unai.no_light, 1),
1150 mee_onoff ("Disable blending", 0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
1151 mee_end,
1152};
1153
1154static int menu_loop_plugin_gpu_unai(int id, int keys)
1155{
1156 int sel = 0;
1157 me_loop(e_menu_plugin_gpu_unai, &sel);
1158 return 0;
1159}
1160
bd6267e6 1161static const char *men_gpu_dithering[] = { "None", "Game dependant", "Always", NULL };
5440b88e 1162//static const char h_gpu_0[] = "Needed for Chrono Cross";
bd6267e6 1163static const char h_gpu_1[] = "Capcom fighting games";
1164static const char h_gpu_2[] = "Black screens in Lunar";
1165static const char h_gpu_3[] = "Compatibility mode";
1166static const char h_gpu_6[] = "Pandemonium 2";
5440b88e 1167//static const char h_gpu_7[] = "Skip every second frame";
bd6267e6 1168static const char h_gpu_8[] = "Needed by Dark Forces";
1169static const char h_gpu_9[] = "better g-colors, worse textures";
1170static const char h_gpu_10[] = "Toggle busy flags after drawing";
1171
17a54a4a 1172static menu_entry e_menu_plugin_gpu_peops[] =
bd6267e6 1173{
e64dc4c5 1174 mee_enum ("Dithering", 0, pl_rearmed_cbs.gpu_peops.iUseDither, men_gpu_dithering),
5440b88e 1175// mee_onoff_h ("Odd/even bit hack", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<0, h_gpu_0),
e64dc4c5 1176 mee_onoff_h ("Expand screen width", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<1, h_gpu_1),
1177 mee_onoff_h ("Ignore brightness color", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<2, h_gpu_2),
1178 mee_onoff_h ("Disable coordinate check", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<3, h_gpu_3),
1179 mee_onoff_h ("Lazy screen update", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<6, h_gpu_6),
5440b88e 1180// mee_onoff_h ("Old frame skipping", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<7, h_gpu_7),
e64dc4c5 1181 mee_onoff_h ("Repeated flat tex triangles ",0,pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<8, h_gpu_8),
1182 mee_onoff_h ("Draw quads with triangles", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<9, h_gpu_9),
1183 mee_onoff_h ("Fake 'gpu busy' states", 0, pl_rearmed_cbs.gpu_peops.dwActFixes, 1<<10, h_gpu_10),
bd6267e6 1184 mee_end,
1185};
1186
17a54a4a 1187static int menu_loop_plugin_gpu_peops(int id, int keys)
bd6267e6 1188{
1189 static int sel = 0;
17a54a4a 1190 me_loop(e_menu_plugin_gpu_peops, &sel);
bd6267e6 1191 return 0;
1192}
1193
746fee51 1194static const char *men_peopsgl_texfilter[] = { "None", "Standard", "Extended",
1195 "Standard-sprites", "Extended-sprites", "Standard+sprites", "Extended+sprites", NULL };
1196static const char *men_peopsgl_fbtex[] = { "Emulated VRam", "Black", "Card", "Card+soft" };
1197
1198static menu_entry e_menu_plugin_gpu_peopsgl[] =
1199{
1200 mee_onoff ("Dithering", 0, pl_rearmed_cbs.gpu_peopsgl.bDrawDither, 1),
1201 mee_enum ("Texture Filtering", 0, pl_rearmed_cbs.gpu_peopsgl.iFilterType, men_peopsgl_texfilter),
1202 mee_enum ("Framebuffer Textures", 0, pl_rearmed_cbs.gpu_peopsgl.iFrameTexType, men_peopsgl_fbtex),
1203 mee_onoff ("Mask Detect", 0, pl_rearmed_cbs.gpu_peopsgl.iUseMask, 1),
1204 mee_onoff ("Opaque Pass", 0, pl_rearmed_cbs.gpu_peopsgl.bOpaquePass, 1),
1205 mee_onoff ("Advanced Blend", 0, pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend, 1),
1206 mee_onoff ("Use Fast Mdec", 0, pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec, 1),
1207 mee_range ("Texture RAM size (MB)", 0, pl_rearmed_cbs.gpu_peopsgl.iVRamSize, 4, 128),
1208 mee_onoff ("Texture garbage collection", 0, pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection, 1),
1209 mee_label ("Fixes/hacks:"),
1210 mee_onoff ("FF7 cursor", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<0),
1211 mee_onoff ("Direct FB updates", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<1),
1212 mee_onoff ("Black brightness", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<2),
1213 mee_onoff ("Swap front detection", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<3),
1214 mee_onoff ("Disable coord check", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<4),
1215 mee_onoff ("No blue glitches (LoD)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<5),
1216 mee_onoff ("Soft FB access", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<6),
1217 mee_onoff ("FF9 rect", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<9),
1218 mee_onoff ("No subtr. blending", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<10),
1219 mee_onoff ("Lazy upload (DW7)", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<11),
1220 mee_onoff ("Additional uploads", 0, pl_rearmed_cbs.gpu_peopsgl.dwActFixes, 1<<15),
1221 mee_end,
1222};
1223
1224static int menu_loop_plugin_gpu_peopsgl(int id, int keys)
1225{
1226 static int sel = 0;
1227 me_loop(e_menu_plugin_gpu_peopsgl, &sel);
1228 return 0;
1229}
1230
bd6267e6 1231static const char *men_spu_interp[] = { "None", "Simple", "Gaussian", "Cubic", NULL };
9e7a7352 1232static const char h_spu_volboost[] = "Large values cause distortion";
bd6267e6 1233
1234static menu_entry e_menu_plugin_spu[] =
1235{
9e7a7352 1236 mee_range_h ("Volume boost", 0, volume_boost, -5, 30, h_spu_volboost),
381ea103 1237 mee_onoff ("Reverb", 0, iUseReverb, 2),
bd6267e6 1238 mee_enum ("Interpolation", 0, iUseInterpolation, men_spu_interp),
1239 mee_onoff ("Adjust XA pitch", 0, iXAPitch, 1),
bd6267e6 1240 mee_end,
1241};
1242
1243static int menu_loop_plugin_spu(int id, int keys)
1244{
1245 static int sel = 0;
51f77282 1246 me_loop(e_menu_plugin_spu, &sel);
bd6267e6 1247 return 0;
1248}
1249
55b0eeea 1250static const char h_bios[] = "HLE is simulated BIOS. BIOS selection is saved in\n"
1251 "savestates and can't be changed there. Must save\n"
1252 "config and reload the game for change to take effect";
746fee51 1253static const char h_plugin_gpu[] =
1254#ifdef __ARM_NEON__
1255 "builtin_gpu is the NEON GPU, very fast and accurate\n"
746fee51 1256#endif
4ea086f6 1257 "gpu_peops is Pete's soft GPU, slow but accurate\n"
1258 "gpu_unai is GPU from PCSX4ALL, fast but glitchy\n"
1259 "gpu_gles Pete's hw GPU, uses 3D chip but is glitchy\n"
746fee51 1260 "must save config and reload the game if changed";
1261static const char h_plugin_spu[] = "spunull effectively disables sound\n"
1262 "must save config and reload the game if changed";
17a54a4a 1263static const char h_gpu_peops[] = "Configure P.E.Op.S. SoftGL Driver V1.17";
746fee51 1264static const char h_gpu_peopsgl[]= "Configure P.E.Op.S. MesaGL Driver V1.78";
17a54a4a 1265static const char h_gpu_unai[] = "Configure Unai/PCSX4ALL Team GPU plugin";
e6eb2066 1266static const char h_spu[] = "Configure built-in P.E.Op.S. Sound Driver V1.7";
bbd837c6 1267
bd6267e6 1268static menu_entry e_menu_plugin_options[] =
1269{
e6eb2066 1270 mee_enum_h ("BIOS", 0, bios_sel, bioses, h_bios),
746fee51 1271 mee_enum_h ("GPU plugin", 0, gpu_plugsel, gpu_plugins, h_plugin_gpu),
1272 mee_enum_h ("SPU plugin", 0, spu_plugsel, spu_plugins, h_plugin_spu),
5440b88e 1273#ifdef __ARM_NEON__
1274 mee_handler_h ("Configure built-in GPU plugin", menu_loop_plugin_gpu_neon, h_gpu_neon),
1275#endif
17a54a4a 1276 mee_handler_h ("Configure gpu_peops plugin", menu_loop_plugin_gpu_peops, h_gpu_peops),
4ea086f6 1277 mee_handler_h ("Configure gpu_unai GPU plugin", menu_loop_plugin_gpu_unai, h_gpu_unai),
1278 mee_handler_h ("Configure gpu_gles GPU plugin", menu_loop_plugin_gpu_peopsgl, h_gpu_peopsgl),
bd6267e6 1279 mee_handler_h ("Configure built-in SPU plugin", menu_loop_plugin_spu, h_spu),
1280 mee_end,
1281};
1282
51f77282 1283static menu_entry e_menu_main2[];
e16a7e51 1284
bd6267e6 1285static int menu_loop_plugin_options(int id, int keys)
1286{
1287 static int sel = 0;
51f77282 1288 me_loop(e_menu_plugin_options, &sel);
bbd837c6 1289
e6eb2066 1290 // sync BIOS/plugins
1291 snprintf(Config.Bios, sizeof(Config.Bios), "%s", bioses[bios_sel]);
bbd837c6 1292 snprintf(Config.Gpu, sizeof(Config.Gpu), "%s", gpu_plugins[gpu_plugsel]);
1293 snprintf(Config.Spu, sizeof(Config.Spu), "%s", spu_plugins[spu_plugsel]);
51f77282 1294 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
bbd837c6 1295
bd6267e6 1296 return 0;
1297}
1298
1299// ------------ adv options menu ------------
1300
a72ac803 1301static const char h_cfg_psxclk[] = "Over/under-clock the PSX, default is " DEFAULT_PSX_CLOCK_S "\n"
1302 "(lower value - less work for the emu, may be faster)";
bab59f00 1303static const char h_cfg_nosmc[] = "Will cause crashes when loading, break memcards";
0ff8c62c 1304static const char h_cfg_gteunn[] = "May cause graphical glitches";
1305static const char h_cfg_gteflgs[] = "Will cause graphical glitches";
1306
1307static menu_entry e_menu_speed_hacks[] =
1308{
1309 mee_range_h ("PSX CPU clock, %%", 0, psx_clock, 1, 500, h_cfg_psxclk),
1310 mee_onoff_h ("Disable SMC checks", 0, new_dynarec_hacks, NDHACK_NO_SMC_CHECK, h_cfg_nosmc),
1311 mee_onoff_h ("Assume GTE regs unneeded", 0, new_dynarec_hacks, NDHACK_GTE_UNNEEDED, h_cfg_gteunn),
1312 mee_onoff_h ("Disable GTE flags", 0, new_dynarec_hacks, NDHACK_GTE_NO_FLAGS, h_cfg_gteflgs),
1313 mee_end,
1314};
1315
1316static int menu_loop_speed_hacks(int id, int keys)
1317{
1318 static int sel = 0;
1319 me_loop(e_menu_speed_hacks, &sel);
1320 return 0;
1321}
1322
4feed8d3 1323static const char *men_cfg_cdrr[] = { "Auto", "ON", "OFF", NULL };
8f892648 1324static const char h_cfg_cpul[] = "Shows CPU usage in %";
90f1d26c 1325static const char h_cfg_spu[] = "Shows active SPU channels\n"
1326 "(green: normal, red: fmod, blue: noise)";
1bd9ee68 1327static const char h_cfg_fl[] = "Frame Limiter keeps the game from running too fast";
bd6267e6 1328static const char h_cfg_xa[] = "Disables XA sound, which can sometimes improve performance";
1329static const char h_cfg_cdda[] = "Disable CD Audio for a performance boost\n"
1330 "(proper .cue/.bin dump is needed otherwise)";
4feed8d3 1331static const char h_cfg_sio[] = "You should not need this, breaks games";
1332static const char h_cfg_spuirq[] = "Compatibility tweak; should be left off";
1333static const char h_cfg_rcnt1[] = "Parasite Eve 2, Vandal Hearts 1/2 Fix\n"
1334 "(timing hack, breaks other games)";
1335static const char h_cfg_rcnt2[] = "InuYasha Sengoku Battle Fix\n"
1336 "(timing hack, breaks other games)";
0ff8c62c 1337static const char h_cfg_cdrr[] = "Compatibility tweak (CD timing hack, breaks FMVs)";
b5e7e49a 1338static const char h_cfg_nodrc[] = "Disable dynamic recompiler and use interpreter\n"
1339 "Might be useful to overcome some dynarec bugs";
0ff8c62c 1340static const char h_cfg_shacks[] = "Breaks games but may give better performance\n"
1341 "must reload game for any change to take effect";
bd6267e6 1342
1343static menu_entry e_menu_adv_options[] =
1344{
fba06457 1345 mee_onoff_h ("Show CPU load", 0, g_opts, OPT_SHOWCPU, h_cfg_cpul),
90f1d26c 1346 mee_onoff_h ("Show SPU channels", 0, g_opts, OPT_SHOWSPU, h_cfg_spu),
bce6b056 1347 mee_onoff_h ("Disable Frame Limiter", 0, g_opts, OPT_NO_FRAMELIM, h_cfg_fl),
bd6267e6 1348 mee_onoff_h ("Disable XA Decoding", 0, Config.Xa, 1, h_cfg_xa),
1349 mee_onoff_h ("Disable CD Audio", 0, Config.Cdda, 1, h_cfg_cdda),
1350 mee_onoff_h ("SIO IRQ Always Enabled", 0, Config.Sio, 1, h_cfg_sio),
1351 mee_onoff_h ("SPU IRQ Always Enabled", 0, Config.SpuIrq, 1, h_cfg_spuirq),
b1be1eee 1352 //mee_onoff_h ("Rootcounter hack", 0, Config.RCntFix, 1, h_cfg_rcnt1),
bd6267e6 1353 mee_onoff_h ("Rootcounter hack 2", 0, Config.VSyncWA, 1, h_cfg_rcnt2),
4feed8d3 1354 mee_enum_h ("CD read reschedule hack",0, Config.CdrReschedule, men_cfg_cdrr, h_cfg_cdrr),
b5e7e49a 1355 mee_onoff_h ("Disable dynarec (slow!)",0, Config.Cpu, 1, h_cfg_nodrc),
0ff8c62c 1356 mee_handler_h ("[Speed hacks]", menu_loop_speed_hacks, h_cfg_shacks),
bd6267e6 1357 mee_end,
1358};
1359
1360static int menu_loop_adv_options(int id, int keys)
1361{
1362 static int sel = 0;
51f77282 1363 me_loop(e_menu_adv_options, &sel);
bd6267e6 1364 return 0;
1365}
1366
69af03a2 1367// ------------ options menu ------------
1368
69af03a2 1369static int mh_restore_defaults(int id, int keys)
1370{
3c70c47b 1371 menu_set_defconfig();
69af03a2 1372 me_update_msg("defaults restored");
1373 return 1;
1374}
1375
907b1e90 1376static const char *men_region[] = { "Auto", "NTSC", "PAL", NULL };
9fe27e25 1377static const char *men_frameskip[] = { "Auto", "Off", "1", "2", "3", NULL };
bd6267e6 1378/*
69af03a2 1379static const char *men_confirm_save[] = { "OFF", "writes", "loads", "both", NULL };
1380static const char h_confirm_save[] = "Ask for confirmation when overwriting save,\n"
1381 "loading state or both";
bd6267e6 1382*/
1383static const char h_restore_def[] = "Switches back to default / recommended\n"
1384 "configuration";
9f4a4237 1385static const char h_frameskip[] = "Warning: frameskip sometimes causes glitches\n";
69af03a2 1386
1387static menu_entry e_menu_options[] =
1388{
bd6267e6 1389// mee_range ("Save slot", 0, state_slot, 0, 9),
1390// mee_enum_h ("Confirm savestate", 0, dummy, men_confirm_save, h_confirm_save),
ea4a16e7 1391 mee_enum_h ("Frameskip", 0, frameskip, men_frameskip, h_frameskip),
bd6267e6 1392 mee_onoff ("Show FPS", 0, g_opts, OPT_SHOWFPS),
907b1e90 1393 mee_enum ("Region", 0, region, men_region),
3c70c47b 1394 mee_range ("CPU clock", MA_OPT_CPU_CLOCKS, cpu_clock, 20, 5000),
55b0eeea 1395 mee_handler_id("[Display]", MA_OPT_DISP_OPTS, menu_loop_gfx_options),
bd6267e6 1396 mee_handler ("[BIOS/Plugins]", menu_loop_plugin_options),
69af03a2 1397 mee_handler ("[Advanced]", menu_loop_adv_options),
cd6e8d0f 1398 mee_cust_nosave("Save global config", MA_OPT_SAVECFG, mh_savecfg, mgn_saveloadcfg),
1399 mee_cust_nosave("Save cfg for loaded game",MA_OPT_SAVECFG_GAME, mh_savecfg, mgn_saveloadcfg),
bd6267e6 1400 mee_handler_h ("Restore default config", mh_restore_defaults, h_restore_def),
69af03a2 1401 mee_end,
1402};
1403
1404static int menu_loop_options(int id, int keys)
1405{
1406 static int sel = 0;
1407 int i;
1408
1409 i = me_id2offset(e_menu_options, MA_OPT_CPU_CLOCKS);
7badc935 1410 e_menu_options[i].enabled = cpu_clock_st > 0 ? 1 : 0;
e16a7e51 1411 me_enable(e_menu_options, MA_OPT_SAVECFG_GAME, ready_to_go && CdromId[0]);
69af03a2 1412
51f77282 1413 me_loop(e_menu_options, &sel);
69af03a2 1414
1415 return 0;
1416}
1417
1418// ------------ debug menu ------------
1419
a72ac803 1420static void draw_frame_debug(GPUFreeze_t *gpuf, int x, int y)
69af03a2 1421{
72bb6fdd 1422 int w = min(g_menuscreen_w, 1024);
1423 int h = min(g_menuscreen_h, 512);
1424 u16 *d = g_menuscreen_ptr;
a72ac803 1425 u16 *s = (u16 *)gpuf->psxVRam + y * 1024 + x;
72bb6fdd 1426 char buff[64];
1427 int ty = 1;
1428
1429 gpuf->ulFreezeVersion = 1;
1430 if (GPU_freeze != NULL)
1431 GPU_freeze(1, gpuf);
1432
1433 for (; h > 0; h--, d += g_menuscreen_w, s += 1024)
1434 bgr555_to_rgb565(d, s, w * 2);
1435
3c70c47b 1436 smalltext_out16(4, 1, "build: "__DATE__ " " __TIME__ " " REV, 0xe7fc);
72bb6fdd 1437 snprintf(buff, sizeof(buff), "GPU sr: %08x", gpuf->ulStatus);
1438 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
1439 snprintf(buff, sizeof(buff), "PC/SP: %08x %08x", psxRegs.pc, psxRegs.GPR.n.sp);
1440 smalltext_out16(4, (ty += me_sfont_h), buff, 0xe7fc);
69af03a2 1441}
1442
1443static void debug_menu_loop(void)
1444{
a72ac803 1445 int inp, df_x = 0, df_y = 0;
72bb6fdd 1446 GPUFreeze_t *gpuf;
69af03a2 1447
72bb6fdd 1448 gpuf = malloc(sizeof(*gpuf));
1449 if (gpuf == NULL)
1450 return;
1451
69af03a2 1452 while (1)
1453 {
72bb6fdd 1454 menu_draw_begin(0);
a72ac803 1455 draw_frame_debug(gpuf, df_x, df_y);
69af03a2 1456 menu_draw_end();
1457
1458 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK|PBTN_MA2|PBTN_MA3|PBTN_L|PBTN_R |
61f97bb0 1459 PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT, NULL, 10);
a72ac803 1460 if (inp & PBTN_MBACK) break;
1461 else if (inp & PBTN_UP) { if (df_y > 0) df_y--; }
1462 else if (inp & PBTN_DOWN) { if (df_y < 512 - g_menuscreen_h) df_y++; }
33344895 1463 else if (inp & PBTN_LEFT) { if (df_x > 0) df_x -= 2; }
1464 else if (inp & PBTN_RIGHT) { if (df_x < 1024 - g_menuscreen_w) df_x += 2; }
69af03a2 1465 }
72bb6fdd 1466
1467 free(gpuf);
69af03a2 1468}
1469
51f77282 1470// --------- memcard manager ---------
1471
1472static void draw_mc_icon(int dx, int dy, const u16 *s)
1473{
1474 u16 *d;
1475 int x, y, l, p;
1476
1477 d = (u16 *)g_menuscreen_ptr + g_menuscreen_w * dy + dx;
1478
1479 for (y = 0; y < 16; y++, s += 16) {
1480 for (l = 0; l < 2; l++, d += g_menuscreen_w) {
1481 for (x = 0; x < 16; x++) {
1482 p = s[x];
1483 d[x*2] = d[x*2 + 1] = ((p & 0x7c00) >> 10)
1484 | ((p & 0x03e0) << 1) | ((p & 0x1f) << 11);
1485 }
1486 }
1487 }
1488}
1489
1490static void draw_mc_bg(void)
1491{
1492 McdBlock *blocks1, *blocks2;
1493 int maxicons = 15;
1494 int i, y, row2;
1495
1496 blocks1 = malloc(15 * sizeof(blocks1[0]));
1497 blocks2 = malloc(15 * sizeof(blocks1[0]));
1498 if (blocks1 == NULL || blocks2 == NULL)
1499 goto out;
1500
1501 for (i = 0; i < 15; i++) {
1502 GetMcdBlockInfo(1, i + 1, &blocks1[i]);
1503 GetMcdBlockInfo(2, i + 1, &blocks2[i]);
1504 }
1505
1506 menu_draw_begin(1);
1507
1508 memcpy(g_menuscreen_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1509
1510 y = g_menuscreen_h / 2 - 15 * 32 / 2;
1511 if (y < 0) {
1512 // doesn't fit..
1513 y = 0;
1514 maxicons = g_menuscreen_h / 32;
1515 }
1516
1517 row2 = g_menuscreen_w / 2;
1518 for (i = 0; i < maxicons; i++) {
1519 draw_mc_icon(8, y + i * 32, (u16 *)blocks1[i].Icon);
1520 smalltext_out16(10+32, y + i * 32 + 8, blocks1[i].sTitle, 0xf71e);
1521
1522 draw_mc_icon(row2 + 8, y + i * 32, (u16 *)blocks2[i].Icon);
1523 smalltext_out16(row2 + 10+32, y + i * 32 + 8, blocks2[i].sTitle, 0xf71e);
1524 }
1525
1526 menu_darken_bg(g_menubg_ptr, g_menuscreen_ptr, g_menuscreen_w * g_menuscreen_h, 0);
1527
1528 menu_draw_end();
1529out:
1530 free(blocks1);
1531 free(blocks2);
1532}
1533
1534static void handle_memcard_sel(void)
1535{
1536 Config.Mcd1[0] = 0;
1537 if (memcard1_sel != 0)
1538 snprintf(Config.Mcd1, sizeof(Config.Mcd1), ".%s%s", MEMCARD_DIR, memcards[memcard1_sel]);
1539 Config.Mcd2[0] = 0;
1540 if (memcard2_sel != 0)
1541 snprintf(Config.Mcd2, sizeof(Config.Mcd2), ".%s%s", MEMCARD_DIR, memcards[memcard2_sel]);
1542 LoadMcds(Config.Mcd1, Config.Mcd2);
1543 draw_mc_bg();
1544}
1545
1546static menu_entry e_memcard_options[] =
1547{
1548 mee_enum("Memory card 1", 0, memcard1_sel, memcards),
1549 mee_enum("Memory card 2", 0, memcard2_sel, memcards),
1550 mee_end,
1551};
1552
1553static int menu_loop_memcards(int id, int keys)
1554{
1555 static int sel = 0;
1556 char *p;
1557 int i;
1558
1559 memcard1_sel = memcard2_sel = 0;
1560 p = strrchr(Config.Mcd1, '/');
1561 if (p != NULL)
1562 for (i = 0; memcards[i] != NULL; i++)
1563 if (strcmp(p + 1, memcards[i]) == 0)
1564 { memcard1_sel = i; break; }
1565 p = strrchr(Config.Mcd2, '/');
1566 if (p != NULL)
1567 for (i = 0; memcards[i] != NULL; i++)
1568 if (strcmp(p + 1, memcards[i]) == 0)
1569 { memcard2_sel = i; break; }
1570
1571 me_loop_d(e_memcard_options, &sel, handle_memcard_sel, NULL);
1572
1573 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
1574
1575 return 0;
1576}
1577
9c27c205 1578// ------------ cheats menu ------------
1579
1580static void draw_cheatlist(int sel)
1581{
1582 int max_cnt, start, i, pos, active;
1583
1584 max_cnt = g_menuscreen_h / me_sfont_h;
1585 start = max_cnt / 2 - sel;
1586
1587 menu_draw_begin(1);
1588
1589 for (i = 0; i < NumCheats; i++) {
1590 pos = start + i;
1591 if (pos < 0) continue;
1592 if (pos >= max_cnt) break;
1593 active = Cheats[i].Enabled;
1594 smalltext_out16(14, pos * me_sfont_h,
1595 active ? "ON " : "OFF", active ? 0xfff6 : 0xffff);
1596 smalltext_out16(14 + me_sfont_w*4, pos * me_sfont_h,
1597 Cheats[i].Descr, active ? 0xfff6 : 0xffff);
1598 }
1599 pos = start + i;
1600 if (pos < max_cnt)
1601 smalltext_out16(14, pos * me_sfont_h, "done", 0xffff);
1602
1603 text_out16(5, max_cnt / 2 * me_sfont_h, ">");
1604 menu_draw_end();
1605}
1606
1607static void menu_loop_cheats(void)
1608{
1609 static int menu_sel = 0;
1610 int inp;
1611
1612 for (;;)
1613 {
1614 draw_cheatlist(menu_sel);
1615 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT|PBTN_L|PBTN_R
1616 |PBTN_MOK|PBTN_MBACK, NULL, 33);
1617 if (inp & PBTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = NumCheats; }
1618 if (inp & PBTN_DOWN) { menu_sel++; if (menu_sel > NumCheats) menu_sel = 0; }
1619 if (inp &(PBTN_LEFT|PBTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }
1620 if (inp &(PBTN_RIGHT|PBTN_R)) { menu_sel+=10; if (menu_sel > NumCheats) menu_sel = NumCheats; }
1621 if (inp & PBTN_MOK) { // action
1622 if (menu_sel < NumCheats)
1623 Cheats[menu_sel].Enabled = !Cheats[menu_sel].Enabled;
1624 else break;
1625 }
1626 if (inp & PBTN_MBACK)
1627 break;
1628 }
1629}
1630
51f77282 1631// --------- main menu help ----------
69af03a2 1632
4f5a1b2a 1633static void menu_bios_warn(void)
1634{
1635 int inp;
1636 static const char msg[] =
cbd45cda 1637 "You don't seem to have copied any BIOS\n"
1638 "files to\n"
1639#ifdef __ARM_ARCH_7A__ // XXX
4f5a1b2a 1640 "<SD card>/pandora/appdata/pcsx_rearmed/bios/\n\n"
cbd45cda 1641#else
1642 "pcsx_rearmed/bios/\n\n"
1643#endif
1644 "While many games work fine with fake\n"
1645 "(HLE) BIOS, others (like MGS and FF8)\n"
1646 "require BIOS to work.\n"
1647 "After copying the file, you'll also need\n"
1648 "to select it in the emu's menu:\n"
1649 "options->[BIOS/Plugins]\n\n"
1650 "The file is usually named SCPH1001.BIN,\n"
1651 "but other not compressed files can be\n"
1652 "used too.\n\n"
2e6189bc 1653 "Press %s or %s to continue";
1654 char tmp_msg[sizeof(msg) + 64];
4f5a1b2a 1655
2e6189bc 1656 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1657 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
4f5a1b2a 1658 while (1)
1659 {
2e6189bc 1660 draw_menu_message(tmp_msg, NULL);
4f5a1b2a 1661
61f97bb0 1662 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
4f5a1b2a 1663 if (inp & (PBTN_MBACK|PBTN_MOK))
1664 return;
1665 }
1666}
1667
1668// ------------ main menu ------------
1669
9c27c205 1670static menu_entry e_menu_main[];
bd6267e6 1671void OnFile_Exit();
1672
1bd9ee68 1673static void draw_frame_main(void)
1674{
65092fd8 1675 struct tm *tmp;
1676 time_t ltime;
7badc935 1677 int capacity;
65092fd8 1678 char ltime_s[16];
1679 char buff[64];
7badc935 1680 char *out;
65092fd8 1681
1bd9ee68 1682 if (CdromId[0] != 0) {
c22b95ab 1683 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1684 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1685 Config.HLE ? "HLE" : "BIOS");
1bd9ee68 1686 smalltext_out16(4, 1, buff, 0x105f);
1687 }
65092fd8 1688
1689 if (ready_to_go) {
7badc935 1690 capacity = plat_get_bat_capacity();
65092fd8 1691 ltime = time(NULL);
1692 tmp = localtime(&ltime);
1693 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
7badc935 1694 if (capacity >= 0) {
1695 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1696 out = buff;
1697 }
1698 else
1699 out = ltime_s;
1700 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
65092fd8 1701 }
1bd9ee68 1702}
1703
1704static void draw_frame_credits(void)
1705{
3ce7adeb 1706 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1bd9ee68 1707}
1708
4f5a1b2a 1709static const char credits_text[] =
1710 "PCSX-ReARMed\n\n"
1711 "(C) 1999-2003 PCSX Team\n"
1712 "(C) 2005-2009 PCSX-df Team\n"
1713 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
4f5a1b2a 1714 "ARM recompiler (C) 2009-2011 Ari64\n"
c069dc1b 1715#ifdef __ARM_NEON__
3ce7adeb 1716 "ARM NEON GPU (c) 2011-2012 Exophase\n"
c069dc1b 1717#endif
1718 "PEOpS GPU and SPU by Pete Bernert\n"
1719 " and the P.E.Op.S. team\n"
1720 "PCSX4ALL plugin by PCSX4ALL team\n"
4f5a1b2a 1721 " Chui, Franxis, Unai\n\n"
1722 "integration, optimization and\n"
3ce7adeb 1723 " frontend (C) 2010-2012 notaz\n";
69af03a2 1724
e16a7e51 1725static int reset_game(void)
1726{
1727 // sanity check
1728 if (bios_sel == 0 && !Config.HLE)
1729 return -1;
1730
1731 ClosePlugins();
1732 OpenPlugins();
1733 SysReset();
1734 if (CheckCdrom() != -1) {
1735 LoadCdrom();
1736 }
1737 return 0;
1738}
1739
51f77282 1740static int reload_plugins(const char *cdimg)
e16a7e51 1741{
76f7048e 1742 pl_vout_buf = NULL;
e16a7e51 1743
1744 ClosePlugins();
51f77282 1745
1746 set_cd_image(cdimg);
e16a7e51 1747 LoadPlugins();
c22b95ab 1748 pcnt_hook_plugins();
e16a7e51 1749 NetOpened = 0;
1750 if (OpenPlugins() == -1) {
1751 me_update_msg("failed to open plugins");
1752 return -1;
1753 }
1754 plugin_call_rearmed_cbs();
1755
0c2871a7 1756 cdrIsoMultidiskCount = 1;
e16a7e51 1757 CdromId[0] = '\0';
1758 CdromLabel[0] = '\0';
1759
51f77282 1760 return 0;
1761}
1762
1763static int run_bios(void)
1764{
1765 if (bios_sel == 0)
1766 return -1;
1767
1768 ready_to_go = 0;
1769 if (reload_plugins(NULL) != 0)
1770 return -1;
e16a7e51 1771 SysReset();
1772
1773 ready_to_go = 1;
1774 return 0;
1775}
1776
51f77282 1777static int run_exe(void)
69af03a2 1778{
51f77282 1779 const char *fname;
1780
1781 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1782 if (fname == NULL)
1783 return -1;
1784
69af03a2 1785 ready_to_go = 0;
51f77282 1786 if (reload_plugins(NULL) != 0)
1787 return -1;
69af03a2 1788
51f77282 1789 SysReset();
1790 if (Load(fname) != 0) {
1791 me_update_msg("exe load failed, bad file?");
1792 printf("meh\n");
bbd837c6 1793 return -1;
69af03a2 1794 }
51f77282 1795
1796 ready_to_go = 1;
1797 return 0;
1798}
1799
1800static int run_cd_image(const char *fname)
1801{
1802 ready_to_go = 0;
1803 reload_plugins(fname);
69af03a2 1804
76d63edf 1805 // always autodetect, menu_sync_config will override as needed
1806 Config.PsxAuto = 1;
1807
69af03a2 1808 if (CheckCdrom() == -1) {
1809 // Only check the CD if we are starting the console with a CD
1810 ClosePlugins();
1811 me_update_msg("unsupported/invalid CD image");
bbd837c6 1812 return -1;
69af03a2 1813 }
1814
bbd837c6 1815 SysReset();
1816
69af03a2 1817 // Read main executable directly from CDRom and start it
1818 if (LoadCdrom() == -1) {
1819 ClosePlugins();
1820 me_update_msg("failed to load CD image");
bbd837c6 1821 return -1;
69af03a2 1822 }
1823
9c27c205 1824 emu_on_new_cd();
69af03a2 1825 ready_to_go = 1;
9c27c205 1826
bbd837c6 1827 return 0;
69af03a2 1828}
1829
bbd837c6 1830static int romsel_run(void)
69af03a2 1831{
bbd837c6 1832 int prev_gpu, prev_spu;
51f77282 1833 const char *fname;
bbd837c6 1834
1835 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1836 if (fname == NULL)
1837 return -1;
69af03a2 1838
bbd837c6 1839 printf("selected file: %s\n", fname);
1840
dc990066 1841 new_dynarec_clear_full();
1842
bbd837c6 1843 if (run_cd_image(fname) != 0)
1844 return -1;
1845
1846 prev_gpu = gpu_plugsel;
1847 prev_spu = spu_plugsel;
1848 if (menu_load_config(1) != 0)
1849 menu_load_config(0);
1850
1851 // check for plugin changes, have to repeat
1852 // loading if game config changed plugins to reload them
1853 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1854 printf("plugin change detected, reloading plugins..\n");
1855 if (run_cd_image(fname) != 0)
1856 return -1;
1857 }
1858
1859 strcpy(last_selected_fname, rom_fname_reload);
66456088 1860 menu_do_last_cd_img(0);
bbd837c6 1861 return 0;
1862}
1863
1df403c5 1864static int swap_cd_image(void)
1865{
1866 char *fname;
1867
1868 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1869 if (fname == NULL)
1870 return -1;
1871
1872 printf("selected file: %s\n", fname);
1873
1874 CdromId[0] = '\0';
1875 CdromLabel[0] = '\0';
1876
1877 set_cd_image(fname);
1878 if (ReloadCdromPlugin() < 0) {
1879 me_update_msg("failed to load cdr plugin");
1880 return -1;
1881 }
1882 if (CDR_open() < 0) {
1883 me_update_msg("failed to open cdr plugin");
1884 return -1;
1885 }
1886
1887 SetCdOpenCaseTime(time(NULL) + 2);
1888 LidInterrupt();
1889
1890 strcpy(last_selected_fname, rom_fname_reload);
1891 return 0;
1892}
1893
0c2871a7 1894static int swap_cd_multidisk(void)
1895{
1896 cdrIsoMultidiskSelect++;
1897 CdromId[0] = '\0';
1898 CdromLabel[0] = '\0';
1899
1900 CDR_close();
1901 if (CDR_open() < 0) {
1902 me_update_msg("failed to open cdr plugin");
1903 return -1;
1904 }
1905
1906 SetCdOpenCaseTime(time(NULL) + 2);
1907 LidInterrupt();
1908
1909 return 0;
1910}
1911
9c27c205 1912static void load_pcsx_cht(void)
1913{
1914 char path[256];
1915 char *fname;
1916
1917 path[0] = 0;
1918 fname = menu_loop_romsel(path, sizeof(path));
1919 if (fname == NULL)
1920 return;
1921
1922 printf("selected cheat file: %s\n", fname);
1923 LoadCheats(fname);
1924
1925 if (NumCheats == 0 && NumCodes == 0)
1926 me_update_msg("failed to load cheats");
1927 else {
1928 snprintf(path, sizeof(path), "%d cheat(s) loaded", NumCheats + NumCodes);
1929 me_update_msg(path);
1930 }
1931 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
1932}
1933
bbd837c6 1934static int main_menu_handler(int id, int keys)
1935{
69af03a2 1936 switch (id)
1937 {
1938 case MA_MAIN_RESUME_GAME:
3c70c47b 1939 if (ready_to_go)
1940 return 1;
69af03a2 1941 break;
1942 case MA_MAIN_SAVE_STATE:
1943 if (ready_to_go)
1944 return menu_loop_savestate(0);
1945 break;
1946 case MA_MAIN_LOAD_STATE:
1947 if (ready_to_go)
1948 return menu_loop_savestate(1);
1949 break;
1950 case MA_MAIN_RESET_GAME:
e16a7e51 1951 if (ready_to_go && reset_game() == 0)
3c70c47b 1952 return 1;
69af03a2 1953 break;
1954 case MA_MAIN_LOAD_ROM:
bbd837c6 1955 if (romsel_run() == 0)
69af03a2 1956 return 1;
1957 break;
1df403c5 1958 case MA_MAIN_SWAP_CD:
1959 if (swap_cd_image() == 0)
1960 return 1;
1961 break;
0c2871a7 1962 case MA_MAIN_SWAP_CD_MULTI:
1963 if (swap_cd_multidisk() == 0)
1964 return 1;
1965 break;
e16a7e51 1966 case MA_MAIN_RUN_BIOS:
1967 if (run_bios() == 0)
1968 return 1;
1969 break;
51f77282 1970 case MA_MAIN_RUN_EXE:
1971 if (run_exe() == 0)
1972 return 1;
1973 break;
9c27c205 1974 case MA_MAIN_CHEATS:
1975 menu_loop_cheats();
1976 break;
1977 case MA_MAIN_LOAD_CHEATS:
1978 load_pcsx_cht();
1979 break;
69af03a2 1980 case MA_MAIN_CREDITS:
4f5a1b2a 1981 draw_menu_message(credits_text, draw_frame_credits);
61f97bb0 1982 in_menu_wait(PBTN_MOK|PBTN_MBACK, NULL, 70);
69af03a2 1983 break;
1984 case MA_MAIN_EXIT:
bd6267e6 1985 OnFile_Exit();
1986 break;
69af03a2 1987 default:
1988 lprintf("%s: something unknown selected\n", __FUNCTION__);
1989 break;
1990 }
1991
1992 return 0;
1993}
1994
51f77282 1995static menu_entry e_menu_main2[] =
1996{
0c2871a7 1997 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
1998 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
1999 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2000 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
51f77282 2001 mee_handler ("Memcard manager", menu_loop_memcards),
9c27c205 2002 mee_handler_id("Load PCSX cheats..", MA_MAIN_LOAD_CHEATS, main_menu_handler),
51f77282 2003 mee_end,
2004};
2005
2006static int main_menu2_handler(int id, int keys)
2007{
2008 static int sel = 0;
2009
2010 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
0c2871a7 2011 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
51f77282 2012 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
9c27c205 2013 me_enable(e_menu_main2, MA_MAIN_LOAD_CHEATS, ready_to_go);
51f77282 2014
2015 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2016}
2017
2018static const char h_extra[] = "Change CD, manage memcards..\n";
2019
69af03a2 2020static menu_entry e_menu_main[] =
2021{
2022 mee_label (""),
2023 mee_label (""),
2024 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2025 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2026 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2027 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2028 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2029 mee_handler ("Options", menu_loop_options),
2030 mee_handler ("Controls", menu_loop_keyconfig),
9c27c205 2031 mee_handler_id("Cheats", MA_MAIN_CHEATS, main_menu_handler),
51f77282 2032 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
69af03a2 2033 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2034 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2035 mee_end,
2036};
2037
3c70c47b 2038// ----------------------------
2039
bd6267e6 2040static void menu_leave_emu(void);
2041
69af03a2 2042void menu_loop(void)
2043{
2044 static int sel = 0;
2045
bd6267e6 2046 menu_leave_emu();
69af03a2 2047
4f5a1b2a 2048 if (bioses[1] == NULL && !warned_about_bios) {
2049 menu_bios_warn();
2050 warned_about_bios = 1;
2051 }
2052
69af03a2 2053 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
e16a7e51 2054 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2055 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
69af03a2 2056 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
9c27c205 2057 me_enable(e_menu_main, MA_MAIN_CHEATS, ready_to_go && NumCheats);
69af03a2 2058
69af03a2 2059 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2060
2061 do {
51f77282 2062 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
69af03a2 2063 } while (!ready_to_go);
2064
2065 /* wait until menu, ok, back is released */
61f97bb0 2066 while (in_menu_wait_any(NULL, 50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
69af03a2 2067 ;
2068
2069 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2070
3c70c47b 2071 menu_prepare_emu();
2072}
2073
51f77282 2074static int qsort_strcmp(const void *p1, const void *p2)
2075{
2076 char * const *s1 = (char * const *)p1;
2077 char * const *s2 = (char * const *)p2;
2078 return strcasecmp(*s1, *s2);
2079}
2080
e6eb2066 2081static void scan_bios_plugins(void)
bbd837c6 2082{
2083 char fname[MAXPATHLEN];
2084 struct dirent *ent;
51f77282 2085 int bios_i, gpu_i, spu_i, mc_i;
bbd837c6 2086 char *p;
2087 DIR *dir;
2088
e6eb2066 2089 bioses[0] = "HLE";
bbd837c6 2090 gpu_plugins[0] = "builtin_gpu";
2091 spu_plugins[0] = "builtin_spu";
51f77282 2092 memcards[0] = "(none)";
2093 bios_i = gpu_i = spu_i = mc_i = 1;
e6eb2066 2094
2095 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2096 dir = opendir(fname);
2097 if (dir == NULL) {
2098 perror("scan_bios_plugins bios opendir");
2099 goto do_plugins;
2100 }
2101
2102 while (1) {
2103 struct stat st;
2104
2105 errno = 0;
2106 ent = readdir(dir);
2107 if (ent == NULL) {
2108 if (errno != 0)
2109 perror("readdir");
2110 break;
2111 }
2112
2113 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2114 continue;
2115
2116 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2117 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2118 printf("bad BIOS file: %s\n", ent->d_name);
2119 continue;
2120 }
2121
2122 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2123 bioses[bios_i++] = strdup(ent->d_name);
2124 continue;
2125 }
2126
2127 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2128 }
2129
2130 closedir(dir);
bbd837c6 2131
e6eb2066 2132do_plugins:
bbd837c6 2133 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2134 dir = opendir(fname);
2135 if (dir == NULL) {
51f77282 2136 perror("scan_bios_plugins plugins opendir");
2137 goto do_memcards;
bbd837c6 2138 }
2139
2140 while (1) {
2141 void *h, *tmp;
2142
2143 errno = 0;
2144 ent = readdir(dir);
2145 if (ent == NULL) {
2146 if (errno != 0)
2147 perror("readdir");
2148 break;
2149 }
2150 p = strstr(ent->d_name, ".so");
2151 if (p == NULL)
2152 continue;
2153
2154 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2155 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2156 if (h == NULL) {
2157 fprintf(stderr, "%s\n", dlerror());
2158 continue;
2159 }
2160
2161 // now what do we have here?
2162 tmp = dlsym(h, "GPUinit");
2163 if (tmp) {
2164 dlclose(h);
2165 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2166 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2167 continue;
2168 }
2169
2170 tmp = dlsym(h, "SPUinit");
2171 if (tmp) {
2172 dlclose(h);
2173 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2174 spu_plugins[spu_i++] = strdup(ent->d_name);
2175 continue;
2176 }
2177
2178 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2179 dlclose(h);
2180 }
2181
2182 closedir(dir);
51f77282 2183
2184do_memcards:
2185 dir = opendir("." MEMCARD_DIR);
2186 if (dir == NULL) {
2187 perror("scan_bios_plugins memcards opendir");
2188 return;
2189 }
2190
2191 while (1) {
2192 struct stat st;
2193
2194 errno = 0;
2195 ent = readdir(dir);
2196 if (ent == NULL) {
2197 if (errno != 0)
2198 perror("readdir");
2199 break;
2200 }
2201
2202 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2203 continue;
2204
2205 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2206 if (stat(fname, &st) != 0) {
2207 printf("bad memcard file: %s\n", ent->d_name);
2208 continue;
2209 }
2210
2211 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2212 memcards[mc_i++] = strdup(ent->d_name);
2213 continue;
2214 }
2215
2216 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2217 }
2218
2219 if (mc_i > 2)
2220 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2221
2222 closedir(dir);
bbd837c6 2223}
2224
3c70c47b 2225void menu_init(void)
2226{
4f3639fa 2227 char buff[MAXPATHLEN];
2228
2229 strcpy(last_selected_fname, "/media");
2230
ab423939 2231 cpu_clock_st = cpu_clock = plat_cpu_clock_get();
2232
e6eb2066 2233 scan_bios_plugins();
4f3639fa 2234 menu_init_common();
2235
3c70c47b 2236 menu_set_defconfig();
2237 menu_load_config(0);
4df9f5f8 2238 menu_do_last_cd_img(1);
ddc0a02a 2239 last_vout_w = 320;
2240 last_vout_h = 240;
2241 last_vout_bpp = 16;
bd6267e6 2242
4f3639fa 2243 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
7badc935 2244 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2245 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2246 fprintf(stderr, "OOM\n");
4f3639fa 2247 exit(1);
7badc935 2248 }
2249
4f3639fa 2250 emu_make_path(buff, "skin/background.png", sizeof(buff));
2251 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
55b0eeea 2252
2253#ifndef __ARM_ARCH_7A__ /* XXX */
a72ac803 2254 me_enable(e_menu_gfx_options, MA_OPT_SCALER, 0);
2255 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, 0);
2256 me_enable(e_menu_gfx_options, MA_OPT_SCALER_C, 0);
55b0eeea 2257 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2258#else
a72ac803 2259 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, 0);
b944a30e 2260 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
55b0eeea 2261 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2262#endif
3c70c47b 2263}
2264
bd6267e6 2265void menu_notify_mode_change(int w, int h, int bpp)
3c70c47b 2266{
ddc0a02a 2267 last_vout_w = w;
2268 last_vout_h = h;
2269 last_vout_bpp = bpp;
3c70c47b 2270}
2271
bd6267e6 2272static void menu_leave_emu(void)
2273{
6d1a1ac2 2274 if (GPU_close != NULL) {
2275 int ret = GPU_close();
2276 if (ret)
2277 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2278 }
bd6267e6 2279
55b0eeea 2280 plat_video_menu_enter(ready_to_go);
2281
4f3639fa 2282 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
b105cf4f 2283 if (pl_vout_buf != NULL && ready_to_go) {
ddc0a02a 2284 int x = max(0, g_menuscreen_w - last_vout_w);
2285 int y = max(0, g_menuscreen_h / 2 - last_vout_h / 2);
2286 int w = min(g_menuscreen_w, last_vout_w);
2287 int h = min(g_menuscreen_h, last_vout_h);
4f3639fa 2288 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
b105cf4f 2289 char *s = pl_vout_buf;
bd6267e6 2290
ddc0a02a 2291 if (last_vout_bpp == 16) {
2292 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 2)
b105cf4f 2293 menu_darken_bg(d, s, w, 0);
2294 }
2295 else {
ddc0a02a 2296 for (; h > 0; h--, d += g_menuscreen_w, s += last_vout_w * 3) {
00a5d459 2297 rgb888_to_rgb565(d, s, w * 3);
b105cf4f 2298 menu_darken_bg(d, d, w, 0);
2299 }
2300 }
bd6267e6 2301 }
fba06457 2302
1bd9ee68 2303 if (ready_to_go)
55b0eeea 2304 cpu_clock = plat_cpu_clock_get();
bd6267e6 2305}
2306
3c70c47b 2307void menu_prepare_emu(void)
2308{
b5e7e49a 2309 R3000Acpu *prev_cpu = psxCpu;
2310
fba06457 2311 plat_video_menu_leave();
2312
b5e7e49a 2313 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2314 if (psxCpu != prev_cpu)
2315 // note that this does not really reset, just clears drc caches
2316 psxCpu->Reset();
2317
bd6267e6 2318 // core doesn't care about Config.Cdda changes,
2319 // so handle them manually here
2320 if (Config.Cdda)
2321 CDR_stop();
6d1a1ac2 2322
907b1e90 2323 menu_sync_config();
7badc935 2324 if (cpu_clock > 0)
2325 plat_cpu_clock_apply(cpu_clock);
fba06457 2326
e64dc4c5 2327 // push config to GPU plugin
2328 plugin_call_rearmed_cbs();
2329
6d1a1ac2 2330 if (GPU_open != NULL) {
6d1a1ac2 2331 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2332 if (ret)
2333 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2334 }
384f5f43 2335
4c08b9e7 2336 dfinput_activate();
69af03a2 2337}
2338
2339void me_update_msg(const char *msg)
2340{
2341 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2342 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2343
2344 menu_error_time = plat_get_ticks_ms();
2345 lprintf("msg: %s\n", menu_error_msg);
2346}
2347
ab423939 2348void menu_finish(void)
2349{
2350 plat_cpu_clock_apply(cpu_clock_st);
2351}