bugfix, sprites adjustment
[libpicofe.git] / gp2x / menu.c
CommitLineData
95151aea 1// (c) Copyright 2006,2007 notaz, All rights reserved.\r
720ee7f6 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
f013066e 17#include "../common/emu.h"\r
c7a4ff64 18#include "../common/menu.h"\r
f013066e 19#include "../common/arm_utils.h"\r
c7a4ff64 20#include "../common/readpng.h"\r
720ee7f6 21#include "version.h"\r
22\r
70d2ecc5 23#include <Pico/PicoInt.h>\r
24#include <Pico/Patch.h>\r
25#include <zlib/zlib.h>\r
720ee7f6 26\r
27#ifndef _DIRENT_HAVE_D_TYPE\r
260f1bcc 28#error "need d_type for file browser"\r
720ee7f6 29#endif\r
30\r
720ee7f6 31extern int mmuhack_status;\r
720ee7f6 32\r
30d5518a 33const char * const keyNames[] = {\r
720ee7f6 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
f9a37a02 40static void menu_darken_bg(void *dst, int pixels, int darker);\r
13059a60 41static void menu_prepare_bg(int use_game_bg);\r
720ee7f6 42\r
720ee7f6 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
6af8fee5 49 static int repeats = 0, wait = 20;\r
720ee7f6 50 int release = 0, i;\r
51\r
704c0ea3 52 if (repeats == 2) wait = 3;\r
53 else if (repeats == 4) wait = 2;\r
54 else if (repeats == 6) wait = 1;\r
720ee7f6 55\r
704c0ea3 56 for (i = 0; i < wait && inp_prev == gp2x_joystick_read(1); i++) {\r
5e2e14f2 57 if (i == 0) repeats++;\r
704c0ea3 58 usleep(30000);\r
720ee7f6 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
6af8fee5 68 wait = 20;\r
720ee7f6 69 }\r
260f1bcc 70 if (wait > 6 && (ret&(GP2X_UP|GP2X_LEFT|GP2X_DOWN|GP2X_RIGHT|GP2X_L|GP2X_R)))\r
6af8fee5 71 wait = 6;\r
720ee7f6 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
367b6f1f 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
558d8e1f 129 // ... but allow select\r
130 ret |= inp_prev & GP2X_SELECT;\r
367b6f1f 131\r
720ee7f6 132 return ret;\r
133}\r
134\r
c7a4ff64 135static void menu_flip(void)\r
136{\r
137 gp2x_video_flush_cache();\r
138 gp2x_video_flip2();\r
139}\r
720ee7f6 140\r
141\r
b9f8cb3d 142// --------- loading ROM screen ----------\r
143\r
677b5dd8 144static int cdload_called = 0;\r
145\r
b9f8cb3d 146static void load_progress_cb(int percent)\r
147{\r
148 int ln, len = percent * 320 / 100;\r
13059a60 149 unsigned short *dst = (unsigned short *)gp2x_screen + 320*20;\r
b9f8cb3d 150\r
151 if (len > 320) len = 320;\r
677b5dd8 152 for (ln = 8; ln > 0; ln--, dst += 320)\r
13059a60 153 memset(dst, 0xff, len*2);\r
154 menu_flip();\r
b9f8cb3d 155}\r
156\r
677b5dd8 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
6245d5a0 166 dst += 320*30;\r
677b5dd8 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
6245d5a0 171 menu_flip();\r
677b5dd8 172 cdload_called = 1;\r
173}\r
174\r
b9f8cb3d 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
144a28a0 180 if (rom_loaded) gp2x_pd_clone_buffer2();\r
13059a60 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
b9f8cb3d 187 PicoCartLoadProgressCB = load_progress_cb;\r
677b5dd8 188 PicoCDLoadProgressCB = cdload_progress_cb;\r
189 cdload_called = 0;\r
b9f8cb3d 190}\r
191\r
192void menu_romload_end(void)\r
193{\r
6245d5a0 194 PicoCartLoadProgressCB = PicoCDLoadProgressCB = NULL;\r
677b5dd8 195 smalltext_out16(1, cdload_called ? 60 : 30, "Starting emulation...", 0xffff);\r
13059a60 196 menu_flip();\r
b9f8cb3d 197}\r
198\r
720ee7f6 199// -------------- ROM selector --------------\r
200\r
13059a60 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
1ceda417 205 static const char *rom_exts[] = { "zip", "bin", "smd", "gen", "iso", "cso", "cue" };\r
13059a60 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
720ee7f6 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
f9a37a02 224 gp2x_pd_clone_buffer2();\r
225\r
144a28a0 226 if (!rom_loaded) {\r
f9a37a02 227 menu_darken_bg(gp2x_screen, 320*240, 0);\r
13059a60 228 }\r
229\r
f9a37a02 230 menu_darken_bg((char *)gp2x_screen + 320*120*2, 320*8, 0);\r
720ee7f6 231\r
232 if(start - 2 >= 0)\r
13059a60 233 smalltext_out16_lim(14, (start - 2)*10, curdir, 0xffff, 53-2);\r
720ee7f6 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
13059a60 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
720ee7f6 241 } else {\r
13059a60 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
720ee7f6 244 }\r
245 }\r
13059a60 246 text_out16(5, 120, ">");\r
247 menu_flip();\r
720ee7f6 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
79cad122 259static char *filter_exts[] = {\r
260 ".mp3", ".MP3", ".srm", ".brm", "s.gz", ".mds", "bcfg", ".txt", ".htm", "html",\r
1ceda417 261 ".jpg", ".gpe"\r
79cad122 262};\r
0d0558bd 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
720ee7f6 281\r
55c7b464 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
720ee7f6 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
55c7b464 315rescan:\r
720ee7f6 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
0d0558bd 326 n = scandir(curr_path, &namelist, scandir_filter, scandir_cmp);\r
720ee7f6 327 if (n < 0) {\r
328 // try root\r
0d0558bd 329 n = scandir("/", &namelist, scandir_filter, scandir_cmp);\r
720ee7f6 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
55c7b464 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
720ee7f6 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
5e2e14f2 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
55c7b464 359 if ((inp & GP2X_B) || (inp & (GP2X_SELECT|GP2X_A)) == (GP2X_SELECT|GP2X_A)) // enter dir/select || delete\r
360 {\r
720ee7f6 361 again:\r
55c7b464 362 if (namelist[sel+1]->d_type == DT_REG)\r
363 {\r
720ee7f6 364 strcpy(romFileName, curr_path);\r
365 strcat(romFileName, "/");\r
366 strcat(romFileName, namelist[sel+1]->d_name);\r
55c7b464 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
720ee7f6 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
55c7b464 402 }\r
403 else\r
404 {\r
720ee7f6 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
55c7b464 425 while (n--) free(namelist[n]);\r
720ee7f6 426 free(namelist);\r
427 }\r
428\r
429 return ret;\r
430}\r
431\r
0ae6813e 432// ------------ debug menu ------------\r
433\r
434char *debugString(void);\r
2707a9cb 435void PicoDrawShowSpriteStats(unsigned short *screen);\r
436void PicoDrawShowPalette(unsigned short *screen);\r
0ae6813e 437\r
2707a9cb 438static void draw_main_debug(void)\r
0ae6813e 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
13059a60 451 smalltext_out16_lim(1, line*10, str, 0xffff, len);\r
0ae6813e 452 if (*p == 0) break;\r
453 p++; str = p;\r
454 }\r
2707a9cb 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
84e21f25 466 emu_forcedFrame(0);\r
2707a9cb 467 smalltext_out16(4, 232, layer_str, 0xffff);\r
0ae6813e 468}\r
469\r
470static void debug_menu_loop(void)\r
471{\r
2707a9cb 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
0ae6813e 496}\r
497\r
70d2ecc5 498// ------------ patch/gg menu ------------\r
499\r
500static void draw_patchlist(int sel)\r
501{\r
13059a60 502 int start, i, pos, active;\r
70d2ecc5 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
13059a60 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
70d2ecc5 515 }\r
516 pos = start + i;\r
13059a60 517 if (pos < 24) smalltext_out16_lim(14, pos*10, "done", 0xffff, 4);\r
70d2ecc5 518\r
13059a60 519 text_out16(5, 120, ">");\r
520 menu_flip();\r
70d2ecc5 521}\r
522\r
523\r
0ae6813e 524static void patches_menu_loop(void)\r
70d2ecc5 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
4ffd2858 547// ------------ savestate loader ------------\r
548\r
4ffd2858 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
f013066e 559 if (emu_checkSaveFile(slot))\r
4ffd2858 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
f013066e 587 emu_setSaveStateCbs(1);\r
4ffd2858 588 } else {\r
589 file = fopen(fname, "rb");\r
f013066e 590 emu_setSaveStateCbs(0);\r
4ffd2858 591 }\r
592\r
593 if (file) {\r
dd5fd477 594 if (PicoAHW & PAHW_MCD) {\r
4ffd2858 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
84e21f25 608 emu_forcedFrame(POPT_EN_SOFTSCALE);\r
13059a60 609 menu_prepare_bg(1);\r
4ffd2858 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
13059a60 626 text_out16(tl_x, 30, is_loading ? "Load state" : "Save state");\r
627\r
c7a4ff64 628 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 108);\r
4ffd2858 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
13059a60 634 text_out16(tl_x, y, "SLOT %i (%s)", i, (state_slot_flags & (1 << i)) ? "USED" : "free");\r
4ffd2858 635 }\r
13059a60 636 text_out16(tl_x, y, "back");\r
4ffd2858 637\r
13059a60 638 menu_flip();\r
4ffd2858 639}\r
640\r
641static int savestate_menu_loop(int is_loading)\r
642{\r
59d0f042 643 static int menu_sel = 10;\r
644 int menu_sel_max = 10;\r
4ffd2858 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
720ee7f6 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
95151aea 693static char *action_binds(int player_idx, int action_mask)\r
720ee7f6 694{\r
95151aea 695 static char strkeys[32*5];\r
720ee7f6 696 int joy, i;\r
697\r
698 strkeys[0] = 0;\r
95151aea 699 for (i = 0; i < 32; i++) // i is key index\r
720ee7f6 700 {\r
95151aea 701 if (currentConfig.KeyBinds[i] & action_mask)\r
720ee7f6 702 {\r
95151aea 703 if (player_idx >= 0 && ((currentConfig.KeyBinds[i] >> 16) & 3) != player_idx) continue;\r
367b6f1f 704 if (strkeys[0]) { strcat(strkeys, " + "); strcat(strkeys, keyNames[i]); break; }\r
705 else strcpy(strkeys, keyNames[i]);\r
720ee7f6 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
95151aea 712 if (currentConfig.JoyBinds[joy][i] & action_mask)\r
720ee7f6 713 {\r
95151aea 714 if (player_idx >= 0 && ((currentConfig.JoyBinds[joy][i] >> 16) & 3) != player_idx) continue;\r
720ee7f6 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
e67f6454 724 // limit..\r
725 strkeys[20] = 0;\r
726\r
95151aea 727 return strkeys;\r
728}\r
729\r
e67f6454 730static void unbind_action(int action, int pl_idx, int joy)\r
95151aea 731{\r
732 int i, u;\r
733\r
e67f6454 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
b4c711c3 740 }\r
e67f6454 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
b4c711c3 751 for (i = 0; i < 32; i++) {\r
e67f6454 752 if (pl_idx >= 0 && (currentConfig.JoyBinds[joy-1][i]&0x30000) != (pl_idx<<16)) continue;\r
753 currentConfig.JoyBinds[joy-1][i] &= ~action;\r
b4c711c3 754 }\r
e67f6454 755 }\r
95151aea 756}\r
757\r
b4c711c3 758static int count_bound_keys(int action, int pl_idx, int joy)\r
95151aea 759{\r
760 int i, keys = 0;\r
761\r
762 if (joy)\r
763 {\r
b4c711c3 764 for (i = 0; i < 32; i++) {\r
765 if (pl_idx >= 0 && (currentConfig.JoyBinds[joy-1][i]&0x30000) != (pl_idx<<16)) continue;\r
95151aea 766 if (currentConfig.JoyBinds[joy-1][i] & action) keys++;\r
b4c711c3 767 }\r
95151aea 768 }\r
769 else\r
770 {\r
b4c711c3 771 for (i = 0; i < 32; i++) {\r
772 if (pl_idx >= 0 && (currentConfig.KeyBinds[i]&0x30000) != (pl_idx<<16)) continue;\r
95151aea 773 if (currentConfig.KeyBinds[i] & action) keys++;\r
b4c711c3 774 }\r
95151aea 775 }\r
776 return keys;\r
777}\r
778\r
367b6f1f 779static void draw_key_config(const me_bind_action *opts, int opt_cnt, int player_idx, int sel)\r
95151aea 780{\r
781 int x, y, tl_y = 40, i;\r
782\r
e5d315a5 783 gp2x_pd_clone_buffer2();\r
95151aea 784 if (player_idx >= 0) {\r
13059a60 785 text_out16(80, 20, "Player %i controls", player_idx + 1);\r
b4c711c3 786 x = 80;\r
95151aea 787 } else {\r
13059a60 788 text_out16(80, 20, "Emulator controls");\r
95151aea 789 x = 40;\r
790 }\r
791\r
e1cd546f 792 menu_draw_selection(x - 16, tl_y + sel*10, (player_idx >= 0) ? 66 : 140);\r
13059a60 793\r
95151aea 794 y = tl_y;\r
795 for (i = 0; i < opt_cnt; i++, y+=10)\r
13059a60 796 text_out16(x, y, "%s : %s", opts[i].name, action_binds(player_idx, opts[i].mask));\r
95151aea 797\r
13059a60 798 text_out16(x, y, "Done");\r
95151aea 799\r
800 if (sel < opt_cnt) {\r
13059a60 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
95151aea 805 } else {\r
13059a60 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
95151aea 809 }\r
13059a60 810 menu_flip();\r
720ee7f6 811}\r
812\r
367b6f1f 813static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_idx)\r
720ee7f6 814{\r
95151aea 815 int joy = 0, sel = 0, menu_sel_max = opt_cnt, prev_select = 0, i;\r
720ee7f6 816 unsigned long inp = 0;\r
817\r
818 for (;;)\r
819 {\r
95151aea 820 draw_key_config(opts, opt_cnt, player_idx, sel);\r
720ee7f6 821 inp = wait_for_input_usbjoy(CONFIGURABLE_KEYS, &joy);\r
822 // printf("got %08lX from joy %i\n", inp, joy);\r
558d8e1f 823 if (joy == 0)\r
824 {\r
95151aea 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
720ee7f6 829 }\r
95151aea 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
e67f6454 836 unbind_action(opts[sel].mask, player_idx, -1);\r
95151aea 837 prev_select = inp & GP2X_SELECT;\r
720ee7f6 838 inp &= CONFIGURABLE_KEYS;\r
839 inp &= ~GP2X_SELECT;\r
720ee7f6 840 for (i = 0; i < 32; i++)\r
841 if (inp & (1 << i)) {\r
b4c711c3 842 if (count_bound_keys(opts[sel].mask, player_idx, 0) >= 2)\r
95151aea 843 currentConfig.KeyBinds[i] &= ~opts[sel].mask; // allow to unbind only\r
844 else currentConfig.KeyBinds[i] ^= opts[sel].mask;\r
7695af0a 845 if (player_idx >= 0 && (currentConfig.KeyBinds[i] & opts[sel].mask)) {\r
95151aea 846 currentConfig.KeyBinds[i] &= ~(3 << 16);\r
847 currentConfig.KeyBinds[i] |= player_idx << 16;\r
848 }\r
720ee7f6 849 }\r
95151aea 850 }\r
851 else if (sel < opt_cnt)\r
852 {\r
720ee7f6 853 for (i = 0; i < 32; i++)\r
854 if (inp & (1 << i)) {\r
e67f6454 855 int *bind = &currentConfig.JoyBinds[joy-1][i];\r
856 if ((*bind & opts[sel].mask) && (player_idx < 0 || player_idx == ((*bind>>16)&3)))\r
367b6f1f 857 *bind &= ~opts[sel].mask;\r
e67f6454 858 else {\r
859 // override\r
860 unbind_action(opts[sel].mask, player_idx, joy);\r
861 *bind = opts[sel].mask;\r
367b6f1f 862 if (player_idx > 0) *bind |= player_idx << 16;\r
95151aea 863 }\r
720ee7f6 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
e5d315a5 875 gp2x_pd_clone_buffer2();\r
c7a4ff64 876 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 138);\r
720ee7f6 877\r
13059a60 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
720ee7f6 882\r
883 tl_x = 25;\r
13059a60 884 text_out16(tl_x, (y=110), "USB joys detected:");\r
720ee7f6 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
13059a60 888 text_out16(tl_x, (y+=10), "%i: %s", i+1, joyname);\r
720ee7f6 889 }\r
890 } else {\r
13059a60 891 text_out16(tl_x, (y+=10), "none");\r
720ee7f6 892 }\r
893\r
13059a60 894 menu_flip();\r
720ee7f6 895}\r
896\r
95151aea 897\r
e1cd546f 898// player2_flag, reserved, ?, ?,\r
899// ?, ?, fast forward, menu\r
95151aea 900// "NEXT SAVE SLOT", "PREV SAVE SLOT", "SWITCH RENDERER", "SAVE STATE",\r
901// "LOAD STATE", "VOLUME UP", "VOLUME DOWN", "DONE"\r
367b6f1f 902me_bind_action emuctrl_actions[] =\r
95151aea 903{\r
e1cd546f 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
95151aea 917};\r
918\r
720ee7f6 919static void kc_sel_loop(void)\r
920{\r
95151aea 921 int menu_sel = 3, menu_sel_max = 3;\r
720ee7f6 922 unsigned long inp = 0;\r
dd5fd477 923 int is_6button = PicoOpt & POPT_6BTN_PAD;\r
720ee7f6 924\r
95151aea 925 while (1)\r
720ee7f6 926 {\r
927 draw_kc_sel(menu_sel);\r
928 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X);\r
95151aea 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
720ee7f6 932 switch (menu_sel) {\r
367b6f1f 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
95151aea 935 case 2: key_config_loop(emuctrl_actions,\r
8e708f92 936 sizeof(emuctrl_actions)/sizeof(emuctrl_actions[0]) - 1, -1); return;\r
144a28a0 937 case 3: if (!rom_loaded) emu_WriteConfig(0); return;\r
720ee7f6 938 default: return;\r
939 }\r
940 }\r
95151aea 941 if (inp & GP2X_X) return;\r
720ee7f6 942 }\r
943}\r
944\r
945\r
daf91588 946// --------- sega/mega cd options ----------\r
947\r
59633198 948menu_entry cdopt_entries[] =\r
daf91588 949{\r
0ae25549 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
59633198 961};\r
962\r
963#define CDOPT_ENTRY_COUNT (sizeof(cdopt_entries) / sizeof(cdopt_entries[0]))\r
30d5518a 964const int cdopt_entry_count = CDOPT_ENTRY_COUNT;\r
59633198 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
13059a60 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
59633198 982 case MA_CDOPT_READAHEAD:\r
983 if (PicoCDBuffers > 1) sprintf(ra_buff, "%5iK", PicoCDBuffers * 2);\r
984 else strcpy(ra_buff, " OFF");\r
13059a60 985 text_out16(x, y, "ReadAhead buffer %s", ra_buff);\r
59633198 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
5f9922e6 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
daf91588 999\r
e5d315a5 1000 gp2x_pd_clone_buffer2();\r
1001\r
c7a4ff64 1002 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 246);\r
daf91588 1003\r
13059a60 1004 me_draw(cdopt_entries, CDOPT_ENTRY_COUNT, tl_x, tl_y, menu_cdopt_cust_draw, bios_names);\r
daf91588 1005\r
59633198 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
13059a60 1010 text_out16(tl_x, 210, "Press start to test selected BIOS");\r
daf91588 1011\r
13059a60 1012 menu_flip();\r
daf91588 1013}\r
1014\r
1015static void cd_menu_loop_options(void)\r
1016{\r
59d0f042 1017 static int menu_sel = 0;\r
1018 int menu_sel_max = 10;\r
daf91588 1019 unsigned long inp = 0;\r
59633198 1020 struct bios_names_t bios_names;\r
1021 menu_id selected_id;\r
1022 char *bios, *p;\r
daf91588 1023\r
f013066e 1024 if (emu_findBios(4, &bios)) { // US\r
daf91588 1025 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
59633198 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
daf91588 1028\r
f013066e 1029 if (emu_findBios(8, &bios)) { // EU\r
daf91588 1030 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
59633198 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
daf91588 1033\r
f013066e 1034 if (emu_findBios(1, &bios)) { // JP\r
daf91588 1035 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
59633198 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
daf91588 1038\r
1039 for(;;)\r
1040 {\r
59633198 1041 draw_cd_menu_options(menu_sel, &bios_names);\r
daf91588 1042 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A|GP2X_START);\r
59633198 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
88bfc63d 1051 if (PicoCDBuffers < 2) PicoCDBuffers = 0;\r
59633198 1052 } else {\r
88bfc63d 1053 if (PicoCDBuffers < 2) PicoCDBuffers = 2;\r
59633198 1054 else PicoCDBuffers <<= 1;\r
1055 if (PicoCDBuffers > 8*1024) PicoCDBuffers = 8*1024; // 16M\r
1056 }\r
daf91588 1057 }\r
1058 }\r
59633198 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
f013066e 1068 if (emu_findBios(4, &bios)) { // test US\r
daf91588 1069 strcpy(romFileName, bios);\r
1070 engineState = PGS_ReloadRom;\r
1071 return;\r
1072 }\r
1073 break;\r
59633198 1074 case MA_CDOPT_TESTBIOS_EUR:\r
f013066e 1075 if (emu_findBios(8, &bios)) { // test EU\r
daf91588 1076 strcpy(romFileName, bios);\r
1077 engineState = PGS_ReloadRom;\r
1078 return;\r
1079 }\r
1080 break;\r
59633198 1081 case MA_CDOPT_TESTBIOS_JAP:\r
f013066e 1082 if (emu_findBios(1, &bios)) { // test JP\r
daf91588 1083 strcpy(romFileName, bios);\r
1084 engineState = PGS_ReloadRom;\r
1085 return;\r
1086 }\r
1087 break;\r
59633198 1088 default:\r
1089 break;\r
daf91588 1090 }\r
1091 }\r
59633198 1092 if (inp & (GP2X_X|GP2X_A)) return;\r
daf91588 1093 }\r
1094}\r
1095\r
1096\r
1097// --------- advanced options ----------\r
1098\r
59633198 1099menu_entry opt2_entries[] =\r
1100{\r
0ae25549 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
30d5518a 1104 { "Disable sprite limit", MB_ONOFF, MA_OPT2_NO_SPRITE_LIM, &PicoOpt, 0x40000, 0, 0, 1, 1 },\r
367b6f1f 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
0ae25549 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
367b6f1f 1113 { "SVP dynarec", MB_ONOFF, MA_OPT2_SVP_DYNAREC, &PicoOpt, 0x20000, 0, 0, 1, 1 },\r
260f1bcc 1114 { "Disable idle loop patching",MB_ONOFF, MA_OPT2_NO_IDLE_LOOPS, &PicoOpt, 0x80000, 0, 0, 1, 1 },\r
0ae25549 1115 { "done", MB_NONE, MA_OPT2_DONE, NULL, 0, 0, 0, 1, 0 },\r
59633198 1116};\r
1117\r
1118#define OPT2_ENTRY_COUNT (sizeof(opt2_entries) / sizeof(opt2_entries[0]))\r
30d5518a 1119const int opt2_entry_count = OPT2_ENTRY_COUNT;\r
59633198 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
13059a60 1124 text_out16(x, y, "Gamma correction %i.%02i", currentConfig.gamma / 100, currentConfig.gamma%100);\r
59633198 1125 else if (entry->id == MA_OPT2_SQUIDGEHACK)\r
0ae25549 1126 text_out16(x, y, "Squidgehack (now %s %s", mmuhack_status ? "active) " : "inactive)",\r
59633198 1127 (currentConfig.EmuOpt&0x0010)?"ON":"OFF");\r
1128}\r
1129\r
1130\r
720ee7f6 1131static void draw_amenu_options(int menu_sel)\r
1132{\r
59633198 1133 int tl_x = 25, tl_y = 50;\r
720ee7f6 1134\r
e5d315a5 1135 gp2x_pd_clone_buffer2();\r
1136\r
c7a4ff64 1137 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 252);\r
720ee7f6 1138\r
13059a60 1139 me_draw(opt2_entries, OPT2_ENTRY_COUNT, tl_x, tl_y, menu_opt2_cust_draw, NULL);\r
720ee7f6 1140\r
13059a60 1141 menu_flip();\r
720ee7f6 1142}\r
1143\r
1144static void amenu_loop_options(void)\r
1145{\r
59d0f042 1146 static int menu_sel = 0;\r
59633198 1147 int menu_sel_max;\r
720ee7f6 1148 unsigned long inp = 0;\r
59633198 1149 menu_id selected_id;\r
1150\r
1151 menu_sel_max = me_count_enabled(opt2_entries, OPT2_ENTRY_COUNT) - 1;\r
720ee7f6 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
59633198 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
720ee7f6 1170 }\r
1171 }\r
59633198 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
720ee7f6 1176 }\r
1177 }\r
59633198 1178 if (inp & (GP2X_X|GP2X_A)) return;\r
720ee7f6 1179 }\r
1180}\r
1181\r
1182// -------------- options --------------\r
1183\r
59633198 1184\r
1185menu_entry opt_entries[] =\r
1186{\r
0ae25549 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
0ae25549 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
59633198 1206};\r
1207\r
1208#define OPT_ENTRY_COUNT (sizeof(opt_entries) / sizeof(opt_entries[0]))\r
0ae25549 1209const int opt_entry_count = OPT_ENTRY_COUNT;\r
720ee7f6 1210\r
59633198 1211\r
1212static void menu_opt_cust_draw(const menu_entry *entry, int x, int y, void *param)\r
720ee7f6 1213{\r
59633198 1214 char *str, str24[24];\r
1215\r
1216 switch (entry->id)\r
1217 {\r
1218 case MA_OPT_RENDERER:\r
dd5fd477 1219 if (PicoOpt & POPT_ALT_RENDERER)\r
59633198 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
13059a60 1225 text_out16(x, y, "Renderer: %s", str);\r
59633198 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
13059a60 1234 text_out16(x, y, "Scaling: %s", str);\r
59633198 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
13059a60 1240 text_out16(x, y, "Frameskip %s", str24);\r
59633198 1241 break;\r
1242 case MA_OPT_SOUND_QUALITY:\r
dd5fd477 1243 str = (PicoOpt & POPT_EN_STEREO) ? "stereo" : "mono";\r
0ae25549 1244 text_out16(x, y, "Sound Quality: %5iHz %s", PsndRate, str);\r
59633198 1245 break;\r
1246 case MA_OPT_REGION:\r
0ae25549 1247 text_out16(x, y, "Region: %s", me_region_name(PicoRegionOverride, PicoAutoRgnOrder));\r
59633198 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
13059a60 1256 text_out16(x, y, "Confirm savestate %s", str);\r
59633198 1257 break;\r
1258 case MA_OPT_CPU_CLOCKS:\r
13059a60 1259 text_out16(x, y, "GP2X CPU clocks %iMhz", currentConfig.CPUclock);\r
59633198 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
13059a60 1264 text_out16(x, y, "Save cfg as default%s", str24);\r
59633198 1265 break;\r
1266 case MA_OPT_LOADCFG:\r
13059a60 1267 text_out16(x, y, "Load cfg from profile %i", config_slot);\r
59633198 1268 break;\r
1269 default:\r
1270 printf("%s: unimplemented (%i)\n", __FUNCTION__, entry->id);\r
1271 break;\r
46ede6a6 1272 }\r
59633198 1273}\r
1274\r
1275\r
1276\r
1277static void draw_menu_options(int menu_sel)\r
1278{\r
13059a60 1279 int tl_x = 25, tl_y = 24;\r
720ee7f6 1280\r
e5d315a5 1281 gp2x_pd_clone_buffer2();\r
1282\r
c7a4ff64 1283 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 284);\r
720ee7f6 1284\r
13059a60 1285 me_draw(opt_entries, OPT_ENTRY_COUNT, tl_x, tl_y, menu_opt_cust_draw, NULL);\r
720ee7f6 1286\r
13059a60 1287 menu_flip();\r
720ee7f6 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
979ba09f 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
0ae25549 1309 if (!PicoRegionOverride) {\r
979ba09f 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
0ae25549 1313 else PicoRegionOverride=1;\r
979ba09f 1314 }\r
0ae25549 1315 else PicoRegionOverride<<=1;\r
1316 if (PicoRegionOverride > 8) PicoRegionOverride = 8;\r
979ba09f 1317 } else {\r
0ae25549 1318 if (!PicoRegionOverride) {\r
979ba09f 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
0ae25549 1323 else PicoRegionOverride>>=1;\r
979ba09f 1324 }\r
1325}\r
1326\r
720ee7f6 1327static void menu_options_save(void)\r
1328{\r
426ecc58 1329 if (PicoRegionOverride) {\r
1330 // force setting possibly changed..\r
1331 Pico.m.pal = (PicoRegionOverride == 2 || PicoRegionOverride == 8) ? 1 : 0;\r
1332 }\r
dd5fd477 1333 if (!(PicoOpt & POPT_6BTN_PAD)) {\r
95151aea 1334 // unbind XYZ MODE, just in case\r
e67f6454 1335 unbind_action(0xf00, -1, -1);\r
720ee7f6 1336 }\r
1337}\r
1338\r
daf91588 1339static int menu_loop_options(void)\r
720ee7f6 1340{\r
59d0f042 1341 static int menu_sel = 0;\r
59633198 1342 int menu_sel_max, ret;\r
720ee7f6 1343 unsigned long inp = 0;\r
59633198 1344 menu_id selected_id;\r
720ee7f6 1345\r
144a28a0 1346 me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_SAVECFG_GAME, rom_loaded);\r
59633198 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
95151aea 1349 if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;\r
59633198 1350\r
1351 while (1)\r
720ee7f6 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
59633198 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
0ae25549 1358 if (inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choice\r
59633198 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
0ae25549 1363 if (PicoOpt&0x10) PicoOpt&= ~0x10;\r
59633198 1364 else if (!(currentConfig.EmuOpt &0x80))currentConfig.EmuOpt |= 0x80;\r
1365 else if ( currentConfig.EmuOpt &0x80) break;\r
1366 } else {\r
0ae25549 1367 if (PicoOpt&0x10) break;\r
1368 else if (!(currentConfig.EmuOpt &0x80))PicoOpt|= 0x10;\r
59633198 1369 else if ( currentConfig.EmuOpt &0x80) currentConfig.EmuOpt &= ~0x80;\r
1370 }\r
1371 break;\r
1372 case MA_OPT_SOUND_QUALITY:\r
0ae25549 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
59633198 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
95151aea 1445 ret = emu_ReadConfig(1, 1);\r
1446 if (!ret) ret = emu_ReadConfig(0, 1);\r
1447 if (ret) strcpy(menuErrorMsg, "config loaded");\r
59633198 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
720ee7f6 1454 }\r
1455 }\r
979ba09f 1456 if(inp & (GP2X_X|GP2X_A)) {\r
720ee7f6 1457 menu_options_save();\r
daf91588 1458 return 0; // done (update, no write)\r
720ee7f6 1459 }\r
720ee7f6 1460 }\r
1461}\r
1462\r
1463// -------------- credits --------------\r
1464\r
1465static void draw_menu_credits(void)\r
1466{\r
260f1bcc 1467 int tl_x = 15, tl_y = 56, y;\r
e5d315a5 1468 gp2x_pd_clone_buffer2();\r
720ee7f6 1469\r
30d5518a 1470 text_out16(tl_x, 20, "PicoDrive v" VERSION " (c) notaz, 2006-2008");\r
720ee7f6 1471 y = tl_y;\r
13059a60 1472 text_out16(tl_x, y, "Credits:");\r
4b8f4f3c 1473 text_out16(tl_x, (y+=10), "fDave: Cyclone 68000 core,");\r
13059a60 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
13059a60 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
260f1bcc 1480 text_out16(tl_x, (y+=10), "GnoStiC / Puck2099: USB joy code");\r
13059a60 1481 text_out16(tl_x, (y+=10), "craigix: GP2X hardware");\r
f9a37a02 1482 text_out16(tl_x, (y+=10), "ketchupgun: skin design");\r
13059a60 1483\r
7a938d57 1484 text_out16(tl_x, (y+=20), "special thanks (for docs, ideas):");\r
260f1bcc 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
13059a60 1490 menu_flip();\r
720ee7f6 1491}\r
1492\r
1493\r
1494// -------------- root menu --------------\r
1495\r
59633198 1496menu_entry main_entries[] =\r
1497{\r
0ae25549 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
59633198 1508};\r
1509\r
1510#define MAIN_ENTRY_COUNT (sizeof(main_entries) / sizeof(main_entries[0]))\r
1511\r
720ee7f6 1512static void draw_menu_root(int menu_sel)\r
1513{\r
59633198 1514 const int tl_x = 70, tl_y = 70;\r
1515\r
e5d315a5 1516 gp2x_pd_clone_buffer2();\r
720ee7f6 1517\r
13059a60 1518 text_out16(tl_x, 20, "PicoDrive v" VERSION);\r
1519\r
c7a4ff64 1520 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 146);\r
720ee7f6 1521\r
59633198 1522 me_draw(main_entries, MAIN_ENTRY_COUNT, tl_x, tl_y, NULL, NULL);\r
720ee7f6 1523\r
720ee7f6 1524 // error\r
13059a60 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
720ee7f6 1530}\r
1531\r
1532\r
1533static void menu_loop_root(void)\r
1534{\r
59633198 1535 static int menu_sel = 0;\r
1536 int ret, menu_sel_max;\r
720ee7f6 1537 unsigned long inp = 0;\r
720ee7f6 1538\r
144a28a0 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
59633198 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
95151aea 1546 if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;\r
720ee7f6 1547\r
79cad122 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
720ee7f6 1553 {\r
1554 draw_menu_root(menu_sel);\r
0ae6813e 1555 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X|GP2X_SELECT|GP2X_L|GP2X_R);\r
59633198 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
0ae6813e 1558 if((inp & (GP2X_L|GP2X_R)) == (GP2X_L|GP2X_R)) debug_menu_loop();\r
720ee7f6 1559 if(inp &(GP2X_SELECT|GP2X_X)){\r
144a28a0 1560 if (rom_loaded) {\r
720ee7f6 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
59633198 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
144a28a0 1570 if (rom_loaded) {\r
5e2e14f2 1571 while (gp2x_joystick_read(1) & GP2X_B) usleep(50*1000);\r
1572 engineState = PGS_Running;\r
1573 return;\r
1574 }\r
720ee7f6 1575 break;\r
59633198 1576 case MA_MAIN_SAVE_STATE:\r
144a28a0 1577 if (rom_loaded) {\r
4ffd2858 1578 if(savestate_menu_loop(0))\r
720ee7f6 1579 continue;\r
720ee7f6 1580 engineState = PGS_Running;\r
1581 return;\r
1582 }\r
1583 break;\r
59633198 1584 case MA_MAIN_LOAD_STATE:\r
144a28a0 1585 if (rom_loaded) {\r
4ffd2858 1586 if(savestate_menu_loop(1))\r
720ee7f6 1587 continue;\r
446b090c 1588 while (gp2x_joystick_read(1) & GP2X_B) usleep(50*1000);\r
720ee7f6 1589 engineState = PGS_Running;\r
1590 return;\r
1591 }\r
1592 break;\r
59633198 1593 case MA_MAIN_RESET_GAME:\r
144a28a0 1594 if (rom_loaded) {\r
720ee7f6 1595 emu_ResetGame();\r
446b090c 1596 while (gp2x_joystick_read(1) & GP2X_B) usleep(50*1000);\r
720ee7f6 1597 engineState = PGS_Running;\r
1598 return;\r
1599 }\r
1600 break;\r
59633198 1601 case MA_MAIN_LOAD_ROM:\r
13059a60 1602 {\r
1603 char curr_path[PATH_MAX], *selfname;\r
1604 FILE *tstf;\r
367b6f1f 1605 if ( (tstf = fopen(lastRomFile, "rb")) )\r
13059a60 1606 {\r
1607 fclose(tstf);\r
367b6f1f 1608 strcpy(curr_path, lastRomFile);\r
13059a60 1609 }\r
1610 else\r
1611 getcwd(curr_path, PATH_MAX);\r
720ee7f6 1612 selfname = romsel_loop(curr_path);\r
1613 if (selfname) {\r
1614 printf("selected file: %s\n", selfname);\r
720ee7f6 1615 engineState = PGS_ReloadRom;\r
13059a60 1616 return;\r
720ee7f6 1617 }\r
13059a60 1618 break;\r
1619 }\r
59633198 1620 case MA_MAIN_OPTIONS:\r
daf91588 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
720ee7f6 1625 break;\r
59633198 1626 case MA_MAIN_CONTROLS:\r
720ee7f6 1627 kc_sel_loop();\r
1628 break;\r
59633198 1629 case MA_MAIN_CREDITS:\r
720ee7f6 1630 draw_menu_credits();\r
1631 usleep(500*1000);\r
1632 inp = wait_for_input(GP2X_B|GP2X_X);\r
1633 break;\r
59633198 1634 case MA_MAIN_EXIT:\r
720ee7f6 1635 engineState = PGS_Quit;\r
1636 return;\r
59633198 1637 case MA_MAIN_PATCHES:\r
144a28a0 1638 if (rom_loaded && PicoPatches) {\r
70d2ecc5 1639 patches_menu_loop();\r
1640 PicoPatchApply();\r
1641 strcpy(menuErrorMsg, "Patches applied");\r
1642 continue;\r
1643 }\r
1644 break;\r
59633198 1645 default:\r
1646 printf("%s: something unknown selected\n", __FUNCTION__);\r
1647 break;\r
720ee7f6 1648 }\r
1649 }\r
1650 menuErrorMsg[0] = 0; // clear error msg\r
1651 }\r
1652}\r
1653\r
f9a37a02 1654static void menu_darken_bg(void *dst, int pixels, int darker)\r
720ee7f6 1655{\r
13059a60 1656 unsigned int *screen = dst;\r
1657 pixels /= 2;\r
f9a37a02 1658 if (darker)\r
13059a60 1659 {\r
f9a37a02 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
13059a60 1673 }\r
1674}\r
e5d315a5 1675\r
13059a60 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
f9a37a02 1682 menu_darken_bg((char *)gp2x_screen + 320*8*2, 320*224, 1);\r
13059a60 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
4ffd2858 1689 }\r
720ee7f6 1690\r
13059a60 1691 // copy to buffer2\r
1692 gp2x_memcpy_buffers((1<<2), gp2x_screen, 0, 320*240*2);\r
4ffd2858 1693}\r
1694\r
1695static void menu_gfx_prepare(void)\r
1696{\r
144a28a0 1697 menu_prepare_bg(rom_loaded);\r
4ffd2858 1698\r
13059a60 1699 // switch to 16bpp\r
1700 gp2x_video_changemode2(16);\r
79cad122 1701 gp2x_video_RGB_setscaling(0, 320, 240);\r
13059a60 1702 menu_flip();\r
e5d315a5 1703}\r
1704\r
1705\r
1706void menu_loop(void)\r
1707{\r
1708 menu_gfx_prepare();\r
720ee7f6 1709\r
1710 menu_loop_root();\r
1711\r
1712 menuErrorMsg[0] = 0;\r
1713}\r
5e2e14f2 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
13059a60 1721 memset(gp2x_screen, 0, 320*240*2);\r
5e2e14f2 1722\r
13059a60 1723 text_out16(tl_x, 20, "The unit is about to");\r
1724 text_out16(tl_x, 30, "close the CD tray.");\r
5e2e14f2 1725\r
1726 y = tl_y;\r
13059a60 1727 text_out16(tl_x, y, "Load new CD image");\r
1728 text_out16(tl_x, (y+=10), "Insert nothing");\r
5e2e14f2 1729\r
1730 // draw cursor\r
13059a60 1731 text_out16(tl_x - 16, tl_y + menu_sel*10, ">");\r
5e2e14f2 1732 // error\r
13059a60 1733 if (menuErrorMsg[0]) text_out16(5, 226, menuErrorMsg);\r
1734 menu_flip();\r
5e2e14f2 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
c7a4ff64 1745 gp2x_memset_all_buffers(0, 0, 320*240*2);\r
5e2e14f2 1746 menu_gfx_prepare();\r
1747\r
367b6f1f 1748 if ( (tstf = fopen(lastRomFile, "rb")) )\r
5e2e14f2 1749 {\r
1750 fclose(tstf);\r
367b6f1f 1751 strcpy(curr_path, lastRomFile);\r
5e2e14f2 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
1ceda417 1773 int ret = -1;\r
1774 cd_img_type cd_type;\r
f013066e 1775 cd_type = emu_cdCheck(NULL);\r
1ceda417 1776 if (cd_type != CIT_NOT_CD)\r
1777 ret = Insert_CD(romFileName, cd_type);\r
5e2e14f2 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