1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
34 #include "rbunicode.h"
36 #include "scroll_engine.h"
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 unsigned fg_pattern IDATA_ATTR
= 0xFF; /* initially black */
50 static unsigned bg_pattern IDATA_ATTR
= 0x00; /* initially white */
51 static int drawmode
= DRMODE_SOLID
;
52 static int xmargin
= 0;
53 static int ymargin
= 0;
54 static int curfont
= FONT_SYSFIXED
;
60 /* Call device specific init */
65 /*** parameter handling ***/
67 void lcd_set_drawmode(int mode
)
69 drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
72 int lcd_get_drawmode(void)
77 void lcd_set_foreground(unsigned brightness
)
79 fg_pattern
= 0x55 * (~brightness
& 3);
82 unsigned lcd_get_foreground(void)
84 return ~fg_pattern
& 3;
87 void lcd_set_background(unsigned brightness
)
89 bg_pattern
= 0x55 * (~brightness
& 3);
92 unsigned lcd_get_background(void)
94 return ~bg_pattern
& 3;
97 void lcd_set_drawinfo(int mode
, unsigned fg_brightness
, unsigned bg_brightness
)
99 lcd_set_drawmode(mode
);
100 lcd_set_foreground(fg_brightness
);
101 lcd_set_background(bg_brightness
);
104 void lcd_setmargins(int x
, int y
)
110 int lcd_getxmargin(void)
115 int lcd_getymargin(void)
120 void lcd_setfont(int newfont
)
125 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
127 return font_getstringsize(str
, w
, h
, curfont
);
130 /*** low-level drawing functions ***/
132 static void setpixel(int x
, int y
)
134 unsigned mask
= pixmask
[x
& 3];
135 fb_data
*address
= &lcd_framebuffer
[y
][x
>>2];
136 unsigned data
= *address
;
138 *address
= data
^ ((data
^ fg_pattern
) & mask
);
141 static void clearpixel(int x
, int y
)
143 unsigned mask
= pixmask
[x
& 3];
144 fb_data
*address
= &lcd_framebuffer
[y
][x
>>2];
145 unsigned data
= *address
;
147 *address
= data
^ ((data
^ bg_pattern
) & mask
);
150 static void clearimgpixel(int x
, int y
)
152 unsigned mask
= pixmask
[x
& 3];
153 fb_data
*address
= &lcd_framebuffer
[y
][x
>>2];
154 unsigned data
= *address
;
156 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
);
159 static void flippixel(int x
, int y
)
161 unsigned mask
= pixmask
[x
& 3];
162 fb_data
*address
= &lcd_framebuffer
[y
][x
>>2];
167 static void nopixel(int x
, int y
)
173 lcd_pixelfunc_type
* const lcd_pixelfuncs_bgcolor
[8] = {
174 flippixel
, nopixel
, setpixel
, setpixel
,
175 nopixel
, clearpixel
, nopixel
, clearpixel
178 lcd_pixelfunc_type
* const lcd_pixelfuncs_backdrop
[8] = {
179 flippixel
, nopixel
, setpixel
, setpixel
,
180 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
183 lcd_pixelfunc_type
* const * lcd_pixelfuncs
= lcd_pixelfuncs_bgcolor
;
186 /* 'mask' and 'bits' contain 2 bits per pixel */
187 static void flipblock(fb_data
*address
, unsigned mask
, unsigned bits
)
189 static void flipblock(fb_data
*address
, unsigned mask
, unsigned bits
)
191 *address
^= bits
& mask
;
194 static void bgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
196 static void bgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
198 unsigned data
= *address
;
200 *address
= data
^ ((data
^ bg_pattern
) & mask
& ~bits
);
203 static void bgimgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
205 static void bgimgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
207 unsigned data
= *address
;
209 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
& ~bits
);
212 static void fgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
214 static void fgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
216 unsigned data
= *address
;
218 *address
= data
^ ((data
^ fg_pattern
) & mask
& bits
);
221 static void solidblock(fb_data
*address
, unsigned mask
, unsigned bits
)
223 static void solidblock(fb_data
*address
, unsigned mask
, unsigned bits
)
225 unsigned data
= *address
;
226 unsigned bgp
= bg_pattern
;
228 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
229 *address
= data
^ ((data
^ bits
) & mask
);
232 static void solidimgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
234 static void solidimgblock(fb_data
*address
, unsigned mask
, unsigned bits
)
236 unsigned data
= *address
;
237 unsigned bgp
= *(address
+ lcd_backdrop_offset
);
239 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
240 *address
= data
^ ((data
^ bits
) & mask
);
243 static void flipinvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
245 static void flipinvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
247 *address
^= ~bits
& mask
;
250 static void bginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
252 static void bginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
254 unsigned data
= *address
;
256 *address
= data
^ ((data
^ bg_pattern
) & mask
& bits
);
259 static void bgimginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
261 static void bgimginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
263 unsigned data
= *address
;
265 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
& bits
);
268 static void fginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
270 static void fginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
272 unsigned data
= *address
;
274 *address
= data
^ ((data
^ fg_pattern
) & mask
& ~bits
);
277 static void solidinvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
279 static void solidinvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
281 unsigned data
= *address
;
282 unsigned fgp
= fg_pattern
;
284 bits
= fgp
^ ((fgp
^ bg_pattern
) & bits
);
285 *address
= data
^ ((data
^ bits
) & mask
);
288 static void solidimginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
290 static void solidimginvblock(fb_data
*address
, unsigned mask
, unsigned bits
)
292 unsigned data
= *address
;
293 unsigned fgp
= fg_pattern
;
295 bits
= fgp
^ ((fgp
^ *(address
+ lcd_backdrop_offset
)) & bits
);
296 *address
= data
^ ((data
^ bits
) & mask
);
299 lcd_blockfunc_type
* const lcd_blockfuncs_bgcolor
[8] = {
300 flipblock
, bgblock
, fgblock
, solidblock
,
301 flipinvblock
, bginvblock
, fginvblock
, solidinvblock
304 lcd_blockfunc_type
* const lcd_blockfuncs_backdrop
[8] = {
305 flipblock
, bgimgblock
, fgblock
, solidimgblock
,
306 flipinvblock
, bgimginvblock
, fginvblock
, solidimginvblock
309 lcd_blockfunc_type
* const * lcd_blockfuncs
= lcd_blockfuncs_bgcolor
;
312 void lcd_set_backdrop(fb_data
* backdrop
)
314 lcd_backdrop
= backdrop
;
317 lcd_backdrop_offset
= (long)backdrop
- (long)lcd_framebuffer
;
318 lcd_pixelfuncs
= lcd_pixelfuncs_backdrop
;
319 lcd_blockfuncs
= lcd_blockfuncs_backdrop
;
323 lcd_backdrop_offset
= 0;
324 lcd_pixelfuncs
= lcd_pixelfuncs_bgcolor
;
325 lcd_blockfuncs
= lcd_blockfuncs_bgcolor
;
329 fb_data
* lcd_get_backdrop(void)
335 static inline void setblock(fb_data
*address
, unsigned mask
, unsigned bits
)
337 unsigned data
= *address
;
340 *address
= data
^ (bits
& mask
);
343 /*** drawing functions ***/
345 /* Clear the whole display */
346 void lcd_clear_display(void)
348 if (drawmode
& DRMODE_INVERSEVID
)
350 memset(lcd_framebuffer
, fg_pattern
, sizeof lcd_framebuffer
);
355 memcpy(lcd_framebuffer
, lcd_backdrop
, sizeof lcd_framebuffer
);
357 memset(lcd_framebuffer
, bg_pattern
, sizeof lcd_framebuffer
);
360 lcd_scroll_info
.lines
= 0;
363 /* Set a single pixel */
364 void lcd_drawpixel(int x
, int y
)
366 if (((unsigned)x
< LCD_WIDTH
) && ((unsigned)y
< LCD_HEIGHT
))
367 lcd_pixelfuncs
[drawmode
](x
, y
);
371 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
379 lcd_pixelfunc_type
*pfunc
= lcd_pixelfuncs
[drawmode
];
381 deltax
= abs(x2
- x1
);
382 deltay
= abs(y2
- y1
);
386 if (deltax
>= deltay
)
389 d
= 2 * deltay
- deltax
;
391 dinc2
= (deltay
- deltax
) * 2;
398 d
= 2 * deltax
- deltay
;
400 dinc2
= (deltax
- deltay
) * 2;
404 numpixels
++; /* include endpoints */
421 for (i
= 0; i
< numpixels
; i
++)
423 if (((unsigned)x
< LCD_WIDTH
) && ((unsigned)y
< LCD_HEIGHT
))
441 /* Draw a horizontal line (optimised) */
442 void lcd_hline(int x1
, int x2
, int y
)
446 unsigned mask
, mask_right
;
447 lcd_blockfunc_type
*bfunc
;
457 /* nothing to draw? */
458 if (((unsigned)y
>= LCD_HEIGHT
) || (x1
>= LCD_WIDTH
) || (x2
< 0))
467 bfunc
= lcd_blockfuncs
[drawmode
];
468 dst
= &lcd_framebuffer
[y
][x1
>>2];
470 mask
= 0xFFu
>> (2 * (x1
& 3));
471 mask_right
= 0xFFu
<< (2 * (~nx
& 3));
473 for (; nx
>= 4; nx
-= 4)
475 bfunc(dst
++, mask
, 0xFFu
);
479 bfunc(dst
, mask
, 0xFFu
);
482 /* Draw a vertical line (optimised) */
483 void lcd_vline(int x
, int y1
, int y2
)
486 unsigned char *dst
, *dst_end
;
488 lcd_blockfunc_type
*bfunc
;
498 /* nothing to draw? */
499 if (((unsigned)x
>= LCD_WIDTH
) || (y1
>= LCD_HEIGHT
) || (y2
< 0))
505 if (y2
>= LCD_HEIGHT
)
508 bfunc
= lcd_blockfuncs
[drawmode
];
509 dst
= &lcd_framebuffer
[y1
][x
>>2];
510 mask
= pixmask
[x
& 3];
512 dst_end
= dst
+ (y2
- y1
) * LCD_FBWIDTH
;
515 bfunc(dst
, mask
, 0xFFu
);
518 while (dst
<= dst_end
);
521 /* Draw a rectangular box */
522 void lcd_drawrect(int x
, int y
, int width
, int height
)
524 if ((width
<= 0) || (height
<= 0))
527 int x2
= x
+ width
- 1;
528 int y2
= y
+ height
- 1;
531 lcd_vline(x2
, y
, y2
);
533 lcd_hline(x
, x2
, y2
);
536 /* Fill a rectangular area */
537 void lcd_fillrect(int x
, int y
, int width
, int height
)
540 unsigned char *dst
, *dst_end
;
541 unsigned mask
, mask_right
;
542 lcd_blockfunc_type
*bfunc
;
544 /* nothing to draw? */
545 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
546 || (x
+ width
<= 0) || (y
+ height
<= 0))
560 if (x
+ width
> LCD_WIDTH
)
561 width
= LCD_WIDTH
- x
;
562 if (y
+ height
> LCD_HEIGHT
)
563 height
= LCD_HEIGHT
- y
;
565 bfunc
= lcd_blockfuncs
[drawmode
];
566 dst
= &lcd_framebuffer
[y
][x
>>2];
567 nx
= width
- 1 + (x
& 3);
568 mask
= 0xFFu
>> (2 * (x
& 3));
569 mask_right
= 0xFFu
<< (2 * (~nx
& 3));
571 for (; nx
>= 4; nx
-= 4)
573 unsigned char *dst_col
= dst
;
575 dst_end
= dst_col
+ height
* LCD_FBWIDTH
;
578 bfunc(dst_col
, mask
, 0xFFu
);
579 dst_col
+= LCD_FBWIDTH
;
581 while (dst_col
< dst_end
);
588 dst_end
= dst
+ height
* LCD_FBWIDTH
;
591 bfunc(dst
, mask
, 0xFFu
);
594 while (dst
< dst_end
);
597 /* About Rockbox' internal monochrome bitmap format:
599 * A bitmap contains one bit for every pixel that defines if that pixel is
600 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
602 * The bytes are stored in row-major order, with byte 0 being top left,
603 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
604 * 0..7, the second row defines pixel row 8..15 etc. */
606 /* Draw a partial monochrome bitmap */
607 void lcd_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
608 int stride
, int x
, int y
, int width
, int height
)
610 void lcd_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
611 int stride
, int x
, int y
, int width
, int height
)
614 const unsigned char * src_end
;
615 lcd_pixelfunc_type
* fgfunc
;
616 lcd_pixelfunc_type
* bgfunc
;
618 /* nothing to draw? */
619 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
620 || (x
+ width
<= 0) || (y
+ height
<= 0))
636 if (x
+ width
> LCD_WIDTH
)
637 width
= LCD_WIDTH
- x
;
638 if (y
+ height
> LCD_HEIGHT
)
639 height
= LCD_HEIGHT
- y
;
641 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
643 src_end
= src
+ width
;
645 fgfunc
= lcd_pixelfuncs
[drawmode
];
646 bgfunc
= lcd_pixelfuncs
[drawmode
^ DRMODE_INVERSEVID
];
650 const unsigned char *src_col
= src
++;
651 unsigned data
= *src_col
>> src_y
;
652 int numbits
= 8 - ((int)src_y
);
676 while (src
< src_end
);
679 /* Draw a full monochrome bitmap */
680 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
682 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
685 /* About Rockbox' internal native bitmap format:
687 * A bitmap contains two bits for every pixel. 00 = white, 01 = light grey,
688 * 10 = dark grey, 11 = black. Bits within a byte are arranged horizontally,
690 * The bytes are stored in row-major order, with byte 0 being top left,
691 * byte 1 2nd from left etc. Each row of bytes defines one pixel row.
693 * This is the same as the internal lcd hw format. */
695 /* Draw a partial native bitmap */
696 void lcd_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
697 int stride
, int x
, int y
, int width
, int height
)
699 void lcd_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
700 int stride
, int x
, int y
, int width
, int height
)
703 unsigned char *dst
, *dst_end
;
704 unsigned mask
, mask_right
;
706 /* nothing to draw? */
707 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
708 || (x
+ width
<= 0) || (y
+ height
<= 0))
724 if (x
+ width
> LCD_WIDTH
)
725 width
= LCD_WIDTH
- x
;
726 if (y
+ height
> LCD_HEIGHT
)
727 height
= LCD_HEIGHT
- y
;
729 stride
= (stride
+ 3) >> 2; /* convert to no. of bytes */
731 src
+= stride
* src_y
+ (src_x
>> 2); /* move starting point */
734 dst
= &lcd_framebuffer
[y
][x
>>2];
736 nx
= width
- 1 + shift
+ src_x
;
738 mask
= 0xFF00u
>> (2 * (shift
+ src_x
));
739 mask_right
= 0xFFu
<< (2 * (~nx
& 3));
742 dst_end
= dst
+ height
* LCD_FBWIDTH
;
745 const unsigned char *src_row
= src
;
746 unsigned char *dst_row
= dst
;
747 unsigned mask_row
= mask
>> 8;
750 for (x
= nx
; x
>= 4; x
-= 4)
752 data
= (data
<< 8) | *src_row
++;
756 setblock(dst_row
, mask_row
, data
>> shift
);
764 data
= (data
<< 8) | *src_row
;
765 setblock(dst_row
, mask_row
& mask_right
, data
>> shift
);
770 while (dst
< dst_end
);
773 /* Draw a full native bitmap */
774 void lcd_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
776 lcd_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
779 /* put a string at a given pixel position, skipping first ofs pixel columns */
780 static void lcd_putsxyofs(int x
, int y
, int ofs
, const unsigned char *str
)
784 struct font
* pf
= font_get(curfont
);
786 ucs
= bidi_l2v(str
, 1);
788 while ((ch
= *ucs
++) != 0 && x
< LCD_WIDTH
)
791 const unsigned char *bits
;
793 /* get proportional width and glyph bits */
794 width
= font_get_width(pf
,ch
);
802 bits
= font_get_bits(pf
, ch
);
804 lcd_mono_bitmap_part(bits
, ofs
, 0, width
, x
, y
, width
- ofs
,
812 /* put a string at a given pixel position */
813 void lcd_putsxy(int x
, int y
, const unsigned char *str
)
815 lcd_putsxyofs(x
, y
, 0, str
);
818 /*** line oriented text output ***/
820 /* put a string at a given char position */
821 void lcd_puts(int x
, int y
, const unsigned char *str
)
823 lcd_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, 0);
826 void lcd_puts_style(int x
, int y
, const unsigned char *str
, int style
)
828 lcd_puts_style_offset(x
, y
, str
, style
, 0);
831 void lcd_puts_offset(int x
, int y
, const unsigned char *str
, int offset
)
833 lcd_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, offset
);
836 /* put a string at a given char position, style, and pixel position,
837 * skipping first offset pixel columns */
838 void lcd_puts_style_offset(int x
, int y
, const unsigned char *str
,
839 int style
, int offset
)
841 int xpos
,ypos
,w
,h
,xrect
;
842 int lastmode
= drawmode
;
844 /* make sure scrolling is turned off on the line we are updating */
845 lcd_scroll_info
.lines
&= ~(1 << y
);
850 lcd_getstringsize(str
, &w
, &h
);
851 xpos
= xmargin
+ x
*w
/ utf8length((char *)str
);
852 ypos
= ymargin
+ y
*h
;
853 drawmode
= (style
& STYLE_INVERT
) ?
854 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
855 lcd_putsxyofs(xpos
, ypos
, offset
, str
);
856 drawmode
^= DRMODE_INVERSEVID
;
857 xrect
= xpos
+ MAX(w
- offset
, 0);
858 lcd_fillrect(xrect
, ypos
, LCD_WIDTH
- xrect
, h
);
863 void lcd_puts_scroll(int x
, int y
, const unsigned char *string
)
865 lcd_puts_scroll_style(x
, y
, string
, STYLE_DEFAULT
);
868 void lcd_puts_scroll_style(int x
, int y
, const unsigned char *string
, int style
)
870 lcd_puts_scroll_style_offset(x
, y
, string
, style
, 0);
873 void lcd_puts_scroll_offset(int x
, int y
, const unsigned char *string
, int offset
)
875 lcd_puts_scroll_style_offset(x
, y
, string
, STYLE_DEFAULT
, offset
);
878 void lcd_puts_scroll_style_offset(int x
, int y
, const unsigned char *string
,
879 int style
, int offset
)
881 struct scrollinfo
* s
;
884 if(y
>=LCD_SCROLLABLE_LINES
) return;
886 s
= &lcd_scroll_info
.scroll
[y
];
888 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
;
890 if (style
& STYLE_INVERT
) {
891 lcd_puts_style_offset(x
,y
,string
,STYLE_INVERT
,offset
);
894 lcd_puts_offset(x
,y
,string
,offset
);
896 lcd_getstringsize(string
, &w
, &h
);
898 if (LCD_WIDTH
- x
* 8 - xmargin
< w
) {
899 /* prepare scroll line */
902 memset(s
->line
, 0, sizeof s
->line
);
903 strcpy(s
->line
, (char *)string
);
906 s
->width
= lcd_getstringsize((unsigned char *)s
->line
, &w
, &h
);
908 /* scroll bidirectional or forward only depending on the string
910 if ( lcd_scroll_info
.bidir_limit
) {
911 s
->bidir
= s
->width
< (LCD_WIDTH
- xmargin
) *
912 (100 + lcd_scroll_info
.bidir_limit
) / 100;
917 if (!s
->bidir
) { /* add spaces if scrolling in the round */
918 strcat(s
->line
, " ");
919 /* get new width incl. spaces */
920 s
->width
= lcd_getstringsize((unsigned char *)s
->line
, &w
, &h
);
923 end
= strchr(s
->line
, '\0');
924 strncpy(end
, (char *)string
, LCD_WIDTH
/2);
926 s
->len
= utf8length((char *)string
);
928 s
->startx
= xmargin
+ x
* s
->width
/ s
->len
;;
930 lcd_scroll_info
.lines
|= (1<<y
);
933 /* force a bit switch-off since it doesn't scroll */
934 lcd_scroll_info
.lines
&= ~(1<<y
);
937 void lcd_scroll_fn(void)
940 struct scrollinfo
* s
;
945 for ( index
= 0; index
< LCD_SCROLLABLE_LINES
; index
++ ) {
947 if ((lcd_scroll_info
.lines
& (1 << index
)) == 0)
950 s
= &lcd_scroll_info
.scroll
[index
];
953 if (TIME_BEFORE(current_tick
, s
->start_tick
))
957 s
->offset
-= lcd_scroll_info
.step
;
959 s
->offset
+= lcd_scroll_info
.step
;
961 pf
= font_get(curfont
);
963 ypos
= ymargin
+ index
* pf
->height
;
965 if (s
->bidir
) { /* scroll bidirectional */
966 if (s
->offset
<= 0) {
967 /* at beginning of line */
970 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
* 2;
972 if (s
->offset
>= s
->width
- (LCD_WIDTH
- xpos
)) {
974 s
->offset
= s
->width
- (LCD_WIDTH
- xpos
);
976 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
* 2;
980 /* scroll forward the whole time */
981 if (s
->offset
>= s
->width
)
982 s
->offset
%= s
->width
;
986 drawmode
= (s
->style
&STYLE_INVERT
) ?
987 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
988 lcd_putsxyofs(xpos
, ypos
, s
->offset
, s
->line
);
990 lcd_update_rect(xpos
, ypos
, LCD_WIDTH
- xpos
, pf
->height
);