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