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