1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 Jens Arnold
12 * Rockbox driver for 2bit vertically interleaved LCDs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
36 #include "rbunicode.h"
38 #include "scroll_engine.h"
40 #ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */
41 #define LCDFN(fn) lcd_ ## fn
42 #define FBFN(fn) fb_ ## fn
43 #define LCDM(ma) LCD_ ## ma
44 #define LCDNAME "lcd_"
50 FBFN(data
) LCDFN(framebuffer
)[LCDM(FBHEIGHT
)][LCDM(FBWIDTH
)] IBSS_ATTR
;
52 static const FBFN(data
) patterns
[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000};
54 static FBFN(data
) *backdrop
= NULL
;
55 static long backdrop_offset IDATA_ATTR
= 0;
57 static struct viewport default_vp
=
62 .height
= LCDM(HEIGHT
),
63 .font
= FONT_SYSFIXED
,
64 .drawmode
= DRMODE_SOLID
,
65 .fg_pattern
= LCDM(DEFAULT_FG
),
66 .bg_pattern
= LCDM(DEFAULT_BG
)
69 static struct viewport
*current_vp IBSS_ATTR
;
71 static unsigned fg_pattern IBSS_ATTR
;
72 static unsigned bg_pattern IBSS_ATTR
;
76 void LCDFN(set_viewport
)(struct viewport
* vp
)
79 current_vp
= &default_vp
;
83 fg_pattern
= patterns
[current_vp
->fg_pattern
& 3];
84 bg_pattern
= patterns
[current_vp
->bg_pattern
& 3];
87 void LCDFN(update_viewport
)(void)
89 LCDFN(update_rect
)(current_vp
->x
, current_vp
->y
,
90 current_vp
->width
, current_vp
->height
);
93 void LCDFN(update_viewport_rect
)(int x
, int y
, int width
, int height
)
95 LCDFN(update_rect
)(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
99 void LCDFN(init
)(void)
101 LCDFN(set_viewport
)(NULL
);
102 LCDFN(clear_display
)();
104 LCDFN(init_device
)();
111 /*** parameter handling ***/
113 #if !defined(MAIN_LCD) && defined(HAVE_LCD_COLOR)
114 /* When compiling for remote LCD and the main LCD is colour. */
115 unsigned lcd_remote_color_to_native(unsigned color
)
117 unsigned r
= (color
& 0xf800) >> 10;
118 unsigned g
= (color
& 0x07e0) >> 5;
119 unsigned b
= (color
& 0x001f) << 2;
122 * |Y'| = |0.299000 0.587000 0.114000| |G|
125 return (5*r
+ 9*g
+ b
) >> 8;
129 void LCDFN(set_drawmode
)(int mode
)
131 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
134 int LCDFN(get_drawmode
)(void)
136 return current_vp
->drawmode
;
139 void LCDFN(set_foreground
)(unsigned brightness
)
141 current_vp
->fg_pattern
= brightness
;
142 fg_pattern
= patterns
[brightness
& 3];
145 unsigned LCDFN(get_foreground
)(void)
147 return current_vp
->fg_pattern
;
150 void LCDFN(set_background
)(unsigned brightness
)
152 current_vp
->bg_pattern
= brightness
;
153 bg_pattern
= patterns
[brightness
& 3];
156 unsigned LCDFN(get_background
)(void)
158 return current_vp
->bg_pattern
;
161 void LCDFN(set_drawinfo
)(int mode
, unsigned fg_brightness
,
162 unsigned bg_brightness
)
164 LCDFN(set_drawmode
)(mode
);
165 LCDFN(set_foreground
)(fg_brightness
);
166 LCDFN(set_background
)(bg_brightness
);
169 int LCDFN(getwidth
)(void)
171 return current_vp
->width
;
174 int LCDFN(getheight
)(void)
176 return current_vp
->height
;
178 void LCDFN(setfont
)(int newfont
)
180 current_vp
->font
= newfont
;
183 int LCDFN(getfont
)(void)
185 return current_vp
->font
;
188 int LCDFN(getstringsize
)(const unsigned char *str
, int *w
, int *h
)
190 return font_getstringsize(str
, w
, h
, current_vp
->font
);
193 /*** low-level drawing functions ***/
195 static void setpixel(int x
, int y
)
197 unsigned mask
= 0x0101 << (y
& 7);
198 FBFN(data
) *address
= &LCDFN(framebuffer
)[y
>>3][x
];
199 unsigned data
= *address
;
201 *address
= data
^ ((data
^ fg_pattern
) & mask
);
204 static void clearpixel(int x
, int y
)
206 unsigned mask
= 0x0101 << (y
& 7);
207 FBFN(data
) *address
= &LCDFN(framebuffer
)[y
>>3][x
];
208 unsigned data
= *address
;
210 *address
= data
^ ((data
^ bg_pattern
) & mask
);
213 static void clearimgpixel(int x
, int y
)
215 unsigned mask
= 0x0101 << (y
& 7);
216 FBFN(data
) *address
= &LCDFN(framebuffer
)[y
>>3][x
];
217 unsigned data
= *address
;
219 *address
= data
^ ((data
^ *(FBFN(data
) *)((long)address
220 + backdrop_offset
)) & mask
);
223 static void flippixel(int x
, int y
)
225 unsigned mask
= 0x0101 << (y
& 7);
226 FBFN(data
) *address
= &LCDFN(framebuffer
)[y
>>3][x
];
231 static void nopixel(int x
, int y
)
237 LCDFN(pixelfunc_type
)* const LCDFN(pixelfuncs_bgcolor
)[8] = {
238 flippixel
, nopixel
, setpixel
, setpixel
,
239 nopixel
, clearpixel
, nopixel
, clearpixel
242 LCDFN(pixelfunc_type
)* const LCDFN(pixelfuncs_backdrop
)[8] = {
243 flippixel
, nopixel
, setpixel
, setpixel
,
244 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
247 LCDFN(pixelfunc_type
)* const *LCDFN(pixelfuncs
) = LCDFN(pixelfuncs_bgcolor
);
249 /* 'mask' and 'bits' contain 2 bits per pixel */
250 static void ICODE_ATTR
flipblock(FBFN(data
) *address
, unsigned mask
,
253 *address
^= bits
& mask
;
256 static void ICODE_ATTR
bgblock(FBFN(data
) *address
, unsigned mask
,
259 unsigned data
= *address
;
261 *address
= data
^ ((data
^ bg_pattern
) & mask
& ~bits
);
264 static void ICODE_ATTR
bgimgblock(FBFN(data
) *address
, unsigned mask
,
267 unsigned data
= *address
;
269 *address
= data
^ ((data
^ *(FBFN(data
) *)((long)address
270 + backdrop_offset
)) & mask
& ~bits
);
273 static void ICODE_ATTR
fgblock(FBFN(data
) *address
, unsigned mask
,
276 unsigned data
= *address
;
278 *address
= data
^ ((data
^ fg_pattern
) & mask
& bits
);
281 static void ICODE_ATTR
solidblock(FBFN(data
) *address
, unsigned mask
,
284 unsigned data
= *address
;
285 unsigned bgp
= bg_pattern
;
287 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
288 *address
= data
^ ((data
^ bits
) & mask
);
291 static void ICODE_ATTR
solidimgblock(FBFN(data
) *address
, unsigned mask
,
294 unsigned data
= *address
;
295 unsigned bgp
= *(FBFN(data
) *)((long)address
+ backdrop_offset
);
297 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
298 *address
= data
^ ((data
^ bits
) & mask
);
301 static void ICODE_ATTR
flipinvblock(FBFN(data
) *address
, unsigned mask
,
304 *address
^= ~bits
& mask
;
307 static void ICODE_ATTR
bginvblock(FBFN(data
) *address
, unsigned mask
,
310 unsigned data
= *address
;
312 *address
= data
^ ((data
^ bg_pattern
) & mask
& bits
);
315 static void ICODE_ATTR
bgimginvblock(FBFN(data
) *address
, unsigned mask
,
318 unsigned data
= *address
;
320 *address
= data
^ ((data
^ *(FBFN(data
) *)((long)address
321 + backdrop_offset
)) & mask
& bits
);
324 static void ICODE_ATTR
fginvblock(FBFN(data
) *address
, unsigned mask
,
327 unsigned data
= *address
;
329 *address
= data
^ ((data
^ fg_pattern
) & mask
& ~bits
);
332 static void ICODE_ATTR
solidinvblock(FBFN(data
) *address
, unsigned mask
,
335 unsigned data
= *address
;
336 unsigned fgp
= fg_pattern
;
338 bits
= fgp
^ ((fgp
^ bg_pattern
) & bits
);
339 *address
= data
^ ((data
^ bits
) & mask
);
342 static void ICODE_ATTR
solidimginvblock(FBFN(data
) *address
, unsigned mask
,
345 unsigned data
= *address
;
346 unsigned fgp
= fg_pattern
;
348 bits
= fgp
^ ((fgp
^ *(FBFN(data
) *)((long)address
349 + backdrop_offset
)) & bits
);
350 *address
= data
^ ((data
^ bits
) & mask
);
353 LCDFN(blockfunc_type
)* const LCDFN(blockfuncs_bgcolor
)[8] = {
354 flipblock
, bgblock
, fgblock
, solidblock
,
355 flipinvblock
, bginvblock
, fginvblock
, solidinvblock
358 LCDFN(blockfunc_type
)* const LCDFN(blockfuncs_backdrop
)[8] = {
359 flipblock
, bgimgblock
, fgblock
, solidimgblock
,
360 flipinvblock
, bgimginvblock
, fginvblock
, solidimginvblock
363 LCDFN(blockfunc_type
)* const *LCDFN(blockfuncs
) = LCDFN(blockfuncs_bgcolor
);
366 void LCDFN(set_backdrop
)(FBFN(data
) *bd
)
371 backdrop_offset
= (long)bd
- (long)LCDFN(framebuffer
);
372 LCDFN(pixelfuncs
) = LCDFN(pixelfuncs_backdrop
);
373 LCDFN(blockfuncs
) = LCDFN(blockfuncs_backdrop
);
378 LCDFN(pixelfuncs
) = LCDFN(pixelfuncs_bgcolor
);
379 LCDFN(blockfuncs
) = LCDFN(blockfuncs_bgcolor
);
383 FBFN(data
)* LCDFN(get_backdrop
)(void)
388 static inline void setblock(FBFN(data
) *address
, unsigned mask
, unsigned bits
)
390 unsigned data
= *address
;
393 *address
= data
^ (bits
& mask
);
396 /*** drawing functions ***/
398 /* Clear the whole display */
399 void LCDFN(clear_display
)(void)
401 if (default_vp
.drawmode
& DRMODE_INVERSEVID
)
403 memset(LCDFN(framebuffer
), patterns
[default_vp
.fg_pattern
& 3],
404 sizeof LCDFN(framebuffer
));
409 memcpy(LCDFN(framebuffer
), backdrop
, sizeof LCDFN(framebuffer
));
411 memset(LCDFN(framebuffer
), patterns
[default_vp
.bg_pattern
& 3],
412 sizeof LCDFN(framebuffer
));
415 LCDFN(scroll_info
).lines
= 0;
418 /* Clear the current viewport */
419 void LCDFN(clear_viewport
)(void)
423 if (current_vp
== &default_vp
)
425 LCDFN(clear_display
)();
429 lastmode
= current_vp
->drawmode
;
431 /* Invert the INVERSEVID bit and set basic mode to SOLID */
432 current_vp
->drawmode
= (~lastmode
& DRMODE_INVERSEVID
) |
435 LCDFN(fillrect
)(0, 0, current_vp
->width
, current_vp
->height
);
437 current_vp
->drawmode
= lastmode
;
439 LCDFN(scroll_stop
)(current_vp
);
443 /* Set a single pixel */
444 void LCDFN(drawpixel
)(int x
, int y
)
446 if (((unsigned)x
< (unsigned)current_vp
->width
) &&
447 ((unsigned)y
< (unsigned)current_vp
->height
))
448 LCDFN(pixelfuncs
)[current_vp
->drawmode
](current_vp
->x
+x
, current_vp
->y
+y
);
452 void LCDFN(drawline
)(int x1
, int y1
, int x2
, int y2
)
460 LCDFN(pixelfunc_type
) *pfunc
= LCDFN(pixelfuncs
)[current_vp
->drawmode
];
462 deltax
= abs(x2
- x1
);
465 DEBUGF(LCDNAME
"drawline() called for vertical line - optimisation.\n");
466 LCDFN(vline
)(x1
, y1
, y2
);
469 deltay
= abs(y2
- y1
);
472 DEBUGF(LCDNAME
"drawline() called for horizontal line - optimisation.\n");
473 LCDFN(hline
)(x1
, x2
, y1
);
479 if (deltax
>= deltay
)
482 d
= 2 * deltay
- deltax
;
484 dinc2
= (deltay
- deltax
) * 2;
491 d
= 2 * deltax
- deltay
;
493 dinc2
= (deltax
- deltay
) * 2;
497 numpixels
++; /* include endpoints */
514 for (i
= 0; i
< numpixels
; i
++)
516 if (((unsigned)x
< (unsigned)current_vp
->width
) &&
517 ((unsigned)y
< (unsigned)current_vp
->height
))
518 pfunc(current_vp
->x
+ x
, current_vp
->y
+ y
);
535 /* Draw a horizontal line (optimised) */
536 void LCDFN(hline
)(int x1
, int x2
, int y
)
540 FBFN(data
) *dst
, *dst_end
;
542 LCDFN(blockfunc_type
) *bfunc
;
552 /* nothing to draw? */
553 if (((unsigned)y
>= (unsigned)current_vp
->height
) || (x1
>= current_vp
->width
)
560 if (x2
>= current_vp
->width
)
561 x2
= current_vp
->width
-1;
565 /* adjust x1 and y to viewport */
569 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
570 dst
= &LCDFN(framebuffer
)[y
>>3][x1
];
571 mask
= 0x0101 << (y
& 7);
573 dst_end
= dst
+ width
;
575 bfunc(dst
++, mask
, 0xFFFFu
);
576 while (dst
< dst_end
);
579 /* Draw a vertical line (optimised) */
580 void LCDFN(vline
)(int x
, int y1
, int y2
)
584 unsigned mask
, mask_bottom
;
585 LCDFN(blockfunc_type
) *bfunc
;
595 /* nothing to draw? */
596 if (((unsigned)x
>= (unsigned)current_vp
->width
) || (y1
>= current_vp
->height
)
603 if (y2
>= current_vp
->height
)
604 y2
= current_vp
->height
-1;
606 /* adjust for viewport */
611 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
612 dst
= &LCDFN(framebuffer
)[y1
>>3][x
];
614 mask
= (0xFFu
<< (y1
& 7)) & 0xFFu
;
616 mask_bottom
= 0xFFu
>> (~ny
& 7);
617 mask_bottom
|= mask_bottom
<< 8;
619 for (; ny
>= 8; ny
-= 8)
621 bfunc(dst
, mask
, 0xFFFFu
);
626 bfunc(dst
, mask
, 0xFFFFu
);
629 /* Draw a rectangular box */
630 void LCDFN(drawrect
)(int x
, int y
, int width
, int height
)
632 if ((width
<= 0) || (height
<= 0))
635 int x2
= x
+ width
- 1;
636 int y2
= y
+ height
- 1;
638 LCDFN(vline
)(x
, y
, y2
);
639 LCDFN(vline
)(x2
, y
, y2
);
640 LCDFN(hline
)(x
, x2
, y
);
641 LCDFN(hline
)(x
, x2
, y2
);
644 /* Fill a rectangular area */
645 void LCDFN(fillrect
)(int x
, int y
, int width
, int height
)
648 FBFN(data
) *dst
, *dst_end
;
649 unsigned mask
, mask_bottom
;
651 LCDFN(blockfunc_type
) *bfunc
;
652 bool fillopt
= false;
654 /* nothing to draw? */
655 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
656 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
670 if (x
+ width
> current_vp
->width
)
671 width
= current_vp
->width
- x
;
672 if (y
+ height
> current_vp
->height
)
673 height
= current_vp
->height
- y
;
675 /* adjust for viewport */
679 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
681 if ((current_vp
->drawmode
& DRMODE_BG
) && !backdrop
)
689 if (current_vp
->drawmode
& DRMODE_FG
)
695 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
696 dst
= &LCDFN(framebuffer
)[y
>>3][x
];
697 ny
= height
- 1 + (y
& 7);
698 mask
= (0xFFu
<< (y
& 7)) & 0xFFu
;
700 mask_bottom
= 0xFFu
>> (~ny
& 7);
701 mask_bottom
|= mask_bottom
<< 8;
703 for (; ny
>= 8; ny
-= 8)
705 if (fillopt
&& (mask
== 0xFFFFu
))
706 memset16(dst
, bits
, width
);
709 FBFN(data
) *dst_row
= dst
;
711 dst_end
= dst_row
+ width
;
713 bfunc(dst_row
++, mask
, 0xFFFFu
);
714 while (dst_row
< dst_end
);
722 if (fillopt
&& (mask
== 0xFFFFu
))
723 memset16(dst
, bits
, width
);
726 dst_end
= dst
+ width
;
728 bfunc(dst
++, mask
, 0xFFFFu
);
729 while (dst
< dst_end
);
733 /* About Rockbox' internal monochrome bitmap format:
735 * A bitmap contains one bit for every pixel that defines if that pixel is
736 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
738 * The bytes are stored in row-major order, with byte 0 being top left,
739 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
740 * 0..7, the second row defines pixel row 8..15 etc.
742 * This is similar to the internal lcd hw format. */
744 /* Draw a partial monochrome bitmap */
745 void ICODE_ATTR
LCDFN(mono_bitmap_part
)(const unsigned char *src
, int src_x
,
746 int src_y
, int stride
, int x
, int y
,
747 int width
, int height
)
750 FBFN(data
) *dst
, *dst_end
;
751 unsigned data
, mask
, mask_bottom
;
752 LCDFN(blockfunc_type
) *bfunc
;
754 /* nothing to draw? */
755 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
756 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
772 if (x
+ width
> current_vp
->width
)
773 width
= current_vp
->width
- x
;
774 if (y
+ height
> current_vp
->height
)
775 height
= current_vp
->height
- y
;
777 /* adjust for viewport */
781 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
784 dst
= &LCDFN(framebuffer
)[y
>>3][x
];
786 ny
= height
- 1 + shift
+ src_y
;
788 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
789 mask
= 0xFFu
<< (shift
+ src_y
);
790 /* not byte-doubled here because shift+src_y can be > 7 */
791 mask_bottom
= 0xFFu
>> (~ny
& 7);
792 mask_bottom
|= mask_bottom
<< 8;
799 for (; ny
>= 8; ny
-= 8)
801 const unsigned char *src_row
= src
;
802 FBFN(data
) *dst_row
= dst
;
804 dst_end
= dst_row
+ width
;
808 bfunc(dst_row
++, mask
, data
| (data
<< 8));
810 while (dst_row
< dst_end
);
818 dst_end
= dst
+ width
;
822 bfunc(dst
++, mask
, data
| (data
<< 8));
824 while (dst
< dst_end
);
830 dst_end
= dst
+ width
;
833 const unsigned char *src_col
= src
++;
834 FBFN(data
) *dst_col
= dst
++;
835 unsigned mask_col
= mask
& 0xFFu
;
837 mask_col
|= mask_col
<< 8;
840 for (y
= ny
; y
>= 8; y
-= 8)
842 data
|= *src_col
<< shift
;
846 ddata
= data
& 0xFFu
;
847 bfunc(dst_col
, mask_col
, ddata
| (ddata
<< 8));
852 mask_col
= (mask
>> 8) & 0xFFu
;
853 mask_col
|= mask_col
<< 8;
857 dst_col
+= LCDM(WIDTH
);
860 data
|= *src_col
<< shift
;
861 mask_col
&= mask_bottom
;
862 ddata
= data
& 0xFFu
;
863 bfunc(dst_col
, mask_col
, ddata
| (ddata
<< 8));
865 while (dst
< dst_end
);
869 /* Draw a full monochrome bitmap */
870 void LCDFN(mono_bitmap
)(const unsigned char *src
, int x
, int y
, int width
,
873 LCDFN(mono_bitmap_part
)(src
, 0, 0, width
, x
, y
, width
, height
);
876 /* About Rockbox' internal native bitmap format:
878 * A bitmap contains one bit in each byte of a pair of bytes for every pixel.
879 * 00 = white, 01 = light grey, 10 = dark grey, 11 = black. Bits within a byte
880 * are arranged vertically, LSB at top.
881 * The pairs of bytes are stored as shorts, in row-major order, with word 0
882 * being top left, word 1 2nd from left etc. The first row of words defines
883 * pixel rows 0..7, the second row defines pixel row 8..15 etc.
885 * This is the same as the internal lcd hw format. */
887 /* Draw a partial native bitmap */
888 void ICODE_ATTR
LCDFN(bitmap_part
)(const FBFN(data
) *src
, int src_x
,
889 int src_y
, int stride
, int x
, int y
,
890 int width
, int height
)
893 FBFN(data
) *dst
, *dst_end
;
894 unsigned mask
, mask_bottom
;
896 /* nothing to draw? */
897 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
898 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
914 if (x
+ width
> current_vp
->width
)
915 width
= current_vp
->width
- x
;
916 if (y
+ height
> current_vp
->height
)
917 height
= current_vp
->height
- y
;
919 /* adjust for viewport */
923 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
926 dst
= &LCDFN(framebuffer
)[y
>>3][x
];
928 ny
= height
- 1 + shift
+ src_y
;
930 mask
= 0xFFu
<< (shift
+ src_y
);
931 /* not byte-doubled here because shift+src_y can be > 7 */
932 mask_bottom
= 0xFFu
>> (~ny
& 7);
933 mask_bottom
|= mask_bottom
<< 8;
940 for (; ny
>= 8; ny
-= 8)
943 memcpy(dst
, src
, width
* sizeof(FBFN(data
)));
946 const FBFN(data
) *src_row
= src
;
947 FBFN(data
) *dst_row
= dst
;
949 dst_end
= dst_row
+ width
;
951 setblock(dst_row
++, mask
, *src_row
++);
952 while (dst_row
< dst_end
);
961 memcpy(dst
, src
, width
* sizeof(FBFN(data
)));
964 dst_end
= dst
+ width
;
966 setblock(dst
++, mask
, *src
++);
967 while (dst
< dst_end
);
972 unsigned datamask
= (0xFFu
<< shift
) & 0xFFu
;
974 datamask
|= datamask
<< 8;
976 dst_end
= dst
+ width
;
979 const FBFN(data
) *src_col
= src
++;
980 FBFN(data
) *dst_col
= dst
++;
981 unsigned mask_col
= mask
& 0xFFu
;
982 unsigned data
, olddata
= 0;
984 mask_col
|= mask_col
<< 8;
986 for (y
= ny
; y
>= 8; y
-= 8)
988 data
= *src_col
<< shift
;
992 setblock(dst_col
, mask_col
,
993 olddata
^((olddata
^ data
) & datamask
));
998 mask_col
= (mask
>> 8) & 0xFFu
;
999 mask_col
|= mask_col
<< 8;
1002 dst_col
+= LCDM(WIDTH
);
1003 olddata
= data
>> 8;
1005 data
= *src_col
<< shift
;
1006 setblock(dst_col
, mask_col
& mask_bottom
,
1007 olddata
^((olddata
^ data
) & datamask
));
1009 while (dst
< dst_end
);
1013 /* Draw a full native bitmap */
1014 void LCDFN(bitmap
)(const FBFN(data
) *src
, int x
, int y
, int width
, int height
)
1016 LCDFN(bitmap_part
)(src
, 0, 0, width
, x
, y
, width
, height
);
1019 /* put a string at a given pixel position, skipping first ofs pixel columns */
1020 static void LCDFN(putsxyofs
)(int x
, int y
, int ofs
, const unsigned char *str
)
1023 unsigned short *ucs
;
1024 struct font
* pf
= font_get(current_vp
->font
);
1026 ucs
= bidi_l2v(str
, 1);
1028 while ((ch
= *ucs
++) != 0 && x
< current_vp
->width
)
1031 const unsigned char *bits
;
1033 /* get proportional width and glyph bits */
1034 width
= font_get_width(pf
, ch
);
1042 bits
= font_get_bits(pf
, ch
);
1044 LCDFN(mono_bitmap_part
)(bits
, ofs
, 0, width
, x
, y
, width
- ofs
,
1052 /* put a string at a given pixel position */
1053 void LCDFN(putsxy
)(int x
, int y
, const unsigned char *str
)
1055 LCDFN(putsxyofs
)(x
, y
, 0, str
);
1058 /*** line oriented text output ***/
1060 /* put a string at a given char position */
1061 void LCDFN(puts
)(int x
, int y
, const unsigned char *str
)
1063 LCDFN(puts_style_offset
)(x
, y
, str
, STYLE_DEFAULT
, 0);
1066 void LCDFN(puts_style
)(int x
, int y
, const unsigned char *str
, int style
)
1068 LCDFN(puts_style_offset
)(x
, y
, str
, style
, 0);
1071 void LCDFN(puts_offset
)(int x
, int y
, const unsigned char *str
, int offset
)
1073 LCDFN(puts_style_offset
)(x
, y
, str
, STYLE_DEFAULT
, offset
);
1076 /* put a string at a given char position, style, and pixel position,
1077 * skipping first offset pixel columns */
1078 void LCDFN(puts_style_offset
)(int x
, int y
, const unsigned char *str
,
1079 int style
, int offset
)
1081 int xpos
,ypos
,w
,h
,xrect
;
1082 int lastmode
= current_vp
->drawmode
;
1084 /* make sure scrolling is turned off on the line we are updating */
1085 LCDFN(scroll_stop_line
)(current_vp
, y
);
1090 LCDFN(getstringsize
)(str
, &w
, &h
);
1091 xpos
= x
*w
/ utf8length((char *)str
);
1093 current_vp
->drawmode
= (style
& STYLE_INVERT
) ?
1094 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1095 LCDFN(putsxyofs
)(xpos
, ypos
, offset
, str
);
1096 current_vp
->drawmode
^= DRMODE_INVERSEVID
;
1097 xrect
= xpos
+ MAX(w
- offset
, 0);
1098 LCDFN(fillrect
)(xrect
, ypos
, current_vp
->width
- xrect
, h
);
1099 current_vp
->drawmode
= lastmode
;
1103 void LCDFN(puts_scroll
)(int x
, int y
, const unsigned char *string
)
1105 LCDFN(puts_scroll_style
)(x
, y
, string
, STYLE_DEFAULT
);
1108 void LCDFN(puts_scroll_style
)(int x
, int y
, const unsigned char *string
, int style
)
1110 LCDFN(puts_scroll_style_offset
)(x
, y
, string
, style
, 0);
1113 void LCDFN(puts_scroll_offset
)(int x
, int y
, const unsigned char *string
, int offset
)
1115 LCDFN(puts_scroll_style_offset
)(x
, y
, string
, STYLE_DEFAULT
, offset
);
1118 void LCDFN(puts_scroll_style_offset
)(int x
, int y
, const unsigned char *string
,
1119 int style
, int offset
)
1121 struct scrollinfo
* s
;
1124 if ((unsigned)y
>= (unsigned)current_vp
->height
)
1127 /* remove any previously scrolling line at the same location */
1128 LCDFN(scroll_stop_line
)(current_vp
, y
);
1130 if (LCDFN(scroll_info
).lines
>= LCDM(SCROLLABLE_LINES
)) return;
1132 s
= &LCDFN(scroll_info
).scroll
[LCDFN(scroll_info
).lines
];
1134 s
->start_tick
= current_tick
+ LCDFN(scroll_info
).delay
;
1136 if (style
& STYLE_INVERT
) {
1137 LCDFN(puts_style_offset
)(x
,y
,string
,STYLE_INVERT
,offset
);
1140 LCDFN(puts_offset
)(x
,y
,string
,offset
);
1142 LCDFN(getstringsize
)(string
, &w
, &h
);
1144 if (current_vp
->width
- x
* 8 < w
) {
1145 /* prepare scroll line */
1148 memset(s
->line
, 0, sizeof s
->line
);
1149 strcpy(s
->line
, string
);
1152 s
->width
= LCDFN(getstringsize
)(s
->line
, &w
, &h
);
1154 /* scroll bidirectional or forward only depending on the string
1156 if ( LCDFN(scroll_info
).bidir_limit
) {
1157 s
->bidir
= s
->width
< (current_vp
->width
) *
1158 (100 + LCDFN(scroll_info
).bidir_limit
) / 100;
1163 if (!s
->bidir
) { /* add spaces if scrolling in the round */
1164 strcat(s
->line
, " ");
1165 /* get new width incl. spaces */
1166 s
->width
= LCDFN(getstringsize
)(s
->line
, &w
, &h
);
1169 end
= strchr(s
->line
, '\0');
1170 strncpy(end
, (char *)string
, current_vp
->width
/2);
1174 s
->len
= utf8length((char *)string
);
1176 s
->startx
= x
* s
->width
/ s
->len
;
1177 s
->backward
= false;
1179 LCDFN(scroll_info
).lines
++;
1183 void LCDFN(scroll_fn
)(void)
1186 struct scrollinfo
* s
;
1190 struct viewport
* old_vp
= current_vp
;
1192 for ( index
= 0; index
< LCDFN(scroll_info
).lines
; index
++ ) {
1193 s
= &LCDFN(scroll_info
).scroll
[index
];
1196 if (TIME_BEFORE(current_tick
, s
->start_tick
))
1199 LCDFN(set_viewport
)(s
->vp
);
1202 s
->offset
-= LCDFN(scroll_info
).step
;
1204 s
->offset
+= LCDFN(scroll_info
).step
;
1206 pf
= font_get(current_vp
->font
);
1208 ypos
= s
->y
* pf
->height
;
1210 if (s
->bidir
) { /* scroll bidirectional */
1211 if (s
->offset
<= 0) {
1212 /* at beginning of line */
1214 s
->backward
= false;
1215 s
->start_tick
= current_tick
+ LCDFN(scroll_info
).delay
* 2;
1217 if (s
->offset
>= s
->width
- (current_vp
->width
- xpos
)) {
1218 /* at end of line */
1219 s
->offset
= s
->width
- (current_vp
->width
- xpos
);
1221 s
->start_tick
= current_tick
+ LCDFN(scroll_info
).delay
* 2;
1225 /* scroll forward the whole time */
1226 if (s
->offset
>= s
->width
)
1227 s
->offset
%= s
->width
;
1230 lastmode
= current_vp
->drawmode
;
1231 current_vp
->drawmode
= (s
->style
&STYLE_INVERT
) ?
1232 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1233 LCDFN(putsxyofs
)(xpos
, ypos
, s
->offset
, s
->line
);
1234 current_vp
->drawmode
= lastmode
;
1235 LCDFN(update_viewport_rect
)(xpos
, ypos
,
1236 current_vp
->width
- xpos
, pf
->height
);
1239 LCDFN(set_viewport
)(old_vp
);