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