Add the viewport functions to the screens API, including a new getfont() function...
[Rockbox.git] / firmware / drivers / lcd-2bit-horz.c
blob195885c0728e98e89360e18d82801eddbcf5ebe4
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * LCD driver for horizontally-packed 2bpp greyscale display
12 * Based on code from the rockbox lcd's driver
14 * Copyright (c) 2006 Seven Le Mesle (sevlm@free.fr)
16 * All files in this archive are subject to the GNU General Public License.
17 * See the file COPYING in the source tree root for full license agreement.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
23 #include "config.h"
24 #include "cpu.h"
25 #include "lcd.h"
26 #include "kernel.h"
27 #include "thread.h"
28 #include <string.h>
29 #include <stdlib.h>
30 #include "file.h"
31 #include "debug.h"
32 #include "system.h"
33 #include "font.h"
34 #include "rbunicode.h"
35 #include "bidi.h"
36 #include "scroll_engine.h"
38 /*** globals ***/
40 unsigned char lcd_framebuffer[LCD_FBHEIGHT][LCD_FBWIDTH] IBSS_ATTR;
42 static const unsigned char pixmask[4] ICONST_ATTR = {
43 0xC0, 0x30, 0x0C, 0x03
46 static fb_data* lcd_backdrop = NULL;
47 static long lcd_backdrop_offset IDATA_ATTR = 0;
49 static struct viewport default_vp =
51 .x = 0,
52 .y = 0,
53 .width = LCD_WIDTH,
54 .height = LCD_HEIGHT,
55 .font = FONT_SYSFIXED,
56 .drawmode = DRMODE_SOLID,
57 .xmargin = 0,
58 .ymargin = 0,
59 .fg_pattern = LCD_DEFAULT_FG,
60 .bg_pattern = LCD_DEFAULT_BG
63 static struct viewport* current_vp IBSS_ATTR;
64 static unsigned fg_pattern IBSS_ATTR;
65 static unsigned bg_pattern IBSS_ATTR;
67 /* LCD init */
68 void lcd_init(void)
70 /* Initialise the viewport */
71 lcd_set_viewport(NULL);
73 lcd_clear_display();
74 /* Call device specific init */
75 lcd_init_device();
76 scroll_init();
79 /*** Viewports ***/
81 void lcd_set_viewport(struct viewport* vp)
83 if (vp == NULL)
84 current_vp = &default_vp;
85 else
86 current_vp = vp;
88 fg_pattern = 0x55 * (~current_vp->fg_pattern & 3);
89 bg_pattern = 0x55 * (~current_vp->bg_pattern & 3);
92 void lcd_update_viewport(void)
94 lcd_update_rect(current_vp->x, current_vp->y,
95 current_vp->width, current_vp->height);
98 void lcd_update_viewport_rect(int x, int y, int width, int height)
100 lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height);
103 /*** parameter handling ***/
105 void lcd_set_drawmode(int mode)
107 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
110 int lcd_get_drawmode(void)
112 return current_vp->drawmode;
115 void lcd_set_foreground(unsigned brightness)
117 current_vp->fg_pattern = brightness;
118 fg_pattern = 0x55 * (~brightness & 3);
121 unsigned lcd_get_foreground(void)
123 return current_vp->fg_pattern;
126 void lcd_set_background(unsigned brightness)
128 current_vp->bg_pattern = brightness;
129 bg_pattern = 0x55 * (~brightness & 3);
132 unsigned lcd_get_background(void)
134 return current_vp->bg_pattern;
137 void lcd_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness)
139 lcd_set_drawmode(mode);
140 lcd_set_foreground(fg_brightness);
141 lcd_set_background(bg_brightness);
144 void lcd_setmargins(int x, int y)
146 current_vp->xmargin = x;
147 current_vp->ymargin = y;
150 int lcd_getxmargin(void)
152 return current_vp->xmargin;
155 int lcd_getymargin(void)
157 return current_vp->ymargin;
160 int lcd_getwidth(void)
162 return current_vp->width;
165 int lcd_getheight(void)
167 return current_vp->height;
170 void lcd_setfont(int newfont)
172 current_vp->font = newfont;
175 int lcd_getfont(void)
177 return current_vp->font;
180 int lcd_getstringsize(const unsigned char *str, int *w, int *h)
182 return font_getstringsize(str, w, h, current_vp->font);
185 /*** low-level drawing functions ***/
187 static void setpixel(int x, int y)
189 unsigned mask = pixmask[x & 3];
190 fb_data *address = &lcd_framebuffer[y][x>>2];
191 unsigned data = *address;
193 *address = data ^ ((data ^ fg_pattern) & mask);
196 static void clearpixel(int x, int y)
198 unsigned mask = pixmask[x & 3];
199 fb_data *address = &lcd_framebuffer[y][x>>2];
200 unsigned data = *address;
202 *address = data ^ ((data ^ bg_pattern) & mask);
205 static void clearimgpixel(int x, int y)
207 unsigned mask = pixmask[x & 3];
208 fb_data *address = &lcd_framebuffer[y][x>>2];
209 unsigned data = *address;
211 *address = data ^ ((data ^ *(address + lcd_backdrop_offset)) & mask);
214 static void flippixel(int x, int y)
216 unsigned mask = pixmask[x & 3];
217 fb_data *address = &lcd_framebuffer[y][x>>2];
219 *address ^= mask;
222 static void nopixel(int x, int y)
224 (void)x;
225 (void)y;
228 lcd_pixelfunc_type* const lcd_pixelfuncs_bgcolor[8] = {
229 flippixel, nopixel, setpixel, setpixel,
230 nopixel, clearpixel, nopixel, clearpixel
233 lcd_pixelfunc_type* const lcd_pixelfuncs_backdrop[8] = {
234 flippixel, nopixel, setpixel, setpixel,
235 nopixel, clearimgpixel, nopixel, clearimgpixel
238 lcd_pixelfunc_type* const * lcd_pixelfuncs = lcd_pixelfuncs_bgcolor;
241 /* 'mask' and 'bits' contain 2 bits per pixel */
242 static void flipblock(fb_data *address, unsigned mask, unsigned bits)
243 ICODE_ATTR;
244 static void flipblock(fb_data *address, unsigned mask, unsigned bits)
246 *address ^= bits & mask;
249 static void bgblock(fb_data *address, unsigned mask, unsigned bits)
250 ICODE_ATTR;
251 static void bgblock(fb_data *address, unsigned mask, unsigned bits)
253 unsigned data = *address;
255 *address = data ^ ((data ^ bg_pattern) & mask & ~bits);
258 static void bgimgblock(fb_data *address, unsigned mask, unsigned bits)
259 ICODE_ATTR;
260 static void bgimgblock(fb_data *address, unsigned mask, unsigned bits)
262 unsigned data = *address;
264 *address = data ^ ((data ^ *(address + lcd_backdrop_offset)) & mask & ~bits);
267 static void fgblock(fb_data *address, unsigned mask, unsigned bits)
268 ICODE_ATTR;
269 static void fgblock(fb_data *address, unsigned mask, unsigned bits)
271 unsigned data = *address;
273 *address = data ^ ((data ^ fg_pattern) & mask & bits);
276 static void solidblock(fb_data *address, unsigned mask, unsigned bits)
277 ICODE_ATTR;
278 static void solidblock(fb_data *address, unsigned mask, unsigned bits)
280 unsigned data = *address;
281 unsigned bgp = bg_pattern;
283 bits = bgp ^ ((bgp ^ fg_pattern) & bits);
284 *address = data ^ ((data ^ bits) & mask);
287 static void solidimgblock(fb_data *address, unsigned mask, unsigned bits)
288 ICODE_ATTR;
289 static void solidimgblock(fb_data *address, unsigned mask, unsigned bits)
291 unsigned data = *address;
292 unsigned bgp = *(address + lcd_backdrop_offset);
294 bits = bgp ^ ((bgp ^ fg_pattern) & bits);
295 *address = data ^ ((data ^ bits) & mask);
298 static void flipinvblock(fb_data *address, unsigned mask, unsigned bits)
299 ICODE_ATTR;
300 static void flipinvblock(fb_data *address, unsigned mask, unsigned bits)
302 *address ^= ~bits & mask;
305 static void bginvblock(fb_data *address, unsigned mask, unsigned bits)
306 ICODE_ATTR;
307 static void bginvblock(fb_data *address, unsigned mask, unsigned bits)
309 unsigned data = *address;
311 *address = data ^ ((data ^ bg_pattern) & mask & bits);
314 static void bgimginvblock(fb_data *address, unsigned mask, unsigned bits)
315 ICODE_ATTR;
316 static void bgimginvblock(fb_data *address, unsigned mask, unsigned bits)
318 unsigned data = *address;
320 *address = data ^ ((data ^ *(address + lcd_backdrop_offset)) & mask & bits);
323 static void fginvblock(fb_data *address, unsigned mask, unsigned bits)
324 ICODE_ATTR;
325 static void fginvblock(fb_data *address, unsigned mask, unsigned bits)
327 unsigned data = *address;
329 *address = data ^ ((data ^ fg_pattern) & mask & ~bits);
332 static void solidinvblock(fb_data *address, unsigned mask, unsigned bits)
333 ICODE_ATTR;
334 static void solidinvblock(fb_data *address, unsigned mask, unsigned bits)
336 unsigned data = *address;
337 unsigned fgp = fg_pattern;
339 bits = fgp ^ ((fgp ^ bg_pattern) & bits);
340 *address = data ^ ((data ^ bits) & mask);
343 static void solidimginvblock(fb_data *address, unsigned mask, unsigned bits)
344 ICODE_ATTR;
345 static void solidimginvblock(fb_data *address, unsigned mask, unsigned bits)
347 unsigned data = *address;
348 unsigned fgp = fg_pattern;
350 bits = fgp ^ ((fgp ^ *(address + lcd_backdrop_offset)) & bits);
351 *address = data ^ ((data ^ bits) & mask);
354 lcd_blockfunc_type* const lcd_blockfuncs_bgcolor[8] = {
355 flipblock, bgblock, fgblock, solidblock,
356 flipinvblock, bginvblock, fginvblock, solidinvblock
359 lcd_blockfunc_type* const lcd_blockfuncs_backdrop[8] = {
360 flipblock, bgimgblock, fgblock, solidimgblock,
361 flipinvblock, bgimginvblock, fginvblock, solidimginvblock
364 lcd_blockfunc_type* const * lcd_blockfuncs = lcd_blockfuncs_bgcolor;
367 void lcd_set_backdrop(fb_data* backdrop)
369 lcd_backdrop = backdrop;
370 if (backdrop)
372 lcd_backdrop_offset = (long)backdrop - (long)lcd_framebuffer;
373 lcd_pixelfuncs = lcd_pixelfuncs_backdrop;
374 lcd_blockfuncs = lcd_blockfuncs_backdrop;
376 else
378 lcd_backdrop_offset = 0;
379 lcd_pixelfuncs = lcd_pixelfuncs_bgcolor;
380 lcd_blockfuncs = lcd_blockfuncs_bgcolor;
384 fb_data* lcd_get_backdrop(void)
386 return lcd_backdrop;
390 static inline void setblock(fb_data *address, unsigned mask, unsigned bits)
392 unsigned data = *address;
394 bits ^= data;
395 *address = data ^ (bits & mask);
398 /*** drawing functions ***/
400 /* Clear the whole display */
401 void lcd_clear_display(void)
403 if (current_vp->drawmode & DRMODE_INVERSEVID)
405 memset(lcd_framebuffer, fg_pattern, sizeof lcd_framebuffer);
407 else
409 if (lcd_backdrop)
410 memcpy(lcd_framebuffer, lcd_backdrop, sizeof lcd_framebuffer);
411 else
412 memset(lcd_framebuffer, bg_pattern, sizeof lcd_framebuffer);
415 lcd_scroll_info.lines = 0;
418 /* Clear the current viewport */
419 void lcd_clear_viewport(void)
421 int lastmode;
423 if (current_vp == &default_vp)
425 lcd_clear_display();
427 else
429 lastmode = current_vp->drawmode;
431 /* Invert the INVERSEVID bit and set basic mode to SOLID */
432 current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) |
433 DRMODE_SOLID;
435 lcd_fillrect(0, 0, current_vp->width, current_vp->height);
437 current_vp->drawmode = lastmode;
439 lcd_scroll_stop(current_vp);
443 /* Set a single pixel */
444 void lcd_drawpixel(int x, int y)
446 if (((unsigned)x < (unsigned)current_vp->width) &&
447 ((unsigned)y < (unsigned)current_vp->height))
448 lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
451 /* Draw a line */
452 void lcd_drawline(int x1, int y1, int x2, int y2)
454 int numpixels;
455 int i;
456 int deltax, deltay;
457 int d, dinc1, dinc2;
458 int x, xinc1, xinc2;
459 int y, yinc1, yinc2;
460 lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[current_vp->drawmode];
462 deltax = abs(x2 - x1);
463 deltay = abs(y2 - y1);
464 xinc2 = 1;
465 yinc2 = 1;
467 if (deltax >= deltay)
469 numpixels = deltax;
470 d = 2 * deltay - deltax;
471 dinc1 = deltay * 2;
472 dinc2 = (deltay - deltax) * 2;
473 xinc1 = 1;
474 yinc1 = 0;
476 else
478 numpixels = deltay;
479 d = 2 * deltax - deltay;
480 dinc1 = deltax * 2;
481 dinc2 = (deltax - deltay) * 2;
482 xinc1 = 0;
483 yinc1 = 1;
485 numpixels++; /* include endpoints */
487 if (x1 > x2)
489 xinc1 = -xinc1;
490 xinc2 = -xinc2;
493 if (y1 > y2)
495 yinc1 = -yinc1;
496 yinc2 = -yinc2;
499 x = x1;
500 y = y1;
502 for (i = 0; i < numpixels; i++)
504 if (((unsigned)x < (unsigned)current_vp->width) &&
505 ((unsigned)y < (unsigned)current_vp->height))
506 pfunc(current_vp->x + x, current_vp->y + y);
508 if (d < 0)
510 d += dinc1;
511 x += xinc1;
512 y += yinc1;
514 else
516 d += dinc2;
517 x += xinc2;
518 y += yinc2;
523 /* Draw a horizontal line (optimised) */
524 void lcd_hline(int x1, int x2, int y)
526 int nx;
527 unsigned char *dst;
528 unsigned mask, mask_right;
529 lcd_blockfunc_type *bfunc;
531 /* direction flip */
532 if (x2 < x1)
534 nx = x1;
535 x1 = x2;
536 x2 = nx;
539 /* nothing to draw? */
540 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
541 || (x2 < 0))
542 return;
544 /* clipping */
545 if (x1 < 0)
546 x1 = 0;
547 if (x2 >= current_vp->width)
548 x2 = current_vp->width-1;
550 /* adjust to viewport */
551 x1 += current_vp->x;
552 x2 += current_vp->x;
553 y += current_vp->y;
555 bfunc = lcd_blockfuncs[current_vp->drawmode];
556 dst = &lcd_framebuffer[y][x1>>2];
557 nx = x2 - (x1 & ~3);
558 mask = 0xFFu >> (2 * (x1 & 3));
559 mask_right = 0xFFu << (2 * (~nx & 3));
561 for (; nx >= 4; nx -= 4)
563 bfunc(dst++, mask, 0xFFu);
564 mask = 0xFFu;
566 mask &= mask_right;
567 bfunc(dst, mask, 0xFFu);
570 /* Draw a vertical line (optimised) */
571 void lcd_vline(int x, int y1, int y2)
573 int y;
574 unsigned char *dst, *dst_end;
575 unsigned mask;
576 lcd_blockfunc_type *bfunc;
578 /* direction flip */
579 if (y2 < y1)
581 y = y1;
582 y1 = y2;
583 y2 = y;
586 /* nothing to draw? */
587 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
588 || (y2 < 0))
589 return;
591 /* clipping */
592 if (y1 < 0)
593 y1 = 0;
594 if (y2 >= current_vp->height)
595 y2 = current_vp->height-1;
597 /* adjust for viewport */
598 y1 += current_vp->y;
599 y2 += current_vp->y;
600 x += current_vp->x;
602 bfunc = lcd_blockfuncs[current_vp->drawmode];
603 dst = &lcd_framebuffer[y1][x>>2];
604 mask = pixmask[x & 3];
606 dst_end = dst + (y2 - y1) * LCD_FBWIDTH;
609 bfunc(dst, mask, 0xFFu);
610 dst += LCD_FBWIDTH;
612 while (dst <= dst_end);
615 /* Draw a rectangular box */
616 void lcd_drawrect(int x, int y, int width, int height)
618 if ((width <= 0) || (height <= 0))
619 return;
621 int x2 = x + width - 1;
622 int y2 = y + height - 1;
624 lcd_vline(x, y, y2);
625 lcd_vline(x2, y, y2);
626 lcd_hline(x, x2, y);
627 lcd_hline(x, x2, y2);
630 /* Fill a rectangular area */
631 void lcd_fillrect(int x, int y, int width, int height)
633 int nx;
634 unsigned char *dst, *dst_end;
635 unsigned mask, mask_right;
636 lcd_blockfunc_type *bfunc;
638 /* nothing to draw? */
639 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || (y >= current_vp->height)
640 || (x + width <= 0) || (y + height <= 0))
641 return;
643 /* clipping */
644 if (x < 0)
646 width += x;
647 x = 0;
649 if (y < 0)
651 height += y;
652 y = 0;
654 if (x + width > current_vp->width)
655 width = current_vp->width - x;
656 if (y + height > current_vp->height)
657 height = current_vp->height - y;
659 /* adjust for viewport */
660 x += current_vp->x;
661 y += current_vp->y;
663 bfunc = lcd_blockfuncs[current_vp->drawmode];
664 dst = &lcd_framebuffer[y][x>>2];
665 nx = width - 1 + (x & 3);
666 mask = 0xFFu >> (2 * (x & 3));
667 mask_right = 0xFFu << (2 * (~nx & 3));
669 for (; nx >= 4; nx -= 4)
671 unsigned char *dst_col = dst;
673 dst_end = dst_col + height * LCD_FBWIDTH;
676 bfunc(dst_col, mask, 0xFFu);
677 dst_col += LCD_FBWIDTH;
679 while (dst_col < dst_end);
681 dst++;
682 mask = 0xFFu;
684 mask &= mask_right;
686 dst_end = dst + height * LCD_FBWIDTH;
689 bfunc(dst, mask, 0xFFu);
690 dst += LCD_FBWIDTH;
692 while (dst < dst_end);
695 /* About Rockbox' internal monochrome bitmap format:
697 * A bitmap contains one bit for every pixel that defines if that pixel is
698 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
699 * at top.
700 * The bytes are stored in row-major order, with byte 0 being top left,
701 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
702 * 0..7, the second row defines pixel row 8..15 etc. */
704 /* Draw a partial monochrome bitmap */
705 void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
706 int stride, int x, int y, int width, int height)
707 ICODE_ATTR;
708 void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
709 int stride, int x, int y, int width, int height)
711 int ny, nx, ymax;
712 const unsigned char * src_end;
713 lcd_pixelfunc_type* fgfunc;
714 lcd_pixelfunc_type* bgfunc;
716 /* nothing to draw? */
717 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
718 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
719 return;
721 /* clipping */
722 if (x < 0)
724 width += x;
725 src_x -= x;
726 x = 0;
728 if (y < 0)
730 height += y;
731 src_y -= y;
732 y = 0;
734 if (x + width > current_vp->width)
735 width = current_vp->width - x;
736 if (y + height > current_vp->height)
737 height = current_vp->height - y;
739 /* adjust for viewport */
740 x += current_vp->x;
741 y += current_vp->y;
743 src += stride * (src_y >> 3) + src_x; /* move starting point */
744 src_y &= 7;
745 src_end = src + width;
747 fgfunc = lcd_pixelfuncs[current_vp->drawmode];
748 bgfunc = lcd_pixelfuncs[current_vp->drawmode ^ DRMODE_INVERSEVID];
749 nx = x;
752 const unsigned char *src_col = src++;
753 unsigned data = *src_col >> src_y;
754 int numbits = 8 - ((int)src_y);
756 ymax = y + height;
757 ny = y;
760 if (data & 0x01)
761 fgfunc(nx,ny);
762 else
763 bgfunc(nx,ny);
765 ny++;
767 data >>= 1;
768 if (--numbits == 0)
770 src_col += stride;
771 data = *src_col;
772 numbits = 8;
775 while (ny < ymax);
776 nx++;
778 while (src < src_end);
781 /* Draw a full monochrome bitmap */
782 void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int height)
784 lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height);
787 /* About Rockbox' internal native bitmap format:
789 * A bitmap contains two bits for every pixel. 00 = white, 01 = light grey,
790 * 10 = dark grey, 11 = black. Bits within a byte are arranged horizontally,
791 * MSB at the left.
792 * The bytes are stored in row-major order, with byte 0 being top left,
793 * byte 1 2nd from left etc. Each row of bytes defines one pixel row.
795 * This is the same as the internal lcd hw format. */
797 /* Draw a partial native bitmap */
798 void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
799 int stride, int x, int y, int width, int height)
800 ICODE_ATTR;
801 void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y,
802 int stride, int x, int y, int width, int height)
804 int shift, nx;
805 unsigned char *dst, *dst_end;
806 unsigned mask, mask_right;
808 /* nothing to draw? */
809 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
810 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
811 return;
813 /* clipping */
814 if (x < 0)
816 width += x;
817 src_x -= x;
818 x = 0;
820 if (y < 0)
822 height += y;
823 src_y -= y;
824 y = 0;
826 if (x + width > current_vp->width)
827 width = current_vp->width - x;
828 if (y + height > current_vp->height)
829 height = current_vp->height - y;
831 /* adjust for viewport */
832 x += current_vp->x;
833 y += current_vp->y;
835 stride = (stride + 3) >> 2; /* convert to no. of bytes */
837 src += stride * src_y + (src_x >> 2); /* move starting point */
838 src_x &= 3;
839 x -= src_x;
840 dst = &lcd_framebuffer[y][x>>2];
841 shift = x & 3;
842 nx = width - 1 + shift + src_x;
844 mask = 0xFF00u >> (2 * (shift + src_x));
845 mask_right = 0xFFu << (2 * (~nx & 3));
847 shift *= 2;
848 dst_end = dst + height * LCD_FBWIDTH;
851 const unsigned char *src_row = src;
852 unsigned char *dst_row = dst;
853 unsigned mask_row = mask >> 8;
854 unsigned data = 0;
856 for (x = nx; x >= 4; x -= 4)
858 data = (data << 8) | *src_row++;
860 if (mask_row & 0xFF)
862 setblock(dst_row, mask_row, data >> shift);
863 mask_row = 0xFF;
865 else
866 mask_row = mask;
868 dst_row++;
870 data = (data << 8) | *src_row;
871 setblock(dst_row, mask_row & mask_right, data >> shift);
873 src += stride;
874 dst += LCD_FBWIDTH;
876 while (dst < dst_end);
879 /* Draw a full native bitmap */
880 void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height)
882 lcd_bitmap_part(src, 0, 0, width, x, y, width, height);
885 /* put a string at a given pixel position, skipping first ofs pixel columns */
886 static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
888 unsigned short ch;
889 unsigned short *ucs;
890 struct font* pf = font_get(current_vp->font);
892 ucs = bidi_l2v(str, 1);
894 while ((ch = *ucs++) != 0 && x < current_vp->width)
896 int width;
897 const unsigned char *bits;
899 /* get proportional width and glyph bits */
900 width = font_get_width(pf,ch);
902 if (ofs > width)
904 ofs -= width;
905 continue;
908 bits = font_get_bits(pf, ch);
910 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs,
911 pf->height);
913 x += width - ofs;
914 ofs = 0;
918 /* put a string at a given pixel position */
919 void lcd_putsxy(int x, int y, const unsigned char *str)
921 lcd_putsxyofs(x, y, 0, str);
924 /*** line oriented text output ***/
926 /* put a string at a given char position */
927 void lcd_puts(int x, int y, const unsigned char *str)
929 lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, 0);
932 void lcd_puts_style(int x, int y, const unsigned char *str, int style)
934 lcd_puts_style_offset(x, y, str, style, 0);
937 void lcd_puts_offset(int x, int y, const unsigned char *str, int offset)
939 lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, offset);
942 /* put a string at a given char position, style, and pixel position,
943 * skipping first offset pixel columns */
944 void lcd_puts_style_offset(int x, int y, const unsigned char *str,
945 int style, int offset)
947 int xpos,ypos,w,h,xrect;
948 int lastmode = current_vp->drawmode;
950 /* make sure scrolling is turned off on the line we are updating */
951 lcd_scroll_stop_line(current_vp, y);
953 if(!str || !str[0])
954 return;
956 lcd_getstringsize(str, &w, &h);
957 xpos = current_vp->xmargin + x*w / utf8length((char *)str);
958 ypos = current_vp->ymargin + y*h;
959 current_vp->drawmode = (style & STYLE_INVERT) ?
960 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
961 lcd_putsxyofs(xpos, ypos, offset, str);
962 current_vp->drawmode ^= DRMODE_INVERSEVID;
963 xrect = xpos + MAX(w - offset, 0);
964 lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
965 current_vp->drawmode = lastmode;
968 /*** scrolling ***/
969 void lcd_puts_scroll(int x, int y, const unsigned char *string)
971 lcd_puts_scroll_style(x, y, string, STYLE_DEFAULT);
974 void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style)
976 lcd_puts_scroll_style_offset(x, y, string, style, 0);
979 void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, int offset)
981 lcd_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset);
984 void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
985 int style, int offset)
987 struct scrollinfo* s;
988 int w, h;
990 if ((unsigned)y >= (unsigned)current_vp->height)
991 return;
993 /* remove any previously scrolling line at the same location */
994 lcd_scroll_stop_line(current_vp, y);
996 if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return;
998 s = &lcd_scroll_info.scroll[lcd_scroll_info.lines];
1000 s->start_tick = current_tick + lcd_scroll_info.delay;
1001 s->style = style;
1002 if (style & STYLE_INVERT) {
1003 lcd_puts_style_offset(x,y,string,STYLE_INVERT,offset);
1005 else
1006 lcd_puts_offset(x,y,string,offset);
1008 lcd_getstringsize(string, &w, &h);
1010 if (current_vp->width - x * 8 - current_vp->xmargin < w) {
1011 /* prepare scroll line */
1012 char *end;
1014 memset(s->line, 0, sizeof s->line);
1015 strcpy(s->line, (char *)string);
1017 /* get width */
1018 s->width = lcd_getstringsize((unsigned char *)s->line, &w, &h);
1020 /* scroll bidirectional or forward only depending on the string
1021 width */
1022 if ( lcd_scroll_info.bidir_limit ) {
1023 s->bidir = s->width < (current_vp->width - current_vp->xmargin) *
1024 (100 + lcd_scroll_info.bidir_limit) / 100;
1026 else
1027 s->bidir = false;
1029 if (!s->bidir) { /* add spaces if scrolling in the round */
1030 strcat(s->line, " ");
1031 /* get new width incl. spaces */
1032 s->width = lcd_getstringsize((unsigned char *)s->line, &w, &h);
1035 end = strchr(s->line, '\0');
1036 strncpy(end, (char *)string, current_vp->width/2);
1038 s->vp = current_vp;
1039 s->y = y;
1040 s->len = utf8length((char *)string);
1041 s->offset = offset;
1042 s->startx = current_vp->xmargin + x * s->width / s->len;;
1043 s->backward = false;
1044 lcd_scroll_info.lines++;
1048 void lcd_scroll_fn(void)
1050 struct font* pf;
1051 struct scrollinfo* s;
1052 int index;
1053 int xpos, ypos;
1054 int lastmode;
1055 struct viewport* old_vp = current_vp;
1057 for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
1058 s = &lcd_scroll_info.scroll[index];
1060 /* check pause */
1061 if (TIME_BEFORE(current_tick, s->start_tick))
1062 continue;
1064 lcd_set_viewport(s->vp);
1066 if (s->backward)
1067 s->offset -= lcd_scroll_info.step;
1068 else
1069 s->offset += lcd_scroll_info.step;
1071 pf = font_get(current_vp->font);
1072 xpos = s->startx;
1073 ypos = current_vp->ymargin + s->y * pf->height;
1075 if (s->bidir) { /* scroll bidirectional */
1076 if (s->offset <= 0) {
1077 /* at beginning of line */
1078 s->offset = 0;
1079 s->backward = false;
1080 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
1082 if (s->offset >= s->width - (current_vp->width - xpos)) {
1083 /* at end of line */
1084 s->offset = s->width - (current_vp->width - xpos);
1085 s->backward = true;
1086 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
1089 else {
1090 /* scroll forward the whole time */
1091 if (s->offset >= s->width)
1092 s->offset %= s->width;
1095 lastmode = current_vp->drawmode;
1096 current_vp->drawmode = (s->style&STYLE_INVERT) ?
1097 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
1098 lcd_putsxyofs(xpos, ypos, s->offset, s->line);
1099 current_vp->drawmode = lastmode;
1100 lcd_update_viewport_rect(xpos, ypos, current_vp->width - xpos, pf->height);
1103 lcd_set_viewport(old_vp);