menu.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. // (c) Copyright 2006,2007 notaz, All rights reserved.
  2. // Free for non-commercial use.
  3. // For commercial use, separate licencing terms must be obtained.
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <stdlib.h>
  7. #include <stdarg.h>
  8. #include "menu.h"
  9. #include "fonts.h"
  10. #include "readpng.h"
  11. #include "lprintf.h"
  12. #include "common.h"
  13. #include "emu.h"
  14. char menuErrorMsg[64] = { 0, };
  15. // PicoPad[] format: MXYZ SACB RLDU
  16. me_bind_action me_ctrl_actions[15] =
  17. {
  18. { "UP ", 0x0001 },
  19. { "DOWN ", 0x0002 },
  20. { "LEFT ", 0x0004 },
  21. { "RIGHT ", 0x0008 },
  22. { "A ", 0x0040 },
  23. { "B ", 0x0010 },
  24. { "C ", 0x0020 },
  25. { "A turbo", 0x4000 },
  26. { "B turbo", 0x1000 },
  27. { "C turbo", 0x2000 },
  28. { "START ", 0x0080 },
  29. { "MODE ", 0x0800 },
  30. { "X ", 0x0400 },
  31. { "Y ", 0x0200 },
  32. { "Z ", 0x0100 }
  33. };
  34. #ifndef UIQ3
  35. static unsigned char menu_font_data[10240];
  36. static int menu_text_color = 0xffff; // default to white
  37. static int menu_sel_color = -1; // disabled
  38. // draws text to current bbp16 screen
  39. static void text_out16_(int x, int y, const char *text, int color)
  40. {
  41. int i, l, u, tr, tg, tb, len;
  42. unsigned short *dest = (unsigned short *)SCREEN_BUFFER + x + y*SCREEN_WIDTH;
  43. tr = (color & 0xf800) >> 8;
  44. tg = (color & 0x07e0) >> 3;
  45. tb = (color & 0x001f) << 3;
  46. if (text == (void *)1)
  47. {
  48. // selector symbol
  49. text = "";
  50. len = 1;
  51. }
  52. else
  53. len = strlen(text);
  54. for (i = 0; i < len; i++)
  55. {
  56. unsigned char *src = menu_font_data + (unsigned int)text[i]*4*10;
  57. unsigned short *dst = dest;
  58. for (l = 0; l < 10; l++, dst += SCREEN_WIDTH-8)
  59. {
  60. for (u = 8/2; u > 0; u--, src++)
  61. {
  62. int c, r, g, b;
  63. c = *src >> 4;
  64. r = (*dst & 0xf800) >> 8;
  65. g = (*dst & 0x07e0) >> 3;
  66. b = (*dst & 0x001f) << 3;
  67. r = (c^0xf)*r/15 + c*tr/15;
  68. g = (c^0xf)*g/15 + c*tg/15;
  69. b = (c^0xf)*b/15 + c*tb/15;
  70. *dst++ = ((r<<8)&0xf800) | ((g<<3)&0x07e0) | (b>>3);
  71. c = *src & 0xf;
  72. r = (*dst & 0xf800) >> 8;
  73. g = (*dst & 0x07e0) >> 3;
  74. b = (*dst & 0x001f) << 3;
  75. r = (c^0xf)*r/15 + c*tr/15;
  76. g = (c^0xf)*g/15 + c*tg/15;
  77. b = (c^0xf)*b/15 + c*tb/15;
  78. *dst++ = ((r<<8)&0xf800) | ((g<<3)&0x07e0) | (b>>3);
  79. }
  80. }
  81. dest += 8;
  82. }
  83. }
  84. void text_out16(int x, int y, const char *texto, ...)
  85. {
  86. va_list args;
  87. char buffer[512];
  88. va_start(args,texto);
  89. vsprintf(buffer,texto,args);
  90. va_end(args);
  91. text_out16_(x,y,buffer,menu_text_color);
  92. }
  93. void smalltext_out16(int x, int y, const char *texto, int color)
  94. {
  95. int i;
  96. unsigned char *src;
  97. unsigned short *dst;
  98. for (i = 0;; i++, x += 6)
  99. {
  100. unsigned char c = (unsigned char) texto[i];
  101. int h = 8;
  102. if (!c) break;
  103. src = fontdata6x8[c];
  104. dst = (unsigned short *)SCREEN_BUFFER + x + y*SCREEN_WIDTH;
  105. while (h--)
  106. {
  107. int w = 0x20;
  108. while (w)
  109. {
  110. if( *src & w ) *dst = color;
  111. dst++;
  112. w>>=1;
  113. }
  114. src++;
  115. dst += SCREEN_WIDTH-6;
  116. }
  117. }
  118. }
  119. void smalltext_out16_lim(int x, int y, const char *texto, int color, int max)
  120. {
  121. char buffer[SCREEN_WIDTH/6+1];
  122. strncpy(buffer, texto, SCREEN_WIDTH/6);
  123. if (max > SCREEN_WIDTH/6) max = SCREEN_WIDTH/6;
  124. if (max < 0) max = 0;
  125. buffer[max] = 0;
  126. smalltext_out16(x, y, buffer, color);
  127. }
  128. void menu_draw_selection(int x, int y, int w)
  129. {
  130. int i, h;
  131. unsigned short *dst, *dest;
  132. text_out16_(x, y, (void *)1, (menu_sel_color < 0) ? menu_text_color : menu_sel_color);
  133. if (menu_sel_color < 0) return; // no selection hilight
  134. if (y > 0) y--;
  135. dest = (unsigned short *)SCREEN_BUFFER + x + y*SCREEN_WIDTH + 14;
  136. for (h = 11; h > 0; h--)
  137. {
  138. dst = dest;
  139. for (i = w; i > 0; i--)
  140. *dst++ = menu_sel_color;
  141. dest += SCREEN_WIDTH;
  142. }
  143. }
  144. static int parse_hex_color(char *buff)
  145. {
  146. char *endp = buff;
  147. int t = (int) strtoul(buff, &endp, 16);
  148. if (endp != buff)
  149. #ifdef PSP
  150. return ((t<<8)&0xf800) | ((t>>5)&0x07e0) | ((t>>19)&0x1f);
  151. #else
  152. return ((t>>8)&0xf800) | ((t>>5)&0x07e0) | ((t>>3)&0x1f);
  153. #endif
  154. return -1;
  155. }
  156. void menu_init(void)
  157. {
  158. int c, l;
  159. unsigned char *fd = menu_font_data;
  160. char buff[256];
  161. FILE *f;
  162. // generate default font from fontdata8x8
  163. memset(menu_font_data, 0, sizeof(menu_font_data));
  164. for (c = 0; c < 256; c++)
  165. {
  166. for (l = 0; l < 8; l++)
  167. {
  168. unsigned char fd8x8 = fontdata8x8[c*8+l];
  169. if (fd8x8&0x80) *fd |= 0xf0;
  170. if (fd8x8&0x40) *fd |= 0x0f; fd++;
  171. if (fd8x8&0x20) *fd |= 0xf0;
  172. if (fd8x8&0x10) *fd |= 0x0f; fd++;
  173. if (fd8x8&0x08) *fd |= 0xf0;
  174. if (fd8x8&0x04) *fd |= 0x0f; fd++;
  175. if (fd8x8&0x02) *fd |= 0xf0;
  176. if (fd8x8&0x01) *fd |= 0x0f; fd++;
  177. }
  178. fd += 8*2/2; // 2 empty lines
  179. }
  180. // load custom font and selector (stored as 1st symbol in font table)
  181. readpng(menu_font_data, "skin/font.png", READPNG_FONT);
  182. memcpy(menu_font_data, menu_font_data + ((int)'>')*4*10, 4*10); // default selector symbol is '>'
  183. readpng(menu_font_data, "skin/selector.png", READPNG_SELECTOR);
  184. // load custom colors
  185. f = fopen("skin/skin.txt", "r");
  186. if (f != NULL)
  187. {
  188. lprintf("found skin.txt\n");
  189. while (!feof(f))
  190. {
  191. fgets(buff, sizeof(buff), f);
  192. if (buff[0] == '#' || buff[0] == '/') continue; // comment
  193. if (buff[0] == '\r' || buff[0] == '\n') continue; // empty line
  194. if (strncmp(buff, "text_color=", 11) == 0)
  195. {
  196. int tmp = parse_hex_color(buff+11);
  197. if (tmp >= 0) menu_text_color = tmp;
  198. else lprintf("skin.txt: parse error for text_color\n");
  199. }
  200. else if (strncmp(buff, "selection_color=", 16) == 0)
  201. {
  202. int tmp = parse_hex_color(buff+16);
  203. if (tmp >= 0) menu_sel_color = tmp;
  204. else lprintf("skin.txt: parse error for selection_color\n");
  205. }
  206. else
  207. lprintf("skin.txt: parse error: %s\n", buff);
  208. }
  209. fclose(f);
  210. }
  211. }
  212. int me_id2offset(const menu_entry *entries, int count, menu_id id)
  213. {
  214. int i;
  215. for (i = 0; i < count; i++)
  216. {
  217. if (entries[i].id == id) return i;
  218. }
  219. lprintf("%s: id %i not found\n", __FUNCTION__, id);
  220. return 0;
  221. }
  222. void me_enable(menu_entry *entries, int count, menu_id id, int enable)
  223. {
  224. int i = me_id2offset(entries, count, id);
  225. entries[i].enabled = enable;
  226. }
  227. int me_count_enabled(const menu_entry *entries, int count)
  228. {
  229. int i, ret = 0;
  230. for (i = 0; i < count; i++)
  231. {
  232. if (entries[i].enabled) ret++;
  233. }
  234. return ret;
  235. }
  236. menu_id me_index2id(const menu_entry *entries, int count, int index)
  237. {
  238. int i;
  239. for (i = 0; i < count; i++)
  240. {
  241. if (entries[i].enabled)
  242. {
  243. if (index == 0) break;
  244. index--;
  245. }
  246. }
  247. if (i >= count) i = count - 1;
  248. return entries[i].id;
  249. }
  250. void me_draw(const menu_entry *entries, int count, int x, int y, me_draw_custom_f *cust_draw, void *param)
  251. {
  252. int i, y1 = y;
  253. for (i = 0; i < count; i++)
  254. {
  255. if (!entries[i].enabled) continue;
  256. if (entries[i].name == NULL)
  257. {
  258. if (cust_draw != NULL)
  259. cust_draw(&entries[i], x, y1, param);
  260. y1 += 10;
  261. continue;
  262. }
  263. text_out16(x, y1, entries[i].name);
  264. if (entries[i].beh == MB_ONOFF)
  265. text_out16(x + 27*8, y1, (*(int *)entries[i].var & entries[i].mask) ? "ON" : "OFF");
  266. else if (entries[i].beh == MB_RANGE)
  267. text_out16(x + 27*8, y1, "%i", *(int *)entries[i].var);
  268. y1 += 10;
  269. }
  270. }
  271. int me_process(menu_entry *entries, int count, menu_id id, int is_next)
  272. {
  273. int i = me_id2offset(entries, count, id);
  274. menu_entry *entry = &entries[i];
  275. switch (entry->beh)
  276. {
  277. case MB_ONOFF:
  278. *(int *)entry->var ^= entry->mask;
  279. return 1;
  280. case MB_RANGE:
  281. *(int *)entry->var += is_next ? 1 : -1;
  282. if (*(int *)entry->var < (int)entry->min) *(int *)entry->var = (int)entry->min;
  283. if (*(int *)entry->var > (int)entry->max) *(int *)entry->var = (int)entry->max;
  284. return 1;
  285. default:
  286. return 0;
  287. }
  288. }
  289. // ------------ debug menu ------------
  290. #include <sys/stat.h>
  291. #include <sys/types.h>
  292. #include <Pico/Pico.h>
  293. #include <Pico/Debug.h>
  294. void SekStepM68k(void);
  295. static void draw_text_debug(const char *str, int skip, int from)
  296. {
  297. const char *p;
  298. int len, line;
  299. p = str;
  300. while (skip-- > 0)
  301. {
  302. while (*p && *p != '\n') p++;
  303. if (*p == 0 || p[1] == 0) return;
  304. p++;
  305. }
  306. str = p;
  307. for (line = from; line < SCREEN_HEIGHT/10; line++)
  308. {
  309. while (*p && *p != '\n') p++;
  310. len = p - str;
  311. if (len > 55) len = 55;
  312. smalltext_out16_lim(1, line*10, str, 0xffff, len);
  313. if (*p == 0) break;
  314. p++; str = p;
  315. }
  316. }
  317. static void draw_frame_debug(void)
  318. {
  319. char layer_str[48] = "layers: ";
  320. if (PicoDrawMask & PDRAW_LAYERB_ON) memcpy(layer_str + 8, "B", 1);
  321. if (PicoDrawMask & PDRAW_LAYERA_ON) memcpy(layer_str + 10, "A", 1);
  322. if (PicoDrawMask & PDRAW_SPRITES_LOW_ON) memcpy(layer_str + 12, "spr_lo", 6);
  323. if (PicoDrawMask & PDRAW_SPRITES_HI_ON) memcpy(layer_str + 19, "spr_hi", 6);
  324. clear_screen();
  325. emu_forcedFrame(0);
  326. smalltext_out16(4, SCREEN_HEIGHT-8, layer_str, 0xffff);
  327. }
  328. void debug_menu_loop(void)
  329. {
  330. int inp, mode = 0;
  331. int spr_offs = 0, dumped = 0;
  332. char *tmp;
  333. while (1)
  334. {
  335. switch (mode)
  336. {
  337. case 0: menu_draw_begin();
  338. tmp = PDebugMain();
  339. emu_platformDebugCat(tmp);
  340. draw_text_debug(tmp, 0, 0);
  341. if (dumped) {
  342. smalltext_out16(SCREEN_WIDTH-6*10, SCREEN_HEIGHT-8, "dumped", 0xffff);
  343. dumped = 0;
  344. }
  345. break;
  346. case 1: draw_frame_debug(); break;
  347. case 2: clear_screen();
  348. emu_forcedFrame(0);
  349. darken_screen();
  350. PDebugShowSpriteStats((unsigned short *)SCREEN_BUFFER + (SCREEN_HEIGHT/2 - 240/2)*SCREEN_WIDTH +
  351. SCREEN_WIDTH/2 - 320/2, SCREEN_WIDTH); break;
  352. case 3: clear_screen();
  353. PDebugShowPalette(SCREEN_BUFFER, SCREEN_WIDTH);
  354. PDebugShowSprite((unsigned short *)SCREEN_BUFFER + SCREEN_WIDTH*120+SCREEN_WIDTH/2+16,
  355. SCREEN_WIDTH, spr_offs);
  356. draw_text_debug(PDebugSpriteList(), spr_offs, 6);
  357. break;
  358. }
  359. menu_draw_end();
  360. inp = read_buttons(BTN_EAST|BTN_SOUTH|BTN_WEST|BTN_L|BTN_R|BTN_UP|BTN_DOWN|BTN_LEFT|BTN_RIGHT);
  361. if (inp & BTN_SOUTH) return;
  362. if (inp & BTN_L) { mode--; if (mode < 0) mode = 3; }
  363. if (inp & BTN_R) { mode++; if (mode > 3) mode = 0; }
  364. switch (mode)
  365. {
  366. case 0:
  367. if (inp & BTN_EAST) SekStepM68k();
  368. if ((inp & (BTN_WEST|BTN_LEFT)) == (BTN_WEST|BTN_LEFT)) {
  369. mkdir("dumps", 0777);
  370. PDebugDumpMem();
  371. while (inp & BTN_WEST) inp = read_buttons_async(BTN_WEST);
  372. dumped = 1;
  373. }
  374. break;
  375. case 1:
  376. if (inp & BTN_LEFT) PicoDrawMask ^= PDRAW_LAYERB_ON;
  377. if (inp & BTN_RIGHT) PicoDrawMask ^= PDRAW_LAYERA_ON;
  378. if (inp & BTN_DOWN) PicoDrawMask ^= PDRAW_SPRITES_LOW_ON;
  379. if (inp & BTN_UP) PicoDrawMask ^= PDRAW_SPRITES_HI_ON;
  380. if (inp & BTN_EAST) {
  381. PsndOut = NULL; // just in case
  382. PicoSkipFrame = 1;
  383. PicoFrame();
  384. PicoSkipFrame = 0;
  385. while (inp & BTN_EAST) inp = read_buttons_async(BTN_EAST);
  386. }
  387. break;
  388. case 3:
  389. if (inp & BTN_DOWN) spr_offs++;
  390. if (inp & BTN_UP) spr_offs--;
  391. if (spr_offs < 0) spr_offs = 0;
  392. break;
  393. }
  394. }
  395. }
  396. #endif // !UIQ3
  397. // ------------ util ------------
  398. const char *me_region_name(unsigned int code, int auto_order)
  399. {
  400. static const char *names[] = { "Auto", " Japan NTSC", " Japan PAL", " USA", " Europe" };
  401. static const char *names_short[] = { "", " JP", " JP", " US", " EU" };
  402. int u, i = 0;
  403. if (code) {
  404. code <<= 1;
  405. while((code >>= 1)) i++;
  406. if (i > 4) return "unknown";
  407. return names[i];
  408. } else {
  409. static char name[24];
  410. strcpy(name, "Auto:");
  411. for (u = 0; u < 3; u++) {
  412. i = 0; code = ((auto_order >> u*4) & 0xf) << 1;
  413. while((code >>= 1)) i++;
  414. strcat(name, names_short[i]);
  415. }
  416. return name;
  417. }
  418. }