1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
23 #include "lcd-remote.h"
32 #include "rbunicode.h"
34 #include "scroll_engine.h"
38 fb_remote_data lcd_remote_framebuffer
[LCD_REMOTE_FBHEIGHT
][LCD_REMOTE_FBWIDTH
]
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)
58 void lcd_remote_setmargins(int x
, int y
)
64 int lcd_remote_getxmargin(void)
69 int lcd_remote_getymargin(void)
74 void lcd_remote_setfont(int 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
)
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
)
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
)
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
)
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
)
135 static void solidblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
137 unsigned data
= *address
;
140 *address
= data
^ (bits
& mask
);
143 static void flipinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
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
)
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
)
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
)
166 static void solidinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
168 unsigned data
= *address
;
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
);
198 void lcd_remote_drawline(int x1
, int y1
, int x2
, int y2
)
206 lcd_remote_pixelfunc_type
*pfunc
= lcd_remote_pixelfuncs
[drawmode
];
208 deltax
= abs(x2
- x1
);
209 deltay
= abs(y2
- y1
);
213 if (deltax
>= deltay
)
216 d
= 2 * deltay
- deltax
;
218 dinc2
= (deltay
- deltax
) * 2;
225 d
= 2 * deltax
- deltay
;
227 dinc2
= (deltax
- deltay
) * 2;
231 numpixels
++; /* include endpoints */
248 for (i
= 0; i
< numpixels
; i
++)
250 if (((unsigned)x
< LCD_REMOTE_WIDTH
) && ((unsigned)y
< LCD_REMOTE_HEIGHT
))
268 /* Draw a horizontal line (optimised) */
269 void lcd_remote_hline(int x1
, int x2
, int y
)
272 fb_remote_data
*dst
, *dst_end
;
274 lcd_remote_blockfunc_type
*bfunc
;
284 /* nothing to draw? */
285 if (((unsigned)y
>= LCD_REMOTE_HEIGHT
) || (x1
>= LCD_REMOTE_WIDTH
)
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
];
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
)
310 unsigned mask
, mask_bottom
;
311 lcd_remote_blockfunc_type
*bfunc
;
321 /* nothing to draw? */
322 if (((unsigned)x
>= LCD_REMOTE_WIDTH
) || (y1
>= LCD_REMOTE_HEIGHT
)
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
];
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
;
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))
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
)
367 fb_remote_data
*dst
, *dst_end
;
368 unsigned mask
, mask_bottom
;
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))
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
)
403 if (drawmode
& DRMODE_FG
)
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
);
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
;
434 if (fillopt
&& (mask
== 0xFFu
))
435 memset(dst
, bits
, width
);
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
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
)
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
)
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))
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 */
494 dst
= &lcd_remote_framebuffer
[y
>>3][x
];
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);
504 bool copyopt
= (drawmode
== DRMODE_SOLID
);
506 for (; ny
>= 8; ny
-= 8)
508 if (copyopt
&& (mask
== 0xFFu
))
509 memcpy(dst
, src
, width
);
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
);
522 dst
+= LCD_REMOTE_WIDTH
;
527 if (copyopt
&& (mask
== 0xFFu
))
528 memcpy(dst
, src
, width
);
531 dst_end
= dst
+ width
;
533 bfunc(dst
++, mask
, *src
++);
534 while (dst
< dst_end
);
539 dst_end
= dst
+ width
;
542 const unsigned char *src_col
= src
++;
543 fb_remote_data
*dst_col
= dst
++;
544 unsigned mask_col
= mask
;
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
);
560 dst_col
+= LCD_REMOTE_WIDTH
;
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
,
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
)
582 struct font
* pf
= font_get(curfont
);
584 ucs
= bidi_l2v(str
, 1);
586 while ((ch
= *ucs
++) != 0 && x
< LCD_REMOTE_WIDTH
)
589 const unsigned char *bits
;
591 /* get proportional width and glyph bits */
592 width
= font_get_width(pf
, ch
);
600 bits
= font_get_bits(pf
, ch
);
602 lcd_remote_bitmap_part(bits
, ofs
, 0, width
, x
, y
, width
- ofs
,
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
);
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
);
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
;
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
;
689 if (style
& STYLE_INVERT
) {
691 lcd_remote_puts_style_offset(x
,y
,string
,STYLE_INVERT
,offset
);
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 */
702 memset(s
->line
, 0, sizeof s
->line
);
703 strcpy(s
->line
, (char *)string
);
706 s
->width
= lcd_remote_getstringsize((unsigned char *)s
->line
, &w
, &h
);
708 /* scroll bidirectional or forward only depending on the string
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;
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
);
728 s
->startx
= xmargin
+ x
* s
->width
/ s
->len
;;
730 lcd_remote_scroll_info
.lines
|= (1<<y
);
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)
740 struct scrollinfo
* s
;
745 for ( index
= 0; index
< LCD_REMOTE_SCROLLABLE_LINES
; index
++ ) {
747 if ((lcd_remote_scroll_info
.lines
& (1 << index
)) == 0)
750 s
= &lcd_remote_scroll_info
.scroll
[index
];
753 if (TIME_BEFORE(current_tick
, s
->start_tick
))
757 s
->offset
-= lcd_remote_scroll_info
.step
;
759 s
->offset
+= lcd_remote_scroll_info
.step
;
761 pf
= font_get(curfont
);
763 ypos
= ymargin
+ index
* pf
->height
;
765 if (s
->bidir
) { /* scroll bidirectional */
766 if (s
->offset
<= 0) {
767 /* at beginning of line */
770 s
->start_tick
= current_tick
+ lcd_remote_scroll_info
.delay
*2;
772 if (s
->offset
>= s
->width
- (LCD_REMOTE_WIDTH
- xpos
)) {
774 s
->offset
= s
->width
- (LCD_REMOTE_WIDTH
- xpos
);
776 s
->start_tick
= current_tick
+ lcd_remote_scroll_info
.delay
*2;
780 /* scroll forward the whole time */
781 if (s
->offset
>= s
->width
)
782 s
->offset
%= s
->width
;
786 drawmode
= s
->invert
?
787 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
788 lcd_remote_putsxyofs(xpos
, ypos
, s
->offset
, s
->line
);
790 lcd_remote_update_rect(xpos
, ypos
, LCD_REMOTE_WIDTH
- xpos
, pf
->height
);
795 void lcd_remote_init(void)
798 /* Call device specific init */
799 lcd_remote_init_device();