Use the AMS_LOWMEM define to indicate memory size as the .lds files do in config...
[kugel-rb.git] / apps / plugins / lib / grey_draw.c
blob3b8169442607ae0feb3f1b17eb4fe3ffe2b5c842
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * New greyscale framework
11 * Drawing functions
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 ****************************************************************************/
28 #include "plugin.h"
29 #include "grey.h"
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)
50 (void)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]);
79 /* Draw a line */
80 void grey_drawline(int x1, int y1, int x2, int y2)
82 int numpixels;
83 int i;
84 int deltax, deltay;
85 int d, dinc1, dinc2;
86 int x, xinc1, xinc2;
87 int y, yinc1, yinc2;
88 void (*pfunc)(unsigned char *address) = _grey_pixelfuncs[_grey_info.drawmode];
90 deltax = abs(x2 - x1);
91 deltay = abs(y2 - y1);
92 xinc2 = 1;
93 yinc2 = 1;
95 if (deltax >= deltay)
97 numpixels = deltax;
98 d = 2 * deltay - deltax;
99 dinc1 = deltay * 2;
100 dinc2 = (deltay - deltax) * 2;
101 xinc1 = 1;
102 yinc1 = 0;
104 else
106 numpixels = deltay;
107 d = 2 * deltax - deltay;
108 dinc1 = deltax * 2;
109 dinc2 = (deltax - deltay) * 2;
110 xinc1 = 0;
111 yinc1 = 1;
113 numpixels++; /* include endpoints */
115 if (x1 > x2)
117 xinc1 = -xinc1;
118 xinc2 = -xinc2;
121 if (y1 > y2)
123 yinc1 = -yinc1;
124 yinc2 = -yinc2;
127 x = x1;
128 y = y1;
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]);
136 if (d < 0)
138 d += dinc1;
139 x += xinc1;
140 y += yinc1;
142 else
144 d += dinc2;
145 x += xinc2;
146 y += yinc2;
151 /* Draw a horizontal line (optimised) */
152 void grey_hline(int x1, int x2, int y)
154 int x;
155 int value = 0;
156 unsigned char *dst;
157 bool fillopt = false;
159 /* direction flip */
160 if (x2 < x1)
162 x = x1;
163 x1 = x2;
164 x2 = x;
167 /* nothing to draw? */
168 if (((unsigned)y >= (unsigned)_grey_info.height)
169 || (x1 >= _grey_info.width) || (x2 < 0))
170 return;
172 /* drawmode and optimisation */
173 if (_grey_info.drawmode & DRMODE_INVERSEVID)
175 if (_grey_info.drawmode & DRMODE_BG)
177 fillopt = true;
178 value = _grey_info.bg_brightness;
181 else
183 if (_grey_info.drawmode & DRMODE_FG)
185 fillopt = true;
186 value = _grey_info.fg_brightness;
189 if (!fillopt && _grey_info.drawmode != DRMODE_COMPLEMENT)
190 return;
192 /* clipping */
193 if (x1 < 0)
194 x1 = 0;
195 if (x2 >= _grey_info.width)
196 x2 = _grey_info.width - 1;
198 dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y) + x1];
200 if (fillopt)
201 rb->memset(dst, value, x2 - x1 + 1);
202 else /* DRMODE_COMPLEMENT */
204 unsigned char *dst_end = dst + x2 - x1;
206 *dst = ~(*dst);
207 while (++dst <= dst_end);
211 /* Draw a vertical line (optimised) */
212 void grey_vline(int x, int y1, int y2)
214 int y;
215 unsigned char *dst, *dst_end;
216 void (*pfunc)(unsigned char *address);
218 /* direction flip */
219 if (y2 < y1)
221 y = y1;
222 y1 = y2;
223 y2 = y;
226 /* nothing to draw? */
227 if (((unsigned)x >= (unsigned)_grey_info.width)
228 || (y1 >= _grey_info.height) || (y2 < 0))
229 return;
231 /* clipping */
232 if (y1 < 0)
233 y1 = 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);
243 pfunc(dst);
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)
252 int x, y;
253 long fp_x1, fp_x2, fp_dx1, fp_dx2;
255 /* sort vertices by increasing y value */
256 if (y1 > y3)
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;
274 else
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);
301 fp_x1 += fp_dx1;
302 fp_x2 += fp_dx2;
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);
312 fp_x1 += fp_dx1;
313 fp_x2 += fp_dx2;
319 /* Draw a rectangular box */
320 void grey_drawrect(int x, int y, int width, int height)
322 if ((width <= 0) || (height <= 0))
323 return;
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)
337 int value = 0;
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))
344 return;
346 /* drawmode and optimisation */
347 if (_grey_info.drawmode & DRMODE_INVERSEVID)
349 if (_grey_info.drawmode & DRMODE_BG)
351 fillopt = true;
352 value = _grey_info.bg_brightness;
355 else
357 if (_grey_info.drawmode & DRMODE_FG)
359 fillopt = true;
360 value = _grey_info.fg_brightness;
363 if (!fillopt && _grey_info.drawmode != DRMODE_COMPLEMENT)
364 return;
366 /* clipping */
367 if (x < 0)
369 width += x;
370 x = 0;
372 if (y < 0)
374 height += y;
375 y = 0;
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);
387 if (fillopt)
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;
420 int dwidth;
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))
425 return;
427 /* clipping */
428 if (x < 0)
430 width += x;
431 src_x -= x;
432 x = 0;
434 if (y < 0)
436 height += y;
437 src_y -= y;
438 y = 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 */
446 src_y &= 7;
447 src_end = src + width;
448 dwidth = _grey_info.width;
449 dst = &_grey_info.buffer[_GREY_MULUQ(dwidth, y) + x];
450 dst_end = dst + _GREY_MULUQ(dwidth, height);
452 if (drmode & DRMODE_INVERSEVID)
454 dmask = 0x1ff; /* bit 8 == sentinel */
455 drmode &= DRMODE_SOLID; /* mask out inversevid */
460 const unsigned char *src_col = src++;
461 unsigned char *dst_col = dst++;
462 unsigned data = (*src_col ^ dmask) >> src_y;
463 int fg, bg;
465 #define UPDATE_SRC do { \
466 data >>= 1; \
467 if (data == 0x001) { \
468 src_col += stride; \
469 data = *src_col ^ dmask; \
471 } while (0)
473 switch (drmode)
475 case DRMODE_COMPLEMENT:
478 if (data & 0x01)
479 *dst_col = ~(*dst_col);
481 dst_col += dwidth;
482 UPDATE_SRC;
484 while (dst_col < dst_end);
485 break;
487 case DRMODE_BG:
488 bg = _grey_info.bg_brightness;
491 if (!(data & 0x01))
492 *dst_col = bg;
494 dst_col += dwidth;
495 UPDATE_SRC;
497 while (dst_col < dst_end);
498 break;
500 case DRMODE_FG:
501 fg = _grey_info.fg_brightness;
504 if (data & 0x01)
505 *dst_col = fg;
507 dst_col += dwidth;
508 UPDATE_SRC;
510 while (dst_col < dst_end);
511 break;
513 case DRMODE_SOLID:
514 fg = _grey_info.fg_brightness;
515 bg = _grey_info.bg_brightness;
518 *dst_col = (data & 0x01) ? fg : bg;
519 dst_col += dwidth;
520 UPDATE_SRC;
522 while (dst_col < dst_end);
523 break;
526 while (src < src_end);
529 /* Draw a full monochrome bitmap */
530 void grey_mono_bitmap(const unsigned char *src, int x, int y, int width, int height)
532 grey_mono_bitmap_part(src, 0, 0, width, x, y, width, height);
535 /* Draw a partial greyscale bitmap, canonical format */
536 void grey_gray_bitmap_part(const unsigned char *src, int src_x, int src_y,
537 int stride, int x, int y, int width, int height)
539 unsigned char *dst, *dst_end;
541 /* nothing to draw? */
542 if ((width <= 0) || (height <= 0) || (x >= _grey_info.width)
543 || (y >= _grey_info.height) || (x + width <= 0) || (y + height <= 0))
544 return;
546 /* clipping */
547 if (x < 0)
549 width += x;
550 src_x -= x;
551 x = 0;
553 if (y < 0)
555 height += y;
556 src_y -= y;
557 y = 0;
559 if (x + width > _grey_info.width)
560 width = _grey_info.width - x;
561 if (y + height > _grey_info.height)
562 height = _grey_info.height - y;
564 src += _GREY_MULUQ(stride, src_y) + src_x; /* move starting point */
565 dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y) + x];
566 dst_end = dst + _GREY_MULUQ(_grey_info.width, height);
570 rb->memcpy(dst, src, width);
571 dst += _grey_info.width;
572 src += stride;
574 while (dst < dst_end);
577 /* Draw a full greyscale bitmap, canonical format */
578 void grey_gray_bitmap(const unsigned char *src, int x, int y, int width,
579 int height)
581 grey_gray_bitmap_part(src, 0, 0, width, x, y, width, height);
584 /* Put a string at a given pixel position, skipping first ofs pixel columns */
585 void grey_putsxyofs(int x, int y, int ofs, const unsigned char *str)
587 int ch;
588 unsigned short *ucs;
589 struct font* pf = rb->font_get(_grey_info.curfont);
591 ucs = rb->bidi_l2v(str, 1);
593 while ((ch = *ucs++) != 0 && x < _grey_info.width)
595 int width;
596 const unsigned char *bits;
598 /* get proportional width and glyph bits */
599 width = rb->font_get_width(pf, ch);
601 if (ofs > width)
603 ofs -= width;
604 continue;
607 bits = rb->font_get_bits(pf, ch);
609 grey_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
611 x += width - ofs;
612 ofs = 0;
616 /* Put a string at a given pixel position */
617 void grey_putsxy(int x, int y, const unsigned char *str)
619 grey_putsxyofs(x, y, 0, str);
622 /*** Unbuffered drawing functions ***/
624 /* Clear the greyscale display (sets all pixels to white) */
625 void grey_ub_clear_display(void)
627 int value = _grey_info.gvalue[(_grey_info.drawmode & DRMODE_INVERSEVID) ?
628 _grey_info.fg_brightness :
629 _grey_info.bg_brightness];
631 rb->memset(_grey_info.values, value,
632 _GREY_MULUQ(_grey_info.width, _grey_info.height));
633 #ifdef SIMULATOR
634 rb->sim_lcd_ex_update_rect(_grey_info.x, _grey_info.y,
635 _grey_info.width, _grey_info.height);
636 #endif
639 /* Assembler optimised helper function for copying a single line to the
640 * greyvalue buffer. */
641 void _grey_line1(int width, unsigned char *dst, const unsigned char *src,
642 const unsigned char *lut);
644 /* Draw a partial greyscale bitmap, canonical format */
645 void grey_ub_gray_bitmap_part(const unsigned char *src, int src_x, int src_y,
646 int stride, int x, int y, int width, int height)
648 int yc, ye;
649 unsigned char *dst;
651 /* nothing to draw? */
652 if ((width <= 0) || (height <= 0) || (x >= _grey_info.width)
653 || (y >= _grey_info.height) || (x + width <= 0) || (y + height <= 0))
654 return;
656 /* clipping */
657 if (x < 0)
659 width += x;
660 src_x -= x;
661 x = 0;
663 if (y < 0)
665 height += y;
666 src_y -= y;
667 y = 0;
669 if (x + width > _grey_info.width)
670 width = _grey_info.width - x;
671 if (y + height > _grey_info.height)
672 height = _grey_info.height - y;
674 src += _GREY_MULUQ(stride, src_y) + src_x; /* move starting point */
675 yc = y;
676 ye = y + height;
677 dst = _grey_info.values + (x << _GREY_BSHIFT);
681 #if LCD_PIXELFORMAT == HORIZONTAL_PACKING
682 int idx = _GREY_MULUQ(_grey_info.width, yc);
683 #else /* vertical packing or vertical interleaved */
684 int idx = _GREY_MULUQ(_grey_info.width, yc & ~_GREY_BMASK)
685 + (~yc & _GREY_BMASK);
686 #endif /* LCD_PIXELFORMAT */
688 #if ((LCD_PIXELFORMAT == VERTICAL_PACKING) && (LCD_DEPTH == 1) && (CONFIG_CPU == SH7034)) \
689 || ((LCD_PIXELFORMAT == VERTICAL_PACKING) && (LCD_DEPTH == 2) && defined(CPU_COLDFIRE)) \
690 || ((LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) && defined(CPU_COLDFIRE))
691 _grey_line1(width, dst + idx, src, _grey_info.gvalue);
692 #else
693 unsigned char *dst_row = dst + idx;
694 const unsigned char *src_row = src;
695 const unsigned char *src_end = src + width;
699 *dst_row = _grey_info.gvalue[*src_row++];
700 dst_row += _GREY_BSIZE;
702 while (src_row < src_end);
703 #endif
705 src += stride;
707 while (++yc < ye);
708 #ifdef SIMULATOR
709 rb->sim_lcd_ex_update_rect(_grey_info.x + x, _grey_info.y + y,
710 width, height);
711 #endif
714 /* Draw a full greyscale bitmap, canonical format */
715 void grey_ub_gray_bitmap(const unsigned char *src, int x, int y, int width,
716 int height)
718 grey_ub_gray_bitmap_part(src, 0, 0, width, x, y, width, height);
721 static void output_row_grey_8(uint32_t row, void * row_in,
722 struct scaler_context *ctx)
724 uint8_t *dest = (uint8_t*)ctx->bm->data + ctx->bm->width * row;
725 rb->memcpy(dest, row_in, ctx->bm->width);
728 static void output_row_grey_32(uint32_t row, void * row_in,
729 struct scaler_context *ctx)
731 int col;
732 uint32_t *qp = (uint32_t*)row_in;
733 uint8_t *dest = (uint8_t*)ctx->bm->data + ctx->bm->width * row;
734 for (col = 0; col < ctx->bm->width; col++)
735 *dest++ = SC_OUT(*qp++, ctx);
738 static unsigned int get_size_grey(struct bitmap *bm)
740 return bm->width * bm->height;
743 const struct custom_format format_grey = {
744 .output_row_8 = output_row_grey_8,
745 .output_row_32 = output_row_grey_32,
746 .get_size = get_size_grey