vid.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. // EmuScan routines for Pico, also simple text and shape drawing routines.
  2. // (c) Copyright 2006, notaz
  3. // All Rights Reserved
  4. #include "vid.h"
  5. #include "../Engine.h"
  6. #include <Pico/PicoInt.h>
  7. #include "../../common/emu.h"
  8. #include "blit.h"
  9. #include "debug.h"
  10. // global stuff
  11. extern TPicoAreaConfigEntry areaConfig[];
  12. extern const char *actionNames[];
  13. // main framebuffer
  14. static void *screenbuff = 0; // pointer to real device video memory
  15. //static
  16. extern "C" { unsigned char *PicoDraw2FB = 0; } // temporary buffer
  17. const int framebuffsize = (8+320)*(8+240+8)*2+8*2; // actual framebuffer size (in bytes+to support new rendering mode)
  18. // drawer function pointers
  19. static void (*drawTextFps)(const char *text) = 0;
  20. static void (*drawTextNotice)(const char *text) = 0;
  21. // blitter
  22. static void (*vidBlit)(int full) = 0;
  23. // colors
  24. const unsigned short color_red = 0x022F;
  25. const unsigned short color_red_dim = 0x0004;
  26. const unsigned short color_green = 0x01F1;
  27. const unsigned short color_blue = 0x0F11;
  28. const unsigned short color_grey = 0x0222;
  29. // other
  30. int txtheight_fit = 138;
  31. // bitmasks
  32. static const unsigned long mask_numbers[] = {
  33. 0x12244800, // 47 2F /
  34. 0x69999600, // 48 30 0
  35. 0x26222200, // 49 31 1
  36. 0x69168F00, // 50 32 2
  37. 0x69219600, // 51 33 3
  38. 0x266AF200, // 52 34 4
  39. 0xF8E11E00, // 53 35 5
  40. 0x68E99600, // 54 36 6
  41. 0x71222200, // 55 37 7
  42. 0x69699600, // 56 38 8
  43. 0x69719600, // 57 39 9
  44. 0x04004000, // 58 3A :
  45. 0x04004400, // 59 3B ;
  46. 0x01242100, // 60 3C <
  47. 0x00707000, // 61 3D =
  48. 0x04212400, // 62 3E >
  49. 0x69240400, // 63 3F ?
  50. 0x00000000, // 64 40 @ [used instead of space for now]
  51. 0x22579900, // 65 41 A
  52. 0xE9E99E00, // 66 42 B
  53. 0x69889600, // 67 43 C
  54. 0xE9999E00, // 68 44 D
  55. 0xF8E88F00, // 69 45 E
  56. 0xF8E88800, // 70 46 F
  57. 0x698B9700, // 71 47 G
  58. 0x99F99900, // 72 48 H
  59. 0x44444400, // 73 49 I
  60. 0x11119600, // 74 4A J
  61. 0x9ACCA900, // 75 4B K
  62. 0x88888F00, // 76 4C L
  63. 0x9F999900, // 77 4D M
  64. 0x9DDBB900, // 78 4E N
  65. 0x69999600, // 79 4F O
  66. 0xE99E8800, // 80 50 P
  67. 0x6999A500, // 81 51 Q
  68. 0xE99E9900, // 82 52 R
  69. 0x69429600, // 83 53 S
  70. 0x72222200, // 84 54 T
  71. 0x99999600, // 85 55 U
  72. 0x55552200, // 86 56 V
  73. 0x9999F900, // 87 57 W
  74. 0x55225500, // 88 58 X
  75. 0x55222200, // 89 59 Y
  76. 0xF1248F00, // 90 5A Z
  77. };
  78. ////////////////////////////////
  79. // PicoScan functions
  80. static int EmuScanBegin8(unsigned int num)
  81. {
  82. DrawLineDest = PicoDraw2FB + 328*num + 328*8 + 8;
  83. return 0;
  84. }
  85. static int EmuScanEndFit0(unsigned int num)
  86. {
  87. // 0.75, 168 lines
  88. static int u = 0, num2 = 0;
  89. if(!num) u = num2 = 0;
  90. DrawLineDest = PicoDraw2FB + 328*(++num2) + 328*8 + 8;
  91. u += 6666;
  92. if(u < 10000) {
  93. // u += 7500;
  94. return 1;
  95. }
  96. u -= 10000;
  97. return 0;
  98. }
  99. ////////////////////////////////
  100. // text drawers
  101. // warning: text must be at least 1px away from screen borders
  102. static void drawTextM2(int x, int y, const char *text)
  103. {
  104. unsigned char *vidmem = PicoDraw2FB + 328*8 + 8;
  105. int charmask, i, cx = x, cy;
  106. unsigned char *l, *le;
  107. // darken the background (left border)
  108. for(l=vidmem+(cx-1)+(y-1)*328, le=l+8*328; l < le; l+=328) *l = 0xE0;
  109. for(const char *p=text; *p; p++) {
  110. cy = y;
  111. charmask = *(mask_numbers + (*p - 0x2F));
  112. for(l = vidmem+cx+(y-1)*328, le = l+8*328; l < le; l+=328-4) {
  113. *l = 0xE0; l++; *l = 0xE0; l++;
  114. *l = 0xE0; l++; *l = 0xE0; l++;
  115. *l = 0xE0;
  116. }
  117. for(i=0; i < 24; i++) {
  118. if(charmask&0x80000000) *( vidmem + (cx+(i&3)) + (cy+(i>>2))*328 ) = 0xf0;
  119. charmask <<= 1;
  120. }
  121. cx += 5;
  122. }
  123. }
  124. static void drawTextM2Fat(int x, int y, const char *text)
  125. {
  126. unsigned char *vidmem = PicoDraw2FB + 328*8 + 8;
  127. int charmask, i, cx = x&~1, cy;
  128. unsigned short *l, *le;
  129. // darken the background (left border)
  130. for(l=(unsigned short *)(vidmem+(cx-2)+(y-1)*328), le=l+8*328/2; l < le; l+=328/2) *l = 0xE0;
  131. for(const char *p=text; *p; p++) {
  132. cy = y;
  133. for(l = (unsigned short *)(vidmem+cx+(y-1)*328), le = l+8*328/2; l < le; l+=328/2) {
  134. l += 4;
  135. *l-- = 0xe0e0; *l-- = 0xe0e0; *l-- = 0xe0e0; *l-- = 0xe0e0; *l = 0xe0e0;
  136. }
  137. charmask = *(mask_numbers + (*p - 0x2F));
  138. for(i=0; i < 24; i++) {
  139. if(charmask&0x80000000) *(unsigned short *)( vidmem + cx+(i&3)*2 + (cy+(i>>2))*328 ) = 0xf0f0;
  140. charmask <<= 1;
  141. }
  142. cx += 5*2;
  143. }
  144. }
  145. static void drawTextFpsCenter0(const char *text)
  146. {
  147. if(!text) return;
  148. drawTextM2(214, 216, text);
  149. }
  150. static void drawTextFpsFit0(const char *text)
  151. {
  152. if(!text) return;
  153. drawTextM2Fat((Pico.video.reg[12]&1) ? 256-32 : 224-32, 160, text);
  154. }
  155. static void drawTextFpsFit2_0(const char *text)
  156. {
  157. if(!text) return;
  158. drawTextM2Fat((Pico.video.reg[12]&1) ? 256-32 : 224-32, 216, text);
  159. }
  160. static void drawTextFps0(const char *text)
  161. {
  162. if(!text) return;
  163. drawTextM2((Pico.video.reg[12]&1) ? 256 : 224, 216, text);
  164. }
  165. static void drawTextNoticeCenter0(const char *text)
  166. {
  167. if(!text) return;
  168. drawTextM2(2, 216, text);
  169. }
  170. static void drawTextNoticeFit0(const char *text)
  171. {
  172. if(!text) return;
  173. drawTextM2Fat(2, 160, text);
  174. }
  175. static void drawTextNoticeFit2_0(const char *text)
  176. {
  177. if(!text) return;
  178. drawTextM2Fat(2, 216, text);
  179. }
  180. static void drawTextNotice0(const char *text)
  181. {
  182. if(!text) return;
  183. drawTextM2(2, 216, text);
  184. }
  185. // -----------------------------------------------------------------
  186. static int localPal[0x100];
  187. static void fillLocalPal(void)
  188. {
  189. Pico.m.dirtyPal = 0;
  190. if (PicoOpt&0x10) {
  191. // 8bit fast renderer
  192. vidConvCpyRGB32(localPal, Pico.cram, 0x40);
  193. return;
  194. }
  195. // 8bit accurate renderer
  196. if(Pico.video.reg[0xC]&8) { // shadow/hilight mode
  197. vidConvCpyRGB32(localPal, Pico.cram, 0x40);
  198. vidConvCpyRGB32sh(localPal+0x40, Pico.cram, 0x40);
  199. vidConvCpyRGB32hi(localPal+0x80, Pico.cram, 0x40);
  200. memcpy32(localPal+0xc0, localPal+0x40, 0x40);
  201. localPal[0xe0] = 0x00000000; // reserved pixels for OSD
  202. localPal[0xf0] = 0x00ee0000;
  203. } else if (rendstatus & 0x20) { // mid-frame palette changes
  204. vidConvCpyRGB32(localPal, Pico.cram, 0x40);
  205. vidConvCpyRGB32(localPal+0x40, HighPal, 0x40);
  206. vidConvCpyRGB32(localPal+0x80, HighPal+0x40, 0x40);
  207. } else {
  208. vidConvCpyRGB32(localPal, Pico.cram, 0x40);
  209. }
  210. }
  211. // note: the internal 8 pixel border is taken care by asm code
  212. static void vidBlit_90(int full)
  213. {
  214. unsigned char *ps = PicoDraw2FB+328*8;
  215. unsigned long *pd = (unsigned long *) screenbuff;
  216. if (Pico.m.dirtyPal) fillLocalPal();
  217. if(Pico.video.reg[12]&1)
  218. vidConvCpy_90(pd, ps, localPal, 320/8);
  219. else {
  220. if(full) vidClear(pd, 32);
  221. pd += 256*32;
  222. vidConvCpy_90(pd, ps, localPal, 256/8);
  223. if(full) vidClear(pd + 256*256, 32);
  224. }
  225. }
  226. static void vidBlit_270(int full)
  227. {
  228. unsigned char *ps = PicoDraw2FB+328*8;
  229. unsigned long *pd = (unsigned long *) screenbuff;
  230. if (Pico.m.dirtyPal) fillLocalPal();
  231. if(Pico.video.reg[12]&1)
  232. vidConvCpy_270(pd, ps, localPal, 320/8);
  233. else {
  234. if(full) vidClear(pd, 32);
  235. pd += 256*32;
  236. ps -= 64; // the blitter starts copying from the right border, so we need to adjust
  237. vidConvCpy_270(pd, ps, localPal, 256/8);
  238. if(full) vidClear(pd + 256*256, 32);
  239. }
  240. }
  241. static void vidBlitCenter_0(int full)
  242. {
  243. unsigned char *ps = PicoDraw2FB+328*8+8;
  244. unsigned long *pd = (unsigned long *) screenbuff;
  245. if (Pico.m.dirtyPal) fillLocalPal();
  246. if(Pico.video.reg[12]&1) ps += 32;
  247. vidConvCpy_center_0(pd, ps, localPal);
  248. if(full) vidClear(pd + 224*256, 96);
  249. }
  250. static void vidBlitCenter_180(int full)
  251. {
  252. unsigned char *ps = PicoDraw2FB+328*8+8;
  253. unsigned long *pd = (unsigned long *) screenbuff;
  254. if (Pico.m.dirtyPal) fillLocalPal();
  255. if(Pico.video.reg[12]&1) ps += 32;
  256. vidConvCpy_center_180(pd, ps, localPal);
  257. if(full) vidClear(pd + 224*256, 96);
  258. }
  259. static void vidBlitFit_0(int full)
  260. {
  261. if (Pico.m.dirtyPal) fillLocalPal();
  262. if(Pico.video.reg[12]&1)
  263. vidConvCpy_center2_40c_0(screenbuff, PicoDraw2FB+328*8, localPal, 168);
  264. else vidConvCpy_center2_32c_0(screenbuff, PicoDraw2FB+328*8, localPal, 168);
  265. if(full) vidClear((unsigned long *)screenbuff + 168*256, 320-168);
  266. }
  267. static void vidBlitFit_180(int full)
  268. {
  269. if (Pico.m.dirtyPal) fillLocalPal();
  270. if(Pico.video.reg[12]&1)
  271. vidConvCpy_center2_40c_180(screenbuff, PicoDraw2FB+328*8, localPal, 168);
  272. else vidConvCpy_center2_32c_180(screenbuff, PicoDraw2FB+328*8-64, localPal, 168);
  273. if(full) vidClear((unsigned long *)screenbuff + 168*256, 320-168);
  274. }
  275. static void vidBlitFit2_0(int full)
  276. {
  277. if (Pico.m.dirtyPal) fillLocalPal();
  278. if(Pico.video.reg[12]&1)
  279. vidConvCpy_center2_40c_0(screenbuff, PicoDraw2FB+328*8, localPal, 224);
  280. else vidConvCpy_center2_32c_0(screenbuff, PicoDraw2FB+328*8, localPal, 224);
  281. if(full) vidClear((unsigned long *)screenbuff + 224*256, 96);
  282. }
  283. static void vidBlitFit2_180(int full)
  284. {
  285. if (Pico.m.dirtyPal) fillLocalPal();
  286. if(Pico.video.reg[12]&1)
  287. vidConvCpy_center2_40c_180(screenbuff, PicoDraw2FB+328*8, localPal, 224);
  288. else vidConvCpy_center2_32c_180(screenbuff, PicoDraw2FB+328*8-64, localPal, 224);
  289. if(full) vidClear((unsigned long *)screenbuff + 224*256, 96);
  290. }
  291. static void vidBlitCfg(void)
  292. {
  293. unsigned short *ps = (unsigned short *) PicoDraw2FB;
  294. unsigned long *pd = (unsigned long *) screenbuff;
  295. int i;
  296. // hangs randomly (due to repeated ldms/stms?)
  297. //for (int i = 1; i < 320; i++, ps += 240, pd += 256)
  298. // vidConvCpyRGB32(pd, ps, 240);
  299. for (i = 0; i < 320; i++, pd += 16)
  300. for (int u = 0; u < 240; u++, ps++, pd++)
  301. *pd = ((*ps & 0xf) << 20) | ((*ps & 0xf0) << 8) | ((*ps & 0xf00) >> 4);
  302. }
  303. ////////////////////////////////
  304. // main functions
  305. int vidInit(void *vidmem, int reinit)
  306. {
  307. if(!reinit) {
  308. // prepare framebuffer
  309. screenbuff = vidmem;
  310. PicoDraw2FB = (unsigned char *) malloc(framebuffsize);
  311. if(!screenbuff) return KErrNotSupported;
  312. if(!PicoDraw2FB) return KErrNoMemory;
  313. memset(PicoDraw2FB, 0, framebuffsize);
  314. }
  315. // select suitable blitters
  316. vidBlit = vidBlit_270;
  317. PicoScanBegin = EmuScanBegin8;
  318. drawTextFps = drawTextFps0;
  319. drawTextNotice = drawTextNotice0;
  320. memset(localPal, 0, 0x100*4);
  321. localPal[0xe0] = 0x00000000; // reserved pixels for OSD
  322. localPal[0xf0] = 0x00ee0000;
  323. // setup all orientation related stuff
  324. if (currentConfig.rotation == TPicoConfig::PRot0)
  325. {
  326. if (currentConfig.scaling == TPicoConfig::PMCenter) {
  327. vidBlit = vidBlitCenter_0;
  328. drawTextFps = drawTextFpsCenter0;
  329. drawTextNotice = drawTextNoticeCenter0;
  330. } else if (currentConfig.scaling == TPicoConfig::PMFit2) {
  331. vidBlit = vidBlitFit2_0;
  332. drawTextFps = drawTextFpsFit2_0;
  333. drawTextNotice = drawTextNoticeFit2_0;
  334. } else {
  335. vidBlit = vidBlitFit_0;
  336. drawTextFps = drawTextFpsFit0;
  337. drawTextNotice = drawTextNoticeFit0;
  338. PicoScanEnd = EmuScanEndFit0;
  339. }
  340. } else if (currentConfig.rotation == TPicoConfig::PRot90) {
  341. vidBlit = vidBlit_90;
  342. }
  343. else if (currentConfig.rotation == TPicoConfig::PRot180)
  344. {
  345. if (currentConfig.scaling == TPicoConfig::PMCenter)
  346. {
  347. vidBlit = vidBlitCenter_180;
  348. drawTextFps = drawTextFpsCenter0;
  349. drawTextNotice = drawTextNoticeCenter0;
  350. }
  351. else if (currentConfig.scaling == TPicoConfig::PMFit2) {
  352. vidBlit = vidBlitFit2_180;
  353. drawTextFps = drawTextFpsFit2_0;
  354. drawTextNotice = drawTextNoticeFit2_0;
  355. } else {
  356. vidBlit = vidBlitFit_180;
  357. drawTextFps = drawTextFpsFit0;
  358. drawTextNotice = drawTextNoticeFit0;
  359. PicoScanEnd = EmuScanEndFit0;
  360. }
  361. }
  362. else if (currentConfig.rotation == TPicoConfig::PRot270) {
  363. vidBlit = vidBlit_270;
  364. }
  365. vidBlit(1);
  366. PicoOpt |= 0x100;
  367. Pico.m.dirtyPal = 1;
  368. return 0;
  369. }
  370. void vidFree()
  371. {
  372. free(PicoDraw2FB);
  373. PicoDraw2FB = 0;
  374. }
  375. void vidDrawFrame(char *noticeStr, char *fpsStr, int num)
  376. {
  377. DrawLineDest = PicoDraw2FB + 328*8 + 8;
  378. // PicoFrame(); // moved to main loop
  379. if (currentConfig.EmuOpt & EOPT_SHOW_FPS)
  380. drawTextFps(fpsStr);
  381. drawTextNotice(noticeStr);
  382. vidBlit(!num); // copy full frame once a second
  383. }
  384. // -----------------------------------------------------------------
  385. static void drawText0(int x, int y, const char *text, long color)
  386. {
  387. unsigned short *vidmem=(unsigned short *)PicoDraw2FB;
  388. int charmask, i, cx = x, cy;
  389. unsigned short *l, *le, dmask=0x0333;
  390. // darken the background (left border)
  391. for(l=vidmem+(cx-1)+(y-1)*240, le=vidmem+(cx-1)+(y+7)*240; l < le; l+=240)
  392. *l = (*l >> 2) & dmask;
  393. for(const char *p=text; *p; p++) {
  394. cy = y;
  395. charmask = *(mask_numbers + (*p - 0x2F));
  396. for(l = vidmem+cx+(y-1)*240, le = vidmem+cx+(y+7)*240; l < le; l+=240-4) {
  397. *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;
  398. *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;
  399. *l = (*l >> 2) & dmask;
  400. }
  401. for(i=0; i < 24; i++) {
  402. // draw dot. Is this fast?
  403. if(charmask&0x80000000) *( vidmem + (cx+(i&3)) + (cy+(i>>2))*240 ) = color;
  404. charmask <<= 1;
  405. }
  406. cx += 5;
  407. }
  408. }
  409. // draws rect with width - 1 and height - 1
  410. static void drawRect(const TRect &rc, unsigned short color)
  411. {
  412. unsigned short *vidmem=(unsigned short *)PicoDraw2FB;
  413. if(rc.iTl.iX - rc.iBr.iX && rc.iTl.iY - rc.iBr.iY) {
  414. int stepX = rc.iTl.iX < rc.iBr.iX ? 1 : -1;
  415. int stepY = rc.iTl.iY < rc.iBr.iY ? 1 : -1;
  416. for(int x = rc.iTl.iX;; x += stepX) {
  417. *(vidmem + rc.iTl.iY*240 + x) = *(vidmem + (rc.iBr.iY - stepY)*240 + x) = color;
  418. if(x == rc.iBr.iX - stepX) break;
  419. }
  420. for(int y = rc.iTl.iY;; y += stepY) {
  421. *(vidmem + y*240 + rc.iTl.iX) = *(vidmem + y*240 + rc.iBr.iX - stepX) = color;
  422. if(y == rc.iBr.iY - stepY) break;
  423. }
  424. }
  425. }
  426. // draws fullsize filled rect
  427. static void drawRectFilled(const TRect rc, unsigned short color)
  428. {
  429. unsigned short *vidmem=(unsigned short *)PicoDraw2FB;
  430. if(rc.iTl.iX - rc.iBr.iX && rc.iTl.iY - rc.iBr.iY) {
  431. int stepX = rc.iTl.iX < rc.iBr.iX ? 1 : -1;
  432. int stepY = rc.iTl.iY < rc.iBr.iY ? 1 : -1;
  433. for(int y = rc.iTl.iY;; y += stepY) {
  434. for(int x = rc.iTl.iX;; x += stepX) {
  435. *(vidmem + y*240 + x) = *(vidmem + y*240 + x) = color;
  436. if(x == rc.iBr.iX) break;
  437. }
  438. if(y == rc.iBr.iY) break;
  439. }
  440. }
  441. }
  442. // direction: -1 left, 1 right
  443. static void drawArrow0(TPoint p, int direction, unsigned short color)
  444. {
  445. unsigned short *vidmem=(unsigned short *)PicoDraw2FB;
  446. int width = 15;
  447. int x = p.iX;
  448. int y = p.iY;
  449. for(; width > 0; x+=direction, y++, width -=2)
  450. for(int i=0; i < width; i++)
  451. *(vidmem + x + y*240 + i*240) = color;
  452. }
  453. static char *vidGetScanName(int scan)
  454. {
  455. static char buff[32];
  456. if((scan >= '0' && scan <= '9') || (scan >= 'A' && scan <= 'Z')) {
  457. buff[0] = (char) scan; buff[1] = 0;
  458. } else {
  459. switch(scan) {
  460. case 0x01: strcpy(buff, "BSPACE"); break;
  461. case 0x03: strcpy(buff, "OK"); break;
  462. case 0x05: strcpy(buff, "SPACE"); break;
  463. case 0x0e: strcpy(buff, "AST"); break;
  464. case 0x0f: strcpy(buff, "HASH"); break;
  465. case 0x12: strcpy(buff, "SHIFT"); break;
  466. case 0x19: strcpy(buff, "ALT"); break;
  467. case 0x79: strcpy(buff, "PLUS"); break;
  468. case 0x7a: strcpy(buff, "DOT"); break;
  469. case 0xa5: strcpy(buff, "JOG@UP"); break;
  470. case 0xa6: strcpy(buff, "JOG@DOWN"); break;
  471. case 0xb5: strcpy(buff, "INET"); break;
  472. case 0xd4: strcpy(buff, "JOG@PUSH"); break;
  473. case 0xd5: strcpy(buff, "BACK"); break;
  474. default: sprintf(buff, "KEY@%02X", scan); break;
  475. }
  476. }
  477. return buff;
  478. }
  479. void vidKeyConfigFrame(const TUint whichAction)
  480. {
  481. int i;
  482. char buttonNames[128];
  483. buttonNames[0] = 0;
  484. memset(PicoDraw2FB, 0, framebuffsize);
  485. unsigned long currentActCode = 1 << whichAction;
  486. // draw all "buttons" in reverse order
  487. const TPicoAreaConfigEntry *e = areaConfig + 1; i = 0;
  488. while(e->rect != TRect(0,0,0,0)) { e++; i++; }
  489. for(e--, i--; e->rect != TRect(0,0,0,0); e--, i--)
  490. drawRect(e->rect, (currentConfig.KeyBinds[i+256] & currentActCode) ? color_red : color_red_dim);
  491. // action name control
  492. drawRectFilled(TRect(72, 2, 168, 20), color_grey); // 96x14
  493. drawArrow0(TPoint(80, 3), -1, color_green);
  494. drawArrow0(TPoint(160, 3), 1, color_green);
  495. drawText0(86, 9, actionNames[whichAction], color_red);
  496. // draw active button names if there are any
  497. for (i = 0; i < 256; i++) {
  498. if (currentConfig.KeyBinds[i] & currentActCode) {
  499. if(buttonNames[0]) strcat(buttonNames, ";@");
  500. strcat(buttonNames, vidGetScanName(i));
  501. }
  502. }
  503. if (buttonNames[0]) {
  504. buttonNames[61] = 0; // only 60 chars fit
  505. drawText0(6, 48, buttonNames, color_blue);
  506. }
  507. vidBlitCfg();
  508. }
  509. void vidDrawNotice(const char *txt)
  510. {
  511. if(PicoDraw2FB) {
  512. drawTextNotice(txt);
  513. vidBlit(1);
  514. }
  515. }