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
;
70 #if defined(SIMULATOR)
71 /* Force the viewport to be within bounds. If this happens it should
72 * be considered an error - the viewport will not draw as it might be
75 if((unsigned) current_vp
->x
> (unsigned) LCDM(WIDTH
)
76 || (unsigned) current_vp
->y
> (unsigned) LCDM(HEIGHT
)
77 || current_vp
->x
+ current_vp
->width
> LCDM(WIDTH
)
78 || current_vp
->y
+ current_vp
->height
> LCDM(HEIGHT
))
80 #if !defined(HAVE_VIEWPORT_CLIP)
85 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
86 current_vp
->x
, current_vp
->y
,
87 current_vp
->width
, current_vp
->height
);
93 void LCDFN(update_viewport
)(void)
95 LCDFN(update_rect
)(current_vp
->x
, current_vp
->y
,
96 current_vp
->width
, current_vp
->height
);
99 void LCDFN(update_viewport_rect
)(int x
, int y
, int width
, int height
)
101 LCDFN(update_rect
)(current_vp
->x
+ x
, current_vp
->y
+ y
, width
, height
);
105 void LCDFN(init
)(void)
107 LCDFN(clear_display
)();
108 LCDFN(init_device
)();
114 /*** parameter handling ***/
116 void LCDFN(set_drawmode
)(int mode
)
118 current_vp
->drawmode
= mode
& (DRMODE_SOLID
|DRMODE_INVERSEVID
);
121 int LCDFN(get_drawmode
)(void)
123 return current_vp
->drawmode
;
126 int LCDFN(getwidth
)(void)
128 return current_vp
->width
;
131 int LCDFN(getheight
)(void)
133 return current_vp
->height
;
136 void LCDFN(setfont
)(int newfont
)
138 current_vp
->font
= newfont
;
141 int LCDFN(getfont
)(void)
143 return current_vp
->font
;
146 int LCDFN(getstringsize
)(const unsigned char *str
, int *w
, int *h
)
148 return font_getstringsize(str
, w
, h
, current_vp
->font
);
151 /*** low-level drawing functions ***/
153 static void setpixel(int x
, int y
)
155 LCDFN(framebuffer
)[y
>>3][x
] |= BIT_N(y
& 7);
158 static void clearpixel(int x
, int y
)
160 LCDFN(framebuffer
)[y
>>3][x
] &= ~BIT_N(y
& 7);
163 static void flippixel(int x
, int y
)
165 LCDFN(framebuffer
)[y
>>3][x
] ^= BIT_N(y
& 7);
168 static void nopixel(int x
, int y
)
174 LCDFN(pixelfunc_type
)* const LCDFN(pixelfuncs
)[8] = {
175 flippixel
, nopixel
, setpixel
, setpixel
,
176 nopixel
, clearpixel
, nopixel
, clearpixel
179 static void ICODE_ATTR
flipblock(FBFN(data
) *address
, unsigned mask
,
182 *address
^= bits
& mask
;
185 static void ICODE_ATTR
bgblock(FBFN(data
) *address
, unsigned mask
,
188 *address
&= bits
| ~mask
;
191 static void ICODE_ATTR
fgblock(FBFN(data
) *address
, unsigned mask
,
194 *address
|= bits
& mask
;
197 static void ICODE_ATTR
solidblock(FBFN(data
) *address
, unsigned mask
,
200 unsigned data
= *(char*)address
;
203 *address
= data
^ (bits
& mask
);
206 static void ICODE_ATTR
flipinvblock(FBFN(data
) *address
, unsigned mask
,
209 *address
^= ~bits
& mask
;
212 static void ICODE_ATTR
bginvblock(FBFN(data
) *address
, unsigned mask
,
215 *address
&= ~(bits
& mask
);
218 static void ICODE_ATTR
fginvblock(FBFN(data
) *address
, unsigned mask
,
221 *address
|= ~bits
& mask
;
224 static void ICODE_ATTR
solidinvblock(FBFN(data
) *address
, unsigned mask
,
227 unsigned data
= *(char *)address
;
230 *address
= data
^ (bits
& mask
);
233 LCDFN(blockfunc_type
)* const LCDFN(blockfuncs
)[8] = {
234 flipblock
, bgblock
, fgblock
, solidblock
,
235 flipinvblock
, bginvblock
, fginvblock
, solidinvblock
238 /*** drawing functions ***/
240 /* Clear the whole display */
241 void LCDFN(clear_display
)(void)
243 unsigned bits
= (current_vp
->drawmode
& DRMODE_INVERSEVID
) ? 0xFFu
: 0;
245 memset(LCDFN(framebuffer
), bits
, sizeof LCDFN(framebuffer
));
246 LCDFN(scroll_info
).lines
= 0;
249 /* Clear the current viewport */
250 void LCDFN(clear_viewport
)(void)
254 if (current_vp
== &default_vp
)
256 LCDFN(clear_display
)();
260 oldmode
= current_vp
->drawmode
;
262 /* Invert the INVERSEVID bit and set basic mode to SOLID */
263 current_vp
->drawmode
= (~current_vp
->drawmode
& DRMODE_INVERSEVID
) |
266 LCDFN(fillrect
)(0, 0, current_vp
->width
, current_vp
->height
);
268 current_vp
->drawmode
= oldmode
;
270 LCDFN(scroll_stop
)(current_vp
);
274 /* Set a single pixel */
275 void LCDFN(drawpixel
)(int x
, int y
)
277 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
278 && ((unsigned)y
< (unsigned)current_vp
->height
)
279 #if defined(HAVE_VIEWPORT_CLIP)
280 && ((unsigned)x
< (unsigned)LCDM(WIDTH
))
281 && ((unsigned)y
< (unsigned)LCDM(HEIGHT
))
284 LCDFN(pixelfuncs
)[current_vp
->drawmode
](current_vp
->x
+ x
, current_vp
->y
+ y
);
288 void LCDFN(drawline
)(int x1
, int y1
, int x2
, int y2
)
296 LCDFN(pixelfunc_type
) *pfunc
= LCDFN(pixelfuncs
)[current_vp
->drawmode
];
298 deltax
= abs(x2
- x1
);
301 /* DEBUGF(LCDNAME "drawline() called for vertical line - optimisation.\n"); */
302 LCDFN(vline
)(x1
, y1
, y2
);
305 deltay
= abs(y2
- y1
);
308 /* DEBUGF(LCDNAME "drawline() called for horizontal line - optimisation.\n"); */
309 LCDFN(hline
)(x1
, x2
, y1
);
315 if (deltax
>= deltay
)
318 d
= 2 * deltay
- deltax
;
320 dinc2
= (deltay
- deltax
) * 2;
327 d
= 2 * deltax
- deltay
;
329 dinc2
= (deltax
- deltay
) * 2;
333 numpixels
++; /* include endpoints */
350 for (i
= 0; i
< numpixels
; i
++)
352 if ( ((unsigned)x
< (unsigned)current_vp
->width
)
353 && ((unsigned)y
< (unsigned)current_vp
->height
)
354 #if defined(HAVE_VIEWPORT_CLIP)
355 && ((unsigned)x
< (unsigned)LCDM(WIDTH
))
356 && ((unsigned)y
< (unsigned)LCDM(HEIGHT
))
359 pfunc(current_vp
->x
+ x
, current_vp
->y
+ y
);
376 /* Draw a horizontal line (optimised) */
377 void LCDFN(hline
)(int x1
, int x2
, int y
)
380 unsigned char *dst
, *dst_end
;
382 LCDFN(blockfunc_type
) *bfunc
;
392 /******************** In viewport clipping **********************/
393 /* nothing to draw? */
394 if (((unsigned)y
>= (unsigned)current_vp
->height
) || (x1
>= current_vp
->width
)
400 if (x2
>= current_vp
->width
)
401 x2
= current_vp
->width
-1;
403 /* adjust to viewport */
408 #if defined(HAVE_VIEWPORT_CLIP)
409 /********************* Viewport on screen clipping ********************/
410 /* nothing to draw? */
411 if (((unsigned)y
>= (unsigned) LCDM(HEIGHT
)) || (x1
>= LCDM(WIDTH
))
418 if (x2
>= LCDM(WIDTH
))
424 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
425 dst
= &LCDFN(framebuffer
)[y
>>3][x1
];
428 dst_end
= dst
+ width
;
430 bfunc(dst
++, mask
, 0xFFu
);
431 while (dst
< dst_end
);
434 /* Draw a vertical line (optimised) */
435 void LCDFN(vline
)(int x
, int y1
, int y2
)
439 unsigned mask
, mask_bottom
;
440 LCDFN(blockfunc_type
) *bfunc
;
450 /******************** In viewport clipping **********************/
451 /* nothing to draw? */
452 if (((unsigned)x
>= (unsigned)current_vp
->width
) || (y1
>= current_vp
->height
)
458 if (y2
>= current_vp
->height
)
459 y2
= current_vp
->height
-1;
461 /* adjust for viewport */
466 #if defined(HAVE_VIEWPORT_CLIP)
467 /********************* Viewport on screen clipping ********************/
468 /* nothing to draw? */
469 if (( (unsigned) x
>= (unsigned)LCDM(WIDTH
)) || (y1
>= LCDM(HEIGHT
))
476 if (y2
>= LCDM(HEIGHT
))
480 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
481 dst
= &LCDFN(framebuffer
)[y1
>>3][x
];
483 mask
= 0xFFu
<< (y1
& 7);
484 mask_bottom
= 0xFFu
>> (~ny
& 7);
486 for (; ny
>= 8; ny
-= 8)
488 bfunc(dst
, mask
, 0xFFu
);
493 bfunc(dst
, mask
, 0xFFu
);
496 /* Draw a rectangular box */
497 void LCDFN(drawrect
)(int x
, int y
, int width
, int height
)
499 if ((width
<= 0) || (height
<= 0))
502 int x2
= x
+ width
- 1;
503 int y2
= y
+ height
- 1;
505 LCDFN(vline
)(x
, y
, y2
);
506 LCDFN(vline
)(x2
, y
, y2
);
507 LCDFN(hline
)(x
, x2
, y
);
508 LCDFN(hline
)(x
, x2
, y2
);
511 /* Fill a rectangular area */
512 void LCDFN(fillrect
)(int x
, int y
, int width
, int height
)
515 FBFN(data
) *dst
, *dst_end
;
516 unsigned mask
, mask_bottom
;
518 LCDFN(blockfunc_type
) *bfunc
;
519 bool fillopt
= false;
521 /******************** In viewport clipping **********************/
522 /* nothing to draw? */
523 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
524 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
537 if (x
+ width
> current_vp
->width
)
538 width
= current_vp
->width
- x
;
539 if (y
+ height
> current_vp
->height
)
540 height
= current_vp
->height
- y
;
542 /* adjust for viewport */
546 #if defined(HAVE_VIEWPORT_CLIP)
547 /********************* Viewport on screen clipping ********************/
548 /* nothing to draw? */
549 if ((x
>= LCDM(WIDTH
)) || (y
>= LCDM(HEIGHT
))
550 || (x
+ width
<= 0) || (y
+ height
<= 0))
553 /* clip image in viewport in screen */
564 if (x
+ width
> LCDM(WIDTH
))
565 width
= LCDM(WIDTH
) - x
;
566 if (y
+ height
> LCDM(HEIGHT
))
567 height
= LCDM(HEIGHT
) - y
;
570 if (current_vp
->drawmode
& DRMODE_INVERSEVID
)
572 if (current_vp
->drawmode
& DRMODE_BG
)
579 if (current_vp
->drawmode
& DRMODE_FG
)
585 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
586 dst
= &LCDFN(framebuffer
)[y
>>3][x
];
587 ny
= height
- 1 + (y
& 7);
588 mask
= 0xFFu
<< (y
& 7);
589 mask_bottom
= 0xFFu
>> (~ny
& 7);
591 for (; ny
>= 8; ny
-= 8)
593 if (fillopt
&& (mask
== 0xFFu
))
594 memset(dst
, bits
, width
);
597 FBFN(data
) *dst_row
= dst
;
599 dst_end
= dst_row
+ width
;
601 bfunc(dst_row
++, mask
, 0xFFu
);
602 while (dst_row
< dst_end
);
610 if (fillopt
&& (mask
== 0xFFu
))
611 memset(dst
, bits
, width
);
614 dst_end
= dst
+ width
;
616 bfunc(dst
++, mask
, 0xFFu
);
617 while (dst
< dst_end
);
621 /* About Rockbox' internal bitmap format:
623 * A bitmap contains one bit for every pixel that defines if that pixel is
624 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
626 * The bytes are stored in row-major order, with byte 0 being top left,
627 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
628 * 0..7, the second row defines pixel row 8..15 etc.
630 * This is the same as the internal lcd hw format. */
632 /* Draw a partial bitmap */
633 void ICODE_ATTR
LCDFN(bitmap_part
)(const unsigned char *src
, int src_x
,
634 int src_y
, int stride
, int x
, int y
,
635 int width
, int height
)
638 FBFN(data
) *dst
, *dst_end
;
639 unsigned mask
, mask_bottom
;
640 LCDFN(blockfunc_type
) *bfunc
;
642 /******************** Image in viewport clipping **********************/
643 /* nothing to draw? */
644 if ((width
<= 0) || (height
<= 0) || (x
>= current_vp
->width
)
645 || (y
>= current_vp
->height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
648 /* clip image in viewport */
661 if (x
+ width
> current_vp
->width
)
662 width
= current_vp
->width
- x
;
663 if (y
+ height
> current_vp
->height
)
664 height
= current_vp
->height
- y
;
666 /* adjust for viewport */
670 #if defined(HAVE_VIEWPORT_CLIP)
671 /********************* Viewport on screen clipping ********************/
672 /* nothing to draw? */
673 if ((x
>= LCDM(WIDTH
)) || (y
>= LCDM(HEIGHT
))
674 || (x
+ width
<= 0) || (y
+ height
<= 0))
677 /* clip image in viewport in screen */
690 if (x
+ width
> LCDM(WIDTH
))
691 width
= LCDM(WIDTH
) - x
;
692 if (y
+ height
> LCDM(HEIGHT
))
693 height
= LCDM(HEIGHT
) - y
;
696 src
+= stride
* (src_y
>> 3) + src_x
; /* move starting point */
699 dst
= &LCDFN(framebuffer
)[y
>>3][x
];
701 ny
= height
- 1 + shift
+ src_y
;
703 bfunc
= LCDFN(blockfuncs
)[current_vp
->drawmode
];
704 mask
= 0xFFu
<< (shift
+ src_y
);
705 mask_bottom
= 0xFFu
>> (~ny
& 7);
709 bool copyopt
= (current_vp
->drawmode
== DRMODE_SOLID
);
711 for (; ny
>= 8; ny
-= 8)
713 if (copyopt
&& (mask
== 0xFFu
))
714 memcpy(dst
, src
, width
);
717 const unsigned char *src_row
= src
;
718 FBFN(data
) *dst_row
= dst
;
720 dst_end
= dst_row
+ width
;
722 bfunc(dst_row
++, mask
, *src_row
++);
723 while (dst_row
< dst_end
);
732 if (copyopt
&& (mask
== 0xFFu
))
733 memcpy(dst
, src
, width
);
736 dst_end
= dst
+ width
;
738 bfunc(dst
++, mask
, *src
++);
739 while (dst
< dst_end
);
744 dst_end
= dst
+ width
;
747 const unsigned char *src_col
= src
++;
748 FBFN(data
) *dst_col
= dst
++;
749 unsigned mask_col
= mask
;
752 for (y
= ny
; y
>= 8; y
-= 8)
754 data
|= *src_col
<< shift
;
756 if (mask_col
& 0xFFu
)
758 bfunc(dst_col
, mask_col
, data
);
765 dst_col
+= LCDM(WIDTH
);
768 data
|= *src_col
<< shift
;
769 bfunc(dst_col
, mask_col
& mask_bottom
, data
);
771 while (dst
< dst_end
);
775 /* Draw a full bitmap */
776 void LCDFN(bitmap
)(const unsigned char *src
, int x
, int y
, int width
,
779 LCDFN(bitmap_part
)(src
, 0, 0, width
, x
, y
, width
, height
);
782 #include "lcd-bitmap-common.c"