1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2004 by Linus Nielsen Feltzing
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
33 #include "rbunicode.h"
35 #include "scroll_engine.h"
39 fb_data lcd_static_framebuffer
[LCD_FBHEIGHT
][LCD_FBWIDTH
] IRAM_LCDFRAMEBUFFER
;
40 fb_data
*lcd_framebuffer
= &lcd_static_framebuffer
[0][0];
42 const unsigned char lcd_dibits
[16] ICONST_ATTR
= {
43 0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F,
44 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF
47 static const unsigned char pixmask
[4] ICONST_ATTR
= {
48 0x03, 0x0C, 0x30, 0xC0
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
66 static struct viewport
* current_vp IBSS_ATTR
;
67 static unsigned fg_pattern IBSS_ATTR
;
68 static unsigned bg_pattern IBSS_ATTR
;
73 /* Initialise the viewport */
74 lcd_set_viewport(NULL
);
77 /* Call device specific init */
84 void lcd_set_viewport(struct viewport
* vp
)
87 current_vp
= &default_vp
;
91 fg_pattern
= 0x55 * (~current_vp
->fg_pattern
& 3);
92 bg_pattern
= 0x55 * (~current_vp
->bg_pattern
& 3);
94 #if defined(SIMULATOR)
95 /* Force the viewport to be within bounds. If this happens it should
96 * be considered an error - the viewport will not draw as it might be
99 if((unsigned) current_vp
->x
> (unsigned) LCD_WIDTH
100 || (unsigned) current_vp
->y
> (unsigned) LCD_HEIGHT
101 || current_vp
->x
+ current_vp
->width
> LCD_WIDTH
102 || current_vp
->y
+ current_vp
->height
> LCD_HEIGHT
)
104 #if !defined(HAVE_VIEWPORT_CLIP)
109 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
110 current_vp
->x
, current_vp
->y
,
111 current_vp
->width
, current_vp
->height
);
117 void lcd_update_viewport(void)
119 lcd_update_rect(current_vp
->x
, current_vp
->y
,
120 current_vp
->width
, current_vp
->height
);
123 void lcd_update_viewport_rect(int x
, int y
, int width
, int height
)
125 lcd_update_rect(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
129 /*** parameter handling ***/
131 void lcd_set_drawmode(int mode
)
133 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
136 int lcd_get_drawmode(void)
138 return current_vp
->drawmode
;
141 void lcd_set_foreground(unsigned brightness
)
143 current_vp
->fg_pattern
= brightness
;
144 fg_pattern
= 0x55 * (~brightness
& 3);
147 unsigned lcd_get_foreground(void)
149 return current_vp
->fg_pattern
;
152 void lcd_set_background(unsigned brightness
)
154 current_vp
->bg_pattern
= brightness
;
155 bg_pattern
= 0x55 * (~brightness
& 3);
158 unsigned lcd_get_background(void)
160 return current_vp
->bg_pattern
;
163 void lcd_set_drawinfo(int mode
, unsigned fg_brightness
, unsigned bg_brightness
)
165 lcd_set_drawmode(mode
);
166 lcd_set_foreground(fg_brightness
);
167 lcd_set_background(bg_brightness
);
170 int lcd_getwidth(void)
172 return current_vp
->width
;
175 int lcd_getheight(void)
177 return current_vp
->height
;
180 void lcd_setfont(int newfont
)
182 current_vp
->font
= newfont
;
185 int lcd_getfont(void)
187 return current_vp
->font
;
190 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
192 return font_getstringsize(str
, w
, h
, current_vp
->font
);
195 /*** low-level drawing functions ***/
197 static void setpixel(int x
, int y
)
199 unsigned mask
= pixmask
[y
& 3];
200 fb_data
*address
= FBADDR(x
,y
>>2);
201 unsigned data
= *address
;
203 *address
= data
^ ((data
^ fg_pattern
) & mask
);
206 static void clearpixel(int x
, int y
)
208 unsigned mask
= pixmask
[y
& 3];
209 fb_data
*address
= FBADDR(x
,y
>>2);
210 unsigned data
= *address
;
212 *address
= data
^ ((data
^ bg_pattern
) & mask
);
215 static void clearimgpixel(int x
, int y
)
217 unsigned mask
= pixmask
[y
& 3];
218 fb_data
*address
= FBADDR(x
,y
>>2);
219 unsigned data
= *address
;
221 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
);
224 static void flippixel(int x
, int y
)
226 unsigned mask
= pixmask
[y
& 3];
227 fb_data
*address
= FBADDR(x
,y
>>2);
232 static void nopixel(int x
, int y
)
238 lcd_pixelfunc_type
* const lcd_pixelfuncs_bgcolor
[8] = {
239 flippixel
, nopixel
, setpixel
, setpixel
,
240 nopixel
, clearpixel
, nopixel
, clearpixel
243 lcd_pixelfunc_type
* const lcd_pixelfuncs_backdrop
[8] = {
244 flippixel
, nopixel
, setpixel
, setpixel
,
245 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
249 lcd_pixelfunc_type
* const * lcd_pixelfuncs
= lcd_pixelfuncs_bgcolor
;
251 /* 'mask' and 'bits' contain 2 bits per pixel */
252 static void ICODE_ATTR
flipblock(fb_data
*address
, unsigned mask
,
255 *address
^= bits
& mask
;
258 static void ICODE_ATTR
bgblock(fb_data
*address
, unsigned mask
,
261 unsigned data
= *address
;
263 *address
= data
^ ((data
^ bg_pattern
) & mask
& ~bits
);
266 static void ICODE_ATTR
bgimgblock(fb_data
*address
, unsigned mask
,
269 unsigned data
= *address
;
271 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
& ~bits
);
274 static void ICODE_ATTR
fgblock(fb_data
*address
, unsigned mask
,
277 unsigned data
= *address
;
279 *address
= data
^ ((data
^ fg_pattern
) & mask
& bits
);
282 static void ICODE_ATTR
solidblock(fb_data
*address
, unsigned mask
,
285 unsigned data
= *address
;
286 unsigned bgp
= bg_pattern
;
288 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
289 *address
= data
^ ((data
^ bits
) & mask
);
292 static void ICODE_ATTR
solidimgblock(fb_data
*address
, unsigned mask
,
295 unsigned data
= *address
;
296 unsigned bgp
= *(address
+ lcd_backdrop_offset
);
298 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
299 *address
= data
^ ((data
^ bits
) & mask
);
302 static void ICODE_ATTR
flipinvblock(fb_data
*address
, unsigned mask
,
305 *address
^= ~bits
& mask
;
308 static void ICODE_ATTR
bginvblock(fb_data
*address
, unsigned mask
,
311 unsigned data
= *address
;
313 *address
= data
^ ((data
^ bg_pattern
) & mask
& bits
);
316 static void ICODE_ATTR
bgimginvblock(fb_data
*address
, unsigned mask
,
319 unsigned data
= *address
;
321 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
& bits
);
324 static void ICODE_ATTR
fginvblock(fb_data
*address
, unsigned mask
,
327 unsigned data
= *address
;
329 *address
= data
^ ((data
^ fg_pattern
) & mask
& ~bits
);
332 static void ICODE_ATTR
solidinvblock(fb_data
*address
, unsigned mask
,
335 unsigned data
= *address
;
336 unsigned fgp
= fg_pattern
;
338 bits
= fgp
^ ((fgp
^ bg_pattern
) & bits
);
339 *address
= data
^ ((data
^ bits
) & mask
);
342 static void ICODE_ATTR
solidimginvblock(fb_data
*address
, unsigned mask
,
345 unsigned data
= *address
;
346 unsigned fgp
= fg_pattern
;
348 bits
= fgp
^ ((fgp
^ *(address
+ lcd_backdrop_offset
)) & bits
);
349 *address
= data
^ ((data
^ bits
) & mask
);
352 lcd_blockfunc_type
* const lcd_blockfuncs_bgcolor
[8] = {
353 flipblock
, bgblock
, fgblock
, solidblock
,
354 flipinvblock
, bginvblock
, fginvblock
, solidinvblock
357 lcd_blockfunc_type
* const lcd_blockfuncs_backdrop
[8] = {
358 flipblock
, bgimgblock
, fgblock
, solidimgblock
,
359 flipinvblock
, bgimginvblock
, fginvblock
, solidimginvblock
362 lcd_blockfunc_type
* const * lcd_blockfuncs
= lcd_blockfuncs_bgcolor
;
365 void lcd_set_backdrop(fb_data
* backdrop
)
367 lcd_backdrop
= backdrop
;
370 lcd_backdrop_offset
= (long)backdrop
- (long)lcd_framebuffer
;
371 lcd_pixelfuncs
= lcd_pixelfuncs_backdrop
;
372 lcd_blockfuncs
= lcd_blockfuncs_backdrop
;
376 lcd_backdrop_offset
= 0;
377 lcd_pixelfuncs
= lcd_pixelfuncs_bgcolor
;
378 lcd_blockfuncs
= lcd_blockfuncs_bgcolor
;
382 fb_data
* lcd_get_backdrop(void)
388 static inline void setblock(fb_data
*address
, unsigned mask
, unsigned bits
)
390 unsigned data
= *address
;
393 *address
= data
^ (bits
& mask
);
396 /*** drawing functions ***/
398 /* Clear the whole display */
399 void lcd_clear_display(void)
401 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
403 memset(lcd_framebuffer
, fg_pattern
, FRAMEBUFFER_SIZE
);
408 memcpy(lcd_framebuffer
, lcd_backdrop
, FRAMEBUFFER_SIZE
);
410 memset(lcd_framebuffer
, bg_pattern
, FRAMEBUFFER_SIZE
);
413 lcd_scroll_info
.lines
= 0;
416 /* Clear the current viewport */
417 void lcd_clear_viewport(void)
421 if (current_vp
== &default_vp
)
427 lastmode
= current_vp
->drawmode
;
429 /* Invert the INVERSEVID bit and set basic mode to SOLID */
430 current_vp
->drawmode
= (~lastmode
& DRMODE_INVERSEVID
) |
433 lcd_fillrect(0, 0, current_vp
->width
, current_vp
->height
);
435 current_vp
->drawmode
= lastmode
;
437 lcd_scroll_stop(current_vp
);
441 /* Set a single pixel */
442 void lcd_drawpixel(int x
, int y
)
444 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
445 && ((unsigned)y
< (unsigned)current_vp
->height
)
446 #if defined(HAVE_VIEWPORT_CLIP)
447 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
448 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
451 lcd_pixelfuncs
[current_vp
->drawmode
](current_vp
->x
+ x
, current_vp
->y
+ y
);
455 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
463 lcd_pixelfunc_type
*pfunc
= lcd_pixelfuncs
[current_vp
->drawmode
];
465 deltax
= abs(x2
- x1
);
468 /* DEBUGF("lcd_drawline() called for vertical line - optimisation.\n"); */
469 lcd_vline(x1
, y1
, y2
);
472 deltay
= abs(y2
- y1
);
475 /* DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n"); */
476 lcd_hline(x1
, x2
, y1
);
482 if (deltax
>= deltay
)
485 d
= 2 * deltay
- deltax
;
487 dinc2
= (deltay
- deltax
) * 2;
494 d
= 2 * deltax
- deltay
;
496 dinc2
= (deltax
- deltay
) * 2;
500 numpixels
++; /* include endpoints */
517 for (i
= 0; i
< numpixels
; i
++)
519 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
520 && ((unsigned)y
< (unsigned)current_vp
->height
)
521 #if defined(HAVE_VIEWPORT_CLIP)
522 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
523 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
526 pfunc(current_vp
->x
+ x
, current_vp
->y
+ y
);
543 /* Draw a horizontal line (optimised) */
544 void lcd_hline(int x1
, int x2
, int y
)
548 fb_data
*dst
, *dst_end
;
550 lcd_blockfunc_type
*bfunc
;
560 /******************** In viewport clipping **********************/
561 /* nothing to draw? */
562 if (((unsigned)y
>= (unsigned)current_vp
->height
) || (x1
>= current_vp
->width
)
568 if (x2
>= current_vp
->width
)
569 x2
= current_vp
->width
-1;
571 /* adjust x1 and y to viewport */
576 #if defined(HAVE_VIEWPORT_CLIP)
577 /********************* Viewport on screen clipping ********************/
578 /* nothing to draw? */
579 if (((unsigned)y
>= (unsigned) LCD_HEIGHT
) || (x1
>= LCD_WIDTH
)
592 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
593 dst
= FBADDR(x1
,y
>>2);
594 mask
= pixmask
[y
& 3];
596 dst_end
= dst
+ width
;
598 bfunc(dst
++, mask
, 0xFFu
);
599 while (dst
< dst_end
);
602 /* Draw a vertical line (optimised) */
603 void lcd_vline(int x
, int y1
, int y2
)
607 unsigned mask
, mask_bottom
;
608 lcd_blockfunc_type
*bfunc
;
618 /******************** In viewport clipping **********************/
619 /* nothing to draw? */
620 if (((unsigned)x
>= (unsigned)current_vp
->width
) || (y1
>= current_vp
->height
)
626 if (y2
>= current_vp
->height
)
627 y2
= current_vp
->height
-1;
629 /* adjust for viewport */
634 #if defined(HAVE_VIEWPORT_CLIP)
635 /********************* Viewport on screen clipping ********************/
636 /* nothing to draw? */
637 if (( (unsigned) x
>= (unsigned)LCD_WIDTH
) || (y1
>= LCD_HEIGHT
)
644 if (y2
>= LCD_HEIGHT
)
648 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
649 dst
= FBADDR(x
,y1
>>2);
651 mask
= 0xFFu
<< (2 * (y1
& 3));
652 mask_bottom
= 0xFFu
>> (2 * (~ny
& 3));
654 for (; ny
>= 4; ny
-= 4)
656 bfunc(dst
, mask
, 0xFFu
);
661 bfunc(dst
, mask
, 0xFFu
);
664 /* Draw a rectangular box */
665 void lcd_drawrect(int x
, int y
, int width
, int height
)
667 if ((width
<= 0) || (height
<= 0))
670 int x2
= x
+ width
- 1;
671 int y2
= y
+ height
- 1;
674 lcd_vline(x2
, y
, y2
);
676 lcd_hline(x
, x2
, y2
);
679 /* Fill a rectangular area */
680 void lcd_fillrect(int x
, int y
, int width
, int height
)
683 fb_data
*dst
, *dst_end
;
684 unsigned mask
, mask_bottom
;
686 lcd_blockfunc_type
*bfunc
;
687 bool fillopt
= false;
689 /******************** In viewport clipping **********************/
690 /* nothing to draw? */
691 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
692 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
705 if (x
+ width
> current_vp
->width
)
706 width
= current_vp
->width
- x
;
707 if (y
+ height
> current_vp
->height
)
708 height
= current_vp
->height
- y
;
710 /* adjust for viewport */
714 #if defined(HAVE_VIEWPORT_CLIP)
715 /********************* Viewport on screen clipping ********************/
716 /* nothing to draw? */
717 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
718 || (x
+ width
<= 0) || (y
+ height
<= 0))
721 /* clip image in viewport in screen */
732 if (x
+ width
> LCD_WIDTH
)
733 width
= LCD_WIDTH
- x
;
734 if (y
+ height
> LCD_HEIGHT
)
735 height
= LCD_HEIGHT
- y
;
738 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
740 if ((current_vp
->drawmode
& DRMODE_BG
) && !lcd_backdrop
)
748 if (current_vp
->drawmode
& DRMODE_FG
)
754 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
755 dst
= FBADDR(x
,y
>>2);
756 ny
= height
- 1 + (y
& 3);
757 mask
= 0xFFu
<< (2 * (y
& 3));
758 mask_bottom
= 0xFFu
>> (2 * (~ny
& 3));
760 for (; ny
>= 4; ny
-= 4)
762 if (fillopt
&& (mask
== 0xFFu
))
763 memset(dst
, bits
, width
);
766 fb_data
*dst_row
= dst
;
768 dst_end
= dst_row
+ width
;
770 bfunc(dst_row
++, mask
, 0xFFu
);
771 while (dst_row
< dst_end
);
779 if (fillopt
&& (mask
== 0xFFu
))
780 memset(dst
, bits
, width
);
783 dst_end
= dst
+ width
;
785 bfunc(dst
++, mask
, 0xFFu
);
786 while (dst
< dst_end
);
790 /* About Rockbox' internal monochrome bitmap format:
792 * A bitmap contains one bit for every pixel that defines if that pixel is
793 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
795 * The bytes are stored in row-major order, with byte 0 being top left,
796 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
797 * 0..7, the second row defines pixel row 8..15 etc.
799 * This is similar to the internal lcd hw format. */
801 /* Draw a partial monochrome bitmap */
802 void ICODE_ATTR
lcd_mono_bitmap_part(const unsigned char *src
, int src_x
,
803 int src_y
, int stride
, int x
, int y
,
804 int width
, int height
)
807 fb_data
*dst
, *dst_end
;
808 unsigned mask
, mask_bottom
;
809 lcd_blockfunc_type
*bfunc
;
811 /******************** Image in viewport clipping **********************/
812 /* nothing to draw? */
813 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
814 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
829 if (x
+ width
> current_vp
->width
)
830 width
= current_vp
->width
- x
;
831 if (y
+ height
> current_vp
->height
)
832 height
= current_vp
->height
- y
;
834 /* adjust for viewport */
838 #if defined(HAVE_VIEWPORT_CLIP)
839 /********************* Viewport on screen clipping ********************/
840 /* nothing to draw? */
841 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
842 || (x
+ width
<= 0) || (y
+ height
<= 0))
845 /* clip image in viewport in screen */
858 if (x
+ width
> LCD_WIDTH
)
859 width
= LCD_WIDTH
- x
;
860 if (y
+ height
> LCD_HEIGHT
)
861 height
= LCD_HEIGHT
- y
;
864 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
867 dst
= FBADDR(x
,y
>>2);
869 ny
= height
- 1 + shift
+ src_y
;
870 mask
= 0xFFFFu
<< (2 * (shift
+ src_y
));
871 /* Overflowing bits aren't important. */
872 mask_bottom
= 0xFFFFu
>> (2 * (~ny
& 7));
874 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
878 unsigned dmask1
, dmask2
, data
;
880 dmask1
= mask
& 0xFFu
;
883 for (; ny
>= 8; ny
-= 8)
885 const unsigned char *src_row
= src
;
886 fb_data
*dst_row
= dst
+ LCD_WIDTH
;
888 dst_end
= dst_row
+ width
;
895 bfunc(dst_row
- LCD_WIDTH
, dmask1
, lcd_dibits
[data
&0x0F]);
896 bfunc(dst_row
++, dmask2
, lcd_dibits
[(data
>>4)&0x0F]);
898 while (dst_row
< dst_end
);
903 bfunc(dst_row
++, dmask2
, lcd_dibits
[((*src_row
++)>>4)&0x0F]);
904 while (dst_row
< dst_end
);
908 dmask1
= dmask2
= 0xFFu
;
910 dmask1
&= mask_bottom
;
911 /* & 0xFFu is unnecessary here - dmask1 can't exceed that*/
912 dmask2
&= (mask_bottom
>> 8);
913 dst_end
= dst
+ width
;
922 bfunc(dst
, dmask1
, lcd_dibits
[data
&0x0F]);
923 bfunc((dst
++) + LCD_WIDTH
, dmask2
, lcd_dibits
[(data
>>4)&0x0F]);
925 while (dst
< dst_end
);
930 bfunc(dst
++, dmask1
, lcd_dibits
[(*src
++)&0x0F]);
931 while (dst
< dst_end
);
937 bfunc((dst
++) + LCD_WIDTH
, dmask2
, lcd_dibits
[((*src
++)>>4)&0x0F]);
938 while (dst
< dst_end
);
943 dst_end
= dst
+ width
;
946 const unsigned char *src_col
= src
++;
947 fb_data
*dst_col
= dst
++;
948 unsigned mask_col
= mask
;
951 for (y
= ny
; y
>= 8; y
-= 8)
953 data
|= *src_col
<< shift
;
955 if (mask_col
& 0xFFFFu
)
957 if (mask_col
& 0xFFu
)
958 bfunc(dst_col
, mask_col
, lcd_dibits
[data
&0x0F]);
959 bfunc(dst_col
+ LCD_WIDTH
, mask_col
>> 8,
960 lcd_dibits
[(data
>>4)&0x0F]);
967 dst_col
+= 2*LCD_WIDTH
;
970 data
|= *src_col
<< shift
;
971 mask_col
&= mask_bottom
;
972 if (mask_col
& 0xFFu
)
973 bfunc(dst_col
, mask_col
, lcd_dibits
[data
&0x0F]);
974 if (mask_col
& 0xFF00u
)
975 bfunc(dst_col
+ LCD_WIDTH
, mask_col
>> 8,
976 lcd_dibits
[(data
>>4)&0x0F]);
978 while (dst
< dst_end
);
982 /* Draw a full monochrome bitmap */
983 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
985 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
988 /* About Rockbox' internal native bitmap format:
990 * A bitmap contains two bits for every pixel. 00 = white, 01 = light grey,
991 * 10 = dark grey, 11 = black. Bits within a byte are arranged vertically, LSB
993 * The bytes are stored in row-major order, with byte 0 being top left,
994 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
995 * 0..3, the second row defines pixel row 4..7 etc.
997 * This is the same as the internal lcd hw format. */
999 /* Draw a partial native bitmap */
1000 void ICODE_ATTR
lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
1001 int stride
, int x
, int y
, int width
,
1005 fb_data
*dst
, *dst_end
;
1006 unsigned mask
, mask_bottom
;
1008 /******************** Image in viewport clipping **********************/
1009 /* nothing to draw? */
1010 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
1011 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
1026 if (x
+ width
> current_vp
->width
)
1027 width
= current_vp
->width
- x
;
1028 if (y
+ height
> current_vp
->height
)
1029 height
= current_vp
->height
- y
;
1031 /* adjust for viewport */
1035 #if defined(HAVE_VIEWPORT_CLIP)
1036 /********************* Viewport on screen clipping ********************/
1037 /* nothing to draw? */
1038 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
1039 || (x
+ width
<= 0) || (y
+ height
<= 0))
1042 /* clip image in viewport in screen */
1055 if (x
+ width
> LCD_WIDTH
)
1056 width
= LCD_WIDTH
- x
;
1057 if (y
+ height
> LCD_HEIGHT
)
1058 height
= LCD_HEIGHT
- y
;
1061 src
+= stride
* (src_y
>> 2) + src_x
; /* move starting point */
1064 dst
= FBADDR(x
,y
>>2);
1066 ny
= height
- 1 + shift
+ src_y
;
1068 mask
= 0xFFu
<< (2 * (shift
+ src_y
));
1069 mask_bottom
= 0xFFu
>> (2 * (~ny
& 3));
1073 for (; ny
>= 4; ny
-= 4)
1076 memcpy(dst
, src
, width
);
1079 const fb_data
*src_row
= src
;
1080 fb_data
*dst_row
= dst
;
1082 dst_end
= dst_row
+ width
;
1084 setblock(dst_row
++, mask
, *src_row
++);
1085 while (dst_row
< dst_end
);
1091 mask
&= mask_bottom
;
1094 memcpy(dst
, src
, width
);
1097 dst_end
= dst
+ width
;
1099 setblock(dst
++, mask
, *src
++);
1100 while (dst
< dst_end
);
1106 dst_end
= dst
+ width
;
1109 const fb_data
*src_col
= src
++;
1110 fb_data
*dst_col
= dst
++;
1111 unsigned mask_col
= mask
;
1114 for (y
= ny
; y
>= 4; y
-= 4)
1116 data
|= *src_col
<< shift
;
1118 if (mask_col
& 0xFFu
)
1120 setblock(dst_col
, mask_col
, data
);
1127 dst_col
+= LCD_WIDTH
;
1130 data
|= *src_col
<< shift
;
1131 setblock(dst_col
, mask_col
& mask_bottom
, data
);
1133 while (dst
< dst_end
);
1137 /* Draw a full native bitmap */
1138 void lcd_bitmap(const fb_data
*src
, int x
, int y
, int width
, int height
)
1140 lcd_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
1143 #include "lcd-bitmap-common.c"