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