unified menu wip and some reorganization for it
[libpicofe.git] / common / menu.c
CommitLineData
c7a4ff64 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#include <stdio.h>\r
7#include <string.h>\r
8#include <stdlib.h>\r
9#include <stdarg.h>\r
10\r
11#include "menu.h"\r
12#include "fonts.h"\r
13#include "readpng.h"\r
14#include "lprintf.h"\r
b8464531 15#include "common.h"\r
fce20e73 16#include "input.h"\r
b8464531 17#include "emu.h"\r
24b24674 18#include "plat.h"\r
c7a4ff64 19\r
24b24674 20#include <pico/patch.h>\r
c7a4ff64 21\r
f013066e 22char menuErrorMsg[64] = { 0, };\r
23\r
367b6f1f 24// PicoPad[] format: MXYZ SACB RLDU\r
6589c840 25me_bind_action me_ctrl_actions[15] =\r
367b6f1f 26{\r
6589c840 27 { "UP ", 0x0001 },\r
28 { "DOWN ", 0x0002 },\r
29 { "LEFT ", 0x0004 },\r
30 { "RIGHT ", 0x0008 },\r
31 { "A ", 0x0040 },\r
32 { "B ", 0x0010 },\r
33 { "C ", 0x0020 },\r
34 { "A turbo", 0x4000 },\r
35 { "B turbo", 0x1000 },\r
36 { "C turbo", 0x2000 },\r
37 { "START ", 0x0080 },\r
38 { "MODE ", 0x0800 },\r
39 { "X ", 0x0400 },\r
40 { "Y ", 0x0200 },\r
41 { "Z ", 0x0100 }\r
367b6f1f 42};\r
43\r
44\r
36f6fd5a 45#ifndef UIQ3\r
46\r
c7a4ff64 47static unsigned char menu_font_data[10240];\r
48static int menu_text_color = 0xffff; // default to white\r
49static int menu_sel_color = -1; // disabled\r
50\r
51// draws text to current bbp16 screen\r
52static void text_out16_(int x, int y, const char *text, int color)\r
53{\r
54 int i, l, u, tr, tg, tb, len;\r
55 unsigned short *dest = (unsigned short *)SCREEN_BUFFER + x + y*SCREEN_WIDTH;\r
56 tr = (color & 0xf800) >> 8;\r
57 tg = (color & 0x07e0) >> 3;\r
58 tb = (color & 0x001f) << 3;\r
59\r
60 if (text == (void *)1)\r
61 {\r
62 // selector symbol\r
63 text = "";\r
64 len = 1;\r
65 }\r
66 else\r
67 len = strlen(text);\r
68\r
69 for (i = 0; i < len; i++)\r
70 {\r
71 unsigned char *src = menu_font_data + (unsigned int)text[i]*4*10;\r
72 unsigned short *dst = dest;\r
73 for (l = 0; l < 10; l++, dst += SCREEN_WIDTH-8)\r
74 {\r
75 for (u = 8/2; u > 0; u--, src++)\r
76 {\r
77 int c, r, g, b;\r
78 c = *src >> 4;\r
79 r = (*dst & 0xf800) >> 8;\r
80 g = (*dst & 0x07e0) >> 3;\r
81 b = (*dst & 0x001f) << 3;\r
82 r = (c^0xf)*r/15 + c*tr/15;\r
83 g = (c^0xf)*g/15 + c*tg/15;\r
84 b = (c^0xf)*b/15 + c*tb/15;\r
85 *dst++ = ((r<<8)&0xf800) | ((g<<3)&0x07e0) | (b>>3);\r
86 c = *src & 0xf;\r
87 r = (*dst & 0xf800) >> 8;\r
88 g = (*dst & 0x07e0) >> 3;\r
89 b = (*dst & 0x001f) << 3;\r
90 r = (c^0xf)*r/15 + c*tr/15;\r
91 g = (c^0xf)*g/15 + c*tg/15;\r
92 b = (c^0xf)*b/15 + c*tb/15;\r
93 *dst++ = ((r<<8)&0xf800) | ((g<<3)&0x07e0) | (b>>3);\r
94 }\r
95 }\r
96 dest += 8;\r
97 }\r
98}\r
99\r
100void text_out16(int x, int y, const char *texto, ...)\r
101{\r
102 va_list args;\r
24b24674 103 char buffer[256];\r
104 int maxw = (SCREEN_WIDTH - x) / 8;\r
c7a4ff64 105\r
24b24674 106 va_start(args, texto);\r
107 vsnprintf(buffer, sizeof(buffer), texto, args);\r
c7a4ff64 108 va_end(args);\r
109\r
24b24674 110 if (maxw > 255)\r
111 maxw = 255;\r
112 buffer[maxw] = 0;\r
113\r
c7a4ff64 114 text_out16_(x,y,buffer,menu_text_color);\r
115}\r
116\r
117\r
118void smalltext_out16(int x, int y, const char *texto, int color)\r
119{\r
120 int i;\r
121 unsigned char *src;\r
122 unsigned short *dst;\r
123\r
124 for (i = 0;; i++, x += 6)\r
125 {\r
126 unsigned char c = (unsigned char) texto[i];\r
127 int h = 8;\r
128\r
129 if (!c) break;\r
130\r
131 src = fontdata6x8[c];\r
132 dst = (unsigned short *)SCREEN_BUFFER + x + y*SCREEN_WIDTH;\r
133\r
134 while (h--)\r
135 {\r
136 int w = 0x20;\r
137 while (w)\r
138 {\r
139 if( *src & w ) *dst = color;\r
140 dst++;\r
141 w>>=1;\r
142 }\r
143 src++;\r
144\r
145 dst += SCREEN_WIDTH-6;\r
146 }\r
147 }\r
148}\r
149\r
150void smalltext_out16_lim(int x, int y, const char *texto, int color, int max)\r
151{\r
152 char buffer[SCREEN_WIDTH/6+1];\r
153\r
154 strncpy(buffer, texto, SCREEN_WIDTH/6);\r
155 if (max > SCREEN_WIDTH/6) max = SCREEN_WIDTH/6;\r
156 if (max < 0) max = 0;\r
157 buffer[max] = 0;\r
158\r
159 smalltext_out16(x, y, buffer, color);\r
160}\r
161\r
162void menu_draw_selection(int x, int y, int w)\r
163{\r
164 int i, h;\r
165 unsigned short *dst, *dest;\r
166\r
167 text_out16_(x, y, (void *)1, (menu_sel_color < 0) ? menu_text_color : menu_sel_color);\r
168\r
169 if (menu_sel_color < 0) return; // no selection hilight\r
170\r
171 if (y > 0) y--;\r
172 dest = (unsigned short *)SCREEN_BUFFER + x + y*SCREEN_WIDTH + 14;\r
173 for (h = 11; h > 0; h--)\r
174 {\r
175 dst = dest;\r
176 for (i = w; i > 0; i--)\r
177 *dst++ = menu_sel_color;\r
178 dest += SCREEN_WIDTH;\r
179 }\r
180}\r
181\r
182static int parse_hex_color(char *buff)\r
183{\r
184 char *endp = buff;\r
185 int t = (int) strtoul(buff, &endp, 16);\r
703e4c7b 186 if (endp != buff)\r
187#ifdef PSP\r
188 return ((t<<8)&0xf800) | ((t>>5)&0x07e0) | ((t>>19)&0x1f);\r
189#else\r
190 return ((t>>8)&0xf800) | ((t>>5)&0x07e0) | ((t>>3)&0x1f);\r
191#endif\r
c7a4ff64 192 return -1;\r
193}\r
194\r
195void menu_init(void)\r
196{\r
197 int c, l;\r
198 unsigned char *fd = menu_font_data;\r
199 char buff[256];\r
200 FILE *f;\r
201\r
202 // generate default font from fontdata8x8\r
203 memset(menu_font_data, 0, sizeof(menu_font_data));\r
204 for (c = 0; c < 256; c++)\r
205 {\r
206 for (l = 0; l < 8; l++)\r
207 {\r
208 unsigned char fd8x8 = fontdata8x8[c*8+l];\r
209 if (fd8x8&0x80) *fd |= 0xf0;\r
210 if (fd8x8&0x40) *fd |= 0x0f; fd++;\r
211 if (fd8x8&0x20) *fd |= 0xf0;\r
212 if (fd8x8&0x10) *fd |= 0x0f; fd++;\r
213 if (fd8x8&0x08) *fd |= 0xf0;\r
214 if (fd8x8&0x04) *fd |= 0x0f; fd++;\r
215 if (fd8x8&0x02) *fd |= 0xf0;\r
216 if (fd8x8&0x01) *fd |= 0x0f; fd++;\r
217 }\r
218 fd += 8*2/2; // 2 empty lines\r
219 }\r
220\r
221 // load custom font and selector (stored as 1st symbol in font table)\r
222 readpng(menu_font_data, "skin/font.png", READPNG_FONT);\r
223 memcpy(menu_font_data, menu_font_data + ((int)'>')*4*10, 4*10); // default selector symbol is '>'\r
224 readpng(menu_font_data, "skin/selector.png", READPNG_SELECTOR);\r
225\r
226 // load custom colors\r
227 f = fopen("skin/skin.txt", "r");\r
228 if (f != NULL)\r
229 {\r
230 lprintf("found skin.txt\n");\r
231 while (!feof(f))\r
232 {\r
233 fgets(buff, sizeof(buff), f);\r
234 if (buff[0] == '#' || buff[0] == '/') continue; // comment\r
235 if (buff[0] == '\r' || buff[0] == '\n') continue; // empty line\r
236 if (strncmp(buff, "text_color=", 11) == 0)\r
237 {\r
238 int tmp = parse_hex_color(buff+11);\r
239 if (tmp >= 0) menu_text_color = tmp;\r
240 else lprintf("skin.txt: parse error for text_color\n");\r
241 }\r
242 else if (strncmp(buff, "selection_color=", 16) == 0)\r
243 {\r
244 int tmp = parse_hex_color(buff+16);\r
245 if (tmp >= 0) menu_sel_color = tmp;\r
246 else lprintf("skin.txt: parse error for selection_color\n");\r
247 }\r
248 else\r
249 lprintf("skin.txt: parse error: %s\n", buff);\r
250 }\r
251 fclose(f);\r
252 }\r
253}\r
254\r
255\r
24b24674 256int me_id2offset(const menu_entry *ent, menu_id id)\r
c7a4ff64 257{\r
258 int i;\r
24b24674 259 for (i = 0; ent->name; ent++, i++)\r
260 if (ent->id == id) return i;\r
c7a4ff64 261\r
262 lprintf("%s: id %i not found\n", __FUNCTION__, id);\r
263 return 0;\r
264}\r
265\r
24b24674 266void me_enable(menu_entry *entries, menu_id id, int enable)\r
c7a4ff64 267{\r
24b24674 268 int i = me_id2offset(entries, id);\r
c7a4ff64 269 entries[i].enabled = enable;\r
270}\r
271\r
24b24674 272int me_count(const menu_entry *ent)\r
c7a4ff64 273{\r
24b24674 274 int ret;\r
c7a4ff64 275\r
24b24674 276 for (ret = 0; ent->name; ent++, ret++)\r
277 ;\r
c7a4ff64 278\r
279 return ret;\r
280}\r
281\r
24b24674 282menu_id me_index2id(const menu_entry *ent, int index)\r
c7a4ff64 283{\r
24b24674 284 const menu_entry *last;\r
c7a4ff64 285\r
24b24674 286 for (; ent->name; ent++)\r
c7a4ff64 287 {\r
24b24674 288 if (ent->enabled)\r
c7a4ff64 289 {\r
290 if (index == 0) break;\r
291 index--;\r
292 }\r
24b24674 293 last = ent;\r
c7a4ff64 294 }\r
24b24674 295 if (ent->name == NULL)\r
296 ent = last;\r
297 return ent->id;\r
c7a4ff64 298}\r
299\r
24b24674 300/* TODO rm */\r
c7a4ff64 301void me_draw(const menu_entry *entries, int count, int x, int y, me_draw_custom_f *cust_draw, void *param)\r
302{\r
303 int i, y1 = y;\r
304\r
305 for (i = 0; i < count; i++)\r
306 {\r
307 if (!entries[i].enabled) continue;\r
308 if (entries[i].name == NULL)\r
309 {\r
310 if (cust_draw != NULL)\r
311 cust_draw(&entries[i], x, y1, param);\r
312 y1 += 10;\r
313 continue;\r
314 }\r
315 text_out16(x, y1, entries[i].name);\r
24b24674 316 if (entries[i].beh == MB_OPT_ONOFF)\r
c7a4ff64 317 text_out16(x + 27*8, y1, (*(int *)entries[i].var & entries[i].mask) ? "ON" : "OFF");\r
24b24674 318 else if (entries[i].beh == MB_OPT_RANGE)\r
c7a4ff64 319 text_out16(x + 27*8, y1, "%i", *(int *)entries[i].var);\r
320 y1 += 10;\r
321 }\r
24b24674 322\r
323}\r
324\r
325static void me_draw2(const menu_entry *entries, int sel)\r
326{\r
327 const menu_entry *ent;\r
328 int x, y, w = 0, h = 0;\r
329 int opt_offs = 27*8;\r
330 const char *name;\r
331 int asel = 0;\r
332 int i, n;\r
333\r
334 /* calculate size of menu rect */\r
335 for (ent = entries, i = n = 0; ent->name; ent++, i++)\r
336 {\r
337 int wt;\r
338\r
339 if (!ent->enabled)\r
340 continue;\r
341\r
342 if (i == sel)\r
343 asel = n;\r
344\r
345 name = NULL;\r
346 wt = strlen(ent->name) * 8; /* FIXME: unhardcode font width */\r
347 if (wt == 0 && ent->generate_name)\r
348 name = ent->generate_name(1);\r
349 if (name != NULL)\r
350 wt = strlen(name) * 8;\r
351\r
352 if (ent->beh != MB_NONE)\r
353 {\r
354 if (wt > opt_offs)\r
355 opt_offs = wt + 8;\r
356 wt = opt_offs;\r
357\r
358 switch (ent->beh) {\r
359 case MB_NONE: break;\r
360 case MB_OPT_ONOFF:\r
361 case MB_OPT_RANGE: wt += 8*3; break;\r
362 case MB_OPT_CUSTOM:\r
363 name = NULL;\r
364 if (ent->generate_name != NULL)\r
365 name = ent->generate_name(0);\r
366 if (name != NULL)\r
367 wt += strlen(name) * 8;\r
368 break;\r
369 }\r
370 }\r
371\r
372 if (wt > w)\r
373 w = wt;\r
374 n++;\r
375 }\r
376 h = n * 10;\r
377 w += 16; /* selector */\r
378\r
379 if (w > SCREEN_WIDTH) {\r
380 lprintf("width %d > %d\n", w, SCREEN_WIDTH);\r
381 w = SCREEN_WIDTH;\r
382 }\r
383 if (h > SCREEN_HEIGHT) {\r
384 lprintf("height %d > %d\n", w, SCREEN_HEIGHT);\r
385 h = SCREEN_HEIGHT;\r
386 }\r
387\r
388 x = SCREEN_WIDTH / 2 - w / 2;\r
389 y = SCREEN_HEIGHT / 2 - h / 2;\r
390\r
391 /* draw */\r
392 plat_video_menu_begin();\r
393 menu_draw_selection(x, y + asel * 10, w);\r
394\r
395 for (ent = entries; ent->name; ent++)\r
396 {\r
397 if (!ent->enabled)\r
398 continue;\r
399\r
400 name = ent->name;\r
401 if (strlen(name) == 0) {\r
402 if (ent->generate_name)\r
403 name = ent->generate_name(1);\r
404 }\r
405 if (name != NULL)\r
406 text_out16(x + 16, y, name);\r
407\r
408 switch (ent->beh) {\r
409 case MB_NONE:\r
410 break;\r
411 case MB_OPT_ONOFF:\r
412 text_out16(x + 16 + opt_offs, y, (*(int *)ent->var & ent->mask) ? "ON" : "OFF");\r
413 break;\r
414 case MB_OPT_RANGE:\r
415 text_out16(x + 16 + opt_offs, y, "%i", *(int *)ent->var);\r
416 break;\r
417 case MB_OPT_CUSTOM:\r
418 name = NULL;\r
419 if (ent->generate_name)\r
420 name = ent->generate_name(0);\r
421 if (name != NULL)\r
422 text_out16(x + 16 + opt_offs, y, "%s", name);\r
423 break;\r
424 }\r
425\r
426 y += 10;\r
427 }\r
428\r
429 plat_video_menu_end();\r
c7a4ff64 430}\r
431\r
24b24674 432int me_process(menu_entry *entries, menu_id id, int is_next)\r
c7a4ff64 433{\r
24b24674 434 int i = me_id2offset(entries, id);\r
c7a4ff64 435 menu_entry *entry = &entries[i];\r
436 switch (entry->beh)\r
437 {\r
24b24674 438 case MB_OPT_ONOFF:\r
c7a4ff64 439 *(int *)entry->var ^= entry->mask;\r
440 return 1;\r
24b24674 441 case MB_OPT_RANGE:\r
c7a4ff64 442 *(int *)entry->var += is_next ? 1 : -1;\r
443 if (*(int *)entry->var < (int)entry->min) *(int *)entry->var = (int)entry->min;\r
444 if (*(int *)entry->var > (int)entry->max) *(int *)entry->var = (int)entry->max;\r
445 return 1;\r
446 default:\r
447 return 0;\r
448 }\r
449}\r
450\r
24b24674 451static void me_loop(menu_entry *menu, int *menu_sel)\r
452{\r
453 int ret, inp, sel = *menu_sel, menu_sel_max;\r
454\r
455 menu_sel_max = me_count(menu) - 1;\r
456 if (menu_sel_max < 1) {\r
457 lprintf("no enabled menu entries\n");\r
458 return;\r
459 }\r
460\r
461 while (!menu[sel].enabled && sel < menu_sel_max)\r
462 sel++;\r
463\r
464 /* make sure action buttons are not pressed on entering menu */\r
465 me_draw2(menu, sel);\r
466 while (in_menu_wait_any(50) & (PBTN_MOK|PBTN_MBACK|PBTN_MENU));\r
467\r
468 for (;;)\r
469 {\r
470 me_draw2(menu, sel);\r
471 inp = in_menu_wait(PBTN_UP|PBTN_DOWN|PBTN_MOK|PBTN_MBACK|PBTN_MENU|PBTN_L|PBTN_R);\r
472 if (inp & PBTN_UP ) {\r
473 do {\r
474 sel--;\r
475 if (sel < 0)\r
476 sel = menu_sel_max;\r
477 }\r
478 while (!menu[sel].enabled);\r
479 }\r
480 if (inp & PBTN_DOWN) {\r
481 do {\r
482 sel++;\r
483 if (sel > menu_sel_max)\r
484 sel = 0;\r
485 }\r
486 while (!menu[sel].enabled);\r
487 }\r
488// if ((inp & (PBTN_L|PBTN_R)) == (PBTN_L|PBTN_R)) debug_menu_loop(); // TODO\r
489 if (inp & (PBTN_MENU|PBTN_MBACK))\r
490 break;\r
491\r
492 if (inp & PBTN_MOK)\r
493 {\r
494 if (menu[sel].submenu_handler != NULL) {\r
495 ret = menu[sel].submenu_handler(menu[sel].id);\r
496 if (ret) break;\r
497 }\r
498 }\r
499// menuErrorMsg[0] = 0; // TODO: clear error msg\r
500 }\r
501 *menu_sel = sel;\r
502}\r
503\r
504/* ***************************************** */\r
505\r
506/* TODO s */\r
507int menu_loop_tray(void) { return 0; }\r
508void menu_romload_prepare(const char *rom_name) {}\r
509void menu_romload_end(void) {}\r
510me_bind_action emuctrl_actions[1];\r
511menu_entry opt_entries[1];\r
512menu_entry opt2_entries[1];\r
513menu_entry cdopt_entries[1];\r
514menu_entry ctrlopt_entries[1];\r
515const int opt_entry_count = 0;\r
516const int opt2_entry_count = 0;\r
517const int cdopt_entry_count = 0;\r
518const int ctrlopt_entry_count = 0;\r
519\r
520extern int engineState;\r
521\r
522int savestate_menu_loop(int a) { return 1; }\r
523int menu_loop_options() { return 1; }\r
524void kc_sel_loop() {}\r
525void draw_menu_credits() {}\r
526void patches_menu_loop() {}\r
527\r
528// ------------ main menu ------------\r
529\r
530static int main_menu_handler(menu_id id)\r
531{\r
532 int ret;\r
533\r
534 switch (id)\r
535 {\r
536 case MA_MAIN_RESUME_GAME:\r
537 if (rom_loaded) {\r
538 while (in_menu_wait_any(50) & PBTN_MOK);\r
539 engineState = PGS_Running;\r
540 return 1;\r
541 }\r
542 break;\r
543 case MA_MAIN_SAVE_STATE:\r
544 if (rom_loaded) {\r
545 if (savestate_menu_loop(0))\r
546 break;\r
547 engineState = PGS_Running;\r
548 return 1;\r
549 }\r
550 break;\r
551 case MA_MAIN_LOAD_STATE:\r
552 if (rom_loaded) {\r
553 if (savestate_menu_loop(1))\r
554 break;\r
555 while (in_menu_wait_any(50) & PBTN_MOK);\r
556 engineState = PGS_Running;\r
557 return 1;\r
558 }\r
559 break;\r
560 case MA_MAIN_RESET_GAME:\r
561 if (rom_loaded) {\r
562 emu_ResetGame();\r
563 while (in_menu_wait_any(50) & PBTN_MOK);\r
564 engineState = PGS_Running;\r
565 return 1;\r
566 }\r
567 break;\r
568 case MA_MAIN_LOAD_ROM:\r
569 {\r
570/* char curr_path[PATH_MAX], *selfname;\r
571 FILE *tstf;\r
572 if ( (tstf = fopen(loadedRomFName, "rb")) )\r
573 {\r
574 fclose(tstf);\r
575 strcpy(curr_path, loadedRomFName);\r
576 }\r
577 else\r
578 getcwd(curr_path, PATH_MAX);\r
579 selfname = romsel_loop(curr_path);\r
580 if (selfname) {\r
581 printf("selected file: %s\n", selfname);\r
582 engineState = PGS_ReloadRom;\r
583 return;\r
584 }*/\r
585 break;\r
586 }\r
587 case MA_MAIN_OPTIONS:\r
588 ret = menu_loop_options();\r
589 if (ret == 1) break; // status update\r
590 if (engineState == PGS_ReloadRom)\r
591 return 1; // BIOS test\r
592 break;\r
593 case MA_MAIN_CONTROLS:\r
594 kc_sel_loop();\r
595 break;\r
596 case MA_MAIN_CREDITS:\r
597 draw_menu_credits();\r
598 usleep(500*1000); /* FIXME */\r
599 in_menu_wait(PBTN_MOK|PBTN_MBACK);\r
600 break;\r
601 case MA_MAIN_EXIT:\r
602 engineState = PGS_Quit;\r
603 return 1;\r
604 case MA_MAIN_PATCHES:\r
605 if (rom_loaded && PicoPatches) {\r
606 patches_menu_loop();\r
607 PicoPatchApply();\r
608 strcpy(menuErrorMsg, "Patches applied");\r
609 }\r
610 break;\r
611 default:\r
612 lprintf("%s: something unknown selected\n", __FUNCTION__);\r
613 break;\r
614 }\r
615\r
616 return 0;\r
617}\r
618\r
619menu_entry e_main_menu[] =\r
620{\r
621 mee_submenu_id("Resume game", MA_MAIN_RESUME_GAME, main_menu_handler),\r
622 mee_submenu_id("Save State", MA_MAIN_SAVE_STATE, main_menu_handler),\r
623 mee_submenu_id("Load State", MA_MAIN_LOAD_STATE, main_menu_handler),\r
624 mee_submenu_id("Reset game", MA_MAIN_RESET_GAME, main_menu_handler),\r
625 mee_submenu_id("Load new ROM/ISO", MA_MAIN_LOAD_ROM, main_menu_handler),\r
626 mee_submenu_id("Change options", MA_MAIN_OPTIONS, main_menu_handler),\r
627 mee_submenu_id("Credits", MA_MAIN_CREDITS, main_menu_handler),\r
628 mee_submenu_id("Patches / GameGenie",MA_MAIN_PATCHES, main_menu_handler),\r
629 mee_submenu_id("Exit", MA_MAIN_EXIT, main_menu_handler),\r
630 mee_end,\r
631};\r
632\r
633void menu_loop(void)\r
634{\r
635 static int sel = 0;\r
636\r
637 me_enable(e_main_menu, MA_MAIN_RESUME_GAME, rom_loaded);\r
638 me_enable(e_main_menu, MA_MAIN_SAVE_STATE, rom_loaded);\r
639 me_enable(e_main_menu, MA_MAIN_LOAD_STATE, rom_loaded);\r
640 me_enable(e_main_menu, MA_MAIN_RESET_GAME, rom_loaded);\r
641 me_enable(e_main_menu, MA_MAIN_PATCHES, PicoPatches != NULL);\r
642\r
643 plat_video_menu_enter(rom_loaded);\r
644 in_set_blocking(1);\r
645 me_loop(e_main_menu, &sel);\r
646 in_set_blocking(0);\r
647\r
648 if (rom_loaded) {\r
649 while (in_menu_wait_any(50) & (PBTN_MENU|PBTN_MBACK)); // wait until select is released\r
650 engineState = PGS_Running;\r
651 }\r
652\r
653}\r
654\r
b8464531 655// ------------ debug menu ------------\r
656\r
657#include <sys/stat.h>\r
658#include <sys/types.h>\r
659\r
f11bad75 660#include <pico/pico.h>\r
661#include <pico/debug.h>\r
b8464531 662\r
663void SekStepM68k(void);\r
664\r
725d7f6c 665static void mplayer_loop(void)\r
666{\r
667 emu_startSound();\r
668\r
669 while (1)\r
670 {\r
671 PDebugZ80Frame();\r
fce20e73 672 if (in_menu_wait_any(0) & PBTN_NORTH) break;\r
725d7f6c 673 emu_waitSound();\r
674 }\r
675\r
676 emu_endSound();\r
677}\r
678\r
b8464531 679static void draw_text_debug(const char *str, int skip, int from)\r
680{\r
681 const char *p;\r
682 int len, line;\r
683\r
684 p = str;\r
685 while (skip-- > 0)\r
686 {\r
687 while (*p && *p != '\n') p++;\r
688 if (*p == 0 || p[1] == 0) return;\r
689 p++;\r
690 }\r
691\r
692 str = p;\r
693 for (line = from; line < SCREEN_HEIGHT/10; line++)\r
694 {\r
695 while (*p && *p != '\n') p++;\r
696 len = p - str;\r
697 if (len > 55) len = 55;\r
698 smalltext_out16_lim(1, line*10, str, 0xffff, len);\r
699 if (*p == 0) break;\r
700 p++; str = p;\r
701 }\r
702}\r
703\r
704static void draw_frame_debug(void)\r
705{\r
706 char layer_str[48] = "layers: ";\r
707 if (PicoDrawMask & PDRAW_LAYERB_ON) memcpy(layer_str + 8, "B", 1);\r
708 if (PicoDrawMask & PDRAW_LAYERA_ON) memcpy(layer_str + 10, "A", 1);\r
709 if (PicoDrawMask & PDRAW_SPRITES_LOW_ON) memcpy(layer_str + 12, "spr_lo", 6);\r
710 if (PicoDrawMask & PDRAW_SPRITES_HI_ON) memcpy(layer_str + 19, "spr_hi", 6);\r
711\r
712 clear_screen();\r
713 emu_forcedFrame(0);\r
714 smalltext_out16(4, SCREEN_HEIGHT-8, layer_str, 0xffff);\r
715}\r
716\r
717void debug_menu_loop(void)\r
718{\r
719 int inp, mode = 0;\r
720 int spr_offs = 0, dumped = 0;\r
7443ecd9 721 char *tmp;\r
b8464531 722\r
723 while (1)\r
724 {\r
725 switch (mode)\r
726 {\r
24b24674 727 case 0: plat_video_menu_begin();\r
7443ecd9 728 tmp = PDebugMain();\r
729 emu_platformDebugCat(tmp);\r
730 draw_text_debug(tmp, 0, 0);\r
b8464531 731 if (dumped) {\r
732 smalltext_out16(SCREEN_WIDTH-6*10, SCREEN_HEIGHT-8, "dumped", 0xffff);\r
733 dumped = 0;\r
734 }\r
735 break;\r
736 case 1: draw_frame_debug(); break;\r
737 case 2: clear_screen();\r
738 emu_forcedFrame(0);\r
739 darken_screen();\r
dfa8d77a 740 PDebugShowSpriteStats((unsigned short *)SCREEN_BUFFER + (SCREEN_HEIGHT/2 - 240/2)*SCREEN_WIDTH +\r
741 SCREEN_WIDTH/2 - 320/2, SCREEN_WIDTH); break;\r
b8464531 742 case 3: clear_screen();\r
743 PDebugShowPalette(SCREEN_BUFFER, SCREEN_WIDTH);\r
744 PDebugShowSprite((unsigned short *)SCREEN_BUFFER + SCREEN_WIDTH*120+SCREEN_WIDTH/2+16,\r
745 SCREEN_WIDTH, spr_offs);\r
746 draw_text_debug(PDebugSpriteList(), spr_offs, 6);\r
747 break;\r
748 }\r
24b24674 749 plat_video_menu_end();\r
b8464531 750\r
fce20e73 751 inp = in_menu_wait(PBTN_EAST|PBTN_MBACK|PBTN_WEST|PBTN_NORTH|PBTN_L|PBTN_R|PBTN_UP|PBTN_DOWN|PBTN_LEFT|PBTN_RIGHT);\r
752 if (inp & PBTN_MBACK) return;\r
b3972d82 753 if (inp & PBTN_L) { mode--; if (mode < 0) mode = 3; }\r
754 if (inp & PBTN_R) { mode++; if (mode > 3) mode = 0; }\r
b8464531 755 switch (mode)\r
756 {\r
757 case 0:\r
b3972d82 758 if (inp & PBTN_EAST) SekStepM68k();\r
759 if (inp & PBTN_NORTH) {\r
fce20e73 760 while (inp & PBTN_NORTH) inp = in_menu_wait_any(-1);\r
725d7f6c 761 mplayer_loop();\r
762 }\r
b3972d82 763 if ((inp & (PBTN_WEST|PBTN_LEFT)) == (PBTN_WEST|PBTN_LEFT)) {\r
b8464531 764 mkdir("dumps", 0777);\r
765 PDebugDumpMem();\r
fce20e73 766 while (inp & PBTN_WEST) inp = in_menu_wait_any(-1);\r
b8464531 767 dumped = 1;\r
768 }\r
769 break;\r
770 case 1:\r
b3972d82 771 if (inp & PBTN_LEFT) PicoDrawMask ^= PDRAW_LAYERB_ON;\r
772 if (inp & PBTN_RIGHT) PicoDrawMask ^= PDRAW_LAYERA_ON;\r
773 if (inp & PBTN_DOWN) PicoDrawMask ^= PDRAW_SPRITES_LOW_ON;\r
774 if (inp & PBTN_UP) PicoDrawMask ^= PDRAW_SPRITES_HI_ON;\r
775 if (inp & PBTN_EAST) {\r
8e6cbce1 776 PsndOut = NULL; // just in case\r
777 PicoSkipFrame = 1;\r
778 PicoFrame();\r
779 PicoSkipFrame = 0;\r
fce20e73 780 while (inp & PBTN_EAST) inp = in_menu_wait_any(-1);\r
8e6cbce1 781 }\r
b8464531 782 break;\r
783 case 3:\r
b3972d82 784 if (inp & PBTN_DOWN) spr_offs++;\r
785 if (inp & PBTN_UP) spr_offs--;\r
b8464531 786 if (spr_offs < 0) spr_offs = 0;\r
787 break;\r
788 }\r
789 }\r
790}\r
791\r
36f6fd5a 792#endif // !UIQ3\r
793\r
794// ------------ util ------------\r
795\r
796const char *me_region_name(unsigned int code, int auto_order)\r
797{\r
798 static const char *names[] = { "Auto", " Japan NTSC", " Japan PAL", " USA", " Europe" };\r
799 static const char *names_short[] = { "", " JP", " JP", " US", " EU" };\r
800 int u, i = 0;\r
801 if (code) {\r
802 code <<= 1;\r
803 while((code >>= 1)) i++;\r
804 if (i > 4) return "unknown";\r
805 return names[i];\r
806 } else {\r
807 static char name[24];\r
808 strcpy(name, "Auto:");\r
809 for (u = 0; u < 3; u++) {\r
810 i = 0; code = ((auto_order >> u*4) & 0xf) << 1;\r
811 while((code >>= 1)) i++;\r
812 strcat(name, names_short[i]);\r
813 }\r
814 return name;\r
815 }\r
816}\r
817\r
24b24674 818/* TODO: rename */\r
819void menu_darken_bg(void *dst, int pixels, int darker)\r
820{\r
821 unsigned int *screen = dst;\r
822 pixels /= 2;\r
823 if (darker)\r
824 {\r
825 while (pixels--)\r
826 {\r
827 unsigned int p = *screen;\r
828 *screen++ = ((p&0xf79ef79e)>>1) - ((p&0xc618c618)>>3);\r
829 }\r
830 }\r
831 else\r
832 {\r
833 while (pixels--)\r
834 {\r
835 unsigned int p = *screen;\r
836 *screen++ = (p&0xf79ef79e)>>1;\r
837 }\r
838 }\r
839}\r
b8464531 840\r