1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 Jens Arnold
12 * Rockbox driver for 2bit vertically interleaved 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 ****************************************************************************/
34 #include "rbunicode.h"
36 #include "scroll_engine.h"
38 #ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */
39 #define LCDFN(fn) lcd_ ## fn
40 #define FBFN(fn) fb_ ## fn
41 #define LCDM(ma) LCD_ ## ma
47 FBFN(data
) LCDFN(framebuffer
)[LCDM(FBHEIGHT
)][LCDM(FBWIDTH
)] IBSS_ATTR
;
49 static const FBFN(data
) patterns
[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000};
51 static FBFN(data
) *backdrop
= NULL
;
52 static long backdrop_offset IDATA_ATTR
= 0;
54 static struct viewport default_vp
=
59 .height
= LCDM(HEIGHT
),
60 .font
= FONT_SYSFIXED
,
61 .drawmode
= DRMODE_SOLID
,
64 .fg_pattern
= LCDM(DEFAULT_FG
),
65 .bg_pattern
= LCDM(DEFAULT_BG
)
68 static struct viewport
*current_vp IBSS_ATTR
;
70 static unsigned fg_pattern IBSS_ATTR
;
71 static unsigned bg_pattern IBSS_ATTR
;
75 void LCDFN(set_viewport
)(struct viewport
* vp
)
78 current_vp
= &default_vp
;
82 fg_pattern
= patterns
[current_vp
->fg_pattern
& 3];
83 bg_pattern
= patterns
[current_vp
->bg_pattern
& 3];
86 void LCDFN(update_viewport
)(void)
88 LCDFN(update_rect
)(current_vp
->x
, current_vp
->y
,
89 current_vp
->width
, current_vp
->height
);
92 void LCDFN(update_viewport_rect
)(int x
, int y
, int width
, int height
)
94 LCDFN(update_rect
)(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
98 void LCDFN(init
)(void)
100 LCDFN(set_viewport
)(NULL
);
101 LCDFN(clear_display
)();
103 LCDFN(init_device
)();
110 /*** parameter handling ***/
112 #if !defined(MAIN_LCD) && defined(HAVE_LCD_COLOR)
113 /* When compiling for remote LCD and the main LCD is colour. */
114 unsigned lcd_remote_color_to_native(unsigned color
)
116 unsigned r
= (color
& 0xf800) >> 10;
117 unsigned g
= (color
& 0x07e0) >> 5;
118 unsigned b
= (color
& 0x001f) << 2;
121 * |Y'| = |0.299000 0.587000 0.114000| |G|
124 return (5*r
+ 9*g
+ b
) >> 8;
128 void LCDFN(set_drawmode
)(int mode
)
130 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
133 int LCDFN(get_drawmode
)(void)
135 return current_vp
->drawmode
;
138 void LCDFN(set_foreground
)(unsigned brightness
)
140 current_vp
->fg_pattern
= brightness
;
141 fg_pattern
= patterns
[brightness
& 3];
144 unsigned LCDFN(get_foreground
)(void)
146 return current_vp
->fg_pattern
;
149 void LCDFN(set_background
)(unsigned brightness
)
151 current_vp
->bg_pattern
= brightness
;
152 bg_pattern
= patterns
[brightness
& 3];
155 unsigned LCDFN(get_background
)(void)
157 return current_vp
->bg_pattern
;
160 void LCDFN(set_drawinfo
)(int mode
, unsigned fg_brightness
,
161 unsigned bg_brightness
)
163 LCDFN(set_drawmode
)(mode
);
164 LCDFN(set_foreground
)(fg_brightness
);
165 LCDFN(set_background
)(bg_brightness
);
168 int LCDFN(getwidth
)(void)
170 return current_vp
->width
;
173 int LCDFN(getheight
)(void)
175 return current_vp
->height
;
178 void LCDFN(setmargins
)(int x
, int y
)
180 current_vp
->xmargin
= x
;
181 current_vp
->ymargin
= y
;
184 int LCDFN(getxmargin
)(void)
186 return current_vp
->xmargin
;
189 int LCDFN(getymargin
)(void)
191 return current_vp
->ymargin
;
194 void LCDFN(setfont
)(int newfont
)
196 current_vp
->font
= newfont
;
199 int LCDFN(getfont
)(void)
201 return current_vp
->font
;
204 int LCDFN(getstringsize
)(const unsigned char *str
, int *w
, int *h
)
206 return font_getstringsize(str
, w
, h
, current_vp
->font
);
209 /*** low-level drawing functions ***/
211 static void setpixel(int x
, int y
)
213 unsigned mask
= 0x0101 << (y
& 7);
214 FBFN(data
) *address
= &LCDFN(framebuffer
)[y
>>3][x
];
215 unsigned data
= *address
;
217 *address
= data
^ ((data
^ fg_pattern
) & mask
);
220 static void clearpixel(int x
, int y
)
222 unsigned mask
= 0x0101 << (y
& 7);
223 FBFN(data
) *address
= &LCDFN(framebuffer
)[y
>>3][x
];
224 unsigned data
= *address
;
226 *address
= data
^ ((data
^ bg_pattern
) & mask
);
229 static void clearimgpixel(int x
, int y
)
231 unsigned mask
= 0x0101 << (y
& 7);
232 FBFN(data
) *address
= &LCDFN(framebuffer
)[y
>>3][x
];
233 unsigned data
= *address
;
235 *address
= data
^ ((data
^ *(FBFN(data
) *)((long)address
236 + backdrop_offset
)) & mask
);
239 static void flippixel(int x
, int y
)
241 unsigned mask
= 0x0101 << (y
& 7);
242 FBFN(data
) *address
= &LCDFN(framebuffer
)[y
>>3][x
];
247 static void nopixel(int x
, int y
)
253 LCDFN(pixelfunc_type
)* const LCDFN(pixelfuncs_bgcolor
)[8] = {
254 flippixel
, nopixel
, setpixel
, setpixel
,
255 nopixel
, clearpixel
, nopixel
, clearpixel
258 LCDFN(pixelfunc_type
)* const LCDFN(pixelfuncs_backdrop
)[8] = {
259 flippixel
, nopixel
, setpixel
, setpixel
,
260 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
263 LCDFN(pixelfunc_type
)* const *LCDFN(pixelfuncs
) = LCDFN(pixelfuncs_bgcolor
);
265 /* 'mask' and 'bits' contain 2 bits per pixel */
266 static void ICODE_ATTR
flipblock(FBFN(data
) *address
, unsigned mask
,
269 *address
^= bits
& mask
;
272 static void ICODE_ATTR
bgblock(FBFN(data
) *address
, unsigned mask
,
275 unsigned data
= *address
;
277 *address
= data
^ ((data
^ bg_pattern
) & mask
& ~bits
);
280 static void ICODE_ATTR
bgimgblock(FBFN(data
) *address
, unsigned mask
,
283 unsigned data
= *address
;
285 *address
= data
^ ((data
^ *(FBFN(data
) *)((long)address
286 + backdrop_offset
)) & mask
& ~bits
);
289 static void ICODE_ATTR
fgblock(FBFN(data
) *address
, unsigned mask
,
292 unsigned data
= *address
;
294 *address
= data
^ ((data
^ fg_pattern
) & mask
& bits
);
297 static void ICODE_ATTR
solidblock(FBFN(data
) *address
, unsigned mask
,
300 unsigned data
= *address
;
301 unsigned bgp
= bg_pattern
;
303 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
304 *address
= data
^ ((data
^ bits
) & mask
);
307 static void ICODE_ATTR
solidimgblock(FBFN(data
) *address
, unsigned mask
,
310 unsigned data
= *address
;
311 unsigned bgp
= *(FBFN(data
) *)((long)address
+ backdrop_offset
);
313 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
314 *address
= data
^ ((data
^ bits
) & mask
);
317 static void ICODE_ATTR
flipinvblock(FBFN(data
) *address
, unsigned mask
,
320 *address
^= ~bits
& mask
;
323 static void ICODE_ATTR
bginvblock(FBFN(data
) *address
, unsigned mask
,
326 unsigned data
= *address
;
328 *address
= data
^ ((data
^ bg_pattern
) & mask
& bits
);
331 static void ICODE_ATTR
bgimginvblock(FBFN(data
) *address
, unsigned mask
,
334 unsigned data
= *address
;
336 *address
= data
^ ((data
^ *(FBFN(data
) *)((long)address
337 + backdrop_offset
)) & mask
& bits
);
340 static void ICODE_ATTR
fginvblock(FBFN(data
) *address
, unsigned mask
,
343 unsigned data
= *address
;
345 *address
= data
^ ((data
^ fg_pattern
) & mask
& ~bits
);
348 static void ICODE_ATTR
solidinvblock(FBFN(data
) *address
, unsigned mask
,
351 unsigned data
= *address
;
352 unsigned fgp
= fg_pattern
;
354 bits
= fgp
^ ((fgp
^ bg_pattern
) & bits
);
355 *address
= data
^ ((data
^ bits
) & mask
);
358 static void ICODE_ATTR
solidimginvblock(FBFN(data
) *address
, unsigned mask
,
361 unsigned data
= *address
;
362 unsigned fgp
= fg_pattern
;
364 bits
= fgp
^ ((fgp
^ *(FBFN(data
) *)((long)address
365 + backdrop_offset
)) & bits
);
366 *address
= data
^ ((data
^ bits
) & mask
);
369 LCDFN(blockfunc_type
)* const LCDFN(blockfuncs_bgcolor
)[8] = {
370 flipblock
, bgblock
, fgblock
, solidblock
,
371 flipinvblock
, bginvblock
, fginvblock
, solidinvblock
374 LCDFN(blockfunc_type
)* const LCDFN(blockfuncs_backdrop
)[8] = {
375 flipblock
, bgimgblock
, fgblock
, solidimgblock
,
376 flipinvblock
, bgimginvblock
, fginvblock
, solidimginvblock
379 LCDFN(blockfunc_type
)* const *LCDFN(blockfuncs
) = LCDFN(blockfuncs_bgcolor
);
382 void LCDFN(set_backdrop
)(FBFN(data
) *bd
)
387 backdrop_offset
= (long)bd
- (long)LCDFN(framebuffer
);
388 LCDFN(pixelfuncs
) = LCDFN(pixelfuncs_backdrop
);
389 LCDFN(blockfuncs
) = LCDFN(blockfuncs_backdrop
);
394 LCDFN(pixelfuncs
) = LCDFN(pixelfuncs_bgcolor
);
395 LCDFN(blockfuncs
) = LCDFN(blockfuncs_bgcolor
);
399 FBFN(data
)* LCDFN(get_backdrop
)(void)
404 static inline void setblock(FBFN(data
) *address
, unsigned mask
, unsigned bits
)
406 unsigned data
= *address
;
409 *address
= data
^ (bits
& mask
);
412 /*** drawing functions ***/
414 /* Clear the whole display */
415 void LCDFN(clear_display
)(void)
417 if (default_vp
.drawmode
& DRMODE_INVERSEVID
)
419 memset(LCDFN(framebuffer
), patterns
[default_vp
.fg_pattern
& 3],
420 sizeof LCDFN(framebuffer
));
425 memcpy(LCDFN(framebuffer
), backdrop
, sizeof LCDFN(framebuffer
));
427 memset(LCDFN(framebuffer
), patterns
[default_vp
.bg_pattern
& 3],
428 sizeof LCDFN(framebuffer
));
431 LCDFN(scroll_info
).lines
= 0;
434 /* Clear the current viewport */
435 void LCDFN(clear_viewport
)(void)
439 if (current_vp
== &default_vp
)
441 LCDFN(clear_display
)();
445 lastmode
= current_vp
->drawmode
;
447 /* Invert the INVERSEVID bit and set basic mode to SOLID */
448 current_vp
->drawmode
= (~lastmode
& DRMODE_INVERSEVID
) |
451 LCDFN(fillrect
)(0, 0, current_vp
->width
, current_vp
->height
);
453 current_vp
->drawmode
= lastmode
;
455 LCDFN(scroll_stop
)(current_vp
);
459 /* Set a single pixel */
460 void LCDFN(drawpixel
)(int x
, int y
)
462 if (((unsigned)x
< (unsigned)current_vp
->width
) &&
463 ((unsigned)y
< (unsigned)current_vp
->height
))
464 LCDFN(pixelfuncs
)[current_vp
->drawmode
](current_vp
->x
+x
, current_vp
->y
+y
);
468 void LCDFN(drawline
)(int x1
, int y1
, int x2
, int y2
)
476 LCDFN(pixelfunc_type
) *pfunc
= LCDFN(pixelfuncs
)[current_vp
->drawmode
];
478 deltax
= abs(x2
- x1
);
479 deltay
= abs(y2
- y1
);
483 if (deltax
>= deltay
)
486 d
= 2 * deltay
- deltax
;
488 dinc2
= (deltay
- deltax
) * 2;
495 d
= 2 * deltax
- deltay
;
497 dinc2
= (deltax
- deltay
) * 2;
501 numpixels
++; /* include endpoints */
518 for (i
= 0; i
< numpixels
; i
++)
520 if (((unsigned)x
< (unsigned)current_vp
->width
) &&
521 ((unsigned)y
< (unsigned)current_vp
->height
))
522 pfunc(current_vp
->x
+ x
, current_vp
->y
+ y
);
539 /* Draw a horizontal line (optimised) */
540 void LCDFN(hline
)(int x1
, int x2
, int y
)
544 FBFN(data
) *dst
, *dst_end
;
546 LCDFN(blockfunc_type
) *bfunc
;
556 /* nothing to draw? */
557 if (((unsigned)y
>= (unsigned)current_vp
->height
) || (x1
>= current_vp
->width
)
564 if (x2
>= current_vp
->width
)
565 x2
= current_vp
->width
-1;
569 /* adjust x1 and y to viewport */
573 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
574 dst
= &LCDFN(framebuffer
)[y
>>3][x1
];
575 mask
= 0x0101 << (y
& 7);
577 dst_end
= dst
+ width
;
579 bfunc(dst
++, mask
, 0xFFFFu
);
580 while (dst
< dst_end
);
583 /* Draw a vertical line (optimised) */
584 void LCDFN(vline
)(int x
, int y1
, int y2
)
588 unsigned mask
, mask_bottom
;
589 LCDFN(blockfunc_type
) *bfunc
;
599 /* nothing to draw? */
600 if (((unsigned)x
>= (unsigned)current_vp
->width
) || (y1
>= current_vp
->height
)
607 if (y2
>= current_vp
->height
)
608 y2
= current_vp
->height
-1;
610 /* adjust for viewport */
615 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
616 dst
= &LCDFN(framebuffer
)[y1
>>3][x
];
618 mask
= (0xFFu
<< (y1
& 7)) & 0xFFu
;
620 mask_bottom
= 0xFFu
>> (~ny
& 7);
621 mask_bottom
|= mask_bottom
<< 8;
623 for (; ny
>= 8; ny
-= 8)
625 bfunc(dst
, mask
, 0xFFFFu
);
630 bfunc(dst
, mask
, 0xFFFFu
);
633 /* Draw a rectangular box */
634 void LCDFN(drawrect
)(int x
, int y
, int width
, int height
)
636 if ((width
<= 0) || (height
<= 0))
639 int x2
= x
+ width
- 1;
640 int y2
= y
+ height
- 1;
642 LCDFN(vline
)(x
, y
, y2
);
643 LCDFN(vline
)(x2
, y
, y2
);
644 LCDFN(hline
)(x
, x2
, y
);
645 LCDFN(hline
)(x
, x2
, y2
);
648 /* Fill a rectangular area */
649 void LCDFN(fillrect
)(int x
, int y
, int width
, int height
)
652 FBFN(data
) *dst
, *dst_end
;
653 unsigned mask
, mask_bottom
;
655 LCDFN(blockfunc_type
) *bfunc
;
656 bool fillopt
= false;
658 /* nothing to draw? */
659 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
660 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
674 if (x
+ width
> current_vp
->width
)
675 width
= current_vp
->width
- x
;
676 if (y
+ height
> current_vp
->height
)
677 height
= current_vp
->height
- y
;
679 /* adjust for viewport */
683 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
685 if ((current_vp
->drawmode
& DRMODE_BG
) && !backdrop
)
693 if (current_vp
->drawmode
& DRMODE_FG
)
699 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
700 dst
= &LCDFN(framebuffer
)[y
>>3][x
];
701 ny
= height
- 1 + (y
& 7);
702 mask
= (0xFFu
<< (y
& 7)) & 0xFFu
;
704 mask_bottom
= 0xFFu
>> (~ny
& 7);
705 mask_bottom
|= mask_bottom
<< 8;
707 for (; ny
>= 8; ny
-= 8)
709 if (fillopt
&& (mask
== 0xFFFFu
))
710 memset16(dst
, bits
, width
);
713 FBFN(data
) *dst_row
= dst
;
715 dst_end
= dst_row
+ width
;
717 bfunc(dst_row
++, mask
, 0xFFFFu
);
718 while (dst_row
< dst_end
);
726 if (fillopt
&& (mask
== 0xFFFFu
))
727 memset16(dst
, bits
, width
);
730 dst_end
= dst
+ width
;
732 bfunc(dst
++, mask
, 0xFFFFu
);
733 while (dst
< dst_end
);
737 /* About Rockbox' internal monochrome bitmap format:
739 * A bitmap contains one bit for every pixel that defines if that pixel is
740 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
742 * The bytes are stored in row-major order, with byte 0 being top left,
743 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
744 * 0..7, the second row defines pixel row 8..15 etc.
746 * This is similar to the internal lcd hw format. */
748 /* Draw a partial monochrome bitmap */
749 void ICODE_ATTR
LCDFN(mono_bitmap_part
)(const unsigned char *src
, int src_x
,
750 int src_y
, int stride
, int x
, int y
,
751 int width
, int height
)
754 FBFN(data
) *dst
, *dst_end
;
755 unsigned data
, mask
, mask_bottom
;
756 LCDFN(blockfunc_type
) *bfunc
;
758 /* nothing to draw? */
759 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
760 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
776 if (x
+ width
> current_vp
->width
)
777 width
= current_vp
->width
- x
;
778 if (y
+ height
> current_vp
->height
)
779 height
= current_vp
->height
- y
;
781 /* adjust for viewport */
785 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
788 dst
= &LCDFN(framebuffer
)[y
>>3][x
];
790 ny
= height
- 1 + shift
+ src_y
;
792 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
793 mask
= 0xFFu
<< (shift
+ src_y
);
794 /* not byte-doubled here because shift+src_y can be > 7 */
795 mask_bottom
= 0xFFu
>> (~ny
& 7);
796 mask_bottom
|= mask_bottom
<< 8;
803 for (; ny
>= 8; ny
-= 8)
805 const unsigned char *src_row
= src
;
806 FBFN(data
) *dst_row
= dst
;
808 dst_end
= dst_row
+ width
;
812 bfunc(dst_row
++, mask
, data
| (data
<< 8));
814 while (dst_row
< dst_end
);
822 dst_end
= dst
+ width
;
826 bfunc(dst
++, mask
, data
| (data
<< 8));
828 while (dst
< dst_end
);
834 dst_end
= dst
+ width
;
837 const unsigned char *src_col
= src
++;
838 FBFN(data
) *dst_col
= dst
++;
839 unsigned mask_col
= mask
& 0xFFu
;
841 mask_col
|= mask_col
<< 8;
844 for (y
= ny
; y
>= 8; y
-= 8)
846 data
|= *src_col
<< shift
;
850 ddata
= data
& 0xFFu
;
851 bfunc(dst_col
, mask_col
, ddata
| (ddata
<< 8));
856 mask_col
= (mask
>> 8) & 0xFFu
;
857 mask_col
|= mask_col
<< 8;
861 dst_col
+= LCDM(WIDTH
);
864 data
|= *src_col
<< shift
;
865 mask_col
&= mask_bottom
;
866 ddata
= data
& 0xFFu
;
867 bfunc(dst_col
, mask_col
, ddata
| (ddata
<< 8));
869 while (dst
< dst_end
);
873 /* Draw a full monochrome bitmap */
874 void LCDFN(mono_bitmap
)(const unsigned char *src
, int x
, int y
, int width
,
877 LCDFN(mono_bitmap_part
)(src
, 0, 0, width
, x
, y
, width
, height
);
880 /* About Rockbox' internal native bitmap format:
882 * A bitmap contains one bit in each byte of a pair of bytes for every pixel.
883 * 00 = white, 01 = light grey, 10 = dark grey, 11 = black. Bits within a byte
884 * are arranged vertically, LSB at top.
885 * The pairs of bytes are stored as shorts, in row-major order, with word 0
886 * being top left, word 1 2nd from left etc. The first row of words defines
887 * pixel rows 0..7, the second row defines pixel row 8..15 etc.
889 * This is the same as the internal lcd hw format. */
891 /* Draw a partial native bitmap */
892 void ICODE_ATTR
LCDFN(bitmap_part
)(const FBFN(data
) *src
, int src_x
,
893 int src_y
, int stride
, int x
, int y
,
894 int width
, int height
)
897 FBFN(data
) *dst
, *dst_end
;
898 unsigned mask
, mask_bottom
;
900 /* nothing to draw? */
901 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
902 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
918 if (x
+ width
> current_vp
->width
)
919 width
= current_vp
->width
- x
;
920 if (y
+ height
> current_vp
->height
)
921 height
= current_vp
->height
- y
;
923 /* adjust for viewport */
927 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
930 dst
= &LCDFN(framebuffer
)[y
>>3][x
];
932 ny
= height
- 1 + shift
+ src_y
;
934 mask
= 0xFFu
<< (shift
+ src_y
);
935 /* not byte-doubled here because shift+src_y can be > 7 */
936 mask_bottom
= 0xFFu
>> (~ny
& 7);
937 mask_bottom
|= mask_bottom
<< 8;
944 for (; ny
>= 8; ny
-= 8)
947 memcpy(dst
, src
, width
* sizeof(FBFN(data
)));
950 const FBFN(data
) *src_row
= src
;
951 FBFN(data
) *dst_row
= dst
;
953 dst_end
= dst_row
+ width
;
955 setblock(dst_row
++, mask
, *src_row
++);
956 while (dst_row
< dst_end
);
965 memcpy(dst
, src
, width
* sizeof(FBFN(data
)));
968 dst_end
= dst
+ width
;
970 setblock(dst
++, mask
, *src
++);
971 while (dst
< dst_end
);
976 unsigned datamask
= (0xFFu
<< shift
) & 0xFFu
;
978 datamask
|= datamask
<< 8;
980 dst_end
= dst
+ width
;
983 const FBFN(data
) *src_col
= src
++;
984 FBFN(data
) *dst_col
= dst
++;
985 unsigned mask_col
= mask
& 0xFFu
;
986 unsigned data
, olddata
= 0;
988 mask_col
|= mask_col
<< 8;
990 for (y
= ny
; y
>= 8; y
-= 8)
992 data
= *src_col
<< shift
;
996 setblock(dst_col
, mask_col
,
997 olddata
^((olddata
^ data
) & datamask
));
1002 mask_col
= (mask
>> 8) & 0xFFu
;
1003 mask_col
|= mask_col
<< 8;
1006 dst_col
+= LCDM(WIDTH
);
1007 olddata
= data
>> 8;
1009 data
= *src_col
<< shift
;
1010 setblock(dst_col
, mask_col
& mask_bottom
,
1011 olddata
^((olddata
^ data
) & datamask
));
1013 while (dst
< dst_end
);
1017 /* Draw a full native bitmap */
1018 void LCDFN(bitmap
)(const FBFN(data
) *src
, int x
, int y
, int width
, int height
)
1020 LCDFN(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 LCDFN(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 LCDFN(mono_bitmap_part
)(bits
, ofs
, 0, width
, x
, y
, width
- ofs
,
1056 /* put a string at a given pixel position */
1057 void LCDFN(putsxy
)(int x
, int y
, const unsigned char *str
)
1059 LCDFN(putsxyofs
)(x
, y
, 0, str
);
1062 /*** line oriented text output ***/
1064 /* put a string at a given char position */
1065 void LCDFN(puts
)(int x
, int y
, const unsigned char *str
)
1067 LCDFN(puts_style_offset
)(x
, y
, str
, STYLE_DEFAULT
, 0);
1070 void LCDFN(puts_style
)(int x
, int y
, const unsigned char *str
, int style
)
1072 LCDFN(puts_style_offset
)(x
, y
, str
, style
, 0);
1075 void LCDFN(puts_offset
)(int x
, int y
, const unsigned char *str
, int offset
)
1077 LCDFN(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 LCDFN(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 LCDFN(scroll_stop_line
)(current_vp
, y
);
1094 LCDFN(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 LCDFN(putsxyofs
)(xpos
, ypos
, offset
, str
);
1100 current_vp
->drawmode
^= DRMODE_INVERSEVID
;
1101 xrect
= xpos
+ MAX(w
- offset
, 0);
1102 LCDFN(fillrect
)(xrect
, ypos
, current_vp
->width
- xrect
, h
);
1103 current_vp
->drawmode
= lastmode
;
1107 void LCDFN(puts_scroll
)(int x
, int y
, const unsigned char *string
)
1109 LCDFN(puts_scroll_style
)(x
, y
, string
, STYLE_DEFAULT
);
1112 void LCDFN(puts_scroll_style
)(int x
, int y
, const unsigned char *string
, int style
)
1114 LCDFN(puts_scroll_style_offset
)(x
, y
, string
, style
, 0);
1117 void LCDFN(puts_scroll_offset
)(int x
, int y
, const unsigned char *string
, int offset
)
1119 LCDFN(puts_scroll_style_offset
)(x
, y
, string
, STYLE_DEFAULT
, offset
);
1122 void LCDFN(puts_scroll_style_offset
)(int x
, int y
, const unsigned char *string
,
1123 int style
, int offset
)
1125 struct scrollinfo
* s
;
1128 if ((unsigned)y
>= (unsigned)current_vp
->height
)
1131 /* remove any previously scrolling line at the same location */
1132 LCDFN(scroll_stop_line
)(current_vp
, y
);
1134 if (LCDFN(scroll_info
).lines
>= LCDM(SCROLLABLE_LINES
)) return;
1136 s
= &LCDFN(scroll_info
).scroll
[LCDFN(scroll_info
).lines
];
1138 s
->start_tick
= current_tick
+ LCDFN(scroll_info
).delay
;
1140 if (style
& STYLE_INVERT
) {
1141 LCDFN(puts_style_offset
)(x
,y
,string
,STYLE_INVERT
,offset
);
1144 LCDFN(puts_offset
)(x
,y
,string
,offset
);
1146 LCDFN(getstringsize
)(string
, &w
, &h
);
1148 if (current_vp
->width
- x
* 8 - current_vp
->xmargin
< w
) {
1149 /* prepare scroll line */
1152 memset(s
->line
, 0, sizeof s
->line
);
1153 strcpy(s
->line
, string
);
1156 s
->width
= LCDFN(getstringsize
)(s
->line
, &w
, &h
);
1158 /* scroll bidirectional or forward only depending on the string
1160 if ( LCDFN(scroll_info
).bidir_limit
) {
1161 s
->bidir
= s
->width
< (current_vp
->width
- current_vp
->xmargin
) *
1162 (100 + LCDFN(scroll_info
).bidir_limit
) / 100;
1167 if (!s
->bidir
) { /* add spaces if scrolling in the round */
1168 strcat(s
->line
, " ");
1169 /* get new width incl. spaces */
1170 s
->width
= LCDFN(getstringsize
)(s
->line
, &w
, &h
);
1173 end
= strchr(s
->line
, '\0');
1174 strncpy(end
, (char *)string
, current_vp
->width
/2);
1178 s
->len
= utf8length((char *)string
);
1180 s
->startx
= current_vp
->xmargin
+ x
* s
->width
/ s
->len
;
1181 s
->backward
= false;
1183 LCDFN(scroll_info
).lines
++;
1187 void LCDFN(scroll_fn
)(void)
1190 struct scrollinfo
* s
;
1194 struct viewport
* old_vp
= current_vp
;
1196 for ( index
= 0; index
< LCDFN(scroll_info
).lines
; index
++ ) {
1197 s
= &LCDFN(scroll_info
).scroll
[index
];
1200 if (TIME_BEFORE(current_tick
, s
->start_tick
))
1203 LCDFN(set_viewport
)(s
->vp
);
1206 s
->offset
-= LCDFN(scroll_info
).step
;
1208 s
->offset
+= LCDFN(scroll_info
).step
;
1210 pf
= font_get(current_vp
->font
);
1212 ypos
= current_vp
->ymargin
+ s
->y
* pf
->height
;
1214 if (s
->bidir
) { /* scroll bidirectional */
1215 if (s
->offset
<= 0) {
1216 /* at beginning of line */
1218 s
->backward
= false;
1219 s
->start_tick
= current_tick
+ LCDFN(scroll_info
).delay
* 2;
1221 if (s
->offset
>= s
->width
- (current_vp
->width
- xpos
)) {
1222 /* at end of line */
1223 s
->offset
= s
->width
- (current_vp
->width
- xpos
);
1225 s
->start_tick
= current_tick
+ LCDFN(scroll_info
).delay
* 2;
1229 /* scroll forward the whole time */
1230 if (s
->offset
>= s
->width
)
1231 s
->offset
%= s
->width
;
1234 lastmode
= current_vp
->drawmode
;
1235 current_vp
->drawmode
= (s
->style
&STYLE_INVERT
) ?
1236 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1237 LCDFN(putsxyofs
)(xpos
, ypos
, s
->offset
, s
->line
);
1238 current_vp
->drawmode
= lastmode
;
1239 LCDFN(update_viewport_rect
)(xpos
, ypos
,
1240 current_vp
->width
- xpos
, pf
->height
);
1243 LCDFN(set_viewport
)(old_vp
);