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 * All files in this archive are subject to the GNU General Public License.
19 * See the file COPYING in the source tree root for full license agreement.
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied.
24 ****************************************************************************/
29 /*** low-level drawing functions ***/
31 static void setpixel(unsigned char *address
)
33 *address
= _grey_info
.fg_brightness
;
36 static void clearpixel(unsigned char *address
)
38 *address
= _grey_info
.bg_brightness
;
41 static void flippixel(unsigned char *address
)
43 *address
= ~(*address
);
46 static void nopixel(unsigned char *address
)
51 void (* const _grey_pixelfuncs
[8])(unsigned char *address
) = {
52 flippixel
, nopixel
, setpixel
, setpixel
,
53 nopixel
, clearpixel
, nopixel
, clearpixel
56 /*** Drawing functions ***/
58 /* Clear the whole display */
59 void grey_clear_display(void)
61 int value
= (_grey_info
.drawmode
& DRMODE_INVERSEVID
) ?
62 _grey_info
.fg_brightness
: _grey_info
.bg_brightness
;
64 _grey_info
.rb
->memset(_grey_info
.buffer
, value
,
65 _GREY_MULUQ(_grey_info
.width
, _grey_info
.height
));
68 /* Set a single pixel */
69 void grey_drawpixel(int x
, int y
)
71 if (((unsigned)x
< (unsigned)_grey_info
.width
)
72 && ((unsigned)y
< (unsigned)_grey_info
.height
))
73 _grey_pixelfuncs
[_grey_info
.drawmode
](&_grey_info
.buffer
[_GREY_MULUQ(
74 _grey_info
.width
, y
) + x
]);
78 void grey_drawline(int x1
, int y1
, int x2
, int y2
)
86 void (*pfunc
)(unsigned char *address
) = _grey_pixelfuncs
[_grey_info
.drawmode
];
88 deltax
= abs(x2
- x1
);
89 deltay
= abs(y2
- y1
);
96 d
= 2 * deltay
- deltax
;
98 dinc2
= (deltay
- deltax
) * 2;
105 d
= 2 * deltax
- deltay
;
107 dinc2
= (deltax
- deltay
) * 2;
111 numpixels
++; /* include endpoints */
128 for (i
= 0; i
< numpixels
; i
++)
130 if (((unsigned)x
< (unsigned)_grey_info
.width
)
131 && ((unsigned)y
< (unsigned)_grey_info
.height
))
132 pfunc(&_grey_info
.buffer
[_GREY_MULUQ(_grey_info
.width
, y
) + x
]);
149 /* Draw a horizontal line (optimised) */
150 void grey_hline(int x1
, int x2
, int y
)
155 bool fillopt
= false;
156 void (*pfunc
)(unsigned char *address
);
166 /* nothing to draw? */
167 if (((unsigned)y
>= (unsigned)_grey_info
.height
)
168 || (x1
>= _grey_info
.width
) || (x2
< 0))
174 if (x2
>= _grey_info
.width
)
175 x2
= _grey_info
.width
- 1;
177 if (_grey_info
.drawmode
& DRMODE_INVERSEVID
)
179 if (_grey_info
.drawmode
& DRMODE_BG
)
182 value
= _grey_info
.bg_brightness
;
187 if (_grey_info
.drawmode
& DRMODE_FG
)
190 value
= _grey_info
.fg_brightness
;
193 pfunc
= _grey_pixelfuncs
[_grey_info
.drawmode
];
194 dst
= &_grey_info
.buffer
[_GREY_MULUQ(_grey_info
.width
, y
) + x1
];
197 _grey_info
.rb
->memset(dst
, value
, x2
- x1
+ 1);
200 unsigned char *dst_end
= dst
+ x2
- x1
;
203 while (dst
<= dst_end
);
207 /* Draw a vertical line (optimised) */
208 void grey_vline(int x
, int y1
, int y2
)
211 unsigned char *dst
, *dst_end
;
212 void (*pfunc
)(unsigned char *address
);
222 /* nothing to draw? */
223 if (((unsigned)x
>= (unsigned)_grey_info
.width
)
224 || (y1
>= _grey_info
.height
) || (y2
< 0))
230 if (y2
>= _grey_info
.height
)
231 y2
= _grey_info
.height
- 1;
233 pfunc
= _grey_pixelfuncs
[_grey_info
.drawmode
];
234 dst
= &_grey_info
.buffer
[_GREY_MULUQ(_grey_info
.width
, y1
) + x
];
236 dst_end
= dst
+ _GREY_MULUQ(_grey_info
.width
, y2
- y1
);
240 dst
+= _grey_info
.width
;
242 while (dst
<= dst_end
);
245 /* Draw a filled triangle */
246 void grey_filltriangle(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
)
249 long fp_x1
, fp_x2
, fp_dx1
, fp_dx2
;
251 /* sort vertices by increasing y value */
254 if (y2
< y3
) /* y2 < y3 < y1 */
256 x
= x1
; x1
= x2
; x2
= x3
; x3
= x
;
257 y
= y1
; y1
= y2
; y2
= y3
; y3
= y
;
259 else if (y2
> y1
) /* y3 < y1 < y2 */
261 x
= x1
; x1
= x3
; x3
= x2
; x2
= x
;
262 y
= y1
; y1
= y3
; y3
= y2
; y2
= y
;
264 else /* y3 <= y2 <= y1 */
266 x
= x1
; x1
= x3
; x3
= x
;
267 y
= y1
; y1
= y3
; y3
= y
;
272 if (y2
< y1
) /* y2 < y1 <= y3 */
274 x
= x1
; x1
= x2
; x2
= x
;
275 y
= y1
; y1
= y2
; y2
= y
;
277 else if (y2
> y3
) /* y1 <= y3 < y2 */
279 x
= x2
; x2
= x3
; x3
= x
;
280 y
= y2
; y2
= y3
; y3
= y
;
282 /* else already sorted */
285 if (y1
< y3
) /* draw */
287 fp_dx1
= ((x3
- x1
) << 16) / (y3
- y1
);
288 fp_x1
= (x1
<< 16) + (1<<15) + (fp_dx1
>> 1);
290 if (y1
< y2
) /* first part */
292 fp_dx2
= ((x2
- x1
) << 16) / (y2
- y1
);
293 fp_x2
= (x1
<< 16) + (1<<15) + (fp_dx2
>> 1);
294 for (y
= y1
; y
< y2
; y
++)
296 grey_hline(fp_x1
>> 16, fp_x2
>> 16, y
);
301 if (y2
< y3
) /* second part */
303 fp_dx2
= ((x3
- x2
) << 16) / (y3
- y2
);
304 fp_x2
= (x2
<< 16) + (1<<15) + (fp_dx2
>> 1);
305 for (y
= y2
; y
< y3
; y
++)
307 grey_hline(fp_x1
>> 16, fp_x2
>> 16, y
);
315 /* Draw a rectangular box */
316 void grey_drawrect(int x
, int y
, int width
, int height
)
318 if ((width
<= 0) || (height
<= 0))
321 int x2
= x
+ width
- 1;
322 int y2
= y
+ height
- 1;
324 grey_vline(x
, y
, y2
);
325 grey_vline(x2
, y
, y2
);
326 grey_hline(x
, x2
, y
);
327 grey_hline(x
, x2
, y2
);
330 /* Fill a rectangular area */
331 void grey_fillrect(int x
, int y
, int width
, int height
)
334 unsigned char *dst
, *dst_end
;
335 bool fillopt
= false;
336 void (*pfunc
)(unsigned char *address
);
338 /* nothing to draw? */
339 if ((width
<= 0) || (height
<= 0) || (x
>= _grey_info
.width
)
340 || (y
>= _grey_info
.height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
354 if (x
+ width
> _grey_info
.width
)
355 width
= _grey_info
.width
- x
;
356 if (y
+ height
> _grey_info
.height
)
357 height
= _grey_info
.height
- y
;
359 if (_grey_info
.drawmode
& DRMODE_INVERSEVID
)
361 if (_grey_info
.drawmode
& DRMODE_BG
)
364 value
= _grey_info
.bg_brightness
;
369 if (_grey_info
.drawmode
& DRMODE_FG
)
372 value
= _grey_info
.fg_brightness
;
375 pfunc
= _grey_pixelfuncs
[_grey_info
.drawmode
];
376 dst
= &_grey_info
.buffer
[_GREY_MULUQ(_grey_info
.width
, y
) + x
];
377 dst_end
= dst
+ _GREY_MULUQ(_grey_info
.width
, height
);
382 _grey_info
.rb
->memset(dst
, value
, width
);
385 unsigned char *dst_row
= dst
;
386 unsigned char *row_end
= dst_row
+ width
;
390 while (dst_row
< row_end
);
392 dst
+= _grey_info
.width
;
394 while (dst
< dst_end
);
397 /* About Rockbox' internal monochrome bitmap format:
399 * A bitmap contains one bit for every pixel that defines if that pixel is
400 * foreground (1) or background (0). Bits within a byte are arranged
401 * vertically, LSB at top.
402 * The bytes are stored in row-major order, with byte 0 being top left,
403 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
404 * 0..7, the second row defines pixel row 8..15 etc. */
406 /* Draw a partial monochrome bitmap */
407 void grey_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
408 int stride
, int x
, int y
, int width
, int height
)
410 const unsigned char *src_end
;
411 unsigned char *dst
, *dst_end
;
412 void (*fgfunc
)(unsigned char *address
);
413 void (*bgfunc
)(unsigned char *address
);
415 /* nothing to draw? */
416 if ((width
<= 0) || (height
<= 0) || (x
>= _grey_info
.width
)
417 || (y
>= _grey_info
.height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
433 if (x
+ width
> _grey_info
.width
)
434 width
= _grey_info
.width
- x
;
435 if (y
+ height
> _grey_info
.height
)
436 height
= _grey_info
.height
- y
;
438 src
+= _GREY_MULUQ(stride
, src_y
>> 3) + src_x
; /* move starting point */
440 src_end
= src
+ width
;
442 fgfunc
= _grey_pixelfuncs
[_grey_info
.drawmode
];
443 bgfunc
= _grey_pixelfuncs
[_grey_info
.drawmode
^ DRMODE_INVERSEVID
];
444 dst
= &_grey_info
.buffer
[_GREY_MULUQ(_grey_info
.width
, y
) + x
];
448 const unsigned char *src_col
= src
++;
449 unsigned char *dst_col
= dst
++;
450 unsigned data
= *src_col
>> src_y
;
451 int numbits
= 8 - src_y
;
453 dst_end
= dst_col
+ _GREY_MULUQ(_grey_info
.width
, height
);
461 dst_col
+= _grey_info
.width
;
471 while (dst_col
< dst_end
);
473 while (src
< src_end
);
476 /* Draw a full monochrome bitmap */
477 void grey_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
479 grey_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
482 /* Draw a partial greyscale bitmap, canonical format */
483 void grey_gray_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
484 int stride
, int x
, int y
, int width
, int height
)
486 unsigned char *dst
, *dst_end
;
488 /* nothing to draw? */
489 if ((width
<= 0) || (height
<= 0) || (x
>= _grey_info
.width
)
490 || (y
>= _grey_info
.height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
506 if (x
+ width
> _grey_info
.width
)
507 width
= _grey_info
.width
- x
;
508 if (y
+ height
> _grey_info
.height
)
509 height
= _grey_info
.height
- y
;
511 src
+= _GREY_MULUQ(stride
, src_y
) + src_x
; /* move starting point */
512 dst
= &_grey_info
.buffer
[_GREY_MULUQ(_grey_info
.width
, y
) + x
];
513 dst_end
= dst
+ _GREY_MULUQ(_grey_info
.width
, height
);
517 _grey_info
.rb
->memcpy(dst
, src
, width
);
518 dst
+= _grey_info
.width
;
521 while (dst
< dst_end
);
524 /* Draw a full greyscale bitmap, canonical format */
525 void grey_gray_bitmap(const unsigned char *src
, int x
, int y
, int width
,
528 grey_gray_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
531 /* Put a string at a given pixel position, skipping first ofs pixel columns */
532 void grey_putsxyofs(int x
, int y
, int ofs
, const unsigned char *str
)
535 struct font
* pf
= _grey_info
.rb
->font_get(_grey_info
.curfont
);
537 while ((ch
= *str
++) != '\0' && x
< _grey_info
.width
)
540 const unsigned char *bits
;
542 /* check input range */
543 if (ch
< pf
->firstchar
|| ch
>= pf
->firstchar
+pf
->size
)
544 ch
= pf
->defaultchar
;
547 /* get proportional width and glyph bits */
548 width
= pf
->width
? pf
->width
[ch
] : pf
->maxwidth
;
556 bits
= pf
->bits
+ (pf
->offset
?
557 pf
->offset
[ch
] : (((pf
->height
+ 7) >> 3) * pf
->maxwidth
* ch
));
559 grey_mono_bitmap_part(bits
, ofs
, 0, width
, x
, y
, width
- ofs
, pf
->height
);
566 /* Put a string at a given pixel position */
567 void grey_putsxy(int x
, int y
, const unsigned char *str
)
569 grey_putsxyofs(x
, y
, 0, str
);
572 /*** Unbuffered drawing functions ***/
574 /* Clear the greyscale display (sets all pixels to white) */
575 void grey_ub_clear_display(void)
577 int value
= _grey_info
.gvalue
[(_grey_info
.drawmode
& DRMODE_INVERSEVID
) ?
578 _grey_info
.fg_brightness
:
579 _grey_info
.bg_brightness
];
581 _grey_info
.rb
->memset(_grey_info
.values
, value
,
582 _GREY_MULUQ(_grey_info
.width
, _grey_info
.height
));
584 _grey_info
.rb
->sim_lcd_ex_update_rect(_grey_info
.x
, _grey_info
.y
,
585 _grey_info
.width
, _grey_info
.height
);
589 /* Assembler optimised helper function for copying a single line to the
590 * greyvalue buffer. */
591 void _grey_line1(int width
, unsigned char *dst
, const unsigned char *src
,
592 const unsigned char *lut
);
594 /* Draw a partial greyscale bitmap, canonical format */
595 void grey_ub_gray_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
596 int stride
, int x
, int y
, int width
, int height
)
601 /* nothing to draw? */
602 if ((width
<= 0) || (height
<= 0) || (x
>= _grey_info
.width
)
603 || (y
>= _grey_info
.height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
619 if (x
+ width
> _grey_info
.width
)
620 width
= _grey_info
.width
- x
;
621 if (y
+ height
> _grey_info
.height
)
622 height
= _grey_info
.height
- y
;
624 src
+= _GREY_MULUQ(stride
, src_y
) + src_x
; /* move starting point */
627 dst
= _grey_info
.values
+ (x
<< _GREY_BSHIFT
);
631 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
632 int idx
= _GREY_MULUQ(_grey_info
.width
, yc
);
633 #else /* vertical packing or vertical interleaved */
634 int idx
= _GREY_MULUQ(_grey_info
.width
, yc
& ~_GREY_BMASK
)
635 + (~yc
& _GREY_BMASK
);
636 #endif /* LCD_PIXELFORMAT */
638 #if ((LCD_PIXELFORMAT == VERTICAL_PACKING) && (LCD_DEPTH == 1) && (CONFIG_CPU == SH7034)) \
639 || ((LCD_PIXELFORMAT == VERTICAL_PACKING) && (LCD_DEPTH == 2) && defined(CPU_COLDFIRE)) \
640 || ((LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) && defined(CPU_COLDFIRE))
641 _grey_line1(width
, dst
+ idx
, src
, _grey_info
.gvalue
);
643 unsigned char *dst_row
= dst
+ idx
;
644 const unsigned char *src_row
= src
;
645 const unsigned char *src_end
= src
+ width
;
649 *dst_row
= _grey_info
.gvalue
[*src_row
++];
650 dst_row
+= _GREY_BSIZE
;
652 while (src_row
< src_end
);
659 _grey_info
.rb
->sim_lcd_ex_update_rect(_grey_info
.x
+ x
, _grey_info
.y
+ y
,
664 /* Draw a full greyscale bitmap, canonical format */
665 void grey_ub_gray_bitmap(const unsigned char *src
, int x
, int y
, int width
,
668 grey_ub_gray_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);