switch Cyclone to submodule on it's own git repo
[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; // PicoDraw2FB 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 + 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) + 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 += (240+VID_BORDER_R)*32;\r
276                 vidConvCpy_90(pd, ps, localPal, 256/8);\r
277                 if(full) vidClear(pd + (240+VID_BORDER_R)*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 += (240+VID_BORDER_R)*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 + (240+VID_BORDER_R)*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 + (240+VID_BORDER_R)*224, 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 + (240+VID_BORDER_R)*224, 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 + (240+VID_BORDER_R)*168, 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 + (240+VID_BORDER_R)*168, 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 + (240+VID_BORDER_R)*224, 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 + (240+VID_BORDER_R)*224, 96);\r
354 }\r
355 \r
356 static void vidBlitCfg(void)\r
357 {\r
358         unsigned short *ps = (unsigned short *) PicoDraw2FB;\r
359         unsigned long *pd = (unsigned long *) screenbuff;\r
360         int i;\r
361 \r
362         // hangs randomly (due to repeated ldms/stms?)\r
363         //for (int i = 1; i < 320; i++, ps += 240, pd += 256)\r
364         //      vidConvCpyRGB32(pd, ps, 240);\r
365 \r
366         for (i = 0; i < 320; i++, pd += VID_BORDER_R)\r
367                 for (int u = 0; u < 240; u++, ps++, pd++)\r
368                         *pd = ((*ps & 0xf) << 20) | ((*ps & 0xf0) << 8) | ((*ps & 0xf00) >> 4);\r
369 }\r
370 \r
371 \r
372 ////////////////////////////////\r
373 // main functions\r
374 \r
375 int vidInit(void *vidmem, int reinit)\r
376 {\r
377         if(!reinit) {\r
378                 // prepare framebuffer\r
379                 screenbuff = vidmem;\r
380                 PicoDraw2FB = (unsigned char *) malloc(framebuffsize);\r
381 \r
382                 if(!screenbuff) return KErrNotSupported;\r
383                 if(!PicoDraw2FB)  return KErrNoMemory;\r
384 \r
385                 memset(PicoDraw2FB, 0, framebuffsize);\r
386         }\r
387 \r
388         // select suitable blitters\r
389         vidBlit = vidBlit_270;\r
390         PicoScanBegin = EmuScanBegin8;\r
391         PicoScanEnd = NULL;\r
392         drawTextFps = drawTextFps0;\r
393         drawTextNotice = drawTextNotice0;\r
394 \r
395         memset(localPal, 0, 0x100*4);\r
396         localPal[0xe0] = 0x00000000; // reserved pixels for OSD\r
397         localPal[0xf0] = 0x00ee0000;\r
398 \r
399         // setup all orientation related stuff\r
400         if (currentConfig.rotation == TPicoConfig::PRot0)\r
401         {\r
402                 if (currentConfig.scaling == TPicoConfig::PMCenter) {\r
403                         vidBlit = vidBlitCenter_0;\r
404                         drawTextFps = drawTextFpsCenter0;\r
405                         drawTextNotice = drawTextNoticeCenter0;\r
406                 } else if (currentConfig.scaling == TPicoConfig::PMFit2) {\r
407                         vidBlit = vidBlitFit2_0;\r
408                         drawTextFps = drawTextFpsFit2_0;\r
409                         drawTextNotice = drawTextNoticeFit2_0;\r
410                 } else {\r
411                         vidBlit = vidBlitFit_0;\r
412                         drawTextFps = drawTextFpsFit0;\r
413                         drawTextNotice = drawTextNoticeFit0;\r
414                         PicoScanBegin = NULL;\r
415                         PicoScanEnd = EmuScanEndFit0;\r
416                 }\r
417         } else if (currentConfig.rotation == TPicoConfig::PRot90) {\r
418                 vidBlit = vidBlit_90;\r
419         }\r
420         else if (currentConfig.rotation == TPicoConfig::PRot180)\r
421         {\r
422                 if (currentConfig.scaling == TPicoConfig::PMCenter)\r
423                 {\r
424                         vidBlit = vidBlitCenter_180;\r
425                         drawTextFps = drawTextFpsCenter0;\r
426                         drawTextNotice = drawTextNoticeCenter0;\r
427                 }\r
428                 else if (currentConfig.scaling == TPicoConfig::PMFit2) {\r
429                         vidBlit = vidBlitFit2_180;\r
430                         drawTextFps = drawTextFpsFit2_0;\r
431                         drawTextNotice = drawTextNoticeFit2_0;\r
432                 } else {\r
433                         vidBlit = vidBlitFit_180;\r
434                         drawTextFps = drawTextFpsFit0;\r
435                         drawTextNotice = drawTextNoticeFit0;\r
436                         PicoScanBegin = NULL;\r
437                         PicoScanEnd = EmuScanEndFit0;\r
438                 }\r
439         }\r
440         else if (currentConfig.rotation == TPicoConfig::PRot270) {\r
441                 vidBlit = vidBlit_270;\r
442         }\r
443 \r
444         fillLocalPal();\r
445         vidBlit(1);\r
446         PicoOpt |= 0x100;\r
447         Pico.m.dirtyPal = 1;\r
448 \r
449         return 0;\r
450 }\r
451 \r
452 void vidFree()\r
453 {\r
454         free(PicoDraw2FB);\r
455         PicoDraw2FB = 0;\r
456 }\r
457 \r
458 void vidDrawFrame(char *noticeStr, char *fpsStr, int num)\r
459 {\r
460         DrawLineDest = PicoDraw2FB + 328*8 + 8;\r
461 \r
462 //      PicoFrame(); // moved to main loop\r
463         if (currentConfig.EmuOpt & EOPT_SHOW_FPS)\r
464                 drawTextFps(fpsStr);\r
465         drawTextNotice(noticeStr);\r
466 \r
467         if (Pico.m.dirtyPal) fillLocalPal();\r
468         vidBlit(!num); // copy full frame once a second\r
469 }\r
470 \r
471 // -----------------------------------------------------------------\r
472 \r
473 static void drawText0(int x, int y, const char *text, long color)\r
474 {\r
475         unsigned short *vidmem=(unsigned short *)PicoDraw2FB;\r
476         int charmask, i, cx = x, cy;\r
477         unsigned short *l, *le, dmask=0x0333;\r
478 \r
479         // darken the background (left border)\r
480         for(l=vidmem+(cx-1)+(y-1)*240, le=vidmem+(cx-1)+(y+7)*240; l < le; l+=240)\r
481                 *l = (*l >> 2) & dmask;\r
482 \r
483         for(const char *p=text; *p; p++) {\r
484                 cy = y;\r
485                 charmask = *(mask_numbers + (*p - 0x2F));\r
486 \r
487                 for(l = vidmem+cx+(y-1)*240, le = vidmem+cx+(y+7)*240; l < le; l+=240-4) {\r
488                         *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;\r
489                         *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;\r
490                         *l = (*l >> 2) & dmask;\r
491                 }\r
492 \r
493                 for(i=0; i < 24; i++) {\r
494                         // draw dot. Is this fast?\r
495                         if(charmask&0x80000000) *( vidmem + (cx+(i&3)) + (cy+(i>>2))*240 ) = color;\r
496                         charmask <<= 1;\r
497                 }\r
498                 cx += 5;\r
499         }\r
500 }\r
501 \r
502 // draws rect with width - 1 and height - 1\r
503 static void drawRect(const TRect &rc, unsigned short color)\r
504 {\r
505         unsigned short *vidmem=(unsigned short *)PicoDraw2FB;\r
506 \r
507         if(rc.iTl.iX - rc.iBr.iX && rc.iTl.iY - rc.iBr.iY) {\r
508                 int stepX = rc.iTl.iX < rc.iBr.iX ? 1 : -1;\r
509                 int stepY = rc.iTl.iY < rc.iBr.iY ? 1 : -1;\r
510                 \r
511                 for(int x = rc.iTl.iX;; x += stepX) {\r
512                         *(vidmem + rc.iTl.iY*240 + x) = *(vidmem + (rc.iBr.iY - stepY)*240 + x) = color;\r
513                         if(x == rc.iBr.iX - stepX) break;\r
514                 }\r
515                 \r
516                 for(int y = rc.iTl.iY;; y += stepY) {\r
517                         *(vidmem + y*240 + rc.iTl.iX) = *(vidmem + y*240 + rc.iBr.iX - stepX) = color;\r
518                         if(y == rc.iBr.iY - stepY) break;\r
519                 }\r
520         }\r
521 }\r
522 \r
523 // draws fullsize filled rect\r
524 static void drawRectFilled(const TRect rc, unsigned short color)\r
525 {\r
526         unsigned short *vidmem=(unsigned short *)PicoDraw2FB;\r
527 \r
528         if(rc.iTl.iX - rc.iBr.iX && rc.iTl.iY - rc.iBr.iY) {\r
529                 int stepX = rc.iTl.iX < rc.iBr.iX ? 1 : -1;\r
530                 int stepY = rc.iTl.iY < rc.iBr.iY ? 1 : -1;\r
531                 \r
532                 for(int y = rc.iTl.iY;; y += stepY) {\r
533                         for(int x = rc.iTl.iX;; x += stepX) {\r
534                                 *(vidmem + y*240 + x) = *(vidmem + y*240 + x) = color;\r
535                                 if(x == rc.iBr.iX) break;\r
536                         }\r
537                         if(y == rc.iBr.iY) break;\r
538                 }\r
539         }\r
540 }\r
541 \r
542 // direction: -1 left, 1 right\r
543 static void drawArrow0(TPoint p, int direction, unsigned short color)\r
544 {\r
545         unsigned short *vidmem=(unsigned short *)PicoDraw2FB;\r
546         int width = 15;\r
547         int x = p.iX;\r
548         int y = p.iY;\r
549 \r
550         for(; width > 0; x+=direction, y++, width -=2)\r
551                 for(int i=0; i < width; i++)\r
552                         *(vidmem + x + y*240 + i*240) = color;\r
553 }\r
554 \r
555 static char *vidGetScanName(int scan)\r
556 {\r
557         static char buff[32];\r
558 \r
559         if((scan >= '0' && scan <= '9') || (scan >= 'A' && scan <= 'Z')) {\r
560                 buff[0] = (char) scan; buff[1] = 0;\r
561         } else {\r
562                 switch(scan) {\r
563                         case 0x01: strcpy(buff, "BSPACE");   break;\r
564                         case 0x03: strcpy(buff, "OK");       break;\r
565                         case 0x05: strcpy(buff, "SPACE");    break;\r
566                         case 0x0e: strcpy(buff, "AST");      break;\r
567                         case 0x0f: strcpy(buff, "HASH");     break;\r
568                         case 0x12: strcpy(buff, "SHIFT");    break;\r
569                         case 0x19: strcpy(buff, "ALT");      break;\r
570                         case 0x79: strcpy(buff, "PLUS");     break;\r
571                         case 0x7a: strcpy(buff, "DOT");      break;\r
572                         case 0xa5: strcpy(buff, "JOG@UP");   break;\r
573                         case 0xa6: strcpy(buff, "JOG@DOWN"); break;\r
574                         case 0xb5: strcpy(buff, "INET");     break;\r
575                         case 0xd4: strcpy(buff, "JOG@PUSH"); break;\r
576                         case 0xd5: strcpy(buff, "BACK");     break;\r
577                         default:  sprintf(buff, "KEY@%02X", scan); break;\r
578                 }\r
579         }\r
580 \r
581         return buff;\r
582 }\r
583 \r
584 void vidKeyConfigFrame(const TUint whichAction)\r
585 {\r
586         int i;\r
587         char buttonNames[128];\r
588         buttonNames[0] = 0;\r
589         memset(PicoDraw2FB, 0, framebuffsize);\r
590 \r
591         unsigned long currentActCode = 1 << whichAction;\r
592 \r
593         // draw all "buttons" in reverse order\r
594         const TPicoAreaConfigEntry *e = areaConfig + 1; i = 0;\r
595         while(e->rect != TRect(0,0,0,0)) { e++; i++; }\r
596         for(e--, i--; e->rect != TRect(0,0,0,0); e--, i--)\r
597                 drawRect(e->rect, (currentConfig.KeyBinds[i+256] & currentActCode) ? color_red : color_red_dim);\r
598 \r
599         // action name control\r
600         drawRectFilled(TRect(72, 2, 168, 20), color_grey); // 96x14\r
601         drawArrow0(TPoint(80, 3), -1, color_green);\r
602         drawArrow0(TPoint(160, 3), 1, color_green);\r
603 \r
604         drawText0(86, 9, actionNames[whichAction], color_red);\r
605 \r
606         // draw active button names if there are any\r
607         for (i = 0; i < 256; i++) {\r
608                 if (currentConfig.KeyBinds[i] & currentActCode) {\r
609                         if(buttonNames[0]) strcat(buttonNames, ";@");\r
610                         strcat(buttonNames, vidGetScanName(i));\r
611                 }\r
612         }\r
613 \r
614         if (buttonNames[0]) {\r
615                 buttonNames[61] = 0; // only 60 chars fit\r
616                 drawText0(6, 48, buttonNames, color_blue);\r
617         }\r
618 \r
619         vidBlitCfg();\r
620 }\r
621 \r
622 void vidDrawNotice(const char *txt)\r
623 {\r
624         if(PicoDraw2FB) {\r
625                 drawTextNotice(txt);\r
626                 vidBlit(1);\r
627         }\r
628 }\r