improve linux makefile
[picodrive.git] / platform / uiq2 / 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 "ClientServer.h"\r
8 #include "SimpleServer.h"\r
9 #include "pico\picoInt.h"\r
10 #include "blit.h"\r
11 #include "debug.h"\r
12 \r
13 // global stuff\r
14 extern TPicoConfig currentConfig;\r
15 extern TPicoKeyConfigEntry *keyConfig;\r
16 extern TPicoAreaConfigEntry areaConfig[];\r
17 extern const char * actionNames[];\r
18 \r
19 // main framebuffer\r
20 static void *screenbuff = 0; // pointer to real device video memory\r
21 //static\r
22 unsigned short *framebuff = 0;  // temporary buffer in sega native BGR format\r
23 const  int framebuffsize  = (8+320)*(8+208+8)*2; // actual framebuffer size (in bytes+to support new rendering mode)\r
24 static int framebuff_offs = 0; // where to start copying (in pixels)\r
25 static int framebuff_len  = 0; // how much of the framebuffer actually needs to be copied (in pixels)\r
26 static int fc_lines, fc_inc; // lines, inc for "0 fit2" mode\r
27 \r
28 // drawer function pointers\r
29 void (*drawTextFps)(const char *text) = 0;\r
30 void (*drawTextNotice)(const char *text) = 0;\r
31 \r
32 // blitter\r
33 void (*vidBlit)(int full) = 0;\r
34 void (*vidBlitKeyCfg)(int full) = 0;\r
35 \r
36 // stuff for rendermode2\r
37 static unsigned short cram_high[0x40];\r
38 static unsigned short dt_dmask=0x0333;\r
39 unsigned short color_redM2 = 0x022F;\r
40 \r
41 // colors\r
42 const unsigned short color_red     = 0x022F;\r
43 const unsigned short color_red_dim = 0x0004;\r
44 const unsigned short color_green   = 0x01F1;\r
45 const unsigned short color_blue    = 0x0F11;\r
46 const unsigned short color_grey    = 0x0222;\r
47 \r
48 // other\r
49 int txtheight_fit = 138;\r
50 \r
51 // bitmasks\r
52 static const unsigned long mask_numbers[] = {\r
53         0x12244800, // 47 2F /\r
54         0x69999600, // 48 30 0\r
55         0x26222200, // 49 31 1\r
56         0x69168F00, // 50 32 2\r
57         0x69219600, // 51 33 3\r
58         0x266AF200, // 52 34 4\r
59         0xF8E11E00, // 53 35 5\r
60         0x68E99600, // 54 36 6\r
61         0x71222200, // 55 37 7\r
62         0x69699600, // 56 38 8\r
63         0x69719600, // 57 39 9\r
64         0x04004000, // 58 3A :\r
65         0x04004400, // 59 3B ;\r
66         0x01242100, // 60 3C <\r
67         0x00707000, // 61 3D =\r
68         0x04212400, // 62 3E >\r
69         0x69240400, // 63 3F ?\r
70         0x00000000, // 64 40 @ [used instead of space for now]\r
71         0x22579900, // 65 41 A\r
72         0xE9E99E00, // 66 42 B\r
73         0x69889600, // 67 43 C\r
74         0xE9999E00, // 68 44 D\r
75         0xF8E88F00, // 69 45 E\r
76         0xF8E88800, // 70 46 F\r
77         0x698B9700, // 71 47 G\r
78         0x99F99900, // 72 48 H\r
79         0x44444400, // 73 49 I\r
80         0x11119600, // 74 4A J\r
81         0x9ACCA900, // 75 4B K\r
82         0x88888F00, // 76 4C L\r
83         0x9F999900, // 77 4D M\r
84         0x9DDBB900, // 78 4E N\r
85         0x69999600, // 79 4F O\r
86         0xE99E8800, // 80 50 P\r
87         0x6999A500, // 81 51 Q\r
88         0xE99E9900, // 82 52 R\r
89         0x69429600, // 83 53 S\r
90         0x72222200, // 84 54 T\r
91         0x99999600, // 85 55 U\r
92         0x55552200, // 86 56 V\r
93         0x9999F900, // 87 57 W\r
94         0x55225500, // 88 58 X\r
95         0x55222200, // 89 59 Y\r
96         0xF1248F00, // 90 5A Z\r
97 };\r
98 \r
99 \r
100 ////////////////////////////////\r
101 // Cram functions\r
102 \r
103 inline int EmuCramNull(int cram)\r
104 {\r
105   User::Panic(_L("Cram called!!"), 0);\r
106   return cram;\r
107 }\r
108 \r
109 \r
110 ////////////////////////////////\r
111 // PicoScan functions in "center" mode\r
112 \r
113 int EmuScanCenter0(unsigned int num, unsigned short *sdata)\r
114 {\r
115   //unsigned short *vidmem=framebuff;\r
116 \r
117   //unsigned short *sp, *sto;\r
118   //sp=sdata+56; sto=sdata+264; vidmem += num*208;\r
119 \r
120   //do { *vidmem++ = *sp++; } while(sp < sto);\r
121   memcpy(framebuff + num*208, sdata+56, 208*2); // memcpy gives ~1 fps (~2 with optimized memcpy)\r
122 \r
123   return 0;\r
124 }\r
125 \r
126 \r
127 int EmuScanCenter90(unsigned int num, unsigned short *sdata)\r
128 {\r
129   // ignore top and bottom lines\r
130   if(num < 8)   return 7-num;     // skip first 8 lines\r
131   if(num > 215) return 223+8-num; // this should not happen, just in case\r
132 \r
133   num -= 8;\r
134   if(!num) {\r
135         if(Pico.video.reg[12]&1) { // copy less in 32-col mode\r
136           framebuff_offs= 0;\r
137       framebuff_len = 208*320;\r
138         } else {\r
139           framebuff_offs= 208*32;\r
140       framebuff_len = 208*256;\r
141         }\r
142   }\r
143 \r
144   unsigned short *vidmem=framebuff;\r
145   vidmem += 207-num; // adjust x\r
146 \r
147   // do less copy in 32-column mode\r
148   unsigned short *sp, *sto;\r
149   int pixels;\r
150   if(!(Pico.video.reg[12]&1))\r
151        { sp=sdata+32; sto=sdata+288; pixels = 288; vidmem += 32*208; }\r
152   else { sp=sdata;    sto=sdata+320; pixels = 320; }\r
153 \r
154   do { *vidmem = *sp++; vidmem+=208; } while(sp < sto);\r
155 \r
156   if(num == 207) return 16; // skip bottom of this frame and top of next\r
157 \r
158   return 0;\r
159 }\r
160 \r
161 \r
162 int EmuScanCenter180(unsigned int num, unsigned short *sdata)\r
163 {\r
164   unsigned short *vidmem=framebuff;\r
165 \r
166   unsigned short *sp, *sto;\r
167   sp=sdata+56; sto=sdata+264; vidmem += (224-num)*208;\r
168 \r
169   do { *(--vidmem) = *sp++; } while(sp < sto); // reversed\r
170 \r
171   return 0;\r
172 }\r
173 \r
174 \r
175 int EmuScanCenter270(unsigned int num, unsigned short *sdata)\r
176 {\r
177   // ignore top and bottom lines\r
178   if(num < 8)   return 7-num;     // skip first 8 lines\r
179   if(num > 215) return 223-num+8;\r
180 \r
181   num -= 8;\r
182   if(num > 207) return 0;\r
183   if(!num) {\r
184         if(Pico.video.reg[12]&1) {\r
185           framebuff_offs= 0;\r
186       framebuff_len = 208*320;\r
187         } else {\r
188           framebuff_offs= 208*32;\r
189       framebuff_len = 208*256;\r
190         }\r
191   }\r
192 \r
193   unsigned short *vidmem=framebuff+320*208;\r
194   vidmem -= 208-num; // adjust x\r
195 \r
196   // do less copy in 32-column mode\r
197   unsigned short *sp, *sto;\r
198   if(!(Pico.video.reg[12]&1))\r
199        { sp=sdata+32; sto=sdata+288; vidmem -= 32*208; }\r
200   else { sp=sdata;    sto=sdata+320; }\r
201 \r
202   do { *vidmem = *sp++; vidmem-=208; } while(sp < sto);\r
203 \r
204   if(num == 207) return 16; // skip bottom of this frame and top of next\r
205 \r
206   return 0;\r
207 }\r
208 \r
209 \r
210 \r
211 ////////////////////////////////\r
212 // PicoScan functions in "fit" mode\r
213 \r
214 static int EmuScanFit0(unsigned int num, unsigned short *sdata)\r
215 {\r
216   // 0.65, 145 lines in normal mode; 0.8125, 182 lines in 32-column mode\r
217 \r
218   // draw this line? (ARM4s don't support division, so do some tricks here)\r
219   static int u = 0, num2 = 0;\r
220   if(!num) {\r
221     u = num2 = 0;\r
222         if(currentConfig.iScreenMode == TPicoConfig::PMFit) {\r
223       if(Pico.video.reg[12]&1) { // 32 col mode? This can change on any frame\r
224         fc_inc = 6500;\r
225             txtheight_fit = 138;\r
226         framebuff_len = 208*145;\r
227             memset(framebuff+208*145, 0, 208*37*2);\r
228       } else {\r
229         fc_inc = 8125;\r
230             txtheight_fit = 175;\r
231         framebuff_len = 208*182;\r
232       }\r
233         }\r
234   }\r
235   u += fc_inc;\r
236   if(u < 10000) return 0;\r
237   u -= 10000;\r
238 \r
239   unsigned short *vidmem=framebuff;\r
240 \r
241   int slen;\r
242   unsigned short *sp;\r
243   if(!(Pico.video.reg[12]&1))\r
244        { sp=sdata+32; slen=256; }\r
245   else { sp=sdata;    slen=320; }\r
246 \r
247   vidmem += num2*208;\r
248 /*\r
249   int i=0;\r
250   while(sp < sto) {\r
251         i += inc;\r
252     if(i >= 10000) {\r
253           *vidmem++ = *sp;\r
254           i -= 10000;\r
255         }\r
256         sp++;\r
257   }\r
258 */\r
259   PicuShrink(vidmem, 208, sp, slen);\r
260 \r
261   num2++;\r
262 \r
263   // calculate how many lines pico engine should skip,\r
264   // making sure this func will be called on scanline 0\r
265   int skip = 0;\r
266   while(u+fc_inc < 10000 && num+skip != 223) { u+=fc_inc; skip++; }\r
267 \r
268   return skip;\r
269 }\r
270 \r
271 int EmuScanFit90(unsigned int num, unsigned short *sdata)\r
272 {\r
273   // 0.9285\r
274 \r
275   // draw this line?\r
276   static int u = 0, num2 = 0;\r
277   if(!num) {\r
278     u = num2 = 0;\r
279         if(Pico.video.reg[12]&1) {\r
280           framebuff_offs= 0;\r
281       framebuff_len = 208*320;\r
282         } else {\r
283           framebuff_offs= 208*32;\r
284       framebuff_len = 208*256;\r
285         }\r
286   }\r
287   u += 9285;\r
288   if(u < 10000) return 0;\r
289   u -= 10000;\r
290 \r
291   unsigned short *vidmem=framebuff;\r
292   vidmem += 207-num2; // adjust x\r
293 \r
294   // do less copy in 32-column mode\r
295   unsigned short *sp, *sto;\r
296   if(!(Pico.video.reg[12]&1))\r
297        { sp=sdata+32; sto=sdata+288; vidmem += 32*208; }\r
298   else { sp=sdata;    sto=sdata+320; }\r
299 \r
300   do { *vidmem = *sp++; vidmem+=208; } while(sp < sto);\r
301 \r
302   num2++;\r
303 \r
304   // skip next line?\r
305   if(u+9285 < 10000 && num != 223) { u+=9285; return 1; }\r
306 \r
307   return 0;\r
308 }\r
309 \r
310 int EmuScanFit180(unsigned int num, unsigned short *sdata)\r
311 {\r
312   // 0.65, 145 lines in normal mode; 0.8125, 182 lines in 32-column mode\r
313 \r
314   // draw this line? (ARM4s don't support division)\r
315   static int u = 0, num2 = 0;\r
316   if(!num) {\r
317     u = num2 = 0;\r
318         if(currentConfig.iScreenMode == TPicoConfig::PMFit) {\r
319       if(Pico.video.reg[12]&1) { // 32 col mode? This can change on any frame\r
320             fc_lines = 145;\r
321         fc_inc = 6500;\r
322             txtheight_fit = 138;\r
323         framebuff_len = 208*145;\r
324             memset(framebuff+208*145, 0, 208*37*2);\r
325       } else {\r
326         fc_lines = 182;\r
327         fc_inc = 8125;\r
328             txtheight_fit = 175;\r
329         framebuff_len = 208*182;\r
330       }\r
331     }\r
332   }\r
333   u += fc_inc;\r
334   if(u < 10000) return 0;\r
335   u -= 10000;\r
336 \r
337   unsigned short *vidmem=framebuff;\r
338 \r
339   int slen;\r
340   unsigned short *sp;\r
341   if(!(Pico.video.reg[12]&1))\r
342        { sp=sdata+32; slen=256; }\r
343   else { sp=sdata;    slen=320; }\r
344 \r
345   vidmem += (fc_lines-num2)*208;\r
346 \r
347   PicuShrinkReverse(vidmem, 208, sp, slen);\r
348 \r
349   num2++;\r
350 \r
351   // skip some lines?\r
352   int skip = 0;\r
353   while(u+fc_inc < 10000 && num+skip != 223) { u+=fc_inc; skip++; }\r
354 \r
355   return skip;\r
356 }\r
357 \r
358 int EmuScanFit270(unsigned int num, unsigned short *sdata)\r
359 {\r
360   // 0.9285\r
361 \r
362   // draw this line?\r
363   static int u = 0, num2 = 0;\r
364   if(!num) {\r
365     u = num2 = 0;\r
366         if(Pico.video.reg[12]&1) {\r
367           framebuff_offs= 0;\r
368       framebuff_len = 208*320;\r
369         } else {\r
370           framebuff_offs= 208*32;\r
371       framebuff_len = 208*256;\r
372         }\r
373   }\r
374   u += 9285;\r
375   if(u < 10000) return 0;\r
376   u -= 10000;\r
377 \r
378   unsigned short *vidmem=framebuff+320*208;\r
379   vidmem -= 208-num2; // adjust x\r
380 \r
381   // do less copy in 32-column mode\r
382   unsigned short *sp, *sto;\r
383   if(!(Pico.video.reg[12]&1))\r
384        { sp=sdata+32; sto=sdata+288; vidmem -= 32*208; }\r
385   else { sp=sdata;    sto=sdata+320; }\r
386 \r
387   do { *vidmem = *sp++; vidmem-=208; } while(sp < sto);\r
388 \r
389   num2++;\r
390 \r
391   // skip next line?\r
392   if(u+9285 < 10000 && num != 223) { u+=9285; return 1; }\r
393 \r
394   return 0;\r
395 }\r
396 \r
397 \r
398 ////////////////////////////////\r
399 // text drawers\r
400 // warning: text must be at least 1px away from screen borders\r
401 \r
402 void drawTextM2(int x, int y, const char *text, long color)\r
403 {\r
404         unsigned short *vidmem=framebuff;\r
405         int charmask, i, cx = x, cy;\r
406         unsigned short *l, *le;\r
407 \r
408         // darken the background (left border)\r
409         for(l=vidmem+(cx-1)+(y-1)*328, le=vidmem+(cx-1)+(y+7)*328; l < le; l+=328)\r
410                 *l = (*l >> 2) & dt_dmask;\r
411 \r
412         for(const char *p=text; *p; p++) {\r
413                 cy = y;\r
414                 charmask = *(mask_numbers + (*p - 0x2F));\r
415 \r
416                 for(l = vidmem+cx+(y-1)*328, le = vidmem+cx+(y+7)*328; l < le; l+=328-4) {\r
417                         *l = (*l >> 2) & dt_dmask; l++; *l = (*l >> 2) & dt_dmask; l++;\r
418                         *l = (*l >> 2) & dt_dmask; l++; *l = (*l >> 2) & dt_dmask; l++;\r
419                         *l = (*l >> 2) & dt_dmask;\r
420                 }\r
421 \r
422                 for(i=0; i < 24; i++) {\r
423                         // draw dot. Is this fast?\r
424                         if(charmask&0x80000000) *( vidmem + (cx+(i&3)) + (cy+(i>>2))*328 ) = color;\r
425                         charmask <<= 1;\r
426                 }\r
427                 cx += 5;\r
428         }\r
429 }\r
430 \r
431 void drawText0(int x, int y, const char *text, long color)\r
432 {\r
433         unsigned short *vidmem=framebuff;\r
434         int charmask, i, cx = x, cy;\r
435         unsigned short *l, *le, dmask=0x0333;\r
436 \r
437         // darken the background (left border)\r
438         for(l=vidmem+(cx-1)+(y-1)*208, le=vidmem+(cx-1)+(y+7)*208; l < le; l+=208)\r
439                 *l = (*l >> 2) & dmask;\r
440 \r
441         for(const char *p=text; *p; p++) {\r
442                 cy = y;\r
443                 charmask = *(mask_numbers + (*p - 0x2F));\r
444 \r
445                 for(l = vidmem+cx+(y-1)*208, le = vidmem+cx+(y+7)*208; l < le; l+=208-4) {\r
446                         *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;\r
447                         *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;\r
448                         *l = (*l >> 2) & dmask;\r
449                 }\r
450 \r
451                 for(i=0; i < 24; i++) {\r
452                         // draw dot. Is this fast?\r
453                         if(charmask&0x80000000) *( vidmem + (cx+(i&3)) + (cy+(i>>2))*208 ) = color;\r
454                         charmask <<= 1;\r
455                 }\r
456                 cx += 5;\r
457         }\r
458 }\r
459 \r
460 void drawText90(int x, int y, const char *text, long color)\r
461 {\r
462         unsigned short *vidmem=framebuff;\r
463         unsigned short *l, *le, dmask=0x0333;\r
464         int charmask, i, cx, cy = y;\r
465 \r
466         for(l=vidmem+(x+1)+(cy-1)*208, le=vidmem+(x-7)+(cy-1)*208; l > le; l--)\r
467                 *l = (*l >> 2) & dmask;\r
468 \r
469         for(const char *p=text; *p; p++) {\r
470                 cx = x;\r
471                 charmask = *(mask_numbers + (*p - 0x2F));\r
472 \r
473                 for(l = vidmem+(x+1)+(cy)*208, le = vidmem+(x+1)+(cy+5)*208; l < le; l+=208+7) {\r
474                         *l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask; l--;\r
475                         *l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask; l--;\r
476                         *l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask; l--;\r
477                         *l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask;\r
478                 }\r
479 \r
480                 for(i=0; i < 24; i++) {\r
481                         if(charmask&0x80000000) *( vidmem + (cy+(i&3))*208 + (cx-(i>>2)) ) = color;\r
482                         charmask <<= 1;\r
483                 }\r
484                 cy += 5;\r
485         }\r
486 }\r
487 \r
488 void drawText180(int x, int y, const char *text, long color)\r
489 {\r
490         unsigned short *vidmem=framebuff;\r
491         int charmask, i, cx = x, cy;\r
492         unsigned short *l, *le, dmask=0x0333;\r
493 \r
494         for(l=vidmem+(cx+1)+(y+1)*208, le=vidmem+(cx+1)+(y-7)*208; l > le; l-=208)\r
495                 *l = (*l >> 2) & dmask;\r
496 \r
497         for(const char *p=text; *p; p++) {\r
498                 cy = y;\r
499                 charmask = *(mask_numbers + (*p - 0x2F));\r
500 \r
501                 for(l = vidmem+cx+(y+1)*208, le = vidmem+cx+(y-8)*208; l > le; l-=208-4) {\r
502                         *l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask; l--;\r
503                         *l = (*l >> 2) & dmask; l--; *l = (*l >> 2) & dmask; l--;\r
504                         *l = (*l >> 2) & dmask;\r
505                 }\r
506 \r
507                 for(i=0; i < 24; i++) {\r
508                         if(charmask&0x80000000) *( vidmem + (cx-(i&3)) + (cy-(i>>2))*208 ) = color;\r
509                         charmask <<= 1;\r
510                 }\r
511                 cx -= 5;\r
512         }\r
513 }\r
514 \r
515 void drawText270(int x, int y, const char *text, long color)\r
516 {\r
517         unsigned short *vidmem=framebuff;\r
518         int charmask, i, cx, cy = y;\r
519         unsigned short *l, *le, dmask=0x0333;\r
520 \r
521         for(l=vidmem+(x-1)+(cy+1)*208, le=vidmem+(x+7)+(cy+1)*208; l < le; l++)\r
522                 *l = (*l >> 2) & dmask;\r
523 \r
524         for(const char *p=text; *p; p++) {\r
525                 cx = x;\r
526                 charmask = *(mask_numbers + (*p - 0x2F));\r
527 \r
528                 for(l = vidmem+(x-1)+(cy)*208, le = vidmem+(x-1)+(cy-5)*208; l > le; l-=208+7) {\r
529                         *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;\r
530                         *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;\r
531                         *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask; l++;\r
532                         *l = (*l >> 2) & dmask; l++; *l = (*l >> 2) & dmask;\r
533                 }\r
534 \r
535                 for(i=0; i < 24; i++) {\r
536                         if(charmask&0x80000000) *( vidmem + (cy-(i&3))*208 + (cx+(i>>2)) ) = color;\r
537                         charmask <<= 1;\r
538                 }\r
539                 cy -= 5;\r
540         }\r
541 }\r
542 \r
543 void drawTextFpsM2(const char *text)\r
544 {\r
545         if(!text) return;\r
546         drawTextM2((Pico.video.reg[12]&1) ? 256 : 224, 200, text, color_redM2);\r
547 }\r
548 \r
549 void drawTextFps0(const char *text)\r
550 {\r
551         if(!text) return;\r
552         drawText0(176, 216, text, color_red);\r
553 }\r
554 \r
555 void drawTextFpsFit0(const char *text)\r
556 {\r
557         if(!text) return;\r
558         drawText0(176, txtheight_fit, text, color_red);\r
559 }\r
560 \r
561 void drawTextFps90(const char *text)\r
562 {\r
563         if(!text) return;\r
564         drawText90(10, 256, text, color_red);\r
565 }\r
566 \r
567 void drawTextFps180(const char *text)\r
568 {\r
569         if(!text) return;\r
570         drawText180(32, 8, text, color_red);\r
571 }\r
572 \r
573 void drawTextFps270(const char *text)\r
574 {\r
575         if(!text) return;\r
576         drawText270(200, 64, text, color_red);\r
577 }\r
578 \r
579 void drawTextNoticeM2(const char *text)\r
580 {\r
581         if(!text) return;\r
582         drawTextM2(20, 200, text, color_redM2);\r
583 }\r
584 \r
585 void drawTextNotice0(const char *text)\r
586 {\r
587         if(!text) return;\r
588         drawText0(2, 216, text, color_red);\r
589 }\r
590 \r
591 void drawTextNoticeFit0(const char *text)\r
592 {\r
593         if(!text) return;\r
594         drawText0(2, txtheight_fit, text, color_red);\r
595 }\r
596 \r
597 void drawTextNotice90(const char *text)\r
598 {\r
599         if(!text) return;\r
600         drawText90(10, 34, text, color_red);\r
601 }\r
602 \r
603 void drawTextNotice180(const char *text)\r
604 {\r
605         if(!text) return;\r
606         drawText180(206, 8, text, color_red);\r
607 }\r
608 \r
609 void drawTextNotice270(const char *text)\r
610 {\r
611         if(!text) return;\r
612         drawText270(200, 286, text, color_red);\r
613 }\r
614 \r
615 \r
616 ////////////////////////////////\r
617 // misc drawers\r
618 \r
619 // draws rect with width - 1 and height - 1\r
620 void drawRect(const TRect &rc, unsigned short color)\r
621 {\r
622         if(rc.iTl.iX - rc.iBr.iX && rc.iTl.iY - rc.iBr.iY) {\r
623                 int stepX = rc.iTl.iX < rc.iBr.iX ? 1 : -1;\r
624                 int stepY = rc.iTl.iY < rc.iBr.iY ? 1 : -1;\r
625                 \r
626                 for(int x = rc.iTl.iX;; x += stepX) {\r
627                         *(framebuff + rc.iTl.iY*208 + x) = *(framebuff + (rc.iBr.iY - stepY)*208 + x) = color;\r
628                         if(x == rc.iBr.iX - stepX) break;\r
629                 }\r
630                 \r
631                 for(int y = rc.iTl.iY;; y += stepY) {\r
632                         *(framebuff + y*208 + rc.iTl.iX) = *(framebuff + y*208 + rc.iBr.iX - stepX) = color;\r
633                         if(y == rc.iBr.iY - stepY) break;\r
634                 }\r
635         }\r
636 }\r
637 \r
638 // draws fullsize filled rect\r
639 void drawRectFilled(const TRect rc, unsigned short color)\r
640 {\r
641         if(rc.iTl.iX - rc.iBr.iX && rc.iTl.iY - rc.iBr.iY) {\r
642                 int stepX = rc.iTl.iX < rc.iBr.iX ? 1 : -1;\r
643                 int stepY = rc.iTl.iY < rc.iBr.iY ? 1 : -1;\r
644                 \r
645                 for(int y = rc.iTl.iY;; y += stepY) {\r
646                         for(int x = rc.iTl.iX;; x += stepX) {\r
647                                 *(framebuff + y*208 + x) = *(framebuff + y*208 + x) = color;\r
648                                 if(x == rc.iBr.iX) break;\r
649                         }\r
650                         if(y == rc.iBr.iY) break;\r
651                 }\r
652         }\r
653 }\r
654 \r
655 // direction: -1 left, 1 right\r
656 void drawArrow0(TPoint p, int direction, unsigned short color)\r
657 {\r
658         int width = 11;\r
659         int x = p.iX;\r
660         int y = p.iY;\r
661 \r
662         for(; width > 0; x+=direction, y++, width -=2)\r
663                 for(int i=0; i < width; i++)\r
664                         *(framebuff + x + y*208 + i*208) = color;\r
665 }\r
666 \r
667 void drawArrow90(TPoint p, int direction, unsigned short color)\r
668 {\r
669         int width = 11;\r
670         int x = p.iX - width;\r
671         int y = p.iY;\r
672 \r
673         for(; width > 0; x++, y+=direction, width -=2)\r
674                 for(int i=0; i < width; i++)\r
675                         *(framebuff + x + y*208 + i) = color;\r
676 }\r
677 \r
678 \r
679 // copies temporary framebuff to real device framebuffer\r
680 void vidBlitRGB444(int full)\r
681 {\r
682         unsigned short *ps;\r
683         unsigned short *pd;\r
684         int pixels;\r
685         if(full) {\r
686                 ps = framebuff;\r
687                 pd = (unsigned short *) screenbuff;\r
688                 pixels = 208*320;\r
689         } else {\r
690                 ps = framebuff + framebuff_offs;\r
691                 pd = (unsigned short *) screenbuff + framebuff_offs;\r
692                 pixels = framebuff_len;\r
693         }\r
694 \r
695         vidConvCpyRGB444(pd, ps, pixels);\r
696         //for(unsigned short *ps_end = ps + pixels; ps < ps_end; ps++)\r
697                 // Convert 0000bbb0 ggg0rrr0\r
698                 // to      0000rrr0 ggg0bbb0\r
699         //      *pd++ = ((*ps&0x000F)<<8) | (*ps&0x00F0) | ((*ps&0x0F00)>>8);\r
700 }\r
701 \r
702 void vidBlitRGB565(int full)\r
703 {\r
704         unsigned short *ps;\r
705         unsigned short *pd;\r
706         int pixels;\r
707         if(full) {\r
708                 ps = framebuff;\r
709                 pd = (unsigned short *) screenbuff;\r
710                 pixels = 208*320;\r
711         } else {\r
712                 ps = framebuff  + framebuff_offs;\r
713                 pd = (unsigned short *) screenbuff + framebuff_offs;\r
714                 pixels = framebuff_len;\r
715         }\r
716 \r
717         vidConvCpyRGB565(pd, ps, pixels);\r
718         //for(; ps < ps_end; ps++)\r
719                 // Convert 0000bbb0 ggg0rrr0\r
720                 // to      rrr00ggg 000bbb00\r
721         //      *pd++ = ((*ps&0x000F)<<12) | ((*ps&0x00F0)<<3) | ((*ps&0x0F00)>>7);\r
722 }\r
723 \r
724 void vidBlitRGB32(int full)\r
725 {\r
726         unsigned short *ps;\r
727         unsigned long  *pd;\r
728         int pixels;\r
729         if(full) {\r
730                 ps = framebuff;\r
731                 pd = (unsigned long *) screenbuff;\r
732                 pixels = 208*320;\r
733         } else {\r
734                 ps = framebuff  + framebuff_offs;\r
735                 pd = (unsigned long *) screenbuff + framebuff_offs;\r
736                 pixels = framebuff_len;\r
737         }\r
738 \r
739         vidConvCpyRGB32(pd, ps, pixels);\r
740         //for(; ps < ps_end; ps++)\r
741                 // Convert          0000bbb0 ggg0rrr0\r
742                 // to  ..0 rrr00000 ggg00000 bbb00000\r
743         //      *pd++ = ((*ps&0x000F)<<20) | ((*ps&0x00F0)<<8) | ((*ps&0x0F00)>>4);\r
744 }\r
745 \r
746 // -------- rendermode 2 ---------\r
747 \r
748 void vidBlit16M2(int full)\r
749 {\r
750         unsigned short *ps = framebuff+328*8;\r
751         unsigned short *pd = (unsigned short *) screenbuff;\r
752 \r
753         if(currentConfig.iScreenRotation == TPicoConfig::PRot90) {\r
754                 if(Pico.video.reg[12]&1)\r
755                         vidConvCpyM2_16_90(pd, ps, 320/8);\r
756                 else {\r
757                         if(full) memset(pd, 0, 208*32*2);\r
758                         pd += 208*32;\r
759                         vidConvCpyM2_16_90(pd, ps, 256/8);\r
760                         if(full) memset(pd + 208*256, 0, 208*32*2);\r
761                 }\r
762         } else if(currentConfig.iScreenRotation == TPicoConfig::PRot270) {\r
763                 if(Pico.video.reg[12]&1)\r
764                         vidConvCpyM2_16_270(pd, ps, 320/8);\r
765                 else {\r
766                         if(full) memset(pd, 0, 208*32*2);\r
767                         pd += 208*32;\r
768                         ps -= 64;     // the blitter starts copying from the right border, so we need to adjust\r
769                         vidConvCpyM2_16_270(pd, ps, 256/8);\r
770                         if(full) memset(pd + 208*256, 0, 208*32*2);\r
771                 }\r
772         }\r
773 /*\r
774     for(int x=0; x < 320; x++)\r
775                 for(int y=207; y>=0; y--) {\r
776                         *pd++ = *(ps+8+x+y*328);\r
777                 }\r
778 */\r
779 }\r
780 \r
781 void vidBlitRGB32M2(int full)\r
782 {\r
783         unsigned short *ps = framebuff+328*8;\r
784         unsigned long  *pd = (unsigned long *) screenbuff;\r
785 \r
786         if(currentConfig.iScreenRotation == TPicoConfig::PRot90) {\r
787                 if(Pico.video.reg[12]&1)\r
788                         vidConvCpyM2_RGB32_90(pd, ps, 320/8);\r
789                 else {\r
790                         if(full) memset(pd, 0, 208*32*4);\r
791                         pd += 208*32;\r
792                         vidConvCpyM2_RGB32_90(pd, ps, 256/8);\r
793                         if(full) memset(pd + 208*256, 0, 208*32*4);\r
794                 }\r
795         } else if(currentConfig.iScreenRotation == TPicoConfig::PRot270) {\r
796                 if(Pico.video.reg[12]&1)\r
797                         vidConvCpyM2_RGB32_270(pd, ps, 320/8);\r
798                 else {\r
799                         if(full) memset(pd, 0, 208*32*4);\r
800                         pd += 208*32;\r
801                         ps -= 64;     // the blitter starts copying from the right border, so we need to adjust\r
802                         vidConvCpyM2_RGB32_270(pd, ps, 256/8);\r
803                         if(full) memset(pd + 208*256, 0, 208*32*4);\r
804                 }\r
805         }\r
806 }\r
807 \r
808 void PrepareCramRGB444M2()\r
809 {\r
810         vidConvCpyRGB444(cram_high, Pico.cram, 0x40);\r
811 }\r
812 \r
813 void PrepareCramRGB565M2()\r
814 {\r
815         vidConvCpyRGB565(cram_high, Pico.cram, 0x40);\r
816 }\r
817 \r
818 \r
819 ////////////////////////////////\r
820 // main functions\r
821 \r
822 int vidInit(int displayMode, void *vidmem, int p800, int reinit)\r
823 {\r
824         if(!reinit) {\r
825                 // prepare framebuffer\r
826                 screenbuff = (unsigned short *) vidmem;\r
827                 framebuff =  (unsigned short *) malloc(framebuffsize);\r
828 \r
829                 if(!screenbuff) return KErrNotSupported;\r
830                 if(!framebuff)  return KErrNoMemory;\r
831 \r
832                 // Cram function: go and hack Pico so it never gets called\r
833                 PicoCram = EmuCramNull;\r
834         }\r
835 \r
836         // select suitable blitter\r
837         switch(displayMode) {\r
838                 case EColor4K:  vidBlit = vidBlitKeyCfg = vidBlitRGB444; break;\r
839                 case EColor64K: vidBlit = vidBlitKeyCfg = vidBlitRGB565; break;\r
840                 case EColor16M: vidBlit = vidBlitKeyCfg = vidBlitRGB32;  break;\r
841                 default: return KErrNotSupported;\r
842         }\r
843 \r
844         memset(framebuff, 0, framebuffsize);\r
845 \r
846         // rendermode 2?\r
847         if(PicoOpt&0x10) {\r
848                 switch(displayMode) {\r
849                         case EColor4K:\r
850                                 vidBlit = vidBlit16M2;\r
851                                 PicoPrepareCram = PrepareCramRGB444M2;\r
852                                 PicoCramHigh = cram_high;\r
853                                 color_redM2 = 0x0F22;\r
854                                 dt_dmask = 0x0333;\r
855                                 break;\r
856                         case EColor64K:\r
857                                 vidBlit = vidBlit16M2;\r
858                                 PicoPrepareCram = PrepareCramRGB565M2;\r
859                                 PicoCramHigh = cram_high;\r
860                                 color_redM2 = 0xF882;\r
861                                 dt_dmask = 0x39e7;\r
862                                 break;\r
863                         case EColor16M:\r
864                                 vidBlit = vidBlitRGB32M2;\r
865                                 break;\r
866                 }\r
867                 drawTextFps = drawTextFpsM2;\r
868                 drawTextNotice = drawTextNoticeM2;\r
869                 vidBlit(1);\r
870                 return 0;\r
871         }\r
872 \r
873         framebuff_offs = 0;\r
874         framebuff_len  = 208*320;\r
875         vidBlit(1);\r
876 \r
877         // setup all orientation related stuff\r
878         if(currentConfig.iScreenRotation == TPicoConfig::PRot0) {\r
879                 if(currentConfig.iScreenMode == TPicoConfig::PMCenter) {\r
880                         PicoScan = EmuScanCenter0;\r
881                         framebuff_len = 208*224;\r
882                         drawTextFps = drawTextFps0;\r
883                         drawTextNotice = drawTextNotice0;\r
884                 } else {\r
885                         if(currentConfig.iScreenMode == TPicoConfig::PMFit2) {\r
886                                 if(p800) {\r
887                                         fc_inc = 6518; // 0.651786 (144+2)\r
888                                         txtheight_fit = 139;\r
889                                         framebuff_len = 208*146;\r
890                                 } else {\r
891                                         fc_inc = 9286; // 0.92857\r
892                                         txtheight_fit = 201;\r
893                                         framebuff_len = 208*208;\r
894                                 }\r
895                         }\r
896                         PicoScan = EmuScanFit0;\r
897                         drawTextFps = drawTextFpsFit0;\r
898                         drawTextNotice = drawTextNoticeFit0;\r
899                 }\r
900         } else if(currentConfig.iScreenRotation == TPicoConfig::PRot90) {\r
901                 if(currentConfig.iScreenMode == TPicoConfig::PMFit)\r
902                          PicoScan = EmuScanFit90;\r
903                 else PicoScan = EmuScanCenter90;\r
904                 drawTextFps = drawTextFps90;\r
905                 drawTextNotice = drawTextNotice90;\r
906         } else if(currentConfig.iScreenRotation == TPicoConfig::PRot180) {\r
907                 if(currentConfig.iScreenMode == TPicoConfig::PMCenter) {\r
908                         PicoScan = EmuScanCenter180;\r
909                         framebuff_len = 208*224;\r
910                 } else {\r
911                         if(currentConfig.iScreenMode == TPicoConfig::PMFit2) {\r
912                                 if(p800) {\r
913                                         fc_inc = 6518; // 0.651786\r
914                                         fc_lines = 146;\r
915                                         framebuff_len = 208*146;\r
916                                 } else {\r
917                                         fc_inc = 9286; // 0.92857\r
918                                         fc_lines = 208;\r
919                                         framebuff_len = 208*208;\r
920                                 }\r
921                         }\r
922                         PicoScan = EmuScanFit180;\r
923                 }\r
924                 drawTextFps = drawTextFps180;\r
925                 drawTextNotice = drawTextNotice180;\r
926         } else if(currentConfig.iScreenRotation == TPicoConfig::PRot270) {\r
927                 if(currentConfig.iScreenMode == TPicoConfig::PMFit)\r
928                          PicoScan = EmuScanFit270;\r
929                 else PicoScan = EmuScanCenter270;\r
930                 drawTextFps = drawTextFps270;\r
931                 drawTextNotice = drawTextNotice270;\r
932         }\r
933 \r
934         return 0;\r
935 }\r
936 \r
937 void vidFree()\r
938 {\r
939         free(framebuff);\r
940         framebuff = 0;\r
941 }\r
942 \r
943 void vidDrawFrame(char *noticeStr, char *fpsStr, int num)\r
944 {\r
945         PicoFrame();\r
946         if(currentConfig.iFlags & 2)\r
947                 drawTextFps(fpsStr);\r
948         drawTextNotice(noticeStr);\r
949 \r
950         vidBlit(!num); // copy full frame once a second\r
951 }\r
952 \r
953 void vidKeyConfigFrame(const TUint whichAction, TInt flipClosed)\r
954 {\r
955         int i;\r
956         char buttonNames[128];\r
957         buttonNames[0] = 0;\r
958         memset(framebuff, 0, framebuffsize);\r
959 \r
960         unsigned long currentActCode = 1 << whichAction;\r
961 \r
962         if(flipClosed) {\r
963                 drawRectFilled(TRect(56, 2, 152, 16), color_grey); // 96x14\r
964                 drawArrow0(TPoint(64, 3), -1, color_green);\r
965                 drawArrow0(TPoint(144, 3), 1, color_green);\r
966                 drawText0(64, 20, "USE@JOG@TO@SELECT", color_red);\r
967 \r
968                 drawText0(68, 6, actionNames[whichAction], color_red);\r
969         } else {\r
970                 // draw all "buttons" in reverse order\r
971                 const TPicoAreaConfigEntry *e = areaConfig + 1; i = 0;\r
972                 while(e->rect != TRect(0,0,0,0)) { e++; i++; }\r
973                 for(e--, i--; e->rect != TRect(0,0,0,0); e--, i--)\r
974                         drawRect(e->rect, (currentConfig.iAreaBinds[i] & currentActCode) ? color_red : color_red_dim);\r
975         \r
976                 // draw config controls\r
977                 drawRectFilled(TRect(190, 112, 204, 208), color_grey);\r
978                 drawArrow90(TPoint(203, 120), -1, color_green);\r
979                 drawArrow90(TPoint(203, 200),  1, color_green);\r
980 \r
981                 drawText90(200, 124, actionNames[whichAction], color_red);\r
982         }\r
983 \r
984         // draw active button names if there are any\r
985         i = 0;\r
986         for(TPicoKeyConfigEntry *e = keyConfig; e->name; e++, i++)\r
987                 if(currentConfig.iKeyBinds[i] & currentActCode) {\r
988                         if(buttonNames[0]) strcat(buttonNames, ";@");\r
989                         strcat(buttonNames, e->name);\r
990                 }\r
991         if(buttonNames[0]) {\r
992                 if(flipClosed) {\r
993                         buttonNames[41] = 0; // only 61 chars fit\r
994                         drawText0(2, 138, buttonNames, color_blue);\r
995                 } else {\r
996                         buttonNames[61] = 0;\r
997                         drawText90(12, 10, buttonNames, color_blue);\r
998                 }\r
999         }\r
1000 \r
1001         vidBlitKeyCfg(1);\r
1002 }\r
1003 \r
1004 void vidDrawFCconfigDone()\r
1005 {\r
1006         drawText0(64, 20, "USE@JOG@TO@SELECT", 0); // blank prev text\r
1007         drawText0(54, 30, "OPEN@FLIP@TO@CONTINUE", color_red);\r
1008         vidBlitKeyCfg(1);\r
1009 }\r
1010 \r
1011 void vidDrawNotice(const char *txt)\r
1012 {\r
1013         if(framebuff) {\r
1014                 drawTextNotice(txt);\r
1015                 vidBlit(1);\r
1016         }\r
1017 }\r