1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2004 by Linus Nielsen Feltzing
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
31 #include "rbunicode.h"
33 #include "scroll_engine.h"
37 fb_data lcd_framebuffer
[LCD_FBHEIGHT
][LCD_FBWIDTH
] IBSS_ATTR
;
39 const unsigned char lcd_dibits
[16] ICONST_ATTR
= {
40 0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F,
41 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF
44 static const unsigned char pixmask
[4] ICONST_ATTR
= {
45 0x03, 0x0C, 0x30, 0xC0
48 static fb_data
* lcd_backdrop
= NULL
;
49 static long lcd_backdrop_offset IDATA_ATTR
= 0;
51 static struct viewport default_vp
=
57 .font
= FONT_SYSFIXED
,
58 .drawmode
= DRMODE_SOLID
,
61 .fg_pattern
= LCD_DEFAULT_FG
,
62 .bg_pattern
= LCD_DEFAULT_BG
65 static struct viewport
* current_vp IBSS_ATTR
;
66 static unsigned fg_pattern IBSS_ATTR
;
67 static unsigned bg_pattern IBSS_ATTR
;
72 /* Initialise the viewport */
73 lcd_set_viewport(NULL
);
76 /* Call device specific init */
83 void lcd_set_viewport(struct viewport
* vp
)
86 current_vp
= &default_vp
;
90 fg_pattern
= 0x55 * (~current_vp
->fg_pattern
& 3);
91 bg_pattern
= 0x55 * (~current_vp
->bg_pattern
& 3);
94 void lcd_update_viewport(void)
96 lcd_update_rect(current_vp
->x
, current_vp
->y
,
97 current_vp
->width
, current_vp
->height
);
100 void lcd_update_viewport_rect(int x
, int y
, int width
, int height
)
102 lcd_update_rect(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
106 /*** parameter handling ***/
108 void lcd_set_drawmode(int mode
)
110 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
113 int lcd_get_drawmode(void)
115 return current_vp
->drawmode
;
118 void lcd_set_foreground(unsigned brightness
)
120 current_vp
->fg_pattern
= brightness
;
121 fg_pattern
= 0x55 * (~brightness
& 3);
124 unsigned lcd_get_foreground(void)
126 return current_vp
->fg_pattern
;
129 void lcd_set_background(unsigned brightness
)
131 current_vp
->bg_pattern
= brightness
;
132 bg_pattern
= 0x55 * (~brightness
& 3);
135 unsigned lcd_get_background(void)
137 return current_vp
->bg_pattern
;
140 void lcd_set_drawinfo(int mode
, unsigned fg_brightness
, unsigned bg_brightness
)
142 lcd_set_drawmode(mode
);
143 lcd_set_foreground(fg_brightness
);
144 lcd_set_background(bg_brightness
);
147 void lcd_setmargins(int x
, int y
)
149 current_vp
->xmargin
= x
;
150 current_vp
->ymargin
= y
;
153 int lcd_getxmargin(void)
155 return current_vp
->xmargin
;
158 int lcd_getymargin(void)
160 return current_vp
->ymargin
;
163 int lcd_getwidth(void)
165 return current_vp
->width
;
168 int lcd_getheight(void)
170 return current_vp
->height
;
173 void lcd_setfont(int newfont
)
175 current_vp
->font
= newfont
;
178 int lcd_getfont(void)
180 return current_vp
->font
;
183 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
185 return font_getstringsize(str
, w
, h
, current_vp
->font
);
188 /*** low-level drawing functions ***/
190 static void setpixel(int x
, int y
)
192 unsigned mask
= pixmask
[y
& 3];
193 fb_data
*address
= &lcd_framebuffer
[y
>>2][x
];
194 unsigned data
= *address
;
196 *address
= data
^ ((data
^ fg_pattern
) & mask
);
199 static void clearpixel(int x
, int y
)
201 unsigned mask
= pixmask
[y
& 3];
202 fb_data
*address
= &lcd_framebuffer
[y
>>2][x
];
203 unsigned data
= *address
;
205 *address
= data
^ ((data
^ bg_pattern
) & mask
);
208 static void clearimgpixel(int x
, int y
)
210 unsigned mask
= pixmask
[y
& 3];
211 fb_data
*address
= &lcd_framebuffer
[y
>>2][x
];
212 unsigned data
= *address
;
214 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
);
217 static void flippixel(int x
, int y
)
219 unsigned mask
= pixmask
[y
& 3];
220 fb_data
*address
= &lcd_framebuffer
[y
>>2][x
];
225 static void nopixel(int x
, int y
)
231 lcd_pixelfunc_type
* const lcd_pixelfuncs_bgcolor
[8] = {
232 flippixel
, nopixel
, setpixel
, setpixel
,
233 nopixel
, clearpixel
, nopixel
, clearpixel
236 lcd_pixelfunc_type
* const lcd_pixelfuncs_backdrop
[8] = {
237 flippixel
, nopixel
, setpixel
, setpixel
,
238 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
242 lcd_pixelfunc_type
* const * lcd_pixelfuncs
= lcd_pixelfuncs_bgcolor
;
244 /* 'mask' and 'bits' contain 2 bits per pixel */
245 static void flipblock(fb_data
*address
, unsigned mask
, unsigned bits
)
247 static void flipblock(fb_data
*address
, unsigned mask
, unsigned bits
)
249 *address
^= bits
& mask
;
252 static void bgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
254 static void bgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
256 unsigned data
= *address
;
258 *address
= data
^ ((data
^ bg_pattern
) & mask
& ~bits
);
261 static void bgimgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
263 static void bgimgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
265 unsigned data
= *address
;
267 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
& ~bits
);
270 static void fgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
272 static void fgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
274 unsigned data
= *address
;
276 *address
= data
^ ((data
^ fg_pattern
) & mask
& bits
);
279 static void solidblock(fb_data
*address
, unsigned mask
, unsigned bits
)
281 static void solidblock(fb_data
*address
, unsigned mask
, unsigned bits
)
283 unsigned data
= *address
;
284 unsigned bgp
= bg_pattern
;
286 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
287 *address
= data
^ ((data
^ bits
) & mask
);
290 static void solidimgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
292 static void solidimgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
294 unsigned data
= *address
;
295 unsigned bgp
= *(address
+ lcd_backdrop_offset
);
297 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
298 *address
= data
^ ((data
^ bits
) & mask
);
301 static void flipinvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
303 static void flipinvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
305 *address
^= ~bits
& mask
;
308 static void bginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
310 static void bginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
312 unsigned data
= *address
;
314 *address
= data
^ ((data
^ bg_pattern
) & mask
& bits
);
317 static void bgimginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
319 static void bgimginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
321 unsigned data
= *address
;
323 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
& bits
);
326 static void fginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
328 static void fginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
330 unsigned data
= *address
;
332 *address
= data
^ ((data
^ fg_pattern
) & mask
& ~bits
);
335 static void solidinvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
337 static void solidinvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
339 unsigned data
= *address
;
340 unsigned fgp
= fg_pattern
;
342 bits
= fgp
^ ((fgp
^ bg_pattern
) & bits
);
343 *address
= data
^ ((data
^ bits
) & mask
);
346 static void solidimginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
348 static void solidimginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
350 unsigned data
= *address
;
351 unsigned fgp
= fg_pattern
;
353 bits
= fgp
^ ((fgp
^ *(address
+ lcd_backdrop_offset
)) & bits
);
354 *address
= data
^ ((data
^ bits
) & mask
);
357 lcd_blockfunc_type
* const lcd_blockfuncs_bgcolor
[8] = {
358 flipblock
, bgblock
, fgblock
, solidblock
,
359 flipinvblock
, bginvblock
, fginvblock
, solidinvblock
362 lcd_blockfunc_type
* const lcd_blockfuncs_backdrop
[8] = {
363 flipblock
, bgimgblock
, fgblock
, solidimgblock
,
364 flipinvblock
, bgimginvblock
, fginvblock
, solidimginvblock
367 lcd_blockfunc_type
* const * lcd_blockfuncs
= lcd_blockfuncs_bgcolor
;
370 void lcd_set_backdrop(fb_data
* backdrop
)
372 lcd_backdrop
= backdrop
;
375 lcd_backdrop_offset
= (long)backdrop
- (long)lcd_framebuffer
;
376 lcd_pixelfuncs
= lcd_pixelfuncs_backdrop
;
377 lcd_blockfuncs
= lcd_blockfuncs_backdrop
;
381 lcd_backdrop_offset
= 0;
382 lcd_pixelfuncs
= lcd_pixelfuncs_bgcolor
;
383 lcd_blockfuncs
= lcd_blockfuncs_bgcolor
;
387 fb_data
* lcd_get_backdrop(void)
393 static inline void setblock(fb_data
*address
, unsigned mask
, unsigned bits
)
395 unsigned data
= *address
;
398 *address
= data
^ (bits
& mask
);
401 /*** drawing functions ***/
403 /* Clear the whole display */
404 void lcd_clear_display(void)
406 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
408 memset(lcd_framebuffer
, fg_pattern
, sizeof lcd_framebuffer
);
413 memcpy(lcd_framebuffer
, lcd_backdrop
, sizeof lcd_framebuffer
);
415 memset(lcd_framebuffer
, bg_pattern
, sizeof lcd_framebuffer
);
418 lcd_scroll_info
.lines
= 0;
421 /* Clear the current viewport */
422 void lcd_clear_viewport(void)
426 if (current_vp
== &default_vp
)
432 lastmode
= current_vp
->drawmode
;
434 /* Invert the INVERSEVID bit and set basic mode to SOLID */
435 current_vp
->drawmode
= (~lastmode
& DRMODE_INVERSEVID
) |
438 lcd_fillrect(0, 0, current_vp
->width
, current_vp
->height
);
440 current_vp
->drawmode
= lastmode
;
442 lcd_scroll_stop(current_vp
);
446 /* Set a single pixel */
447 void lcd_drawpixel(int x
, int y
)
449 if (((unsigned)x
< (unsigned)current_vp
->width
) &&
450 ((unsigned)y
< (unsigned)current_vp
->height
))
451 lcd_pixelfuncs
[current_vp
->drawmode
](current_vp
->x
+ x
, current_vp
->y
+ y
);
455 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
463 lcd_pixelfunc_type
*pfunc
= lcd_pixelfuncs
[current_vp
->drawmode
];
465 deltax
= abs(x2
- x1
);
466 deltay
= abs(y2
- y1
);
470 if (deltax
>= deltay
)
473 d
= 2 * deltay
- deltax
;
475 dinc2
= (deltay
- deltax
) * 2;
482 d
= 2 * deltax
- deltay
;
484 dinc2
= (deltax
- deltay
) * 2;
488 numpixels
++; /* include endpoints */
505 for (i
= 0; i
< numpixels
; i
++)
507 if (((unsigned)x
< (unsigned)current_vp
->width
) &&
508 ((unsigned)y
< (unsigned)current_vp
->height
))
509 pfunc(current_vp
->x
+ x
, current_vp
->y
+ y
);
526 /* Draw a horizontal line (optimised) */
527 void lcd_hline(int x1
, int x2
, int y
)
531 fb_data
*dst
, *dst_end
;
533 lcd_blockfunc_type
*bfunc
;
543 /* nothing to draw? */
544 if (((unsigned)y
>= (unsigned)current_vp
->height
) || (x1
>= current_vp
->width
)
551 if (x2
>= current_vp
->width
)
552 x2
= current_vp
->width
-1;
556 /* adjust x1 and y to viewport */
560 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
561 dst
= &lcd_framebuffer
[y
>>2][x1
];
562 mask
= pixmask
[y
& 3];
564 dst_end
= dst
+ width
;
566 bfunc(dst
++, mask
, 0xFFu
);
567 while (dst
< dst_end
);
570 /* Draw a vertical line (optimised) */
571 void lcd_vline(int x
, int y1
, int y2
)
575 unsigned mask
, mask_bottom
;
576 lcd_blockfunc_type
*bfunc
;
586 /* nothing to draw? */
587 if (((unsigned)x
>= (unsigned)current_vp
->width
) || (y1
>= current_vp
->height
)
594 if (y2
>= current_vp
->height
)
595 y2
= current_vp
->height
-1;
597 /* adjust for viewport */
602 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
603 dst
= &lcd_framebuffer
[y1
>>2][x
];
605 mask
= 0xFFu
<< (2 * (y1
& 3));
606 mask_bottom
= 0xFFu
>> (2 * (~ny
& 3));
608 for (; ny
>= 4; ny
-= 4)
610 bfunc(dst
, mask
, 0xFFu
);
615 bfunc(dst
, mask
, 0xFFu
);
618 /* Draw a rectangular box */
619 void lcd_drawrect(int x
, int y
, int width
, int height
)
621 if ((width
<= 0) || (height
<= 0))
624 int x2
= x
+ width
- 1;
625 int y2
= y
+ height
- 1;
628 lcd_vline(x2
, y
, y2
);
630 lcd_hline(x
, x2
, y2
);
633 /* Fill a rectangular area */
634 void lcd_fillrect(int x
, int y
, int width
, int height
)
637 fb_data
*dst
, *dst_end
;
638 unsigned mask
, mask_bottom
;
640 lcd_blockfunc_type
*bfunc
;
641 bool fillopt
= false;
643 /* nothing to draw? */
644 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
645 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
659 if (x
+ width
> current_vp
->width
)
660 width
= current_vp
->width
- x
;
661 if (y
+ height
> current_vp
->height
)
662 height
= current_vp
->height
- y
;
664 /* adjust for viewport */
668 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
670 if ((current_vp
->drawmode
& DRMODE_BG
) && !lcd_backdrop
)
678 if (current_vp
->drawmode
& DRMODE_FG
)
684 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
685 dst
= &lcd_framebuffer
[y
>>2][x
];
686 ny
= height
- 1 + (y
& 3);
687 mask
= 0xFFu
<< (2 * (y
& 3));
688 mask_bottom
= 0xFFu
>> (2 * (~ny
& 3));
690 for (; ny
>= 4; ny
-= 4)
692 if (fillopt
&& (mask
== 0xFFu
))
693 memset(dst
, bits
, width
);
696 fb_data
*dst_row
= dst
;
698 dst_end
= dst_row
+ width
;
700 bfunc(dst_row
++, mask
, 0xFFu
);
701 while (dst_row
< dst_end
);
709 if (fillopt
&& (mask
== 0xFFu
))
710 memset(dst
, bits
, width
);
713 dst_end
= dst
+ width
;
715 bfunc(dst
++, mask
, 0xFFu
);
716 while (dst
< dst_end
);
720 /* About Rockbox' internal monochrome bitmap format:
722 * A bitmap contains one bit for every pixel that defines if that pixel is
723 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
725 * The bytes are stored in row-major order, with byte 0 being top left,
726 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
727 * 0..7, the second row defines pixel row 8..15 etc.
729 * This is similar to the internal lcd hw format. */
731 /* Draw a partial monochrome bitmap */
732 void lcd_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
733 int stride
, int x
, int y
, int width
, int height
)
735 void lcd_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
736 int stride
, int x
, int y
, int width
, int height
)
739 fb_data
*dst
, *dst_end
;
740 unsigned mask
, mask_bottom
;
741 lcd_blockfunc_type
*bfunc
;
743 /* nothing to draw? */
744 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
745 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
761 if (x
+ width
> current_vp
->width
)
762 width
= current_vp
->width
- x
;
763 if (y
+ height
> current_vp
->height
)
764 height
= current_vp
->height
- y
;
766 /* adjust for viewport */
770 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
773 dst
= &lcd_framebuffer
[y
>>2][x
];
775 ny
= height
- 1 + shift
+ src_y
;
777 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
778 mask
= 0xFFu
<< (shift
+ src_y
);
779 mask_bottom
= 0xFFu
>> (~ny
& 7);
783 unsigned dmask1
, dmask2
, data
;
785 for (; ny
>= 8; ny
-= 8)
787 const unsigned char *src_row
= src
;
788 fb_data
*dst_row
= dst
+ LCD_WIDTH
;
790 dmask1
= lcd_dibits
[mask
&0x0F];
791 dmask2
= lcd_dibits
[(mask
>>4)&0x0F];
792 dst_end
= dst_row
+ width
;
799 bfunc(dst_row
- LCD_WIDTH
, dmask1
, lcd_dibits
[data
&0x0F]);
800 bfunc(dst_row
++, dmask2
, lcd_dibits
[(data
>>4)&0x0F]);
802 while (dst_row
< dst_end
);
807 bfunc(dst_row
++, dmask2
, lcd_dibits
[((*src_row
++)>>4)&0x0F]);
808 while (dst_row
< dst_end
);
815 dmask1
= lcd_dibits
[mask
&0x0F];
816 dmask2
= lcd_dibits
[(mask
>>4)&0x0F];
817 dst_end
= dst
+ width
;
826 bfunc(dst
, dmask1
, lcd_dibits
[data
&0x0F]);
827 bfunc((dst
++) + LCD_WIDTH
, dmask2
, lcd_dibits
[(data
>>4)&0x0F]);
829 while (dst
< dst_end
);
834 bfunc(dst
++, dmask1
, lcd_dibits
[(*src
++)&0x0F]);
835 while (dst
< dst_end
);
841 bfunc((dst
++) + LCD_WIDTH
, dmask2
, lcd_dibits
[((*src
++)>>4)&0x0F]);
842 while (dst
< dst_end
);
847 dst_end
= dst
+ width
;
850 const unsigned char *src_col
= src
++;
851 fb_data
*dst_col
= dst
++;
852 unsigned mask_col
= mask
;
855 for (y
= ny
; y
>= 8; y
-= 8)
857 data
|= *src_col
<< shift
;
859 if (mask_col
& 0xFFu
)
862 bfunc(dst_col
, lcd_dibits
[mask_col
&0x0F], lcd_dibits
[data
&0x0F]);
863 bfunc(dst_col
+ LCD_WIDTH
, lcd_dibits
[(mask_col
>>4)&0x0F],
864 lcd_dibits
[(data
>>4)&0x0F]);
871 dst_col
+= 2*LCD_WIDTH
;
874 data
|= *src_col
<< shift
;
875 mask_bottom
&= mask_col
;
876 if (mask_bottom
& 0x0F)
877 bfunc(dst_col
, lcd_dibits
[mask_bottom
&0x0F], lcd_dibits
[data
&0x0F]);
878 if (mask_bottom
& 0xF0)
879 bfunc(dst_col
+ LCD_WIDTH
, lcd_dibits
[(mask_bottom
&0xF0)>>4],
880 lcd_dibits
[(data
>>4)&0x0F]);
882 while (dst
< dst_end
);
886 /* Draw a full monochrome bitmap */
887 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
889 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
892 /* About Rockbox' internal native bitmap format:
894 * A bitmap contains two bits for every pixel. 00 = white, 01 = light grey,
895 * 10 = dark grey, 11 = black. Bits within a byte are arranged vertically, LSB
897 * The bytes are stored in row-major order, with byte 0 being top left,
898 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
899 * 0..3, the second row defines pixel row 4..7 etc.
901 * This is the same as the internal lcd hw format. */
903 /* Draw a partial native bitmap */
904 void lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
905 int stride
, int x
, int y
, int width
, int height
)
907 void lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
908 int stride
, int x
, int y
, int width
, int height
)
911 fb_data
*dst
, *dst_end
;
912 unsigned mask
, mask_bottom
;
914 /* nothing to draw? */
915 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
916 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
932 if (x
+ width
> current_vp
->width
)
933 width
= current_vp
->width
- x
;
934 if (y
+ height
> current_vp
->height
)
935 height
= current_vp
->height
- y
;
937 /* adjust for viewport */
941 src
+= stride
* (src_y
>> 2) + src_x
; /* move starting point */
944 dst
= &lcd_framebuffer
[y
>>2][x
];
946 ny
= height
- 1 + shift
+ src_y
;
948 mask
= 0xFFu
<< (2 * (shift
+ src_y
));
949 mask_bottom
= 0xFFu
>> (2 * (~ny
& 3));
953 for (; ny
>= 4; ny
-= 4)
956 memcpy(dst
, src
, width
);
959 const fb_data
*src_row
= src
;
960 fb_data
*dst_row
= dst
;
962 dst_end
= dst_row
+ width
;
964 setblock(dst_row
++, mask
, *src_row
++);
965 while (dst_row
< dst_end
);
974 memcpy(dst
, src
, width
);
977 dst_end
= dst
+ width
;
979 setblock(dst
++, mask
, *src
++);
980 while (dst
< dst_end
);
986 dst_end
= dst
+ width
;
989 const fb_data
*src_col
= src
++;
990 fb_data
*dst_col
= dst
++;
991 unsigned mask_col
= mask
;
994 for (y
= ny
; y
>= 4; y
-= 4)
996 data
|= *src_col
<< shift
;
998 if (mask_col
& 0xFFu
)
1000 setblock(dst_col
, mask_col
, data
);
1007 dst_col
+= LCD_WIDTH
;
1010 data
|= *src_col
<< shift
;
1011 setblock(dst_col
, mask_col
& mask_bottom
, data
);
1013 while (dst
< dst_end
);
1017 /* Draw a full native bitmap */
1018 void lcd_bitmap(const fb_data
*src
, int x
, int y
, int width
, int height
)
1020 lcd_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
1023 /* put a string at a given pixel position, skipping first ofs pixel columns */
1024 static void lcd_putsxyofs(int x
, int y
, int ofs
, const unsigned char *str
)
1027 unsigned short *ucs
;
1028 struct font
* pf
= font_get(current_vp
->font
);
1030 ucs
= bidi_l2v(str
, 1);
1032 while ((ch
= *ucs
++) != 0 && x
< current_vp
->width
)
1035 const unsigned char *bits
;
1037 /* get proportional width and glyph bits */
1038 width
= font_get_width(pf
,ch
);
1046 bits
= font_get_bits(pf
, ch
);
1048 lcd_mono_bitmap_part(bits
, ofs
, 0, width
, x
, y
, width
- ofs
,
1056 /* put a string at a given pixel position */
1057 void lcd_putsxy(int x
, int y
, const unsigned char *str
)
1059 lcd_putsxyofs(x
, y
, 0, str
);
1062 /*** line oriented text output ***/
1064 /* put a string at a given char position */
1065 void lcd_puts(int x
, int y
, const unsigned char *str
)
1067 lcd_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, 0);
1070 void lcd_puts_style(int x
, int y
, const unsigned char *str
, int style
)
1072 lcd_puts_style_offset(x
, y
, str
, style
, 0);
1075 void lcd_puts_offset(int x
, int y
, const unsigned char *str
, int offset
)
1077 lcd_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, offset
);
1080 /* put a string at a given char position, style, and pixel position,
1081 * skipping first offset pixel columns */
1082 void lcd_puts_style_offset(int x
, int y
, const unsigned char *str
,
1083 int style
, int offset
)
1085 int xpos
,ypos
,w
,h
,xrect
;
1086 int lastmode
= current_vp
->drawmode
;
1088 /* make sure scrolling is turned off on the line we are updating */
1089 lcd_scroll_stop_line(current_vp
, y
);
1094 lcd_getstringsize(str
, &w
, &h
);
1095 xpos
= current_vp
->xmargin
+ x
*w
/ utf8length((char *)str
);
1096 ypos
= current_vp
->ymargin
+ y
*h
;
1097 current_vp
->drawmode
= (style
& STYLE_INVERT
) ?
1098 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1099 lcd_putsxyofs(xpos
, ypos
, offset
, str
);
1100 current_vp
->drawmode
^= DRMODE_INVERSEVID
;
1101 xrect
= xpos
+ MAX(w
- offset
, 0);
1102 lcd_fillrect(xrect
, ypos
, current_vp
->width
- xrect
, h
);
1103 current_vp
->drawmode
= lastmode
;
1108 void lcd_puts_scroll(int x
, int y
, const unsigned char *string
)
1110 lcd_puts_scroll_style(x
, y
, string
, STYLE_DEFAULT
);
1113 void lcd_puts_scroll_style(int x
, int y
, const unsigned char *string
, int style
)
1115 lcd_puts_scroll_style_offset(x
, y
, string
, style
, 0);
1118 void lcd_puts_scroll_offset(int x
, int y
, const unsigned char *string
, int offset
)
1120 lcd_puts_scroll_style_offset(x
, y
, string
, STYLE_DEFAULT
, offset
);
1123 void lcd_puts_scroll_style_offset(int x
, int y
, const unsigned char *string
,
1124 int style
, int offset
)
1126 struct scrollinfo
* s
;
1129 if ((unsigned)y
>= (unsigned)current_vp
->height
)
1132 /* remove any previously scrolling line at the same location */
1133 lcd_scroll_stop_line(current_vp
, y
);
1135 if (lcd_scroll_info
.lines
>= LCD_SCROLLABLE_LINES
) return;
1137 s
= &lcd_scroll_info
.scroll
[lcd_scroll_info
.lines
];
1139 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
;
1141 if (style
& STYLE_INVERT
) {
1142 lcd_puts_style_offset(x
,y
,string
,STYLE_INVERT
,offset
);
1145 lcd_puts_offset(x
,y
,string
,offset
);
1147 lcd_getstringsize(string
, &w
, &h
);
1149 if (current_vp
->width
- x
* 8 - current_vp
->xmargin
< w
) {
1150 /* prepare scroll line */
1153 memset(s
->line
, 0, sizeof s
->line
);
1154 strcpy(s
->line
, (char *)string
);
1157 s
->width
= lcd_getstringsize((unsigned char *)s
->line
, &w
, &h
);
1159 /* scroll bidirectional or forward only depending on the string
1161 if ( lcd_scroll_info
.bidir_limit
) {
1162 s
->bidir
= s
->width
< (current_vp
->width
- current_vp
->xmargin
) *
1163 (100 + lcd_scroll_info
.bidir_limit
) / 100;
1168 if (!s
->bidir
) { /* add spaces if scrolling in the round */
1169 strcat(s
->line
, " ");
1170 /* get new width incl. spaces */
1171 s
->width
= lcd_getstringsize((unsigned char *)s
->line
, &w
, &h
);
1174 end
= strchr(s
->line
, '\0');
1175 strncpy(end
, (char *)string
, current_vp
->width
/2);
1179 s
->len
= utf8length((char *)string
);
1181 s
->startx
= current_vp
->xmargin
+ x
* s
->width
/ s
->len
;
1182 s
->backward
= false;
1184 lcd_scroll_info
.lines
++;
1188 void lcd_scroll_fn(void)
1191 struct scrollinfo
* s
;
1195 struct viewport
* old_vp
= current_vp
;
1197 for ( index
= 0; index
< lcd_scroll_info
.lines
; index
++ ) {
1198 s
= &lcd_scroll_info
.scroll
[index
];
1201 if (TIME_BEFORE(current_tick
, s
->start_tick
))
1204 lcd_set_viewport(s
->vp
);
1207 s
->offset
-= lcd_scroll_info
.step
;
1209 s
->offset
+= lcd_scroll_info
.step
;
1211 pf
= font_get(current_vp
->font
);
1213 ypos
= current_vp
->ymargin
+ s
->y
* pf
->height
;
1215 if (s
->bidir
) { /* scroll bidirectional */
1216 if (s
->offset
<= 0) {
1217 /* at beginning of line */
1219 s
->backward
= false;
1220 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
* 2;
1222 if (s
->offset
>= s
->width
- (current_vp
->width
- xpos
)) {
1223 /* at end of line */
1224 s
->offset
= s
->width
- (current_vp
->width
- xpos
);
1226 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
* 2;
1230 /* scroll forward the whole time */
1231 if (s
->offset
>= s
->width
)
1232 s
->offset
%= s
->width
;
1235 lastmode
= current_vp
->drawmode
;
1236 current_vp
->drawmode
= (s
->style
&STYLE_INVERT
) ?
1237 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1238 lcd_putsxyofs(xpos
, ypos
, s
->offset
, s
->line
);
1239 current_vp
->drawmode
= lastmode
;
1240 lcd_update_viewport_rect(xpos
, ypos
,
1241 current_vp
->width
- xpos
, pf
->height
);
1244 lcd_set_viewport(old_vp
);