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 ****************************************************************************/
31 #include "string-extra.h" /* mem*() */
36 #include "rbunicode.h"
38 #include "scroll_engine.h"
47 fb_data lcd_framebuffer
[LCD_FBHEIGHT
][LCD_FBWIDTH
]
48 IRAM_LCDFRAMEBUFFER
CACHEALIGN_AT_LEAST_ATTR(16);
51 static fb_data
* lcd_backdrop
= NULL
;
52 static long lcd_backdrop_offset IDATA_ATTR
= 0;
54 static struct viewport default_vp
=
60 .font
= FONT_SYSFIXED
,
61 .drawmode
= DRMODE_SOLID
,
62 .fg_pattern
= LCD_DEFAULT_FG
,
63 .bg_pattern
= LCD_DEFAULT_BG
,
64 .lss_pattern
= LCD_DEFAULT_BG
,
65 .lse_pattern
= LCD_DEFAULT_BG
,
66 .lst_pattern
= LCD_DEFAULT_BG
,
69 /* The Gigabeat target build requires access to the current fg_pattern
71 #if defined(SIMULATOR)
72 static struct viewport
* current_vp IDATA_ATTR
= &default_vp
;
74 struct viewport
* current_vp IDATA_ATTR
= &default_vp
;
82 /* Call device specific init */
88 void lcd_set_viewport(struct viewport
* vp
)
91 current_vp
= &default_vp
;
95 #if defined(SIMULATOR)
96 /* Force the viewport to be within bounds. If this happens it should
97 * be considered an error - the viewport will not draw as it might be
100 if((unsigned) current_vp
->x
> (unsigned) LCD_WIDTH
101 || (unsigned) current_vp
->y
> (unsigned) LCD_HEIGHT
102 || current_vp
->x
+ current_vp
->width
> LCD_WIDTH
103 || current_vp
->y
+ current_vp
->height
> LCD_HEIGHT
)
105 #if !defined(HAVE_VIEWPORT_CLIP)
110 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
111 current_vp
->x
, current_vp
->y
,
112 current_vp
->width
, current_vp
->height
);
118 void lcd_update_viewport(void)
120 lcd_update_rect(current_vp
->x
, current_vp
->y
,
121 current_vp
->width
, current_vp
->height
);
124 void lcd_update_viewport_rect(int x
, int y
, int width
, int height
)
126 lcd_update_rect(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
129 /*** parameter handling ***/
131 void lcd_set_drawmode(int mode
)
133 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
136 int lcd_get_drawmode(void)
138 return current_vp
->drawmode
;
141 void lcd_set_foreground(unsigned color
)
143 current_vp
->fg_pattern
= color
;
146 unsigned lcd_get_foreground(void)
148 return current_vp
->fg_pattern
;
151 void lcd_set_background(unsigned color
)
153 current_vp
->bg_pattern
= color
;
156 unsigned lcd_get_background(void)
158 return current_vp
->bg_pattern
;
161 void lcd_set_selector_start(unsigned color
)
163 current_vp
->lss_pattern
= color
;
166 void lcd_set_selector_end(unsigned color
)
168 current_vp
->lse_pattern
= color
;
171 void lcd_set_selector_text(unsigned color
)
173 current_vp
->lst_pattern
= color
;
176 void lcd_set_drawinfo(int mode
, unsigned fg_color
, unsigned bg_color
)
178 lcd_set_drawmode(mode
);
179 current_vp
->fg_pattern
= fg_color
;
180 current_vp
->bg_pattern
= bg_color
;
183 int lcd_getwidth(void)
185 return current_vp
->width
;
188 int lcd_getheight(void)
190 return current_vp
->height
;
193 void lcd_setfont(int newfont
)
195 current_vp
->font
= newfont
;
198 int lcd_getfont(void)
200 return current_vp
->font
;
203 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
205 return font_getstringsize(str
, w
, h
, current_vp
->font
);
208 /*** low-level drawing functions ***/
210 #define LCDADDR(x, y) (&lcd_framebuffer[0][0] + LCD_HEIGHT*(x) + (y))
212 static void ICODE_ATTR
setpixel(fb_data
*address
)
214 *address
= current_vp
->fg_pattern
;
217 static void ICODE_ATTR
clearpixel(fb_data
*address
)
219 *address
= current_vp
->bg_pattern
;
222 static void ICODE_ATTR
clearimgpixel(fb_data
*address
)
224 *address
= *(fb_data
*)((long)address
+ lcd_backdrop_offset
);
227 static void ICODE_ATTR
flippixel(fb_data
*address
)
229 *address
= ~(*address
);
232 static void ICODE_ATTR
nopixel(fb_data
*address
)
237 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_bgcolor
[8] = {
238 flippixel
, nopixel
, setpixel
, setpixel
,
239 nopixel
, clearpixel
, nopixel
, clearpixel
242 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_backdrop
[8] = {
243 flippixel
, nopixel
, setpixel
, setpixel
,
244 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
247 lcd_fastpixelfunc_type
* const * lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
249 void lcd_set_backdrop(fb_data
* backdrop
)
251 lcd_backdrop
= backdrop
;
254 lcd_backdrop_offset
= (long)backdrop
- (long)&lcd_framebuffer
[0][0];
255 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_backdrop
;
259 lcd_backdrop_offset
= 0;
260 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
264 fb_data
* lcd_get_backdrop(void)
269 /*** drawing functions ***/
271 /* Clear the current viewport */
272 void lcd_clear_viewport(void)
274 fb_data
*dst
, *dst_end
;
276 dst
= LCDADDR(current_vp
->x
, current_vp
->y
);
277 dst_end
= dst
+ current_vp
->width
* LCD_HEIGHT
;
279 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
283 memset16(dst
, current_vp
->fg_pattern
, current_vp
->height
);
286 while (dst
< dst_end
);
294 memset16(dst
, current_vp
->bg_pattern
, current_vp
->height
);
297 while (dst
< dst_end
);
303 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
304 current_vp
->height
* sizeof(fb_data
));
307 while (dst
< dst_end
);
311 if (current_vp
== &default_vp
)
313 lcd_scroll_info
.lines
= 0;
317 lcd_scroll_stop(current_vp
);
321 /* Clear the whole display */
322 void lcd_clear_display(void)
324 struct viewport
* old_vp
= current_vp
;
326 current_vp
= &default_vp
;
328 lcd_clear_viewport();
333 /* Set a single pixel */
334 void lcd_drawpixel(int x
, int y
)
336 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
337 && ((unsigned)y
< (unsigned)current_vp
->height
)
338 #if defined(HAVE_VIEWPORT_CLIP)
339 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
340 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
343 lcd_fastpixelfuncs
[current_vp
->drawmode
](LCDADDR(current_vp
->x
+x
, current_vp
->y
+y
));
347 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
355 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
357 deltay
= abs(y2
- y1
);
360 /* DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n"); */
361 lcd_hline(x1
, x2
, y1
);
364 deltax
= abs(x2
- x1
);
367 /* DEBUGF("lcd_drawline() called for vertical line - optimisation.\n"); */
368 lcd_vline(x1
, y1
, y2
);
374 if (deltax
>= deltay
)
377 d
= 2 * deltay
- deltax
;
379 dinc2
= (deltay
- deltax
) * 2;
386 d
= 2 * deltax
- deltay
;
388 dinc2
= (deltax
- deltay
) * 2;
392 numpixels
++; /* include endpoints */
409 for (i
= 0; i
< numpixels
; i
++)
411 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
412 && ((unsigned)y
< (unsigned)current_vp
->height
)
413 #if defined(HAVE_VIEWPORT_CLIP)
414 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
415 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
418 pfunc(LCDADDR(x
+ current_vp
->x
, y
+ current_vp
->y
));
435 /* Draw a horizontal line (optimised) */
436 void lcd_hline(int x1
, int x2
, int y
)
439 fb_data
*dst
, *dst_end
;
440 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
450 /******************** In viewport clipping **********************/
451 /* nothing to draw? */
452 if (((unsigned)y
>= (unsigned)current_vp
->height
) ||
453 (x1
>= current_vp
->width
) ||
459 if (x2
>= current_vp
->width
)
460 x2
= current_vp
->width
-1;
462 /* Adjust x1 and y to viewport */
467 #if defined(HAVE_VIEWPORT_CLIP)
468 /********************* Viewport on screen clipping ********************/
469 /* nothing to draw? */
470 if (((unsigned)y
>= (unsigned) LCD_HEIGHT
) || (x1
>= LCD_WIDTH
)
481 dst
= LCDADDR(x1
, y
);
482 dst_end
= dst
+ (x2
- x1
) * LCD_HEIGHT
;
489 while (dst
<= dst_end
);
492 /* Draw a vertical line (optimised) */
493 void lcd_vline(int x
, int y1
, int y2
)
497 enum fill_opt fillopt
= OPT_NONE
;
498 fb_data
*dst
, *dst_end
;
508 /******************** In viewport clipping **********************/
509 /* nothing to draw? */
510 if (((unsigned)x
>= (unsigned)current_vp
->width
) ||
511 (y1
>= current_vp
->height
) ||
517 if (y2
>= current_vp
->height
)
518 y2
= current_vp
->height
-1;
520 /* adjust for viewport */
525 #if defined(HAVE_VIEWPORT_CLIP)
526 /********************* Viewport on screen clipping ********************/
527 /* nothing to draw? */
528 if (( (unsigned) x
>= (unsigned)LCD_WIDTH
) || (y1
>= LCD_HEIGHT
)
535 if (y2
>= LCD_HEIGHT
)
539 height
= y2
- y1
+ 1;
541 /* drawmode and optimisation */
542 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
544 if (current_vp
->drawmode
& DRMODE_BG
)
549 bits
= current_vp
->bg_pattern
;
557 if (current_vp
->drawmode
& DRMODE_FG
)
560 bits
= current_vp
->fg_pattern
;
563 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
566 dst
= LCDADDR(x
, y1
);
571 memset16(dst
, bits
, height
);
575 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
576 height
* sizeof(fb_data
));
579 case OPT_NONE
: /* DRMODE_COMPLEMENT */
580 dst_end
= dst
+ height
;
583 while (++dst
< dst_end
);
588 /* Draw a rectangular box */
589 void lcd_drawrect(int x
, int y
, int width
, int height
)
591 if ((width
<= 0) || (height
<= 0))
594 int x2
= x
+ width
- 1;
595 int y2
= y
+ height
- 1;
598 lcd_vline(x2
, y
, y2
);
600 lcd_hline(x
, x2
, y2
);
603 /* Fill a rectangular area */
604 void lcd_fillrect(int x
, int y
, int width
, int height
)
607 enum fill_opt fillopt
= OPT_NONE
;
608 fb_data
*dst
, *dst_end
;
610 /******************** In viewport clipping **********************/
611 /* nothing to draw? */
612 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
613 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
626 if (x
+ width
> current_vp
->width
)
627 width
= current_vp
->width
- x
;
628 if (y
+ height
> current_vp
->height
)
629 height
= current_vp
->height
- y
;
631 /* adjust for viewport */
635 #if defined(HAVE_VIEWPORT_CLIP)
636 /********************* Viewport on screen clipping ********************/
637 /* nothing to draw? */
638 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
639 || (x
+ width
<= 0) || (y
+ height
<= 0))
642 /* clip image in viewport in screen */
653 if (x
+ width
> LCD_WIDTH
)
654 width
= LCD_WIDTH
- x
;
655 if (y
+ height
> LCD_HEIGHT
)
656 height
= LCD_HEIGHT
- y
;
659 /* drawmode and optimisation */
660 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
662 if (current_vp
->drawmode
& DRMODE_BG
)
667 bits
= current_vp
->bg_pattern
;
675 if (current_vp
->drawmode
& DRMODE_FG
)
678 bits
= current_vp
->fg_pattern
;
681 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
685 dst_end
= dst
+ width
* LCD_HEIGHT
;
689 fb_data
*dst_col
, *col_end
;
694 memset16(dst
, bits
, height
);
698 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
699 height
* sizeof(fb_data
));
702 case OPT_NONE
: /* DRMODE_COMPLEMENT */
704 col_end
= dst_col
+ height
;
706 *dst_col
= ~(*dst_col
);
707 while (++dst_col
< col_end
);
712 while (dst
< dst_end
);
715 /* About Rockbox' internal monochrome bitmap format:
717 * A bitmap contains one bit for every pixel that defines if that pixel is
718 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
720 * The bytes are stored in row-major order, with byte 0 being top left,
721 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
722 * 0..7, the second row defines pixel row 8..15 etc.
724 * This is the mono bitmap format used on all other targets so far; the
725 * pixel packing doesn't really matter on a 8bit+ target. */
727 /* Draw a partial monochrome bitmap */
729 void ICODE_ATTR
lcd_mono_bitmap_part(const unsigned char *src
, int src_x
,
730 int src_y
, int stride
, int x
, int y
,
731 int width
, int height
)
733 const unsigned char *src_end
;
734 fb_data
*dst
, *dst_end
;
735 unsigned dmask
= 0x100; /* bit 8 == sentinel */
736 int drmode
= current_vp
->drawmode
;
738 /******************** Image in viewport clipping **********************/
739 /* nothing to draw? */
740 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
741 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
756 if (x
+ width
> current_vp
->width
)
757 width
= current_vp
->width
- x
;
758 if (y
+ height
> current_vp
->height
)
759 height
= current_vp
->height
- y
;
761 /* adjust for viewport */
765 #if defined(HAVE_VIEWPORT_CLIP)
766 /********************* Viewport on screen clipping ********************/
767 /* nothing to draw? */
768 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
769 || (x
+ width
<= 0) || (y
+ height
<= 0))
772 /* clip image in viewport in screen */
785 if (x
+ width
> LCD_WIDTH
)
786 width
= LCD_WIDTH
- x
;
787 if (y
+ height
> LCD_HEIGHT
)
788 height
= LCD_HEIGHT
- y
;
791 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
793 src_end
= src
+ width
;
795 dst_end
= dst
+ height
;
797 if (drmode
& DRMODE_INVERSEVID
)
799 dmask
= 0x1ff; /* bit 8 == sentinel */
800 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
805 const unsigned char *src_col
= src
++;
806 unsigned data
= (*src_col
^ dmask
) >> src_y
;
807 fb_data
*dst_col
= dst
;
811 #define UPDATE_SRC do { \
813 if (data == 0x001) { \
815 data = *src_col ^ dmask; \
821 case DRMODE_COMPLEMENT
:
825 *dst_col
= ~(*dst_col
);
830 while (dst_col
< dst_end
);
836 bo
= lcd_backdrop_offset
;
840 *dst_col
= *(fb_data
*)((long)dst_col
+ bo
);
845 while (dst_col
< dst_end
);
849 bg
= current_vp
->bg_pattern
;
858 while (dst_col
< dst_end
);
863 fg
= current_vp
->fg_pattern
;
872 while (dst_col
< dst_end
);
876 fg
= current_vp
->fg_pattern
;
879 bo
= lcd_backdrop_offset
;
882 *dst_col
= (data
& 0x01) ? fg
883 : *(fb_data
*)((long)dst_col
+ bo
);
887 while (dst_col
< dst_end
);
891 bg
= current_vp
->bg_pattern
;
894 *dst_col
= (data
& 0x01) ? fg
: bg
;
898 while (dst_col
< dst_end
);
904 dst_end
+= LCD_HEIGHT
;
905 } while (src
< src_end
);
907 /* Draw a full monochrome bitmap */
908 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
910 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
913 /* Draw a partial native bitmap */
914 void ICODE_ATTR
lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
915 int stride
, int x
, int y
, int width
,
918 fb_data
*dst
, *dst_end
;
920 /******************** Image in viewport clipping **********************/
921 /* nothing to draw? */
922 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
923 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
939 if (x
+ width
> current_vp
->width
)
940 width
= current_vp
->width
- x
;
941 if (y
+ height
> current_vp
->height
)
942 height
= current_vp
->height
- y
;
944 /* adjust for viewport */
948 #if defined(HAVE_VIEWPORT_CLIP)
949 /********************* Viewport on screen clipping ********************/
950 /* nothing to draw? */
951 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
952 || (x
+ width
<= 0) || (y
+ height
<= 0))
955 /* clip image in viewport in screen */
968 if (x
+ width
> LCD_WIDTH
)
969 width
= LCD_WIDTH
- x
;
970 if (y
+ height
> LCD_HEIGHT
)
971 height
= LCD_HEIGHT
- y
;
974 src
+= stride
* src_x
+ src_y
; /* move starting point */
976 dst_end
= dst
+ width
* LCD_HEIGHT
;
980 memcpy(dst
, src
, height
* sizeof(fb_data
));
984 while (dst
< dst_end
);
987 /* Draw a full native bitmap */
988 void lcd_bitmap(const fb_data
*src
, int x
, int y
, int width
, int height
)
990 lcd_bitmap_part(src
, 0, 0, STRIDE(SCREEN_MAIN
, width
, height
), x
, y
, width
, height
);
993 #if !defined(TOSHIBA_GIGABEAT_F) && !defined(TOSHIBA_GIGABEAT_S) \
994 || defined(SIMULATOR)
995 /* Draw a partial native bitmap */
996 void ICODE_ATTR
lcd_bitmap_transparent_part(const fb_data
*src
, int src_x
,
997 int src_y
, int stride
, int x
,
998 int y
, int width
, int height
)
1000 fb_data
*dst
, *dst_end
;
1002 /******************** Image in viewport clipping **********************/
1003 /* nothing to draw? */
1004 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
1005 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
1021 if (x
+ width
> current_vp
->width
)
1022 width
= current_vp
->width
- x
;
1023 if (y
+ height
> current_vp
->height
)
1024 height
= current_vp
->height
- y
;
1026 /* adjust for viewport */
1030 #if defined(HAVE_VIEWPORT_CLIP)
1031 /********************* Viewport on screen clipping ********************/
1032 /* nothing to draw? */
1033 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
1034 || (x
+ width
<= 0) || (y
+ height
<= 0))
1037 /* clip image in viewport in screen */
1050 if (x
+ width
> LCD_WIDTH
)
1051 width
= LCD_WIDTH
- x
;
1052 if (y
+ height
> LCD_HEIGHT
)
1053 height
= LCD_HEIGHT
- y
;
1056 src
+= stride
* src_x
+ src_y
; /* move starting point */
1057 dst
= LCDADDR(x
, y
);
1058 dst_end
= dst
+ width
* LCD_HEIGHT
;
1063 for(i
= 0;i
< height
;i
++)
1065 if (src
[i
] == REPLACEWITHFG_COLOR
)
1066 dst
[i
] = current_vp
->fg_pattern
;
1067 else if(src
[i
] != TRANSPARENT_COLOR
)
1073 while (dst
< dst_end
);
1075 #endif /* !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR) */
1077 /* Draw a full native bitmap with a transparent color */
1078 void lcd_bitmap_transparent(const fb_data
*src
, int x
, int y
,
1079 int width
, int height
)
1081 lcd_bitmap_transparent_part(src
, 0, 0,
1082 STRIDE(SCREEN_MAIN
, width
, height
), x
, y
, width
, height
);
1085 #include "lcd-bitmap-common.c"