psx_gpu: fix a blending issue
[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"
2e6189bc 1701 "Press %s or %s to continue";
1702 char tmp_msg[sizeof(msg) + 64];
4f5a1b2a 1703
2e6189bc 1704 snprintf(tmp_msg, sizeof(tmp_msg), msg,
1705 in_get_key_name(-1, -PBTN_MOK), in_get_key_name(-1, -PBTN_MBACK));
4f5a1b2a 1706 while (1)
1707 {
2e6189bc 1708 draw_menu_message(tmp_msg, NULL);
4f5a1b2a 1709
1710 inp = in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
1711 if (inp & (PBTN_MBACK|PBTN_MOK))
1712 return;
1713 }
1714}
1715
1716// ------------ main menu ------------
1717
bd6267e6 1718void OnFile_Exit();
1719
1bd9ee68 1720static void draw_frame_main(void)
1721{
65092fd8 1722 struct tm *tmp;
1723 time_t ltime;
7badc935 1724 int capacity;
65092fd8 1725 char ltime_s[16];
1726 char buff[64];
7badc935 1727 char *out;
65092fd8 1728
1bd9ee68 1729 if (CdromId[0] != 0) {
c22b95ab 1730 snprintf(buff, sizeof(buff), "%.32s/%.9s (running as %s, with %s)",
1731 get_cd_label(), CdromId, Config.PsxType ? "PAL" : "NTSC",
1732 Config.HLE ? "HLE" : "BIOS");
1bd9ee68 1733 smalltext_out16(4, 1, buff, 0x105f);
1734 }
65092fd8 1735
1736 if (ready_to_go) {
7badc935 1737 capacity = plat_get_bat_capacity();
65092fd8 1738 ltime = time(NULL);
1739 tmp = localtime(&ltime);
1740 strftime(ltime_s, sizeof(ltime_s), "%H:%M", tmp);
7badc935 1741 if (capacity >= 0) {
1742 snprintf(buff, sizeof(buff), "%s %3d%%", ltime_s, capacity);
1743 out = buff;
1744 }
1745 else
1746 out = ltime_s;
1747 smalltext_out16(4, 1 + me_sfont_h, out, 0x105f);
65092fd8 1748 }
1bd9ee68 1749}
1750
1751static void draw_frame_credits(void)
1752{
3ce7adeb 1753 smalltext_out16(4, 1, "build: " __DATE__ " " __TIME__ " " REV, 0xe7fc);
1bd9ee68 1754}
1755
4f5a1b2a 1756static const char credits_text[] =
1757 "PCSX-ReARMed\n\n"
1758 "(C) 1999-2003 PCSX Team\n"
1759 "(C) 2005-2009 PCSX-df Team\n"
1760 "(C) 2009-2011 PCSX-Reloaded Team\n\n"
4f5a1b2a 1761 "ARM recompiler (C) 2009-2011 Ari64\n"
c069dc1b 1762#ifdef __ARM_NEON__
3ce7adeb 1763 "ARM NEON GPU (c) 2011-2012 Exophase\n"
c069dc1b 1764#endif
1765 "PEOpS GPU and SPU by Pete Bernert\n"
1766 " and the P.E.Op.S. team\n"
1767 "PCSX4ALL plugin by PCSX4ALL team\n"
4f5a1b2a 1768 " Chui, Franxis, Unai\n\n"
1769 "integration, optimization and\n"
3ce7adeb 1770 " frontend (C) 2010-2012 notaz\n";
69af03a2 1771
e16a7e51 1772static int reset_game(void)
1773{
1774 // sanity check
1775 if (bios_sel == 0 && !Config.HLE)
1776 return -1;
1777
1778 ClosePlugins();
1779 OpenPlugins();
1780 SysReset();
1781 if (CheckCdrom() != -1) {
1782 LoadCdrom();
1783 }
1784 return 0;
1785}
1786
51f77282 1787static int reload_plugins(const char *cdimg)
e16a7e51 1788{
76f7048e 1789 pl_vout_buf = NULL;
e16a7e51 1790
1791 ClosePlugins();
51f77282 1792
1793 set_cd_image(cdimg);
e16a7e51 1794 LoadPlugins();
c22b95ab 1795 pcnt_hook_plugins();
e16a7e51 1796 NetOpened = 0;
1797 if (OpenPlugins() == -1) {
1798 me_update_msg("failed to open plugins");
1799 return -1;
1800 }
1801 plugin_call_rearmed_cbs();
1802
0c2871a7 1803 cdrIsoMultidiskCount = 1;
e16a7e51 1804 CdromId[0] = '\0';
1805 CdromLabel[0] = '\0';
1806
51f77282 1807 return 0;
1808}
1809
1810static int run_bios(void)
1811{
1812 if (bios_sel == 0)
1813 return -1;
1814
1815 ready_to_go = 0;
1816 if (reload_plugins(NULL) != 0)
1817 return -1;
e16a7e51 1818 SysReset();
1819
1820 ready_to_go = 1;
1821 return 0;
1822}
1823
51f77282 1824static int run_exe(void)
69af03a2 1825{
51f77282 1826 const char *fname;
1827
1828 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1829 if (fname == NULL)
1830 return -1;
1831
69af03a2 1832 ready_to_go = 0;
51f77282 1833 if (reload_plugins(NULL) != 0)
1834 return -1;
69af03a2 1835
51f77282 1836 SysReset();
1837 if (Load(fname) != 0) {
1838 me_update_msg("exe load failed, bad file?");
1839 printf("meh\n");
bbd837c6 1840 return -1;
69af03a2 1841 }
51f77282 1842
1843 ready_to_go = 1;
1844 return 0;
1845}
1846
1847static int run_cd_image(const char *fname)
1848{
1849 ready_to_go = 0;
1850 reload_plugins(fname);
69af03a2 1851
76d63edf 1852 // always autodetect, menu_sync_config will override as needed
1853 Config.PsxAuto = 1;
1854
69af03a2 1855 if (CheckCdrom() == -1) {
1856 // Only check the CD if we are starting the console with a CD
1857 ClosePlugins();
1858 me_update_msg("unsupported/invalid CD image");
bbd837c6 1859 return -1;
69af03a2 1860 }
1861
bbd837c6 1862 SysReset();
1863
69af03a2 1864 // Read main executable directly from CDRom and start it
1865 if (LoadCdrom() == -1) {
1866 ClosePlugins();
1867 me_update_msg("failed to load CD image");
bbd837c6 1868 return -1;
69af03a2 1869 }
1870
1871 ready_to_go = 1;
47232ea4 1872 snprintf(hud_msg, sizeof(hud_msg), "Booting up...");
1873 hud_new_msg = 2;
bbd837c6 1874 return 0;
69af03a2 1875}
1876
bbd837c6 1877static int romsel_run(void)
69af03a2 1878{
bbd837c6 1879 int prev_gpu, prev_spu;
51f77282 1880 const char *fname;
bbd837c6 1881
1882 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1883 if (fname == NULL)
1884 return -1;
69af03a2 1885
bbd837c6 1886 printf("selected file: %s\n", fname);
1887
dc990066 1888 new_dynarec_clear_full();
1889
bbd837c6 1890 if (run_cd_image(fname) != 0)
1891 return -1;
1892
1893 prev_gpu = gpu_plugsel;
1894 prev_spu = spu_plugsel;
1895 if (menu_load_config(1) != 0)
1896 menu_load_config(0);
1897
1898 // check for plugin changes, have to repeat
1899 // loading if game config changed plugins to reload them
1900 if (prev_gpu != gpu_plugsel || prev_spu != spu_plugsel) {
1901 printf("plugin change detected, reloading plugins..\n");
1902 if (run_cd_image(fname) != 0)
1903 return -1;
1904 }
1905
bab59f00 1906 if (Config.HLE)
1907 printf("note: running without BIOS, expect compatibility problems\n");
1908
bbd837c6 1909 strcpy(last_selected_fname, rom_fname_reload);
1910 return 0;
1911}
1912
1df403c5 1913static int swap_cd_image(void)
1914{
1915 char *fname;
1916
1917 fname = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname));
1918 if (fname == NULL)
1919 return -1;
1920
1921 printf("selected file: %s\n", fname);
1922
1923 CdromId[0] = '\0';
1924 CdromLabel[0] = '\0';
1925
1926 set_cd_image(fname);
1927 if (ReloadCdromPlugin() < 0) {
1928 me_update_msg("failed to load cdr plugin");
1929 return -1;
1930 }
1931 if (CDR_open() < 0) {
1932 me_update_msg("failed to open cdr plugin");
1933 return -1;
1934 }
1935
1936 SetCdOpenCaseTime(time(NULL) + 2);
1937 LidInterrupt();
1938
1939 strcpy(last_selected_fname, rom_fname_reload);
1940 return 0;
1941}
1942
0c2871a7 1943static int swap_cd_multidisk(void)
1944{
1945 cdrIsoMultidiskSelect++;
1946 CdromId[0] = '\0';
1947 CdromLabel[0] = '\0';
1948
1949 CDR_close();
1950 if (CDR_open() < 0) {
1951 me_update_msg("failed to open cdr plugin");
1952 return -1;
1953 }
1954
1955 SetCdOpenCaseTime(time(NULL) + 2);
1956 LidInterrupt();
1957
1958 return 0;
1959}
1960
bbd837c6 1961static int main_menu_handler(int id, int keys)
1962{
69af03a2 1963 switch (id)
1964 {
1965 case MA_MAIN_RESUME_GAME:
3c70c47b 1966 if (ready_to_go)
1967 return 1;
69af03a2 1968 break;
1969 case MA_MAIN_SAVE_STATE:
1970 if (ready_to_go)
1971 return menu_loop_savestate(0);
1972 break;
1973 case MA_MAIN_LOAD_STATE:
1974 if (ready_to_go)
1975 return menu_loop_savestate(1);
1976 break;
1977 case MA_MAIN_RESET_GAME:
e16a7e51 1978 if (ready_to_go && reset_game() == 0)
3c70c47b 1979 return 1;
69af03a2 1980 break;
1981 case MA_MAIN_LOAD_ROM:
bbd837c6 1982 if (romsel_run() == 0)
69af03a2 1983 return 1;
1984 break;
1df403c5 1985 case MA_MAIN_SWAP_CD:
1986 if (swap_cd_image() == 0)
1987 return 1;
1988 break;
0c2871a7 1989 case MA_MAIN_SWAP_CD_MULTI:
1990 if (swap_cd_multidisk() == 0)
1991 return 1;
1992 break;
e16a7e51 1993 case MA_MAIN_RUN_BIOS:
1994 if (run_bios() == 0)
1995 return 1;
1996 break;
51f77282 1997 case MA_MAIN_RUN_EXE:
1998 if (run_exe() == 0)
1999 return 1;
2000 break;
69af03a2 2001 case MA_MAIN_CREDITS:
4f5a1b2a 2002 draw_menu_message(credits_text, draw_frame_credits);
69af03a2 2003 in_menu_wait(PBTN_MOK|PBTN_MBACK, 70);
2004 break;
2005 case MA_MAIN_EXIT:
bd6267e6 2006 OnFile_Exit();
2007 break;
69af03a2 2008 default:
2009 lprintf("%s: something unknown selected\n", __FUNCTION__);
2010 break;
2011 }
2012
2013 return 0;
2014}
2015
51f77282 2016static menu_entry e_menu_main2[] =
2017{
0c2871a7 2018 mee_handler_id("Change CD image", MA_MAIN_SWAP_CD, main_menu_handler),
2019 mee_handler_id("Next multidisk CD", MA_MAIN_SWAP_CD_MULTI, main_menu_handler),
2020 mee_handler_id("Run BIOS", MA_MAIN_RUN_BIOS, main_menu_handler),
2021 mee_handler_id("Run EXE", MA_MAIN_RUN_EXE, main_menu_handler),
51f77282 2022 mee_handler ("Memcard manager", menu_loop_memcards),
2023 mee_end,
2024};
2025
2026static int main_menu2_handler(int id, int keys)
2027{
2028 static int sel = 0;
2029
2030 me_enable(e_menu_main2, MA_MAIN_SWAP_CD, ready_to_go);
0c2871a7 2031 me_enable(e_menu_main2, MA_MAIN_SWAP_CD_MULTI, ready_to_go && cdrIsoMultidiskCount > 1);
51f77282 2032 me_enable(e_menu_main2, MA_MAIN_RUN_BIOS, bios_sel != 0);
2033
2034 return me_loop_d(e_menu_main2, &sel, NULL, draw_frame_main);
2035}
2036
2037static const char h_extra[] = "Change CD, manage memcards..\n";
2038
69af03a2 2039static menu_entry e_menu_main[] =
2040{
2041 mee_label (""),
2042 mee_label (""),
2043 mee_handler_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),
2044 mee_handler_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),
2045 mee_handler_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),
2046 mee_handler_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),
2047 mee_handler_id("Load CD image", MA_MAIN_LOAD_ROM, main_menu_handler),
2048 mee_handler ("Options", menu_loop_options),
2049 mee_handler ("Controls", menu_loop_keyconfig),
51f77282 2050 mee_handler_h ("Extra stuff", main_menu2_handler, h_extra),
69af03a2 2051 mee_handler_id("Credits", MA_MAIN_CREDITS, main_menu_handler),
2052 mee_handler_id("Exit", MA_MAIN_EXIT, main_menu_handler),
2053 mee_end,
2054};
2055
3c70c47b 2056// ----------------------------
2057
bd6267e6 2058static void menu_leave_emu(void);
2059
69af03a2 2060void menu_loop(void)
2061{
2062 static int sel = 0;
2063
bd6267e6 2064 menu_leave_emu();
69af03a2 2065
4f5a1b2a 2066 if (bioses[1] == NULL && !warned_about_bios) {
2067 menu_bios_warn();
2068 warned_about_bios = 1;
2069 }
2070
69af03a2 2071 me_enable(e_menu_main, MA_MAIN_RESUME_GAME, ready_to_go);
e16a7e51 2072 me_enable(e_menu_main, MA_MAIN_SAVE_STATE, ready_to_go && CdromId[0]);
2073 me_enable(e_menu_main, MA_MAIN_LOAD_STATE, ready_to_go && CdromId[0]);
69af03a2 2074 me_enable(e_menu_main, MA_MAIN_RESET_GAME, ready_to_go);
2075
69af03a2 2076 in_set_config_int(0, IN_CFG_BLOCKING, 1);
2077
2078 do {
51f77282 2079 me_loop_d(e_menu_main, &sel, NULL, draw_frame_main);
69af03a2 2080 } while (!ready_to_go);
2081
2082 /* wait until menu, ok, back is released */
2083 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MOK|PBTN_MBACK))
2084 ;
2085
2086 in_set_config_int(0, IN_CFG_BLOCKING, 0);
2087
3c70c47b 2088 menu_prepare_emu();
2089}
2090
51f77282 2091static int qsort_strcmp(const void *p1, const void *p2)
2092{
2093 char * const *s1 = (char * const *)p1;
2094 char * const *s2 = (char * const *)p2;
2095 return strcasecmp(*s1, *s2);
2096}
2097
e6eb2066 2098static void scan_bios_plugins(void)
bbd837c6 2099{
2100 char fname[MAXPATHLEN];
2101 struct dirent *ent;
51f77282 2102 int bios_i, gpu_i, spu_i, mc_i;
bbd837c6 2103 char *p;
2104 DIR *dir;
2105
e6eb2066 2106 bioses[0] = "HLE";
bbd837c6 2107 gpu_plugins[0] = "builtin_gpu";
2108 spu_plugins[0] = "builtin_spu";
51f77282 2109 memcards[0] = "(none)";
2110 bios_i = gpu_i = spu_i = mc_i = 1;
e6eb2066 2111
2112 snprintf(fname, sizeof(fname), "%s/", Config.BiosDir);
2113 dir = opendir(fname);
2114 if (dir == NULL) {
2115 perror("scan_bios_plugins bios opendir");
2116 goto do_plugins;
2117 }
2118
2119 while (1) {
2120 struct stat st;
2121
2122 errno = 0;
2123 ent = readdir(dir);
2124 if (ent == NULL) {
2125 if (errno != 0)
2126 perror("readdir");
2127 break;
2128 }
2129
2130 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2131 continue;
2132
2133 snprintf(fname, sizeof(fname), "%s/%s", Config.BiosDir, ent->d_name);
2134 if (stat(fname, &st) != 0 || st.st_size != 512*1024) {
2135 printf("bad BIOS file: %s\n", ent->d_name);
2136 continue;
2137 }
2138
2139 if (bios_i < ARRAY_SIZE(bioses) - 1) {
2140 bioses[bios_i++] = strdup(ent->d_name);
2141 continue;
2142 }
2143
2144 printf("too many BIOSes, dropping \"%s\"\n", ent->d_name);
2145 }
2146
2147 closedir(dir);
bbd837c6 2148
e6eb2066 2149do_plugins:
bbd837c6 2150 snprintf(fname, sizeof(fname), "%s/", Config.PluginsDir);
2151 dir = opendir(fname);
2152 if (dir == NULL) {
51f77282 2153 perror("scan_bios_plugins plugins opendir");
2154 goto do_memcards;
bbd837c6 2155 }
2156
2157 while (1) {
2158 void *h, *tmp;
2159
2160 errno = 0;
2161 ent = readdir(dir);
2162 if (ent == NULL) {
2163 if (errno != 0)
2164 perror("readdir");
2165 break;
2166 }
2167 p = strstr(ent->d_name, ".so");
2168 if (p == NULL)
2169 continue;
2170
2171 snprintf(fname, sizeof(fname), "%s/%s", Config.PluginsDir, ent->d_name);
2172 h = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
2173 if (h == NULL) {
2174 fprintf(stderr, "%s\n", dlerror());
2175 continue;
2176 }
2177
2178 // now what do we have here?
2179 tmp = dlsym(h, "GPUinit");
2180 if (tmp) {
2181 dlclose(h);
2182 if (gpu_i < ARRAY_SIZE(gpu_plugins) - 1)
2183 gpu_plugins[gpu_i++] = strdup(ent->d_name);
2184 continue;
2185 }
2186
2187 tmp = dlsym(h, "SPUinit");
2188 if (tmp) {
2189 dlclose(h);
2190 if (spu_i < ARRAY_SIZE(spu_plugins) - 1)
2191 spu_plugins[spu_i++] = strdup(ent->d_name);
2192 continue;
2193 }
2194
2195 fprintf(stderr, "ignoring unidentified plugin: %s\n", fname);
2196 dlclose(h);
2197 }
2198
2199 closedir(dir);
51f77282 2200
2201do_memcards:
2202 dir = opendir("." MEMCARD_DIR);
2203 if (dir == NULL) {
2204 perror("scan_bios_plugins memcards opendir");
2205 return;
2206 }
2207
2208 while (1) {
2209 struct stat st;
2210
2211 errno = 0;
2212 ent = readdir(dir);
2213 if (ent == NULL) {
2214 if (errno != 0)
2215 perror("readdir");
2216 break;
2217 }
2218
2219 if (ent->d_type != DT_REG && ent->d_type != DT_LNK)
2220 continue;
2221
2222 snprintf(fname, sizeof(fname), "." MEMCARD_DIR "%s", ent->d_name);
2223 if (stat(fname, &st) != 0) {
2224 printf("bad memcard file: %s\n", ent->d_name);
2225 continue;
2226 }
2227
2228 if (mc_i < ARRAY_SIZE(memcards) - 1) {
2229 memcards[mc_i++] = strdup(ent->d_name);
2230 continue;
2231 }
2232
2233 printf("too many memcards, dropping \"%s\"\n", ent->d_name);
2234 }
2235
2236 if (mc_i > 2)
2237 qsort(memcards + 1, mc_i - 1, sizeof(memcards[0]), qsort_strcmp);
2238
2239 closedir(dir);
bbd837c6 2240}
2241
3c70c47b 2242void menu_init(void)
2243{
4f3639fa 2244 char buff[MAXPATHLEN];
2245
2246 strcpy(last_selected_fname, "/media");
2247
e6eb2066 2248 scan_bios_plugins();
4f3639fa 2249 pnd_menu_init();
2250 menu_init_common();
2251
3c70c47b 2252 menu_set_defconfig();
2253 menu_load_config(0);
3c70c47b 2254 last_psx_w = 320;
2255 last_psx_h = 240;
bd6267e6 2256 last_psx_bpp = 16;
2257
4f3639fa 2258 g_menubg_src_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
7badc935 2259 g_menubg_ptr = calloc(g_menuscreen_w * g_menuscreen_h * 2, 1);
2260 if (g_menubg_src_ptr == NULL || g_menubg_ptr == NULL) {
2261 fprintf(stderr, "OOM\n");
4f3639fa 2262 exit(1);
7badc935 2263 }
2264
4f3639fa 2265 emu_make_path(buff, "skin/background.png", sizeof(buff));
2266 readpng(g_menubg_src_ptr, buff, READPNG_BG, g_menuscreen_w, g_menuscreen_h);
55b0eeea 2267
2268#ifndef __ARM_ARCH_7A__ /* XXX */
a72ac803 2269 me_enable(e_menu_gfx_options, MA_OPT_SCALER, 0);
2270 me_enable(e_menu_gfx_options, MA_OPT_FILTERING, 0);
2271 me_enable(e_menu_gfx_options, MA_OPT_SCALER_C, 0);
55b0eeea 2272 me_enable(e_menu_keyconfig, MA_CTRL_NUBS_BTNS, 0);
2273#else
a72ac803 2274 me_enable(e_menu_gfx_options, MA_OPT_SCALER2, 0);
b944a30e 2275 me_enable(e_menu_keyconfig, MA_CTRL_VIBRATION, 0);
55b0eeea 2276 me_enable(e_menu_keyconfig, MA_CTRL_DEADZONE, 0);
2277#endif
3c70c47b 2278}
2279
bd6267e6 2280void menu_notify_mode_change(int w, int h, int bpp)
3c70c47b 2281{
a185be70 2282 float mult;
2283 int imult;
2284
3c70c47b 2285 last_psx_w = w;
2286 last_psx_h = h;
bd6267e6 2287 last_psx_bpp = bpp;
3c70c47b 2288
b105cf4f 2289 // XXX: should really menu code cotrol the layer size?
a185be70 2290 switch (scaling) {
2291 case SCALE_1_1:
3c70c47b 2292 g_layer_w = w; g_layer_h = h;
a185be70 2293 break;
2294
a185be70 2295 case SCALE_4_3v2:
fb005d87 2296 if (h > g_menuscreen_h || (240 < h && h <= 360))
2297 goto fractional_4_3;
2298
a185be70 2299 // 4:3 that prefers integer scaling
2300 imult = g_menuscreen_h / h;
2301 g_layer_w = w * imult;
2302 g_layer_h = h * imult;
2303 mult = (float)g_layer_w / (float)g_layer_h;
2304 if (mult < 1.25f || mult > 1.666f)
2305 g_layer_w = 4.0f/3.0f * (float)g_layer_h;
2306 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2307 break;
2308
fb005d87 2309 fractional_4_3:
2310 case SCALE_4_3:
2311 mult = 240.0f / (float)h * 4.0f / 3.0f;
2312 if (h > 256)
2313 mult *= 2.0f;
2314 g_layer_w = mult * (float)g_menuscreen_h;
2315 g_layer_h = g_menuscreen_h;
2316 printf(" -> %dx%d %.1f\n", g_layer_w, g_layer_h, mult);
2317 break;
2318
a185be70 2319 case SCALE_FULLSCREEN:
2320 g_layer_w = g_menuscreen_w;
2321 g_layer_h = g_menuscreen_h;
2322 break;
2323
2324 default:
2325 break;
3c70c47b 2326 }
a185be70 2327
2328 g_layer_x = g_menuscreen_w / 2 - g_layer_w / 2;
2329 g_layer_y = g_menuscreen_h / 2 - g_layer_h / 2;
2330 if (g_layer_x < 0) g_layer_x = 0;
2331 if (g_layer_y < 0) g_layer_y = 0;
2332 if (g_layer_w > g_menuscreen_w) g_layer_w = g_menuscreen_w;
2333 if (g_layer_h > g_menuscreen_h) g_layer_w = g_menuscreen_h;
3c70c47b 2334}
2335
bd6267e6 2336static void menu_leave_emu(void)
2337{
6d1a1ac2 2338 if (GPU_close != NULL) {
2339 int ret = GPU_close();
2340 if (ret)
2341 fprintf(stderr, "Warning: GPU_close returned %d\n", ret);
2342 }
bd6267e6 2343
55b0eeea 2344 plat_video_menu_enter(ready_to_go);
2345
4f3639fa 2346 memcpy(g_menubg_ptr, g_menubg_src_ptr, g_menuscreen_w * g_menuscreen_h * 2);
b105cf4f 2347 if (pl_vout_buf != NULL && ready_to_go) {
bd6267e6 2348 int x = max(0, g_menuscreen_w - last_psx_w);
2349 int y = max(0, g_menuscreen_h / 2 - last_psx_h / 2);
2350 int w = min(g_menuscreen_w, last_psx_w);
2351 int h = min(g_menuscreen_h, last_psx_h);
4f3639fa 2352 u16 *d = (u16 *)g_menubg_ptr + g_menuscreen_w * y + x;
b105cf4f 2353 char *s = pl_vout_buf;
bd6267e6 2354
b105cf4f 2355 if (last_psx_bpp == 16) {
2356 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w * 2)
2357 menu_darken_bg(d, s, w, 0);
2358 }
2359 else {
2360 for (; h > 0; h--, d += g_menuscreen_w, s += last_psx_w * 3) {
2361 bgr888_to_rgb565(d, s, w * 3);
2362 menu_darken_bg(d, d, w, 0);
2363 }
2364 }
bd6267e6 2365 }
fba06457 2366
1bd9ee68 2367 if (ready_to_go)
55b0eeea 2368 cpu_clock = plat_cpu_clock_get();
bd6267e6 2369}
2370
3c70c47b 2371void menu_prepare_emu(void)
2372{
b5e7e49a 2373 R3000Acpu *prev_cpu = psxCpu;
2374
fba06457 2375 plat_video_menu_leave();
2376
a185be70 2377 menu_notify_mode_change(last_psx_w, last_psx_h, last_psx_bpp);
bd6267e6 2378
b5e7e49a 2379 psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
2380 if (psxCpu != prev_cpu)
2381 // note that this does not really reset, just clears drc caches
2382 psxCpu->Reset();
2383
bd6267e6 2384 // core doesn't care about Config.Cdda changes,
2385 // so handle them manually here
2386 if (Config.Cdda)
2387 CDR_stop();
6d1a1ac2 2388
907b1e90 2389 menu_sync_config();
cefe86b7 2390 apply_lcdrate(Config.PsxType);
2391 apply_filter(filter);
7badc935 2392 if (cpu_clock > 0)
2393 plat_cpu_clock_apply(cpu_clock);
fba06457 2394
e64dc4c5 2395 // push config to GPU plugin
2396 plugin_call_rearmed_cbs();
2397
6d1a1ac2 2398 if (GPU_open != NULL) {
6d1a1ac2 2399 int ret = GPU_open(&gpuDisp, "PCSX", NULL);
2400 if (ret)
2401 fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
2402 }
384f5f43 2403
4c08b9e7 2404 dfinput_activate();
69af03a2 2405}
2406
2407void me_update_msg(const char *msg)
2408{
2409 strncpy(menu_error_msg, msg, sizeof(menu_error_msg));
2410 menu_error_msg[sizeof(menu_error_msg) - 1] = 0;
2411
2412 menu_error_time = plat_get_ticks_ms();
2413 lprintf("msg: %s\n", menu_error_msg);
2414}
2415