Colour targets: Revert an optimisation from almost 18 months ago that actually turned...
[Rockbox.git] / firmware / drivers / lcd-16bit.c
bloba7e89b0d6d6eea79c534c4ee4761dd243cc013af
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Dave Chapman
12 * Rockbox driver for 16-bit colour 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 ****************************************************************************/
23 #include "config.h"
25 #include "cpu.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 enum fill_opt {
41 OPT_NONE = 0,
42 OPT_SET,
43 OPT_COPY
46 /*** globals ***/
47 fb_data lcd_framebuffer[LCD_FBHEIGHT][LCD_FBWIDTH]
48 IRAM_LCDFRAMEBUFFER CACHEALIGN_AT_LEAST_ATTR(16);
51 static fb_data* lcd_backdrop = NULL;
52 static long lcd_backdrop_offset IDATA_ATTR = 0;
54 #ifdef HAVE_LCD_ENABLE
55 static void (*lcd_enable_hook)(void) = NULL;
56 #endif
58 static struct viewport default_vp =
60 .x = 0,
61 .y = 0,
62 .width = LCD_WIDTH,
63 .height = LCD_HEIGHT,
64 .font = FONT_SYSFIXED,
65 .drawmode = DRMODE_SOLID,
66 .fg_pattern = LCD_DEFAULT_FG,
67 .bg_pattern = LCD_DEFAULT_BG,
68 .lss_pattern = LCD_DEFAULT_BG,
69 .lse_pattern = LCD_DEFAULT_BG,
70 .lst_pattern = LCD_DEFAULT_BG,
73 /* The Gigabeat target build requires access to the current fg_pattern
74 in lcd-meg-fx.c */
75 #if (!defined(TOSHIBA_GIGABEAT_F)&& !defined(TOSHIBA_GIGABEAT_S)) || defined(SIMULATOR)
76 static struct viewport* current_vp IDATA_ATTR = &default_vp;
77 #else
78 struct viewport* current_vp IDATA_ATTR = &default_vp;
79 #endif
81 /* LCD init */
82 void lcd_init(void)
84 lcd_clear_display();
86 /* Call device specific init */
87 lcd_init_device();
88 scroll_init();
91 /*** Helpers - consolidate optional code ***/
92 #ifdef HAVE_LCD_ENABLE
93 void lcd_set_enable_hook(void (*enable_hook)(void))
95 lcd_enable_hook = enable_hook;
98 /* To be called by target driver after enabling display and refreshing it */
99 void lcd_call_enable_hook(void)
101 void (*enable_hook)(void) = lcd_enable_hook;
103 if (enable_hook != NULL)
104 enable_hook();
106 #endif
108 /*** Viewports ***/
110 void lcd_set_viewport(struct viewport* vp)
112 if (vp == NULL)
113 current_vp = &default_vp;
114 else
115 current_vp = vp;
118 void lcd_update_viewport(void)
120 lcd_update_rect(current_vp->x, current_vp->y,
121 current_vp->width, current_vp->height);
124 void lcd_update_viewport_rect(int x, int y, int width, int height)
126 lcd_update_rect(current_vp->x + x, current_vp->y + y, width, height);
129 /*** parameter handling ***/
131 void lcd_set_drawmode(int mode)
133 current_vp->drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
136 int lcd_get_drawmode(void)
138 return current_vp->drawmode;
141 void lcd_set_foreground(unsigned color)
143 current_vp->fg_pattern = color;
146 unsigned lcd_get_foreground(void)
148 return current_vp->fg_pattern;
151 void lcd_set_background(unsigned color)
153 current_vp->bg_pattern = color;
156 unsigned lcd_get_background(void)
158 return current_vp->bg_pattern;
161 void lcd_set_selector_start(unsigned color)
163 current_vp->lss_pattern = color;
166 void lcd_set_selector_end(unsigned color)
168 current_vp->lse_pattern = color;
171 void lcd_set_selector_text(unsigned color)
173 current_vp->lst_pattern = color;
176 void lcd_set_drawinfo(int mode, unsigned fg_color, unsigned bg_color)
178 lcd_set_drawmode(mode);
179 current_vp->fg_pattern = fg_color;
180 current_vp->bg_pattern = bg_color;
183 int lcd_getwidth(void)
185 return current_vp->width;
188 int lcd_getheight(void)
190 return current_vp->height;
193 void lcd_setfont(int newfont)
195 current_vp->font = newfont;
198 int lcd_getfont(void)
200 return current_vp->font;
203 int lcd_getstringsize(const unsigned char *str, int *w, int *h)
205 return font_getstringsize(str, w, h, current_vp->font);
208 /*** low-level drawing functions ***/
210 #define LCDADDR(x, y) (&lcd_framebuffer[(y)][(x)])
212 static void ICODE_ATTR setpixel(fb_data *address)
214 *address = current_vp->fg_pattern;
217 static void ICODE_ATTR clearpixel(fb_data *address)
219 *address = current_vp->bg_pattern;
222 static void ICODE_ATTR clearimgpixel(fb_data *address)
224 *address = *(fb_data *)((long)address + lcd_backdrop_offset);
227 static void ICODE_ATTR flippixel(fb_data *address)
229 *address = ~(*address);
232 static void ICODE_ATTR nopixel(fb_data *address)
234 (void)address;
237 lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_bgcolor[8] = {
238 flippixel, nopixel, setpixel, setpixel,
239 nopixel, clearpixel, nopixel, clearpixel
242 lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_backdrop[8] = {
243 flippixel, nopixel, setpixel, setpixel,
244 nopixel, clearimgpixel, nopixel, clearimgpixel
247 lcd_fastpixelfunc_type* const * lcd_fastpixelfuncs = lcd_fastpixelfuncs_bgcolor;
249 void lcd_set_backdrop(fb_data* backdrop)
251 lcd_backdrop = backdrop;
252 if (backdrop)
254 lcd_backdrop_offset = (long)backdrop - (long)&lcd_framebuffer[0][0];
255 lcd_fastpixelfuncs = lcd_fastpixelfuncs_backdrop;
257 else
259 lcd_backdrop_offset = 0;
260 lcd_fastpixelfuncs = lcd_fastpixelfuncs_bgcolor;
264 fb_data* lcd_get_backdrop(void)
266 return lcd_backdrop;
269 /*** drawing functions ***/
271 /* Clear the current viewport */
272 void lcd_clear_viewport(void)
274 fb_data *dst, *dst_end;
276 dst = LCDADDR(current_vp->x, current_vp->y);
277 dst_end = dst + current_vp->height * LCD_WIDTH;
279 if (current_vp->drawmode & DRMODE_INVERSEVID)
283 memset16(dst, current_vp->fg_pattern, current_vp->width);
284 dst += LCD_WIDTH;
286 while (dst < dst_end);
288 else
290 if (!lcd_backdrop)
294 memset16(dst, current_vp->bg_pattern, current_vp->width);
295 dst += LCD_WIDTH;
297 while (dst < dst_end);
299 else
303 memcpy(dst, (void *)((long)dst + lcd_backdrop_offset),
304 current_vp->width * sizeof(fb_data));
305 dst += LCD_WIDTH;
307 while (dst < dst_end);
311 if (current_vp == &default_vp)
313 lcd_scroll_info.lines = 0;
315 else
317 lcd_scroll_stop(current_vp);
321 /* Clear the whole display */
322 void lcd_clear_display(void)
324 struct viewport* old_vp = current_vp;
326 current_vp = &default_vp;
328 lcd_clear_viewport();
330 current_vp = old_vp;
333 /* Set a single pixel */
334 void lcd_drawpixel(int x, int y)
336 if (((unsigned)x < (unsigned)current_vp->width) &&
337 ((unsigned)y < (unsigned)current_vp->height))
338 lcd_fastpixelfuncs[current_vp->drawmode](LCDADDR(current_vp->x+x, current_vp->y+y));
341 /* Draw a line */
342 void lcd_drawline(int x1, int y1, int x2, int y2)
344 int numpixels;
345 int i;
346 int deltax, deltay;
347 int d, dinc1, dinc2;
348 int x, xinc1, xinc2;
349 int y, yinc1, yinc2;
350 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
352 deltay = abs(y2 - y1);
353 if (deltay == 0)
355 DEBUGF("lcd_drawline() called for horizontal line - optimisation.\n");
356 lcd_hline(x1, x2, y1);
357 return;
359 deltax = abs(x2 - x1);
360 if (deltax == 0)
362 DEBUGF("lcd_drawline() called for vertical line - optimisation.\n");
363 lcd_vline(x1, y1, y2);
364 return;
366 xinc2 = 1;
367 yinc2 = 1;
369 if (deltax >= deltay)
371 numpixels = deltax;
372 d = 2 * deltay - deltax;
373 dinc1 = deltay * 2;
374 dinc2 = (deltay - deltax) * 2;
375 xinc1 = 1;
376 yinc1 = 0;
378 else
380 numpixels = deltay;
381 d = 2 * deltax - deltay;
382 dinc1 = deltax * 2;
383 dinc2 = (deltax - deltay) * 2;
384 xinc1 = 0;
385 yinc1 = 1;
387 numpixels++; /* include endpoints */
389 if (x1 > x2)
391 xinc1 = -xinc1;
392 xinc2 = -xinc2;
395 if (y1 > y2)
397 yinc1 = -yinc1;
398 yinc2 = -yinc2;
401 x = x1;
402 y = y1;
404 for (i = 0; i < numpixels; i++)
406 if (((unsigned)x < (unsigned)current_vp->width) && ((unsigned)y < (unsigned)current_vp->height))
407 pfunc(LCDADDR(x + current_vp->x, y + current_vp->y));
409 if (d < 0)
411 d += dinc1;
412 x += xinc1;
413 y += yinc1;
415 else
417 d += dinc2;
418 x += xinc2;
419 y += yinc2;
424 /* Draw a horizontal line (optimised) */
425 void lcd_hline(int x1, int x2, int y)
427 int x, width;
428 unsigned bits = 0;
429 enum fill_opt fillopt = OPT_NONE;
430 fb_data *dst, *dst_end;
431 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
433 /* direction flip */
434 if (x2 < x1)
436 x = x1;
437 x1 = x2;
438 x2 = x;
441 /* nothing to draw? */
442 if (((unsigned)y >= (unsigned)current_vp->height) ||
443 (x1 >= current_vp->width) ||
444 (x2 < 0))
445 return;
447 /* clipping */
448 if (x1 < 0)
449 x1 = 0;
450 if (x2 >= current_vp->width)
451 x2 = current_vp->width-1;
453 width = x2 - x1 + 1;
455 /* Adjust x1 and y to viewport */
456 x1 += current_vp->x;
457 y += current_vp->y;
459 if (current_vp->drawmode & DRMODE_INVERSEVID)
461 if (current_vp->drawmode & DRMODE_BG)
463 if (!lcd_backdrop)
465 fillopt = OPT_SET;
466 bits = current_vp->bg_pattern;
468 else
469 fillopt = OPT_COPY;
472 else
474 if (current_vp->drawmode & DRMODE_FG)
476 fillopt = OPT_SET;
477 bits = current_vp->fg_pattern;
480 dst = LCDADDR(x1, y);
482 switch (fillopt)
484 case OPT_SET:
485 memset16(dst, bits, width);
486 break;
488 case OPT_COPY:
489 memcpy(dst, (void *)((long)dst + lcd_backdrop_offset),
490 width * sizeof(fb_data));
491 break;
493 case OPT_NONE:
494 dst_end = dst + width;
496 pfunc(dst++);
497 while (dst < dst_end);
498 break;
502 /* Draw a vertical line (optimised) */
503 void lcd_vline(int x, int y1, int y2)
505 int y;
506 fb_data *dst, *dst_end;
507 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
509 /* direction flip */
510 if (y2 < y1)
512 y = y1;
513 y1 = y2;
514 y2 = y;
517 /* nothing to draw? */
518 if ((x >= current_vp->width) ||
519 (y1 >= current_vp->height) ||
520 (y2 < 0))
521 return;
523 /* clipping */
524 if (y1 < 0)
525 y1 = 0;
526 if (y2 >= current_vp->height)
527 y2 = current_vp->height-1;
529 dst = LCDADDR(x + current_vp->x, y1 + current_vp->y);
530 dst_end = dst + (y2 - y1) * LCD_WIDTH;
534 pfunc(dst);
535 dst += LCD_WIDTH;
537 while (dst <= dst_end);
540 /* Draw a rectangular box */
541 void lcd_drawrect(int x, int y, int width, int height)
543 if ((width <= 0) || (height <= 0))
544 return;
546 int x2 = x + width - 1;
547 int y2 = y + height - 1;
549 lcd_vline(x, y, y2);
550 lcd_vline(x2, y, y2);
551 lcd_hline(x, x2, y);
552 lcd_hline(x, x2, y2);
555 /* Fill a rectangular area */
556 void lcd_fillrect(int x, int y, int width, int height)
558 unsigned bits = 0;
559 enum fill_opt fillopt = OPT_NONE;
560 fb_data *dst, *dst_end;
561 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[current_vp->drawmode];
563 /* nothing to draw? */
564 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
565 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
566 return;
568 /* clipping */
569 if (x < 0)
571 width += x;
572 x = 0;
574 if (y < 0)
576 height += y;
577 y = 0;
579 if (x + width > current_vp->width)
580 width = current_vp->width - x;
581 if (y + height > current_vp->height)
582 height = current_vp->height - y;
584 if (current_vp->drawmode & DRMODE_INVERSEVID)
586 if (current_vp->drawmode & DRMODE_BG)
588 if (!lcd_backdrop)
590 fillopt = OPT_SET;
591 bits = current_vp->bg_pattern;
593 else
594 fillopt = OPT_COPY;
597 else
599 if (current_vp->drawmode & DRMODE_FG)
601 fillopt = OPT_SET;
602 bits = current_vp->fg_pattern;
605 dst = LCDADDR(current_vp->x + x, current_vp->y + y);
606 dst_end = dst + height * LCD_WIDTH;
610 fb_data *dst_row, *row_end;
612 switch (fillopt)
614 case OPT_SET:
615 memset16(dst, bits, width);
616 break;
618 case OPT_COPY:
619 memcpy(dst, (void *)((long)dst + lcd_backdrop_offset),
620 width * sizeof(fb_data));
621 break;
623 case OPT_NONE:
624 dst_row = dst;
625 row_end = dst_row + width;
627 pfunc(dst_row++);
628 while (dst_row < row_end);
629 break;
631 dst += LCD_WIDTH;
633 while (dst < dst_end);
636 /* Fill a rectangle with a gradient */
637 static void lcd_gradient_rect(int x1, int x2, int y, int h)
639 int old_pattern = current_vp->fg_pattern;
641 if (h == 0) return;
643 int h_r = RGB_UNPACK_RED(current_vp->lss_pattern) << 16;
644 int h_b = RGB_UNPACK_BLUE(current_vp->lss_pattern) << 16;
645 int h_g = RGB_UNPACK_GREEN(current_vp->lss_pattern) << 16;
646 int rstep = (h_r - ((signed)RGB_UNPACK_RED(current_vp->lse_pattern) << 16)) / h;
647 int gstep = (h_g - ((signed)RGB_UNPACK_GREEN(current_vp->lse_pattern) << 16)) / h;
648 int bstep = (h_b - ((signed)RGB_UNPACK_BLUE(current_vp->lse_pattern) << 16)) / h;
649 int count;
651 current_vp->fg_pattern = current_vp->lss_pattern;
652 for(count = 0; count < h; count++) {
653 lcd_hline(x1, x2, y + count);
654 h_r -= rstep;
655 h_g -= gstep;
656 h_b -= bstep;
657 current_vp->fg_pattern = LCD_RGBPACK(h_r >> 16, h_g >> 16, h_b >> 16);
660 current_vp->fg_pattern = old_pattern;
663 #define H_COLOR(lss, lse, cur_line, max_line) \
664 (((lse) - (lss)) * (cur_line) / (max_line) + (lss))
666 /* Fill a rectangle with a gradient for scrolling line. To draw a gradient that
667 covers several lines, we need to know how many lines will be covered
668 (the num_lines arg), and which one is the current line within the selection
669 (the cur_line arg). */
670 static void lcd_gradient_rect_scroll(int x1, int x2, int y, int h,
671 unsigned char num_lines, unsigned char cur_line)
673 if (h == 0 || num_lines == 0) return;
675 unsigned tmp_lss = current_vp->lss_pattern;
676 unsigned tmp_lse = current_vp->lse_pattern;
677 int lss_r = (signed)RGB_UNPACK_RED(current_vp->lss_pattern);
678 int lss_b = (signed)RGB_UNPACK_BLUE(current_vp->lss_pattern);
679 int lss_g = (signed)RGB_UNPACK_GREEN(current_vp->lss_pattern);
680 int lse_r = (signed)RGB_UNPACK_RED(current_vp->lse_pattern);
681 int lse_b = (signed)RGB_UNPACK_BLUE(current_vp->lse_pattern);
682 int lse_g = (signed)RGB_UNPACK_GREEN(current_vp->lse_pattern);
684 int h_r = H_COLOR(lss_r, lse_r, cur_line, num_lines);
685 int h_g = H_COLOR(lss_g, lse_g, cur_line, num_lines);
686 int h_b = H_COLOR(lss_b, lse_b, cur_line, num_lines);
687 lcd_set_selector_start(LCD_RGBPACK(h_r, h_g, h_b));
689 int l_r = H_COLOR(lss_r, lse_r, cur_line+1, num_lines);
690 int l_g = H_COLOR(lss_g, lse_g, cur_line+1, num_lines);
691 int l_b = H_COLOR(lss_b, lse_b, cur_line+1, num_lines);
692 lcd_set_selector_end(LCD_RGBPACK(l_r, l_g, l_b));
694 lcd_gradient_rect(x1, x2, y, h);
696 current_vp->lss_pattern = tmp_lss;
697 current_vp->lse_pattern = tmp_lse;
700 /* About Rockbox' internal monochrome bitmap format:
702 * A bitmap contains one bit for every pixel that defines if that pixel is
703 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
704 * at top.
705 * The bytes are stored in row-major order, with byte 0 being top left,
706 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
707 * 0..7, the second row defines pixel row 8..15 etc.
709 * This is the mono bitmap format used on all other targets so far; the
710 * pixel packing doesn't really matter on a 8bit+ target. */
712 /* Draw a partial monochrome bitmap */
714 void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
715 int src_y, int stride, int x, int y,
716 int width, int height)
718 const unsigned char *src_end;
719 fb_data *dst, *dst_end;
720 lcd_fastpixelfunc_type *fgfunc, *bgfunc;
722 /* nothing to draw? */
723 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
724 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
725 return;
727 /* clipping */
728 if (x < 0)
730 width += x;
731 src_x -= x;
732 x = 0;
734 if (y < 0)
736 height += y;
737 src_y -= y;
738 y = 0;
740 if (x + width > current_vp->width)
741 width = current_vp->width - x;
742 if (y + height > current_vp->height)
743 height = current_vp->height - y;
745 src += stride * (src_y >> 3) + src_x; /* move starting point */
746 src_y &= 7;
747 src_end = src + width;
749 dst = LCDADDR(current_vp->x + x, current_vp->y + y);
750 fgfunc = lcd_fastpixelfuncs[current_vp->drawmode];
751 bgfunc = lcd_fastpixelfuncs[current_vp->drawmode ^ DRMODE_INVERSEVID];
754 const unsigned char *src_col = src++;
755 unsigned data = *src_col >> src_y;
756 fb_data *dst_col = dst++;
757 int numbits = 8 - src_y;
758 dst_end = dst_col + height * LCD_WIDTH;
761 if (data & 0x01)
762 fgfunc(dst_col);
763 else
764 bgfunc(dst_col);
766 dst_col += LCD_WIDTH;
768 data >>= 1;
769 if (--numbits == 0)
771 src_col += stride;
772 data = *src_col;
773 numbits = 8;
776 while (dst_col < dst_end);
778 while (src < src_end);
780 /* Draw a full monochrome bitmap */
781 void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int height)
783 lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height);
786 /* Draw a partial native bitmap */
787 void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
788 int stride, int x, int y, int width,
789 int height)
791 fb_data *dst, *dst_end;
793 /* nothing to draw? */
794 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
795 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
796 return;
798 /* clipping */
799 if (x < 0)
801 width += x;
802 src_x -= x;
803 x = 0;
805 if (y < 0)
807 height += y;
808 src_y -= y;
809 y = 0;
811 if (x + width > current_vp->width)
812 width = current_vp->width - x;
813 if (y + height > current_vp->height)
814 height = current_vp->height - y;
816 src += stride * src_y + src_x; /* move starting point */
817 dst = LCDADDR(current_vp->x + x, current_vp->y + y);
818 dst_end = dst + height * LCD_WIDTH;
822 memcpy(dst, src, width * sizeof(fb_data));
823 src += stride;
824 dst += LCD_WIDTH;
826 while (dst < dst_end);
829 /* Draw a full native bitmap */
830 void lcd_bitmap(const fb_data *src, int x, int y, int width, int height)
832 lcd_bitmap_part(src, 0, 0, width, x, y, width, height);
835 #if !defined(TOSHIBA_GIGABEAT_F) && !defined(TOSHIBA_GIGABEAT_S) \
836 || defined(SIMULATOR)
837 /* Draw a partial native bitmap */
838 void ICODE_ATTR lcd_bitmap_transparent_part(const fb_data *src, int src_x,
839 int src_y, int stride, int x,
840 int y, int width, int height)
842 fb_data *dst, *dst_end;
844 /* nothing to draw? */
845 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
846 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
847 return;
849 /* clipping */
850 if (x < 0)
852 width += x;
853 src_x -= x;
854 x = 0;
856 if (y < 0)
858 height += y;
859 src_y -= y;
860 y = 0;
862 if (x + width > current_vp->width)
863 width = current_vp->width - x;
864 if (y + height > current_vp->height)
865 height = current_vp->height - y;
867 src += stride * src_y + src_x; /* move starting point */
868 dst = LCDADDR(current_vp->x + x, current_vp->y + y);
869 dst_end = dst + height * LCD_WIDTH;
873 int i;
874 for(i = 0;i < width;i++)
876 if (src[i] == REPLACEWITHFG_COLOR)
877 dst[i] = current_vp->fg_pattern;
878 else if(src[i] != TRANSPARENT_COLOR)
879 dst[i] = src[i];
881 src += stride;
882 dst += LCD_WIDTH;
884 while (dst < dst_end);
886 #endif /* !defined(TOSHIBA_GIGABEAT_F) || defined(SIMULATOR) */
888 /* Draw a full native bitmap with a transparent color */
889 void lcd_bitmap_transparent(const fb_data *src, int x, int y,
890 int width, int height)
892 lcd_bitmap_transparent_part(src, 0, 0, width, x, y, width, height);
895 /* put a string at a given pixel position, skipping first ofs pixel columns */
896 static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
898 unsigned short ch;
899 unsigned short *ucs;
900 struct font* pf = font_get(current_vp->font);
902 ucs = bidi_l2v(str, 1);
904 while ((ch = *ucs++) != 0 && x < current_vp->width)
906 int width;
907 const unsigned char *bits;
909 /* get proportional width and glyph bits */
910 width = font_get_width(pf,ch);
912 if (ofs > width)
914 ofs -= width;
915 continue;
918 bits = font_get_bits(pf, ch);
920 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
922 x += width - ofs;
923 ofs = 0;
927 /* put a string at a given pixel position */
928 void lcd_putsxy(int x, int y, const unsigned char *str)
930 lcd_putsxyofs(x, y, 0, str);
933 /*** line oriented text output ***/
935 /* put a string at a given char position */
936 void lcd_puts(int x, int y, const unsigned char *str)
938 lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, 0);
941 void lcd_puts_style(int x, int y, const unsigned char *str, int style)
943 lcd_puts_style_offset(x, y, str, style, 0);
946 void lcd_puts_offset(int x, int y, const unsigned char *str, int offset)
948 lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, offset);
951 /* put a string at a given char position, style, and pixel position,
952 * skipping first offset pixel columns */
953 void lcd_puts_style_offset(int x, int y, const unsigned char *str, int style,
954 int offset)
956 int xpos,ypos,w,h,xrect;
957 int lastmode = current_vp->drawmode;
958 int oldfgcolor = current_vp->fg_pattern;
959 int oldbgcolor = current_vp->bg_pattern;
961 /* make sure scrolling is turned off on the line we are updating */
962 lcd_scroll_stop_line(current_vp, y);
964 if(!str || !str[0])
965 return;
967 lcd_getstringsize(str, &w, &h);
968 xpos = x*w / utf8length(str);
969 ypos = y*h;
970 current_vp->drawmode = (style & STYLE_INVERT) ?
971 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
972 if (style & STYLE_COLORED) {
973 if (current_vp->drawmode == DRMODE_SOLID)
974 current_vp->fg_pattern = style & STYLE_COLOR_MASK;
975 else
976 current_vp->bg_pattern = style & STYLE_COLOR_MASK;
978 current_vp->drawmode ^= DRMODE_INVERSEVID;
979 xrect = xpos + MAX(w - offset, 0);
981 if (style & STYLE_GRADIENT) {
982 current_vp->drawmode = DRMODE_FG;
983 if (CURLN_UNPACK(style) == 0)
984 lcd_gradient_rect(xpos, current_vp->width, ypos, h*NUMLN_UNPACK(style));
985 current_vp->fg_pattern = current_vp->lst_pattern;
987 else if (style & STYLE_COLORBAR) {
988 current_vp->drawmode = DRMODE_FG;
989 current_vp->fg_pattern = current_vp->lss_pattern;
990 lcd_fillrect(xpos, ypos, current_vp->width - xpos, h);
991 current_vp->fg_pattern = current_vp->lst_pattern;
993 else {
994 lcd_fillrect(xrect, ypos, current_vp->width - xrect, h);
995 current_vp->drawmode = (style & STYLE_INVERT) ?
996 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
998 lcd_putsxyofs(xpos, ypos, offset, str);
999 current_vp->drawmode = lastmode;
1000 current_vp->fg_pattern = oldfgcolor;
1001 current_vp->bg_pattern = oldbgcolor;
1004 /*** scrolling ***/
1005 void lcd_puts_scroll(int x, int y, const unsigned char *string)
1007 lcd_puts_scroll_style(x, y, string, STYLE_DEFAULT);
1010 void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style)
1012 lcd_puts_scroll_style_offset(x, y, string, style, 0);
1015 void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, int offset)
1017 lcd_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset);
1020 /* Initialise a scrolling line at (x,y) in current viewport */
1022 void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
1023 int style, int offset)
1025 struct scrollinfo* s;
1026 int w, h;
1028 if ((unsigned)y >= (unsigned)current_vp->height)
1029 return;
1031 /* remove any previously scrolling line at the same location */
1032 lcd_scroll_stop_line(current_vp, y);
1034 if (lcd_scroll_info.lines >= LCD_SCROLLABLE_LINES) return;
1036 s = &lcd_scroll_info.scroll[lcd_scroll_info.lines];
1038 s->start_tick = current_tick + lcd_scroll_info.delay;
1039 s->style = style;
1040 lcd_puts_style_offset(x,y,string,style,offset);
1042 lcd_getstringsize(string, &w, &h);
1044 if (current_vp->width - x * 8 < w) {
1045 /* prepare scroll line */
1046 char *end;
1048 memset(s->line, 0, sizeof s->line);
1049 strcpy(s->line, string);
1051 /* get width */
1052 s->width = lcd_getstringsize(s->line, &w, &h);
1054 /* scroll bidirectional or forward only depending on the string
1055 width */
1056 if ( lcd_scroll_info.bidir_limit ) {
1057 s->bidir = s->width < (current_vp->width) *
1058 (100 + lcd_scroll_info.bidir_limit) / 100;
1060 else
1061 s->bidir = false;
1063 if (!s->bidir) { /* add spaces if scrolling in the round */
1064 strcat(s->line, " ");
1065 /* get new width incl. spaces */
1066 s->width = lcd_getstringsize(s->line, &w, &h);
1069 end = strchr(s->line, '\0');
1070 strncpy(end, string, current_vp->width/2);
1072 s->vp = current_vp;
1073 s->y = y;
1074 s->len = utf8length(string);
1075 s->offset = offset;
1076 s->startx = x * s->width / s->len;
1077 s->backward = false;
1078 lcd_scroll_info.lines++;
1082 void lcd_scroll_fn(void)
1084 struct font* pf;
1085 struct scrollinfo* s;
1086 int index;
1087 int xpos, ypos;
1088 int lastmode;
1089 unsigned old_fgcolor;
1090 unsigned old_bgcolor;
1091 struct viewport* old_vp = current_vp;
1093 for ( index = 0; index < lcd_scroll_info.lines; index++ ) {
1094 s = &lcd_scroll_info.scroll[index];
1096 /* check pause */
1097 if (TIME_BEFORE(current_tick, s->start_tick))
1098 continue;
1100 lcd_set_viewport(s->vp);
1101 old_fgcolor = current_vp->fg_pattern;
1102 old_bgcolor = current_vp->bg_pattern;
1104 if (s->style&STYLE_COLORED) {
1105 if (s->style&STYLE_MODE_MASK) {
1106 current_vp->fg_pattern = old_fgcolor;
1107 current_vp->bg_pattern = s->style&STYLE_COLOR_MASK;
1109 else {
1110 current_vp->fg_pattern = s->style&STYLE_COLOR_MASK;
1111 current_vp->bg_pattern = old_bgcolor;
1115 if (s->backward)
1116 s->offset -= lcd_scroll_info.step;
1117 else
1118 s->offset += lcd_scroll_info.step;
1120 pf = font_get(current_vp->font);
1121 xpos = s->startx;
1122 ypos = s->y * pf->height;
1124 if (s->bidir) { /* scroll bidirectional */
1125 if (s->offset <= 0) {
1126 /* at beginning of line */
1127 s->offset = 0;
1128 s->backward = false;
1129 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
1131 if (s->offset >= s->width - (current_vp->width - xpos)) {
1132 /* at end of line */
1133 s->offset = s->width - (current_vp->width - xpos);
1134 s->backward = true;
1135 s->start_tick = current_tick + lcd_scroll_info.delay * 2;
1138 else {
1139 /* scroll forward the whole time */
1140 if (s->offset >= s->width)
1141 s->offset %= s->width;
1144 lastmode = current_vp->drawmode;
1145 switch (s->style&STYLE_MODE_MASK) {
1146 case STYLE_INVERT:
1147 current_vp->drawmode = DRMODE_SOLID|DRMODE_INVERSEVID;
1148 break;
1149 case STYLE_COLORBAR:
1150 /* Solid colour line selector */
1151 current_vp->drawmode = DRMODE_FG;
1152 current_vp->fg_pattern = current_vp->lss_pattern;
1153 lcd_fillrect(xpos, ypos, current_vp->width - xpos, pf->height);
1154 current_vp->fg_pattern = current_vp->lst_pattern;
1155 break;
1156 case STYLE_GRADIENT:
1157 /* Gradient line selector */
1158 current_vp->drawmode = DRMODE_FG;
1159 lcd_gradient_rect_scroll(xpos, current_vp->width, ypos, (signed)pf->height,
1160 NUMLN_UNPACK(s->style),
1161 CURLN_UNPACK(s->style));
1162 current_vp->fg_pattern = current_vp->lst_pattern;
1163 break;
1164 default:
1165 current_vp->drawmode = DRMODE_SOLID;
1166 break;
1168 lcd_putsxyofs(xpos, ypos, s->offset, s->line);
1169 current_vp->drawmode = lastmode;
1170 current_vp->fg_pattern = old_fgcolor;
1171 current_vp->bg_pattern = old_bgcolor;
1172 lcd_update_viewport_rect(xpos, ypos, current_vp->width - xpos, pf->height);
1175 lcd_set_viewport(old_vp);