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