1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 by Dave Chapman
12 * Rockbox driver for 16-bit colour 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"
45 fb_data lcd_framebuffer
[LCD_FBHEIGHT
][LCD_FBWIDTH
] IRAM_LCDFRAMEBUFFER
__attribute__ ((aligned (16)));
48 static fb_data
* lcd_backdrop
= NULL
;
49 static long lcd_backdrop_offset IDATA_ATTR
= 0;
51 #if !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR)
52 static unsigned fg_pattern IDATA_ATTR
= LCD_DEFAULT_FG
;
53 static unsigned bg_pattern IDATA_ATTR
= LCD_DEFAULT_BG
;
55 unsigned fg_pattern IDATA_ATTR
= LCD_DEFAULT_FG
;
56 unsigned bg_pattern IDATA_ATTR
= LCD_DEFAULT_BG
;
59 static int drawmode
= DRMODE_SOLID
;
60 static int xmargin
= 0;
61 static int ymargin
= 0;
62 static int curfont
= FONT_SYSFIXED
;
69 /* Call device specific init */
74 /*** parameter handling ***/
76 void lcd_set_drawmode(int mode
)
78 drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
81 int lcd_get_drawmode(void)
86 void lcd_set_foreground(unsigned color
)
91 unsigned lcd_get_foreground(void)
96 void lcd_set_background(unsigned color
)
101 unsigned lcd_get_background(void)
106 void lcd_set_drawinfo(int mode
, unsigned fg_color
, unsigned bg_color
)
108 lcd_set_drawmode(mode
);
109 fg_pattern
= fg_color
;
110 bg_pattern
= bg_color
;
113 void lcd_setmargins(int x
, int y
)
119 int lcd_getxmargin(void)
124 int lcd_getymargin(void)
129 void lcd_setfont(int newfont
)
134 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
136 return font_getstringsize(str
, w
, h
, curfont
);
139 /*** low-level drawing functions ***/
141 #define LCDADDR(x, y) (&lcd_framebuffer[(y)][(x)])
143 static void setpixel(fb_data
*address
) ICODE_ATTR
;
144 static void setpixel(fb_data
*address
)
146 *address
= fg_pattern
;
149 static void clearpixel(fb_data
*address
) ICODE_ATTR
;
150 static void clearpixel(fb_data
*address
)
152 *address
= bg_pattern
;
155 static void clearimgpixel(fb_data
*address
) ICODE_ATTR
;
156 static void clearimgpixel(fb_data
*address
)
158 *address
= *(fb_data
*)((long)address
+ lcd_backdrop_offset
);
161 static void flippixel(fb_data
*address
) ICODE_ATTR
;
162 static void flippixel(fb_data
*address
)
164 *address
= ~(*address
);
167 static void nopixel(fb_data
*address
) ICODE_ATTR
;
168 static void nopixel(fb_data
*address
)
173 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_bgcolor
[8] = {
174 flippixel
, nopixel
, setpixel
, setpixel
,
175 nopixel
, clearpixel
, nopixel
, clearpixel
178 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_backdrop
[8] = {
179 flippixel
, nopixel
, setpixel
, setpixel
,
180 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
183 lcd_fastpixelfunc_type
* const * lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
185 void lcd_set_backdrop(fb_data
* backdrop
)
187 lcd_backdrop
= backdrop
;
190 lcd_backdrop_offset
= (long)backdrop
- (long)&lcd_framebuffer
[0][0];
191 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_backdrop
;
195 lcd_backdrop_offset
= 0;
196 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
200 fb_data
* lcd_get_backdrop(void)
205 /*** drawing functions ***/
207 /* Clear the whole display */
208 void lcd_clear_display(void)
210 fb_data
*dst
= LCDADDR(0, 0);
212 if (drawmode
& DRMODE_INVERSEVID
)
214 memset16(dst
, fg_pattern
, LCD_WIDTH
*LCD_HEIGHT
);
219 memset16(dst
, bg_pattern
, LCD_WIDTH
*LCD_HEIGHT
);
221 memcpy(dst
, lcd_backdrop
, sizeof(lcd_framebuffer
));
224 lcd_scroll_info
.lines
= 0;
227 /* Set a single pixel */
228 void lcd_drawpixel(int x
, int y
)
230 if (((unsigned)x
< LCD_WIDTH
) && ((unsigned)y
< LCD_HEIGHT
))
231 lcd_fastpixelfuncs
[drawmode
](LCDADDR(x
, y
));
235 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
243 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[drawmode
];
245 deltax
= abs(x2
- x1
);
246 deltay
= abs(y2
- y1
);
250 if (deltax
>= deltay
)
253 d
= 2 * deltay
- deltax
;
255 dinc2
= (deltay
- deltax
) * 2;
262 d
= 2 * deltax
- deltay
;
264 dinc2
= (deltax
- deltay
) * 2;
268 numpixels
++; /* include endpoints */
285 for (i
= 0; i
< numpixels
; i
++)
287 if (((unsigned)x
< LCD_WIDTH
) && ((unsigned)y
< LCD_HEIGHT
))
288 pfunc(LCDADDR(x
, y
));
305 /* Draw a horizontal line (optimised) */
306 void lcd_hline(int x1
, int x2
, int y
)
310 enum fill_opt fillopt
= OPT_NONE
;
311 fb_data
*dst
, *dst_end
;
312 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[drawmode
];
322 /* nothing to draw? */
323 if (((unsigned)y
>= LCD_HEIGHT
) || (x1
>= LCD_WIDTH
) || (x2
< 0))
332 if (drawmode
& DRMODE_INVERSEVID
)
334 if (drawmode
& DRMODE_BG
)
347 if (drawmode
& DRMODE_FG
)
353 dst
= LCDADDR(x1
, y
);
359 memset16(dst
, bits
, width
);
363 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
364 width
* sizeof(fb_data
));
368 dst_end
= dst
+ width
;
371 while (dst
< dst_end
);
376 /* Draw a vertical line (optimised) */
377 void lcd_vline(int x
, int y1
, int y2
)
380 fb_data
*dst
, *dst_end
;
381 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[drawmode
];
391 /* nothing to draw? */
392 if (((unsigned)x
>= LCD_WIDTH
) || (y1
>= LCD_HEIGHT
) || (y2
< 0))
398 if (y2
>= LCD_HEIGHT
)
401 dst
= LCDADDR(x
, y1
);
402 dst_end
= dst
+ (y2
- y1
) * LCD_WIDTH
;
409 while (dst
<= dst_end
);
412 /* Draw a rectangular box */
413 void lcd_drawrect(int x
, int y
, int width
, int height
)
415 if ((width
<= 0) || (height
<= 0))
418 int x2
= x
+ width
- 1;
419 int y2
= y
+ height
- 1;
422 lcd_vline(x2
, y
, y2
);
424 lcd_hline(x
, x2
, y2
);
427 /* Fill a rectangular area */
428 void lcd_fillrect(int x
, int y
, int width
, int height
)
431 enum fill_opt fillopt
= OPT_NONE
;
432 fb_data
*dst
, *dst_end
;
433 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[drawmode
];
435 /* nothing to draw? */
436 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
437 || (x
+ width
<= 0) || (y
+ height
<= 0))
451 if (x
+ width
> LCD_WIDTH
)
452 width
= LCD_WIDTH
- x
;
453 if (y
+ height
> LCD_HEIGHT
)
454 height
= LCD_HEIGHT
- y
;
456 if (drawmode
& DRMODE_INVERSEVID
)
458 if (drawmode
& DRMODE_BG
)
471 if (drawmode
& DRMODE_FG
)
478 dst_end
= dst
+ height
* LCD_WIDTH
;
482 fb_data
*dst_row
, *row_end
;
487 memset16(dst
, bits
, width
);
491 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
492 width
* sizeof(fb_data
));
497 row_end
= dst_row
+ width
;
500 while (dst_row
< row_end
);
505 while (dst
< dst_end
);
508 /* About Rockbox' internal monochrome bitmap format:
510 * A bitmap contains one bit for every pixel that defines if that pixel is
511 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
513 * The bytes are stored in row-major order, with byte 0 being top left,
514 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
515 * 0..7, the second row defines pixel row 8..15 etc.
517 * This is the mono bitmap format used on all other targets so far; the
518 * pixel packing doesn't really matter on a 8bit+ target. */
520 /* Draw a partial monochrome bitmap */
522 void lcd_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
523 int stride
, int x
, int y
, int width
, int height
)
525 void lcd_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
526 int stride
, int x
, int y
, int width
, int height
)
528 const unsigned char *src_end
;
530 fb_data
*dst
, *dst_end
, *backdrop
;
531 lcd_fastpixelfunc_type
*fgfunc
, *bgfunc
;
533 /* nothing to draw? */
534 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
535 || (x
+ width
<= 0) || (y
+ height
<= 0))
551 if (x
+ width
> LCD_WIDTH
)
552 width
= LCD_WIDTH
- x
;
553 if (y
+ height
> LCD_HEIGHT
)
554 height
= LCD_HEIGHT
- y
;
556 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
558 src_end
= src
+ width
;
561 has_backdrop
= (lcd_backdrop
!= NULL
);
562 backdrop
= lcd_backdrop
+ y
* LCD_WIDTH
+ x
;
563 fgfunc
= lcd_fastpixelfuncs
[drawmode
];
564 bgfunc
= lcd_fastpixelfuncs
[drawmode
^ DRMODE_INVERSEVID
];
567 const unsigned char *src_col
= src
++;
568 unsigned data
= *src_col
>> src_y
;
569 fb_data
*dst_col
= dst
++;
570 int numbits
= 8 - src_y
;
571 fb_data
*backdrop_col
= backdrop
++;
572 dst_end
= dst_col
+ height
* LCD_WIDTH
;
579 *dst_col
= fg_pattern
;
581 *dst_col
= has_backdrop
? *backdrop_col
: bg_pattern
;
585 *dst_col
= fg_pattern
;
587 case (DRMODE_SOLID
|DRMODE_INVERSEVID
):
589 *dst_col
= has_backdrop
? *backdrop_col
: bg_pattern
;
591 *dst_col
= fg_pattern
;
600 dst_col
+= LCD_WIDTH
;
601 backdrop_col
+= LCD_WIDTH
;
610 while (dst_col
< dst_end
);
612 while (src
< src_end
);
614 /* Draw a full monochrome bitmap */
615 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
617 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
620 /* Draw a partial native bitmap */
621 void lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
622 int stride
, int x
, int y
, int width
, int height
)
624 void lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
625 int stride
, int x
, int y
, int width
, int height
)
627 fb_data
*dst
, *dst_end
;
629 /* nothing to draw? */
630 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
631 || (x
+ width
<= 0) || (y
+ height
<= 0))
647 if (x
+ width
> LCD_WIDTH
)
648 width
= LCD_WIDTH
- x
;
649 if (y
+ height
> LCD_HEIGHT
)
650 height
= LCD_HEIGHT
- y
;
652 src
+= stride
* src_y
+ src_x
; /* move starting point */
654 dst_end
= dst
+ height
* LCD_WIDTH
;
658 memcpy(dst
, src
, width
* sizeof(fb_data
));
662 while (dst
< dst_end
);
665 /* Draw a full native bitmap */
666 void lcd_bitmap(const fb_data
*src
, int x
, int y
, int width
, int height
)
668 lcd_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
671 #if !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR)
672 /* Draw a partial native bitmap */
673 void lcd_bitmap_transparent_part(const fb_data
*src
, int src_x
, int src_y
,
674 int stride
, int x
, int y
, int width
,
675 int height
) ICODE_ATTR
;
676 void lcd_bitmap_transparent_part(const fb_data
*src
, int src_x
, int src_y
,
677 int stride
, int x
, int y
, int width
,
680 fb_data
*dst
, *dst_end
;
682 /* nothing to draw? */
683 if ((width
<= 0) || (height
<= 0) || (x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
684 || (x
+ width
<= 0) || (y
+ height
<= 0))
700 if (x
+ width
> LCD_WIDTH
)
701 width
= LCD_WIDTH
- x
;
702 if (y
+ height
> LCD_HEIGHT
)
703 height
= LCD_HEIGHT
- y
;
705 src
+= stride
* src_y
+ src_x
; /* move starting point */
707 dst_end
= dst
+ height
* LCD_WIDTH
;
712 for(i
= 0;i
< width
;i
++)
714 if (src
[i
] == REPLACEWITHFG_COLOR
)
716 else if(src
[i
] != TRANSPARENT_COLOR
)
722 while (dst
< dst_end
);
724 #endif /* !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR) */
726 /* Draw a full native bitmap with a transparent color */
727 void lcd_bitmap_transparent(const fb_data
*src
, int x
, int y
,
728 int width
, int height
)
730 lcd_bitmap_transparent_part(src
, 0, 0, width
, x
, y
, width
, height
);
733 /* put a string at a given pixel position, skipping first ofs pixel columns */
734 static void lcd_putsxyofs(int x
, int y
, int ofs
, const unsigned char *str
)
738 struct font
* pf
= font_get(curfont
);
740 ucs
= bidi_l2v(str
, 1);
742 while ((ch
= *ucs
++) != 0 && x
< LCD_WIDTH
)
745 const unsigned char *bits
;
747 /* get proportional width and glyph bits */
748 width
= font_get_width(pf
,ch
);
756 bits
= font_get_bits(pf
, ch
);
758 lcd_mono_bitmap_part(bits
, ofs
, 0, width
, x
, y
, width
- ofs
, pf
->height
);
765 /* put a string at a given pixel position */
766 void lcd_putsxy(int x
, int y
, const unsigned char *str
)
768 lcd_putsxyofs(x
, y
, 0, str
);
771 /*** line oriented text output ***/
773 /* put a string at a given char position */
774 void lcd_puts(int x
, int y
, const unsigned char *str
)
776 lcd_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, 0);
779 void lcd_puts_style(int x
, int y
, const unsigned char *str
, int style
)
781 lcd_puts_style_offset(x
, y
, str
, style
, 0);
784 void lcd_puts_offset(int x
, int y
, const unsigned char *str
, int offset
)
786 lcd_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, offset
);
789 /* put a string at a given char position, style, and pixel position,
790 * skipping first offset pixel columns */
791 void lcd_puts_style_offset(int x
, int y
, const unsigned char *str
, int style
,
794 int xpos
,ypos
,w
,h
,xrect
;
795 int lastmode
= drawmode
;
796 int oldfgcolor
= fg_pattern
;
797 int oldbgcolor
= bg_pattern
;
799 /* make sure scrolling is turned off on the line we are updating */
800 lcd_scroll_info
.lines
&= ~(1 << y
);
805 lcd_getstringsize(str
, &w
, &h
);
806 xpos
= xmargin
+ x
*w
/ utf8length(str
);
807 ypos
= ymargin
+ y
*h
;
808 drawmode
= (style
& STYLE_INVERT
) ?
809 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
810 if (style
& STYLE_COLORED
) {
811 if (drawmode
== DRMODE_SOLID
)
812 fg_pattern
= style
& STYLE_COLOR_MASK
;
814 bg_pattern
= style
& STYLE_COLOR_MASK
;
816 lcd_putsxyofs(xpos
, ypos
, offset
, str
);
817 drawmode
^= DRMODE_INVERSEVID
;
818 xrect
= xpos
+ MAX(w
- offset
, 0);
819 lcd_fillrect(xrect
, ypos
, LCD_WIDTH
- xrect
, h
);
821 fg_pattern
= oldfgcolor
;
822 bg_pattern
= oldbgcolor
;
826 void lcd_puts_scroll(int x
, int y
, const unsigned char *string
)
828 lcd_puts_scroll_style(x
, y
, string
, STYLE_DEFAULT
);
831 void lcd_puts_scroll_style(int x
, int y
, const unsigned char *string
, int style
)
833 lcd_puts_scroll_style_offset(x
, y
, string
, style
, 0);
836 void lcd_puts_scroll_offset(int x
, int y
, const unsigned char *string
, int offset
)
838 lcd_puts_scroll_style_offset(x
, y
, string
, STYLE_DEFAULT
, offset
);
841 void lcd_puts_scroll_style_offset(int x
, int y
, const unsigned char *string
,
842 int style
, int offset
)
844 struct scrollinfo
* s
;
847 if(y
>=LCD_SCROLLABLE_LINES
) return;
849 s
= &lcd_scroll_info
.scroll
[y
];
851 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
;
853 if (style
& STYLE_INVERT
) {
856 lcd_puts_style_offset(x
,y
,string
,style
,offset
);
858 lcd_getstringsize(string
, &w
, &h
);
860 if (LCD_WIDTH
- x
* 8 - xmargin
< w
) {
861 /* prepare scroll line */
864 memset(s
->line
, 0, sizeof s
->line
);
865 strcpy(s
->line
, string
);
868 s
->width
= lcd_getstringsize(s
->line
, &w
, &h
);
870 /* scroll bidirectional or forward only depending on the string
872 if ( lcd_scroll_info
.bidir_limit
) {
873 s
->bidir
= s
->width
< (LCD_WIDTH
- xmargin
) *
874 (100 + lcd_scroll_info
.bidir_limit
) / 100;
879 if (!s
->bidir
) { /* add spaces if scrolling in the round */
880 strcat(s
->line
, " ");
881 /* get new width incl. spaces */
882 s
->width
= lcd_getstringsize(s
->line
, &w
, &h
);
885 end
= strchr(s
->line
, '\0');
886 strncpy(end
, string
, LCD_WIDTH
/2);
888 s
->len
= utf8length(string
);
890 s
->startx
= xmargin
+ x
* s
->width
/ s
->len
;
892 s
->line_color
= (style
&STYLE_COLORED
)?
893 (style
&STYLE_COLOR_MASK
): -1;
894 lcd_scroll_info
.lines
|= (1<<y
);
897 /* force a bit switch-off since it doesn't scroll */
898 lcd_scroll_info
.lines
&= ~(1<<y
);
901 void lcd_scroll_fn(void)
904 struct scrollinfo
* s
;
908 unsigned old_fgcolor
= fg_pattern
;
909 unsigned old_bgcolor
= bg_pattern
;
911 for ( index
= 0; index
< LCD_SCROLLABLE_LINES
; index
++ ) {
913 if ((lcd_scroll_info
.lines
& (1 << index
)) == 0)
916 s
= &lcd_scroll_info
.scroll
[index
];
919 if (TIME_BEFORE(current_tick
, s
->start_tick
))
922 if (s
->line_color
>= 0) {
924 fg_pattern
= old_fgcolor
;
925 bg_pattern
= s
->line_color
;
928 fg_pattern
= s
->line_color
;
929 bg_pattern
= old_bgcolor
;
934 s
->offset
-= lcd_scroll_info
.step
;
936 s
->offset
+= lcd_scroll_info
.step
;
938 pf
= font_get(curfont
);
940 ypos
= ymargin
+ index
* pf
->height
;
942 if (s
->bidir
) { /* scroll bidirectional */
943 if (s
->offset
<= 0) {
944 /* at beginning of line */
947 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
* 2;
949 if (s
->offset
>= s
->width
- (LCD_WIDTH
- xpos
)) {
951 s
->offset
= s
->width
- (LCD_WIDTH
- xpos
);
953 s
->start_tick
= current_tick
+ lcd_scroll_info
.delay
* 2;
957 /* scroll forward the whole time */
958 if (s
->offset
>= s
->width
)
959 s
->offset
%= s
->width
;
963 drawmode
= s
->invert
?
964 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
965 lcd_putsxyofs(xpos
, ypos
, s
->offset
, s
->line
);
967 lcd_update_rect(xpos
, ypos
, LCD_WIDTH
- xpos
, pf
->height
);
970 fg_pattern
= old_fgcolor
;
971 bg_pattern
= old_bgcolor
;