1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * LCD driver for horizontally-packed 2bpp greyscale display
12 * Based on code from the rockbox lcd's driver
14 * Copyright (c) 2006 Seven Le Mesle (sevlm@free.fr)
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied.
24 ****************************************************************************/
36 #include "rbunicode.h"
38 #include "scroll_engine.h"
42 unsigned char lcd_framebuffer
[LCD_FBHEIGHT
][LCD_FBWIDTH
] IRAM_LCDFRAMEBUFFER
;
44 static const unsigned char pixmask
[4] ICONST_ATTR
= {
45 0xC0, 0x30, 0x0C, 0x03
48 static fb_data
* lcd_backdrop
= NULL
;
49 static long lcd_backdrop_offset IDATA_ATTR
= 0;
51 static struct viewport default_vp
=
57 .font
= FONT_SYSFIXED
,
58 .drawmode
= DRMODE_SOLID
,
59 .fg_pattern
= LCD_DEFAULT_FG
,
60 .bg_pattern
= LCD_DEFAULT_BG
63 static struct viewport
* current_vp IBSS_ATTR
;
64 static unsigned fg_pattern IBSS_ATTR
;
65 static unsigned bg_pattern IBSS_ATTR
;
70 /* Initialise the viewport */
71 lcd_set_viewport(NULL
);
74 /* Call device specific init */
81 void lcd_set_viewport(struct viewport
* vp
)
84 current_vp
= &default_vp
;
88 fg_pattern
= 0x55 * (~current_vp
->fg_pattern
& 3);
89 bg_pattern
= 0x55 * (~current_vp
->bg_pattern
& 3);
91 #if defined(SIMULATOR)
92 /* Force the viewport to be within bounds. If this happens it should
93 * be considered an error - the viewport will not draw as it might be
96 if((unsigned) current_vp
->x
> (unsigned) LCD_WIDTH
97 || (unsigned) current_vp
->y
> (unsigned) LCD_HEIGHT
98 || current_vp
->x
+ current_vp
->width
> LCD_WIDTH
99 || current_vp
->y
+ current_vp
->height
> LCD_HEIGHT
)
101 #if !defined(HAVE_VIEWPORT_CLIP)
106 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
107 current_vp
->x
, current_vp
->y
,
108 current_vp
->width
, current_vp
->height
);
114 void lcd_update_viewport(void)
116 lcd_update_rect(current_vp
->x
, current_vp
->y
,
117 current_vp
->width
, current_vp
->height
);
120 void lcd_update_viewport_rect(int x
, int y
, int width
, int height
)
122 lcd_update_rect(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
125 /*** parameter handling ***/
127 void lcd_set_drawmode(int mode
)
129 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
132 int lcd_get_drawmode(void)
134 return current_vp
->drawmode
;
137 void lcd_set_foreground(unsigned brightness
)
139 current_vp
->fg_pattern
= brightness
;
140 fg_pattern
= 0x55 * (~brightness
& 3);
143 unsigned lcd_get_foreground(void)
145 return current_vp
->fg_pattern
;
148 void lcd_set_background(unsigned brightness
)
150 current_vp
->bg_pattern
= brightness
;
151 bg_pattern
= 0x55 * (~brightness
& 3);
154 unsigned lcd_get_background(void)
156 return current_vp
->bg_pattern
;
159 void lcd_set_drawinfo(int mode
, unsigned fg_brightness
, unsigned bg_brightness
)
161 lcd_set_drawmode(mode
);
162 lcd_set_foreground(fg_brightness
);
163 lcd_set_background(bg_brightness
);
166 int lcd_getwidth(void)
168 return current_vp
->width
;
171 int lcd_getheight(void)
173 return current_vp
->height
;
176 void lcd_setfont(int newfont
)
178 current_vp
->font
= newfont
;
181 int lcd_getfont(void)
183 return current_vp
->font
;
186 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
188 return font_getstringsize(str
, w
, h
, current_vp
->font
);
191 /*** low-level drawing functions ***/
193 static void setpixel(int x
, int y
)
195 unsigned mask
= pixmask
[x
& 3];
196 fb_data
*address
= &lcd_framebuffer
[y
][x
>>2];
197 unsigned data
= *address
;
199 *address
= data
^ ((data
^ fg_pattern
) & mask
);
202 static void clearpixel(int x
, int y
)
204 unsigned mask
= pixmask
[x
& 3];
205 fb_data
*address
= &lcd_framebuffer
[y
][x
>>2];
206 unsigned data
= *address
;
208 *address
= data
^ ((data
^ bg_pattern
) & mask
);
211 static void clearimgpixel(int x
, int y
)
213 unsigned mask
= pixmask
[x
& 3];
214 fb_data
*address
= &lcd_framebuffer
[y
][x
>>2];
215 unsigned data
= *address
;
217 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
);
220 static void flippixel(int x
, int y
)
222 unsigned mask
= pixmask
[x
& 3];
223 fb_data
*address
= &lcd_framebuffer
[y
][x
>>2];
228 static void nopixel(int x
, int y
)
234 lcd_pixelfunc_type
* const lcd_pixelfuncs_bgcolor
[8] = {
235 flippixel
, nopixel
, setpixel
, setpixel
,
236 nopixel
, clearpixel
, nopixel
, clearpixel
239 lcd_pixelfunc_type
* const lcd_pixelfuncs_backdrop
[8] = {
240 flippixel
, nopixel
, setpixel
, setpixel
,
241 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
244 lcd_pixelfunc_type
* const * lcd_pixelfuncs
= lcd_pixelfuncs_bgcolor
;
247 /* 'mask' and 'bits' contain 2 bits per pixel */
248 static void ICODE_ATTR
flipblock(fb_data
*address
, unsigned mask
,
251 *address
^= bits
& mask
;
254 static void ICODE_ATTR
bgblock(fb_data
*address
, unsigned mask
,
257 unsigned data
= *address
;
259 *address
= data
^ ((data
^ bg_pattern
) & mask
& ~bits
);
262 static void ICODE_ATTR
bgimgblock(fb_data
*address
, unsigned mask
,
265 unsigned data
= *address
;
267 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
& ~bits
);
270 static void ICODE_ATTR
fgblock(fb_data
*address
, unsigned mask
,
273 unsigned data
= *address
;
275 *address
= data
^ ((data
^ fg_pattern
) & mask
& bits
);
278 static void ICODE_ATTR
solidblock(fb_data
*address
, unsigned mask
,
281 unsigned data
= *address
;
282 unsigned bgp
= bg_pattern
;
284 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
285 *address
= data
^ ((data
^ bits
) & mask
);
288 static void ICODE_ATTR
solidimgblock(fb_data
*address
, unsigned mask
,
291 unsigned data
= *address
;
292 unsigned bgp
= *(address
+ lcd_backdrop_offset
);
294 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
295 *address
= data
^ ((data
^ bits
) & mask
);
298 static void ICODE_ATTR
flipinvblock(fb_data
*address
, unsigned mask
,
301 *address
^= ~bits
& mask
;
304 static void ICODE_ATTR
bginvblock(fb_data
*address
, unsigned mask
,
307 unsigned data
= *address
;
309 *address
= data
^ ((data
^ bg_pattern
) & mask
& bits
);
312 static void ICODE_ATTR
bgimginvblock(fb_data
*address
, unsigned mask
,
315 unsigned data
= *address
;
317 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
& bits
);
320 static void ICODE_ATTR
fginvblock(fb_data
*address
, unsigned mask
,
323 unsigned data
= *address
;
325 *address
= data
^ ((data
^ fg_pattern
) & mask
& ~bits
);
328 static void ICODE_ATTR
solidinvblock(fb_data
*address
, unsigned mask
,
331 unsigned data
= *address
;
332 unsigned fgp
= fg_pattern
;
334 bits
= fgp
^ ((fgp
^ bg_pattern
) & bits
);
335 *address
= data
^ ((data
^ bits
) & mask
);
338 static void ICODE_ATTR
solidimginvblock(fb_data
*address
, unsigned mask
,
341 unsigned data
= *address
;
342 unsigned fgp
= fg_pattern
;
344 bits
= fgp
^ ((fgp
^ *(address
+ lcd_backdrop_offset
)) & bits
);
345 *address
= data
^ ((data
^ bits
) & mask
);
348 lcd_blockfunc_type
* const lcd_blockfuncs_bgcolor
[8] = {
349 flipblock
, bgblock
, fgblock
, solidblock
,
350 flipinvblock
, bginvblock
, fginvblock
, solidinvblock
353 lcd_blockfunc_type
* const lcd_blockfuncs_backdrop
[8] = {
354 flipblock
, bgimgblock
, fgblock
, solidimgblock
,
355 flipinvblock
, bgimginvblock
, fginvblock
, solidimginvblock
358 lcd_blockfunc_type
* const * lcd_blockfuncs
= lcd_blockfuncs_bgcolor
;
361 void lcd_set_backdrop(fb_data
* backdrop
)
363 lcd_backdrop
= backdrop
;
366 lcd_backdrop_offset
= (long)backdrop
- (long)lcd_framebuffer
;
367 lcd_pixelfuncs
= lcd_pixelfuncs_backdrop
;
368 lcd_blockfuncs
= lcd_blockfuncs_backdrop
;
372 lcd_backdrop_offset
= 0;
373 lcd_pixelfuncs
= lcd_pixelfuncs_bgcolor
;
374 lcd_blockfuncs
= lcd_blockfuncs_bgcolor
;
378 fb_data
* lcd_get_backdrop(void)
384 static inline void setblock(fb_data
*address
, unsigned mask
, unsigned bits
)
386 unsigned data
= *address
;
389 *address
= data
^ (bits
& mask
);
392 /*** drawing functions ***/
394 /* Clear the whole display */
395 void lcd_clear_display(void)
397 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
399 memset(lcd_framebuffer
, fg_pattern
, sizeof lcd_framebuffer
);
404 memcpy(lcd_framebuffer
, lcd_backdrop
, sizeof lcd_framebuffer
);
406 memset(lcd_framebuffer
, bg_pattern
, sizeof lcd_framebuffer
);
409 lcd_scroll_info
.lines
= 0;
412 /* Clear the current viewport */
413 void lcd_clear_viewport(void)
417 if (current_vp
== &default_vp
)
423 lastmode
= current_vp
->drawmode
;
425 /* Invert the INVERSEVID bit and set basic mode to SOLID */
426 current_vp
->drawmode
= (~lastmode
& DRMODE_INVERSEVID
) |
429 lcd_fillrect(0, 0, current_vp
->width
, current_vp
->height
);
431 current_vp
->drawmode
= lastmode
;
433 lcd_scroll_stop(current_vp
);
437 /* Set a single pixel */
438 void lcd_drawpixel(int x
, int y
)
440 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
441 && ((unsigned)y
< (unsigned)current_vp
->height
)
442 #if defined(HAVE_VIEWPORT_CLIP)
443 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
444 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
447 lcd_pixelfuncs
[current_vp
->drawmode
](current_vp
->x
+ x
, current_vp
->y
+ y
);
451 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
459 lcd_pixelfunc_type
*pfunc
= lcd_pixelfuncs
[current_vp
->drawmode
];
461 deltay
= abs(y2
- y1
);
464 DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n");
465 lcd_hline(x1
, x2
, y1
);
468 deltax
= abs(x2
- x1
);
471 DEBUGF("lcd_drawline() called for vertical line - optimisation.\n");
472 lcd_vline(x1
, y1
, y2
);
478 if (deltax
>= deltay
)
481 d
= 2 * deltay
- deltax
;
483 dinc2
= (deltay
- deltax
) * 2;
490 d
= 2 * deltax
- deltay
;
492 dinc2
= (deltax
- deltay
) * 2;
496 numpixels
++; /* include endpoints */
513 for (i
= 0; i
< numpixels
; i
++)
515 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
516 && ((unsigned)y
< (unsigned)current_vp
->height
)
517 #if defined(HAVE_VIEWPORT_CLIP)
518 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
519 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
522 pfunc(current_vp
->x
+ x
, current_vp
->y
+ y
);
539 /* Draw a horizontal line (optimised) */
540 void lcd_hline(int x1
, int x2
, int y
)
544 unsigned mask
, mask_right
;
545 lcd_blockfunc_type
*bfunc
;
555 /******************** In viewport clipping **********************/
556 /* nothing to draw? */
557 if (((unsigned)y
>= (unsigned)current_vp
->height
) || (x1
>= current_vp
->width
)
563 if (x2
>= current_vp
->width
)
564 x2
= current_vp
->width
-1;
566 /* adjust to viewport */
571 #if defined(HAVE_VIEWPORT_CLIP)
572 /********************* Viewport on screen clipping ********************/
573 /* nothing to draw? */
574 if (((unsigned)y
>= (unsigned) LCD_HEIGHT
) || (x1
>= LCD_WIDTH
)
585 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
586 dst
= &lcd_framebuffer
[y
][x1
>>2];
588 mask
= 0xFFu
>> (2 * (x1
& 3));
589 mask_right
= 0xFFu
<< (2 * (~nx
& 3));
591 for (; nx
>= 4; nx
-= 4)
593 bfunc(dst
++, mask
, 0xFFu
);
597 bfunc(dst
, mask
, 0xFFu
);
600 /* Draw a vertical line (optimised) */
601 void lcd_vline(int x
, int y1
, int y2
)
604 unsigned char *dst
, *dst_end
;
606 lcd_blockfunc_type
*bfunc
;
616 /******************** In viewport clipping **********************/
617 /* nothing to draw? */
618 if (((unsigned)x
>= (unsigned)current_vp
->width
) || (y1
>= current_vp
->height
)
624 if (y2
>= current_vp
->height
)
625 y2
= current_vp
->height
-1;
627 /* adjust for viewport */
632 #if defined(HAVE_VIEWPORT_CLIP)
633 /********************* Viewport on screen clipping ********************/
634 /* nothing to draw? */
635 if (( (unsigned) x
>= (unsigned)LCD_WIDTH
) || (y1
>= LCD_HEIGHT
)
642 if (y2
>= LCD_HEIGHT
)
646 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
647 dst
= &lcd_framebuffer
[y1
][x
>>2];
648 mask
= pixmask
[x
& 3];
650 dst_end
= dst
+ (y2
- y1
) * LCD_FBWIDTH
;
653 bfunc(dst
, mask
, 0xFFu
);
656 while (dst
<= dst_end
);
659 /* Draw a rectangular box */
660 void lcd_drawrect(int x
, int y
, int width
, int height
)
662 if ((width
<= 0) || (height
<= 0))
665 int x2
= x
+ width
- 1;
666 int y2
= y
+ height
- 1;
669 lcd_vline(x2
, y
, y2
);
671 lcd_hline(x
, x2
, y2
);
674 /* Fill a rectangular area */
675 void lcd_fillrect(int x
, int y
, int width
, int height
)
678 unsigned char *dst
, *dst_end
;
679 unsigned mask
, mask_right
;
680 lcd_blockfunc_type
*bfunc
;
682 /******************** In viewport clipping **********************/
683 /* nothing to draw? */
684 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) || (y
>= current_vp
->height
)
685 || (x
+ width
<= 0) || (y
+ height
<= 0))
698 if (x
+ width
> current_vp
->width
)
699 width
= current_vp
->width
- x
;
700 if (y
+ height
> current_vp
->height
)
701 height
= current_vp
->height
- y
;
703 /* adjust for viewport */
707 #if defined(HAVE_VIEWPORT_CLIP)
708 /********************* Viewport on screen clipping ********************/
709 /* nothing to draw? */
710 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
711 || (x
+ width
<= 0) || (y
+ height
<= 0))
714 /* clip image in viewport in screen */
725 if (x
+ width
> LCD_WIDTH
)
726 width
= LCD_WIDTH
- x
;
727 if (y
+ height
> LCD_HEIGHT
)
728 height
= LCD_HEIGHT
- y
;
731 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
732 dst
= &lcd_framebuffer
[y
][x
>>2];
733 nx
= width
- 1 + (x
& 3);
734 mask
= 0xFFu
>> (2 * (x
& 3));
735 mask_right
= 0xFFu
<< (2 * (~nx
& 3));
737 for (; nx
>= 4; nx
-= 4)
739 unsigned char *dst_col
= dst
;
741 dst_end
= dst_col
+ height
* LCD_FBWIDTH
;
744 bfunc(dst_col
, mask
, 0xFFu
);
745 dst_col
+= LCD_FBWIDTH
;
747 while (dst_col
< dst_end
);
754 dst_end
= dst
+ height
* LCD_FBWIDTH
;
757 bfunc(dst
, mask
, 0xFFu
);
760 while (dst
< dst_end
);
763 /* About Rockbox' internal monochrome bitmap format:
765 * A bitmap contains one bit for every pixel that defines if that pixel is
766 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
768 * The bytes are stored in row-major order, with byte 0 being top left,
769 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
770 * 0..7, the second row defines pixel row 8..15 etc. */
772 /* Draw a partial monochrome bitmap */
773 void ICODE_ATTR
lcd_mono_bitmap_part(const unsigned char *src
, int src_x
,
774 int src_y
, int stride
, int x
, int y
,
775 int width
, int height
)
777 const unsigned char *src_end
;
778 fb_data
*dst
, *dst_end
;
779 unsigned dmask
= 0x100; /* bit 8 == sentinel */
781 int drmode
= current_vp
->drawmode
;
783 /******************** Image in viewport clipping **********************/
784 /* nothing to draw? */
785 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
786 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
801 if (x
+ width
> current_vp
->width
)
802 width
= current_vp
->width
- x
;
803 if (y
+ height
> current_vp
->height
)
804 height
= current_vp
->height
- y
;
806 x
+= current_vp
->x
; /* adjust for viewport */
807 y
+= current_vp
->y
; /* adjust for viewport */
809 #if defined(HAVE_VIEWPORT_CLIP)
810 /********************* Viewport on screen clipping ********************/
811 /* nothing to draw? */
812 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
813 || (x
+ width
<= 0) || (y
+ height
<= 0))
816 /* clip image in viewport in screen */
829 if (x
+ width
> LCD_WIDTH
)
830 width
= LCD_WIDTH
- x
;
831 if (y
+ height
> LCD_HEIGHT
)
832 height
= LCD_HEIGHT
- y
;
835 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
837 src_end
= src
+ width
;
839 dst
= &lcd_framebuffer
[y
][x
>> 2];
840 dst_end
= dst
+ height
* LCD_FBWIDTH
;
841 dst_mask
= pixmask
[x
& 3];
843 if (drmode
& DRMODE_INVERSEVID
)
845 dmask
= 0x1ff; /* bit 8 == sentinel */
846 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
851 const unsigned char *src_col
= src
++;
852 unsigned data
= (*src_col
^ dmask
) >> src_y
;
853 fb_data
*dst_col
= dst
;
857 #define UPDATE_SRC do { \
859 if (data == 0x001) { \
861 data = *src_col ^ dmask; \
867 case DRMODE_COMPLEMENT
:
871 *dst_col
^= dst_mask
;
873 dst_col
+= LCD_FBWIDTH
;
876 while (dst_col
< dst_end
);
882 bo
= lcd_backdrop_offset
;
887 unsigned block
= *dst_col
;
889 ^ ((block
^ *(dst_col
+ bo
)) & dst_mask
);
891 dst_col
+= LCD_FBWIDTH
;
894 while (dst_col
< dst_end
);
903 unsigned block
= *dst_col
;
904 *dst_col
= block
^ ((block
^ bg
) & dst_mask
);
906 dst_col
+= LCD_FBWIDTH
;
909 while (dst_col
< dst_end
);
919 unsigned block
= *dst_col
;
920 *dst_col
= block
^ ((block
^ fg
) & dst_mask
);
922 dst_col
+= LCD_FBWIDTH
;
925 while (dst_col
< dst_end
);
932 bo
= lcd_backdrop_offset
;
935 unsigned block
= *dst_col
;
936 *dst_col
= block
^ ((block
^ ((data
& 0x01) ?
937 fg
: *(dst_col
+ bo
))) & dst_mask
);
939 dst_col
+= LCD_FBWIDTH
;
942 while (dst_col
< dst_end
);
949 unsigned block
= *dst_col
;
950 *dst_col
= block
^ ((block
^ ((data
& 0x01) ?
951 fg
: bg
)) & dst_mask
);
953 dst_col
+= LCD_FBWIDTH
;
956 while (dst_col
< dst_end
);
967 while (src
< src_end
);
970 /* Draw a full monochrome bitmap */
971 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
973 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
976 /* About Rockbox' internal native bitmap format:
978 * A bitmap contains two bits for every pixel. 00 = white, 01 = light grey,
979 * 10 = dark grey, 11 = black. Bits within a byte are arranged horizontally,
981 * The bytes are stored in row-major order, with byte 0 being top left,
982 * byte 1 2nd from left etc. Each row of bytes defines one pixel row.
984 * This is the same as the internal lcd hw format. */
986 /* Draw a partial native bitmap */
987 void ICODE_ATTR
lcd_bitmap_part(const unsigned char *src
, int src_x
,
988 int src_y
, int stride
, int x
, int y
,
989 int width
, int height
)
992 unsigned char *dst
, *dst_end
;
993 unsigned mask
, mask_right
;
995 /******************** Image in viewport clipping **********************/
996 /* nothing to draw? */
997 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
998 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
1013 if (x
+ width
> current_vp
->width
)
1014 width
= current_vp
->width
- x
;
1015 if (y
+ height
> current_vp
->height
)
1016 height
= current_vp
->height
- y
;
1018 /* adjust for viewport */
1022 #if defined(HAVE_VIEWPORT_CLIP)
1023 /********************* Viewport on screen clipping ********************/
1024 /* nothing to draw? */
1025 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
1026 || (x
+ width
<= 0) || (y
+ height
<= 0))
1029 /* clip image in viewport in screen */
1042 if (x
+ width
> LCD_WIDTH
)
1043 width
= LCD_WIDTH
- x
;
1044 if (y
+ height
> LCD_HEIGHT
)
1045 height
= LCD_HEIGHT
- y
;
1048 stride
= (stride
+ 3) >> 2; /* convert to no. of bytes */
1050 src
+= stride
* src_y
+ (src_x
>> 2); /* move starting point */
1053 dst
= &lcd_framebuffer
[y
][x
>>2];
1055 nx
= width
- 1 + shift
+ src_x
;
1057 mask
= 0xFF00u
>> (2 * (shift
+ src_x
));
1058 mask_right
= 0xFFu
<< (2 * (~nx
& 3));
1061 dst_end
= dst
+ height
* LCD_FBWIDTH
;
1064 const unsigned char *src_row
= src
;
1065 unsigned char *dst_row
= dst
;
1066 unsigned mask_row
= mask
>> 8;
1069 for (x
= nx
; x
>= 4; x
-= 4)
1071 data
= (data
<< 8) | *src_row
++;
1073 if (mask_row
& 0xFF)
1075 setblock(dst_row
, mask_row
, data
>> shift
);
1083 data
= (data
<< 8) | *src_row
;
1084 setblock(dst_row
, mask_row
& mask_right
, data
>> shift
);
1089 while (dst
< dst_end
);
1092 /* Draw a full native bitmap */
1093 void lcd_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
1095 lcd_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
1098 #include "lcd-bitmap-common.c"