Theme Editor: Implemented %xd tag with subimages
[kugel-rb.git] / firmware / drivers / lcd-1bit-vert.c
blobfd77ba75781474fa249a6eeb0f0e2cd54ec2382d
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Alan Korr
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 ****************************************************************************/
22 #include "config.h"
24 #include "lcd.h"
25 #include "kernel.h"
26 #include "thread.h"
27 #include <string.h>
28 #include <stdlib.h>
29 #include "file.h"
30 #include "debug.h"
31 #include "system.h"
32 #include "font.h"
33 #include "rbunicode.h"
34 #include "bidi.h"
35 #include "scroll_engine.h"
37 #ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */
38 #define LCDFN(fn) lcd_ ## fn
39 #define FBFN(fn) fb_ ## fn
40 #define LCDM(ma) LCD_ ## ma
41 #define LCDNAME "lcd_"
42 #define MAIN_LCD
43 #endif
45 /*** globals ***/
47 FBFN(data) LCDFN(framebuffer)[LCDM(FBHEIGHT)][LCDM(FBWIDTH)] IRAM_LCDFRAMEBUFFER;
49 static struct viewport default_vp =
51 .x = 0,
52 .y = 0,
53 .width = LCDM(WIDTH),
54 .height = LCDM(HEIGHT),
55 .font = FONT_SYSFIXED,
56 .drawmode = DRMODE_SOLID,
59 static struct viewport* current_vp = &default_vp;
61 /*** Viewports ***/
63 void LCDFN(set_viewport)(struct viewport* vp)
65 if (vp == NULL)
66 current_vp = &default_vp;
67 else
68 current_vp = vp;
70 #if defined(SIMULATOR)
71 /* Force the viewport to be within bounds. If this happens it should
72 * be considered an error - the viewport will not draw as it might be
73 * expected.
75 if((unsigned) current_vp->x > (unsigned) LCDM(WIDTH)
76 || (unsigned) current_vp->y > (unsigned) LCDM(HEIGHT)
77 || current_vp->x + current_vp->width > LCDM(WIDTH)
78 || current_vp->y + current_vp->height > LCDM(HEIGHT))
80 #if !defined(HAVE_VIEWPORT_CLIP)
81 DEBUGF("ERROR: "
82 #else
83 DEBUGF("NOTE: "
84 #endif
85 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
86 current_vp->x, current_vp->y,
87 current_vp->width, current_vp->height);
90 #endif
93 void LCDFN(update_viewport)(void)
95 LCDFN(update_rect)(current_vp->x, current_vp->y,
96 current_vp->width, current_vp->height);
99 void LCDFN(update_viewport_rect)(int x, int y, int width, int height)
101 LCDFN(update_rect)(current_vp->x + x, current_vp->y + y, width, height);
104 /* LCD init */
105 void LCDFN(init)(void)
107 LCDFN(clear_display)();
108 LCDFN(init_device)();
109 #ifdef MAIN_LCD
110 scroll_init();
111 #endif
114 /*** parameter handling ***/
116 void LCDFN(set_drawmode)(int mode)
118 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
121 int LCDFN(get_drawmode)(void)
123 return current_vp->drawmode;
126 int LCDFN(getwidth)(void)
128 return current_vp->width;
131 int LCDFN(getheight)(void)
133 return current_vp->height;
136 void LCDFN(setfont)(int newfont)
138 current_vp->font = newfont;
141 int LCDFN(getfont)(void)
143 return current_vp->font;
146 int LCDFN(getstringsize)(const unsigned char *str, int *w, int *h)
148 return font_getstringsize(str, w, h, current_vp->font);
151 /*** low-level drawing functions ***/
153 static void setpixel(int x, int y)
155 LCDFN(framebuffer)[y>>3][x] |= BIT_N(y & 7);
158 static void clearpixel(int x, int y)
160 LCDFN(framebuffer)[y>>3][x] &= ~BIT_N(y & 7);
163 static void flippixel(int x, int y)
165 LCDFN(framebuffer)[y>>3][x] ^= BIT_N(y & 7);
168 static void nopixel(int x, int y)
170 (void)x;
171 (void)y;
174 LCDFN(pixelfunc_type)* const LCDFN(pixelfuncs)[8] = {
175 flippixel, nopixel, setpixel, setpixel,
176 nopixel, clearpixel, nopixel, clearpixel
179 static void ICODE_ATTR flipblock(FBFN(data) *address, unsigned mask,
180 unsigned bits)
182 *address ^= bits & mask;
185 static void ICODE_ATTR bgblock(FBFN(data) *address, unsigned mask,
186 unsigned bits)
188 *address &= bits | ~mask;
191 static void ICODE_ATTR fgblock(FBFN(data) *address, unsigned mask,
192 unsigned bits)
194 *address |= bits & mask;
197 static void ICODE_ATTR solidblock(FBFN(data) *address, unsigned mask,
198 unsigned bits)
200 unsigned data = *(char*)address;
202 bits ^= data;
203 *address = data ^ (bits & mask);
206 static void ICODE_ATTR flipinvblock(FBFN(data) *address, unsigned mask,
207 unsigned bits)
209 *address ^= ~bits & mask;
212 static void ICODE_ATTR bginvblock(FBFN(data) *address, unsigned mask,
213 unsigned bits)
215 *address &= ~(bits & mask);
218 static void ICODE_ATTR fginvblock(FBFN(data) *address, unsigned mask,
219 unsigned bits)
221 *address |= ~bits & mask;
224 static void ICODE_ATTR solidinvblock(FBFN(data) *address, unsigned mask,
225 unsigned bits)
227 unsigned data = *(char *)address;
229 bits = ~bits ^ data;
230 *address = data ^ (bits & mask);
233 LCDFN(blockfunc_type)* const LCDFN(blockfuncs)[8] = {
234 flipblock, bgblock, fgblock, solidblock,
235 flipinvblock, bginvblock, fginvblock, solidinvblock
238 /*** drawing functions ***/
240 /* Clear the whole display */
241 void LCDFN(clear_display)(void)
243 unsigned bits = (current_vp->drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0;
245 memset(LCDFN(framebuffer), bits, sizeof LCDFN(framebuffer));
246 LCDFN(scroll_info).lines = 0;
249 /* Clear the current viewport */
250 void LCDFN(clear_viewport)(void)
252 int oldmode;
254 if (current_vp == &default_vp)
256 LCDFN(clear_display)();
258 else
260 oldmode = current_vp->drawmode;
262 /* Invert the INVERSEVID bit and set basic mode to SOLID */
263 current_vp->drawmode = (~current_vp->drawmode & DRMODE_INVERSEVID) |
264 DRMODE_SOLID;
266 LCDFN(fillrect)(0, 0, current_vp->width, current_vp->height);
268 current_vp->drawmode = oldmode;
270 LCDFN(scroll_stop)(current_vp);
274 /* Set a single pixel */
275 void LCDFN(drawpixel)(int x, int y)
277 if ( ((unsigned)x < (unsigned)current_vp->width)
278 && ((unsigned)y < (unsigned)current_vp->height)
279 #if defined(HAVE_VIEWPORT_CLIP)
280 && ((unsigned)x < (unsigned)LCDM(WIDTH))
281 && ((unsigned)y < (unsigned)LCDM(HEIGHT))
282 #endif
284 LCDFN(pixelfuncs)[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
287 /* Draw a line */
288 void LCDFN(drawline)(int x1, int y1, int x2, int y2)
290 int numpixels;
291 int i;
292 int deltax, deltay;
293 int d, dinc1, dinc2;
294 int x, xinc1, xinc2;
295 int y, yinc1, yinc2;
296 LCDFN(pixelfunc_type) *pfunc = LCDFN(pixelfuncs)[current_vp->drawmode];
298 deltax = abs(x2 - x1);
299 if (deltax == 0)
301 /* DEBUGF(LCDNAME "drawline() called for vertical line - optimisation.\n"); */
302 LCDFN(vline)(x1, y1, y2);
303 return;
305 deltay = abs(y2 - y1);
306 if (deltay == 0)
308 /* DEBUGF(LCDNAME "drawline() called for horizontal line - optimisation.\n"); */
309 LCDFN(hline)(x1, x2, y1);
310 return;
312 xinc2 = 1;
313 yinc2 = 1;
315 if (deltax >= deltay)
317 numpixels = deltax;
318 d = 2 * deltay - deltax;
319 dinc1 = deltay * 2;
320 dinc2 = (deltay - deltax) * 2;
321 xinc1 = 1;
322 yinc1 = 0;
324 else
326 numpixels = deltay;
327 d = 2 * deltax - deltay;
328 dinc1 = deltax * 2;
329 dinc2 = (deltax - deltay) * 2;
330 xinc1 = 0;
331 yinc1 = 1;
333 numpixels++; /* include endpoints */
335 if (x1 > x2)
337 xinc1 = -xinc1;
338 xinc2 = -xinc2;
341 if (y1 > y2)
343 yinc1 = -yinc1;
344 yinc2 = -yinc2;
347 x = x1;
348 y = y1;
350 for (i = 0; i < numpixels; i++)
352 if ( ((unsigned)x < (unsigned)current_vp->width)
353 && ((unsigned)y < (unsigned)current_vp->height)
354 #if defined(HAVE_VIEWPORT_CLIP)
355 && ((unsigned)x < (unsigned)LCDM(WIDTH))
356 && ((unsigned)y < (unsigned)LCDM(HEIGHT))
357 #endif
359 pfunc(current_vp->x + x, current_vp->y + y);
361 if (d < 0)
363 d += dinc1;
364 x += xinc1;
365 y += yinc1;
367 else
369 d += dinc2;
370 x += xinc2;
371 y += yinc2;
376 /* Draw a horizontal line (optimised) */
377 void LCDFN(hline)(int x1, int x2, int y)
379 int x, width;
380 unsigned char *dst, *dst_end;
381 unsigned mask;
382 LCDFN(blockfunc_type) *bfunc;
384 /* direction flip */
385 if (x2 < x1)
387 x = x1;
388 x1 = x2;
389 x2 = x;
392 /******************** In viewport clipping **********************/
393 /* nothing to draw? */
394 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
395 || (x2 < 0))
396 return;
398 if (x1 < 0)
399 x1 = 0;
400 if (x2 >= current_vp->width)
401 x2 = current_vp->width-1;
403 /* adjust to viewport */
404 x1 += current_vp->x;
405 x2 += current_vp->x;
406 y += current_vp->y;
408 #if defined(HAVE_VIEWPORT_CLIP)
409 /********************* Viewport on screen clipping ********************/
410 /* nothing to draw? */
411 if (((unsigned)y >= (unsigned) LCDM(HEIGHT)) || (x1 >= LCDM(WIDTH))
412 || (x2 < 0))
413 return;
415 /* clipping */
416 if (x1 < 0)
417 x1 = 0;
418 if (x2 >= LCDM(WIDTH))
419 x2 = LCDM(WIDTH)-1;
420 #endif
422 width = x2 - x1 + 1;
424 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
425 dst = &LCDFN(framebuffer)[y>>3][x1];
426 mask = BIT_N(y & 7);
428 dst_end = dst + width;
430 bfunc(dst++, mask, 0xFFu);
431 while (dst < dst_end);
434 /* Draw a vertical line (optimised) */
435 void LCDFN(vline)(int x, int y1, int y2)
437 int ny;
438 FBFN(data) *dst;
439 unsigned mask, mask_bottom;
440 LCDFN(blockfunc_type) *bfunc;
442 /* direction flip */
443 if (y2 < y1)
445 ny = y1;
446 y1 = y2;
447 y2 = ny;
450 /******************** In viewport clipping **********************/
451 /* nothing to draw? */
452 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
453 || (y2 < 0))
454 return;
456 if (y1 < 0)
457 y1 = 0;
458 if (y2 >= current_vp->height)
459 y2 = current_vp->height-1;
461 /* adjust for viewport */
462 y1 += current_vp->y;
463 y2 += current_vp->y;
464 x += current_vp->x;
466 #if defined(HAVE_VIEWPORT_CLIP)
467 /********************* Viewport on screen clipping ********************/
468 /* nothing to draw? */
469 if (( (unsigned) x >= (unsigned)LCDM(WIDTH)) || (y1 >= LCDM(HEIGHT))
470 || (y2 < 0))
471 return;
473 /* clipping */
474 if (y1 < 0)
475 y1 = 0;
476 if (y2 >= LCDM(HEIGHT))
477 y2 = LCDM(HEIGHT)-1;
478 #endif
480 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
481 dst = &LCDFN(framebuffer)[y1>>3][x];
482 ny = y2 - (y1 & ~7);
483 mask = 0xFFu << (y1 & 7);
484 mask_bottom = 0xFFu >> (~ny & 7);
486 for (; ny >= 8; ny -= 8)
488 bfunc(dst, mask, 0xFFu);
489 dst += LCDM(WIDTH);
490 mask = 0xFFu;
492 mask &= mask_bottom;
493 bfunc(dst, mask, 0xFFu);
496 /* Draw a rectangular box */
497 void LCDFN(drawrect)(int x, int y, int width, int height)
499 if ((width <= 0) || (height <= 0))
500 return;
502 int x2 = x + width - 1;
503 int y2 = y + height - 1;
505 LCDFN(vline)(x, y, y2);
506 LCDFN(vline)(x2, y, y2);
507 LCDFN(hline)(x, x2, y);
508 LCDFN(hline)(x, x2, y2);
511 /* Fill a rectangular area */
512 void LCDFN(fillrect)(int x, int y, int width, int height)
514 int ny;
515 FBFN(data) *dst, *dst_end;
516 unsigned mask, mask_bottom;
517 unsigned bits = 0;
518 LCDFN(blockfunc_type) *bfunc;
519 bool fillopt = false;
521 /******************** In viewport clipping **********************/
522 /* nothing to draw? */
523 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
524 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
525 return;
527 if (x < 0)
529 width += x;
530 x = 0;
532 if (y < 0)
534 height += y;
535 y = 0;
537 if (x + width > current_vp->width)
538 width = current_vp->width - x;
539 if (y + height > current_vp->height)
540 height = current_vp->height - y;
542 /* adjust for viewport */
543 x += current_vp->x;
544 y += current_vp->y;
546 #if defined(HAVE_VIEWPORT_CLIP)
547 /********************* Viewport on screen clipping ********************/
548 /* nothing to draw? */
549 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
550 || (x + width <= 0) || (y + height <= 0))
551 return;
553 /* clip image in viewport in screen */
554 if (x < 0)
556 width += x;
557 x = 0;
559 if (y < 0)
561 height += y;
562 y = 0;
564 if (x + width > LCDM(WIDTH))
565 width = LCDM(WIDTH) - x;
566 if (y + height > LCDM(HEIGHT))
567 height = LCDM(HEIGHT) - y;
568 #endif
570 if (current_vp->drawmode & DRMODE_INVERSEVID)
572 if (current_vp->drawmode & DRMODE_BG)
574 fillopt = true;
577 else
579 if (current_vp->drawmode & DRMODE_FG)
581 fillopt = true;
582 bits = 0xFFu;
585 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
586 dst = &LCDFN(framebuffer)[y>>3][x];
587 ny = height - 1 + (y & 7);
588 mask = 0xFFu << (y & 7);
589 mask_bottom = 0xFFu >> (~ny & 7);
591 for (; ny >= 8; ny -= 8)
593 if (fillopt && (mask == 0xFFu))
594 memset(dst, bits, width);
595 else
597 FBFN(data) *dst_row = dst;
599 dst_end = dst_row + width;
601 bfunc(dst_row++, mask, 0xFFu);
602 while (dst_row < dst_end);
605 dst += LCDM(WIDTH);
606 mask = 0xFFu;
608 mask &= mask_bottom;
610 if (fillopt && (mask == 0xFFu))
611 memset(dst, bits, width);
612 else
614 dst_end = dst + width;
616 bfunc(dst++, mask, 0xFFu);
617 while (dst < dst_end);
621 /* About Rockbox' internal bitmap format:
623 * A bitmap contains one bit for every pixel that defines if that pixel is
624 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
625 * at top.
626 * The bytes are stored in row-major order, with byte 0 being top left,
627 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
628 * 0..7, the second row defines pixel row 8..15 etc.
630 * This is the same as the internal lcd hw format. */
632 /* Draw a partial bitmap */
633 void ICODE_ATTR LCDFN(bitmap_part)(const unsigned char *src, int src_x,
634 int src_y, int stride, int x, int y,
635 int width, int height)
637 int shift, ny;
638 FBFN(data) *dst, *dst_end;
639 unsigned mask, mask_bottom;
640 LCDFN(blockfunc_type) *bfunc;
642 /******************** Image in viewport clipping **********************/
643 /* nothing to draw? */
644 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
645 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
646 return;
648 /* clip image in viewport */
649 if (x < 0)
651 width += x;
652 src_x -= x;
653 x = 0;
655 if (y < 0)
657 height += y;
658 src_y -= y;
659 y = 0;
661 if (x + width > current_vp->width)
662 width = current_vp->width - x;
663 if (y + height > current_vp->height)
664 height = current_vp->height - y;
666 /* adjust for viewport */
667 x += current_vp->x;
668 y += current_vp->y;
670 #if defined(HAVE_VIEWPORT_CLIP)
671 /********************* Viewport on screen clipping ********************/
672 /* nothing to draw? */
673 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
674 || (x + width <= 0) || (y + height <= 0))
675 return;
677 /* clip image in viewport in screen */
678 if (x < 0)
680 width += x;
681 src_x -= x;
682 x = 0;
684 if (y < 0)
686 height += y;
687 src_y -= y;
688 y = 0;
690 if (x + width > LCDM(WIDTH))
691 width = LCDM(WIDTH) - x;
692 if (y + height > LCDM(HEIGHT))
693 height = LCDM(HEIGHT) - y;
694 #endif
696 src += stride * (src_y >> 3) + src_x; /* move starting point */
697 src_y &= 7;
698 y -= src_y;
699 dst = &LCDFN(framebuffer)[y>>3][x];
700 shift = y & 7;
701 ny = height - 1 + shift + src_y;
703 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
704 mask = 0xFFu << (shift + src_y);
705 mask_bottom = 0xFFu >> (~ny & 7);
707 if (shift == 0)
709 bool copyopt = (current_vp->drawmode == DRMODE_SOLID);
711 for (; ny >= 8; ny -= 8)
713 if (copyopt && (mask == 0xFFu))
714 memcpy(dst, src, width);
715 else
717 const unsigned char *src_row = src;
718 FBFN(data) *dst_row = dst;
720 dst_end = dst_row + width;
722 bfunc(dst_row++, mask, *src_row++);
723 while (dst_row < dst_end);
726 src += stride;
727 dst += LCDM(WIDTH);
728 mask = 0xFFu;
730 mask &= mask_bottom;
732 if (copyopt && (mask == 0xFFu))
733 memcpy(dst, src, width);
734 else
736 dst_end = dst + width;
738 bfunc(dst++, mask, *src++);
739 while (dst < dst_end);
742 else
744 dst_end = dst + width;
747 const unsigned char *src_col = src++;
748 FBFN(data) *dst_col = dst++;
749 unsigned mask_col = mask;
750 unsigned data = 0;
752 for (y = ny; y >= 8; y -= 8)
754 data |= *src_col << shift;
756 if (mask_col & 0xFFu)
758 bfunc(dst_col, mask_col, data);
759 mask_col = 0xFFu;
761 else
762 mask_col >>= 8;
764 src_col += stride;
765 dst_col += LCDM(WIDTH);
766 data >>= 8;
768 data |= *src_col << shift;
769 bfunc(dst_col, mask_col & mask_bottom, data);
771 while (dst < dst_end);
775 /* Draw a full bitmap */
776 void LCDFN(bitmap)(const unsigned char *src, int x, int y, int width,
777 int height)
779 LCDFN(bitmap_part)(src, 0, 0, width, x, y, width, height);
782 #include "lcd-bitmap-common.c"