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 _grey_info
.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;
158 void (*pfunc
)(unsigned char *address
);
168 /* nothing to draw? */
169 if (((unsigned)y
>= (unsigned)_grey_info
.height
)
170 || (x1
>= _grey_info
.width
) || (x2
< 0))
176 if (x2
>= _grey_info
.width
)
177 x2
= _grey_info
.width
- 1;
179 if (_grey_info
.drawmode
& DRMODE_INVERSEVID
)
181 if (_grey_info
.drawmode
& DRMODE_BG
)
184 value
= _grey_info
.bg_brightness
;
189 if (_grey_info
.drawmode
& DRMODE_FG
)
192 value
= _grey_info
.fg_brightness
;
195 pfunc
= _grey_pixelfuncs
[_grey_info
.drawmode
];
196 dst
= &_grey_info
.buffer
[_GREY_MULUQ(_grey_info
.width
, y
) + x1
];
199 _grey_info
.rb
->memset(dst
, value
, x2
- x1
+ 1);
202 unsigned char *dst_end
= dst
+ x2
- x1
;
205 while (dst
<= dst_end
);
209 /* Draw a vertical line (optimised) */
210 void grey_vline(int x
, int y1
, int y2
)
213 unsigned char *dst
, *dst_end
;
214 void (*pfunc
)(unsigned char *address
);
224 /* nothing to draw? */
225 if (((unsigned)x
>= (unsigned)_grey_info
.width
)
226 || (y1
>= _grey_info
.height
) || (y2
< 0))
232 if (y2
>= _grey_info
.height
)
233 y2
= _grey_info
.height
- 1;
235 pfunc
= _grey_pixelfuncs
[_grey_info
.drawmode
];
236 dst
= &_grey_info
.buffer
[_GREY_MULUQ(_grey_info
.width
, y1
) + x
];
238 dst_end
= dst
+ _GREY_MULUQ(_grey_info
.width
, y2
- y1
);
242 dst
+= _grey_info
.width
;
244 while (dst
<= dst_end
);
247 /* Draw a filled triangle */
248 void grey_filltriangle(int x1
, int y1
, int x2
, int y2
, int x3
, int y3
)
251 long fp_x1
, fp_x2
, fp_dx1
, fp_dx2
;
253 /* sort vertices by increasing y value */
256 if (y2
< y3
) /* y2 < y3 < y1 */
258 x
= x1
; x1
= x2
; x2
= x3
; x3
= x
;
259 y
= y1
; y1
= y2
; y2
= y3
; y3
= y
;
261 else if (y2
> y1
) /* y3 < y1 < y2 */
263 x
= x1
; x1
= x3
; x3
= x2
; x2
= x
;
264 y
= y1
; y1
= y3
; y3
= y2
; y2
= y
;
266 else /* y3 <= y2 <= y1 */
268 x
= x1
; x1
= x3
; x3
= x
;
269 y
= y1
; y1
= y3
; y3
= y
;
274 if (y2
< y1
) /* y2 < y1 <= y3 */
276 x
= x1
; x1
= x2
; x2
= x
;
277 y
= y1
; y1
= y2
; y2
= y
;
279 else if (y2
> y3
) /* y1 <= y3 < y2 */
281 x
= x2
; x2
= x3
; x3
= x
;
282 y
= y2
; y2
= y3
; y3
= y
;
284 /* else already sorted */
287 if (y1
< y3
) /* draw */
289 fp_dx1
= ((x3
- x1
) << 16) / (y3
- y1
);
290 fp_x1
= (x1
<< 16) + (1<<15) + (fp_dx1
>> 1);
292 if (y1
< y2
) /* first part */
294 fp_dx2
= ((x2
- x1
) << 16) / (y2
- y1
);
295 fp_x2
= (x1
<< 16) + (1<<15) + (fp_dx2
>> 1);
296 for (y
= y1
; y
< y2
; y
++)
298 grey_hline(fp_x1
>> 16, fp_x2
>> 16, y
);
303 if (y2
< y3
) /* second part */
305 fp_dx2
= ((x3
- x2
) << 16) / (y3
- y2
);
306 fp_x2
= (x2
<< 16) + (1<<15) + (fp_dx2
>> 1);
307 for (y
= y2
; y
< y3
; y
++)
309 grey_hline(fp_x1
>> 16, fp_x2
>> 16, y
);
317 /* Draw a rectangular box */
318 void grey_drawrect(int x
, int y
, int width
, int height
)
320 if ((width
<= 0) || (height
<= 0))
323 int x2
= x
+ width
- 1;
324 int y2
= y
+ height
- 1;
326 grey_vline(x
, y
, y2
);
327 grey_vline(x2
, y
, y2
);
328 grey_hline(x
, x2
, y
);
329 grey_hline(x
, x2
, y2
);
332 /* Fill a rectangular area */
333 void grey_fillrect(int x
, int y
, int width
, int height
)
336 unsigned char *dst
, *dst_end
;
337 bool fillopt
= false;
338 void (*pfunc
)(unsigned char *address
);
340 /* nothing to draw? */
341 if ((width
<= 0) || (height
<= 0) || (x
>= _grey_info
.width
)
342 || (y
>= _grey_info
.height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
356 if (x
+ width
> _grey_info
.width
)
357 width
= _grey_info
.width
- x
;
358 if (y
+ height
> _grey_info
.height
)
359 height
= _grey_info
.height
- y
;
361 if (_grey_info
.drawmode
& DRMODE_INVERSEVID
)
363 if (_grey_info
.drawmode
& DRMODE_BG
)
366 value
= _grey_info
.bg_brightness
;
371 if (_grey_info
.drawmode
& DRMODE_FG
)
374 value
= _grey_info
.fg_brightness
;
377 pfunc
= _grey_pixelfuncs
[_grey_info
.drawmode
];
378 dst
= &_grey_info
.buffer
[_GREY_MULUQ(_grey_info
.width
, y
) + x
];
379 dst_end
= dst
+ _GREY_MULUQ(_grey_info
.width
, height
);
384 _grey_info
.rb
->memset(dst
, value
, width
);
387 unsigned char *dst_row
= dst
;
388 unsigned char *row_end
= dst_row
+ width
;
392 while (dst_row
< row_end
);
394 dst
+= _grey_info
.width
;
396 while (dst
< dst_end
);
399 /* About Rockbox' internal monochrome bitmap format:
401 * A bitmap contains one bit for every pixel that defines if that pixel is
402 * foreground (1) or background (0). Bits within a byte are arranged
403 * vertically, LSB at top.
404 * The bytes are stored in row-major order, with byte 0 being top left,
405 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
406 * 0..7, the second row defines pixel row 8..15 etc. */
408 /* Draw a partial monochrome bitmap */
409 void grey_mono_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
410 int stride
, int x
, int y
, int width
, int height
)
412 const unsigned char *src_end
;
413 unsigned char *dst
, *dst_end
;
414 void (*fgfunc
)(unsigned char *address
);
415 void (*bgfunc
)(unsigned char *address
);
417 /* nothing to draw? */
418 if ((width
<= 0) || (height
<= 0) || (x
>= _grey_info
.width
)
419 || (y
>= _grey_info
.height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
435 if (x
+ width
> _grey_info
.width
)
436 width
= _grey_info
.width
- x
;
437 if (y
+ height
> _grey_info
.height
)
438 height
= _grey_info
.height
- y
;
440 src
+= _GREY_MULUQ(stride
, src_y
>> 3) + src_x
; /* move starting point */
442 src_end
= src
+ width
;
444 fgfunc
= _grey_pixelfuncs
[_grey_info
.drawmode
];
445 bgfunc
= _grey_pixelfuncs
[_grey_info
.drawmode
^ DRMODE_INVERSEVID
];
446 dst
= &_grey_info
.buffer
[_GREY_MULUQ(_grey_info
.width
, y
) + x
];
450 const unsigned char *src_col
= src
++;
451 unsigned char *dst_col
= dst
++;
452 unsigned data
= *src_col
>> src_y
;
453 int numbits
= 8 - src_y
;
455 dst_end
= dst_col
+ _GREY_MULUQ(_grey_info
.width
, height
);
463 dst_col
+= _grey_info
.width
;
473 while (dst_col
< dst_end
);
475 while (src
< src_end
);
478 /* Draw a full monochrome bitmap */
479 void grey_mono_bitmap(const unsigned char *src
, int x
, int y
, int width
, int height
)
481 grey_mono_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
484 /* Draw a partial greyscale bitmap, canonical format */
485 void grey_gray_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
486 int stride
, int x
, int y
, int width
, int height
)
488 unsigned char *dst
, *dst_end
;
490 /* nothing to draw? */
491 if ((width
<= 0) || (height
<= 0) || (x
>= _grey_info
.width
)
492 || (y
>= _grey_info
.height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
508 if (x
+ width
> _grey_info
.width
)
509 width
= _grey_info
.width
- x
;
510 if (y
+ height
> _grey_info
.height
)
511 height
= _grey_info
.height
- y
;
513 src
+= _GREY_MULUQ(stride
, src_y
) + src_x
; /* move starting point */
514 dst
= &_grey_info
.buffer
[_GREY_MULUQ(_grey_info
.width
, y
) + x
];
515 dst_end
= dst
+ _GREY_MULUQ(_grey_info
.width
, height
);
519 _grey_info
.rb
->memcpy(dst
, src
, width
);
520 dst
+= _grey_info
.width
;
523 while (dst
< dst_end
);
526 /* Draw a full greyscale bitmap, canonical format */
527 void grey_gray_bitmap(const unsigned char *src
, int x
, int y
, int width
,
530 grey_gray_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);
533 /* Put a string at a given pixel position, skipping first ofs pixel columns */
534 void grey_putsxyofs(int x
, int y
, int ofs
, const unsigned char *str
)
537 struct font
* pf
= _grey_info
.rb
->font_get(_grey_info
.curfont
);
539 while ((ch
= *str
++) != '\0' && x
< _grey_info
.width
)
542 const unsigned char *bits
;
544 /* check input range */
545 if (ch
< pf
->firstchar
|| ch
>= pf
->firstchar
+pf
->size
)
546 ch
= pf
->defaultchar
;
549 /* get proportional width and glyph bits */
550 width
= pf
->width
? pf
->width
[ch
] : pf
->maxwidth
;
558 bits
= pf
->bits
+ (pf
->offset
?
559 pf
->offset
[ch
] : (((pf
->height
+ 7) >> 3) * pf
->maxwidth
* ch
));
561 grey_mono_bitmap_part(bits
, ofs
, 0, width
, x
, y
, width
- ofs
, pf
->height
);
568 /* Put a string at a given pixel position */
569 void grey_putsxy(int x
, int y
, const unsigned char *str
)
571 grey_putsxyofs(x
, y
, 0, str
);
574 /*** Unbuffered drawing functions ***/
576 /* Clear the greyscale display (sets all pixels to white) */
577 void grey_ub_clear_display(void)
579 int value
= _grey_info
.gvalue
[(_grey_info
.drawmode
& DRMODE_INVERSEVID
) ?
580 _grey_info
.fg_brightness
:
581 _grey_info
.bg_brightness
];
583 _grey_info
.rb
->memset(_grey_info
.values
, value
,
584 _GREY_MULUQ(_grey_info
.width
, _grey_info
.height
));
586 _grey_info
.rb
->sim_lcd_ex_update_rect(_grey_info
.x
, _grey_info
.y
,
587 _grey_info
.width
, _grey_info
.height
);
591 /* Assembler optimised helper function for copying a single line to the
592 * greyvalue buffer. */
593 void _grey_line1(int width
, unsigned char *dst
, const unsigned char *src
,
594 const unsigned char *lut
);
596 /* Draw a partial greyscale bitmap, canonical format */
597 void grey_ub_gray_bitmap_part(const unsigned char *src
, int src_x
, int src_y
,
598 int stride
, int x
, int y
, int width
, int height
)
603 /* nothing to draw? */
604 if ((width
<= 0) || (height
<= 0) || (x
>= _grey_info
.width
)
605 || (y
>= _grey_info
.height
) || (x
+ width
<= 0) || (y
+ height
<= 0))
621 if (x
+ width
> _grey_info
.width
)
622 width
= _grey_info
.width
- x
;
623 if (y
+ height
> _grey_info
.height
)
624 height
= _grey_info
.height
- y
;
626 src
+= _GREY_MULUQ(stride
, src_y
) + src_x
; /* move starting point */
629 dst
= _grey_info
.values
+ (x
<< _GREY_BSHIFT
);
633 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
634 int idx
= _GREY_MULUQ(_grey_info
.width
, yc
);
635 #else /* vertical packing or vertical interleaved */
636 int idx
= _GREY_MULUQ(_grey_info
.width
, yc
& ~_GREY_BMASK
)
637 + (~yc
& _GREY_BMASK
);
638 #endif /* LCD_PIXELFORMAT */
640 #if ((LCD_PIXELFORMAT == VERTICAL_PACKING) && (LCD_DEPTH == 1) && (CONFIG_CPU == SH7034)) \
641 || ((LCD_PIXELFORMAT == VERTICAL_PACKING) && (LCD_DEPTH == 2) && defined(CPU_COLDFIRE)) \
642 || ((LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) && defined(CPU_COLDFIRE))
643 _grey_line1(width
, dst
+ idx
, src
, _grey_info
.gvalue
);
645 unsigned char *dst_row
= dst
+ idx
;
646 const unsigned char *src_row
= src
;
647 const unsigned char *src_end
= src
+ width
;
651 *dst_row
= _grey_info
.gvalue
[*src_row
++];
652 dst_row
+= _GREY_BSIZE
;
654 while (src_row
< src_end
);
661 _grey_info
.rb
->sim_lcd_ex_update_rect(_grey_info
.x
+ x
, _grey_info
.y
+ y
,
666 /* Draw a full greyscale bitmap, canonical format */
667 void grey_ub_gray_bitmap(const unsigned char *src
, int x
, int y
, int width
,
670 grey_ub_gray_bitmap_part(src
, 0, 0, width
, x
, y
, width
, height
);