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