1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 by Dave Chapman
11 * Copyright (C) 2009 by Karl Kurbjun
13 * Rockbox driver for 16-bit colour LCDs with vertical strides
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
37 #include "rbunicode.h"
39 #include "scroll_engine.h"
48 fb_data lcd_framebuffer
[LCD_FBHEIGHT
][LCD_FBWIDTH
]
49 IRAM_LCDFRAMEBUFFER
CACHEALIGN_AT_LEAST_ATTR(16);
52 static fb_data
* lcd_backdrop
= NULL
;
53 static long lcd_backdrop_offset IDATA_ATTR
= 0;
55 static struct viewport default_vp
=
61 .font
= FONT_SYSFIXED
,
62 .drawmode
= DRMODE_SOLID
,
63 .fg_pattern
= LCD_DEFAULT_FG
,
64 .bg_pattern
= LCD_DEFAULT_BG
,
65 .lss_pattern
= LCD_DEFAULT_BG
,
66 .lse_pattern
= LCD_DEFAULT_BG
,
67 .lst_pattern
= LCD_DEFAULT_BG
,
70 /* The Gigabeat target build requires access to the current fg_pattern
72 #if defined(SIMULATOR)
73 static struct viewport
* current_vp IDATA_ATTR
= &default_vp
;
75 struct viewport
* current_vp IDATA_ATTR
= &default_vp
;
83 /* Call device specific init */
89 void lcd_set_viewport(struct viewport
* vp
)
92 current_vp
= &default_vp
;
96 #if defined(SIMULATOR)
97 /* Force the viewport to be within bounds. If this happens it should
98 * be considered an error - the viewport will not draw as it might be
101 if((unsigned) current_vp
->x
> (unsigned) LCD_WIDTH
102 || (unsigned) current_vp
->y
> (unsigned) LCD_HEIGHT
103 || current_vp
->x
+ current_vp
->width
> LCD_WIDTH
104 || current_vp
->y
+ current_vp
->height
> LCD_HEIGHT
)
106 #if !defined(HAVE_VIEWPORT_CLIP)
111 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
112 current_vp
->x
, current_vp
->y
,
113 current_vp
->width
, current_vp
->height
);
119 void lcd_update_viewport(void)
121 lcd_update_rect(current_vp
->x
, current_vp
->y
,
122 current_vp
->width
, current_vp
->height
);
125 void lcd_update_viewport_rect(int x
, int y
, int width
, int height
)
127 lcd_update_rect(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
130 /*** parameter handling ***/
132 void lcd_set_drawmode(int mode
)
134 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
137 int lcd_get_drawmode(void)
139 return current_vp
->drawmode
;
142 void lcd_set_foreground(unsigned color
)
144 current_vp
->fg_pattern
= color
;
147 unsigned lcd_get_foreground(void)
149 return current_vp
->fg_pattern
;
152 void lcd_set_background(unsigned color
)
154 current_vp
->bg_pattern
= color
;
157 unsigned lcd_get_background(void)
159 return current_vp
->bg_pattern
;
162 void lcd_set_selector_start(unsigned color
)
164 current_vp
->lss_pattern
= color
;
167 void lcd_set_selector_end(unsigned color
)
169 current_vp
->lse_pattern
= color
;
172 void lcd_set_selector_text(unsigned color
)
174 current_vp
->lst_pattern
= color
;
177 void lcd_set_drawinfo(int mode
, unsigned fg_color
, unsigned bg_color
)
179 lcd_set_drawmode(mode
);
180 current_vp
->fg_pattern
= fg_color
;
181 current_vp
->bg_pattern
= bg_color
;
184 int lcd_getwidth(void)
186 return current_vp
->width
;
189 int lcd_getheight(void)
191 return current_vp
->height
;
194 void lcd_setfont(int newfont
)
196 current_vp
->font
= newfont
;
199 int lcd_getfont(void)
201 return current_vp
->font
;
204 int lcd_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 #define LCDADDR(x, y) (&lcd_framebuffer[0][0] + LCD_HEIGHT*(x) + (y))
213 static void ICODE_ATTR
setpixel(fb_data
*address
)
215 *address
= current_vp
->fg_pattern
;
218 static void ICODE_ATTR
clearpixel(fb_data
*address
)
220 *address
= current_vp
->bg_pattern
;
223 static void ICODE_ATTR
clearimgpixel(fb_data
*address
)
225 *address
= *(fb_data
*)((long)address
+ lcd_backdrop_offset
);
228 static void ICODE_ATTR
flippixel(fb_data
*address
)
230 *address
= ~(*address
);
233 static void ICODE_ATTR
nopixel(fb_data
*address
)
238 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_bgcolor
[8] = {
239 flippixel
, nopixel
, setpixel
, setpixel
,
240 nopixel
, clearpixel
, nopixel
, clearpixel
243 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_backdrop
[8] = {
244 flippixel
, nopixel
, setpixel
, setpixel
,
245 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
248 lcd_fastpixelfunc_type
* const * lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
250 void lcd_set_backdrop(fb_data
* backdrop
)
252 lcd_backdrop
= backdrop
;
255 lcd_backdrop_offset
= (long)backdrop
- (long)&lcd_framebuffer
[0][0];
256 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_backdrop
;
260 lcd_backdrop_offset
= 0;
261 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
265 fb_data
* lcd_get_backdrop(void)
270 /*** drawing functions ***/
272 /* Clear the current viewport */
273 void lcd_clear_viewport(void)
275 fb_data
*dst
, *dst_end
;
277 dst
= LCDADDR(current_vp
->x
, current_vp
->y
);
278 dst_end
= dst
+ current_vp
->width
* LCD_HEIGHT
;
280 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
284 memset16(dst
, current_vp
->fg_pattern
, current_vp
->height
);
287 while (dst
< dst_end
);
295 memset16(dst
, current_vp
->bg_pattern
, current_vp
->height
);
298 while (dst
< dst_end
);
304 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
305 current_vp
->height
* sizeof(fb_data
));
308 while (dst
< dst_end
);
312 if (current_vp
== &default_vp
)
314 lcd_scroll_info
.lines
= 0;
318 lcd_scroll_stop(current_vp
);
322 /* Clear the whole display */
323 void lcd_clear_display(void)
325 struct viewport
* old_vp
= current_vp
;
327 current_vp
= &default_vp
;
329 lcd_clear_viewport();
334 /* Set a single pixel */
335 void lcd_drawpixel(int x
, int y
)
337 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
338 && ((unsigned)y
< (unsigned)current_vp
->height
)
339 #if defined(HAVE_VIEWPORT_CLIP)
340 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
341 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
344 lcd_fastpixelfuncs
[current_vp
->drawmode
](LCDADDR(current_vp
->x
+x
, current_vp
->y
+y
));
348 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
356 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
358 deltay
= abs(y2
- y1
);
361 /* DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n"); */
362 lcd_hline(x1
, x2
, y1
);
365 deltax
= abs(x2
- x1
);
368 /* DEBUGF("lcd_drawline() called for vertical line - optimisation.\n"); */
369 lcd_vline(x1
, y1
, y2
);
375 if (deltax
>= deltay
)
378 d
= 2 * deltay
- deltax
;
380 dinc2
= (deltay
- deltax
) * 2;
387 d
= 2 * deltax
- deltay
;
389 dinc2
= (deltax
- deltay
) * 2;
393 numpixels
++; /* include endpoints */
410 for (i
= 0; i
< numpixels
; i
++)
412 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
413 && ((unsigned)y
< (unsigned)current_vp
->height
)
414 #if defined(HAVE_VIEWPORT_CLIP)
415 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
416 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
419 pfunc(LCDADDR(x
+ current_vp
->x
, y
+ current_vp
->y
));
436 /* Draw a horizontal line (optimised) */
437 void lcd_hline(int x1
, int x2
, int y
)
440 fb_data
*dst
, *dst_end
;
441 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
451 /******************** In viewport clipping **********************/
452 /* nothing to draw? */
453 if (((unsigned)y
>= (unsigned)current_vp
->height
) ||
454 (x1
>= current_vp
->width
) ||
460 if (x2
>= current_vp
->width
)
461 x2
= current_vp
->width
-1;
463 /* Adjust x1 and y to viewport */
468 #if defined(HAVE_VIEWPORT_CLIP)
469 /********************* Viewport on screen clipping ********************/
470 /* nothing to draw? */
471 if (((unsigned)y
>= (unsigned) LCD_HEIGHT
) || (x1
>= LCD_WIDTH
)
482 dst
= LCDADDR(x1
, y
);
483 dst_end
= dst
+ (x2
- x1
) * LCD_HEIGHT
;
490 while (dst
<= dst_end
);
493 /* Draw a vertical line (optimised) */
494 void lcd_vline(int x
, int y1
, int y2
)
498 enum fill_opt fillopt
= OPT_NONE
;
499 fb_data
*dst
, *dst_end
;
509 /******************** In viewport clipping **********************/
510 /* nothing to draw? */
511 if (((unsigned)x
>= (unsigned)current_vp
->width
) ||
512 (y1
>= current_vp
->height
) ||
518 if (y2
>= current_vp
->height
)
519 y2
= current_vp
->height
-1;
521 /* adjust for viewport */
526 #if defined(HAVE_VIEWPORT_CLIP)
527 /********************* Viewport on screen clipping ********************/
528 /* nothing to draw? */
529 if (( (unsigned) x
>= (unsigned)LCD_WIDTH
) || (y1
>= LCD_HEIGHT
)
536 if (y2
>= LCD_HEIGHT
)
540 height
= y2
- y1
+ 1;
542 /* drawmode and optimisation */
543 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
545 if (current_vp
->drawmode
& DRMODE_BG
)
550 bits
= current_vp
->bg_pattern
;
558 if (current_vp
->drawmode
& DRMODE_FG
)
561 bits
= current_vp
->fg_pattern
;
564 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
567 dst
= LCDADDR(x
, y1
);
572 memset16(dst
, bits
, height
);
576 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
577 height
* sizeof(fb_data
));
580 case OPT_NONE
: /* DRMODE_COMPLEMENT */
581 dst_end
= dst
+ height
;
584 while (++dst
< dst_end
);
589 /* Draw a rectangular box */
590 void lcd_drawrect(int x
, int y
, int width
, int height
)
592 if ((width
<= 0) || (height
<= 0))
595 int x2
= x
+ width
- 1;
596 int y2
= y
+ height
- 1;
599 lcd_vline(x2
, y
, y2
);
601 lcd_hline(x
, x2
, y2
);
604 /* Fill a rectangular area */
605 void lcd_fillrect(int x
, int y
, int width
, int height
)
608 enum fill_opt fillopt
= OPT_NONE
;
609 fb_data
*dst
, *dst_end
;
611 /******************** In viewport clipping **********************/
612 /* nothing to draw? */
613 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
614 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
627 if (x
+ width
> current_vp
->width
)
628 width
= current_vp
->width
- x
;
629 if (y
+ height
> current_vp
->height
)
630 height
= current_vp
->height
- y
;
632 /* adjust for viewport */
636 #if defined(HAVE_VIEWPORT_CLIP)
637 /********************* Viewport on screen clipping ********************/
638 /* nothing to draw? */
639 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
640 || (x
+ width
<= 0) || (y
+ height
<= 0))
643 /* clip image in viewport in screen */
654 if (x
+ width
> LCD_WIDTH
)
655 width
= LCD_WIDTH
- x
;
656 if (y
+ height
> LCD_HEIGHT
)
657 height
= LCD_HEIGHT
- y
;
660 /* drawmode and optimisation */
661 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
663 if (current_vp
->drawmode
& DRMODE_BG
)
668 bits
= current_vp
->bg_pattern
;
676 if (current_vp
->drawmode
& DRMODE_FG
)
679 bits
= current_vp
->fg_pattern
;
682 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
686 dst_end
= dst
+ width
* LCD_HEIGHT
;
690 fb_data
*dst_col
, *col_end
;
695 memset16(dst
, bits
, height
);
699 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
700 height
* sizeof(fb_data
));
703 case OPT_NONE
: /* DRMODE_COMPLEMENT */
705 col_end
= dst_col
+ height
;
707 *dst_col
= ~(*dst_col
);
708 while (++dst_col
< col_end
);
713 while (dst
< dst_end
);
716 /* About Rockbox' internal monochrome bitmap format:
718 * A bitmap contains one bit for every pixel that defines if that pixel is
719 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
721 * The bytes are stored in row-major order, with byte 0 being top left,
722 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
723 * 0..7, the second row defines pixel row 8..15 etc.
725 * This is the mono bitmap format used on all other targets so far; the
726 * pixel packing doesn't really matter on a 8bit+ target. */
728 /* Draw a partial monochrome bitmap */
730 void ICODE_ATTR
lcd_mono_bitmap_part(const unsigned char *src
, int src_x
,
731 int src_y
, int stride
, int x
, int y
,
732 int width
, int height
)
734 const unsigned char *src_end
;
735 fb_data
*dst
, *dst_end
;
736 unsigned dmask
= 0x100; /* bit 8 == sentinel */
737 int drmode
= current_vp
->drawmode
;
739 /******************** Image in viewport clipping **********************/
740 /* nothing to draw? */
741 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
742 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
757 if (x
+ width
> current_vp
->width
)
758 width
= current_vp
->width
- x
;
759 if (y
+ height
> current_vp
->height
)
760 height
= current_vp
->height
- y
;
762 /* adjust for viewport */
766 #if defined(HAVE_VIEWPORT_CLIP)
767 /********************* Viewport on screen clipping ********************/
768 /* nothing to draw? */
769 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
770 || (x
+ width
<= 0) || (y
+ height
<= 0))
773 /* clip image in viewport in screen */
786 if (x
+ width
> LCD_WIDTH
)
787 width
= LCD_WIDTH
- x
;
788 if (y
+ height
> LCD_HEIGHT
)
789 height
= LCD_HEIGHT
- y
;
792 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
794 src_end
= src
+ width
;
796 dst_end
= dst
+ height
;
798 if (drmode
& DRMODE_INVERSEVID
)
800 dmask
= 0x1ff; /* bit 8 == sentinel */
801 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
806 const unsigned char *src_col
= src
++;
807 unsigned data
= (*src_col
^ dmask
) >> src_y
;
808 fb_data
*dst_col
= dst
;
812 #define UPDATE_SRC do { \
814 if (data == 0x001) { \
816 data = *src_col ^ dmask; \
822 case DRMODE_COMPLEMENT
:
826 *dst_col
= ~(*dst_col
);
831 while (dst_col
< dst_end
);
837 bo
= lcd_backdrop_offset
;
841 *dst_col
= *(fb_data
*)((long)dst_col
+ bo
);
846 while (dst_col
< dst_end
);
850 bg
= current_vp
->bg_pattern
;
859 while (dst_col
< dst_end
);
864 fg
= current_vp
->fg_pattern
;
873 while (dst_col
< dst_end
);
877 fg
= current_vp
->fg_pattern
;
880 bo
= lcd_backdrop_offset
;
883 *dst_col
= (data
& 0x01) ? fg
884 : *(fb_data
*)((long)dst_col
+ bo
);
888 while (dst_col
< dst_end
);
892 bg
= current_vp
->bg_pattern
;
895 *dst_col
= (data
& 0x01) ? fg
: bg
;
899 while (dst_col
< dst_end
);
905 dst_end
+= LCD_HEIGHT
;
906 } while (src
< src_end
);
908 /* Draw a full monochrome bitmap */
909 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
911 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
914 /* Draw a partial native bitmap */
915 void ICODE_ATTR
lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
916 int stride
, int x
, int y
, int width
,
919 fb_data
*dst
, *dst_end
;
921 /******************** Image in viewport clipping **********************/
922 /* nothing to draw? */
923 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
924 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
940 if (x
+ width
> current_vp
->width
)
941 width
= current_vp
->width
- x
;
942 if (y
+ height
> current_vp
->height
)
943 height
= current_vp
->height
- y
;
945 /* adjust for viewport */
949 #if defined(HAVE_VIEWPORT_CLIP)
950 /********************* Viewport on screen clipping ********************/
951 /* nothing to draw? */
952 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
953 || (x
+ width
<= 0) || (y
+ height
<= 0))
956 /* clip image in viewport in screen */
969 if (x
+ width
> LCD_WIDTH
)
970 width
= LCD_WIDTH
- x
;
971 if (y
+ height
> LCD_HEIGHT
)
972 height
= LCD_HEIGHT
- y
;
975 src
+= stride
* src_x
+ src_y
; /* move starting point */
977 dst_end
= dst
+ width
* LCD_HEIGHT
;
981 memcpy(dst
, src
, height
* sizeof(fb_data
));
985 while (dst
< dst_end
);
988 /* Draw a full native bitmap */
989 void lcd_bitmap(const fb_data
*src
, int x
, int y
, int width
, int height
)
991 lcd_bitmap_part(src
, 0, 0, STRIDE(SCREEN_MAIN
, width
, height
), x
, y
, width
, height
);
994 #if !defined(TOSHIBA_GIGABEAT_F) && !defined(TOSHIBA_GIGABEAT_S) \
995 || defined(SIMULATOR)
996 /* Draw a partial native bitmap */
997 void ICODE_ATTR
lcd_bitmap_transparent_part(const fb_data
*src
, int src_x
,
998 int src_y
, int stride
, int x
,
999 int y
, int width
, int height
)
1001 fb_data
*dst
, *dst_end
;
1003 /******************** Image in viewport clipping **********************/
1004 /* nothing to draw? */
1005 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
1006 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
1022 if (x
+ width
> current_vp
->width
)
1023 width
= current_vp
->width
- x
;
1024 if (y
+ height
> current_vp
->height
)
1025 height
= current_vp
->height
- y
;
1027 /* adjust for viewport */
1031 #if defined(HAVE_VIEWPORT_CLIP)
1032 /********************* Viewport on screen clipping ********************/
1033 /* nothing to draw? */
1034 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
1035 || (x
+ width
<= 0) || (y
+ height
<= 0))
1038 /* clip image in viewport in screen */
1051 if (x
+ width
> LCD_WIDTH
)
1052 width
= LCD_WIDTH
- x
;
1053 if (y
+ height
> LCD_HEIGHT
)
1054 height
= LCD_HEIGHT
- y
;
1057 src
+= stride
* src_x
+ src_y
; /* move starting point */
1058 dst
= LCDADDR(x
, y
);
1059 dst_end
= dst
+ width
* LCD_HEIGHT
;
1064 for(i
= 0;i
< height
;i
++)
1066 if (src
[i
] == REPLACEWITHFG_COLOR
)
1067 dst
[i
] = current_vp
->fg_pattern
;
1068 else if(src
[i
] != TRANSPARENT_COLOR
)
1074 while (dst
< dst_end
);
1076 #endif /* !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR) */
1078 /* Draw a full native bitmap with a transparent color */
1079 void lcd_bitmap_transparent(const fb_data
*src
, int x
, int y
,
1080 int width
, int height
)
1082 lcd_bitmap_transparent_part(src
, 0, 0,
1083 STRIDE(SCREEN_MAIN
, width
, height
), x
, y
, width
, height
);
1086 #include "lcd-bitmap-common.c"