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