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
;
97 void lcd_update_viewport(void)
99 lcd_update_rect(current_vp
->x
, current_vp
->y
,
100 current_vp
->width
, current_vp
->height
);
103 void lcd_update_viewport_rect(int x
, int y
, int width
, int height
)
105 lcd_update_rect(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
108 /*** parameter handling ***/
110 void lcd_set_drawmode(int mode
)
112 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
115 int lcd_get_drawmode(void)
117 return current_vp
->drawmode
;
120 void lcd_set_foreground(unsigned color
)
122 current_vp
->fg_pattern
= color
;
125 unsigned lcd_get_foreground(void)
127 return current_vp
->fg_pattern
;
130 void lcd_set_background(unsigned color
)
132 current_vp
->bg_pattern
= color
;
135 unsigned lcd_get_background(void)
137 return current_vp
->bg_pattern
;
140 void lcd_set_selector_start(unsigned color
)
142 current_vp
->lss_pattern
= color
;
145 void lcd_set_selector_end(unsigned color
)
147 current_vp
->lse_pattern
= color
;
150 void lcd_set_selector_text(unsigned color
)
152 current_vp
->lst_pattern
= color
;
155 void lcd_set_drawinfo(int mode
, unsigned fg_color
, unsigned bg_color
)
157 lcd_set_drawmode(mode
);
158 current_vp
->fg_pattern
= fg_color
;
159 current_vp
->bg_pattern
= bg_color
;
162 int lcd_getwidth(void)
164 return current_vp
->width
;
167 int lcd_getheight(void)
169 return current_vp
->height
;
172 void lcd_setfont(int newfont
)
174 current_vp
->font
= newfont
;
177 int lcd_getfont(void)
179 return current_vp
->font
;
182 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
184 return font_getstringsize(str
, w
, h
, current_vp
->font
);
187 /*** low-level drawing functions ***/
189 #define LCDADDR(x, y) (&lcd_framebuffer[0][0] + LCD_HEIGHT*(x) + (y))
191 static void ICODE_ATTR
setpixel(fb_data
*address
)
193 *address
= current_vp
->fg_pattern
;
196 static void ICODE_ATTR
clearpixel(fb_data
*address
)
198 *address
= current_vp
->bg_pattern
;
201 static void ICODE_ATTR
clearimgpixel(fb_data
*address
)
203 *address
= *(fb_data
*)((long)address
+ lcd_backdrop_offset
);
206 static void ICODE_ATTR
flippixel(fb_data
*address
)
208 *address
= ~(*address
);
211 static void ICODE_ATTR
nopixel(fb_data
*address
)
216 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_bgcolor
[8] = {
217 flippixel
, nopixel
, setpixel
, setpixel
,
218 nopixel
, clearpixel
, nopixel
, clearpixel
221 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_backdrop
[8] = {
222 flippixel
, nopixel
, setpixel
, setpixel
,
223 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
226 lcd_fastpixelfunc_type
* const * lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
228 void lcd_set_backdrop(fb_data
* backdrop
)
230 lcd_backdrop
= backdrop
;
233 lcd_backdrop_offset
= (long)backdrop
- (long)&lcd_framebuffer
[0][0];
234 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_backdrop
;
238 lcd_backdrop_offset
= 0;
239 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
243 fb_data
* lcd_get_backdrop(void)
248 /*** drawing functions ***/
250 /* Clear the current viewport */
251 void lcd_clear_viewport(void)
253 fb_data
*dst
, *dst_end
;
255 dst
= LCDADDR(current_vp
->x
, current_vp
->y
);
256 dst_end
= dst
+ current_vp
->width
* LCD_HEIGHT
;
258 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
262 memset16(dst
, current_vp
->fg_pattern
, current_vp
->height
);
265 while (dst
< dst_end
);
273 memset16(dst
, current_vp
->bg_pattern
, current_vp
->height
);
276 while (dst
< dst_end
);
282 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
283 current_vp
->height
* sizeof(fb_data
));
286 while (dst
< dst_end
);
290 if (current_vp
== &default_vp
)
292 lcd_scroll_info
.lines
= 0;
296 lcd_scroll_stop(current_vp
);
300 /* Clear the whole display */
301 void lcd_clear_display(void)
303 struct viewport
* old_vp
= current_vp
;
305 current_vp
= &default_vp
;
307 lcd_clear_viewport();
312 /* Set a single pixel */
313 void lcd_drawpixel(int x
, int y
)
315 if (((unsigned)x
< (unsigned)current_vp
->width
) &&
316 ((unsigned)y
< (unsigned)current_vp
->height
))
317 lcd_fastpixelfuncs
[current_vp
->drawmode
](LCDADDR(current_vp
->x
+x
, current_vp
->y
+y
));
321 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
329 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
331 deltay
= abs(y2
- y1
);
334 DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n");
335 lcd_hline(x1
, x2
, y1
);
338 deltax
= abs(x2
- x1
);
341 DEBUGF("lcd_drawline() called for vertical line - optimisation.\n");
342 lcd_vline(x1
, y1
, y2
);
348 if (deltax
>= deltay
)
351 d
= 2 * deltay
- deltax
;
353 dinc2
= (deltay
- deltax
) * 2;
360 d
= 2 * deltax
- deltay
;
362 dinc2
= (deltax
- deltay
) * 2;
366 numpixels
++; /* include endpoints */
383 for (i
= 0; i
< numpixels
; i
++)
385 if (((unsigned)x
< (unsigned)current_vp
->width
) && ((unsigned)y
< (unsigned)current_vp
->height
))
386 pfunc(LCDADDR(x
+ current_vp
->x
, y
+ current_vp
->y
));
403 /* Draw a horizontal line (optimised) */
404 void lcd_hline(int x1
, int x2
, int y
)
407 fb_data
*dst
, *dst_end
;
408 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
418 /* nothing to draw? */
419 if (((unsigned)y
>= (unsigned)current_vp
->height
) ||
420 (x1
>= current_vp
->width
) ||
427 if (x2
>= current_vp
->width
)
428 x2
= current_vp
->width
-1;
430 dst
= LCDADDR(x1
+ current_vp
->x
, y
+ current_vp
->y
);
431 dst_end
= dst
+ (x2
- x1
) * LCD_HEIGHT
;
438 while (dst
<= dst_end
);
441 /* Draw a vertical line (optimised) */
442 void lcd_vline(int x
, int y1
, int y2
)
446 enum fill_opt fillopt
= OPT_NONE
;
447 fb_data
*dst
, *dst_end
;
457 /* nothing to draw? */
458 if (((unsigned)x
>= (unsigned)current_vp
->width
) ||
459 (y1
>= current_vp
->height
) ||
463 /* drawmode and optimisation */
464 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
466 if (current_vp
->drawmode
& DRMODE_BG
)
471 bits
= current_vp
->bg_pattern
;
479 if (current_vp
->drawmode
& DRMODE_FG
)
482 bits
= current_vp
->fg_pattern
;
485 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
491 if (y2
>= current_vp
->height
)
492 y2
= current_vp
->height
-1;
494 height
= y2
- y1
+ 1;
496 /* Adjust y1 and x to viewport */
500 dst
= LCDADDR(x
, y1
);
505 memset16(dst
, bits
, height
);
509 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
510 height
* sizeof(fb_data
));
513 case OPT_NONE
: /* DRMODE_COMPLEMENT */
514 dst_end
= dst
+ height
;
517 while (++dst
< dst_end
);
522 /* Draw a rectangular box */
523 void lcd_drawrect(int x
, int y
, int width
, int height
)
525 if ((width
<= 0) || (height
<= 0))
528 int x2
= x
+ width
- 1;
529 int y2
= y
+ height
- 1;
532 lcd_vline(x2
, y
, y2
);
534 lcd_hline(x
, x2
, y2
);
537 /* Fill a rectangular area */
538 void lcd_fillrect(int x
, int y
, int width
, int height
)
541 enum fill_opt fillopt
= OPT_NONE
;
542 fb_data
*dst
, *dst_end
;
544 /* nothing to draw? */
545 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
546 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
549 /* drawmode and optimisation */
550 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
552 if (current_vp
->drawmode
& DRMODE_BG
)
557 bits
= current_vp
->bg_pattern
;
565 if (current_vp
->drawmode
& DRMODE_FG
)
568 bits
= current_vp
->fg_pattern
;
571 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
585 if (x
+ width
> current_vp
->width
)
586 width
= current_vp
->width
- x
;
587 if (y
+ height
> current_vp
->height
)
588 height
= current_vp
->height
- y
;
590 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
591 dst_end
= dst
+ width
* LCD_HEIGHT
;
595 fb_data
*dst_col
, *col_end
;
600 memset16(dst
, bits
, height
);
604 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
605 height
* sizeof(fb_data
));
608 case OPT_NONE
: /* DRMODE_COMPLEMENT */
610 col_end
= dst_col
+ height
;
612 *dst_col
= ~(*dst_col
);
613 while (++dst_col
< col_end
);
618 while (dst
< dst_end
);
621 /* About Rockbox' internal monochrome bitmap format:
623 * A bitmap contains one bit for every pixel that defines if that pixel is
624 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
626 * The bytes are stored in row-major order, with byte 0 being top left,
627 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
628 * 0..7, the second row defines pixel row 8..15 etc.
630 * This is the mono bitmap format used on all other targets so far; the
631 * pixel packing doesn't really matter on a 8bit+ target. */
633 /* Draw a partial monochrome bitmap */
635 void ICODE_ATTR
lcd_mono_bitmap_part(const unsigned char *src
, int src_x
,
636 int src_y
, int stride
, int x
, int y
,
637 int width
, int height
)
639 const unsigned char *src_end
;
640 fb_data
*dst
, *dst_end
;
641 unsigned dmask
= 0x100; /* bit 8 == sentinel */
642 int drmode
= current_vp
->drawmode
;
644 /* nothing to draw? */
645 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
646 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
662 if (x
+ width
> current_vp
->width
)
663 width
= current_vp
->width
- x
;
664 if (y
+ height
> current_vp
->height
)
665 height
= current_vp
->height
- y
;
667 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
669 src_end
= src
+ width
;
670 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
671 dst_end
= dst
+ height
;
673 if (drmode
& DRMODE_INVERSEVID
)
675 dmask
= 0x1ff; /* bit 8 == sentinel */
676 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
681 const unsigned char *src_col
= src
++;
682 unsigned data
= (*src_col
^ dmask
) >> src_y
;
683 fb_data
*dst_col
= dst
;
687 #define UPDATE_SRC do { \
689 if (data == 0x001) { \
691 data = *src_col ^ dmask; \
697 case DRMODE_COMPLEMENT
:
701 *dst_col
= ~(*dst_col
);
706 while (dst_col
< dst_end
);
712 bo
= lcd_backdrop_offset
;
716 *dst_col
= *(fb_data
*)((long)dst_col
+ bo
);
721 while (dst_col
< dst_end
);
725 bg
= current_vp
->bg_pattern
;
734 while (dst_col
< dst_end
);
739 fg
= current_vp
->fg_pattern
;
748 while (dst_col
< dst_end
);
752 fg
= current_vp
->fg_pattern
;
755 bo
= lcd_backdrop_offset
;
758 *dst_col
= (data
& 0x01) ? fg
759 : *(fb_data
*)((long)dst_col
+ bo
);
763 while (dst_col
< dst_end
);
767 bg
= current_vp
->bg_pattern
;
770 *dst_col
= (data
& 0x01) ? fg
: bg
;
774 while (dst_col
< dst_end
);
780 dst_end
+= LCD_HEIGHT
;
781 } while (src
< src_end
);
783 /* Draw a full monochrome bitmap */
784 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
786 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
789 /* Draw a partial native bitmap */
790 void ICODE_ATTR
lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
791 int stride
, int x
, int y
, int width
,
794 fb_data
*dst
, *dst_end
;
796 /* nothing to draw? */
797 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
798 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
814 if (x
+ width
> current_vp
->width
)
815 width
= current_vp
->width
- x
;
816 if (y
+ height
> current_vp
->height
)
817 height
= current_vp
->height
- y
;
819 src
+= stride
* src_x
+ src_y
; /* move starting point */
820 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
821 dst_end
= dst
+ width
* LCD_HEIGHT
;
825 memcpy(dst
, src
, height
* sizeof(fb_data
));
829 while (dst
< dst_end
);
832 /* Draw a full native bitmap */
833 void lcd_bitmap(const fb_data
*src
, int x
, int y
, int width
, int height
)
835 lcd_bitmap_part(src
, 0, 0, STRIDE(SCREEN_MAIN
, width
, height
), x
, y
, width
, height
);
838 #if !defined(TOSHIBA_GIGABEAT_F) && !defined(TOSHIBA_GIGABEAT_S) \
839 || defined(SIMULATOR)
840 /* Draw a partial native bitmap */
841 void ICODE_ATTR
lcd_bitmap_transparent_part(const fb_data
*src
, int src_x
,
842 int src_y
, int stride
, int x
,
843 int y
, int width
, int height
)
845 fb_data
*dst
, *dst_end
;
847 /* nothing to draw? */
848 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
849 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
865 if (x
+ width
> current_vp
->width
)
866 width
= current_vp
->width
- x
;
867 if (y
+ height
> current_vp
->height
)
868 height
= current_vp
->height
- y
;
870 src
+= stride
* src_x
+ src_y
; /* move starting point */
871 dst
= LCDADDR(current_vp
->x
+ x
, current_vp
->y
+ y
);
872 dst_end
= dst
+ width
* LCD_HEIGHT
;
877 for(i
= 0;i
< height
;i
++)
879 if (src
[i
] == REPLACEWITHFG_COLOR
)
880 dst
[i
] = current_vp
->fg_pattern
;
881 else if(src
[i
] != TRANSPARENT_COLOR
)
887 while (dst
< dst_end
);
889 #endif /* !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR) */
891 /* Draw a full native bitmap with a transparent color */
892 void lcd_bitmap_transparent(const fb_data
*src
, int x
, int y
,
893 int width
, int height
)
895 lcd_bitmap_transparent_part(src
, 0, 0,
896 STRIDE(SCREEN_MAIN
, width
, height
), x
, y
, width
, height
);
899 #include "lcd-bitmap-common.c"