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