bugfix, sprites adjustment
[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
053fd9b4 28#error "need d_type for file browser"\r
cc68a136 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
053fd9b4 70 if (wait > 6 && (ret&(GP2X_UP|GP2X_LEFT|GP2X_DOWN|GP2X_RIGHT|GP2X_L|GP2X_R)))\r
38576063 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
fbc65db7 435void PicoDrawShowSpriteStats(unsigned short *screen);\r
436void PicoDrawShowPalette(unsigned short *screen);\r
0af33fe0 437\r
fbc65db7 438static void draw_main_debug(void)\r
0af33fe0 439{\r
440 char *p, *str = debugString();\r
441 int len, line;\r
442\r
443 gp2x_pd_clone_buffer2();\r
444\r
445 p = str;\r
446 for (line = 0; line < 24; line++)\r
447 {\r
448 while (*p && *p != '\n') p++;\r
449 len = p - str;\r
450 if (len > 55) len = 55;\r
a12e0116 451 smalltext_out16_lim(1, line*10, str, 0xffff, len);\r
0af33fe0 452 if (*p == 0) break;\r
453 p++; str = p;\r
454 }\r
fbc65db7 455}\r
456\r
457static void draw_frame_debug(void)\r
458{\r
459 char layer_str[48] = "layers: ";\r
460 if (PicoDrawMask & PDRAW_LAYERB_ON) memcpy(layer_str + 8, "B", 1);\r
461 if (PicoDrawMask & PDRAW_LAYERA_ON) memcpy(layer_str + 10, "A", 1);\r
462 if (PicoDrawMask & PDRAW_SPRITES_LOW_ON) memcpy(layer_str + 12, "spr_lo", 6);\r
463 if (PicoDrawMask & PDRAW_SPRITES_HI_ON) memcpy(layer_str + 19, "spr_hi", 6);\r
464\r
465 memset(gp2x_screen, 0, 320*240*2);\r
0fc0e241 466 emu_forcedFrame(0);\r
fbc65db7 467 smalltext_out16(4, 232, layer_str, 0xffff);\r
0af33fe0 468}\r
469\r
470static void debug_menu_loop(void)\r
471{\r
fbc65db7 472 int inp, mode = 0;\r
473\r
474 while (1)\r
475 {\r
476 switch (mode)\r
477 {\r
478 case 0: draw_main_debug(); break;\r
479 case 1: draw_frame_debug(); break;\r
480 case 2: PicoDrawShowSpriteStats(gp2x_screen); break;\r
481 case 3: PicoDrawShowPalette(gp2x_screen); break;\r
482 }\r
483 menu_flip();\r
484\r
485 inp = wait_for_input(GP2X_B|GP2X_X|GP2X_L|GP2X_R|GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT);\r
486 if (inp & (GP2X_B|GP2X_X)) return;\r
487 if (inp & GP2X_L) { mode--; if (mode < 0) mode = 3; }\r
488 if (inp & GP2X_R) { mode++; if (mode > 3) mode = 0; }\r
489 if (mode == 1) {\r
490 if (inp & GP2X_LEFT) PicoDrawMask ^= PDRAW_LAYERB_ON;\r
491 if (inp & GP2X_RIGHT) PicoDrawMask ^= PDRAW_LAYERA_ON;\r
492 if (inp & GP2X_DOWN) PicoDrawMask ^= PDRAW_SPRITES_LOW_ON;\r
493 if (inp & GP2X_UP) PicoDrawMask ^= PDRAW_SPRITES_HI_ON;\r
494 }\r
495 }\r
0af33fe0 496}\r
497\r
b67ef287 498// ------------ patch/gg menu ------------\r
499\r
500static void draw_patchlist(int sel)\r
501{\r
a12e0116 502 int start, i, pos, active;\r
b67ef287 503\r
504 start = 12 - sel;\r
505\r
506 gp2x_pd_clone_buffer2();\r
507\r
508 for (i = 0; i < PicoPatchCount; i++) {\r
509 pos = start + i;\r
510 if (pos < 0) continue;\r
511 if (pos > 23) break;\r
a12e0116 512 active = PicoPatches[i].active;\r
513 smalltext_out16_lim(14, pos*10, active ? "ON " : "OFF", active ? 0xfff6 : 0xffff, 3);\r
514 smalltext_out16_lim(14+6*4, pos*10, PicoPatches[i].name, active ? 0xfff6 : 0xffff, 53-6);\r
b67ef287 515 }\r
516 pos = start + i;\r
a12e0116 517 if (pos < 24) smalltext_out16_lim(14, pos*10, "done", 0xffff, 4);\r
b67ef287 518\r
a12e0116 519 text_out16(5, 120, ">");\r
520 menu_flip();\r
b67ef287 521}\r
522\r
523\r
0af33fe0 524static void patches_menu_loop(void)\r
b67ef287 525{\r
526 int menu_sel = 0;\r
527 unsigned long inp = 0;\r
528\r
529 for(;;)\r
530 {\r
531 draw_patchlist(menu_sel);\r
532 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_L|GP2X_R|GP2X_B|GP2X_X);\r
533 if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = PicoPatchCount; }\r
534 if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > PicoPatchCount) menu_sel = 0; }\r
535 if(inp &(GP2X_LEFT|GP2X_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }\r
536 if(inp &(GP2X_RIGHT|GP2X_R)) { menu_sel+=10; if (menu_sel > PicoPatchCount) menu_sel = PicoPatchCount; }\r
537 if(inp & GP2X_B) { // action\r
538 if (menu_sel < PicoPatchCount)\r
539 PicoPatches[menu_sel].active = !PicoPatches[menu_sel].active;\r
540 else return;\r
541 }\r
542 if(inp & GP2X_X) return;\r
543 }\r
544\r
545}\r
546\r
860c6322 547// ------------ savestate loader ------------\r
548\r
860c6322 549static int state_slot_flags = 0;\r
550\r
551static void state_check_slots(void)\r
552{\r
553 int slot;\r
554\r
555 state_slot_flags = 0;\r
556\r
557 for (slot = 0; slot < 10; slot++)\r
558 {\r
ea8c405f 559 if (emu_checkSaveFile(slot))\r
860c6322 560 {\r
561 state_slot_flags |= 1 << slot;\r
562 }\r
563 }\r
564}\r
565\r
566static void draw_savestate_bg(int slot)\r
567{\r
568 struct PicoVideo tmp_pv;\r
569 unsigned short tmp_cram[0x40];\r
570 unsigned short tmp_vsram[0x40];\r
571 void *tmp_vram, *file;\r
572 char *fname;\r
573\r
574 fname = emu_GetSaveFName(1, 0, slot);\r
575 if (!fname) return;\r
576\r
577 tmp_vram = malloc(sizeof(Pico.vram));\r
578 if (tmp_vram == NULL) return;\r
579\r
580 memcpy(tmp_vram, Pico.vram, sizeof(Pico.vram));\r
581 memcpy(tmp_cram, Pico.cram, sizeof(Pico.cram));\r
582 memcpy(tmp_vsram, Pico.vsram, sizeof(Pico.vsram));\r
583 memcpy(&tmp_pv, &Pico.video, sizeof(Pico.video));\r
584\r
585 if (strcmp(fname + strlen(fname) - 3, ".gz") == 0) {\r
586 file = gzopen(fname, "rb");\r
ea8c405f 587 emu_setSaveStateCbs(1);\r
860c6322 588 } else {\r
589 file = fopen(fname, "rb");\r
ea8c405f 590 emu_setSaveStateCbs(0);\r
860c6322 591 }\r
592\r
593 if (file) {\r
602133e1 594 if (PicoAHW & PAHW_MCD) {\r
860c6322 595 PicoCdLoadStateGfx(file);\r
596 } else {\r
597 areaSeek(file, 0x10020, SEEK_SET); // skip header and RAM in state file\r
598 areaRead(Pico.vram, 1, sizeof(Pico.vram), file);\r
599 areaSeek(file, 0x2000, SEEK_CUR);\r
600 areaRead(Pico.cram, 1, sizeof(Pico.cram), file);\r
601 areaRead(Pico.vsram, 1, sizeof(Pico.vsram), file);\r
602 areaSeek(file, 0x221a0, SEEK_SET);\r
603 areaRead(&Pico.video, 1, sizeof(Pico.video), file);\r
604 }\r
605 areaClose(file);\r
606 }\r
607\r
0fc0e241 608 emu_forcedFrame(POPT_EN_SOFTSCALE);\r
a12e0116 609 menu_prepare_bg(1);\r
860c6322 610\r
611 memcpy(Pico.vram, tmp_vram, sizeof(Pico.vram));\r
612 memcpy(Pico.cram, tmp_cram, sizeof(Pico.cram));\r
613 memcpy(Pico.vsram, tmp_vsram, sizeof(Pico.vsram));\r
614 memcpy(&Pico.video, &tmp_pv, sizeof(Pico.video));\r
615 free(tmp_vram);\r
616}\r
617\r
618static void draw_savestate_menu(int menu_sel, int is_loading)\r
619{\r
620 int tl_x = 25, tl_y = 60, y, i;\r
621\r
622 if (state_slot_flags & (1 << menu_sel))\r
623 draw_savestate_bg(menu_sel);\r
624 gp2x_pd_clone_buffer2();\r
625\r
a12e0116 626 text_out16(tl_x, 30, is_loading ? "Load state" : "Save state");\r
627\r
e5f426aa 628 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 108);\r
860c6322 629\r
630 /* draw all 10 slots */\r
631 y = tl_y;\r
632 for (i = 0; i < 10; i++, y+=10)\r
633 {\r
a12e0116 634 text_out16(tl_x, y, "SLOT %i (%s)", i, (state_slot_flags & (1 << i)) ? "USED" : "free");\r
860c6322 635 }\r
a12e0116 636 text_out16(tl_x, y, "back");\r
860c6322 637\r
a12e0116 638 menu_flip();\r
860c6322 639}\r
640\r
641static int savestate_menu_loop(int is_loading)\r
642{\r
aae35e84 643 static int menu_sel = 10;\r
644 int menu_sel_max = 10;\r
860c6322 645 unsigned long inp = 0;\r
646\r
647 state_check_slots();\r
648\r
649 for(;;)\r
650 {\r
651 draw_savestate_menu(menu_sel, is_loading);\r
652 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X);\r
653 if(inp & GP2X_UP ) {\r
654 do {\r
655 menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max;\r
656 } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading);\r
657 }\r
658 if(inp & GP2X_DOWN) {\r
659 do {\r
660 menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0;\r
661 } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading);\r
662 }\r
663 if(inp & GP2X_B) { // save/load\r
664 if (menu_sel < 10) {\r
665 state_slot = menu_sel;\r
666 if (emu_SaveLoadGame(is_loading, 0)) {\r
667 strcpy(menuErrorMsg, is_loading ? "Load failed" : "Save failed");\r
668 return 1;\r
669 }\r
670 return 0;\r
671 } else return 1;\r
672 }\r
673 if(inp & GP2X_X) return 1;\r
674 }\r
675}\r
676\r
cc68a136 677// -------------- key config --------------\r
678\r
679static char *usb_joy_key_name(int joy, int num)\r
680{\r
681 static char name[16];\r
682 switch (num)\r
683 {\r
684 case 0: sprintf(name, "Joy%i UP", joy); break;\r
685 case 1: sprintf(name, "Joy%i DOWN", joy); break;\r
686 case 2: sprintf(name, "Joy%i LEFT", joy); break;\r
687 case 3: sprintf(name, "Joy%i RIGHT", joy); break;\r
688 default:sprintf(name, "Joy%i b%i", joy, num-3); break;\r
689 }\r
690 return name;\r
691}\r
692\r
d524c827 693static char *action_binds(int player_idx, int action_mask)\r
cc68a136 694{\r
d524c827 695 static char strkeys[32*5];\r
cc68a136 696 int joy, i;\r
697\r
698 strkeys[0] = 0;\r
d524c827 699 for (i = 0; i < 32; i++) // i is key index\r
cc68a136 700 {\r
d524c827 701 if (currentConfig.KeyBinds[i] & action_mask)\r
cc68a136 702 {\r
d524c827 703 if (player_idx >= 0 && ((currentConfig.KeyBinds[i] >> 16) & 3) != player_idx) continue;\r
1ca2ea4f 704 if (strkeys[0]) { strcat(strkeys, " + "); strcat(strkeys, keyNames[i]); break; }\r
705 else strcpy(strkeys, keyNames[i]);\r
cc68a136 706 }\r
707 }\r
708 for (joy = 0; joy < num_of_joys; joy++)\r
709 {\r
710 for (i = 0; i < 32; i++)\r
711 {\r
d524c827 712 if (currentConfig.JoyBinds[joy][i] & action_mask)\r
cc68a136 713 {\r
d524c827 714 if (player_idx >= 0 && ((currentConfig.JoyBinds[joy][i] >> 16) & 3) != player_idx) continue;\r
cc68a136 715 if (strkeys[0]) {\r
716 strcat(strkeys, ", "); strcat(strkeys, usb_joy_key_name(joy + 1, i));\r
717 break;\r
718 }\r
719 else strcpy(strkeys, usb_joy_key_name(joy + 1, i));\r
720 }\r
721 }\r
722 }\r
723\r
45499284 724 // limit..\r
725 strkeys[20] = 0;\r
726\r
d524c827 727 return strkeys;\r
728}\r
729\r
45499284 730static void unbind_action(int action, int pl_idx, int joy)\r
d524c827 731{\r
732 int i, u;\r
733\r
45499284 734 if (joy <= 0)\r
735 {\r
736 for (i = 0; i < 32; i++) {\r
737 if (pl_idx >= 0 && (currentConfig.KeyBinds[i]&0x30000) != (pl_idx<<16)) continue;\r
738 currentConfig.KeyBinds[i] &= ~action;\r
739 }\r
b4fe3a4a 740 }\r
45499284 741 if (joy < 0)\r
742 {\r
743 for (u = 0; u < 4; u++)\r
744 for (i = 0; i < 32; i++) {\r
745 if (pl_idx >= 0 && (currentConfig.JoyBinds[u][i]&0x30000) != (pl_idx<<16)) continue;\r
746 currentConfig.JoyBinds[u][i] &= ~action;\r
747 }\r
748 }\r
749 else if (joy > 0)\r
750 {\r
b4fe3a4a 751 for (i = 0; i < 32; i++) {\r
45499284 752 if (pl_idx >= 0 && (currentConfig.JoyBinds[joy-1][i]&0x30000) != (pl_idx<<16)) continue;\r
753 currentConfig.JoyBinds[joy-1][i] &= ~action;\r
b4fe3a4a 754 }\r
45499284 755 }\r
d524c827 756}\r
757\r
b4fe3a4a 758static int count_bound_keys(int action, int pl_idx, int joy)\r
d524c827 759{\r
760 int i, keys = 0;\r
761\r
762 if (joy)\r
763 {\r
b4fe3a4a 764 for (i = 0; i < 32; i++) {\r
765 if (pl_idx >= 0 && (currentConfig.JoyBinds[joy-1][i]&0x30000) != (pl_idx<<16)) continue;\r
d524c827 766 if (currentConfig.JoyBinds[joy-1][i] & action) keys++;\r
b4fe3a4a 767 }\r
d524c827 768 }\r
769 else\r
770 {\r
b4fe3a4a 771 for (i = 0; i < 32; i++) {\r
772 if (pl_idx >= 0 && (currentConfig.KeyBinds[i]&0x30000) != (pl_idx<<16)) continue;\r
d524c827 773 if (currentConfig.KeyBinds[i] & action) keys++;\r
b4fe3a4a 774 }\r
d524c827 775 }\r
776 return keys;\r
777}\r
778\r
1ca2ea4f 779static void draw_key_config(const me_bind_action *opts, int opt_cnt, int player_idx, int sel)\r
d524c827 780{\r
781 int x, y, tl_y = 40, i;\r
782\r
e11c5548 783 gp2x_pd_clone_buffer2();\r
d524c827 784 if (player_idx >= 0) {\r
a12e0116 785 text_out16(80, 20, "Player %i controls", player_idx + 1);\r
b4fe3a4a 786 x = 80;\r
d524c827 787 } else {\r
a12e0116 788 text_out16(80, 20, "Emulator controls");\r
d524c827 789 x = 40;\r
790 }\r
791\r
406c96c5 792 menu_draw_selection(x - 16, tl_y + sel*10, (player_idx >= 0) ? 66 : 140);\r
a12e0116 793\r
d524c827 794 y = tl_y;\r
795 for (i = 0; i < opt_cnt; i++, y+=10)\r
a12e0116 796 text_out16(x, y, "%s : %s", opts[i].name, action_binds(player_idx, opts[i].mask));\r
d524c827 797\r
a12e0116 798 text_out16(x, y, "Done");\r
d524c827 799\r
800 if (sel < opt_cnt) {\r
a12e0116 801 text_out16(30, 180, "Press a button to bind/unbind");\r
802 text_out16(30, 190, "Use SELECT to clear");\r
803 text_out16(30, 200, "To bind UP/DOWN, hold SELECT");\r
804 text_out16(30, 210, "Select \"Done\" to exit");\r
d524c827 805 } else {\r
a12e0116 806 text_out16(30, 190, "Use Options -> Save cfg");\r
807 text_out16(30, 200, "to save controls");\r
808 text_out16(30, 210, "Press B or X to exit");\r
d524c827 809 }\r
a12e0116 810 menu_flip();\r
cc68a136 811}\r
812\r
1ca2ea4f 813static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_idx)\r
cc68a136 814{\r
d524c827 815 int joy = 0, sel = 0, menu_sel_max = opt_cnt, prev_select = 0, i;\r
cc68a136 816 unsigned long inp = 0;\r
817\r
818 for (;;)\r
819 {\r
d524c827 820 draw_key_config(opts, opt_cnt, player_idx, sel);\r
cc68a136 821 inp = wait_for_input_usbjoy(CONFIGURABLE_KEYS, &joy);\r
822 // printf("got %08lX from joy %i\n", inp, joy);\r
a39b7867 823 if (joy == 0)\r
824 {\r
d524c827 825 if (!(inp & GP2X_SELECT)) {\r
826 prev_select = 0;\r
827 if(inp & GP2X_UP ) { sel--; if (sel < 0) sel = menu_sel_max; continue; }\r
828 if(inp & GP2X_DOWN) { sel++; if (sel > menu_sel_max) sel = 0; continue; }\r
cc68a136 829 }\r
d524c827 830 if (sel >= opt_cnt) {\r
831 if (inp & (GP2X_B|GP2X_X)) break;\r
832 else continue;\r
833 }\r
834 // if we are here, we want to bind/unbind something\r
835 if ((inp & GP2X_SELECT) && !prev_select)\r
45499284 836 unbind_action(opts[sel].mask, player_idx, -1);\r
d524c827 837 prev_select = inp & GP2X_SELECT;\r
cc68a136 838 inp &= CONFIGURABLE_KEYS;\r
839 inp &= ~GP2X_SELECT;\r
cc68a136 840 for (i = 0; i < 32; i++)\r
841 if (inp & (1 << i)) {\r
b4fe3a4a 842 if (count_bound_keys(opts[sel].mask, player_idx, 0) >= 2)\r
d524c827 843 currentConfig.KeyBinds[i] &= ~opts[sel].mask; // allow to unbind only\r
844 else currentConfig.KeyBinds[i] ^= opts[sel].mask;\r
c9077ab4 845 if (player_idx >= 0 && (currentConfig.KeyBinds[i] & opts[sel].mask)) {\r
d524c827 846 currentConfig.KeyBinds[i] &= ~(3 << 16);\r
847 currentConfig.KeyBinds[i] |= player_idx << 16;\r
848 }\r
cc68a136 849 }\r
d524c827 850 }\r
851 else if (sel < opt_cnt)\r
852 {\r
cc68a136 853 for (i = 0; i < 32; i++)\r
854 if (inp & (1 << i)) {\r
45499284 855 int *bind = &currentConfig.JoyBinds[joy-1][i];\r
856 if ((*bind & opts[sel].mask) && (player_idx < 0 || player_idx == ((*bind>>16)&3)))\r
1ca2ea4f 857 *bind &= ~opts[sel].mask;\r
45499284 858 else {\r
859 // override\r
860 unbind_action(opts[sel].mask, player_idx, joy);\r
861 *bind = opts[sel].mask;\r
1ca2ea4f 862 if (player_idx > 0) *bind |= player_idx << 16;\r
d524c827 863 }\r
cc68a136 864 }\r
865 }\r
866 }\r
867}\r
868\r
869static void draw_kc_sel(int menu_sel)\r
870{\r
871 int tl_x = 25+40, tl_y = 60, y, i;\r
872 char joyname[36];\r
873\r
874 y = tl_y;\r
e11c5548 875 gp2x_pd_clone_buffer2();\r
e5f426aa 876 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 138);\r
cc68a136 877\r
a12e0116 878 text_out16(tl_x, y, "Player 1");\r
879 text_out16(tl_x, (y+=10), "Player 2");\r
880 text_out16(tl_x, (y+=10), "Emulator controls");\r
881 text_out16(tl_x, (y+=10), "Done");\r
cc68a136 882\r
883 tl_x = 25;\r
a12e0116 884 text_out16(tl_x, (y=110), "USB joys detected:");\r
cc68a136 885 if (num_of_joys > 0) {\r
886 for (i = 0; i < num_of_joys; i++) {\r
887 strncpy(joyname, joy_name(joys[i]), 33); joyname[33] = 0;\r
a12e0116 888 text_out16(tl_x, (y+=10), "%i: %s", i+1, joyname);\r
cc68a136 889 }\r
890 } else {\r
a12e0116 891 text_out16(tl_x, (y+=10), "none");\r
cc68a136 892 }\r
893\r
a12e0116 894 menu_flip();\r
cc68a136 895}\r
896\r
d524c827 897\r
406c96c5 898// player2_flag, reserved, ?, ?,\r
899// ?, ?, fast forward, menu\r
d524c827 900// "NEXT SAVE SLOT", "PREV SAVE SLOT", "SWITCH RENDERER", "SAVE STATE",\r
901// "LOAD STATE", "VOLUME UP", "VOLUME DOWN", "DONE"\r
1ca2ea4f 902me_bind_action emuctrl_actions[] =\r
d524c827 903{\r
406c96c5 904 { "Load State ", 1<<28 },\r
905 { "Save State ", 1<<27 },\r
906 { "Prev Save Slot ", 1<<25 },\r
907 { "Next Save Slot ", 1<<24 },\r
908 { "Switch Renderer ", 1<<26 },\r
909 { "Volume Down ", 1<<30 },\r
910 { "Volume Up ", 1<<29 },\r
911 { "Fast forward ", 1<<22 },\r
912 { "Enter Menu ", 1<<23 },\r
913 { "Pico Next page ", 1<<21 },\r
914 { "Pico Prev page ", 1<<20 },\r
915 { "Pico Switch input", 1<<19 },\r
916 { NULL, 0 }\r
d524c827 917};\r
918\r
cc68a136 919static void kc_sel_loop(void)\r
920{\r
d524c827 921 int menu_sel = 3, menu_sel_max = 3;\r
cc68a136 922 unsigned long inp = 0;\r
602133e1 923 int is_6button = PicoOpt & POPT_6BTN_PAD;\r
cc68a136 924\r
d524c827 925 while (1)\r
cc68a136 926 {\r
927 draw_kc_sel(menu_sel);\r
928 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X);\r
d524c827 929 if (inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
930 if (inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
931 if (inp & GP2X_B) {\r
cc68a136 932 switch (menu_sel) {\r
1ca2ea4f 933 case 0: key_config_loop(me_ctrl_actions, is_6button ? 12 : 8, 0); return;\r
934 case 1: key_config_loop(me_ctrl_actions, is_6button ? 12 : 8, 1); return;\r
d524c827 935 case 2: key_config_loop(emuctrl_actions,\r
bdec53c9 936 sizeof(emuctrl_actions)/sizeof(emuctrl_actions[0]) - 1, -1); return;\r
eacee137 937 case 3: if (!rom_loaded) emu_WriteConfig(0); return;\r
cc68a136 938 default: return;\r
939 }\r
940 }\r
d524c827 941 if (inp & GP2X_X) return;\r
cc68a136 942 }\r
943}\r
944\r
945\r
bf098bc5 946// --------- sega/mega cd options ----------\r
947\r
4e8a534c 948menu_entry cdopt_entries[] =\r
bf098bc5 949{\r
58c86d00 950 { NULL, MB_NONE, MA_CDOPT_TESTBIOS_USA, NULL, 0, 0, 0, 1, 0 },\r
951 { NULL, MB_NONE, MA_CDOPT_TESTBIOS_EUR, NULL, 0, 0, 0, 1, 0 },\r
952 { NULL, MB_NONE, MA_CDOPT_TESTBIOS_JAP, NULL, 0, 0, 0, 1, 0 },\r
953 { "CD LEDs", MB_ONOFF, MA_CDOPT_LEDS, &currentConfig.EmuOpt, 0x0400, 0, 0, 1, 1 },\r
954 { "CDDA audio (using mp3s)", MB_ONOFF, MA_CDOPT_CDDA, &PicoOpt, 0x0800, 0, 0, 1, 1 },\r
955 { "PCM audio", MB_ONOFF, MA_CDOPT_PCM, &PicoOpt, 0x0400, 0, 0, 1, 1 },\r
956 { NULL, MB_NONE, MA_CDOPT_READAHEAD, NULL, 0, 0, 0, 1, 1 },\r
957 { "SaveRAM cart", MB_ONOFF, MA_CDOPT_SAVERAM, &PicoOpt, 0x8000, 0, 0, 1, 1 },\r
958 { "Scale/Rot. fx (slow)", MB_ONOFF, MA_CDOPT_SCALEROT_CHIP,&PicoOpt, 0x1000, 0, 0, 1, 1 },\r
959 { "Better sync (slow)", MB_ONOFF, MA_CDOPT_BETTER_SYNC, &PicoOpt, 0x2000, 0, 0, 1, 1 },\r
960 { "done", MB_NONE, MA_CDOPT_DONE, NULL, 0, 0, 0, 1, 0 },\r
4e8a534c 961};\r
962\r
963#define CDOPT_ENTRY_COUNT (sizeof(cdopt_entries) / sizeof(cdopt_entries[0]))\r
f9d3ee9d 964const int cdopt_entry_count = CDOPT_ENTRY_COUNT;\r
4e8a534c 965\r
966\r
967struct bios_names_t\r
968{\r
969 char us[32], eu[32], jp[32];\r
970};\r
971\r
972static void menu_cdopt_cust_draw(const menu_entry *entry, int x, int y, void *param)\r
973{\r
974 struct bios_names_t *bios_names = param;\r
975 char ra_buff[16];\r
976\r
977 switch (entry->id)\r
978 {\r
a12e0116 979 case MA_CDOPT_TESTBIOS_USA: text_out16(x, y, "USA BIOS: %s", bios_names->us); break;\r
980 case MA_CDOPT_TESTBIOS_EUR: text_out16(x, y, "EUR BIOS: %s", bios_names->eu); break;\r
981 case MA_CDOPT_TESTBIOS_JAP: text_out16(x, y, "JAP BIOS: %s", bios_names->jp); break;\r
4e8a534c 982 case MA_CDOPT_READAHEAD:\r
983 if (PicoCDBuffers > 1) sprintf(ra_buff, "%5iK", PicoCDBuffers * 2);\r
984 else strcpy(ra_buff, " OFF");\r
a12e0116 985 text_out16(x, y, "ReadAhead buffer %s", ra_buff);\r
4e8a534c 986 break;\r
987 default:break;\r
988 }\r
989}\r
990\r
991static void draw_cd_menu_options(int menu_sel, struct bios_names_t *bios_names)\r
992{\r
993 int tl_x = 25, tl_y = 60;\r
994 menu_id selected_id;\r
0a051f55 995 char ra_buff[16];\r
996\r
997 if (PicoCDBuffers > 1) sprintf(ra_buff, "%5iK", PicoCDBuffers * 2);\r
998 else strcpy(ra_buff, " OFF");\r
bf098bc5 999\r
e11c5548 1000 gp2x_pd_clone_buffer2();\r
1001\r
e5f426aa 1002 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 246);\r
bf098bc5 1003\r
a12e0116 1004 me_draw(cdopt_entries, CDOPT_ENTRY_COUNT, tl_x, tl_y, menu_cdopt_cust_draw, bios_names);\r
bf098bc5 1005\r
4e8a534c 1006 selected_id = me_index2id(cdopt_entries, CDOPT_ENTRY_COUNT, menu_sel);\r
1007 if ((selected_id == MA_CDOPT_TESTBIOS_USA && strcmp(bios_names->us, "NOT FOUND")) ||\r
1008 (selected_id == MA_CDOPT_TESTBIOS_EUR && strcmp(bios_names->eu, "NOT FOUND")) ||\r
1009 (selected_id == MA_CDOPT_TESTBIOS_JAP && strcmp(bios_names->jp, "NOT FOUND")))\r
a12e0116 1010 text_out16(tl_x, 210, "Press start to test selected BIOS");\r
bf098bc5 1011\r
a12e0116 1012 menu_flip();\r
bf098bc5 1013}\r
1014\r
1015static void cd_menu_loop_options(void)\r
1016{\r
aae35e84 1017 static int menu_sel = 0;\r
1018 int menu_sel_max = 10;\r
bf098bc5 1019 unsigned long inp = 0;\r
4e8a534c 1020 struct bios_names_t bios_names;\r
1021 menu_id selected_id;\r
1022 char *bios, *p;\r
bf098bc5 1023\r
ea8c405f 1024 if (emu_findBios(4, &bios)) { // US\r
bf098bc5 1025 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
4e8a534c 1026 strncpy(bios_names.us, p, sizeof(bios_names.us)); bios_names.us[sizeof(bios_names.us)-1] = 0;\r
1027 } else strcpy(bios_names.us, "NOT FOUND");\r
bf098bc5 1028\r
ea8c405f 1029 if (emu_findBios(8, &bios)) { // EU\r
bf098bc5 1030 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
4e8a534c 1031 strncpy(bios_names.eu, p, sizeof(bios_names.eu)); bios_names.eu[sizeof(bios_names.eu)-1] = 0;\r
1032 } else strcpy(bios_names.eu, "NOT FOUND");\r
bf098bc5 1033\r
ea8c405f 1034 if (emu_findBios(1, &bios)) { // JP\r
bf098bc5 1035 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
4e8a534c 1036 strncpy(bios_names.jp, p, sizeof(bios_names.jp)); bios_names.jp[sizeof(bios_names.jp)-1] = 0;\r
1037 } else strcpy(bios_names.jp, "NOT FOUND");\r
bf098bc5 1038\r
1039 for(;;)\r
1040 {\r
4e8a534c 1041 draw_cd_menu_options(menu_sel, &bios_names);\r
bf098bc5 1042 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A|GP2X_START);\r
4e8a534c 1043 if (inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1044 if (inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
1045 selected_id = me_index2id(cdopt_entries, CDOPT_ENTRY_COUNT, menu_sel);\r
1046 if (inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choise\r
1047 if (!me_process(cdopt_entries, CDOPT_ENTRY_COUNT, selected_id, (inp&GP2X_RIGHT) ? 1 : 0) &&\r
1048 selected_id == MA_CDOPT_READAHEAD) {\r
1049 if (inp & GP2X_LEFT) {\r
1050 PicoCDBuffers >>= 1;\r
2d2247c2 1051 if (PicoCDBuffers < 2) PicoCDBuffers = 0;\r
4e8a534c 1052 } else {\r
2d2247c2 1053 if (PicoCDBuffers < 2) PicoCDBuffers = 2;\r
4e8a534c 1054 else PicoCDBuffers <<= 1;\r
1055 if (PicoCDBuffers > 8*1024) PicoCDBuffers = 8*1024; // 16M\r
1056 }\r
bf098bc5 1057 }\r
1058 }\r
4e8a534c 1059 if (inp & GP2X_B) { // toggleable options\r
1060 if (!me_process(cdopt_entries, CDOPT_ENTRY_COUNT, selected_id, 1) &&\r
1061 selected_id == MA_CDOPT_DONE) {\r
1062 return;\r
1063 }\r
1064 }\r
1065 if (inp & GP2X_START) { // BIOS testers\r
1066 switch (selected_id) {\r
1067 case MA_CDOPT_TESTBIOS_USA:\r
ea8c405f 1068 if (emu_findBios(4, &bios)) { // test US\r
bf098bc5 1069 strcpy(romFileName, bios);\r
1070 engineState = PGS_ReloadRom;\r
1071 return;\r
1072 }\r
1073 break;\r
4e8a534c 1074 case MA_CDOPT_TESTBIOS_EUR:\r
ea8c405f 1075 if (emu_findBios(8, &bios)) { // test EU\r
bf098bc5 1076 strcpy(romFileName, bios);\r
1077 engineState = PGS_ReloadRom;\r
1078 return;\r
1079 }\r
1080 break;\r
4e8a534c 1081 case MA_CDOPT_TESTBIOS_JAP:\r
ea8c405f 1082 if (emu_findBios(1, &bios)) { // test JP\r
bf098bc5 1083 strcpy(romFileName, bios);\r
1084 engineState = PGS_ReloadRom;\r
1085 return;\r
1086 }\r
1087 break;\r
4e8a534c 1088 default:\r
1089 break;\r
bf098bc5 1090 }\r
1091 }\r
4e8a534c 1092 if (inp & (GP2X_X|GP2X_A)) return;\r
bf098bc5 1093 }\r
1094}\r
1095\r
1096\r
1097// --------- advanced options ----------\r
1098\r
4e8a534c 1099menu_entry opt2_entries[] =\r
1100{\r
58c86d00 1101 { NULL, MB_NONE, MA_OPT2_GAMMA, NULL, 0, 0, 0, 1, 1 },\r
1102 { "A_SN's gamma curve", MB_ONOFF, MA_OPT2_A_SN_GAMMA, &currentConfig.EmuOpt, 0x1000, 0, 0, 1, 1 },\r
1103 { "Perfect vsync", MB_ONOFF, MA_OPT2_VSYNC, &currentConfig.EmuOpt, 0x2000, 0, 0, 1, 1 },\r
f9d3ee9d 1104 { "Disable sprite limit", MB_ONOFF, MA_OPT2_NO_SPRITE_LIM, &PicoOpt, 0x40000, 0, 0, 1, 1 },\r
1ca2ea4f 1105 { "Emulate Z80", MB_ONOFF, MA_OPT2_ENABLE_Z80, &PicoOpt, 0x00004, 0, 0, 1, 1 },\r
1106 { "Emulate YM2612 (FM)", MB_ONOFF, MA_OPT2_ENABLE_YM2612, &PicoOpt, 0x00001, 0, 0, 1, 1 },\r
1107 { "Emulate SN76496 (PSG)", MB_ONOFF, MA_OPT2_ENABLE_SN76496,&PicoOpt, 0x00002, 0, 0, 1, 1 },\r
58c86d00 1108 { "gzip savestates", MB_ONOFF, MA_OPT2_GZIP_STATES, &currentConfig.EmuOpt, 0x0008, 0, 0, 1, 1 },\r
1109 { "Don't save last used ROM", MB_ONOFF, MA_OPT2_NO_LAST_ROM, &currentConfig.EmuOpt, 0x0020, 0, 0, 1, 1 },\r
1110 { "needs restart:", MB_NONE, MA_NONE, NULL, 0, 0, 0, 1, 0 },\r
1111 { "craigix's RAM timings", MB_ONOFF, MA_OPT2_RAMTIMINGS, &currentConfig.EmuOpt, 0x0100, 0, 0, 1, 1 },\r
1112 { NULL, MB_ONOFF, MA_OPT2_SQUIDGEHACK, &currentConfig.EmuOpt, 0x0010, 0, 0, 1, 1 },\r
1ca2ea4f 1113 { "SVP dynarec", MB_ONOFF, MA_OPT2_SVP_DYNAREC, &PicoOpt, 0x20000, 0, 0, 1, 1 },\r
053fd9b4 1114 { "Disable idle loop patching",MB_ONOFF, MA_OPT2_NO_IDLE_LOOPS, &PicoOpt, 0x80000, 0, 0, 1, 1 },\r
58c86d00 1115 { "done", MB_NONE, MA_OPT2_DONE, NULL, 0, 0, 0, 1, 0 },\r
4e8a534c 1116};\r
1117\r
1118#define OPT2_ENTRY_COUNT (sizeof(opt2_entries) / sizeof(opt2_entries[0]))\r
f9d3ee9d 1119const int opt2_entry_count = OPT2_ENTRY_COUNT;\r
4e8a534c 1120\r
1121static void menu_opt2_cust_draw(const menu_entry *entry, int x, int y, void *param)\r
1122{\r
1123 if (entry->id == MA_OPT2_GAMMA)\r
a12e0116 1124 text_out16(x, y, "Gamma correction %i.%02i", currentConfig.gamma / 100, currentConfig.gamma%100);\r
4e8a534c 1125 else if (entry->id == MA_OPT2_SQUIDGEHACK)\r
58c86d00 1126 text_out16(x, y, "Squidgehack (now %s %s", mmuhack_status ? "active) " : "inactive)",\r
4e8a534c 1127 (currentConfig.EmuOpt&0x0010)?"ON":"OFF");\r
1128}\r
1129\r
1130\r
cc68a136 1131static void draw_amenu_options(int menu_sel)\r
1132{\r
4e8a534c 1133 int tl_x = 25, tl_y = 50;\r
cc68a136 1134\r
e11c5548 1135 gp2x_pd_clone_buffer2();\r
1136\r
e5f426aa 1137 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 252);\r
cc68a136 1138\r
a12e0116 1139 me_draw(opt2_entries, OPT2_ENTRY_COUNT, tl_x, tl_y, menu_opt2_cust_draw, NULL);\r
cc68a136 1140\r
a12e0116 1141 menu_flip();\r
cc68a136 1142}\r
1143\r
1144static void amenu_loop_options(void)\r
1145{\r
aae35e84 1146 static int menu_sel = 0;\r
4e8a534c 1147 int menu_sel_max;\r
cc68a136 1148 unsigned long inp = 0;\r
4e8a534c 1149 menu_id selected_id;\r
1150\r
1151 menu_sel_max = me_count_enabled(opt2_entries, OPT2_ENTRY_COUNT) - 1;\r
cc68a136 1152\r
1153 for(;;)\r
1154 {\r
1155 draw_amenu_options(menu_sel);\r
1156 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A);\r
4e8a534c 1157 if (inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1158 if (inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
1159 selected_id = me_index2id(opt2_entries, OPT2_ENTRY_COUNT, menu_sel);\r
1160 if (inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choise\r
1161 if (!me_process(opt2_entries, OPT2_ENTRY_COUNT, selected_id, (inp&GP2X_RIGHT) ? 1 : 0) &&\r
1162 selected_id == MA_OPT2_GAMMA) {\r
1163 while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) {\r
1164 currentConfig.gamma += (inp & GP2X_LEFT) ? -1 : 1;\r
1165 if (currentConfig.gamma < 1) currentConfig.gamma = 1;\r
1166 if (currentConfig.gamma > 300) currentConfig.gamma = 300;\r
1167 draw_amenu_options(menu_sel);\r
1168 usleep(18*1000);\r
1169 }\r
cc68a136 1170 }\r
1171 }\r
4e8a534c 1172 if (inp & GP2X_B) { // toggleable options\r
1173 if (!me_process(opt2_entries, OPT2_ENTRY_COUNT, selected_id, 1) &&\r
1174 selected_id == MA_OPT2_DONE) {\r
1175 return;\r
cc68a136 1176 }\r
1177 }\r
4e8a534c 1178 if (inp & (GP2X_X|GP2X_A)) return;\r
cc68a136 1179 }\r
1180}\r
1181\r
1182// -------------- options --------------\r
1183\r
4e8a534c 1184\r
1185menu_entry opt_entries[] =\r
1186{\r
58c86d00 1187 { NULL, MB_NONE, MA_OPT_RENDERER, NULL, 0, 0, 0, 1, 1 },\r
1188 { NULL, MB_RANGE, MA_OPT_SCALING, &currentConfig.scaling, 0, 0, 3, 1, 1 },\r
58c86d00 1189 { "Accurate sprites (slower)", MB_ONOFF, MA_OPT_ACC_SPRITES, &PicoOpt, 0x080, 0, 0, 1, 1 },\r
1190 { "Show FPS", MB_ONOFF, MA_OPT_SHOW_FPS, &currentConfig.EmuOpt, 0x002, 0, 0, 1, 1 },\r
1191 { NULL, MB_RANGE, MA_OPT_FRAMESKIP, &currentConfig.Frameskip, 0, -1, 16, 1, 1 },\r
1192 { "Enable sound", MB_ONOFF, MA_OPT_ENABLE_SOUND, &currentConfig.EmuOpt, 0x004, 0, 0, 1, 1 },\r
1193 { NULL, MB_NONE, MA_OPT_SOUND_QUALITY, NULL, 0, 0, 0, 1, 1 },\r
1194 { "Use ARM940 core for sound", MB_ONOFF, MA_OPT_ARM940_SOUND, &PicoOpt, 0x200, 0, 0, 1, 1 },\r
1195 { "6 button pad", MB_ONOFF, MA_OPT_6BUTTON_PAD, &PicoOpt, 0x020, 0, 0, 1, 1 },\r
1196 { NULL, MB_NONE, MA_OPT_REGION, NULL, 0, 0, 0, 1, 1 },\r
1197 { "Use SRAM/BRAM savestates", MB_ONOFF, MA_OPT_SRAM_STATES, &currentConfig.EmuOpt, 0x001, 0, 0, 1, 1 },\r
1198 { NULL, MB_NONE, MA_OPT_CONFIRM_STATES,NULL, 0, 0, 0, 1, 1 },\r
1199 { "Save slot", MB_RANGE, MA_OPT_SAVE_SLOT, &state_slot, 0, 0, 9, 1, 1 },\r
1200 { NULL, MB_NONE, MA_OPT_CPU_CLOCKS, NULL, 0, 0, 0, 1, 1 },\r
1201 { "[Sega/Mega CD options]", MB_NONE, MA_OPT_SCD_OPTS, NULL, 0, 0, 0, 1, 0 },\r
1202 { "[advanced options]", MB_NONE, MA_OPT_ADV_OPTS, NULL, 0, 0, 0, 1, 0 },\r
1203 { NULL, MB_NONE, MA_OPT_SAVECFG, NULL, 0, 0, 0, 1, 0 },\r
1204 { "Save cfg for current game only",MB_NONE,MA_OPT_SAVECFG_GAME,NULL, 0, 0, 0, 1, 0 },\r
1205 { NULL, MB_NONE, MA_OPT_LOADCFG, NULL, 0, 0, 0, 1, 0 },\r
4e8a534c 1206};\r
1207\r
1208#define OPT_ENTRY_COUNT (sizeof(opt_entries) / sizeof(opt_entries[0]))\r
58c86d00 1209const int opt_entry_count = OPT_ENTRY_COUNT;\r
cc68a136 1210\r
4e8a534c 1211\r
1212static void menu_opt_cust_draw(const menu_entry *entry, int x, int y, void *param)\r
cc68a136 1213{\r
4e8a534c 1214 char *str, str24[24];\r
1215\r
1216 switch (entry->id)\r
1217 {\r
1218 case MA_OPT_RENDERER:\r
602133e1 1219 if (PicoOpt & POPT_ALT_RENDERER)\r
4e8a534c 1220 str = " 8bit fast";\r
1221 else if (currentConfig.EmuOpt&0x80)\r
1222 str = "16bit accurate";\r
1223 else\r
1224 str = " 8bit accurate";\r
a12e0116 1225 text_out16(x, y, "Renderer: %s", str);\r
4e8a534c 1226 break;\r
1227 case MA_OPT_SCALING:\r
1228 switch (currentConfig.scaling) {\r
1229 default: str = " OFF"; break;\r
1230 case 1: str = "hw horizontal"; break;\r
1231 case 2: str = "hw horiz. + vert."; break;\r
1232 case 3: str = "sw horizontal"; break;\r
1233 }\r
a12e0116 1234 text_out16(x, y, "Scaling: %s", str);\r
4e8a534c 1235 break;\r
1236 case MA_OPT_FRAMESKIP:\r
1237 if (currentConfig.Frameskip < 0)\r
1238 strcpy(str24, "Auto");\r
1239 else sprintf(str24, "%i", currentConfig.Frameskip);\r
a12e0116 1240 text_out16(x, y, "Frameskip %s", str24);\r
4e8a534c 1241 break;\r
1242 case MA_OPT_SOUND_QUALITY:\r
602133e1 1243 str = (PicoOpt & POPT_EN_STEREO) ? "stereo" : "mono";\r
58c86d00 1244 text_out16(x, y, "Sound Quality: %5iHz %s", PsndRate, str);\r
4e8a534c 1245 break;\r
1246 case MA_OPT_REGION:\r
58c86d00 1247 text_out16(x, y, "Region: %s", me_region_name(PicoRegionOverride, PicoAutoRgnOrder));\r
4e8a534c 1248 break;\r
1249 case MA_OPT_CONFIRM_STATES:\r
1250 switch ((currentConfig.EmuOpt >> 9) & 5) {\r
1251 default: str = "OFF"; break;\r
1252 case 1: str = "writes"; break;\r
1253 case 4: str = "loads"; break;\r
1254 case 5: str = "both"; break;\r
1255 }\r
a12e0116 1256 text_out16(x, y, "Confirm savestate %s", str);\r
4e8a534c 1257 break;\r
1258 case MA_OPT_CPU_CLOCKS:\r
a12e0116 1259 text_out16(x, y, "GP2X CPU clocks %iMhz", currentConfig.CPUclock);\r
4e8a534c 1260 break;\r
1261 case MA_OPT_SAVECFG:\r
1262 str24[0] = 0;\r
1263 if (config_slot != 0) sprintf(str24, " (profile: %i)", config_slot);\r
a12e0116 1264 text_out16(x, y, "Save cfg as default%s", str24);\r
4e8a534c 1265 break;\r
1266 case MA_OPT_LOADCFG:\r
a12e0116 1267 text_out16(x, y, "Load cfg from profile %i", config_slot);\r
4e8a534c 1268 break;\r
1269 default:\r
1270 printf("%s: unimplemented (%i)\n", __FUNCTION__, entry->id);\r
1271 break;\r
46969540 1272 }\r
4e8a534c 1273}\r
1274\r
1275\r
1276\r
1277static void draw_menu_options(int menu_sel)\r
1278{\r
a12e0116 1279 int tl_x = 25, tl_y = 24;\r
cc68a136 1280\r
e11c5548 1281 gp2x_pd_clone_buffer2();\r
1282\r
e5f426aa 1283 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 284);\r
cc68a136 1284\r
a12e0116 1285 me_draw(opt_entries, OPT_ENTRY_COUNT, tl_x, tl_y, menu_opt_cust_draw, NULL);\r
cc68a136 1286\r
a12e0116 1287 menu_flip();\r
cc68a136 1288}\r
1289\r
1290static int sndrate_prevnext(int rate, int dir)\r
1291{\r
1292 int i, rates[] = { 8000, 11025, 16000, 22050, 44100 };\r
1293\r
1294 for (i = 0; i < 5; i++)\r
1295 if (rates[i] == rate) break;\r
1296\r
1297 i += dir ? 1 : -1;\r
1298 if (i > 4) return dir ? 44100 : 22050;\r
1299 if (i < 0) return dir ? 11025 : 8000;\r
1300 return rates[i];\r
1301}\r
1302\r
51a902ae 1303static void region_prevnext(int right)\r
1304{\r
1305 // jp_ntsc=1, jp_pal=2, usa=4, eu=8\r
1306 static int rgn_orders[] = { 0x148, 0x184, 0x814, 0x418, 0x841, 0x481 };\r
1307 int i;\r
1308 if (right) {\r
58c86d00 1309 if (!PicoRegionOverride) {\r
51a902ae 1310 for (i = 0; i < 6; i++)\r
1311 if (rgn_orders[i] == PicoAutoRgnOrder) break;\r
1312 if (i < 5) PicoAutoRgnOrder = rgn_orders[i+1];\r
58c86d00 1313 else PicoRegionOverride=1;\r
51a902ae 1314 }\r
58c86d00 1315 else PicoRegionOverride<<=1;\r
1316 if (PicoRegionOverride > 8) PicoRegionOverride = 8;\r
51a902ae 1317 } else {\r
58c86d00 1318 if (!PicoRegionOverride) {\r
51a902ae 1319 for (i = 0; i < 6; i++)\r
1320 if (rgn_orders[i] == PicoAutoRgnOrder) break;\r
1321 if (i > 0) PicoAutoRgnOrder = rgn_orders[i-1];\r
1322 }\r
58c86d00 1323 else PicoRegionOverride>>=1;\r
51a902ae 1324 }\r
1325}\r
1326\r
cc68a136 1327static void menu_options_save(void)\r
1328{\r
7d0143a2 1329 if (PicoRegionOverride) {\r
1330 // force setting possibly changed..\r
1331 Pico.m.pal = (PicoRegionOverride == 2 || PicoRegionOverride == 8) ? 1 : 0;\r
1332 }\r
602133e1 1333 if (!(PicoOpt & POPT_6BTN_PAD)) {\r
d524c827 1334 // unbind XYZ MODE, just in case\r
45499284 1335 unbind_action(0xf00, -1, -1);\r
cc68a136 1336 }\r
1337}\r
1338\r
bf098bc5 1339static int menu_loop_options(void)\r
cc68a136 1340{\r
aae35e84 1341 static int menu_sel = 0;\r
4e8a534c 1342 int menu_sel_max, ret;\r
cc68a136 1343 unsigned long inp = 0;\r
4e8a534c 1344 menu_id selected_id;\r
cc68a136 1345\r
eacee137 1346 me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_SAVECFG_GAME, rom_loaded);\r
4e8a534c 1347 me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_LOADCFG, config_slot != config_slot_current);\r
1348 menu_sel_max = me_count_enabled(opt_entries, OPT_ENTRY_COUNT) - 1;\r
d524c827 1349 if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;\r
4e8a534c 1350\r
1351 while (1)\r
cc68a136 1352 {\r
1353 draw_menu_options(menu_sel);\r
1354 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A);\r
4e8a534c 1355 if (inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1356 if (inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
1357 selected_id = me_index2id(opt_entries, OPT_ENTRY_COUNT, menu_sel);\r
58c86d00 1358 if (inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choice\r
4e8a534c 1359 if (!me_process(opt_entries, OPT_ENTRY_COUNT, selected_id, (inp&GP2X_RIGHT) ? 1 : 0)) {\r
1360 switch (selected_id) {\r
1361 case MA_OPT_RENDERER:\r
1362 if (inp & GP2X_LEFT) {\r
58c86d00 1363 if (PicoOpt&0x10) PicoOpt&= ~0x10;\r
4e8a534c 1364 else if (!(currentConfig.EmuOpt &0x80))currentConfig.EmuOpt |= 0x80;\r
1365 else if ( currentConfig.EmuOpt &0x80) break;\r
1366 } else {\r
58c86d00 1367 if (PicoOpt&0x10) break;\r
1368 else if (!(currentConfig.EmuOpt &0x80))PicoOpt|= 0x10;\r
4e8a534c 1369 else if ( currentConfig.EmuOpt &0x80) currentConfig.EmuOpt &= ~0x80;\r
1370 }\r
1371 break;\r
1372 case MA_OPT_SOUND_QUALITY:\r
58c86d00 1373 if ((inp & GP2X_RIGHT) && PsndRate == 44100 && !(PicoOpt&0x08)) {\r
1374 PsndRate = 8000; PicoOpt|= 0x08;\r
1375 } else if ((inp & GP2X_LEFT) && PsndRate == 8000 && (PicoOpt&0x08)) {\r
1376 PsndRate = 44100; PicoOpt&=~0x08;\r
1377 } else PsndRate = sndrate_prevnext(PsndRate, inp & GP2X_RIGHT);\r
4e8a534c 1378 break;\r
1379 case MA_OPT_REGION:\r
1380 region_prevnext(inp & GP2X_RIGHT);\r
1381 break;\r
1382 case MA_OPT_CONFIRM_STATES: {\r
1383 int n = ((currentConfig.EmuOpt>>9)&1) | ((currentConfig.EmuOpt>>10)&2);\r
1384 n += (inp & GP2X_LEFT) ? -1 : 1;\r
1385 if (n < 0) n = 0; else if (n > 3) n = 3;\r
1386 n |= n << 1; n &= ~2;\r
1387 currentConfig.EmuOpt &= ~0xa00;\r
1388 currentConfig.EmuOpt |= n << 9;\r
1389 break;\r
1390 }\r
1391 case MA_OPT_SAVE_SLOT:\r
1392 if (inp & GP2X_RIGHT) {\r
1393 state_slot++; if (state_slot > 9) state_slot = 0;\r
1394 } else {state_slot--; if (state_slot < 0) state_slot = 9;\r
1395 }\r
1396 break;\r
1397 case MA_OPT_CPU_CLOCKS:\r
1398 while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) {\r
1399 currentConfig.CPUclock += (inp & GP2X_LEFT) ? -1 : 1;\r
1400 if (currentConfig.CPUclock < 1) currentConfig.CPUclock = 1;\r
1401 draw_menu_options(menu_sel);\r
1402 usleep(50*1000);\r
1403 }\r
1404 break;\r
1405 case MA_OPT_SAVECFG:\r
1406 case MA_OPT_SAVECFG_GAME:\r
1407 case MA_OPT_LOADCFG:\r
1408 config_slot += (inp&GP2X_RIGHT) ? 1 : -1;\r
1409 if (config_slot > 9) config_slot = 0;\r
1410 if (config_slot < 0) config_slot = 9;\r
1411 me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_LOADCFG, config_slot != config_slot_current);\r
1412 menu_sel_max = me_count_enabled(opt_entries, OPT_ENTRY_COUNT) - 1;\r
1413 if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;\r
1414 break;\r
1415 default:\r
1416 //printf("%s: something unknown selected (%i)\n", __FUNCTION__, selected_id);\r
1417 break;\r
1418 }\r
1419 }\r
1420 }\r
1421 if (inp & GP2X_B) {\r
1422 if (!me_process(opt_entries, OPT_ENTRY_COUNT, selected_id, 1))\r
1423 {\r
1424 switch (selected_id)\r
1425 {\r
1426 case MA_OPT_SCD_OPTS:\r
1427 cd_menu_loop_options();\r
1428 if (engineState == PGS_ReloadRom)\r
1429 return 0; // test BIOS\r
1430 break;\r
1431 case MA_OPT_ADV_OPTS:\r
1432 amenu_loop_options();\r
1433 break;\r
1434 case MA_OPT_SAVECFG: // done (update and write)\r
1435 menu_options_save();\r
1436 if (emu_WriteConfig(0)) strcpy(menuErrorMsg, "config saved");\r
1437 else strcpy(menuErrorMsg, "failed to write config");\r
1438 return 1;\r
1439 case MA_OPT_SAVECFG_GAME: // done (update and write for current game)\r
1440 menu_options_save();\r
1441 if (emu_WriteConfig(1)) strcpy(menuErrorMsg, "config saved");\r
1442 else strcpy(menuErrorMsg, "failed to write config");\r
1443 return 1;\r
1444 case MA_OPT_LOADCFG:\r
d524c827 1445 ret = emu_ReadConfig(1, 1);\r
1446 if (!ret) ret = emu_ReadConfig(0, 1);\r
1447 if (ret) strcpy(menuErrorMsg, "config loaded");\r
4e8a534c 1448 else strcpy(menuErrorMsg, "failed to load config");\r
1449 return 1;\r
1450 default:\r
1451 //printf("%s: something unknown selected (%i)\n", __FUNCTION__, selected_id);\r
1452 break;\r
1453 }\r
cc68a136 1454 }\r
1455 }\r
51a902ae 1456 if(inp & (GP2X_X|GP2X_A)) {\r
cc68a136 1457 menu_options_save();\r
bf098bc5 1458 return 0; // done (update, no write)\r
cc68a136 1459 }\r
cc68a136 1460 }\r
1461}\r
1462\r
1463// -------------- credits --------------\r
1464\r
1465static void draw_menu_credits(void)\r
1466{\r
053fd9b4 1467 int tl_x = 15, tl_y = 56, y;\r
e11c5548 1468 gp2x_pd_clone_buffer2();\r
cc68a136 1469\r
f9d3ee9d 1470 text_out16(tl_x, 20, "PicoDrive v" VERSION " (c) notaz, 2006-2008");\r
cc68a136 1471 y = tl_y;\r
a12e0116 1472 text_out16(tl_x, y, "Credits:");\r
3ec29f01 1473 text_out16(tl_x, (y+=10), "fDave: Cyclone 68000 core,");\r
a12e0116 1474 text_out16(tl_x, (y+=10), " base code of PicoDrive");\r
1475 text_out16(tl_x, (y+=10), "Reesy & FluBBa: DrZ80 core");\r
1476 text_out16(tl_x, (y+=10), "MAME devs: YM2612 and SN76496 cores");\r
a12e0116 1477 text_out16(tl_x, (y+=10), "rlyeh and others: minimal SDK");\r
1478 text_out16(tl_x, (y+=10), "Squidge: squidgehack");\r
1479 text_out16(tl_x, (y+=10), "Dzz: ARM940 sample");\r
053fd9b4 1480 text_out16(tl_x, (y+=10), "GnoStiC / Puck2099: USB joy code");\r
a12e0116 1481 text_out16(tl_x, (y+=10), "craigix: GP2X hardware");\r
a4f0cc86 1482 text_out16(tl_x, (y+=10), "ketchupgun: skin design");\r
a12e0116 1483\r
1a65e3b1 1484 text_out16(tl_x, (y+=20), "special thanks (for docs, ideas):");\r
053fd9b4 1485 text_out16(tl_x, (y+=10), " Charles MacDonald, Haze,");\r
1486 text_out16(tl_x, (y+=10), " Stephane Dallongeville,");\r
1487 text_out16(tl_x, (y+=10), " Lordus, Exophase, Rokas,");\r
1488 text_out16(tl_x, (y+=10), " Nemesis, Tasco Deluxe");\r
1489\r
a12e0116 1490 menu_flip();\r
cc68a136 1491}\r
1492\r
1493\r
1494// -------------- root menu --------------\r
1495\r
4e8a534c 1496menu_entry main_entries[] =\r
1497{\r
58c86d00 1498 { "Resume game", MB_NONE, MA_MAIN_RESUME_GAME, NULL, 0, 0, 0, 0, 0 },\r
1499 { "Save State", MB_NONE, MA_MAIN_SAVE_STATE, NULL, 0, 0, 0, 0, 0 },\r
1500 { "Load State", MB_NONE, MA_MAIN_LOAD_STATE, NULL, 0, 0, 0, 0, 0 },\r
1501 { "Reset game", MB_NONE, MA_MAIN_RESET_GAME, NULL, 0, 0, 0, 0, 0 },\r
1502 { "Load new ROM/ISO", MB_NONE, MA_MAIN_LOAD_ROM, NULL, 0, 0, 0, 1, 0 },\r
1503 { "Change options", MB_NONE, MA_MAIN_OPTIONS, NULL, 0, 0, 0, 1, 0 },\r
1504 { "Configure controls", MB_NONE, MA_MAIN_CONTROLS, NULL, 0, 0, 0, 1, 0 },\r
1505 { "Credits", MB_NONE, MA_MAIN_CREDITS, NULL, 0, 0, 0, 1, 0 },\r
1506 { "Patches / GameGenie",MB_NONE, MA_MAIN_PATCHES, NULL, 0, 0, 0, 0, 0 },\r
1507 { "Exit", MB_NONE, MA_MAIN_EXIT, NULL, 0, 0, 0, 1, 0 }\r
4e8a534c 1508};\r
1509\r
1510#define MAIN_ENTRY_COUNT (sizeof(main_entries) / sizeof(main_entries[0]))\r
1511\r
cc68a136 1512static void draw_menu_root(int menu_sel)\r
1513{\r
4e8a534c 1514 const int tl_x = 70, tl_y = 70;\r
1515\r
e11c5548 1516 gp2x_pd_clone_buffer2();\r
cc68a136 1517\r
a12e0116 1518 text_out16(tl_x, 20, "PicoDrive v" VERSION);\r
1519\r
e5f426aa 1520 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 146);\r
cc68a136 1521\r
4e8a534c 1522 me_draw(main_entries, MAIN_ENTRY_COUNT, tl_x, tl_y, NULL, NULL);\r
cc68a136 1523\r
cc68a136 1524 // error\r
a12e0116 1525 if (menuErrorMsg[0]) {\r
1526 memset((char *)gp2x_screen + 320*224*2, 0, 320*16*2);\r
1527 text_out16(5, 226, menuErrorMsg);\r
1528 }\r
1529 menu_flip();\r
cc68a136 1530}\r
1531\r
1532\r
1533static void menu_loop_root(void)\r
1534{\r
4e8a534c 1535 static int menu_sel = 0;\r
1536 int ret, menu_sel_max;\r
cc68a136 1537 unsigned long inp = 0;\r
cc68a136 1538\r
eacee137 1539 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_RESUME_GAME, rom_loaded);\r
1540 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_SAVE_STATE, rom_loaded);\r
1541 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_LOAD_STATE, rom_loaded);\r
1542 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_RESET_GAME, rom_loaded);\r
4e8a534c 1543 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_PATCHES, PicoPatches != NULL);\r
1544\r
1545 menu_sel_max = me_count_enabled(main_entries, MAIN_ENTRY_COUNT) - 1;\r
d524c827 1546 if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;\r
cc68a136 1547\r
2433f409 1548 /* make sure action buttons are not pressed on entering menu */\r
1549 draw_menu_root(menu_sel);\r
1550 while (gp2x_joystick_read(1) & (GP2X_B|GP2X_X|GP2X_SELECT)) usleep(50*1000);\r
1551\r
1552 for (;;)\r
cc68a136 1553 {\r
1554 draw_menu_root(menu_sel);\r
0af33fe0 1555 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X|GP2X_SELECT|GP2X_L|GP2X_R);\r
4e8a534c 1556 if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1557 if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
0af33fe0 1558 if((inp & (GP2X_L|GP2X_R)) == (GP2X_L|GP2X_R)) debug_menu_loop();\r
cc68a136 1559 if(inp &(GP2X_SELECT|GP2X_X)){\r
eacee137 1560 if (rom_loaded) {\r
cc68a136 1561 while (gp2x_joystick_read(1) & (GP2X_SELECT|GP2X_X)) usleep(50*1000); // wait until select is released\r
1562 engineState = PGS_Running;\r
1563 break;\r
1564 }\r
1565 }\r
4e8a534c 1566 if(inp & GP2X_B) {\r
1567 switch (me_index2id(main_entries, MAIN_ENTRY_COUNT, menu_sel))\r
1568 {\r
1569 case MA_MAIN_RESUME_GAME:\r
eacee137 1570 if (rom_loaded) {\r
721cd396 1571 while (gp2x_joystick_read(1) & GP2X_B) usleep(50*1000);\r
1572 engineState = PGS_Running;\r
1573 return;\r
1574 }\r
cc68a136 1575 break;\r
4e8a534c 1576 case MA_MAIN_SAVE_STATE:\r
eacee137 1577 if (rom_loaded) {\r
860c6322 1578 if(savestate_menu_loop(0))\r
cc68a136 1579 continue;\r
cc68a136 1580 engineState = PGS_Running;\r
1581 return;\r
1582 }\r
1583 break;\r
4e8a534c 1584 case MA_MAIN_LOAD_STATE:\r
eacee137 1585 if (rom_loaded) {\r
860c6322 1586 if(savestate_menu_loop(1))\r
cc68a136 1587 continue;\r
5ed2561c 1588 while (gp2x_joystick_read(1) & GP2X_B) usleep(50*1000);\r
cc68a136 1589 engineState = PGS_Running;\r
1590 return;\r
1591 }\r
1592 break;\r
4e8a534c 1593 case MA_MAIN_RESET_GAME:\r
eacee137 1594 if (rom_loaded) {\r
cc68a136 1595 emu_ResetGame();\r
5ed2561c 1596 while (gp2x_joystick_read(1) & GP2X_B) usleep(50*1000);\r
cc68a136 1597 engineState = PGS_Running;\r
1598 return;\r
1599 }\r
1600 break;\r
4e8a534c 1601 case MA_MAIN_LOAD_ROM:\r
a12e0116 1602 {\r
1603 char curr_path[PATH_MAX], *selfname;\r
1604 FILE *tstf;\r
1ca2ea4f 1605 if ( (tstf = fopen(lastRomFile, "rb")) )\r
a12e0116 1606 {\r
1607 fclose(tstf);\r
1ca2ea4f 1608 strcpy(curr_path, lastRomFile);\r
a12e0116 1609 }\r
1610 else\r
1611 getcwd(curr_path, PATH_MAX);\r
cc68a136 1612 selfname = romsel_loop(curr_path);\r
1613 if (selfname) {\r
1614 printf("selected file: %s\n", selfname);\r
cc68a136 1615 engineState = PGS_ReloadRom;\r
a12e0116 1616 return;\r
cc68a136 1617 }\r
a12e0116 1618 break;\r
1619 }\r
4e8a534c 1620 case MA_MAIN_OPTIONS:\r
bf098bc5 1621 ret = menu_loop_options();\r
1622 if (ret == 1) continue; // status update\r
1623 if (engineState == PGS_ReloadRom)\r
1624 return; // BIOS test\r
cc68a136 1625 break;\r
4e8a534c 1626 case MA_MAIN_CONTROLS:\r
cc68a136 1627 kc_sel_loop();\r
1628 break;\r
4e8a534c 1629 case MA_MAIN_CREDITS:\r
cc68a136 1630 draw_menu_credits();\r
1631 usleep(500*1000);\r
1632 inp = wait_for_input(GP2X_B|GP2X_X);\r
1633 break;\r
4e8a534c 1634 case MA_MAIN_EXIT:\r
cc68a136 1635 engineState = PGS_Quit;\r
1636 return;\r
4e8a534c 1637 case MA_MAIN_PATCHES:\r
eacee137 1638 if (rom_loaded && PicoPatches) {\r
b67ef287 1639 patches_menu_loop();\r
1640 PicoPatchApply();\r
1641 strcpy(menuErrorMsg, "Patches applied");\r
1642 continue;\r
1643 }\r
1644 break;\r
4e8a534c 1645 default:\r
1646 printf("%s: something unknown selected\n", __FUNCTION__);\r
1647 break;\r
cc68a136 1648 }\r
1649 }\r
1650 menuErrorMsg[0] = 0; // clear error msg\r
1651 }\r
1652}\r
1653\r
a4f0cc86 1654static void menu_darken_bg(void *dst, int pixels, int darker)\r
cc68a136 1655{\r
a12e0116 1656 unsigned int *screen = dst;\r
1657 pixels /= 2;\r
a4f0cc86 1658 if (darker)\r
a12e0116 1659 {\r
a4f0cc86 1660 while (pixels--)\r
1661 {\r
1662 unsigned int p = *screen;\r
1663 *screen++ = ((p&0xf79ef79e)>>1) - ((p&0xc618c618)>>3);\r
1664 }\r
1665 }\r
1666 else\r
1667 {\r
1668 while (pixels--)\r
1669 {\r
1670 unsigned int p = *screen;\r
1671 *screen++ = (p&0xf79ef79e)>>1;\r
1672 }\r
a12e0116 1673 }\r
1674}\r
e11c5548 1675\r
a12e0116 1676static void menu_prepare_bg(int use_game_bg)\r
1677{\r
1678 if (use_game_bg)\r
1679 {\r
1680 // darken the active framebuffer\r
1681 memset(gp2x_screen, 0, 320*8*2);\r
a4f0cc86 1682 menu_darken_bg((char *)gp2x_screen + 320*8*2, 320*224, 1);\r
a12e0116 1683 memset((char *)gp2x_screen + 320*232*2, 0, 320*8*2);\r
1684 }\r
1685 else\r
1686 {\r
1687 // should really only happen once, on startup..\r
1688 readpng(gp2x_screen, "skin/background.png", READPNG_BG);\r
860c6322 1689 }\r
cc68a136 1690\r
a12e0116 1691 // copy to buffer2\r
1692 gp2x_memcpy_buffers((1<<2), gp2x_screen, 0, 320*240*2);\r
860c6322 1693}\r
1694\r
1695static void menu_gfx_prepare(void)\r
1696{\r
eacee137 1697 menu_prepare_bg(rom_loaded);\r
860c6322 1698\r
a12e0116 1699 // switch to 16bpp\r
1700 gp2x_video_changemode2(16);\r
2433f409 1701 gp2x_video_RGB_setscaling(0, 320, 240);\r
a12e0116 1702 menu_flip();\r
e11c5548 1703}\r
1704\r
1705\r
1706void menu_loop(void)\r
1707{\r
1708 menu_gfx_prepare();\r
cc68a136 1709\r
1710 menu_loop_root();\r
1711\r
1712 menuErrorMsg[0] = 0;\r
1713}\r
721cd396 1714\r
1715\r
1716// --------- CD tray close menu ----------\r
1717\r
1718static void draw_menu_tray(int menu_sel)\r
1719{\r
1720 int tl_x = 70, tl_y = 90, y;\r
a12e0116 1721 memset(gp2x_screen, 0, 320*240*2);\r
721cd396 1722\r
a12e0116 1723 text_out16(tl_x, 20, "The unit is about to");\r
1724 text_out16(tl_x, 30, "close the CD tray.");\r
721cd396 1725\r
1726 y = tl_y;\r
a12e0116 1727 text_out16(tl_x, y, "Load new CD image");\r
1728 text_out16(tl_x, (y+=10), "Insert nothing");\r
721cd396 1729\r
1730 // draw cursor\r
a12e0116 1731 text_out16(tl_x - 16, tl_y + menu_sel*10, ">");\r
721cd396 1732 // error\r
a12e0116 1733 if (menuErrorMsg[0]) text_out16(5, 226, menuErrorMsg);\r
1734 menu_flip();\r
721cd396 1735}\r
1736\r
1737\r
1738int menu_loop_tray(void)\r
1739{\r
1740 int menu_sel = 0, menu_sel_max = 1;\r
1741 unsigned long inp = 0;\r
1742 char curr_path[PATH_MAX], *selfname;\r
1743 FILE *tstf;\r
1744\r
e5f426aa 1745 gp2x_memset_all_buffers(0, 0, 320*240*2);\r
721cd396 1746 menu_gfx_prepare();\r
1747\r
1ca2ea4f 1748 if ( (tstf = fopen(lastRomFile, "rb")) )\r
721cd396 1749 {\r
1750 fclose(tstf);\r
1ca2ea4f 1751 strcpy(curr_path, lastRomFile);\r
721cd396 1752 }\r
1753 else\r
1754 {\r
1755 getcwd(curr_path, PATH_MAX);\r
1756 }\r
1757\r
1758 /* make sure action buttons are not pressed on entering menu */\r
1759 draw_menu_tray(menu_sel);\r
1760 while (gp2x_joystick_read(1) & GP2X_B) usleep(50*1000);\r
1761\r
1762 for (;;)\r
1763 {\r
1764 draw_menu_tray(menu_sel);\r
1765 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B);\r
1766 if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1767 if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
1768 if(inp & GP2X_B ) {\r
1769 switch (menu_sel) {\r
1770 case 0: // select image\r
1771 selfname = romsel_loop(curr_path);\r
1772 if (selfname) {\r
b923ecbe 1773 int ret = -1;\r
1774 cd_img_type cd_type;\r
ea8c405f 1775 cd_type = emu_cdCheck(NULL);\r
b923ecbe 1776 if (cd_type != CIT_NOT_CD)\r
1777 ret = Insert_CD(romFileName, cd_type);\r
721cd396 1778 if (ret != 0) {\r
1779 sprintf(menuErrorMsg, "Load failed, invalid CD image?");\r
1780 printf("%s\n", menuErrorMsg);\r
1781 continue;\r
1782 }\r
1783 engineState = PGS_RestartRun;\r
1784 return 1;\r
1785 }\r
1786 break;\r
1787 case 1: // insert nothing\r
1788 engineState = PGS_RestartRun;\r
1789 return 0;\r
1790 }\r
1791 }\r
1792 menuErrorMsg[0] = 0; // clear error msg\r
1793 }\r
1794}\r
1795\r
1796\r