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 /*** parameter handling ***/
116 void lcd_set_drawmode(int mode
)
118 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
121 int lcd_get_drawmode(void)
123 return current_vp
->drawmode
;
126 void lcd_set_foreground(unsigned color
)
128 current_vp
->fg_pattern
= color
;
131 unsigned lcd_get_foreground(void)
133 return current_vp
->fg_pattern
;
136 void lcd_set_background(unsigned color
)
138 current_vp
->bg_pattern
= color
;
141 unsigned lcd_get_background(void)
143 return current_vp
->bg_pattern
;
146 void lcd_set_selector_start(unsigned color
)
148 current_vp
->lss_pattern
= color
;
151 void lcd_set_selector_end(unsigned color
)
153 current_vp
->lse_pattern
= color
;
156 void lcd_set_selector_text(unsigned color
)
158 current_vp
->lst_pattern
= color
;
161 void lcd_set_drawinfo(int mode
, unsigned fg_color
, unsigned bg_color
)
163 lcd_set_drawmode(mode
);
164 current_vp
->fg_pattern
= fg_color
;
165 current_vp
->bg_pattern
= bg_color
;
168 int lcd_getwidth(void)
170 return current_vp
->width
;
173 int lcd_getheight(void)
175 return current_vp
->height
;
178 void lcd_setfont(int newfont
)
180 current_vp
->font
= newfont
;
183 int lcd_getfont(void)
185 return current_vp
->font
;
188 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
190 return font_getstringsize(str
, w
, h
, current_vp
->font
);
193 /*** low-level drawing functions ***/
195 static void ICODE_ATTR
setpixel(fb_data
*address
)
197 *address
= current_vp
->fg_pattern
;
200 static void ICODE_ATTR
clearpixel(fb_data
*address
)
202 *address
= current_vp
->bg_pattern
;
205 static void ICODE_ATTR
clearimgpixel(fb_data
*address
)
207 *address
= *(fb_data
*)((long)address
+ lcd_backdrop_offset
);
210 static void ICODE_ATTR
flippixel(fb_data
*address
)
212 *address
= ~(*address
);
215 static void ICODE_ATTR
nopixel(fb_data
*address
)
220 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_bgcolor
[8] = {
221 flippixel
, nopixel
, setpixel
, setpixel
,
222 nopixel
, clearpixel
, nopixel
, clearpixel
225 lcd_fastpixelfunc_type
* const lcd_fastpixelfuncs_backdrop
[8] = {
226 flippixel
, nopixel
, setpixel
, setpixel
,
227 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
230 lcd_fastpixelfunc_type
* const * lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
232 void lcd_set_backdrop(fb_data
* backdrop
)
234 lcd_backdrop
= backdrop
;
237 lcd_backdrop_offset
= (long)backdrop
- (long)lcd_framebuffer
;
238 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_backdrop
;
242 lcd_backdrop_offset
= 0;
243 lcd_fastpixelfuncs
= lcd_fastpixelfuncs_bgcolor
;
247 fb_data
* lcd_get_backdrop(void)
252 /* Clear the whole display */
253 void lcd_clear_display(void)
255 struct viewport
* old_vp
= current_vp
;
257 current_vp
= &default_vp
;
259 lcd_clear_viewport();
264 /* Set a single pixel */
265 void lcd_drawpixel(int x
, int y
)
267 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
268 && ((unsigned)y
< (unsigned)current_vp
->height
)
269 #if defined(HAVE_VIEWPORT_CLIP)
270 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
271 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
274 lcd_fastpixelfuncs
[current_vp
->drawmode
](FBADDR(current_vp
->x
+x
, current_vp
->y
+y
));
278 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
286 lcd_fastpixelfunc_type
*pfunc
= lcd_fastpixelfuncs
[current_vp
->drawmode
];
288 deltay
= abs(y2
- y1
);
291 /* DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n"); */
292 lcd_hline(x1
, x2
, y1
);
295 deltax
= abs(x2
- x1
);
298 /* DEBUGF("lcd_drawline() called for vertical line - optimisation.\n"); */
299 lcd_vline(x1
, y1
, y2
);
305 if (deltax
>= deltay
)
308 d
= 2 * deltay
- deltax
;
310 dinc2
= (deltay
- deltax
) * 2;
317 d
= 2 * deltax
- deltay
;
319 dinc2
= (deltax
- deltay
) * 2;
323 numpixels
++; /* include endpoints */
340 for (i
= 0; i
< numpixels
; i
++)
342 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
343 && ((unsigned)y
< (unsigned)current_vp
->height
)
344 #if defined(HAVE_VIEWPORT_CLIP)
345 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
346 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
349 pfunc(FBADDR(x
+ current_vp
->x
, y
+ current_vp
->y
));
366 /* Draw a rectangular box */
367 void lcd_drawrect(int x
, int y
, int width
, int height
)
369 if ((width
<= 0) || (height
<= 0))
372 int x2
= x
+ width
- 1;
373 int y2
= y
+ height
- 1;
376 lcd_vline(x2
, y
, y2
);
378 lcd_hline(x
, x2
, y2
);
382 /* About Rockbox' internal monochrome bitmap format:
384 * A bitmap contains one bit for every pixel that defines if that pixel is
385 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
387 * The bytes are stored in row-major order, with byte 0 being top left,
388 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
389 * 0..7, the second row defines pixel row 8..15 etc.
391 * This is the mono bitmap format used on all other targets so far; the
392 * pixel packing doesn't really matter on a 8bit+ target. */
394 /* Draw a partial monochrome bitmap */
396 void ICODE_ATTR
lcd_mono_bitmap_part(const unsigned char *src
, int src_x
,
397 int src_y
, int stride
, int x
, int y
,
398 int width
, int height
)
400 const unsigned char *src_end
;
401 fb_data
*dst
, *dst_col
;
402 unsigned dmask
= 0x100; /* bit 8 == sentinel */
403 int drmode
= current_vp
->drawmode
;
406 /******************** Image in viewport clipping **********************/
407 /* nothing to draw? */
408 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
409 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
424 if (x
+ width
> current_vp
->width
)
425 width
= current_vp
->width
- x
;
426 if (y
+ height
> current_vp
->height
)
427 height
= current_vp
->height
- y
;
429 /* adjust for viewport */
433 #if defined(HAVE_VIEWPORT_CLIP)
434 /********************* Viewport on screen clipping ********************/
435 /* nothing to draw? */
436 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
437 || (x
+ width
<= 0) || (y
+ height
<= 0))
440 /* clip image in viewport in screen */
453 if (x
+ width
> LCD_WIDTH
)
454 width
= LCD_WIDTH
- x
;
455 if (y
+ height
> LCD_HEIGHT
)
456 height
= LCD_HEIGHT
- y
;
459 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
461 src_end
= src
+ width
;
462 dst_col
= FBADDR(x
, y
);
465 if (drmode
& DRMODE_INVERSEVID
)
467 dmask
= 0x1ff; /* bit 8 == sentinel */
468 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
471 /* go through each column and update each pixel */
474 const unsigned char *src_col
= src
++;
475 unsigned data
= (*src_col
^ dmask
) >> src_y
;
483 #define UPDATE_SRC do { \
485 if (data == 0x001) { \
487 data = *src_col ^ dmask; \
493 case DRMODE_COMPLEMENT
:
508 bo
= lcd_backdrop_offset
;
512 *dst
= *(fb_data
*)((long)dst
+ bo
);
521 bg
= current_vp
->bg_pattern
;
535 fg
= current_vp
->fg_pattern
;
548 fg
= current_vp
->fg_pattern
;
551 bo
= lcd_backdrop_offset
;
554 *dst
= (data
& 0x01) ? fg
555 : *(fb_data
*)((long)dst
+ bo
);
563 bg
= current_vp
->bg_pattern
;
566 *dst
= (data
& 0x01) ? fg
: bg
;
575 while (src
< src_end
);
577 /* Draw a full monochrome bitmap */
578 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
580 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
584 /* About Rockbox' internal alpha channel format (for ALPHA_COLOR_FONT_DEPTH == 2)
586 * For each pixel, 4bit of alpha information is stored in a byte-stream,
587 * so two pixels are packed into one byte.
588 * The lower nibble is the first pixel, the upper one the second. The stride is
589 * horizontal. E.g row0: pixel0: byte0[0:3], pixel1: byte0[4:7], pixel2: byte1[0:3],...
590 * The format is independant of the internal display orientation and color
591 * representation, as to support the same font files on all displays.
592 * The values go linear from 0 (fully transparent) to 15 (fully opaque).
594 * This might suggest that rows need to have an even number of pixels.
595 * However this is generally not the case. lcd_alpha_bitmap_part_mix() can deal
596 * with uneven colums (i.e. two rows can share one byte). And font files do
598 * However, this is difficult to do for image files, especially bottom-up bitmaps,
599 * so lcd_bmp() do expect even rows.
602 #define ALPHA_COLOR_FONT_DEPTH 2
603 #define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH)
604 #define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1)
605 #define ALPHA_COLOR_PIXEL_PER_BYTE (8 >> ALPHA_COLOR_FONT_DEPTH)
606 #define ALPHA_COLOR_PIXEL_PER_WORD (32 >> ALPHA_COLOR_FONT_DEPTH)
608 #define BLEND_INIT do {} while (0)
609 #define BLEND_FINISH do {} while(0)
610 #define BLEND_START(acc, color, alpha) \
611 asm volatile("mul %0, %1, %2" : "=&r" (acc) : "r" (color), "r" (alpha))
612 #define BLEND_CONT(acc, color, alpha) \
613 asm volatile("mla %0, %1, %2, %0" : "+&r" (acc) : "r" (color), "r" (alpha))
614 #define BLEND_OUT(acc) do {} while (0)
615 #elif defined(CPU_COLDFIRE)
616 #define ALPHA_BITMAP_READ_WORDS
618 unsigned long _macsr = coldfire_get_macsr(); \
619 coldfire_set_macsr(EMAC_UNSIGNED)
620 #define BLEND_FINISH \
621 coldfire_set_macsr(_macsr)
622 #define BLEND_START(acc, color, alpha) \
623 asm volatile("mac.l %0, %1, %%acc0" :: "%d" (color), "d" (alpha))
624 #define BLEND_CONT BLEND_START
625 #define BLEND_OUT(acc) asm volatile("movclr.l %%acc0, %0" : "=d" (acc))
627 #define BLEND_INIT do {} while (0)
628 #define BLEND_FINISH do {} while(0)
629 #define BLEND_START(acc, color, alpha) ((acc) = (color) * (alpha))
630 #define BLEND_CONT(acc, color, alpha) ((acc) += (color) * (alpha))
631 #define BLEND_OUT(acc) do {} while (0)
634 /* Blend the given two colors */
635 static inline unsigned blend_two_colors(unsigned c1
, unsigned c2
, unsigned a
)
637 a
+= a
>> (ALPHA_COLOR_LOOKUP_SHIFT
- 1);
638 #if (LCD_PIXELFORMAT == RGB565SWAPPED)
642 unsigned c1l
= (c1
| (c1
<< 16)) & 0x07e0f81f;
643 unsigned c2l
= (c2
| (c2
<< 16)) & 0x07e0f81f;
645 BLEND_START(p
, c1l
, a
);
646 BLEND_CONT(p
, c2l
, ALPHA_COLOR_LOOKUP_SIZE
+ 1 - a
);
648 p
= (p
>> ALPHA_COLOR_LOOKUP_SHIFT
) & 0x07e0f81f;
650 #if (LCD_PIXELFORMAT == RGB565SWAPPED)
657 /* Blend the given color with the value from the alpha_color_lookup table */
658 static inline unsigned blend_color(unsigned c
, unsigned a
)
660 return blend_two_colors(c
, current_vp
->fg_pattern
, a
);
663 /* Blend an image with an alpha channel
664 * if image is NULL, drawing will happen according to the drawmode
665 * src is the alpha channel (4bit per pixel) */
666 static void ICODE_ATTR
lcd_alpha_bitmap_part_mix(const fb_data
* image
,
667 const unsigned char *src
, int src_x
,
668 int src_y
, int x
, int y
,
669 int width
, int height
,
670 int stride_image
, int stride_src
)
672 fb_data
*dst
, *dst_row
;
673 const fb_data
*image_row
;
674 unsigned dmask
= 0x00000000;
675 int drmode
= current_vp
->drawmode
;
676 /* nothing to draw? */
677 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
678 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
680 /* initialize blending */
696 if (x
+ width
> current_vp
->width
)
697 width
= current_vp
->width
- x
;
698 if (y
+ height
> current_vp
->height
)
699 height
= current_vp
->height
- y
;
701 /* adjust for viewport */
705 #if defined(HAVE_VIEWPORT_CLIP)
706 /********************* Viewport on screen clipping ********************/
707 /* nothing to draw? */
708 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
709 || (x
+ width
<= 0) || (y
+ height
<= 0))
715 /* clip image in viewport in screen */
728 if (x
+ width
> LCD_WIDTH
)
729 width
= LCD_WIDTH
- x
;
730 if (y
+ height
> LCD_HEIGHT
)
731 height
= LCD_HEIGHT
- y
;
734 if (drmode
& DRMODE_INVERSEVID
)
737 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
739 /* sourcing from an image ignore drawmode.
740 * Set to DRMODE_BG as we use its code path in the switch below */
745 if (drmode
== DRMODE_BG
)
750 dst_row
= FBADDR(x
, y
);
752 int col
, row
= height
;
753 unsigned data
, pixels
;
754 unsigned skip_end
= (stride_src
- width
);
755 unsigned skip_start
= src_y
* stride_src
+ src_x
;
756 unsigned skip_start_image
= STRIDE_MAIN(src_y
* stride_image
+ src_x
,
757 src_x
* stride_image
+ src_y
);
759 #ifdef ALPHA_BITMAP_READ_WORDS
760 uint32_t *src_w
= (uint32_t *)((uintptr_t)src
& ~3);
761 skip_start
+= ALPHA_COLOR_PIXEL_PER_BYTE
* ((uintptr_t)src
& 3);
762 src_w
+= skip_start
/ ALPHA_COLOR_PIXEL_PER_WORD
;
763 data
= letoh32(*src_w
++) ^ dmask
;
764 pixels
= skip_start
% ALPHA_COLOR_PIXEL_PER_WORD
;
766 src
+= skip_start
/ ALPHA_COLOR_PIXEL_PER_BYTE
;
768 pixels
= skip_start
% ALPHA_COLOR_PIXEL_PER_BYTE
;
770 data
>>= pixels
* ALPHA_COLOR_LOOKUP_SHIFT
;
771 #ifdef ALPHA_BITMAP_READ_WORDS
775 image
+= skip_start_image
;
778 /* go through the rows and update each pixel */
786 image_row
+= STRIDE_MAIN(stride_image
,1);
790 #ifdef ALPHA_BITMAP_READ_WORDS
791 #define UPDATE_SRC_ALPHA do { \
793 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
796 data = letoh32(*src_w++) ^ dmask; \
797 pixels = ALPHA_COLOR_PIXEL_PER_WORD; \
800 #elif ALPHA_COLOR_PIXEL_PER_BYTE == 2
801 #define UPDATE_SRC_ALPHA do { \
803 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
805 data = *(++src) ^ dmask; \
808 #define UPDATE_SRC_ALPHA do { \
809 if (pixels = (++pixels % ALPHA_COLOR_PIXEL_PER_BYTE)) \
810 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \
812 data = *(++src) ^ dmask; \
815 /* we don't want to have this in our inner
816 * loop and the codesize increase is minimal */
819 case DRMODE_COMPLEMENT
:
822 *dst
= blend_two_colors(*dst
, ~(*dst
),
823 data
& ALPHA_COLOR_LOOKUP_SIZE
);
832 uintptr_t bo
= lcd_backdrop_offset
;
835 *dst
= blend_two_colors(*(fb_data
*)((uintptr_t)dst
+ bo
),
836 *image
, data
& ALPHA_COLOR_LOOKUP_SIZE
);
839 image
+= STRIDE_MAIN(1, stride_image
);
848 *dst
= blend_two_colors(current_vp
->bg_pattern
,
849 *image
, data
& ALPHA_COLOR_LOOKUP_SIZE
);
851 image
+= STRIDE_MAIN(1, stride_image
);
860 *dst
= blend_color(*dst
, data
& ALPHA_COLOR_LOOKUP_SIZE
);
869 uintptr_t bo
= lcd_backdrop_offset
;
872 *dst
= blend_color(*(fb_data
*)((uintptr_t)dst
+ bo
),
873 data
& ALPHA_COLOR_LOOKUP_SIZE
);
883 *dst
= blend_color(current_vp
->bg_pattern
,
884 data
& ALPHA_COLOR_LOOKUP_SIZE
);
892 #ifdef ALPHA_BITMAP_READ_WORDS
893 if (skip_end
< pixels
)
896 data
>>= skip_end
* ALPHA_COLOR_LOOKUP_SHIFT
;
898 pixels
= skip_end
- pixels
;
899 src_w
+= pixels
/ ALPHA_COLOR_PIXEL_PER_WORD
;
900 pixels
%= ALPHA_COLOR_PIXEL_PER_WORD
;
901 data
= letoh32(*src_w
++) ^ dmask
;
902 data
>>= pixels
* ALPHA_COLOR_LOOKUP_SHIFT
;
909 if (pixels
>= ALPHA_COLOR_PIXEL_PER_BYTE
)
911 src
+= pixels
/ ALPHA_COLOR_PIXEL_PER_BYTE
;
912 pixels
%= ALPHA_COLOR_PIXEL_PER_BYTE
;
914 data
>>= pixels
* ALPHA_COLOR_LOOKUP_SHIFT
;
916 data
>>= skip_end
* ALPHA_COLOR_LOOKUP_SHIFT
;
924 /* Draw a full native bitmap */
925 void lcd_bitmap(const fb_data
*src
, int x
, int y
, int width
, int height
)
927 lcd_bitmap_part(src
, 0, 0, STRIDE(SCREEN_MAIN
, width
, height
), x
, y
, width
, height
);
930 /* Draw a full native bitmap with a transparent color */
931 void lcd_bitmap_transparent(const fb_data
*src
, int x
, int y
,
932 int width
, int height
)
934 lcd_bitmap_transparent_part(src
, 0, 0,
935 STRIDE(SCREEN_MAIN
, width
, height
), x
, y
, width
, height
);
938 /* draw alpha bitmap for anti-alias font */
939 void ICODE_ATTR
lcd_alpha_bitmap_part(const unsigned char *src
, int src_x
,
940 int src_y
, int stride
, int x
, int y
,
941 int width
, int height
)
943 lcd_alpha_bitmap_part_mix(NULL
, src
, src_x
, src_y
, x
, y
, width
, height
, 0, stride
);
946 /* Draw a partial bitmap (mono or native) including alpha channel */
947 void ICODE_ATTR
lcd_bmp_part(const struct bitmap
* bm
, int src_x
, int src_y
,
948 int x
, int y
, int width
, int height
)
950 int bitmap_stride
= STRIDE_MAIN(bm
->width
, bm
->height
);
951 if (bm
->format
== FORMAT_MONO
)
952 lcd_mono_bitmap_part(bm
->data
, src_x
, src_y
, bitmap_stride
, x
, y
, width
, height
);
953 else if (bm
->alpha_offset
> 0)
954 lcd_alpha_bitmap_part_mix((fb_data
*)bm
->data
, bm
->data
+bm
->alpha_offset
,
955 src_x
, src_y
, x
, y
, width
, height
,
956 bitmap_stride
, ALIGN_UP(bm
->width
, 2));
958 lcd_bitmap_transparent_part((fb_data
*)bm
->data
,
959 src_x
, src_y
, bitmap_stride
, x
, y
, width
, height
);
962 /* Draw a native bitmap with alpha channel */
963 void ICODE_ATTR
lcd_bmp(const struct bitmap
*bmp
, int x
, int y
)
965 lcd_bmp_part(bmp
, 0, 0, x
, y
, bmp
->width
, bmp
->height
);
969 * |R| |1.000000 -0.000001 1.402000| |Y'|
970 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
971 * |B| |1.000000 1.772000 0.000000| |Pr|
972 * Scaled, normalized, rounded and tweaked to yield RGB 565:
973 * |R| |74 0 101| |Y' - 16| >> 9
974 * |G| = |74 -24 -51| |Cb - 128| >> 8
975 * |B| |74 128 0| |Cr - 128| >> 9
983 static inline int clamp(int val
, int min
, int max
)
994 * weak attribute doesn't work for win32 as of gcc 4.6.2 and binutils 2.21.52
995 * When building win32 simulators, we won't be using an optimized version of
996 * lcd_blit_yuv(), so just don't use the weak attribute.
998 __attribute__((weak
))
1000 void lcd_yuv_set_options(unsigned options
)
1005 /* Draw a partial YUV colour bitmap */
1007 __attribute__((weak
))
1009 void lcd_blit_yuv(unsigned char * const src
[3],
1010 int src_x
, int src_y
, int stride
,
1011 int x
, int y
, int width
, int height
)
1013 const unsigned char *ysrc
, *usrc
, *vsrc
;
1015 fb_data
*dst
, *row_end
;
1018 /* width and height must be >= 2 and an even number */
1020 linecounter
= height
>> 1;
1022 #if LCD_WIDTH >= LCD_HEIGHT
1024 row_end
= dst
+ width
;
1026 dst
= FBADDR(LCD_WIDTH
- y
- 1, x
);
1027 row_end
= dst
+ LCD_WIDTH
* width
;
1031 ysrc
= src
[0] + z
+ src_x
;
1032 usrc
= src
[1] + (z
>> 2) + (src_x
>> 1);
1033 vsrc
= src
[2] + (usrc
- src
[1]);
1035 /* stride => amount to jump from end of last row to start of next */
1038 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
1044 int y
, cb
, cr
, rv
, guv
, bu
, r
, g
, b
;
1046 y
= YFAC
*(*ysrc
++ - 16);
1051 guv
= GUFAC
*cb
+ GVFAC
*cr
;
1058 if ((unsigned)(r
| g
| b
) > 64*256-1)
1060 r
= clamp(r
, 0, 64*256-1);
1061 g
= clamp(g
, 0, 64*256-1);
1062 b
= clamp(b
, 0, 64*256-1);
1065 *dst
= LCD_RGBPACK_LCD(r
>> 9, g
>> 8, b
>> 9);
1067 #if LCD_WIDTH >= LCD_HEIGHT
1073 y
= YFAC
*(*ysrc
++ - 16);
1078 if ((unsigned)(r
| g
| b
) > 64*256-1)
1080 r
= clamp(r
, 0, 64*256-1);
1081 g
= clamp(g
, 0, 64*256-1);
1082 b
= clamp(b
, 0, 64*256-1);
1085 *dst
= LCD_RGBPACK_LCD(r
>> 9, g
>> 8, b
>> 9);
1087 #if LCD_WIDTH >= LCD_HEIGHT
1093 while (dst
< row_end
);
1099 #if LCD_WIDTH >= LCD_HEIGHT
1100 row_end
+= LCD_WIDTH
;
1101 dst
+= LCD_WIDTH
- width
;
1104 dst
-= LCD_WIDTH
*width
+ 1;
1109 int y
, cb
, cr
, rv
, guv
, bu
, r
, g
, b
;
1111 y
= YFAC
*(*ysrc
++ - 16);
1116 guv
= GUFAC
*cb
+ GVFAC
*cr
;
1123 if ((unsigned)(r
| g
| b
) > 64*256-1)
1125 r
= clamp(r
, 0, 64*256-1);
1126 g
= clamp(g
, 0, 64*256-1);
1127 b
= clamp(b
, 0, 64*256-1);
1130 *dst
= LCD_RGBPACK_LCD(r
>> 9, g
>> 8, b
>> 9);
1132 #if LCD_WIDTH >= LCD_HEIGHT
1138 y
= YFAC
*(*ysrc
++ - 16);
1143 if ((unsigned)(r
| g
| b
) > 64*256-1)
1145 r
= clamp(r
, 0, 64*256-1);
1146 g
= clamp(g
, 0, 64*256-1);
1147 b
= clamp(b
, 0, 64*256-1);
1150 *dst
= LCD_RGBPACK_LCD(r
>> 9, g
>> 8, b
>> 9);
1152 #if LCD_WIDTH >= LCD_HEIGHT
1158 while (dst
< row_end
);
1161 usrc
+= stride
>> 1;
1162 vsrc
+= stride
>> 1;
1164 #if LCD_WIDTH >= LCD_HEIGHT
1165 row_end
+= LCD_WIDTH
;
1166 dst
+= LCD_WIDTH
- width
;
1169 dst
-= LCD_WIDTH
*width
+ 1;
1172 while (--linecounter
> 0);
1174 #if LCD_WIDTH >= LCD_HEIGHT
1175 lcd_update_rect(x
, y
, width
, height
);
1177 lcd_update_rect(LCD_WIDTH
- y
- height
, x
, height
, width
);