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_framebuffer
[LCD_FBHEIGHT
][LCD_FBWIDTH
] IRAM_LCDFRAMEBUFFER
;
41 const unsigned char lcd_dibits
[16] ICONST_ATTR
= {
42 0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F,
43 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF
46 static const unsigned char pixmask
[4] ICONST_ATTR
= {
47 0x03, 0x0C, 0x30, 0xC0
50 static fb_data
* lcd_backdrop
= NULL
;
51 static long lcd_backdrop_offset IDATA_ATTR
= 0;
53 static struct viewport default_vp
=
59 .font
= FONT_SYSFIXED
,
60 .drawmode
= DRMODE_SOLID
,
61 .fg_pattern
= LCD_DEFAULT_FG
,
62 .bg_pattern
= LCD_DEFAULT_BG
65 static struct viewport
* current_vp IBSS_ATTR
;
66 static unsigned fg_pattern IBSS_ATTR
;
67 static unsigned bg_pattern IBSS_ATTR
;
72 /* Initialise the viewport */
73 lcd_set_viewport(NULL
);
76 /* Call device specific init */
83 void lcd_set_viewport(struct viewport
* vp
)
86 current_vp
= &default_vp
;
90 fg_pattern
= 0x55 * (~current_vp
->fg_pattern
& 3);
91 bg_pattern
= 0x55 * (~current_vp
->bg_pattern
& 3);
93 #if defined(SIMULATOR)
94 /* Force the viewport to be within bounds. If this happens it should
95 * be considered an error - the viewport will not draw as it might be
98 if((unsigned) current_vp
->x
> (unsigned) LCD_WIDTH
99 || (unsigned) current_vp
->y
> (unsigned) LCD_HEIGHT
100 || current_vp
->x
+ current_vp
->width
> LCD_WIDTH
101 || current_vp
->y
+ current_vp
->height
> LCD_HEIGHT
)
103 #if !defined(HAVE_VIEWPORT_CLIP)
108 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
109 current_vp
->x
, current_vp
->y
,
110 current_vp
->width
, current_vp
->height
);
116 void lcd_update_viewport(void)
118 lcd_update_rect(current_vp
->x
, current_vp
->y
,
119 current_vp
->width
, current_vp
->height
);
122 void lcd_update_viewport_rect(int x
, int y
, int width
, int height
)
124 lcd_update_rect(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
128 /*** parameter handling ***/
130 void lcd_set_drawmode(int mode
)
132 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
135 int lcd_get_drawmode(void)
137 return current_vp
->drawmode
;
140 void lcd_set_foreground(unsigned brightness
)
142 current_vp
->fg_pattern
= brightness
;
143 fg_pattern
= 0x55 * (~brightness
& 3);
146 unsigned lcd_get_foreground(void)
148 return current_vp
->fg_pattern
;
151 void lcd_set_background(unsigned brightness
)
153 current_vp
->bg_pattern
= brightness
;
154 bg_pattern
= 0x55 * (~brightness
& 3);
157 unsigned lcd_get_background(void)
159 return current_vp
->bg_pattern
;
162 void lcd_set_drawinfo(int mode
, unsigned fg_brightness
, unsigned bg_brightness
)
164 lcd_set_drawmode(mode
);
165 lcd_set_foreground(fg_brightness
);
166 lcd_set_background(bg_brightness
);
169 int lcd_getwidth(void)
171 return current_vp
->width
;
174 int lcd_getheight(void)
176 return current_vp
->height
;
179 void lcd_setfont(int newfont
)
181 current_vp
->font
= newfont
;
184 int lcd_getfont(void)
186 return current_vp
->font
;
189 int lcd_getstringsize(const unsigned char *str
, int *w
, int *h
)
191 return font_getstringsize(str
, w
, h
, current_vp
->font
);
194 /*** low-level drawing functions ***/
196 static void setpixel(int x
, int y
)
198 unsigned mask
= pixmask
[y
& 3];
199 fb_data
*address
= &lcd_framebuffer
[y
>>2][x
];
200 unsigned data
= *address
;
202 *address
= data
^ ((data
^ fg_pattern
) & mask
);
205 static void clearpixel(int x
, int y
)
207 unsigned mask
= pixmask
[y
& 3];
208 fb_data
*address
= &lcd_framebuffer
[y
>>2][x
];
209 unsigned data
= *address
;
211 *address
= data
^ ((data
^ bg_pattern
) & mask
);
214 static void clearimgpixel(int x
, int y
)
216 unsigned mask
= pixmask
[y
& 3];
217 fb_data
*address
= &lcd_framebuffer
[y
>>2][x
];
218 unsigned data
= *address
;
220 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
);
223 static void flippixel(int x
, int y
)
225 unsigned mask
= pixmask
[y
& 3];
226 fb_data
*address
= &lcd_framebuffer
[y
>>2][x
];
231 static void nopixel(int x
, int y
)
237 lcd_pixelfunc_type
* const lcd_pixelfuncs_bgcolor
[8] = {
238 flippixel
, nopixel
, setpixel
, setpixel
,
239 nopixel
, clearpixel
, nopixel
, clearpixel
242 lcd_pixelfunc_type
* const lcd_pixelfuncs_backdrop
[8] = {
243 flippixel
, nopixel
, setpixel
, setpixel
,
244 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
248 lcd_pixelfunc_type
* const * lcd_pixelfuncs
= lcd_pixelfuncs_bgcolor
;
250 /* 'mask' and 'bits' contain 2 bits per pixel */
251 static void ICODE_ATTR
flipblock(fb_data
*address
, unsigned mask
,
254 *address
^= bits
& mask
;
257 static void ICODE_ATTR
bgblock(fb_data
*address
, unsigned mask
,
260 unsigned data
= *address
;
262 *address
= data
^ ((data
^ bg_pattern
) & mask
& ~bits
);
265 static void ICODE_ATTR
bgimgblock(fb_data
*address
, unsigned mask
,
268 unsigned data
= *address
;
270 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
& ~bits
);
273 static void ICODE_ATTR
fgblock(fb_data
*address
, unsigned mask
,
276 unsigned data
= *address
;
278 *address
= data
^ ((data
^ fg_pattern
) & mask
& bits
);
281 static void ICODE_ATTR
solidblock(fb_data
*address
, unsigned mask
,
284 unsigned data
= *address
;
285 unsigned bgp
= bg_pattern
;
287 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
288 *address
= data
^ ((data
^ bits
) & mask
);
291 static void ICODE_ATTR
solidimgblock(fb_data
*address
, unsigned mask
,
294 unsigned data
= *address
;
295 unsigned bgp
= *(address
+ lcd_backdrop_offset
);
297 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
298 *address
= data
^ ((data
^ bits
) & mask
);
301 static void ICODE_ATTR
flipinvblock(fb_data
*address
, unsigned mask
,
304 *address
^= ~bits
& mask
;
307 static void ICODE_ATTR
bginvblock(fb_data
*address
, unsigned mask
,
310 unsigned data
= *address
;
312 *address
= data
^ ((data
^ bg_pattern
) & mask
& bits
);
315 static void ICODE_ATTR
bgimginvblock(fb_data
*address
, unsigned mask
,
318 unsigned data
= *address
;
320 *address
= data
^ ((data
^ *(address
+ lcd_backdrop_offset
)) & mask
& bits
);
323 static void ICODE_ATTR
fginvblock(fb_data
*address
, unsigned mask
,
326 unsigned data
= *address
;
328 *address
= data
^ ((data
^ fg_pattern
) & mask
& ~bits
);
331 static void ICODE_ATTR
solidinvblock(fb_data
*address
, unsigned mask
,
334 unsigned data
= *address
;
335 unsigned fgp
= fg_pattern
;
337 bits
= fgp
^ ((fgp
^ bg_pattern
) & bits
);
338 *address
= data
^ ((data
^ bits
) & mask
);
341 static void ICODE_ATTR
solidimginvblock(fb_data
*address
, unsigned mask
,
344 unsigned data
= *address
;
345 unsigned fgp
= fg_pattern
;
347 bits
= fgp
^ ((fgp
^ *(address
+ lcd_backdrop_offset
)) & bits
);
348 *address
= data
^ ((data
^ bits
) & mask
);
351 lcd_blockfunc_type
* const lcd_blockfuncs_bgcolor
[8] = {
352 flipblock
, bgblock
, fgblock
, solidblock
,
353 flipinvblock
, bginvblock
, fginvblock
, solidinvblock
356 lcd_blockfunc_type
* const lcd_blockfuncs_backdrop
[8] = {
357 flipblock
, bgimgblock
, fgblock
, solidimgblock
,
358 flipinvblock
, bgimginvblock
, fginvblock
, solidimginvblock
361 lcd_blockfunc_type
* const * lcd_blockfuncs
= lcd_blockfuncs_bgcolor
;
364 void lcd_set_backdrop(fb_data
* backdrop
)
366 lcd_backdrop
= backdrop
;
369 lcd_backdrop_offset
= (long)backdrop
- (long)lcd_framebuffer
;
370 lcd_pixelfuncs
= lcd_pixelfuncs_backdrop
;
371 lcd_blockfuncs
= lcd_blockfuncs_backdrop
;
375 lcd_backdrop_offset
= 0;
376 lcd_pixelfuncs
= lcd_pixelfuncs_bgcolor
;
377 lcd_blockfuncs
= lcd_blockfuncs_bgcolor
;
381 fb_data
* lcd_get_backdrop(void)
387 static inline void setblock(fb_data
*address
, unsigned mask
, unsigned bits
)
389 unsigned data
= *address
;
392 *address
= data
^ (bits
& mask
);
395 /*** drawing functions ***/
397 /* Clear the whole display */
398 void lcd_clear_display(void)
400 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
402 memset(lcd_framebuffer
, fg_pattern
, sizeof lcd_framebuffer
);
407 memcpy(lcd_framebuffer
, lcd_backdrop
, sizeof lcd_framebuffer
);
409 memset(lcd_framebuffer
, bg_pattern
, sizeof lcd_framebuffer
);
412 lcd_scroll_info
.lines
= 0;
415 /* Clear the current viewport */
416 void lcd_clear_viewport(void)
420 if (current_vp
== &default_vp
)
426 lastmode
= current_vp
->drawmode
;
428 /* Invert the INVERSEVID bit and set basic mode to SOLID */
429 current_vp
->drawmode
= (~lastmode
& DRMODE_INVERSEVID
) |
432 lcd_fillrect(0, 0, current_vp
->width
, current_vp
->height
);
434 current_vp
->drawmode
= lastmode
;
436 lcd_scroll_stop(current_vp
);
440 /* Set a single pixel */
441 void lcd_drawpixel(int x
, int y
)
443 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
444 && ((unsigned)y
< (unsigned)current_vp
->height
)
445 #if defined(HAVE_VIEWPORT_CLIP)
446 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
447 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
450 lcd_pixelfuncs
[current_vp
->drawmode
](current_vp
->x
+ x
, current_vp
->y
+ y
);
454 void lcd_drawline(int x1
, int y1
, int x2
, int y2
)
462 lcd_pixelfunc_type
*pfunc
= lcd_pixelfuncs
[current_vp
->drawmode
];
464 deltax
= abs(x2
- x1
);
467 /* DEBUGF("lcd_drawline() called for vertical line - optimisation.\n"); */
468 lcd_vline(x1
, y1
, y2
);
471 deltay
= abs(y2
- y1
);
474 /* DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n"); */
475 lcd_hline(x1
, x2
, y1
);
481 if (deltax
>= deltay
)
484 d
= 2 * deltay
- deltax
;
486 dinc2
= (deltay
- deltax
) * 2;
493 d
= 2 * deltax
- deltay
;
495 dinc2
= (deltax
- deltay
) * 2;
499 numpixels
++; /* include endpoints */
516 for (i
= 0; i
< numpixels
; i
++)
518 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
519 && ((unsigned)y
< (unsigned)current_vp
->height
)
520 #if defined(HAVE_VIEWPORT_CLIP)
521 && ((unsigned)x
< (unsigned)LCD_WIDTH
)
522 && ((unsigned)y
< (unsigned)LCD_HEIGHT
)
525 pfunc(current_vp
->x
+ x
, current_vp
->y
+ y
);
542 /* Draw a horizontal line (optimised) */
543 void lcd_hline(int x1
, int x2
, int y
)
547 fb_data
*dst
, *dst_end
;
549 lcd_blockfunc_type
*bfunc
;
559 /******************** In viewport clipping **********************/
560 /* nothing to draw? */
561 if (((unsigned)y
>= (unsigned)current_vp
->height
) || (x1
>= current_vp
->width
)
567 if (x2
>= current_vp
->width
)
568 x2
= current_vp
->width
-1;
570 /* adjust x1 and y to viewport */
575 #if defined(HAVE_VIEWPORT_CLIP)
576 /********************* Viewport on screen clipping ********************/
577 /* nothing to draw? */
578 if (((unsigned)y
>= (unsigned) LCD_HEIGHT
) || (x1
>= LCD_WIDTH
)
591 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
592 dst
= &lcd_framebuffer
[y
>>2][x1
];
593 mask
= pixmask
[y
& 3];
595 dst_end
= dst
+ width
;
597 bfunc(dst
++, mask
, 0xFFu
);
598 while (dst
< dst_end
);
601 /* Draw a vertical line (optimised) */
602 void lcd_vline(int x
, int y1
, int y2
)
606 unsigned mask
, mask_bottom
;
607 lcd_blockfunc_type
*bfunc
;
617 /******************** In viewport clipping **********************/
618 /* nothing to draw? */
619 if (((unsigned)x
>= (unsigned)current_vp
->width
) || (y1
>= current_vp
->height
)
625 if (y2
>= current_vp
->height
)
626 y2
= current_vp
->height
-1;
628 /* adjust for viewport */
633 #if defined(HAVE_VIEWPORT_CLIP)
634 /********************* Viewport on screen clipping ********************/
635 /* nothing to draw? */
636 if (( (unsigned) x
>= (unsigned)LCD_WIDTH
) || (y1
>= LCD_HEIGHT
)
643 if (y2
>= LCD_HEIGHT
)
647 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
648 dst
= &lcd_framebuffer
[y1
>>2][x
];
650 mask
= 0xFFu
<< (2 * (y1
& 3));
651 mask_bottom
= 0xFFu
>> (2 * (~ny
& 3));
653 for (; ny
>= 4; ny
-= 4)
655 bfunc(dst
, mask
, 0xFFu
);
660 bfunc(dst
, mask
, 0xFFu
);
663 /* Draw a rectangular box */
664 void lcd_drawrect(int x
, int y
, int width
, int height
)
666 if ((width
<= 0) || (height
<= 0))
669 int x2
= x
+ width
- 1;
670 int y2
= y
+ height
- 1;
673 lcd_vline(x2
, y
, y2
);
675 lcd_hline(x
, x2
, y2
);
678 /* Fill a rectangular area */
679 void lcd_fillrect(int x
, int y
, int width
, int height
)
682 fb_data
*dst
, *dst_end
;
683 unsigned mask
, mask_bottom
;
685 lcd_blockfunc_type
*bfunc
;
686 bool fillopt
= false;
688 /******************** In viewport clipping **********************/
689 /* nothing to draw? */
690 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
691 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
704 if (x
+ width
> current_vp
->width
)
705 width
= current_vp
->width
- x
;
706 if (y
+ height
> current_vp
->height
)
707 height
= current_vp
->height
- y
;
709 /* adjust for viewport */
713 #if defined(HAVE_VIEWPORT_CLIP)
714 /********************* Viewport on screen clipping ********************/
715 /* nothing to draw? */
716 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
717 || (x
+ width
<= 0) || (y
+ height
<= 0))
720 /* clip image in viewport in screen */
731 if (x
+ width
> LCD_WIDTH
)
732 width
= LCD_WIDTH
- x
;
733 if (y
+ height
> LCD_HEIGHT
)
734 height
= LCD_HEIGHT
- y
;
737 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
739 if ((current_vp
->drawmode
& DRMODE_BG
) && !lcd_backdrop
)
747 if (current_vp
->drawmode
& DRMODE_FG
)
753 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
754 dst
= &lcd_framebuffer
[y
>>2][x
];
755 ny
= height
- 1 + (y
& 3);
756 mask
= 0xFFu
<< (2 * (y
& 3));
757 mask_bottom
= 0xFFu
>> (2 * (~ny
& 3));
759 for (; ny
>= 4; ny
-= 4)
761 if (fillopt
&& (mask
== 0xFFu
))
762 memset(dst
, bits
, width
);
765 fb_data
*dst_row
= dst
;
767 dst_end
= dst_row
+ width
;
769 bfunc(dst_row
++, mask
, 0xFFu
);
770 while (dst_row
< dst_end
);
778 if (fillopt
&& (mask
== 0xFFu
))
779 memset(dst
, bits
, width
);
782 dst_end
= dst
+ width
;
784 bfunc(dst
++, mask
, 0xFFu
);
785 while (dst
< dst_end
);
789 /* About Rockbox' internal monochrome bitmap format:
791 * A bitmap contains one bit for every pixel that defines if that pixel is
792 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
794 * The bytes are stored in row-major order, with byte 0 being top left,
795 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
796 * 0..7, the second row defines pixel row 8..15 etc.
798 * This is similar to the internal lcd hw format. */
800 /* Draw a partial monochrome bitmap */
801 void ICODE_ATTR
lcd_mono_bitmap_part(const unsigned char *src
, int src_x
,
802 int src_y
, int stride
, int x
, int y
,
803 int width
, int height
)
806 fb_data
*dst
, *dst_end
;
807 unsigned mask
, mask_bottom
;
808 lcd_blockfunc_type
*bfunc
;
810 /******************** Image in viewport clipping **********************/
811 /* nothing to draw? */
812 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
813 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
828 if (x
+ width
> current_vp
->width
)
829 width
= current_vp
->width
- x
;
830 if (y
+ height
> current_vp
->height
)
831 height
= current_vp
->height
- y
;
833 /* adjust for viewport */
837 #if defined(HAVE_VIEWPORT_CLIP)
838 /********************* Viewport on screen clipping ********************/
839 /* nothing to draw? */
840 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
841 || (x
+ width
<= 0) || (y
+ height
<= 0))
844 /* clip image in viewport in screen */
857 if (x
+ width
> LCD_WIDTH
)
858 width
= LCD_WIDTH
- x
;
859 if (y
+ height
> LCD_HEIGHT
)
860 height
= LCD_HEIGHT
- y
;
863 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
866 dst
= &lcd_framebuffer
[y
>>2][x
];
868 ny
= height
- 1 + shift
+ src_y
;
869 mask
= 0xFFFFu
<< (2 * (shift
+ src_y
));
870 /* Overflowing bits aren't important. */
871 mask_bottom
= 0xFFFFu
>> (2 * (~ny
& 7));
873 bfunc
= lcd_blockfuncs
[current_vp
->drawmode
];
877 unsigned dmask1
, dmask2
, data
;
879 dmask1
= mask
& 0xFFu
;
882 for (; ny
>= 8; ny
-= 8)
884 const unsigned char *src_row
= src
;
885 fb_data
*dst_row
= dst
+ LCD_WIDTH
;
887 dst_end
= dst_row
+ width
;
894 bfunc(dst_row
- LCD_WIDTH
, dmask1
, lcd_dibits
[data
&0x0F]);
895 bfunc(dst_row
++, dmask2
, lcd_dibits
[(data
>>4)&0x0F]);
897 while (dst_row
< dst_end
);
902 bfunc(dst_row
++, dmask2
, lcd_dibits
[((*src_row
++)>>4)&0x0F]);
903 while (dst_row
< dst_end
);
907 dmask1
= dmask2
= 0xFFu
;
909 dmask1
&= mask_bottom
;
910 /* & 0xFFu is unnecessary here - dmask1 can't exceed that*/
911 dmask2
&= (mask_bottom
>> 8);
912 dst_end
= dst
+ width
;
921 bfunc(dst
, dmask1
, lcd_dibits
[data
&0x0F]);
922 bfunc((dst
++) + LCD_WIDTH
, dmask2
, lcd_dibits
[(data
>>4)&0x0F]);
924 while (dst
< dst_end
);
929 bfunc(dst
++, dmask1
, lcd_dibits
[(*src
++)&0x0F]);
930 while (dst
< dst_end
);
936 bfunc((dst
++) + LCD_WIDTH
, dmask2
, lcd_dibits
[((*src
++)>>4)&0x0F]);
937 while (dst
< dst_end
);
942 dst_end
= dst
+ width
;
945 const unsigned char *src_col
= src
++;
946 fb_data
*dst_col
= dst
++;
947 unsigned mask_col
= mask
;
950 for (y
= ny
; y
>= 8; y
-= 8)
952 data
|= *src_col
<< shift
;
954 if (mask_col
& 0xFFFFu
)
956 if (mask_col
& 0xFFu
)
957 bfunc(dst_col
, mask_col
, lcd_dibits
[data
&0x0F]);
958 bfunc(dst_col
+ LCD_WIDTH
, mask_col
>> 8,
959 lcd_dibits
[(data
>>4)&0x0F]);
966 dst_col
+= 2*LCD_WIDTH
;
969 data
|= *src_col
<< shift
;
970 mask_col
&= mask_bottom
;
971 if (mask_col
& 0xFFu
)
972 bfunc(dst_col
, mask_col
, lcd_dibits
[data
&0x0F]);
973 if (mask_col
& 0xFF00u
)
974 bfunc(dst_col
+ LCD_WIDTH
, mask_col
>> 8,
975 lcd_dibits
[(data
>>4)&0x0F]);
977 while (dst
< dst_end
);
981 /* Draw a full monochrome bitmap */
982 void lcd_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
984 lcd_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
987 /* About Rockbox' internal native bitmap format:
989 * A bitmap contains two bits for every pixel. 00 = white, 01 = light grey,
990 * 10 = dark grey, 11 = black. Bits within a byte are arranged vertically, LSB
992 * The bytes are stored in row-major order, with byte 0 being top left,
993 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
994 * 0..3, the second row defines pixel row 4..7 etc.
996 * This is the same as the internal lcd hw format. */
998 /* Draw a partial native bitmap */
999 void ICODE_ATTR
lcd_bitmap_part(const fb_data
*src
, int src_x
, int src_y
,
1000 int stride
, int x
, int y
, int width
,
1004 fb_data
*dst
, *dst_end
;
1005 unsigned mask
, mask_bottom
;
1007 /******************** Image in viewport clipping **********************/
1008 /* nothing to draw? */
1009 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
1010 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
1025 if (x
+ width
> current_vp
->width
)
1026 width
= current_vp
->width
- x
;
1027 if (y
+ height
> current_vp
->height
)
1028 height
= current_vp
->height
- y
;
1030 /* adjust for viewport */
1034 #if defined(HAVE_VIEWPORT_CLIP)
1035 /********************* Viewport on screen clipping ********************/
1036 /* nothing to draw? */
1037 if ((x
>= LCD_WIDTH
) || (y
>= LCD_HEIGHT
)
1038 || (x
+ width
<= 0) || (y
+ height
<= 0))
1041 /* clip image in viewport in screen */
1054 if (x
+ width
> LCD_WIDTH
)
1055 width
= LCD_WIDTH
- x
;
1056 if (y
+ height
> LCD_HEIGHT
)
1057 height
= LCD_HEIGHT
- y
;
1060 src
+= stride
* (src_y
>> 2) + src_x
; /* move starting point */
1063 dst
= &lcd_framebuffer
[y
>>2][x
];
1065 ny
= height
- 1 + shift
+ src_y
;
1067 mask
= 0xFFu
<< (2 * (shift
+ src_y
));
1068 mask_bottom
= 0xFFu
>> (2 * (~ny
& 3));
1072 for (; ny
>= 4; ny
-= 4)
1075 memcpy(dst
, src
, width
);
1078 const fb_data
*src_row
= src
;
1079 fb_data
*dst_row
= dst
;
1081 dst_end
= dst_row
+ width
;
1083 setblock(dst_row
++, mask
, *src_row
++);
1084 while (dst_row
< dst_end
);
1090 mask
&= mask_bottom
;
1093 memcpy(dst
, src
, width
);
1096 dst_end
= dst
+ width
;
1098 setblock(dst
++, mask
, *src
++);
1099 while (dst
< dst_end
);
1105 dst_end
= dst
+ width
;
1108 const fb_data
*src_col
= src
++;
1109 fb_data
*dst_col
= dst
++;
1110 unsigned mask_col
= mask
;
1113 for (y
= ny
; y
>= 4; y
-= 4)
1115 data
|= *src_col
<< shift
;
1117 if (mask_col
& 0xFFu
)
1119 setblock(dst_col
, mask_col
, data
);
1126 dst_col
+= LCD_WIDTH
;
1129 data
|= *src_col
<< shift
;
1130 setblock(dst_col
, mask_col
& mask_bottom
, data
);
1132 while (dst
< dst_end
);
1136 /* Draw a full native bitmap */
1137 void lcd_bitmap(const fb_data
*src
, int x
, int y
, int width
, int height
)
1139 lcd_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
1142 #include "lcd-bitmap-common.c"