Sansa clip+: do not set GPIO B7 in the display driver, it's already used for FM radio I2C
[kugel-rb.git] / firmware / drivers / lcd-2bit-vi.c
blob697d1a77832e170eb6cdaa497438593893c05e00
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 <stdlib.h>
30 #include "string-extra.h" /* mem*() */
31 #include "file.h"
32 #include "debug.h"
33 #include "system.h"
34 #include "font.h"
35 #include "rbunicode.h"
36 #include "bidi.h"
37 #include "scroll_engine.h"
39 #ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */
40 #define LCDFN(fn) lcd_ ## fn
41 #define FBFN(fn) fb_ ## fn
42 #define LCDM(ma) LCD_ ## ma
43 #define LCDNAME "lcd_"
44 #define MAIN_LCD
45 #endif
47 /*** globals ***/
49 FBFN(data) LCDFN(framebuffer)[LCDM(FBHEIGHT)][LCDM(FBWIDTH)] IRAM_LCDFRAMEBUFFER;
51 static const FBFN(data) patterns[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000};
53 static FBFN(data) *backdrop = NULL;
54 static long backdrop_offset IDATA_ATTR = 0;
56 static struct viewport default_vp =
58 .x = 0,
59 .y = 0,
60 .width = LCDM(WIDTH),
61 .height = LCDM(HEIGHT),
62 .font = FONT_SYSFIXED,
63 .drawmode = DRMODE_SOLID,
64 .fg_pattern = LCDM(DEFAULT_FG),
65 .bg_pattern = LCDM(DEFAULT_BG)
68 static struct viewport * current_vp IBSS_ATTR;
70 static unsigned fg_pattern IBSS_ATTR;
71 static unsigned bg_pattern IBSS_ATTR;
73 /*** Viewports ***/
75 void LCDFN(set_viewport)(struct viewport* vp)
77 if (vp == NULL)
78 current_vp = &default_vp;
79 else
80 current_vp = vp;
82 fg_pattern = patterns[current_vp->fg_pattern & 3];
83 bg_pattern = patterns[current_vp->bg_pattern & 3];
85 #if defined(SIMULATOR)
86 /* Force the viewport to be within bounds. If this happens it should
87 * be considered an error - the viewport will not draw as it might be
88 * expected.
90 if((unsigned) current_vp->x > (unsigned) LCDM(WIDTH)
91 || (unsigned) current_vp->y > (unsigned) LCDM(HEIGHT)
92 || current_vp->x + current_vp->width > LCDM(WIDTH)
93 || current_vp->y + current_vp->height > LCDM(HEIGHT))
95 #if !defined(HAVE_VIEWPORT_CLIP)
96 DEBUGF("ERROR: "
97 #else
98 DEBUGF("NOTE: "
99 #endif
100 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
101 current_vp->x, current_vp->y,
102 current_vp->width, current_vp->height);
105 #endif
108 void LCDFN(update_viewport)(void)
110 LCDFN(update_rect)(current_vp->x, current_vp->y,
111 current_vp->width, current_vp->height);
114 void LCDFN(update_viewport_rect)(int x, int y, int width, int height)
116 LCDFN(update_rect)(current_vp->x + x, current_vp->y + y, width, height);
119 /* LCD init */
120 void LCDFN(init)(void)
122 LCDFN(set_viewport)(NULL);
123 LCDFN(clear_display)();
124 LCDFN(init_device)();
125 #ifdef MAIN_LCD
126 scroll_init();
127 #endif
130 /*** parameter handling ***/
132 #if !defined(MAIN_LCD) && defined(HAVE_LCD_COLOR)
133 /* When compiling for remote LCD and the main LCD is colour. */
134 unsigned lcd_remote_color_to_native(unsigned color)
136 unsigned r = (color & 0xf800) >> 10;
137 unsigned g = (color & 0x07e0) >> 5;
138 unsigned b = (color & 0x001f) << 2;
140 * |R|
141 * |Y'| = |0.299000 0.587000 0.114000| |G|
142 * |B|
144 return (5*r + 9*g + b) >> 8;
146 #endif
148 void LCDFN(set_drawmode)(int mode)
150 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
153 int LCDFN(get_drawmode)(void)
155 return current_vp->drawmode;
158 void LCDFN(set_foreground)(unsigned brightness)
160 current_vp->fg_pattern = brightness;
161 fg_pattern = patterns[brightness & 3];
164 unsigned LCDFN(get_foreground)(void)
166 return current_vp->fg_pattern;
169 void LCDFN(set_background)(unsigned brightness)
171 current_vp->bg_pattern = brightness;
172 bg_pattern = patterns[brightness & 3];
175 unsigned LCDFN(get_background)(void)
177 return current_vp->bg_pattern;
180 void LCDFN(set_drawinfo)(int mode, unsigned fg_brightness,
181 unsigned bg_brightness)
183 LCDFN(set_drawmode)(mode);
184 LCDFN(set_foreground)(fg_brightness);
185 LCDFN(set_background)(bg_brightness);
188 int LCDFN(getwidth)(void)
190 return current_vp->width;
193 int LCDFN(getheight)(void)
195 return current_vp->height;
197 void LCDFN(setfont)(int newfont)
199 current_vp->font = newfont;
202 int LCDFN(getfont)(void)
204 return current_vp->font;
207 int LCDFN(getstringsize)(const unsigned char *str, int *w, int *h)
209 return font_getstringsize(str, w, h, current_vp->font);
212 /*** low-level drawing functions ***/
214 static void setpixel(int x, int y)
216 unsigned mask = 0x0101 << (y & 7);
217 FBFN(data) *address = &LCDFN(framebuffer)[y>>3][x];
218 unsigned data = *address;
220 *address = data ^ ((data ^ fg_pattern) & mask);
223 static void clearpixel(int x, int y)
225 unsigned mask = 0x0101 << (y & 7);
226 FBFN(data) *address = &LCDFN(framebuffer)[y>>3][x];
227 unsigned data = *address;
229 *address = data ^ ((data ^ bg_pattern) & mask);
232 static void clearimgpixel(int x, int y)
234 unsigned mask = 0x0101 << (y & 7);
235 FBFN(data) *address = &LCDFN(framebuffer)[y>>3][x];
236 unsigned data = *address;
238 *address = data ^ ((data ^ *(FBFN(data) *)((long)address
239 + backdrop_offset)) & mask);
242 static void flippixel(int x, int y)
244 unsigned mask = 0x0101 << (y & 7);
245 FBFN(data) *address = &LCDFN(framebuffer)[y>>3][x];
247 *address ^= mask;
250 static void nopixel(int x, int y)
252 (void)x;
253 (void)y;
256 LCDFN(pixelfunc_type)* const LCDFN(pixelfuncs_bgcolor)[8] = {
257 flippixel, nopixel, setpixel, setpixel,
258 nopixel, clearpixel, nopixel, clearpixel
261 LCDFN(pixelfunc_type)* const LCDFN(pixelfuncs_backdrop)[8] = {
262 flippixel, nopixel, setpixel, setpixel,
263 nopixel, clearimgpixel, nopixel, clearimgpixel
266 LCDFN(pixelfunc_type)* const *LCDFN(pixelfuncs) = LCDFN(pixelfuncs_bgcolor);
268 /* 'mask' and 'bits' contain 2 bits per pixel */
269 static void ICODE_ATTR flipblock(FBFN(data) *address, unsigned mask,
270 unsigned bits)
272 *address ^= bits & mask;
275 static void ICODE_ATTR bgblock(FBFN(data) *address, unsigned mask,
276 unsigned bits)
278 unsigned data = *address;
280 *address = data ^ ((data ^ bg_pattern) & mask & ~bits);
283 static void ICODE_ATTR bgimgblock(FBFN(data) *address, unsigned mask,
284 unsigned bits)
286 unsigned data = *address;
288 *address = data ^ ((data ^ *(FBFN(data) *)((long)address
289 + backdrop_offset)) & mask & ~bits);
292 static void ICODE_ATTR fgblock(FBFN(data) *address, unsigned mask,
293 unsigned bits)
295 unsigned data = *address;
297 *address = data ^ ((data ^ fg_pattern) & mask & bits);
300 static void ICODE_ATTR solidblock(FBFN(data) *address, unsigned mask,
301 unsigned bits)
303 unsigned data = *address;
304 unsigned bgp = bg_pattern;
306 bits = bgp ^ ((bgp ^ fg_pattern) & bits);
307 *address = data ^ ((data ^ bits) & mask);
310 static void ICODE_ATTR solidimgblock(FBFN(data) *address, unsigned mask,
311 unsigned bits)
313 unsigned data = *address;
314 unsigned bgp = *(FBFN(data) *)((long)address + backdrop_offset);
316 bits = bgp ^ ((bgp ^ fg_pattern) & bits);
317 *address = data ^ ((data ^ bits) & mask);
320 static void ICODE_ATTR flipinvblock(FBFN(data) *address, unsigned mask,
321 unsigned bits)
323 *address ^= ~bits & mask;
326 static void ICODE_ATTR bginvblock(FBFN(data) *address, unsigned mask,
327 unsigned bits)
329 unsigned data = *address;
331 *address = data ^ ((data ^ bg_pattern) & mask & bits);
334 static void ICODE_ATTR bgimginvblock(FBFN(data) *address, unsigned mask,
335 unsigned bits)
337 unsigned data = *address;
339 *address = data ^ ((data ^ *(FBFN(data) *)((long)address
340 + backdrop_offset)) & mask & bits);
343 static void ICODE_ATTR fginvblock(FBFN(data) *address, unsigned mask,
344 unsigned bits)
346 unsigned data = *address;
348 *address = data ^ ((data ^ fg_pattern) & mask & ~bits);
351 static void ICODE_ATTR solidinvblock(FBFN(data) *address, unsigned mask,
352 unsigned bits)
354 unsigned data = *address;
355 unsigned fgp = fg_pattern;
357 bits = fgp ^ ((fgp ^ bg_pattern) & bits);
358 *address = data ^ ((data ^ bits) & mask);
361 static void ICODE_ATTR solidimginvblock(FBFN(data) *address, unsigned mask,
362 unsigned bits)
364 unsigned data = *address;
365 unsigned fgp = fg_pattern;
367 bits = fgp ^ ((fgp ^ *(FBFN(data) *)((long)address
368 + backdrop_offset)) & bits);
369 *address = data ^ ((data ^ bits) & mask);
372 LCDFN(blockfunc_type)* const LCDFN(blockfuncs_bgcolor)[8] = {
373 flipblock, bgblock, fgblock, solidblock,
374 flipinvblock, bginvblock, fginvblock, solidinvblock
377 LCDFN(blockfunc_type)* const LCDFN(blockfuncs_backdrop)[8] = {
378 flipblock, bgimgblock, fgblock, solidimgblock,
379 flipinvblock, bgimginvblock, fginvblock, solidimginvblock
382 LCDFN(blockfunc_type)* const *LCDFN(blockfuncs) = LCDFN(blockfuncs_bgcolor);
385 void LCDFN(set_backdrop)(FBFN(data) *bd)
387 backdrop = bd;
388 if (bd)
390 backdrop_offset = (long)bd - (long)LCDFN(framebuffer);
391 LCDFN(pixelfuncs) = LCDFN(pixelfuncs_backdrop);
392 LCDFN(blockfuncs) = LCDFN(blockfuncs_backdrop);
394 else
396 backdrop_offset = 0;
397 LCDFN(pixelfuncs) = LCDFN(pixelfuncs_bgcolor);
398 LCDFN(blockfuncs) = LCDFN(blockfuncs_bgcolor);
402 FBFN(data)* LCDFN(get_backdrop)(void)
404 return backdrop;
407 static inline void setblock(FBFN(data) *address, unsigned mask, unsigned bits)
409 unsigned data = *address;
411 bits ^= data;
412 *address = data ^ (bits & mask);
415 /*** drawing functions ***/
417 /* Clear the whole display */
418 void LCDFN(clear_display)(void)
420 if (default_vp.drawmode & DRMODE_INVERSEVID)
422 memset(LCDFN(framebuffer), patterns[default_vp.fg_pattern & 3],
423 sizeof LCDFN(framebuffer));
425 else
427 if (backdrop)
428 memcpy(LCDFN(framebuffer), backdrop, sizeof LCDFN(framebuffer));
429 else
430 memset(LCDFN(framebuffer), patterns[default_vp.bg_pattern & 3],
431 sizeof LCDFN(framebuffer));
434 LCDFN(scroll_info).lines = 0;
437 /* Clear the current viewport */
438 void LCDFN(clear_viewport)(void)
440 int lastmode;
442 if (current_vp == &default_vp)
444 LCDFN(clear_display)();
446 else
448 lastmode = current_vp->drawmode;
450 /* Invert the INVERSEVID bit and set basic mode to SOLID */
451 current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) |
452 DRMODE_SOLID;
454 LCDFN(fillrect)(0, 0, current_vp->width, current_vp->height);
456 current_vp->drawmode = lastmode;
458 LCDFN(scroll_stop)(current_vp);
462 /* Set a single pixel */
463 void LCDFN(drawpixel)(int x, int y)
465 if ( ((unsigned)x < (unsigned)current_vp->width)
466 && ((unsigned)y < (unsigned)current_vp->height)
467 #if defined(HAVE_VIEWPORT_CLIP)
468 && ((unsigned)x < (unsigned)LCDM(WIDTH))
469 && ((unsigned)y < (unsigned)LCDM(HEIGHT))
470 #endif
472 LCDFN(pixelfuncs)[current_vp->drawmode](current_vp->x+x, current_vp->y+y);
475 /* Draw a line */
476 void LCDFN(drawline)(int x1, int y1, int x2, int y2)
478 int numpixels;
479 int i;
480 int deltax, deltay;
481 int d, dinc1, dinc2;
482 int x, xinc1, xinc2;
483 int y, yinc1, yinc2;
484 LCDFN(pixelfunc_type) *pfunc = LCDFN(pixelfuncs)[current_vp->drawmode];
486 deltax = abs(x2 - x1);
487 if (deltax == 0)
489 /* DEBUGF(LCDNAME "drawline() called for vertical line - optimisation.\n"); */
490 LCDFN(vline)(x1, y1, y2);
491 return;
493 deltay = abs(y2 - y1);
494 if (deltay == 0)
496 /* DEBUGF(LCDNAME "drawline() called for horizontal line - optimisation.\n"); */
497 LCDFN(hline)(x1, x2, y1);
498 return;
500 xinc2 = 1;
501 yinc2 = 1;
503 if (deltax >= deltay)
505 numpixels = deltax;
506 d = 2 * deltay - deltax;
507 dinc1 = deltay * 2;
508 dinc2 = (deltay - deltax) * 2;
509 xinc1 = 1;
510 yinc1 = 0;
512 else
514 numpixels = deltay;
515 d = 2 * deltax - deltay;
516 dinc1 = deltax * 2;
517 dinc2 = (deltax - deltay) * 2;
518 xinc1 = 0;
519 yinc1 = 1;
521 numpixels++; /* include endpoints */
523 if (x1 > x2)
525 xinc1 = -xinc1;
526 xinc2 = -xinc2;
529 if (y1 > y2)
531 yinc1 = -yinc1;
532 yinc2 = -yinc2;
535 x = x1;
536 y = y1;
538 for (i = 0; i < numpixels; i++)
540 if ( ((unsigned)x < (unsigned)current_vp->width)
541 && ((unsigned)y < (unsigned)current_vp->height)
542 #if defined(HAVE_VIEWPORT_CLIP)
543 && ((unsigned)x < (unsigned)LCDM(WIDTH))
544 && ((unsigned)y < (unsigned)LCDM(HEIGHT))
545 #endif
547 pfunc(current_vp->x + x, current_vp->y + y);
549 if (d < 0)
551 d += dinc1;
552 x += xinc1;
553 y += yinc1;
555 else
557 d += dinc2;
558 x += xinc2;
559 y += yinc2;
564 /* Draw a horizontal line (optimised) */
565 void LCDFN(hline)(int x1, int x2, int y)
567 int x;
568 int width;
569 FBFN(data) *dst, *dst_end;
570 unsigned mask;
571 LCDFN(blockfunc_type) *bfunc;
573 /* direction flip */
574 if (x2 < x1)
576 x = x1;
577 x1 = x2;
578 x2 = x;
581 /******************** In viewport clipping **********************/
582 /* nothing to draw? */
583 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
584 || (x2 < 0))
585 return;
587 if (x1 < 0)
588 x1 = 0;
589 if (x2 >= current_vp->width)
590 x2 = current_vp->width-1;
592 /* adjust x1 and y to viewport */
593 x1 += current_vp->x;
594 x2 += current_vp->x;
595 y += current_vp->y;
597 #if defined(HAVE_VIEWPORT_CLIP)
598 /********************* Viewport on screen clipping ********************/
599 /* nothing to draw? */
600 if (((unsigned)y >= (unsigned) LCDM(HEIGHT)) || (x1 >= LCDM(WIDTH))
601 || (x2 < 0))
602 return;
604 /* clipping */
605 if (x1 < 0)
606 x1 = 0;
607 if (x2 >= LCDM(WIDTH))
608 x2 = LCDM(WIDTH)-1;
609 #endif
611 width = x2 - x1 + 1;
613 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
614 dst = &LCDFN(framebuffer)[y>>3][x1];
615 mask = 0x0101 << (y & 7);
617 dst_end = dst + width;
619 bfunc(dst++, mask, 0xFFFFu);
620 while (dst < dst_end);
623 /* Draw a vertical line (optimised) */
624 void LCDFN(vline)(int x, int y1, int y2)
626 int ny;
627 FBFN(data) *dst;
628 unsigned mask, mask_bottom;
629 LCDFN(blockfunc_type) *bfunc;
631 /* direction flip */
632 if (y2 < y1)
634 ny = y1;
635 y1 = y2;
636 y2 = ny;
639 /******************** In viewport clipping **********************/
640 /* nothing to draw? */
641 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
642 || (y2 < 0))
643 return;
645 if (y1 < 0)
646 y1 = 0;
647 if (y2 >= current_vp->height)
648 y2 = current_vp->height-1;
650 /* adjust for viewport */
651 y1 += current_vp->y;
652 y2 += current_vp->y;
653 x += current_vp->x;
655 #if defined(HAVE_VIEWPORT_CLIP)
656 /********************* Viewport on screen clipping ********************/
657 /* nothing to draw? */
658 if (( (unsigned) x >= (unsigned)LCDM(WIDTH)) || (y1 >= LCDM(HEIGHT))
659 || (y2 < 0))
660 return;
662 /* clipping */
663 if (y1 < 0)
664 y1 = 0;
665 if (y2 >= LCDM(HEIGHT))
666 y2 = LCDM(HEIGHT)-1;
667 #endif
669 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
670 dst = &LCDFN(framebuffer)[y1>>3][x];
671 ny = y2 - (y1 & ~7);
672 mask = (0xFFu << (y1 & 7)) & 0xFFu;
673 mask |= mask << 8;
674 mask_bottom = 0xFFu >> (~ny & 7);
675 mask_bottom |= mask_bottom << 8;
677 for (; ny >= 8; ny -= 8)
679 bfunc(dst, mask, 0xFFFFu);
680 dst += LCDM(WIDTH);
681 mask = 0xFFFFu;
683 mask &= mask_bottom;
684 bfunc(dst, mask, 0xFFFFu);
687 /* Draw a rectangular box */
688 void LCDFN(drawrect)(int x, int y, int width, int height)
690 if ((width <= 0) || (height <= 0))
691 return;
693 int x2 = x + width - 1;
694 int y2 = y + height - 1;
696 LCDFN(vline)(x, y, y2);
697 LCDFN(vline)(x2, y, y2);
698 LCDFN(hline)(x, x2, y);
699 LCDFN(hline)(x, x2, y2);
702 /* Fill a rectangular area */
703 void LCDFN(fillrect)(int x, int y, int width, int height)
705 int ny;
706 FBFN(data) *dst, *dst_end;
707 unsigned mask, mask_bottom;
708 unsigned bits = 0;
709 LCDFN(blockfunc_type) *bfunc;
710 bool fillopt = false;
712 /******************** In viewport clipping **********************/
713 /* nothing to draw? */
714 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
715 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
716 return;
718 if (x < 0)
720 width += x;
721 x = 0;
723 if (y < 0)
725 height += y;
726 y = 0;
728 if (x + width > current_vp->width)
729 width = current_vp->width - x;
730 if (y + height > current_vp->height)
731 height = current_vp->height - y;
733 /* adjust for viewport */
734 x += current_vp->x;
735 y += current_vp->y;
737 #if defined(HAVE_VIEWPORT_CLIP)
738 /********************* Viewport on screen clipping ********************/
739 /* nothing to draw? */
740 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
741 || (x + width <= 0) || (y + height <= 0))
742 return;
744 /* clip image in viewport in screen */
745 if (x < 0)
747 width += x;
748 x = 0;
750 if (y < 0)
752 height += y;
753 y = 0;
755 if (x + width > LCDM(WIDTH))
756 width = LCDM(WIDTH) - x;
757 if (y + height > LCDM(HEIGHT))
758 height = LCDM(HEIGHT) - y;
759 #endif
762 if (current_vp->drawmode & DRMODE_INVERSEVID)
764 if ((current_vp->drawmode & DRMODE_BG) && !backdrop)
766 fillopt = true;
767 bits = bg_pattern;
770 else
772 if (current_vp->drawmode & DRMODE_FG)
774 fillopt = true;
775 bits = fg_pattern;
778 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
779 dst = &LCDFN(framebuffer)[y>>3][x];
780 ny = height - 1 + (y & 7);
781 mask = (0xFFu << (y & 7)) & 0xFFu;
782 mask |= mask << 8;
783 mask_bottom = 0xFFu >> (~ny & 7);
784 mask_bottom |= mask_bottom << 8;
786 for (; ny >= 8; ny -= 8)
788 if (fillopt && (mask == 0xFFFFu))
789 memset16(dst, bits, width);
790 else
792 FBFN(data) *dst_row = dst;
794 dst_end = dst_row + width;
796 bfunc(dst_row++, mask, 0xFFFFu);
797 while (dst_row < dst_end);
800 dst += LCDM(WIDTH);
801 mask = 0xFFFFu;
803 mask &= mask_bottom;
805 if (fillopt && (mask == 0xFFFFu))
806 memset16(dst, bits, width);
807 else
809 dst_end = dst + width;
811 bfunc(dst++, mask, 0xFFFFu);
812 while (dst < dst_end);
816 /* About Rockbox' internal monochrome bitmap format:
818 * A bitmap contains one bit for every pixel that defines if that pixel is
819 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
820 * at top.
821 * The bytes are stored in row-major order, with byte 0 being top left,
822 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
823 * 0..7, the second row defines pixel row 8..15 etc.
825 * This is similar to the internal lcd hw format. */
827 /* Draw a partial monochrome bitmap */
828 void ICODE_ATTR LCDFN(mono_bitmap_part)(const unsigned char *src, int src_x,
829 int src_y, int stride, int x, int y,
830 int width, int height)
832 int shift, ny;
833 FBFN(data) *dst, *dst_end;
834 unsigned data, mask, mask_bottom;
835 LCDFN(blockfunc_type) *bfunc;
837 /******************** Image in viewport clipping **********************/
838 /* nothing to draw? */
839 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
840 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
841 return;
843 if (x < 0)
845 width += x;
846 src_x -= x;
847 x = 0;
849 if (y < 0)
851 height += y;
852 src_y -= y;
853 y = 0;
855 if (x + width > current_vp->width)
856 width = current_vp->width - x;
857 if (y + height > current_vp->height)
858 height = current_vp->height - y;
860 /* adjust for viewport */
861 x += current_vp->x;
862 y += current_vp->y;
864 #if defined(HAVE_VIEWPORT_CLIP)
865 /********************* Viewport on screen clipping ********************/
866 /* nothing to draw? */
867 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
868 || (x + width <= 0) || (y + height <= 0))
869 return;
871 /* clip image in viewport in screen */
872 if (x < 0)
874 width += x;
875 src_x -= x;
876 x = 0;
878 if (y < 0)
880 height += y;
881 src_y -= y;
882 y = 0;
884 if (x + width > LCDM(WIDTH))
885 width = LCDM(WIDTH) - x;
886 if (y + height > LCDM(HEIGHT))
887 height = LCDM(HEIGHT) - y;
888 #endif
890 src += stride * (src_y >> 3) + src_x; /* move starting point */
891 src_y &= 7;
892 y -= src_y;
893 dst = &LCDFN(framebuffer)[y>>3][x];
894 shift = y & 7;
895 ny = height - 1 + shift + src_y;
897 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
898 mask = 0xFFu << (shift + src_y);
899 /* not byte-doubled here because shift+src_y can be > 7 */
900 mask_bottom = 0xFFu >> (~ny & 7);
901 mask_bottom |= mask_bottom << 8;
903 if (shift == 0)
905 mask &= 0xFFu;
906 mask |= mask << 8;
908 for (; ny >= 8; ny -= 8)
910 const unsigned char *src_row = src;
911 FBFN(data) *dst_row = dst;
913 dst_end = dst_row + width;
916 data = *src_row++;
917 bfunc(dst_row++, mask, data | (data << 8));
919 while (dst_row < dst_end);
921 src += stride;
922 dst += LCDM(WIDTH);
923 mask = 0xFFFFu;
925 mask &= mask_bottom;
927 dst_end = dst + width;
930 data = *src++;
931 bfunc(dst++, mask, data | (data << 8));
933 while (dst < dst_end);
935 else
937 unsigned ddata;
939 dst_end = dst + width;
942 const unsigned char *src_col = src++;
943 FBFN(data) *dst_col = dst++;
944 unsigned mask_col = mask & 0xFFu;
946 mask_col |= mask_col << 8;
947 data = 0;
949 for (y = ny; y >= 8; y -= 8)
951 data |= *src_col << shift;
953 if (mask_col)
955 ddata = data & 0xFFu;
956 bfunc(dst_col, mask_col, ddata | (ddata << 8));
957 mask_col = 0xFFFFu;
959 else
961 mask_col = (mask >> 8) & 0xFFu;
962 mask_col |= mask_col << 8;
965 src_col += stride;
966 dst_col += LCDM(WIDTH);
967 data >>= 8;
969 data |= *src_col << shift;
970 mask_col &= mask_bottom;
971 ddata = data & 0xFFu;
972 bfunc(dst_col, mask_col, ddata | (ddata << 8));
974 while (dst < dst_end);
978 /* Draw a full monochrome bitmap */
979 void LCDFN(mono_bitmap)(const unsigned char *src, int x, int y, int width,
980 int height)
982 LCDFN(mono_bitmap_part)(src, 0, 0, width, x, y, width, height);
985 /* About Rockbox' internal native bitmap format:
987 * A bitmap contains one bit in each byte of a pair of bytes for every pixel.
988 * 00 = white, 01 = light grey, 10 = dark grey, 11 = black. Bits within a byte
989 * are arranged vertically, LSB at top.
990 * The pairs of bytes are stored as shorts, in row-major order, with word 0
991 * being top left, word 1 2nd from left etc. The first row of words defines
992 * pixel rows 0..7, the second row defines pixel row 8..15 etc.
994 * This is the same as the internal lcd hw format. */
996 /* Draw a partial native bitmap */
997 void ICODE_ATTR LCDFN(bitmap_part)(const FBFN(data) *src, int src_x,
998 int src_y, int stride, int x, int y,
999 int width, int height)
1001 int shift, ny;
1002 FBFN(data) *dst, *dst_end;
1003 unsigned mask, mask_bottom;
1005 /******************** Image in viewport clipping **********************/
1006 /* nothing to draw? */
1007 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
1008 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
1009 return;
1011 if (x < 0)
1013 width += x;
1014 src_x -= x;
1015 x = 0;
1017 if (y < 0)
1019 height += y;
1020 src_y -= y;
1021 y = 0;
1023 if (x + width > current_vp->width)
1024 width = current_vp->width - x;
1025 if (y + height > current_vp->height)
1026 height = current_vp->height - y;
1028 /* adjust for viewport */
1029 x += current_vp->x;
1030 y += current_vp->y;
1032 #if defined(HAVE_VIEWPORT_CLIP)
1033 /********************* Viewport on screen clipping ********************/
1034 /* nothing to draw? */
1035 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
1036 || (x + width <= 0) || (y + height <= 0))
1037 return;
1039 /* clip image in viewport in screen */
1040 if (x < 0)
1042 width += x;
1043 src_x -= x;
1044 x = 0;
1046 if (y < 0)
1048 height += y;
1049 src_y -= y;
1050 y = 0;
1052 if (x + width > LCDM(WIDTH))
1053 width = LCDM(WIDTH) - x;
1054 if (y + height > LCDM(HEIGHT))
1055 height = LCDM(HEIGHT) - y;
1056 #endif
1058 src += stride * (src_y >> 3) + src_x; /* move starting point */
1059 src_y &= 7;
1060 y -= src_y;
1061 dst = &LCDFN(framebuffer)[y>>3][x];
1062 shift = y & 7;
1063 ny = height - 1 + shift + src_y;
1065 mask = 0xFFu << (shift + src_y);
1066 /* not byte-doubled here because shift+src_y can be > 7 */
1067 mask_bottom = 0xFFu >> (~ny & 7);
1068 mask_bottom |= mask_bottom << 8;
1070 if (shift == 0)
1072 mask &= 0xFFu;
1073 mask |= mask << 8;
1075 for (; ny >= 8; ny -= 8)
1077 if (mask == 0xFFFFu)
1078 memcpy(dst, src, width * sizeof(FBFN(data)));
1079 else
1081 const FBFN(data) *src_row = src;
1082 FBFN(data) *dst_row = dst;
1084 dst_end = dst_row + width;
1086 setblock(dst_row++, mask, *src_row++);
1087 while (dst_row < dst_end);
1089 src += stride;
1090 dst += LCDM(WIDTH);
1091 mask = 0xFFFFu;
1093 mask &= mask_bottom;
1095 if (mask == 0xFFFFu)
1096 memcpy(dst, src, width * sizeof(FBFN(data)));
1097 else
1099 dst_end = dst + width;
1101 setblock(dst++, mask, *src++);
1102 while (dst < dst_end);
1105 else
1107 unsigned datamask = (0xFFu << shift) & 0xFFu;
1109 datamask |= datamask << 8;
1111 dst_end = dst + width;
1114 const FBFN(data) *src_col = src++;
1115 FBFN(data) *dst_col = dst++;
1116 unsigned mask_col = mask & 0xFFu;
1117 unsigned data, olddata = 0;
1119 mask_col |= mask_col << 8;
1121 for (y = ny; y >= 8; y -= 8)
1123 data = *src_col << shift;
1125 if (mask_col)
1127 setblock(dst_col, mask_col,
1128 olddata ^((olddata ^ data) & datamask));
1129 mask_col = 0xFFFFu;
1131 else
1133 mask_col = (mask >> 8) & 0xFFu;
1134 mask_col |= mask_col << 8;
1136 src_col += stride;
1137 dst_col += LCDM(WIDTH);
1138 olddata = data >> 8;
1140 data = *src_col << shift;
1141 setblock(dst_col, mask_col & mask_bottom,
1142 olddata ^((olddata ^ data) & datamask));
1144 while (dst < dst_end);
1148 /* Draw a full native bitmap */
1149 void LCDFN(bitmap)(const FBFN(data) *src, int x, int y, int width, int height)
1151 LCDFN(bitmap_part)(src, 0, 0, width, x, y, width, height);
1154 #include "lcd-bitmap-common.c"