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 * 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"
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(TOSHIBA_GIGABEAT_F)&& !defined(TOSHIBA_GIGABEAT_S)) || 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
;
96 void lcd_update_viewport(void)
98 lcd_update_rect(current_vp
->x
, current_vp
->y
,
99 current_vp
->width
, current_vp
->height
);
102 void lcd_update_viewport_rect(int x
, int y
, int width
, int height
)
104 lcd_update_rect(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
107 /*** parameter handling ***/
109 void lcd_set_drawmode(int mode
)
111 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
114 int lcd_get_drawmode(void)
116 return current_vp
->drawmode
;
119 void lcd_set_foreground(unsigned color
)
121 current_vp
->fg_pattern
= color
;
124 unsigned lcd_get_foreground(void)
126 return current_vp
->fg_pattern
;
129 void lcd_set_background(unsigned color
)
131 current_vp
->bg_pattern
= color
;
134 unsigned lcd_get_background(void)
136 return current_vp
->bg_pattern
;
139 void lcd_set_selector_start(unsigned color
)
141 current_vp
->lss_pattern
= color
;
144 void lcd_set_selector_end(unsigned color
)
146 current_vp
->lse_pattern
= color
;
149 void lcd_set_selector_text(unsigned color
)
151 current_vp
->lst_pattern
= color
;
154 void lcd_set_drawinfo(int mode
, unsigned fg_color
, unsigned bg_color
)
156 lcd_set_drawmode(mode
);
157 current_vp
->fg_pattern
= fg_color
;
158 current_vp
->bg_pattern
= bg_color
;
161 int lcd_getwidth(void)
163 return current_vp
->width
;
166 int lcd_getheight(void)
168 return current_vp
->height
;
171 void lcd_setfont(int newfont
)
173 current_vp
->font
= newfont
;
176 int lcd_getfont(void)
178 return current_vp
->font
;
181 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
183 return font_getstringsize(str
, w
, h
, current_vp
->font
);
186 /*** low-level drawing functions ***/
188 #define LCDADDR(x, y) (&lcd_framebuffer[(y)][(x)])
190 static void ICODE_ATTR
setpixel(fb_data
*address
)
192 *address
= current_vp
->fg_pattern
;
195 static void ICODE_ATTR
clearpixel(fb_data
*address
)
197 *address
= current_vp
->bg_pattern
;
200 static void ICODE_ATTR
clearimgpixel(fb_data
*address
)
202 *address
= *(fb_data
*)((long)address
+ lcd_backdrop_offset
);
205 static void ICODE_ATTR
flippixel(fb_data
*address
)
207 *address
= ~(*address
);
210 static void ICODE_ATTR
nopixel(fb_data
*address
)
215 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_bgcolor
[8] = {
216 flippixel
, nopixel
, setpixel
, setpixel
,
217 nopixel
, clearpixel
, nopixel
, clearpixel
220 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_backdrop
[8] = {
221 flippixel
, nopixel
, setpixel
, setpixel
,
222 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
225 lcd_fastpixelfunc_type
* const * lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
227 void lcd_set_backdrop(fb_data
* backdrop
)
229 lcd_backdrop
= backdrop
;
232 lcd_backdrop_offset
= (long)backdrop
- (long)&lcd_framebuffer
[0][0];
233 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_backdrop
;
237 lcd_backdrop_offset
= 0;
238 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
242 fb_data
* lcd_get_backdrop(void)
247 /*** drawing functions ***/
249 /* Clear the current viewport */
250 void lcd_clear_viewport(void)
252 fb_data
*dst
, *dst_end
;
254 dst
= LCDADDR(current_vp
->x
, current_vp
->y
);
255 dst_end
= dst
+ current_vp
->height
* LCD_WIDTH
;
257 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
261 memset16(dst
, current_vp
->fg_pattern
, current_vp
->width
);
264 while (dst
< dst_end
);
272 memset16(dst
, current_vp
->bg_pattern
, current_vp
->width
);
275 while (dst
< dst_end
);
281 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
282 current_vp
->width
* sizeof(fb_data
));
285 while (dst
< dst_end
);
289 if (current_vp
== &default_vp
)
291 lcd_scroll_info
.lines
= 0;
295 lcd_scroll_stop(current_vp
);
299 /* Clear the whole display */
300 void lcd_clear_display(void)
302 struct viewport
* old_vp
= current_vp
;
304 current_vp
= &default_vp
;
306 lcd_clear_viewport();
311 /* Set a single pixel */
312 void lcd_drawpixel(int x
, int y
)
314 if (((unsigned)x
< (unsigned)current_vp
->width
) &&
315 ((unsigned)y
< (unsigned)current_vp
->height
))
316 lcd_fastpixelfuncs
[current_vp
->drawmode
](LCDADDR(current_vp
->x
+x
, current_vp
->y
+y
));
320 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
328 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
330 deltay
= abs(y2
- y1
);
333 DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n");
334 lcd_hline(x1
, x2
, y1
);
337 deltax
= abs(x2
- x1
);
340 DEBUGF("lcd_drawline() called for vertical line - optimisation.\n");
341 lcd_vline(x1
, y1
, y2
);
347 if (deltax
>= deltay
)
350 d
= 2 * deltay
- deltax
;
352 dinc2
= (deltay
- deltax
) * 2;
359 d
= 2 * deltax
- deltay
;
361 dinc2
= (deltax
- deltay
) * 2;
365 numpixels
++; /* include endpoints */
382 for (i
= 0; i
< numpixels
; i
++)
384 if (((unsigned)x
< (unsigned)current_vp
->width
) && ((unsigned)y
< (unsigned)current_vp
->height
))
385 pfunc(LCDADDR(x
+ current_vp
->x
, y
+ current_vp
->y
));
402 /* Draw a horizontal line (optimised) */
403 void lcd_hline(int x1
, int x2
, int y
)
407 enum fill_opt fillopt
= OPT_NONE
;
408 fb_data
*dst
, *dst_end
;
418 /* nothing to draw? */
419 if (((unsigned)y
>= (unsigned)current_vp
->height
) ||
420 (x1
>= current_vp
->width
) ||
424 /* drawmode and optimisation */
425 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
427 if (current_vp
->drawmode
& DRMODE_BG
)
432 bits
= current_vp
->bg_pattern
;
440 if (current_vp
->drawmode
& DRMODE_FG
)
443 bits
= current_vp
->fg_pattern
;
446 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
452 if (x2
>= current_vp
->width
)
453 x2
= current_vp
->width
-1;
457 /* Adjust x1 and y to viewport */
461 dst
= LCDADDR(x1
, y
);
466 memset16(dst
, bits
, width
);
470 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
471 width
* sizeof(fb_data
));
474 case OPT_NONE
: /* DRMODE_COMPLEMENT */
475 dst_end
= dst
+ width
;
478 while (++dst
< dst_end
);
483 /* Draw a vertical line (optimised) */
484 void lcd_vline(int x
, int y1
, int y2
)
487 fb_data
*dst
, *dst_end
;
488 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
498 /* nothing to draw? */
499 if (((unsigned)x
>= (unsigned)current_vp
->width
) ||
500 (y1
>= current_vp
->height
) ||
507 if (y2
>= current_vp
->height
)
508 y2
= current_vp
->height
-1;
510 dst
= LCDADDR(x
+ current_vp
->x
, y1
+ current_vp
->y
);
511 dst_end
= dst
+ (y2
- y1
) * LCD_WIDTH
;
518 while (dst
<= dst_end
);
521 /* Draw a rectangular box */
522 void lcd_drawrect(int x
, int y
, int width
, int height
)
524 if ((width
<= 0) || (height
<= 0))
527 int x2
= x
+ width
- 1;
528 int y2
= y
+ height
- 1;
531 lcd_vline(x2
, y
, y2
);
533 lcd_hline(x
, x2
, y2
);
536 /* Fill a rectangular area */
537 void lcd_fillrect(int x
, int y
, int width
, int height
)
540 enum fill_opt fillopt
= OPT_NONE
;
541 fb_data
*dst
, *dst_end
;
543 /* nothing to draw? */
544 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
545 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
548 /* drawmode and optimisation */
549 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
551 if (current_vp
->drawmode
& DRMODE_BG
)
556 bits
= current_vp
->bg_pattern
;
564 if (current_vp
->drawmode
& DRMODE_FG
)
567 bits
= current_vp
->fg_pattern
;
570 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
584 if (x
+ width
> current_vp
->width
)
585 width
= current_vp
->width
- x
;
586 if (y
+ height
> current_vp
->height
)
587 height
= current_vp
->height
- y
;
589 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
590 dst_end
= dst
+ height
* LCD_WIDTH
;
594 fb_data
*dst_row
, *row_end
;
599 memset16(dst
, bits
, width
);
603 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
604 width
* sizeof(fb_data
));
607 case OPT_NONE
: /* DRMODE_COMPLEMENT */
609 row_end
= dst_row
+ width
;
611 *dst_row
= ~(*dst_row
);
612 while (++dst_row
< row_end
);
617 while (dst
< dst_end
);
620 /* About Rockbox' internal monochrome bitmap format:
622 * A bitmap contains one bit for every pixel that defines if that pixel is
623 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
625 * The bytes are stored in row-major order, with byte 0 being top left,
626 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
627 * 0..7, the second row defines pixel row 8..15 etc.
629 * This is the mono bitmap format used on all other targets so far; the
630 * pixel packing doesn't really matter on a 8bit+ target. */
632 /* Draw a partial monochrome bitmap */
634 void ICODE_ATTR
lcd_mono_bitmap_part(const unsigned char *src
, int src_x
,
635 int src_y
, int stride
, int x
, int y
,
636 int width
, int height
)
638 const unsigned char *src_end
;
639 fb_data
*dst
, *dst_end
;
640 unsigned dmask
= 0x100; /* bit 8 == sentinel */
641 int drmode
= current_vp
->drawmode
;
643 /* nothing to draw? */
644 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
645 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
661 if (x
+ width
> current_vp
->width
)
662 width
= current_vp
->width
- x
;
663 if (y
+ height
> current_vp
->height
)
664 height
= current_vp
->height
- y
;
666 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
668 src_end
= src
+ width
;
669 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
670 dst_end
= dst
+ height
* LCD_WIDTH
;
672 if (drmode
& DRMODE_INVERSEVID
)
674 dmask
= 0x1ff; /* bit 8 == sentinel */
675 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
680 const unsigned char *src_col
= src
++;
681 unsigned data
= (*src_col
^ dmask
) >> src_y
;
682 fb_data
*dst_col
= dst
++;
686 #define UPDATE_SRC do { \
688 if (data == 0x001) { \
690 data = *src_col ^ dmask; \
696 case DRMODE_COMPLEMENT
:
700 *dst_col
= ~(*dst_col
);
702 dst_col
+= LCD_WIDTH
;
705 while (dst_col
< dst_end
);
711 bo
= lcd_backdrop_offset
;
715 *dst_col
= *(fb_data
*)((long)dst_col
+ bo
);
717 dst_col
+= LCD_WIDTH
;
720 while (dst_col
< dst_end
);
724 bg
= current_vp
->bg_pattern
;
730 dst_col
+= LCD_WIDTH
;
733 while (dst_col
< dst_end
);
738 fg
= current_vp
->fg_pattern
;
744 dst_col
+= LCD_WIDTH
;
747 while (dst_col
< dst_end
);
751 fg
= current_vp
->fg_pattern
;
754 bo
= lcd_backdrop_offset
;
757 *dst_col
= (data
& 0x01) ? fg
758 : *(fb_data
*)((long)dst_col
+ bo
);
759 dst_col
+= LCD_WIDTH
;
762 while (dst_col
< dst_end
);
766 bg
= current_vp
->bg_pattern
;
769 *dst_col
= (data
& 0x01) ? fg
: bg
;
770 dst_col
+= LCD_WIDTH
;
773 while (dst_col
< dst_end
);
778 while (src
< src_end
);
780 /* Draw a full monochrome bitmap */
781 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
783 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
786 /* Draw a partial native bitmap */
787 void ICODE_ATTR
lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
788 int stride
, int x
, int y
, int width
,
791 fb_data
*dst
, *dst_end
;
793 /* nothing to draw? */
794 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
795 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
811 if (x
+ width
> current_vp
->width
)
812 width
= current_vp
->width
- x
;
813 if (y
+ height
> current_vp
->height
)
814 height
= current_vp
->height
- y
;
816 src
+= stride
* src_y
+ src_x
; /* move starting point */
817 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
818 dst_end
= dst
+ height
* LCD_WIDTH
;
822 memcpy(dst
, src
, width
* sizeof(fb_data
));
826 while (dst
< dst_end
);
829 /* Draw a full native bitmap */
830 void lcd_bitmap(const fb_data
*src
, int x
, int y
, int width
, int height
)
832 lcd_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
835 #if !defined(TOSHIBA_GIGABEAT_F) && !defined(TOSHIBA_GIGABEAT_S) \
836 || defined(SIMULATOR)
837 /* Draw a partial native bitmap */
838 void ICODE_ATTR
lcd_bitmap_transparent_part(const fb_data
*src
, int src_x
,
839 int src_y
, int stride
, int x
,
840 int y
, int width
, int height
)
842 fb_data
*dst
, *dst_end
;
844 /* nothing to draw? */
845 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
846 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
862 if (x
+ width
> current_vp
->width
)
863 width
= current_vp
->width
- x
;
864 if (y
+ height
> current_vp
->height
)
865 height
= current_vp
->height
- y
;
867 src
+= stride
* src_y
+ src_x
; /* move starting point */
868 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
869 dst_end
= dst
+ height
* LCD_WIDTH
;
874 for(i
= 0;i
< width
;i
++)
876 if (src
[i
] == REPLACEWITHFG_COLOR
)
877 dst
[i
] = current_vp
->fg_pattern
;
878 else if(src
[i
] != TRANSPARENT_COLOR
)
884 while (dst
< dst_end
);
886 #endif /* !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR) */
888 /* Draw a full native bitmap with a transparent color */
889 void lcd_bitmap_transparent(const fb_data
*src
, int x
, int y
,
890 int width
, int height
)
892 lcd_bitmap_transparent_part(src
, 0, 0, width
, x
, y
, width
, height
);
895 #include "lcd-bitmap-common.c"