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