UIQ3 update, some makefile unification, rm old configs, stuff
[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/PicoInt.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(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(2, 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         } else if (rendstatus & 0x20) { // mid-frame palette changes\r
254                 vidConvCpyRGB32(localPal, Pico.cram, 0x40);\r
255                 vidConvCpyRGB32(localPal+0x40, HighPal, 0x40);\r
256                 vidConvCpyRGB32(localPal+0x80, HighPal+0x40, 0x40);\r
257         } else {\r
258                 vidConvCpyRGB32(localPal, Pico.cram, 0x40);\r
259         }\r
260 }\r
261 \r
262 \r
263 // note: the internal 8 pixel border is taken care by asm code\r
264 static void vidBlit_90(int full)\r
265 {\r
266         unsigned char *ps = PicoDraw2FB+328*8;\r
267         unsigned long *pd = (unsigned long *) screenbuff;\r
268 \r
269         if (Pico.m.dirtyPal) fillLocalPal();\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.m.dirtyPal) fillLocalPal();\r
288 \r
289         if(Pico.video.reg[12]&1)\r
290                 vidConvCpy_270(pd, ps, localPal, 320/8);\r
291         else {\r
292                 if(full) vidClear(pd, 32);\r
293                 pd += 256*32;\r
294                 ps -= 64;     // the blitter starts copying from the right border, so we need to adjust\r
295                 vidConvCpy_270(pd, ps, localPal, 256/8);\r
296                 if(full) vidClear(pd + 256*256, 32);\r
297         }\r
298 }\r
299 \r
300 \r
301 static void vidBlitCenter_0(int full)\r
302 {\r
303         unsigned char *ps = PicoDraw2FB+328*8+8;\r
304         unsigned long *pd = (unsigned long *) screenbuff;\r
305 \r
306         if (Pico.m.dirtyPal) fillLocalPal();\r
307 \r
308         if(Pico.video.reg[12]&1) ps += 32;\r
309         vidConvCpy_center_0(pd, ps, localPal);\r
310         if(full) vidClear(pd + 224*256, 96);\r
311 }\r
312 \r
313 \r
314 static void vidBlitCenter_180(int full)\r
315 {\r
316         unsigned char *ps = PicoDraw2FB+328*8+8;\r
317         unsigned long *pd = (unsigned long *) screenbuff;\r
318 \r
319         if (Pico.m.dirtyPal) fillLocalPal();\r
320 \r
321         if(Pico.video.reg[12]&1) ps += 32;\r
322         vidConvCpy_center_180(pd, ps, localPal);\r
323         if(full) vidClear(pd + 224*256, 96);\r
324 }\r
325 \r
326 \r
327 static void vidBlitFit_0(int full)\r
328 {\r
329         if (Pico.m.dirtyPal) fillLocalPal();\r
330 \r
331         if(Pico.video.reg[12]&1)\r
332                  vidConvCpy_center2_40c_0(screenbuff, PicoDraw2FB+328*8, localPal, 168);\r
333         else vidConvCpy_center2_32c_0(screenbuff, PicoDraw2FB+328*8, localPal, 168);\r
334         if(full) vidClear((unsigned long *)screenbuff + 168*256, 320-168);\r
335 }\r
336 \r
337 \r
338 static void vidBlitFit_180(int full)\r
339 {\r
340         if (Pico.m.dirtyPal) fillLocalPal();\r
341 \r
342         if(Pico.video.reg[12]&1)\r
343              vidConvCpy_center2_40c_180(screenbuff, PicoDraw2FB+328*8, localPal, 168);\r
344         else vidConvCpy_center2_32c_180(screenbuff, PicoDraw2FB+328*8-64, localPal, 168);\r
345         if(full) vidClear((unsigned long *)screenbuff + 168*256, 320-168);\r
346 }\r
347 \r
348 \r
349 static void vidBlitFit2_0(int full)\r
350 {\r
351         if (Pico.m.dirtyPal) fillLocalPal();\r
352 \r
353         if(Pico.video.reg[12]&1)\r
354              vidConvCpy_center2_40c_0(screenbuff, PicoDraw2FB+328*8, localPal, 224);\r
355         else vidConvCpy_center2_32c_0(screenbuff, PicoDraw2FB+328*8, localPal, 224);\r
356         if(full) vidClear((unsigned long *)screenbuff + 224*256, 96);\r
357 }\r
358 \r
359 \r
360 static void vidBlitFit2_180(int full)\r
361 {\r
362         if (Pico.m.dirtyPal) fillLocalPal();\r
363 \r
364         if(Pico.video.reg[12]&1)\r
365              vidConvCpy_center2_40c_180(screenbuff, PicoDraw2FB+328*8, localPal, 224);\r
366         else vidConvCpy_center2_32c_180(screenbuff, PicoDraw2FB+328*8-64, localPal, 224);\r
367         if(full) vidClear((unsigned long *)screenbuff + 224*256, 96);\r
368 }\r
369 \r
370 \r
371 static void vidBlitCfg(void)\r
372 {\r
373         unsigned short *ps = (unsigned short *) PicoDraw2FB;\r
374         unsigned long *pd = (unsigned long *) screenbuff;\r
375         int i;\r
376 \r
377         // hangs randomly (due to repeated ldms/stms?)\r
378         //for (int i = 1; i < 320; i++, ps += 240, pd += 256)\r
379         //      vidConvCpyRGB32(pd, ps, 240);\r
380 \r
381         for (i = 0; i < 320; i++, pd += 16)\r
382                 for (int u = 0; u < 240; u++, ps++, pd++)\r
383                         *pd = ((*ps & 0xf) << 20) | ((*ps & 0xf0) << 8) | ((*ps & 0xf00) >> 4);\r
384 }\r
385 \r
386 \r
387 ////////////////////////////////\r
388 // main functions\r
389 \r
390 int vidInit(void *vidmem, int reinit)\r
391 {\r
392         if(!reinit) {\r
393                 // prepare framebuffer\r
394                 screenbuff = vidmem;\r
395                 PicoDraw2FB = (unsigned char *) malloc(framebuffsize);\r
396 \r
397                 if(!screenbuff) return KErrNotSupported;\r
398                 if(!PicoDraw2FB)  return KErrNoMemory;\r
399 \r
400                 memset(PicoDraw2FB, 0, framebuffsize);\r
401         }\r
402 \r
403         // select suitable blitters\r
404         vidBlit = vidBlit_270;\r
405         PicoScanBegin = EmuScanBegin8;\r
406         drawTextFps = drawTextFps0;\r
407         drawTextNotice = drawTextNotice0;\r
408 \r
409         memset(localPal, 0, 0x100*4);\r
410         localPal[0xe0] = 0x00000000; // reserved pixels for OSD\r
411         localPal[0xf0] = 0x00ee0000;\r
412 \r
413         // setup all orientation related stuff\r
414         if (currentConfig.rotation == TPicoConfig::PRot0)\r
415         {\r
416                 if (currentConfig.scaling == TPicoConfig::PMCenter) {\r
417                         vidBlit = vidBlitCenter_0;\r
418                         drawTextFps = drawTextFpsCenter0;\r
419                         drawTextNotice = drawTextNoticeCenter0;\r
420                 } else if (currentConfig.scaling == TPicoConfig::PMFit2) {\r
421                         vidBlit = vidBlitFit2_0;\r
422                         drawTextFps = drawTextFpsFit2_0;\r
423                         drawTextNotice = drawTextNoticeFit2_0;\r
424                 } else {\r
425                         vidBlit = vidBlitFit_0;\r
426                         drawTextFps = drawTextFpsFit0;\r
427                         drawTextNotice = drawTextNoticeFit0;\r
428                         PicoScanEnd = EmuScanEndFit0;\r
429                 }\r
430         } else if (currentConfig.rotation == TPicoConfig::PRot90) {\r
431                 vidBlit = vidBlit_90;\r
432         }\r
433         else if (currentConfig.rotation == TPicoConfig::PRot180)\r
434         {\r
435                 if (currentConfig.scaling == TPicoConfig::PMCenter)\r
436                 {\r
437                         vidBlit = vidBlitCenter_180;\r
438                         drawTextFps = drawTextFpsCenter0;\r
439                         drawTextNotice = drawTextNoticeCenter0;\r
440                 }\r
441                 else if (currentConfig.scaling == TPicoConfig::PMFit2) {\r
442                         vidBlit = vidBlitFit2_180;\r
443                         drawTextFps = drawTextFpsFit2_0;\r
444                         drawTextNotice = drawTextNoticeFit2_0;\r
445                 } else {\r
446                         vidBlit = vidBlitFit_180;\r
447                         drawTextFps = drawTextFpsFit0;\r
448                         drawTextNotice = drawTextNoticeFit0;\r
449                         PicoScanEnd = EmuScanEndFit0;\r
450                 }\r
451         }\r
452         else if (currentConfig.rotation == TPicoConfig::PRot270) {\r
453                 vidBlit = vidBlit_270;\r
454         }\r
455 \r
456         vidBlit(1);\r
457         PicoOpt |= 0x100;\r
458         Pico.m.dirtyPal = 1;\r
459 \r
460         return 0;\r
461 }\r
462 \r
463 void vidFree()\r
464 {\r
465         free(PicoDraw2FB);\r
466         PicoDraw2FB = 0;\r
467 }\r
468 \r
469 void vidDrawFrame(char *noticeStr, char *fpsStr, int num)\r
470 {\r
471         DrawLineDest = PicoDraw2FB + 328*8 + 8;\r
472 \r
473 //      PicoFrame(); // moved to main loop\r
474         if (currentConfig.EmuOpt & EOPT_SHOW_FPS)\r
475                 drawTextFps(fpsStr);\r
476         drawTextNotice(noticeStr);\r
477 \r
478         vidBlit(!num); // copy full frame once a second\r
479 }\r
480 \r
481 // -----------------------------------------------------------------\r
482 \r
483 static void drawText0(int x, int y, const char *text, long color)\r
484 {\r
485         unsigned short *vidmem=(unsigned short *)PicoDraw2FB;\r
486         int charmask, i, cx = x, cy;\r
487         unsigned short *l, *le, dmask=0x0333;\r
488 \r
489         // darken the background (left border)\r
490         for(l=vidmem+(cx-1)+(y-1)*240, le=vidmem+(cx-1)+(y+7)*240; l < le; l+=240)\r
491                 *l = (*l >> 2) & dmask;\r
492 \r
493         for(const char *p=text; *p; p++) {\r
494                 cy = y;\r
495                 charmask = *(mask_numbers + (*p - 0x2F));\r
496 \r
497                 for(l = vidmem+cx+(y-1)*240, le = vidmem+cx+(y+7)*240; l < le; l+=240-4) {\r
498                         *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;\r
499                         *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;\r
500                         *l = (*l >> 2) & dmask;\r
501                 }\r
502 \r
503                 for(i=0; i < 24; i++) {\r
504                         // draw dot. Is this fast?\r
505                         if(charmask&0x80000000) *( vidmem + (cx+(i&3)) + (cy+(i>>2))*240 ) = color;\r
506                         charmask <<= 1;\r
507                 }\r
508                 cx += 5;\r
509         }\r
510 }\r
511 \r
512 // draws rect with width - 1 and height - 1\r
513 static void drawRect(const TRect &rc, unsigned short color)\r
514 {\r
515         unsigned short *vidmem=(unsigned short *)PicoDraw2FB;\r
516 \r
517         if(rc.iTl.iX - rc.iBr.iX && rc.iTl.iY - rc.iBr.iY) {\r
518                 int stepX = rc.iTl.iX < rc.iBr.iX ? 1 : -1;\r
519                 int stepY = rc.iTl.iY < rc.iBr.iY ? 1 : -1;\r
520                 \r
521                 for(int x = rc.iTl.iX;; x += stepX) {\r
522                         *(vidmem + rc.iTl.iY*240 + x) = *(vidmem + (rc.iBr.iY - stepY)*240 + x) = color;\r
523                         if(x == rc.iBr.iX - stepX) break;\r
524                 }\r
525                 \r
526                 for(int y = rc.iTl.iY;; y += stepY) {\r
527                         *(vidmem + y*240 + rc.iTl.iX) = *(vidmem + y*240 + rc.iBr.iX - stepX) = color;\r
528                         if(y == rc.iBr.iY - stepY) break;\r
529                 }\r
530         }\r
531 }\r
532 \r
533 // draws fullsize filled rect\r
534 static void drawRectFilled(const TRect rc, unsigned short color)\r
535 {\r
536         unsigned short *vidmem=(unsigned short *)PicoDraw2FB;\r
537 \r
538         if(rc.iTl.iX - rc.iBr.iX && rc.iTl.iY - rc.iBr.iY) {\r
539                 int stepX = rc.iTl.iX < rc.iBr.iX ? 1 : -1;\r
540                 int stepY = rc.iTl.iY < rc.iBr.iY ? 1 : -1;\r
541                 \r
542                 for(int y = rc.iTl.iY;; y += stepY) {\r
543                         for(int x = rc.iTl.iX;; x += stepX) {\r
544                                 *(vidmem + y*240 + x) = *(vidmem + y*240 + x) = color;\r
545                                 if(x == rc.iBr.iX) break;\r
546                         }\r
547                         if(y == rc.iBr.iY) break;\r
548                 }\r
549         }\r
550 }\r
551 \r
552 // direction: -1 left, 1 right\r
553 static void drawArrow0(TPoint p, int direction, unsigned short color)\r
554 {\r
555         unsigned short *vidmem=(unsigned short *)PicoDraw2FB;\r
556         int width = 15;\r
557         int x = p.iX;\r
558         int y = p.iY;\r
559 \r
560         for(; width > 0; x+=direction, y++, width -=2)\r
561                 for(int i=0; i < width; i++)\r
562                         *(vidmem + x + y*240 + i*240) = color;\r
563 }\r
564 \r
565 static char *vidGetScanName(int scan)\r
566 {\r
567         static char buff[32];\r
568 \r
569         if((scan >= '0' && scan <= '9') || (scan >= 'A' && scan <= 'Z')) {\r
570                 buff[0] = (char) scan; buff[1] = 0;\r
571         } else {\r
572                 switch(scan) {\r
573                         case 0x01: strcpy(buff, "BSPACE");   break;\r
574                         case 0x03: strcpy(buff, "OK");       break;\r
575                         case 0x05: strcpy(buff, "SPACE");    break;\r
576                         case 0x0e: strcpy(buff, "AST");      break;\r
577                         case 0x0f: strcpy(buff, "HASH");     break;\r
578                         case 0x12: strcpy(buff, "SHIFT");    break;\r
579                         case 0x19: strcpy(buff, "ALT");      break;\r
580                         case 0x79: strcpy(buff, "PLUS");     break;\r
581                         case 0x7a: strcpy(buff, "DOT");      break;\r
582                         case 0xa5: strcpy(buff, "JOG@UP");   break;\r
583                         case 0xa6: strcpy(buff, "JOG@DOWN"); break;\r
584                         case 0xb5: strcpy(buff, "INET");     break;\r
585                         case 0xd4: strcpy(buff, "JOG@PUSH"); break;\r
586                         case 0xd5: strcpy(buff, "BACK");     break;\r
587                         default:  sprintf(buff, "KEY@%02X", scan); break;\r
588                 }\r
589         }\r
590 \r
591         return buff;\r
592 }\r
593 \r
594 void vidKeyConfigFrame(const TUint whichAction)\r
595 {\r
596         int i;\r
597         char buttonNames[128];\r
598         buttonNames[0] = 0;\r
599         memset(PicoDraw2FB, 0, framebuffsize);\r
600 \r
601         unsigned long currentActCode = 1 << whichAction;\r
602 \r
603         // draw all "buttons" in reverse order\r
604         const TPicoAreaConfigEntry *e = areaConfig + 1; i = 0;\r
605         while(e->rect != TRect(0,0,0,0)) { e++; i++; }\r
606         for(e--, i--; e->rect != TRect(0,0,0,0); e--, i--)\r
607                 drawRect(e->rect, (currentConfig.KeyBinds[i+256] & currentActCode) ? color_red : color_red_dim);\r
608 \r
609         // action name control\r
610         drawRectFilled(TRect(72, 2, 168, 20), color_grey); // 96x14\r
611         drawArrow0(TPoint(80, 3), -1, color_green);\r
612         drawArrow0(TPoint(160, 3), 1, color_green);\r
613 \r
614         drawText0(86, 9, actionNames[whichAction], color_red);\r
615 \r
616         // draw active button names if there are any\r
617         for (i = 0; i < 256; i++) {\r
618                 if (currentConfig.KeyBinds[i] & currentActCode) {\r
619                         if(buttonNames[0]) strcat(buttonNames, ";@");\r
620                         strcat(buttonNames, vidGetScanName(i));\r
621                 }\r
622         }\r
623 \r
624         if (buttonNames[0]) {\r
625                 buttonNames[61] = 0; // only 60 chars fit\r
626                 drawText0(6, 48, buttonNames, color_blue);\r
627         }\r
628 \r
629         vidBlitCfg();\r
630 }\r
631 \r
632 void vidDrawNotice(const char *txt)\r
633 {\r
634         if(PicoDraw2FB) {\r
635                 drawTextNotice(txt);\r
636                 vidBlit(1);\r
637         }\r
638 }\r