diff options
author | Jens Arnold <amiconn@rockbox.org> | 2006-11-12 13:22:59 +0000 |
---|---|---|
committer | Jens Arnold <amiconn@rockbox.org> | 2006-11-12 13:22:59 +0000 |
commit | 6bdf3ee6f28097e25770ae43e28dd4b59054e88f (patch) | |
tree | fb95473e5753cb801c643e31b1b30033a33bafe6 /firmware/drivers/lcd-1bit-vert.c | |
parent | 3875b5766769a5f75d460614c0279aaad72e0922 (diff) | |
download | rockbox-6bdf3ee6f28097e25770ae43e28dd4b59054e88f.tar.gz rockbox-6bdf3ee6f28097e25770ae43e28dd4b59054e88f.zip |
Split 1 bit LCD code and move appropriate parts to target tree. Only archos code is tested.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11517 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers/lcd-1bit-vert.c')
-rwxr-xr-x | firmware/drivers/lcd-1bit-vert.c | 860 |
1 files changed, 860 insertions, 0 deletions
diff --git a/firmware/drivers/lcd-1bit-vert.c b/firmware/drivers/lcd-1bit-vert.c new file mode 100755 index 0000000000..6ae92af72b --- /dev/null +++ b/firmware/drivers/lcd-1bit-vert.c | |||
@@ -0,0 +1,860 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 by Alan Korr | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "config.h" | ||
20 | |||
21 | #include "lcd.h" | ||
22 | #include "kernel.h" | ||
23 | #include "thread.h" | ||
24 | #include <string.h> | ||
25 | #include <stdlib.h> | ||
26 | #include "file.h" | ||
27 | #include "debug.h" | ||
28 | #include "system.h" | ||
29 | #include "font.h" | ||
30 | #include "hwcompat.h" | ||
31 | #include "rbunicode.h" | ||
32 | #include "bidi.h" | ||
33 | |||
34 | /*** definitions ***/ | ||
35 | |||
36 | #define SCROLLABLE_LINES ((LCD_HEIGHT+4)/5 < 32 ? (LCD_HEIGHT+4)/5 : 32) | ||
37 | |||
38 | /*** globals ***/ | ||
39 | |||
40 | unsigned char lcd_framebuffer[LCD_HEIGHT/8][LCD_WIDTH]; | ||
41 | |||
42 | static int drawmode = DRMODE_SOLID; | ||
43 | static int xmargin = 0; | ||
44 | static int ymargin = 0; | ||
45 | static int curfont = FONT_SYSFIXED; | ||
46 | |||
47 | /* scrolling */ | ||
48 | static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */ | ||
49 | static void scroll_thread(void); | ||
50 | static char scroll_stack[DEFAULT_STACK_SIZE]; | ||
51 | static const char scroll_name[] = "scroll"; | ||
52 | static int scroll_ticks = 12; /* # of ticks between updates*/ | ||
53 | static int scroll_delay = HZ/2; /* ticks delay before start */ | ||
54 | static int scroll_step = 6; /* pixels per scroll step */ | ||
55 | static int bidir_limit = 50; /* percent */ | ||
56 | static struct scrollinfo scroll[SCROLLABLE_LINES]; | ||
57 | |||
58 | static const char scroll_tick_table[16] = { | ||
59 | /* Hz values: | ||
60 | 1, 1.25, 1.55, 2, 2.5, 3.12, 4, 5, 6.25, 8.33, 10, 12.5, 16.7, 20, 25, 33 */ | ||
61 | 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3 | ||
62 | }; | ||
63 | |||
64 | /* LCD init */ | ||
65 | void lcd_init(void) | ||
66 | { | ||
67 | lcd_clear_display(); | ||
68 | /* Call device specific init */ | ||
69 | lcd_init_device(); | ||
70 | create_thread(scroll_thread, scroll_stack, | ||
71 | sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE)); | ||
72 | } | ||
73 | |||
74 | /*** parameter handling ***/ | ||
75 | |||
76 | void lcd_set_drawmode(int mode) | ||
77 | { | ||
78 | drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); | ||
79 | } | ||
80 | |||
81 | int lcd_get_drawmode(void) | ||
82 | { | ||
83 | return drawmode; | ||
84 | } | ||
85 | |||
86 | void lcd_setmargins(int x, int y) | ||
87 | { | ||
88 | xmargin = x; | ||
89 | ymargin = y; | ||
90 | } | ||
91 | |||
92 | int lcd_getxmargin(void) | ||
93 | { | ||
94 | return xmargin; | ||
95 | } | ||
96 | |||
97 | int lcd_getymargin(void) | ||
98 | { | ||
99 | return ymargin; | ||
100 | } | ||
101 | |||
102 | void lcd_setfont(int newfont) | ||
103 | { | ||
104 | curfont = newfont; | ||
105 | } | ||
106 | |||
107 | int lcd_getstringsize(const unsigned char *str, int *w, int *h) | ||
108 | { | ||
109 | return font_getstringsize(str, w, h, curfont); | ||
110 | } | ||
111 | |||
112 | /*** low-level drawing functions ***/ | ||
113 | |||
114 | static void setpixel(int x, int y) | ||
115 | { | ||
116 | lcd_framebuffer[y>>3][x] |= 1 << (y & 7); | ||
117 | } | ||
118 | |||
119 | static void clearpixel(int x, int y) | ||
120 | { | ||
121 | lcd_framebuffer[y>>3][x] &= ~(1 << (y & 7)); | ||
122 | } | ||
123 | |||
124 | static void flippixel(int x, int y) | ||
125 | { | ||
126 | lcd_framebuffer[y>>3][x] ^= 1 << (y & 7); | ||
127 | } | ||
128 | |||
129 | static void nopixel(int x, int y) | ||
130 | { | ||
131 | (void)x; | ||
132 | (void)y; | ||
133 | } | ||
134 | |||
135 | lcd_pixelfunc_type* const lcd_pixelfuncs[8] = { | ||
136 | flippixel, nopixel, setpixel, setpixel, | ||
137 | nopixel, clearpixel, nopixel, clearpixel | ||
138 | }; | ||
139 | |||
140 | static void flipblock(unsigned char *address, unsigned mask, unsigned bits) | ||
141 | ICODE_ATTR; | ||
142 | static void flipblock(unsigned char *address, unsigned mask, unsigned bits) | ||
143 | { | ||
144 | *address ^= bits & mask; | ||
145 | } | ||
146 | |||
147 | static void bgblock(unsigned char *address, unsigned mask, unsigned bits) | ||
148 | ICODE_ATTR; | ||
149 | static void bgblock(unsigned char *address, unsigned mask, unsigned bits) | ||
150 | { | ||
151 | *address &= bits | ~mask; | ||
152 | } | ||
153 | |||
154 | static void fgblock(unsigned char *address, unsigned mask, unsigned bits) | ||
155 | ICODE_ATTR; | ||
156 | static void fgblock(unsigned char *address, unsigned mask, unsigned bits) | ||
157 | { | ||
158 | *address |= bits & mask; | ||
159 | } | ||
160 | |||
161 | static void solidblock(unsigned char *address, unsigned mask, unsigned bits) | ||
162 | ICODE_ATTR; | ||
163 | static void solidblock(unsigned char *address, unsigned mask, unsigned bits) | ||
164 | { | ||
165 | unsigned data = *(char*)address; | ||
166 | |||
167 | bits ^= data; | ||
168 | *address = data ^ (bits & mask); | ||
169 | } | ||
170 | |||
171 | static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
172 | ICODE_ATTR; | ||
173 | static void flipinvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
174 | { | ||
175 | *address ^= ~bits & mask; | ||
176 | } | ||
177 | |||
178 | static void bginvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
179 | ICODE_ATTR; | ||
180 | static void bginvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
181 | { | ||
182 | *address &= ~(bits & mask); | ||
183 | } | ||
184 | |||
185 | static void fginvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
186 | ICODE_ATTR; | ||
187 | static void fginvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
188 | { | ||
189 | *address |= ~bits & mask; | ||
190 | } | ||
191 | |||
192 | static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
193 | ICODE_ATTR; | ||
194 | static void solidinvblock(unsigned char *address, unsigned mask, unsigned bits) | ||
195 | { | ||
196 | unsigned data = *(char *)address; | ||
197 | |||
198 | bits = ~bits ^ data; | ||
199 | *address = data ^ (bits & mask); | ||
200 | } | ||
201 | |||
202 | lcd_blockfunc_type* const lcd_blockfuncs[8] = { | ||
203 | flipblock, bgblock, fgblock, solidblock, | ||
204 | flipinvblock, bginvblock, fginvblock, solidinvblock | ||
205 | }; | ||
206 | |||
207 | /*** drawing functions ***/ | ||
208 | |||
209 | /* Clear the whole display */ | ||
210 | void lcd_clear_display(void) | ||
211 | { | ||
212 | unsigned bits = (drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0; | ||
213 | |||
214 | memset(lcd_framebuffer, bits, sizeof lcd_framebuffer); | ||
215 | scrolling_lines = 0; | ||
216 | } | ||
217 | |||
218 | /* Set a single pixel */ | ||
219 | void lcd_drawpixel(int x, int y) | ||
220 | { | ||
221 | if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) | ||
222 | lcd_pixelfuncs[drawmode](x, y); | ||
223 | } | ||
224 | |||
225 | /* Draw a line */ | ||
226 | void lcd_drawline(int x1, int y1, int x2, int y2) | ||
227 | { | ||
228 | int numpixels; | ||
229 | int i; | ||
230 | int deltax, deltay; | ||
231 | int d, dinc1, dinc2; | ||
232 | int x, xinc1, xinc2; | ||
233 | int y, yinc1, yinc2; | ||
234 | lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; | ||
235 | |||
236 | deltax = abs(x2 - x1); | ||
237 | deltay = abs(y2 - y1); | ||
238 | xinc2 = 1; | ||
239 | yinc2 = 1; | ||
240 | |||
241 | if (deltax >= deltay) | ||
242 | { | ||
243 | numpixels = deltax; | ||
244 | d = 2 * deltay - deltax; | ||
245 | dinc1 = deltay * 2; | ||
246 | dinc2 = (deltay - deltax) * 2; | ||
247 | xinc1 = 1; | ||
248 | yinc1 = 0; | ||
249 | } | ||
250 | else | ||
251 | { | ||
252 | numpixels = deltay; | ||
253 | d = 2 * deltax - deltay; | ||
254 | dinc1 = deltax * 2; | ||
255 | dinc2 = (deltax - deltay) * 2; | ||
256 | xinc1 = 0; | ||
257 | yinc1 = 1; | ||
258 | } | ||
259 | numpixels++; /* include endpoints */ | ||
260 | |||
261 | if (x1 > x2) | ||
262 | { | ||
263 | xinc1 = -xinc1; | ||
264 | xinc2 = -xinc2; | ||
265 | } | ||
266 | |||
267 | if (y1 > y2) | ||
268 | { | ||
269 | yinc1 = -yinc1; | ||
270 | yinc2 = -yinc2; | ||
271 | } | ||
272 | |||
273 | x = x1; | ||
274 | y = y1; | ||
275 | |||
276 | for (i = 0; i < numpixels; i++) | ||
277 | { | ||
278 | if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) | ||
279 | pfunc(x, y); | ||
280 | |||
281 | if (d < 0) | ||
282 | { | ||
283 | d += dinc1; | ||
284 | x += xinc1; | ||
285 | y += yinc1; | ||
286 | } | ||
287 | else | ||
288 | { | ||
289 | d += dinc2; | ||
290 | x += xinc2; | ||
291 | y += yinc2; | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | |||
296 | /* Draw a horizontal line (optimised) */ | ||
297 | void lcd_hline(int x1, int x2, int y) | ||
298 | { | ||
299 | int x; | ||
300 | unsigned char *dst, *dst_end; | ||
301 | unsigned mask; | ||
302 | lcd_blockfunc_type *bfunc; | ||
303 | |||
304 | /* direction flip */ | ||
305 | if (x2 < x1) | ||
306 | { | ||
307 | x = x1; | ||
308 | x1 = x2; | ||
309 | x2 = x; | ||
310 | } | ||
311 | |||
312 | /* nothing to draw? */ | ||
313 | if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0)) | ||
314 | return; | ||
315 | |||
316 | /* clipping */ | ||
317 | if (x1 < 0) | ||
318 | x1 = 0; | ||
319 | if (x2 >= LCD_WIDTH) | ||
320 | x2 = LCD_WIDTH-1; | ||
321 | |||
322 | bfunc = lcd_blockfuncs[drawmode]; | ||
323 | dst = &lcd_framebuffer[y>>3][x1]; | ||
324 | mask = 1 << (y & 7); | ||
325 | |||
326 | dst_end = dst + x2 - x1; | ||
327 | do | ||
328 | bfunc(dst++, mask, 0xFFu); | ||
329 | while (dst <= dst_end); | ||
330 | } | ||
331 | |||
332 | /* Draw a vertical line (optimised) */ | ||
333 | void lcd_vline(int x, int y1, int y2) | ||
334 | { | ||
335 | int ny; | ||
336 | unsigned char *dst; | ||
337 | unsigned mask, mask_bottom; | ||
338 | lcd_blockfunc_type *bfunc; | ||
339 | |||
340 | /* direction flip */ | ||
341 | if (y2 < y1) | ||
342 | { | ||
343 | ny = y1; | ||
344 | y1 = y2; | ||
345 | y2 = ny; | ||
346 | } | ||
347 | |||
348 | /* nothing to draw? */ | ||
349 | if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0)) | ||
350 | return; | ||
351 | |||
352 | /* clipping */ | ||
353 | if (y1 < 0) | ||
354 | y1 = 0; | ||
355 | if (y2 >= LCD_HEIGHT) | ||
356 | y2 = LCD_HEIGHT-1; | ||
357 | |||
358 | bfunc = lcd_blockfuncs[drawmode]; | ||
359 | dst = &lcd_framebuffer[y1>>3][x]; | ||
360 | ny = y2 - (y1 & ~7); | ||
361 | mask = 0xFFu << (y1 & 7); | ||
362 | mask_bottom = 0xFFu >> (~ny & 7); | ||
363 | |||
364 | for (; ny >= 8; ny -= 8) | ||
365 | { | ||
366 | bfunc(dst, mask, 0xFFu); | ||
367 | dst += LCD_WIDTH; | ||
368 | mask = 0xFFu; | ||
369 | } | ||
370 | mask &= mask_bottom; | ||
371 | bfunc(dst, mask, 0xFFu); | ||
372 | } | ||
373 | |||
374 | /* Draw a rectangular box */ | ||
375 | void lcd_drawrect(int x, int y, int width, int height) | ||
376 | { | ||
377 | if ((width <= 0) || (height <= 0)) | ||
378 | return; | ||
379 | |||
380 | int x2 = x + width - 1; | ||
381 | int y2 = y + height - 1; | ||
382 | |||
383 | lcd_vline(x, y, y2); | ||
384 | lcd_vline(x2, y, y2); | ||
385 | lcd_hline(x, x2, y); | ||
386 | lcd_hline(x, x2, y2); | ||
387 | } | ||
388 | |||
389 | /* Fill a rectangular area */ | ||
390 | void lcd_fillrect(int x, int y, int width, int height) | ||
391 | { | ||
392 | int ny; | ||
393 | unsigned char *dst, *dst_end; | ||
394 | unsigned mask, mask_bottom; | ||
395 | unsigned bits = 0; | ||
396 | lcd_blockfunc_type *bfunc; | ||
397 | bool fillopt = false; | ||
398 | |||
399 | /* nothing to draw? */ | ||
400 | if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) | ||
401 | || (x + width <= 0) || (y + height <= 0)) | ||
402 | return; | ||
403 | |||
404 | /* clipping */ | ||
405 | if (x < 0) | ||
406 | { | ||
407 | width += x; | ||
408 | x = 0; | ||
409 | } | ||
410 | if (y < 0) | ||
411 | { | ||
412 | height += y; | ||
413 | y = 0; | ||
414 | } | ||
415 | if (x + width > LCD_WIDTH) | ||
416 | width = LCD_WIDTH - x; | ||
417 | if (y + height > LCD_HEIGHT) | ||
418 | height = LCD_HEIGHT - y; | ||
419 | |||
420 | if (drawmode & DRMODE_INVERSEVID) | ||
421 | { | ||
422 | if (drawmode & DRMODE_BG) | ||
423 | { | ||
424 | fillopt = true; | ||
425 | } | ||
426 | } | ||
427 | else | ||
428 | { | ||
429 | if (drawmode & DRMODE_FG) | ||
430 | { | ||
431 | fillopt = true; | ||
432 | bits = 0xFFu; | ||
433 | } | ||
434 | } | ||
435 | bfunc = lcd_blockfuncs[drawmode]; | ||
436 | dst = &lcd_framebuffer[y>>3][x]; | ||
437 | ny = height - 1 + (y & 7); | ||
438 | mask = 0xFFu << (y & 7); | ||
439 | mask_bottom = 0xFFu >> (~ny & 7); | ||
440 | |||
441 | for (; ny >= 8; ny -= 8) | ||
442 | { | ||
443 | if (fillopt && (mask == 0xFFu)) | ||
444 | memset(dst, bits, width); | ||
445 | else | ||
446 | { | ||
447 | unsigned char *dst_row = dst; | ||
448 | |||
449 | dst_end = dst_row + width; | ||
450 | do | ||
451 | bfunc(dst_row++, mask, 0xFFu); | ||
452 | while (dst_row < dst_end); | ||
453 | } | ||
454 | |||
455 | dst += LCD_WIDTH; | ||
456 | mask = 0xFFu; | ||
457 | } | ||
458 | mask &= mask_bottom; | ||
459 | |||
460 | if (fillopt && (mask == 0xFFu)) | ||
461 | memset(dst, bits, width); | ||
462 | else | ||
463 | { | ||
464 | dst_end = dst + width; | ||
465 | do | ||
466 | bfunc(dst++, mask, 0xFFu); | ||
467 | while (dst < dst_end); | ||
468 | } | ||
469 | } | ||
470 | |||
471 | /* About Rockbox' internal bitmap format: | ||
472 | * | ||
473 | * A bitmap contains one bit for every pixel that defines if that pixel is | ||
474 | * black (1) or white (0). Bits within a byte are arranged vertically, LSB | ||
475 | * at top. | ||
476 | * The bytes are stored in row-major order, with byte 0 being top left, | ||
477 | * byte 1 2nd from left etc. The first row of bytes defines pixel rows | ||
478 | * 0..7, the second row defines pixel row 8..15 etc. | ||
479 | * | ||
480 | * This is the same as the internal lcd hw format. */ | ||
481 | |||
482 | /* Draw a partial bitmap */ | ||
483 | void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, | ||
484 | int stride, int x, int y, int width, int height) | ||
485 | ICODE_ATTR; | ||
486 | void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, | ||
487 | int stride, int x, int y, int width, int height) | ||
488 | { | ||
489 | int shift, ny; | ||
490 | unsigned char *dst, *dst_end; | ||
491 | unsigned mask, mask_bottom; | ||
492 | lcd_blockfunc_type *bfunc; | ||
493 | |||
494 | /* nothing to draw? */ | ||
495 | if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) | ||
496 | || (x + width <= 0) || (y + height <= 0)) | ||
497 | return; | ||
498 | |||
499 | /* clipping */ | ||
500 | if (x < 0) | ||
501 | { | ||
502 | width += x; | ||
503 | src_x -= x; | ||
504 | x = 0; | ||
505 | } | ||
506 | if (y < 0) | ||
507 | { | ||
508 | height += y; | ||
509 | src_y -= y; | ||
510 | y = 0; | ||
511 | } | ||
512 | if (x + width > LCD_WIDTH) | ||
513 | width = LCD_WIDTH - x; | ||
514 | if (y + height > LCD_HEIGHT) | ||
515 | height = LCD_HEIGHT - y; | ||
516 | |||
517 | src += stride * (src_y >> 3) + src_x; /* move starting point */ | ||
518 | src_y &= 7; | ||
519 | y -= src_y; | ||
520 | dst = &lcd_framebuffer[y>>3][x]; | ||
521 | shift = y & 7; | ||
522 | ny = height - 1 + shift + src_y; | ||
523 | |||
524 | bfunc = lcd_blockfuncs[drawmode]; | ||
525 | mask = 0xFFu << (shift + src_y); | ||
526 | mask_bottom = 0xFFu >> (~ny & 7); | ||
527 | |||
528 | if (shift == 0) | ||
529 | { | ||
530 | bool copyopt = (drawmode == DRMODE_SOLID); | ||
531 | |||
532 | for (; ny >= 8; ny -= 8) | ||
533 | { | ||
534 | if (copyopt && (mask == 0xFFu)) | ||
535 | memcpy(dst, src, width); | ||
536 | else | ||
537 | { | ||
538 | const unsigned char *src_row = src; | ||
539 | unsigned char *dst_row = dst; | ||
540 | |||
541 | dst_end = dst_row + width; | ||
542 | do | ||
543 | bfunc(dst_row++, mask, *src_row++); | ||
544 | while (dst_row < dst_end); | ||
545 | } | ||
546 | |||
547 | src += stride; | ||
548 | dst += LCD_WIDTH; | ||
549 | mask = 0xFFu; | ||
550 | } | ||
551 | mask &= mask_bottom; | ||
552 | |||
553 | if (copyopt && (mask == 0xFFu)) | ||
554 | memcpy(dst, src, width); | ||
555 | else | ||
556 | { | ||
557 | dst_end = dst + width; | ||
558 | do | ||
559 | bfunc(dst++, mask, *src++); | ||
560 | while (dst < dst_end); | ||
561 | } | ||
562 | } | ||
563 | else | ||
564 | { | ||
565 | dst_end = dst + width; | ||
566 | do | ||
567 | { | ||
568 | const unsigned char *src_col = src++; | ||
569 | unsigned char *dst_col = dst++; | ||
570 | unsigned mask_col = mask; | ||
571 | unsigned data = 0; | ||
572 | |||
573 | for (y = ny; y >= 8; y -= 8) | ||
574 | { | ||
575 | data |= *src_col << shift; | ||
576 | |||
577 | if (mask_col & 0xFFu) | ||
578 | { | ||
579 | bfunc(dst_col, mask_col, data); | ||
580 | mask_col = 0xFFu; | ||
581 | } | ||
582 | else | ||
583 | mask_col >>= 8; | ||
584 | |||
585 | src_col += stride; | ||
586 | dst_col += LCD_WIDTH; | ||
587 | data >>= 8; | ||
588 | } | ||
589 | data |= *src_col << shift; | ||
590 | bfunc(dst_col, mask_col & mask_bottom, data); | ||
591 | } | ||
592 | while (dst < dst_end); | ||
593 | } | ||
594 | } | ||
595 | |||
596 | /* Draw a full bitmap */ | ||
597 | void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height) | ||
598 | { | ||
599 | lcd_bitmap_part(src, 0, 0, width, x, y, width, height); | ||
600 | } | ||
601 | |||
602 | /* put a string at a given pixel position, skipping first ofs pixel columns */ | ||
603 | static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) | ||
604 | { | ||
605 | unsigned short ch; | ||
606 | unsigned short *ucs; | ||
607 | struct font* pf = font_get(curfont); | ||
608 | |||
609 | ucs = bidi_l2v(str, 1); | ||
610 | |||
611 | while ((ch = *ucs++) != 0 && x < LCD_WIDTH) | ||
612 | { | ||
613 | int width; | ||
614 | const unsigned char *bits; | ||
615 | |||
616 | /* get proportional width and glyph bits */ | ||
617 | width = font_get_width(pf,ch); | ||
618 | |||
619 | if (ofs > width) | ||
620 | { | ||
621 | ofs -= width; | ||
622 | continue; | ||
623 | } | ||
624 | |||
625 | bits = font_get_bits(pf, ch); | ||
626 | |||
627 | lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, | ||
628 | pf->height); | ||
629 | |||
630 | x += width - ofs; | ||
631 | ofs = 0; | ||
632 | } | ||
633 | } | ||
634 | /* put a string at a given pixel position */ | ||
635 | void lcd_putsxy(int x, int y, const unsigned char *str) | ||
636 | { | ||
637 | lcd_putsxyofs(x, y, 0, str); | ||
638 | } | ||
639 | |||
640 | /*** Line oriented text output ***/ | ||
641 | |||
642 | /* put a string at a given char position */ | ||
643 | void lcd_puts(int x, int y, const unsigned char *str) | ||
644 | { | ||
645 | lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, 0); | ||
646 | } | ||
647 | |||
648 | void lcd_puts_style(int x, int y, const unsigned char *str, int style) | ||
649 | { | ||
650 | lcd_puts_style_offset(x, y, str, style, 0); | ||
651 | } | ||
652 | |||
653 | void lcd_puts_offset(int x, int y, const unsigned char *str, int offset) | ||
654 | { | ||
655 | lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, offset); | ||
656 | } | ||
657 | |||
658 | /* put a string at a given char position, style, and pixel position, | ||
659 | * skipping first offset pixel columns */ | ||
660 | void lcd_puts_style_offset(int x, int y, const unsigned char *str, | ||
661 | int style, int offset) | ||
662 | { | ||
663 | int xpos,ypos,w,h,xrect; | ||
664 | int lastmode = drawmode; | ||
665 | |||
666 | /* make sure scrolling is turned off on the line we are updating */ | ||
667 | scrolling_lines &= ~(1 << y); | ||
668 | |||
669 | if(!str || !str[0]) | ||
670 | return; | ||
671 | |||
672 | lcd_getstringsize(str, &w, &h); | ||
673 | xpos = xmargin + x*w / utf8length(str); | ||
674 | ypos = ymargin + y*h; | ||
675 | drawmode = (style & STYLE_INVERT) ? | ||
676 | (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; | ||
677 | lcd_putsxyofs(xpos, ypos, offset, str); | ||
678 | drawmode ^= DRMODE_INVERSEVID; | ||
679 | xrect = xpos + MAX(w - offset, 0); | ||
680 | lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h); | ||
681 | drawmode = lastmode; | ||
682 | } | ||
683 | |||
684 | /*** scrolling ***/ | ||
685 | |||
686 | /* Reverse the invert setting of the scrolling line (if any) at given char | ||
687 | position. Setting will go into affect next time line scrolls. */ | ||
688 | void lcd_invertscroll(int x, int y) | ||
689 | { | ||
690 | struct scrollinfo* s; | ||
691 | |||
692 | (void)x; | ||
693 | |||
694 | s = &scroll[y]; | ||
695 | s->invert = !s->invert; | ||
696 | } | ||
697 | |||
698 | void lcd_stop_scroll(void) | ||
699 | { | ||
700 | scrolling_lines=0; | ||
701 | } | ||
702 | |||
703 | void lcd_scroll_speed(int speed) | ||
704 | { | ||
705 | scroll_ticks = scroll_tick_table[speed]; | ||
706 | } | ||
707 | |||
708 | void lcd_scroll_step(int step) | ||
709 | { | ||
710 | scroll_step = step; | ||
711 | } | ||
712 | |||
713 | void lcd_scroll_delay(int ms) | ||
714 | { | ||
715 | scroll_delay = ms / (HZ / 10); | ||
716 | } | ||
717 | |||
718 | void lcd_bidir_scroll(int percent) | ||
719 | { | ||
720 | bidir_limit = percent; | ||
721 | } | ||
722 | |||
723 | void lcd_puts_scroll(int x, int y, const unsigned char *string) | ||
724 | { | ||
725 | lcd_puts_scroll_style(x, y, string, STYLE_DEFAULT); | ||
726 | } | ||
727 | |||
728 | void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style) | ||
729 | { | ||
730 | lcd_puts_scroll_style_offset(x, y, string, style, 0); | ||
731 | } | ||
732 | |||
733 | void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, | ||
734 | int offset) | ||
735 | { | ||
736 | lcd_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset); | ||
737 | } | ||
738 | |||
739 | void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string, | ||
740 | int style, int offset) | ||
741 | { | ||
742 | struct scrollinfo* s; | ||
743 | int w, h; | ||
744 | |||
745 | s = &scroll[y]; | ||
746 | |||
747 | s->start_tick = current_tick + scroll_delay; | ||
748 | s->invert = false; | ||
749 | if (style & STYLE_INVERT) { | ||
750 | s->invert = true; | ||
751 | lcd_puts_style_offset(x,y,string,STYLE_INVERT,offset); | ||
752 | } | ||
753 | else | ||
754 | lcd_puts_offset(x,y,string,offset); | ||
755 | |||
756 | lcd_getstringsize(string, &w, &h); | ||
757 | |||
758 | if (LCD_WIDTH - x * 8 - xmargin < w) { | ||
759 | /* prepare scroll line */ | ||
760 | char *end; | ||
761 | |||
762 | memset(s->line, 0, sizeof s->line); | ||
763 | strcpy(s->line, string); | ||
764 | |||
765 | /* get width */ | ||
766 | s->width = lcd_getstringsize(s->line, &w, &h); | ||
767 | |||
768 | /* scroll bidirectional or forward only depending on the string | ||
769 | width */ | ||
770 | if ( bidir_limit ) { | ||
771 | s->bidir = s->width < (LCD_WIDTH - xmargin) * | ||
772 | (100 + bidir_limit) / 100; | ||
773 | } | ||
774 | else | ||
775 | s->bidir = false; | ||
776 | |||
777 | if (!s->bidir) { /* add spaces if scrolling in the round */ | ||
778 | strcat(s->line, " "); | ||
779 | /* get new width incl. spaces */ | ||
780 | s->width = lcd_getstringsize(s->line, &w, &h); | ||
781 | } | ||
782 | |||
783 | end = strchr(s->line, '\0'); | ||
784 | strncpy(end, string, LCD_WIDTH/2); | ||
785 | |||
786 | s->len = utf8length(string); | ||
787 | s->offset = offset; | ||
788 | s->startx = xmargin + x * s->width / s->len;; | ||
789 | s->backward = false; | ||
790 | scrolling_lines |= (1<<y); | ||
791 | } | ||
792 | else | ||
793 | /* force a bit switch-off since it doesn't scroll */ | ||
794 | scrolling_lines &= ~(1<<y); | ||
795 | } | ||
796 | |||
797 | static void scroll_thread(void) | ||
798 | { | ||
799 | struct font* pf; | ||
800 | struct scrollinfo* s; | ||
801 | int index; | ||
802 | int xpos, ypos; | ||
803 | int lastmode; | ||
804 | |||
805 | /* initialize scroll struct array */ | ||
806 | scrolling_lines = 0; | ||
807 | |||
808 | while ( 1 ) { | ||
809 | for ( index = 0; index < SCROLLABLE_LINES; index++ ) { | ||
810 | /* really scroll? */ | ||
811 | if ( !(scrolling_lines&(1<<index)) ) | ||
812 | continue; | ||
813 | |||
814 | s = &scroll[index]; | ||
815 | |||
816 | /* check pause */ | ||
817 | if (TIME_BEFORE(current_tick, s->start_tick)) | ||
818 | continue; | ||
819 | |||
820 | if (s->backward) | ||
821 | s->offset -= scroll_step; | ||
822 | else | ||
823 | s->offset += scroll_step; | ||
824 | |||
825 | pf = font_get(curfont); | ||
826 | xpos = s->startx; | ||
827 | ypos = ymargin + index * pf->height; | ||
828 | |||
829 | if (s->bidir) { /* scroll bidirectional */ | ||
830 | if (s->offset <= 0) { | ||
831 | /* at beginning of line */ | ||
832 | s->offset = 0; | ||
833 | s->backward = false; | ||
834 | s->start_tick = current_tick + scroll_delay * 2; | ||
835 | } | ||
836 | if (s->offset >= s->width - (LCD_WIDTH - xpos)) { | ||
837 | /* at end of line */ | ||
838 | s->offset = s->width - (LCD_WIDTH - xpos); | ||
839 | s->backward = true; | ||
840 | s->start_tick = current_tick + scroll_delay * 2; | ||
841 | } | ||
842 | } | ||
843 | else { | ||
844 | /* scroll forward the whole time */ | ||
845 | if (s->offset >= s->width) | ||
846 | s->offset %= s->width; | ||
847 | } | ||
848 | |||
849 | lastmode = drawmode; | ||
850 | drawmode = s->invert ? | ||
851 | (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID; | ||
852 | lcd_putsxyofs(xpos, ypos, s->offset, s->line); | ||
853 | drawmode = lastmode; | ||
854 | lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); | ||
855 | } | ||
856 | |||
857 | sleep(scroll_ticks); | ||
858 | } | ||
859 | } | ||
860 | |||