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