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