moved game_def.cfg, few games added
[picodrive.git] / platform / gp2x / menu.c
CommitLineData
d524c827 1// (c) Copyright 2006,2007 notaz, All rights reserved.\r
cc68a136 2// Free for non-commercial use.\r
3\r
4// For commercial use, separate licencing terms must be obtained.\r
5\r
6#include <stdio.h>\r
7#include <string.h>\r
8#include <stdlib.h>\r
9#include <stdarg.h>\r
10#include <unistd.h>\r
11#include <dirent.h>\r
12\r
13#include "gp2x.h"\r
14#include "emu.h"\r
15#include "menu.h"\r
16#include "usbjoy.h"\r
ea8c405f 17#include "../common/emu.h"\r
e5f426aa 18#include "../common/menu.h"\r
ea8c405f 19#include "../common/arm_utils.h"\r
e5f426aa 20#include "../common/readpng.h"\r
cc68a136 21#include "version.h"\r
22\r
b67ef287 23#include <Pico/PicoInt.h>\r
24#include <Pico/Patch.h>\r
25#include <zlib/zlib.h>\r
cc68a136 26\r
27#ifndef _DIRENT_HAVE_D_TYPE\r
28#error "need d_type for file browser\r
29#endif\r
30\r
cc68a136 31extern int mmuhack_status;\r
cc68a136 32\r
1ca2ea4f 33const char *keyNames[] = {\r
cc68a136 34 "UP", "???", "LEFT", "???", "DOWN", "???", "RIGHT", "???",\r
35 "START", "SELECT", "L", "R", "A", "B", "X", "Y",\r
36 "???", "???", "???", "???", "???", "???", "VOL DOWN", "VOL UP",\r
37 "???", "???", "???", "PUSH", "???", "???", "???", "???"\r
38};\r
39\r
a4f0cc86 40static void menu_darken_bg(void *dst, int pixels, int darker);\r
a12e0116 41static void menu_prepare_bg(int use_game_bg);\r
cc68a136 42\r
cc68a136 43static unsigned long inp_prev = 0;\r
44static int inp_prevjoy = 0;\r
45\r
46static unsigned long wait_for_input(unsigned long interesting)\r
47{\r
48 unsigned long ret;\r
721cd396 49 static int repeats = 0, wait = 50*1000;\r
cc68a136 50 int release = 0, i;\r
51\r
721cd396 52 if (repeats == 2 || repeats == 4) wait /= 2;\r
53 if (repeats == 6) wait = 15 * 1000;\r
cc68a136 54\r
55 for (i = 0; i < 6 && inp_prev == gp2x_joystick_read(1); i++) {\r
721cd396 56 if (i == 0) repeats++;\r
57 if (wait >= 30*1000) usleep(wait); // usleep sleeps for ~30ms minimum\r
58 else spend_cycles(wait * currentConfig.CPUclock);\r
cc68a136 59 }\r
60\r
61 while ( !((ret = gp2x_joystick_read(1)) & interesting) ) {\r
62 usleep(50000);\r
63 release = 1;\r
64 }\r
65\r
66 if (release || ret != inp_prev) {\r
67 repeats = 0;\r
721cd396 68 wait = 50*1000;\r
cc68a136 69 }\r
70 inp_prev = ret;\r
71 inp_prevjoy = 0;\r
72\r
73 // we don't need diagonals in menus\r
74 if ((ret&GP2X_UP) && (ret&GP2X_LEFT)) ret &= ~GP2X_LEFT;\r
75 if ((ret&GP2X_UP) && (ret&GP2X_RIGHT)) ret &= ~GP2X_RIGHT;\r
76 if ((ret&GP2X_DOWN) && (ret&GP2X_LEFT)) ret &= ~GP2X_LEFT;\r
77 if ((ret&GP2X_DOWN) && (ret&GP2X_RIGHT)) ret &= ~GP2X_RIGHT;\r
78\r
79 return ret;\r
80}\r
81\r
82static unsigned long input2_read(unsigned long interesting, int *joy)\r
83{\r
84 unsigned long ret;\r
85 int i;\r
86\r
87 do\r
88 {\r
89 *joy = 0;\r
90 if ((ret = gp2x_joystick_read(0) & interesting)) break;\r
91 gp2x_usbjoy_update();\r
92 for (i = 0; i < num_of_joys; i++) {\r
93 ret = gp2x_usbjoy_check2(i);\r
94 if (ret) { *joy = i + 1; break; }\r
95 }\r
96 if (ret) break;\r
97 }\r
98 while(0);\r
99\r
100 return ret;\r
101}\r
102\r
103// similar to wait_for_input(), but returns joy num\r
104static unsigned long wait_for_input_usbjoy(unsigned long interesting, int *joy)\r
105{\r
106 unsigned long ret;\r
107 const int wait = 300*1000;\r
108 int i;\r
109\r
110 if (inp_prevjoy == 0) inp_prev &= interesting;\r
111 for (i = 0; i < 6; i++) {\r
112 ret = input2_read(interesting, joy);\r
113 if (*joy != inp_prevjoy || ret != inp_prev) break;\r
114 usleep(wait/6);\r
115 }\r
116\r
117 while ( !(ret = input2_read(interesting, joy)) ) {\r
118 usleep(50000);\r
119 }\r
120\r
121 inp_prev = ret;\r
122 inp_prevjoy = *joy;\r
123\r
1ca2ea4f 124 // handle only 1 event at a time\r
125 for (i = 1; i != 0; i <<= 1)\r
126 if (ret & i) { ret &= i; break; }\r
a39b7867 127 // ... but allow select\r
128 ret |= inp_prev & GP2X_SELECT;\r
1ca2ea4f 129\r
cc68a136 130 return ret;\r
131}\r
132\r
e5f426aa 133static void menu_flip(void)\r
134{\r
135 gp2x_video_flush_cache();\r
136 gp2x_video_flip2();\r
137}\r
cc68a136 138\r
139\r
a9b3ffd3 140// --------- loading ROM screen ----------\r
141\r
ea08c296 142static int cdload_called = 0;\r
143\r
a9b3ffd3 144static void load_progress_cb(int percent)\r
145{\r
146 int ln, len = percent * 320 / 100;\r
a12e0116 147 unsigned short *dst = (unsigned short *)gp2x_screen + 320*20;\r
a9b3ffd3 148\r
149 if (len > 320) len = 320;\r
ea08c296 150 for (ln = 8; ln > 0; ln--, dst += 320)\r
a12e0116 151 memset(dst, 0xff, len*2);\r
152 menu_flip();\r
a9b3ffd3 153}\r
154\r
ea08c296 155static void cdload_progress_cb(int percent)\r
156{\r
157 int ln, len = percent * 320 / 100;\r
158 unsigned short *dst = (unsigned short *)gp2x_screen + 320*20;\r
159\r
160 memset(dst, 0xff, 320*2*8);\r
161\r
162 smalltext_out16(1, 3*10, "Processing CD image / MP3s", 0xffff);\r
163 smalltext_out16_lim(1, 4*10, romFileName, 0xffff, 80);\r
ca61ee42 164 dst += 320*30;\r
ea08c296 165\r
166 if (len > 320) len = 320;\r
167 for (ln = 8; ln > 0; ln--, dst += 320)\r
168 memset(dst, 0xff, len*2);\r
ca61ee42 169 menu_flip();\r
ea08c296 170 cdload_called = 1;\r
171}\r
172\r
a9b3ffd3 173void menu_romload_prepare(const char *rom_name)\r
174{\r
175 const char *p = rom_name + strlen(rom_name);\r
176 while (p > rom_name && *p != '/') p--;\r
177\r
eacee137 178 if (rom_loaded) gp2x_pd_clone_buffer2();\r
a12e0116 179 else memset(gp2x_screen, 0, 320*240*2);\r
180\r
181 smalltext_out16(1, 1, "Loading", 0xffff);\r
182 smalltext_out16_lim(1, 10, p, 0xffff, 53);\r
183 gp2x_memcpy_buffers(3, gp2x_screen, 0, 320*240*2);\r
184 menu_flip();\r
a9b3ffd3 185 PicoCartLoadProgressCB = load_progress_cb;\r
ea08c296 186 PicoCDLoadProgressCB = cdload_progress_cb;\r
187 cdload_called = 0;\r
a9b3ffd3 188}\r
189\r
190void menu_romload_end(void)\r
191{\r
ca61ee42 192 PicoCartLoadProgressCB = PicoCDLoadProgressCB = NULL;\r
ea08c296 193 smalltext_out16(1, cdload_called ? 60 : 30, "Starting emulation...", 0xffff);\r
a12e0116 194 menu_flip();\r
a9b3ffd3 195}\r
196\r
cc68a136 197// -------------- ROM selector --------------\r
198\r
a12e0116 199// rrrr rggg gggb bbbb\r
200static unsigned short file2color(const char *fname)\r
201{\r
202 const char *ext = fname + strlen(fname) - 3;\r
71de3cd9 203 static const char *rom_exts[] = { "zip", "bin", "smd", "gen", "iso", "cso" };\r
a12e0116 204 static const char *other_exts[] = { "gmv", "pat" };\r
205 int i;\r
206\r
207 if (ext < fname) ext = fname;\r
208 for (i = 0; i < sizeof(rom_exts)/sizeof(rom_exts[0]); i++)\r
209 if (strcasecmp(ext, rom_exts[i]) == 0) return 0xbdff;\r
210 for (i = 0; i < sizeof(other_exts)/sizeof(other_exts[0]); i++)\r
211 if (strcasecmp(ext, other_exts[i]) == 0) return 0xaff5;\r
212 return 0xffff;\r
213}\r
214\r
cc68a136 215static void draw_dirlist(char *curdir, struct dirent **namelist, int n, int sel)\r
216{\r
217 int start, i, pos;\r
218\r
219 start = 12 - sel;\r
220 n--; // exclude current dir (".")\r
221\r
a4f0cc86 222 gp2x_pd_clone_buffer2();\r
223\r
eacee137 224 if (!rom_loaded) {\r
a4f0cc86 225 menu_darken_bg(gp2x_screen, 320*240, 0);\r
a12e0116 226 }\r
227\r
a4f0cc86 228 menu_darken_bg((char *)gp2x_screen + 320*120*2, 320*8, 0);\r
cc68a136 229\r
230 if(start - 2 >= 0)\r
a12e0116 231 smalltext_out16_lim(14, (start - 2)*10, curdir, 0xffff, 53-2);\r
cc68a136 232 for (i = 0; i < n; i++) {\r
233 pos = start + i;\r
234 if (pos < 0) continue;\r
235 if (pos > 23) break;\r
236 if (namelist[i+1]->d_type == DT_DIR) {\r
a12e0116 237 smalltext_out16_lim(14, pos*10, "/", 0xfff6, 1);\r
238 smalltext_out16_lim(14+6, pos*10, namelist[i+1]->d_name, 0xfff6, 53-3);\r
cc68a136 239 } else {\r
a12e0116 240 unsigned short color = file2color(namelist[i+1]->d_name);\r
241 smalltext_out16_lim(14, pos*10, namelist[i+1]->d_name, color, 53-2);\r
cc68a136 242 }\r
243 }\r
a12e0116 244 text_out16(5, 120, ">");\r
245 menu_flip();\r
cc68a136 246}\r
247\r
248static int scandir_cmp(const void *p1, const void *p2)\r
249{\r
250 struct dirent **d1 = (struct dirent **)p1, **d2 = (struct dirent **)p2;\r
251 if ((*d1)->d_type == (*d2)->d_type) return alphasort(d1, d2);\r
252 if ((*d1)->d_type == DT_DIR) return -1; // put before\r
253 if ((*d2)->d_type == DT_DIR) return 1;\r
254 return alphasort(d1, d2);\r
255}\r
256\r
2433f409 257static char *filter_exts[] = {\r
258 ".mp3", ".MP3", ".srm", ".brm", "s.gz", ".mds", "bcfg", ".txt", ".htm", "html",\r
259 ".jpg", ".gpe", ".cue"\r
260};\r
c008977e 261\r
262static int scandir_filter(const struct dirent *ent)\r
263{\r
264 const char *p;\r
265 int i;\r
266\r
267 if (ent == NULL || ent->d_name == NULL) return 0;\r
268 if (strlen(ent->d_name) < 5) return 1;\r
269\r
270 p = ent->d_name + strlen(ent->d_name) - 4;\r
271\r
272 for (i = 0; i < sizeof(filter_exts)/sizeof(filter_exts[0]); i++)\r
273 {\r
274 if (strcmp(p, filter_exts[i]) == 0) return 0;\r
275 }\r
276\r
277 return 1;\r
278}\r
cc68a136 279\r
1b13dae0 280static void do_delete(const char *fpath, const char *fname)\r
281{\r
282 int len, inp;\r
283\r
284 gp2x_pd_clone_buffer2();\r
285\r
286 if (!rom_loaded)\r
287 menu_darken_bg(gp2x_screen, 320*240, 0);\r
288\r
289 len = strlen(fname);\r
290 if (len > 320/6) len = 320/6;\r
291\r
292 text_out16(320/2 - 15*8/2, 80, "About to delete");\r
293 smalltext_out16_lim(320/2 - len*6/2, 95, fname, 0xbdff, len);\r
294 text_out16(320/2 - 13*8/2, 110, "Are you sure?");\r
295 text_out16(320/2 - 25*8/2, 120, "(Y - confirm, X - cancel)");\r
296 menu_flip();\r
297\r
298\r
299 while (gp2x_joystick_read(1) & (GP2X_A|GP2X_SELECT)) usleep(50*1000);\r
300 inp = wait_for_input(GP2X_Y|GP2X_X);\r
301 if (inp & GP2X_Y)\r
302 remove(fpath);\r
303}\r
304\r
cc68a136 305static char *romsel_loop(char *curr_path)\r
306{\r
307 struct dirent **namelist;\r
308 DIR *dir;\r
309 int n, sel = 0;\r
310 unsigned long inp = 0;\r
311 char *ret = NULL, *fname = NULL;\r
312\r
1b13dae0 313rescan:\r
cc68a136 314 // is this a dir or a full path?\r
315 if ((dir = opendir(curr_path))) {\r
316 closedir(dir);\r
317 } else {\r
318 char *p;\r
319 for (p = curr_path + strlen(curr_path) - 1; p > curr_path && *p != '/'; p--);\r
320 *p = 0;\r
321 fname = p+1;\r
322 }\r
323\r
c008977e 324 n = scandir(curr_path, &namelist, scandir_filter, scandir_cmp);\r
cc68a136 325 if (n < 0) {\r
326 // try root\r
c008977e 327 n = scandir("/", &namelist, scandir_filter, scandir_cmp);\r
cc68a136 328 if (n < 0) {\r
329 // oops, we failed\r
330 printf("dir: "); printf(curr_path); printf("\n");\r
331 perror("scandir");\r
332 return NULL;\r
333 }\r
334 }\r
335\r
336 // try to find sel\r
337 if (fname != NULL) {\r
338 int i;\r
339 for (i = 1; i < n; i++) {\r
340 if (strcmp(namelist[i]->d_name, fname) == 0) {\r
341 sel = i - 1;\r
342 break;\r
343 }\r
344 }\r
345 }\r
346\r
347 for (;;)\r
348 {\r
349 draw_dirlist(curr_path, namelist, n, sel);\r
1b13dae0 350 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_L|GP2X_R|GP2X_A|GP2X_B|GP2X_X|GP2X_SELECT);\r
cc68a136 351 if(inp & GP2X_UP ) { sel--; if (sel < 0) sel = n-2; }\r
352 if(inp & GP2X_DOWN) { sel++; if (sel > n-2) sel = 0; }\r
721cd396 353 if(inp & GP2X_LEFT) { sel-=10; if (sel < 0) sel = 0; }\r
354 if(inp & GP2X_L) { sel-=24; if (sel < 0) sel = 0; }\r
355 if(inp & GP2X_RIGHT) { sel+=10; if (sel > n-2) sel = n-2; }\r
356 if(inp & GP2X_R) { sel+=24; if (sel > n-2) sel = n-2; }\r
1b13dae0 357 if ((inp & GP2X_B) || (inp & (GP2X_SELECT|GP2X_A)) == (GP2X_SELECT|GP2X_A)) // enter dir/select || delete\r
358 {\r
cc68a136 359 again:\r
1b13dae0 360 if (namelist[sel+1]->d_type == DT_REG)\r
361 {\r
cc68a136 362 strcpy(romFileName, curr_path);\r
363 strcat(romFileName, "/");\r
364 strcat(romFileName, namelist[sel+1]->d_name);\r
1b13dae0 365 if (inp & GP2X_B) { // return sel\r
366 ret = romFileName;\r
367 break;\r
368 }\r
369 do_delete(romFileName, namelist[sel+1]->d_name);\r
370 if (n > 0) {\r
371 while (n--) free(namelist[n]);\r
372 free(namelist);\r
373 }\r
374 goto rescan;\r
375 }\r
376 else if (namelist[sel+1]->d_type == DT_DIR)\r
377 {\r
378 int newlen;\r
379 char *p, *newdir;\r
380 if (!(inp & GP2X_B)) continue;\r
381 newlen = strlen(curr_path) + strlen(namelist[sel+1]->d_name) + 2;\r
382 newdir = malloc(newlen);\r
cc68a136 383 if (strcmp(namelist[sel+1]->d_name, "..") == 0) {\r
384 char *start = curr_path;\r
385 p = start + strlen(start) - 1;\r
386 while (*p == '/' && p > start) p--;\r
387 while (*p != '/' && p > start) p--;\r
388 if (p <= start) strcpy(newdir, "/");\r
389 else { strncpy(newdir, start, p-start); newdir[p-start] = 0; }\r
390 } else {\r
391 strcpy(newdir, curr_path);\r
392 p = newdir + strlen(newdir) - 1;\r
393 while (*p == '/' && p >= newdir) *p-- = 0;\r
394 strcat(newdir, "/");\r
395 strcat(newdir, namelist[sel+1]->d_name);\r
396 }\r
397 ret = romsel_loop(newdir);\r
398 free(newdir);\r
399 break;\r
1b13dae0 400 }\r
401 else\r
402 {\r
cc68a136 403 // unknown file type, happens on NTFS mounts. Try to guess.\r
404 FILE *tstf; int tmp;\r
405 strcpy(romFileName, curr_path);\r
406 strcat(romFileName, "/");\r
407 strcat(romFileName, namelist[sel+1]->d_name);\r
408 tstf = fopen(romFileName, "rb");\r
409 if (tstf != NULL)\r
410 {\r
411 if (fread(&tmp, 1, 1, tstf) > 0 || ferror(tstf) == 0)\r
412 namelist[sel+1]->d_type = DT_REG;\r
413 else namelist[sel+1]->d_type = DT_DIR;\r
414 fclose(tstf);\r
415 goto again;\r
416 }\r
417 }\r
418 }\r
419 if(inp & GP2X_X) break; // cancel\r
420 }\r
421\r
422 if (n > 0) {\r
1b13dae0 423 while (n--) free(namelist[n]);\r
cc68a136 424 free(namelist);\r
425 }\r
426\r
427 return ret;\r
428}\r
429\r
0af33fe0 430// ------------ debug menu ------------\r
431\r
432char *debugString(void);\r
433\r
434static void draw_debug(void)\r
435{\r
436 char *p, *str = debugString();\r
437 int len, line;\r
438\r
439 gp2x_pd_clone_buffer2();\r
440\r
441 p = str;\r
442 for (line = 0; line < 24; line++)\r
443 {\r
444 while (*p && *p != '\n') p++;\r
445 len = p - str;\r
446 if (len > 55) len = 55;\r
a12e0116 447 smalltext_out16_lim(1, line*10, str, 0xffff, len);\r
0af33fe0 448 if (*p == 0) break;\r
449 p++; str = p;\r
450 }\r
a12e0116 451 menu_flip();\r
0af33fe0 452}\r
453\r
454static void debug_menu_loop(void)\r
455{\r
456 draw_debug();\r
457 wait_for_input(GP2X_B|GP2X_X);\r
458}\r
459\r
b67ef287 460// ------------ patch/gg menu ------------\r
461\r
462static void draw_patchlist(int sel)\r
463{\r
a12e0116 464 int start, i, pos, active;\r
b67ef287 465\r
466 start = 12 - sel;\r
467\r
468 gp2x_pd_clone_buffer2();\r
469\r
470 for (i = 0; i < PicoPatchCount; i++) {\r
471 pos = start + i;\r
472 if (pos < 0) continue;\r
473 if (pos > 23) break;\r
a12e0116 474 active = PicoPatches[i].active;\r
475 smalltext_out16_lim(14, pos*10, active ? "ON " : "OFF", active ? 0xfff6 : 0xffff, 3);\r
476 smalltext_out16_lim(14+6*4, pos*10, PicoPatches[i].name, active ? 0xfff6 : 0xffff, 53-6);\r
b67ef287 477 }\r
478 pos = start + i;\r
a12e0116 479 if (pos < 24) smalltext_out16_lim(14, pos*10, "done", 0xffff, 4);\r
b67ef287 480\r
a12e0116 481 text_out16(5, 120, ">");\r
482 menu_flip();\r
b67ef287 483}\r
484\r
485\r
0af33fe0 486static void patches_menu_loop(void)\r
b67ef287 487{\r
488 int menu_sel = 0;\r
489 unsigned long inp = 0;\r
490\r
491 for(;;)\r
492 {\r
493 draw_patchlist(menu_sel);\r
494 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_L|GP2X_R|GP2X_B|GP2X_X);\r
495 if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = PicoPatchCount; }\r
496 if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > PicoPatchCount) menu_sel = 0; }\r
497 if(inp &(GP2X_LEFT|GP2X_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }\r
498 if(inp &(GP2X_RIGHT|GP2X_R)) { menu_sel+=10; if (menu_sel > PicoPatchCount) menu_sel = PicoPatchCount; }\r
499 if(inp & GP2X_B) { // action\r
500 if (menu_sel < PicoPatchCount)\r
501 PicoPatches[menu_sel].active = !PicoPatches[menu_sel].active;\r
502 else return;\r
503 }\r
504 if(inp & GP2X_X) return;\r
505 }\r
506\r
507}\r
508\r
860c6322 509// ------------ savestate loader ------------\r
510\r
860c6322 511static int state_slot_flags = 0;\r
512\r
513static void state_check_slots(void)\r
514{\r
515 int slot;\r
516\r
517 state_slot_flags = 0;\r
518\r
519 for (slot = 0; slot < 10; slot++)\r
520 {\r
ea8c405f 521 if (emu_checkSaveFile(slot))\r
860c6322 522 {\r
523 state_slot_flags |= 1 << slot;\r
524 }\r
525 }\r
526}\r
527\r
528static void draw_savestate_bg(int slot)\r
529{\r
530 struct PicoVideo tmp_pv;\r
531 unsigned short tmp_cram[0x40];\r
532 unsigned short tmp_vsram[0x40];\r
533 void *tmp_vram, *file;\r
534 char *fname;\r
535\r
536 fname = emu_GetSaveFName(1, 0, slot);\r
537 if (!fname) return;\r
538\r
539 tmp_vram = malloc(sizeof(Pico.vram));\r
540 if (tmp_vram == NULL) return;\r
541\r
542 memcpy(tmp_vram, Pico.vram, sizeof(Pico.vram));\r
543 memcpy(tmp_cram, Pico.cram, sizeof(Pico.cram));\r
544 memcpy(tmp_vsram, Pico.vsram, sizeof(Pico.vsram));\r
545 memcpy(&tmp_pv, &Pico.video, sizeof(Pico.video));\r
546\r
547 if (strcmp(fname + strlen(fname) - 3, ".gz") == 0) {\r
548 file = gzopen(fname, "rb");\r
ea8c405f 549 emu_setSaveStateCbs(1);\r
860c6322 550 } else {\r
551 file = fopen(fname, "rb");\r
ea8c405f 552 emu_setSaveStateCbs(0);\r
860c6322 553 }\r
554\r
555 if (file) {\r
602133e1 556 if (PicoAHW & PAHW_MCD) {\r
860c6322 557 PicoCdLoadStateGfx(file);\r
558 } else {\r
559 areaSeek(file, 0x10020, SEEK_SET); // skip header and RAM in state file\r
560 areaRead(Pico.vram, 1, sizeof(Pico.vram), file);\r
561 areaSeek(file, 0x2000, SEEK_CUR);\r
562 areaRead(Pico.cram, 1, sizeof(Pico.cram), file);\r
563 areaRead(Pico.vsram, 1, sizeof(Pico.vsram), file);\r
564 areaSeek(file, 0x221a0, SEEK_SET);\r
565 areaRead(&Pico.video, 1, sizeof(Pico.video), file);\r
566 }\r
567 areaClose(file);\r
568 }\r
569\r
ea8c405f 570 emu_forcedFrame();\r
a12e0116 571 menu_prepare_bg(1);\r
860c6322 572\r
573 memcpy(Pico.vram, tmp_vram, sizeof(Pico.vram));\r
574 memcpy(Pico.cram, tmp_cram, sizeof(Pico.cram));\r
575 memcpy(Pico.vsram, tmp_vsram, sizeof(Pico.vsram));\r
576 memcpy(&Pico.video, &tmp_pv, sizeof(Pico.video));\r
577 free(tmp_vram);\r
578}\r
579\r
580static void draw_savestate_menu(int menu_sel, int is_loading)\r
581{\r
582 int tl_x = 25, tl_y = 60, y, i;\r
583\r
584 if (state_slot_flags & (1 << menu_sel))\r
585 draw_savestate_bg(menu_sel);\r
586 gp2x_pd_clone_buffer2();\r
587\r
a12e0116 588 text_out16(tl_x, 30, is_loading ? "Load state" : "Save state");\r
589\r
e5f426aa 590 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 108);\r
860c6322 591\r
592 /* draw all 10 slots */\r
593 y = tl_y;\r
594 for (i = 0; i < 10; i++, y+=10)\r
595 {\r
a12e0116 596 text_out16(tl_x, y, "SLOT %i (%s)", i, (state_slot_flags & (1 << i)) ? "USED" : "free");\r
860c6322 597 }\r
a12e0116 598 text_out16(tl_x, y, "back");\r
860c6322 599\r
a12e0116 600 menu_flip();\r
860c6322 601}\r
602\r
603static int savestate_menu_loop(int is_loading)\r
604{\r
aae35e84 605 static int menu_sel = 10;\r
606 int menu_sel_max = 10;\r
860c6322 607 unsigned long inp = 0;\r
608\r
609 state_check_slots();\r
610\r
611 for(;;)\r
612 {\r
613 draw_savestate_menu(menu_sel, is_loading);\r
614 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X);\r
615 if(inp & GP2X_UP ) {\r
616 do {\r
617 menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max;\r
618 } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading);\r
619 }\r
620 if(inp & GP2X_DOWN) {\r
621 do {\r
622 menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0;\r
623 } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading);\r
624 }\r
625 if(inp & GP2X_B) { // save/load\r
626 if (menu_sel < 10) {\r
627 state_slot = menu_sel;\r
628 if (emu_SaveLoadGame(is_loading, 0)) {\r
629 strcpy(menuErrorMsg, is_loading ? "Load failed" : "Save failed");\r
630 return 1;\r
631 }\r
632 return 0;\r
633 } else return 1;\r
634 }\r
635 if(inp & GP2X_X) return 1;\r
636 }\r
637}\r
638\r
cc68a136 639// -------------- key config --------------\r
640\r
641static char *usb_joy_key_name(int joy, int num)\r
642{\r
643 static char name[16];\r
644 switch (num)\r
645 {\r
646 case 0: sprintf(name, "Joy%i UP", joy); break;\r
647 case 1: sprintf(name, "Joy%i DOWN", joy); break;\r
648 case 2: sprintf(name, "Joy%i LEFT", joy); break;\r
649 case 3: sprintf(name, "Joy%i RIGHT", joy); break;\r
650 default:sprintf(name, "Joy%i b%i", joy, num-3); break;\r
651 }\r
652 return name;\r
653}\r
654\r
d524c827 655static char *action_binds(int player_idx, int action_mask)\r
cc68a136 656{\r
d524c827 657 static char strkeys[32*5];\r
cc68a136 658 int joy, i;\r
659\r
660 strkeys[0] = 0;\r
d524c827 661 for (i = 0; i < 32; i++) // i is key index\r
cc68a136 662 {\r
d524c827 663 if (currentConfig.KeyBinds[i] & action_mask)\r
cc68a136 664 {\r
d524c827 665 if (player_idx >= 0 && ((currentConfig.KeyBinds[i] >> 16) & 3) != player_idx) continue;\r
1ca2ea4f 666 if (strkeys[0]) { strcat(strkeys, " + "); strcat(strkeys, keyNames[i]); break; }\r
667 else strcpy(strkeys, keyNames[i]);\r
cc68a136 668 }\r
669 }\r
670 for (joy = 0; joy < num_of_joys; joy++)\r
671 {\r
672 for (i = 0; i < 32; i++)\r
673 {\r
d524c827 674 if (currentConfig.JoyBinds[joy][i] & action_mask)\r
cc68a136 675 {\r
d524c827 676 if (player_idx >= 0 && ((currentConfig.JoyBinds[joy][i] >> 16) & 3) != player_idx) continue;\r
cc68a136 677 if (strkeys[0]) {\r
678 strcat(strkeys, ", "); strcat(strkeys, usb_joy_key_name(joy + 1, i));\r
679 break;\r
680 }\r
681 else strcpy(strkeys, usb_joy_key_name(joy + 1, i));\r
682 }\r
683 }\r
684 }\r
685\r
45499284 686 // limit..\r
687 strkeys[20] = 0;\r
688\r
d524c827 689 return strkeys;\r
690}\r
691\r
45499284 692static void unbind_action(int action, int pl_idx, int joy)\r
d524c827 693{\r
694 int i, u;\r
695\r
45499284 696 if (joy <= 0)\r
697 {\r
698 for (i = 0; i < 32; i++) {\r
699 if (pl_idx >= 0 && (currentConfig.KeyBinds[i]&0x30000) != (pl_idx<<16)) continue;\r
700 currentConfig.KeyBinds[i] &= ~action;\r
701 }\r
b4fe3a4a 702 }\r
45499284 703 if (joy < 0)\r
704 {\r
705 for (u = 0; u < 4; u++)\r
706 for (i = 0; i < 32; i++) {\r
707 if (pl_idx >= 0 && (currentConfig.JoyBinds[u][i]&0x30000) != (pl_idx<<16)) continue;\r
708 currentConfig.JoyBinds[u][i] &= ~action;\r
709 }\r
710 }\r
711 else if (joy > 0)\r
712 {\r
b4fe3a4a 713 for (i = 0; i < 32; i++) {\r
45499284 714 if (pl_idx >= 0 && (currentConfig.JoyBinds[joy-1][i]&0x30000) != (pl_idx<<16)) continue;\r
715 currentConfig.JoyBinds[joy-1][i] &= ~action;\r
b4fe3a4a 716 }\r
45499284 717 }\r
d524c827 718}\r
719\r
b4fe3a4a 720static int count_bound_keys(int action, int pl_idx, int joy)\r
d524c827 721{\r
722 int i, keys = 0;\r
723\r
724 if (joy)\r
725 {\r
b4fe3a4a 726 for (i = 0; i < 32; i++) {\r
727 if (pl_idx >= 0 && (currentConfig.JoyBinds[joy-1][i]&0x30000) != (pl_idx<<16)) continue;\r
d524c827 728 if (currentConfig.JoyBinds[joy-1][i] & action) keys++;\r
b4fe3a4a 729 }\r
d524c827 730 }\r
731 else\r
732 {\r
b4fe3a4a 733 for (i = 0; i < 32; i++) {\r
734 if (pl_idx >= 0 && (currentConfig.KeyBinds[i]&0x30000) != (pl_idx<<16)) continue;\r
d524c827 735 if (currentConfig.KeyBinds[i] & action) keys++;\r
b4fe3a4a 736 }\r
d524c827 737 }\r
738 return keys;\r
739}\r
740\r
1ca2ea4f 741static void draw_key_config(const me_bind_action *opts, int opt_cnt, int player_idx, int sel)\r
d524c827 742{\r
743 int x, y, tl_y = 40, i;\r
744\r
e11c5548 745 gp2x_pd_clone_buffer2();\r
d524c827 746 if (player_idx >= 0) {\r
a12e0116 747 text_out16(80, 20, "Player %i controls", player_idx + 1);\r
b4fe3a4a 748 x = 80;\r
d524c827 749 } else {\r
a12e0116 750 text_out16(80, 20, "Emulator controls");\r
d524c827 751 x = 40;\r
752 }\r
753\r
e5f426aa 754 menu_draw_selection(x - 16, tl_y + sel*10, (player_idx >= 0) ? 66 : 130);\r
a12e0116 755\r
d524c827 756 y = tl_y;\r
757 for (i = 0; i < opt_cnt; i++, y+=10)\r
a12e0116 758 text_out16(x, y, "%s : %s", opts[i].name, action_binds(player_idx, opts[i].mask));\r
d524c827 759\r
a12e0116 760 text_out16(x, y, "Done");\r
d524c827 761\r
762 if (sel < opt_cnt) {\r
a12e0116 763 text_out16(30, 180, "Press a button to bind/unbind");\r
764 text_out16(30, 190, "Use SELECT to clear");\r
765 text_out16(30, 200, "To bind UP/DOWN, hold SELECT");\r
766 text_out16(30, 210, "Select \"Done\" to exit");\r
d524c827 767 } else {\r
a12e0116 768 text_out16(30, 190, "Use Options -> Save cfg");\r
769 text_out16(30, 200, "to save controls");\r
770 text_out16(30, 210, "Press B or X to exit");\r
d524c827 771 }\r
a12e0116 772 menu_flip();\r
cc68a136 773}\r
774\r
1ca2ea4f 775static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_idx)\r
cc68a136 776{\r
d524c827 777 int joy = 0, sel = 0, menu_sel_max = opt_cnt, prev_select = 0, i;\r
cc68a136 778 unsigned long inp = 0;\r
779\r
780 for (;;)\r
781 {\r
d524c827 782 draw_key_config(opts, opt_cnt, player_idx, sel);\r
cc68a136 783 inp = wait_for_input_usbjoy(CONFIGURABLE_KEYS, &joy);\r
784 // printf("got %08lX from joy %i\n", inp, joy);\r
a39b7867 785 if (joy == 0)\r
786 {\r
d524c827 787 if (!(inp & GP2X_SELECT)) {\r
788 prev_select = 0;\r
789 if(inp & GP2X_UP ) { sel--; if (sel < 0) sel = menu_sel_max; continue; }\r
790 if(inp & GP2X_DOWN) { sel++; if (sel > menu_sel_max) sel = 0; continue; }\r
cc68a136 791 }\r
d524c827 792 if (sel >= opt_cnt) {\r
793 if (inp & (GP2X_B|GP2X_X)) break;\r
794 else continue;\r
795 }\r
796 // if we are here, we want to bind/unbind something\r
797 if ((inp & GP2X_SELECT) && !prev_select)\r
45499284 798 unbind_action(opts[sel].mask, player_idx, -1);\r
d524c827 799 prev_select = inp & GP2X_SELECT;\r
cc68a136 800 inp &= CONFIGURABLE_KEYS;\r
801 inp &= ~GP2X_SELECT;\r
cc68a136 802 for (i = 0; i < 32; i++)\r
803 if (inp & (1 << i)) {\r
b4fe3a4a 804 if (count_bound_keys(opts[sel].mask, player_idx, 0) >= 2)\r
d524c827 805 currentConfig.KeyBinds[i] &= ~opts[sel].mask; // allow to unbind only\r
806 else currentConfig.KeyBinds[i] ^= opts[sel].mask;\r
c9077ab4 807 if (player_idx >= 0 && (currentConfig.KeyBinds[i] & opts[sel].mask)) {\r
d524c827 808 currentConfig.KeyBinds[i] &= ~(3 << 16);\r
809 currentConfig.KeyBinds[i] |= player_idx << 16;\r
810 }\r
cc68a136 811 }\r
d524c827 812 }\r
813 else if (sel < opt_cnt)\r
814 {\r
cc68a136 815 for (i = 0; i < 32; i++)\r
816 if (inp & (1 << i)) {\r
45499284 817 int *bind = &currentConfig.JoyBinds[joy-1][i];\r
818 if ((*bind & opts[sel].mask) && (player_idx < 0 || player_idx == ((*bind>>16)&3)))\r
1ca2ea4f 819 *bind &= ~opts[sel].mask;\r
45499284 820 else {\r
821 // override\r
822 unbind_action(opts[sel].mask, player_idx, joy);\r
823 *bind = opts[sel].mask;\r
1ca2ea4f 824 if (player_idx > 0) *bind |= player_idx << 16;\r
d524c827 825 }\r
cc68a136 826 }\r
827 }\r
828 }\r
829}\r
830\r
831static void draw_kc_sel(int menu_sel)\r
832{\r
833 int tl_x = 25+40, tl_y = 60, y, i;\r
834 char joyname[36];\r
835\r
836 y = tl_y;\r
e11c5548 837 gp2x_pd_clone_buffer2();\r
e5f426aa 838 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 138);\r
cc68a136 839\r
a12e0116 840 text_out16(tl_x, y, "Player 1");\r
841 text_out16(tl_x, (y+=10), "Player 2");\r
842 text_out16(tl_x, (y+=10), "Emulator controls");\r
843 text_out16(tl_x, (y+=10), "Done");\r
cc68a136 844\r
845 tl_x = 25;\r
a12e0116 846 text_out16(tl_x, (y=110), "USB joys detected:");\r
cc68a136 847 if (num_of_joys > 0) {\r
848 for (i = 0; i < num_of_joys; i++) {\r
849 strncpy(joyname, joy_name(joys[i]), 33); joyname[33] = 0;\r
a12e0116 850 text_out16(tl_x, (y+=10), "%i: %s", i+1, joyname);\r
cc68a136 851 }\r
852 } else {\r
a12e0116 853 text_out16(tl_x, (y+=10), "none");\r
cc68a136 854 }\r
855\r
a12e0116 856 menu_flip();\r
cc68a136 857}\r
858\r
d524c827 859\r
d524c827 860// player2_flag, ?, ?, ?, ?, ?, ?, menu\r
861// "NEXT SAVE SLOT", "PREV SAVE SLOT", "SWITCH RENDERER", "SAVE STATE",\r
862// "LOAD STATE", "VOLUME UP", "VOLUME DOWN", "DONE"\r
1ca2ea4f 863me_bind_action emuctrl_actions[] =\r
d524c827 864{\r
d524c827 865 { "Load State ", 1<<28 },\r
866 { "Save State ", 1<<27 },\r
d524c827 867 { "Prev Save Slot ", 1<<25 },\r
868 { "Next Save Slot ", 1<<24 },\r
a12e0116 869 { "Switch Renderer", 1<<26 },\r
870 { "Volume Down ", 1<<30 },\r
871 { "Volume Up ", 1<<29 },\r
4a32f01f 872 { "Fast forward ", 1<<22 },\r
d524c827 873 { "Enter Menu ", 1<<23 },\r
1ca2ea4f 874 { NULL, 0 }\r
d524c827 875};\r
876\r
cc68a136 877static void kc_sel_loop(void)\r
878{\r
d524c827 879 int menu_sel = 3, menu_sel_max = 3;\r
cc68a136 880 unsigned long inp = 0;\r
602133e1 881 int is_6button = PicoOpt & POPT_6BTN_PAD;\r
cc68a136 882\r
d524c827 883 while (1)\r
cc68a136 884 {\r
885 draw_kc_sel(menu_sel);\r
886 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X);\r
d524c827 887 if (inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
888 if (inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
889 if (inp & GP2X_B) {\r
cc68a136 890 switch (menu_sel) {\r
1ca2ea4f 891 case 0: key_config_loop(me_ctrl_actions, is_6button ? 12 : 8, 0); return;\r
892 case 1: key_config_loop(me_ctrl_actions, is_6button ? 12 : 8, 1); return;\r
d524c827 893 case 2: key_config_loop(emuctrl_actions,\r
bdec53c9 894 sizeof(emuctrl_actions)/sizeof(emuctrl_actions[0]) - 1, -1); return;\r
eacee137 895 case 3: if (!rom_loaded) emu_WriteConfig(0); return;\r
cc68a136 896 default: return;\r
897 }\r
898 }\r
d524c827 899 if (inp & GP2X_X) return;\r
cc68a136 900 }\r
901}\r
902\r
903\r
bf098bc5 904// --------- sega/mega cd options ----------\r
905\r
4e8a534c 906menu_entry cdopt_entries[] =\r
bf098bc5 907{\r
58c86d00 908 { NULL, MB_NONE, MA_CDOPT_TESTBIOS_USA, NULL, 0, 0, 0, 1, 0 },\r
909 { NULL, MB_NONE, MA_CDOPT_TESTBIOS_EUR, NULL, 0, 0, 0, 1, 0 },\r
910 { NULL, MB_NONE, MA_CDOPT_TESTBIOS_JAP, NULL, 0, 0, 0, 1, 0 },\r
911 { "CD LEDs", MB_ONOFF, MA_CDOPT_LEDS, &currentConfig.EmuOpt, 0x0400, 0, 0, 1, 1 },\r
912 { "CDDA audio (using mp3s)", MB_ONOFF, MA_CDOPT_CDDA, &PicoOpt, 0x0800, 0, 0, 1, 1 },\r
913 { "PCM audio", MB_ONOFF, MA_CDOPT_PCM, &PicoOpt, 0x0400, 0, 0, 1, 1 },\r
914 { NULL, MB_NONE, MA_CDOPT_READAHEAD, NULL, 0, 0, 0, 1, 1 },\r
915 { "SaveRAM cart", MB_ONOFF, MA_CDOPT_SAVERAM, &PicoOpt, 0x8000, 0, 0, 1, 1 },\r
916 { "Scale/Rot. fx (slow)", MB_ONOFF, MA_CDOPT_SCALEROT_CHIP,&PicoOpt, 0x1000, 0, 0, 1, 1 },\r
917 { "Better sync (slow)", MB_ONOFF, MA_CDOPT_BETTER_SYNC, &PicoOpt, 0x2000, 0, 0, 1, 1 },\r
918 { "done", MB_NONE, MA_CDOPT_DONE, NULL, 0, 0, 0, 1, 0 },\r
4e8a534c 919};\r
920\r
58c86d00 921const int cdopt_entry_count = (sizeof(cdopt_entries) / sizeof(cdopt_entries[0]));\r
4e8a534c 922#define CDOPT_ENTRY_COUNT (sizeof(cdopt_entries) / sizeof(cdopt_entries[0]))\r
923\r
924\r
925struct bios_names_t\r
926{\r
927 char us[32], eu[32], jp[32];\r
928};\r
929\r
930static void menu_cdopt_cust_draw(const menu_entry *entry, int x, int y, void *param)\r
931{\r
932 struct bios_names_t *bios_names = param;\r
933 char ra_buff[16];\r
934\r
935 switch (entry->id)\r
936 {\r
a12e0116 937 case MA_CDOPT_TESTBIOS_USA: text_out16(x, y, "USA BIOS: %s", bios_names->us); break;\r
938 case MA_CDOPT_TESTBIOS_EUR: text_out16(x, y, "EUR BIOS: %s", bios_names->eu); break;\r
939 case MA_CDOPT_TESTBIOS_JAP: text_out16(x, y, "JAP BIOS: %s", bios_names->jp); break;\r
4e8a534c 940 case MA_CDOPT_READAHEAD:\r
941 if (PicoCDBuffers > 1) sprintf(ra_buff, "%5iK", PicoCDBuffers * 2);\r
942 else strcpy(ra_buff, " OFF");\r
a12e0116 943 text_out16(x, y, "ReadAhead buffer %s", ra_buff);\r
4e8a534c 944 break;\r
945 default:break;\r
946 }\r
947}\r
948\r
949static void draw_cd_menu_options(int menu_sel, struct bios_names_t *bios_names)\r
950{\r
951 int tl_x = 25, tl_y = 60;\r
952 menu_id selected_id;\r
0a051f55 953 char ra_buff[16];\r
954\r
955 if (PicoCDBuffers > 1) sprintf(ra_buff, "%5iK", PicoCDBuffers * 2);\r
956 else strcpy(ra_buff, " OFF");\r
bf098bc5 957\r
e11c5548 958 gp2x_pd_clone_buffer2();\r
959\r
e5f426aa 960 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 246);\r
bf098bc5 961\r
a12e0116 962 me_draw(cdopt_entries, CDOPT_ENTRY_COUNT, tl_x, tl_y, menu_cdopt_cust_draw, bios_names);\r
bf098bc5 963\r
4e8a534c 964 selected_id = me_index2id(cdopt_entries, CDOPT_ENTRY_COUNT, menu_sel);\r
965 if ((selected_id == MA_CDOPT_TESTBIOS_USA && strcmp(bios_names->us, "NOT FOUND")) ||\r
966 (selected_id == MA_CDOPT_TESTBIOS_EUR && strcmp(bios_names->eu, "NOT FOUND")) ||\r
967 (selected_id == MA_CDOPT_TESTBIOS_JAP && strcmp(bios_names->jp, "NOT FOUND")))\r
a12e0116 968 text_out16(tl_x, 210, "Press start to test selected BIOS");\r
bf098bc5 969\r
a12e0116 970 menu_flip();\r
bf098bc5 971}\r
972\r
973static void cd_menu_loop_options(void)\r
974{\r
aae35e84 975 static int menu_sel = 0;\r
976 int menu_sel_max = 10;\r
bf098bc5 977 unsigned long inp = 0;\r
4e8a534c 978 struct bios_names_t bios_names;\r
979 menu_id selected_id;\r
980 char *bios, *p;\r
bf098bc5 981\r
ea8c405f 982 if (emu_findBios(4, &bios)) { // US\r
bf098bc5 983 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
4e8a534c 984 strncpy(bios_names.us, p, sizeof(bios_names.us)); bios_names.us[sizeof(bios_names.us)-1] = 0;\r
985 } else strcpy(bios_names.us, "NOT FOUND");\r
bf098bc5 986\r
ea8c405f 987 if (emu_findBios(8, &bios)) { // EU\r
bf098bc5 988 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
4e8a534c 989 strncpy(bios_names.eu, p, sizeof(bios_names.eu)); bios_names.eu[sizeof(bios_names.eu)-1] = 0;\r
990 } else strcpy(bios_names.eu, "NOT FOUND");\r
bf098bc5 991\r
ea8c405f 992 if (emu_findBios(1, &bios)) { // JP\r
bf098bc5 993 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
4e8a534c 994 strncpy(bios_names.jp, p, sizeof(bios_names.jp)); bios_names.jp[sizeof(bios_names.jp)-1] = 0;\r
995 } else strcpy(bios_names.jp, "NOT FOUND");\r
bf098bc5 996\r
997 for(;;)\r
998 {\r
4e8a534c 999 draw_cd_menu_options(menu_sel, &bios_names);\r
bf098bc5 1000 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A|GP2X_START);\r
4e8a534c 1001 if (inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1002 if (inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
1003 selected_id = me_index2id(cdopt_entries, CDOPT_ENTRY_COUNT, menu_sel);\r
1004 if (inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choise\r
1005 if (!me_process(cdopt_entries, CDOPT_ENTRY_COUNT, selected_id, (inp&GP2X_RIGHT) ? 1 : 0) &&\r
1006 selected_id == MA_CDOPT_READAHEAD) {\r
1007 if (inp & GP2X_LEFT) {\r
1008 PicoCDBuffers >>= 1;\r
2d2247c2 1009 if (PicoCDBuffers < 2) PicoCDBuffers = 0;\r
4e8a534c 1010 } else {\r
2d2247c2 1011 if (PicoCDBuffers < 2) PicoCDBuffers = 2;\r
4e8a534c 1012 else PicoCDBuffers <<= 1;\r
1013 if (PicoCDBuffers > 8*1024) PicoCDBuffers = 8*1024; // 16M\r
1014 }\r
bf098bc5 1015 }\r
1016 }\r
4e8a534c 1017 if (inp & GP2X_B) { // toggleable options\r
1018 if (!me_process(cdopt_entries, CDOPT_ENTRY_COUNT, selected_id, 1) &&\r
1019 selected_id == MA_CDOPT_DONE) {\r
1020 return;\r
1021 }\r
1022 }\r
1023 if (inp & GP2X_START) { // BIOS testers\r
1024 switch (selected_id) {\r
1025 case MA_CDOPT_TESTBIOS_USA:\r
ea8c405f 1026 if (emu_findBios(4, &bios)) { // test US\r
bf098bc5 1027 strcpy(romFileName, bios);\r
1028 engineState = PGS_ReloadRom;\r
1029 return;\r
1030 }\r
1031 break;\r
4e8a534c 1032 case MA_CDOPT_TESTBIOS_EUR:\r
ea8c405f 1033 if (emu_findBios(8, &bios)) { // test EU\r
bf098bc5 1034 strcpy(romFileName, bios);\r
1035 engineState = PGS_ReloadRom;\r
1036 return;\r
1037 }\r
1038 break;\r
4e8a534c 1039 case MA_CDOPT_TESTBIOS_JAP:\r
ea8c405f 1040 if (emu_findBios(1, &bios)) { // test JP\r
bf098bc5 1041 strcpy(romFileName, bios);\r
1042 engineState = PGS_ReloadRom;\r
1043 return;\r
1044 }\r
1045 break;\r
4e8a534c 1046 default:\r
1047 break;\r
bf098bc5 1048 }\r
1049 }\r
4e8a534c 1050 if (inp & (GP2X_X|GP2X_A)) return;\r
bf098bc5 1051 }\r
1052}\r
1053\r
1054\r
1055// --------- advanced options ----------\r
1056\r
4e8a534c 1057menu_entry opt2_entries[] =\r
1058{\r
58c86d00 1059 { NULL, MB_NONE, MA_OPT2_GAMMA, NULL, 0, 0, 0, 1, 1 },\r
1060 { "A_SN's gamma curve", MB_ONOFF, MA_OPT2_A_SN_GAMMA, &currentConfig.EmuOpt, 0x1000, 0, 0, 1, 1 },\r
1061 { "Perfect vsync", MB_ONOFF, MA_OPT2_VSYNC, &currentConfig.EmuOpt, 0x2000, 0, 0, 1, 1 },\r
1ca2ea4f 1062 { "Emulate Z80", MB_ONOFF, MA_OPT2_ENABLE_Z80, &PicoOpt, 0x00004, 0, 0, 1, 1 },\r
1063 { "Emulate YM2612 (FM)", MB_ONOFF, MA_OPT2_ENABLE_YM2612, &PicoOpt, 0x00001, 0, 0, 1, 1 },\r
1064 { "Emulate SN76496 (PSG)", MB_ONOFF, MA_OPT2_ENABLE_SN76496,&PicoOpt, 0x00002, 0, 0, 1, 1 },\r
95dc5c5e 1065 { "Disable sprite limit", MB_ONOFF, MA_OPT2_NO_SPRITE_LIM, &PicoOpt, 0x40000, 0, 0, 1, 1 },\r
58c86d00 1066 { "gzip savestates", MB_ONOFF, MA_OPT2_GZIP_STATES, &currentConfig.EmuOpt, 0x0008, 0, 0, 1, 1 },\r
1067 { "Don't save last used ROM", MB_ONOFF, MA_OPT2_NO_LAST_ROM, &currentConfig.EmuOpt, 0x0020, 0, 0, 1, 1 },\r
1068 { "needs restart:", MB_NONE, MA_NONE, NULL, 0, 0, 0, 1, 0 },\r
1069 { "craigix's RAM timings", MB_ONOFF, MA_OPT2_RAMTIMINGS, &currentConfig.EmuOpt, 0x0100, 0, 0, 1, 1 },\r
1070 { NULL, MB_ONOFF, MA_OPT2_SQUIDGEHACK, &currentConfig.EmuOpt, 0x0010, 0, 0, 1, 1 },\r
1ca2ea4f 1071 { "SVP dynarec", MB_ONOFF, MA_OPT2_SVP_DYNAREC, &PicoOpt, 0x20000, 0, 0, 1, 1 },\r
58c86d00 1072 { "done", MB_NONE, MA_OPT2_DONE, NULL, 0, 0, 0, 1, 0 },\r
4e8a534c 1073};\r
1074\r
1075#define OPT2_ENTRY_COUNT (sizeof(opt2_entries) / sizeof(opt2_entries[0]))\r
58c86d00 1076const int opt2_entry_count = (sizeof(opt2_entries) / sizeof(opt2_entries[0]));\r
4e8a534c 1077\r
1078static void menu_opt2_cust_draw(const menu_entry *entry, int x, int y, void *param)\r
1079{\r
1080 if (entry->id == MA_OPT2_GAMMA)\r
a12e0116 1081 text_out16(x, y, "Gamma correction %i.%02i", currentConfig.gamma / 100, currentConfig.gamma%100);\r
4e8a534c 1082 else if (entry->id == MA_OPT2_SQUIDGEHACK)\r
58c86d00 1083 text_out16(x, y, "Squidgehack (now %s %s", mmuhack_status ? "active) " : "inactive)",\r
4e8a534c 1084 (currentConfig.EmuOpt&0x0010)?"ON":"OFF");\r
1085}\r
1086\r
1087\r
cc68a136 1088static void draw_amenu_options(int menu_sel)\r
1089{\r
4e8a534c 1090 int tl_x = 25, tl_y = 50;\r
cc68a136 1091\r
e11c5548 1092 gp2x_pd_clone_buffer2();\r
1093\r
e5f426aa 1094 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 252);\r
cc68a136 1095\r
a12e0116 1096 me_draw(opt2_entries, OPT2_ENTRY_COUNT, tl_x, tl_y, menu_opt2_cust_draw, NULL);\r
cc68a136 1097\r
a12e0116 1098 menu_flip();\r
cc68a136 1099}\r
1100\r
1101static void amenu_loop_options(void)\r
1102{\r
aae35e84 1103 static int menu_sel = 0;\r
4e8a534c 1104 int menu_sel_max;\r
cc68a136 1105 unsigned long inp = 0;\r
4e8a534c 1106 menu_id selected_id;\r
1107\r
1108 menu_sel_max = me_count_enabled(opt2_entries, OPT2_ENTRY_COUNT) - 1;\r
cc68a136 1109\r
1110 for(;;)\r
1111 {\r
1112 draw_amenu_options(menu_sel);\r
1113 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A);\r
4e8a534c 1114 if (inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1115 if (inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
1116 selected_id = me_index2id(opt2_entries, OPT2_ENTRY_COUNT, menu_sel);\r
1117 if (inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choise\r
1118 if (!me_process(opt2_entries, OPT2_ENTRY_COUNT, selected_id, (inp&GP2X_RIGHT) ? 1 : 0) &&\r
1119 selected_id == MA_OPT2_GAMMA) {\r
1120 while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) {\r
1121 currentConfig.gamma += (inp & GP2X_LEFT) ? -1 : 1;\r
1122 if (currentConfig.gamma < 1) currentConfig.gamma = 1;\r
1123 if (currentConfig.gamma > 300) currentConfig.gamma = 300;\r
1124 draw_amenu_options(menu_sel);\r
1125 usleep(18*1000);\r
1126 }\r
cc68a136 1127 }\r
1128 }\r
4e8a534c 1129 if (inp & GP2X_B) { // toggleable options\r
1130 if (!me_process(opt2_entries, OPT2_ENTRY_COUNT, selected_id, 1) &&\r
1131 selected_id == MA_OPT2_DONE) {\r
1132 return;\r
cc68a136 1133 }\r
1134 }\r
4e8a534c 1135 if (inp & (GP2X_X|GP2X_A)) return;\r
cc68a136 1136 }\r
1137}\r
1138\r
1139// -------------- options --------------\r
1140\r
4e8a534c 1141\r
1142menu_entry opt_entries[] =\r
1143{\r
58c86d00 1144 { NULL, MB_NONE, MA_OPT_RENDERER, NULL, 0, 0, 0, 1, 1 },\r
1145 { NULL, MB_RANGE, MA_OPT_SCALING, &currentConfig.scaling, 0, 0, 3, 1, 1 },\r
1146 { "Accurate timing (slower)", MB_ONOFF, MA_OPT_ACC_TIMING, &PicoOpt, 0x040, 0, 0, 1, 1 },\r
1147 { "Accurate sprites (slower)", MB_ONOFF, MA_OPT_ACC_SPRITES, &PicoOpt, 0x080, 0, 0, 1, 1 },\r
1148 { "Show FPS", MB_ONOFF, MA_OPT_SHOW_FPS, &currentConfig.EmuOpt, 0x002, 0, 0, 1, 1 },\r
1149 { NULL, MB_RANGE, MA_OPT_FRAMESKIP, &currentConfig.Frameskip, 0, -1, 16, 1, 1 },\r
1150 { "Enable sound", MB_ONOFF, MA_OPT_ENABLE_SOUND, &currentConfig.EmuOpt, 0x004, 0, 0, 1, 1 },\r
1151 { NULL, MB_NONE, MA_OPT_SOUND_QUALITY, NULL, 0, 0, 0, 1, 1 },\r
1152 { "Use ARM940 core for sound", MB_ONOFF, MA_OPT_ARM940_SOUND, &PicoOpt, 0x200, 0, 0, 1, 1 },\r
1153 { "6 button pad", MB_ONOFF, MA_OPT_6BUTTON_PAD, &PicoOpt, 0x020, 0, 0, 1, 1 },\r
1154 { NULL, MB_NONE, MA_OPT_REGION, NULL, 0, 0, 0, 1, 1 },\r
1155 { "Use SRAM/BRAM savestates", MB_ONOFF, MA_OPT_SRAM_STATES, &currentConfig.EmuOpt, 0x001, 0, 0, 1, 1 },\r
1156 { NULL, MB_NONE, MA_OPT_CONFIRM_STATES,NULL, 0, 0, 0, 1, 1 },\r
1157 { "Save slot", MB_RANGE, MA_OPT_SAVE_SLOT, &state_slot, 0, 0, 9, 1, 1 },\r
1158 { NULL, MB_NONE, MA_OPT_CPU_CLOCKS, NULL, 0, 0, 0, 1, 1 },\r
1159 { "[Sega/Mega CD options]", MB_NONE, MA_OPT_SCD_OPTS, NULL, 0, 0, 0, 1, 0 },\r
1160 { "[advanced options]", MB_NONE, MA_OPT_ADV_OPTS, NULL, 0, 0, 0, 1, 0 },\r
1161 { NULL, MB_NONE, MA_OPT_SAVECFG, NULL, 0, 0, 0, 1, 0 },\r
1162 { "Save cfg for current game only",MB_NONE,MA_OPT_SAVECFG_GAME,NULL, 0, 0, 0, 1, 0 },\r
1163 { NULL, MB_NONE, MA_OPT_LOADCFG, NULL, 0, 0, 0, 1, 0 },\r
4e8a534c 1164};\r
1165\r
1166#define OPT_ENTRY_COUNT (sizeof(opt_entries) / sizeof(opt_entries[0]))\r
58c86d00 1167const int opt_entry_count = OPT_ENTRY_COUNT;\r
cc68a136 1168\r
4e8a534c 1169\r
1170static void menu_opt_cust_draw(const menu_entry *entry, int x, int y, void *param)\r
cc68a136 1171{\r
4e8a534c 1172 char *str, str24[24];\r
1173\r
1174 switch (entry->id)\r
1175 {\r
1176 case MA_OPT_RENDERER:\r
602133e1 1177 if (PicoOpt & POPT_ALT_RENDERER)\r
4e8a534c 1178 str = " 8bit fast";\r
1179 else if (currentConfig.EmuOpt&0x80)\r
1180 str = "16bit accurate";\r
1181 else\r
1182 str = " 8bit accurate";\r
a12e0116 1183 text_out16(x, y, "Renderer: %s", str);\r
4e8a534c 1184 break;\r
1185 case MA_OPT_SCALING:\r
1186 switch (currentConfig.scaling) {\r
1187 default: str = " OFF"; break;\r
1188 case 1: str = "hw horizontal"; break;\r
1189 case 2: str = "hw horiz. + vert."; break;\r
1190 case 3: str = "sw horizontal"; break;\r
1191 }\r
a12e0116 1192 text_out16(x, y, "Scaling: %s", str);\r
4e8a534c 1193 break;\r
1194 case MA_OPT_FRAMESKIP:\r
1195 if (currentConfig.Frameskip < 0)\r
1196 strcpy(str24, "Auto");\r
1197 else sprintf(str24, "%i", currentConfig.Frameskip);\r
a12e0116 1198 text_out16(x, y, "Frameskip %s", str24);\r
4e8a534c 1199 break;\r
1200 case MA_OPT_SOUND_QUALITY:\r
602133e1 1201 str = (PicoOpt & POPT_EN_STEREO) ? "stereo" : "mono";\r
58c86d00 1202 text_out16(x, y, "Sound Quality: %5iHz %s", PsndRate, str);\r
4e8a534c 1203 break;\r
1204 case MA_OPT_REGION:\r
58c86d00 1205 text_out16(x, y, "Region: %s", me_region_name(PicoRegionOverride, PicoAutoRgnOrder));\r
4e8a534c 1206 break;\r
1207 case MA_OPT_CONFIRM_STATES:\r
1208 switch ((currentConfig.EmuOpt >> 9) & 5) {\r
1209 default: str = "OFF"; break;\r
1210 case 1: str = "writes"; break;\r
1211 case 4: str = "loads"; break;\r
1212 case 5: str = "both"; break;\r
1213 }\r
a12e0116 1214 text_out16(x, y, "Confirm savestate %s", str);\r
4e8a534c 1215 break;\r
1216 case MA_OPT_CPU_CLOCKS:\r
a12e0116 1217 text_out16(x, y, "GP2X CPU clocks %iMhz", currentConfig.CPUclock);\r
4e8a534c 1218 break;\r
1219 case MA_OPT_SAVECFG:\r
1220 str24[0] = 0;\r
1221 if (config_slot != 0) sprintf(str24, " (profile: %i)", config_slot);\r
a12e0116 1222 text_out16(x, y, "Save cfg as default%s", str24);\r
4e8a534c 1223 break;\r
1224 case MA_OPT_LOADCFG:\r
a12e0116 1225 text_out16(x, y, "Load cfg from profile %i", config_slot);\r
4e8a534c 1226 break;\r
1227 default:\r
1228 printf("%s: unimplemented (%i)\n", __FUNCTION__, entry->id);\r
1229 break;\r
46969540 1230 }\r
4e8a534c 1231}\r
1232\r
1233\r
1234\r
1235static void draw_menu_options(int menu_sel)\r
1236{\r
a12e0116 1237 int tl_x = 25, tl_y = 24;\r
cc68a136 1238\r
e11c5548 1239 gp2x_pd_clone_buffer2();\r
1240\r
e5f426aa 1241 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 284);\r
cc68a136 1242\r
a12e0116 1243 me_draw(opt_entries, OPT_ENTRY_COUNT, tl_x, tl_y, menu_opt_cust_draw, NULL);\r
cc68a136 1244\r
a12e0116 1245 menu_flip();\r
cc68a136 1246}\r
1247\r
1248static int sndrate_prevnext(int rate, int dir)\r
1249{\r
1250 int i, rates[] = { 8000, 11025, 16000, 22050, 44100 };\r
1251\r
1252 for (i = 0; i < 5; i++)\r
1253 if (rates[i] == rate) break;\r
1254\r
1255 i += dir ? 1 : -1;\r
1256 if (i > 4) return dir ? 44100 : 22050;\r
1257 if (i < 0) return dir ? 11025 : 8000;\r
1258 return rates[i];\r
1259}\r
1260\r
51a902ae 1261static void region_prevnext(int right)\r
1262{\r
1263 // jp_ntsc=1, jp_pal=2, usa=4, eu=8\r
1264 static int rgn_orders[] = { 0x148, 0x184, 0x814, 0x418, 0x841, 0x481 };\r
1265 int i;\r
1266 if (right) {\r
58c86d00 1267 if (!PicoRegionOverride) {\r
51a902ae 1268 for (i = 0; i < 6; i++)\r
1269 if (rgn_orders[i] == PicoAutoRgnOrder) break;\r
1270 if (i < 5) PicoAutoRgnOrder = rgn_orders[i+1];\r
58c86d00 1271 else PicoRegionOverride=1;\r
51a902ae 1272 }\r
58c86d00 1273 else PicoRegionOverride<<=1;\r
1274 if (PicoRegionOverride > 8) PicoRegionOverride = 8;\r
51a902ae 1275 } else {\r
58c86d00 1276 if (!PicoRegionOverride) {\r
51a902ae 1277 for (i = 0; i < 6; i++)\r
1278 if (rgn_orders[i] == PicoAutoRgnOrder) break;\r
1279 if (i > 0) PicoAutoRgnOrder = rgn_orders[i-1];\r
1280 }\r
58c86d00 1281 else PicoRegionOverride>>=1;\r
51a902ae 1282 }\r
1283}\r
1284\r
cc68a136 1285static void menu_options_save(void)\r
1286{\r
7d0143a2 1287 if (PicoRegionOverride) {\r
1288 // force setting possibly changed..\r
1289 Pico.m.pal = (PicoRegionOverride == 2 || PicoRegionOverride == 8) ? 1 : 0;\r
1290 }\r
602133e1 1291 if (!(PicoOpt & POPT_6BTN_PAD)) {\r
d524c827 1292 // unbind XYZ MODE, just in case\r
45499284 1293 unbind_action(0xf00, -1, -1);\r
cc68a136 1294 }\r
1295}\r
1296\r
bf098bc5 1297static int menu_loop_options(void)\r
cc68a136 1298{\r
aae35e84 1299 static int menu_sel = 0;\r
4e8a534c 1300 int menu_sel_max, ret;\r
cc68a136 1301 unsigned long inp = 0;\r
4e8a534c 1302 menu_id selected_id;\r
cc68a136 1303\r
eacee137 1304 me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_SAVECFG_GAME, rom_loaded);\r
4e8a534c 1305 me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_LOADCFG, config_slot != config_slot_current);\r
1306 menu_sel_max = me_count_enabled(opt_entries, OPT_ENTRY_COUNT) - 1;\r
d524c827 1307 if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;\r
4e8a534c 1308\r
1309 while (1)\r
cc68a136 1310 {\r
1311 draw_menu_options(menu_sel);\r
1312 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A);\r
4e8a534c 1313 if (inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1314 if (inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
1315 selected_id = me_index2id(opt_entries, OPT_ENTRY_COUNT, menu_sel);\r
58c86d00 1316 if (inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choice\r
4e8a534c 1317 if (!me_process(opt_entries, OPT_ENTRY_COUNT, selected_id, (inp&GP2X_RIGHT) ? 1 : 0)) {\r
1318 switch (selected_id) {\r
1319 case MA_OPT_RENDERER:\r
1320 if (inp & GP2X_LEFT) {\r
58c86d00 1321 if (PicoOpt&0x10) PicoOpt&= ~0x10;\r
4e8a534c 1322 else if (!(currentConfig.EmuOpt &0x80))currentConfig.EmuOpt |= 0x80;\r
1323 else if ( currentConfig.EmuOpt &0x80) break;\r
1324 } else {\r
58c86d00 1325 if (PicoOpt&0x10) break;\r
1326 else if (!(currentConfig.EmuOpt &0x80))PicoOpt|= 0x10;\r
4e8a534c 1327 else if ( currentConfig.EmuOpt &0x80) currentConfig.EmuOpt &= ~0x80;\r
1328 }\r
1329 break;\r
1330 case MA_OPT_SOUND_QUALITY:\r
58c86d00 1331 if ((inp & GP2X_RIGHT) && PsndRate == 44100 && !(PicoOpt&0x08)) {\r
1332 PsndRate = 8000; PicoOpt|= 0x08;\r
1333 } else if ((inp & GP2X_LEFT) && PsndRate == 8000 && (PicoOpt&0x08)) {\r
1334 PsndRate = 44100; PicoOpt&=~0x08;\r
1335 } else PsndRate = sndrate_prevnext(PsndRate, inp & GP2X_RIGHT);\r
4e8a534c 1336 break;\r
1337 case MA_OPT_REGION:\r
1338 region_prevnext(inp & GP2X_RIGHT);\r
1339 break;\r
1340 case MA_OPT_CONFIRM_STATES: {\r
1341 int n = ((currentConfig.EmuOpt>>9)&1) | ((currentConfig.EmuOpt>>10)&2);\r
1342 n += (inp & GP2X_LEFT) ? -1 : 1;\r
1343 if (n < 0) n = 0; else if (n > 3) n = 3;\r
1344 n |= n << 1; n &= ~2;\r
1345 currentConfig.EmuOpt &= ~0xa00;\r
1346 currentConfig.EmuOpt |= n << 9;\r
1347 break;\r
1348 }\r
1349 case MA_OPT_SAVE_SLOT:\r
1350 if (inp & GP2X_RIGHT) {\r
1351 state_slot++; if (state_slot > 9) state_slot = 0;\r
1352 } else {state_slot--; if (state_slot < 0) state_slot = 9;\r
1353 }\r
1354 break;\r
1355 case MA_OPT_CPU_CLOCKS:\r
1356 while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) {\r
1357 currentConfig.CPUclock += (inp & GP2X_LEFT) ? -1 : 1;\r
1358 if (currentConfig.CPUclock < 1) currentConfig.CPUclock = 1;\r
1359 draw_menu_options(menu_sel);\r
1360 usleep(50*1000);\r
1361 }\r
1362 break;\r
1363 case MA_OPT_SAVECFG:\r
1364 case MA_OPT_SAVECFG_GAME:\r
1365 case MA_OPT_LOADCFG:\r
1366 config_slot += (inp&GP2X_RIGHT) ? 1 : -1;\r
1367 if (config_slot > 9) config_slot = 0;\r
1368 if (config_slot < 0) config_slot = 9;\r
1369 me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_LOADCFG, config_slot != config_slot_current);\r
1370 menu_sel_max = me_count_enabled(opt_entries, OPT_ENTRY_COUNT) - 1;\r
1371 if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;\r
1372 break;\r
1373 default:\r
1374 //printf("%s: something unknown selected (%i)\n", __FUNCTION__, selected_id);\r
1375 break;\r
1376 }\r
1377 }\r
1378 }\r
1379 if (inp & GP2X_B) {\r
1380 if (!me_process(opt_entries, OPT_ENTRY_COUNT, selected_id, 1))\r
1381 {\r
1382 switch (selected_id)\r
1383 {\r
1384 case MA_OPT_SCD_OPTS:\r
1385 cd_menu_loop_options();\r
1386 if (engineState == PGS_ReloadRom)\r
1387 return 0; // test BIOS\r
1388 break;\r
1389 case MA_OPT_ADV_OPTS:\r
1390 amenu_loop_options();\r
1391 break;\r
1392 case MA_OPT_SAVECFG: // done (update and write)\r
1393 menu_options_save();\r
1394 if (emu_WriteConfig(0)) strcpy(menuErrorMsg, "config saved");\r
1395 else strcpy(menuErrorMsg, "failed to write config");\r
1396 return 1;\r
1397 case MA_OPT_SAVECFG_GAME: // done (update and write for current game)\r
1398 menu_options_save();\r
1399 if (emu_WriteConfig(1)) strcpy(menuErrorMsg, "config saved");\r
1400 else strcpy(menuErrorMsg, "failed to write config");\r
1401 return 1;\r
1402 case MA_OPT_LOADCFG:\r
d524c827 1403 ret = emu_ReadConfig(1, 1);\r
1404 if (!ret) ret = emu_ReadConfig(0, 1);\r
1405 if (ret) strcpy(menuErrorMsg, "config loaded");\r
4e8a534c 1406 else strcpy(menuErrorMsg, "failed to load config");\r
1407 return 1;\r
1408 default:\r
1409 //printf("%s: something unknown selected (%i)\n", __FUNCTION__, selected_id);\r
1410 break;\r
1411 }\r
cc68a136 1412 }\r
1413 }\r
51a902ae 1414 if(inp & (GP2X_X|GP2X_A)) {\r
cc68a136 1415 menu_options_save();\r
bf098bc5 1416 return 0; // done (update, no write)\r
cc68a136 1417 }\r
cc68a136 1418 }\r
1419}\r
1420\r
1421// -------------- credits --------------\r
1422\r
1423static void draw_menu_credits(void)\r
1424{\r
a12e0116 1425 int tl_x = 15, tl_y = 64, y;\r
e11c5548 1426 gp2x_pd_clone_buffer2();\r
cc68a136 1427\r
a12e0116 1428 text_out16(tl_x, 20, "PicoDrive v" VERSION " (c) notaz, 2006,2007");\r
cc68a136 1429 y = tl_y;\r
a12e0116 1430 text_out16(tl_x, y, "Credits:");\r
3ec29f01 1431 text_out16(tl_x, (y+=10), "fDave: Cyclone 68000 core,");\r
a12e0116 1432 text_out16(tl_x, (y+=10), " base code of PicoDrive");\r
1433 text_out16(tl_x, (y+=10), "Reesy & FluBBa: DrZ80 core");\r
1434 text_out16(tl_x, (y+=10), "MAME devs: YM2612 and SN76496 cores");\r
1435 text_out16(tl_x, (y+=10), "Charles MacDonald: Genesis hw docs");\r
1436 text_out16(tl_x, (y+=10), "Stephane Dallongeville:");\r
1437 text_out16(tl_x, (y+=10), " opensource Gens");\r
1438 text_out16(tl_x, (y+=10), "Haze: Genesis hw info");\r
1439 text_out16(tl_x, (y+=10), "rlyeh and others: minimal SDK");\r
1440 text_out16(tl_x, (y+=10), "Squidge: squidgehack");\r
1441 text_out16(tl_x, (y+=10), "Dzz: ARM940 sample");\r
1442 text_out16(tl_x, (y+=10), "GnoStiC / Puck2099: USB joystick");\r
1443 text_out16(tl_x, (y+=10), "craigix: GP2X hardware");\r
a4f0cc86 1444 text_out16(tl_x, (y+=10), "ketchupgun: skin design");\r
a12e0116 1445\r
1446 menu_flip();\r
cc68a136 1447}\r
1448\r
1449\r
1450// -------------- root menu --------------\r
1451\r
4e8a534c 1452menu_entry main_entries[] =\r
1453{\r
58c86d00 1454 { "Resume game", MB_NONE, MA_MAIN_RESUME_GAME, NULL, 0, 0, 0, 0, 0 },\r
1455 { "Save State", MB_NONE, MA_MAIN_SAVE_STATE, NULL, 0, 0, 0, 0, 0 },\r
1456 { "Load State", MB_NONE, MA_MAIN_LOAD_STATE, NULL, 0, 0, 0, 0, 0 },\r
1457 { "Reset game", MB_NONE, MA_MAIN_RESET_GAME, NULL, 0, 0, 0, 0, 0 },\r
1458 { "Load new ROM/ISO", MB_NONE, MA_MAIN_LOAD_ROM, NULL, 0, 0, 0, 1, 0 },\r
1459 { "Change options", MB_NONE, MA_MAIN_OPTIONS, NULL, 0, 0, 0, 1, 0 },\r
1460 { "Configure controls", MB_NONE, MA_MAIN_CONTROLS, NULL, 0, 0, 0, 1, 0 },\r
1461 { "Credits", MB_NONE, MA_MAIN_CREDITS, NULL, 0, 0, 0, 1, 0 },\r
1462 { "Patches / GameGenie",MB_NONE, MA_MAIN_PATCHES, NULL, 0, 0, 0, 0, 0 },\r
1463 { "Exit", MB_NONE, MA_MAIN_EXIT, NULL, 0, 0, 0, 1, 0 }\r
4e8a534c 1464};\r
1465\r
1466#define MAIN_ENTRY_COUNT (sizeof(main_entries) / sizeof(main_entries[0]))\r
1467\r
cc68a136 1468static void draw_menu_root(int menu_sel)\r
1469{\r
4e8a534c 1470 const int tl_x = 70, tl_y = 70;\r
1471\r
e11c5548 1472 gp2x_pd_clone_buffer2();\r
cc68a136 1473\r
a12e0116 1474 text_out16(tl_x, 20, "PicoDrive v" VERSION);\r
1475\r
e5f426aa 1476 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 146);\r
cc68a136 1477\r
4e8a534c 1478 me_draw(main_entries, MAIN_ENTRY_COUNT, tl_x, tl_y, NULL, NULL);\r
cc68a136 1479\r
cc68a136 1480 // error\r
a12e0116 1481 if (menuErrorMsg[0]) {\r
1482 memset((char *)gp2x_screen + 320*224*2, 0, 320*16*2);\r
1483 text_out16(5, 226, menuErrorMsg);\r
1484 }\r
1485 menu_flip();\r
cc68a136 1486}\r
1487\r
1488\r
1489static void menu_loop_root(void)\r
1490{\r
4e8a534c 1491 static int menu_sel = 0;\r
1492 int ret, menu_sel_max;\r
cc68a136 1493 unsigned long inp = 0;\r
cc68a136 1494\r
eacee137 1495 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_RESUME_GAME, rom_loaded);\r
1496 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_SAVE_STATE, rom_loaded);\r
1497 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_LOAD_STATE, rom_loaded);\r
1498 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_RESET_GAME, rom_loaded);\r
4e8a534c 1499 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_PATCHES, PicoPatches != NULL);\r
1500\r
1501 menu_sel_max = me_count_enabled(main_entries, MAIN_ENTRY_COUNT) - 1;\r
d524c827 1502 if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;\r
cc68a136 1503\r
2433f409 1504 /* make sure action buttons are not pressed on entering menu */\r
1505 draw_menu_root(menu_sel);\r
1506 while (gp2x_joystick_read(1) & (GP2X_B|GP2X_X|GP2X_SELECT)) usleep(50*1000);\r
1507\r
1508 for (;;)\r
cc68a136 1509 {\r
1510 draw_menu_root(menu_sel);\r
0af33fe0 1511 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X|GP2X_SELECT|GP2X_L|GP2X_R);\r
4e8a534c 1512 if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1513 if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
0af33fe0 1514 if((inp & (GP2X_L|GP2X_R)) == (GP2X_L|GP2X_R)) debug_menu_loop();\r
cc68a136 1515 if(inp &(GP2X_SELECT|GP2X_X)){\r
eacee137 1516 if (rom_loaded) {\r
cc68a136 1517 while (gp2x_joystick_read(1) & (GP2X_SELECT|GP2X_X)) usleep(50*1000); // wait until select is released\r
1518 engineState = PGS_Running;\r
1519 break;\r
1520 }\r
1521 }\r
4e8a534c 1522 if(inp & GP2X_B) {\r
1523 switch (me_index2id(main_entries, MAIN_ENTRY_COUNT, menu_sel))\r
1524 {\r
1525 case MA_MAIN_RESUME_GAME:\r
eacee137 1526 if (rom_loaded) {\r
721cd396 1527 while (gp2x_joystick_read(1) & GP2X_B) usleep(50*1000);\r
1528 engineState = PGS_Running;\r
1529 return;\r
1530 }\r
cc68a136 1531 break;\r
4e8a534c 1532 case MA_MAIN_SAVE_STATE:\r
eacee137 1533 if (rom_loaded) {\r
860c6322 1534 if(savestate_menu_loop(0))\r
cc68a136 1535 continue;\r
cc68a136 1536 engineState = PGS_Running;\r
1537 return;\r
1538 }\r
1539 break;\r
4e8a534c 1540 case MA_MAIN_LOAD_STATE:\r
eacee137 1541 if (rom_loaded) {\r
860c6322 1542 if(savestate_menu_loop(1))\r
cc68a136 1543 continue;\r
cc68a136 1544 engineState = PGS_Running;\r
1545 return;\r
1546 }\r
1547 break;\r
4e8a534c 1548 case MA_MAIN_RESET_GAME:\r
eacee137 1549 if (rom_loaded) {\r
cc68a136 1550 emu_ResetGame();\r
1551 engineState = PGS_Running;\r
1552 return;\r
1553 }\r
1554 break;\r
4e8a534c 1555 case MA_MAIN_LOAD_ROM:\r
a12e0116 1556 {\r
1557 char curr_path[PATH_MAX], *selfname;\r
1558 FILE *tstf;\r
1ca2ea4f 1559 if ( (tstf = fopen(lastRomFile, "rb")) )\r
a12e0116 1560 {\r
1561 fclose(tstf);\r
1ca2ea4f 1562 strcpy(curr_path, lastRomFile);\r
a12e0116 1563 }\r
1564 else\r
1565 getcwd(curr_path, PATH_MAX);\r
cc68a136 1566 selfname = romsel_loop(curr_path);\r
1567 if (selfname) {\r
1568 printf("selected file: %s\n", selfname);\r
cc68a136 1569 engineState = PGS_ReloadRom;\r
a12e0116 1570 return;\r
cc68a136 1571 }\r
a12e0116 1572 break;\r
1573 }\r
4e8a534c 1574 case MA_MAIN_OPTIONS:\r
bf098bc5 1575 ret = menu_loop_options();\r
1576 if (ret == 1) continue; // status update\r
1577 if (engineState == PGS_ReloadRom)\r
1578 return; // BIOS test\r
cc68a136 1579 break;\r
4e8a534c 1580 case MA_MAIN_CONTROLS:\r
cc68a136 1581 kc_sel_loop();\r
1582 break;\r
4e8a534c 1583 case MA_MAIN_CREDITS:\r
cc68a136 1584 draw_menu_credits();\r
1585 usleep(500*1000);\r
1586 inp = wait_for_input(GP2X_B|GP2X_X);\r
1587 break;\r
4e8a534c 1588 case MA_MAIN_EXIT:\r
cc68a136 1589 engineState = PGS_Quit;\r
1590 return;\r
4e8a534c 1591 case MA_MAIN_PATCHES:\r
eacee137 1592 if (rom_loaded && PicoPatches) {\r
b67ef287 1593 patches_menu_loop();\r
1594 PicoPatchApply();\r
1595 strcpy(menuErrorMsg, "Patches applied");\r
1596 continue;\r
1597 }\r
1598 break;\r
4e8a534c 1599 default:\r
1600 printf("%s: something unknown selected\n", __FUNCTION__);\r
1601 break;\r
cc68a136 1602 }\r
1603 }\r
1604 menuErrorMsg[0] = 0; // clear error msg\r
1605 }\r
1606}\r
1607\r
a4f0cc86 1608static void menu_darken_bg(void *dst, int pixels, int darker)\r
cc68a136 1609{\r
a12e0116 1610 unsigned int *screen = dst;\r
1611 pixels /= 2;\r
a4f0cc86 1612 if (darker)\r
a12e0116 1613 {\r
a4f0cc86 1614 while (pixels--)\r
1615 {\r
1616 unsigned int p = *screen;\r
1617 *screen++ = ((p&0xf79ef79e)>>1) - ((p&0xc618c618)>>3);\r
1618 }\r
1619 }\r
1620 else\r
1621 {\r
1622 while (pixels--)\r
1623 {\r
1624 unsigned int p = *screen;\r
1625 *screen++ = (p&0xf79ef79e)>>1;\r
1626 }\r
a12e0116 1627 }\r
1628}\r
e11c5548 1629\r
a12e0116 1630static void menu_prepare_bg(int use_game_bg)\r
1631{\r
1632 if (use_game_bg)\r
1633 {\r
1634 // darken the active framebuffer\r
1635 memset(gp2x_screen, 0, 320*8*2);\r
a4f0cc86 1636 menu_darken_bg((char *)gp2x_screen + 320*8*2, 320*224, 1);\r
a12e0116 1637 memset((char *)gp2x_screen + 320*232*2, 0, 320*8*2);\r
1638 }\r
1639 else\r
1640 {\r
1641 // should really only happen once, on startup..\r
1642 readpng(gp2x_screen, "skin/background.png", READPNG_BG);\r
860c6322 1643 }\r
cc68a136 1644\r
a12e0116 1645 // copy to buffer2\r
1646 gp2x_memcpy_buffers((1<<2), gp2x_screen, 0, 320*240*2);\r
860c6322 1647}\r
1648\r
1649static void menu_gfx_prepare(void)\r
1650{\r
eacee137 1651 menu_prepare_bg(rom_loaded);\r
860c6322 1652\r
a12e0116 1653 // switch to 16bpp\r
1654 gp2x_video_changemode2(16);\r
2433f409 1655 gp2x_video_RGB_setscaling(0, 320, 240);\r
a12e0116 1656 menu_flip();\r
e11c5548 1657}\r
1658\r
1659\r
1660void menu_loop(void)\r
1661{\r
1662 menu_gfx_prepare();\r
cc68a136 1663\r
1664 menu_loop_root();\r
1665\r
1666 menuErrorMsg[0] = 0;\r
1667}\r
721cd396 1668\r
1669\r
1670// --------- CD tray close menu ----------\r
1671\r
1672static void draw_menu_tray(int menu_sel)\r
1673{\r
1674 int tl_x = 70, tl_y = 90, y;\r
a12e0116 1675 memset(gp2x_screen, 0, 320*240*2);\r
721cd396 1676\r
a12e0116 1677 text_out16(tl_x, 20, "The unit is about to");\r
1678 text_out16(tl_x, 30, "close the CD tray.");\r
721cd396 1679\r
1680 y = tl_y;\r
a12e0116 1681 text_out16(tl_x, y, "Load new CD image");\r
1682 text_out16(tl_x, (y+=10), "Insert nothing");\r
721cd396 1683\r
1684 // draw cursor\r
a12e0116 1685 text_out16(tl_x - 16, tl_y + menu_sel*10, ">");\r
721cd396 1686 // error\r
a12e0116 1687 if (menuErrorMsg[0]) text_out16(5, 226, menuErrorMsg);\r
1688 menu_flip();\r
721cd396 1689}\r
1690\r
1691\r
1692int menu_loop_tray(void)\r
1693{\r
1694 int menu_sel = 0, menu_sel_max = 1;\r
1695 unsigned long inp = 0;\r
1696 char curr_path[PATH_MAX], *selfname;\r
1697 FILE *tstf;\r
1698\r
e5f426aa 1699 gp2x_memset_all_buffers(0, 0, 320*240*2);\r
721cd396 1700 menu_gfx_prepare();\r
1701\r
1ca2ea4f 1702 if ( (tstf = fopen(lastRomFile, "rb")) )\r
721cd396 1703 {\r
1704 fclose(tstf);\r
1ca2ea4f 1705 strcpy(curr_path, lastRomFile);\r
721cd396 1706 }\r
1707 else\r
1708 {\r
1709 getcwd(curr_path, PATH_MAX);\r
1710 }\r
1711\r
1712 /* make sure action buttons are not pressed on entering menu */\r
1713 draw_menu_tray(menu_sel);\r
1714 while (gp2x_joystick_read(1) & GP2X_B) usleep(50*1000);\r
1715\r
1716 for (;;)\r
1717 {\r
1718 draw_menu_tray(menu_sel);\r
1719 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B);\r
1720 if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1721 if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
1722 if(inp & GP2X_B ) {\r
1723 switch (menu_sel) {\r
1724 case 0: // select image\r
1725 selfname = romsel_loop(curr_path);\r
1726 if (selfname) {\r
1727 int ret = -1, cd_type;\r
ea8c405f 1728 cd_type = emu_cdCheck(NULL);\r
721cd396 1729 if (cd_type > 0)\r
1730 ret = Insert_CD(romFileName, cd_type == 2);\r
1731 if (ret != 0) {\r
1732 sprintf(menuErrorMsg, "Load failed, invalid CD image?");\r
1733 printf("%s\n", menuErrorMsg);\r
1734 continue;\r
1735 }\r
1736 engineState = PGS_RestartRun;\r
1737 return 1;\r
1738 }\r
1739 break;\r
1740 case 1: // insert nothing\r
1741 engineState = PGS_RestartRun;\r
1742 return 0;\r
1743 }\r
1744 }\r
1745 menuErrorMsg[0] = 0; // clear error msg\r
1746 }\r
1747}\r
1748\r
1749\r