summaryrefslogtreecommitdiff
path: root/apps/plugins/lib/grey_draw.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/lib/grey_draw.c')
-rw-r--r--apps/plugins/lib/grey_draw.c681
1 files changed, 681 insertions, 0 deletions
diff --git a/apps/plugins/lib/grey_draw.c b/apps/plugins/lib/grey_draw.c
new file mode 100644
index 0000000000..e243b5fbce
--- /dev/null
+++ b/apps/plugins/lib/grey_draw.c
@@ -0,0 +1,681 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* New greyscale framework
11* Drawing functions
12*
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.
15*
16* Copyright (C) 2008 Jens Arnold
17*
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.
20*
21* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22* KIND, either express or implied.
23*
24****************************************************************************/
25
26#include "plugin.h"
27#include "grey.h"
28
29/*** low-level drawing functions ***/
30
31static void setpixel(unsigned char *address)
32{
33 *address = _grey_info.fg_val;
34}
35
36static void clearpixel(unsigned char *address)
37{
38 *address = _grey_info.bg_val;
39}
40
41static void flippixel(unsigned char *address)
42{
43 *address = 128 - *address;
44}
45
46static void nopixel(unsigned char *address)
47{
48 (void)address;
49}
50
51void (* const _grey_pixelfuncs[8])(unsigned char *address) = {
52 flippixel, nopixel, setpixel, setpixel,
53 nopixel, clearpixel, nopixel, clearpixel
54};
55
56/*** Drawing functions ***/
57
58/* Clear the whole display */
59void grey_clear_display(void)
60{
61 int value = (_grey_info.drawmode & DRMODE_INVERSEVID) ?
62 _grey_info.fg_val : _grey_info.bg_val;
63
64 _grey_rb->memset(_grey_info.buffer, value,
65 _GREY_MULUQ(_grey_info.width, _grey_info.height));
66}
67
68/* Set a single pixel */
69void grey_drawpixel(int x, int y)
70{
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]);
75}
76
77/* Draw a line */
78void grey_drawline(int x1, int y1, int x2, int y2)
79{
80 int numpixels;
81 int i;
82 int deltax, deltay;
83 int d, dinc1, dinc2;
84 int x, xinc1, xinc2;
85 int y, yinc1, yinc2;
86 void (*pfunc)(unsigned char *address) = _grey_pixelfuncs[_grey_info.drawmode];
87
88 deltax = abs(x2 - x1);
89 deltay = abs(y2 - y1);
90 xinc2 = 1;
91 yinc2 = 1;
92
93 if (deltax >= deltay)
94 {
95 numpixels = deltax;
96 d = 2 * deltay - deltax;
97 dinc1 = deltay * 2;
98 dinc2 = (deltay - deltax) * 2;
99 xinc1 = 1;
100 yinc1 = 0;
101 }
102 else
103 {
104 numpixels = deltay;
105 d = 2 * deltax - deltay;
106 dinc1 = deltax * 2;
107 dinc2 = (deltax - deltay) * 2;
108 xinc1 = 0;
109 yinc1 = 1;
110 }
111 numpixels++; /* include endpoints */
112
113 if (x1 > x2)
114 {
115 xinc1 = -xinc1;
116 xinc2 = -xinc2;
117 }
118
119 if (y1 > y2)
120 {
121 yinc1 = -yinc1;
122 yinc2 = -yinc2;
123 }
124
125 x = x1;
126 y = y1;
127
128 for (i = 0; i < numpixels; i++)
129 {
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]);
133
134 if (d < 0)
135 {
136 d += dinc1;
137 x += xinc1;
138 y += yinc1;
139 }
140 else
141 {
142 d += dinc2;
143 x += xinc2;
144 y += yinc2;
145 }
146 }
147}
148
149/* Draw a horizontal line (optimised) */
150void grey_hline(int x1, int x2, int y)
151{
152 int x;
153 int value = 0;
154 unsigned char *dst;
155 bool fillopt = false;
156 void (*pfunc)(unsigned char *address);
157
158 /* direction flip */
159 if (x2 < x1)
160 {
161 x = x1;
162 x1 = x2;
163 x2 = x;
164 }
165
166 /* nothing to draw? */
167 if (((unsigned)y >= (unsigned)_grey_info.height)
168 || (x1 >= _grey_info.width) || (x2 < 0))
169 return;
170
171 /* clipping */
172 if (x1 < 0)
173 x1 = 0;
174 if (x2 >= _grey_info.width)
175 x2 = _grey_info.width - 1;
176
177 if (_grey_info.drawmode & DRMODE_INVERSEVID)
178 {
179 if (_grey_info.drawmode & DRMODE_BG)
180 {
181 fillopt = true;
182 value = _grey_info.bg_val;
183 }
184 }
185 else
186 {
187 if (_grey_info.drawmode & DRMODE_FG)
188 {
189 fillopt = true;
190 value = _grey_info.fg_val;
191 }
192 }
193 pfunc = _grey_pixelfuncs[_grey_info.drawmode];
194 dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y) + x1];
195
196 if (fillopt)
197 _grey_rb->memset(dst, value, x2 - x1 + 1);
198 else
199 {
200 unsigned char *dst_end = dst + x2 - x1;
201 do
202 pfunc(dst++);
203 while (dst <= dst_end);
204 }
205}
206
207/* Draw a vertical line (optimised) */
208void grey_vline(int x, int y1, int y2)
209{
210 int y;
211 unsigned char *dst, *dst_end;
212 void (*pfunc)(unsigned char *address);
213
214 /* direction flip */
215 if (y2 < y1)
216 {
217 y = y1;
218 y1 = y2;
219 y2 = y;
220 }
221
222 /* nothing to draw? */
223 if (((unsigned)x >= (unsigned)_grey_info.width)
224 || (y1 >= _grey_info.height) || (y2 < 0))
225 return;
226
227 /* clipping */
228 if (y1 < 0)
229 y1 = 0;
230 if (y2 >= _grey_info.height)
231 y2 = _grey_info.height - 1;
232
233 pfunc = _grey_pixelfuncs[_grey_info.drawmode];
234 dst = &_grey_info.buffer[_GREY_MULUQ(_grey_info.width, y1) + x];
235
236 dst_end = dst + _GREY_MULUQ(_grey_info.width, y2 - y1);
237 do
238 {
239 pfunc(dst);
240 dst += _grey_info.width;
241 }
242 while (dst <= dst_end);
243}
244
245/* Draw a filled triangle */
246void grey_filltriangle(int x1, int y1, int x2, int y2, int x3, int y3)
247{
248 int x, y;
249 long fp_x1, fp_x2, fp_dx1, fp_dx2;
250
251 /* sort vertices by increasing y value */
252 if (y1 > y3)
253 {
254 if (y2 < y3) /* y2 < y3 < y1 */
255 {
256 x = x1; x1 = x2; x2 = x3; x3 = x;
257 y = y1; y1 = y2; y2 = y3; y3 = y;
258 }
259 else if (y2 > y1) /* y3 < y1 < y2 */
260 {
261 x = x1; x1 = x3; x3 = x2; x2 = x;
262 y = y1; y1 = y3; y3 = y2; y2 = y;
263 }
264 else /* y3 <= y2 <= y1 */
265 {
266 x = x1; x1 = x3; x3 = x;
267 y = y1; y1 = y3; y3 = y;
268 }
269 }
270 else
271 {
272 if (y2 < y1) /* y2 < y1 <= y3 */
273 {
274 x = x1; x1 = x2; x2 = x;
275 y = y1; y1 = y2; y2 = y;
276 }
277 else if (y2 > y3) /* y1 <= y3 < y2 */
278 {
279 x = x2; x2 = x3; x3 = x;
280 y = y2; y2 = y3; y3 = y;
281 }
282 /* else already sorted */
283 }
284
285 if (y1 < y3) /* draw */
286 {
287 fp_dx1 = ((x3 - x1) << 16) / (y3 - y1);
288 fp_x1 = (x1 << 16) + (1<<15) + (fp_dx1 >> 1);
289
290 if (y1 < y2) /* first part */
291 {
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++)
295 {
296 grey_hline(fp_x1 >> 16, fp_x2 >> 16, y);
297 fp_x1 += fp_dx1;
298 fp_x2 += fp_dx2;
299 }
300 }
301 if (y2 < y3) /* second part */
302 {
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++)
306 {
307 grey_hline(fp_x1 >> 16, fp_x2 >> 16, y);
308 fp_x1 += fp_dx1;
309 fp_x2 += fp_dx2;
310 }
311 }
312 }
313}
314
315/* Draw a rectangular box */
316void grey_drawrect(int x, int y, int width, int height)
317{
318 if ((width <= 0) || (height <= 0))
319 return;
320
321 int x2 = x + width - 1;
322 int y2 = y + height - 1;
323
324 grey_vline(x, y, y2);
325 grey_vline(x2, y, y2);
326 grey_hline(x, x2, y);
327 grey_hline(x, x2, y2);
328}
329
330/* Fill a rectangular area */
331void grey_fillrect(int x, int y, int width, int height)
332{
333 int value = 0;
334 unsigned char *dst, *dst_end;
335 bool fillopt = false;
336 void (*pfunc)(unsigned char *address);
337
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))
341 return;
342
343 /* clipping */
344 if (x < 0)
345 {
346 width += x;
347 x = 0;
348 }
349 if (y < 0)
350 {
351 height += y;
352 y = 0;
353 }
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;
358
359 if (_grey_info.drawmode & DRMODE_INVERSEVID)
360 {
361 if (_grey_info.drawmode & DRMODE_BG)
362 {
363 fillopt = true;
364 value = _grey_info.bg_val;
365 }
366 }
367 else
368 {
369 if (_grey_info.drawmode & DRMODE_FG)
370 {
371 fillopt = true;
372 value = _grey_info.fg_val;
373 }
374 }
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);
378
379 do
380 {
381 if (fillopt)
382 _grey_rb->memset(dst, value, width);
383 else
384 {
385 unsigned char *dst_row = dst;
386 unsigned char *row_end = dst_row + width;
387
388 do
389 pfunc(dst_row++);
390 while (dst_row < row_end);
391 }
392 dst += _grey_info.width;
393 }
394 while (dst < dst_end);
395}
396
397/* About Rockbox' internal monochrome bitmap format:
398 *
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. */
405
406/* Draw a partial monochrome bitmap */
407void 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)
409{
410 const unsigned char *src_end;
411 unsigned char *dst, *dst_end;
412 void (*fgfunc)(unsigned char *address);
413 void (*bgfunc)(unsigned char *address);
414
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))
418 return;
419
420 /* clipping */
421 if (x < 0)
422 {
423 width += x;
424 src_x -= x;
425 x = 0;
426 }
427 if (y < 0)
428 {
429 height += y;
430 src_y -= y;
431 y = 0;
432 }
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;
437
438 src += _GREY_MULUQ(stride, src_y >> 3) + src_x; /* move starting point */
439 src_y &= 7;
440 src_end = src + width;
441
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];
445
446 do
447 {
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;
452
453 dst_end = dst_col + _GREY_MULUQ(_grey_info.width, height);
454 do
455 {
456 if (data & 0x01)
457 fgfunc(dst_col);
458 else
459 bgfunc(dst_col);
460
461 dst_col += _grey_info.width;
462
463 data >>= 1;
464 if (--numbits == 0)
465 {
466 src_col += stride;
467 data = *src_col;
468 numbits = 8;
469 }
470 }
471 while (dst_col < dst_end);
472 }
473 while (src < src_end);
474}
475
476/* Draw a full monochrome bitmap */
477void grey_mono_bitmap(const unsigned char *src, int x, int y, int width, int height)
478{
479 grey_mono_bitmap_part(src, 0, 0, width, x, y, width, height);
480}
481
482/* Draw a partial greyscale bitmap, canonical format */
483void 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)
485{
486 unsigned char *dst, *dst_end;
487
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))
491 return;
492
493 /* clipping */
494 if (x < 0)
495 {
496 width += x;
497 src_x -= x;
498 x = 0;
499 }
500 if (y < 0)
501 {
502 height += y;
503 src_y -= y;
504 y = 0;
505 }
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;
510
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);
514
515 do
516 {
517 const unsigned char *src_row = src;
518 unsigned char *dst_row = dst;
519 unsigned char *row_end = dst_row + width;
520
521 do
522 *dst_row++ = _grey_info.gvalue[*src_row++];
523 while (dst_row < row_end);
524
525 src += stride;
526 dst += _grey_info.width;
527 }
528 while (dst < dst_end);
529}
530
531/* Draw a full greyscale bitmap, canonical format */
532void grey_gray_bitmap(const unsigned char *src, int x, int y, int width,
533 int height)
534{
535 grey_gray_bitmap_part(src, 0, 0, width, x, y, width, height);
536}
537
538/* Put a string at a given pixel position, skipping first ofs pixel columns */
539void grey_putsxyofs(int x, int y, int ofs, const unsigned char *str)
540{
541 int ch;
542 struct font* pf = _grey_rb->font_get(_grey_info.curfont);
543
544 while ((ch = *str++) != '\0' && x < _grey_info.width)
545 {
546 int width;
547 const unsigned char *bits;
548
549 /* check input range */
550 if (ch < pf->firstchar || ch >= pf->firstchar+pf->size)
551 ch = pf->defaultchar;
552 ch -= pf->firstchar;
553
554 /* get proportional width and glyph bits */
555 width = pf->width ? pf->width[ch] : pf->maxwidth;
556
557 if (ofs > width)
558 {
559 ofs -= width;
560 continue;
561 }
562
563 bits = pf->bits + (pf->offset ?
564 pf->offset[ch] : (((pf->height + 7) >> 3) * pf->maxwidth * ch));
565
566 grey_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
567
568 x += width - ofs;
569 ofs = 0;
570 }
571}
572
573/* Put a string at a given pixel position */
574void grey_putsxy(int x, int y, const unsigned char *str)
575{
576 grey_putsxyofs(x, y, 0, str);
577}
578
579/*** Unbuffered drawing functions ***/
580
581#ifdef SIMULATOR
582
583/* Clear the whole display */
584void grey_ub_clear_display(void)
585{
586 grey_clear_display();
587 grey_update();
588}
589
590/* Draw a partial greyscale bitmap, canonical format */
591void grey_ub_gray_bitmap_part(const unsigned char *src, int src_x, int src_y,
592 int stride, int x, int y, int width, int height)
593{
594 grey_gray_bitmap_part(src, src_x, src_y, stride, x, y, width, height);
595 grey_update_rect(x, y, width, height);
596}
597
598#else /* !SIMULATOR */
599
600/* Clear the greyscale display (sets all pixels to white) */
601void grey_ub_clear_display(void)
602{
603 int value = (_grey_info.drawmode & DRMODE_INVERSEVID) ?
604 _grey_info.fg_val : _grey_info.bg_val;
605 unsigned char *dst = &_grey_info.data[0].value;
606 unsigned char *dst_end = dst + sizeof(struct grey_data)
607 * _GREY_MULUQ(_grey_info.width, _grey_info.height);
608
609 do
610 {
611 *dst = value;
612 dst += sizeof(struct grey_data);
613 }
614 while (dst < dst_end);
615}
616
617/* Draw a partial greyscale bitmap, canonical format */
618void grey_ub_gray_bitmap_part(const unsigned char *src, int src_x, int src_y,
619 int stride, int x, int y, int width, int height)
620{
621 /* nothing to draw? */
622 if ((width <= 0) || (height <= 0) || (x >= _grey_info.width)
623 || (y >= _grey_info.height) || (x + width <= 0) || (y + height <= 0))
624 return;
625
626 /* clipping */
627 if (x < 0)
628 {
629 width += x;
630 src_x -= x;
631 x = 0;
632 }
633 if (y < 0)
634 {
635 height += y;
636 src_y -= y;
637 y = 0;
638 }
639 if (x + width > _grey_info.width)
640 width = _grey_info.width - x;
641 if (y + height > _grey_info.height)
642 height = _grey_info.height - y;
643
644 src += _GREY_MULUQ(stride, src_y) + src_x; /* move starting point */
645
646 do
647 {
648#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
649 int idx = _GREY_MULUQ(_grey_info.width, y) + x;
650#else
651#if LCD_DEPTH == 1
652 int idx = _GREY_MULUQ(_grey_info.width, y & ~7) + (x << 3) + (~y & 7);
653#elif LCD_DEPTH == 2
654 int idx = _GREY_MULUQ(_grey_info.width, y & ~3) + (x << 2) + (~y & 3);
655#endif
656#endif /* LCD_PIXELFORMAT */
657 unsigned char *dst_row = &_grey_info.data[idx].value;
658 const unsigned char *src_row = src;
659 const unsigned char *src_end = src + width;
660
661 do
662 {
663 *dst_row = _grey_info.gvalue[*src_row++];
664 dst_row += _GREY_X_ADVANCE;
665 }
666 while (src_row < src_end);
667
668 y++;
669 src += stride;
670 }
671 while (--height > 0);
672}
673
674#endif /* !SIMULATOR */
675
676/* Draw a full greyscale bitmap, canonical format */
677void grey_ub_gray_bitmap(const unsigned char *src, int x, int y, int width,
678 int height)
679{
680 grey_ub_gray_bitmap_part(src, 0, 0, width, x, y, width, height);
681}