1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 by Alan Korr
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 ****************************************************************************/
31 #include "rbunicode.h"
33 #include "scroll_engine.h"
35 #ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */
36 #define LCDFN(fn) lcd_ ## fn
37 #define FBFN(fn) fb_ ## fn
38 #define LCDM(ma) LCD_ ## ma
44 FBFN(data
) LCDFN(framebuffer
)[LCDM(FBHEIGHT
)][LCDM(FBWIDTH
)]
45 #if CONFIG_CPU != SH7034
50 static struct viewport default_vp
=
55 .height
= LCDM(HEIGHT
),
56 .font
= FONT_SYSFIXED
,
57 .drawmode
= DRMODE_SOLID
,
62 static struct viewport
* current_vp
= &default_vp
;
66 void LCDFN(set_viewport
)(struct viewport
* vp
)
69 current_vp
= &default_vp
;
74 void LCDFN(update_viewport
)(void)
76 LCDFN(update_rect
)(current_vp
->x
, current_vp
->y
,
77 current_vp
->width
, current_vp
->height
);
80 void LCDFN(update_viewport_rect
)(int x
, int y
, int width
, int height
)
82 LCDFN(update_rect
)(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
86 void LCDFN(init
)(void)
88 LCDFN(clear_display
)();
97 /*** parameter handling ***/
99 void LCDFN(set_drawmode
)(int mode
)
101 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
104 int LCDFN(get_drawmode
)(void)
106 return current_vp
->drawmode
;
109 void LCDFN(setmargins
)(int x
, int y
)
111 current_vp
->xmargin
= x
;
112 current_vp
->ymargin
= y
;
115 int LCDFN(getxmargin
)(void)
117 return current_vp
->xmargin
;
120 int LCDFN(getymargin
)(void)
122 return current_vp
->ymargin
;
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
] |= 1 << (y
& 7);
157 static void clearpixel(int x
, int y
)
159 LCDFN(framebuffer
)[y
>>3][x
] &= ~(1 << (y
& 7));
162 static void flippixel(int x
, int y
)
164 LCDFN(framebuffer
)[y
>>3][x
] ^= 1 << (y
& 7);
167 static void nopixel(int x
, int 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
,
181 *address
^= bits
& mask
;
184 static void ICODE_ATTR
bgblock(FBFN(data
) *address
, unsigned mask
,
187 *address
&= bits
| ~mask
;
190 static void ICODE_ATTR
fgblock(FBFN(data
) *address
, unsigned mask
,
193 *address
|= bits
& mask
;
196 static void ICODE_ATTR
solidblock(FBFN(data
) *address
, unsigned mask
,
199 unsigned data
= *(char*)address
;
202 *address
= data
^ (bits
& mask
);
205 static void ICODE_ATTR
flipinvblock(FBFN(data
) *address
, unsigned mask
,
208 *address
^= ~bits
& mask
;
211 static void ICODE_ATTR
bginvblock(FBFN(data
) *address
, unsigned mask
,
214 *address
&= ~(bits
& mask
);
217 static void ICODE_ATTR
fginvblock(FBFN(data
) *address
, unsigned mask
,
220 *address
|= ~bits
& mask
;
223 static void ICODE_ATTR
solidinvblock(FBFN(data
) *address
, unsigned mask
,
226 unsigned data
= *(char *)address
;
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)
253 if (current_vp
== &default_vp
)
255 LCDFN(clear_display
)();
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
) |
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
);
282 void LCDFN(drawline
)(int x1
, int y1
, int x2
, int y2
)
290 LCDFN(pixelfunc_type
) *pfunc
= LCDFN(pixelfuncs
)[current_vp
->drawmode
];
292 deltax
= abs(x2
- x1
);
293 deltay
= abs(y2
- y1
);
297 if (deltax
>= deltay
)
300 d
= 2 * deltay
- deltax
;
302 dinc2
= (deltay
- deltax
) * 2;
309 d
= 2 * deltax
- deltay
;
311 dinc2
= (deltax
- deltay
) * 2;
315 numpixels
++; /* include endpoints */
332 for (i
= 0; i
< numpixels
; i
++)
334 if (((unsigned)x
< (unsigned)current_vp
->width
)
335 && ((unsigned)y
< (unsigned)current_vp
->height
))
336 pfunc(current_vp
->x
+ x
, current_vp
->y
+ y
);
353 /* Draw a horizontal line (optimised) */
354 void LCDFN(hline
)(int x1
, int x2
, int y
)
357 unsigned char *dst
, *dst_end
;
359 LCDFN(blockfunc_type
) *bfunc
;
369 /* nothing to draw? */
370 if (((unsigned)y
>= (unsigned)current_vp
->height
) || (x1
>= current_vp
->width
)
377 if (x2
>= current_vp
->width
)
378 x2
= current_vp
->width
-1;
382 /* adjust to viewport */
386 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
387 dst
= &LCDFN(framebuffer
)[y
>>3][x1
];
390 dst_end
= dst
+ width
;
392 bfunc(dst
++, mask
, 0xFFu
);
393 while (dst
< dst_end
);
396 /* Draw a vertical line (optimised) */
397 void LCDFN(vline
)(int x
, int y1
, int y2
)
401 unsigned mask
, mask_bottom
;
402 LCDFN(blockfunc_type
) *bfunc
;
412 /* nothing to draw? */
413 if (((unsigned)x
>= (unsigned)current_vp
->width
) || (y1
>= current_vp
->height
)
420 if (y2
>= current_vp
->height
)
421 y2
= current_vp
->height
-1;
423 /* adjust for viewport */
428 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
429 dst
= &LCDFN(framebuffer
)[y1
>>3][x
];
431 mask
= 0xFFu
<< (y1
& 7);
432 mask_bottom
= 0xFFu
>> (~ny
& 7);
434 for (; ny
>= 8; ny
-= 8)
436 bfunc(dst
, mask
, 0xFFu
);
441 bfunc(dst
, mask
, 0xFFu
);
444 /* Draw a rectangular box */
445 void LCDFN(drawrect
)(int x
, int y
, int width
, int height
)
447 if ((width
<= 0) || (height
<= 0))
450 int x2
= x
+ width
- 1;
451 int y2
= y
+ height
- 1;
453 LCDFN(vline
)(x
, y
, y2
);
454 LCDFN(vline
)(x2
, y
, y2
);
455 LCDFN(hline
)(x
, x2
, y
);
456 LCDFN(hline
)(x
, x2
, y2
);
459 /* Fill a rectangular area */
460 void LCDFN(fillrect
)(int x
, int y
, int width
, int height
)
463 FBFN(data
) *dst
, *dst_end
;
464 unsigned mask
, mask_bottom
;
466 LCDFN(blockfunc_type
) *bfunc
;
467 bool fillopt
= false;
469 /* nothing to draw? */
470 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
471 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
485 if (x
+ width
> current_vp
->width
)
486 width
= current_vp
->width
- x
;
487 if (y
+ height
> current_vp
->height
)
488 height
= current_vp
->height
- y
;
490 /* adjust for viewport */
494 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
496 if (current_vp
->drawmode
& DRMODE_BG
)
503 if (current_vp
->drawmode
& DRMODE_FG
)
509 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
510 dst
= &LCDFN(framebuffer
)[y
>>3][x
];
511 ny
= height
- 1 + (y
& 7);
512 mask
= 0xFFu
<< (y
& 7);
513 mask_bottom
= 0xFFu
>> (~ny
& 7);
515 for (; ny
>= 8; ny
-= 8)
517 if (fillopt
&& (mask
== 0xFFu
))
518 memset(dst
, bits
, width
);
521 FBFN(data
) *dst_row
= dst
;
523 dst_end
= dst_row
+ width
;
525 bfunc(dst_row
++, mask
, 0xFFu
);
526 while (dst_row
< dst_end
);
534 if (fillopt
&& (mask
== 0xFFu
))
535 memset(dst
, bits
, width
);
538 dst_end
= dst
+ width
;
540 bfunc(dst
++, mask
, 0xFFu
);
541 while (dst
< dst_end
);
545 /* About Rockbox' internal bitmap format:
547 * A bitmap contains one bit for every pixel that defines if that pixel is
548 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
550 * The bytes are stored in row-major order, with byte 0 being top left,
551 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
552 * 0..7, the second row defines pixel row 8..15 etc.
554 * This is the same as the internal lcd hw format. */
556 /* Draw a partial bitmap */
557 void ICODE_ATTR
LCDFN(bitmap_part
)(const unsigned char *src
, int src_x
,
558 int src_y
, int stride
, int x
, int y
,
559 int width
, int height
)
562 FBFN(data
) *dst
, *dst_end
;
563 unsigned mask
, mask_bottom
;
564 LCDFN(blockfunc_type
) *bfunc
;
566 /* nothing to draw? */
567 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
568 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
584 if (x
+ width
> current_vp
->width
)
585 width
= current_vp
->width
- x
;
586 if (y
+ height
> current_vp
->height
)
587 height
= current_vp
->height
- y
;
589 /* adjust for viewport */
593 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
596 dst
= &LCDFN(framebuffer
)[y
>>3][x
];
598 ny
= height
- 1 + shift
+ src_y
;
600 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
601 mask
= 0xFFu
<< (shift
+ src_y
);
602 mask_bottom
= 0xFFu
>> (~ny
& 7);
606 bool copyopt
= (current_vp
->drawmode
== DRMODE_SOLID
);
608 for (; ny
>= 8; ny
-= 8)
610 if (copyopt
&& (mask
== 0xFFu
))
611 memcpy(dst
, src
, width
);
614 const unsigned char *src_row
= src
;
615 FBFN(data
) *dst_row
= dst
;
617 dst_end
= dst_row
+ width
;
619 bfunc(dst_row
++, mask
, *src_row
++);
620 while (dst_row
< dst_end
);
629 if (copyopt
&& (mask
== 0xFFu
))
630 memcpy(dst
, src
, width
);
633 dst_end
= dst
+ width
;
635 bfunc(dst
++, mask
, *src
++);
636 while (dst
< dst_end
);
641 dst_end
= dst
+ width
;
644 const unsigned char *src_col
= src
++;
645 FBFN(data
) *dst_col
= dst
++;
646 unsigned mask_col
= mask
;
649 for (y
= ny
; y
>= 8; y
-= 8)
651 data
|= *src_col
<< shift
;
653 if (mask_col
& 0xFFu
)
655 bfunc(dst_col
, mask_col
, data
);
662 dst_col
+= LCDM(WIDTH
);
665 data
|= *src_col
<< shift
;
666 bfunc(dst_col
, mask_col
& mask_bottom
, data
);
668 while (dst
< dst_end
);
672 /* Draw a full bitmap */
673 void LCDFN(bitmap
)(const unsigned char *src
, int x
, int y
, int width
,
676 LCDFN(bitmap_part
)(src
, 0, 0, width
, x
, y
, width
, height
);
679 /* put a string at a given pixel position, skipping first ofs pixel columns */
680 static void LCDFN(putsxyofs
)(int x
, int y
, int ofs
, const unsigned char *str
)
684 struct font
* pf
= font_get(current_vp
->font
);
686 ucs
= bidi_l2v(str
, 1);
688 while ((ch
= *ucs
++) != 0 && x
< current_vp
->width
)
691 const unsigned char *bits
;
693 /* get proportional width and glyph bits */
694 width
= font_get_width(pf
, ch
);
702 bits
= font_get_bits(pf
, ch
);
704 LCDFN(mono_bitmap_part
)(bits
, ofs
, 0, width
, x
, y
, width
- ofs
,
711 /* put a string at a given pixel position */
712 void LCDFN(putsxy
)(int x
, int y
, const unsigned char *str
)
714 LCDFN(putsxyofs
)(x
, y
, 0, str
);
717 /*** Line oriented text output ***/
719 /* put a string at a given char position */
720 void LCDFN(puts
)(int x
, int y
, const unsigned char *str
)
722 LCDFN(puts_style_offset
)(x
, y
, str
, STYLE_DEFAULT
, 0);
725 void LCDFN(puts_style
)(int x
, int y
, const unsigned char *str
, int style
)
727 LCDFN(puts_style_offset
)(x
, y
, str
, style
, 0);
730 void LCDFN(puts_offset
)(int x
, int y
, const unsigned char *str
, int offset
)
732 LCDFN(puts_style_offset
)(x
, y
, str
, STYLE_DEFAULT
, offset
);
735 /* put a string at a given char position, style, and pixel position,
736 * skipping first offset pixel columns */
737 void LCDFN(puts_style_offset
)(int x
, int y
, const unsigned char *str
,
738 int style
, int offset
)
740 int xpos
,ypos
,w
,h
,xrect
;
741 int lastmode
= current_vp
->drawmode
;
743 /* make sure scrolling is turned off on the line we are updating */
744 LCDFN(scroll_stop_line
)(current_vp
, y
);
749 LCDFN(getstringsize
)(str
, &w
, &h
);
750 xpos
= current_vp
->xmargin
+ x
*w
/ utf8length(str
);
751 ypos
= current_vp
->ymargin
+ y
*h
;
752 current_vp
->drawmode
= (style
& STYLE_INVERT
) ?
753 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
754 LCDFN(putsxyofs
)(xpos
, ypos
, offset
, str
);
755 current_vp
->drawmode
^= DRMODE_INVERSEVID
;
756 xrect
= xpos
+ MAX(w
- offset
, 0);
757 LCDFN(fillrect
)(xrect
, ypos
, current_vp
->width
- xrect
, h
);
758 current_vp
->drawmode
= lastmode
;
763 void LCDFN(puts_scroll
)(int x
, int y
, const unsigned char *string
)
765 LCDFN(puts_scroll_style
)(x
, y
, string
, STYLE_DEFAULT
);
768 void LCDFN(puts_scroll_style
)(int x
, int y
, const unsigned char *string
,
771 LCDFN(puts_scroll_style_offset
)(x
, y
, string
, style
, 0);
774 void LCDFN(puts_scroll_offset
)(int x
, int y
, const unsigned char *string
,
777 LCDFN(puts_scroll_style_offset
)(x
, y
, string
, STYLE_DEFAULT
, offset
);
780 void LCDFN(puts_scroll_style_offset
)(int x
, int y
, const unsigned char *string
,
781 int style
, int offset
)
783 struct scrollinfo
* s
;
786 if ((unsigned)y
>= (unsigned)current_vp
->height
)
789 /* remove any previously scrolling line at the same location */
790 LCDFN(scroll_stop_line
)(current_vp
, y
);
792 if (LCDFN(scroll_info
.lines
) >= LCDM(SCROLLABLE_LINES
)) return;
794 s
= &LCDFN(scroll_info
).scroll
[LCDFN(scroll_info
).lines
];
796 s
->start_tick
= current_tick
+ LCDFN(scroll_info
).delay
;
798 if (style
& STYLE_INVERT
) {
799 LCDFN(puts_style_offset
)(x
,y
,string
,STYLE_INVERT
,offset
);
802 LCDFN(puts_offset
)(x
,y
,string
,offset
);
804 LCDFN(getstringsize
)(string
, &w
, &h
);
806 if (current_vp
->width
- x
* 8 - current_vp
->xmargin
< w
) {
807 /* prepare scroll line */
810 memset(s
->line
, 0, sizeof s
->line
);
811 strcpy(s
->line
, string
);
814 s
->width
= LCDFN(getstringsize
)(s
->line
, &w
, &h
);
816 /* scroll bidirectional or forward only depending on the string
818 if ( LCDFN(scroll_info
).bidir_limit
) {
819 s
->bidir
= s
->width
< (current_vp
->width
- current_vp
->xmargin
) *
820 (100 + LCDFN(scroll_info
).bidir_limit
) / 100;
825 if (!s
->bidir
) { /* add spaces if scrolling in the round */
826 strcat(s
->line
, " ");
827 /* get new width incl. spaces */
828 s
->width
= LCDFN(getstringsize
)(s
->line
, &w
, &h
);
831 end
= strchr(s
->line
, '\0');
832 strncpy(end
, string
, current_vp
->width
/2);
836 s
->len
= utf8length(string
);
838 s
->startx
= current_vp
->xmargin
+ x
* s
->width
/ s
->len
;;
841 LCDFN(scroll_info
).lines
++;
845 void LCDFN(scroll_fn
)(void)
848 struct scrollinfo
* s
;
852 struct viewport
* old_vp
= current_vp
;
854 for ( index
= 0; index
< LCDFN(scroll_info
).lines
; index
++ ) {
855 s
= &LCDFN(scroll_info
).scroll
[index
];
858 if (TIME_BEFORE(current_tick
, s
->start_tick
))
861 LCDFN(set_viewport
)(s
->vp
);
864 s
->offset
-= LCDFN(scroll_info
).step
;
866 s
->offset
+= LCDFN(scroll_info
).step
;
868 pf
= font_get(current_vp
->font
);
870 ypos
= current_vp
->ymargin
+ s
->y
* pf
->height
;
872 if (s
->bidir
) { /* scroll bidirectional */
873 if (s
->offset
<= 0) {
874 /* at beginning of line */
877 s
->start_tick
= current_tick
+ LCDFN(scroll_info
).delay
* 2;
879 if (s
->offset
>= s
->width
- (current_vp
->width
- xpos
)) {
881 s
->offset
= s
->width
- (current_vp
->width
- xpos
);
883 s
->start_tick
= current_tick
+ LCDFN(scroll_info
).delay
* 2;
887 /* scroll forward the whole time */
888 if (s
->offset
>= s
->width
)
889 s
->offset
%= s
->width
;
892 lastmode
= current_vp
->drawmode
;
893 current_vp
->drawmode
= (s
->style
&STYLE_INVERT
) ?
894 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
895 LCDFN(putsxyofs
)(xpos
, ypos
, s
->offset
, s
->line
);
896 current_vp
->drawmode
= lastmode
;
897 LCDFN(update_viewport_rect
)(xpos
, ypos
, current_vp
->width
- xpos
, pf
->height
);
900 LCDFN(set_viewport
)(old_vp
);