1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2006 Jens Arnold
12 * Rockbox driver for 2bit vertically interleaved remote LCDs
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
24 #include "lcd-remote.h"
34 #include "rbunicode.h"
36 #include "lcd-remote-target.h"
37 #include "scroll_engine.h"
41 fb_remote_data lcd_remote_framebuffer
[LCD_REMOTE_FBHEIGHT
][LCD_REMOTE_FBWIDTH
]
44 static const fb_remote_data patterns
[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000};
46 static fb_remote_data
* remote_backdrop
= NULL
;
47 static long remote_backdrop_offset IDATA_ATTR
= 0;
49 static struct viewport default_vp
=
53 .width
= LCD_REMOTE_WIDTH
,
54 .height
= LCD_REMOTE_HEIGHT
,
55 .font
= FONT_SYSFIXED
,
56 .drawmode
= DRMODE_SOLID
,
59 .fg_pattern
= LCD_REMOTE_DEFAULT_FG
,
60 .bg_pattern
= LCD_REMOTE_DEFAULT_BG
63 static unsigned fg_pattern IBSS_ATTR
;
64 static unsigned bg_pattern IBSS_ATTR
;
66 static struct viewport
* current_vp IBSS_ATTR
;;
70 void lcd_remote_set_viewport(struct viewport
* vp
)
73 current_vp
= &default_vp
;
77 fg_pattern
= patterns
[current_vp
->fg_pattern
& 3];
78 bg_pattern
= patterns
[current_vp
->bg_pattern
& 3];
81 void lcd_remote_update_viewport(void)
83 lcd_remote_update_rect(current_vp
->x
, current_vp
->y
,
84 current_vp
->width
, current_vp
->height
);
87 void lcd_remote_update_viewport_rect(int x
, int y
, int width
, int height
)
89 lcd_remote_update_rect(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
92 /*** parameter handling ***/
93 unsigned lcd_remote_color_to_native(unsigned color
)
95 unsigned r
= (color
& 0xf800) >> 10;
96 unsigned g
= (color
& 0x07e0) >> 5;
97 unsigned b
= (color
& 0x001f) << 2;
100 * |Y'| = |0.299000 0.587000 0.114000| |G|
103 return (5*r
+ 9*g
+ b
) >> 8;
106 void lcd_remote_set_drawmode(int mode
)
108 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
111 int lcd_remote_get_drawmode(void)
113 return current_vp
->drawmode
;
116 void lcd_remote_set_foreground(unsigned brightness
)
118 current_vp
->fg_pattern
= brightness
;
119 fg_pattern
= patterns
[brightness
& 3];
122 unsigned lcd_remote_get_foreground(void)
124 return current_vp
->fg_pattern
;
127 void lcd_remote_set_background(unsigned brightness
)
129 current_vp
->bg_pattern
= brightness
;
130 bg_pattern
= patterns
[brightness
& 3];
133 unsigned lcd_remote_get_background(void)
135 return current_vp
->bg_pattern
;
138 void lcd_remote_set_drawinfo(int mode
, unsigned fg_brightness
,
139 unsigned bg_brightness
)
141 lcd_remote_set_drawmode(mode
);
142 lcd_remote_set_foreground(fg_brightness
);
143 lcd_remote_set_background(bg_brightness
);
146 int lcd_remote_getwidth(void)
148 return current_vp
->width
;
151 int lcd_remote_getheight(void)
153 return current_vp
->height
;
156 void lcd_remote_setmargins(int x
, int y
)
158 current_vp
->xmargin
= x
;
159 current_vp
->ymargin
= y
;
162 int lcd_remote_getxmargin(void)
164 return current_vp
->xmargin
;
167 int lcd_remote_getymargin(void)
169 return current_vp
->ymargin
;
172 void lcd_remote_setfont(int newfont
)
174 current_vp
->font
= newfont
;
177 int lcd_remote_getfont(void)
179 return current_vp
->font
;
182 int lcd_remote_getstringsize(const unsigned char *str
, int *w
, int *h
)
184 return font_getstringsize(str
, w
, h
, current_vp
->font
);
187 /*** low-level drawing functions ***/
189 static void setpixel(int x
, int y
)
191 unsigned mask
= 0x0101 << (y
& 7);
192 fb_remote_data
*address
= &lcd_remote_framebuffer
[y
>>3][x
];
193 unsigned data
= *address
;
195 *address
= data
^ ((data
^ fg_pattern
) & mask
);
198 static void clearpixel(int x
, int y
)
200 unsigned mask
= 0x0101 << (y
& 7);
201 fb_remote_data
*address
= &lcd_remote_framebuffer
[y
>>3][x
];
202 unsigned data
= *address
;
204 *address
= data
^ ((data
^ bg_pattern
) & mask
);
207 static void clearimgpixel(int x
, int y
)
209 unsigned mask
= 0x0101 << (y
& 7);
210 fb_remote_data
*address
= &lcd_remote_framebuffer
[y
>>3][x
];
211 unsigned data
= *address
;
213 *address
= data
^ ((data
^ *(fb_remote_data
*)((long)address
214 + remote_backdrop_offset
)) & mask
);
217 static void flippixel(int x
, int y
)
219 unsigned mask
= 0x0101 << (y
& 7);
220 fb_remote_data
*address
= &lcd_remote_framebuffer
[y
>>3][x
];
225 static void nopixel(int x
, int y
)
231 lcd_remote_pixelfunc_type
* const lcd_remote_pixelfuncs_bgcolor
[8] = {
232 flippixel
, nopixel
, setpixel
, setpixel
,
233 nopixel
, clearpixel
, nopixel
, clearpixel
236 lcd_remote_pixelfunc_type
* const lcd_remote_pixelfuncs_backdrop
[8] = {
237 flippixel
, nopixel
, setpixel
, setpixel
,
238 nopixel
, clearimgpixel
, nopixel
, clearimgpixel
241 lcd_remote_pixelfunc_type
* const *lcd_remote_pixelfuncs
= lcd_remote_pixelfuncs_bgcolor
;
243 /* 'mask' and 'bits' contain 2 bits per pixel */
244 static void flipblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
246 static void flipblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
248 *address
^= bits
& mask
;
251 static void bgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
253 static void bgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
255 unsigned data
= *address
;
257 *address
= data
^ ((data
^ bg_pattern
) & mask
& ~bits
);
260 static void bgimgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
262 static void bgimgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
264 unsigned data
= *address
;
266 *address
= data
^ ((data
^ *(fb_remote_data
*)((long)address
267 + remote_backdrop_offset
)) & mask
& ~bits
);
270 static void fgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
272 static void fgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
274 unsigned data
= *address
;
276 *address
= data
^ ((data
^ fg_pattern
) & mask
& bits
);
279 static void solidblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
281 static void solidblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
283 unsigned data
= *address
;
284 unsigned bgp
= bg_pattern
;
286 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
287 *address
= data
^ ((data
^ bits
) & mask
);
290 static void solidimgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
292 static void solidimgblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
294 unsigned data
= *address
;
295 unsigned bgp
= *(fb_remote_data
*)((long)address
+ remote_backdrop_offset
);
297 bits
= bgp
^ ((bgp
^ fg_pattern
) & bits
);
298 *address
= data
^ ((data
^ bits
) & mask
);
301 static void flipinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
303 static void flipinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
305 *address
^= ~bits
& mask
;
308 static void bginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
310 static void bginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
312 unsigned data
= *address
;
314 *address
= data
^ ((data
^ bg_pattern
) & mask
& bits
);
317 static void bgimginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
319 static void bgimginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
321 unsigned data
= *address
;
323 *address
= data
^ ((data
^ *(fb_remote_data
*)((long)address
324 + remote_backdrop_offset
)) & mask
& bits
);
327 static void fginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
329 static void fginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
331 unsigned data
= *address
;
333 *address
= data
^ ((data
^ fg_pattern
) & mask
& ~bits
);
336 static void solidinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
338 static void solidinvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
340 unsigned data
= *address
;
341 unsigned fgp
= fg_pattern
;
343 bits
= fgp
^ ((fgp
^ bg_pattern
) & bits
);
344 *address
= data
^ ((data
^ bits
) & mask
);
347 static void solidimginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
349 static void solidimginvblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
351 unsigned data
= *address
;
352 unsigned fgp
= fg_pattern
;
354 bits
= fgp
^ ((fgp
^ *(fb_remote_data
*)((long)address
355 + remote_backdrop_offset
)) & bits
);
356 *address
= data
^ ((data
^ bits
) & mask
);
359 lcd_remote_blockfunc_type
* const lcd_remote_blockfuncs_bgcolor
[8] = {
360 flipblock
, bgblock
, fgblock
, solidblock
,
361 flipinvblock
, bginvblock
, fginvblock
, solidinvblock
364 lcd_remote_blockfunc_type
* const lcd_remote_blockfuncs_backdrop
[8] = {
365 flipblock
, bgimgblock
, fgblock
, solidimgblock
,
366 flipinvblock
, bgimginvblock
, fginvblock
, solidimginvblock
369 lcd_remote_blockfunc_type
* const *lcd_remote_blockfuncs
= lcd_remote_blockfuncs_bgcolor
;
372 void lcd_remote_set_backdrop(fb_remote_data
* backdrop
)
374 remote_backdrop
= backdrop
;
377 remote_backdrop_offset
= (long)backdrop
- (long)lcd_remote_framebuffer
;
378 lcd_remote_pixelfuncs
= lcd_remote_pixelfuncs_backdrop
;
379 lcd_remote_blockfuncs
= lcd_remote_blockfuncs_backdrop
;
383 remote_backdrop_offset
= 0;
384 lcd_remote_pixelfuncs
= lcd_remote_pixelfuncs_bgcolor
;
385 lcd_remote_blockfuncs
= lcd_remote_blockfuncs_bgcolor
;
389 fb_remote_data
* lcd_remote_get_backdrop(void)
391 return remote_backdrop
;
394 static inline void setblock(fb_remote_data
*address
, unsigned mask
, unsigned bits
)
396 unsigned data
= *address
;
399 *address
= data
^ (bits
& mask
);
402 /*** drawing functions ***/
404 /* Clear the whole display */
405 void lcd_remote_clear_display(void)
407 if (default_vp
.drawmode
& DRMODE_INVERSEVID
)
409 memset(lcd_remote_framebuffer
, patterns
[default_vp
.fg_pattern
& 3],
410 sizeof lcd_remote_framebuffer
);
415 memcpy(lcd_remote_framebuffer
, remote_backdrop
,
416 sizeof lcd_remote_framebuffer
);
418 memset(lcd_remote_framebuffer
, patterns
[default_vp
.bg_pattern
& 3],
419 sizeof lcd_remote_framebuffer
);
422 lcd_remote_scroll_info
.lines
= 0;
425 /* Clear the current viewport */
426 void lcd_remote_clear_viewport(void)
430 if (current_vp
== &default_vp
)
432 lcd_remote_clear_display();
436 lastmode
= current_vp
->drawmode
;
438 /* Invert the INVERSEVID bit and set basic mode to SOLID */
439 current_vp
->drawmode
= (~lastmode
& DRMODE_INVERSEVID
) |
442 lcd_remote_fillrect(0, 0, current_vp
->width
, current_vp
->height
);
444 current_vp
->drawmode
= lastmode
;
446 lcd_remote_scroll_stop(current_vp
);
450 /* Set a single pixel */
451 void lcd_remote_drawpixel(int x
, int y
)
453 if (((unsigned)x
< (unsigned)current_vp
->width
) &&
454 ((unsigned)y
< (unsigned)current_vp
->height
))
455 lcd_remote_pixelfuncs
[current_vp
->drawmode
](current_vp
->x
+x
, current_vp
->y
+y
);
459 void lcd_remote_drawline(int x1
, int y1
, int x2
, int y2
)
467 lcd_remote_pixelfunc_type
*pfunc
= lcd_remote_pixelfuncs
[current_vp
->drawmode
];
469 deltax
= abs(x2
- x1
);
470 deltay
= abs(y2
- y1
);
474 if (deltax
>= deltay
)
477 d
= 2 * deltay
- deltax
;
479 dinc2
= (deltay
- deltax
) * 2;
486 d
= 2 * deltax
- deltay
;
488 dinc2
= (deltax
- deltay
) * 2;
492 numpixels
++; /* include endpoints */
509 for (i
= 0; i
< numpixels
; i
++)
511 if (((unsigned)x
< (unsigned)current_vp
->width
) &&
512 ((unsigned)y
< (unsigned)current_vp
->height
))
513 pfunc(current_vp
->x
+ x
, current_vp
->y
+ y
);
530 /* Draw a horizontal line (optimised) */
531 void lcd_remote_hline(int x1
, int x2
, int y
)
535 fb_remote_data
*dst
, *dst_end
;
537 lcd_remote_blockfunc_type
*bfunc
;
547 /* nothing to draw? */
548 if (((unsigned)y
>= (unsigned)current_vp
->height
) || (x1
>= current_vp
->width
)
555 if (x2
>= current_vp
->width
)
556 x2
= current_vp
->width
-1;
560 /* adjust x1 and y to viewport */
564 bfunc
= lcd_remote_blockfuncs
[current_vp
->drawmode
];
565 dst
= &lcd_remote_framebuffer
[y
>>3][x1
];
566 mask
= 0x0101 << (y
& 7);
568 dst_end
= dst
+ width
;
570 bfunc(dst
++, mask
, 0xFFFFu
);
571 while (dst
< dst_end
);
574 /* Draw a vertical line (optimised) */
575 void lcd_remote_vline(int x
, int y1
, int y2
)
579 unsigned mask
, mask_bottom
;
580 lcd_remote_blockfunc_type
*bfunc
;
590 /* nothing to draw? */
591 if (((unsigned)x
>= (unsigned)current_vp
->width
) || (y1
>= current_vp
->height
)
598 if (y2
>= current_vp
->height
)
599 y2
= current_vp
->height
-1;
601 /* adjust for viewport */
606 bfunc
= lcd_remote_blockfuncs
[current_vp
->drawmode
];
607 dst
= &lcd_remote_framebuffer
[y1
>>3][x
];
609 mask
= (0xFFu
<< (y1
& 7)) & 0xFFu
;
611 mask_bottom
= 0xFFu
>> (~ny
& 7);
612 mask_bottom
|= mask_bottom
<< 8;
614 for (; ny
>= 8; ny
-= 8)
616 bfunc(dst
, mask
, 0xFFFFu
);
617 dst
+= LCD_REMOTE_WIDTH
;
621 bfunc(dst
, mask
, 0xFFFFu
);
624 /* Draw a rectangular box */
625 void lcd_remote_drawrect(int x
, int y
, int width
, int height
)
627 if ((width
<= 0) || (height
<= 0))
630 int x2
= x
+ width
- 1;
631 int y2
= y
+ height
- 1;
633 lcd_remote_vline(x
, y
, y2
);
634 lcd_remote_vline(x2
, y
, y2
);
635 lcd_remote_hline(x
, x2
, y
);
636 lcd_remote_hline(x
, x2
, y2
);
639 /* Fill a rectangular area */
640 void lcd_remote_fillrect(int x
, int y
, int width
, int height
)
643 fb_remote_data
*dst
, *dst_end
;
644 unsigned mask
, mask_bottom
;
646 lcd_remote_blockfunc_type
*bfunc
;
647 bool fillopt
= false;
649 /* nothing to draw? */
650 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
651 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
665 if (x
+ width
> current_vp
->width
)
666 width
= current_vp
->width
- x
;
667 if (y
+ height
> current_vp
->height
)
668 height
= current_vp
->height
- y
;
670 /* adjust for viewport */
674 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
676 if ((current_vp
->drawmode
& DRMODE_BG
) && !remote_backdrop
)
684 if (current_vp
->drawmode
& DRMODE_FG
)
690 bfunc
= lcd_remote_blockfuncs
[current_vp
->drawmode
];
691 dst
= &lcd_remote_framebuffer
[y
>>3][x
];
692 ny
= height
- 1 + (y
& 7);
693 mask
= (0xFFu
<< (y
& 7)) & 0xFFu
;
695 mask_bottom
= 0xFFu
>> (~ny
& 7);
696 mask_bottom
|= mask_bottom
<< 8;
698 for (; ny
>= 8; ny
-= 8)
700 if (fillopt
&& (mask
== 0xFFFFu
))
701 memset16(dst
, bits
, width
);
704 fb_remote_data
*dst_row
= dst
;
706 dst_end
= dst_row
+ width
;
708 bfunc(dst_row
++, mask
, 0xFFFFu
);
709 while (dst_row
< dst_end
);
712 dst
+= LCD_REMOTE_WIDTH
;
717 if (fillopt
&& (mask
== 0xFFFFu
))
718 memset16(dst
, bits
, width
);
721 dst_end
= dst
+ width
;
723 bfunc(dst
++, mask
, 0xFFFFu
);
724 while (dst
< dst_end
);
728 /* About Rockbox' internal monochrome bitmap format:
730 * A bitmap contains one bit for every pixel that defines if that pixel is
731 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
733 * The bytes are stored in row-major order, with byte 0 being top left,
734 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
735 * 0..7, the second row defines pixel row 8..15 etc.
737 * This is similar to the internal lcd hw format. */
739 /* Draw a partial monochrome bitmap */
740 void lcd_remote_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
741 int stride
, int x
, int y
, int width
, int height
)
743 void lcd_remote_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
744 int stride
, int x
, int y
, int width
, int height
)
747 fb_remote_data
*dst
, *dst_end
;
748 unsigned data
, mask
, mask_bottom
;
749 lcd_remote_blockfunc_type
*bfunc
;
751 /* nothing to draw? */
752 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
) ||
753 (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
769 if (x
+ width
> current_vp
->width
)
770 width
= current_vp
->width
- x
;
771 if (y
+ height
> current_vp
->height
)
772 height
= current_vp
->height
- y
;
774 /* adjust for viewport */
778 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
781 dst
= &lcd_remote_framebuffer
[y
>>3][x
];
783 ny
= height
- 1 + shift
+ src_y
;
785 bfunc
= lcd_remote_blockfuncs
[current_vp
->drawmode
];
786 mask
= 0xFFu
<< (shift
+ src_y
);
787 /* not byte-doubled here because shift+src_y can be > 7 */
788 mask_bottom
= 0xFFu
>> (~ny
& 7);
789 mask_bottom
|= mask_bottom
<< 8;
796 for (; ny
>= 8; ny
-= 8)
798 const unsigned char *src_row
= src
;
799 fb_remote_data
*dst_row
= dst
;
801 dst_end
= dst_row
+ width
;
805 bfunc(dst_row
++, mask
, data
| (data
<< 8));
807 while (dst_row
< dst_end
);
810 dst
+= LCD_REMOTE_WIDTH
;
815 dst_end
= dst
+ width
;
819 bfunc(dst
++, mask
, data
| (data
<< 8));
821 while (dst
< dst_end
);
827 dst_end
= dst
+ width
;
830 const unsigned char *src_col
= src
++;
831 fb_remote_data
*dst_col
= dst
++;
832 unsigned mask_col
= mask
& 0xFFu
;
834 mask_col
|= mask_col
<< 8;
837 for (y
= ny
; y
>= 8; y
-= 8)
839 data
|= *src_col
<< shift
;
843 ddata
= data
& 0xFFu
;
844 bfunc(dst_col
, mask_col
, ddata
| (ddata
<< 8));
849 mask_col
= (mask
>> 8) & 0xFFu
;
850 mask_col
|= mask_col
<< 8;
854 dst_col
+= LCD_REMOTE_WIDTH
;
857 data
|= *src_col
<< shift
;
858 mask_col
&= mask_bottom
;
859 ddata
= data
& 0xFFu
;
860 bfunc(dst_col
, mask_col
, ddata
| (ddata
<< 8));
862 while (dst
< dst_end
);
866 /* Draw a full monochrome bitmap */
867 void lcd_remote_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
,
870 lcd_remote_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
873 /* About Rockbox' internal native bitmap format:
875 * A bitmap contains one bit in each byte of a pair of bytes for every pixel.
876 * 00 = white, 01 = light grey, 10 = dark grey, 11 = black. Bits within a byte
877 * are arranged vertically, LSB at top.
878 * The pairs of bytes are stored as shorts, in row-major order, with word 0
879 * being top left, word 1 2nd from left etc. The first row of words defines
880 * pixel rows 0..7, the second row defines pixel row 8..15 etc.
882 * This is the same as the internal lcd hw format. */
884 /* Draw a partial native bitmap */
885 void lcd_remote_bitmap_part(const fb_remote_data
*src
, int src_x
, int src_y
,
886 int stride
, int x
, int y
, int width
, int height
)
888 void lcd_remote_bitmap_part(const fb_remote_data
*src
, int src_x
, int src_y
,
889 int stride
, int x
, int y
, int width
, int height
)
892 fb_remote_data
*dst
, *dst_end
;
893 unsigned mask
, mask_bottom
;
895 /* nothing to draw? */
896 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
897 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
913 if (x
+ width
> current_vp
->width
)
914 width
= current_vp
->width
- x
;
915 if (y
+ height
> current_vp
->height
)
916 height
= current_vp
->height
- y
;
918 /* adjust for viewport */
922 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
925 dst
= &lcd_remote_framebuffer
[y
>>3][x
];
927 ny
= height
- 1 + shift
+ src_y
;
929 mask
= 0xFFu
<< (shift
+ src_y
);
930 /* not byte-doubled here because shift+src_y can be > 7 */
931 mask_bottom
= 0xFFu
>> (~ny
& 7);
932 mask_bottom
|= mask_bottom
<< 8;
939 for (; ny
>= 8; ny
-= 8)
942 memcpy(dst
, src
, width
* sizeof(fb_remote_data
));
945 const fb_remote_data
*src_row
= src
;
946 fb_remote_data
*dst_row
= dst
;
948 dst_end
= dst_row
+ width
;
950 setblock(dst_row
++, mask
, *src_row
++);
951 while (dst_row
< dst_end
);
954 dst
+= LCD_REMOTE_WIDTH
;
960 memcpy(dst
, src
, width
* sizeof(fb_remote_data
));
963 dst_end
= dst
+ width
;
965 setblock(dst
++, mask
, *src
++);
966 while (dst
< dst_end
);
971 unsigned datamask
= (0xFFu
<< shift
) & 0xFFu
;
973 datamask
|= datamask
<< 8;
975 dst_end
= dst
+ width
;
978 const fb_remote_data
*src_col
= src
++;
979 fb_remote_data
*dst_col
= dst
++;
980 unsigned mask_col
= mask
& 0xFFu
;
981 unsigned data
, olddata
= 0;
983 mask_col
|= mask_col
<< 8;
985 for (y
= ny
; y
>= 8; y
-= 8)
987 data
= *src_col
<< shift
;
991 setblock(dst_col
, mask_col
,
992 olddata
^((olddata
^ data
) & datamask
));
997 mask_col
= (mask
<< 8) & 0xFFu
;
998 mask_col
|= mask_col
<< 8;
1001 dst_col
+= LCD_REMOTE_WIDTH
;
1002 olddata
= data
>> 8;
1004 data
= *src_col
<< shift
;
1005 setblock(dst_col
, mask_col
& mask_bottom
,
1006 olddata
^((olddata
^ data
) & datamask
));
1008 while (dst
< dst_end
);
1012 /* Draw a full native bitmap */
1013 void lcd_remote_bitmap(const fb_remote_data
*src
, int x
, int y
, int width
,
1016 lcd_remote_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
1019 /* put a string at a given pixel position, skipping first ofs pixel columns */
1020 void lcd_remote_putsxyofs(int x
, int y
, int ofs
, const unsigned char *str
)
1023 unsigned short *ucs
;
1024 struct font
* pf
= font_get(current_vp
->font
);
1026 ucs
= bidi_l2v(str
, 1);
1028 while ((ch
= *ucs
++) != 0 && x
< current_vp
->width
)
1031 const unsigned char *bits
;
1033 /* get proportional width and glyph bits */
1034 width
= font_get_width(pf
, ch
);
1042 bits
= font_get_bits(pf
, ch
);
1044 lcd_remote_mono_bitmap_part(bits
, ofs
, 0, width
, x
, y
, width
- ofs
,
1052 /* put a string at a given pixel position */
1053 void lcd_remote_putsxy(int x
, int y
, const unsigned char *str
)
1055 lcd_remote_putsxyofs(x
, y
, 0, str
);
1058 /*** line oriented text output ***/
1060 /* put a string at a given char position */
1061 void lcd_remote_puts(int x
, int y
, const unsigned char *str
)
1063 lcd_remote_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, 0);
1066 void lcd_remote_puts_style(int x
, int y
, const unsigned char *str
, int style
)
1068 lcd_remote_puts_style_offset(x
, y
, str
, style
, 0);
1071 void lcd_remote_puts_offset(int x
, int y
, const unsigned char *str
, int offset
)
1073 lcd_remote_puts_style_offset(x
, y
, str
, STYLE_DEFAULT
, offset
);
1076 /* put a string at a given char position, style, and pixel position,
1077 * skipping first offset pixel columns */
1078 void lcd_remote_puts_style_offset(int x
, int y
, const unsigned char *str
,
1079 int style
, int offset
)
1081 int xpos
,ypos
,w
,h
,xrect
;
1082 int lastmode
= current_vp
->drawmode
;
1084 /* make sure scrolling is turned off on the line we are updating */
1085 lcd_remote_scroll_stop_line(current_vp
, y
);
1090 lcd_remote_getstringsize(str
, &w
, &h
);
1091 xpos
= current_vp
->xmargin
+ x
*w
/ utf8length((char *)str
);
1092 ypos
= current_vp
->ymargin
+ y
*h
;
1093 current_vp
->drawmode
= (style
& STYLE_INVERT
) ?
1094 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1095 lcd_remote_putsxyofs(xpos
, ypos
, offset
, str
);
1096 current_vp
->drawmode
^= DRMODE_INVERSEVID
;
1097 xrect
= xpos
+ MAX(w
- offset
, 0);
1098 lcd_remote_fillrect(xrect
, ypos
, current_vp
->width
- xrect
, h
);
1099 current_vp
->drawmode
= lastmode
;
1103 void lcd_remote_puts_scroll(int x
, int y
, const unsigned char *string
)
1105 lcd_remote_puts_scroll_style(x
, y
, string
, STYLE_DEFAULT
);
1108 void lcd_remote_puts_scroll_style(int x
, int y
, const unsigned char *string
, int style
)
1110 lcd_remote_puts_scroll_style_offset(x
, y
, string
, style
, 0);
1113 void lcd_remote_puts_scroll_offset(int x
, int y
, const unsigned char *string
, int offset
)
1115 lcd_remote_puts_scroll_style_offset(x
, y
, string
, STYLE_DEFAULT
, offset
);
1118 void lcd_remote_puts_scroll_style_offset(int x
, int y
, const unsigned char *string
,
1119 int style
, int offset
)
1121 struct scrollinfo
* s
;
1124 if ((unsigned)y
>= (unsigned)current_vp
->height
)
1127 /* remove any previously scrolling line at the same location */
1128 lcd_remote_scroll_stop_line(current_vp
, y
);
1130 if (lcd_remote_scroll_info
.lines
>= LCD_REMOTE_SCROLLABLE_LINES
) return;
1132 s
= &lcd_remote_scroll_info
.scroll
[lcd_remote_scroll_info
.lines
];
1134 s
->start_tick
= current_tick
+ lcd_remote_scroll_info
.delay
;
1136 if (style
& STYLE_INVERT
) {
1137 lcd_remote_puts_style_offset(x
,y
,string
,STYLE_INVERT
,offset
);
1140 lcd_remote_puts_offset(x
,y
,string
,offset
);
1142 lcd_remote_getstringsize(string
, &w
, &h
);
1144 if (current_vp
->width
- x
* 8 - current_vp
->xmargin
< w
) {
1145 /* prepare scroll line */
1148 memset(s
->line
, 0, sizeof s
->line
);
1149 strcpy(s
->line
, (char *)string
);
1152 s
->width
= lcd_remote_getstringsize((unsigned char *)s
->line
, &w
, &h
);
1154 /* scroll bidirectional or forward only depending on the string
1156 if ( lcd_remote_scroll_info
.bidir_limit
) {
1157 s
->bidir
= s
->width
< (current_vp
->width
- current_vp
->xmargin
) *
1158 (100 + lcd_remote_scroll_info
.bidir_limit
) / 100;
1163 if (!s
->bidir
) { /* add spaces if scrolling in the round */
1164 strcat(s
->line
, " ");
1165 /* get new width incl. spaces */
1166 s
->width
= lcd_remote_getstringsize((unsigned char *)s
->line
, &w
, &h
);
1169 end
= strchr(s
->line
, '\0');
1170 strncpy(end
, (char *)string
, current_vp
->width
/2);
1174 s
->len
= utf8length((char *)string
);
1176 s
->startx
= current_vp
->xmargin
+ x
* s
->width
/ s
->len
;
1177 s
->backward
= false;
1179 lcd_remote_scroll_info
.lines
++;
1183 void lcd_remote_scroll_fn(void)
1186 struct scrollinfo
* s
;
1190 struct viewport
* old_vp
= current_vp
;
1192 for ( index
= 0; index
< lcd_remote_scroll_info
.lines
; index
++ ) {
1193 s
= &lcd_remote_scroll_info
.scroll
[index
];
1196 if (TIME_BEFORE(current_tick
, s
->start_tick
))
1199 lcd_remote_set_viewport(s
->vp
);
1202 s
->offset
-= lcd_remote_scroll_info
.step
;
1204 s
->offset
+= lcd_remote_scroll_info
.step
;
1206 pf
= font_get(current_vp
->font
);
1208 ypos
= current_vp
->ymargin
+ s
->y
* pf
->height
;
1210 if (s
->bidir
) { /* scroll bidirectional */
1211 if (s
->offset
<= 0) {
1212 /* at beginning of line */
1214 s
->backward
= false;
1215 s
->start_tick
= current_tick
+ lcd_remote_scroll_info
.delay
*2;
1217 if (s
->offset
>= s
->width
- (current_vp
->width
- xpos
)) {
1218 /* at end of line */
1219 s
->offset
= s
->width
- (current_vp
->width
- xpos
);
1221 s
->start_tick
= current_tick
+ lcd_remote_scroll_info
.delay
*2;
1225 /* scroll forward the whole time */
1226 if (s
->offset
>= s
->width
)
1227 s
->offset
%= s
->width
;
1230 lastmode
= current_vp
->drawmode
;
1231 current_vp
->drawmode
= (s
->style
&STYLE_INVERT
) ?
1232 (DRMODE_SOLID
|DRMODE_INVERSEVID
) : DRMODE_SOLID
;
1233 lcd_remote_putsxyofs(xpos
, ypos
, s
->offset
, s
->line
);
1234 current_vp
->drawmode
= lastmode
;
1235 lcd_remote_update_viewport_rect(xpos
, ypos
,
1236 current_vp
->width
- xpos
, pf
->height
);
1239 lcd_remote_set_viewport(old_vp
);
1243 void lcd_remote_init(void)
1245 /* Initialise the viewport */
1246 lcd_remote_set_viewport(NULL
);
1249 /* Call device specific init */
1250 lcd_remote_init_device();