summaryrefslogtreecommitdiff
path: root/apps/plugins/lib/gray_draw.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/lib/gray_draw.c')
-rw-r--r--apps/plugins/lib/gray_draw.c826
1 files changed, 826 insertions, 0 deletions
diff --git a/apps/plugins/lib/gray_draw.c b/apps/plugins/lib/gray_draw.c
new file mode 100644
index 0000000000..0742459d4b
--- /dev/null
+++ b/apps/plugins/lib/gray_draw.c
@@ -0,0 +1,826 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Greyscale framework
11* Drawing functions for buffered mode
12*
13* This is a generic framework to use grayscale display within Rockbox
14* plugins. It obviously does not work for the player.
15*
16* Copyright (C) 2004-2005 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#ifndef SIMULATOR /* not for simulator by now */
27#include "plugin.h"
28
29#ifdef HAVE_LCD_BITMAP /* and also not for the Player */
30#include "gray.h"
31
32/*** low-level drawing functions ***/
33
34static void setpixel(unsigned char *address)
35{
36 *address = _gray_info.fg_brightness;
37}
38
39static void clearpixel(unsigned char *address)
40{
41 *address = _gray_info.bg_brightness;
42}
43
44static void flippixel(unsigned char *address)
45{
46 *address = _LEVEL_FAC * _gray_info.depth - *address;
47}
48
49static void nopixel(unsigned char *address)
50{
51 (void)address;
52}
53
54void (* const _gray_pixelfuncs[8])(unsigned char *address) = {
55 flippixel, nopixel, setpixel, setpixel,
56 nopixel, clearpixel, nopixel, clearpixel
57};
58
59/*** Drawing functions ***/
60
61/* Clear the whole display */
62void gray_clear_display(void)
63{
64 int brightness = (_gray_info.drawmode & DRMODE_INVERSEVID) ?
65 _gray_info.fg_brightness : _gray_info.bg_brightness;
66
67 _gray_rb->memset(_gray_info.cur_buffer, brightness,
68 MULU16(_gray_info.width, _gray_info.height));
69}
70
71/* Set a single pixel */
72void gray_drawpixel(int x, int y)
73{
74 if (((unsigned)x < (unsigned)_gray_info.width)
75 && ((unsigned)y < (unsigned)_gray_info.height))
76 _gray_pixelfuncs[_gray_info.drawmode](&_gray_info.cur_buffer[MULU16(x,
77 _gray_info.height) + y]);
78}
79
80/* Draw a line */
81void gray_drawline(int x1, int y1, int x2, int y2)
82{
83 int numpixels;
84 int i;
85 int deltax, deltay;
86 int d, dinc1, dinc2;
87 int x, xinc1, xinc2;
88 int y, yinc1, yinc2;
89 void (*pfunc)(unsigned char *address) = _gray_pixelfuncs[_gray_info.drawmode];
90
91 deltax = abs(x2 - x1);
92 deltay = abs(y2 - y1);
93 xinc2 = 1;
94 yinc2 = 1;
95
96 if (deltax >= deltay)
97 {
98 numpixels = deltax;
99 d = 2 * deltay - deltax;
100 dinc1 = deltay * 2;
101 dinc2 = (deltay - deltax) * 2;
102 xinc1 = 1;
103 yinc1 = 0;
104 }
105 else
106 {
107 numpixels = deltay;
108 d = 2 * deltax - deltay;
109 dinc1 = deltax * 2;
110 dinc2 = (deltax - deltay) * 2;
111 xinc1 = 0;
112 yinc1 = 1;
113 }
114 numpixels++; /* include endpoints */
115
116 if (x1 > x2)
117 {
118 xinc1 = -xinc1;
119 xinc2 = -xinc2;
120 }
121
122 if (y1 > y2)
123 {
124 yinc1 = -yinc1;
125 yinc2 = -yinc2;
126 }
127
128 x = x1;
129 y = y1;
130
131 for (i = 0; i < numpixels; i++)
132 {
133 if (((unsigned)x < (unsigned)_gray_info.width)
134 && ((unsigned)y < (unsigned)_gray_info.height))
135 pfunc(&_gray_info.cur_buffer[MULU16(x, _gray_info.height) + y]);
136
137 if (d < 0)
138 {
139 d += dinc1;
140 x += xinc1;
141 y += yinc1;
142 }
143 else
144 {
145 d += dinc2;
146 x += xinc2;
147 y += yinc2;
148 }
149 }
150}
151
152/* Draw a horizontal line (optimised) */
153void gray_hline(int x1, int x2, int y)
154{
155 int x;
156 unsigned char *dst, *dst_end;
157 void (*pfunc)(unsigned char *address);
158
159 /* direction flip */
160 if (x2 < x1)
161 {
162 x = x1;
163 x1 = x2;
164 x2 = x;
165 }
166
167 /* nothing to draw? */
168 if (((unsigned)y >= (unsigned)_gray_info.height)
169 || (x1 >= _gray_info.width) || (x2 < 0))
170 return;
171
172 /* clipping */
173 if (x1 < 0)
174 x1 = 0;
175 if (x2 >= _gray_info.width)
176 x2 = _gray_info.width - 1;
177
178 pfunc = _gray_pixelfuncs[_gray_info.drawmode];
179 dst = &_gray_info.cur_buffer[MULU16(x1, _gray_info.height) + y];
180
181 dst_end = dst + MULU16(x2 - x1, _gray_info.height);
182 do
183 {
184 pfunc(dst);
185 dst += _gray_info.height;
186 }
187 while (dst <= dst_end);
188}
189
190/* Draw a vertical line (optimised) */
191void gray_vline(int x, int y1, int y2)
192{
193 int y, bits;
194 unsigned char *dst;
195 bool fillopt;
196 void (*pfunc)(unsigned char *address);
197
198 /* direction flip */
199 if (y2 < y1)
200 {
201 y = y1;
202 y1 = y2;
203 y2 = y;
204 }
205
206 /* nothing to draw? */
207 if (((unsigned)x >= (unsigned)_gray_info.width)
208 || (y1 >= _gray_info.height) || (y2 < 0))
209 return;
210
211 /* clipping */
212 if (y1 < 0)
213 y1 = 0;
214 if (y2 >= _gray_info.height)
215 y2 = _gray_info.height - 1;
216
217 bits = _gray_info.fg_brightness;
218 fillopt = (_gray_info.drawmode & DRMODE_INVERSEVID) ?
219 (_gray_info.drawmode & DRMODE_BG) :
220 (_gray_info.drawmode & DRMODE_FG);
221 if (fillopt &&(_gray_info.drawmode & DRMODE_INVERSEVID))
222 bits = _gray_info.bg_brightness;
223
224 pfunc = _gray_pixelfuncs[_gray_info.drawmode];
225 dst = &_gray_info.cur_buffer[MULU16(x, _gray_info.height) + y1];
226
227 if (fillopt)
228 _gray_rb->memset(dst, bits, y2 - y1 + 1);
229 else
230 {
231 unsigned char *dst_end = dst + y2 - y1;
232 do
233 pfunc(dst++);
234 while (dst <= dst_end);
235 }
236}
237
238/* Draw a rectangular box */
239void gray_drawrect(int x, int y, int width, int height)
240{
241 if ((width <= 0) || (height <= 0))
242 return;
243
244 int x2 = x + width - 1;
245 int y2 = y + height - 1;
246
247 gray_vline(x, y, y2);
248 gray_vline(x2, y, y2);
249 gray_hline(x, x2, y);
250 gray_hline(x, x2, y2);
251}
252
253/* Fill a rectangular area */
254void gray_fillrect(int x, int y, int width, int height)
255{
256 int bits;
257 unsigned char *dst, *dst_end;
258 bool fillopt;
259 void (*pfunc)(unsigned char *address);
260
261 /* nothing to draw? */
262 if ((width <= 0) || (height <= 0) || (x >= _gray_info.width)
263 || (y >= _gray_info.height) || (x + width <= 0) || (y + height <= 0))
264 return;
265
266 /* clipping */
267 if (x < 0)
268 {
269 width += x;
270 x = 0;
271 }
272 if (y < 0)
273 {
274 height += y;
275 y = 0;
276 }
277 if (x + width > _gray_info.width)
278 width = _gray_info.width - x;
279 if (y + height > _gray_info.height)
280 height = _gray_info.height - y;
281
282 bits = _gray_info.fg_brightness;
283 fillopt = (_gray_info.drawmode & DRMODE_INVERSEVID) ?
284 (_gray_info.drawmode & DRMODE_BG) :
285 (_gray_info.drawmode & DRMODE_FG);
286 if (fillopt &&(_gray_info.drawmode & DRMODE_INVERSEVID))
287 bits = _gray_info.bg_brightness;
288
289 pfunc = _gray_pixelfuncs[_gray_info.drawmode];
290 dst = &_gray_info.cur_buffer[MULU16(x, _gray_info.height) + y];
291 dst_end = dst + MULU16(width, _gray_info.height);
292
293 do
294 {
295 if (fillopt)
296 _gray_rb->memset(dst, bits, height);
297 else
298 {
299 unsigned char *dst_col = dst;
300 unsigned char *col_end = dst_col + height;
301
302 do
303 pfunc(dst_col++);
304 while (dst_col < col_end);
305 }
306 dst += _gray_info.height;
307 }
308 while (dst < dst_end);
309}
310
311/* Draw a filled triangle */
312void gray_filltriangle(int x1, int y1, int x2, int y2, int x3, int y3)
313{
314 int x, y;
315 long fp_y1, fp_y2, fp_dy1, fp_dy2;
316
317 /* sort vertices by increasing x value */
318 if (x1 > x3)
319 {
320 if (x2 < x3) /* x2 < x3 < x1 */
321 {
322 x = x1; x1 = x2; x2 = x3; x3 = x;
323 y = y1; y1 = y2; y2 = y3; y3 = y;
324 }
325 else if (x2 > x1) /* x3 < x1 < x2 */
326 {
327 x = x1; x1 = x3; x3 = x2; x2 = x;
328 y = y1; y1 = y3; y3 = y2; y2 = y;
329 }
330 else /* x3 <= x2 <= x1 */
331 {
332 x = x1; x1 = x3; x3 = x;
333 y = y1; y1 = y3; y3 = y;
334 }
335 }
336 else
337 {
338 if (x2 < x1) /* x2 < x1 <= x3 */
339 {
340 x = x1; x1 = x2; x2 = x;
341 y = y1; y1 = y2; y2 = y;
342 }
343 else if (x2 > x3) /* x1 <= x3 < x2 */
344 {
345 x = x2; x2 = x3; x3 = x;
346 y = y2; y2 = y3; y3 = y;
347 }
348 /* else already sorted */
349 }
350
351 if (x1 < x3) /* draw */
352 {
353 fp_dy1 = ((y3 - y1) << 16) / (x3 - x1);
354 fp_y1 = (y1 << 16) + (1<<15) + (fp_dy1 >> 1);
355
356 if (x1 < x2) /* first part */
357 {
358 fp_dy2 = ((y2 - y1) << 16) / (x2 - x1);
359 fp_y2 = (y1 << 16) + (1<<15) + (fp_dy2 >> 1);
360 for (x = x1; x < x2; x++)
361 {
362 gray_vline(x, fp_y1 >> 16, fp_y2 >> 16);
363 fp_y1 += fp_dy1;
364 fp_y2 += fp_dy2;
365 }
366 }
367 if (x2 < x3) /* second part */
368 {
369 fp_dy2 = ((y3 - y2) << 16) / (x3 - x2);
370 fp_y2 = (y2 << 16) + (1<<15) + (fp_dy2 >> 1);
371 for (x = x2; x < x3; x++)
372 {
373 gray_vline(x, fp_y1 >> 16, fp_y2 >> 16);
374 fp_y1 += fp_dy1;
375 fp_y2 += fp_dy2;
376 }
377 }
378 }
379}
380
381/* About Rockbox' internal monochrome bitmap format:
382 *
383 * A bitmap contains one bit for every pixel that defines if that pixel is
384 * foreground (1) or background (0). Bits within a byte are arranged
385 * vertically, LSB at top.
386 * The bytes are stored in row-major order, with byte 0 being top left,
387 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
388 * 0..7, the second row defines pixel row 8..15 etc.
389 *
390 * This is similar to the internal lcd hw format. */
391
392/* Draw a partial monochrome bitmap */
393void gray_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
394 int stride, int x, int y, int width, int height)
395{
396 const unsigned char *src_end;
397 unsigned char *dst, *dst_end;
398 void (*fgfunc)(unsigned char *address);
399 void (*bgfunc)(unsigned char *address);
400
401 /* nothing to draw? */
402 if ((width <= 0) || (height <= 0) || (x >= _gray_info.width)
403 || (y >= _gray_info.height) || (x + width <= 0) || (y + height <= 0))
404 return;
405
406 /* clipping */
407 if (x < 0)
408 {
409 width += x;
410 src_x -= x;
411 x = 0;
412 }
413 if (y < 0)
414 {
415 height += y;
416 src_y -= y;
417 y = 0;
418 }
419 if (x + width > _gray_info.width)
420 width = _gray_info.width - x;
421 if (y + height > _gray_info.height)
422 height = _gray_info.height - y;
423
424 src += MULU16(stride, src_y >> 3) + src_x; /* move starting point */
425 src_y &= 7;
426 src_end = src + width;
427
428 dst = &_gray_info.cur_buffer[MULU16(x, _gray_info.height) + y];
429 fgfunc = _gray_pixelfuncs[_gray_info.drawmode];
430 bgfunc = _gray_pixelfuncs[_gray_info.drawmode ^ DRMODE_INVERSEVID];
431
432 do
433 {
434 const unsigned char *src_col = src++;
435 unsigned char *dst_col = dst;
436 unsigned char data = *src_col >> src_y;
437 int numbits = 8 - src_y;
438
439 dst_end = dst_col + height;
440 do
441 {
442 if (data & 0x01)
443 fgfunc(dst_col++);
444 else
445 bgfunc(dst_col++);
446
447 data >>= 1;
448 if (--numbits == 0)
449 {
450 src_col += stride;
451 data = *src_col;
452 numbits = 8;
453 }
454 }
455 while (dst_col < dst_end);
456
457 dst += _gray_info.height;
458 }
459 while (src < src_end);
460}
461
462/* Draw a full monochrome bitmap */
463void gray_mono_bitmap(const unsigned char *src, int x, int y, int width, int height)
464{
465 gray_mono_bitmap_part(src, 0, 0, width, x, y, width, height);
466}
467
468/* Draw a partial greyscale bitmap, canonical format */
469void gray_gray_bitmap_part(const unsigned char *src, int src_x, int src_y,
470 int stride, int x, int y, int width, int height)
471{
472 const unsigned char *src_end;
473 unsigned char *dst, *dst_end;
474
475 /* nothing to draw? */
476 if ((width <= 0) || (height <= 0) || (x >= _gray_info.width)
477 || (y >= _gray_info.height) || (x + width <= 0) || (y + height <= 0))
478 return;
479
480 /* clipping */
481 if (x < 0)
482 {
483 width += x;
484 src_x -= x;
485 x = 0;
486 }
487 if (y < 0)
488 {
489 height += y;
490 src_y -= y;
491 y = 0;
492 }
493 if (x + width > _gray_info.width)
494 width = _gray_info.width - x;
495 if (y + height > _gray_info.height)
496 height = _gray_info.height - y;
497
498 src += MULU16(stride, src_y) + src_x; /* move starting point */
499 src_end = src + width;
500 dst = &_gray_info.cur_buffer[MULU16(x, _gray_info.height) + y];
501
502 do
503 {
504 const unsigned char *src_col = src++;
505 unsigned char *dst_col = dst;
506
507 dst_end = dst_col + height;
508 do
509 {
510 unsigned data = MULU16(_LEVEL_FAC * _gray_info.depth, *src_col) + 127;
511 *dst_col++ = (data + (data >> 8)) >> 8; /* approx. data / 255 */
512 src_col += stride;
513 }
514 while (dst_col < dst_end);
515
516 dst += _gray_info.height;
517 }
518 while (src < src_end);
519}
520
521/* Draw a full greyscale bitmap, canonical format */
522void gray_gray_bitmap(const unsigned char *src, int x, int y, int width,
523 int height)
524{
525 gray_gray_bitmap_part(src, 0, 0, width, x, y, width, height);
526}
527
528/* Put a string at a given pixel position, skipping first ofs pixel columns */
529void gray_putsxyofs(int x, int y, int ofs, const unsigned char *str)
530{
531 int ch;
532 struct font* pf = font_get(_gray_info.curfont);
533
534 while ((ch = *str++) != '\0' && x < _gray_info.width)
535 {
536 int width;
537 const unsigned char *bits;
538
539 /* check input range */
540 if (ch < pf->firstchar || ch >= pf->firstchar+pf->size)
541 ch = pf->defaultchar;
542 ch -= pf->firstchar;
543
544 /* get proportional width and glyph bits */
545 width = pf->width ? pf->width[ch] : pf->maxwidth;
546
547 if (ofs > width)
548 {
549 ofs -= width;
550 continue;
551 }
552
553 bits = pf->bits + (pf->offset ?
554 pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch));
555
556 gray_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
557
558 x += width - ofs;
559 ofs = 0;
560 }
561}
562
563/* Put a string at a given pixel position */
564void gray_putsxy(int x, int y, const unsigned char *str)
565{
566 gray_putsxyofs(x, y, 0, str);
567}
568
569/*** Unbuffered drawing functions ***/
570
571/* Clear the greyscale display (sets all pixels to white) */
572void gray_ub_clear_display(void)
573{
574 _gray_rb->memset(_gray_info.plane_data, 0, MULU16(_gray_info.depth,
575 _gray_info.plane_size));
576}
577
578/* Write a pixel block, defined by their brightnesses in a greymap.
579 Address is the byte in the first bitplane, src is the greymap start address,
580 stride is the increment for the greymap to get to the next pixel, mask
581 determines which pixels of the destination block are changed. For "0" bits,
582 the src address is not incremented! */
583static void _writearray(unsigned char *address, const unsigned char *src,
584 int stride, unsigned mask)
585{
586#if (CONFIG_CPU == SH7034) && (LCD_DEPTH == 1)
587 unsigned long pat_stack[8];
588 unsigned long *pat_ptr = &pat_stack[8];
589 unsigned char *end_addr;
590
591 /* precalculate the bit patterns with random shifts
592 for all 8 pixels and put them on an extra "stack" */
593 asm (
594 "mov #8,r3 \n" /* loop count in r3: 8 pixels */
595 "mov %7,r2 \n" /* copy mask -- gcc bug workaround */
596
597 ".wa_loop: \n" /** load pattern for pixel **/
598 "mov #0,r0 \n" /* pattern for skipped pixel must be 0 */
599 "shlr r2 \n" /* shift out lsb of mask */
600 "bf .wa_skip \n" /* skip this pixel */
601
602 "mov.b @%2,r0 \n" /* load src byte */
603 "extu.b r0,r0 \n" /* extend unsigned */
604 "mulu %4,r0 \n" /* macl = byte * depth; */
605 "sts macl,r1 \n" /* r1 = macl; */
606 "add #127,r1 \n" /* byte += 127; */
607 "mov r1,r0 \n"
608 "shlr8 r1 \n"
609 "add r1,r0 \n" /* byte += byte >> 8; */
610 "shlr8 r0 \n" /* byte >>= 8; */
611 "shll2 r0 \n"
612 "mov.l @(r0,%5),r4 \n" /* r4 = bitpattern[byte]; */
613
614 "mov #75,r0 \n"
615 "mulu r0,%0 \n" /* multiply by 75 */
616 "sts macl,%0 \n"
617 "add #74,%0 \n" /* add another 74 */
618 /* Since the lower bits are not very random: */
619 "swap.b %0,r1 \n" /* get bits 8..15 (need max. 5) */
620 "and %6,r1 \n" /* mask out unneeded bits */
621
622 "cmp/hs %4,r1 \n" /* random >= depth ? */
623 "bf .wa_ntrim \n"
624 "sub %4,r1 \n" /* yes: random -= depth; */
625 ".wa_ntrim: \n"
626
627 "mov.l .ashlsi3,r0 \n" /** rotate pattern **/
628 "jsr @r0 \n" /* r4 -> r0, shift left by r5 */
629 "mov r1,r5 \n"
630
631 "mov %4,r5 \n"
632 "sub r1,r5 \n" /* r5 = depth - r1 */
633 "mov.l .lshrsi3,r1 \n"
634 "jsr @r1 \n" /* r4 -> r0, shift right by r5 */
635 "mov r0,r1 \n" /* store previous result in r1 */
636
637 "or r1,r0 \n" /* rotated_pattern = r0 | r1 */
638
639 ".wa_skip: \n"
640 "mov.l r0,@-%1 \n" /* push on pattern stack */
641
642 "add %3,%2 \n" /* src += stride; */
643 "add #-1,r3 \n" /* decrease loop count */
644 "cmp/pl r3 \n" /* loop count > 0? */
645 "bt .wa_loop \n" /* yes: loop */
646 : /* outputs */
647 /* %0, in & out */ "+r"(_gray_random_buffer),
648 /* %1, in & out */ "+r"(pat_ptr)
649 : /* inputs */
650 /* %2 */ "r"(src),
651 /* %3 */ "r"(stride),
652 /* %4 */ "r"(_gray_info.depth),
653 /* %5 */ "r"(_gray_info.bitpattern),
654 /* %6 */ "r"(_gray_info.randmask),
655 /* %7 */ "r"(mask)
656 : /* clobbers */
657 "r0", "r1", "r2", "r3", "r4", "r5", "macl", "pr"
658 );
659
660 end_addr = address + MULU16(_gray_info.depth, _gray_info.plane_size);
661
662 /* set the bits for all 8 pixels in all bytes according to the
663 * precalculated patterns on the pattern stack */
664 asm (
665 "mov.l @%3+,r1 \n" /* pop all 8 patterns */
666 "mov.l @%3+,r2 \n"
667 "mov.l @%3+,r3 \n"
668 "mov.l @%3+,r8 \n"
669 "mov.l @%3+,r9 \n"
670 "mov.l @%3+,r10 \n"
671 "mov.l @%3+,r11 \n"
672 "mov.l @%3+,r12 \n"
673
674 "not %4,%4 \n" /* "set" mask -> "keep" mask */
675 "extu.b %4,%4 \n" /* mask out high bits */
676 "tst %4,%4 \n" /* nothing to keep? */
677 "bt .wa_sloop \n" /* yes: jump to short loop */
678
679 ".wa_floop: \n" /** full loop (there are bits to keep)**/
680 "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */
681 "rotcl r0 \n" /* rotate t bit into r0 */
682 "shlr r2 \n"
683 "rotcl r0 \n"
684 "shlr r3 \n"
685 "rotcl r0 \n"
686 "shlr r8 \n"
687 "rotcl r0 \n"
688 "shlr r9 \n"
689 "rotcl r0 \n"
690 "shlr r10 \n"
691 "rotcl r0 \n"
692 "shlr r11 \n"
693 "rotcl r0 \n"
694 "shlr r12 \n"
695 "mov.b @%0,%3 \n" /* read old value */
696 "rotcl r0 \n"
697 "and %4,%3 \n" /* mask out unneeded bits */
698 "or r0,%3 \n" /* set new bits */
699 "mov.b %3,@%0 \n" /* store value to bitplane */
700 "add %2,%0 \n" /* advance to next bitplane */
701 "cmp/hi %0,%1 \n" /* last bitplane done? */
702 "bt .wa_floop \n" /* no: loop */
703
704 "bra .wa_end \n"
705 "nop \n"
706
707 ".wa_sloop: \n" /** short loop (nothing to keep) **/
708 "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */
709 "rotcl r0 \n" /* rotate t bit into r0 */
710 "shlr r2 \n"
711 "rotcl r0 \n"
712 "shlr r3 \n"
713 "rotcl r0 \n"
714 "shlr r8 \n"
715 "rotcl r0 \n"
716 "shlr r9 \n"
717 "rotcl r0 \n"
718 "shlr r10 \n"
719 "rotcl r0 \n"
720 "shlr r11 \n"
721 "rotcl r0 \n"
722 "shlr r12 \n"
723 "rotcl r0 \n"
724 "mov.b r0,@%0 \n" /* store byte to bitplane */
725 "add %2,%0 \n" /* advance to next bitplane */
726 "cmp/hi %0,%1 \n" /* last bitplane done? */
727 "bt .wa_sloop \n" /* no: loop */
728
729 ".wa_end: \n"
730 : /* outputs */
731 : /* inputs */
732 /* %0 */ "r"(address),
733 /* %1 */ "r"(end_addr),
734 /* %2 */ "r"(_gray_info.plane_size),
735 /* %3 */ "r"(pat_ptr),
736 /* %4 */ "r"(mask)
737 : /* clobbers */
738 "r0", "r1", "r2", "r3", "r8", "r9", "r10", "r11", "r12"
739 );
740#endif
741}
742
743#if CONFIG_CPU == SH7034
744/* References to C library routines used in _writearray() */
745asm (
746 ".align 2 \n"
747".ashlsi3: \n" /* C library routine: */
748 ".long ___ashlsi3 \n" /* shift r4 left by r5, return in r0 */
749".lshrsi3: \n" /* C library routine: */
750 ".long ___lshrsi3 \n" /* shift r4 right by r5, return in r0 */
751 /* both routines preserve r4, destroy r5 and take ~16 cycles */
752);
753#endif
754
755/* Draw a partial greyscale bitmap, canonical format */
756void gray_ub_gray_bitmap_part(const unsigned char *src, int src_x, int src_y,
757 int stride, int x, int y, int width, int height)
758{
759 int shift, ny;
760 unsigned char *dst, *dst_end;
761 unsigned mask, mask_bottom;
762
763 /* nothing to draw? */
764 if ((width <= 0) || (height <= 0) || (x >= _gray_info.width)
765 || (y >= _gray_info.height) || (x + width <= 0) || (y + height <= 0))
766 return;
767
768 /* clipping */
769 if (x < 0)
770 {
771 width += x;
772 src_x -= x;
773 x = 0;
774 }
775 if (y < 0)
776 {
777 height += y;
778 src_y -= y;
779 y = 0;
780 }
781 if (x + width > _gray_info.width)
782 width = _gray_info.width - x;
783 if (y + height > _gray_info.height)
784 height = _gray_info.height - y;
785
786 shift = y & (_PBLOCK-1);
787 src += MULU16(stride, src_y) + src_x - MULU16(stride, shift);
788 dst = _gray_info.plane_data + x
789 + MULU16(_gray_info.width, y >> _PBLOCK_EXP);
790 ny = height - 1 + shift;
791
792 mask = 0xFFu << shift; /* ATTN LCD_DEPTH == 2 */
793 mask_bottom = 0xFFu >> (~ny & (_PBLOCK-1));
794
795 for (; ny >= _PBLOCK; ny -= _PBLOCK)
796 {
797 const unsigned char *src_row = src;
798 unsigned char *dst_row = dst;
799
800 dst_end = dst_row + width;
801 do
802 _writearray(dst_row++, src_row++, stride, mask);
803 while (dst_row < dst_end);
804
805 src += stride << _PBLOCK_EXP;
806 dst += _gray_info.width;
807 mask = 0xFFu;
808 }
809 mask &= mask_bottom;
810 dst_end = dst + width;
811 do
812 _writearray(dst++, src++, stride, mask);
813 while (dst < dst_end);
814}
815
816/* Draw a full greyscale bitmap, canonical format */
817void gray_ub_gray_bitmap(const unsigned char *src, int x, int y, int width,
818 int height)
819{
820 gray_ub_gray_bitmap_part(src, 0, 0, width, x, y, width, height);
821}
822
823
824#endif /* HAVE_LCD_BITMAP */
825#endif /* !SIMULATOR */
826