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