(hopefully) fix some broken download stuff I introduced yesterday.
[Rockbox.git] / firmware / drivers / lcd-remote-1bit-v.c
blob480df73c2dcbac1883c6299d67f25a83fa485ecc
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Richard S. La Charité III
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "config.h"
21 #include "cpu.h"
22 #include "lcd.h"
23 #include "lcd-remote.h"
24 #include "kernel.h"
25 #include "thread.h"
26 #include <string.h>
27 #include <stdlib.h>
28 #include "file.h"
29 #include "debug.h"
30 #include "system.h"
31 #include "font.h"
32 #include "rbunicode.h"
33 #include "bidi.h"
34 #include "scroll_engine.h"
36 /*** globals ***/
38 fb_remote_data lcd_remote_framebuffer[LCD_REMOTE_FBHEIGHT][LCD_REMOTE_FBWIDTH]
39 IBSS_ATTR;
41 static int drawmode = DRMODE_SOLID;
42 static int xmargin = 0;
43 static int ymargin = 0;
44 static int curfont = FONT_SYSFIXED;
46 /*** parameter handling ***/
48 void lcd_remote_set_drawmode(int mode)
50 drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
53 int lcd_remote_get_drawmode(void)
55 return drawmode;
58 void lcd_remote_setmargins(int x, int y)
60 xmargin = x;
61 ymargin = y;
64 int lcd_remote_getxmargin(void)
66 return xmargin;
69 int lcd_remote_getymargin(void)
71 return ymargin;
74 void lcd_remote_setfont(int newfont)
76 curfont = newfont;
79 int lcd_remote_getstringsize(const unsigned char *str, int *w, int *h)
81 return font_getstringsize(str, w, h, curfont);
84 /*** low-level drawing functions ***/
86 static void setpixel(int x, int y)
88 lcd_remote_framebuffer[y>>3][x] |= 1 << (y & 7);
91 static void clearpixel(int x, int y)
93 lcd_remote_framebuffer[y>>3][x] &= ~(1 << (y & 7));
96 static void flippixel(int x, int y)
98 lcd_remote_framebuffer[y>>3][x] ^= 1 << (y & 7);
101 static void nopixel(int x, int y)
103 (void)x;
104 (void)y;
107 lcd_remote_pixelfunc_type* const lcd_remote_pixelfuncs[8] = {
108 flippixel, nopixel, setpixel, setpixel,
109 nopixel, clearpixel, nopixel, clearpixel
112 static void flipblock(fb_remote_data *address, unsigned mask, unsigned bits)
113 ICODE_ATTR;
114 static void flipblock(fb_remote_data *address, unsigned mask, unsigned bits)
116 *address ^= bits & mask;
119 static void bgblock(fb_remote_data *address, unsigned mask, unsigned bits)
120 ICODE_ATTR;
121 static void bgblock(fb_remote_data *address, unsigned mask, unsigned bits)
123 *address &= bits | ~mask;
126 static void fgblock(fb_remote_data *address, unsigned mask, unsigned bits)
127 ICODE_ATTR;
128 static void fgblock(fb_remote_data *address, unsigned mask, unsigned bits)
130 *address |= bits & mask;
133 static void solidblock(fb_remote_data *address, unsigned mask, unsigned bits)
134 ICODE_ATTR;
135 static void solidblock(fb_remote_data *address, unsigned mask, unsigned bits)
137 unsigned data = *address;
139 bits ^= data;
140 *address = data ^ (bits & mask);
143 static void flipinvblock(fb_remote_data *address, unsigned mask, unsigned bits)
144 ICODE_ATTR;
145 static void flipinvblock(fb_remote_data *address, unsigned mask, unsigned bits)
147 *address ^= ~bits & mask;
150 static void bginvblock(fb_remote_data *address, unsigned mask, unsigned bits)
151 ICODE_ATTR;
152 static void bginvblock(fb_remote_data *address, unsigned mask, unsigned bits)
154 *address &= ~(bits & mask);
157 static void fginvblock(fb_remote_data *address, unsigned mask, unsigned bits)
158 ICODE_ATTR;
159 static void fginvblock(fb_remote_data *address, unsigned mask, unsigned bits)
161 *address |= ~bits & mask;
164 static void solidinvblock(fb_remote_data *address, unsigned mask, unsigned bits)
165 ICODE_ATTR;
166 static void solidinvblock(fb_remote_data *address, unsigned mask, unsigned bits)
168 unsigned data = *address;
170 bits = ~bits ^ data;
171 *address = data ^ (bits & mask);
174 lcd_remote_blockfunc_type* const lcd_remote_blockfuncs[8] = {
175 flipblock, bgblock, fgblock, solidblock,
176 flipinvblock, bginvblock, fginvblock, solidinvblock
179 /*** drawing functions ***/
181 /* Clear the whole display */
182 void lcd_remote_clear_display(void)
184 unsigned bits = (drawmode & DRMODE_INVERSEVID) ? 0xFFu : 0;
186 memset(lcd_remote_framebuffer, bits, sizeof lcd_remote_framebuffer);
187 lcd_remote_scroll_info.lines = 0;
190 /* Set a single pixel */
191 void lcd_remote_drawpixel(int x, int y)
193 if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT))
194 lcd_remote_pixelfuncs[drawmode](x, y);
197 /* Draw a line */
198 void lcd_remote_drawline(int x1, int y1, int x2, int y2)
200 int numpixels;
201 int i;
202 int deltax, deltay;
203 int d, dinc1, dinc2;
204 int x, xinc1, xinc2;
205 int y, yinc1, yinc2;
206 lcd_remote_pixelfunc_type *pfunc = lcd_remote_pixelfuncs[drawmode];
208 deltax = abs(x2 - x1);
209 deltay = abs(y2 - y1);
210 xinc2 = 1;
211 yinc2 = 1;
213 if (deltax >= deltay)
215 numpixels = deltax;
216 d = 2 * deltay - deltax;
217 dinc1 = deltay * 2;
218 dinc2 = (deltay - deltax) * 2;
219 xinc1 = 1;
220 yinc1 = 0;
222 else
224 numpixels = deltay;
225 d = 2 * deltax - deltay;
226 dinc1 = deltax * 2;
227 dinc2 = (deltax - deltay) * 2;
228 xinc1 = 0;
229 yinc1 = 1;
231 numpixels++; /* include endpoints */
233 if (x1 > x2)
235 xinc1 = -xinc1;
236 xinc2 = -xinc2;
239 if (y1 > y2)
241 yinc1 = -yinc1;
242 yinc2 = -yinc2;
245 x = x1;
246 y = y1;
248 for (i = 0; i < numpixels; i++)
250 if (((unsigned)x < LCD_REMOTE_WIDTH) && ((unsigned)y < LCD_REMOTE_HEIGHT))
251 pfunc(x, y);
253 if (d < 0)
255 d += dinc1;
256 x += xinc1;
257 y += yinc1;
259 else
261 d += dinc2;
262 x += xinc2;
263 y += yinc2;
268 /* Draw a horizontal line (optimised) */
269 void lcd_remote_hline(int x1, int x2, int y)
271 int x;
272 fb_remote_data *dst, *dst_end;
273 unsigned mask;
274 lcd_remote_blockfunc_type *bfunc;
276 /* direction flip */
277 if (x2 < x1)
279 x = x1;
280 x1 = x2;
281 x2 = x;
284 /* nothing to draw? */
285 if (((unsigned)y >= LCD_REMOTE_HEIGHT) || (x1 >= LCD_REMOTE_WIDTH)
286 || (x2 < 0))
287 return;
289 /* clipping */
290 if (x1 < 0)
291 x1 = 0;
292 if (x2 >= LCD_REMOTE_WIDTH)
293 x2 = LCD_REMOTE_WIDTH-1;
295 bfunc = lcd_remote_blockfuncs[drawmode];
296 dst = &lcd_remote_framebuffer[y>>3][x1];
297 mask = 1 << (y & 7);
299 dst_end = dst + x2 - x1;
301 bfunc(dst++, mask, 0xFFu);
302 while (dst <= dst_end);
305 /* Draw a vertical line (optimised) */
306 void lcd_remote_vline(int x, int y1, int y2)
308 int ny;
309 fb_remote_data *dst;
310 unsigned mask, mask_bottom;
311 lcd_remote_blockfunc_type *bfunc;
313 /* direction flip */
314 if (y2 < y1)
316 ny = y1;
317 y1 = y2;
318 y2 = ny;
321 /* nothing to draw? */
322 if (((unsigned)x >= LCD_REMOTE_WIDTH) || (y1 >= LCD_REMOTE_HEIGHT)
323 || (y2 < 0))
324 return;
326 /* clipping */
327 if (y1 < 0)
328 y1 = 0;
329 if (y2 >= LCD_REMOTE_HEIGHT)
330 y2 = LCD_REMOTE_HEIGHT-1;
332 bfunc = lcd_remote_blockfuncs[drawmode];
333 dst = &lcd_remote_framebuffer[y1>>3][x];
334 ny = y2 - (y1 & ~7);
335 mask = 0xFFu << (y1 & 7);
336 mask_bottom = 0xFFu >> (~ny & 7);
338 for (; ny >= 8; ny -= 8)
340 bfunc(dst, mask, 0xFFu);
341 dst += LCD_REMOTE_WIDTH;
342 mask = 0xFFu;
344 mask &= mask_bottom;
345 bfunc(dst, mask, 0xFFu);
348 /* Draw a rectangular box */
349 void lcd_remote_drawrect(int x, int y, int width, int height)
351 if ((width <= 0) || (height <= 0))
352 return;
354 int x2 = x + width - 1;
355 int y2 = y + height - 1;
357 lcd_remote_vline(x, y, y2);
358 lcd_remote_vline(x2, y, y2);
359 lcd_remote_hline(x, x2, y);
360 lcd_remote_hline(x, x2, y2);
363 /* Fill a rectangular area */
364 void lcd_remote_fillrect(int x, int y, int width, int height)
366 int ny;
367 fb_remote_data *dst, *dst_end;
368 unsigned mask, mask_bottom;
369 unsigned bits = 0;
370 lcd_remote_blockfunc_type *bfunc;
371 bool fillopt = false;
373 /* nothing to draw? */
374 if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH)
375 || (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0))
376 return;
378 /* clipping */
379 if (x < 0)
381 width += x;
382 x = 0;
384 if (y < 0)
386 height += y;
387 y = 0;
389 if (x + width > LCD_REMOTE_WIDTH)
390 width = LCD_REMOTE_WIDTH - x;
391 if (y + height > LCD_REMOTE_HEIGHT)
392 height = LCD_REMOTE_HEIGHT - y;
394 if (drawmode & DRMODE_INVERSEVID)
396 if (drawmode & DRMODE_BG)
398 fillopt = true;
401 else
403 if (drawmode & DRMODE_FG)
405 fillopt = true;
406 bits = 0xFFu;
409 bfunc = lcd_remote_blockfuncs[drawmode];
410 dst = &lcd_remote_framebuffer[y>>3][x];
411 ny = height - 1 + (y & 7);
412 mask = 0xFFu << (y & 7);
413 mask_bottom = 0xFFu >> (~ny & 7);
415 for (; ny >= 8; ny -= 8)
417 if (fillopt && (mask == 0xFFu))
418 memset(dst, bits, width);
419 else
421 fb_remote_data *dst_row = dst;
423 dst_end = dst_row + width;
425 bfunc(dst_row++, mask, 0xFFu);
426 while (dst_row < dst_end);
429 dst += LCD_REMOTE_WIDTH;
430 mask = 0xFFu;
432 mask &= mask_bottom;
434 if (fillopt && (mask == 0xFFu))
435 memset(dst, bits, width);
436 else
438 dst_end = dst + width;
440 bfunc(dst++, mask, 0xFFu);
441 while (dst < dst_end);
445 /* About Rockbox' internal bitmap format:
447 * A bitmap contains one bit for every pixel that defines if that pixel is
448 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
449 * at top.
450 * The bytes are stored in row-major order, with byte 0 being top left,
451 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
452 * 0..7, the second row defines pixel row 8..15 etc.
454 * This is the same as the internal lcd hw format. */
456 /* Draw a partial bitmap */
457 void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y,
458 int stride, int x, int y, int width, int height)
459 ICODE_ATTR;
460 void lcd_remote_bitmap_part(const unsigned char *src, int src_x, int src_y,
461 int stride, int x, int y, int width, int height)
463 int shift, ny;
464 fb_remote_data *dst, *dst_end;
465 unsigned mask, mask_bottom;
466 lcd_remote_blockfunc_type *bfunc;
468 /* nothing to draw? */
469 if ((width <= 0) || (height <= 0) || (x >= LCD_REMOTE_WIDTH)
470 || (y >= LCD_REMOTE_HEIGHT) || (x + width <= 0) || (y + height <= 0))
471 return;
473 /* clipping */
474 if (x < 0)
476 width += x;
477 src_x -= x;
478 x = 0;
480 if (y < 0)
482 height += y;
483 src_y -= y;
484 y = 0;
486 if (x + width > LCD_REMOTE_WIDTH)
487 width = LCD_REMOTE_WIDTH - x;
488 if (y + height > LCD_REMOTE_HEIGHT)
489 height = LCD_REMOTE_HEIGHT - y;
491 src += stride * (src_y >> 3) + src_x; /* move starting point */
492 src_y &= 7;
493 y -= src_y;
494 dst = &lcd_remote_framebuffer[y>>3][x];
495 shift = y & 7;
496 ny = height - 1 + shift + src_y;
498 bfunc = lcd_remote_blockfuncs[drawmode];
499 mask = 0xFFu << (shift + src_y);
500 mask_bottom = 0xFFu >> (~ny & 7);
502 if (shift == 0)
504 bool copyopt = (drawmode == DRMODE_SOLID);
506 for (; ny >= 8; ny -= 8)
508 if (copyopt && (mask == 0xFFu))
509 memcpy(dst, src, width);
510 else
512 const unsigned char *src_row = src;
513 fb_remote_data *dst_row = dst;
515 dst_end = dst_row + width;
517 bfunc(dst_row++, mask, *src_row++);
518 while (dst_row < dst_end);
521 src += stride;
522 dst += LCD_REMOTE_WIDTH;
523 mask = 0xFFu;
525 mask &= mask_bottom;
527 if (copyopt && (mask == 0xFFu))
528 memcpy(dst, src, width);
529 else
531 dst_end = dst + width;
533 bfunc(dst++, mask, *src++);
534 while (dst < dst_end);
537 else
539 dst_end = dst + width;
542 const unsigned char *src_col = src++;
543 fb_remote_data *dst_col = dst++;
544 unsigned mask_col = mask;
545 unsigned data = 0;
547 for (y = ny; y >= 8; y -= 8)
549 data |= *src_col << shift;
551 if (mask_col & 0xFFu)
553 bfunc(dst_col, mask_col, data);
554 mask_col = 0xFFu;
556 else
557 mask_col >>= 8;
559 src_col += stride;
560 dst_col += LCD_REMOTE_WIDTH;
561 data >>= 8;
563 data |= *src_col << shift;
564 bfunc(dst_col, mask_col & mask_bottom, data);
566 while (dst < dst_end);
570 /* Draw a full bitmap */
571 void lcd_remote_bitmap(const unsigned char *src, int x, int y, int width,
572 int height)
574 lcd_remote_bitmap_part(src, 0, 0, width, x, y, width, height);
577 /* put a string at a given pixel position, skipping first ofs pixel columns */
578 void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str)
580 unsigned short ch;
581 unsigned short *ucs;
582 struct font* pf = font_get(curfont);
584 ucs = bidi_l2v(str, 1);
586 while ((ch = *ucs++) != 0 && x < LCD_REMOTE_WIDTH)
588 int width;
589 const unsigned char *bits;
591 /* get proportional width and glyph bits */
592 width = font_get_width(pf, ch);
594 if (ofs > width)
596 ofs -= width;
597 continue;
600 bits = font_get_bits(pf, ch);
602 lcd_remote_bitmap_part(bits, ofs, 0, width, x, y, width - ofs,
603 pf->height);
605 x += width - ofs;
606 ofs = 0;
610 /* put a string at a given pixel position */
611 void lcd_remote_putsxy(int x, int y, const unsigned char *str)
613 lcd_remote_putsxyofs(x, y, 0, str);
616 /*** line oriented text output ***/
618 /* put a string at a given char position */
619 void lcd_remote_puts(int x, int y, const unsigned char *str)
621 lcd_remote_puts_style_offset(x, y, str, STYLE_DEFAULT, 0);
624 void lcd_remote_puts_style(int x, int y, const unsigned char *str, int style)
626 lcd_remote_puts_style_offset(x, y, str, style, 0);
629 void lcd_remote_puts_offset(int x, int y, const unsigned char *str, int offset)
631 lcd_remote_puts_style_offset(x, y, str, STYLE_DEFAULT, offset);
634 /* put a string at a given char position, style, and pixel position,
635 * skipping first offset pixel columns */
636 void lcd_remote_puts_style_offset(int x, int y, const unsigned char *str,
637 int style, int offset)
639 int xpos,ypos,w,h,xrect;
640 int lastmode = drawmode;
642 /* make sure scrolling is turned off on the line we are updating */
643 lcd_remote_scroll_info.lines &= ~(1 << y);
645 if(!str || !str[0])
646 return;
648 lcd_remote_getstringsize(str, &w, &h);
649 xpos = xmargin + x*w / utf8length((char *)str);
650 ypos = ymargin + y*h;
651 drawmode = (style & STYLE_INVERT) ?
652 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
653 lcd_remote_putsxyofs(xpos, ypos, offset, str);
654 drawmode ^= DRMODE_INVERSEVID;
655 xrect = xpos + MAX(w - offset, 0);
656 lcd_remote_fillrect(xrect, ypos, LCD_REMOTE_WIDTH - xrect, h);
657 drawmode = lastmode;
660 /*** scrolling ***/
662 void lcd_remote_puts_scroll(int x, int y, const unsigned char *string)
664 lcd_remote_puts_scroll_style(x, y, string, STYLE_DEFAULT);
667 void lcd_remote_puts_scroll_style(int x, int y, const unsigned char *string, int style)
669 lcd_remote_puts_scroll_style_offset(x, y, string, style, 0);
672 void lcd_remote_puts_scroll_offset(int x, int y, const unsigned char *string, int offset)
674 lcd_remote_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset);
677 void lcd_remote_puts_scroll_style_offset(int x, int y, const unsigned char *string,
678 int style, int offset)
680 struct scrollinfo* s;
681 int w, h;
683 if(y>=LCD_REMOTE_SCROLLABLE_LINES) return;
685 s = &lcd_remote_scroll_info.scroll[y];
687 s->start_tick = current_tick + lcd_remote_scroll_info.delay;
688 s->invert = false;
689 if (style & STYLE_INVERT) {
690 s->invert = true;
691 lcd_remote_puts_style_offset(x,y,string,STYLE_INVERT,offset);
693 else
694 lcd_remote_puts_offset(x,y,string,offset);
696 lcd_remote_getstringsize(string, &w, &h);
698 if (LCD_REMOTE_WIDTH - x * 8 - xmargin < w) {
699 /* prepare scroll line */
700 char *end;
702 memset(s->line, 0, sizeof s->line);
703 strcpy(s->line, (char *)string);
705 /* get width */
706 s->width = lcd_remote_getstringsize((unsigned char *)s->line, &w, &h);
708 /* scroll bidirectional or forward only depending on the string
709 width */
710 if ( lcd_remote_scroll_info.bidir_limit ) {
711 s->bidir = s->width < (LCD_REMOTE_WIDTH - xmargin) *
712 (100 + lcd_remote_scroll_info.bidir_limit) / 100;
714 else
715 s->bidir = false;
717 if (!s->bidir) { /* add spaces if scrolling in the round */
718 strcat(s->line, " ");
719 /* get new width incl. spaces */
720 s->width = lcd_remote_getstringsize((unsigned char *)s->line, &w, &h);
723 end = strchr(s->line, '\0');
724 strncpy(end, (char *)string, LCD_REMOTE_WIDTH/2);
726 s->len = utf8length((char *)string);
727 s->offset = offset;
728 s->startx = xmargin + x * s->width / s->len;;
729 s->backward = false;
730 lcd_remote_scroll_info.lines |= (1<<y);
732 else
733 /* force a bit switch-off since it doesn't scroll */
734 lcd_remote_scroll_info.lines &= ~(1<<y);
737 void lcd_remote_scroll_fn(void)
739 struct font* pf;
740 struct scrollinfo* s;
741 int index;
742 int xpos, ypos;
743 int lastmode;
745 for ( index = 0; index < LCD_REMOTE_SCROLLABLE_LINES; index++ ) {
746 /* really scroll? */
747 if ((lcd_remote_scroll_info.lines & (1 << index)) == 0)
748 continue;
750 s = &lcd_remote_scroll_info.scroll[index];
752 /* check pause */
753 if (TIME_BEFORE(current_tick, s->start_tick))
754 continue;
756 if (s->backward)
757 s->offset -= lcd_remote_scroll_info.step;
758 else
759 s->offset += lcd_remote_scroll_info.step;
761 pf = font_get(curfont);
762 xpos = s->startx;
763 ypos = ymargin + index * pf->height;
765 if (s->bidir) { /* scroll bidirectional */
766 if (s->offset <= 0) {
767 /* at beginning of line */
768 s->offset = 0;
769 s->backward = false;
770 s->start_tick = current_tick + lcd_remote_scroll_info.delay*2;
772 if (s->offset >= s->width - (LCD_REMOTE_WIDTH - xpos)) {
773 /* at end of line */
774 s->offset = s->width - (LCD_REMOTE_WIDTH - xpos);
775 s->backward = true;
776 s->start_tick = current_tick + lcd_remote_scroll_info.delay*2;
779 else {
780 /* scroll forward the whole time */
781 if (s->offset >= s->width)
782 s->offset %= s->width;
785 lastmode = drawmode;
786 drawmode = s->invert ?
787 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
788 lcd_remote_putsxyofs(xpos, ypos, s->offset, s->line);
789 drawmode = lastmode;
790 lcd_remote_update_rect(xpos, ypos, LCD_REMOTE_WIDTH - xpos, pf->height);
794 /* LCD init */
795 void lcd_remote_init(void)
797 #ifndef SIMULATOR
798 /* Call device specific init */
799 lcd_remote_init_device();
800 #endif