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