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 ****************************************************************************/
25 /* to be #included by lcd-16bit*.c */
27 #if !defined(ROW_INC) || !defined(COL_INC)
28 #error ROW_INC or COL_INC not defined
38 fb_data lcd_static_framebuffer
[LCD_FBHEIGHT
][LCD_FBWIDTH
]
39 IRAM_LCDFRAMEBUFFER
CACHEALIGN_AT_LEAST_ATTR(16);
40 fb_data
*lcd_framebuffer
= &lcd_static_framebuffer
[0][0];
42 static fb_data
* lcd_backdrop
= NULL
;
43 static long lcd_backdrop_offset IDATA_ATTR
= 0;
45 static struct viewport default_vp
=
51 .font
= FONT_SYSFIXED
,
52 .drawmode
= DRMODE_SOLID
,
53 .fg_pattern
= LCD_DEFAULT_FG
,
54 .bg_pattern
= LCD_DEFAULT_BG
,
55 .lss_pattern
= LCD_DEFAULT_BG
,
56 .lse_pattern
= LCD_DEFAULT_BG
,
57 .lst_pattern
= LCD_DEFAULT_BG
,
60 static struct viewport
* current_vp IDATA_ATTR
= &default_vp
;
67 /* Call device specific init */
73 void lcd_set_viewport(struct viewport
* vp
)
76 current_vp
= &default_vp
;
80 #if defined(SIMULATOR)
81 /* Force the viewport to be within bounds. If this happens it should
82 * be considered an error - the viewport will not draw as it might be
85 if((unsigned) current_vp
->x
> (unsigned) LCD_WIDTH
86 || (unsigned) current_vp
->y
> (unsigned) LCD_HEIGHT
87 || current_vp
->x
+ current_vp
->width
> LCD_WIDTH
88 || current_vp
->y
+ current_vp
->height
> LCD_HEIGHT
)
90 #if !defined(HAVE_VIEWPORT_CLIP)
95 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
96 current_vp
->x
, current_vp
->y
,
97 current_vp
->width
, current_vp
->height
);
103 void lcd_update_viewport(void)
105 lcd_update_rect(current_vp
->x
, current_vp
->y
,
106 current_vp
->width
, current_vp
->height
);
109 void lcd_update_viewport_rect(int x
, int y
, int width
, int height
)
111 lcd_update_rect(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
114 /* Clear the current viewport */
115 void lcd_clear_viewport(void)
117 fb_data
*dst
, *dst_end
;
118 int x
, y
, width
, height
;
123 width
= current_vp
->width
;
124 height
= current_vp
->height
;
126 #if defined(HAVE_VIEWPORT_CLIP)
127 /********************* Viewport on screen clipping ********************/
128 /* nothing to draw? */
129 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
130 || (x
+ width
<= 0) || (y
+ height
<= 0))
133 /* clip image in viewport in screen */
144 if (x
+ width
> LCD_WIDTH
)
145 width
= LCD_WIDTH
- x
;
146 if (y
+ height
> LCD_HEIGHT
)
147 height
= LCD_HEIGHT
- y
;
150 len
= STRIDE_MAIN(width
, height
);
151 step
= STRIDE_MAIN(ROW_INC
, COL_INC
);
154 dst_end
= FBADDR(x
+ width
- 1 , y
+ height
- 1);
156 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
160 memset16(dst
, current_vp
->fg_pattern
, len
);
163 while (dst
<= dst_end
);
171 memset16(dst
, current_vp
->bg_pattern
, len
);
174 while (dst
<= dst_end
);
180 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
181 len
* sizeof(fb_data
));
184 while (dst
<= dst_end
);
188 if (current_vp
== &default_vp
)
190 lcd_scroll_info
.lines
= 0;
194 lcd_scroll_stop(current_vp
);
198 /*** parameter handling ***/
200 void lcd_set_drawmode(int mode
)
202 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
205 int lcd_get_drawmode(void)
207 return current_vp
->drawmode
;
210 void lcd_set_foreground(unsigned color
)
212 current_vp
->fg_pattern
= color
;
215 unsigned lcd_get_foreground(void)
217 return current_vp
->fg_pattern
;
220 void lcd_set_background(unsigned color
)
222 current_vp
->bg_pattern
= color
;
225 unsigned lcd_get_background(void)
227 return current_vp
->bg_pattern
;
230 void lcd_set_selector_start(unsigned color
)
232 current_vp
->lss_pattern
= color
;
235 void lcd_set_selector_end(unsigned color
)
237 current_vp
->lse_pattern
= color
;
240 void lcd_set_selector_text(unsigned color
)
242 current_vp
->lst_pattern
= color
;
245 void lcd_set_drawinfo(int mode
, unsigned fg_color
, unsigned bg_color
)
247 lcd_set_drawmode(mode
);
248 current_vp
->fg_pattern
= fg_color
;
249 current_vp
->bg_pattern
= bg_color
;
252 int lcd_getwidth(void)
254 return current_vp
->width
;
257 int lcd_getheight(void)
259 return current_vp
->height
;
262 void lcd_setfont(int newfont
)
264 current_vp
->font
= newfont
;
267 int lcd_getfont(void)
269 return current_vp
->font
;
272 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
274 return font_getstringsize(str
, w
, h
, current_vp
->font
);
277 /*** low-level drawing functions ***/
279 static void ICODE_ATTR
setpixel(fb_data
*address
)
281 *address
= current_vp
->fg_pattern
;
284 static void ICODE_ATTR
clearpixel(fb_data
*address
)
286 *address
= current_vp
->bg_pattern
;
289 static void ICODE_ATTR
clearimgpixel(fb_data
*address
)
291 *address
= *(fb_data
*)((long)address
+ lcd_backdrop_offset
);
294 static void ICODE_ATTR
flippixel(fb_data
*address
)
296 *address
= ~(*address
);
299 static void ICODE_ATTR
nopixel(fb_data
*address
)
304 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_bgcolor
[8] = {
305 flippixel
, nopixel
, setpixel
, setpixel
,
306 nopixel
, clearpixel
, nopixel
, clearpixel
309 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_backdrop
[8] = {
310 flippixel
, nopixel
, setpixel
, setpixel
,
311 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
314 lcd_fastpixelfunc_type
* const * lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
316 void lcd_set_backdrop(fb_data
* backdrop
)
318 lcd_backdrop
= backdrop
;
321 lcd_backdrop_offset
= (long)backdrop
- (long)lcd_framebuffer
;
322 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_backdrop
;
326 lcd_backdrop_offset
= 0;
327 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
331 fb_data
* lcd_get_backdrop(void)
336 /* Clear the whole display */
337 void lcd_clear_display(void)
339 struct viewport
* old_vp
= current_vp
;
341 current_vp
= &default_vp
;
343 lcd_clear_viewport();
348 /* Set a single pixel */
349 void lcd_drawpixel(int x
, int y
)
351 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
352 && ((unsigned)y
< (unsigned)current_vp
->height
)
353 #if defined(HAVE_VIEWPORT_CLIP)
354 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
355 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
358 lcd_fastpixelfuncs
[current_vp
->drawmode
](FBADDR(current_vp
->x
+x
, current_vp
->y
+y
));
362 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
370 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
372 deltay
= abs(y2
- y1
);
375 /* DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n"); */
376 lcd_hline(x1
, x2
, y1
);
379 deltax
= abs(x2
- x1
);
382 /* DEBUGF("lcd_drawline() called for vertical line - optimisation.\n"); */
383 lcd_vline(x1
, y1
, y2
);
389 if (deltax
>= deltay
)
392 d
= 2 * deltay
- deltax
;
394 dinc2
= (deltay
- deltax
) * 2;
401 d
= 2 * deltax
- deltay
;
403 dinc2
= (deltax
- deltay
) * 2;
407 numpixels
++; /* include endpoints */
424 for (i
= 0; i
< numpixels
; i
++)
426 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
427 && ((unsigned)y
< (unsigned)current_vp
->height
)
428 #if defined(HAVE_VIEWPORT_CLIP)
429 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
430 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
433 pfunc(FBADDR(x
+ current_vp
->x
, y
+ current_vp
->y
));
450 /* Draw a rectangular box */
451 void lcd_drawrect(int x
, int y
, int width
, int height
)
453 if ((width
<= 0) || (height
<= 0))
456 int x2
= x
+ width
- 1;
457 int y2
= y
+ height
- 1;
460 lcd_vline(x2
, y
, y2
);
462 lcd_hline(x
, x2
, y2
);
465 /* Fill a rectangular area */
466 void lcd_fillrect(int x
, int y
, int width
, int height
)
469 enum fill_opt fillopt
= OPT_NONE
;
470 fb_data
*dst
, *dst_end
;
473 /******************** In viewport clipping **********************/
474 /* nothing to draw? */
475 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
476 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
489 if (x
+ width
> current_vp
->width
)
490 width
= current_vp
->width
- x
;
491 if (y
+ height
> current_vp
->height
)
492 height
= current_vp
->height
- y
;
494 /* adjust for viewport */
498 #if defined(HAVE_VIEWPORT_CLIP)
499 /********************* Viewport on screen clipping ********************/
500 /* nothing to draw? */
501 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
502 || (x
+ width
<= 0) || (y
+ height
<= 0))
505 /* clip image in viewport in screen */
516 if (x
+ width
> LCD_WIDTH
)
517 width
= LCD_WIDTH
- x
;
518 if (y
+ height
> LCD_HEIGHT
)
519 height
= LCD_HEIGHT
- y
;
522 /* drawmode and optimisation */
523 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
525 if (current_vp
->drawmode
& DRMODE_BG
)
530 bits
= current_vp
->bg_pattern
;
538 if (current_vp
->drawmode
& DRMODE_FG
)
541 bits
= current_vp
->fg_pattern
;
544 if (fillopt
== OPT_NONE
&& current_vp
->drawmode
!= DRMODE_COMPLEMENT
)
548 dst_end
= FBADDR(x
+ width
- 1, y
+ height
- 1);
550 len
= STRIDE_MAIN(width
, height
);
551 step
= STRIDE_MAIN(ROW_INC
, COL_INC
);
558 memset16(dst
, bits
, len
);
562 memcpy(dst
, (void *)((long)dst
+ lcd_backdrop_offset
),
563 len
* sizeof(fb_data
));
566 case OPT_NONE
: /* DRMODE_COMPLEMENT */
568 fb_data
*start
= dst
;
569 fb_data
*end
= start
+ len
;
572 while (++start
< end
);
578 while (dst
<= dst_end
);
581 /* About Rockbox' internal monochrome bitmap format:
583 * A bitmap contains one bit for every pixel that defines if that pixel is
584 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
586 * The bytes are stored in row-major order, with byte 0 being top left,
587 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
588 * 0..7, the second row defines pixel row 8..15 etc.
590 * This is the mono bitmap format used on all other targets so far; the
591 * pixel packing doesn't really matter on a 8bit+ target. */
593 /* Draw a partial monochrome bitmap */
595 void ICODE_ATTR
lcd_mono_bitmap_part(const unsigned char *src
, int src_x
,
596 int src_y
, int stride
, int x
, int y
,
597 int width
, int height
)
599 const unsigned char *src_end
;
600 fb_data
*dst
, *dst_col
;
601 unsigned dmask
= 0x100; /* bit 8 == sentinel */
602 int drmode
= current_vp
->drawmode
;
605 /******************** Image in viewport clipping **********************/
606 /* nothing to draw? */
607 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
608 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
623 if (x
+ width
> current_vp
->width
)
624 width
= current_vp
->width
- x
;
625 if (y
+ height
> current_vp
->height
)
626 height
= current_vp
->height
- y
;
628 /* adjust for viewport */
632 #if defined(HAVE_VIEWPORT_CLIP)
633 /********************* Viewport on screen clipping ********************/
634 /* nothing to draw? */
635 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
636 || (x
+ width
<= 0) || (y
+ height
<= 0))
639 /* clip image in viewport in screen */
652 if (x
+ width
> LCD_WIDTH
)
653 width
= LCD_WIDTH
- x
;
654 if (y
+ height
> LCD_HEIGHT
)
655 height
= LCD_HEIGHT
- y
;
658 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
660 src_end
= src
+ width
;
661 dst_col
= FBADDR(x
, y
);
664 if (drmode
& DRMODE_INVERSEVID
)
666 dmask
= 0x1ff; /* bit 8 == sentinel */
667 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
670 /* go through each column and update each pixel */
673 const unsigned char *src_col
= src
++;
674 unsigned data
= (*src_col
^ dmask
) >> src_y
;
682 #define UPDATE_SRC do { \
684 if (data == 0x001) { \
686 data = *src_col ^ dmask; \
692 case DRMODE_COMPLEMENT
:
707 bo
= lcd_backdrop_offset
;
711 *dst
= *(fb_data
*)((long)dst
+ bo
);
720 bg
= current_vp
->bg_pattern
;
734 fg
= current_vp
->fg_pattern
;
747 fg
= current_vp
->fg_pattern
;
750 bo
= lcd_backdrop_offset
;
753 *dst
= (data
& 0x01) ? fg
754 : *(fb_data
*)((long)dst
+ bo
);
762 bg
= current_vp
->bg_pattern
;
765 *dst
= (data
& 0x01) ? fg
: bg
;
774 while (src
< src_end
);
776 /* Draw a full monochrome bitmap */
777 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
779 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
783 /* About Rockbox' internal alpha channel format (for ALPHA_COLOR_FONT_DEPTH == 2)
785 * For each pixel, 4bit of alpha information is stored in a byte-stream,
786 * so two pixels are packed into one byte.
787 * The lower nibble is the first pixel, the upper one the second. The stride is
788 * horizontal. E.g row0: pixel0: byte0[0:3], pixel1: byte0[4:7], pixel2: byte1[0:3],...
789 * The format is independant of the internal display orientation and color
790 * representation, as to support the same font files on all displays.
791 * The values go linear from 0 (fully transparent) to 15 (fully opaque).
793 * This might suggest that rows need to have an even number of pixels.
794 * However this is generally not the case. lcd_alpha_bitmap_part_mix() can deal
795 * with uneven colums (i.e. two rows can share one byte). And font files do
797 * However, this is difficult to do for image files, especially bottom-up bitmaps,
798 * so lcd_bmp() do expect even rows.
801 #define ALPHA_COLOR_FONT_DEPTH 2
802 #define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH)
803 #define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1)
804 #define ALPHA_COLOR_PIXEL_PER_BYTE (8 >> ALPHA_COLOR_FONT_DEPTH)
805 #define ALPHA_COLOR_PIXEL_PER_WORD (32 >> ALPHA_COLOR_FONT_DEPTH)
807 #define BLEND_INIT do {} while (0)
808 #define BLEND_FINISH do {} while(0)
809 #define BLEND_START(acc, color, alpha) \
810 asm volatile("mul %0, %1, %2" : "=&r" (acc) : "r" (color), "r" (alpha))
811 #define BLEND_CONT(acc, color, alpha) \
812 asm volatile("mla %0, %1, %2, %0" : "+&r" (acc) : "r" (color), "r" (alpha))
813 #define BLEND_OUT(acc) do {} while (0)
814 #elif defined(CPU_COLDFIRE)
815 #define ALPHA_BITMAP_READ_WORDS
817 unsigned long _macsr = coldfire_get_macsr(); \
818 coldfire_set_macsr(EMAC_UNSIGNED)
819 #define BLEND_FINISH \
820 coldfire_set_macsr(_macsr)
821 #define BLEND_START(acc, color, alpha) \
822 asm volatile("mac.l %0, %1, %%acc0" :: "%d" (color), "d" (alpha))
823 #define BLEND_CONT BLEND_START
824 #define BLEND_OUT(acc) asm volatile("movclr.l %%acc0, %0" : "=d" (acc))
826 #define BLEND_INIT do {} while (0)
827 #define BLEND_FINISH do {} while(0)
828 #define BLEND_START(acc, color, alpha) ((acc) = (color) * (alpha))
829 #define BLEND_CONT(acc, color, alpha) ((acc) += (color) * (alpha))
830 #define BLEND_OUT(acc) do {} while (0)
833 /* Blend the given two colors */
834 static inline unsigned blend_two_colors(unsigned c1
, unsigned c2
, unsigned a
)
836 a
+= a
>> (ALPHA_COLOR_LOOKUP_SHIFT
- 1);
837 #if (LCD_PIXELFORMAT == RGB565SWAPPED)
841 unsigned c1l
= (c1
| (c1
<< 16)) & 0x07e0f81f;
842 unsigned c2l
= (c2
| (c2
<< 16)) & 0x07e0f81f;
844 BLEND_START(p
, c1l
, a
);
845 BLEND_CONT(p
, c2l
, ALPHA_COLOR_LOOKUP_SIZE
+ 1 - a
);
847 p
= (p
>> ALPHA_COLOR_LOOKUP_SHIFT
) & 0x07e0f81f;
849 #if (LCD_PIXELFORMAT == RGB565SWAPPED)
856 /* Blend the given color with the value from the alpha_color_lookup table */
857 static inline unsigned blend_color(unsigned c
, unsigned a
)
859 return blend_two_colors(c
, current_vp
->fg_pattern
, a
);
862 /* Blend an image with an alpha channel
863 * if image is NULL, drawing will happen according to the drawmode
864 * src is the alpha channel (4bit per pixel) */
865 static void ICODE_ATTR
lcd_alpha_bitmap_part_mix(const fb_data
* image
,
866 const unsigned char *src
, int src_x
,
867 int src_y
, int x
, int y
,
868 int width
, int height
,
869 int stride_image
, int stride_src
)
871 fb_data
*dst
, *dst_row
;
872 const fb_data
*image_row
;
873 unsigned dmask
= 0x00000000;
874 int drmode
= current_vp
->drawmode
;
875 /* nothing to draw? */
876 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
877 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
879 /* initialize blending */
895 if (x
+ width
> current_vp
->width
)
896 width
= current_vp
->width
- x
;
897 if (y
+ height
> current_vp
->height
)
898 height
= current_vp
->height
- y
;
900 /* adjust for viewport */
904 #if defined(HAVE_VIEWPORT_CLIP)
905 /********************* Viewport on screen clipping ********************/
906 /* nothing to draw? */
907 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
908 || (x
+ width
<= 0) || (y
+ height
<= 0))
914 /* clip image in viewport in screen */
927 if (x
+ width
> LCD_WIDTH
)
928 width
= LCD_WIDTH
- x
;
929 if (y
+ height
> LCD_HEIGHT
)
930 height
= LCD_HEIGHT
- y
;
933 if (drmode
& DRMODE_INVERSEVID
)
936 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
938 /* sourcing from an image ignore drawmode.
939 * Set to DRMODE_BG as we use its code path in the switch below */
944 if (drmode
== DRMODE_BG
)
949 dst_row
= FBADDR(x
, y
);
951 int col
, row
= height
;
952 unsigned data
, pixels
;
953 unsigned skip_end
= (stride_src
- width
);
954 unsigned skip_start
= src_y
* stride_src
+ src_x
;
955 unsigned skip_start_image
= STRIDE_MAIN(src_y
* stride_image
+ src_x
,
956 src_x
* stride_image
+ src_y
);
958 #ifdef ALPHA_BITMAP_READ_WORDS
959 uint32_t *src_w
= (uint32_t *)((uintptr_t)src
& ~3);
960 skip_start
+= ALPHA_COLOR_PIXEL_PER_BYTE
* ((uintptr_t)src
& 3);
961 src_w
+= skip_start
/ ALPHA_COLOR_PIXEL_PER_WORD
;
962 data
= letoh32(*src_w
++) ^ dmask
;
963 pixels
= skip_start
% ALPHA_COLOR_PIXEL_PER_WORD
;
965 src
+= skip_start
/ ALPHA_COLOR_PIXEL_PER_BYTE
;
967 pixels
= skip_start
% ALPHA_COLOR_PIXEL_PER_BYTE
;
969 data
>>= pixels
* ALPHA_COLOR_LOOKUP_SHIFT
;
970 #ifdef ALPHA_BITMAP_READ_WORDS
974 image
+= skip_start_image
;
977 /* go through the rows and update each pixel */
985 image_row
+= STRIDE_MAIN(stride_image
,1);
989 #ifdef ALPHA_BITMAP_READ_WORDS
990 #define UPDATE_SRC_ALPHA do { \
992 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
995 data = letoh32(*src_w++) ^ dmask; \
996 pixels = ALPHA_COLOR_PIXEL_PER_WORD; \
999 #elif ALPHA_COLOR_PIXEL_PER_BYTE == 2
1000 #define UPDATE_SRC_ALPHA do { \
1002 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
1004 data = *(++src) ^ dmask; \
1007 #define UPDATE_SRC_ALPHA do { \
1008 if (pixels = (++pixels % ALPHA_COLOR_PIXEL_PER_BYTE)) \
1009 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
1011 data = *(++src) ^ dmask; \
1014 /* we don't want to have this in our inner
1015 * loop and the codesize increase is minimal */
1018 case DRMODE_COMPLEMENT
:
1021 *dst
= blend_two_colors(*dst
, ~(*dst
),
1022 data
& ALPHA_COLOR_LOOKUP_SIZE
);
1031 uintptr_t bo
= lcd_backdrop_offset
;
1034 *dst
= blend_two_colors(*(fb_data
*)((uintptr_t)dst
+ bo
),
1035 *image
, data
& ALPHA_COLOR_LOOKUP_SIZE
);
1038 image
+= STRIDE_MAIN(1, stride_image
);
1047 *dst
= blend_two_colors(current_vp
->bg_pattern
,
1048 *image
, data
& ALPHA_COLOR_LOOKUP_SIZE
);
1050 image
+= STRIDE_MAIN(1, stride_image
);
1059 *dst
= blend_color(*dst
, data
& ALPHA_COLOR_LOOKUP_SIZE
);
1068 uintptr_t bo
= lcd_backdrop_offset
;
1071 *dst
= blend_color(*(fb_data
*)((uintptr_t)dst
+ bo
),
1072 data
& ALPHA_COLOR_LOOKUP_SIZE
);
1082 *dst
= blend_color(current_vp
->bg_pattern
,
1083 data
& ALPHA_COLOR_LOOKUP_SIZE
);
1091 #ifdef ALPHA_BITMAP_READ_WORDS
1092 if (skip_end
< pixels
)
1095 data
>>= skip_end
* ALPHA_COLOR_LOOKUP_SHIFT
;
1097 pixels
= skip_end
- pixels
;
1098 src_w
+= pixels
/ ALPHA_COLOR_PIXEL_PER_WORD
;
1099 pixels
%= ALPHA_COLOR_PIXEL_PER_WORD
;
1100 data
= letoh32(*src_w
++) ^ dmask
;
1101 data
>>= pixels
* ALPHA_COLOR_LOOKUP_SHIFT
;
1102 pixels
= 8 - pixels
;
1108 if (pixels
>= ALPHA_COLOR_PIXEL_PER_BYTE
)
1110 src
+= pixels
/ ALPHA_COLOR_PIXEL_PER_BYTE
;
1111 pixels
%= ALPHA_COLOR_PIXEL_PER_BYTE
;
1112 data
= *src
^ dmask
;
1113 data
>>= pixels
* ALPHA_COLOR_LOOKUP_SHIFT
;
1115 data
>>= skip_end
* ALPHA_COLOR_LOOKUP_SHIFT
;
1123 /* Draw a full native bitmap */
1124 void lcd_bitmap(const fb_data
*src
, int x
, int y
, int width
, int height
)
1126 lcd_bitmap_part(src
, 0, 0, STRIDE(SCREEN_MAIN
, width
, height
), x
, y
, width
, height
);
1129 /* Draw a full native bitmap with a transparent color */
1130 void lcd_bitmap_transparent(const fb_data
*src
, int x
, int y
,
1131 int width
, int height
)
1133 lcd_bitmap_transparent_part(src
, 0, 0,
1134 STRIDE(SCREEN_MAIN
, width
, height
), x
, y
, width
, height
);
1137 /* draw alpha bitmap for anti-alias font */
1138 void ICODE_ATTR
lcd_alpha_bitmap_part(const unsigned char *src
, int src_x
,
1139 int src_y
, int stride
, int x
, int y
,
1140 int width
, int height
)
1142 lcd_alpha_bitmap_part_mix(NULL
, src
, src_x
, src_y
, x
, y
, width
, height
, 0, stride
);
1145 /* Draw a partial bitmap (mono or native) including alpha channel */
1146 void ICODE_ATTR
lcd_bmp_part(const struct bitmap
* bm
, int src_x
, int src_y
,
1147 int x
, int y
, int width
, int height
)
1149 int bitmap_stride
= STRIDE_MAIN(bm
->width
, bm
->height
);
1150 if (bm
->format
== FORMAT_MONO
)
1151 lcd_mono_bitmap_part(bm
->data
, src_x
, src_y
, bitmap_stride
, x
, y
, width
, height
);
1152 else if (bm
->alpha_offset
> 0)
1153 lcd_alpha_bitmap_part_mix((fb_data
*)bm
->data
, bm
->data
+bm
->alpha_offset
,
1154 src_x
, src_y
, x
, y
, width
, height
,
1155 bitmap_stride
, ALIGN_UP(bm
->width
, 2));
1157 lcd_bitmap_transparent_part((fb_data
*)bm
->data
,
1158 src_x
, src_y
, bitmap_stride
, x
, y
, width
, height
);
1161 /* Draw a native bitmap with alpha channel */
1162 void ICODE_ATTR
lcd_bmp(const struct bitmap
*bmp
, int x
, int y
)
1164 lcd_bmp_part(bmp
, 0, 0, x
, y
, bmp
->width
, bmp
->height
);
1168 * |R| |1.000000 -0.000001 1.402000| |Y'|
1169 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
1170 * |B| |1.000000 1.772000 0.000000| |Pr|
1171 * Scaled, normalized, rounded and tweaked to yield RGB 565:
1172 * |R| |74 0 101| |Y' - 16| >> 9
1173 * |G| = |74 -24 -51| |Cb - 128| >> 8
1174 * |B| |74 128 0| |Cr - 128| >> 9
1182 static inline int clamp(int val
, int min
, int max
)
1193 * weak attribute doesn't work for win32 as of gcc 4.6.2 and binutils 2.21.52
1194 * When building win32 simulators, we won't be using an optimized version of
1195 * lcd_blit_yuv(), so just don't use the weak attribute.
1197 __attribute__((weak
))
1199 void lcd_yuv_set_options(unsigned options
)
1204 /* Draw a partial YUV colour bitmap */
1206 __attribute__((weak
))
1208 void lcd_blit_yuv(unsigned char * const src
[3],
1209 int src_x
, int src_y
, int stride
,
1210 int x
, int y
, int width
, int height
)
1212 const unsigned char *ysrc
, *usrc
, *vsrc
;
1214 fb_data
*dst
, *row_end
;
1217 /* width and height must be >= 2 and an even number */
1219 linecounter
= height
>> 1;
1221 #if LCD_WIDTH >= LCD_HEIGHT
1223 row_end
= dst
+ width
;
1225 dst
= FBADDR(LCD_WIDTH
- y
- 1, x
);
1226 row_end
= dst
+ LCD_WIDTH
* width
;
1230 ysrc
= src
[0] + z
+ src_x
;
1231 usrc
= src
[1] + (z
>> 2) + (src_x
>> 1);
1232 vsrc
= src
[2] + (usrc
- src
[1]);
1234 /* stride => amount to jump from end of last row to start of next */
1237 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
1243 int y
, cb
, cr
, rv
, guv
, bu
, r
, g
, b
;
1245 y
= YFAC
*(*ysrc
++ - 16);
1250 guv
= GUFAC
*cb
+ GVFAC
*cr
;
1257 if ((unsigned)(r
| g
| b
) > 64*256-1)
1259 r
= clamp(r
, 0, 64*256-1);
1260 g
= clamp(g
, 0, 64*256-1);
1261 b
= clamp(b
, 0, 64*256-1);
1264 *dst
= LCD_RGBPACK_LCD(r
>> 9, g
>> 8, b
>> 9);
1266 #if LCD_WIDTH >= LCD_HEIGHT
1272 y
= YFAC
*(*ysrc
++ - 16);
1277 if ((unsigned)(r
| g
| b
) > 64*256-1)
1279 r
= clamp(r
, 0, 64*256-1);
1280 g
= clamp(g
, 0, 64*256-1);
1281 b
= clamp(b
, 0, 64*256-1);
1284 *dst
= LCD_RGBPACK_LCD(r
>> 9, g
>> 8, b
>> 9);
1286 #if LCD_WIDTH >= LCD_HEIGHT
1292 while (dst
< row_end
);
1298 #if LCD_WIDTH >= LCD_HEIGHT
1299 row_end
+= LCD_WIDTH
;
1300 dst
+= LCD_WIDTH
- width
;
1303 dst
-= LCD_WIDTH
*width
+ 1;
1308 int y
, cb
, cr
, rv
, guv
, bu
, r
, g
, b
;
1310 y
= YFAC
*(*ysrc
++ - 16);
1315 guv
= GUFAC
*cb
+ GVFAC
*cr
;
1322 if ((unsigned)(r
| g
| b
) > 64*256-1)
1324 r
= clamp(r
, 0, 64*256-1);
1325 g
= clamp(g
, 0, 64*256-1);
1326 b
= clamp(b
, 0, 64*256-1);
1329 *dst
= LCD_RGBPACK_LCD(r
>> 9, g
>> 8, b
>> 9);
1331 #if LCD_WIDTH >= LCD_HEIGHT
1337 y
= YFAC
*(*ysrc
++ - 16);
1342 if ((unsigned)(r
| g
| b
) > 64*256-1)
1344 r
= clamp(r
, 0, 64*256-1);
1345 g
= clamp(g
, 0, 64*256-1);
1346 b
= clamp(b
, 0, 64*256-1);
1349 *dst
= LCD_RGBPACK_LCD(r
>> 9, g
>> 8, b
>> 9);
1351 #if LCD_WIDTH >= LCD_HEIGHT
1357 while (dst
< row_end
);
1360 usrc
+= stride
>> 1;
1361 vsrc
+= stride
>> 1;
1363 #if LCD_WIDTH >= LCD_HEIGHT
1364 row_end
+= LCD_WIDTH
;
1365 dst
+= LCD_WIDTH
- width
;
1368 dst
-= LCD_WIDTH
*width
+ 1;
1371 while (--linecounter
> 0);
1373 #if LCD_WIDTH >= LCD_HEIGHT
1374 lcd_update_rect(x
, y
, width
, height
);
1376 lcd_update_rect(LCD_WIDTH
- y
- height
, x
, height
, width
);