diff options
Diffstat (limited to 'firmware/drivers/lcd-remote-1bit-v.c')
-rw-r--r-- | firmware/drivers/lcd-remote-1bit-v.c | 884 |
1 files changed, 5 insertions, 879 deletions
diff --git a/firmware/drivers/lcd-remote-1bit-v.c b/firmware/drivers/lcd-remote-1bit-v.c index 20c6f6655c..bed7cc6671 100644 --- a/firmware/drivers/lcd-remote-1bit-v.c +++ b/firmware/drivers/lcd-remote-1bit-v.c | |||
@@ -17,885 +17,11 @@ | |||
17 | * | 17 | * |
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | 19 | ||
20 | #include "config.h" | ||
21 | #include "cpu.h" | ||
22 | #include "lcd.h" | ||
23 | #include "lcd-remote.h" | 20 | #include "lcd-remote.h" |
24 | #include "kernel.h" | ||
25 | #include "thread.h" | ||
26 | #include <string.h> | ||
27 | #include <stdlib.h> | ||
28 | #include "file.h" | ||
29 | #include "debug.h" | ||
30 | #include "system.h" | ||
31 | #include "font.h" | ||
32 | #include "rbunicode.h" | ||
33 | #include "bidi.h" | ||
34 | #include "scroll_engine.h" | ||
35 | 21 | ||
36 | /*** globals ***/ | 22 | /* Compile 1 bit vertical packing LCD driver for remote LCD */ |
23 | #define LCDFN(fn) lcd_remote_ ## fn | ||
24 | #define FBFN(fn) fb_remote_ ## fn | ||
25 | #define LCDM(ma) LCD_REMOTE_ ## ma | ||
37 | 26 | ||
38 | fb_remote_data lcd_remote_framebuffer[LCD_REMOTE_FBHEIGHT][LCD_REMOTE_FBWIDTH] | 27 | #include "lcd-1bit-vert.c" |
39 | IBSS_ATTR; | ||
40 | |||
41 | static struct viewport default_vp = | ||
42 | { | ||
43 | .x = 0, | ||
44 | .y = 0, | ||
45 | .width = LCD_REMOTE_WIDTH, | ||
46 | .height = LCD_REMOTE_HEIGHT, | ||
47 | .font = FONT_SYSFIXED, | ||
48 | .drawmode = DRMODE_SOLID, | ||
49 | .xmargin = 0, | ||
50 | .ymargin = 0, | ||
51 | }; | ||
52 | |||
53 | static struct viewport* current_vp IDATA_ATTR = &default_vp; | ||
54 | |||
55 | /*** Viewports ***/ | ||
56 | |||
57 | void lcd_remote_set_viewport(struct viewport* vp) | ||
58 | { | ||
59 | if (vp == NULL) | ||
60 | current_vp = &default_vp; | ||
61 | else | ||
62 | current_vp = vp; | ||
63 | } | ||
64 | |||
65 | void lcd_remote_update_viewport(void) | ||
66 | { | ||
67 | lcd_remote_update_rect(current_vp->x, current_vp->y, | ||
68 | current_vp->width, current_vp->height); | ||
69 | } | ||
70 | |||
71 | void lcd_remote_update_viewport_rect(int x, int y, int width, int height) | ||
72 | { | ||
73 | lcd_remote_update_rect(current_vp->x + x, current_vp->y + y, width, height); | ||
74 | } | ||
75 | |||
76 | |||
77 | /*** parameter handling ***/ | ||
78 | |||
79 | void lcd_remote_set_drawmode(int mode) | ||
80 | { | ||
81 | current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); | ||
82 | } | ||
83 | |||
84 | int lcd_remote_get_drawmode(void) | ||
85 | { | ||
86 | return current_vp->drawmode; | ||
87 | } | ||
88 | |||
89 | void lcd_remote_setmargins(int x, int y) | ||
90 | { | ||
91 | current_vp->xmargin = x; | ||
92 | current_vp->ymargin = y; | ||
93 | } | ||
94 | |||
95 | int lcd_remote_getwidth(void) | ||
96 | { | ||
97 | return current_vp->width; | ||
98 | } | ||
99 | |||
100 | int lcd_remote_getheight(void) | ||
101 | { | ||
102 | return current_vp->height; | ||
103 | } | ||
104 | |||
105 | int lcd_remote_getxmargin(void) | ||
106 | { | ||
107 | return current_vp->xmargin; | ||
108 | } | ||
109 | |||
110 | int lcd_remote_getymargin(void) | ||
111 | { | ||
112 | return current_vp->ymargin; | ||
113 | } | ||
114 | |||
115 | void lcd_remote_setfont(int newfont) | ||
116 | { | ||
117 | current_vp->font = newfont; | ||
118 | } | ||
119 | |||
120 | int lcd_remote_getfont(void) | ||
121 | { | ||
122 | return current_vp->font; | ||
123 | } | ||
124 | |||
125 | int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h) | ||
126 | { | ||
127 | return font_getstringsize(str, w, h, current_vp->font); | ||
128 | } | ||
129 | |||
130 | /*** low-level drawing functions ***/ | ||
131 | |||
132 | static void setpixel(int x, int y) | ||
133 | { | ||
134 | lcd_remote_framebuffer[y>>3][x] |= 1 << (y & 7); | ||
135 | } | ||
136 | |||
137 | static void clearpixel(int x, int y) | ||
138 | { | ||
139 | lcd_remote_framebuffer[y>>3][x] &= ~(1 << (y & 7)); | ||
140 | } | ||
141 | |||
142 | static void flippixel(int x, int y) | ||
143 | { | ||
144 | lcd_remote_framebuffer[y>>3][x] ^= 1 << (y & 7); | ||
145 | } | ||
146 | |||
147 | static void nopixel(int x, int y) | ||
148 | { | ||
149 | (void)x; | ||
150 | (void)y; | ||
151 | } | ||
152 | |||
153 | lcd_remote_pixelfunc_type* const lcd_remote_pixelfuncs[8] = { | ||
154 | flippixel, nopixel, setpixel, setpixel, | ||
155 | nopixel, clearpixel, nopixel, clearpixel | ||
156 | }; | ||
157 | |||
158 | static void flipblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
159 | ICODE_ATTR; | ||
160 | static void flipblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
161 | { | ||
162 | *address ^= bits & mask; | ||
163 | } | ||
164 | |||
165 | static void bgblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
166 | ICODE_ATTR; | ||
167 | static void bgblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
168 | { | ||
169 | *address &= bits | ~mask; | ||
170 | } | ||
171 | |||
172 | static void fgblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
173 | ICODE_ATTR; | ||
174 | static void fgblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
175 | { | ||
176 | *address |= bits & mask; | ||
177 | } | ||
178 | |||
179 | static void solidblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
180 | ICODE_ATTR; | ||
181 | static void solidblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
182 | { | ||
183 | unsigned data = *address; | ||
184 | |||
185 | bits ^= data; | ||
186 | *address = data ^ (bits & mask); | ||
187 | } | ||
188 | |||
189 | static void flipinvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
190 | ICODE_ATTR; | ||
191 | static void flipinvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
192 | { | ||
193 | *address ^= ~bits & mask; | ||
194 | } | ||
195 | |||
196 | static void bginvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
197 | ICODE_ATTR; | ||
198 | static void bginvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
199 | { | ||
200 | *address &= ~(bits & mask); | ||
201 | } | ||
202 | |||
203 | static void fginvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
204 | ICODE_ATTR; | ||
205 | static void fginvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
206 | { | ||
207 | *address |= ~bits & mask; | ||
208 | } | ||
209 | |||
210 | static void solidinvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
211 | ICODE_ATTR; | ||
212 | static void solidinvblock(fb_remote_data *address, unsigned mask, unsigned bits) | ||
213 | { | ||
214 | unsigned data = *address; | ||
215 | |||
216 | bits = ~bits ^ data; | ||
217 | *address = data ^ (bits & mask); | ||
218 | } | ||
219 | |||
220 | lcd_remote_blockfunc_type* const lcd_remote_blockfuncs[8] = { | ||
221 | flipblock, bgblock, fgblock, solidblock, | ||
222 | flipinvblock, bginvblock, fginvblock, solidinvblock | ||
223 | }; | ||
224 | |||
225 | /*** drawing functions ***/ | ||
226 | |||
227 | /* Clear the whole display */ | ||
228 | void lcd_remote_clear_display(void) | ||
229 | { | ||
230 | unsigned bits = (current_vp->drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0; | ||
231 | |||
232 | memset(lcd_remote_framebuffer, bits, sizeof lcd_remote_framebuffer); | ||
233 | |||
234 | lcd_remote_scroll_info.lines = 0; | ||
235 | } | ||
236 | |||
237 | /* Clear the current viewport */ | ||
238 | void lcd_remote_clear_viewport(void) | ||
239 | { | ||
240 | int oldmode; | ||
241 | |||
242 | if (current_vp == &default_vp) | ||
243 | { | ||
244 | lcd_remote_clear_display(); | ||
245 | } | ||
246 | else | ||
247 | { | ||
248 | oldmode = current_vp->drawmode; | ||
249 | |||
250 | /* Invert the INVERSEVID bit and set basic mode to SOLID */ | ||
251 | current_vp->drawmode = (~current_vp->drawmode & DRMODE_INVERSEVID) | | ||
252 | DRMODE_SOLID; | ||
253 | |||
254 | lcd_remote_fillrect(0, 0, current_vp->width, current_vp->height); | ||
255 | |||
256 | current_vp->drawmode = oldmode; | ||
257 | |||
258 | lcd_remote_scroll_stop(current_vp); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | /* Set a single pixel */ | ||
263 | void lcd_remote_drawpixel(int x, int y) | ||
264 | { | ||
265 | if (((unsigned)x < (unsigned)current_vp->width) && | ||
266 | ((unsigned)y < (unsigned)current_vp->height)) | ||
267 | lcd_remote_pixelfuncs[current_vp->drawmode](current_vp->x+x, current_vp->y+y); | ||
268 | } | ||
269 | |||
270 | /* Draw a line */ | ||
271 | void lcd_remote_drawline(int x1, int y1, int x2, int y2) | ||
272 | { | ||
273 | int numpixels; | ||
274 | int i; | ||
275 | int deltax, deltay; | ||
276 | int d, dinc1, dinc2; | ||
277 | int x, xinc1, xinc2; | ||
278 | int y, yinc1, yinc2; | ||
279 | lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[current_vp->drawmode]; | ||
280 | |||
281 | deltax = abs(x2 - x1); | ||
282 | deltay = abs(y2 - y1); | ||
283 | xinc2 = 1; | ||
284 | yinc2 = 1; | ||
285 | |||
286 | if (deltax >= deltay) | ||
287 | { | ||
288 | numpixels = deltax; | ||
289 | d = 2 * deltay - deltax; | ||
290 | dinc1 = deltay * 2; | ||
291 | dinc2 = (deltay - deltax) * 2; | ||
292 | xinc1 = 1; | ||
293 | yinc1 = 0; | ||
294 | } | ||
295 | else | ||
296 | { | ||
297 | numpixels = deltay; | ||
298 | d = 2 * deltax - deltay; | ||
299 | dinc1 = deltax * 2; | ||
300 | dinc2 = (deltax - deltay) * 2; | ||
301 | xinc1 = 0; | ||
302 | yinc1 = 1; | ||
303 | } | ||
304 | numpixels++; /* include endpoints */ | ||
305 | |||
306 | if (x1 > x2) | ||
307 | { | ||
308 | xinc1 = -xinc1; | ||
309 | xinc2 = -xinc2; | ||
310 | } | ||
311 | |||
312 | if (y1 > y2) | ||
313 | { | ||
314 | yinc1 = -yinc1; | ||
315 | yinc2 = -yinc2; | ||
316 | } | ||
317 | |||
318 | x = x1; | ||
319 | y = y1; | ||
320 | |||
321 | for (i = 0; i < numpixels; i++) | ||
322 | { | ||
323 | if (((unsigned)x < (unsigned)current_vp->width) && ((unsigned)y < (unsigned)current_vp->height)) | ||
324 | pfunc(x + current_vp->x, y + current_vp->y); | ||
325 | |||
326 | if (d < 0) | ||
327 | { | ||
328 | d += dinc1; | ||
329 | x += xinc1; | ||
330 | y += yinc1; | ||
331 | } | ||
332 | else | ||
333 | { | ||
334 | d += dinc2; | ||
335 | x += xinc2; | ||
336 | y += yinc2; | ||
337 | } | ||
338 | } | ||
339 | } | ||
340 | |||
341 | /* Draw a horizontal line (optimised) */ | ||
342 | void lcd_remote_hline(int x1, int x2, int y) | ||
343 | { | ||
344 | int x, width; | ||
345 | fb_remote_data *dst, *dst_end; | ||
346 | unsigned mask; | ||
347 | lcd_remote_blockfunc_type *bfunc; | ||
348 | |||
349 | /* direction flip */ | ||
350 | if (x2 < x1) | ||
351 | { | ||
352 | x = x1; | ||
353 | x1 = x2; | ||
354 | x2 = x; | ||
355 | } | ||
356 | |||
357 | /* nothing to draw? */ | ||
358 | if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width) | ||
359 | || (x2 < 0)) | ||
360 | return; | ||
361 | |||
362 | /* clipping */ | ||
363 | if (x1 < 0) | ||
364 | x1 = 0; | ||
365 | if (x2 >= current_vp->width) | ||
366 | x2 = current_vp->width-1; | ||
367 | |||
368 | width = x2 - x1 + 1; | ||
369 | |||
370 | /* Adjust x1 and y to viewport */ | ||
371 | x1 += current_vp->x; | ||
372 | y += current_vp->y; | ||
373 | |||
374 | bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; | ||
375 | dst = &lcd_remote_framebuffer[y>>3][x1]; | ||
376 | mask = 1 << (y & 7); | ||
377 | |||
378 | dst_end = dst + width; | ||
379 | do | ||
380 | bfunc(dst++, mask, 0xFFu); | ||
381 | while (dst < dst_end); | ||
382 | } | ||
383 | |||
384 | /* Draw a vertical line (optimised) */ | ||
385 | void lcd_remote_vline(int x, int y1, int y2) | ||
386 | { | ||
387 | int ny; | ||
388 | fb_remote_data *dst; | ||
389 | unsigned mask, mask_bottom; | ||
390 | lcd_remote_blockfunc_type *bfunc; | ||
391 | |||
392 | /* direction flip */ | ||
393 | if (y2 < y1) | ||
394 | { | ||
395 | ny = y1; | ||
396 | y1 = y2; | ||
397 | y2 = ny; | ||
398 | } | ||
399 | |||
400 | /* nothing to draw? */ | ||
401 | if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height) | ||
402 | || (y2 < 0)) | ||
403 | return; | ||
404 | |||
405 | /* clipping */ | ||
406 | if (y1 < 0) | ||
407 | y1 = 0; | ||
408 | if (y2 >= current_vp->height) | ||
409 | y2 = current_vp->height-1; | ||
410 | |||
411 | /* adjust for viewport */ | ||
412 | y1 += current_vp->y; | ||
413 | y2 += current_vp->y; | ||
414 | x += current_vp->x; | ||
415 | |||
416 | bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; | ||
417 | dst = &lcd_remote_framebuffer[y1>>3][x]; | ||
418 | ny = y2 - (y1 & ~7); | ||
419 | mask = 0xFFu << (y1 & 7); | ||
420 | mask_bottom = 0xFFu >> (~ny & 7); | ||
421 | |||
422 | for (; ny >= 8; ny -= 8) | ||
423 | { | ||
424 | bfunc(dst, mask, 0xFFu); | ||
425 | dst += LCD_REMOTE_WIDTH; | ||
426 | mask = 0xFFu; | ||
427 | } | ||
428 | mask &= mask_bottom; | ||
429 | bfunc(dst, mask, 0xFFu); | ||
430 | } | ||
431 | |||
432 | /* Draw a rectangular box */ | ||
433 | void lcd_remote_drawrect(int x, int y, int width, int height) | ||
434 | { | ||
435 | if ((width <= 0) || (height <= 0)) | ||
436 | return; | ||
437 | |||
438 | int x2 = x + width - 1; | ||
439 | int y2 = y + height - 1; | ||
440 | |||
441 | lcd_remote_vline(x, y, y2); | ||
442 | lcd_remote_vline(x2, y, y2); | ||
443 | lcd_remote_hline(x, x2, y); | ||
444 | lcd_remote_hline(x, x2, y2); | ||
445 | } | ||
446 | |||
447 | /* Fill a rectangular area */ | ||
448 | void lcd_remote_fillrect(int x, int y, int width, int height) | ||
449 | { | ||
450 | int ny; | ||
451 | fb_remote_data *dst, *dst_end; | ||
452 | unsigned mask, mask_bottom; | ||
453 | unsigned bits = 0; | ||
454 | lcd_remote_blockfunc_type *bfunc; | ||
455 | bool fillopt = false; | ||
456 | |||
457 | /* nothing to draw? */ | ||
458 | if ((width <= 0) || (height <= 0) || (x >= current_vp->width) | ||
459 | || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) | ||
460 | return; | ||
461 | |||
462 | /* clipping */ | ||
463 | if (x < 0) | ||
464 | { | ||
465 | width += x; | ||
466 | x = 0; | ||
467 | } | ||
468 | if (y < 0) | ||
469 | { | ||
470 | height += y; | ||
471 | y = 0; | ||
472 | } | ||
473 | if (x + width > current_vp->width) | ||
474 | width = current_vp->width - x; | ||
475 | if (y + height > current_vp->height) | ||
476 | height = current_vp->height - y; | ||
477 | |||
478 | /* adjust for viewport */ | ||
479 | x += current_vp->x; | ||
480 | y += current_vp->y; | ||
481 | |||
482 | if (current_vp->drawmode & DRMODE_INVERSEVID) | ||
483 | { | ||
484 | if (current_vp->drawmode & DRMODE_BG) | ||
485 | { | ||
486 | fillopt = true; | ||
487 | } | ||
488 | } | ||
489 | else | ||
490 | { | ||
491 | if (current_vp->drawmode & DRMODE_FG) | ||
492 | { | ||
493 | fillopt = true; | ||
494 | bits = 0xFFu; | ||
495 | } | ||
496 | } | ||
497 | |||
498 | bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; | ||
499 | dst = &lcd_remote_framebuffer[y>>3][x]; | ||
500 | ny = height - 1 + (y & 7); | ||
501 | mask = 0xFFu << (y & 7); | ||
502 | mask_bottom = 0xFFu >> (~ny & 7); | ||
503 | |||
504 | for (; ny >= 8; ny -= 8) | ||
505 | { | ||
506 | if (fillopt && (mask == 0xFFu)) | ||
507 | memset(dst, bits, width); | ||
508 | else | ||
509 | { | ||
510 | fb_remote_data *dst_row = dst; | ||
511 | |||
512 | dst_end = dst_row + width; | ||
513 | do | ||
514 | bfunc(dst_row++, mask, 0xFFu); | ||
515 | while (dst_row < dst_end); | ||
516 | } | ||
517 | |||
518 | dst += LCD_REMOTE_WIDTH; | ||
519 | mask = 0xFFu; | ||
520 | } | ||
521 | mask &= mask_bottom; | ||
522 | |||
523 | if (fillopt && (mask == 0xFFu)) | ||
524 | memset(dst, bits, width); | ||
525 | else | ||
526 | { | ||
527 | dst_end = dst + width; | ||
528 | do | ||
529 | bfunc(dst++, mask, 0xFFu); | ||
530 | while (dst < dst_end); | ||
531 | } | ||
532 | } | ||
533 | |||
534 | /* About Rockbox' internal bitmap format: | ||
535 | * | ||
536 | * A bitmap contains one bit for every pixel that defines if that pixel is | ||
537 | * black (1) or white (0). Bits within a byte are arranged vertically, LSB | ||
538 | * at top. | ||
539 | * The bytes are stored in row-major order, with byte 0 being top left, | ||
540 | * byte 1 2nd from left etc. The first row of bytes defines pixel rows | ||
541 | * 0..7, the second row defines pixel row 8..15 etc. | ||
542 | * | ||
543 | * This is the same as the internal lcd hw format. */ | ||
544 | |||
545 | /* Draw a partial bitmap */ | ||
546 | void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y, | ||
547 | int stride, int x, int y, int width, int height) | ||
548 | ICODE_ATTR; | ||
549 | void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y, | ||
550 | int stride, int x, int y, int width, int height) | ||
551 | { | ||
552 | int shift, ny; | ||
553 | fb_remote_data *dst, *dst_end; | ||
554 | unsigned mask, mask_bottom; | ||
555 | lcd_remote_blockfunc_type *bfunc; | ||
556 | |||
557 | /* nothing to draw? */ | ||
558 | if ((width <= 0) || (height <= 0) || (x >= current_vp->width) | ||
559 | || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) | ||
560 | return; | ||
561 | |||
562 | /* clipping */ | ||
563 | if (x < 0) | ||
564 | { | ||
565 | width += x; | ||
566 | src_x -= x; | ||
567 | x = 0; | ||
568 | } | ||
569 | if (y < 0) | ||
570 | { | ||
571 | height += y; | ||
572 | src_y -= y; | ||
573 | y = 0; | ||
574 | } | ||
575 | if (x + width > current_vp->width) | ||
576 | width = current_vp->width - x; | ||
577 | if (y + height > current_vp->height) | ||
578 | height = current_vp->height - y; | ||
579 | |||
580 | /* adjust for viewports */ | ||
581 | x += current_vp->x; | ||
582 | y += current_vp->y; | ||
583 | |||
584 | src += stride * (src_y >> 3) + src_x; /* move starting point */ | ||
585 | src_y &= 7; | ||
586 | y -= src_y; | ||
587 | dst = &lcd_remote_framebuffer[y>>3][x]; | ||
588 | shift = y & 7; | ||
589 | ny = height - 1 + shift + src_y; | ||
590 | |||
591 | bfunc = lcd_remote_blockfuncs[current_vp->drawmode]; | ||
592 | mask = 0xFFu << (shift + src_y); | ||
593 | mask_bottom = 0xFFu >> (~ny & 7); | ||
594 | |||
595 | if (shift == 0) | ||
596 | { | ||
597 | bool copyopt = (current_vp->drawmode == DRMODE_SOLID); | ||
598 | |||
599 | for (; ny >= 8; ny -= 8) | ||
600 | { | ||
601 | if (copyopt && (mask == 0xFFu)) | ||
602 | memcpy(dst, src, width); | ||
603 | else | ||
604 | { | ||
605 | const unsigned char *src_row = src; | ||
606 | fb_remote_data *dst_row = dst; | ||
607 | |||
608 | dst_end = dst_row + width; | ||
609 | do | ||
610 | bfunc(dst_row++, mask, *src_row++); | ||
611 | while (dst_row < dst_end); | ||
612 | } | ||
613 | |||
614 | src += stride; | ||
615 | dst += LCD_REMOTE_WIDTH; | ||
616 | mask = 0xFFu; | ||
617 | } | ||
618 | mask &= mask_bottom; | ||
619 | |||
620 | if (copyopt && (mask == 0xFFu)) | ||
621 | memcpy(dst, src, width); | ||
622 | else | ||
623 | { | ||
624 | dst_end = dst + width; | ||
625 | do | ||
626 | bfunc(dst++, mask, *src++); | ||
627 | while (dst < dst_end); | ||
628 | } | ||
629 | } | ||
630 | else | ||
631 | { | ||
632 | dst_end = dst + width; | ||
633 | do | ||
634 | { | ||
635 | const unsigned char *src_col = src++; | ||
636 | fb_remote_data *dst_col = dst++; | ||
637 | unsigned mask_col = mask; | ||
638 | unsigned data = 0; | ||
639 | |||
640 | for (y = ny; y >= 8; y -= 8) | ||
641 | { | ||
642 | data |= *src_col << shift; | ||
643 | |||
644 | if (mask_col & 0xFFu) | ||
645 | { | ||
646 | bfunc(dst_col, mask_col, data); | ||
647 | mask_col = 0xFFu; | ||
648 | } | ||
649 | else | ||
650 | mask_col >>= 8; | ||
651 | |||
652 | src_col += stride; | ||
653 | dst_col += LCD_REMOTE_WIDTH; | ||
654 | data >>= 8; | ||
655 | } | ||
656 | data |= *src_col << shift; | ||
657 | bfunc(dst_col, mask_col & mask_bottom, data); | ||
658 | } | ||
659 | while (dst < dst_end); | ||
660 | } | ||
661 | } | ||
662 | |||
663 | /* Draw a full bitmap */ | ||
664 | void lcd_remote_bitmap(const unsigned char *src, int x, int y, int width, | ||
665 | int height) | ||
666 | { | ||
667 | lcd_remote_bitmap_part(src, 0, 0, width, x, y, width, height); | ||
668 | } | ||
669 | |||
670 | /* put a string at a given pixel position, skipping first ofs pixel columns */ | ||
671 | void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str) | ||
672 | { | ||
673 | unsigned short ch; | ||
674 | unsigned short *ucs; | ||
675 | struct font* pf = font_get(current_vp->font); | ||
676 | |||
677 | ucs = bidi_l2v(str, 1); | ||
678 | |||
679 | while ((ch = *ucs++) != 0 && x < current_vp->width) | ||
680 | { | ||
681 | int width; | ||
682 | const unsigned char *bits; | ||
683 | |||
684 | /* get proportional width and glyph bits */ | ||
685 | width = font_get_width(pf, ch); | ||
686 | |||
687 | if (ofs > width) | ||
688 | { | ||
689 | ofs -= width; | ||
690 | continue; | ||
691 | } | ||
692 | |||
693 | bits = font_get_bits(pf, ch); | ||
694 | |||
695 | lcd_remote_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, | ||
696 | pf->height); | ||
697 | |||
698 | x += width - ofs; | ||
699 | ofs = 0; | ||
700 | } | ||
701 | } | ||
702 | |||
703 | /* put a string at a given pixel position */ | ||
704 | void lcd_remote_putsxy(int x, int y, const unsigned char *str) | ||
705 | { | ||
706 | lcd_remote_putsxyofs(x, y, 0, str); | ||
707 | } | ||
708 | |||
709 | /*** line oriented text output ***/ | ||
710 | |||
711 | /* put a string at a given char position */ | ||
712 | void lcd_remote_puts(int x, int y, const unsigned char *str) | ||
713 | { | ||
714 | lcd_remote_puts_style_offset(x, y, str, STYLE_DEFAULT, 0); | ||
715 | } | ||
716 | |||
717 | void lcd_remote_puts_style(int x, int y, const unsigned char *str, int style) | ||
718 | { | ||
719 | lcd_remote_puts_style_offset(x, y, str, style, 0); | ||
720 | } | ||
721 | |||
722 | void lcd_remote_puts_offset(int x, int y, const unsigned char *str, int offset) | ||
723 | { | ||
724 | lcd_remote_puts_style_offset(x, y, str, STYLE_DEFAULT, offset); | ||
725 | } | ||
726 | |||
727 | /* put a string at a given char position, style, and pixel position, | ||
728 | * skipping first offset pixel columns */ | ||
729 | void lcd_remote_puts_style_offset(int x, int y, const unsigned char *str, | ||
730 | int style, int offset) | ||
731 | { | ||
732 | int xpos,ypos,w,h,xrect; | ||
733 | int lastmode = current_vp->drawmode; | ||
734 | |||
735 | /* make sure scrolling is turned off on the line we are updating */ | ||
736 | lcd_remote_scroll_stop_line(current_vp, y); | ||
737 | |||
738 | if(!str || !str[0]) | ||
739 | return; | ||
740 | |||
741 | lcd_remote_getstringsize(str, &w, &h); | ||
742 | xpos = current_vp->xmargin + x*w / utf8length((char *)str); | ||
743 | ypos = current_vp->ymargin + y*h; | ||
744 | current_vp->drawmode = (style & STYLE_INVERT) ? | ||
745 | (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; | ||
746 | lcd_remote_putsxyofs(xpos, ypos, offset, str); | ||
747 | current_vp->drawmode ^= DRMODE_INVERSEVID; | ||
748 | xrect = xpos + MAX(w - offset, 0); | ||
749 | lcd_remote_fillrect(xrect, ypos, current_vp->width - xrect, h); | ||
750 | current_vp->drawmode = lastmode; | ||
751 | } | ||
752 | |||
753 | /*** scrolling ***/ | ||
754 | |||
755 | void lcd_remote_puts_scroll(int x, int y, const unsigned char *string) | ||
756 | { | ||
757 | lcd_remote_puts_scroll_style(x, y, string, STYLE_DEFAULT); | ||
758 | } | ||
759 | |||
760 | void lcd_remote_puts_scroll_style(int x, int y, const unsigned char *string, int style) | ||
761 | { | ||
762 | lcd_remote_puts_scroll_style_offset(x, y, string, style, 0); | ||
763 | } | ||
764 | |||
765 | void lcd_remote_puts_scroll_offset(int x, int y, const unsigned char *string, int offset) | ||
766 | { | ||
767 | lcd_remote_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset); | ||
768 | } | ||
769 | |||
770 | void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *string, | ||
771 | int style, int offset) | ||
772 | { | ||
773 | struct scrollinfo* s; | ||
774 | int w, h; | ||
775 | |||
776 | if ((unsigned)y >= (unsigned)current_vp->height) | ||
777 | return; | ||
778 | |||
779 | /* remove any previously scrolling line at the same location */ | ||
780 | lcd_remote_scroll_stop_line(current_vp, y); | ||
781 | |||
782 | if (lcd_remote_scroll_info.lines >= LCD_REMOTE_SCROLLABLE_LINES) return; | ||
783 | |||
784 | s = &lcd_remote_scroll_info.scroll[lcd_remote_scroll_info.lines]; | ||
785 | |||
786 | s->start_tick = current_tick + lcd_remote_scroll_info.delay; | ||
787 | s->style = style; | ||
788 | if (style & STYLE_INVERT) { | ||
789 | lcd_remote_puts_style_offset(x,y,string,STYLE_INVERT,offset); | ||
790 | } | ||
791 | else | ||
792 | lcd_remote_puts_offset(x,y,string,offset); | ||
793 | |||
794 | lcd_remote_getstringsize(string, &w, &h); | ||
795 | |||
796 | if (current_vp->width - x * 8 - current_vp->xmargin < w) { | ||
797 | /* prepare scroll line */ | ||
798 | char *end; | ||
799 | |||
800 | memset(s->line, 0, sizeof s->line); | ||
801 | strcpy(s->line, (char *)string); | ||
802 | |||
803 | /* get width */ | ||
804 | s->width = lcd_remote_getstringsize((unsigned char *)s->line, &w, &h); | ||
805 | |||
806 | /* scroll bidirectional or forward only depending on the string | ||
807 | width */ | ||
808 | if ( lcd_remote_scroll_info.bidir_limit ) { | ||
809 | s->bidir = s->width < (current_vp->width - current_vp->xmargin) * | ||
810 | (100 + lcd_remote_scroll_info.bidir_limit) / 100; | ||
811 | } | ||
812 | else | ||
813 | s->bidir = false; | ||
814 | |||
815 | if (!s->bidir) { /* add spaces if scrolling in the round */ | ||
816 | strcat(s->line, " "); | ||
817 | /* get new width incl. spaces */ | ||
818 | s->width = lcd_remote_getstringsize((unsigned char *)s->line, &w, &h); | ||
819 | } | ||
820 | |||
821 | end = strchr(s->line, '\0'); | ||
822 | strncpy(end, (char *)string, current_vp->width/2); | ||
823 | |||
824 | s->vp = current_vp; | ||
825 | s->y = y; | ||
826 | s->len = utf8length((char *)string); | ||
827 | s->offset = offset; | ||
828 | s->startx = current_vp->xmargin + x * s->width / s->len; | ||
829 | s->backward = false; | ||
830 | |||
831 | lcd_remote_scroll_info.lines++; | ||
832 | } | ||
833 | } | ||
834 | |||
835 | void lcd_remote_scroll_fn(void) | ||
836 | { | ||
837 | struct font* pf; | ||
838 | struct scrollinfo* s; | ||
839 | int index; | ||
840 | int xpos, ypos; | ||
841 | int lastmode; | ||
842 | struct viewport* old_vp = current_vp; | ||
843 | |||
844 | for ( index = 0; index < lcd_remote_scroll_info.lines; index++ ) { | ||
845 | s = &lcd_remote_scroll_info.scroll[index]; | ||
846 | |||
847 | /* check pause */ | ||
848 | if (TIME_BEFORE(current_tick, s->start_tick)) | ||
849 | continue; | ||
850 | |||
851 | lcd_remote_set_viewport(s->vp); | ||
852 | |||
853 | if (s->backward) | ||
854 | s->offset -= lcd_remote_scroll_info.step; | ||
855 | else | ||
856 | s->offset += lcd_remote_scroll_info.step; | ||
857 | |||
858 | pf = font_get(current_vp->font); | ||
859 | xpos = s->startx; | ||
860 | ypos = current_vp->ymargin + s->y * pf->height; | ||
861 | |||
862 | if (s->bidir) { /* scroll bidirectional */ | ||
863 | if (s->offset <= 0) { | ||
864 | /* at beginning of line */ | ||
865 | s->offset = 0; | ||
866 | s->backward = false; | ||
867 | s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; | ||
868 | } | ||
869 | if (s->offset >= s->width - (current_vp->width - xpos)) { | ||
870 | /* at end of line */ | ||
871 | s->offset = s->width - (current_vp->width - xpos); | ||
872 | s->backward = true; | ||
873 | s->start_tick = current_tick + lcd_remote_scroll_info.delay*2; | ||
874 | } | ||
875 | } | ||
876 | else { | ||
877 | /* scroll forward the whole time */ | ||
878 | if (s->offset >= s->width) | ||
879 | s->offset %= s->width; | ||
880 | } | ||
881 | |||
882 | lastmode = current_vp->drawmode; | ||
883 | current_vp->drawmode = (s->style&STYLE_INVERT) ? | ||
884 | (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; | ||
885 | lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line); | ||
886 | current_vp->drawmode = lastmode; | ||
887 | lcd_remote_update_viewport_rect(xpos, ypos, | ||
888 | current_vp->width - xpos, pf->height); | ||
889 | } | ||
890 | |||
891 | lcd_remote_set_viewport(old_vp); | ||
892 | } | ||
893 | |||
894 | /* LCD init */ | ||
895 | void lcd_remote_init(void) | ||
896 | { | ||
897 | #ifndef SIMULATOR | ||
898 | /* Call device specific init */ | ||
899 | lcd_remote_init_device(); | ||
900 | #endif | ||
901 | } | ||