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