FS#8961 - Anti-Aliased Fonts.
[kugel-rb.git] / firmware / drivers / lcd-1bit-vert.c
blobdd6c7cd354802a2eb31430765cb69827acad9760
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;
71 void LCDFN(update_viewport)(void)
73 LCDFN(update_rect)(current_vp->x, current_vp->y,
74 current_vp->width, current_vp->height);
77 void LCDFN(update_viewport_rect)(int x, int y, int width, int height)
79 LCDFN(update_rect)(current_vp->x + x, current_vp->y + y, width, height);
82 /* LCD init */
83 void LCDFN(init)(void)
85 LCDFN(clear_display)();
86 #ifndef SIMULATOR
87 LCDFN(init_device)();
88 #endif
89 #ifdef MAIN_LCD
90 scroll_init();
91 #endif
94 #ifdef MAIN_LCD
95 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
96 static void (*lcd_activation_hook)(void) = NULL;
98 void lcd_activation_set_hook(void (*func)(void))
100 lcd_activation_hook = func;
103 void lcd_activation_call_hook(void)
105 void (*func)(void) = lcd_activation_hook;
107 if (func != NULL)
108 func();
110 #endif
111 #endif
113 /*** parameter handling ***/
115 void LCDFN(set_drawmode)(int mode)
117 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
120 int LCDFN(get_drawmode)(void)
122 return current_vp->drawmode;
125 int LCDFN(getwidth)(void)
127 return current_vp->width;
130 int LCDFN(getheight)(void)
132 return current_vp->height;
135 void LCDFN(setfont)(int newfont)
137 current_vp->font = newfont;
140 int LCDFN(getfont)(void)
142 return current_vp->font;
145 int LCDFN(getstringsize)(const unsigned char *str, int *w, int *h)
147 return font_getstringsize(str, w, h, current_vp->font);
150 /*** low-level drawing functions ***/
152 static void setpixel(int x, int y)
154 LCDFN(framebuffer)[y>>3][x] |= BIT_N(y & 7);
157 static void clearpixel(int x, int y)
159 LCDFN(framebuffer)[y>>3][x] &= ~BIT_N(y & 7);
162 static void flippixel(int x, int y)
164 LCDFN(framebuffer)[y>>3][x] ^= BIT_N(y & 7);
167 static void nopixel(int x, int y)
169 (void)x;
170 (void)y;
173 LCDFN(pixelfunc_type)* const LCDFN(pixelfuncs)[8] = {
174 flippixel, nopixel, setpixel, setpixel,
175 nopixel, clearpixel, nopixel, clearpixel
178 static void ICODE_ATTR flipblock(FBFN(data) *address, unsigned mask,
179 unsigned bits)
181 *address ^= bits & mask;
184 static void ICODE_ATTR bgblock(FBFN(data) *address, unsigned mask,
185 unsigned bits)
187 *address &= bits | ~mask;
190 static void ICODE_ATTR fgblock(FBFN(data) *address, unsigned mask,
191 unsigned bits)
193 *address |= bits & mask;
196 static void ICODE_ATTR solidblock(FBFN(data) *address, unsigned mask,
197 unsigned bits)
199 unsigned data = *(char*)address;
201 bits ^= data;
202 *address = data ^ (bits & mask);
205 static void ICODE_ATTR flipinvblock(FBFN(data) *address, unsigned mask,
206 unsigned bits)
208 *address ^= ~bits & mask;
211 static void ICODE_ATTR bginvblock(FBFN(data) *address, unsigned mask,
212 unsigned bits)
214 *address &= ~(bits & mask);
217 static void ICODE_ATTR fginvblock(FBFN(data) *address, unsigned mask,
218 unsigned bits)
220 *address |= ~bits & mask;
223 static void ICODE_ATTR solidinvblock(FBFN(data) *address, unsigned mask,
224 unsigned bits)
226 unsigned data = *(char *)address;
228 bits = ~bits ^ data;
229 *address = data ^ (bits & mask);
232 LCDFN(blockfunc_type)* const LCDFN(blockfuncs)[8] = {
233 flipblock, bgblock, fgblock, solidblock,
234 flipinvblock, bginvblock, fginvblock, solidinvblock
237 /*** drawing functions ***/
239 /* Clear the whole display */
240 void LCDFN(clear_display)(void)
242 unsigned bits = (current_vp->drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0;
244 memset(LCDFN(framebuffer), bits, sizeof LCDFN(framebuffer));
245 LCDFN(scroll_info).lines = 0;
248 /* Clear the current viewport */
249 void LCDFN(clear_viewport)(void)
251 int oldmode;
253 if (current_vp == &default_vp)
255 LCDFN(clear_display)();
257 else
259 oldmode = current_vp->drawmode;
261 /* Invert the INVERSEVID bit and set basic mode to SOLID */
262 current_vp->drawmode = (~current_vp->drawmode & DRMODE_INVERSEVID) |
263 DRMODE_SOLID;
265 LCDFN(fillrect)(0, 0, current_vp->width, current_vp->height);
267 current_vp->drawmode = oldmode;
269 LCDFN(scroll_stop)(current_vp);
273 /* Set a single pixel */
274 void LCDFN(drawpixel)(int x, int y)
276 if (((unsigned)x < (unsigned)current_vp->width) &&
277 ((unsigned)y < (unsigned)current_vp->height))
278 LCDFN(pixelfuncs)[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
281 /* Draw a line */
282 void LCDFN(drawline)(int x1, int y1, int x2, int y2)
284 int numpixels;
285 int i;
286 int deltax, deltay;
287 int d, dinc1, dinc2;
288 int x, xinc1, xinc2;
289 int y, yinc1, yinc2;
290 LCDFN(pixelfunc_type) *pfunc = LCDFN(pixelfuncs)[current_vp->drawmode];
292 deltax = abs(x2 - x1);
293 if (deltax == 0)
295 DEBUGF(LCDNAME "drawline() called for vertical line - optimisation.\n");
296 LCDFN(vline)(x1, y1, y2);
297 return;
299 deltay = abs(y2 - y1);
300 if (deltay == 0)
302 DEBUGF(LCDNAME "drawline() called for horizontal line - optimisation.\n");
303 LCDFN(hline)(x1, x2, y1);
304 return;
306 xinc2 = 1;
307 yinc2 = 1;
309 if (deltax >= deltay)
311 numpixels = deltax;
312 d = 2 * deltay - deltax;
313 dinc1 = deltay * 2;
314 dinc2 = (deltay - deltax) * 2;
315 xinc1 = 1;
316 yinc1 = 0;
318 else
320 numpixels = deltay;
321 d = 2 * deltax - deltay;
322 dinc1 = deltax * 2;
323 dinc2 = (deltax - deltay) * 2;
324 xinc1 = 0;
325 yinc1 = 1;
327 numpixels++; /* include endpoints */
329 if (x1 > x2)
331 xinc1 = -xinc1;
332 xinc2 = -xinc2;
335 if (y1 > y2)
337 yinc1 = -yinc1;
338 yinc2 = -yinc2;
341 x = x1;
342 y = y1;
344 for (i = 0; i < numpixels; i++)
346 if (((unsigned)x < (unsigned)current_vp->width)
347 && ((unsigned)y < (unsigned)current_vp->height))
348 pfunc(current_vp->x + x, current_vp->y + y);
350 if (d < 0)
352 d += dinc1;
353 x += xinc1;
354 y += yinc1;
356 else
358 d += dinc2;
359 x += xinc2;
360 y += yinc2;
365 /* Draw a horizontal line (optimised) */
366 void LCDFN(hline)(int x1, int x2, int y)
368 int x, width;
369 unsigned char *dst, *dst_end;
370 unsigned mask;
371 LCDFN(blockfunc_type) *bfunc;
373 /* direction flip */
374 if (x2 < x1)
376 x = x1;
377 x1 = x2;
378 x2 = x;
381 /* nothing to draw? */
382 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
383 || (x2 < 0))
384 return;
386 /* clipping */
387 if (x1 < 0)
388 x1 = 0;
389 if (x2 >= current_vp->width)
390 x2 = current_vp->width-1;
392 width = x2 - x1 + 1;
394 /* adjust to viewport */
395 x1 += current_vp->x;
396 y += current_vp->y;
398 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
399 dst = &LCDFN(framebuffer)[y>>3][x1];
400 mask = BIT_N(y & 7);
402 dst_end = dst + width;
404 bfunc(dst++, mask, 0xFFu);
405 while (dst < dst_end);
408 /* Draw a vertical line (optimised) */
409 void LCDFN(vline)(int x, int y1, int y2)
411 int ny;
412 FBFN(data) *dst;
413 unsigned mask, mask_bottom;
414 LCDFN(blockfunc_type) *bfunc;
416 /* direction flip */
417 if (y2 < y1)
419 ny = y1;
420 y1 = y2;
421 y2 = ny;
424 /* nothing to draw? */
425 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
426 || (y2 < 0))
427 return;
429 /* clipping */
430 if (y1 < 0)
431 y1 = 0;
432 if (y2 >= current_vp->height)
433 y2 = current_vp->height-1;
435 /* adjust for viewport */
436 y1 += current_vp->y;
437 y2 += current_vp->y;
438 x += current_vp->x;
440 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
441 dst = &LCDFN(framebuffer)[y1>>3][x];
442 ny = y2 - (y1 & ~7);
443 mask = 0xFFu << (y1 & 7);
444 mask_bottom = 0xFFu >> (~ny & 7);
446 for (; ny >= 8; ny -= 8)
448 bfunc(dst, mask, 0xFFu);
449 dst += LCDM(WIDTH);
450 mask = 0xFFu;
452 mask &= mask_bottom;
453 bfunc(dst, mask, 0xFFu);
456 /* Draw a rectangular box */
457 void LCDFN(drawrect)(int x, int y, int width, int height)
459 if ((width <= 0) || (height <= 0))
460 return;
462 int x2 = x + width - 1;
463 int y2 = y + height - 1;
465 LCDFN(vline)(x, y, y2);
466 LCDFN(vline)(x2, y, y2);
467 LCDFN(hline)(x, x2, y);
468 LCDFN(hline)(x, x2, y2);
471 /* Fill a rectangular area */
472 void LCDFN(fillrect)(int x, int y, int width, int height)
474 int ny;
475 FBFN(data) *dst, *dst_end;
476 unsigned mask, mask_bottom;
477 unsigned bits = 0;
478 LCDFN(blockfunc_type) *bfunc;
479 bool fillopt = false;
481 /* nothing to draw? */
482 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
483 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
484 return;
486 /* clipping */
487 if (x < 0)
489 width += x;
490 x = 0;
492 if (y < 0)
494 height += y;
495 y = 0;
497 if (x + width > current_vp->width)
498 width = current_vp->width - x;
499 if (y + height > current_vp->height)
500 height = current_vp->height - y;
502 /* adjust for viewport */
503 x += current_vp->x;
504 y += current_vp->y;
506 if (current_vp->drawmode & DRMODE_INVERSEVID)
508 if (current_vp->drawmode & DRMODE_BG)
510 fillopt = true;
513 else
515 if (current_vp->drawmode & DRMODE_FG)
517 fillopt = true;
518 bits = 0xFFu;
521 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
522 dst = &LCDFN(framebuffer)[y>>3][x];
523 ny = height - 1 + (y & 7);
524 mask = 0xFFu << (y & 7);
525 mask_bottom = 0xFFu >> (~ny & 7);
527 for (; ny >= 8; ny -= 8)
529 if (fillopt && (mask == 0xFFu))
530 memset(dst, bits, width);
531 else
533 FBFN(data) *dst_row = dst;
535 dst_end = dst_row + width;
537 bfunc(dst_row++, mask, 0xFFu);
538 while (dst_row < dst_end);
541 dst += LCDM(WIDTH);
542 mask = 0xFFu;
544 mask &= mask_bottom;
546 if (fillopt && (mask == 0xFFu))
547 memset(dst, bits, width);
548 else
550 dst_end = dst + width;
552 bfunc(dst++, mask, 0xFFu);
553 while (dst < dst_end);
557 /* About Rockbox' internal bitmap format:
559 * A bitmap contains one bit for every pixel that defines if that pixel is
560 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
561 * at top.
562 * The bytes are stored in row-major order, with byte 0 being top left,
563 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
564 * 0..7, the second row defines pixel row 8..15 etc.
566 * This is the same as the internal lcd hw format. */
568 /* Draw a partial bitmap */
569 void ICODE_ATTR LCDFN(bitmap_part)(const unsigned char *src, int src_x,
570 int src_y, int stride, int x, int y,
571 int width, int height)
573 int shift, ny;
574 FBFN(data) *dst, *dst_end;
575 unsigned mask, mask_bottom;
576 LCDFN(blockfunc_type) *bfunc;
578 /* nothing to draw? */
579 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
580 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
581 return;
583 /* clipping */
584 if (x < 0)
586 width += x;
587 src_x -= x;
588 x = 0;
590 if (y < 0)
592 height += y;
593 src_y -= y;
594 y = 0;
596 if (x + width > current_vp->width)
597 width = current_vp->width - x;
598 if (y + height > current_vp->height)
599 height = current_vp->height - y;
601 /* adjust for viewport */
602 x += current_vp->x;
603 y += current_vp->y;
605 src += stride * (src_y >> 3) + src_x; /* move starting point */
606 src_y &= 7;
607 y -= src_y;
608 dst = &LCDFN(framebuffer)[y>>3][x];
609 shift = y & 7;
610 ny = height - 1 + shift + src_y;
612 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
613 mask = 0xFFu << (shift + src_y);
614 mask_bottom = 0xFFu >> (~ny & 7);
616 if (shift == 0)
618 bool copyopt = (current_vp->drawmode == DRMODE_SOLID);
620 for (; ny >= 8; ny -= 8)
622 if (copyopt && (mask == 0xFFu))
623 memcpy(dst, src, width);
624 else
626 const unsigned char *src_row = src;
627 FBFN(data) *dst_row = dst;
629 dst_end = dst_row + width;
631 bfunc(dst_row++, mask, *src_row++);
632 while (dst_row < dst_end);
635 src += stride;
636 dst += LCDM(WIDTH);
637 mask = 0xFFu;
639 mask &= mask_bottom;
641 if (copyopt && (mask == 0xFFu))
642 memcpy(dst, src, width);
643 else
645 dst_end = dst + width;
647 bfunc(dst++, mask, *src++);
648 while (dst < dst_end);
651 else
653 dst_end = dst + width;
656 const unsigned char *src_col = src++;
657 FBFN(data) *dst_col = dst++;
658 unsigned mask_col = mask;
659 unsigned data = 0;
661 for (y = ny; y >= 8; y -= 8)
663 data |= *src_col << shift;
665 if (mask_col & 0xFFu)
667 bfunc(dst_col, mask_col, data);
668 mask_col = 0xFFu;
670 else
671 mask_col >>= 8;
673 src_col += stride;
674 dst_col += LCDM(WIDTH);
675 data >>= 8;
677 data |= *src_col << shift;
678 bfunc(dst_col, mask_col & mask_bottom, data);
680 while (dst < dst_end);
684 /* Draw a full bitmap */
685 void LCDFN(bitmap)(const unsigned char *src, int x, int y, int width,
686 int height)
688 LCDFN(bitmap_part)(src, 0, 0, width, x, y, width, height);
691 #include "lcd-bitmap-common.c"