renderers (interlace and stuff)
[picodrive.git] / platform / uiq2 / vid.cpp
... / ...
CommitLineData
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
14extern TPicoConfig currentConfig;\r
15extern TPicoKeyConfigEntry *keyConfig;\r
16extern TPicoAreaConfigEntry areaConfig[];\r
17extern const char * actionNames[];\r
18\r
19// main framebuffer\r
20static void *screenbuff = 0; // pointer to real device video memory\r
21//static\r
22unsigned short *framebuff = 0; // temporary buffer in sega native BGR format\r
23const int framebuffsize = (8+320)*(8+208+8)*2; // actual framebuffer size (in bytes+to support new rendering mode)\r
24static int framebuff_offs = 0; // where to start copying (in pixels)\r
25static int framebuff_len = 0; // how much of the framebuffer actually needs to be copied (in pixels)\r
26static int fc_lines, fc_inc; // lines, inc for "0 fit2" mode\r
27\r
28// drawer function pointers\r
29void (*drawTextFps)(const char *text) = 0;\r
30void (*drawTextNotice)(const char *text) = 0;\r
31\r
32// blitter\r
33void (*vidBlit)(int full) = 0;\r
34void (*vidBlitKeyCfg)(int full) = 0;\r
35\r
36// stuff for rendermode2\r
37static unsigned short cram_high[0x40];\r
38static unsigned short dt_dmask=0x0333;\r
39unsigned short color_redM2 = 0x022F;\r
40\r
41// colors\r
42const unsigned short color_red = 0x022F;\r
43const unsigned short color_red_dim = 0x0004;\r
44const unsigned short color_green = 0x01F1;\r
45const unsigned short color_blue = 0x0F11;\r
46const unsigned short color_grey = 0x0222;\r
47\r
48// other\r
49int txtheight_fit = 138;\r
50\r
51// bitmasks\r
52static 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
103inline 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
113int 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
127int 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
162int 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
175int 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
214static 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
271int 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
310int 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
358int 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
402void 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
431void 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
460void 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
488void 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
515void 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
543void 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
549void drawTextFps0(const char *text)\r
550{\r
551 if(!text) return;\r
552 drawText0(176, 216, text, color_red);\r
553}\r
554\r
555void 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
561void drawTextFps90(const char *text)\r
562{\r
563 if(!text) return;\r
564 drawText90(10, 256, text, color_red);\r
565}\r
566\r
567void drawTextFps180(const char *text)\r
568{\r
569 if(!text) return;\r
570 drawText180(32, 8, text, color_red);\r
571}\r
572\r
573void drawTextFps270(const char *text)\r
574{\r
575 if(!text) return;\r
576 drawText270(200, 64, text, color_red);\r
577}\r
578\r
579void drawTextNoticeM2(const char *text)\r
580{\r
581 if(!text) return;\r
582 drawTextM2(20, 200, text, color_redM2);\r
583}\r
584\r
585void drawTextNotice0(const char *text)\r
586{\r
587 if(!text) return;\r
588 drawText0(2, 216, text, color_red);\r
589}\r
590\r
591void 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
597void drawTextNotice90(const char *text)\r
598{\r
599 if(!text) return;\r
600 drawText90(10, 34, text, color_red);\r
601}\r
602\r
603void drawTextNotice180(const char *text)\r
604{\r
605 if(!text) return;\r
606 drawText180(206, 8, text, color_red);\r
607}\r
608\r
609void 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
620void 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
639void 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
656void 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
667void 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
680void 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
702void 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
724void 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
748void 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
781void 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
808void PrepareCramRGB444M2()\r
809{\r
810 vidConvCpyRGB444(cram_high, Pico.cram, 0x40);\r
811}\r
812\r
813void 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
822int 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
937void vidFree()\r
938{\r
939 free(framebuff);\r
940 framebuff = 0;\r
941}\r
942\r
943void 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
953void 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
1004void 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
1011void vidDrawNotice(const char *txt)\r
1012{\r
1013 if(framebuff) {\r
1014 drawTextNotice(txt);\r
1015 vidBlit(1);\r
1016 }\r
1017}\r