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