diff options
Diffstat (limited to 'apps/plugins/lib/gray_draw.c')
-rw-r--r-- | apps/plugins/lib/gray_draw.c | 826 |
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 | |||
34 | static void setpixel(unsigned char *address) | ||
35 | { | ||
36 | *address = _gray_info.fg_brightness; | ||
37 | } | ||
38 | |||
39 | static void clearpixel(unsigned char *address) | ||
40 | { | ||
41 | *address = _gray_info.bg_brightness; | ||
42 | } | ||
43 | |||
44 | static void flippixel(unsigned char *address) | ||
45 | { | ||
46 | *address = _LEVEL_FAC * _gray_info.depth - *address; | ||
47 | } | ||
48 | |||
49 | static void nopixel(unsigned char *address) | ||
50 | { | ||
51 | (void)address; | ||
52 | } | ||
53 | |||
54 | void (* 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 */ | ||
62 | void 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 */ | ||
72 | void 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 */ | ||
81 | void 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) */ | ||
153 | void 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) */ | ||
191 | void 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 */ | ||
239 | void 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 */ | ||
254 | void 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 */ | ||
312 | void 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 */ | ||
393 | void 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 */ | ||
463 | void 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 */ | ||
469 | void 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 */ | ||
522 | void 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 */ | ||
529 | void 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 */ | ||
564 | void 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) */ | ||
572 | void 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! */ | ||
583 | static 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() */ | ||
745 | asm ( | ||
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 */ | ||
756 | void 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 */ | ||
817 | void 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 | |||