diff options
Diffstat (limited to 'firmware/drivers/lcd-remote-2bit-vi.c')
-rw-r--r-- | firmware/drivers/lcd-remote-2bit-vi.c | 1235 |
1 files changed, 6 insertions, 1229 deletions
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 | } | ||