1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 Jens Arnold
12 * Rockbox driver for 2bit vertically interleaved remote LCDs
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
24 #include "lcd-remote.h"
34 #include "rbunicode.h"
36 #include "lcd-remote-target.h"
37 #include "scroll_engine.h"
41 fb_remote_data lcd_remote_framebuffer
[LCD_REMOTE_FBHEIGHT
][LCD_REMOTE_FBWIDTH
]
44 static const fb_remote_data patterns
[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000};
46 static fb_remote_data
* remote_backdrop
= NULL
;
47 static long remote_backdrop_offset IDATA_ATTR
= 0;
49 static unsigned fg_pattern IDATA_ATTR
= 0xFFFF; /* initially black */
50 static unsigned bg_pattern IDATA_ATTR
= 0x0000; /* initially white */
51 static int drawmode
= DRMODE_SOLID
;
52 static int xmargin
= 0;
53 static int ymargin
= 0;
54 static int curfont
= FONT_SYSFIXED
;
56 /*** parameter handling ***/
57 unsigned lcd_remote_color_to_native(unsigned color
)
59 unsigned r
= (color
& 0xf800) >> 10;
60 unsigned g
= (color
& 0x07e0) >> 5;
61 unsigned b
= (color
& 0x001f) << 2;
64 * |Y'| = |0.299000 0.587000 0.114000| |G|
67 return (5*r
+ 9*g
+ b
) >> 8;
70 void lcd_remote_set_drawmode(int mode
)
72 drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
75 int lcd_remote_get_drawmode(void)
80 void lcd_remote_set_foreground(unsigned brightness
)
82 fg_pattern
= patterns
[brightness
& 3];
85 unsigned lcd_remote_get_foreground(void)
87 return (~fg_pattern
>> 7) & 3;
90 void lcd_remote_set_background(unsigned brightness
)
92 bg_pattern
= patterns
[brightness
& 3];
95 unsigned lcd_remote_get_background(void)
97 return (~bg_pattern
>> 7) & 3;
100 void lcd_remote_set_drawinfo(int mode
, unsigned fg_brightness
,
101 unsigned bg_brightness
)
103 lcd_remote_set_drawmode(mode
);
104 lcd_remote_set_foreground(fg_brightness
);
105 lcd_remote_set_background(bg_brightness
);
108 void lcd_remote_setmargins(int x
, int y
)
114 int lcd_remote_getxmargin(void)
119 int lcd_remote_getymargin(void)
124 void lcd_remote_setfont(int newfont
)
129 int lcd_remote_getstringsize(const unsigned char *str
, int *w
, int *h
)
131 return font_getstringsize(str
, w
, h
, curfont
);
134 /*** low-level drawing functions ***/
136 static void setpixel(int x
, int y
)
138 unsigned mask
= 0x0101 << (y
& 7);
139 fb_remote_data
*address
= &lcd_remote_framebuffer
[y
>>3][x
];
140 unsigned data
= *address
;
142 *address
= data
^ ((data
^ fg_pattern
) & mask
);
145 static void clearpixel(int x
, int y
)
147 unsigned mask
= 0x0101 << (y
& 7);
148 fb_remote_data
*address
= &lcd_remote_framebuffer
[y
>>3][x
];
149 unsigned data
= *address
;
151 *address
= data
^ ((data
^ bg_pattern
) & mask
);
154 static void clearimgpixel(int x
, int y
)
156 unsigned mask
= 0x0101 << (y
& 7);
157 fb_remote_data
*address
= &lcd_remote_framebuffer
[y
>>3][x
];
158 unsigned data
= *address
;
160 *address
= data
^ ((data
^ *(fb_remote_data
*)((long)address
161 + remote_backdrop_offset
)) & mask
);
164 static void flippixel(int x
, int y
)
166 unsigned mask
= 0x0101 << (y
& 7);
167 fb_remote_data
*address
= &lcd_remote_framebuffer
[y
>>3][x
];
172 static void nopixel(int x
, int y
)
178 lcd_remote_pixelfunc_type
* const lcd_remote_pixelfuncs_bgcolor
[8] = {
179 flippixel
, nopixel
, setpixel
, setpixel
,
180 nopixel
, clearpixel
, nopixel
, clearpixel
183 lcd_remote_pixelfunc_type
* const lcd_remote_pixelfuncs_backdrop
[8] = {
184 flippixel
, nopixel
, setpixel
, setpixel
,
185 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
188 lcd_remote_pixelfunc_type
* const *lcd_remote_pixelfuncs
= lcd_remote_pixelfuncs_bgcolor
;
190 /* 'mask' and 'bits' contain 2 bits per pixel */
191 static void flipblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
193 static void flipblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
195 *address
^= bits
& mask
;
198 static void bgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
200 static void bgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
202 unsigned data
= *address
;
204 *address
= data
^ ((data
^ bg_pattern
) & mask
& ~bits
);
207 static void bgimgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
209 static void bgimgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
211 unsigned data
= *address
;
213 *address
= data
^ ((data
^ *(fb_remote_data
*)((long)address
214 + remote_backdrop_offset
)) & mask
& ~bits
);
217 static void fgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
219 static void fgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
221 unsigned data
= *address
;
223 *address
= data
^ ((data
^ fg_pattern
) & mask
& bits
);
226 static void solidblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
228 static void solidblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
230 unsigned data
= *address
;
231 unsigned bgp
= bg_pattern
;
233 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
234 *address
= data
^ ((data
^ bits
) & mask
);
237 static void solidimgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
239 static void solidimgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
241 unsigned data
= *address
;
242 unsigned bgp
= *(fb_remote_data
*)((long)address
+ remote_backdrop_offset
);
244 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
245 *address
= data
^ ((data
^ bits
) & mask
);
248 static void flipinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
250 static void flipinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
252 *address
^= ~bits
& mask
;
255 static void bginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
257 static void bginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
259 unsigned data
= *address
;
261 *address
= data
^ ((data
^ bg_pattern
) & mask
& bits
);
264 static void bgimginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
266 static void bgimginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
268 unsigned data
= *address
;
270 *address
= data
^ ((data
^ *(fb_remote_data
*)((long)address
271 + remote_backdrop_offset
)) & mask
& bits
);
274 static void fginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
276 static void fginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
278 unsigned data
= *address
;
280 *address
= data
^ ((data
^ fg_pattern
) & mask
& ~bits
);
283 static void solidinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
285 static void solidinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
287 unsigned data
= *address
;
288 unsigned fgp
= fg_pattern
;
290 bits
= fgp
^ ((fgp
^ bg_pattern
) & bits
);
291 *address
= data
^ ((data
^ bits
) & mask
);
294 static void solidimginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
296 static void solidimginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
298 unsigned data
= *address
;
299 unsigned fgp
= fg_pattern
;
301 bits
= fgp
^ ((fgp
^ *(fb_remote_data
*)((long)address
302 + remote_backdrop_offset
)) & bits
);
303 *address
= data
^ ((data
^ bits
) & mask
);
306 lcd_remote_blockfunc_type
* const lcd_remote_blockfuncs_bgcolor
[8] = {
307 flipblock
, bgblock
, fgblock
, solidblock
,
308 flipinvblock
, bginvblock
, fginvblock
, solidinvblock
311 lcd_remote_blockfunc_type
* const lcd_remote_blockfuncs_backdrop
[8] = {
312 flipblock
, bgimgblock
, fgblock
, solidimgblock
,
313 flipinvblock
, bgimginvblock
, fginvblock
, solidimginvblock
316 lcd_remote_blockfunc_type
* const *lcd_remote_blockfuncs
= lcd_remote_blockfuncs_bgcolor
;
319 void lcd_remote_set_backdrop(fb_remote_data
* backdrop
)
321 remote_backdrop
= backdrop
;
324 remote_backdrop_offset
= (long)backdrop
- (long)lcd_remote_framebuffer
;
325 lcd_remote_pixelfuncs
= lcd_remote_pixelfuncs_backdrop
;
326 lcd_remote_blockfuncs
= lcd_remote_blockfuncs_backdrop
;
330 remote_backdrop_offset
= 0;
331 lcd_remote_pixelfuncs
= lcd_remote_pixelfuncs_bgcolor
;
332 lcd_remote_blockfuncs
= lcd_remote_blockfuncs_bgcolor
;
336 fb_remote_data
* lcd_remote_get_backdrop(void)
338 return remote_backdrop
;
341 static inline void setblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
343 unsigned data
= *address
;
346 *address
= data
^ (bits
& mask
);
349 /*** drawing functions ***/
351 /* Clear the whole display */
352 void lcd_remote_clear_display(void)
354 if (drawmode
& DRMODE_INVERSEVID
)
356 memset(lcd_remote_framebuffer
, fg_pattern
,
357 sizeof lcd_remote_framebuffer
);
362 memcpy(lcd_remote_framebuffer
, remote_backdrop
,
363 sizeof lcd_remote_framebuffer
);
365 memset(lcd_remote_framebuffer
, bg_pattern
,
366 sizeof lcd_remote_framebuffer
);
369 lcd_remote_scroll_info
.lines
= 0;
372 /* Set a single pixel */
373 void lcd_remote_drawpixel(int x
, int y
)
375 if (((unsigned)x
< LCD_REMOTE_WIDTH
) && ((unsigned)y
< LCD_REMOTE_HEIGHT
))
376 lcd_remote_pixelfuncs
[drawmode
](x
, y
);
380 void lcd_remote_drawline(int x1
, int y1
, int x2
, int y2
)
388 lcd_remote_pixelfunc_type
*pfunc
= lcd_remote_pixelfuncs
[drawmode
];
390 deltax
= abs(x2
- x1
);
391 deltay
= abs(y2
- y1
);
395 if (deltax
>= deltay
)
398 d
= 2 * deltay
- deltax
;
400 dinc2
= (deltay
- deltax
) * 2;
407 d
= 2 * deltax
- deltay
;
409 dinc2
= (deltax
- deltay
) * 2;
413 numpixels
++; /* include endpoints */
430 for (i
= 0; i
< numpixels
; i
++)
432 if (((unsigned)x
< LCD_REMOTE_WIDTH
) && ((unsigned)y
< LCD_REMOTE_HEIGHT
))
450 /* Draw a horizontal line (optimised) */
451 void lcd_remote_hline(int x1
, int x2
, int y
)
454 fb_remote_data
*dst
, *dst_end
;
456 lcd_remote_blockfunc_type
*bfunc
;
466 /* nothing to draw? */
467 if (((unsigned)y
>= LCD_REMOTE_HEIGHT
) || (x1
>= LCD_REMOTE_WIDTH
)
474 if (x2
>= LCD_REMOTE_WIDTH
)
475 x2
= LCD_REMOTE_WIDTH
-1;
477 bfunc
= lcd_remote_blockfuncs
[drawmode
];
478 dst
= &lcd_remote_framebuffer
[y
>>3][x1
];
479 mask
= 0x0101 << (y
& 7);
481 dst_end
= dst
+ x2
- x1
;
483 bfunc(dst
++, mask
, 0xFFFFu
);
484 while (dst
<= dst_end
);
487 /* Draw a vertical line (optimised) */
488 void lcd_remote_vline(int x
, int y1
, int y2
)
492 unsigned mask
, mask_bottom
;
493 lcd_remote_blockfunc_type
*bfunc
;
503 /* nothing to draw? */
504 if (((unsigned)x
>= LCD_REMOTE_WIDTH
) || (y1
>= LCD_REMOTE_HEIGHT
)
511 if (y2
>= LCD_REMOTE_HEIGHT
)
512 y2
= LCD_REMOTE_HEIGHT
-1;
514 bfunc
= lcd_remote_blockfuncs
[drawmode
];
515 dst
= &lcd_remote_framebuffer
[y1
>>3][x
];
517 mask
= (0xFFu
<< (y1
& 7)) & 0xFFu
;
519 mask_bottom
= 0xFFu
>> (~ny
& 7);
520 mask_bottom
|= mask_bottom
<< 8;
522 for (; ny
>= 8; ny
-= 8)
524 bfunc(dst
, mask
, 0xFFFFu
);
525 dst
+= LCD_REMOTE_WIDTH
;
529 bfunc(dst
, mask
, 0xFFFFu
);
532 /* Draw a rectangular box */
533 void lcd_remote_drawrect(int x
, int y
, int width
, int height
)
535 if ((width
<= 0) || (height
<= 0))
538 int x2
= x
+ width
- 1;
539 int y2
= y
+ height
- 1;
541 lcd_remote_vline(x
, y
, y2
);
542 lcd_remote_vline(x2
, y
, y2
);
543 lcd_remote_hline(x
, x2
, y
);
544 lcd_remote_hline(x
, x2
, y2
);
547 /* Fill a rectangular area */
548 void lcd_remote_fillrect(int x
, int y
, int width
, int height
)
551 fb_remote_data
*dst
, *dst_end
;
552 unsigned mask
, mask_bottom
;
554 lcd_remote_blockfunc_type
*bfunc
;
555 bool fillopt
= false;
557 /* nothing to draw? */
558 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_REMOTE_WIDTH
)
559 || (y
>= LCD_REMOTE_HEIGHT
) || (x
+ width
<= 0) || (y
+ height
<= 0))
573 if (x
+ width
> LCD_REMOTE_WIDTH
)
574 width
= LCD_REMOTE_WIDTH
- x
;
575 if (y
+ height
> LCD_REMOTE_HEIGHT
)
576 height
= LCD_REMOTE_HEIGHT
- y
;
578 if (drawmode
& DRMODE_INVERSEVID
)
580 if ((drawmode
& DRMODE_BG
) && !remote_backdrop
)
588 if (drawmode
& DRMODE_FG
)
594 bfunc
= lcd_remote_blockfuncs
[drawmode
];
595 dst
= &lcd_remote_framebuffer
[y
>>3][x
];
596 ny
= height
- 1 + (y
& 7);
597 mask
= (0xFFu
<< (y
& 7)) & 0xFFu
;
599 mask_bottom
= 0xFFu
>> (~ny
& 7);
600 mask_bottom
|= mask_bottom
<< 8;
602 for (; ny
>= 8; ny
-= 8)
604 if (fillopt
&& (mask
== 0xFFFFu
))
605 memset16(dst
, bits
, width
);
608 fb_remote_data
*dst_row
= dst
;
610 dst_end
= dst_row
+ width
;
612 bfunc(dst_row
++, mask
, 0xFFFFu
);
613 while (dst_row
< dst_end
);
616 dst
+= LCD_REMOTE_WIDTH
;
621 if (fillopt
&& (mask
== 0xFFFFu
))
622 memset16(dst
, bits
, width
);
625 dst_end
= dst
+ width
;
627 bfunc(dst
++, mask
, 0xFFFFu
);
628 while (dst
< dst_end
);
632 /* About Rockbox' internal monochrome bitmap format:
634 * A bitmap contains one bit for every pixel that defines if that pixel is
635 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
637 * The bytes are stored in row-major order, with byte 0 being top left,
638 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
639 * 0..7, the second row defines pixel row 8..15 etc.
641 * This is similar to the internal lcd hw format. */
643 /* Draw a partial monochrome bitmap */
644 void lcd_remote_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
645 int stride
, int x
, int y
, int width
, int height
)
647 void lcd_remote_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
648 int stride
, int x
, int y
, int width
, int height
)
651 fb_remote_data
*dst
, *dst_end
;
652 unsigned data
, mask
, mask_bottom
;
653 lcd_remote_blockfunc_type
*bfunc
;
655 /* nothing to draw? */
656 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_REMOTE_WIDTH
)
657 || (y
>= LCD_REMOTE_HEIGHT
) || (x
+ width
<= 0) || (y
+ height
<= 0))
673 if (x
+ width
> LCD_REMOTE_WIDTH
)
674 width
= LCD_REMOTE_WIDTH
- x
;
675 if (y
+ height
> LCD_REMOTE_HEIGHT
)
676 height
= LCD_REMOTE_HEIGHT
- y
;
678 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
681 dst
= &lcd_remote_framebuffer
[y
>>3][x
];
683 ny
= height
- 1 + shift
+ src_y
;
685 bfunc
= lcd_remote_blockfuncs
[drawmode
];
686 mask
= 0xFFu
<< (shift
+ src_y
);
687 /* not byte-doubled here because shift+src_y can be > 7 */
688 mask_bottom
= 0xFFu
>> (~ny
& 7);
689 mask_bottom
|= mask_bottom
<< 8;
696 for (; ny
>= 8; ny
-= 8)
698 const unsigned char *src_row
= src
;
699 fb_remote_data
*dst_row
= dst
;
701 dst_end
= dst_row
+ width
;
705 bfunc(dst_row
++, mask
, data
| (data
<< 8));
707 while (dst_row
< dst_end
);
710 dst
+= LCD_REMOTE_WIDTH
;
715 dst_end
= dst
+ width
;
719 bfunc(dst
++, mask
, data
| (data
<< 8));
721 while (dst
< dst_end
);
727 dst_end
= dst
+ width
;
730 const unsigned char *src_col
= src
++;
731 fb_remote_data
*dst_col
= dst
++;
732 unsigned mask_col
= mask
& 0xFFu
;
734 mask_col
|= mask_col
<< 8;
737 for (y
= ny
; y
>= 8; y
-= 8)
739 data
|= *src_col
<< shift
;
743 ddata
= data
& 0xFFu
;
744 bfunc(dst_col
, mask_col
, ddata
| (ddata
<< 8));
749 mask_col
= (mask
>> 8) & 0xFFu
;
750 mask_col
|= mask_col
<< 8;
754 dst_col
+= LCD_REMOTE_WIDTH
;
757 data
|= *src_col
<< shift
;
758 mask_col
&= mask_bottom
;
759 ddata
= data
& 0xFFu
;
760 bfunc(dst_col
, mask_col
, ddata
| (ddata
<< 8));
762 while (dst
< dst_end
);
766 /* Draw a full monochrome bitmap */
767 void lcd_remote_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
,
770 lcd_remote_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
773 /* About Rockbox' internal native bitmap format:
775 * A bitmap contains one bit in each byte of a pair of bytes for every pixel.
776 * 00 = white, 01 = light grey, 10 = dark grey, 11 = black. Bits within a byte
777 * are arranged vertically, LSB at top.
778 * The pairs of bytes are stored as shorts, in row-major order, with word 0
779 * being top left, word 1 2nd from left etc. The first row of words defines
780 * pixel rows 0..7, the second row defines pixel row 8..15 etc.
782 * This is the same as the internal lcd hw format. */
784 /* Draw a partial native bitmap */
785 void lcd_remote_bitmap_part(const fb_remote_data
*src
, int src_x
, int src_y
,
786 int stride
, int x
, int y
, int width
, int height
)
788 void lcd_remote_bitmap_part(const fb_remote_data
*src
, int src_x
, int src_y
,
789 int stride
, int x
, int y
, int width
, int height
)
792 fb_remote_data
*dst
, *dst_end
;
793 unsigned mask
, mask_bottom
;
795 /* nothing to draw? */
796 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_REMOTE_WIDTH
)
797 || (y
>= LCD_REMOTE_HEIGHT
) || (x
+ width
<= 0) || (y
+ height
<= 0))
813 if (x
+ width
> LCD_REMOTE_WIDTH
)
814 width
= LCD_REMOTE_WIDTH
- x
;
815 if (y
+ height
> LCD_REMOTE_HEIGHT
)
816 height
= LCD_REMOTE_HEIGHT
- y
;
818 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
821 dst
= &lcd_remote_framebuffer
[y
>>3][x
];
823 ny
= height
- 1 + shift
+ src_y
;
825 mask
= 0xFFu
<< (shift
+ src_y
);
826 /* not byte-doubled here because shift+src_y can be > 7 */
827 mask_bottom
= 0xFFu
>> (~ny
& 7);
828 mask_bottom
|= mask_bottom
<< 8;
835 for (; ny
>= 8; ny
-= 8)
838 memcpy(dst
, src
, width
* sizeof(fb_remote_data
));
841 const fb_remote_data
*src_row
= src
;
842 fb_remote_data
*dst_row
= dst
;
844 dst_end
= dst_row
+ width
;
846 setblock(dst_row
++, mask
, *src_row
++);
847 while (dst_row
< dst_end
);
850 dst
+= LCD_REMOTE_WIDTH
;
856 memcpy(dst
, src
, width
* sizeof(fb_remote_data
));
859 dst_end
= dst
+ width
;
861 setblock(dst
++, mask
, *src
++);
862 while (dst
< dst_end
);
867 unsigned datamask
= (0xFFu
<< shift
) & 0xFFu
;
869 datamask
|= datamask
<< 8;
871 dst_end
= dst
+ width
;
874 const fb_remote_data
*src_col
= src
++;
875 fb_remote_data
*dst_col
= dst
++;
876 unsigned mask_col
= mask
& 0xFFu
;
877 unsigned data
, olddata
= 0;
879 mask_col
|= mask_col
<< 8;
881 for (y
= ny
; y
>= 8; y
-= 8)
883 data
= *src_col
<< shift
;
887 setblock(dst_col
, mask_col
,
888 olddata
^((olddata
^ data
) & datamask
));
893 mask_col
= (mask
<< 8) & 0xFFu
;
894 mask_col
|= mask_col
<< 8;
897 dst_col
+= LCD_REMOTE_WIDTH
;
900 data
= *src_col
<< shift
;
901 setblock(dst_col
, mask_col
& mask_bottom
,
902 olddata
^((olddata
^ data
) & datamask
));
904 while (dst
< dst_end
);
908 /* Draw a full native bitmap */
909 void lcd_remote_bitmap(const fb_remote_data
*src
, int x
, int y
, int width
,
912 lcd_remote_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
915 /* put a string at a given pixel position, skipping first ofs pixel columns */
916 void lcd_remote_putsxyofs(int x
, int y
, int ofs
, const unsigned char *str
)
920 struct font
* pf
= font_get(curfont
);
922 ucs
= bidi_l2v(str
, 1);
924 while ((ch
= *ucs
++) != 0 && x
< LCD_REMOTE_WIDTH
)
927 const unsigned char *bits
;
929 /* get proportional width and glyph bits */
930 width
= font_get_width(pf
, ch
);
938 bits
= font_get_bits(pf
, ch
);
940 lcd_remote_mono_bitmap_part(bits
, ofs
, 0, width
, x
, y
, width
- ofs
,
948 /* put a string at a given pixel position */
949 void lcd_remote_putsxy(int x
, int y
, const unsigned char *str
)
951 lcd_remote_putsxyofs(x
, y
, 0, str
);
954 /*** line oriented text output ***/
956 /* put a string at a given char position */
957 void lcd_remote_puts(int x
, int y
, const unsigned char *str
)
959 lcd_remote_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, 0);
962 void lcd_remote_puts_style(int x
, int y
, const unsigned char *str
, int style
)
964 lcd_remote_puts_style_offset(x
, y
, str
, style
, 0);
967 void lcd_remote_puts_offset(int x
, int y
, const unsigned char *str
, int offset
)
969 lcd_remote_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, offset
);
972 /* put a string at a given char position, style, and pixel position,
973 * skipping first offset pixel columns */
974 void lcd_remote_puts_style_offset(int x
, int y
, const unsigned char *str
,
975 int style
, int offset
)
977 int xpos
,ypos
,w
,h
,xrect
;
978 int lastmode
= drawmode
;
980 /* make sure scrolling is turned off on the line we are updating */
981 lcd_remote_scroll_info
.lines
&= ~(1 << y
);
986 lcd_remote_getstringsize(str
, &w
, &h
);
987 xpos
= xmargin
+ x
*w
/ utf8length((char *)str
);
988 ypos
= ymargin
+ y
*h
;
989 drawmode
= (style
& STYLE_INVERT
) ?
990 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
991 lcd_remote_putsxyofs(xpos
, ypos
, offset
, str
);
992 drawmode
^= DRMODE_INVERSEVID
;
993 xrect
= xpos
+ MAX(w
- offset
, 0);
994 lcd_remote_fillrect(xrect
, ypos
, LCD_REMOTE_WIDTH
- xrect
, h
);
999 void lcd_remote_puts_scroll(int x
, int y
, const unsigned char *string
)
1001 lcd_remote_puts_scroll_style(x
, y
, string
, STYLE_DEFAULT
);
1004 void lcd_remote_puts_scroll_style(int x
, int y
, const unsigned char *string
, int style
)
1006 lcd_remote_puts_scroll_style_offset(x
, y
, string
, style
, 0);
1009 void lcd_remote_puts_scroll_offset(int x
, int y
, const unsigned char *string
, int offset
)
1011 lcd_remote_puts_scroll_style_offset(x
, y
, string
, STYLE_DEFAULT
, offset
);
1014 void lcd_remote_puts_scroll_style_offset(int x
, int y
, const unsigned char *string
,
1015 int style
, int offset
)
1017 struct scrollinfo
* s
;
1020 if(y
>=LCD_REMOTE_SCROLLABLE_LINES
) return;
1022 s
= &lcd_remote_scroll_info
.scroll
[y
];
1024 s
->start_tick
= current_tick
+ lcd_remote_scroll_info
.delay
;
1026 if (style
& STYLE_INVERT
) {
1028 lcd_remote_puts_style_offset(x
,y
,string
,STYLE_INVERT
,offset
);
1031 lcd_remote_puts_offset(x
,y
,string
,offset
);
1033 lcd_remote_getstringsize(string
, &w
, &h
);
1035 if (LCD_REMOTE_WIDTH
- x
* 8 - xmargin
< w
) {
1036 /* prepare scroll line */
1039 memset(s
->line
, 0, sizeof s
->line
);
1040 strcpy(s
->line
, (char *)string
);
1043 s
->width
= lcd_remote_getstringsize((unsigned char *)s
->line
, &w
, &h
);
1045 /* scroll bidirectional or forward only depending on the string
1047 if ( lcd_remote_scroll_info
.bidir_limit
) {
1048 s
->bidir
= s
->width
< (LCD_REMOTE_WIDTH
- xmargin
) *
1049 (100 + lcd_remote_scroll_info
.bidir_limit
) / 100;
1054 if (!s
->bidir
) { /* add spaces if scrolling in the round */
1055 strcat(s
->line
, " ");
1056 /* get new width incl. spaces */
1057 s
->width
= lcd_remote_getstringsize((unsigned char *)s
->line
, &w
, &h
);
1060 end
= strchr(s
->line
, '\0');
1061 strncpy(end
, (char *)string
, LCD_REMOTE_WIDTH
/2);
1063 s
->len
= utf8length((char *)string
);
1065 s
->startx
= xmargin
+ x
* s
->width
/ s
->len
;;
1066 s
->backward
= false;
1067 lcd_remote_scroll_info
.lines
|= (1<<y
);
1070 /* force a bit switch-off since it doesn't scroll */
1071 lcd_remote_scroll_info
.lines
&= ~(1<<y
);
1074 void lcd_remote_scroll_fn(void)
1077 struct scrollinfo
* s
;
1082 for ( index
= 0; index
< LCD_REMOTE_SCROLLABLE_LINES
; index
++ ) {
1083 /* really scroll? */
1084 if ((lcd_remote_scroll_info
.lines
& (1 << index
)) == 0)
1087 s
= &lcd_remote_scroll_info
.scroll
[index
];
1090 if (TIME_BEFORE(current_tick
, s
->start_tick
))
1094 s
->offset
-= lcd_remote_scroll_info
.step
;
1096 s
->offset
+= lcd_remote_scroll_info
.step
;
1098 pf
= font_get(curfont
);
1100 ypos
= ymargin
+ index
* pf
->height
;
1102 if (s
->bidir
) { /* scroll bidirectional */
1103 if (s
->offset
<= 0) {
1104 /* at beginning of line */
1106 s
->backward
= false;
1107 s
->start_tick
= current_tick
+ lcd_remote_scroll_info
.delay
*2;
1109 if (s
->offset
>= s
->width
- (LCD_REMOTE_WIDTH
- xpos
)) {
1110 /* at end of line */
1111 s
->offset
= s
->width
- (LCD_REMOTE_WIDTH
- xpos
);
1113 s
->start_tick
= current_tick
+ lcd_remote_scroll_info
.delay
*2;
1117 /* scroll forward the whole time */
1118 if (s
->offset
>= s
->width
)
1119 s
->offset
%= s
->width
;
1122 lastmode
= drawmode
;
1123 drawmode
= s
->invert
?
1124 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1125 lcd_remote_putsxyofs(xpos
, ypos
, s
->offset
, s
->line
);
1126 drawmode
= lastmode
;
1127 lcd_remote_update_rect(xpos
, ypos
, LCD_REMOTE_WIDTH
- xpos
, pf
->height
);
1132 void lcd_remote_init(void)
1135 /* Call device specific init */
1136 lcd_remote_init_device();