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