1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 by Alan Korr
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
33 #include "rbunicode.h"
35 #include "scroll_engine.h"
37 #ifndef LCDFN /* Not compiling for remote - define macros for main LCD. */
38 #define LCDFN(fn) lcd_ ## fn
39 #define FBFN(fn) fb_ ## fn
40 #define LCDM(ma) LCD_ ## ma
41 #define LCDNAME "lcd_"
47 FBFN(data
) LCDFN(framebuffer
)[LCDM(FBHEIGHT
)][LCDM(FBWIDTH
)] IRAM_LCDFRAMEBUFFER
;
49 static struct viewport default_vp
=
54 .height
= LCDM(HEIGHT
),
55 .font
= FONT_SYSFIXED
,
56 .drawmode
= DRMODE_SOLID
,
59 static struct viewport
* current_vp
= &default_vp
;
63 void LCDFN(set_viewport
)(struct viewport
* vp
)
66 current_vp
= &default_vp
;
71 void LCDFN(update_viewport
)(void)
73 LCDFN(update_rect
)(current_vp
->x
, current_vp
->y
,
74 current_vp
->width
, current_vp
->height
);
77 void LCDFN(update_viewport_rect
)(int x
, int y
, int width
, int height
)
79 LCDFN(update_rect
)(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
83 void LCDFN(init
)(void)
85 LCDFN(clear_display
)();
95 #if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
96 static void (*lcd_activation_hook
)(void) = NULL
;
98 void lcd_activation_set_hook(void (*func
)(void))
100 lcd_activation_hook
= func
;
103 void lcd_activation_call_hook(void)
105 void (*func
)(void) = lcd_activation_hook
;
113 /*** parameter handling ***/
115 void LCDFN(set_drawmode
)(int mode
)
117 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
120 int LCDFN(get_drawmode
)(void)
122 return current_vp
->drawmode
;
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
] |= BIT_N(y
& 7);
157 static void clearpixel(int x
, int y
)
159 LCDFN(framebuffer
)[y
>>3][x
] &= ~BIT_N(y
& 7);
162 static void flippixel(int x
, int y
)
164 LCDFN(framebuffer
)[y
>>3][x
] ^= BIT_N(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
);
295 DEBUGF(LCDNAME
"drawline() called for vertical line - optimisation.\n");
296 LCDFN(vline
)(x1
, y1
, y2
);
299 deltay
= abs(y2
- y1
);
302 DEBUGF(LCDNAME
"drawline() called for horizontal line - optimisation.\n");
303 LCDFN(hline
)(x1
, x2
, y1
);
309 if (deltax
>= deltay
)
312 d
= 2 * deltay
- deltax
;
314 dinc2
= (deltay
- deltax
) * 2;
321 d
= 2 * deltax
- deltay
;
323 dinc2
= (deltax
- deltay
) * 2;
327 numpixels
++; /* include endpoints */
344 for (i
= 0; i
< numpixels
; i
++)
346 if (((unsigned)x
< (unsigned)current_vp
->width
)
347 && ((unsigned)y
< (unsigned)current_vp
->height
))
348 pfunc(current_vp
->x
+ x
, current_vp
->y
+ y
);
365 /* Draw a horizontal line (optimised) */
366 void LCDFN(hline
)(int x1
, int x2
, int y
)
369 unsigned char *dst
, *dst_end
;
371 LCDFN(blockfunc_type
) *bfunc
;
381 /* nothing to draw? */
382 if (((unsigned)y
>= (unsigned)current_vp
->height
) || (x1
>= current_vp
->width
)
389 if (x2
>= current_vp
->width
)
390 x2
= current_vp
->width
-1;
394 /* adjust to viewport */
398 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
399 dst
= &LCDFN(framebuffer
)[y
>>3][x1
];
402 dst_end
= dst
+ width
;
404 bfunc(dst
++, mask
, 0xFFu
);
405 while (dst
< dst_end
);
408 /* Draw a vertical line (optimised) */
409 void LCDFN(vline
)(int x
, int y1
, int y2
)
413 unsigned mask
, mask_bottom
;
414 LCDFN(blockfunc_type
) *bfunc
;
424 /* nothing to draw? */
425 if (((unsigned)x
>= (unsigned)current_vp
->width
) || (y1
>= current_vp
->height
)
432 if (y2
>= current_vp
->height
)
433 y2
= current_vp
->height
-1;
435 /* adjust for viewport */
440 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
441 dst
= &LCDFN(framebuffer
)[y1
>>3][x
];
443 mask
= 0xFFu
<< (y1
& 7);
444 mask_bottom
= 0xFFu
>> (~ny
& 7);
446 for (; ny
>= 8; ny
-= 8)
448 bfunc(dst
, mask
, 0xFFu
);
453 bfunc(dst
, mask
, 0xFFu
);
456 /* Draw a rectangular box */
457 void LCDFN(drawrect
)(int x
, int y
, int width
, int height
)
459 if ((width
<= 0) || (height
<= 0))
462 int x2
= x
+ width
- 1;
463 int y2
= y
+ height
- 1;
465 LCDFN(vline
)(x
, y
, y2
);
466 LCDFN(vline
)(x2
, y
, y2
);
467 LCDFN(hline
)(x
, x2
, y
);
468 LCDFN(hline
)(x
, x2
, y2
);
471 /* Fill a rectangular area */
472 void LCDFN(fillrect
)(int x
, int y
, int width
, int height
)
475 FBFN(data
) *dst
, *dst_end
;
476 unsigned mask
, mask_bottom
;
478 LCDFN(blockfunc_type
) *bfunc
;
479 bool fillopt
= false;
481 /* nothing to draw? */
482 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
483 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
497 if (x
+ width
> current_vp
->width
)
498 width
= current_vp
->width
- x
;
499 if (y
+ height
> current_vp
->height
)
500 height
= current_vp
->height
- y
;
502 /* adjust for viewport */
506 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
508 if (current_vp
->drawmode
& DRMODE_BG
)
515 if (current_vp
->drawmode
& DRMODE_FG
)
521 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
522 dst
= &LCDFN(framebuffer
)[y
>>3][x
];
523 ny
= height
- 1 + (y
& 7);
524 mask
= 0xFFu
<< (y
& 7);
525 mask_bottom
= 0xFFu
>> (~ny
& 7);
527 for (; ny
>= 8; ny
-= 8)
529 if (fillopt
&& (mask
== 0xFFu
))
530 memset(dst
, bits
, width
);
533 FBFN(data
) *dst_row
= dst
;
535 dst_end
= dst_row
+ width
;
537 bfunc(dst_row
++, mask
, 0xFFu
);
538 while (dst_row
< dst_end
);
546 if (fillopt
&& (mask
== 0xFFu
))
547 memset(dst
, bits
, width
);
550 dst_end
= dst
+ width
;
552 bfunc(dst
++, mask
, 0xFFu
);
553 while (dst
< dst_end
);
557 /* About Rockbox' internal bitmap format:
559 * A bitmap contains one bit for every pixel that defines if that pixel is
560 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
562 * The bytes are stored in row-major order, with byte 0 being top left,
563 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
564 * 0..7, the second row defines pixel row 8..15 etc.
566 * This is the same as the internal lcd hw format. */
568 /* Draw a partial bitmap */
569 void ICODE_ATTR
LCDFN(bitmap_part
)(const unsigned char *src
, int src_x
,
570 int src_y
, int stride
, int x
, int y
,
571 int width
, int height
)
574 FBFN(data
) *dst
, *dst_end
;
575 unsigned mask
, mask_bottom
;
576 LCDFN(blockfunc_type
) *bfunc
;
578 /* nothing to draw? */
579 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
580 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
596 if (x
+ width
> current_vp
->width
)
597 width
= current_vp
->width
- x
;
598 if (y
+ height
> current_vp
->height
)
599 height
= current_vp
->height
- y
;
601 /* adjust for viewport */
605 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
608 dst
= &LCDFN(framebuffer
)[y
>>3][x
];
610 ny
= height
- 1 + shift
+ src_y
;
612 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
613 mask
= 0xFFu
<< (shift
+ src_y
);
614 mask_bottom
= 0xFFu
>> (~ny
& 7);
618 bool copyopt
= (current_vp
->drawmode
== DRMODE_SOLID
);
620 for (; ny
>= 8; ny
-= 8)
622 if (copyopt
&& (mask
== 0xFFu
))
623 memcpy(dst
, src
, width
);
626 const unsigned char *src_row
= src
;
627 FBFN(data
) *dst_row
= dst
;
629 dst_end
= dst_row
+ width
;
631 bfunc(dst_row
++, mask
, *src_row
++);
632 while (dst_row
< dst_end
);
641 if (copyopt
&& (mask
== 0xFFu
))
642 memcpy(dst
, src
, width
);
645 dst_end
= dst
+ width
;
647 bfunc(dst
++, mask
, *src
++);
648 while (dst
< dst_end
);
653 dst_end
= dst
+ width
;
656 const unsigned char *src_col
= src
++;
657 FBFN(data
) *dst_col
= dst
++;
658 unsigned mask_col
= mask
;
661 for (y
= ny
; y
>= 8; y
-= 8)
663 data
|= *src_col
<< shift
;
665 if (mask_col
& 0xFFu
)
667 bfunc(dst_col
, mask_col
, data
);
674 dst_col
+= LCDM(WIDTH
);
677 data
|= *src_col
<< shift
;
678 bfunc(dst_col
, mask_col
& mask_bottom
, data
);
680 while (dst
< dst_end
);
684 /* Draw a full bitmap */
685 void LCDFN(bitmap
)(const unsigned char *src
, int x
, int y
, int width
,
688 LCDFN(bitmap_part
)(src
, 0, 0, width
, x
, y
, width
, height
);
691 #include "lcd-bitmap-common.c"