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