FS#8961 - Anti-Aliased Fonts.
[kugel-rb.git] / firmware / drivers / lcd-2bit-vert.c
bloba124e3e15d3dbcffb474aa6cc18386370673b6e7
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
21 #include "config.h"
23 #include "system.h"
24 #include "cpu.h"
25 #include "kernel.h"
26 #include "lcd.h"
27 #include "thread.h"
28 #include <string.h>
29 #include <stdlib.h>
30 #include "file.h"
31 #include "debug.h"
32 #include "font.h"
33 #include "rbunicode.h"
34 #include "bidi.h"
35 #include "scroll_engine.h"
37 /*** globals ***/
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 =
55 .x = 0,
56 .y = 0,
57 .width = LCD_WIDTH,
58 .height = LCD_HEIGHT,
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;
69 /* LCD init */
70 void lcd_init(void)
72 /* Initialise the viewport */
73 lcd_set_viewport(NULL);
75 lcd_clear_display();
76 /* Call device specific init */
77 lcd_init_device();
78 scroll_init();
81 /*** Viewports ***/
83 void lcd_set_viewport(struct viewport* vp)
85 if (vp == NULL)
86 current_vp = &default_vp;
87 else
88 current_vp = vp;
90 fg_pattern = 0x55 * (~current_vp->fg_pattern & 3);
91 bg_pattern = 0x55 * (~current_vp->bg_pattern & 3);
94 void lcd_update_viewport(void)
96 lcd_update_rect(current_vp->x, current_vp->y,
97 current_vp->width, current_vp->height);
100 void lcd_update_viewport_rect(int x, int y, int width, int height)
102 lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height);
106 /*** parameter handling ***/
108 void lcd_set_drawmode(int mode)
110 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
113 int lcd_get_drawmode(void)
115 return current_vp->drawmode;
118 void lcd_set_foreground(unsigned brightness)
120 current_vp->fg_pattern = brightness;
121 fg_pattern = 0x55 * (~brightness & 3);
124 unsigned lcd_get_foreground(void)
126 return current_vp->fg_pattern;
129 void lcd_set_background(unsigned brightness)
131 current_vp->bg_pattern = brightness;
132 bg_pattern = 0x55 * (~brightness & 3);
135 unsigned lcd_get_background(void)
137 return current_vp->bg_pattern;
140 void lcd_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness)
142 lcd_set_drawmode(mode);
143 lcd_set_foreground(fg_brightness);
144 lcd_set_background(bg_brightness);
147 int lcd_getwidth(void)
149 return current_vp->width;
152 int lcd_getheight(void)
154 return current_vp->height;
157 void lcd_setfont(int newfont)
159 current_vp->font = newfont;
162 int lcd_getfont(void)
164 return current_vp->font;
167 int lcd_getstringsize(const unsigned char *str, int *w, int *h)
169 return font_getstringsize(str, w, h, current_vp->font);
172 /*** low-level drawing functions ***/
174 static void setpixel(int x, int y)
176 unsigned mask = pixmask[y & 3];
177 fb_data *address = &lcd_framebuffer[y>>2][x];
178 unsigned data = *address;
180 *address = data ^ ((data ^ fg_pattern) & mask);
183 static void clearpixel(int x, int y)
185 unsigned mask = pixmask[y & 3];
186 fb_data *address = &lcd_framebuffer[y>>2][x];
187 unsigned data = *address;
189 *address = data ^ ((data ^ bg_pattern) & mask);
192 static void clearimgpixel(int x, int y)
194 unsigned mask = pixmask[y & 3];
195 fb_data *address = &lcd_framebuffer[y>>2][x];
196 unsigned data = *address;
198 *address = data ^ ((data ^ *(address + lcd_backdrop_offset)) & mask);
201 static void flippixel(int x, int y)
203 unsigned mask = pixmask[y & 3];
204 fb_data *address = &lcd_framebuffer[y>>2][x];
206 *address ^= mask;
209 static void nopixel(int x, int y)
211 (void)x;
212 (void)y;
215 lcd_pixelfunc_type* const lcd_pixelfuncs_bgcolor[8] = {
216 flippixel, nopixel, setpixel, setpixel,
217 nopixel, clearpixel, nopixel, clearpixel
220 lcd_pixelfunc_type* const lcd_pixelfuncs_backdrop[8] = {
221 flippixel, nopixel, setpixel, setpixel,
222 nopixel, clearimgpixel, nopixel, clearimgpixel
226 lcd_pixelfunc_type* const * lcd_pixelfuncs = lcd_pixelfuncs_bgcolor;
228 /* 'mask' and 'bits' contain 2 bits per pixel */
229 static void ICODE_ATTR flipblock(fb_data *address, unsigned mask,
230 unsigned bits)
232 *address ^= bits & mask;
235 static void ICODE_ATTR bgblock(fb_data *address, unsigned mask,
236 unsigned bits)
238 unsigned data = *address;
240 *address = data ^ ((data ^ bg_pattern) & mask & ~bits);
243 static void ICODE_ATTR bgimgblock(fb_data *address, unsigned mask,
244 unsigned bits)
246 unsigned data = *address;
248 *address = data ^ ((data ^ *(address + lcd_backdrop_offset)) & mask & ~bits);
251 static void ICODE_ATTR fgblock(fb_data *address, unsigned mask,
252 unsigned bits)
254 unsigned data = *address;
256 *address = data ^ ((data ^ fg_pattern) & mask & bits);
259 static void ICODE_ATTR solidblock(fb_data *address, unsigned mask,
260 unsigned bits)
262 unsigned data = *address;
263 unsigned bgp = bg_pattern;
265 bits = bgp ^ ((bgp ^ fg_pattern) & bits);
266 *address = data ^ ((data ^ bits) & mask);
269 static void ICODE_ATTR solidimgblock(fb_data *address, unsigned mask,
270 unsigned bits)
272 unsigned data = *address;
273 unsigned bgp = *(address + lcd_backdrop_offset);
275 bits = bgp ^ ((bgp ^ fg_pattern) & bits);
276 *address = data ^ ((data ^ bits) & mask);
279 static void ICODE_ATTR flipinvblock(fb_data *address, unsigned mask,
280 unsigned bits)
282 *address ^= ~bits & mask;
285 static void ICODE_ATTR bginvblock(fb_data *address, unsigned mask,
286 unsigned bits)
288 unsigned data = *address;
290 *address = data ^ ((data ^ bg_pattern) & mask & bits);
293 static void ICODE_ATTR bgimginvblock(fb_data *address, unsigned mask,
294 unsigned bits)
296 unsigned data = *address;
298 *address = data ^ ((data ^ *(address + lcd_backdrop_offset)) & mask & bits);
301 static void ICODE_ATTR fginvblock(fb_data *address, unsigned mask,
302 unsigned bits)
304 unsigned data = *address;
306 *address = data ^ ((data ^ fg_pattern) & mask & ~bits);
309 static void ICODE_ATTR solidinvblock(fb_data *address, unsigned mask,
310 unsigned bits)
312 unsigned data = *address;
313 unsigned fgp = fg_pattern;
315 bits = fgp ^ ((fgp ^ bg_pattern) & bits);
316 *address = data ^ ((data ^ bits) & mask);
319 static void ICODE_ATTR solidimginvblock(fb_data *address, unsigned mask,
320 unsigned bits)
322 unsigned data = *address;
323 unsigned fgp = fg_pattern;
325 bits = fgp ^ ((fgp ^ *(address + lcd_backdrop_offset)) & bits);
326 *address = data ^ ((data ^ bits) & mask);
329 lcd_blockfunc_type* const lcd_blockfuncs_bgcolor[8] = {
330 flipblock, bgblock, fgblock, solidblock,
331 flipinvblock, bginvblock, fginvblock, solidinvblock
334 lcd_blockfunc_type* const lcd_blockfuncs_backdrop[8] = {
335 flipblock, bgimgblock, fgblock, solidimgblock,
336 flipinvblock, bgimginvblock, fginvblock, solidimginvblock
339 lcd_blockfunc_type* const * lcd_blockfuncs = lcd_blockfuncs_bgcolor;
342 void lcd_set_backdrop(fb_data* backdrop)
344 lcd_backdrop = backdrop;
345 if (backdrop)
347 lcd_backdrop_offset = (long)backdrop - (long)lcd_framebuffer;
348 lcd_pixelfuncs = lcd_pixelfuncs_backdrop;
349 lcd_blockfuncs = lcd_blockfuncs_backdrop;
351 else
353 lcd_backdrop_offset = 0;
354 lcd_pixelfuncs = lcd_pixelfuncs_bgcolor;
355 lcd_blockfuncs = lcd_blockfuncs_bgcolor;
359 fb_data* lcd_get_backdrop(void)
361 return lcd_backdrop;
365 static inline void setblock(fb_data *address, unsigned mask, unsigned bits)
367 unsigned data = *address;
369 bits ^= data;
370 *address = data ^ (bits & mask);
373 /*** drawing functions ***/
375 /* Clear the whole display */
376 void lcd_clear_display(void)
378 if (current_vp->drawmode & DRMODE_INVERSEVID)
380 memset(lcd_framebuffer, fg_pattern, sizeof lcd_framebuffer);
382 else
384 if (lcd_backdrop)
385 memcpy(lcd_framebuffer, lcd_backdrop, sizeof lcd_framebuffer);
386 else
387 memset(lcd_framebuffer, bg_pattern, sizeof lcd_framebuffer);
390 lcd_scroll_info.lines = 0;
393 /* Clear the current viewport */
394 void lcd_clear_viewport(void)
396 int lastmode;
398 if (current_vp == &default_vp)
400 lcd_clear_display();
402 else
404 lastmode = current_vp->drawmode;
406 /* Invert the INVERSEVID bit and set basic mode to SOLID */
407 current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) |
408 DRMODE_SOLID;
410 lcd_fillrect(0, 0, current_vp->width, current_vp->height);
412 current_vp->drawmode = lastmode;
414 lcd_scroll_stop(current_vp);
418 /* Set a single pixel */
419 void lcd_drawpixel(int x, int y)
421 if (((unsigned)x < (unsigned)current_vp->width) &&
422 ((unsigned)y < (unsigned)current_vp->height))
423 lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
426 /* Draw a line */
427 void lcd_drawline(int x1, int y1, int x2, int y2)
429 int numpixels;
430 int i;
431 int deltax, deltay;
432 int d, dinc1, dinc2;
433 int x, xinc1, xinc2;
434 int y, yinc1, yinc2;
435 lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[current_vp->drawmode];
437 deltax = abs(x2 - x1);
438 if (deltax == 0)
440 DEBUGF("lcd_drawline() called for vertical line - optimisation.\n");
441 lcd_vline(x1, y1, y2);
442 return;
444 deltay = abs(y2 - y1);
445 if (deltay == 0)
447 DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n");
448 lcd_hline(x1, x2, y1);
449 return;
451 xinc2 = 1;
452 yinc2 = 1;
454 if (deltax >= deltay)
456 numpixels = deltax;
457 d = 2 * deltay - deltax;
458 dinc1 = deltay * 2;
459 dinc2 = (deltay - deltax) * 2;
460 xinc1 = 1;
461 yinc1 = 0;
463 else
465 numpixels = deltay;
466 d = 2 * deltax - deltay;
467 dinc1 = deltax * 2;
468 dinc2 = (deltax - deltay) * 2;
469 xinc1 = 0;
470 yinc1 = 1;
472 numpixels++; /* include endpoints */
474 if (x1 > x2)
476 xinc1 = -xinc1;
477 xinc2 = -xinc2;
480 if (y1 > y2)
482 yinc1 = -yinc1;
483 yinc2 = -yinc2;
486 x = x1;
487 y = y1;
489 for (i = 0; i < numpixels; i++)
491 if (((unsigned)x < (unsigned)current_vp->width) &&
492 ((unsigned)y < (unsigned)current_vp->height))
493 pfunc(current_vp->x + x, current_vp->y + y);
495 if (d < 0)
497 d += dinc1;
498 x += xinc1;
499 y += yinc1;
501 else
503 d += dinc2;
504 x += xinc2;
505 y += yinc2;
510 /* Draw a horizontal line (optimised) */
511 void lcd_hline(int x1, int x2, int y)
513 int x;
514 int width;
515 fb_data *dst, *dst_end;
516 unsigned mask;
517 lcd_blockfunc_type *bfunc;
519 /* direction flip */
520 if (x2 < x1)
522 x = x1;
523 x1 = x2;
524 x2 = x;
527 /* nothing to draw? */
528 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
529 || (x2 < 0))
530 return;
532 /* clipping */
533 if (x1 < 0)
534 x1 = 0;
535 if (x2 >= current_vp->width)
536 x2 = current_vp->width-1;
538 width = x2 - x1 + 1;
540 /* adjust x1 and y to viewport */
541 x1 += current_vp->x;
542 y += current_vp->y;
544 bfunc = lcd_blockfuncs[current_vp->drawmode];
545 dst = &lcd_framebuffer[y>>2][x1];
546 mask = pixmask[y & 3];
548 dst_end = dst + width;
550 bfunc(dst++, mask, 0xFFu);
551 while (dst < dst_end);
554 /* Draw a vertical line (optimised) */
555 void lcd_vline(int x, int y1, int y2)
557 int ny;
558 fb_data *dst;
559 unsigned mask, mask_bottom;
560 lcd_blockfunc_type *bfunc;
562 /* direction flip */
563 if (y2 < y1)
565 ny = y1;
566 y1 = y2;
567 y2 = ny;
570 /* nothing to draw? */
571 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
572 || (y2 < 0))
573 return;
575 /* clipping */
576 if (y1 < 0)
577 y1 = 0;
578 if (y2 >= current_vp->height)
579 y2 = current_vp->height-1;
581 /* adjust for viewport */
582 y1 += current_vp->y;
583 y2 += current_vp->y;
584 x += current_vp->x;
586 bfunc = lcd_blockfuncs[current_vp->drawmode];
587 dst = &lcd_framebuffer[y1>>2][x];
588 ny = y2 - (y1 & ~3);
589 mask = 0xFFu << (2 * (y1 & 3));
590 mask_bottom = 0xFFu >> (2 * (~ny & 3));
592 for (; ny >= 4; ny -= 4)
594 bfunc(dst, mask, 0xFFu);
595 dst += LCD_WIDTH;
596 mask = 0xFFu;
598 mask &= mask_bottom;
599 bfunc(dst, mask, 0xFFu);
602 /* Draw a rectangular box */
603 void lcd_drawrect(int x, int y, int width, int height)
605 if ((width <= 0) || (height <= 0))
606 return;
608 int x2 = x + width - 1;
609 int y2 = y + height - 1;
611 lcd_vline(x, y, y2);
612 lcd_vline(x2, y, y2);
613 lcd_hline(x, x2, y);
614 lcd_hline(x, x2, y2);
617 /* Fill a rectangular area */
618 void lcd_fillrect(int x, int y, int width, int height)
620 int ny;
621 fb_data *dst, *dst_end;
622 unsigned mask, mask_bottom;
623 unsigned bits = 0;
624 lcd_blockfunc_type *bfunc;
625 bool fillopt = false;
627 /* nothing to draw? */
628 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
629 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
630 return;
632 /* clipping */
633 if (x < 0)
635 width += x;
636 x = 0;
638 if (y < 0)
640 height += y;
641 y = 0;
643 if (x + width > current_vp->width)
644 width = current_vp->width - x;
645 if (y + height > current_vp->height)
646 height = current_vp->height - y;
648 /* adjust for viewport */
649 x += current_vp->x;
650 y += current_vp->y;
652 if (current_vp->drawmode & DRMODE_INVERSEVID)
654 if ((current_vp->drawmode & DRMODE_BG) && !lcd_backdrop)
656 fillopt = true;
657 bits = bg_pattern;
660 else
662 if (current_vp->drawmode & DRMODE_FG)
664 fillopt = true;
665 bits = fg_pattern;
668 bfunc = lcd_blockfuncs[current_vp->drawmode];
669 dst = &lcd_framebuffer[y>>2][x];
670 ny = height - 1 + (y & 3);
671 mask = 0xFFu << (2 * (y & 3));
672 mask_bottom = 0xFFu >> (2 * (~ny & 3));
674 for (; ny >= 4; ny -= 4)
676 if (fillopt && (mask == 0xFFu))
677 memset(dst, bits, width);
678 else
680 fb_data *dst_row = dst;
682 dst_end = dst_row + width;
684 bfunc(dst_row++, mask, 0xFFu);
685 while (dst_row < dst_end);
688 dst += LCD_WIDTH;
689 mask = 0xFFu;
691 mask &= mask_bottom;
693 if (fillopt && (mask == 0xFFu))
694 memset(dst, bits, width);
695 else
697 dst_end = dst + width;
699 bfunc(dst++, mask, 0xFFu);
700 while (dst < dst_end);
704 /* About Rockbox' internal monochrome bitmap format:
706 * A bitmap contains one bit for every pixel that defines if that pixel is
707 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
708 * at top.
709 * The bytes are stored in row-major order, with byte 0 being top left,
710 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
711 * 0..7, the second row defines pixel row 8..15 etc.
713 * This is similar to the internal lcd hw format. */
715 /* Draw a partial monochrome bitmap */
716 void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
717 int src_y, int stride, int x, int y,
718 int width, int height)
720 int shift, ny;
721 fb_data *dst, *dst_end;
722 unsigned mask, mask_bottom;
723 lcd_blockfunc_type *bfunc;
725 /* nothing to draw? */
726 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
727 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
728 return;
730 /* clipping */
731 if (x < 0)
733 width += x;
734 src_x -= x;
735 x = 0;
737 if (y < 0)
739 height += y;
740 src_y -= y;
741 y = 0;
743 if (x + width > current_vp->width)
744 width = current_vp->width - x;
745 if (y + height > current_vp->height)
746 height = current_vp->height - y;
748 /* adjust for viewport */
749 x += current_vp->x;
750 y += current_vp->y;
752 src += stride * (src_y >> 3) + src_x; /* move starting point */
753 src_y &= 7;
754 y -= src_y;
755 dst = &lcd_framebuffer[y>>2][x];
756 shift = y & 3;
757 ny = height - 1 + shift + src_y;
758 mask = 0xFFFFu << (2 * (shift + src_y));
759 /* Overflowing bits aren't important. */
760 mask_bottom = 0xFFFFu >> (2 * (~ny & 7));
762 bfunc = lcd_blockfuncs[current_vp->drawmode];
764 if (shift == 0)
766 unsigned dmask1, dmask2, data;
768 dmask1 = mask & 0xFFu;
769 dmask2 = mask >> 8;
771 for (; ny >= 8; ny -= 8)
773 const unsigned char *src_row = src;
774 fb_data *dst_row = dst + LCD_WIDTH;
776 dst_end = dst_row + width;
778 if (dmask1 != 0)
782 data = *src_row++;
783 bfunc(dst_row - LCD_WIDTH, dmask1, lcd_dibits[data&0x0F]);
784 bfunc(dst_row++, dmask2, lcd_dibits[(data>>4)&0x0F]);
786 while (dst_row < dst_end);
788 else
791 bfunc(dst_row++, dmask2, lcd_dibits[((*src_row++)>>4)&0x0F]);
792 while (dst_row < dst_end);
794 src += stride;
795 dst += 2*LCD_WIDTH;
796 dmask1 = dmask2 = 0xFFu;
798 dmask1 &= mask_bottom;
799 /* & 0xFFu is unnecessary here - dmask1 can't exceed that*/
800 dmask2 &= (mask_bottom >> 8);
801 dst_end = dst + width;
803 if (dmask1 != 0)
805 if (dmask2 != 0)
809 data = *src++;
810 bfunc(dst, dmask1, lcd_dibits[data&0x0F]);
811 bfunc((dst++) + LCD_WIDTH, dmask2, lcd_dibits[(data>>4)&0x0F]);
813 while (dst < dst_end);
815 else
818 bfunc(dst++, dmask1, lcd_dibits[(*src++)&0x0F]);
819 while (dst < dst_end);
822 else
825 bfunc((dst++) + LCD_WIDTH, dmask2, lcd_dibits[((*src++)>>4)&0x0F]);
826 while (dst < dst_end);
829 else
831 dst_end = dst + width;
834 const unsigned char *src_col = src++;
835 fb_data *dst_col = dst++;
836 unsigned mask_col = mask;
837 unsigned data = 0;
839 for (y = ny; y >= 8; y -= 8)
841 data |= *src_col << shift;
843 if (mask_col & 0xFFFFu)
845 if (mask_col & 0xFFu)
846 bfunc(dst_col, mask_col, lcd_dibits[data&0x0F]);
847 bfunc(dst_col + LCD_WIDTH, mask_col >> 8,
848 lcd_dibits[(data>>4)&0x0F]);
849 mask_col = 0xFFFFu;
851 else
852 mask_col >>= 16;
854 src_col += stride;
855 dst_col += 2*LCD_WIDTH;
856 data >>= 8;
858 data |= *src_col << shift;
859 mask_col &= mask_bottom ;
860 if (mask_col & 0xFFu)
861 bfunc(dst_col, mask_col, lcd_dibits[data&0x0F]);
862 if (mask_col & 0xFF00u)
863 bfunc(dst_col + LCD_WIDTH, mask_col >> 8,
864 lcd_dibits[(data>>4)&0x0F]);
866 while (dst < dst_end);
870 /* Draw a full monochrome bitmap */
871 void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int height)
873 lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height);
876 /* About Rockbox' internal native bitmap format:
878 * A bitmap contains two bits for every pixel. 00 = white, 01 = light grey,
879 * 10 = dark grey, 11 = black. Bits within a byte are arranged vertically, LSB
880 * at top.
881 * The bytes are stored in row-major order, with byte 0 being top left,
882 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
883 * 0..3, the second row defines pixel row 4..7 etc.
885 * This is the same as the internal lcd hw format. */
887 /* Draw a partial native bitmap */
888 void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
889 int stride, int x, int y, int width,
890 int height)
892 int shift, ny;
893 fb_data *dst, *dst_end;
894 unsigned mask, mask_bottom;
896 /* nothing to draw? */
897 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
898 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
899 return;
901 /* clipping */
902 if (x < 0)
904 width += x;
905 src_x -= x;
906 x = 0;
908 if (y < 0)
910 height += y;
911 src_y -= y;
912 y = 0;
914 if (x + width > current_vp->width)
915 width = current_vp->width - x;
916 if (y + height > current_vp->height)
917 height = current_vp->height - y;
919 /* adjust for viewport */
920 x += current_vp->x;
921 y += current_vp->y;
923 src += stride * (src_y >> 2) + src_x; /* move starting point */
924 src_y &= 3;
925 y -= src_y;
926 dst = &lcd_framebuffer[y>>2][x];
927 shift = y & 3;
928 ny = height - 1 + shift + src_y;
930 mask = 0xFFu << (2 * (shift + src_y));
931 mask_bottom = 0xFFu >> (2 * (~ny & 3));
933 if (shift == 0)
935 for (; ny >= 4; ny -= 4)
937 if (mask == 0xFFu)
938 memcpy(dst, src, width);
939 else
941 const fb_data *src_row = src;
942 fb_data *dst_row = dst;
944 dst_end = dst_row + width;
946 setblock(dst_row++, mask, *src_row++);
947 while (dst_row < dst_end);
949 src += stride;
950 dst += LCD_WIDTH;
951 mask = 0xFFu;
953 mask &= mask_bottom;
955 if (mask == 0xFFu)
956 memcpy(dst, src, width);
957 else
959 dst_end = dst + width;
961 setblock(dst++, mask, *src++);
962 while (dst < dst_end);
965 else
967 shift *= 2;
968 dst_end = dst + width;
971 const fb_data *src_col = src++;
972 fb_data *dst_col = dst++;
973 unsigned mask_col = mask;
974 unsigned data = 0;
976 for (y = ny; y >= 4; y -= 4)
978 data |= *src_col << shift;
980 if (mask_col & 0xFFu)
982 setblock(dst_col, mask_col, data);
983 mask_col = 0xFFu;
985 else
986 mask_col >>= 8;
988 src_col += stride;
989 dst_col += LCD_WIDTH;
990 data >>= 8;
992 data |= *src_col << shift;
993 setblock(dst_col, mask_col & mask_bottom, data);
995 while (dst < dst_end);
999 /* Draw a full native bitmap */
1000 void lcd_bitmap(const fb_data *src, int x, int y, int width, int height)
1002 lcd_bitmap_part(src, 0, 0, width, x, y, width, height);
1005 #include "lcd-bitmap-common.c"