fonts, buffer aligment, save progress
[libpicofe.git] / gp2x / menu.c
CommitLineData
720ee7f6 1// (c) Copyright 2006 notaz, All rights reserved.\r
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
0805b5b4 16#include "fonts.h"\r
720ee7f6 17#include "usbjoy.h"\r
18#include "version.h"\r
19\r
20#include "Pico/PicoInt.h"\r
21\r
22#ifndef _DIRENT_HAVE_D_TYPE\r
23#error "need d_type for file browser\r
24#endif\r
25\r
26extern char *actionNames[];\r
27extern char romFileName[PATH_MAX];\r
28extern char *rom_data;\r
29extern int mmuhack_status;\r
30extern int state_slot;\r
31\r
32static char *gp2xKeyNames[] = {\r
33 "UP", "???", "LEFT", "???", "DOWN", "???", "RIGHT", "???",\r
34 "START", "SELECT", "L", "R", "A", "B", "X", "Y",\r
35 "???", "???", "???", "???", "???", "???", "VOL DOWN", "VOL UP",\r
36 "???", "???", "???", "PUSH", "???", "???", "???", "???"\r
37};\r
38\r
39char menuErrorMsg[40] = {0, };\r
40\r
41\r
0805b5b4 42static void gp2x_text(unsigned char *screen, int x, int y, const char *text, int color)\r
720ee7f6 43{\r
44 int i,l;\r
45\r
46 screen = screen + x + y*320;\r
47\r
48 for (i = 0; i < strlen(text); i++)\r
49 {\r
50 for (l=0;l<8;l++)\r
51 {\r
52 if(fontdata8x8[((text[i])*8)+l]&0x80) screen[l*320+0]=color;\r
53 if(fontdata8x8[((text[i])*8)+l]&0x40) screen[l*320+1]=color;\r
54 if(fontdata8x8[((text[i])*8)+l]&0x20) screen[l*320+2]=color;\r
55 if(fontdata8x8[((text[i])*8)+l]&0x10) screen[l*320+3]=color;\r
56 if(fontdata8x8[((text[i])*8)+l]&0x08) screen[l*320+4]=color;\r
57 if(fontdata8x8[((text[i])*8)+l]&0x04) screen[l*320+5]=color;\r
58 if(fontdata8x8[((text[i])*8)+l]&0x02) screen[l*320+6]=color;\r
59 if(fontdata8x8[((text[i])*8)+l]&0x01) screen[l*320+7]=color;\r
60 }\r
61 screen += 8;\r
62 }\r
63}\r
64\r
65// draws white text to current bbp15 screen\r
0805b5b4 66void gp2x_text_out15(int x, int y, const char *text)\r
720ee7f6 67{\r
68 int i,l;\r
69 unsigned short *screen = gp2x_screen;\r
70\r
71 screen = screen + x + y*320;\r
72\r
73 for (i = 0; i < strlen(text); i++)\r
74 {\r
75 for (l=0;l<8;l++)\r
76 {\r
77 if(fontdata8x8[((text[i])*8)+l]&0x80) screen[l*320+0]=0xffff;\r
78 if(fontdata8x8[((text[i])*8)+l]&0x40) screen[l*320+1]=0xffff;\r
79 if(fontdata8x8[((text[i])*8)+l]&0x20) screen[l*320+2]=0xffff;\r
80 if(fontdata8x8[((text[i])*8)+l]&0x10) screen[l*320+3]=0xffff;\r
81 if(fontdata8x8[((text[i])*8)+l]&0x08) screen[l*320+4]=0xffff;\r
82 if(fontdata8x8[((text[i])*8)+l]&0x04) screen[l*320+5]=0xffff;\r
83 if(fontdata8x8[((text[i])*8)+l]&0x02) screen[l*320+6]=0xffff;\r
84 if(fontdata8x8[((text[i])*8)+l]&0x01) screen[l*320+7]=0xffff;\r
85 }\r
86 screen += 8;\r
87 }\r
88}\r
89\r
90\r
0805b5b4 91void gp2x_text_out8(int x, int y, const char *texto, ...)\r
720ee7f6 92{\r
93 va_list args;\r
94 char buffer[512];\r
95\r
96 va_start(args,texto);\r
97 vsprintf(buffer,texto,args);\r
98 va_end(args);\r
99\r
e5d315a5 100 gp2x_text(gp2x_screen,x,y,buffer,0xf0);\r
720ee7f6 101}\r
102\r
103\r
0805b5b4 104void gp2x_text_out8_2(int x, int y, const char *texto, int color)\r
720ee7f6 105{\r
106 gp2x_text(gp2x_screen, x, y, texto, color);\r
107}\r
108\r
0805b5b4 109void gp2x_text_out8_lim(int x, int y, const char *texto, int max)\r
720ee7f6 110{\r
111 char buffer[320/8+1];\r
112\r
113 strncpy(buffer, texto, 320/8);\r
114 if (max > 320/8) max = 320/8;\r
115 if (max < 0) max = 0;\r
116 buffer[max] = 0;\r
117\r
e5d315a5 118 gp2x_text(gp2x_screen,x,y,buffer,0xf0);\r
720ee7f6 119}\r
120\r
0805b5b4 121static void gp2x_smalltext8(int x, int y, const char *texto)\r
122{\r
123 int i;\r
124 unsigned char *src, *dst;\r
125\r
126 for (i = 0;; i++, x += 6)\r
127 {\r
128 unsigned char c = (unsigned char) texto[i];\r
129 int h = 8;\r
130\r
131 if (!c) break;\r
132\r
133 src = fontdata6x8[c];\r
134 dst = (unsigned char *)gp2x_screen + x + y*320;\r
135\r
136 while (h--)\r
137 {\r
138 int w = 0x20;\r
139 while (w)\r
140 {\r
141 if( *src & w ) *dst = 0xf0;\r
142 dst++;\r
143 w>>=1;\r
144 }\r
145 src++;\r
146\r
147 dst += 320-6;\r
148 }\r
149 }\r
150}\r
151\r
152static void gp2x_smalltext8_lim(int x, int y, const char *texto, int max)\r
153{\r
154 char buffer[320/6+1];\r
155\r
156 strncpy(buffer, texto, 320/6);\r
157 if (max > 320/6) max = 320/6;\r
158 if (max < 0) max = 0;\r
159 buffer[max] = 0;\r
160\r
161 gp2x_smalltext8(x, y, buffer);\r
162}\r
163\r
720ee7f6 164\r
165static unsigned long inp_prev = 0;\r
166static int inp_prevjoy = 0;\r
167\r
168static unsigned long wait_for_input(unsigned long interesting)\r
169{\r
170 unsigned long ret;\r
171 static int repeats = 0, wait = 300*1000;\r
172 int release = 0, i;\r
173\r
174 if (repeats == 5 || repeats == 15 || repeats == 30) wait /= 2;\r
175\r
176 for (i = 0; i < 6 && inp_prev == gp2x_joystick_read(1); i++) {\r
177 if(i == 0) repeats++;\r
178 usleep(wait/6);\r
179 }\r
180\r
181 while ( !((ret = gp2x_joystick_read(1)) & interesting) ) {\r
182 usleep(50000);\r
183 release = 1;\r
184 }\r
185\r
186 if (release || ret != inp_prev) {\r
187 repeats = 0;\r
188 wait = 300*1000;\r
189 }\r
190 inp_prev = ret;\r
191 inp_prevjoy = 0;\r
192\r
193 // we don't need diagonals in menus\r
194 if ((ret&GP2X_UP) && (ret&GP2X_LEFT)) ret &= ~GP2X_LEFT;\r
195 if ((ret&GP2X_UP) && (ret&GP2X_RIGHT)) ret &= ~GP2X_RIGHT;\r
196 if ((ret&GP2X_DOWN) && (ret&GP2X_LEFT)) ret &= ~GP2X_LEFT;\r
197 if ((ret&GP2X_DOWN) && (ret&GP2X_RIGHT)) ret &= ~GP2X_RIGHT;\r
198\r
199 return ret;\r
200}\r
201\r
202static unsigned long input2_read(unsigned long interesting, int *joy)\r
203{\r
204 unsigned long ret;\r
205 int i;\r
206\r
207 do\r
208 {\r
209 *joy = 0;\r
210 if ((ret = gp2x_joystick_read(0) & interesting)) break;\r
211 gp2x_usbjoy_update();\r
212 for (i = 0; i < num_of_joys; i++) {\r
213 ret = gp2x_usbjoy_check2(i);\r
214 if (ret) { *joy = i + 1; break; }\r
215 }\r
216 if (ret) break;\r
217 }\r
218 while(0);\r
219\r
220 return ret;\r
221}\r
222\r
223// similar to wait_for_input(), but returns joy num\r
224static unsigned long wait_for_input_usbjoy(unsigned long interesting, int *joy)\r
225{\r
226 unsigned long ret;\r
227 const int wait = 300*1000;\r
228 int i;\r
229\r
230 if (inp_prevjoy == 0) inp_prev &= interesting;\r
231 for (i = 0; i < 6; i++) {\r
232 ret = input2_read(interesting, joy);\r
233 if (*joy != inp_prevjoy || ret != inp_prev) break;\r
234 usleep(wait/6);\r
235 }\r
236\r
237 while ( !(ret = input2_read(interesting, joy)) ) {\r
238 usleep(50000);\r
239 }\r
240\r
241 inp_prev = ret;\r
242 inp_prevjoy = *joy;\r
243\r
244 return ret;\r
245}\r
246\r
247\r
248\r
249// -------------- ROM selector --------------\r
250\r
251static void draw_dirlist(char *curdir, struct dirent **namelist, int n, int sel)\r
252{\r
253 int start, i, pos;\r
254\r
255 start = 12 - sel;\r
256 n--; // exclude current dir (".")\r
257\r
e5d315a5 258 //memset(gp2x_screen, 0, 320*240);\r
259 gp2x_pd_clone_buffer2();\r
720ee7f6 260\r
261 if(start - 2 >= 0)\r
0805b5b4 262 gp2x_smalltext8_lim(14, (start - 2)*10, curdir, 53-2);\r
720ee7f6 263 for (i = 0; i < n; i++) {\r
264 pos = start + i;\r
265 if (pos < 0) continue;\r
266 if (pos > 23) break;\r
267 if (namelist[i+1]->d_type == DT_DIR) {\r
0805b5b4 268 gp2x_smalltext8_lim(14, pos*10, "/", 1);\r
269 gp2x_smalltext8_lim(14+6, pos*10, namelist[i+1]->d_name, 53-3);\r
720ee7f6 270 } else {\r
0805b5b4 271 gp2x_smalltext8_lim(14, pos*10, namelist[i+1]->d_name, 53-2);\r
720ee7f6 272 }\r
273 }\r
274 gp2x_text_out8(5, 120, ">");\r
e5d315a5 275 gp2x_video_flip2();\r
720ee7f6 276}\r
277\r
278static int scandir_cmp(const void *p1, const void *p2)\r
279{\r
280 struct dirent **d1 = (struct dirent **)p1, **d2 = (struct dirent **)p2;\r
281 if ((*d1)->d_type == (*d2)->d_type) return alphasort(d1, d2);\r
282 if ((*d1)->d_type == DT_DIR) return -1; // put before\r
283 if ((*d2)->d_type == DT_DIR) return 1;\r
284 return alphasort(d1, d2);\r
285}\r
286\r
287\r
288static char *romsel_loop(char *curr_path)\r
289{\r
290 struct dirent **namelist;\r
291 DIR *dir;\r
292 int n, sel = 0;\r
293 unsigned long inp = 0;\r
294 char *ret = NULL, *fname = NULL;\r
295\r
296 // is this a dir or a full path?\r
297 if ((dir = opendir(curr_path))) {\r
298 closedir(dir);\r
299 } else {\r
300 char *p;\r
301 for (p = curr_path + strlen(curr_path) - 1; p > curr_path && *p != '/'; p--);\r
302 *p = 0;\r
303 fname = p+1;\r
304 }\r
305\r
306 n = scandir(curr_path, &namelist, 0, scandir_cmp);\r
307 if (n < 0) {\r
308 // try root\r
309 n = scandir(curr_path, &namelist, 0, scandir_cmp);\r
310 if (n < 0) {\r
311 // oops, we failed\r
312 printf("dir: "); printf(curr_path); printf("\n");\r
313 perror("scandir");\r
314 return NULL;\r
315 }\r
316 }\r
317\r
318 // try to find sel\r
319 if (fname != NULL) {\r
320 int i;\r
321 for (i = 1; i < n; i++) {\r
322 if (strcmp(namelist[i]->d_name, fname) == 0) {\r
323 sel = i - 1;\r
324 break;\r
325 }\r
326 }\r
327 }\r
328\r
329 for (;;)\r
330 {\r
331 draw_dirlist(curr_path, namelist, n, sel);\r
5111820c 332 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_L|GP2X_R|GP2X_B|GP2X_X);\r
720ee7f6 333 if(inp & GP2X_UP ) { sel--; if (sel < 0) sel = n-2; }\r
334 if(inp & GP2X_DOWN) { sel++; if (sel > n-2) sel = 0; }\r
5111820c 335 if(inp &(GP2X_LEFT|GP2X_L)) { sel-=10; if (sel < 0) sel = 0; }\r
336 if(inp &(GP2X_RIGHT|GP2X_R)) { sel+=10; if (sel > n-2) sel = n-2; }\r
720ee7f6 337 if(inp & GP2X_B) { // enter dir/select\r
338 again:\r
339 if (namelist[sel+1]->d_type == DT_REG) {\r
340 strcpy(romFileName, curr_path);\r
341 strcat(romFileName, "/");\r
342 strcat(romFileName, namelist[sel+1]->d_name);\r
343 ret = romFileName;\r
344 break;\r
345 } else if (namelist[sel+1]->d_type == DT_DIR) {\r
346 int newlen = strlen(curr_path) + strlen(namelist[sel+1]->d_name) + 2;\r
347 char *p, *newdir = malloc(newlen);\r
348 if (strcmp(namelist[sel+1]->d_name, "..") == 0) {\r
349 char *start = curr_path;\r
350 p = start + strlen(start) - 1;\r
351 while (*p == '/' && p > start) p--;\r
352 while (*p != '/' && p > start) p--;\r
353 if (p <= start) strcpy(newdir, "/");\r
354 else { strncpy(newdir, start, p-start); newdir[p-start] = 0; }\r
355 } else {\r
356 strcpy(newdir, curr_path);\r
357 p = newdir + strlen(newdir) - 1;\r
358 while (*p == '/' && p >= newdir) *p-- = 0;\r
359 strcat(newdir, "/");\r
360 strcat(newdir, namelist[sel+1]->d_name);\r
361 }\r
362 ret = romsel_loop(newdir);\r
363 free(newdir);\r
364 break;\r
365 } else {\r
366 // unknown file type, happens on NTFS mounts. Try to guess.\r
367 FILE *tstf; int tmp;\r
368 strcpy(romFileName, curr_path);\r
369 strcat(romFileName, "/");\r
370 strcat(romFileName, namelist[sel+1]->d_name);\r
371 tstf = fopen(romFileName, "rb");\r
372 if (tstf != NULL)\r
373 {\r
374 if (fread(&tmp, 1, 1, tstf) > 0 || ferror(tstf) == 0)\r
375 namelist[sel+1]->d_type = DT_REG;\r
376 else namelist[sel+1]->d_type = DT_DIR;\r
377 fclose(tstf);\r
378 goto again;\r
379 }\r
380 }\r
381 }\r
382 if(inp & GP2X_X) break; // cancel\r
383 }\r
384\r
385 if (n > 0) {\r
386 while(n--) free(namelist[n]);\r
387 free(namelist);\r
388 }\r
389\r
390 return ret;\r
391}\r
392\r
393// -------------- key config --------------\r
394\r
395static char *usb_joy_key_name(int joy, int num)\r
396{\r
397 static char name[16];\r
398 switch (num)\r
399 {\r
400 case 0: sprintf(name, "Joy%i UP", joy); break;\r
401 case 1: sprintf(name, "Joy%i DOWN", joy); break;\r
402 case 2: sprintf(name, "Joy%i LEFT", joy); break;\r
403 case 3: sprintf(name, "Joy%i RIGHT", joy); break;\r
404 default:sprintf(name, "Joy%i b%i", joy, num-3); break;\r
405 }\r
406 return name;\r
407}\r
408\r
409static void draw_key_config(int curr_act, int is_p2)\r
410{\r
411 char strkeys[32*5];\r
412 int joy, i;\r
413\r
414 strkeys[0] = 0;\r
415 for (i = 0; i < 32; i++)\r
416 {\r
417 if (currentConfig.KeyBinds[i] & (1 << curr_act))\r
418 {\r
419 if (curr_act < 16 && (currentConfig.KeyBinds[i] & (1 << 16)) != (is_p2 << 16)) continue;\r
420 if (strkeys[0]) { strcat(strkeys, " + "); strcat(strkeys, gp2xKeyNames[i]); break; }\r
421 else strcpy(strkeys, gp2xKeyNames[i]);\r
422 }\r
423 }\r
424 for (joy = 0; joy < num_of_joys; joy++)\r
425 {\r
426 for (i = 0; i < 32; i++)\r
427 {\r
428 if (currentConfig.JoyBinds[joy][i] & (1 << curr_act))\r
429 {\r
430 if (curr_act < 16 && (currentConfig.JoyBinds[joy][i] & (1 << 16)) != (is_p2 << 16)) continue;\r
431 if (strkeys[0]) {\r
432 strcat(strkeys, ", "); strcat(strkeys, usb_joy_key_name(joy + 1, i));\r
433 break;\r
434 }\r
435 else strcpy(strkeys, usb_joy_key_name(joy + 1, i));\r
436 }\r
437 }\r
438 }\r
439\r
e5d315a5 440 //memset(gp2x_screen, 0, 320*240);\r
441 gp2x_pd_clone_buffer2();\r
720ee7f6 442 gp2x_text_out8(60, 40, "Action: %s", actionNames[curr_act]);\r
443 gp2x_text_out8(60, 60, "Keys: %s", strkeys);\r
444\r
445 gp2x_text_out8(30, 180, "Use SELECT to change action");\r
446 gp2x_text_out8(30, 190, "Press a key to bind/unbind");\r
447 gp2x_text_out8(30, 200, "Select \"Done\" action and");\r
448 gp2x_text_out8(30, 210, " press any key to finish");\r
e5d315a5 449 gp2x_video_flip2();\r
720ee7f6 450}\r
451\r
452static void key_config_loop(int is_p2)\r
453{\r
454 int curr_act = 0, joy = 0, i;\r
455 unsigned long inp = 0;\r
456\r
457 for (;;)\r
458 {\r
459 draw_key_config(curr_act, is_p2);\r
460 inp = wait_for_input_usbjoy(CONFIGURABLE_KEYS, &joy);\r
461 // printf("got %08lX from joy %i\n", inp, joy);\r
462 if (joy == 0) {\r
463 if (inp & GP2X_SELECT) {\r
464 curr_act++;\r
465 while (!actionNames[curr_act] && curr_act < 32) curr_act++;\r
466 if (curr_act > 31) curr_act = 0;\r
467 }\r
468 inp &= CONFIGURABLE_KEYS;\r
469 inp &= ~GP2X_SELECT;\r
470 }\r
471 if (curr_act == 31 && inp) break;\r
472 if (joy == 0) {\r
473 for (i = 0; i < 32; i++)\r
474 if (inp & (1 << i)) {\r
475 currentConfig.KeyBinds[i] ^= (1 << curr_act);\r
476 if (is_p2) currentConfig.KeyBinds[i] |= (1 << 16); // player 2 flag\r
477 else currentConfig.KeyBinds[i] &= ~(1 << 16);\r
478 }\r
479 } else {\r
480 for (i = 0; i < 32; i++)\r
481 if (inp & (1 << i)) {\r
482 currentConfig.JoyBinds[joy-1][i] ^= (1 << curr_act);\r
483 if (is_p2) currentConfig.JoyBinds[joy-1][i] |= (1 << 16);\r
484 else currentConfig.JoyBinds[joy-1][i] &= ~(1 << 16);\r
485 }\r
486 }\r
487 }\r
488}\r
489\r
490static void draw_kc_sel(int menu_sel)\r
491{\r
492 int tl_x = 25+40, tl_y = 60, y, i;\r
493 char joyname[36];\r
494\r
495 y = tl_y;\r
e5d315a5 496 //memset(gp2x_screen, 0, 320*240);\r
497 gp2x_pd_clone_buffer2();\r
720ee7f6 498 gp2x_text_out8(tl_x, y, "Player 1");\r
499 gp2x_text_out8(tl_x, (y+=10), "Player 2");\r
500 gp2x_text_out8(tl_x, (y+=10), "Done");\r
501\r
502 // draw cursor\r
503 gp2x_text_out8(tl_x - 16, tl_y + menu_sel*10, ">");\r
504\r
505 tl_x = 25;\r
506 gp2x_text_out8(tl_x, (y=110), "USB joys detected:");\r
507 if (num_of_joys > 0) {\r
508 for (i = 0; i < num_of_joys; i++) {\r
509 strncpy(joyname, joy_name(joys[i]), 33); joyname[33] = 0;\r
510 gp2x_text_out8(tl_x, (y+=10), "%i: %s", i+1, joyname);\r
511 }\r
512 } else {\r
513 gp2x_text_out8(tl_x, (y+=10), "none");\r
514 }\r
515\r
516\r
e5d315a5 517 gp2x_video_flip2();\r
720ee7f6 518}\r
519\r
520static void kc_sel_loop(void)\r
521{\r
522 int menu_sel = 2, menu_sel_max = 2;\r
523 unsigned long inp = 0;\r
524\r
525 for(;;)\r
526 {\r
527 draw_kc_sel(menu_sel);\r
528 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X);\r
529 if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
530 if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
531 if(inp & GP2X_B) {\r
532 switch (menu_sel) {\r
533 case 0: key_config_loop(0); return;\r
534 case 1: key_config_loop(1); return;\r
535 default: return;\r
536 }\r
537 }\r
538 if(inp & GP2X_X) return;\r
539 }\r
540}\r
541\r
542\r
543\r
daf91588 544// --------- sega/mega cd options ----------\r
545\r
546static void draw_cd_menu_options(int menu_sel, char *b_us, char *b_eu, char *b_jp)\r
547{\r
548 int tl_x = 25, tl_y = 60, y;\r
549\r
550 y = tl_y;\r
e5d315a5 551 //memset(gp2x_screen, 0, 320*240);\r
552 gp2x_pd_clone_buffer2();\r
553\r
daf91588 554 gp2x_text_out8(tl_x, y, "USA BIOS: %s", b_us); // 0\r
555 gp2x_text_out8(tl_x, (y+=10), "EUR BIOS: %s", b_eu); // 1\r
556 gp2x_text_out8(tl_x, (y+=10), "JAP BIOS: %s", b_jp); // 2\r
979ba09f 557 gp2x_text_out8(tl_x, (y+=10), "CD LEDs %s", (currentConfig.EmuOpt &0x400)?"ON":"OFF"); // 3\r
49fe50f0 558 gp2x_text_out8(tl_x, (y+=10), "CDDA audio (using mp3s) %s", (currentConfig.PicoOpt&0x800)?"ON":"OFF"); // 4\r
559 gp2x_text_out8(tl_x, (y+=10), "PCM audio %s", (currentConfig.PicoOpt&0x400)?"ON":"OFF"); // 5\r
daf91588 560 gp2x_text_out8(tl_x, (y+=10), "Done");\r
561\r
562 // draw cursor\r
563 gp2x_text_out8(tl_x - 16, tl_y + menu_sel*10, ">");\r
564\r
565 if ((menu_sel == 0 && strcmp(b_us, "NOT FOUND")) ||\r
566 (menu_sel == 1 && strcmp(b_eu, "NOT FOUND")) ||\r
567 (menu_sel == 2 && strcmp(b_jp, "NOT FOUND")))\r
568 gp2x_text_out8(tl_x, 220, "Press start to test selected BIOS");\r
569\r
e5d315a5 570 gp2x_video_flip2();\r
daf91588 571}\r
572\r
573static void cd_menu_loop_options(void)\r
574{\r
49fe50f0 575 int menu_sel = 0, menu_sel_max = 6;\r
daf91588 576 unsigned long inp = 0;\r
577 char bios_us[32], bios_eu[32], bios_jp[32], *bios, *p;\r
578\r
579 if (find_bios(4, &bios)) { // US\r
580 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
581 strncpy(bios_us, p, 31); bios_us[31] = 0;\r
582 } else strcpy(bios_us, "NOT FOUND");\r
583\r
584 if (find_bios(8, &bios)) { // EU\r
585 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
586 strncpy(bios_eu, p, 31); bios_eu[31] = 0;\r
587 } else strcpy(bios_eu, "NOT FOUND");\r
588\r
589 if (find_bios(1, &bios)) { // JP\r
590 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
591 strncpy(bios_jp, p, 31); bios_jp[31] = 0;\r
592 } else strcpy(bios_jp, "NOT FOUND");\r
593\r
594 for(;;)\r
595 {\r
596 draw_cd_menu_options(menu_sel, bios_us, bios_eu, bios_jp);\r
597 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A|GP2X_START);\r
598 if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
599 if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
600 if((inp& GP2X_B)||(inp&GP2X_LEFT)||(inp&GP2X_RIGHT)) { // toggleable options\r
601 switch (menu_sel) {\r
979ba09f 602 case 3: currentConfig.EmuOpt ^=0x400; break;\r
49fe50f0 603 case 4: currentConfig.PicoOpt^=0x800; break;\r
604 case 5: currentConfig.PicoOpt^=0x400; break;\r
605 case 6: return;\r
daf91588 606 }\r
607 }\r
608 if(inp & (GP2X_X|GP2X_A)) return;\r
609 if(inp & GP2X_START) { // BIOS testers\r
610 switch (menu_sel) {\r
611 case 0: if (find_bios(4, &bios)) { // test US\r
612 strcpy(romFileName, bios);\r
613 engineState = PGS_ReloadRom;\r
614 return;\r
615 }\r
616 break;\r
617 case 1: if (find_bios(8, &bios)) { // test EU\r
618 strcpy(romFileName, bios);\r
619 engineState = PGS_ReloadRom;\r
620 return;\r
621 }\r
622 break;\r
623 case 2: if (find_bios(1, &bios)) { // test JP\r
624 strcpy(romFileName, bios);\r
625 engineState = PGS_ReloadRom;\r
626 return;\r
627 }\r
628 break;\r
629 }\r
630 }\r
631 }\r
632}\r
633\r
634\r
635// --------- advanced options ----------\r
636\r
720ee7f6 637static void draw_amenu_options(int menu_sel)\r
638{\r
639 int tl_x = 25, tl_y = 60, y;\r
640 char *mms = mmuhack_status ? "active) " : "inactive)";\r
641\r
642 y = tl_y;\r
e5d315a5 643 //memset(gp2x_screen, 0, 320*240);\r
644 gp2x_pd_clone_buffer2();\r
645\r
979ba09f 646 gp2x_text_out8(tl_x, y, "Scale 32 column mode %s", (currentConfig.PicoOpt&0x100)?"ON":"OFF"); // 0\r
647 gp2x_text_out8(tl_x, (y+=10), "Gamma correction %i.%02i", currentConfig.gamma / 100, currentConfig.gamma%100); // 1\r
648 gp2x_text_out8(tl_x, (y+=10), "Emulate Z80 %s", (currentConfig.PicoOpt&0x004)?"ON":"OFF"); // 2\r
649 gp2x_text_out8(tl_x, (y+=10), "Emulate YM2612 (FM) %s", (currentConfig.PicoOpt&0x001)?"ON":"OFF"); // 3\r
650 gp2x_text_out8(tl_x, (y+=10), "Emulate SN76496 (PSG) %s", (currentConfig.PicoOpt&0x002)?"ON":"OFF"); // 4\r
651 gp2x_text_out8(tl_x, (y+=10), "gzip savestates %s", (currentConfig.EmuOpt &0x008)?"ON":"OFF"); // 5\r
652 gp2x_text_out8(tl_x, (y+=10), "Don't save config on exit %s", (currentConfig.EmuOpt &0x020)?"ON":"OFF"); // 6\r
720ee7f6 653 gp2x_text_out8(tl_x, (y+=10), "needs restart:");\r
979ba09f 654 gp2x_text_out8(tl_x, (y+=10), "craigix's RAM timings %s", (currentConfig.EmuOpt &0x100)?"ON":"OFF"); // 8\r
655 gp2x_text_out8(tl_x, (y+=10), "squidgehack (now %s %s", mms, (currentConfig.EmuOpt &0x010)?"ON":"OFF"); // 9\r
720ee7f6 656 gp2x_text_out8(tl_x, (y+=10), "Done");\r
657\r
658 // draw cursor\r
659 gp2x_text_out8(tl_x - 16, tl_y + menu_sel*10, ">");\r
660\r
e5d315a5 661 gp2x_video_flip2();\r
720ee7f6 662}\r
663\r
664static void amenu_loop_options(void)\r
665{\r
47f22a1f 666 int menu_sel = 0, menu_sel_max = 10;\r
720ee7f6 667 unsigned long inp = 0;\r
668\r
669 for(;;)\r
670 {\r
671 draw_amenu_options(menu_sel);\r
672 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A);\r
673 if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
674 if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
675 if((inp& GP2X_B)||(inp&GP2X_LEFT)||(inp&GP2X_RIGHT)) { // toggleable options\r
676 switch (menu_sel) {\r
979ba09f 677 case 0: currentConfig.PicoOpt^=0x100; break;\r
678 case 2: currentConfig.PicoOpt^=0x004; break;\r
679 case 3: currentConfig.PicoOpt^=0x001; break;\r
680 case 4: currentConfig.PicoOpt^=0x002; break;\r
681 case 5: currentConfig.EmuOpt ^=0x008; break;\r
682 case 6: currentConfig.EmuOpt ^=0x020; break;\r
683 case 8: currentConfig.EmuOpt ^=0x100; break;\r
684 case 9: currentConfig.EmuOpt ^=0x010; break;\r
720ee7f6 685 case 10: return;\r
686 }\r
687 }\r
688 if(inp & (GP2X_X|GP2X_A)) return;\r
689 if(inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choise\r
690 switch (menu_sel) {\r
691 case 1:\r
692 while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) {\r
979ba09f 693 currentConfig.gamma += (inp & GP2X_LEFT) ? -1 : 1;\r
694 if (currentConfig.gamma < 1) currentConfig.gamma = 1;\r
695 if (currentConfig.gamma > 300) currentConfig.gamma = 300;\r
720ee7f6 696 draw_amenu_options(menu_sel);\r
697 usleep(18*1000);\r
698 }\r
699 break;\r
700 }\r
701 }\r
702 }\r
703}\r
704\r
705// -------------- options --------------\r
706\r
979ba09f 707static const char *region_name(unsigned int code)\r
720ee7f6 708{\r
979ba09f 709 static const char *names[] = { "Auto", " Japan NTSC", " Japan PAL", " USA", " Europe" };\r
710 static const char *names_short[] = { "", " JP", " JP", " US", " EU" };\r
711 int u, i = 0;\r
712 if (code) {\r
713 code <<= 1;\r
714 while((code >>= 1)) i++;\r
715 if (i > 4) return "unknown";\r
716 return names[i];\r
717 } else {\r
718 static char name[24];\r
719 strcpy(name, "Auto:");\r
720 for (u = 0; u < 3; u++) {\r
721 i = 0; code = ((PicoAutoRgnOrder >> u*4) & 0xf) << 1;\r
722 while((code >>= 1)) i++;\r
723 strcat(name, names_short[i]);\r
724 }\r
725 return name;\r
726 }\r
720ee7f6 727}\r
728\r
729static void draw_menu_options(int menu_sel)\r
730{\r
731 int tl_x = 25, tl_y = 40, y;\r
732 char monostereo[8], strframeskip[8], *strrend;\r
733\r
979ba09f 734 strcpy(monostereo, (currentConfig.PicoOpt&0x08)?"stereo":"mono");\r
735 if (currentConfig.Frameskip < 0)\r
720ee7f6 736 strcpy(strframeskip, "Auto");\r
979ba09f 737 else sprintf(strframeskip, "%i", currentConfig.Frameskip);\r
738 if (currentConfig.PicoOpt&0x10) {\r
720ee7f6 739 strrend = " 8bit fast";\r
979ba09f 740 } else if (currentConfig.EmuOpt&0x80) {\r
720ee7f6 741 strrend = "16bit accurate";\r
742 } else {\r
743 strrend = " 8bit accurate";\r
744 }\r
745\r
746 y = tl_y;\r
e5d315a5 747 //memset(gp2x_screen, 0, 320*240);\r
748 gp2x_pd_clone_buffer2();\r
749\r
720ee7f6 750 gp2x_text_out8(tl_x, y, "Renderer: %s", strrend); // 0\r
979ba09f 751 gp2x_text_out8(tl_x, (y+=10), "Accurate timing (slower) %s", (currentConfig.PicoOpt&0x040)?"ON":"OFF"); // 1\r
752 gp2x_text_out8(tl_x, (y+=10), "Accurate sprites (slower) %s", (currentConfig.PicoOpt&0x080)?"ON":"OFF"); // 2\r
753 gp2x_text_out8(tl_x, (y+=10), "Show FPS %s", (currentConfig.EmuOpt &0x002)?"ON":"OFF"); // 3\r
720ee7f6 754 gp2x_text_out8(tl_x, (y+=10), "Frameskip %s", strframeskip);\r
979ba09f 755 gp2x_text_out8(tl_x, (y+=10), "Enable sound %s", (currentConfig.EmuOpt &0x004)?"ON":"OFF"); // 5\r
756 gp2x_text_out8(tl_x, (y+=10), "Sound Quality: %5iHz %s", currentConfig.PsndRate, monostereo);\r
757 gp2x_text_out8(tl_x, (y+=10), "Use ARM940 core for sound %s", (currentConfig.PicoOpt&0x200)?"ON":"OFF"); // 7\r
758 gp2x_text_out8(tl_x, (y+=10), "6 button pad %s", (currentConfig.PicoOpt&0x020)?"ON":"OFF"); // 8\r
759 gp2x_text_out8(tl_x, (y+=10), "Genesis Region: %s", region_name(currentConfig.PicoRegion));\r
760 gp2x_text_out8(tl_x, (y+=10), "Use SRAM/BRAM savestates %s", (currentConfig.EmuOpt &0x001)?"ON":"OFF"); // 10\r
761 gp2x_text_out8(tl_x, (y+=10), "Confirm save overwrites %s", (currentConfig.EmuOpt &0x200)?"ON":"OFF"); // 11\r
720ee7f6 762 gp2x_text_out8(tl_x, (y+=10), "Save slot %i", state_slot); // 12\r
979ba09f 763 gp2x_text_out8(tl_x, (y+=10), "GP2X CPU clocks %iMhz", currentConfig.CPUclock);\r
daf91588 764 gp2x_text_out8(tl_x, (y+=10), "[Sega/Mega CD options]");\r
765 gp2x_text_out8(tl_x, (y+=10), "[advanced options]"); // 15\r
720ee7f6 766 gp2x_text_out8(tl_x, (y+=10), "Save cfg as default");\r
767 if (rom_data)\r
768 gp2x_text_out8(tl_x, (y+=10), "Save cfg for current game only");\r
769\r
770 // draw cursor\r
771 gp2x_text_out8(tl_x - 16, tl_y + menu_sel*10, ">");\r
772\r
e5d315a5 773 gp2x_video_flip2();\r
720ee7f6 774}\r
775\r
776static int sndrate_prevnext(int rate, int dir)\r
777{\r
778 int i, rates[] = { 8000, 11025, 16000, 22050, 44100 };\r
779\r
780 for (i = 0; i < 5; i++)\r
781 if (rates[i] == rate) break;\r
782\r
783 i += dir ? 1 : -1;\r
784 if (i > 4) return dir ? 44100 : 22050;\r
785 if (i < 0) return dir ? 11025 : 8000;\r
786 return rates[i];\r
787}\r
788\r
979ba09f 789static void region_prevnext(int right)\r
790{\r
791 // jp_ntsc=1, jp_pal=2, usa=4, eu=8\r
792 static int rgn_orders[] = { 0x148, 0x184, 0x814, 0x418, 0x841, 0x481 };\r
793 int i;\r
794 if (right) {\r
795 if (!currentConfig.PicoRegion) {\r
796 for (i = 0; i < 6; i++)\r
797 if (rgn_orders[i] == PicoAutoRgnOrder) break;\r
798 if (i < 5) PicoAutoRgnOrder = rgn_orders[i+1];\r
799 else currentConfig.PicoRegion=1;\r
800 }\r
801 else currentConfig.PicoRegion<<=1;\r
802 if (currentConfig.PicoRegion > 8) currentConfig.PicoRegion = 8;\r
803 } else {\r
804 if (!currentConfig.PicoRegion) {\r
805 for (i = 0; i < 6; i++)\r
806 if (rgn_orders[i] == PicoAutoRgnOrder) break;\r
807 if (i > 0) PicoAutoRgnOrder = rgn_orders[i-1];\r
808 }\r
809 else currentConfig.PicoRegion>>=1;\r
810 }\r
811}\r
812\r
720ee7f6 813static void menu_options_save(void)\r
814{\r
720ee7f6 815 PicoOpt = currentConfig.PicoOpt;\r
816 PsndRate = currentConfig.PsndRate;\r
817 PicoRegionOverride = currentConfig.PicoRegion;\r
818 if (PicoOpt & 0x20) {\r
819 actionNames[ 8] = "Z"; actionNames[ 9] = "Y";\r
820 actionNames[10] = "X"; actionNames[11] = "MODE";\r
821 } else {\r
822 actionNames[8] = actionNames[9] = actionNames[10] = actionNames[11] = 0;\r
823 }\r
824}\r
825\r
daf91588 826static int menu_loop_options(void)\r
720ee7f6 827{\r
daf91588 828 int menu_sel = 0, menu_sel_max = 16;\r
720ee7f6 829 unsigned long inp = 0;\r
830\r
831 if (rom_data) menu_sel_max++;\r
979ba09f 832 currentConfig.PicoOpt = PicoOpt;\r
833 currentConfig.PsndRate = PsndRate;\r
834 currentConfig.PicoRegion = PicoRegionOverride;\r
720ee7f6 835\r
836 for(;;)\r
837 {\r
838 draw_menu_options(menu_sel);\r
839 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_LEFT|GP2X_RIGHT|GP2X_B|GP2X_X|GP2X_A);\r
840 if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
841 if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
842 if((inp& GP2X_B)||(inp&GP2X_LEFT)||(inp&GP2X_RIGHT)) { // toggleable options\r
843 switch (menu_sel) {\r
979ba09f 844 case 1: currentConfig.PicoOpt^=0x040; break;\r
845 case 2: currentConfig.PicoOpt^=0x080; break;\r
846 case 3: currentConfig.EmuOpt ^=0x002; break;\r
847 case 5: currentConfig.EmuOpt ^=0x004; break;\r
848 case 7: currentConfig.PicoOpt^=0x200; break;\r
849 case 8: currentConfig.PicoOpt^=0x020; break;\r
850 case 10: currentConfig.EmuOpt ^=0x001; break;\r
851 case 11: currentConfig.EmuOpt ^=0x200; break;\r
daf91588 852 case 14: cd_menu_loop_options();\r
853 if (engineState == PGS_ReloadRom)\r
854 return 0; // test BIOS\r
855 break;\r
856 case 15: amenu_loop_options(); break;\r
857 case 16: // done (update and write)\r
720ee7f6 858 menu_options_save();\r
daf91588 859 if (emu_WriteConfig(0)) strcpy(menuErrorMsg, "config saved");\r
860 else strcpy(menuErrorMsg, "failed to write config");\r
861 return 1;\r
862 case 17: // done (update and write for current game)\r
720ee7f6 863 menu_options_save();\r
daf91588 864 if (emu_WriteConfig(1)) strcpy(menuErrorMsg, "config saved");\r
865 else strcpy(menuErrorMsg, "failed to write config");\r
866 return 1;\r
720ee7f6 867 }\r
868 }\r
979ba09f 869 if(inp & (GP2X_X|GP2X_A)) {\r
720ee7f6 870 menu_options_save();\r
daf91588 871 return 0; // done (update, no write)\r
720ee7f6 872 }\r
873 if(inp & (GP2X_LEFT|GP2X_RIGHT)) { // multi choise\r
874 switch (menu_sel) {\r
875 case 0:\r
876 if (inp & GP2X_LEFT) {\r
979ba09f 877 if ( currentConfig.PicoOpt&0x10) currentConfig.PicoOpt&= ~0x10;\r
878 else if (!(currentConfig.EmuOpt &0x80))currentConfig.EmuOpt |= 0x80;\r
879 else if ( currentConfig.EmuOpt &0x80) break;\r
720ee7f6 880 } else {\r
979ba09f 881 if ( currentConfig.PicoOpt&0x10) break;\r
882 else if (!(currentConfig.EmuOpt &0x80))currentConfig.PicoOpt|= 0x10;\r
883 else if ( currentConfig.EmuOpt &0x80) currentConfig.EmuOpt &= ~0x80;\r
720ee7f6 884 }\r
885 break;\r
886 case 4:\r
979ba09f 887 currentConfig.Frameskip += (inp & GP2X_LEFT) ? -1 : 1;\r
888 if (currentConfig.Frameskip < 0) currentConfig.Frameskip = -1;\r
889 if (currentConfig.Frameskip > 32) currentConfig.Frameskip = 32;\r
720ee7f6 890 break;\r
891 case 6:\r
979ba09f 892 if ((inp & GP2X_RIGHT) && currentConfig.PsndRate == 44100 && !(currentConfig.PicoOpt&0x08)) {\r
893 currentConfig.PsndRate = 8000; currentConfig.PicoOpt|= 0x08;\r
894 } else if ((inp & GP2X_LEFT) && currentConfig.PsndRate == 8000 && (currentConfig.PicoOpt&0x08)) {\r
895 currentConfig.PsndRate = 44100; currentConfig.PicoOpt&=~0x08;\r
896 } else currentConfig.PsndRate = sndrate_prevnext(currentConfig.PsndRate, inp & GP2X_RIGHT);\r
720ee7f6 897 break;\r
898 case 9:\r
979ba09f 899 region_prevnext(inp & GP2X_RIGHT);\r
720ee7f6 900 break;\r
901 case 12:\r
902 if (inp & GP2X_RIGHT) {\r
903 state_slot++; if (state_slot > 9) state_slot = 0;\r
904 } else {state_slot--; if (state_slot < 0) state_slot = 9;\r
905 }\r
906 break;\r
907 case 13:\r
908 while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) {\r
979ba09f 909 currentConfig.CPUclock += (inp & GP2X_LEFT) ? -1 : 1;\r
910 if (currentConfig.CPUclock < 1) currentConfig.CPUclock = 1;\r
720ee7f6 911 draw_menu_options(menu_sel);\r
912 usleep(50*1000);\r
913 }\r
914 break;\r
915 }\r
916 }\r
917 }\r
918}\r
919\r
920// -------------- credits --------------\r
921\r
922static void draw_menu_credits(void)\r
923{\r
924 int tl_x = 15, tl_y = 70, y;\r
e5d315a5 925 //memset(gp2x_screen, 0, 320*240);\r
926 gp2x_pd_clone_buffer2();\r
720ee7f6 927\r
5111820c 928 gp2x_text_out8(tl_x, 20, "PicoDrive v" VERSION " (c) notaz, 2006,2007");\r
720ee7f6 929 y = tl_y;\r
930 gp2x_text_out8(tl_x, y, "Credits:");\r
931 gp2x_text_out8(tl_x, (y+=10), "Dave: Cyclone 68000 core,");\r
932 gp2x_text_out8(tl_x, (y+=10), " base code of PicoDrive");\r
933 gp2x_text_out8(tl_x, (y+=10), "Reesy & FluBBa: DrZ80 core");\r
934 gp2x_text_out8(tl_x, (y+=10), "MAME devs: YM2612 and SN76496 cores");\r
935 gp2x_text_out8(tl_x, (y+=10), "Charles MacDonald: Genesis hw docs");\r
936 gp2x_text_out8(tl_x, (y+=10), "Stephane Dallongeville:");\r
937 gp2x_text_out8(tl_x, (y+=10), " opensource Gens");\r
938 gp2x_text_out8(tl_x, (y+=10), "Haze: Genesis hw info");\r
939 gp2x_text_out8(tl_x, (y+=10), "rlyeh and others: minimal SDK");\r
940 gp2x_text_out8(tl_x, (y+=10), "Squidge: squidgehack");\r
941 gp2x_text_out8(tl_x, (y+=10), "Dzz: ARM940 sample");\r
942 gp2x_text_out8(tl_x, (y+=10), "GnoStiC / Puck2099: USB joystick");\r
943 gp2x_text_out8(tl_x, (y+=10), "craigix: GP2X hardware");\r
944\r
e5d315a5 945 gp2x_video_flip2();\r
720ee7f6 946}\r
947\r
948\r
949// -------------- root menu --------------\r
950\r
951static void draw_menu_root(int menu_sel)\r
952{\r
953 int tl_x = 70, tl_y = 70, y;\r
e5d315a5 954 //memset(gp2x_screen, 0, 320*240);\r
955 gp2x_pd_clone_buffer2();\r
720ee7f6 956\r
957 gp2x_text_out8(tl_x, 20, "PicoDrive v" VERSION);\r
958\r
959 y = tl_y;\r
960 if (rom_data) {\r
961 gp2x_text_out8(tl_x, y, "Resume game");\r
962 gp2x_text_out8(tl_x, (y+=10), "Save State");\r
963 gp2x_text_out8(tl_x, (y+=10), "Load State");\r
964 gp2x_text_out8(tl_x, (y+=10), "Reset game");\r
965 } else {\r
966 y += 30;\r
967 }\r
8dfb9fd5 968 gp2x_text_out8(tl_x, (y+=10), "Load new ROM/ISO");\r
720ee7f6 969 gp2x_text_out8(tl_x, (y+=10), "Change options");\r
970 gp2x_text_out8(tl_x, (y+=10), "Configure controls");\r
971 gp2x_text_out8(tl_x, (y+=10), "Credits");\r
972 gp2x_text_out8(tl_x, (y+=10), "Exit");\r
973\r
974 // draw cursor\r
975 gp2x_text_out8(tl_x - 16, tl_y + menu_sel*10, ">");\r
976 // error\r
977 if (menuErrorMsg[0]) gp2x_text_out8(5, 226, menuErrorMsg);\r
e5d315a5 978 gp2x_video_flip2();\r
720ee7f6 979}\r
980\r
981\r
982static void menu_loop_root(void)\r
983{\r
daf91588 984 int ret, menu_sel = 4, menu_sel_max = 8, menu_sel_min = 4;\r
720ee7f6 985 unsigned long inp = 0;\r
986 char curr_path[PATH_MAX], *selfname;\r
987 FILE *tstf;\r
988\r
989 if ( (tstf = fopen(currentConfig.lastRomFile, "rb")) )\r
990 {\r
991 fclose(tstf);\r
992 strcpy(curr_path, currentConfig.lastRomFile);\r
993 }\r
994 else\r
995 {\r
996 getcwd(curr_path, PATH_MAX);\r
997 }\r
998\r
999 if (rom_data) menu_sel = menu_sel_min = 0;\r
1000\r
1001 for(;;)\r
1002 {\r
1003 draw_menu_root(menu_sel);\r
1004 inp = wait_for_input(GP2X_UP|GP2X_DOWN|GP2X_B|GP2X_X|GP2X_SELECT);\r
1005 if(inp & GP2X_UP ) { menu_sel--; if (menu_sel < menu_sel_min) menu_sel = menu_sel_max; }\r
1006 if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = menu_sel_min; }\r
1007 if(inp &(GP2X_SELECT|GP2X_X)){\r
1008 if (rom_data) {\r
1009 while (gp2x_joystick_read(1) & (GP2X_SELECT|GP2X_X)) usleep(50*1000); // wait until select is released\r
1010 engineState = PGS_Running;\r
1011 break;\r
1012 }\r
1013 }\r
1014 if(inp & GP2X_B ) {\r
1015 switch (menu_sel) {\r
1016 case 0: // resume game\r
1017 if (rom_data) { engineState = PGS_Running; return; }\r
1018 break;\r
1019 case 1: // save state\r
1020 if (rom_data) {\r
1021 if(emu_SaveLoadGame(0, 0)) {\r
1022 strcpy(menuErrorMsg, "save failed");\r
1023 continue;\r
1024 }\r
1025 engineState = PGS_Running;\r
1026 return;\r
1027 }\r
1028 break;\r
1029 case 2: // load state\r
1030 if (rom_data) {\r
1031 if(emu_SaveLoadGame(1, 0)) {\r
1032 strcpy(menuErrorMsg, "load failed");\r
1033 continue;\r
1034 }\r
1035 engineState = PGS_Running;\r
1036 return;\r
1037 }\r
1038 break;\r
1039 case 3: // reset game\r
1040 if (rom_data) {\r
1041 emu_ResetGame();\r
1042 engineState = PGS_Running;\r
1043 return;\r
1044 }\r
1045 break;\r
1046 case 4: // select rom\r
1047 selfname = romsel_loop(curr_path);\r
1048 if (selfname) {\r
1049 printf("selected file: %s\n", selfname);\r
720ee7f6 1050 engineState = PGS_ReloadRom;\r
1051 }\r
1052 return;\r
1053 case 5: // options\r
daf91588 1054 ret = menu_loop_options();\r
1055 if (ret == 1) continue; // status update\r
1056 if (engineState == PGS_ReloadRom)\r
1057 return; // BIOS test\r
720ee7f6 1058 break;\r
1059 case 6: // controls\r
1060 kc_sel_loop();\r
1061 break;\r
1062 case 7: // credits\r
1063 draw_menu_credits();\r
1064 usleep(500*1000);\r
1065 inp = wait_for_input(GP2X_B|GP2X_X);\r
1066 break;\r
1067 case 8: // exit\r
1068 engineState = PGS_Quit;\r
1069 return;\r
1070 }\r
1071 }\r
1072 menuErrorMsg[0] = 0; // clear error msg\r
1073 }\r
1074}\r
1075\r
1076\r
e5d315a5 1077static void menu_gfx_prepare(void)\r
720ee7f6 1078{\r
e5d315a5 1079 extern int localPal[0x100];\r
1080 int i;\r
1081\r
1082 // don't clear old palette just for fun (but make it dark)\r
1083 for (i = 0x100-1; i >= 0; i--)\r
1084 localPal[i] = (localPal[i] >> 2) & 0x003f3f3f;\r
1085 localPal[0xe0] = 0x00000000; // reserved pixels for OSD\r
1086 localPal[0xf0] = 0x00ffffff;\r
720ee7f6 1087\r
1088 // switch to 8bpp\r
e5d315a5 1089 gp2x_video_changemode2(8);\r
720ee7f6 1090 gp2x_video_RGB_setscaling(320, 240);\r
e5d315a5 1091 gp2x_video_setpalette(localPal, 0x100);\r
1092 gp2x_video_flip2();\r
1093}\r
1094\r
1095\r
1096void menu_loop(void)\r
1097{\r
1098 menu_gfx_prepare();\r
720ee7f6 1099\r
1100 menu_loop_root();\r
1101\r
1102 menuErrorMsg[0] = 0;\r
1103}\r