diff options
author | Jens Arnold <amiconn@rockbox.org> | 2008-03-09 23:52:59 +0000 |
---|---|---|
committer | Jens Arnold <amiconn@rockbox.org> | 2008-03-09 23:52:59 +0000 |
commit | 67481f5fd672bac50ae8fa8eb05b6b13ebe25035 (patch) | |
tree | 01946eaac50fba865c0bdb221cc04cdeb2b75143 | |
parent | afd5c6a03f7b95db6d43f78b515901e74ccf15da (diff) | |
download | rockbox-67481f5fd672bac50ae8fa8eb05b6b13ebe25035.tar.gz rockbox-67481f5fd672bac50ae8fa8eb05b6b13ebe25035.zip |
First step towards the iAudio M3 port: Make the 2bit vertically interleaved LCD driver code usable for main or remote. The M3 remote will be treated as the main LCD.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16598 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | firmware/drivers/lcd-2bit-vi.c | 1243 | ||||
-rw-r--r-- | firmware/drivers/lcd-remote-2bit-vi.c | 1235 |
2 files changed, 1249 insertions, 1229 deletions
diff --git a/firmware/drivers/lcd-2bit-vi.c b/firmware/drivers/lcd-2bit-vi.c new file mode 100644 index 0000000000..d0ef79bcd8 --- /dev/null +++ b/firmware/drivers/lcd-2bit-vi.c | |||
@@ -0,0 +1,1243 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 Jens Arnold | ||
11 | * | ||
12 | * Rockbox driver for 2bit vertically interleaved LCDs | ||
13 | * | ||
14 | * All files in this archive are subject to the GNU General Public License. | ||
15 | * See the file COPYING in the source tree root for full license agreement. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include "config.h" | ||
23 | |||
24 | #include "lcd.h" | ||
25 | #include "kernel.h" | ||
26 | #include "thread.h" | ||
27 | #include <string.h> | ||
28 | #include <stdlib.h> | ||
29 | #include "memory.h" | ||
30 | #include "file.h" | ||
31 | #include "debug.h" | ||
32 | #include "system.h" | ||
33 | #include "font.h" | ||
34 | #include "rbunicode.h" | ||
35 | #include "bidi.h" | ||
36 | #include "scroll_engine.h" | ||
37 | |||
38 | #ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */ | ||
39 | #define LCDFN(fn) lcd_ ## fn | ||
40 | #define FBFN(fn) fb_ ## fn | ||
41 | #define LCDM(ma) LCD_ ## ma | ||
42 | #define MAIN_LCD | ||
43 | #endif | ||
44 | |||
45 | /*** globals ***/ | ||
46 | |||
47 | FBFN(data) LCDFN(framebuffer)[LCDM(FBHEIGHT)][LCDM(FBWIDTH)] IBSS_ATTR; | ||
48 | |||
49 | static const FBFN(data) patterns[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000}; | ||
50 | |||
51 | static FBFN(data) *backdrop = NULL; | ||
52 | static long backdrop_offset IDATA_ATTR = 0; | ||
53 | |||
54 | static struct viewport default_vp = | ||
55 | { | ||
56 | .x = 0, | ||
57 | .y = 0, | ||
58 | .width = LCDM(WIDTH), | ||
59 | .height = LCDM(HEIGHT), | ||
60 | .font = FONT_SYSFIXED, | ||
61 | .drawmode = DRMODE_SOLID, | ||
62 | .xmargin = 0, | ||
63 | .ymargin = 0, | ||
64 | .fg_pattern = LCDM(DEFAULT_FG), | ||
65 | .bg_pattern = LCDM(DEFAULT_BG) | ||
66 | }; | ||
67 | |||
68 | static struct viewport IDATA_ATTR *current_vp = &default_vp; | ||
69 | |||
70 | static unsigned fg_pattern IBSS_ATTR; | ||
71 | static unsigned bg_pattern IBSS_ATTR; | ||
72 | |||
73 | /*** Viewports ***/ | ||
74 | |||
75 | void LCDFN(set_viewport)(struct viewport* vp) | ||
76 | { | ||
77 | if (vp == NULL) | ||
78 | current_vp = &default_vp; | ||
79 | else | ||
80 | current_vp = vp; | ||
81 | |||
82 | fg_pattern = patterns[current_vp->fg_pattern & 3]; | ||
83 | bg_pattern = patterns[current_vp->bg_pattern & 3]; | ||
84 | } | ||
85 | |||
86 | void LCDFN(update_viewport)(void) | ||
87 | { | ||
88 | LCDFN(update_rect)(current_vp->x, current_vp->y, | ||
89 | current_vp->width, current_vp->height); | ||
90 | } | ||
91 | |||
92 | void LCDFN(update_viewport_rect)(int x, int y, int width, int height) | ||
93 | { | ||
94 | LCDFN(update_rect)(current_vp->x + x, current_vp->y + y, width, height); | ||
95 | } | ||
96 | |||
97 | /* LCD init */ | ||
98 | void LCDFN(init)(void) | ||
99 | { | ||
100 | LCDFN(clear_display)(); | ||
101 | #ifndef SIMULATOR | ||
102 | LCDFN(init_device)(); | ||
103 | #endif | ||
104 | #ifdef MAIN_LCD | ||
105 | scroll_init(); | ||
106 | #endif | ||
107 | } | ||
108 | |||
109 | /*** parameter handling ***/ | ||
110 | |||
111 | #if !defined(MAIN_LCD) && defined(HAVE_LCD_COLOR) | ||
112 | /* When compiling for remote LCD and the main LCD is colour. */ | ||
113 | unsigned lcd_remote_color_to_native(unsigned color) | ||
114 | { | ||
115 | unsigned r = (color & 0xf800) >> 10; | ||
116 | unsigned g = (color & 0x07e0) >> 5; | ||
117 | unsigned b = (color & 0x001f) << 2; | ||
118 | /* | ||
119 | * |R| | ||
120 | * |Y'| = |0.299000 0.587000 0.114000| |G| | ||
121 | * |B| | ||
122 | */ | ||
123 | return (5*r + 9*g + b) >> 8; | ||
124 | } | ||
125 | #endif | ||
126 | |||
127 | void LCDFN(set_drawmode)(int mode) | ||
128 | { | ||
129 | current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); | ||
130 | } | ||
131 | |||
132 | int LCDFN(get_drawmode)(void) | ||
133 | { | ||
134 | return current_vp->drawmode; | ||
135 | } | ||
136 | |||
137 | void LCDFN(set_foreground)(unsigned brightness) | ||
138 | { | ||
139 | current_vp->fg_pattern = brightness; | ||
140 | fg_pattern = patterns[brightness & 3]; | ||
141 | } | ||
142 | |||
143 | unsigned LCDFN(get_foreground)(void) | ||
144 | { | ||
145 | return current_vp->fg_pattern; | ||
146 | } | ||
147 | |||
148 | void LCDFN(set_background)(unsigned brightness) | ||
149 | { | ||
150 | current_vp->bg_pattern = brightness; | ||
151 | bg_pattern = patterns[brightness & 3]; | ||
152 | } | ||
153 | |||
154 | unsigned LCDFN(get_background)(void) | ||
155 | { | ||
156 | return current_vp->bg_pattern; | ||
157 | } | ||
158 | |||
159 | void LCDFN(set_drawinfo)(int mode, unsigned fg_brightness, | ||
160 | unsigned bg_brightness) | ||
161 | { | ||
162 | LCDFN(set_drawmode)(mode); | ||
163 | LCDFN(set_foreground)(fg_brightness); | ||
164 | LCDFN(set_background)(bg_brightness); | ||
165 | } | ||
166 | |||
167 | int LCDFN(getwidth)(void) | ||
168 | { | ||
169 | return current_vp->width; | ||
170 | } | ||
171 | |||
172 | int LCDFN(getheight)(void) | ||
173 | { | ||
174 | return current_vp->height; | ||
175 | } | ||
176 | |||
177 | void LCDFN(setmargins)(int x, int y) | ||
178 | { | ||
179 | current_vp->xmargin = x; | ||
180 | current_vp->ymargin = y; | ||
181 | } | ||
182 | |||
183 | int LCDFN(getxmargin)(void) | ||
184 | { | ||
185 | return current_vp->xmargin; | ||
186 | } | ||
187 | |||
188 | int LCDFN(getymargin)(void) | ||
189 | { | ||
190 | return current_vp->ymargin; | ||
191 | } | ||
192 | |||
193 | void LCDFN(setfont)(int newfont) | ||
194 | { | ||
195 | current_vp->font = newfont; | ||
196 | } | ||
197 | |||
198 | int LCDFN(getfont)(void) | ||
199 | { | ||
200 | return current_vp->font; | ||
201 | } | ||
202 | |||
203 | int LCDFN(getstringsize)(const unsigned char *str, int *w, int *h) | ||
204 | { | ||
205 | return font_getstringsize(str, w, h, current_vp->font); | ||
206 | } | ||
207 | |||
208 | /*** low-level drawing functions ***/ | ||
209 | |||
210 | static void setpixel(int x, int y) | ||
211 | { | ||
212 | unsigned mask = 0x0101 << (y & 7); | ||
213 | FBFN(data) *address = &LCDFN(framebuffer)[y>>3][x]; | ||
214 | unsigned data = *address; | ||
215 | |||
216 | *address = data ^ ((data ^ fg_pattern) & mask); | ||
217 | } | ||
218 | |||
219 | static void clearpixel(int x, int y) | ||
220 | { | ||
221 | unsigned mask = 0x0101 << (y & 7); | ||
222 | FBFN(data) *address = &LCDFN(framebuffer)[y>>3][x]; | ||
223 | unsigned data = *address; | ||
224 | |||
225 | *address = data ^ ((data ^ bg_pattern) & mask); | ||
226 | } | ||
227 | |||
228 | static void clearimgpixel(int x, int y) | ||
229 | { | ||
230 | unsigned mask = 0x0101 << (y & 7); | ||
231 | FBFN(data) *address = &LCDFN(framebuffer)[y>>3][x]; | ||
232 | unsigned data = *address; | ||
233 | |||
234 | *address = data ^ ((data ^ *(FBFN(data) *)((long)address | ||
235 | + backdrop_offset)) & mask); | ||
236 | } | ||
237 | |||
238 | static void flippixel(int x, int y) | ||
239 | { | ||
240 | unsigned mask = 0x0101 << (y & 7); | ||
241 | FBFN(data) *address = &LCDFN(framebuffer)[y>>3][x]; | ||
242 | |||
243 | *address ^= mask; | ||
244 | } | ||
245 | |||
246 | static void nopixel(int x, int y) | ||
247 | { | ||
248 | (void)x; | ||
249 | (void)y; | ||
250 | } | ||
251 | |||
252 | LCDFN(pixelfunc_type)* const LCDFN(pixelfuncs_bgcolor)[8] = { | ||
253 | flippixel, nopixel, setpixel, setpixel, | ||
254 | nopixel, clearpixel, nopixel, clearpixel | ||
255 | }; | ||
256 | |||
257 | LCDFN(pixelfunc_type)* const LCDFN(pixelfuncs_backdrop)[8] = { | ||
258 | flippixel, nopixel, setpixel, setpixel, | ||
259 | nopixel, clearimgpixel, nopixel, clearimgpixel | ||
260 | }; | ||
261 | |||
262 | LCDFN(pixelfunc_type)* const *LCDFN(pixelfuncs) = LCDFN(pixelfuncs_bgcolor); | ||
263 | |||
264 | /* 'mask' and 'bits' contain 2 bits per pixel */ | ||
265 | static void ICODE_ATTR flipblock(FBFN(data) *address, unsigned mask, | ||
266 | unsigned bits) | ||
267 | { | ||
268 | *address ^= bits & mask; | ||
269 | } | ||
270 | |||
271 | static void ICODE_ATTR bgblock(FBFN(data) *address, unsigned mask, | ||
272 | unsigned bits) | ||
273 | { | ||
274 | unsigned data = *address; | ||
275 | |||
276 | *address = data ^ ((data ^ bg_pattern) & mask & ~bits); | ||
277 | } | ||
278 | |||
279 | static void ICODE_ATTR bgimgblock(FBFN(data) *address, unsigned mask, | ||
280 | unsigned bits) | ||
281 | { | ||
282 | unsigned data = *address; | ||
283 | |||
284 | *address = data ^ ((data ^ *(FBFN(data) *)((long)address | ||
285 | + backdrop_offset)) & mask & ~bits); | ||
286 | } | ||
287 | |||
288 | static void ICODE_ATTR fgblock(FBFN(data) *address, unsigned mask, | ||
289 | unsigned bits) | ||
290 | { | ||
291 | unsigned data = *address; | ||
292 | |||
293 | *address = data ^ ((data ^ fg_pattern) & mask & bits); | ||
294 | } | ||
295 | |||
296 | static void ICODE_ATTR solidblock(FBFN(data) *address, unsigned mask, | ||
297 | unsigned bits) | ||
298 | { | ||
299 | unsigned data = *address; | ||
300 | unsigned bgp = bg_pattern; | ||
301 | |||
302 | bits = bgp ^ ((bgp ^ fg_pattern) & bits); | ||
303 | *address = data ^ ((data ^ bits) & mask); | ||
304 | } | ||
305 | |||
306 | static void ICODE_ATTR solidimgblock(FBFN(data) *address, unsigned mask, | ||
307 | unsigned bits) | ||
308 | { | ||
309 | unsigned data = *address; | ||
310 | unsigned bgp = *(FBFN(data) *)((long)address + backdrop_offset); | ||
311 | |||
312 | bits = bgp ^ ((bgp ^ fg_pattern) & bits); | ||
313 | *address = data ^ ((data ^ bits) & mask); | ||
314 | } | ||
315 | |||
316 | static void ICODE_ATTR flipinvblock(FBFN(data) *address, unsigned mask, | ||
317 | unsigned bits) | ||
318 | { | ||
319 | *address ^= ~bits & mask; | ||
320 | } | ||
321 | |||
322 | static void ICODE_ATTR bginvblock(FBFN(data) *address, unsigned mask, | ||
323 | unsigned bits) | ||
324 | { | ||
325 | unsigned data = *address; | ||
326 | |||
327 | *address = data ^ ((data ^ bg_pattern) & mask & bits); | ||
328 | } | ||
329 | |||
330 | static void ICODE_ATTR bgimginvblock(FBFN(data) *address, unsigned mask, | ||
331 | unsigned bits) | ||
332 | { | ||
333 | unsigned data = *address; | ||
334 | |||
335 | *address = data ^ ((data ^ *(FBFN(data) *)((long)address | ||
336 | + backdrop_offset)) & mask & bits); | ||
337 | } | ||
338 | |||
339 | static void ICODE_ATTR fginvblock(FBFN(data) *address, unsigned mask, | ||
340 | unsigned bits) | ||
341 | { | ||
342 | unsigned data = *address; | ||
343 | |||
344 | *address = data ^ ((data ^ fg_pattern) & mask & ~bits); | ||
345 | } | ||
346 | |||
347 | static void ICODE_ATTR solidinvblock(FBFN(data) *address, unsigned mask, | ||
348 | unsigned bits) | ||
349 | { | ||
350 | unsigned data = *address; | ||
351 | unsigned fgp = fg_pattern; | ||
352 | |||
353 | bits = fgp ^ ((fgp ^ bg_pattern) & bits); | ||
354 | *address = data ^ ((data ^ bits) & mask); | ||
355 | } | ||
356 | |||
357 | static void ICODE_ATTR solidimginvblock(FBFN(data) *address, unsigned mask, | ||
358 | unsigned bits) | ||
359 | { | ||
360 | unsigned data = *address; | ||
361 | unsigned fgp = fg_pattern; | ||
362 | |||
363 | bits = fgp ^ ((fgp ^ *(FBFN(data) *)((long)address | ||
364 | + backdrop_offset)) & bits); | ||
365 | *address = data ^ ((data ^ bits) & mask); | ||
366 | } | ||
367 | |||
368 | LCDFN(blockfunc_type)* const LCDFN(blockfuncs_bgcolor)[8] = { | ||
369 | flipblock, bgblock, fgblock, solidblock, | ||
370 | flipinvblock, bginvblock, fginvblock, solidinvblock | ||
371 | }; | ||
372 | |||
373 | LCDFN(blockfunc_type)* const LCDFN(blockfuncs_backdrop)[8] = { | ||
374 | flipblock, bgimgblock, fgblock, solidimgblock, | ||
375 | flipinvblock, bgimginvblock, fginvblock, solidimginvblock | ||
376 | }; | ||
377 | |||
378 | LCDFN(blockfunc_type)* const *LCDFN(blockfuncs) = LCDFN(blockfuncs_bgcolor); | ||
379 | |||
380 | |||
381 | void LCDFN(set_backdrop)(FBFN(data) *bd) | ||
382 | { | ||
383 | backdrop = bd; | ||
384 | if (bd) | ||
385 | { | ||
386 | backdrop_offset = (long)bd - (long)LCDFN(framebuffer); | ||
387 | LCDFN(pixelfuncs) = LCDFN(pixelfuncs_backdrop); | ||
388 | LCDFN(blockfuncs) = LCDFN(blockfuncs_backdrop); | ||
389 | } | ||
390 | else | ||
391 | { | ||
392 | backdrop_offset = 0; | ||
393 | LCDFN(pixelfuncs) = LCDFN(pixelfuncs_bgcolor); | ||
394 | LCDFN(blockfuncs) = LCDFN(blockfuncs_bgcolor); | ||
395 | } | ||
396 | } | ||
397 | |||
398 | FBFN(data)* LCDFN(get_backdrop)(void) | ||
399 | { | ||
400 | return backdrop; | ||
401 | } | ||
402 | |||
403 | static inline void setblock(FBFN(data) *address, unsigned mask, unsigned bits) | ||
404 | { | ||
405 | unsigned data = *address; | ||
406 | |||
407 | bits ^= data; | ||
408 | *address = data ^ (bits & mask); | ||
409 | } | ||
410 | |||
411 | /*** drawing functions ***/ | ||
412 | |||
413 | /* Clear the whole display */ | ||
414 | void LCDFN(clear_display)(void) | ||
415 | { | ||
416 | if (default_vp.drawmode & DRMODE_INVERSEVID) | ||
417 | { | ||
418 | memset(LCDFN(framebuffer), patterns[default_vp.fg_pattern & 3], | ||
419 | sizeof LCDFN(framebuffer)); | ||
420 | } | ||
421 | else | ||
422 | { | ||
423 | if (backdrop) | ||
424 | memcpy(LCDFN(framebuffer), backdrop, sizeof LCDFN(framebuffer)); | ||
425 | else | ||
426 | memset(LCDFN(framebuffer), patterns[default_vp.bg_pattern & 3], | ||
427 | sizeof LCDFN(framebuffer)); | ||
428 | } | ||
429 | |||
430 | LCDFN(scroll_info).lines = 0; | ||
431 | } | ||
432 | |||
433 | /* Clear the current viewport */ | ||
434 | void LCDFN(clear_viewport)(void) | ||
435 | { | ||
436 | int lastmode; | ||
437 | |||
438 | if (current_vp == &default_vp) | ||
439 | { | ||
440 | LCDFN(clear_display)(); | ||
441 | } | ||
442 | else | ||
443 | { | ||
444 | lastmode = current_vp->drawmode; | ||
445 | |||
446 | /* Invert the INVERSEVID bit and set basic mode to SOLID */ | ||
447 | current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) | | ||
448 | DRMODE_SOLID; | ||
449 | |||
450 | LCDFN(fillrect)(0, 0, current_vp->width, current_vp->height); | ||
451 | |||
452 | current_vp->drawmode = lastmode; | ||
453 | |||
454 | LCDFN(scroll_stop)(current_vp); | ||
455 | } | ||
456 | } | ||
457 | |||
458 | /* Set a single pixel */ | ||
459 | void LCDFN(drawpixel)(int x, int y) | ||
460 | { | ||
461 | if (((unsigned)x < (unsigned)current_vp->width) && | ||
462 | ((unsigned)y < (unsigned)current_vp->height)) | ||
463 | LCDFN(pixelfuncs)[current_vp->drawmode](current_vp->x+x, current_vp->y+y); | ||
464 | } | ||
465 | |||
466 | /* Draw a line */ | ||
467 | void LCDFN(drawline)(int x1, int y1, int x2, int y2) | ||
468 | { | ||
469 | int numpixels; | ||
470 | int i; | ||
471 | int deltax, deltay; | ||
472 | int d, dinc1, dinc2; | ||
473 | int x, xinc1, xinc2; | ||
474 | int y, yinc1, yinc2; | ||
475 | LCDFN(pixelfunc_type) *pfunc = LCDFN(pixelfuncs)[current_vp->drawmode]; | ||
476 | |||
477 | deltax = abs(x2 - x1); | ||
478 | deltay = abs(y2 - y1); | ||
479 | xinc2 = 1; | ||
480 | yinc2 = 1; | ||
481 | |||
482 | if (deltax >= deltay) | ||
483 | { | ||
484 | numpixels = deltax; | ||
485 | d = 2 * deltay - deltax; | ||
486 | dinc1 = deltay * 2; | ||
487 | dinc2 = (deltay - deltax) * 2; | ||
488 | xinc1 = 1; | ||
489 | yinc1 = 0; | ||
490 | } | ||
491 | else | ||
492 | { | ||
493 | numpixels = deltay; | ||
494 | d = 2 * deltax - deltay; | ||
495 | dinc1 = deltax * 2; | ||
496 | dinc2 = (deltax - deltay) * 2; | ||
497 | xinc1 = 0; | ||
498 | yinc1 = 1; | ||
499 | } | ||
500 | numpixels++; /* include endpoints */ | ||
501 | |||
502 | if (x1 > x2) | ||
503 | { | ||
504 | xinc1 = -xinc1; | ||
505 | xinc2 = -xinc2; | ||
506 | } | ||
507 | |||
508 | if (y1 > y2) | ||
509 | { | ||
510 | yinc1 = -yinc1; | ||
511 | yinc2 = -yinc2; | ||
512 | } | ||
513 | |||
514 | x = x1; | ||
515 | y = y1; | ||
516 | |||
517 | for (i = 0; i < numpixels; i++) | ||
518 | { | ||
519 | if (((unsigned)x < (unsigned)current_vp->width) && | ||
520 | ((unsigned)y < (unsigned)current_vp->height)) | ||
521 | pfunc(current_vp->x + x, current_vp->y + y); | ||
522 | |||
523 | if (d < 0) | ||
524 | { | ||
525 | d += dinc1; | ||
526 | x += xinc1; | ||
527 | y += yinc1; | ||
528 | } | ||
529 | else | ||
530 | { | ||
531 | d += dinc2; | ||
532 | x += xinc2; | ||
533 | y += yinc2; | ||
534 | } | ||
535 | } | ||
536 | } | ||
537 | |||
538 | /* Draw a horizontal line (optimised) */ | ||
539 | void LCDFN(hline)(int x1, int x2, int y) | ||
540 | { | ||
541 | int x; | ||
542 | int width; | ||
543 | FBFN(data) *dst, *dst_end; | ||
544 | unsigned mask; | ||
545 | LCDFN(blockfunc_type) *bfunc; | ||
546 | |||
547 | /* direction flip */ | ||
548 | if (x2 < x1) | ||
549 | { | ||
550 | x = x1; | ||
551 | x1 = x2; | ||
552 | x2 = x; | ||
553 | } | ||
554 | |||
555 | /* nothing to draw? */ | ||
556 | if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width) | ||
557 | || (x2 < 0)) | ||
558 | return; | ||
559 | |||
560 | /* clipping */ | ||
561 | if (x1 < 0) | ||
562 | x1 = 0; | ||
563 | if (x2 >= current_vp->width) | ||
564 | x2 = current_vp->width-1; | ||
565 | |||
566 | width = x2 - x1 + 1; | ||
567 | |||
568 | /* adjust x1 and y to viewport */ | ||
569 | x1 += current_vp->x; | ||
570 | y += current_vp->y; | ||
571 | |||
572 | bfunc = LCDFN(blockfuncs)[current_vp->drawmode]; | ||
573 | dst = &LCDFN(framebuffer)[y>>3][x1]; | ||
574 | mask = 0x0101 << (y & 7); | ||
575 | |||
576 | dst_end = dst + width; | ||
577 | do | ||
578 | bfunc(dst++, mask, 0xFFFFu); | ||
579 | while (dst < dst_end); | ||
580 | } | ||
581 | |||
582 | /* Draw a vertical line (optimised) */ | ||
583 | void LCDFN(vline)(int x, int y1, int y2) | ||
584 | { | ||
585 | int ny; | ||
586 | FBFN(data) *dst; | ||
587 | unsigned mask, mask_bottom; | ||
588 | LCDFN(blockfunc_type) *bfunc; | ||
589 | |||
590 | /* direction flip */ | ||
591 | if (y2 < y1) | ||
592 | { | ||
593 | ny = y1; | ||
594 | y1 = y2; | ||
595 | y2 = ny; | ||
596 | } | ||
597 | |||
598 | /* nothing to draw? */ | ||
599 | if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height) | ||
600 | || (y2 < 0)) | ||
601 | return; | ||
602 | |||
603 | /* clipping */ | ||
604 | if (y1 < 0) | ||
605 | y1 = 0; | ||
606 | if (y2 >= current_vp->height) | ||
607 | y2 = current_vp->height-1; | ||
608 | |||
609 | /* adjust for viewport */ | ||
610 | y1 += current_vp->y; | ||
611 | y2 += current_vp->y; | ||
612 | x += current_vp->x; | ||
613 | |||
614 | bfunc = LCDFN(blockfuncs)[current_vp->drawmode]; | ||
615 | dst = &LCDFN(framebuffer)[y1>>3][x]; | ||
616 | ny = y2 - (y1 & ~7); | ||
617 | mask = (0xFFu << (y1 & 7)) & 0xFFu; | ||
618 | mask |= mask << 8; | ||
619 | mask_bottom = 0xFFu >> (~ny & 7); | ||
620 | mask_bottom |= mask_bottom << 8; | ||
621 | |||
622 | for (; ny >= 8; ny -= 8) | ||
623 | { | ||
624 | bfunc(dst, mask, 0xFFFFu); | ||
625 | dst += LCDM(WIDTH); | ||
626 | mask = 0xFFFFu; | ||
627 | } | ||
628 | mask &= mask_bottom; | ||
629 | bfunc(dst, mask, 0xFFFFu); | ||
630 | } | ||
631 | |||
632 | /* Draw a rectangular box */ | ||
633 | void LCDFN(drawrect)(int x, int y, int width, int height) | ||
634 | { | ||
635 | if ((width <= 0) || (height <= 0)) | ||
636 | return; | ||
637 | |||
638 | int x2 = x + width - 1; | ||
639 | int y2 = y + height - 1; | ||
640 | |||
641 | LCDFN(vline)(x, y, y2); | ||
642 | LCDFN(vline)(x2, y, y2); | ||
643 | LCDFN(hline)(x, x2, y); | ||
644 | LCDFN(hline)(x, x2, y2); | ||
645 | } | ||
646 | |||
647 | /* Fill a rectangular area */ | ||
648 | void LCDFN(fillrect)(int x, int y, int width, int height) | ||
649 | { | ||
650 | int ny; | ||
651 | FBFN(data) *dst, *dst_end; | ||
652 | unsigned mask, mask_bottom; | ||
653 | unsigned bits = 0; | ||
654 | LCDFN(blockfunc_type) *bfunc; | ||
655 | bool fillopt = false; | ||
656 | |||
657 | /* nothing to draw? */ | ||
658 | if ((width <= 0) || (height <= 0) || (x >= current_vp->width) | ||
659 | || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) | ||
660 | return; | ||
661 | |||
662 | /* clipping */ | ||
663 | if (x < 0) | ||
664 | { | ||
665 | width += x; | ||
666 | x = 0; | ||
667 | } | ||
668 | if (y < 0) | ||
669 | { | ||
670 | height += y; | ||
671 | y = 0; | ||
672 | } | ||
673 | if (x + width > current_vp->width) | ||
674 | width = current_vp->width - x; | ||
675 | if (y + height > current_vp->height) | ||
676 | height = current_vp->height - y; | ||
677 | |||
678 | /* adjust for viewport */ | ||
679 | x += current_vp->x; | ||
680 | y += current_vp->y; | ||
681 | |||
682 | if (current_vp->drawmode & DRMODE_INVERSEVID) | ||
683 | { | ||
684 | if ((current_vp->drawmode & DRMODE_BG) && !backdrop) | ||
685 | { | ||
686 | fillopt = true; | ||
687 | bits = bg_pattern; | ||
688 | } | ||
689 | } | ||
690 | else | ||
691 | { | ||
692 | if (current_vp->drawmode & DRMODE_FG) | ||
693 | { | ||
694 | fillopt = true; | ||
695 | bits = fg_pattern; | ||
696 | } | ||
697 | } | ||
698 | bfunc = LCDFN(blockfuncs)[current_vp->drawmode]; | ||
699 | dst = &LCDFN(framebuffer)[y>>3][x]; | ||
700 | ny = height - 1 + (y & 7); | ||
701 | mask = (0xFFu << (y & 7)) & 0xFFu; | ||
702 | mask |= mask << 8; | ||
703 | mask_bottom = 0xFFu >> (~ny & 7); | ||
704 | mask_bottom |= mask_bottom << 8; | ||
705 | |||
706 | for (; ny >= 8; ny -= 8) | ||
707 | { | ||
708 | if (fillopt && (mask == 0xFFFFu)) | ||
709 | memset16(dst, bits, width); | ||
710 | else | ||
711 | { | ||
712 | FBFN(data) *dst_row = dst; | ||
713 | |||
714 | dst_end = dst_row + width; | ||
715 | do | ||
716 | bfunc(dst_row++, mask, 0xFFFFu); | ||
717 | while (dst_row < dst_end); | ||
718 | } | ||
719 | |||
720 | dst += LCDM(WIDTH); | ||
721 | mask = 0xFFFFu; | ||
722 | } | ||
723 | mask &= mask_bottom; | ||
724 | |||
725 | if (fillopt && (mask == 0xFFFFu)) | ||
726 | memset16(dst, bits, width); | ||
727 | else | ||
728 | { | ||
729 | dst_end = dst + width; | ||
730 | do | ||
731 | bfunc(dst++, mask, 0xFFFFu); | ||
732 | while (dst < dst_end); | ||
733 | } | ||
734 | } | ||
735 | |||
736 | /* About Rockbox' internal monochrome bitmap format: | ||
737 | * | ||
738 | * A bitmap contains one bit for every pixel that defines if that pixel is | ||
739 | * black (1) or white (0). Bits within a byte are arranged vertically, LSB | ||
740 | * at top. | ||
741 | * The bytes are stored in row-major order, with byte 0 being top left, | ||
742 | * byte 1 2nd from left etc. The first row of bytes defines pixel rows | ||
743 | * 0..7, the second row defines pixel row 8..15 etc. | ||
744 | * | ||
745 | * This is similar to the internal lcd hw format. */ | ||
746 | |||
747 | /* Draw a partial monochrome bitmap */ | ||
748 | void ICODE_ATTR LCDFN(mono_bitmap_part)(const unsigned char *src, int src_x, | ||
749 | int src_y, int stride, int x, int y, | ||
750 | int width, int height) | ||
751 | { | ||
752 | int shift, ny; | ||
753 | FBFN(data) *dst, *dst_end; | ||
754 | unsigned data, mask, mask_bottom; | ||
755 | LCDFN(blockfunc_type) *bfunc; | ||
756 | |||
757 | /* nothing to draw? */ | ||
758 | if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || | ||
759 | (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) | ||
760 | return; | ||
761 | |||
762 | /* clipping */ | ||
763 | if (x < 0) | ||
764 | { | ||
765 | width += x; | ||
766 | src_x -= x; | ||
767 | x = 0; | ||
768 | } | ||
769 | if (y < 0) | ||
770 | { | ||
771 | height += y; | ||
772 | src_y -= y; | ||
773 | y = 0; | ||
774 | } | ||
775 | if (x + width > current_vp->width) | ||
776 | width = current_vp->width - x; | ||
777 | if (y + height > current_vp->height) | ||
778 | height = current_vp->height - y; | ||
779 | |||
780 | /* adjust for viewport */ | ||
781 | x += current_vp->x; | ||
782 | y += current_vp->y; | ||
783 | |||
784 | src += stride * (src_y >> 3) + src_x; /* move starting point */ | ||
785 | src_y &= 7; | ||
786 | y -= src_y; | ||
787 | dst = &LCDFN(framebuffer)[y>>3][x]; | ||
788 | shift = y & 7; | ||
789 | ny = height - 1 + shift + src_y; | ||
790 | |||
791 | bfunc = LCDFN(blockfuncs)[current_vp->drawmode]; | ||
792 | mask = 0xFFu << (shift + src_y); | ||
793 | /* not byte-doubled here because shift+src_y can be > 7 */ | ||
794 | mask_bottom = 0xFFu >> (~ny & 7); | ||
795 | mask_bottom |= mask_bottom << 8; | ||
796 | |||
797 | if (shift == 0) | ||
798 | { | ||
799 | mask &= 0xFFu; | ||
800 | mask |= mask << 8; | ||
801 | |||
802 | for (; ny >= 8; ny -= 8) | ||
803 | { | ||
804 | const unsigned char *src_row = src; | ||
805 | FBFN(data) *dst_row = dst; | ||
806 | |||
807 | dst_end = dst_row + width; | ||
808 | do | ||
809 | { | ||
810 | data = *src_row++; | ||
811 | bfunc(dst_row++, mask, data | (data << 8)); | ||
812 | } | ||
813 | while (dst_row < dst_end); | ||
814 | |||
815 | src += stride; | ||
816 | dst += LCDM(WIDTH); | ||
817 | mask = 0xFFFFu; | ||
818 | } | ||
819 | mask &= mask_bottom; | ||
820 | |||
821 | dst_end = dst + width; | ||
822 | do | ||
823 | { | ||
824 | data = *src++; | ||
825 | bfunc(dst++, mask, data | (data << 8)); | ||
826 | } | ||
827 | while (dst < dst_end); | ||
828 | } | ||
829 | else | ||
830 | { | ||
831 | unsigned ddata; | ||
832 | |||
833 | dst_end = dst + width; | ||
834 | do | ||
835 | { | ||
836 | const unsigned char *src_col = src++; | ||
837 | FBFN(data) *dst_col = dst++; | ||
838 | unsigned mask_col = mask & 0xFFu; | ||
839 | |||
840 | mask_col |= mask_col << 8; | ||
841 | data = 0; | ||
842 | |||
843 | for (y = ny; y >= 8; y -= 8) | ||
844 | { | ||
845 | data |= *src_col << shift; | ||
846 | |||
847 | if (mask_col) | ||
848 | { | ||
849 | ddata = data & 0xFFu; | ||
850 | bfunc(dst_col, mask_col, ddata | (ddata << 8)); | ||
851 | mask_col = 0xFFFFu; | ||
852 | } | ||
853 | else | ||
854 | { | ||
855 | mask_col = (mask >> 8) & 0xFFu; | ||
856 | mask_col |= mask_col << 8; | ||
857 | } | ||
858 | |||
859 | src_col += stride; | ||
860 | dst_col += LCDM(WIDTH); | ||
861 | data >>= 8; | ||
862 | } | ||
863 | data |= *src_col << shift; | ||
864 | mask_col &= mask_bottom; | ||
865 | ddata = data & 0xFFu; | ||
866 | bfunc(dst_col, mask_col, ddata | (ddata << 8)); | ||
867 | } | ||
868 | while (dst < dst_end); | ||
869 | } | ||
870 | } | ||
871 | |||
872 | /* Draw a full monochrome bitmap */ | ||
873 | void LCDFN(mono_bitmap)(const unsigned char *src, int x, int y, int width, | ||
874 | int height) | ||
875 | { | ||
876 | LCDFN(mono_bitmap_part)(src, 0, 0, width, x, y, width, height); | ||
877 | } | ||
878 | |||
879 | /* About Rockbox' internal native bitmap format: | ||
880 | * | ||
881 | * A bitmap contains one bit in each byte of a pair of bytes for every pixel. | ||
882 | * 00 = white, 01 = light grey, 10 = dark grey, 11 = black. Bits within a byte | ||
883 | * are arranged vertically, LSB at top. | ||
884 | * The pairs of bytes are stored as shorts, in row-major order, with word 0 | ||
885 | * being top left, word 1 2nd from left etc. The first row of words defines | ||
886 | * pixel rows 0..7, the second row defines pixel row 8..15 etc. | ||
887 | * | ||
888 | * This is the same as the internal lcd hw format. */ | ||
889 | |||
890 | /* Draw a partial native bitmap */ | ||
891 | void ICODE_ATTR LCDFN(bitmap_part)(const FBFN(data) *src, int src_x, | ||
892 | int src_y, int stride, int x, int y, | ||
893 | int width, int height) | ||
894 | { | ||
895 | int shift, ny; | ||
896 | FBFN(data) *dst, *dst_end; | ||
897 | unsigned mask, mask_bottom; | ||
898 | |||
899 | /* nothing to draw? */ | ||
900 | if ((width <= 0) || (height <= 0) || (x >= current_vp->width) | ||
901 | || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) | ||
902 | return; | ||
903 | |||
904 | /* clipping */ | ||
905 | if (x < 0) | ||
906 | { | ||
907 | width += x; | ||
908 | src_x -= x; | ||
909 | x = 0; | ||
910 | } | ||
911 | if (y < 0) | ||
912 | { | ||
913 | height += y; | ||
914 | src_y -= y; | ||
915 | y = 0; | ||
916 | } | ||
917 | if (x + width > current_vp->width) | ||
918 | width = current_vp->width - x; | ||
919 | if (y + height > current_vp->height) | ||
920 | height = current_vp->height - y; | ||
921 | |||
922 | /* adjust for viewport */ | ||
923 | x += current_vp->x; | ||
924 | y += current_vp->y; | ||
925 | |||
926 | src += stride * (src_y >> 3) + src_x; /* move starting point */ | ||
927 | src_y &= 7; | ||
928 | y -= src_y; | ||
929 | dst = &LCDFN(framebuffer)[y>>3][x]; | ||
930 | shift = y & 7; | ||
931 | ny = height - 1 + shift + src_y; | ||
932 | |||
933 | mask = 0xFFu << (shift + src_y); | ||
934 | /* not byte-doubled here because shift+src_y can be > 7 */ | ||
935 | mask_bottom = 0xFFu >> (~ny & 7); | ||
936 | mask_bottom |= mask_bottom << 8; | ||
937 | |||
938 | if (shift == 0) | ||
939 | { | ||
940 | mask &= 0xFFu; | ||
941 | mask |= mask << 8; | ||
942 | |||
943 | for (; ny >= 8; ny -= 8) | ||
944 | { | ||
945 | if (mask == 0xFFFFu) | ||
946 | memcpy(dst, src, width * sizeof(FBFN(data))); | ||
947 | else | ||
948 | { | ||
949 | const FBFN(data) *src_row = src; | ||
950 | FBFN(data) *dst_row = dst; | ||
951 | |||
952 | dst_end = dst_row + width; | ||
953 | do | ||
954 | setblock(dst_row++, mask, *src_row++); | ||
955 | while (dst_row < dst_end); | ||
956 | } | ||
957 | src += stride; | ||
958 | dst += LCDM(WIDTH); | ||
959 | mask = 0xFFFFu; | ||
960 | } | ||
961 | mask &= mask_bottom; | ||
962 | |||
963 | if (mask == 0xFFFFu) | ||
964 | memcpy(dst, src, width * sizeof(FBFN(data))); | ||
965 | else | ||
966 | { | ||
967 | dst_end = dst + width; | ||
968 | do | ||
969 | setblock(dst++, mask, *src++); | ||
970 | while (dst < dst_end); | ||
971 | } | ||
972 | } | ||
973 | else | ||
974 | { | ||
975 | unsigned datamask = (0xFFu << shift) & 0xFFu; | ||
976 | |||
977 | datamask |= datamask << 8; | ||
978 | |||
979 | dst_end = dst + width; | ||
980 | do | ||
981 | { | ||
982 | const FBFN(data) *src_col = src++; | ||
983 | FBFN(data) *dst_col = dst++; | ||
984 | unsigned mask_col = mask & 0xFFu; | ||
985 | unsigned data, olddata = 0; | ||
986 | |||
987 | mask_col |= mask_col << 8; | ||
988 | |||
989 | for (y = ny; y >= 8; y -= 8) | ||
990 | { | ||
991 | data = *src_col << shift; | ||
992 | |||
993 | if (mask_col) | ||
994 | { | ||
995 | setblock(dst_col, mask_col, | ||
996 | olddata ^((olddata ^ data) & datamask)); | ||
997 | mask_col = 0xFFFFu; | ||
998 | } | ||
999 | else | ||
1000 | { | ||
1001 | mask_col = (mask << 8) & 0xFFu; | ||
1002 | mask_col |= mask_col << 8; | ||
1003 | } | ||
1004 | src_col += stride; | ||
1005 | dst_col += LCDM(WIDTH); | ||
1006 | olddata = data >> 8; | ||
1007 | } | ||
1008 | data = *src_col << shift; | ||
1009 | setblock(dst_col, mask_col & mask_bottom, | ||
1010 | olddata ^((olddata ^ data) & datamask)); | ||
1011 | } | ||
1012 | while (dst < dst_end); | ||
1013 | } | ||
1014 | } | ||
1015 | |||
1016 | /* Draw a full native bitmap */ | ||
1017 | void LCDFN(bitmap)(const FBFN(data) *src, int x, int y, int width, int height) | ||
1018 | { | ||
1019 | LCDFN(bitmap_part)(src, 0, 0, width, x, y, width, height); | ||
1020 | } | ||
1021 | |||
1022 | /* put a string at a given pixel position, skipping first ofs pixel columns */ | ||
1023 | static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str) | ||
1024 | { | ||
1025 | unsigned short ch; | ||
1026 | unsigned short *ucs; | ||
1027 | struct font* pf = font_get(current_vp->font); | ||
1028 | |||
1029 | ucs = bidi_l2v(str, 1); | ||
1030 | |||
1031 | while ((ch = *ucs++) != 0 && x < current_vp->width) | ||
1032 | { | ||
1033 | int width; | ||
1034 | const unsigned char *bits; | ||
1035 | |||
1036 | /* get proportional width and glyph bits */ | ||
1037 | width = font_get_width(pf, ch); | ||
1038 | |||
1039 | if (ofs > width) | ||
1040 | { | ||
1041 | ofs -= width; | ||
1042 | continue; | ||
1043 | } | ||
1044 | |||
1045 | bits = font_get_bits(pf, ch); | ||
1046 | |||
1047 | LCDFN(mono_bitmap_part)(bits, ofs, 0, width, x, y, width - ofs, | ||
1048 | pf->height); | ||
1049 | |||
1050 | x += width - ofs; | ||
1051 | ofs = 0; | ||
1052 | } | ||
1053 | } | ||
1054 | |||
1055 | /* put a string at a given pixel position */ | ||
1056 | void LCDFN(putsxy)(int x, int y, const unsigned char *str) | ||
1057 | { | ||
1058 | LCDFN(putsxyofs)(x, y, 0, str); | ||
1059 | } | ||
1060 | |||
1061 | /*** line oriented text output ***/ | ||
1062 | |||
1063 | /* put a string at a given char position */ | ||
1064 | void LCDFN(puts)(int x, int y, const unsigned char *str) | ||
1065 | { | ||
1066 | LCDFN(puts_style_offset)(x, y, str, STYLE_DEFAULT, 0); | ||
1067 | } | ||
1068 | |||
1069 | void LCDFN(puts_style)(int x, int y, const unsigned char *str, int style) | ||
1070 | { | ||
1071 | LCDFN(puts_style_offset)(x, y, str, style, 0); | ||
1072 | } | ||
1073 | |||
1074 | void LCDFN(puts_offset)(int x, int y, const unsigned char *str, int offset) | ||
1075 | { | ||
1076 | LCDFN(puts_style_offset)(x, y, str, STYLE_DEFAULT, offset); | ||
1077 | } | ||
1078 | |||
1079 | /* put a string at a given char position, style, and pixel position, | ||
1080 | * skipping first offset pixel columns */ | ||
1081 | void LCDFN(puts_style_offset)(int x, int y, const unsigned char *str, | ||
1082 | int style, int offset) | ||
1083 | { | ||
1084 | int xpos,ypos,w,h,xrect; | ||
1085 | int lastmode = current_vp->drawmode; | ||
1086 | |||
1087 | /* make sure scrolling is turned off on the line we are updating */ | ||
1088 | LCDFN(scroll_stop_line)(current_vp, y); | ||
1089 | |||
1090 | if(!str || !str[0]) | ||
1091 | return; | ||
1092 | |||
1093 | LCDFN(getstringsize)(str, &w, &h); | ||
1094 | xpos = current_vp->xmargin + x*w / utf8length((char *)str); | ||
1095 | ypos = current_vp->ymargin + y*h; | ||
1096 | current_vp->drawmode = (style & STYLE_INVERT) ? | ||
1097 | (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; | ||
1098 | LCDFN(putsxyofs)(xpos, ypos, offset, str); | ||
1099 | current_vp->drawmode ^= DRMODE_INVERSEVID; | ||
1100 | xrect = xpos + MAX(w - offset, 0); | ||
1101 | LCDFN(fillrect)(xrect, ypos, current_vp->width - xrect, h); | ||
1102 | current_vp->drawmode = lastmode; | ||
1103 | } | ||
1104 | |||
1105 | /*** scrolling ***/ | ||
1106 | void LCDFN(puts_scroll)(int x, int y, const unsigned char *string) | ||
1107 | { | ||
1108 | LCDFN(puts_scroll_style)(x, y, string, STYLE_DEFAULT); | ||
1109 | } | ||
1110 | |||
1111 | void LCDFN(puts_scroll_style)(int x, int y, const unsigned char *string, int style) | ||
1112 | { | ||
1113 | LCDFN(puts_scroll_style_offset)(x, y, string, style, 0); | ||
1114 | } | ||
1115 | |||
1116 | void LCDFN(puts_scroll_offset)(int x, int y, const unsigned char *string, int offset) | ||
1117 | { | ||
1118 | LCDFN(puts_scroll_style_offset)(x, y, string, STYLE_DEFAULT, offset); | ||
1119 | } | ||
1120 | |||
1121 | void LCDFN(puts_scroll_style_offset)(int x, int y, const unsigned char *string, | ||
1122 | int style, int offset) | ||
1123 | { | ||
1124 | struct scrollinfo* s; | ||
1125 | int w, h; | ||
1126 | |||
1127 | if ((unsigned)y >= (unsigned)current_vp->height) | ||
1128 | return; | ||
1129 | |||
1130 | /* remove any previously scrolling line at the same location */ | ||
1131 | LCDFN(scroll_stop_line)(current_vp, y); | ||
1132 | |||
1133 | if (LCDFN(scroll_info).lines >= LCDM(SCROLLABLE_LINES)) return; | ||
1134 | |||
1135 | s = &LCDFN(scroll_info).scroll[LCDFN(scroll_info).lines]; | ||
1136 | |||
1137 | s->start_tick = current_tick + LCDFN(scroll_info).delay; | ||
1138 | s->style = style; | ||
1139 | if (style & STYLE_INVERT) { | ||
1140 | LCDFN(puts_style_offset)(x,y,string,STYLE_INVERT,offset); | ||
1141 | } | ||
1142 | else | ||
1143 | LCDFN(puts_offset)(x,y,string,offset); | ||
1144 | |||
1145 | LCDFN(getstringsize)(string, &w, &h); | ||
1146 | |||
1147 | if (current_vp->width - x * 8 - current_vp->xmargin < w) { | ||
1148 | /* prepare scroll line */ | ||
1149 | char *end; | ||
1150 | |||
1151 | memset(s->line, 0, sizeof s->line); | ||
1152 | strcpy(s->line, string); | ||
1153 | |||
1154 | /* get width */ | ||
1155 | s->width = LCDFN(getstringsize)(s->line, &w, &h); | ||
1156 | |||
1157 | /* scroll bidirectional or forward only depending on the string | ||
1158 | width */ | ||
1159 | if ( LCDFN(scroll_info).bidir_limit ) { | ||
1160 | s->bidir = s->width < (current_vp->width - current_vp->xmargin) * | ||
1161 | (100 + LCDFN(scroll_info).bidir_limit) / 100; | ||
1162 | } | ||
1163 | else | ||
1164 | s->bidir = false; | ||
1165 | |||
1166 | if (!s->bidir) { /* add spaces if scrolling in the round */ | ||
1167 | strcat(s->line, " "); | ||
1168 | /* get new width incl. spaces */ | ||
1169 | s->width = LCDFN(getstringsize)(s->line, &w, &h); | ||
1170 | } | ||
1171 | |||
1172 | end = strchr(s->line, '\0'); | ||
1173 | strncpy(end, (char *)string, current_vp->width/2); | ||
1174 | |||
1175 | s->vp = current_vp; | ||
1176 | s->y = y; | ||
1177 | s->len = utf8length((char *)string); | ||
1178 | s->offset = offset; | ||
1179 | s->startx = current_vp->xmargin + x * s->width / s->len; | ||
1180 | s->backward = false; | ||
1181 | |||
1182 | LCDFN(scroll_info).lines++; | ||
1183 | } | ||
1184 | } | ||
1185 | |||
1186 | void LCDFN(scroll_fn)(void) | ||
1187 | { | ||
1188 | struct font* pf; | ||
1189 | struct scrollinfo* s; | ||
1190 | int index; | ||
1191 | int xpos, ypos; | ||
1192 | int lastmode; | ||
1193 | struct viewport* old_vp = current_vp; | ||
1194 | |||
1195 | for ( index = 0; index < LCDFN(scroll_info).lines; index++ ) { | ||
1196 | s = &LCDFN(scroll_info).scroll[index]; | ||
1197 | |||
1198 | /* check pause */ | ||
1199 | if (TIME_BEFORE(current_tick, s->start_tick)) | ||
1200 | continue; | ||
1201 | |||
1202 | LCDFN(set_viewport)(s->vp); | ||
1203 | |||
1204 | if (s->backward) | ||
1205 | s->offset -= LCDFN(scroll_info).step; | ||
1206 | else | ||
1207 | s->offset += LCDFN(scroll_info).step; | ||
1208 | |||
1209 | pf = font_get(current_vp->font); | ||
1210 | xpos = s->startx; | ||
1211 | ypos = current_vp->ymargin + s->y * pf->height; | ||
1212 | |||
1213 | if (s->bidir) { /* scroll bidirectional */ | ||
1214 | if (s->offset <= 0) { | ||
1215 | /* at beginning of line */ | ||
1216 | s->offset = 0; | ||
1217 | s->backward = false; | ||
1218 | s->start_tick = current_tick + LCDFN(scroll_info).delay * 2; | ||
1219 | } | ||
1220 | if (s->offset >= s->width - (current_vp->width - xpos)) { | ||
1221 | /* at end of line */ | ||
1222 | s->offset = s->width - (current_vp->width - xpos); | ||
1223 | s->backward = true; | ||
1224 | s->start_tick = current_tick + LCDFN(scroll_info).delay * 2; | ||
1225 | } | ||
1226 | } | ||
1227 | else { | ||
1228 | /* scroll forward the whole time */ | ||
1229 | if (s->offset >= s->width) | ||
1230 | s->offset %= s->width; | ||
1231 | } | ||
1232 | |||
1233 | lastmode = current_vp->drawmode; | ||
1234 | current_vp->drawmode = (s->style&STYLE_INVERT) ? | ||
1235 | (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; | ||
1236 | LCDFN(putsxyofs)(xpos, ypos, s->offset, s->line); | ||
1237 | current_vp->drawmode = lastmode; | ||
1238 | LCDFN(update_viewport_rect)(xpos, ypos, | ||
1239 | current_vp->width - xpos, pf->height); | ||
1240 | } | ||
1241 | |||
1242 | LCDFN(set_viewport)(old_vp); | ||
1243 | } | ||
diff --git a/firmware/drivers/lcd-remote-2bit-vi.c b/firmware/drivers/lcd-remote-2bit-vi.c index 9f70e95195..d2440a6296 100644 --- a/firmware/drivers/lcd-remote-2bit-vi.c +++ b/firmware/drivers/lcd-remote-2bit-vi.c | |||
@@ -18,1235 +18,12 @@ | |||
18 | * KIND, either express or implied. | 18 | * KIND, either express or implied. |
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #include "config.h" | ||
22 | #include "cpu.h" | ||
23 | #include "lcd.h" | ||
24 | #include "lcd-remote.h" | ||
25 | #include "kernel.h" | ||
26 | #include "thread.h" | ||
27 | #include <string.h> | ||
28 | #include <stdlib.h> | ||
29 | #include "memory.h" | ||
30 | #include "file.h" | ||
31 | #include "debug.h" | ||
32 | #include "system.h" | ||
33 | #include "font.h" | ||
34 | #include "rbunicode.h" | ||
35 | #include "bidi.h" | ||
36 | #include "lcd-remote-target.h" | ||
37 | #include "scroll_engine.h" | ||
38 | |||
39 | /*** globals ***/ | ||
40 | |||
41 | fb_remote_data lcd_remote_framebuffer[LCD_REMOTE_FBHEIGHT][LCD_REMOTE_FBWIDTH] | ||
42 | IBSS_ATTR; | ||
43 | |||
44 | static const fb_remote_data patterns[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000}; | ||
45 | |||
46 | static fb_remote_data* remote_backdrop = NULL; | ||
47 | static long remote_backdrop_offset IDATA_ATTR = 0; | ||
48 | |||
49 | static struct viewport default_vp = | ||
50 | { | ||
51 | .x = 0, | ||
52 | .y = 0, | ||
53 | .width = LCD_REMOTE_WIDTH, | ||
54 | .height = LCD_REMOTE_HEIGHT, | ||
55 | .font = FONT_SYSFIXED, | ||
56 | .drawmode = DRMODE_SOLID, | ||
57 | .xmargin = 0, | ||
58 | .ymargin = 0, | ||
59 | .fg_pattern = LCD_REMOTE_DEFAULT_FG, | ||
60 | .bg_pattern = LCD_REMOTE_DEFAULT_BG | ||
61 | }; | ||
62 | |||
63 | static unsigned fg_pattern IBSS_ATTR; | ||
64 | static unsigned bg_pattern IBSS_ATTR; | ||
65 | |||
66 | static struct viewport* current_vp IBSS_ATTR;; | ||
67 | |||
68 | /*** Viewports ***/ | ||
69 | |||
70 | void lcd_remote_set_viewport(struct viewport* vp) | ||
71 | { | ||
72 | if (vp == NULL) | ||
73 | current_vp = &default_vp; | ||
74 | else | ||
75 | current_vp = vp; | ||
76 | |||
77 | fg_pattern = patterns[current_vp->fg_pattern & 3]; | ||
78 | bg_pattern = patterns[current_vp->bg_pattern & 3]; | ||
79 | } | ||
80 | |||
81 | void lcd_remote_update_viewport(void) | ||
82 | { | ||
83 | lcd_remote_update_rect(current_vp->x, current_vp->y, | ||
84 | current_vp->width, current_vp->height); | ||
85 | } | ||
86 | |||
87 | void lcd_remote_update_viewport_rect(int x, int y, int width, int height) | ||
88 | { | ||
89 | lcd_remote_update_rect(current_vp->x + x, current_vp->y + y, width, height); | ||
90 | } | ||
91 | |||
92 | /*** parameter handling ***/ | ||
93 | unsigned lcd_remote_color_to_native(unsigned color) | ||
94 | { | ||
95 | unsigned r = (color & 0xf800) >> 10; | ||
96 | unsigned g = (color & 0x07e0) >> 5; | ||
97 | unsigned b = (color & 0x001f) << 2; | ||
98 | /* | ||
99 | * |R| | ||
100 | * |Y'| = |0.299000 0.587000 0.114000| |G| | ||
101 | * |B| | ||
102 | */ | ||
103 | return (5*r + 9*g + b) >> 8; | ||
104 | } | ||
105 | |||
106 | void lcd_remote_set_drawmode(int mode) | ||
107 | { | ||
108 | current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); | ||
109 | } | ||
110 | |||
111 | int lcd_remote_get_drawmode(void) | ||
112 | { | ||
113 | return current_vp->drawmode; | ||
114 | } | ||
115 | |||
116 | void lcd_remote_set_foreground(unsigned brightness) | ||
117 | { | ||
118 | current_vp->fg_pattern = brightness; | ||
119 | fg_pattern = patterns[brightness & 3]; | ||
120 | } | ||
121 | |||
122 | unsigned lcd_remote_get_foreground(void) | ||
123 | { | ||
124 | return current_vp->fg_pattern; | ||
125 | } | ||
126 | |||
127 | void lcd_remote_set_background(unsigned brightness) | ||
128 | { | ||
129 | current_vp->bg_pattern = brightness; | ||
130 | bg_pattern = patterns[brightness & 3]; | ||
131 | } | ||
132 | |||
133 | unsigned lcd_remote_get_background(void) | ||
134 | { | ||
135 | return current_vp->bg_pattern; | ||
136 | } | ||
137 | |||
138 | void lcd_remote_set_drawinfo(int mode, unsigned fg_brightness, | ||
139 | unsigned bg_brightness) | ||
140 | { | ||
141 | lcd_remote_set_drawmode(mode); | ||
142 | lcd_remote_set_foreground(fg_brightness); | ||
143 | lcd_remote_set_background(bg_brightness); | ||
144 | } | ||
145 | |||
146 | int lcd_remote_getwidth(void) | ||
147 | { | ||
148 | return current_vp->width; | ||
149 | } | ||
150 | |||
151 | int lcd_remote_getheight(void) | ||
152 | { | ||
153 | return current_vp->height; | ||
154 | } | ||
155 | |||
156 | void lcd_remote_setmargins(int x, int y) | ||
157 | { | ||
158 | current_vp->xmargin = x; | ||
159 | current_vp->ymargin = y; | ||
160 | } | ||
161 | |||
162 | int lcd_remote_getxmargin(void) | ||
163 | { | ||
164 | return current_vp->xmargin; | ||
165 | } | ||
166 | |||
167 | int lcd_remote_getymargin(void) | ||
168 | { | ||
169 | return current_vp->ymargin; | ||
170 | } | ||
171 | |||
172 | void lcd_remote_setfont(int newfont) | ||
173 | { | ||
174 | current_vp->font = newfont; | ||
175 | } | ||
176 | |||
177 | int lcd_remote_getfont(void) | ||
178 | { | ||
179 | return current_vp->font; | ||
180 | } | ||
181 | |||
182 | int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h) | ||
183 | { | ||
184 | return font_getstringsize(str, w, h, current_vp->font); | ||
185 | } | ||
186 | |||
187 | /*** low-level drawing functions ***/ | ||
188 | |||
189 | static void setpixel(int x, int y) | ||
190 | { | ||
191 | unsigned mask = 0x0101 << (y & 7); | ||
192 | fb_remote_data *address = &lcd_remote_framebuffer[y>>3][x]; | ||
193 | unsigned data = *address; | ||
194 | |||
195 | *address = data ^ ((data ^ fg_pattern) & mask); | ||
196 | } | ||
197 | |||
198 | static void clearpixel(int x, int y) | ||
199 | { | ||
200 | unsigned mask = 0x0101 << (y & 7); | ||
201 | fb_remote_data *address = &lcd_remote_framebuffer[y>>3][x]; | ||
202 | unsigned data = *address; | ||
203 | |||
204 | *address = data ^ ((data ^ bg_pattern) & mask); | ||
205 | } | ||
206 | |||
207 | static void clearimgpixel(int x, int y) | ||
208 | { | ||
209 | unsigned mask = 0x0101 << (y & 7); | ||
210 | fb_remote_data *address = &lcd_remote_framebuffer[y>>3][x]; | ||
211 | unsigned data = *address; | ||
212 | |||
213 | *address = data ^ ((data ^ *(fb_remote_data *)((long)address | ||
214 | + remote_backdrop_offset)) & mask); | ||
215 | } | ||
216 | |||
217 | static void flippixel(int x, int y) | ||
218 | { | ||
219 | unsigned mask = 0x0101 << (y & 7); | ||
220 | fb_remote_data *address = &lcd_remote_framebuffer[y>>3][x]; | ||
221 | |||
222 | *address ^= mask; | ||
223 | } | ||
224 | |||
225 | static void nopixel(int x, int y) | ||
226 | { | ||
227 | (void)x; | ||
228 | (void)y; | ||
229 | } | ||
230 | |||
231 | lcd_remote_pixelfunc_type* const lcd_remote_pixelfuncs_bgcolor[8] = { | ||
232 | flippixel, nopixel, setpixel, setpixel, | ||
233 | nopixel, clearpixel, nopixel, clearpixel | ||
234 | }; | ||
235 | |||
236 | lcd_remote_pixelfunc_type* const lcd_remote_pixelfuncs_backdrop[8] = { | ||
237 | flippixel, nopixel, setpixel, setpixel, | ||
238 | nopixel, clearimgpixel, nopixel, clearimgpixel | ||
239 | }; | ||
240 | |||
241 | lcd_remote_pixelfunc_type* const *lcd_remote_pixelfuncs = lcd_remote_pixelfuncs_bgcolor; | ||
242 | |||
243 | /* 'mask' and 'bits' contain 2 bits per pixel */ | ||
244 | static void flipblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
245 | ICODE_ATTR; | ||
246 | static void flipblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
247 | { | ||
248 | *address ^= bits & mask; | ||
249 | } | ||
250 | |||
251 | static void bgblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
252 | ICODE_ATTR; | ||
253 | static void bgblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
254 | { | ||
255 | unsigned data = *address; | ||
256 | |||
257 | *address = data ^ ((data ^ bg_pattern) & mask & ~bits); | ||
258 | } | ||
259 | |||
260 | static void bgimgblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
261 | ICODE_ATTR; | ||
262 | static void bgimgblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
263 | { | ||
264 | unsigned data = *address; | ||
265 | |||
266 | *address = data ^ ((data ^ *(fb_remote_data *)((long)address | ||
267 | + remote_backdrop_offset)) & mask & ~bits); | ||
268 | } | ||
269 | |||
270 | static void fgblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
271 | ICODE_ATTR; | ||
272 | static void fgblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
273 | { | ||
274 | unsigned data = *address; | ||
275 | |||
276 | *address = data ^ ((data ^ fg_pattern) & mask & bits); | ||
277 | } | ||
278 | |||
279 | static void solidblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
280 | ICODE_ATTR; | ||
281 | static void solidblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
282 | { | ||
283 | unsigned data = *address; | ||
284 | unsigned bgp = bg_pattern; | ||
285 | |||
286 | bits = bgp ^ ((bgp ^ fg_pattern) & bits); | ||
287 | *address = data ^ ((data ^ bits) & mask); | ||
288 | } | ||
289 | |||
290 | static void solidimgblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
291 | ICODE_ATTR; | ||
292 | static void solidimgblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
293 | { | ||
294 | unsigned data = *address; | ||
295 | unsigned bgp = *(fb_remote_data *)((long)address + remote_backdrop_offset); | ||
296 | |||
297 | bits = bgp ^ ((bgp ^ fg_pattern) & bits); | ||
298 | *address = data ^ ((data ^ bits) & mask); | ||
299 | } | ||
300 | |||
301 | static void flipinvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
302 | ICODE_ATTR; | ||
303 | static void flipinvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
304 | { | ||
305 | *address ^= ~bits & mask; | ||
306 | } | ||
307 | |||
308 | static void bginvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
309 | ICODE_ATTR; | ||
310 | static void bginvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
311 | { | ||
312 | unsigned data = *address; | ||
313 | |||
314 | *address = data ^ ((data ^ bg_pattern) & mask & bits); | ||
315 | } | ||
316 | |||
317 | static void bgimginvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
318 | ICODE_ATTR; | ||
319 | static void bgimginvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
320 | { | ||
321 | unsigned data = *address; | ||
322 | |||
323 | *address = data ^ ((data ^ *(fb_remote_data *)((long)address | ||
324 | + remote_backdrop_offset)) & mask & bits); | ||
325 | } | ||
326 | |||
327 | static void fginvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
328 | ICODE_ATTR; | ||
329 | static void fginvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
330 | { | ||
331 | unsigned data = *address; | ||
332 | |||
333 | *address = data ^ ((data ^ fg_pattern) & mask & ~bits); | ||
334 | } | ||
335 | |||
336 | static void solidinvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
337 | ICODE_ATTR; | ||
338 | static void solidinvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
339 | { | ||
340 | unsigned data = *address; | ||
341 | unsigned fgp = fg_pattern; | ||
342 | |||
343 | bits = fgp ^ ((fgp ^ bg_pattern) & bits); | ||
344 | *address = data ^ ((data ^ bits) & mask); | ||
345 | } | ||
346 | |||
347 | static void solidimginvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
348 | ICODE_ATTR; | ||
349 | static void solidimginvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
350 | { | ||
351 | unsigned data = *address; | ||
352 | unsigned fgp = fg_pattern; | ||
353 | |||
354 | bits = fgp ^ ((fgp ^ *(fb_remote_data *)((long)address | ||
355 | + remote_backdrop_offset)) & bits); | ||
356 | *address = data ^ ((data ^ bits) & mask); | ||
357 | } | ||
358 | |||
359 | lcd_remote_blockfunc_type* const lcd_remote_blockfuncs_bgcolor[8] = { | ||
360 | flipblock, bgblock, fgblock, solidblock, | ||
361 | flipinvblock, bginvblock, fginvblock, solidinvblock | ||
362 | }; | ||
363 | |||
364 | lcd_remote_blockfunc_type* const lcd_remote_blockfuncs_backdrop[8] = { | ||
365 | flipblock, bgimgblock, fgblock, solidimgblock, | ||
366 | flipinvblock, bgimginvblock, fginvblock, solidimginvblock | ||
367 | }; | ||
368 | |||
369 | lcd_remote_blockfunc_type* const *lcd_remote_blockfuncs = lcd_remote_blockfuncs_bgcolor; | ||
370 | |||
371 | |||
372 | void lcd_remote_set_backdrop(fb_remote_data* backdrop) | ||
373 | { | ||
374 | remote_backdrop = backdrop; | ||
375 | if (backdrop) | ||
376 | { | ||
377 | remote_backdrop_offset = (long)backdrop - (long)lcd_remote_framebuffer; | ||
378 | lcd_remote_pixelfuncs = lcd_remote_pixelfuncs_backdrop; | ||
379 | lcd_remote_blockfuncs = lcd_remote_blockfuncs_backdrop; | ||
380 | } | ||
381 | else | ||
382 | { | ||
383 | remote_backdrop_offset = 0; | ||
384 | lcd_remote_pixelfuncs = lcd_remote_pixelfuncs_bgcolor; | ||
385 | lcd_remote_blockfuncs = lcd_remote_blockfuncs_bgcolor; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | fb_remote_data* lcd_remote_get_backdrop(void) | ||
390 | { | ||
391 | return remote_backdrop; | ||
392 | } | ||
393 | |||
394 | static inline void setblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
395 | { | ||
396 | unsigned data = *address; | ||
397 | |||
398 | bits ^= data; | ||
399 | *address = data ^ (bits & mask); | ||
400 | } | ||
401 | |||
402 | /*** drawing functions ***/ | ||
403 | |||
404 | /* Clear the whole display */ | ||
405 | void lcd_remote_clear_display(void) | ||
406 | { | ||
407 | if (default_vp.drawmode & DRMODE_INVERSEVID) | ||
408 | { | ||
409 | memset(lcd_remote_framebuffer, patterns[default_vp.fg_pattern & 3], | ||
410 | sizeof lcd_remote_framebuffer); | ||
411 | } | ||
412 | else | ||
413 | { | ||
414 | if (remote_backdrop) | ||
415 | memcpy(lcd_remote_framebuffer, remote_backdrop, | ||
416 | sizeof lcd_remote_framebuffer); | ||
417 | else | ||
418 | memset(lcd_remote_framebuffer, patterns[default_vp.bg_pattern & 3], | ||
419 | sizeof lcd_remote_framebuffer); | ||
420 | } | ||
421 | |||
422 | lcd_remote_scroll_info.lines = 0; | ||
423 | } | ||
424 | |||
425 | /* Clear the current viewport */ | ||
426 | void lcd_remote_clear_viewport(void) | ||
427 | { | ||
428 | int lastmode; | ||
429 | |||
430 | if (current_vp == &default_vp) | ||
431 | { | ||
432 | lcd_remote_clear_display(); | ||
433 | } | ||
434 | else | ||
435 | { | ||
436 | lastmode = current_vp->drawmode; | ||
437 | |||
438 | /* Invert the INVERSEVID bit and set basic mode to SOLID */ | ||
439 | current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) | | ||
440 | DRMODE_SOLID; | ||
441 | |||
442 | lcd_remote_fillrect(0, 0, current_vp->width, current_vp->height); | ||
443 | |||
444 | current_vp->drawmode = lastmode; | ||
445 | |||
446 | lcd_remote_scroll_stop(current_vp); | ||
447 | } | ||
448 | } | ||
449 | |||
450 | /* Set a single pixel */ | ||
451 | void lcd_remote_drawpixel(int x, int y) | ||
452 | { | ||
453 | if (((unsigned)x < (unsigned)current_vp->width) && | ||
454 | ((unsigned)y < (unsigned)current_vp->height)) | ||
455 | lcd_remote_pixelfuncs[current_vp->drawmode](current_vp->x+x, current_vp->y+y); | ||
456 | } | ||
457 | |||
458 | /* Draw a line */ | ||
459 | void lcd_remote_drawline(int x1, int y1, int x2, int y2) | ||
460 | { | ||
461 | int numpixels; | ||
462 | int i; | ||
463 | int deltax, deltay; | ||
464 | int d, dinc1, dinc2; | ||
465 | int x, xinc1, xinc2; | ||
466 | int y, yinc1, yinc2; | ||
467 | lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[current_vp->drawmode]; | ||
468 | |||
469 | deltax = abs(x2 - x1); | ||
470 | deltay = abs(y2 - y1); | ||
471 | xinc2 = 1; | ||
472 | yinc2 = 1; | ||
473 | |||
474 | if (deltax >= deltay) | ||
475 | { | ||
476 | numpixels = deltax; | ||
477 | d = 2 * deltay - deltax; | ||
478 | dinc1 = deltay * 2; | ||
479 | dinc2 = (deltay - deltax) * 2; | ||
480 | xinc1 = 1; | ||
481 | yinc1 = 0; | ||
482 | } | ||
483 | else | ||
484 | { | ||
485 | numpixels = deltay; | ||
486 | d = 2 * deltax - deltay; | ||
487 | dinc1 = deltax * 2; | ||
488 | dinc2 = (deltax - deltay) * 2; | ||
489 | xinc1 = 0; | ||
490 | yinc1 = 1; | ||
491 | } | ||
492 | numpixels++; /* include endpoints */ | ||
493 | |||
494 | if (x1 > x2) | ||
495 | { | ||
496 | xinc1 = -xinc1; | ||
497 | xinc2 = -xinc2; | ||
498 | } | ||
499 | |||
500 | if (y1 > y2) | ||
501 | { | ||
502 | yinc1 = -yinc1; | ||
503 | yinc2 = -yinc2; | ||
504 | } | ||
505 | |||
506 | x = x1; | ||
507 | y = y1; | ||
508 | |||
509 | for (i = 0; i < numpixels; i++) | ||
510 | { | ||
511 | if (((unsigned)x < (unsigned)current_vp->width) && | ||
512 | ((unsigned)y < (unsigned)current_vp->height)) | ||
513 | pfunc(current_vp->x + x, current_vp->y + y); | ||
514 | |||
515 | if (d < 0) | ||
516 | { | ||
517 | d += dinc1; | ||
518 | x += xinc1; | ||
519 | y += yinc1; | ||
520 | } | ||
521 | else | ||
522 | { | ||
523 | d += dinc2; | ||
524 | x += xinc2; | ||
525 | y += yinc2; | ||
526 | } | ||
527 | } | ||
528 | } | ||
529 | |||
530 | /* Draw a horizontal line (optimised) */ | ||
531 | void lcd_remote_hline(int x1, int x2, int y) | ||
532 | { | ||
533 | int x; | ||
534 | int width; | ||
535 | fb_remote_data *dst, *dst_end; | ||
536 | unsigned mask; | ||
537 | lcd_remote_blockfunc_type *bfunc; | ||
538 | |||
539 | /* direction flip */ | ||
540 | if (x2 < x1) | ||
541 | { | ||
542 | x = x1; | ||
543 | x1 = x2; | ||
544 | x2 = x; | ||
545 | } | ||
546 | |||
547 | /* nothing to draw? */ | ||
548 | if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width) | ||
549 | || (x2 < 0)) | ||
550 | return; | ||
551 | |||
552 | /* clipping */ | ||
553 | if (x1 < 0) | ||
554 | x1 = 0; | ||
555 | if (x2 >= current_vp->width) | ||
556 | x2 = current_vp->width-1; | ||
557 | |||
558 | width = x2 - x1 + 1; | ||
559 | |||
560 | /* adjust x1 and y to viewport */ | ||
561 | x1 += current_vp->x; | ||
562 | y += current_vp->y; | ||
563 | |||
564 | bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; | ||
565 | dst = &lcd_remote_framebuffer[y>>3][x1]; | ||
566 | mask = 0x0101 << (y & 7); | ||
567 | |||
568 | dst_end = dst + width; | ||
569 | do | ||
570 | bfunc(dst++, mask, 0xFFFFu); | ||
571 | while (dst < dst_end); | ||
572 | } | ||
573 | |||
574 | /* Draw a vertical line (optimised) */ | ||
575 | void lcd_remote_vline(int x, int y1, int y2) | ||
576 | { | ||
577 | int ny; | ||
578 | fb_remote_data *dst; | ||
579 | unsigned mask, mask_bottom; | ||
580 | lcd_remote_blockfunc_type *bfunc; | ||
581 | |||
582 | /* direction flip */ | ||
583 | if (y2 < y1) | ||
584 | { | ||
585 | ny = y1; | ||
586 | y1 = y2; | ||
587 | y2 = ny; | ||
588 | } | ||
589 | 21 | ||
590 | /* nothing to draw? */ | 22 | #include "lcd-remote.h" |
591 | if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height) | ||
592 | || (y2 < 0)) | ||
593 | return; | ||
594 | |||
595 | /* clipping */ | ||
596 | if (y1 < 0) | ||
597 | y1 = 0; | ||
598 | if (y2 >= current_vp->height) | ||
599 | y2 = current_vp->height-1; | ||
600 | |||
601 | /* adjust for viewport */ | ||
602 | y1 += current_vp->y; | ||
603 | y2 += current_vp->y; | ||
604 | x += current_vp->x; | ||
605 | |||
606 | bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; | ||
607 | dst = &lcd_remote_framebuffer[y1>>3][x]; | ||
608 | ny = y2 - (y1 & ~7); | ||
609 | mask = (0xFFu << (y1 & 7)) & 0xFFu; | ||
610 | mask |= mask << 8; | ||
611 | mask_bottom = 0xFFu >> (~ny & 7); | ||
612 | mask_bottom |= mask_bottom << 8; | ||
613 | |||
614 | for (; ny >= 8; ny -= 8) | ||
615 | { | ||
616 | bfunc(dst, mask, 0xFFFFu); | ||
617 | dst += LCD_REMOTE_WIDTH; | ||
618 | mask = 0xFFFFu; | ||
619 | } | ||
620 | mask &= mask_bottom; | ||
621 | bfunc(dst, mask, 0xFFFFu); | ||
622 | } | ||
623 | |||
624 | /* Draw a rectangular box */ | ||
625 | void lcd_remote_drawrect(int x, int y, int width, int height) | ||
626 | { | ||
627 | if ((width <= 0) || (height <= 0)) | ||
628 | return; | ||
629 | |||
630 | int x2 = x + width - 1; | ||
631 | int y2 = y + height - 1; | ||
632 | |||
633 | lcd_remote_vline(x, y, y2); | ||
634 | lcd_remote_vline(x2, y, y2); | ||
635 | lcd_remote_hline(x, x2, y); | ||
636 | lcd_remote_hline(x, x2, y2); | ||
637 | } | ||
638 | |||
639 | /* Fill a rectangular area */ | ||
640 | void lcd_remote_fillrect(int x, int y, int width, int height) | ||
641 | { | ||
642 | int ny; | ||
643 | fb_remote_data *dst, *dst_end; | ||
644 | unsigned mask, mask_bottom; | ||
645 | unsigned bits = 0; | ||
646 | lcd_remote_blockfunc_type *bfunc; | ||
647 | bool fillopt = false; | ||
648 | |||
649 | /* nothing to draw? */ | ||
650 | if ((width <= 0) || (height <= 0) || (x >= current_vp->width) | ||
651 | || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) | ||
652 | return; | ||
653 | |||
654 | /* clipping */ | ||
655 | if (x < 0) | ||
656 | { | ||
657 | width += x; | ||
658 | x = 0; | ||
659 | } | ||
660 | if (y < 0) | ||
661 | { | ||
662 | height += y; | ||
663 | y = 0; | ||
664 | } | ||
665 | if (x + width > current_vp->width) | ||
666 | width = current_vp->width - x; | ||
667 | if (y + height > current_vp->height) | ||
668 | height = current_vp->height - y; | ||
669 | |||
670 | /* adjust for viewport */ | ||
671 | x += current_vp->x; | ||
672 | y += current_vp->y; | ||
673 | |||
674 | if (current_vp->drawmode & DRMODE_INVERSEVID) | ||
675 | { | ||
676 | if ((current_vp->drawmode & DRMODE_BG) && !remote_backdrop) | ||
677 | { | ||
678 | fillopt = true; | ||
679 | bits = bg_pattern; | ||
680 | } | ||
681 | } | ||
682 | else | ||
683 | { | ||
684 | if (current_vp->drawmode & DRMODE_FG) | ||
685 | { | ||
686 | fillopt = true; | ||
687 | bits = fg_pattern; | ||
688 | } | ||
689 | } | ||
690 | bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; | ||
691 | dst = &lcd_remote_framebuffer[y>>3][x]; | ||
692 | ny = height - 1 + (y & 7); | ||
693 | mask = (0xFFu << (y & 7)) & 0xFFu; | ||
694 | mask |= mask << 8; | ||
695 | mask_bottom = 0xFFu >> (~ny & 7); | ||
696 | mask_bottom |= mask_bottom << 8; | ||
697 | |||
698 | for (; ny >= 8; ny -= 8) | ||
699 | { | ||
700 | if (fillopt && (mask == 0xFFFFu)) | ||
701 | memset16(dst, bits, width); | ||
702 | else | ||
703 | { | ||
704 | fb_remote_data *dst_row = dst; | ||
705 | |||
706 | dst_end = dst_row + width; | ||
707 | do | ||
708 | bfunc(dst_row++, mask, 0xFFFFu); | ||
709 | while (dst_row < dst_end); | ||
710 | } | ||
711 | |||
712 | dst += LCD_REMOTE_WIDTH; | ||
713 | mask = 0xFFFFu; | ||
714 | } | ||
715 | mask &= mask_bottom; | ||
716 | |||
717 | if (fillopt && (mask == 0xFFFFu)) | ||
718 | memset16(dst, bits, width); | ||
719 | else | ||
720 | { | ||
721 | dst_end = dst + width; | ||
722 | do | ||
723 | bfunc(dst++, mask, 0xFFFFu); | ||
724 | while (dst < dst_end); | ||
725 | } | ||
726 | } | ||
727 | |||
728 | /* About Rockbox' internal monochrome bitmap format: | ||
729 | * | ||
730 | * A bitmap contains one bit for every pixel that defines if that pixel is | ||
731 | * black (1) or white (0). Bits within a byte are arranged vertically, LSB | ||
732 | * at top. | ||
733 | * The bytes are stored in row-major order, with byte 0 being top left, | ||
734 | * byte 1 2nd from left etc. The first row of bytes defines pixel rows | ||
735 | * 0..7, the second row defines pixel row 8..15 etc. | ||
736 | * | ||
737 | * This is similar to the internal lcd hw format. */ | ||
738 | |||
739 | /* Draw a partial monochrome bitmap */ | ||
740 | void lcd_remote_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, | ||
741 | int stride, int x, int y, int width, int height) | ||
742 | ICODE_ATTR; | ||
743 | void lcd_remote_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, | ||
744 | int stride, int x, int y, int width, int height) | ||
745 | { | ||
746 | int shift, ny; | ||
747 | fb_remote_data *dst, *dst_end; | ||
748 | unsigned data, mask, mask_bottom; | ||
749 | lcd_remote_blockfunc_type *bfunc; | ||
750 | |||
751 | /* nothing to draw? */ | ||
752 | if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || | ||
753 | (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) | ||
754 | return; | ||
755 | |||
756 | /* clipping */ | ||
757 | if (x < 0) | ||
758 | { | ||
759 | width += x; | ||
760 | src_x -= x; | ||
761 | x = 0; | ||
762 | } | ||
763 | if (y < 0) | ||
764 | { | ||
765 | height += y; | ||
766 | src_y -= y; | ||
767 | y = 0; | ||
768 | } | ||
769 | if (x + width > current_vp->width) | ||
770 | width = current_vp->width - x; | ||
771 | if (y + height > current_vp->height) | ||
772 | height = current_vp->height - y; | ||
773 | |||
774 | /* adjust for viewport */ | ||
775 | x += current_vp->x; | ||
776 | y += current_vp->y; | ||
777 | |||
778 | src += stride * (src_y >> 3) + src_x; /* move starting point */ | ||
779 | src_y &= 7; | ||
780 | y -= src_y; | ||
781 | dst = &lcd_remote_framebuffer[y>>3][x]; | ||
782 | shift = y & 7; | ||
783 | ny = height - 1 + shift + src_y; | ||
784 | |||
785 | bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; | ||
786 | mask = 0xFFu << (shift + src_y); | ||
787 | /* not byte-doubled here because shift+src_y can be > 7 */ | ||
788 | mask_bottom = 0xFFu >> (~ny & 7); | ||
789 | mask_bottom |= mask_bottom << 8; | ||
790 | |||
791 | if (shift == 0) | ||
792 | { | ||
793 | mask &= 0xFFu; | ||
794 | mask |= mask << 8; | ||
795 | |||
796 | for (; ny >= 8; ny -= 8) | ||
797 | { | ||
798 | const unsigned char *src_row = src; | ||
799 | fb_remote_data *dst_row = dst; | ||
800 | |||
801 | dst_end = dst_row + width; | ||
802 | do | ||
803 | { | ||
804 | data = *src_row++; | ||
805 | bfunc(dst_row++, mask, data | (data << 8)); | ||
806 | } | ||
807 | while (dst_row < dst_end); | ||
808 | |||
809 | src += stride; | ||
810 | dst += LCD_REMOTE_WIDTH; | ||
811 | mask = 0xFFFFu; | ||
812 | } | ||
813 | mask &= mask_bottom; | ||
814 | |||
815 | dst_end = dst + width; | ||
816 | do | ||
817 | { | ||
818 | data = *src++; | ||
819 | bfunc(dst++, mask, data | (data << 8)); | ||
820 | } | ||
821 | while (dst < dst_end); | ||
822 | } | ||
823 | else | ||
824 | { | ||
825 | unsigned ddata; | ||
826 | |||
827 | dst_end = dst + width; | ||
828 | do | ||
829 | { | ||
830 | const unsigned char *src_col = src++; | ||
831 | fb_remote_data *dst_col = dst++; | ||
832 | unsigned mask_col = mask & 0xFFu; | ||
833 | |||
834 | mask_col |= mask_col << 8; | ||
835 | data = 0; | ||
836 | |||
837 | for (y = ny; y >= 8; y -= 8) | ||
838 | { | ||
839 | data |= *src_col << shift; | ||
840 | |||
841 | if (mask_col) | ||
842 | { | ||
843 | ddata = data & 0xFFu; | ||
844 | bfunc(dst_col, mask_col, ddata | (ddata << 8)); | ||
845 | mask_col = 0xFFFFu; | ||
846 | } | ||
847 | else | ||
848 | { | ||
849 | mask_col = (mask >> 8) & 0xFFu; | ||
850 | mask_col |= mask_col << 8; | ||
851 | } | ||
852 | |||
853 | src_col += stride; | ||
854 | dst_col += LCD_REMOTE_WIDTH; | ||
855 | data >>= 8; | ||
856 | } | ||
857 | data |= *src_col << shift; | ||
858 | mask_col &= mask_bottom; | ||
859 | ddata = data & 0xFFu; | ||
860 | bfunc(dst_col, mask_col, ddata | (ddata << 8)); | ||
861 | } | ||
862 | while (dst < dst_end); | ||
863 | } | ||
864 | } | ||
865 | |||
866 | /* Draw a full monochrome bitmap */ | ||
867 | void lcd_remote_mono_bitmap(const unsigned char *src, int x, int y, int width, | ||
868 | int height) | ||
869 | { | ||
870 | lcd_remote_mono_bitmap_part(src, 0, 0, width, x, y, width, height); | ||
871 | } | ||
872 | |||
873 | /* About Rockbox' internal native bitmap format: | ||
874 | * | ||
875 | * A bitmap contains one bit in each byte of a pair of bytes for every pixel. | ||
876 | * 00 = white, 01 = light grey, 10 = dark grey, 11 = black. Bits within a byte | ||
877 | * are arranged vertically, LSB at top. | ||
878 | * The pairs of bytes are stored as shorts, in row-major order, with word 0 | ||
879 | * being top left, word 1 2nd from left etc. The first row of words defines | ||
880 | * pixel rows 0..7, the second row defines pixel row 8..15 etc. | ||
881 | * | ||
882 | * This is the same as the internal lcd hw format. */ | ||
883 | |||
884 | /* Draw a partial native bitmap */ | ||
885 | void lcd_remote_bitmap_part(const fb_remote_data *src, int src_x, int src_y, | ||
886 | int stride, int x, int y, int width, int height) | ||
887 | ICODE_ATTR; | ||
888 | void lcd_remote_bitmap_part(const fb_remote_data *src, int src_x, int src_y, | ||
889 | int stride, int x, int y, int width, int height) | ||
890 | { | ||
891 | int shift, ny; | ||
892 | fb_remote_data *dst, *dst_end; | ||
893 | unsigned mask, mask_bottom; | ||
894 | |||
895 | /* nothing to draw? */ | ||
896 | if ((width <= 0) || (height <= 0) || (x >= current_vp->width) | ||
897 | || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) | ||
898 | return; | ||
899 | |||
900 | /* clipping */ | ||
901 | if (x < 0) | ||
902 | { | ||
903 | width += x; | ||
904 | src_x -= x; | ||
905 | x = 0; | ||
906 | } | ||
907 | if (y < 0) | ||
908 | { | ||
909 | height += y; | ||
910 | src_y -= y; | ||
911 | y = 0; | ||
912 | } | ||
913 | if (x + width > current_vp->width) | ||
914 | width = current_vp->width - x; | ||
915 | if (y + height > current_vp->height) | ||
916 | height = current_vp->height - y; | ||
917 | |||
918 | /* adjust for viewport */ | ||
919 | x += current_vp->x; | ||
920 | y += current_vp->y; | ||
921 | |||
922 | src += stride * (src_y >> 3) + src_x; /* move starting point */ | ||
923 | src_y &= 7; | ||
924 | y -= src_y; | ||
925 | dst = &lcd_remote_framebuffer[y>>3][x]; | ||
926 | shift = y & 7; | ||
927 | ny = height - 1 + shift + src_y; | ||
928 | |||
929 | mask = 0xFFu << (shift + src_y); | ||
930 | /* not byte-doubled here because shift+src_y can be > 7 */ | ||
931 | mask_bottom = 0xFFu >> (~ny & 7); | ||
932 | mask_bottom |= mask_bottom << 8; | ||
933 | |||
934 | if (shift == 0) | ||
935 | { | ||
936 | mask &= 0xFFu; | ||
937 | mask |= mask << 8; | ||
938 | |||
939 | for (; ny >= 8; ny -= 8) | ||
940 | { | ||
941 | if (mask == 0xFFFFu) | ||
942 | memcpy(dst, src, width * sizeof(fb_remote_data)); | ||
943 | else | ||
944 | { | ||
945 | const fb_remote_data *src_row = src; | ||
946 | fb_remote_data *dst_row = dst; | ||
947 | |||
948 | dst_end = dst_row + width; | ||
949 | do | ||
950 | setblock(dst_row++, mask, *src_row++); | ||
951 | while (dst_row < dst_end); | ||
952 | } | ||
953 | src += stride; | ||
954 | dst += LCD_REMOTE_WIDTH; | ||
955 | mask = 0xFFFFu; | ||
956 | } | ||
957 | mask &= mask_bottom; | ||
958 | |||
959 | if (mask == 0xFFFFu) | ||
960 | memcpy(dst, src, width * sizeof(fb_remote_data)); | ||
961 | else | ||
962 | { | ||
963 | dst_end = dst + width; | ||
964 | do | ||
965 | setblock(dst++, mask, *src++); | ||
966 | while (dst < dst_end); | ||
967 | } | ||
968 | } | ||
969 | else | ||
970 | { | ||
971 | unsigned datamask = (0xFFu << shift) & 0xFFu; | ||
972 | |||
973 | datamask |= datamask << 8; | ||
974 | |||
975 | dst_end = dst + width; | ||
976 | do | ||
977 | { | ||
978 | const fb_remote_data *src_col = src++; | ||
979 | fb_remote_data *dst_col = dst++; | ||
980 | unsigned mask_col = mask & 0xFFu; | ||
981 | unsigned data, olddata = 0; | ||
982 | |||
983 | mask_col |= mask_col << 8; | ||
984 | |||
985 | for (y = ny; y >= 8; y -= 8) | ||
986 | { | ||
987 | data = *src_col << shift; | ||
988 | |||
989 | if (mask_col) | ||
990 | { | ||
991 | setblock(dst_col, mask_col, | ||
992 | olddata ^((olddata ^ data) & datamask)); | ||
993 | mask_col = 0xFFFFu; | ||
994 | } | ||
995 | else | ||
996 | { | ||
997 | mask_col = (mask << 8) & 0xFFu; | ||
998 | mask_col |= mask_col << 8; | ||
999 | } | ||
1000 | src_col += stride; | ||
1001 | dst_col += LCD_REMOTE_WIDTH; | ||
1002 | olddata = data >> 8; | ||
1003 | } | ||
1004 | data = *src_col << shift; | ||
1005 | setblock(dst_col, mask_col & mask_bottom, | ||
1006 | olddata ^((olddata ^ data) & datamask)); | ||
1007 | } | ||
1008 | while (dst < dst_end); | ||
1009 | } | ||
1010 | } | ||
1011 | |||
1012 | /* Draw a full native bitmap */ | ||
1013 | void lcd_remote_bitmap(const fb_remote_data *src, int x, int y, int width, | ||
1014 | int height) | ||
1015 | { | ||
1016 | lcd_remote_bitmap_part(src, 0, 0, width, x, y, width, height); | ||
1017 | } | ||
1018 | |||
1019 | /* put a string at a given pixel position, skipping first ofs pixel columns */ | ||
1020 | void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str) | ||
1021 | { | ||
1022 | unsigned short ch; | ||
1023 | unsigned short *ucs; | ||
1024 | struct font* pf = font_get(current_vp->font); | ||
1025 | |||
1026 | ucs = bidi_l2v(str, 1); | ||
1027 | |||
1028 | while ((ch = *ucs++) != 0 && x < current_vp->width) | ||
1029 | { | ||
1030 | int width; | ||
1031 | const unsigned char *bits; | ||
1032 | |||
1033 | /* get proportional width and glyph bits */ | ||
1034 | width = font_get_width(pf, ch); | ||
1035 | |||
1036 | if (ofs > width) | ||
1037 | { | ||
1038 | ofs -= width; | ||
1039 | continue; | ||
1040 | } | ||
1041 | |||
1042 | bits = font_get_bits(pf, ch); | ||
1043 | |||
1044 | lcd_remote_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, | ||
1045 | pf->height); | ||
1046 | |||
1047 | x += width - ofs; | ||
1048 | ofs = 0; | ||
1049 | } | ||
1050 | } | ||
1051 | |||
1052 | /* put a string at a given pixel position */ | ||
1053 | void lcd_remote_putsxy(int x, int y, const unsigned char *str) | ||
1054 | { | ||
1055 | lcd_remote_putsxyofs(x, y, 0, str); | ||
1056 | } | ||
1057 | |||
1058 | /*** line oriented text output ***/ | ||
1059 | |||
1060 | /* put a string at a given char position */ | ||
1061 | void lcd_remote_puts(int x, int y, const unsigned char *str) | ||
1062 | { | ||
1063 | lcd_remote_puts_style_offset(x, y, str, STYLE_DEFAULT, 0); | ||
1064 | } | ||
1065 | |||
1066 | void lcd_remote_puts_style(int x, int y, const unsigned char *str, int style) | ||
1067 | { | ||
1068 | lcd_remote_puts_style_offset(x, y, str, style, 0); | ||
1069 | } | ||
1070 | |||
1071 | void lcd_remote_puts_offset(int x, int y, const unsigned char *str, int offset) | ||
1072 | { | ||
1073 | lcd_remote_puts_style_offset(x, y, str, STYLE_DEFAULT, offset); | ||
1074 | } | ||
1075 | |||
1076 | /* put a string at a given char position, style, and pixel position, | ||
1077 | * skipping first offset pixel columns */ | ||
1078 | void lcd_remote_puts_style_offset(int x, int y, const unsigned char *str, | ||
1079 | int style, int offset) | ||
1080 | { | ||
1081 | int xpos,ypos,w,h,xrect; | ||
1082 | int lastmode = current_vp->drawmode; | ||
1083 | |||
1084 | /* make sure scrolling is turned off on the line we are updating */ | ||
1085 | lcd_remote_scroll_stop_line(current_vp, y); | ||
1086 | |||
1087 | if(!str || !str[0]) | ||
1088 | return; | ||
1089 | |||
1090 | lcd_remote_getstringsize(str, &w, &h); | ||
1091 | xpos = current_vp->xmargin + x*w / utf8length((char *)str); | ||
1092 | ypos = current_vp->ymargin + y*h; | ||
1093 | current_vp->drawmode = (style & STYLE_INVERT) ? | ||
1094 | (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; | ||
1095 | lcd_remote_putsxyofs(xpos, ypos, offset, str); | ||
1096 | current_vp->drawmode ^= DRMODE_INVERSEVID; | ||
1097 | xrect = xpos + MAX(w - offset, 0); | ||
1098 | lcd_remote_fillrect(xrect, ypos, current_vp->width - xrect, h); | ||
1099 | current_vp->drawmode = lastmode; | ||
1100 | } | ||
1101 | |||
1102 | /*** scrolling ***/ | ||
1103 | void lcd_remote_puts_scroll(int x, int y, const unsigned char *string) | ||
1104 | { | ||
1105 | lcd_remote_puts_scroll_style(x, y, string, STYLE_DEFAULT); | ||
1106 | } | ||
1107 | |||
1108 | void lcd_remote_puts_scroll_style(int x, int y, const unsigned char *string, int style) | ||
1109 | { | ||
1110 | lcd_remote_puts_scroll_style_offset(x, y, string, style, 0); | ||
1111 | } | ||
1112 | |||
1113 | void lcd_remote_puts_scroll_offset(int x, int y, const unsigned char *string, int offset) | ||
1114 | { | ||
1115 | lcd_remote_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset); | ||
1116 | } | ||
1117 | |||
1118 | void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *string, | ||
1119 | int style, int offset) | ||
1120 | { | ||
1121 | struct scrollinfo* s; | ||
1122 | int w, h; | ||
1123 | |||
1124 | if ((unsigned)y >= (unsigned)current_vp->height) | ||
1125 | return; | ||
1126 | |||
1127 | /* remove any previously scrolling line at the same location */ | ||
1128 | lcd_remote_scroll_stop_line(current_vp, y); | ||
1129 | |||
1130 | if (lcd_remote_scroll_info.lines >= LCD_REMOTE_SCROLLABLE_LINES) return; | ||
1131 | |||
1132 | s = &lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines]; | ||
1133 | |||
1134 | s->start_tick = current_tick + lcd_remote_scroll_info.delay; | ||
1135 | s->style = style; | ||
1136 | if (style & STYLE_INVERT) { | ||
1137 | lcd_remote_puts_style_offset(x,y,string,STYLE_INVERT,offset); | ||
1138 | } | ||
1139 | else | ||
1140 | lcd_remote_puts_offset(x,y,string,offset); | ||
1141 | |||
1142 | lcd_remote_getstringsize(string, &w, &h); | ||
1143 | |||
1144 | if (current_vp->width - x * 8 - current_vp->xmargin < w) { | ||
1145 | /* prepare scroll line */ | ||
1146 | char *end; | ||
1147 | |||
1148 | memset(s->line, 0, sizeof s->line); | ||
1149 | strcpy(s->line, (char *)string); | ||
1150 | |||
1151 | /* get width */ | ||
1152 | s->width = lcd_remote_getstringsize((unsigned char *)s->line, &w, &h); | ||
1153 | |||
1154 | /* scroll bidirectional or forward only depending on the string | ||
1155 | width */ | ||
1156 | if ( lcd_remote_scroll_info.bidir_limit ) { | ||
1157 | s->bidir = s->width < (current_vp->width - current_vp->xmargin) * | ||
1158 | (100 + lcd_remote_scroll_info.bidir_limit) / 100; | ||
1159 | } | ||
1160 | else | ||
1161 | s->bidir = false; | ||
1162 | |||
1163 | if (!s->bidir) { /* add spaces if scrolling in the round */ | ||
1164 | strcat(s->line, " "); | ||
1165 | /* get new width incl. spaces */ | ||
1166 | s->width = lcd_remote_getstringsize((unsigned char *)s->line, &w, &h); | ||
1167 | } | ||
1168 | |||
1169 | end = strchr(s->line, '\0'); | ||
1170 | strncpy(end, (char *)string, current_vp->width/2); | ||
1171 | |||
1172 | s->vp = current_vp; | ||
1173 | s->y = y; | ||
1174 | s->len = utf8length((char *)string); | ||
1175 | s->offset = offset; | ||
1176 | s->startx = current_vp->xmargin + x * s->width / s->len; | ||
1177 | s->backward = false; | ||
1178 | |||
1179 | lcd_remote_scroll_info.lines++; | ||
1180 | } | ||
1181 | } | ||
1182 | |||
1183 | void lcd_remote_scroll_fn(void) | ||
1184 | { | ||
1185 | struct font* pf; | ||
1186 | struct scrollinfo* s; | ||
1187 | int index; | ||
1188 | int xpos, ypos; | ||
1189 | int lastmode; | ||
1190 | struct viewport* old_vp = current_vp; | ||
1191 | |||
1192 | for ( index = 0; index < lcd_remote_scroll_info.lines; index++ ) { | ||
1193 | s = &lcd_remote_scroll_info.scroll[index]; | ||
1194 | |||
1195 | /* check pause */ | ||
1196 | if (TIME_BEFORE(current_tick, s->start_tick)) | ||
1197 | continue; | ||
1198 | |||
1199 | lcd_remote_set_viewport(s->vp); | ||
1200 | |||
1201 | if (s->backward) | ||
1202 | s->offset -= lcd_remote_scroll_info.step; | ||
1203 | else | ||
1204 | s->offset += lcd_remote_scroll_info.step; | ||
1205 | |||
1206 | pf = font_get(current_vp->font); | ||
1207 | xpos = s->startx; | ||
1208 | ypos = current_vp->ymargin + s->y * pf->height; | ||
1209 | |||
1210 | if (s->bidir) { /* scroll bidirectional */ | ||
1211 | if (s->offset <= 0) { | ||
1212 | /* at beginning of line */ | ||
1213 | s->offset = 0; | ||
1214 | s->backward = false; | ||
1215 | s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; | ||
1216 | } | ||
1217 | if (s->offset >= s->width - (current_vp->width - xpos)) { | ||
1218 | /* at end of line */ | ||
1219 | s->offset = s->width - (current_vp->width - xpos); | ||
1220 | s->backward = true; | ||
1221 | s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; | ||
1222 | } | ||
1223 | } | ||
1224 | else { | ||
1225 | /* scroll forward the whole time */ | ||
1226 | if (s->offset >= s->width) | ||
1227 | s->offset %= s->width; | ||
1228 | } | ||
1229 | |||
1230 | lastmode = current_vp->drawmode; | ||
1231 | current_vp->drawmode = (s->style&STYLE_INVERT) ? | ||
1232 | (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; | ||
1233 | lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line); | ||
1234 | current_vp->drawmode = lastmode; | ||
1235 | lcd_remote_update_viewport_rect(xpos, ypos, | ||
1236 | current_vp->width - xpos, pf->height); | ||
1237 | } | ||
1238 | |||
1239 | lcd_remote_set_viewport(old_vp); | ||
1240 | } | ||
1241 | 23 | ||
1242 | /* LCD init */ | 24 | /* Compile 2 bit vertical interleaved LCD driver for remote LCD */ |
1243 | void lcd_remote_init(void) | 25 | #define LCDFN(fn) lcd_remote_ ## fn |
1244 | { | 26 | #define FBFN(fn) fb_remote_ ## fn |
1245 | /* Initialise the viewport */ | 27 | #define LCDM(ma) LCD_REMOTE_ ## ma |
1246 | lcd_remote_set_viewport(NULL); | ||
1247 | 28 | ||
1248 | #ifndef SIMULATOR | 29 | #include "lcd-2bit-vi.c" |
1249 | /* Call device specific init */ | ||
1250 | lcd_remote_init_device(); | ||
1251 | #endif | ||
1252 | } | ||