fuzev2: prevent button light flickering when accessing µSD
[kugel-rb.git] / firmware / drivers / lcd-2bit-vert.c
blob02699099d7f26fb7c592d2909b1909279f6cf383
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);
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
96 * expected.
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)
104 DEBUGF("ERROR: "
105 #else
106 DEBUGF("NOTE: "
107 #endif
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);
113 #endif
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];
228 *address ^= mask;
231 static void nopixel(int x, int y)
233 (void)x;
234 (void)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,
252 unsigned bits)
254 *address ^= bits & mask;
257 static void ICODE_ATTR bgblock(fb_data *address, unsigned mask,
258 unsigned bits)
260 unsigned data = *address;
262 *address = data ^ ((data ^ bg_pattern) & mask & ~bits);
265 static void ICODE_ATTR bgimgblock(fb_data *address, unsigned mask,
266 unsigned bits)
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,
274 unsigned bits)
276 unsigned data = *address;
278 *address = data ^ ((data ^ fg_pattern) & mask & bits);
281 static void ICODE_ATTR solidblock(fb_data *address, unsigned mask,
282 unsigned bits)
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,
292 unsigned bits)
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,
302 unsigned bits)
304 *address ^= ~bits & mask;
307 static void ICODE_ATTR bginvblock(fb_data *address, unsigned mask,
308 unsigned bits)
310 unsigned data = *address;
312 *address = data ^ ((data ^ bg_pattern) & mask & bits);
315 static void ICODE_ATTR bgimginvblock(fb_data *address, unsigned mask,
316 unsigned bits)
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,
324 unsigned bits)
326 unsigned data = *address;
328 *address = data ^ ((data ^ fg_pattern) & mask & ~bits);
331 static void ICODE_ATTR solidinvblock(fb_data *address, unsigned mask,
332 unsigned bits)
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,
342 unsigned bits)
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;
367 if (backdrop)
369 lcd_backdrop_offset = (long)backdrop - (long)lcd_framebuffer;
370 lcd_pixelfuncs = lcd_pixelfuncs_backdrop;
371 lcd_blockfuncs = lcd_blockfuncs_backdrop;
373 else
375 lcd_backdrop_offset = 0;
376 lcd_pixelfuncs = lcd_pixelfuncs_bgcolor;
377 lcd_blockfuncs = lcd_blockfuncs_bgcolor;
381 fb_data* lcd_get_backdrop(void)
383 return lcd_backdrop;
387 static inline void setblock(fb_data *address, unsigned mask, unsigned bits)
389 unsigned data = *address;
391 bits ^= data;
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);
404 else
406 if (lcd_backdrop)
407 memcpy(lcd_framebuffer, lcd_backdrop, sizeof lcd_framebuffer);
408 else
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)
418 int lastmode;
420 if (current_vp == &default_vp)
422 lcd_clear_display();
424 else
426 lastmode = current_vp->drawmode;
428 /* Invert the INVERSEVID bit and set basic mode to SOLID */
429 current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) |
430 DRMODE_SOLID;
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)
448 #endif
450 lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
453 /* Draw a line */
454 void lcd_drawline(int x1, int y1, int x2, int y2)
456 int numpixels;
457 int i;
458 int deltax, deltay;
459 int d, dinc1, dinc2;
460 int x, xinc1, xinc2;
461 int y, yinc1, yinc2;
462 lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[current_vp->drawmode];
464 deltax = abs(x2 - x1);
465 if (deltax == 0)
467 /* DEBUGF("lcd_drawline() called for vertical line - optimisation.\n"); */
468 lcd_vline(x1, y1, y2);
469 return;
471 deltay = abs(y2 - y1);
472 if (deltay == 0)
474 /* DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n"); */
475 lcd_hline(x1, x2, y1);
476 return;
478 xinc2 = 1;
479 yinc2 = 1;
481 if (deltax >= deltay)
483 numpixels = deltax;
484 d = 2 * deltay - deltax;
485 dinc1 = deltay * 2;
486 dinc2 = (deltay - deltax) * 2;
487 xinc1 = 1;
488 yinc1 = 0;
490 else
492 numpixels = deltay;
493 d = 2 * deltax - deltay;
494 dinc1 = deltax * 2;
495 dinc2 = (deltax - deltay) * 2;
496 xinc1 = 0;
497 yinc1 = 1;
499 numpixels++; /* include endpoints */
501 if (x1 > x2)
503 xinc1 = -xinc1;
504 xinc2 = -xinc2;
507 if (y1 > y2)
509 yinc1 = -yinc1;
510 yinc2 = -yinc2;
513 x = x1;
514 y = y1;
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)
523 #endif
525 pfunc(current_vp->x + x, current_vp->y + y);
527 if (d < 0)
529 d += dinc1;
530 x += xinc1;
531 y += yinc1;
533 else
535 d += dinc2;
536 x += xinc2;
537 y += yinc2;
542 /* Draw a horizontal line (optimised) */
543 void lcd_hline(int x1, int x2, int y)
545 int x;
546 int width;
547 fb_data *dst, *dst_end;
548 unsigned mask;
549 lcd_blockfunc_type *bfunc;
551 /* direction flip */
552 if (x2 < x1)
554 x = x1;
555 x1 = x2;
556 x2 = x;
559 /******************** In viewport clipping **********************/
560 /* nothing to draw? */
561 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
562 || (x2 < 0))
563 return;
565 if (x1 < 0)
566 x1 = 0;
567 if (x2 >= current_vp->width)
568 x2 = current_vp->width-1;
570 /* adjust x1 and y to viewport */
571 x1 += current_vp->x;
572 x2 += current_vp->x;
573 y += current_vp->y;
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)
579 || (x2 < 0))
580 return;
582 /* clipping */
583 if (x1 < 0)
584 x1 = 0;
585 if (x2 >= LCD_WIDTH)
586 x2 = LCD_WIDTH-1;
587 #endif
589 width = x2 - x1 + 1;
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)
604 int ny;
605 fb_data *dst;
606 unsigned mask, mask_bottom;
607 lcd_blockfunc_type *bfunc;
609 /* direction flip */
610 if (y2 < y1)
612 ny = y1;
613 y1 = y2;
614 y2 = ny;
617 /******************** In viewport clipping **********************/
618 /* nothing to draw? */
619 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
620 || (y2 < 0))
621 return;
623 if (y1 < 0)
624 y1 = 0;
625 if (y2 >= current_vp->height)
626 y2 = current_vp->height-1;
628 /* adjust for viewport */
629 y1 += current_vp->y;
630 y2 += current_vp->y;
631 x += current_vp->x;
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)
637 || (y2 < 0))
638 return;
640 /* clipping */
641 if (y1 < 0)
642 y1 = 0;
643 if (y2 >= LCD_HEIGHT)
644 y2 = LCD_HEIGHT-1;
645 #endif
647 bfunc = lcd_blockfuncs[current_vp->drawmode];
648 dst = &lcd_framebuffer[y1>>2][x];
649 ny = y2 - (y1 & ~3);
650 mask = 0xFFu << (2 * (y1 & 3));
651 mask_bottom = 0xFFu >> (2 * (~ny & 3));
653 for (; ny >= 4; ny -= 4)
655 bfunc(dst, mask, 0xFFu);
656 dst += LCD_WIDTH;
657 mask = 0xFFu;
659 mask &= mask_bottom;
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))
667 return;
669 int x2 = x + width - 1;
670 int y2 = y + height - 1;
672 lcd_vline(x, y, y2);
673 lcd_vline(x2, y, y2);
674 lcd_hline(x, x2, y);
675 lcd_hline(x, x2, y2);
678 /* Fill a rectangular area */
679 void lcd_fillrect(int x, int y, int width, int height)
681 int ny;
682 fb_data *dst, *dst_end;
683 unsigned mask, mask_bottom;
684 unsigned bits = 0;
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))
692 return;
694 if (x < 0)
696 width += x;
697 x = 0;
699 if (y < 0)
701 height += y;
702 y = 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 */
710 x += current_vp->x;
711 y += current_vp->y;
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))
718 return;
720 /* clip image in viewport in screen */
721 if (x < 0)
723 width += x;
724 x = 0;
726 if (y < 0)
728 height += y;
729 y = 0;
731 if (x + width > LCD_WIDTH)
732 width = LCD_WIDTH - x;
733 if (y + height > LCD_HEIGHT)
734 height = LCD_HEIGHT - y;
735 #endif
737 if (current_vp->drawmode & DRMODE_INVERSEVID)
739 if ((current_vp->drawmode & DRMODE_BG) && !lcd_backdrop)
741 fillopt = true;
742 bits = bg_pattern;
745 else
747 if (current_vp->drawmode & DRMODE_FG)
749 fillopt = true;
750 bits = fg_pattern;
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);
763 else
765 fb_data *dst_row = dst;
767 dst_end = dst_row + width;
769 bfunc(dst_row++, mask, 0xFFu);
770 while (dst_row < dst_end);
773 dst += LCD_WIDTH;
774 mask = 0xFFu;
776 mask &= mask_bottom;
778 if (fillopt && (mask == 0xFFu))
779 memset(dst, bits, width);
780 else
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
793 * at top.
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)
805 int shift, ny;
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))
814 return;
816 if (x < 0)
818 width += x;
819 src_x -= x;
820 x = 0;
822 if (y < 0)
824 height += y;
825 src_y -= y;
826 y = 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 */
834 x += current_vp->x;
835 y += current_vp->y;
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))
842 return;
844 /* clip image in viewport in screen */
845 if (x < 0)
847 width += x;
848 src_x -= x;
849 x = 0;
851 if (y < 0)
853 height += y;
854 src_y -= y;
855 y = 0;
857 if (x + width > LCD_WIDTH)
858 width = LCD_WIDTH - x;
859 if (y + height > LCD_HEIGHT)
860 height = LCD_HEIGHT - y;
861 #endif
863 src += stride * (src_y >> 3) + src_x; /* move starting point */
864 src_y &= 7;
865 y -= src_y;
866 dst = &lcd_framebuffer[y>>2][x];
867 shift = y & 3;
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];
875 if (shift == 0)
877 unsigned dmask1, dmask2, data;
879 dmask1 = mask & 0xFFu;
880 dmask2 = mask >> 8;
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;
889 if (dmask1 != 0)
893 data = *src_row++;
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);
899 else
902 bfunc(dst_row++, dmask2, lcd_dibits[((*src_row++)>>4)&0x0F]);
903 while (dst_row < dst_end);
905 src += stride;
906 dst += 2*LCD_WIDTH;
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;
914 if (dmask1 != 0)
916 if (dmask2 != 0)
920 data = *src++;
921 bfunc(dst, dmask1, lcd_dibits[data&0x0F]);
922 bfunc((dst++) + LCD_WIDTH, dmask2, lcd_dibits[(data>>4)&0x0F]);
924 while (dst < dst_end);
926 else
929 bfunc(dst++, dmask1, lcd_dibits[(*src++)&0x0F]);
930 while (dst < dst_end);
933 else
936 bfunc((dst++) + LCD_WIDTH, dmask2, lcd_dibits[((*src++)>>4)&0x0F]);
937 while (dst < dst_end);
940 else
942 dst_end = dst + width;
945 const unsigned char *src_col = src++;
946 fb_data *dst_col = dst++;
947 unsigned mask_col = mask;
948 unsigned data = 0;
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]);
960 mask_col = 0xFFFFu;
962 else
963 mask_col >>= 16;
965 src_col += stride;
966 dst_col += 2*LCD_WIDTH;
967 data >>= 8;
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
991 * at top.
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,
1001 int height)
1003 int shift, ny;
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))
1011 return;
1013 if (x < 0)
1015 width += x;
1016 src_x -= x;
1017 x = 0;
1019 if (y < 0)
1021 height += y;
1022 src_y -= y;
1023 y = 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 */
1031 x += current_vp->x;
1032 y += current_vp->y;
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))
1039 return;
1041 /* clip image in viewport in screen */
1042 if (x < 0)
1044 width += x;
1045 src_x -= x;
1046 x = 0;
1048 if (y < 0)
1050 height += y;
1051 src_y -= y;
1052 y = 0;
1054 if (x + width > LCD_WIDTH)
1055 width = LCD_WIDTH - x;
1056 if (y + height > LCD_HEIGHT)
1057 height = LCD_HEIGHT - y;
1058 #endif
1060 src += stride * (src_y >> 2) + src_x; /* move starting point */
1061 src_y &= 3;
1062 y -= src_y;
1063 dst = &lcd_framebuffer[y>>2][x];
1064 shift = y & 3;
1065 ny = height - 1 + shift + src_y;
1067 mask = 0xFFu << (2 * (shift + src_y));
1068 mask_bottom = 0xFFu >> (2 * (~ny & 3));
1070 if (shift == 0)
1072 for (; ny >= 4; ny -= 4)
1074 if (mask == 0xFFu)
1075 memcpy(dst, src, width);
1076 else
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);
1086 src += stride;
1087 dst += LCD_WIDTH;
1088 mask = 0xFFu;
1090 mask &= mask_bottom;
1092 if (mask == 0xFFu)
1093 memcpy(dst, src, width);
1094 else
1096 dst_end = dst + width;
1098 setblock(dst++, mask, *src++);
1099 while (dst < dst_end);
1102 else
1104 shift *= 2;
1105 dst_end = dst + width;
1108 const fb_data *src_col = src++;
1109 fb_data *dst_col = dst++;
1110 unsigned mask_col = mask;
1111 unsigned data = 0;
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);
1120 mask_col = 0xFFu;
1122 else
1123 mask_col >>= 8;
1125 src_col += stride;
1126 dst_col += LCD_WIDTH;
1127 data >>= 8;
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"