1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * New greyscale framework
13 * This is a generic framework to display 129 shades of grey on low-depth
14 * bitmap LCDs (Archos b&w, Iriver & Ipod 4-grey) within plugins.
16 * Copyright (C) 2008 Jens Arnold
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
23 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
24 * KIND, either express or implied.
26 ****************************************************************************/
31 extern struct viewport _grey_default_vp
;
33 /*** low-level drawing functions ***/
35 static void setpixel(unsigned char *address
)
37 *address
= _GREY_FG_BRIGHTNESS(_grey_info
.vp
);
40 static void clearpixel(unsigned char *address
)
42 *address
= _GREY_BG_BRIGHTNESS(_grey_info
.vp
);
45 static void flippixel(unsigned char *address
)
47 *address
= ~(*address
);
50 static void nopixel(unsigned char *address
)
55 void (* const _grey_pixelfuncs
[8])(unsigned char *address
) = {
56 flippixel
, nopixel
, setpixel
, setpixel
,
57 nopixel
, clearpixel
, nopixel
, clearpixel
60 /*** Drawing functions ***/
62 /* Clear the current viewport */
63 void grey_clear_viewport(void)
65 struct viewport
*vp
= _grey_info
.vp
;
66 int drawmode
= vp
->drawmode
;
67 vp
->drawmode
= DRMODE_SOLID
| DRMODE_INVERSEVID
;
68 grey_fillrect(0, 0, vp
->width
, vp
->height
);
69 vp
->drawmode
= drawmode
;
72 /* Clear the whole display */
73 void grey_clear_display(void)
75 struct viewport
*vp
= &_grey_default_vp
;
77 int value
= (vp
->drawmode
& DRMODE_INVERSEVID
) ?
78 _GREY_FG_BRIGHTNESS(vp
) : _GREY_BG_BRIGHTNESS(vp
);
80 rb
->memset(_grey_info
.curbuffer
, value
,
81 _GREY_MULUQ(_grey_info
.cb_width
, _grey_info
.cb_height
));
84 /* Set a single pixel */
85 void grey_drawpixel(int x
, int y
)
87 if (x
>= _grey_info
.clip_l
&& x
< _grey_info
.clip_r
&&
88 y
>= _grey_info
.clip_t
&& y
< _grey_info
.clip_b
)
90 int dst_stride
= _grey_info
.cb_width
;
91 struct viewport
*vp
= _grey_info
.vp
;
92 _grey_pixelfuncs
[vp
->drawmode
](
93 &_grey_info
.curbuffer
[
94 _GREY_MULUQ(dst_stride
, vp
->y
- _grey_info
.cb_y
+ y
) +
95 vp
->x
- _grey_info
.cb_x
+ x
]);
100 void grey_drawline(int x1
, int y1
, int x2
, int y2
)
102 struct viewport
*vp
= _grey_info
.vp
;
109 void (*pfunc
)(unsigned char *address
) = _grey_pixelfuncs
[vp
->drawmode
];
113 deltax
= abs(x2
- x1
);
114 deltay
= abs(y2
- y1
);
118 if (deltax
>= deltay
)
121 d
= 2 * deltay
- deltax
;
123 dinc2
= (deltay
- deltax
) * 2;
130 d
= 2 * deltax
- deltay
;
132 dinc2
= (deltax
- deltay
) * 2;
136 numpixels
++; /* include endpoints */
153 dwidth
= _grey_info
.cb_width
;
154 xoffs
= vp
->x
- _grey_info
.cb_x
;
155 yoffs
= vp
->y
- _grey_info
.cb_y
;
157 for (i
= 0; i
< numpixels
; i
++)
159 if (x
>= _grey_info
.clip_l
&& x
< _grey_info
.clip_r
&&
160 y
>= _grey_info
.clip_t
&& y
< _grey_info
.clip_b
)
162 pfunc(&_grey_info
.curbuffer
[_GREY_MULUQ(dwidth
, yoffs
+ y
) +
181 /* Draw a horizontal line (optimised) */
182 void grey_hline(int x1
, int x2
, int y
)
184 struct viewport
*vp
= _grey_info
.vp
;
188 bool fillopt
= false;
199 /* nothing to draw? */
200 if (y
< _grey_info
.clip_t
|| y
>= _grey_info
.clip_b
||
201 x1
>= _grey_info
.clip_r
|| x2
< _grey_info
.clip_l
)
204 /* drawmode and optimisation */
205 if (vp
->drawmode
& DRMODE_INVERSEVID
)
207 if (vp
->drawmode
& DRMODE_BG
)
210 value
= _GREY_BG_BRIGHTNESS(vp
);
215 if (vp
->drawmode
& DRMODE_FG
)
218 value
= _GREY_FG_BRIGHTNESS(vp
);
221 if (!fillopt
&& vp
->drawmode
!= DRMODE_COMPLEMENT
)
225 if (x1
< _grey_info
.clip_l
)
226 x1
= _grey_info
.clip_l
;
227 if (x2
>= _grey_info
.clip_r
)
228 x2
= _grey_info
.clip_r
- 1;
230 dwidth
= _grey_info
.cb_width
;
231 dst
= &_grey_info
.curbuffer
[
232 _GREY_MULUQ(dwidth
, vp
->y
- _grey_info
.cb_y
+ y
) +
233 vp
->x
- _grey_info
.cb_x
+ x1
];
236 rb
->memset(dst
, value
, x2
- x1
+ 1);
237 else /* DRMODE_COMPLEMENT */
239 unsigned char *dst_end
= dst
+ x2
- x1
;
242 while (++dst
<= dst_end
);
246 /* Draw a vertical line (optimised) */
247 void grey_vline(int x
, int y1
, int y2
)
249 struct viewport
*vp
= _grey_info
.vp
;
251 unsigned char *dst
, *dst_end
;
252 void (*pfunc
)(unsigned char *address
);
263 /* nothing to draw? */
264 if (x
< _grey_info
.clip_l
|| x
>= _grey_info
.clip_r
||
265 y1
>= _grey_info
.clip_b
|| y2
< _grey_info
.clip_t
)
269 if (y1
< _grey_info
.clip_t
)
270 y1
= _grey_info
.clip_t
;
271 if (y2
>= _grey_info
.clip_b
)
272 y2
= _grey_info
.clip_b
- 1;
274 dwidth
= _grey_info
.cb_width
;
275 pfunc
= _grey_pixelfuncs
[vp
->drawmode
];
276 dst
= &_grey_info
.curbuffer
[
277 _GREY_MULUQ(dwidth
, vp
->y
- _grey_info
.cb_y
+ y1
) +
278 vp
->x
- _grey_info
.cb_x
+ x
];
280 dst_end
= dst
+ _GREY_MULUQ(dwidth
, y2
- y1
);
286 while (dst
<= dst_end
);
289 /* Draw a filled triangle */
290 void grey_filltriangle(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
)
293 long fp_x1
, fp_x2
, fp_dx1
, fp_dx2
;
295 /* sort vertices by increasing y value */
298 if (y2
< y3
) /* y2 < y3 < y1 */
300 x
= x1
; x1
= x2
; x2
= x3
; x3
= x
;
301 y
= y1
; y1
= y2
; y2
= y3
; y3
= y
;
303 else if (y2
> y1
) /* y3 < y1 < y2 */
305 x
= x1
; x1
= x3
; x3
= x2
; x2
= x
;
306 y
= y1
; y1
= y3
; y3
= y2
; y2
= y
;
308 else /* y3 <= y2 <= y1 */
310 x
= x1
; x1
= x3
; x3
= x
;
311 y
= y1
; y1
= y3
; y3
= y
;
316 if (y2
< y1
) /* y2 < y1 <= y3 */
318 x
= x1
; x1
= x2
; x2
= x
;
319 y
= y1
; y1
= y2
; y2
= y
;
321 else if (y2
> y3
) /* y1 <= y3 < y2 */
323 x
= x2
; x2
= x3
; x3
= x
;
324 y
= y2
; y2
= y3
; y3
= y
;
326 /* else already sorted */
329 if (y1
< y3
) /* draw */
331 fp_dx1
= ((x3
- x1
) << 16) / (y3
- y1
);
332 fp_x1
= (x1
<< 16) + (1<<15) + (fp_dx1
>> 1);
334 if (y1
< y2
) /* first part */
336 fp_dx2
= ((x2
- x1
) << 16) / (y2
- y1
);
337 fp_x2
= (x1
<< 16) + (1<<15) + (fp_dx2
>> 1);
338 for (y
= y1
; y
< y2
; y
++)
340 grey_hline(fp_x1
>> 16, fp_x2
>> 16, y
);
345 if (y2
< y3
) /* second part */
347 fp_dx2
= ((x3
- x2
) << 16) / (y3
- y2
);
348 fp_x2
= (x2
<< 16) + (1<<15) + (fp_dx2
>> 1);
349 for (y
= y2
; y
< y3
; y
++)
351 grey_hline(fp_x1
>> 16, fp_x2
>> 16, y
);
359 /* Draw a rectangular box */
360 void grey_drawrect(int x
, int y
, int width
, int height
)
362 if ((width
<= 0) || (height
<= 0))
365 int x2
= x
+ width
- 1;
366 int y2
= y
+ height
- 1;
368 grey_vline(x
, y
, y2
);
369 grey_vline(x2
, y
, y2
);
370 grey_hline(x
, x2
, y
);
371 grey_hline(x
, x2
, y2
);
374 /* Fill a rectangular area */
375 void grey_fillrect(int x
, int y
, int width
, int height
)
377 struct viewport
*vp
= _grey_info
.vp
;
379 unsigned char *dst
, *dst_end
;
380 bool fillopt
= false;
383 /* drawmode and optimisation */
384 if (vp
->drawmode
& DRMODE_INVERSEVID
)
386 if (vp
->drawmode
& DRMODE_BG
)
389 value
= _GREY_BG_BRIGHTNESS(vp
);
394 if (vp
->drawmode
& DRMODE_FG
)
397 value
= _GREY_FG_BRIGHTNESS(vp
);
401 if (!fillopt
&& vp
->drawmode
!= DRMODE_COMPLEMENT
)
405 if (x
< _grey_info
.clip_l
)
407 width
+= x
- _grey_info
.clip_l
;
408 x
= _grey_info
.clip_l
;
411 if (x
+ width
> _grey_info
.clip_r
)
412 width
= _grey_info
.clip_r
- x
;
417 if (y
< _grey_info
.clip_t
)
419 height
+= y
- _grey_info
.clip_t
;
420 y
= _grey_info
.clip_t
;
423 if (y
+ height
> _grey_info
.clip_b
)
424 height
= _grey_info
.clip_b
- y
;
429 dwidth
= _grey_info
.cb_width
;
430 dst
= &_grey_info
.curbuffer
[
431 _GREY_MULUQ(dwidth
, _grey_info
.vp
->y
- _grey_info
.cb_y
+ y
) +
432 _grey_info
.vp
->x
- _grey_info
.cb_x
+ x
];
433 dst_end
= dst
+ _GREY_MULUQ(dwidth
, height
);
438 rb
->memset(dst
, value
, width
);
439 else /* DRMODE_COMPLEMENT */
441 unsigned char *dst_row
= dst
;
442 unsigned char *row_end
= dst_row
+ width
;
445 *dst_row
= ~(*dst_row
);
446 while (++dst_row
< row_end
);
450 while (dst
< dst_end
);
453 /* About Rockbox' internal monochrome bitmap format:
455 * A bitmap contains one bit for every pixel that defines if that pixel is
456 * foreground (1) or background (0). Bits within a byte are arranged
457 * vertically, LSB at top.
458 * The bytes are stored in row-major order, with byte 0 being top left,
459 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
460 * 0..7, the second row defines pixel row 8..15 etc. */
462 /* Draw a partial monochrome bitmap */
463 void grey_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
464 int stride
, int x
, int y
, int width
, int height
)
466 struct viewport
*vp
= _grey_info
.vp
;
467 const unsigned char *src_end
;
468 unsigned char *dst
, *dst_end
;
469 unsigned dmask
= 0x100; /* bit 8 == sentinel */
470 int drmode
= vp
->drawmode
;
474 if (x
< _grey_info
.clip_l
)
476 int dx
= x
- _grey_info
.clip_l
;
479 x
= _grey_info
.clip_l
;
482 if (x
+ width
> _grey_info
.clip_r
)
483 width
= _grey_info
.clip_r
- x
;
488 if (y
< _grey_info
.clip_t
)
490 int dy
= y
- _grey_info
.clip_t
;
493 y
= _grey_info
.clip_t
;
496 if (y
+ height
> _grey_info
.clip_b
)
497 height
= _grey_info
.clip_b
- y
;
502 src
+= _GREY_MULUQ(stride
, src_y
>> 3) + src_x
; /* move starting point */
504 src_end
= src
+ width
;
505 dwidth
= _grey_info
.cb_width
;
506 dst
= &_grey_info
.curbuffer
[
507 _GREY_MULUQ(dwidth
, vp
->y
- _grey_info
.cb_y
+ y
) +
508 vp
->x
- _grey_info
.cb_x
+ x
];
509 dst_end
= dst
+ _GREY_MULUQ(dwidth
, height
);
511 if (drmode
& DRMODE_INVERSEVID
)
513 dmask
= 0x1ff; /* bit 8 == sentinel */
514 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
519 const unsigned char *src_col
= src
++;
520 unsigned char *dst_col
= dst
++;
521 unsigned data
= (*src_col
^ dmask
) >> src_y
;
524 #define UPDATE_SRC do { \
526 if (data == 0x001) { \
528 data = *src_col ^ dmask; \
534 case DRMODE_COMPLEMENT
:
538 *dst_col
= ~(*dst_col
);
543 while (dst_col
< dst_end
);
547 bg
= _GREY_BG_BRIGHTNESS(vp
);
556 while (dst_col
< dst_end
);
560 fg
= _GREY_FG_BRIGHTNESS(vp
);
569 while (dst_col
< dst_end
);
573 fg
= _GREY_FG_BRIGHTNESS(vp
);
574 bg
= _GREY_BG_BRIGHTNESS(vp
);
577 *dst_col
= (data
& 0x01) ? fg
: bg
;
581 while (dst_col
< dst_end
);
585 while (src
< src_end
);
588 /* Draw a full monochrome bitmap */
589 void grey_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
591 grey_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
594 /* Draw a partial greyscale bitmap, canonical format */
595 void grey_gray_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
596 int stride
, int x
, int y
, int width
, int height
)
598 unsigned char *dst
, *dst_end
;
602 if (x
< _grey_info
.clip_l
)
604 int dx
= x
- _grey_info
.clip_l
;
607 x
= _grey_info
.clip_l
;
610 if (x
+ width
> _grey_info
.clip_r
)
611 width
= _grey_info
.clip_r
- x
;
618 int dy
= y
- _grey_info
.clip_t
;
621 y
= _grey_info
.clip_t
;
624 if (y
+ height
> _grey_info
.clip_b
)
625 height
= _grey_info
.clip_b
- y
;
630 dwidth
= _grey_info
.cb_width
;
631 src
+= _GREY_MULUQ(stride
, src_y
) + src_x
; /* move starting point */
632 dst
= &_grey_info
.curbuffer
[
633 _GREY_MULUQ(dwidth
, _grey_info
.vp
->y
- _grey_info
.cb_y
+ y
) +
634 _grey_info
.vp
->x
- _grey_info
.cb_x
+ x
];
635 dst_end
= dst
+ _GREY_MULUQ(dwidth
, height
);
639 rb
->memcpy(dst
, src
, width
);
643 while (dst
< dst_end
);
646 /* Draw a full greyscale bitmap, canonical format */
647 void grey_gray_bitmap(const unsigned char *src
, int x
, int y
, int width
,
650 grey_gray_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
653 /* Put a string at a given pixel position, skipping first ofs pixel columns */
654 void grey_putsxyofs(int x
, int y
, int ofs
, const unsigned char *str
)
660 if (_grey_info
.clip_b
<= _grey_info
.clip_t
)
663 pf
= rb
->font_get(_grey_info
.vp
->font
);
664 ucs
= rb
->bidi_l2v(str
, 1);
666 while ((ch
= *ucs
++) != 0 && x
< _grey_info
.clip_r
)
669 const unsigned char *bits
;
671 /* get proportional width and glyph bits */
672 width
= rb
->font_get_width(pf
, ch
);
680 bits
= rb
->font_get_bits(pf
, ch
);
682 grey_mono_bitmap_part(bits
, ofs
, 0, width
, x
, y
, width
- ofs
, pf
->height
);
689 /* Put a string at a given pixel position */
690 void grey_putsxy(int x
, int y
, const unsigned char *str
)
692 grey_putsxyofs(x
, y
, 0, str
);
695 /*** Unbuffered drawing functions ***/
697 /* Clear the greyscale display (sets all pixels to white) */
698 void grey_ub_clear_display(void)
700 struct viewport
*vp
= &_grey_default_vp
;
701 int value
= _grey_info
.gvalue
[(vp
->drawmode
& DRMODE_INVERSEVID
) ?
702 _GREY_FG_BRIGHTNESS(vp
) :
703 _GREY_BG_BRIGHTNESS(vp
)];
705 rb
->memset(_grey_info
.values
, value
,
706 _GREY_MULUQ(_grey_info
.width
, _grey_info
.height
));
708 rb
->sim_lcd_ex_update_rect(_grey_info
.x
, _grey_info
.y
,
709 _grey_info
.width
, _grey_info
.height
);
713 /* Assembler optimised helper function for copying a single line to the
714 * greyvalue buffer. */
715 void _grey_line1(int width
, unsigned char *dst
, const unsigned char *src
,
716 const unsigned char *lut
);
718 /* Draw a partial greyscale bitmap, canonical format */
719 void grey_ub_gray_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
720 int stride
, int x
, int y
, int width
, int height
)
725 /* nothing to draw? */
726 if ((width
<= 0) || (height
<= 0) || (x
>= _grey_info
.width
)
727 || (y
>= _grey_info
.height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
743 if (x
+ width
> _grey_info
.width
)
744 width
= _grey_info
.width
- x
;
745 if (y
+ height
> _grey_info
.height
)
746 height
= _grey_info
.height
- y
;
748 src
+= _GREY_MULUQ(stride
, src_y
) + src_x
; /* move starting point */
751 dst
= _grey_info
.values
+ (x
<< _GREY_BSHIFT
);
755 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
756 int idx
= _GREY_MULUQ(_grey_info
.width
, yc
);
757 #else /* vertical packing or vertical interleaved */
758 int idx
= _GREY_MULUQ(_grey_info
.width
, yc
& ~_GREY_BMASK
)
759 + (~yc
& _GREY_BMASK
);
760 #endif /* LCD_PIXELFORMAT */
762 #if ((LCD_PIXELFORMAT == VERTICAL_PACKING) && (LCD_DEPTH == 1) && (CONFIG_CPU == SH7034)) \
763 || ((LCD_PIXELFORMAT == VERTICAL_PACKING) && (LCD_DEPTH == 2) && defined(CPU_COLDFIRE)) \
764 || ((LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) && defined(CPU_COLDFIRE))
765 _grey_line1(width
, dst
+ idx
, src
, _grey_info
.gvalue
);
767 unsigned char *dst_row
= dst
+ idx
;
768 const unsigned char *src_row
= src
;
769 const unsigned char *src_end
= src
+ width
;
773 *dst_row
= _grey_info
.gvalue
[*src_row
++];
774 dst_row
+= _GREY_BSIZE
;
776 while (src_row
< src_end
);
783 rb
->sim_lcd_ex_update_rect(_grey_info
.x
+ x
, _grey_info
.y
+ y
,
788 /* Draw a full greyscale bitmap, canonical format */
789 void grey_ub_gray_bitmap(const unsigned char *src
, int x
, int y
, int width
,
792 grey_ub_gray_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
795 static void output_row_grey_8(uint32_t row
, void * row_in
,
796 struct scaler_context
*ctx
)
798 uint8_t *dest
= (uint8_t*)ctx
->bm
->data
+ ctx
->bm
->width
* row
;
799 rb
->memcpy(dest
, row_in
, ctx
->bm
->width
);
802 static void output_row_grey_32(uint32_t row
, void * row_in
,
803 struct scaler_context
*ctx
)
806 uint32_t *qp
= (uint32_t*)row_in
;
807 uint8_t *dest
= (uint8_t*)ctx
->bm
->data
+ ctx
->bm
->width
* row
;
808 for (col
= 0; col
< ctx
->bm
->width
; col
++)
809 *dest
++ = SC_OUT(*qp
++, ctx
);
812 static unsigned int get_size_grey(struct bitmap
*bm
)
814 return bm
->width
* bm
->height
;
817 const struct custom_format format_grey
= {
818 .output_row_8
= output_row_grey_8
,
819 .output_row_32
= output_row_grey_32
,
820 .get_size
= get_size_grey