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 /*** low-level drawing functions ***/
33 static void setpixel(unsigned char *address
)
35 *address
= _grey_info
.fg_brightness
;
38 static void clearpixel(unsigned char *address
)
40 *address
= _grey_info
.bg_brightness
;
43 static void flippixel(unsigned char *address
)
45 *address
= ~(*address
);
48 static void nopixel(unsigned char *address
)
53 void (* const _grey_pixelfuncs
[8])(unsigned char *address
) = {
54 flippixel
, nopixel
, setpixel
, setpixel
,
55 nopixel
, clearpixel
, nopixel
, clearpixel
58 /*** Drawing functions ***/
60 /* Clear the whole display */
61 void grey_clear_display(void)
63 int value
= (_grey_info
.drawmode
& DRMODE_INVERSEVID
) ?
64 _grey_info
.fg_brightness
: _grey_info
.bg_brightness
;
66 rb
->memset(_grey_info
.buffer
, value
,
67 _GREY_MULUQ(_grey_info
.width
, _grey_info
.height
));
70 /* Set a single pixel */
71 void grey_drawpixel(int x
, int y
)
73 if (((unsigned)x
< (unsigned)_grey_info
.width
)
74 && ((unsigned)y
< (unsigned)_grey_info
.height
))
75 _grey_pixelfuncs
[_grey_info
.drawmode
](&_grey_info
.buffer
[_GREY_MULUQ(
76 _grey_info
.width
, y
) + x
]);
80 void grey_drawline(int x1
, int y1
, int x2
, int y2
)
88 void (*pfunc
)(unsigned char *address
) = _grey_pixelfuncs
[_grey_info
.drawmode
];
90 deltax
= abs(x2
- x1
);
91 deltay
= abs(y2
- y1
);
98 d
= 2 * deltay
- deltax
;
100 dinc2
= (deltay
- deltax
) * 2;
107 d
= 2 * deltax
- deltay
;
109 dinc2
= (deltax
- deltay
) * 2;
113 numpixels
++; /* include endpoints */
130 for (i
= 0; i
< numpixels
; i
++)
132 if (((unsigned)x
< (unsigned)_grey_info
.width
)
133 && ((unsigned)y
< (unsigned)_grey_info
.height
))
134 pfunc(&_grey_info
.buffer
[_GREY_MULUQ(_grey_info
.width
, y
) + x
]);
151 /* Draw a horizontal line (optimised) */
152 void grey_hline(int x1
, int x2
, int y
)
157 bool fillopt
= false;
167 /* nothing to draw? */
168 if (((unsigned)y
>= (unsigned)_grey_info
.height
)
169 || (x1
>= _grey_info
.width
) || (x2
< 0))
172 /* drawmode and optimisation */
173 if (_grey_info
.drawmode
& DRMODE_INVERSEVID
)
175 if (_grey_info
.drawmode
& DRMODE_BG
)
178 value
= _grey_info
.bg_brightness
;
183 if (_grey_info
.drawmode
& DRMODE_FG
)
186 value
= _grey_info
.fg_brightness
;
189 if (!fillopt
&& _grey_info
.drawmode
!= DRMODE_COMPLEMENT
)
195 if (x2
>= _grey_info
.width
)
196 x2
= _grey_info
.width
- 1;
198 dst
= &_grey_info
.buffer
[_GREY_MULUQ(_grey_info
.width
, y
) + x1
];
201 rb
->memset(dst
, value
, x2
- x1
+ 1);
202 else /* DRMODE_COMPLEMENT */
204 unsigned char *dst_end
= dst
+ x2
- x1
;
207 while (++dst
<= dst_end
);
211 /* Draw a vertical line (optimised) */
212 void grey_vline(int x
, int y1
, int y2
)
215 unsigned char *dst
, *dst_end
;
216 void (*pfunc
)(unsigned char *address
);
226 /* nothing to draw? */
227 if (((unsigned)x
>= (unsigned)_grey_info
.width
)
228 || (y1
>= _grey_info
.height
) || (y2
< 0))
234 if (y2
>= _grey_info
.height
)
235 y2
= _grey_info
.height
- 1;
237 pfunc
= _grey_pixelfuncs
[_grey_info
.drawmode
];
238 dst
= &_grey_info
.buffer
[_GREY_MULUQ(_grey_info
.width
, y1
) + x
];
240 dst_end
= dst
+ _GREY_MULUQ(_grey_info
.width
, y2
- y1
);
244 dst
+= _grey_info
.width
;
246 while (dst
<= dst_end
);
249 /* Draw a filled triangle */
250 void grey_filltriangle(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
)
253 long fp_x1
, fp_x2
, fp_dx1
, fp_dx2
;
255 /* sort vertices by increasing y value */
258 if (y2
< y3
) /* y2 < y3 < y1 */
260 x
= x1
; x1
= x2
; x2
= x3
; x3
= x
;
261 y
= y1
; y1
= y2
; y2
= y3
; y3
= y
;
263 else if (y2
> y1
) /* y3 < y1 < y2 */
265 x
= x1
; x1
= x3
; x3
= x2
; x2
= x
;
266 y
= y1
; y1
= y3
; y3
= y2
; y2
= y
;
268 else /* y3 <= y2 <= y1 */
270 x
= x1
; x1
= x3
; x3
= x
;
271 y
= y1
; y1
= y3
; y3
= y
;
276 if (y2
< y1
) /* y2 < y1 <= y3 */
278 x
= x1
; x1
= x2
; x2
= x
;
279 y
= y1
; y1
= y2
; y2
= y
;
281 else if (y2
> y3
) /* y1 <= y3 < y2 */
283 x
= x2
; x2
= x3
; x3
= x
;
284 y
= y2
; y2
= y3
; y3
= y
;
286 /* else already sorted */
289 if (y1
< y3
) /* draw */
291 fp_dx1
= ((x3
- x1
) << 16) / (y3
- y1
);
292 fp_x1
= (x1
<< 16) + (1<<15) + (fp_dx1
>> 1);
294 if (y1
< y2
) /* first part */
296 fp_dx2
= ((x2
- x1
) << 16) / (y2
- y1
);
297 fp_x2
= (x1
<< 16) + (1<<15) + (fp_dx2
>> 1);
298 for (y
= y1
; y
< y2
; y
++)
300 grey_hline(fp_x1
>> 16, fp_x2
>> 16, y
);
305 if (y2
< y3
) /* second part */
307 fp_dx2
= ((x3
- x2
) << 16) / (y3
- y2
);
308 fp_x2
= (x2
<< 16) + (1<<15) + (fp_dx2
>> 1);
309 for (y
= y2
; y
< y3
; y
++)
311 grey_hline(fp_x1
>> 16, fp_x2
>> 16, y
);
319 /* Draw a rectangular box */
320 void grey_drawrect(int x
, int y
, int width
, int height
)
322 if ((width
<= 0) || (height
<= 0))
325 int x2
= x
+ width
- 1;
326 int y2
= y
+ height
- 1;
328 grey_vline(x
, y
, y2
);
329 grey_vline(x2
, y
, y2
);
330 grey_hline(x
, x2
, y
);
331 grey_hline(x
, x2
, y2
);
334 /* Fill a rectangular area */
335 void grey_fillrect(int x
, int y
, int width
, int height
)
338 unsigned char *dst
, *dst_end
;
339 bool fillopt
= false;
341 /* nothing to draw? */
342 if ((width
<= 0) || (height
<= 0) || (x
>= _grey_info
.width
)
343 || (y
>= _grey_info
.height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
346 /* drawmode and optimisation */
347 if (_grey_info
.drawmode
& DRMODE_INVERSEVID
)
349 if (_grey_info
.drawmode
& DRMODE_BG
)
352 value
= _grey_info
.bg_brightness
;
357 if (_grey_info
.drawmode
& DRMODE_FG
)
360 value
= _grey_info
.fg_brightness
;
363 if (!fillopt
&& _grey_info
.drawmode
!= DRMODE_COMPLEMENT
)
377 if (x
+ width
> _grey_info
.width
)
378 width
= _grey_info
.width
- x
;
379 if (y
+ height
> _grey_info
.height
)
380 height
= _grey_info
.height
- y
;
382 dst
= &_grey_info
.buffer
[_GREY_MULUQ(_grey_info
.width
, y
) + x
];
383 dst_end
= dst
+ _GREY_MULUQ(_grey_info
.width
, height
);
388 rb
->memset(dst
, value
, width
);
389 else /* DRMODE_COMPLEMENT */
391 unsigned char *dst_row
= dst
;
392 unsigned char *row_end
= dst_row
+ width
;
395 *dst_row
= ~(*dst_row
);
396 while (++dst_row
< row_end
);
398 dst
+= _grey_info
.width
;
400 while (dst
< dst_end
);
403 /* About Rockbox' internal monochrome bitmap format:
405 * A bitmap contains one bit for every pixel that defines if that pixel is
406 * foreground (1) or background (0). Bits within a byte are arranged
407 * vertically, LSB at top.
408 * The bytes are stored in row-major order, with byte 0 being top left,
409 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
410 * 0..7, the second row defines pixel row 8..15 etc. */
412 /* Draw a partial monochrome bitmap */
413 void grey_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
414 int stride
, int x
, int y
, int width
, int height
)
416 const unsigned char *src_end
;
417 unsigned char *dst
, *dst_end
;
418 unsigned dmask
= 0x100; /* bit 8 == sentinel */
419 int drmode
= _grey_info
.drawmode
;
422 /* nothing to draw? */
423 if ((width
<= 0) || (height
<= 0) || (x
>= _grey_info
.width
)
424 || (y
>= _grey_info
.height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
440 if (x
+ width
> _grey_info
.width
)
441 width
= _grey_info
.width
- x
;
442 if (y
+ height
> _grey_info
.height
)
443 height
= _grey_info
.height
- y
;
445 src
+= _GREY_MULUQ(stride
, src_y
>> 3) + src_x
; /* move starting point */
447 src_end
= src
+ width
;
448 dwidth
= _grey_info
.width
;
449 dst
= &_grey_info
.buffer
[_GREY_MULUQ(dwidth
, y
) + x
];
451 if (drmode
& DRMODE_INVERSEVID
)
453 dmask
= 0x1ff; /* bit 8 == sentinel */
454 drmode
&= DRMODE_SOLID
; /* mask out inversevid */
459 const unsigned char *src_col
= src
++;
460 unsigned char *dst_col
= dst
++;
461 unsigned data
= (*src_col
^ dmask
) >> src_y
;
464 dst_end
= dst_col
+ _GREY_MULUQ(dwidth
, height
);
466 #define UPDATE_SRC do { \
468 if (data == 0x001) { \
470 data = *src_col ^ dmask; \
476 case DRMODE_COMPLEMENT
:
480 *dst_col
= ~(*dst_col
);
485 while (dst_col
< dst_end
);
489 bg
= _grey_info
.bg_brightness
;
498 while (dst_col
< dst_end
);
502 fg
= _grey_info
.fg_brightness
;
511 while (dst_col
< dst_end
);
515 fg
= _grey_info
.fg_brightness
;
516 bg
= _grey_info
.bg_brightness
;
519 *dst_col
= (data
& 0x01) ? fg
: bg
;
523 while (dst_col
< dst_end
);
527 while (src
< src_end
);
530 /* Draw a full monochrome bitmap */
531 void grey_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
533 grey_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
536 /* Draw a partial greyscale bitmap, canonical format */
537 void grey_gray_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
538 int stride
, int x
, int y
, int width
, int height
)
540 unsigned char *dst
, *dst_end
;
542 /* nothing to draw? */
543 if ((width
<= 0) || (height
<= 0) || (x
>= _grey_info
.width
)
544 || (y
>= _grey_info
.height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
560 if (x
+ width
> _grey_info
.width
)
561 width
= _grey_info
.width
- x
;
562 if (y
+ height
> _grey_info
.height
)
563 height
= _grey_info
.height
- y
;
565 src
+= _GREY_MULUQ(stride
, src_y
) + src_x
; /* move starting point */
566 dst
= &_grey_info
.buffer
[_GREY_MULUQ(_grey_info
.width
, y
) + x
];
567 dst_end
= dst
+ _GREY_MULUQ(_grey_info
.width
, height
);
571 rb
->memcpy(dst
, src
, width
);
572 dst
+= _grey_info
.width
;
575 while (dst
< dst_end
);
578 /* Draw a full greyscale bitmap, canonical format */
579 void grey_gray_bitmap(const unsigned char *src
, int x
, int y
, int width
,
582 grey_gray_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
585 /* Put a string at a given pixel position, skipping first ofs pixel columns */
586 void grey_putsxyofs(int x
, int y
, int ofs
, const unsigned char *str
)
590 struct font
* pf
= rb
->font_get(_grey_info
.curfont
);
592 ucs
= rb
->bidi_l2v(str
, 1);
594 while ((ch
= *ucs
++) != 0 && x
< _grey_info
.width
)
597 const unsigned char *bits
;
599 /* get proportional width and glyph bits */
600 width
= rb
->font_get_width(pf
, ch
);
608 bits
= rb
->font_get_bits(pf
, ch
);
610 grey_mono_bitmap_part(bits
, ofs
, 0, width
, x
, y
, width
- ofs
, pf
->height
);
617 /* Put a string at a given pixel position */
618 void grey_putsxy(int x
, int y
, const unsigned char *str
)
620 grey_putsxyofs(x
, y
, 0, str
);
623 /*** Unbuffered drawing functions ***/
625 /* Clear the greyscale display (sets all pixels to white) */
626 void grey_ub_clear_display(void)
628 int value
= _grey_info
.gvalue
[(_grey_info
.drawmode
& DRMODE_INVERSEVID
) ?
629 _grey_info
.fg_brightness
:
630 _grey_info
.bg_brightness
];
632 rb
->memset(_grey_info
.values
, value
,
633 _GREY_MULUQ(_grey_info
.width
, _grey_info
.height
));
635 rb
->sim_lcd_ex_update_rect(_grey_info
.x
, _grey_info
.y
,
636 _grey_info
.width
, _grey_info
.height
);
640 /* Assembler optimised helper function for copying a single line to the
641 * greyvalue buffer. */
642 void _grey_line1(int width
, unsigned char *dst
, const unsigned char *src
,
643 const unsigned char *lut
);
645 /* Draw a partial greyscale bitmap, canonical format */
646 void grey_ub_gray_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
647 int stride
, int x
, int y
, int width
, int height
)
652 /* nothing to draw? */
653 if ((width
<= 0) || (height
<= 0) || (x
>= _grey_info
.width
)
654 || (y
>= _grey_info
.height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
670 if (x
+ width
> _grey_info
.width
)
671 width
= _grey_info
.width
- x
;
672 if (y
+ height
> _grey_info
.height
)
673 height
= _grey_info
.height
- y
;
675 src
+= _GREY_MULUQ(stride
, src_y
) + src_x
; /* move starting point */
678 dst
= _grey_info
.values
+ (x
<< _GREY_BSHIFT
);
682 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
683 int idx
= _GREY_MULUQ(_grey_info
.width
, yc
);
684 #else /* vertical packing or vertical interleaved */
685 int idx
= _GREY_MULUQ(_grey_info
.width
, yc
& ~_GREY_BMASK
)
686 + (~yc
& _GREY_BMASK
);
687 #endif /* LCD_PIXELFORMAT */
689 #if ((LCD_PIXELFORMAT == VERTICAL_PACKING) && (LCD_DEPTH == 1) && (CONFIG_CPU == SH7034)) \
690 || ((LCD_PIXELFORMAT == VERTICAL_PACKING) && (LCD_DEPTH == 2) && defined(CPU_COLDFIRE)) \
691 || ((LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) && defined(CPU_COLDFIRE))
692 _grey_line1(width
, dst
+ idx
, src
, _grey_info
.gvalue
);
694 unsigned char *dst_row
= dst
+ idx
;
695 const unsigned char *src_row
= src
;
696 const unsigned char *src_end
= src
+ width
;
700 *dst_row
= _grey_info
.gvalue
[*src_row
++];
701 dst_row
+= _GREY_BSIZE
;
703 while (src_row
< src_end
);
710 rb
->sim_lcd_ex_update_rect(_grey_info
.x
+ x
, _grey_info
.y
+ y
,
715 /* Draw a full greyscale bitmap, canonical format */
716 void grey_ub_gray_bitmap(const unsigned char *src
, int x
, int y
, int width
,
719 grey_ub_gray_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
722 static void output_row_grey_8(uint32_t row
, void * row_in
,
723 struct scaler_context
*ctx
)
725 uint8_t *dest
= (uint8_t*)ctx
->bm
->data
+ ctx
->bm
->width
* row
;
726 rb
->memcpy(dest
, row_in
, ctx
->bm
->width
);
729 static void output_row_grey_32(uint32_t row
, void * row_in
,
730 struct scaler_context
*ctx
)
733 uint32_t *qp
= (uint32_t*)row_in
;
734 uint8_t *dest
= (uint8_t*)ctx
->bm
->data
+ ctx
->bm
->width
* row
;
735 for (col
= 0; col
< ctx
->bm
->width
; col
++)
736 *dest
++ = SC_OUT(*qp
++, ctx
);
739 static unsigned int get_size_grey(struct bitmap
*bm
)
741 return bm
->width
* bm
->height
;
744 const struct custom_format format_grey
= {
745 .output_row_8
= output_row_grey_8
,
746 .output_row_32
= output_row_grey_32
,
747 .get_size
= get_size_grey