fuzev2: prevent button light flickering when accessing µSD
[kugel-rb.git] / firmware / drivers / lcd-2bit-vi.c
blob803a3678d0663d6fa923cc6f80e58f67ae371475
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 Jens Arnold
12 * Rockbox driver for 2bit vertically interleaved LCDs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
24 #include "config.h"
26 #include "lcd.h"
27 #include "kernel.h"
28 #include "thread.h"
29 #include <string.h>
30 #include <stdlib.h>
31 #include "memory.h"
32 #include "file.h"
33 #include "debug.h"
34 #include "system.h"
35 #include "font.h"
36 #include "rbunicode.h"
37 #include "bidi.h"
38 #include "scroll_engine.h"
40 #ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */
41 #define LCDFN(fn) lcd_ ## fn
42 #define FBFN(fn) fb_ ## fn
43 #define LCDM(ma) LCD_ ## ma
44 #define LCDNAME "lcd_"
45 #define MAIN_LCD
46 #endif
48 /*** globals ***/
50 FBFN(data) LCDFN(framebuffer)[LCDM(FBHEIGHT)][LCDM(FBWIDTH)] IRAM_LCDFRAMEBUFFER;
52 static const FBFN(data) patterns[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000};
54 static FBFN(data) *backdrop = NULL;
55 static long backdrop_offset IDATA_ATTR = 0;
57 static struct viewport default_vp =
59 .x = 0,
60 .y = 0,
61 .width = LCDM(WIDTH),
62 .height = LCDM(HEIGHT),
63 .font = FONT_SYSFIXED,
64 .drawmode = DRMODE_SOLID,
65 .fg_pattern = LCDM(DEFAULT_FG),
66 .bg_pattern = LCDM(DEFAULT_BG)
69 static struct viewport * current_vp IBSS_ATTR;
71 static unsigned fg_pattern IBSS_ATTR;
72 static unsigned bg_pattern IBSS_ATTR;
74 /*** Viewports ***/
76 void LCDFN(set_viewport)(struct viewport* vp)
78 if (vp == NULL)
79 current_vp = &default_vp;
80 else
81 current_vp = vp;
83 fg_pattern = patterns[current_vp->fg_pattern & 3];
84 bg_pattern = patterns[current_vp->bg_pattern & 3];
86 #if defined(SIMULATOR)
87 /* Force the viewport to be within bounds. If this happens it should
88 * be considered an error - the viewport will not draw as it might be
89 * expected.
91 if((unsigned) current_vp->x > (unsigned) LCDM(WIDTH)
92 || (unsigned) current_vp->y > (unsigned) LCDM(HEIGHT)
93 || current_vp->x + current_vp->width > LCDM(WIDTH)
94 || current_vp->y + current_vp->height > LCDM(HEIGHT))
96 #if !defined(HAVE_VIEWPORT_CLIP)
97 DEBUGF("ERROR: "
98 #else
99 DEBUGF("NOTE: "
100 #endif
101 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
102 current_vp->x, current_vp->y,
103 current_vp->width, current_vp->height);
106 #endif
109 void LCDFN(update_viewport)(void)
111 LCDFN(update_rect)(current_vp->x, current_vp->y,
112 current_vp->width, current_vp->height);
115 void LCDFN(update_viewport_rect)(int x, int y, int width, int height)
117 LCDFN(update_rect)(current_vp->x + x, current_vp->y + y, width, height);
120 /* LCD init */
121 void LCDFN(init)(void)
123 LCDFN(set_viewport)(NULL);
124 LCDFN(clear_display)();
125 #ifndef SIMULATOR
126 LCDFN(init_device)();
127 #endif
128 #ifdef MAIN_LCD
129 scroll_init();
130 #endif
133 /*** parameter handling ***/
135 #if !defined(MAIN_LCD) && defined(HAVE_LCD_COLOR)
136 /* When compiling for remote LCD and the main LCD is colour. */
137 unsigned lcd_remote_color_to_native(unsigned color)
139 unsigned r = (color & 0xf800) >> 10;
140 unsigned g = (color & 0x07e0) >> 5;
141 unsigned b = (color & 0x001f) << 2;
143 * |R|
144 * |Y'| = |0.299000 0.587000 0.114000| |G|
145 * |B|
147 return (5*r + 9*g + b) >> 8;
149 #endif
151 void LCDFN(set_drawmode)(int mode)
153 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
156 int LCDFN(get_drawmode)(void)
158 return current_vp->drawmode;
161 void LCDFN(set_foreground)(unsigned brightness)
163 current_vp->fg_pattern = brightness;
164 fg_pattern = patterns[brightness & 3];
167 unsigned LCDFN(get_foreground)(void)
169 return current_vp->fg_pattern;
172 void LCDFN(set_background)(unsigned brightness)
174 current_vp->bg_pattern = brightness;
175 bg_pattern = patterns[brightness & 3];
178 unsigned LCDFN(get_background)(void)
180 return current_vp->bg_pattern;
183 void LCDFN(set_drawinfo)(int mode, unsigned fg_brightness,
184 unsigned bg_brightness)
186 LCDFN(set_drawmode)(mode);
187 LCDFN(set_foreground)(fg_brightness);
188 LCDFN(set_background)(bg_brightness);
191 int LCDFN(getwidth)(void)
193 return current_vp->width;
196 int LCDFN(getheight)(void)
198 return current_vp->height;
200 void LCDFN(setfont)(int newfont)
202 current_vp->font = newfont;
205 int LCDFN(getfont)(void)
207 return current_vp->font;
210 int LCDFN(getstringsize)(const unsigned char *str, int *w, int *h)
212 return font_getstringsize(str, w, h, current_vp->font);
215 /*** low-level drawing functions ***/
217 static void setpixel(int x, int y)
219 unsigned mask = 0x0101 << (y & 7);
220 FBFN(data) *address = &LCDFN(framebuffer)[y>>3][x];
221 unsigned data = *address;
223 *address = data ^ ((data ^ fg_pattern) & mask);
226 static void clearpixel(int x, int y)
228 unsigned mask = 0x0101 << (y & 7);
229 FBFN(data) *address = &LCDFN(framebuffer)[y>>3][x];
230 unsigned data = *address;
232 *address = data ^ ((data ^ bg_pattern) & mask);
235 static void clearimgpixel(int x, int y)
237 unsigned mask = 0x0101 << (y & 7);
238 FBFN(data) *address = &LCDFN(framebuffer)[y>>3][x];
239 unsigned data = *address;
241 *address = data ^ ((data ^ *(FBFN(data) *)((long)address
242 + backdrop_offset)) & mask);
245 static void flippixel(int x, int y)
247 unsigned mask = 0x0101 << (y & 7);
248 FBFN(data) *address = &LCDFN(framebuffer)[y>>3][x];
250 *address ^= mask;
253 static void nopixel(int x, int y)
255 (void)x;
256 (void)y;
259 LCDFN(pixelfunc_type)* const LCDFN(pixelfuncs_bgcolor)[8] = {
260 flippixel, nopixel, setpixel, setpixel,
261 nopixel, clearpixel, nopixel, clearpixel
264 LCDFN(pixelfunc_type)* const LCDFN(pixelfuncs_backdrop)[8] = {
265 flippixel, nopixel, setpixel, setpixel,
266 nopixel, clearimgpixel, nopixel, clearimgpixel
269 LCDFN(pixelfunc_type)* const *LCDFN(pixelfuncs) = LCDFN(pixelfuncs_bgcolor);
271 /* 'mask' and 'bits' contain 2 bits per pixel */
272 static void ICODE_ATTR flipblock(FBFN(data) *address, unsigned mask,
273 unsigned bits)
275 *address ^= bits & mask;
278 static void ICODE_ATTR bgblock(FBFN(data) *address, unsigned mask,
279 unsigned bits)
281 unsigned data = *address;
283 *address = data ^ ((data ^ bg_pattern) & mask & ~bits);
286 static void ICODE_ATTR bgimgblock(FBFN(data) *address, unsigned mask,
287 unsigned bits)
289 unsigned data = *address;
291 *address = data ^ ((data ^ *(FBFN(data) *)((long)address
292 + backdrop_offset)) & mask & ~bits);
295 static void ICODE_ATTR fgblock(FBFN(data) *address, unsigned mask,
296 unsigned bits)
298 unsigned data = *address;
300 *address = data ^ ((data ^ fg_pattern) & mask & bits);
303 static void ICODE_ATTR solidblock(FBFN(data) *address, unsigned mask,
304 unsigned bits)
306 unsigned data = *address;
307 unsigned bgp = bg_pattern;
309 bits = bgp ^ ((bgp ^ fg_pattern) & bits);
310 *address = data ^ ((data ^ bits) & mask);
313 static void ICODE_ATTR solidimgblock(FBFN(data) *address, unsigned mask,
314 unsigned bits)
316 unsigned data = *address;
317 unsigned bgp = *(FBFN(data) *)((long)address + backdrop_offset);
319 bits = bgp ^ ((bgp ^ fg_pattern) & bits);
320 *address = data ^ ((data ^ bits) & mask);
323 static void ICODE_ATTR flipinvblock(FBFN(data) *address, unsigned mask,
324 unsigned bits)
326 *address ^= ~bits & mask;
329 static void ICODE_ATTR bginvblock(FBFN(data) *address, unsigned mask,
330 unsigned bits)
332 unsigned data = *address;
334 *address = data ^ ((data ^ bg_pattern) & mask & bits);
337 static void ICODE_ATTR bgimginvblock(FBFN(data) *address, unsigned mask,
338 unsigned bits)
340 unsigned data = *address;
342 *address = data ^ ((data ^ *(FBFN(data) *)((long)address
343 + backdrop_offset)) & mask & bits);
346 static void ICODE_ATTR fginvblock(FBFN(data) *address, unsigned mask,
347 unsigned bits)
349 unsigned data = *address;
351 *address = data ^ ((data ^ fg_pattern) & mask & ~bits);
354 static void ICODE_ATTR solidinvblock(FBFN(data) *address, unsigned mask,
355 unsigned bits)
357 unsigned data = *address;
358 unsigned fgp = fg_pattern;
360 bits = fgp ^ ((fgp ^ bg_pattern) & bits);
361 *address = data ^ ((data ^ bits) & mask);
364 static void ICODE_ATTR solidimginvblock(FBFN(data) *address, unsigned mask,
365 unsigned bits)
367 unsigned data = *address;
368 unsigned fgp = fg_pattern;
370 bits = fgp ^ ((fgp ^ *(FBFN(data) *)((long)address
371 + backdrop_offset)) & bits);
372 *address = data ^ ((data ^ bits) & mask);
375 LCDFN(blockfunc_type)* const LCDFN(blockfuncs_bgcolor)[8] = {
376 flipblock, bgblock, fgblock, solidblock,
377 flipinvblock, bginvblock, fginvblock, solidinvblock
380 LCDFN(blockfunc_type)* const LCDFN(blockfuncs_backdrop)[8] = {
381 flipblock, bgimgblock, fgblock, solidimgblock,
382 flipinvblock, bgimginvblock, fginvblock, solidimginvblock
385 LCDFN(blockfunc_type)* const *LCDFN(blockfuncs) = LCDFN(blockfuncs_bgcolor);
388 void LCDFN(set_backdrop)(FBFN(data) *bd)
390 backdrop = bd;
391 if (bd)
393 backdrop_offset = (long)bd - (long)LCDFN(framebuffer);
394 LCDFN(pixelfuncs) = LCDFN(pixelfuncs_backdrop);
395 LCDFN(blockfuncs) = LCDFN(blockfuncs_backdrop);
397 else
399 backdrop_offset = 0;
400 LCDFN(pixelfuncs) = LCDFN(pixelfuncs_bgcolor);
401 LCDFN(blockfuncs) = LCDFN(blockfuncs_bgcolor);
405 FBFN(data)* LCDFN(get_backdrop)(void)
407 return backdrop;
410 static inline void setblock(FBFN(data) *address, unsigned mask, unsigned bits)
412 unsigned data = *address;
414 bits ^= data;
415 *address = data ^ (bits & mask);
418 /*** drawing functions ***/
420 /* Clear the whole display */
421 void LCDFN(clear_display)(void)
423 if (default_vp.drawmode & DRMODE_INVERSEVID)
425 memset(LCDFN(framebuffer), patterns[default_vp.fg_pattern & 3],
426 sizeof LCDFN(framebuffer));
428 else
430 if (backdrop)
431 memcpy(LCDFN(framebuffer), backdrop, sizeof LCDFN(framebuffer));
432 else
433 memset(LCDFN(framebuffer), patterns[default_vp.bg_pattern & 3],
434 sizeof LCDFN(framebuffer));
437 LCDFN(scroll_info).lines = 0;
440 /* Clear the current viewport */
441 void LCDFN(clear_viewport)(void)
443 int lastmode;
445 if (current_vp == &default_vp)
447 LCDFN(clear_display)();
449 else
451 lastmode = current_vp->drawmode;
453 /* Invert the INVERSEVID bit and set basic mode to SOLID */
454 current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) |
455 DRMODE_SOLID;
457 LCDFN(fillrect)(0, 0, current_vp->width, current_vp->height);
459 current_vp->drawmode = lastmode;
461 LCDFN(scroll_stop)(current_vp);
465 /* Set a single pixel */
466 void LCDFN(drawpixel)(int x, int y)
468 if ( ((unsigned)x < (unsigned)current_vp->width)
469 && ((unsigned)y < (unsigned)current_vp->height)
470 #if defined(HAVE_VIEWPORT_CLIP)
471 && ((unsigned)x < (unsigned)LCDM(WIDTH))
472 && ((unsigned)y < (unsigned)LCDM(HEIGHT))
473 #endif
475 LCDFN(pixelfuncs)[current_vp->drawmode](current_vp->x+x, current_vp->y+y);
478 /* Draw a line */
479 void LCDFN(drawline)(int x1, int y1, int x2, int y2)
481 int numpixels;
482 int i;
483 int deltax, deltay;
484 int d, dinc1, dinc2;
485 int x, xinc1, xinc2;
486 int y, yinc1, yinc2;
487 LCDFN(pixelfunc_type) *pfunc = LCDFN(pixelfuncs)[current_vp->drawmode];
489 deltax = abs(x2 - x1);
490 if (deltax == 0)
492 /* DEBUGF(LCDNAME "drawline() called for vertical line - optimisation.\n"); */
493 LCDFN(vline)(x1, y1, y2);
494 return;
496 deltay = abs(y2 - y1);
497 if (deltay == 0)
499 /* DEBUGF(LCDNAME "drawline() called for horizontal line - optimisation.\n"); */
500 LCDFN(hline)(x1, x2, y1);
501 return;
503 xinc2 = 1;
504 yinc2 = 1;
506 if (deltax >= deltay)
508 numpixels = deltax;
509 d = 2 * deltay - deltax;
510 dinc1 = deltay * 2;
511 dinc2 = (deltay - deltax) * 2;
512 xinc1 = 1;
513 yinc1 = 0;
515 else
517 numpixels = deltay;
518 d = 2 * deltax - deltay;
519 dinc1 = deltax * 2;
520 dinc2 = (deltax - deltay) * 2;
521 xinc1 = 0;
522 yinc1 = 1;
524 numpixels++; /* include endpoints */
526 if (x1 > x2)
528 xinc1 = -xinc1;
529 xinc2 = -xinc2;
532 if (y1 > y2)
534 yinc1 = -yinc1;
535 yinc2 = -yinc2;
538 x = x1;
539 y = y1;
541 for (i = 0; i < numpixels; i++)
543 if ( ((unsigned)x < (unsigned)current_vp->width)
544 && ((unsigned)y < (unsigned)current_vp->height)
545 #if defined(HAVE_VIEWPORT_CLIP)
546 && ((unsigned)x < (unsigned)LCDM(WIDTH))
547 && ((unsigned)y < (unsigned)LCDM(HEIGHT))
548 #endif
550 pfunc(current_vp->x + x, current_vp->y + y);
552 if (d < 0)
554 d += dinc1;
555 x += xinc1;
556 y += yinc1;
558 else
560 d += dinc2;
561 x += xinc2;
562 y += yinc2;
567 /* Draw a horizontal line (optimised) */
568 void LCDFN(hline)(int x1, int x2, int y)
570 int x;
571 int width;
572 FBFN(data) *dst, *dst_end;
573 unsigned mask;
574 LCDFN(blockfunc_type) *bfunc;
576 /* direction flip */
577 if (x2 < x1)
579 x = x1;
580 x1 = x2;
581 x2 = x;
584 /******************** In viewport clipping **********************/
585 /* nothing to draw? */
586 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
587 || (x2 < 0))
588 return;
590 if (x1 < 0)
591 x1 = 0;
592 if (x2 >= current_vp->width)
593 x2 = current_vp->width-1;
595 /* adjust x1 and y to viewport */
596 x1 += current_vp->x;
597 x2 += current_vp->x;
598 y += current_vp->y;
600 #if defined(HAVE_VIEWPORT_CLIP)
601 /********************* Viewport on screen clipping ********************/
602 /* nothing to draw? */
603 if (((unsigned)y >= (unsigned) LCDM(HEIGHT)) || (x1 >= LCDM(WIDTH))
604 || (x2 < 0))
605 return;
607 /* clipping */
608 if (x1 < 0)
609 x1 = 0;
610 if (x2 >= LCDM(WIDTH))
611 x2 = LCDM(WIDTH)-1;
612 #endif
614 width = x2 - x1 + 1;
616 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
617 dst = &LCDFN(framebuffer)[y>>3][x1];
618 mask = 0x0101 << (y & 7);
620 dst_end = dst + width;
622 bfunc(dst++, mask, 0xFFFFu);
623 while (dst < dst_end);
626 /* Draw a vertical line (optimised) */
627 void LCDFN(vline)(int x, int y1, int y2)
629 int ny;
630 FBFN(data) *dst;
631 unsigned mask, mask_bottom;
632 LCDFN(blockfunc_type) *bfunc;
634 /* direction flip */
635 if (y2 < y1)
637 ny = y1;
638 y1 = y2;
639 y2 = ny;
642 /******************** In viewport clipping **********************/
643 /* nothing to draw? */
644 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
645 || (y2 < 0))
646 return;
648 if (y1 < 0)
649 y1 = 0;
650 if (y2 >= current_vp->height)
651 y2 = current_vp->height-1;
653 /* adjust for viewport */
654 y1 += current_vp->y;
655 y2 += current_vp->y;
656 x += current_vp->x;
658 #if defined(HAVE_VIEWPORT_CLIP)
659 /********************* Viewport on screen clipping ********************/
660 /* nothing to draw? */
661 if (( (unsigned) x >= (unsigned)LCDM(WIDTH)) || (y1 >= LCDM(HEIGHT))
662 || (y2 < 0))
663 return;
665 /* clipping */
666 if (y1 < 0)
667 y1 = 0;
668 if (y2 >= LCDM(HEIGHT))
669 y2 = LCDM(HEIGHT)-1;
670 #endif
672 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
673 dst = &LCDFN(framebuffer)[y1>>3][x];
674 ny = y2 - (y1 & ~7);
675 mask = (0xFFu << (y1 & 7)) & 0xFFu;
676 mask |= mask << 8;
677 mask_bottom = 0xFFu >> (~ny & 7);
678 mask_bottom |= mask_bottom << 8;
680 for (; ny >= 8; ny -= 8)
682 bfunc(dst, mask, 0xFFFFu);
683 dst += LCDM(WIDTH);
684 mask = 0xFFFFu;
686 mask &= mask_bottom;
687 bfunc(dst, mask, 0xFFFFu);
690 /* Draw a rectangular box */
691 void LCDFN(drawrect)(int x, int y, int width, int height)
693 if ((width <= 0) || (height <= 0))
694 return;
696 int x2 = x + width - 1;
697 int y2 = y + height - 1;
699 LCDFN(vline)(x, y, y2);
700 LCDFN(vline)(x2, y, y2);
701 LCDFN(hline)(x, x2, y);
702 LCDFN(hline)(x, x2, y2);
705 /* Fill a rectangular area */
706 void LCDFN(fillrect)(int x, int y, int width, int height)
708 int ny;
709 FBFN(data) *dst, *dst_end;
710 unsigned mask, mask_bottom;
711 unsigned bits = 0;
712 LCDFN(blockfunc_type) *bfunc;
713 bool fillopt = false;
715 /******************** In viewport clipping **********************/
716 /* nothing to draw? */
717 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
718 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
719 return;
721 if (x < 0)
723 width += x;
724 x = 0;
726 if (y < 0)
728 height += y;
729 y = 0;
731 if (x + width > current_vp->width)
732 width = current_vp->width - x;
733 if (y + height > current_vp->height)
734 height = current_vp->height - y;
736 /* adjust for viewport */
737 x += current_vp->x;
738 y += current_vp->y;
740 #if defined(HAVE_VIEWPORT_CLIP)
741 /********************* Viewport on screen clipping ********************/
742 /* nothing to draw? */
743 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
744 || (x + width <= 0) || (y + height <= 0))
745 return;
747 /* clip image in viewport in screen */
748 if (x < 0)
750 width += x;
751 x = 0;
753 if (y < 0)
755 height += y;
756 y = 0;
758 if (x + width > LCDM(WIDTH))
759 width = LCDM(WIDTH) - x;
760 if (y + height > LCDM(HEIGHT))
761 height = LCDM(HEIGHT) - y;
762 #endif
765 if (current_vp->drawmode & DRMODE_INVERSEVID)
767 if ((current_vp->drawmode & DRMODE_BG) && !backdrop)
769 fillopt = true;
770 bits = bg_pattern;
773 else
775 if (current_vp->drawmode & DRMODE_FG)
777 fillopt = true;
778 bits = fg_pattern;
781 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
782 dst = &LCDFN(framebuffer)[y>>3][x];
783 ny = height - 1 + (y & 7);
784 mask = (0xFFu << (y & 7)) & 0xFFu;
785 mask |= mask << 8;
786 mask_bottom = 0xFFu >> (~ny & 7);
787 mask_bottom |= mask_bottom << 8;
789 for (; ny >= 8; ny -= 8)
791 if (fillopt && (mask == 0xFFFFu))
792 memset16(dst, bits, width);
793 else
795 FBFN(data) *dst_row = dst;
797 dst_end = dst_row + width;
799 bfunc(dst_row++, mask, 0xFFFFu);
800 while (dst_row < dst_end);
803 dst += LCDM(WIDTH);
804 mask = 0xFFFFu;
806 mask &= mask_bottom;
808 if (fillopt && (mask == 0xFFFFu))
809 memset16(dst, bits, width);
810 else
812 dst_end = dst + width;
814 bfunc(dst++, mask, 0xFFFFu);
815 while (dst < dst_end);
819 /* About Rockbox' internal monochrome bitmap format:
821 * A bitmap contains one bit for every pixel that defines if that pixel is
822 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
823 * at top.
824 * The bytes are stored in row-major order, with byte 0 being top left,
825 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
826 * 0..7, the second row defines pixel row 8..15 etc.
828 * This is similar to the internal lcd hw format. */
830 /* Draw a partial monochrome bitmap */
831 void ICODE_ATTR LCDFN(mono_bitmap_part)(const unsigned char *src, int src_x,
832 int src_y, int stride, int x, int y,
833 int width, int height)
835 int shift, ny;
836 FBFN(data) *dst, *dst_end;
837 unsigned data, mask, mask_bottom;
838 LCDFN(blockfunc_type) *bfunc;
840 /******************** Image in viewport clipping **********************/
841 /* nothing to draw? */
842 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
843 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
844 return;
846 if (x < 0)
848 width += x;
849 src_x -= x;
850 x = 0;
852 if (y < 0)
854 height += y;
855 src_y -= y;
856 y = 0;
858 if (x + width > current_vp->width)
859 width = current_vp->width - x;
860 if (y + height > current_vp->height)
861 height = current_vp->height - y;
863 /* adjust for viewport */
864 x += current_vp->x;
865 y += current_vp->y;
867 #if defined(HAVE_VIEWPORT_CLIP)
868 /********************* Viewport on screen clipping ********************/
869 /* nothing to draw? */
870 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
871 || (x + width <= 0) || (y + height <= 0))
872 return;
874 /* clip image in viewport in screen */
875 if (x < 0)
877 width += x;
878 src_x -= x;
879 x = 0;
881 if (y < 0)
883 height += y;
884 src_y -= y;
885 y = 0;
887 if (x + width > LCDM(WIDTH))
888 width = LCDM(WIDTH) - x;
889 if (y + height > LCDM(HEIGHT))
890 height = LCDM(HEIGHT) - y;
891 #endif
893 src += stride * (src_y >> 3) + src_x; /* move starting point */
894 src_y &= 7;
895 y -= src_y;
896 dst = &LCDFN(framebuffer)[y>>3][x];
897 shift = y & 7;
898 ny = height - 1 + shift + src_y;
900 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
901 mask = 0xFFu << (shift + src_y);
902 /* not byte-doubled here because shift+src_y can be > 7 */
903 mask_bottom = 0xFFu >> (~ny & 7);
904 mask_bottom |= mask_bottom << 8;
906 if (shift == 0)
908 mask &= 0xFFu;
909 mask |= mask << 8;
911 for (; ny >= 8; ny -= 8)
913 const unsigned char *src_row = src;
914 FBFN(data) *dst_row = dst;
916 dst_end = dst_row + width;
919 data = *src_row++;
920 bfunc(dst_row++, mask, data | (data << 8));
922 while (dst_row < dst_end);
924 src += stride;
925 dst += LCDM(WIDTH);
926 mask = 0xFFFFu;
928 mask &= mask_bottom;
930 dst_end = dst + width;
933 data = *src++;
934 bfunc(dst++, mask, data | (data << 8));
936 while (dst < dst_end);
938 else
940 unsigned ddata;
942 dst_end = dst + width;
945 const unsigned char *src_col = src++;
946 FBFN(data) *dst_col = dst++;
947 unsigned mask_col = mask & 0xFFu;
949 mask_col |= mask_col << 8;
950 data = 0;
952 for (y = ny; y >= 8; y -= 8)
954 data |= *src_col << shift;
956 if (mask_col)
958 ddata = data & 0xFFu;
959 bfunc(dst_col, mask_col, ddata | (ddata << 8));
960 mask_col = 0xFFFFu;
962 else
964 mask_col = (mask >> 8) & 0xFFu;
965 mask_col |= mask_col << 8;
968 src_col += stride;
969 dst_col += LCDM(WIDTH);
970 data >>= 8;
972 data |= *src_col << shift;
973 mask_col &= mask_bottom;
974 ddata = data & 0xFFu;
975 bfunc(dst_col, mask_col, ddata | (ddata << 8));
977 while (dst < dst_end);
981 /* Draw a full monochrome bitmap */
982 void LCDFN(mono_bitmap)(const unsigned char *src, int x, int y, int width,
983 int height)
985 LCDFN(mono_bitmap_part)(src, 0, 0, width, x, y, width, height);
988 /* About Rockbox' internal native bitmap format:
990 * A bitmap contains one bit in each byte of a pair of bytes for every pixel.
991 * 00 = white, 01 = light grey, 10 = dark grey, 11 = black. Bits within a byte
992 * are arranged vertically, LSB at top.
993 * The pairs of bytes are stored as shorts, in row-major order, with word 0
994 * being top left, word 1 2nd from left etc. The first row of words defines
995 * pixel rows 0..7, the second row defines pixel row 8..15 etc.
997 * This is the same as the internal lcd hw format. */
999 /* Draw a partial native bitmap */
1000 void ICODE_ATTR LCDFN(bitmap_part)(const FBFN(data) *src, int src_x,
1001 int src_y, int stride, int x, int y,
1002 int width, int height)
1004 int shift, ny;
1005 FBFN(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))
1012 return;
1014 if (x < 0)
1016 width += x;
1017 src_x -= x;
1018 x = 0;
1020 if (y < 0)
1022 height += y;
1023 src_y -= y;
1024 y = 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 */
1032 x += current_vp->x;
1033 y += current_vp->y;
1035 #if defined(HAVE_VIEWPORT_CLIP)
1036 /********************* Viewport on screen clipping ********************/
1037 /* nothing to draw? */
1038 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
1039 || (x + width <= 0) || (y + height <= 0))
1040 return;
1042 /* clip image in viewport in screen */
1043 if (x < 0)
1045 width += x;
1046 src_x -= x;
1047 x = 0;
1049 if (y < 0)
1051 height += y;
1052 src_y -= y;
1053 y = 0;
1055 if (x + width > LCDM(WIDTH))
1056 width = LCDM(WIDTH) - x;
1057 if (y + height > LCDM(HEIGHT))
1058 height = LCDM(HEIGHT) - y;
1059 #endif
1061 src += stride * (src_y >> 3) + src_x; /* move starting point */
1062 src_y &= 7;
1063 y -= src_y;
1064 dst = &LCDFN(framebuffer)[y>>3][x];
1065 shift = y & 7;
1066 ny = height - 1 + shift + src_y;
1068 mask = 0xFFu << (shift + src_y);
1069 /* not byte-doubled here because shift+src_y can be > 7 */
1070 mask_bottom = 0xFFu >> (~ny & 7);
1071 mask_bottom |= mask_bottom << 8;
1073 if (shift == 0)
1075 mask &= 0xFFu;
1076 mask |= mask << 8;
1078 for (; ny >= 8; ny -= 8)
1080 if (mask == 0xFFFFu)
1081 memcpy(dst, src, width * sizeof(FBFN(data)));
1082 else
1084 const FBFN(data) *src_row = src;
1085 FBFN(data) *dst_row = dst;
1087 dst_end = dst_row + width;
1089 setblock(dst_row++, mask, *src_row++);
1090 while (dst_row < dst_end);
1092 src += stride;
1093 dst += LCDM(WIDTH);
1094 mask = 0xFFFFu;
1096 mask &= mask_bottom;
1098 if (mask == 0xFFFFu)
1099 memcpy(dst, src, width * sizeof(FBFN(data)));
1100 else
1102 dst_end = dst + width;
1104 setblock(dst++, mask, *src++);
1105 while (dst < dst_end);
1108 else
1110 unsigned datamask = (0xFFu << shift) & 0xFFu;
1112 datamask |= datamask << 8;
1114 dst_end = dst + width;
1117 const FBFN(data) *src_col = src++;
1118 FBFN(data) *dst_col = dst++;
1119 unsigned mask_col = mask & 0xFFu;
1120 unsigned data, olddata = 0;
1122 mask_col |= mask_col << 8;
1124 for (y = ny; y >= 8; y -= 8)
1126 data = *src_col << shift;
1128 if (mask_col)
1130 setblock(dst_col, mask_col,
1131 olddata ^((olddata ^ data) & datamask));
1132 mask_col = 0xFFFFu;
1134 else
1136 mask_col = (mask >> 8) & 0xFFu;
1137 mask_col |= mask_col << 8;
1139 src_col += stride;
1140 dst_col += LCDM(WIDTH);
1141 olddata = data >> 8;
1143 data = *src_col << shift;
1144 setblock(dst_col, mask_col & mask_bottom,
1145 olddata ^((olddata ^ data) & datamask));
1147 while (dst < dst_end);
1151 /* Draw a full native bitmap */
1152 void LCDFN(bitmap)(const FBFN(data) *src, int x, int y, int width, int height)
1154 LCDFN(bitmap_part)(src, 0, 0, width, x, y, width, height);
1157 #include "lcd-bitmap-common.c"