Theme Editor: Implemented %xd tag with subimages
[kugel-rb.git] / firmware / drivers / lcd-2bit-vi.c
blob5dd94a15a0294943fe21a1b737adb34852406be7
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 LCDFN(init_device)();
126 #ifdef MAIN_LCD
127 scroll_init();
128 #endif
131 /*** parameter handling ***/
133 #if !defined(MAIN_LCD) && defined(HAVE_LCD_COLOR)
134 /* When compiling for remote LCD and the main LCD is colour. */
135 unsigned lcd_remote_color_to_native(unsigned color)
137 unsigned r = (color & 0xf800) >> 10;
138 unsigned g = (color & 0x07e0) >> 5;
139 unsigned b = (color & 0x001f) << 2;
141 * |R|
142 * |Y'| = |0.299000 0.587000 0.114000| |G|
143 * |B|
145 return (5*r + 9*g + b) >> 8;
147 #endif
149 void LCDFN(set_drawmode)(int mode)
151 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
154 int LCDFN(get_drawmode)(void)
156 return current_vp->drawmode;
159 void LCDFN(set_foreground)(unsigned brightness)
161 current_vp->fg_pattern = brightness;
162 fg_pattern = patterns[brightness & 3];
165 unsigned LCDFN(get_foreground)(void)
167 return current_vp->fg_pattern;
170 void LCDFN(set_background)(unsigned brightness)
172 current_vp->bg_pattern = brightness;
173 bg_pattern = patterns[brightness & 3];
176 unsigned LCDFN(get_background)(void)
178 return current_vp->bg_pattern;
181 void LCDFN(set_drawinfo)(int mode, unsigned fg_brightness,
182 unsigned bg_brightness)
184 LCDFN(set_drawmode)(mode);
185 LCDFN(set_foreground)(fg_brightness);
186 LCDFN(set_background)(bg_brightness);
189 int LCDFN(getwidth)(void)
191 return current_vp->width;
194 int LCDFN(getheight)(void)
196 return current_vp->height;
198 void LCDFN(setfont)(int newfont)
200 current_vp->font = newfont;
203 int LCDFN(getfont)(void)
205 return current_vp->font;
208 int LCDFN(getstringsize)(const unsigned char *str, int *w, int *h)
210 return font_getstringsize(str, w, h, current_vp->font);
213 /*** low-level drawing functions ***/
215 static void setpixel(int x, int y)
217 unsigned mask = 0x0101 << (y & 7);
218 FBFN(data) *address = &LCDFN(framebuffer)[y>>3][x];
219 unsigned data = *address;
221 *address = data ^ ((data ^ fg_pattern) & mask);
224 static void clearpixel(int x, int y)
226 unsigned mask = 0x0101 << (y & 7);
227 FBFN(data) *address = &LCDFN(framebuffer)[y>>3][x];
228 unsigned data = *address;
230 *address = data ^ ((data ^ bg_pattern) & mask);
233 static void clearimgpixel(int x, int y)
235 unsigned mask = 0x0101 << (y & 7);
236 FBFN(data) *address = &LCDFN(framebuffer)[y>>3][x];
237 unsigned data = *address;
239 *address = data ^ ((data ^ *(FBFN(data) *)((long)address
240 + backdrop_offset)) & mask);
243 static void flippixel(int x, int y)
245 unsigned mask = 0x0101 << (y & 7);
246 FBFN(data) *address = &LCDFN(framebuffer)[y>>3][x];
248 *address ^= mask;
251 static void nopixel(int x, int y)
253 (void)x;
254 (void)y;
257 LCDFN(pixelfunc_type)* const LCDFN(pixelfuncs_bgcolor)[8] = {
258 flippixel, nopixel, setpixel, setpixel,
259 nopixel, clearpixel, nopixel, clearpixel
262 LCDFN(pixelfunc_type)* const LCDFN(pixelfuncs_backdrop)[8] = {
263 flippixel, nopixel, setpixel, setpixel,
264 nopixel, clearimgpixel, nopixel, clearimgpixel
267 LCDFN(pixelfunc_type)* const *LCDFN(pixelfuncs) = LCDFN(pixelfuncs_bgcolor);
269 /* 'mask' and 'bits' contain 2 bits per pixel */
270 static void ICODE_ATTR flipblock(FBFN(data) *address, unsigned mask,
271 unsigned bits)
273 *address ^= bits & mask;
276 static void ICODE_ATTR bgblock(FBFN(data) *address, unsigned mask,
277 unsigned bits)
279 unsigned data = *address;
281 *address = data ^ ((data ^ bg_pattern) & mask & ~bits);
284 static void ICODE_ATTR bgimgblock(FBFN(data) *address, unsigned mask,
285 unsigned bits)
287 unsigned data = *address;
289 *address = data ^ ((data ^ *(FBFN(data) *)((long)address
290 + backdrop_offset)) & mask & ~bits);
293 static void ICODE_ATTR fgblock(FBFN(data) *address, unsigned mask,
294 unsigned bits)
296 unsigned data = *address;
298 *address = data ^ ((data ^ fg_pattern) & mask & bits);
301 static void ICODE_ATTR solidblock(FBFN(data) *address, unsigned mask,
302 unsigned bits)
304 unsigned data = *address;
305 unsigned bgp = bg_pattern;
307 bits = bgp ^ ((bgp ^ fg_pattern) & bits);
308 *address = data ^ ((data ^ bits) & mask);
311 static void ICODE_ATTR solidimgblock(FBFN(data) *address, unsigned mask,
312 unsigned bits)
314 unsigned data = *address;
315 unsigned bgp = *(FBFN(data) *)((long)address + backdrop_offset);
317 bits = bgp ^ ((bgp ^ fg_pattern) & bits);
318 *address = data ^ ((data ^ bits) & mask);
321 static void ICODE_ATTR flipinvblock(FBFN(data) *address, unsigned mask,
322 unsigned bits)
324 *address ^= ~bits & mask;
327 static void ICODE_ATTR bginvblock(FBFN(data) *address, unsigned mask,
328 unsigned bits)
330 unsigned data = *address;
332 *address = data ^ ((data ^ bg_pattern) & mask & bits);
335 static void ICODE_ATTR bgimginvblock(FBFN(data) *address, unsigned mask,
336 unsigned bits)
338 unsigned data = *address;
340 *address = data ^ ((data ^ *(FBFN(data) *)((long)address
341 + backdrop_offset)) & mask & bits);
344 static void ICODE_ATTR fginvblock(FBFN(data) *address, unsigned mask,
345 unsigned bits)
347 unsigned data = *address;
349 *address = data ^ ((data ^ fg_pattern) & mask & ~bits);
352 static void ICODE_ATTR solidinvblock(FBFN(data) *address, unsigned mask,
353 unsigned bits)
355 unsigned data = *address;
356 unsigned fgp = fg_pattern;
358 bits = fgp ^ ((fgp ^ bg_pattern) & bits);
359 *address = data ^ ((data ^ bits) & mask);
362 static void ICODE_ATTR solidimginvblock(FBFN(data) *address, unsigned mask,
363 unsigned bits)
365 unsigned data = *address;
366 unsigned fgp = fg_pattern;
368 bits = fgp ^ ((fgp ^ *(FBFN(data) *)((long)address
369 + backdrop_offset)) & bits);
370 *address = data ^ ((data ^ bits) & mask);
373 LCDFN(blockfunc_type)* const LCDFN(blockfuncs_bgcolor)[8] = {
374 flipblock, bgblock, fgblock, solidblock,
375 flipinvblock, bginvblock, fginvblock, solidinvblock
378 LCDFN(blockfunc_type)* const LCDFN(blockfuncs_backdrop)[8] = {
379 flipblock, bgimgblock, fgblock, solidimgblock,
380 flipinvblock, bgimginvblock, fginvblock, solidimginvblock
383 LCDFN(blockfunc_type)* const *LCDFN(blockfuncs) = LCDFN(blockfuncs_bgcolor);
386 void LCDFN(set_backdrop)(FBFN(data) *bd)
388 backdrop = bd;
389 if (bd)
391 backdrop_offset = (long)bd - (long)LCDFN(framebuffer);
392 LCDFN(pixelfuncs) = LCDFN(pixelfuncs_backdrop);
393 LCDFN(blockfuncs) = LCDFN(blockfuncs_backdrop);
395 else
397 backdrop_offset = 0;
398 LCDFN(pixelfuncs) = LCDFN(pixelfuncs_bgcolor);
399 LCDFN(blockfuncs) = LCDFN(blockfuncs_bgcolor);
403 FBFN(data)* LCDFN(get_backdrop)(void)
405 return backdrop;
408 static inline void setblock(FBFN(data) *address, unsigned mask, unsigned bits)
410 unsigned data = *address;
412 bits ^= data;
413 *address = data ^ (bits & mask);
416 /*** drawing functions ***/
418 /* Clear the whole display */
419 void LCDFN(clear_display)(void)
421 if (default_vp.drawmode & DRMODE_INVERSEVID)
423 memset(LCDFN(framebuffer), patterns[default_vp.fg_pattern & 3],
424 sizeof LCDFN(framebuffer));
426 else
428 if (backdrop)
429 memcpy(LCDFN(framebuffer), backdrop, sizeof LCDFN(framebuffer));
430 else
431 memset(LCDFN(framebuffer), patterns[default_vp.bg_pattern & 3],
432 sizeof LCDFN(framebuffer));
435 LCDFN(scroll_info).lines = 0;
438 /* Clear the current viewport */
439 void LCDFN(clear_viewport)(void)
441 int lastmode;
443 if (current_vp == &default_vp)
445 LCDFN(clear_display)();
447 else
449 lastmode = current_vp->drawmode;
451 /* Invert the INVERSEVID bit and set basic mode to SOLID */
452 current_vp->drawmode = (~lastmode & DRMODE_INVERSEVID) |
453 DRMODE_SOLID;
455 LCDFN(fillrect)(0, 0, current_vp->width, current_vp->height);
457 current_vp->drawmode = lastmode;
459 LCDFN(scroll_stop)(current_vp);
463 /* Set a single pixel */
464 void LCDFN(drawpixel)(int x, int y)
466 if ( ((unsigned)x < (unsigned)current_vp->width)
467 && ((unsigned)y < (unsigned)current_vp->height)
468 #if defined(HAVE_VIEWPORT_CLIP)
469 && ((unsigned)x < (unsigned)LCDM(WIDTH))
470 && ((unsigned)y < (unsigned)LCDM(HEIGHT))
471 #endif
473 LCDFN(pixelfuncs)[current_vp->drawmode](current_vp->x+x, current_vp->y+y);
476 /* Draw a line */
477 void LCDFN(drawline)(int x1, int y1, int x2, int y2)
479 int numpixels;
480 int i;
481 int deltax, deltay;
482 int d, dinc1, dinc2;
483 int x, xinc1, xinc2;
484 int y, yinc1, yinc2;
485 LCDFN(pixelfunc_type) *pfunc = LCDFN(pixelfuncs)[current_vp->drawmode];
487 deltax = abs(x2 - x1);
488 if (deltax == 0)
490 /* DEBUGF(LCDNAME "drawline() called for vertical line - optimisation.\n"); */
491 LCDFN(vline)(x1, y1, y2);
492 return;
494 deltay = abs(y2 - y1);
495 if (deltay == 0)
497 /* DEBUGF(LCDNAME "drawline() called for horizontal line - optimisation.\n"); */
498 LCDFN(hline)(x1, x2, y1);
499 return;
501 xinc2 = 1;
502 yinc2 = 1;
504 if (deltax >= deltay)
506 numpixels = deltax;
507 d = 2 * deltay - deltax;
508 dinc1 = deltay * 2;
509 dinc2 = (deltay - deltax) * 2;
510 xinc1 = 1;
511 yinc1 = 0;
513 else
515 numpixels = deltay;
516 d = 2 * deltax - deltay;
517 dinc1 = deltax * 2;
518 dinc2 = (deltax - deltay) * 2;
519 xinc1 = 0;
520 yinc1 = 1;
522 numpixels++; /* include endpoints */
524 if (x1 > x2)
526 xinc1 = -xinc1;
527 xinc2 = -xinc2;
530 if (y1 > y2)
532 yinc1 = -yinc1;
533 yinc2 = -yinc2;
536 x = x1;
537 y = y1;
539 for (i = 0; i < numpixels; i++)
541 if ( ((unsigned)x < (unsigned)current_vp->width)
542 && ((unsigned)y < (unsigned)current_vp->height)
543 #if defined(HAVE_VIEWPORT_CLIP)
544 && ((unsigned)x < (unsigned)LCDM(WIDTH))
545 && ((unsigned)y < (unsigned)LCDM(HEIGHT))
546 #endif
548 pfunc(current_vp->x + x, current_vp->y + y);
550 if (d < 0)
552 d += dinc1;
553 x += xinc1;
554 y += yinc1;
556 else
558 d += dinc2;
559 x += xinc2;
560 y += yinc2;
565 /* Draw a horizontal line (optimised) */
566 void LCDFN(hline)(int x1, int x2, int y)
568 int x;
569 int width;
570 FBFN(data) *dst, *dst_end;
571 unsigned mask;
572 LCDFN(blockfunc_type) *bfunc;
574 /* direction flip */
575 if (x2 < x1)
577 x = x1;
578 x1 = x2;
579 x2 = x;
582 /******************** In viewport clipping **********************/
583 /* nothing to draw? */
584 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
585 || (x2 < 0))
586 return;
588 if (x1 < 0)
589 x1 = 0;
590 if (x2 >= current_vp->width)
591 x2 = current_vp->width-1;
593 /* adjust x1 and y to viewport */
594 x1 += current_vp->x;
595 x2 += current_vp->x;
596 y += current_vp->y;
598 #if defined(HAVE_VIEWPORT_CLIP)
599 /********************* Viewport on screen clipping ********************/
600 /* nothing to draw? */
601 if (((unsigned)y >= (unsigned) LCDM(HEIGHT)) || (x1 >= LCDM(WIDTH))
602 || (x2 < 0))
603 return;
605 /* clipping */
606 if (x1 < 0)
607 x1 = 0;
608 if (x2 >= LCDM(WIDTH))
609 x2 = LCDM(WIDTH)-1;
610 #endif
612 width = x2 - x1 + 1;
614 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
615 dst = &LCDFN(framebuffer)[y>>3][x1];
616 mask = 0x0101 << (y & 7);
618 dst_end = dst + width;
620 bfunc(dst++, mask, 0xFFFFu);
621 while (dst < dst_end);
624 /* Draw a vertical line (optimised) */
625 void LCDFN(vline)(int x, int y1, int y2)
627 int ny;
628 FBFN(data) *dst;
629 unsigned mask, mask_bottom;
630 LCDFN(blockfunc_type) *bfunc;
632 /* direction flip */
633 if (y2 < y1)
635 ny = y1;
636 y1 = y2;
637 y2 = ny;
640 /******************** In viewport clipping **********************/
641 /* nothing to draw? */
642 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
643 || (y2 < 0))
644 return;
646 if (y1 < 0)
647 y1 = 0;
648 if (y2 >= current_vp->height)
649 y2 = current_vp->height-1;
651 /* adjust for viewport */
652 y1 += current_vp->y;
653 y2 += current_vp->y;
654 x += current_vp->x;
656 #if defined(HAVE_VIEWPORT_CLIP)
657 /********************* Viewport on screen clipping ********************/
658 /* nothing to draw? */
659 if (( (unsigned) x >= (unsigned)LCDM(WIDTH)) || (y1 >= LCDM(HEIGHT))
660 || (y2 < 0))
661 return;
663 /* clipping */
664 if (y1 < 0)
665 y1 = 0;
666 if (y2 >= LCDM(HEIGHT))
667 y2 = LCDM(HEIGHT)-1;
668 #endif
670 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
671 dst = &LCDFN(framebuffer)[y1>>3][x];
672 ny = y2 - (y1 & ~7);
673 mask = (0xFFu << (y1 & 7)) & 0xFFu;
674 mask |= mask << 8;
675 mask_bottom = 0xFFu >> (~ny & 7);
676 mask_bottom |= mask_bottom << 8;
678 for (; ny >= 8; ny -= 8)
680 bfunc(dst, mask, 0xFFFFu);
681 dst += LCDM(WIDTH);
682 mask = 0xFFFFu;
684 mask &= mask_bottom;
685 bfunc(dst, mask, 0xFFFFu);
688 /* Draw a rectangular box */
689 void LCDFN(drawrect)(int x, int y, int width, int height)
691 if ((width <= 0) || (height <= 0))
692 return;
694 int x2 = x + width - 1;
695 int y2 = y + height - 1;
697 LCDFN(vline)(x, y, y2);
698 LCDFN(vline)(x2, y, y2);
699 LCDFN(hline)(x, x2, y);
700 LCDFN(hline)(x, x2, y2);
703 /* Fill a rectangular area */
704 void LCDFN(fillrect)(int x, int y, int width, int height)
706 int ny;
707 FBFN(data) *dst, *dst_end;
708 unsigned mask, mask_bottom;
709 unsigned bits = 0;
710 LCDFN(blockfunc_type) *bfunc;
711 bool fillopt = false;
713 /******************** In viewport clipping **********************/
714 /* nothing to draw? */
715 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
716 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
717 return;
719 if (x < 0)
721 width += x;
722 x = 0;
724 if (y < 0)
726 height += y;
727 y = 0;
729 if (x + width > current_vp->width)
730 width = current_vp->width - x;
731 if (y + height > current_vp->height)
732 height = current_vp->height - y;
734 /* adjust for viewport */
735 x += current_vp->x;
736 y += current_vp->y;
738 #if defined(HAVE_VIEWPORT_CLIP)
739 /********************* Viewport on screen clipping ********************/
740 /* nothing to draw? */
741 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
742 || (x + width <= 0) || (y + height <= 0))
743 return;
745 /* clip image in viewport in screen */
746 if (x < 0)
748 width += x;
749 x = 0;
751 if (y < 0)
753 height += y;
754 y = 0;
756 if (x + width > LCDM(WIDTH))
757 width = LCDM(WIDTH) - x;
758 if (y + height > LCDM(HEIGHT))
759 height = LCDM(HEIGHT) - y;
760 #endif
763 if (current_vp->drawmode & DRMODE_INVERSEVID)
765 if ((current_vp->drawmode & DRMODE_BG) && !backdrop)
767 fillopt = true;
768 bits = bg_pattern;
771 else
773 if (current_vp->drawmode & DRMODE_FG)
775 fillopt = true;
776 bits = fg_pattern;
779 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
780 dst = &LCDFN(framebuffer)[y>>3][x];
781 ny = height - 1 + (y & 7);
782 mask = (0xFFu << (y & 7)) & 0xFFu;
783 mask |= mask << 8;
784 mask_bottom = 0xFFu >> (~ny & 7);
785 mask_bottom |= mask_bottom << 8;
787 for (; ny >= 8; ny -= 8)
789 if (fillopt && (mask == 0xFFFFu))
790 memset16(dst, bits, width);
791 else
793 FBFN(data) *dst_row = dst;
795 dst_end = dst_row + width;
797 bfunc(dst_row++, mask, 0xFFFFu);
798 while (dst_row < dst_end);
801 dst += LCDM(WIDTH);
802 mask = 0xFFFFu;
804 mask &= mask_bottom;
806 if (fillopt && (mask == 0xFFFFu))
807 memset16(dst, bits, width);
808 else
810 dst_end = dst + width;
812 bfunc(dst++, mask, 0xFFFFu);
813 while (dst < dst_end);
817 /* About Rockbox' internal monochrome bitmap format:
819 * A bitmap contains one bit for every pixel that defines if that pixel is
820 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
821 * at top.
822 * The bytes are stored in row-major order, with byte 0 being top left,
823 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
824 * 0..7, the second row defines pixel row 8..15 etc.
826 * This is similar to the internal lcd hw format. */
828 /* Draw a partial monochrome bitmap */
829 void ICODE_ATTR LCDFN(mono_bitmap_part)(const unsigned char *src, int src_x,
830 int src_y, int stride, int x, int y,
831 int width, int height)
833 int shift, ny;
834 FBFN(data) *dst, *dst_end;
835 unsigned data, mask, mask_bottom;
836 LCDFN(blockfunc_type) *bfunc;
838 /******************** Image in viewport clipping **********************/
839 /* nothing to draw? */
840 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
841 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
842 return;
844 if (x < 0)
846 width += x;
847 src_x -= x;
848 x = 0;
850 if (y < 0)
852 height += y;
853 src_y -= y;
854 y = 0;
856 if (x + width > current_vp->width)
857 width = current_vp->width - x;
858 if (y + height > current_vp->height)
859 height = current_vp->height - y;
861 /* adjust for viewport */
862 x += current_vp->x;
863 y += current_vp->y;
865 #if defined(HAVE_VIEWPORT_CLIP)
866 /********************* Viewport on screen clipping ********************/
867 /* nothing to draw? */
868 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
869 || (x + width <= 0) || (y + height <= 0))
870 return;
872 /* clip image in viewport in screen */
873 if (x < 0)
875 width += x;
876 src_x -= x;
877 x = 0;
879 if (y < 0)
881 height += y;
882 src_y -= y;
883 y = 0;
885 if (x + width > LCDM(WIDTH))
886 width = LCDM(WIDTH) - x;
887 if (y + height > LCDM(HEIGHT))
888 height = LCDM(HEIGHT) - y;
889 #endif
891 src += stride * (src_y >> 3) + src_x; /* move starting point */
892 src_y &= 7;
893 y -= src_y;
894 dst = &LCDFN(framebuffer)[y>>3][x];
895 shift = y & 7;
896 ny = height - 1 + shift + src_y;
898 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
899 mask = 0xFFu << (shift + src_y);
900 /* not byte-doubled here because shift+src_y can be > 7 */
901 mask_bottom = 0xFFu >> (~ny & 7);
902 mask_bottom |= mask_bottom << 8;
904 if (shift == 0)
906 mask &= 0xFFu;
907 mask |= mask << 8;
909 for (; ny >= 8; ny -= 8)
911 const unsigned char *src_row = src;
912 FBFN(data) *dst_row = dst;
914 dst_end = dst_row + width;
917 data = *src_row++;
918 bfunc(dst_row++, mask, data | (data << 8));
920 while (dst_row < dst_end);
922 src += stride;
923 dst += LCDM(WIDTH);
924 mask = 0xFFFFu;
926 mask &= mask_bottom;
928 dst_end = dst + width;
931 data = *src++;
932 bfunc(dst++, mask, data | (data << 8));
934 while (dst < dst_end);
936 else
938 unsigned ddata;
940 dst_end = dst + width;
943 const unsigned char *src_col = src++;
944 FBFN(data) *dst_col = dst++;
945 unsigned mask_col = mask & 0xFFu;
947 mask_col |= mask_col << 8;
948 data = 0;
950 for (y = ny; y >= 8; y -= 8)
952 data |= *src_col << shift;
954 if (mask_col)
956 ddata = data & 0xFFu;
957 bfunc(dst_col, mask_col, ddata | (ddata << 8));
958 mask_col = 0xFFFFu;
960 else
962 mask_col = (mask >> 8) & 0xFFu;
963 mask_col |= mask_col << 8;
966 src_col += stride;
967 dst_col += LCDM(WIDTH);
968 data >>= 8;
970 data |= *src_col << shift;
971 mask_col &= mask_bottom;
972 ddata = data & 0xFFu;
973 bfunc(dst_col, mask_col, ddata | (ddata << 8));
975 while (dst < dst_end);
979 /* Draw a full monochrome bitmap */
980 void LCDFN(mono_bitmap)(const unsigned char *src, int x, int y, int width,
981 int height)
983 LCDFN(mono_bitmap_part)(src, 0, 0, width, x, y, width, height);
986 /* About Rockbox' internal native bitmap format:
988 * A bitmap contains one bit in each byte of a pair of bytes for every pixel.
989 * 00 = white, 01 = light grey, 10 = dark grey, 11 = black. Bits within a byte
990 * are arranged vertically, LSB at top.
991 * The pairs of bytes are stored as shorts, in row-major order, with word 0
992 * being top left, word 1 2nd from left etc. The first row of words defines
993 * pixel rows 0..7, the second row defines pixel row 8..15 etc.
995 * This is the same as the internal lcd hw format. */
997 /* Draw a partial native bitmap */
998 void ICODE_ATTR LCDFN(bitmap_part)(const FBFN(data) *src, int src_x,
999 int src_y, int stride, int x, int y,
1000 int width, int height)
1002 int shift, ny;
1003 FBFN(data) *dst, *dst_end;
1004 unsigned mask, mask_bottom;
1006 /******************** Image in viewport clipping **********************/
1007 /* nothing to draw? */
1008 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
1009 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
1010 return;
1012 if (x < 0)
1014 width += x;
1015 src_x -= x;
1016 x = 0;
1018 if (y < 0)
1020 height += y;
1021 src_y -= y;
1022 y = 0;
1024 if (x + width > current_vp->width)
1025 width = current_vp->width - x;
1026 if (y + height > current_vp->height)
1027 height = current_vp->height - y;
1029 /* adjust for viewport */
1030 x += current_vp->x;
1031 y += current_vp->y;
1033 #if defined(HAVE_VIEWPORT_CLIP)
1034 /********************* Viewport on screen clipping ********************/
1035 /* nothing to draw? */
1036 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
1037 || (x + width <= 0) || (y + height <= 0))
1038 return;
1040 /* clip image in viewport in screen */
1041 if (x < 0)
1043 width += x;
1044 src_x -= x;
1045 x = 0;
1047 if (y < 0)
1049 height += y;
1050 src_y -= y;
1051 y = 0;
1053 if (x + width > LCDM(WIDTH))
1054 width = LCDM(WIDTH) - x;
1055 if (y + height > LCDM(HEIGHT))
1056 height = LCDM(HEIGHT) - y;
1057 #endif
1059 src += stride * (src_y >> 3) + src_x; /* move starting point */
1060 src_y &= 7;
1061 y -= src_y;
1062 dst = &LCDFN(framebuffer)[y>>3][x];
1063 shift = y & 7;
1064 ny = height - 1 + shift + src_y;
1066 mask = 0xFFu << (shift + src_y);
1067 /* not byte-doubled here because shift+src_y can be > 7 */
1068 mask_bottom = 0xFFu >> (~ny & 7);
1069 mask_bottom |= mask_bottom << 8;
1071 if (shift == 0)
1073 mask &= 0xFFu;
1074 mask |= mask << 8;
1076 for (; ny >= 8; ny -= 8)
1078 if (mask == 0xFFFFu)
1079 memcpy(dst, src, width * sizeof(FBFN(data)));
1080 else
1082 const FBFN(data) *src_row = src;
1083 FBFN(data) *dst_row = dst;
1085 dst_end = dst_row + width;
1087 setblock(dst_row++, mask, *src_row++);
1088 while (dst_row < dst_end);
1090 src += stride;
1091 dst += LCDM(WIDTH);
1092 mask = 0xFFFFu;
1094 mask &= mask_bottom;
1096 if (mask == 0xFFFFu)
1097 memcpy(dst, src, width * sizeof(FBFN(data)));
1098 else
1100 dst_end = dst + width;
1102 setblock(dst++, mask, *src++);
1103 while (dst < dst_end);
1106 else
1108 unsigned datamask = (0xFFu << shift) & 0xFFu;
1110 datamask |= datamask << 8;
1112 dst_end = dst + width;
1115 const FBFN(data) *src_col = src++;
1116 FBFN(data) *dst_col = dst++;
1117 unsigned mask_col = mask & 0xFFu;
1118 unsigned data, olddata = 0;
1120 mask_col |= mask_col << 8;
1122 for (y = ny; y >= 8; y -= 8)
1124 data = *src_col << shift;
1126 if (mask_col)
1128 setblock(dst_col, mask_col,
1129 olddata ^((olddata ^ data) & datamask));
1130 mask_col = 0xFFFFu;
1132 else
1134 mask_col = (mask >> 8) & 0xFFu;
1135 mask_col |= mask_col << 8;
1137 src_col += stride;
1138 dst_col += LCDM(WIDTH);
1139 olddata = data >> 8;
1141 data = *src_col << shift;
1142 setblock(dst_col, mask_col & mask_bottom,
1143 olddata ^((olddata ^ data) & datamask));
1145 while (dst < dst_end);
1149 /* Draw a full native bitmap */
1150 void LCDFN(bitmap)(const FBFN(data) *src, int x, int y, int width, int height)
1152 LCDFN(bitmap_part)(src, 0, 0, width, x, y, width, height);
1155 #include "lcd-bitmap-common.c"