idle loop hack, psp bugfix, plat debug str
[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
441// ------------ patch/gg menu ------------\r
442\r
443static void draw_patchlist(int sel)\r
444{\r
445 int start, i, pos, active;\r
446\r
447 start = 12 - sel;\r
448\r
449 menu_draw_begin(1);\r
450\r
451 for (i = 0; i < PicoPatchCount; i++) {\r
452 pos = start + i;\r
453 if (pos < 0) continue;\r
454 if (pos > 23) break;\r
455 active = PicoPatches[i].active;\r
456 smalltext_out16_lim(14, pos*10, active ? "ON " : "OFF", active ? 0xfff6 : 0xffff, 3);\r
457 smalltext_out16_lim(14+6*4, pos*10, PicoPatches[i].name, active ? 0xfff6 : 0xffff, 53-6);\r
458 }\r
459 pos = start + i;\r
460 if (pos < 24) smalltext_out16_lim(14, pos*10, "done", 0xffff, 4);\r
461\r
462 text_out16(5, 120, ">");\r
463 menu_draw_end();\r
464}\r
465\r
466\r
467static void patches_menu_loop(void)\r
468{\r
469 int menu_sel = 0;\r
470 unsigned long inp = 0;\r
471\r
472 for(;;)\r
473 {\r
474 draw_patchlist(menu_sel);\r
475 inp = wait_for_input(BTN_UP|BTN_DOWN|BTN_LEFT|BTN_RIGHT|BTN_L|BTN_R|BTN_PLAY|BTN_STOP);\r
476 if(inp & BTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = PicoPatchCount; }\r
477 if(inp & BTN_DOWN) { menu_sel++; if (menu_sel > PicoPatchCount) menu_sel = 0; }\r
478 if(inp &(BTN_LEFT|BTN_L)) { menu_sel-=10; if (menu_sel < 0) menu_sel = 0; }\r
479 if(inp &(BTN_RIGHT|BTN_R)) { menu_sel+=10; if (menu_sel > PicoPatchCount) menu_sel = PicoPatchCount; }\r
480 if(inp & BTN_PLAY) { // action\r
481 if (menu_sel < PicoPatchCount)\r
482 PicoPatches[menu_sel].active = !PicoPatches[menu_sel].active;\r
483 else return;\r
484 }\r
485 if(inp & BTN_STOP) return;\r
486 }\r
487\r
488}\r
489\r
490// ------------ savestate loader ------------\r
491\r
492static int state_slot_flags = 0;\r
493\r
494static void state_check_slots(void)\r
495{\r
496 int slot;\r
497\r
498 state_slot_flags = 0;\r
499\r
500 for (slot = 0; slot < 10; slot++)\r
501 {\r
ea8c405f 502 if (emu_checkSaveFile(slot))\r
e5f426aa 503 {\r
504 state_slot_flags |= 1 << slot;\r
505 }\r
506 }\r
507}\r
508\r
509static void draw_savestate_bg(int slot)\r
510{\r
511 struct PicoVideo tmp_pv;\r
512 unsigned short tmp_cram[0x40];\r
513 unsigned short tmp_vsram[0x40];\r
514 void *tmp_vram, *file;\r
515 char *fname;\r
516\r
517 fname = emu_GetSaveFName(1, 0, slot);\r
518 if (!fname) return;\r
519\r
520 tmp_vram = malloc(sizeof(Pico.vram));\r
521 if (tmp_vram == NULL) return;\r
522\r
523 memcpy(tmp_vram, Pico.vram, sizeof(Pico.vram));\r
524 memcpy(tmp_cram, Pico.cram, sizeof(Pico.cram));\r
525 memcpy(tmp_vsram, Pico.vsram, sizeof(Pico.vsram));\r
526 memcpy(&tmp_pv, &Pico.video, sizeof(Pico.video));\r
527\r
528 if (strcmp(fname + strlen(fname) - 3, ".gz") == 0) {\r
529 file = gzopen(fname, "rb");\r
ea8c405f 530 emu_setSaveStateCbs(1);\r
e5f426aa 531 } else {\r
532 file = fopen(fname, "rb");\r
ea8c405f 533 emu_setSaveStateCbs(0);\r
e5f426aa 534 }\r
535\r
536 if (file) {\r
602133e1 537 if (PicoAHW & 1) {\r
e5f426aa 538 PicoCdLoadStateGfx(file);\r
539 } else {\r
540 areaSeek(file, 0x10020, SEEK_SET); // skip header and RAM in state file\r
541 areaRead(Pico.vram, 1, sizeof(Pico.vram), file);\r
542 areaSeek(file, 0x2000, SEEK_CUR);\r
543 areaRead(Pico.cram, 1, sizeof(Pico.cram), file);\r
544 areaRead(Pico.vsram, 1, sizeof(Pico.vsram), file);\r
545 areaSeek(file, 0x221a0, SEEK_SET);\r
546 areaRead(&Pico.video, 1, sizeof(Pico.video), file);\r
547 }\r
548 areaClose(file);\r
549 }\r
550\r
0fc0e241 551 emu_forcedFrame(POPT_EN_SOFTSCALE);\r
e5f426aa 552 menu_prepare_bg(1);\r
553\r
554 memcpy(Pico.vram, tmp_vram, sizeof(Pico.vram));\r
555 memcpy(Pico.cram, tmp_cram, sizeof(Pico.cram));\r
556 memcpy(Pico.vsram, tmp_vsram, sizeof(Pico.vsram));\r
557 memcpy(&Pico.video, &tmp_pv, sizeof(Pico.video));\r
558 free(tmp_vram);\r
559}\r
560\r
561static void draw_savestate_menu(int menu_sel, int is_loading)\r
562{\r
563 int tl_x = 25, tl_y = 60, y, i;\r
564\r
565 if (state_slot_flags & (1 << menu_sel))\r
566 draw_savestate_bg(menu_sel);\r
567 menu_draw_begin(1);\r
568\r
569 text_out16(tl_x, 30, is_loading ? "Load state" : "Save state");\r
570\r
571 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 108);\r
572\r
573 /* draw all 10 slots */\r
574 y = tl_y;\r
575 for (i = 0; i < 10; i++, y+=10)\r
576 {\r
577 text_out16(tl_x, y, "SLOT %i (%s)", i, (state_slot_flags & (1 << i)) ? "USED" : "free");\r
578 }\r
579 text_out16(tl_x, y, "back");\r
580\r
581 menu_draw_end();\r
582}\r
583\r
584static int savestate_menu_loop(int is_loading)\r
585{\r
586 static int menu_sel = 10;\r
587 int menu_sel_max = 10;\r
588 unsigned long inp = 0;\r
589\r
590 state_check_slots();\r
591\r
592 for(;;)\r
593 {\r
594 draw_savestate_menu(menu_sel, is_loading);\r
595 inp = wait_for_input(BTN_UP|BTN_DOWN|BTN_PLAY|BTN_STOP);\r
596 if(inp & BTN_UP ) {\r
597 do {\r
598 menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max;\r
599 } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading);\r
600 }\r
601 if(inp & BTN_DOWN) {\r
602 do {\r
603 menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0;\r
604 } while (!(state_slot_flags & (1 << menu_sel)) && menu_sel != menu_sel_max && is_loading);\r
605 }\r
606 if(inp & BTN_PLAY) { // save/load\r
607 if (menu_sel < 10) {\r
608 state_slot = menu_sel;\r
c77ca79e 609 PicoStateProgressCB = emu_stateCb; /* also suitable for menu */\r
e5f426aa 610 if (emu_SaveLoadGame(is_loading, 0)) {\r
611 strcpy(menuErrorMsg, is_loading ? "Load failed" : "Save failed");\r
612 return 1;\r
613 }\r
614 return 0;\r
615 } else return 1;\r
616 }\r
617 if(inp & BTN_STOP) return 1;\r
618 }\r
619}\r
620\r
621// -------------- key config --------------\r
622\r
623static char *action_binds(int player_idx, int action_mask)\r
624{\r
625 static char strkeys[32*5];\r
626 int i;\r
627\r
628 strkeys[0] = 0;\r
629 for (i = 0; i < 32; i++) // i is key index\r
630 {\r
631 if (currentConfig.KeyBinds[i] & action_mask)\r
632 {\r
633 if (player_idx >= 0 && ((currentConfig.KeyBinds[i] >> 16) & 3) != player_idx) continue;\r
634 if (strkeys[0]) { strcat(strkeys, " + "); strcat(strkeys, gizKeyNames[i]); break; }\r
635 else strcpy(strkeys, gizKeyNames[i]);\r
636 }\r
637 }\r
638\r
639 return strkeys;\r
640}\r
641\r
642static void unbind_action(int action)\r
643{\r
644 int i;\r
645\r
646 for (i = 0; i < 32; i++)\r
647 currentConfig.KeyBinds[i] &= ~action;\r
648}\r
649\r
c9077ab4 650static int count_bound_keys(int action, int pl_idx)\r
e5f426aa 651{\r
652 int i, keys = 0;\r
653\r
654 for (i = 0; i < 32; i++)\r
c9077ab4 655 {\r
656 if (pl_idx >= 0 && (currentConfig.KeyBinds[i]&0x30000) != (pl_idx<<16)) continue;\r
e5f426aa 657 if (currentConfig.KeyBinds[i] & action) keys++;\r
c9077ab4 658 }\r
e5f426aa 659\r
660 return keys;\r
661}\r
662\r
1ca2ea4f 663static void draw_key_config(const me_bind_action *opts, int opt_cnt, int player_idx, int sel)\r
e5f426aa 664{\r
f0f0d2df 665 int x, y, tl_y = 30, i;\r
e5f426aa 666\r
667 menu_draw_begin(1);\r
668 if (player_idx >= 0) {\r
f0f0d2df 669 text_out16(80, 10, "Player %i controls", player_idx + 1);\r
c9077ab4 670 x = 80;\r
e5f426aa 671 } else {\r
f0f0d2df 672 text_out16(80, 10, "Emulator controls");\r
e5f426aa 673 x = 40;\r
674 }\r
675\r
676 menu_draw_selection(x - 16, tl_y + sel*10, (player_idx >= 0) ? 66 : 130);\r
677\r
678 y = tl_y;\r
679 for (i = 0; i < opt_cnt; i++, y+=10)\r
680 text_out16(x, y, "%s : %s", opts[i].name, action_binds(player_idx, opts[i].mask));\r
681\r
682 text_out16(x, y, "Done");\r
683\r
684 if (sel < opt_cnt) {\r
f0f0d2df 685 text_out16(30, 195, "Press a button to bind/unbind");\r
686 text_out16(30, 205, "Use HOME to clear");\r
687 text_out16(30, 215, "To bind UP/DOWN, hold HOME");\r
688 text_out16(30, 225, "Select \"Done\" to exit");\r
e5f426aa 689 } else {\r
f0f0d2df 690 text_out16(30, 205, "Use Options -> Save cfg");\r
691 text_out16(30, 215, "to save controls");\r
692 text_out16(30, 225, "Press PLAY or STOP to exit");\r
e5f426aa 693 }\r
694 menu_draw_end();\r
695}\r
696\r
1ca2ea4f 697static void key_config_loop(const me_bind_action *opts, int opt_cnt, int player_idx)\r
e5f426aa 698{\r
699 int sel = 0, menu_sel_max = opt_cnt, prev_select = 0, i;\r
700 unsigned long inp = 0;\r
701\r
702 for (;;)\r
703 {\r
704 draw_key_config(opts, opt_cnt, player_idx, sel);\r
9839d126 705 inp = wait_for_input(CONFIGURABLE_KEYS|BTN_HOME);\r
e5f426aa 706 if (!(inp & BTN_HOME)) {\r
707 prev_select = 0;\r
708 if(inp & BTN_UP ) { sel--; if (sel < 0) sel = menu_sel_max; continue; }\r
709 if(inp & BTN_DOWN) { sel++; if (sel > menu_sel_max) sel = 0; continue; }\r
710 }\r
711 if (sel >= opt_cnt) {\r
712 if (inp & (BTN_PLAY|BTN_STOP)) break;\r
713 else continue;\r
714 }\r
715 // if we are here, we want to bind/unbind something\r
716 if ((inp & BTN_HOME) && !prev_select)\r
717 unbind_action(opts[sel].mask);\r
718 prev_select = inp & BTN_HOME;\r
719 inp &= CONFIGURABLE_KEYS;\r
720 inp &= ~BTN_HOME;\r
721 for (i = 0; i < 32; i++)\r
722 if (inp & (1 << i)) {\r
c9077ab4 723 if (count_bound_keys(opts[sel].mask, player_idx) >= 2)\r
724 currentConfig.KeyBinds[i] &= ~opts[sel].mask; // allow to unbind only\r
e5f426aa 725 else currentConfig.KeyBinds[i] ^= opts[sel].mask;\r
c9077ab4 726 if (player_idx >= 0 && (currentConfig.KeyBinds[i] & opts[sel].mask)) {\r
e5f426aa 727 currentConfig.KeyBinds[i] &= ~(3 << 16);\r
728 currentConfig.KeyBinds[i] |= player_idx << 16;\r
729 }\r
730 }\r
731 }\r
732}\r
733\r
f0f0d2df 734menu_entry ctrlopt_entries[] =\r
735{\r
736 { "Player 1", MB_NONE, MA_CTRL_PLAYER1, NULL, 0, 0, 0, 1, 0 },\r
737 { "Player 2", MB_NONE, MA_CTRL_PLAYER2, NULL, 0, 0, 0, 1, 0 },\r
738 { "Emulator controls", MB_NONE, MA_CTRL_EMU, NULL, 0, 0, 0, 1, 0 },\r
739 { "6 button pad", MB_ONOFF, MA_OPT_6BUTTON_PAD, &PicoOpt, 0x020, 0, 0, 1, 1 },\r
740 { "Turbo rate", MB_RANGE, MA_CTRL_TURBO_RATE, &currentConfig.turbo_rate, 0, 1, 30, 1, 1 },\r
741 { "Done", MB_NONE, MA_CTRL_DONE, NULL, 0, 0, 0, 1, 0 },\r
742};\r
743\r
744#define CTRLOPT_ENTRY_COUNT (sizeof(ctrlopt_entries) / sizeof(ctrlopt_entries[0]))\r
745const int ctrlopt_entry_count = CTRLOPT_ENTRY_COUNT;\r
746\r
e5f426aa 747static void draw_kc_sel(int menu_sel)\r
748{\r
749 int tl_x = 25+40, tl_y = 60, y;\r
750\r
751 y = tl_y;\r
752 menu_draw_begin(1);\r
753 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 138);\r
754\r
f0f0d2df 755 me_draw(ctrlopt_entries, ctrlopt_entry_count, tl_x, tl_y, NULL, NULL);\r
e5f426aa 756\r
757 menu_draw_end();\r
758}\r
759\r
760\r
e5f426aa 761// player2_flag, ?, ?, ?, ?, ?, ?, menu\r
762// "NEXT SAVE SLOT", "PREV SAVE SLOT", "SWITCH RENDERER", "SAVE STATE",\r
763// "LOAD STATE", "VOLUME UP", "VOLUME DOWN", "DONE"\r
1ca2ea4f 764me_bind_action emuctrl_actions[] =\r
e5f426aa 765{\r
766 { "Load State ", 1<<28 },\r
767 { "Save State ", 1<<27 },\r
768 { "Prev Save Slot ", 1<<25 },\r
769 { "Next Save Slot ", 1<<24 },\r
770 { "Switch Renderer", 1<<26 },\r
771 { "Volume Down ", 1<<30 },\r
772 { "Volume Up ", 1<<29 },\r
1ca2ea4f 773 { NULL, 0 }\r
e5f426aa 774};\r
775\r
776static void kc_sel_loop(void)\r
777{\r
f0f0d2df 778 int menu_sel = 5, menu_sel_max = 5;\r
e5f426aa 779 unsigned long inp = 0;\r
f0f0d2df 780 menu_id selected_id;\r
e5f426aa 781\r
782 while (1)\r
783 {\r
784 draw_kc_sel(menu_sel);\r
785 inp = wait_for_input(BTN_UP|BTN_DOWN|BTN_PLAY|BTN_STOP);\r
f0f0d2df 786 selected_id = me_index2id(ctrlopt_entries, CTRLOPT_ENTRY_COUNT, menu_sel);\r
787 if (inp & (BTN_LEFT|BTN_RIGHT)) // multi choise\r
788 me_process(ctrlopt_entries, CTRLOPT_ENTRY_COUNT, selected_id, (inp&BTN_RIGHT) ? 1 : 0);\r
e5f426aa 789 if (inp & BTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
790 if (inp & BTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
791 if (inp & BTN_PLAY) {\r
f0f0d2df 792 int is_6button = currentConfig.PicoOpt & 0x020;\r
793 switch (selected_id) {\r
794 case MA_CTRL_PLAYER1: key_config_loop(me_ctrl_actions, is_6button ? 15 : 11, 0); return;\r
795 case MA_CTRL_PLAYER2: key_config_loop(me_ctrl_actions, is_6button ? 15 : 11, 1); return;\r
796 case MA_CTRL_EMU: key_config_loop(emuctrl_actions,\r
797 sizeof(emuctrl_actions)/sizeof(emuctrl_actions[0]) - 1, -1); return;\r
798 case MA_CTRL_DONE: if (!rom_loaded) emu_WriteConfig(0); return;\r
e5f426aa 799 default: return;\r
800 }\r
801 }\r
802 if (inp & BTN_STOP) return;\r
803 }\r
804}\r
805\r
806\r
807// --------- sega/mega cd options ----------\r
808\r
809menu_entry cdopt_entries[] =\r
810{\r
811 { NULL, MB_NONE, MA_CDOPT_TESTBIOS_USA, NULL, 0, 0, 0, 1 },\r
812 { NULL, MB_NONE, MA_CDOPT_TESTBIOS_EUR, NULL, 0, 0, 0, 1 },\r
813 { NULL, MB_NONE, MA_CDOPT_TESTBIOS_JAP, NULL, 0, 0, 0, 1 },\r
814 { "CD LEDs", MB_ONOFF, MA_CDOPT_LEDS, &currentConfig.EmuOpt, 0x0400, 0, 0, 1 },\r
815 { "CDDA audio (using mp3s)", MB_ONOFF, MA_CDOPT_CDDA, &currentConfig.PicoOpt, 0x0800, 0, 0, 1 },\r
816 { "PCM audio", MB_ONOFF, MA_CDOPT_PCM, &currentConfig.PicoOpt, 0x0400, 0, 0, 1 },\r
817 { NULL, MB_NONE, MA_CDOPT_READAHEAD, NULL, 0, 0, 0, 1 },\r
818 { "SaveRAM cart", MB_ONOFF, MA_CDOPT_SAVERAM, &currentConfig.PicoOpt, 0x8000, 0, 0, 1 },\r
819 { "Scale/Rot. fx (slow)", MB_ONOFF, MA_CDOPT_SCALEROT_CHIP,&currentConfig.PicoOpt, 0x1000, 0, 0, 1 },\r
820 { "Better sync (slow)", MB_ONOFF, MA_CDOPT_BETTER_SYNC, &currentConfig.PicoOpt, 0x2000, 0, 0, 1 },\r
821 { "done", MB_NONE, MA_CDOPT_DONE, NULL, 0, 0, 0, 1 },\r
822};\r
823\r
824#define CDOPT_ENTRY_COUNT (sizeof(cdopt_entries) / sizeof(cdopt_entries[0]))\r
825\r
826\r
827struct bios_names_t\r
828{\r
829 char us[32], eu[32], jp[32];\r
830};\r
831\r
832static void menu_cdopt_cust_draw(const menu_entry *entry, int x, int y, void *param)\r
833{\r
834 struct bios_names_t *bios_names = param;\r
835 char ra_buff[16];\r
836\r
837 switch (entry->id)\r
838 {\r
839 case MA_CDOPT_TESTBIOS_USA: text_out16(x, y, "USA BIOS: %s", bios_names->us); break;\r
840 case MA_CDOPT_TESTBIOS_EUR: text_out16(x, y, "EUR BIOS: %s", bios_names->eu); break;\r
841 case MA_CDOPT_TESTBIOS_JAP: text_out16(x, y, "JAP BIOS: %s", bios_names->jp); break;\r
842 case MA_CDOPT_READAHEAD:\r
843 if (PicoCDBuffers > 1) sprintf(ra_buff, "%5iK", PicoCDBuffers * 2);\r
844 else strcpy(ra_buff, " OFF");\r
845 text_out16(x, y, "ReadAhead buffer %s", ra_buff);\r
846 break;\r
847 default:break;\r
848 }\r
849}\r
850\r
851static void draw_cd_menu_options(int menu_sel, struct bios_names_t *bios_names)\r
852{\r
853 int tl_x = 25, tl_y = 60;\r
854 menu_id selected_id;\r
855 char ra_buff[16];\r
856\r
857 if (PicoCDBuffers > 1) sprintf(ra_buff, "%5iK", PicoCDBuffers * 2);\r
858 else strcpy(ra_buff, " OFF");\r
859\r
860 menu_draw_begin(1);\r
861\r
862 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 246);\r
863\r
864 me_draw(cdopt_entries, CDOPT_ENTRY_COUNT, tl_x, tl_y, menu_cdopt_cust_draw, bios_names);\r
865\r
866 selected_id = me_index2id(cdopt_entries, CDOPT_ENTRY_COUNT, menu_sel);\r
867 if ((selected_id == MA_CDOPT_TESTBIOS_USA && strcmp(bios_names->us, "NOT FOUND")) ||\r
868 (selected_id == MA_CDOPT_TESTBIOS_EUR && strcmp(bios_names->eu, "NOT FOUND")) ||\r
869 (selected_id == MA_CDOPT_TESTBIOS_JAP && strcmp(bios_names->jp, "NOT FOUND")))\r
870 text_out16(tl_x, 210, "Press start to test selected BIOS");\r
871\r
872 menu_draw_end();\r
873}\r
874\r
875static void cd_menu_loop_options(void)\r
876{\r
877 static int menu_sel = 0;\r
878 int menu_sel_max = 10;\r
879 unsigned long inp = 0;\r
880 struct bios_names_t bios_names;\r
881 menu_id selected_id;\r
882 char *bios, *p;\r
883\r
ea8c405f 884 if (emu_findBios(4, &bios)) { // US\r
e5f426aa 885 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
886 strncpy(bios_names.us, p, sizeof(bios_names.us)); bios_names.us[sizeof(bios_names.us)-1] = 0;\r
887 } else strcpy(bios_names.us, "NOT FOUND");\r
888\r
ea8c405f 889 if (emu_findBios(8, &bios)) { // EU\r
e5f426aa 890 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
891 strncpy(bios_names.eu, p, sizeof(bios_names.eu)); bios_names.eu[sizeof(bios_names.eu)-1] = 0;\r
892 } else strcpy(bios_names.eu, "NOT FOUND");\r
893\r
ea8c405f 894 if (emu_findBios(1, &bios)) { // JP\r
e5f426aa 895 for (p = bios+strlen(bios)-1; p > bios && *p != '/'; p--); p++;\r
896 strncpy(bios_names.jp, p, sizeof(bios_names.jp)); bios_names.jp[sizeof(bios_names.jp)-1] = 0;\r
897 } else strcpy(bios_names.jp, "NOT FOUND");\r
898\r
899 for(;;)\r
900 {\r
901 draw_cd_menu_options(menu_sel, &bios_names);\r
902 inp = wait_for_input(BTN_UP|BTN_DOWN|BTN_LEFT|BTN_RIGHT|BTN_PLAY|BTN_STOP|BTN_REW);\r
903 if (inp & BTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
904 if (inp & BTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
905 selected_id = me_index2id(cdopt_entries, CDOPT_ENTRY_COUNT, menu_sel);\r
906 if (inp & (BTN_LEFT|BTN_RIGHT)) { // multi choise\r
907 if (!me_process(cdopt_entries, CDOPT_ENTRY_COUNT, selected_id, (inp&BTN_RIGHT) ? 1 : 0) &&\r
908 selected_id == MA_CDOPT_READAHEAD) {\r
909 if (inp & BTN_LEFT) {\r
910 PicoCDBuffers >>= 1;\r
2d2247c2 911 if (PicoCDBuffers < 2) PicoCDBuffers = 0;\r
e5f426aa 912 } else {\r
2d2247c2 913 if (PicoCDBuffers < 2) PicoCDBuffers = 2;\r
e5f426aa 914 else PicoCDBuffers <<= 1;\r
915 if (PicoCDBuffers > 8*1024) PicoCDBuffers = 8*1024; // 16M\r
916 }\r
917 }\r
918 }\r
919 if (inp & BTN_PLAY) { // toggleable options\r
920 if (!me_process(cdopt_entries, CDOPT_ENTRY_COUNT, selected_id, 1) &&\r
921 selected_id == MA_CDOPT_DONE) {\r
922 return;\r
923 }\r
924 switch (selected_id) { // BIOS testers\r
925 case MA_CDOPT_TESTBIOS_USA:\r
ea8c405f 926 if (emu_findBios(4, &bios)) { // test US\r
e5f426aa 927 strcpy(romFileName, bios);\r
928 engineState = PGS_ReloadRom;\r
929 return;\r
930 }\r
931 break;\r
932 case MA_CDOPT_TESTBIOS_EUR:\r
ea8c405f 933 if (emu_findBios(8, &bios)) { // test EU\r
e5f426aa 934 strcpy(romFileName, bios);\r
935 engineState = PGS_ReloadRom;\r
936 return;\r
937 }\r
938 break;\r
939 case MA_CDOPT_TESTBIOS_JAP:\r
ea8c405f 940 if (emu_findBios(1, &bios)) { // test JP\r
e5f426aa 941 strcpy(romFileName, bios);\r
942 engineState = PGS_ReloadRom;\r
943 return;\r
944 }\r
945 break;\r
946 default:\r
947 break;\r
948 }\r
949 }\r
950 if (inp & (BTN_STOP|BTN_REW)) return;\r
951 }\r
952}\r
953\r
954\r
955// --------- advanced options ----------\r
956\r
957menu_entry opt2_entries[] =\r
958{\r
6fc57144 959 { "Disable sprite limit", MB_ONOFF, MA_OPT2_NO_SPRITE_LIM, &PicoOpt, 0x40000, 0, 0, 1, 1 },\r
e5f426aa 960 { "Emulate Z80", MB_ONOFF, MA_OPT2_ENABLE_Z80, &currentConfig.PicoOpt,0x0004, 0, 0, 1 },\r
961 { "Emulate YM2612 (FM)", MB_ONOFF, MA_OPT2_ENABLE_YM2612, &currentConfig.PicoOpt,0x0001, 0, 0, 1 },\r
962 { "Emulate SN76496 (PSG)", MB_ONOFF, MA_OPT2_ENABLE_SN76496,&currentConfig.PicoOpt,0x0002, 0, 0, 1 },\r
c77ca79e 963 { "Double buffering", MB_ONOFF, MA_OPT2_DBLBUFF, &currentConfig.EmuOpt, 0x8000, 0, 0, 1 },\r
a8869ad1 964 { "Wait for V-sync (slow)", MB_ONOFF, MA_OPT2_VSYNC, &currentConfig.EmuOpt, 0x2000, 0, 0, 1 },\r
e5f426aa 965 { "gzip savestates", MB_ONOFF, MA_OPT2_GZIP_STATES, &currentConfig.EmuOpt, 0x0008, 0, 0, 1 },\r
966 { "Don't save last used ROM", MB_ONOFF, MA_OPT2_NO_LAST_ROM, &currentConfig.EmuOpt, 0x0020, 0, 0, 1 },\r
967 { "done", MB_NONE, MA_OPT2_DONE, NULL, 0, 0, 0, 1 },\r
968};\r
969\r
970#define OPT2_ENTRY_COUNT (sizeof(opt2_entries) / sizeof(opt2_entries[0]))\r
971\r
972\r
973static void draw_amenu_options(int menu_sel)\r
974{\r
975 int tl_x = 25, tl_y = 50;\r
976\r
977 menu_draw_begin(1);\r
978\r
979 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 252);\r
980\r
981 me_draw(opt2_entries, OPT2_ENTRY_COUNT, tl_x, tl_y, NULL, NULL);\r
982\r
983 menu_draw_end();\r
984}\r
985\r
986static void amenu_loop_options(void)\r
987{\r
988 static int menu_sel = 0;\r
989 int menu_sel_max;\r
990 unsigned long inp = 0;\r
991 menu_id selected_id;\r
992\r
993 menu_sel_max = me_count_enabled(opt2_entries, OPT2_ENTRY_COUNT) - 1;\r
994\r
995 for(;;)\r
996 {\r
997 draw_amenu_options(menu_sel);\r
998 inp = wait_for_input(BTN_UP|BTN_DOWN|BTN_LEFT|BTN_RIGHT|BTN_PLAY|BTN_STOP|BTN_REW);\r
999 if (inp & BTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1000 if (inp & BTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
1001 selected_id = me_index2id(opt2_entries, OPT2_ENTRY_COUNT, menu_sel);\r
1002 if (inp & (BTN_LEFT|BTN_RIGHT)) { // multi choise\r
1003 if (!me_process(opt2_entries, OPT2_ENTRY_COUNT, selected_id, (inp&BTN_RIGHT) ? 1 : 0) &&\r
1004 selected_id == MA_OPT2_GAMMA) {\r
2ec14aec 1005 while ((inp = Framework_PollGetButtons()) & (BTN_LEFT|BTN_RIGHT)) {\r
e5f426aa 1006 currentConfig.gamma += (inp & BTN_LEFT) ? -1 : 1;\r
1007 if (currentConfig.gamma < 1) currentConfig.gamma = 1;\r
1008 if (currentConfig.gamma > 300) currentConfig.gamma = 300;\r
1009 draw_amenu_options(menu_sel);\r
1010 Sleep(18);\r
1011 }\r
1012 }\r
1013 }\r
1014 if (inp & BTN_PLAY) { // toggleable options\r
1015 if (!me_process(opt2_entries, OPT2_ENTRY_COUNT, selected_id, 1) &&\r
1016 selected_id == MA_OPT2_DONE) {\r
1017 return;\r
1018 }\r
1019 }\r
1020 if (inp & (BTN_STOP|BTN_REW)) return;\r
1021 }\r
1022}\r
1023\r
1024// -------------- options --------------\r
1025\r
1026\r
1027menu_entry opt_entries[] =\r
1028{\r
1029 { NULL, MB_NONE, MA_OPT_RENDERER, NULL, 0, 0, 0, 1 },\r
f0f0d2df 1030 { "Accurate sprites", MB_ONOFF, MA_OPT_ACC_SPRITES, &PicoOpt, 0x080, 0, 0, 0, 1 },\r
c77ca79e 1031 { "Scanline mode (faster)", MB_ONOFF, MA_OPT_INTERLACED, &currentConfig.EmuOpt, 0x4000, 0, 0, 1 },\r
a8869ad1 1032 { "Scale low res mode", MB_ONOFF, MA_OPT_SCALING, &currentConfig.scaling, 0x0001, 0, 3, 1 },\r
a8869ad1 1033 { "Show FPS", MB_ONOFF, MA_OPT_SHOW_FPS, &currentConfig.EmuOpt, 0x0002, 0, 0, 1 },\r
e5f426aa 1034 { NULL, MB_RANGE, MA_OPT_FRAMESKIP, &currentConfig.Frameskip, 0, -1, 16, 1 },\r
a8869ad1 1035 { "Enable sound", MB_ONOFF, MA_OPT_ENABLE_SOUND, &currentConfig.EmuOpt, 0x0004, 0, 0, 1 },\r
e5f426aa 1036 { NULL, MB_NONE, MA_OPT_SOUND_QUALITY, NULL, 0, 0, 0, 1 },\r
e5f426aa 1037 { NULL, MB_NONE, MA_OPT_REGION, NULL, 0, 0, 0, 1 },\r
a8869ad1 1038 { "Use SRAM/BRAM savestates", MB_ONOFF, MA_OPT_SRAM_STATES, &currentConfig.EmuOpt, 0x0001, 0, 0, 1 },\r
e5f426aa 1039 { NULL, MB_NONE, MA_OPT_CONFIRM_STATES,NULL, 0, 0, 0, 1 },\r
1040 { "Save slot", MB_RANGE, MA_OPT_SAVE_SLOT, &state_slot, 0, 0, 9, 1 },\r
1041 { "[Sega/Mega CD options]", MB_NONE, MA_OPT_SCD_OPTS, NULL, 0, 0, 0, 1 },\r
1042 { "[advanced options]", MB_NONE, MA_OPT_ADV_OPTS, NULL, 0, 0, 0, 1 },\r
1043 { NULL, MB_NONE, MA_OPT_SAVECFG, NULL, 0, 0, 0, 1 },\r
1044 { "Save cfg for current game only",MB_NONE,MA_OPT_SAVECFG_GAME,NULL, 0, 0, 0, 1 },\r
1045 { NULL, MB_NONE, MA_OPT_LOADCFG, NULL, 0, 0, 0, 1 },\r
1046};\r
1047\r
1048#define OPT_ENTRY_COUNT (sizeof(opt_entries) / sizeof(opt_entries[0]))\r
1049\r
1050\r
e5f426aa 1051static void menu_opt_cust_draw(const menu_entry *entry, int x, int y, void *param)\r
1052{\r
1053 char *str, str24[24];\r
1054\r
1055 switch (entry->id)\r
1056 {\r
1057 case MA_OPT_RENDERER:\r
1058 if (currentConfig.PicoOpt&0x10)\r
1059 str = " 8bit fast";\r
1060 else if (currentConfig.EmuOpt&0x80)\r
1061 str = "16bit accurate";\r
1062 else\r
1063 str = " 8bit accurate";\r
1064 text_out16(x, y, "Renderer: %s", str);\r
1065 break;\r
1066 case MA_OPT_FRAMESKIP:\r
1067 if (currentConfig.Frameskip < 0)\r
1068 strcpy(str24, "Auto");\r
1069 else sprintf(str24, "%i", currentConfig.Frameskip);\r
1070 text_out16(x, y, "Frameskip %s", str24);\r
1071 break;\r
1072 case MA_OPT_SOUND_QUALITY:\r
1073 str = (currentConfig.PicoOpt&0x08)?"stereo":"mono";\r
1074 text_out16(x, y, "Sound Quality: %5iHz %s", currentConfig.PsndRate, str);\r
1075 break;\r
1076 case MA_OPT_REGION:\r
58c86d00 1077 text_out16(x, y, "Region: %s", me_region_name(PicoRegionOverride, PicoAutoRgnOrder));\r
e5f426aa 1078 break;\r
1079 case MA_OPT_CONFIRM_STATES:\r
1080 switch ((currentConfig.EmuOpt >> 9) & 5) {\r
1081 default: str = "OFF"; break;\r
1082 case 1: str = "writes"; break;\r
1083 case 4: str = "loads"; break;\r
1084 case 5: str = "both"; break;\r
1085 }\r
1086 text_out16(x, y, "Confirm savestate %s", str);\r
1087 break;\r
1088 case MA_OPT_SAVECFG:\r
1089 str24[0] = 0;\r
1090 if (config_slot != 0) sprintf(str24, " (profile: %i)", config_slot);\r
1091 text_out16(x, y, "Save cfg as default%s", str24);\r
1092 break;\r
1093 case MA_OPT_LOADCFG:\r
1094 text_out16(x, y, "Load cfg from profile %i", config_slot);\r
1095 break;\r
1096 default:\r
1097 lprintf("%s: unimplemented (%i)\n", __FUNCTION__, entry->id);\r
1098 break;\r
1099 }\r
1100}\r
1101\r
1102\r
1103\r
1104static void draw_menu_options(int menu_sel)\r
1105{\r
1106 int tl_x = 25, tl_y = 24;\r
1107\r
1108 menu_draw_begin(1);\r
1109\r
1110 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 284);\r
1111\r
1112 me_draw(opt_entries, OPT_ENTRY_COUNT, tl_x, tl_y, menu_opt_cust_draw, NULL);\r
1113\r
1114 menu_draw_end();\r
1115}\r
1116\r
1117static int sndrate_prevnext(int rate, int dir)\r
1118{\r
fa283c9a 1119 int i, rates[] = { 11025, 22050, 44100 };\r
e5f426aa 1120\r
1121 for (i = 0; i < 5; i++)\r
1122 if (rates[i] == rate) break;\r
1123\r
1124 i += dir ? 1 : -1;\r
f3d1de29 1125 if (i > 2) return dir ? 44100 : 22050;\r
fa283c9a 1126 if (i < 0) return dir ? 22050 : 11025;\r
e5f426aa 1127 return rates[i];\r
1128}\r
1129\r
1130static void region_prevnext(int right)\r
1131{\r
1132 // jp_ntsc=1, jp_pal=2, usa=4, eu=8\r
1133 static int rgn_orders[] = { 0x148, 0x184, 0x814, 0x418, 0x841, 0x481 };\r
1134 int i;\r
1135 if (right) {\r
58c86d00 1136 if (!PicoRegionOverride) {\r
e5f426aa 1137 for (i = 0; i < 6; i++)\r
1138 if (rgn_orders[i] == PicoAutoRgnOrder) break;\r
1139 if (i < 5) PicoAutoRgnOrder = rgn_orders[i+1];\r
58c86d00 1140 else PicoRegionOverride=1;\r
e5f426aa 1141 }\r
58c86d00 1142 else PicoRegionOverride<<=1;\r
1143 if (PicoRegionOverride > 8) PicoRegionOverride = 8;\r
e5f426aa 1144 } else {\r
58c86d00 1145 if (!PicoRegionOverride) {\r
e5f426aa 1146 for (i = 0; i < 6; i++)\r
1147 if (rgn_orders[i] == PicoAutoRgnOrder) break;\r
1148 if (i > 0) PicoAutoRgnOrder = rgn_orders[i-1];\r
1149 }\r
58c86d00 1150 else PicoRegionOverride>>=1;\r
e5f426aa 1151 }\r
1152}\r
1153\r
1154static void menu_options_save(void)\r
1155{\r
1156 PicoOpt = currentConfig.PicoOpt;\r
1157 PsndRate = currentConfig.PsndRate;\r
7d0143a2 1158 if (PicoRegionOverride) {\r
1159 // force setting possibly changed..\r
1160 Pico.m.pal = (PicoRegionOverride == 2 || PicoRegionOverride == 8) ? 1 : 0;\r
1161 }\r
e5f426aa 1162 if (!(PicoOpt & 0x20)) {\r
1163 // unbind XYZ MODE, just in case\r
1164 unbind_action(0xf00);\r
1165 }\r
e5f426aa 1166}\r
1167\r
1168static int menu_loop_options(void)\r
1169{\r
1170 static int menu_sel = 0;\r
1171 int menu_sel_max, ret;\r
1172 unsigned long inp = 0;\r
1173 menu_id selected_id;\r
1174\r
1175 currentConfig.PicoOpt = PicoOpt;\r
1176 currentConfig.PsndRate = PsndRate;\r
e5f426aa 1177\r
eacee137 1178 me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_SAVECFG_GAME, rom_loaded);\r
e5f426aa 1179 me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_LOADCFG, config_slot != config_slot_current);\r
1180 menu_sel_max = me_count_enabled(opt_entries, OPT_ENTRY_COUNT) - 1;\r
1181 if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;\r
1182\r
1183 while (1)\r
1184 {\r
1185 draw_menu_options(menu_sel);\r
1186 inp = wait_for_input(BTN_UP|BTN_DOWN|BTN_LEFT|BTN_RIGHT|BTN_PLAY|BTN_STOP|BTN_REW);\r
1187 if (inp & BTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1188 if (inp & BTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
1189 selected_id = me_index2id(opt_entries, OPT_ENTRY_COUNT, menu_sel);\r
1190 if (inp & (BTN_LEFT|BTN_RIGHT)) { // multi choise\r
1191 if (!me_process(opt_entries, OPT_ENTRY_COUNT, selected_id, (inp&BTN_RIGHT) ? 1 : 0)) {\r
1192 switch (selected_id) {\r
1193 case MA_OPT_RENDERER:\r
1194 if (inp & BTN_LEFT) {\r
a8869ad1 1195 if ((currentConfig.PicoOpt&0x10) || !(currentConfig.EmuOpt &0x80)) {\r
1196 currentConfig.PicoOpt&= ~0x10;\r
1197 currentConfig.EmuOpt |= 0x80;\r
1198 }\r
e5f426aa 1199 } else {\r
a8869ad1 1200 if (!(currentConfig.PicoOpt&0x10) || (currentConfig.EmuOpt &0x80)) {\r
1201 currentConfig.PicoOpt|= 0x10;\r
1202 currentConfig.EmuOpt &= ~0x80;\r
1203 }\r
e5f426aa 1204 }\r
1205 break;\r
1206 case MA_OPT_SOUND_QUALITY:\r
da42200b 1207 if ((inp & BTN_RIGHT) && currentConfig.PsndRate == 44100 &&\r
1208 !(currentConfig.PicoOpt&0x08))\r
1209 {\r
1210 currentConfig.PsndRate = 11025;\r
1211 currentConfig.PicoOpt |= 8;\r
1212 } else if ((inp & BTN_LEFT) && currentConfig.PsndRate == 11025 &&\r
602133e1 1213 (currentConfig.PicoOpt&0x08) && !(PicoAHW&1))\r
da42200b 1214 {\r
1215 currentConfig.PsndRate = 44100;\r
1216 currentConfig.PicoOpt &= ~8;\r
1217 } else\r
1218 currentConfig.PsndRate = sndrate_prevnext(currentConfig.PsndRate, inp & BTN_RIGHT);\r
e5f426aa 1219 break;\r
1220 case MA_OPT_REGION:\r
1221 region_prevnext(inp & BTN_RIGHT);\r
1222 break;\r
1223 case MA_OPT_CONFIRM_STATES: {\r
1224 int n = ((currentConfig.EmuOpt>>9)&1) | ((currentConfig.EmuOpt>>10)&2);\r
1225 n += (inp & BTN_LEFT) ? -1 : 1;\r
1226 if (n < 0) n = 0; else if (n > 3) n = 3;\r
1227 n |= n << 1; n &= ~2;\r
1228 currentConfig.EmuOpt &= ~0xa00;\r
1229 currentConfig.EmuOpt |= n << 9;\r
1230 break;\r
1231 }\r
1232 case MA_OPT_SAVE_SLOT:\r
1233 if (inp & BTN_RIGHT) {\r
1234 state_slot++; if (state_slot > 9) state_slot = 0;\r
1235 } else {state_slot--; if (state_slot < 0) state_slot = 9;\r
1236 }\r
1237 break;\r
1238 case MA_OPT_SAVECFG:\r
1239 case MA_OPT_SAVECFG_GAME:\r
1240 case MA_OPT_LOADCFG:\r
1241 config_slot += (inp&BTN_RIGHT) ? 1 : -1;\r
1242 if (config_slot > 9) config_slot = 0;\r
1243 if (config_slot < 0) config_slot = 9;\r
1244 me_enable(opt_entries, OPT_ENTRY_COUNT, MA_OPT_LOADCFG, config_slot != config_slot_current);\r
1245 menu_sel_max = me_count_enabled(opt_entries, OPT_ENTRY_COUNT) - 1;\r
1246 if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;\r
1247 break;\r
1248 default:\r
1249 //lprintf("%s: something unknown selected (%i)\n", __FUNCTION__, selected_id);\r
1250 break;\r
1251 }\r
1252 }\r
1253 }\r
1254 if (inp & BTN_PLAY) {\r
1255 if (!me_process(opt_entries, OPT_ENTRY_COUNT, selected_id, 1))\r
1256 {\r
1257 switch (selected_id)\r
1258 {\r
1259 case MA_OPT_SCD_OPTS:\r
1260 cd_menu_loop_options();\r
1261 if (engineState == PGS_ReloadRom)\r
1262 return 0; // test BIOS\r
1263 break;\r
1264 case MA_OPT_ADV_OPTS:\r
1265 amenu_loop_options();\r
1266 break;\r
1267 case MA_OPT_SAVECFG: // done (update and write)\r
1268 menu_options_save();\r
1269 if (emu_WriteConfig(0)) strcpy(menuErrorMsg, "config saved");\r
1270 else strcpy(menuErrorMsg, "failed to write config");\r
1271 return 1;\r
1272 case MA_OPT_SAVECFG_GAME: // done (update and write for current game)\r
1273 menu_options_save();\r
1274 if (emu_WriteConfig(1)) strcpy(menuErrorMsg, "config saved");\r
1275 else strcpy(menuErrorMsg, "failed to write config");\r
1276 return 1;\r
1277 case MA_OPT_LOADCFG:\r
1278 ret = emu_ReadConfig(1, 1);\r
1279 if (!ret) ret = emu_ReadConfig(0, 1);\r
1280 if (ret) strcpy(menuErrorMsg, "config loaded");\r
1281 else strcpy(menuErrorMsg, "failed to load config");\r
1282 return 1;\r
1283 default:\r
1284 //lprintf("%s: something unknown selected (%i)\n", __FUNCTION__, selected_id);\r
1285 break;\r
1286 }\r
1287 }\r
1288 }\r
1289 if(inp & (BTN_STOP|BTN_REW)) {\r
1290 menu_options_save();\r
1291 return 0; // done (update, no write)\r
1292 }\r
1293 }\r
1294}\r
1295\r
1296// -------------- credits --------------\r
1297\r
1298static void draw_menu_credits(void)\r
1299{\r
053fd9b4 1300 int tl_x = 15, tl_y = 56, y;\r
e5f426aa 1301 menu_draw_begin(1);\r
1302\r
6fc57144 1303 text_out16(tl_x, 20, "PicoDrive v" VERSION " (c) notaz, 2006-2008");\r
0ffa8947 1304\r
e5f426aa 1305 y = tl_y;\r
1306 text_out16(tl_x, y, "Credits:");\r
3ec29f01 1307 text_out16(tl_x, (y+=10), "fDave: Cyclone 68000 core,");\r
e5f426aa 1308 text_out16(tl_x, (y+=10), " base code of PicoDrive");\r
1309 text_out16(tl_x, (y+=10), "Reesy & FluBBa: DrZ80 core");\r
1310 text_out16(tl_x, (y+=10), "MAME devs: YM2612 and SN76496 cores");\r
2ec14aec 1311 text_out16(tl_x, (y+=10), "Reesy: kgsdk wrapper, sound code");\r
1312 text_out16(tl_x, (y+=10), "jens.l: gizmondo hardware");\r
e5f426aa 1313 text_out16(tl_x, (y+=10), "ketchupgun: skin design");\r
1314\r
1a65e3b1 1315 text_out16(tl_x, (y+=20), "special thanks (for docs, ideas)");\r
053fd9b4 1316 text_out16(tl_x, (y+=10), " Charles MacDonald, Haze,");\r
1317 text_out16(tl_x, (y+=10), " Stephane Dallongeville,");\r
1318 text_out16(tl_x, (y+=10), " Lordus, Exophase, Rokas,");\r
1319 text_out16(tl_x, (y+=10), " Nemesis, Tasco Deluxe");\r
1320\r
e5f426aa 1321 menu_draw_end();\r
1322}\r
1323\r
1324\r
1325// -------------- root menu --------------\r
1326\r
1327menu_entry main_entries[] =\r
1328{\r
1329 { "Resume game", MB_NONE, MA_MAIN_RESUME_GAME, NULL, 0, 0, 0, 0 },\r
1330 { "Save State", MB_NONE, MA_MAIN_SAVE_STATE, NULL, 0, 0, 0, 0 },\r
1331 { "Load State", MB_NONE, MA_MAIN_LOAD_STATE, NULL, 0, 0, 0, 0 },\r
1332 { "Reset game", MB_NONE, MA_MAIN_RESET_GAME, NULL, 0, 0, 0, 0 },\r
1333 { "Load new ROM/ISO", MB_NONE, MA_MAIN_LOAD_ROM, NULL, 0, 0, 0, 1 },\r
1334 { "Change options", MB_NONE, MA_MAIN_OPTIONS, NULL, 0, 0, 0, 1 },\r
1335 { "Configure controls", MB_NONE, MA_MAIN_CONTROLS, NULL, 0, 0, 0, 1 },\r
1336 { "Credits", MB_NONE, MA_MAIN_CREDITS, NULL, 0, 0, 0, 1 },\r
1337 { "Patches / GameGenie",MB_NONE, MA_MAIN_PATCHES, NULL, 0, 0, 0, 0 },\r
1338 { "Exit", MB_NONE, MA_MAIN_EXIT, NULL, 0, 0, 0, 1 }\r
1339};\r
1340\r
1341#define MAIN_ENTRY_COUNT (sizeof(main_entries) / sizeof(main_entries[0]))\r
1342\r
1343static void draw_menu_root(int menu_sel)\r
1344{\r
1345 const int tl_x = 70, tl_y = 70;\r
1346\r
1347 menu_draw_begin(1);\r
1348\r
1349 text_out16(tl_x, 20, "PicoDrive v" VERSION);\r
1350\r
1351 menu_draw_selection(tl_x - 16, tl_y + menu_sel*10, 146);\r
1352\r
1353 me_draw(main_entries, MAIN_ENTRY_COUNT, tl_x, tl_y, NULL, NULL);\r
1354\r
1355 // error\r
1356 if (menuErrorMsg[0]) {\r
c9077ab4 1357 memset((char *)menu_screen + 321*224*2, 0, 321*16*2);\r
e5f426aa 1358 text_out16(5, 226, menuErrorMsg);\r
1359 }\r
1360 menu_draw_end();\r
1361}\r
1362\r
1363\r
1364static void menu_loop_root(void)\r
1365{\r
1366 static int menu_sel = 0;\r
1367 int ret, menu_sel_max;\r
1368 unsigned long inp = 0;\r
1369\r
eacee137 1370 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_RESUME_GAME, rom_loaded);\r
1371 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_SAVE_STATE, rom_loaded);\r
1372 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_LOAD_STATE, rom_loaded);\r
1373 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_RESET_GAME, rom_loaded);\r
e5f426aa 1374 me_enable(main_entries, MAIN_ENTRY_COUNT, MA_MAIN_PATCHES, PicoPatches != NULL);\r
1375\r
1376 menu_sel_max = me_count_enabled(main_entries, MAIN_ENTRY_COUNT) - 1;\r
1377 if (menu_sel > menu_sel_max) menu_sel = menu_sel_max;\r
1378\r
1379 /* make sure action buttons are not pressed on entering menu */\r
1380 draw_menu_root(menu_sel);\r
c9077ab4 1381\r
2ec14aec 1382 while (Framework_PollGetButtons() & (BTN_PLAY|BTN_STOP|BTN_HOME)) Sleep(50);\r
e5f426aa 1383\r
1384 for (;;)\r
1385 {\r
1386 draw_menu_root(menu_sel);\r
1387 inp = wait_for_input(BTN_UP|BTN_DOWN|BTN_PLAY|BTN_STOP|BTN_HOME|BTN_L|BTN_R);\r
1388 if(inp & BTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1389 if(inp & BTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
fa283c9a 1390 if((inp & (BTN_L|BTN_R)) == (BTN_L|BTN_R)) debug_menu_loop();\r
1391 if( inp & (BTN_HOME|BTN_STOP)) {\r
eacee137 1392 if (rom_loaded) {\r
2ec14aec 1393 while (Framework_PollGetButtons() & (BTN_HOME|BTN_STOP)) Sleep(50); // wait until released\r
e5f426aa 1394 engineState = PGS_Running;\r
1395 break;\r
1396 }\r
1397 }\r
1398 if(inp & BTN_PLAY) {\r
1399 switch (me_index2id(main_entries, MAIN_ENTRY_COUNT, menu_sel))\r
1400 {\r
1401 case MA_MAIN_RESUME_GAME:\r
eacee137 1402 if (rom_loaded) {\r
2ec14aec 1403 while (Framework_PollGetButtons() & BTN_PLAY) Sleep(50);\r
e5f426aa 1404 engineState = PGS_Running;\r
1405 return;\r
1406 }\r
1407 break;\r
1408 case MA_MAIN_SAVE_STATE:\r
eacee137 1409 if (rom_loaded) {\r
e5f426aa 1410 if(savestate_menu_loop(0))\r
1411 continue;\r
1412 engineState = PGS_Running;\r
1413 return;\r
1414 }\r
1415 break;\r
1416 case MA_MAIN_LOAD_STATE:\r
eacee137 1417 if (rom_loaded) {\r
e5f426aa 1418 if(savestate_menu_loop(1))\r
1419 continue;\r
5ed2561c 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_RESET_GAME:\r
eacee137 1426 if (rom_loaded) {\r
e5f426aa 1427 emu_ResetGame();\r
5ed2561c 1428 while (Framework_PollGetButtons() & BTN_PLAY) Sleep(50);\r
e5f426aa 1429 engineState = PGS_Running;\r
1430 return;\r
1431 }\r
1432 break;\r
1433 case MA_MAIN_LOAD_ROM:\r
1434 {\r
1435 char curr_path[MAX_PATH], *selfname;\r
1436 FILE *tstf;\r
1437 if ( (tstf = fopen(currentConfig.lastRomFile, "rb")) )\r
1438 {\r
1439 fclose(tstf);\r
1440 strcpy(curr_path, currentConfig.lastRomFile);\r
1441 }\r
1442 else\r
1443 getcwd(curr_path, MAX_PATH);\r
1444 selfname = romsel_loop(curr_path);\r
1445 if (selfname) {\r
1446 lprintf("selected file: %s\n", selfname);\r
1447 engineState = PGS_ReloadRom;\r
1448 return;\r
1449 }\r
1450 break;\r
1451 }\r
1452 case MA_MAIN_OPTIONS:\r
1453 ret = menu_loop_options();\r
1454 if (ret == 1) continue; // status update\r
1455 if (engineState == PGS_ReloadRom)\r
1456 return; // BIOS test\r
1457 break;\r
1458 case MA_MAIN_CONTROLS:\r
1459 kc_sel_loop();\r
1460 break;\r
1461 case MA_MAIN_CREDITS:\r
1462 draw_menu_credits();\r
1463 Sleep(500);\r
1464 inp = wait_for_input(BTN_PLAY|BTN_STOP);\r
1465 break;\r
1466 case MA_MAIN_EXIT:\r
1467 engineState = PGS_Quit;\r
1468 return;\r
1469 case MA_MAIN_PATCHES:\r
eacee137 1470 if (rom_loaded && PicoPatches) {\r
e5f426aa 1471 patches_menu_loop();\r
1472 PicoPatchApply();\r
1473 strcpy(menuErrorMsg, "Patches applied");\r
1474 continue;\r
1475 }\r
1476 break;\r
1477 default:\r
1478 lprintf("%s: something unknown selected\n", __FUNCTION__);\r
1479 break;\r
1480 }\r
1481 }\r
1482 menuErrorMsg[0] = 0; // clear error msg\r
1483 }\r
1484}\r
1485\r
1486// warning: alignment\r
1487static void menu_darken_bg(void *dst, const void *src, int pixels, int darker)\r
1488{\r
1489 unsigned int *dest = dst;\r
1490 const unsigned int *srce = src;\r
1491 pixels /= 2;\r
1492 if (darker)\r
1493 {\r
1494 while (pixels--)\r
1495 {\r
1496 unsigned int p = *srce++;\r
1497 *dest++ = ((p&0xf79ef79e)>>1) - ((p&0xc618c618)>>3);\r
1498 }\r
1499 }\r
1500 else\r
1501 {\r
1502 while (pixels--)\r
1503 {\r
1504 unsigned int p = *srce++;\r
1505 *dest++ = (p&0xf79ef79e)>>1;\r
1506 }\r
1507 }\r
1508}\r
1509\r
1510static void menu_prepare_bg(int use_game_bg)\r
1511{\r
1512 if (use_game_bg)\r
1513 {\r
1514 // darken the active framebuffer\r
2ec14aec 1515 if (giz_screen == NULL)\r
c77ca79e 1516 giz_screen = Framework2D_LockBuffer(1);\r
e5f426aa 1517 memset(bg_buffer, 0, 321*8*2);\r
1518 menu_darken_bg(bg_buffer + 321*8*2, (char *)giz_screen + 321*8*2, 321*224, 1);\r
1519 memset(bg_buffer + 321*232*2, 0, 321*8*2);\r
2ec14aec 1520 Framework2D_UnlockBuffer();\r
1521 giz_screen = NULL;\r
e5f426aa 1522 }\r
1523 else\r
1524 {\r
c9077ab4 1525 int i;\r
e5f426aa 1526 // should really only happen once, on startup..\r
1527 readpng(bg_buffer, "skin/background.png", READPNG_BG);\r
c9077ab4 1528 // adjust 320 width to 321\r
1529 for (i = 239; i > 0; i--)\r
1530 memmove(bg_buffer + 321*2*i, bg_buffer + 320*2*i, 320*2);\r
e5f426aa 1531 }\r
1532}\r
1533\r
1534static void menu_gfx_prepare(void)\r
1535{\r
eacee137 1536 menu_prepare_bg(rom_loaded);\r
e5f426aa 1537\r
1538 menu_draw_begin(1);\r
1539 menu_draw_end();\r
1540}\r
1541\r
1542\r
1543void menu_loop(void)\r
1544{\r
1545 menu_gfx_prepare();\r
1546\r
1547 menu_loop_root();\r
1548\r
1549 menuErrorMsg[0] = 0;\r
1550}\r
1551\r
1552\r
1553// --------- CD tray close menu ----------\r
1554\r
1555static void draw_menu_tray(int menu_sel)\r
1556{\r
1557 int tl_x = 70, tl_y = 90, y;\r
1558\r
1559 menu_draw_begin(1);\r
1560\r
1561 text_out16(tl_x, 20, "The unit is about to");\r
1562 text_out16(tl_x, 30, "close the CD tray.");\r
1563\r
1564 y = tl_y;\r
1565 text_out16(tl_x, y, "Load new CD image");\r
1566 text_out16(tl_x, (y+=10), "Insert nothing");\r
1567\r
1568 // draw cursor\r
1569 text_out16(tl_x - 16, tl_y + menu_sel*10, ">");\r
1570 // error\r
1571 if (menuErrorMsg[0]) text_out16(5, 226, menuErrorMsg);\r
1572 menu_draw_end();\r
1573}\r
1574\r
1575\r
1576int menu_loop_tray(void)\r
1577{\r
1578 int menu_sel = 0, menu_sel_max = 1;\r
1579 unsigned long inp = 0;\r
1580 char curr_path[MAX_PATH], *selfname;\r
1581 FILE *tstf;\r
1582\r
1583 menu_gfx_prepare();\r
1584\r
1585 if ( (tstf = fopen(currentConfig.lastRomFile, "rb")) )\r
1586 {\r
1587 fclose(tstf);\r
1588 strcpy(curr_path, currentConfig.lastRomFile);\r
1589 }\r
1590 else\r
1591 {\r
1592 getcwd(curr_path, MAX_PATH);\r
1593 }\r
1594\r
1595 /* make sure action buttons are not pressed on entering menu */\r
1596 draw_menu_tray(menu_sel);\r
2ec14aec 1597 while (Framework_PollGetButtons() & BTN_PLAY) Sleep(50);\r
e5f426aa 1598\r
1599 for (;;)\r
1600 {\r
1601 draw_menu_tray(menu_sel);\r
1602 inp = wait_for_input(BTN_UP|BTN_DOWN|BTN_PLAY);\r
1603 if(inp & BTN_UP ) { menu_sel--; if (menu_sel < 0) menu_sel = menu_sel_max; }\r
1604 if(inp & BTN_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; }\r
1605 if(inp & BTN_PLAY ) {\r
1606 switch (menu_sel) {\r
1607 case 0: // select image\r
1608 selfname = romsel_loop(curr_path);\r
1609 if (selfname) {\r
b923ecbe 1610 int ret = -1;\r
1611 cd_img_type cd_type;\r
ea8c405f 1612 cd_type = emu_cdCheck(NULL);\r
b923ecbe 1613 if (cd_type != CIT_NOT_CD)\r
1614 ret = Insert_CD(romFileName, cd_type);\r
e5f426aa 1615 if (ret != 0) {\r
1616 sprintf(menuErrorMsg, "Load failed, invalid CD image?");\r
1617 lprintf("%s\n", menuErrorMsg);\r
1618 continue;\r
1619 }\r
1620 engineState = PGS_RestartRun;\r
1621 return 1;\r
1622 }\r
1623 break;\r
1624 case 1: // insert nothing\r
1625 engineState = PGS_RestartRun;\r
1626 return 0;\r
1627 }\r
1628 }\r
1629 menuErrorMsg[0] = 0; // clear error msg\r
1630 }\r
1631}\r
1632\r
1633\r