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