summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/lib/gray.c1878
-rw-r--r--apps/plugins/lib/gray.h519
-rw-r--r--apps/plugins/lib/gray_black_display.c44
-rw-r--r--apps/plugins/lib/gray_blockfuncs.c262
-rw-r--r--apps/plugins/lib/gray_clear_display.c44
-rw-r--r--apps/plugins/lib/gray_core.c252
-rw-r--r--apps/plugins/lib/gray_deferred_update.c50
-rw-r--r--apps/plugins/lib/gray_drawbitmap.c115
-rw-r--r--apps/plugins/lib/gray_drawgraymap.c274
-rw-r--r--apps/plugins/lib/gray_drawline.c119
-rw-r--r--apps/plugins/lib/gray_drawpixel.c55
-rw-r--r--apps/plugins/lib/gray_drawrect.c62
-rw-r--r--apps/plugins/lib/gray_fillrect.c92
-rw-r--r--apps/plugins/lib/gray_getstringsize.c64
-rw-r--r--apps/plugins/lib/gray_horline.c65
-rw-r--r--apps/plugins/lib/gray_pixelfuncs.c245
-rw-r--r--apps/plugins/lib/gray_position_display.c57
-rw-r--r--apps/plugins/lib/gray_putsxy.c67
-rw-r--r--apps/plugins/lib/gray_scroll_down.c134
-rw-r--r--apps/plugins/lib/gray_scroll_down8.c69
-rw-r--r--apps/plugins/lib/gray_scroll_left.c100
-rw-r--r--apps/plugins/lib/gray_scroll_right.c100
-rw-r--r--apps/plugins/lib/gray_scroll_up.c135
-rw-r--r--apps/plugins/lib/gray_scroll_up8.c69
-rw-r--r--apps/plugins/lib/gray_set_background.c46
-rw-r--r--apps/plugins/lib/gray_set_drawinfo.c47
-rw-r--r--apps/plugins/lib/gray_set_drawmode.c50
-rw-r--r--apps/plugins/lib/gray_set_foreground.c46
-rw-r--r--apps/plugins/lib/gray_setfont.c45
-rw-r--r--apps/plugins/lib/gray_verline.c88
30 files changed, 3110 insertions, 2083 deletions
diff --git a/apps/plugins/lib/gray.c b/apps/plugins/lib/gray.c
deleted file mode 100644
index e68e5eef7b..0000000000
--- a/apps/plugins/lib/gray.c
+++ /dev/null
@@ -1,1878 +0,0 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11*
12* This is a generic framework to use grayscale display within Rockbox
13* plugins. It obviously does not work for the player.
14*
15* Copyright (C) 2004 Jens Arnold
16*
17* All files in this archive are subject to the GNU General Public License.
18* See the file COPYING in the source tree root for full license agreement.
19*
20* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21* KIND, either express or implied.
22*
23****************************************************************************/
24
25#ifndef SIMULATOR /* not for simulator by now */
26#include "plugin.h"
27
28#ifdef HAVE_LCD_BITMAP /* and also not for the Player */
29#include "gray.h"
30
31/**** internal core functions and definitions ****/
32
33/* You do not want to touch these if you don't know exactly what you're
34 * doing. */
35
36#define GRAY_RUNNING 0x0001 /* grayscale overlay is running */
37#define GRAY_DEFERRED_UPDATE 0x0002 /* lcd_update() requested */
38
39/* unsigned 16 bit multiplication (a single instruction on the SH) */
40#define MULU16(a, b) ((unsigned long) \
41 (((unsigned short) (a)) * ((unsigned short) (b))))
42
43/* The grayscale buffer management structure */
44typedef struct
45{
46 int x;
47 int by; /* 8-pixel units */
48 int width;
49 int height;
50 int bheight; /* 8-pixel units */
51 int plane_size;
52 int depth; /* number_of_bitplanes = (number_of_grayscales - 1) */
53 int cur_plane; /* for the timer isr */
54 unsigned long randmask; /* mask for random value in _writepixel() */
55 unsigned long flags; /* various flags, see #defines */
56 unsigned long *bitpattern; /* pointer to start of pattern table */
57 unsigned char *data; /* pointer to start of bitplane data */
58 unsigned long fg_pattern; /* current foreground pattern */
59 unsigned long bg_pattern; /* current background pattern */
60 int drawmode; /* current draw mode */
61 struct font *curfont; /* current selected font */
62} tGraybuf;
63
64/** globals **/
65
66static struct plugin_api *rb = NULL; /* global api struct pointer */
67static tGraybuf *graybuf = NULL; /* pointer to grayscale buffer */
68static short random_buffer;
69
70/** prototypes **/
71
72static void _timer_isr(void);
73
74static void _writepixel(int x, int y, unsigned long pattern);
75static void _invertpixel(int x, int y, unsigned long pattern);
76
77static void _writearray(unsigned char *address, unsigned char *src, int stride,
78 unsigned mask);
79
80static void _writeblock(unsigned char *address, unsigned mask, unsigned bits);
81static void _invertblock(unsigned char *address, unsigned mask, unsigned bits);
82static void _writeblockfg(unsigned char *address, unsigned mask, unsigned bits);
83static void _writeblockbg(unsigned char *address, unsigned mask, unsigned bits);
84
85/** function pointer arrays **/
86
87static void (*_pixelfuncs[4])(int x, int y, unsigned long pattern) = {
88 _invertpixel, _writepixel, _writepixel, _writepixel
89};
90
91static void (*_blockfuncs[4])(unsigned char *address, unsigned mask,
92 unsigned bits) = {
93 _invertblock, _writeblockfg, _writeblockbg, _writeblock
94};
95
96/** implementation **/
97
98/* timer interrupt handler: display next bitplane */
99static void _timer_isr(void)
100{
101 rb->lcd_blit(graybuf->data + MULU16(graybuf->plane_size, graybuf->cur_plane),
102 graybuf->x, graybuf->by, graybuf->width, graybuf->bheight,
103 graybuf->width);
104
105 if (++graybuf->cur_plane >= graybuf->depth)
106 graybuf->cur_plane = 0;
107
108 if (graybuf->flags & GRAY_DEFERRED_UPDATE) /* lcd_update() requested? */
109 {
110 int x1 = MAX(graybuf->x, 0);
111 int x2 = MIN(graybuf->x + graybuf->width, LCD_WIDTH);
112 int y1 = MAX(graybuf->by << 3, 0);
113 int y2 = MIN((graybuf->by << 3) + graybuf->height, LCD_HEIGHT);
114
115 if (y1 > 0) /* refresh part above overlay, full width */
116 rb->lcd_update_rect(0, 0, LCD_WIDTH, y1);
117
118 if (y2 < LCD_HEIGHT) /* refresh part below overlay, full width */
119 rb->lcd_update_rect(0, y2, LCD_WIDTH, LCD_HEIGHT - y2);
120
121 if (x1 > 0) /* refresh part to the left of overlay */
122 rb->lcd_update_rect(0, y1, x1, y2 - y1);
123
124 if (x2 < LCD_WIDTH) /* refresh part to the right of overlay */
125 rb->lcd_update_rect(x2, y1, LCD_WIDTH - x2, y2 - y1);
126
127 graybuf->flags &= ~GRAY_DEFERRED_UPDATE; /* clear request */
128 }
129}
130
131/* Set a pixel to a specific bit pattern (low level routine) */
132static void _writepixel(int x, int y, unsigned long pattern)
133{
134 register unsigned mask, random;
135 register unsigned char *address;
136
137 /* Some (pseudo-)random function must be used here to shift the bit
138 * pattern randomly, otherwise you would get flicker and/or moire.
139 * Since rand() is relatively slow, I've implemented a simple, but very
140 * fast pseudo-random generator based on linear congruency in assembler.
141 * It delivers max. 16 pseudo-random bits in each iteration. */
142
143 /* simple but fast pseudo-random generator */
144 asm (
145 "mov #75,r1 \n"
146 "mulu %1,r1 \n" /* multiply by 75 */
147 "sts macl,%1 \n" /* get result */
148 "add #74,%1 \n" /* add another 74 */
149 /* Since the lower bits are not very random: */
150 "swap.b %1,%0 \n" /* get bits 8..15 (need max. 5) */
151 "and %2,%0 \n" /* mask out unneeded bits */
152 : /* outputs */
153 /* %0 */ "=&r"(random),
154 /* %1, in & out */ "+r"(random_buffer)
155 : /* inputs */
156 /* %2 */ "r"(graybuf->randmask)
157 : /* clobbers */
158 "r1", "macl"
159 );
160
161 /* precalculate mask and byte address in first bitplane */
162 asm (
163 "mov %3,%0 \n" /* take y as base for address offset */
164 "shlr2 %0 \n" /* shift right by 3 (= divide by 8) */
165 "shlr %0 \n"
166 "mulu %0,%2 \n" /* multiply with width */
167 "and #7,%3 \n" /* get lower 3 bits of y */
168 "sts macl,%0 \n" /* get mulu result */
169 "add %4,%0 \n" /* add base + x to get final address */
170
171 "mov %3,%1 \n" /* move lower 3 bits of y out of r0 */
172 "mova .wp_masktable,%3\n" /* get address of mask table in r0 */
173 "bra .wp_predone \n" /* skip the table */
174 "mov.b @(%3,%1),%1 \n" /* get entry from mask table */
175
176 ".align 2 \n"
177 ".wp_masktable: \n" /* mask table */
178 ".byte 0x01 \n"
179 ".byte 0x02 \n"
180 ".byte 0x04 \n"
181 ".byte 0x08 \n"
182 ".byte 0x10 \n"
183 ".byte 0x20 \n"
184 ".byte 0x40 \n"
185 ".byte 0x80 \n"
186
187 ".wp_predone: \n"
188 : /* outputs */
189 /* %0 */ "=&r"(address),
190 /* %1 */ "=&r"(mask)
191 : /* inputs */
192 /* %2 */ "r"(graybuf->width),
193 /* %3 = r0 */ "z"(y),
194 /* %4 */ "r"(graybuf->data + x)
195 : /* clobbers */
196 "macl"
197 );
198
199 /* the hard part: set bits in all bitplanes according to pattern */
200 asm volatile (
201 "cmp/hs %1,%5 \n" /* random >= depth ? */
202 "bf .wp_ntrim \n"
203 "sub %1,%5 \n" /* yes: random -= depth */
204 /* it's sufficient to do this once, since the mask guarantees
205 * random < 2 * depth */
206 ".wp_ntrim: \n"
207
208 /* calculate some addresses */
209 "mulu %4,%1 \n" /* end address offset */
210 "not %3,r1 \n" /* get inverse mask (for "and") */
211 "sts macl,%1 \n" /* result of mulu */
212 "mulu %4,%5 \n" /* address offset of <random>'th plane */
213 "add %2,%1 \n" /* end offset -> end address */
214 "sts macl,%5 \n" /* result of mulu */
215 "add %2,%5 \n" /* address of <random>'th plane */
216 "bra .wp_start1 \n"
217 "mov %5,r2 \n" /* copy address */
218
219 /* first loop: set bits from <random>'th bitplane to last */
220 ".wp_loop1: \n"
221 "mov.b @r2,r3 \n" /* get data byte */
222 "shlr %0 \n" /* shift bit mask, sets t bit */
223 "and r1,r3 \n" /* reset bit (-> "white") */
224 "bf .wp_white1 \n" /* t=0? -> "white" bit */
225 "or %3,r3 \n" /* set bit ("black" bit) */
226 ".wp_white1: \n"
227 "mov.b r3,@r2 \n" /* store data byte */
228 "add %4,r2 \n" /* advance address to next bitplane */
229 ".wp_start1: \n"
230 "cmp/hi r2,%1 \n" /* address < end address ? */
231 "bt .wp_loop1 \n"
232
233 "bra .wp_start2 \n"
234 "nop \n"
235
236 /* second loop: set bits from first to <random-1>'th bitplane
237 * Bit setting works the other way round here to equalize average
238 * execution times for bright and dark pixels */
239 ".wp_loop2: \n"
240 "mov.b @%2,r3 \n" /* get data byte */
241 "shlr %0 \n" /* shift bit mask, sets t bit */
242 "or %3,r3 \n" /* set bit (-> "black") */
243 "bt .wp_black2 \n" /* t=1? -> "black" bit */
244 "and r1,r3 \n" /* reset bit ("white" bit) */
245 ".wp_black2: \n"
246 "mov.b r3,@%2 \n" /* store data byte */
247 "add %4,%2 \n" /* advance address to next bitplane */
248 ".wp_start2: \n"
249 "cmp/hi %2,%5 \n" /* address < <random>'th address ? */
250 "bt .wp_loop2 \n"
251 : /* outputs */
252 : /* inputs */
253 /* %0 */ "r"(pattern),
254 /* %1 */ "r"(graybuf->depth),
255 /* %2 */ "r"(address),
256 /* %3 */ "r"(mask),
257 /* %4 */ "r"(graybuf->plane_size),
258 /* %5 */ "r"(random)
259 : /* clobbers */
260 "r1", "r2", "r3", "macl"
261 );
262}
263
264/* invert all bits for one pixel (low level routine) */
265static void _invertpixel(int x, int y, unsigned long pattern)
266{
267 register unsigned mask;
268 register unsigned char *address;
269
270 (void) pattern; /* not used for invert */
271
272 /* precalculate mask and byte address in first bitplane */
273 asm (
274 "mov %3,%0 \n" /* take y as base for address offset */
275 "shlr2 %0 \n" /* shift right by 3 (= divide by 8) */
276 "shlr %0 \n"
277 "mulu %0,%2 \n" /* multiply with width */
278 "and #7,%3 \n" /* get lower 3 bits of y */
279 "sts macl,%0 \n" /* get mulu result */
280 "add %4,%0 \n" /* add base + x to get final address */
281
282 "mov %3,%1 \n" /* move lower 3 bits of y out of r0 */
283 "mova .ip_masktable,%3\n" /* get address of mask table in r0 */
284 "bra .ip_predone \n" /* skip the table */
285 "mov.b @(%3,%1),%1 \n" /* get entry from mask table */
286
287 ".align 2 \n"
288 ".ip_masktable: \n" /* mask table */
289 ".byte 0x01 \n"
290 ".byte 0x02 \n"
291 ".byte 0x04 \n"
292 ".byte 0x08 \n"
293 ".byte 0x10 \n"
294 ".byte 0x20 \n"
295 ".byte 0x40 \n"
296 ".byte 0x80 \n"
297
298 ".ip_predone: \n"
299 : /* outputs */
300 /* %0 */ "=&r"(address),
301 /* %1 */ "=&r"(mask)
302 : /* inputs */
303 /* %2 */ "r"(graybuf->width),
304 /* %3 = r0 */ "z"(y),
305 /* %4 */ "r"(graybuf->data + x)
306 : /* clobbers */
307 "macl"
308 );
309
310 /* invert bits in all bitplanes */
311 asm volatile (
312 "mov #0,r1 \n" /* current_plane = 0 */
313
314 ".ip_loop: \n"
315 "mov.b @%1,r2 \n" /* get data byte */
316 "add #1,r1 \n" /* current_plane++; */
317 "xor %2,r2 \n" /* invert bits */
318 "mov.b r2,@%1 \n" /* store data byte */
319 "add %3,%1 \n" /* advance address to next bitplane */
320 "cmp/hi r1,%0 \n" /* current_plane < depth ? */
321 "bt .ip_loop \n"
322 : /* outputs */
323 : /* inputs */
324 /* %0 */ "r"(graybuf->depth),
325 /* %1 */ "r"(address),
326 /* %2 */ "r"(mask),
327 /* %3 */ "r"(graybuf->plane_size)
328 : /* clobbers */
329 "r1", "r2"
330 );
331}
332
333/* Write an 8-pixel block, defined by their brightnesses in a graymap.
334 * Address is the byte in the first bitplane, src is the graymap start address,
335 * stride is the increment for the graymap to get to the next pixel, mask
336 * determines which pixels of the destination block are changed. For "0" bits,
337 * the src address is not incremented! */
338static void _writearray(unsigned char *address, unsigned char *src, int stride,
339 unsigned mask)
340{
341 unsigned long pat_stack[8];
342 register unsigned char *end_addr;
343 register unsigned long *pat_ptr = &pat_stack[8];
344
345 /* precalculate the bit patterns with random shifts (same RNG as
346 * _writepixel, see there for an explanation) for all 8 pixels and put them
347 * on an extra "stack" */
348 asm (
349 "mov #8,r3 \n" /* loop count in r3: 8 pixels */
350 "mov %7,r2 \n" /* copy mask */
351
352 ".wa_loop: \n" /** load pattern for pixel **/
353 "mov #0,r0 \n" /* pattern for skipped pixel must be 0 */
354 "shlr r2 \n" /* shift out lsb of mask */
355 "bf .wa_skip \n" /* skip this pixel */
356
357 "mov.b @%2,r0 \n" /* load src byte */
358 "extu.b r0,r0 \n" /* extend unsigned */
359 "mulu %4,r0 \n" /* macl = byte * depth; */
360 "add %3,%2 \n" /* src += stride; */
361 "sts macl,r4 \n" /* r4 = macl; */
362 "add r4,r0 \n" /* byte += r4; */
363 "shlr8 r0 \n" /* byte >>= 8; */
364 "shll2 r0 \n"
365 "mov.l @(r0,%5),r4 \n" /* r4 = bitpattern[byte]; */
366
367 "mov #75,r0 \n"
368 "mulu r0,%0 \n" /* multiply by 75 */
369 "sts macl,%0 \n"
370 "add #74,%0 \n" /* add another 74 */
371 /* Since the lower bits are not very random: */
372 "swap.b %0,r1 \n" /* get bits 8..15 (need max. 5) */
373 "and %6,r1 \n" /* mask out unneeded bits */
374
375 "cmp/hs %4,r1 \n" /* random >= depth ? */
376 "bf .wa_ntrim \n"
377 "sub %4,r1 \n" /* yes: random -= depth; */
378 ".wa_ntrim: \n"
379
380 "mov.l .ashlsi3,r0 \n" /** rotate pattern **/
381 "jsr @r0 \n" /* r4 -> r0, shift left by r5 */
382 "mov r1,r5 \n"
383
384 "mov %4,r5 \n"
385 "sub r1,r5 \n" /* r5 = depth - r1 */
386 "mov.l .lshrsi3,r1 \n"
387 "jsr @r1 \n" /* r4 -> r0, shift right by r5 */
388 "mov r0,r1 \n" /* store previous result in r1 */
389
390 "or r1,r0 \n" /* rotated_pattern = r0 | r1 */
391
392 ".wa_skip: \n"
393 "mov.l r0,@-%1 \n" /* push on pattern stack */
394
395 "add #-1,r3 \n" /* decrease loop count */
396 "cmp/pl r3 \n" /* loop count > 0? */
397 "bt .wa_loop \n" /* yes: loop */
398 : /* outputs */
399 /* %0, in & out */ "+r"(random_buffer),
400 /* %1, in & out */ "+r"(pat_ptr)
401 : /* inputs */
402 /* %2 */ "r"(src),
403 /* %3 */ "r"(stride),
404 /* %4 */ "r"(graybuf->depth),
405 /* %5 */ "r"(graybuf->bitpattern),
406 /* %6 */ "r"(graybuf->randmask),
407 /* %7 */ "r"(mask)
408 : /* clobbers */
409 "r0", "r1", "r2", "r3", "r4", "r5", "macl"
410 );
411
412 end_addr = address + MULU16(graybuf->depth, graybuf->plane_size);
413
414 /* set the bits for all 8 pixels in all bytes according to the
415 * precalculated patterns on the pattern stack */
416 asm volatile (
417 "mov.l @%3+,r1 \n" /* pop all 8 patterns */
418 "mov.l @%3+,r2 \n"
419 "mov.l @%3+,r3 \n"
420 "mov.l @%3+,r8 \n"
421 "mov.l @%3+,r9 \n"
422 "mov.l @%3+,r10 \n"
423 "mov.l @%3+,r11 \n"
424 "mov.l @%3+,r12 \n"
425
426 "not %4,%4 \n" /* "set" mask -> "keep" mask */
427 "extu.b %4,%4 \n" /* mask out high bits */
428 "tst %4,%4 \n" /* nothing to keep? */
429 "bt .wa_sloop \n" /* yes: jump to short loop */
430
431 ".wa_floop: \n" /** full loop (there are bits to keep)**/
432 "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */
433 "rotcl r0 \n" /* rotate t bit into r0 */
434 "shlr r2 \n"
435 "rotcl r0 \n"
436 "shlr r3 \n"
437 "rotcl r0 \n"
438 "shlr r8 \n"
439 "rotcl r0 \n"
440 "shlr r9 \n"
441 "rotcl r0 \n"
442 "shlr r10 \n"
443 "rotcl r0 \n"
444 "shlr r11 \n"
445 "rotcl r0 \n"
446 "shlr r12 \n"
447 "mov.b @%0,%3 \n" /* read old value */
448 "rotcl r0 \n"
449 "and %4,%3 \n" /* mask out unneeded bits */
450 "or r0,%3 \n" /* set new bits */
451 "mov.b %3,@%0 \n" /* store value to bitplane */
452 "add %2,%0 \n" /* advance to next bitplane */
453 "cmp/hi %0,%1 \n" /* last bitplane done? */
454 "bt .wa_floop \n" /* no: loop */
455
456 "bra .wa_end \n"
457 "nop \n"
458
459 ".wa_sloop: \n" /** short loop (nothing to keep) **/
460 "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */
461 "rotcl r0 \n" /* rotate t bit into r0 */
462 "shlr r2 \n"
463 "rotcl r0 \n"
464 "shlr r3 \n"
465 "rotcl r0 \n"
466 "shlr r8 \n"
467 "rotcl r0 \n"
468 "shlr r9 \n"
469 "rotcl r0 \n"
470 "shlr r10 \n"
471 "rotcl r0 \n"
472 "shlr r11 \n"
473 "rotcl r0 \n"
474 "shlr r12 \n"
475 "rotcl r0 \n"
476 "mov.b r0,@%0 \n" /* store byte to bitplane */
477 "add %2,%0 \n" /* advance to next bitplane */
478 "cmp/hi %0,%1 \n" /* last bitplane done? */
479 "bt .wa_sloop \n" /* no: loop */
480
481 ".wa_end: \n"
482 : /* outputs */
483 : /* inputs */
484 /* %0 */ "r"(address),
485 /* %1 */ "r"(end_addr),
486 /* %2 */ "r"(graybuf->plane_size),
487 /* %3 */ "r"(pat_ptr),
488 /* %4 */ "r"(mask)
489 : /* clobbers */
490 "r0", "r1", "r2", "r3", "r8", "r9", "r10", "r11", "r12"
491 );
492}
493
494/* Write an 8-pixel block, defined by foreground and background pattern.
495 * Address is the byte in the first bitplane, mask determines which pixels to
496 * set, and bits determines if the pixel is foreground or background */
497static void _writeblock(unsigned char *address, unsigned mask, unsigned bits)
498{
499 unsigned long pat_stack[8];
500 register unsigned char *end_addr;
501 register unsigned long *pat_ptr = &pat_stack[8];
502
503 /* precalculate the bit patterns with random shifts (same RNG as _writepixel,
504 * see there for an explanation) for all 8 pixels and put them on an
505 * extra stack */
506 asm (
507 "mov #8,r3 \n" /* loop count in r3: 8 pixels */
508 "mov %6,r2 \n" /* copy mask */
509
510 ".wb_loop: \n" /** load pattern for pixel **/
511 "shlr r2 \n" /* shift out lsb of mask */
512 "bf .wb_skip \n" /* skip this pixel */
513
514 "mov %2,r4 \n" /* load foreground pattern */
515 "shlr %7 \n" /* shift out lsb of bits */
516 "bt .wb_fg \n" /* foreground? -> skip next insn */
517 "mov %3,r4 \n" /* load background pattern */
518 ".wb_fg: \n"
519
520 "mov #75,r0 \n"
521 "mulu r0,%0 \n" /* multiply by 75 */
522 "sts macl,%0 \n"
523 "add #74,%0 \n" /* add another 74 */
524 /* Since the lower bits are not very random: */
525 "swap.b %0,r1 \n" /* get bits 8..15 (need max. 5) */
526 "and %5,r1 \n" /* mask out unneeded bits */
527
528 "cmp/hs %4,r1 \n" /* random >= depth ? */
529 "bf .wb_ntrim \n"
530 "sub %4,r1 \n" /* yes: random -= depth; */
531 ".wb_ntrim: \n"
532
533 "mov.l .ashlsi3,r0 \n" /** rotate pattern **/
534 "jsr @r0 \n" /* r4 -> r0, shift left by r5 */
535 "mov r1,r5 \n"
536
537 "mov %4,r5 \n"
538 "sub r1,r5 \n" /* r5 = depth - r1 */
539 "mov.l .lshrsi3,r1 \n"
540 "jsr @r1 \n" /* r4 -> r0, shift right by r5 */
541 "mov r0,r1 \n" /* store previous result in r1 */
542
543 "bra .wb_store \n"
544 "or r1,r0 \n" /* rotated_pattern = r0 | r1 */
545
546 ".wb_skip: \n"
547 "shlr %7 \n" /* shift out lsb of bits to keep in sync */
548 "mov #0,r0 \n" /* pattern for skipped pixel must be 0 */
549
550 ".wb_store: \n"
551 "mov.l r0,@-%1 \n" /* push on pattern stack */
552
553 "add #-1,r3 \n" /* decrease loop count */
554 "cmp/pl r3 \n" /* loop count > 0? */
555 "bt .wb_loop \n" /* yes: loop */
556 : /* outputs */
557 /* %0, in & out */ "+r"(random_buffer),
558 /* %1, in & out */ "+r"(pat_ptr)
559 : /* inputs */
560 /* %2 */ "r"(graybuf->fg_pattern),
561 /* %3 */ "r"(graybuf->bg_pattern),
562 /* %4 */ "r"(graybuf->depth),
563 /* %5 */ "r"(graybuf->randmask),
564 /* %6 */ "r"(mask),
565 /* %7 */ "r"(bits)
566 : /* clobbers */
567 "r0", "r1", "r2", "r3", "r4", "r5", "macl"
568 );
569
570 end_addr = address + MULU16(graybuf->depth, graybuf->plane_size);
571
572 /* set the bits for all 8 pixels in all bytes according to the
573 * precalculated patterns on the pattern stack */
574 asm volatile (
575 "mov.l @%3+,r1 \n" /* pop all 8 patterns */
576 "mov.l @%3+,r2 \n"
577 "mov.l @%3+,r3 \n"
578 "mov.l @%3+,r8 \n"
579 "mov.l @%3+,r9 \n"
580 "mov.l @%3+,r10 \n"
581 "mov.l @%3+,r11 \n"
582 "mov.l @%3+,r12 \n"
583
584 "not %4,%4 \n" /* "set" mask -> "keep" mask */
585 "extu.b %4,%4 \n" /* mask out high bits */
586 "tst %4,%4 \n" /* nothing to keep? */
587 "bt .wb_sloop \n" /* yes: jump to short loop */
588
589 ".wb_floop: \n" /** full loop (there are bits to keep)**/
590 "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */
591 "rotcl r0 \n" /* rotate t bit into r0 */
592 "shlr r2 \n"
593 "rotcl r0 \n"
594 "shlr r3 \n"
595 "rotcl r0 \n"
596 "shlr r8 \n"
597 "rotcl r0 \n"
598 "shlr r9 \n"
599 "rotcl r0 \n"
600 "shlr r10 \n"
601 "rotcl r0 \n"
602 "shlr r11 \n"
603 "rotcl r0 \n"
604 "shlr r12 \n"
605 "mov.b @%0,%3 \n" /* read old value */
606 "rotcl r0 \n"
607 "and %4,%3 \n" /* mask out unneeded bits */
608 "or r0,%3 \n" /* set new bits */
609 "mov.b %3,@%0 \n" /* store value to bitplane */
610 "add %2,%0 \n" /* advance to next bitplane */
611 "cmp/hi %0,%1 \n" /* last bitplane done? */
612 "bt .wb_floop \n" /* no: loop */
613
614 "bra .wb_end \n"
615 "nop \n"
616
617 ".wb_sloop: \n" /** short loop (nothing to keep) **/
618 "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */
619 "rotcl r0 \n" /* rotate t bit into r0 */
620 "shlr r2 \n"
621 "rotcl r0 \n"
622 "shlr r3 \n"
623 "rotcl r0 \n"
624 "shlr r8 \n"
625 "rotcl r0 \n"
626 "shlr r9 \n"
627 "rotcl r0 \n"
628 "shlr r10 \n"
629 "rotcl r0 \n"
630 "shlr r11 \n"
631 "rotcl r0 \n"
632 "shlr r12 \n"
633 "rotcl r0 \n"
634 "mov.b r0,@%0 \n" /* store byte to bitplane */
635 "add %2,%0 \n" /* advance to next bitplane */
636 "cmp/hi %0,%1 \n" /* last bitplane done? */
637 "bt .wb_sloop \n" /* no: loop */
638
639 ".wb_end: \n"
640 : /* outputs */
641 : /* inputs */
642 /* %0 */ "r"(address),
643 /* %1 */ "r"(end_addr),
644 /* %2 */ "r"(graybuf->plane_size),
645 /* %3 */ "r"(pat_ptr),
646 /* %4 */ "r"(mask)
647 : /* clobbers */
648 "r0", "r1", "r2", "r3", "r8", "r9", "r10", "r11", "r12"
649 );
650}
651
652/* References to C library routines used in _writearray and _writeblock */
653asm (
654 ".align 2 \n"
655".ashlsi3: \n" /* C library routine: */
656 ".long ___ashlsi3 \n" /* shift r4 left by r5, return in r0 */
657".lshrsi3: \n" /* C library routine: */
658 ".long ___lshrsi3 \n" /* shift r4 right by r5, return in r0 */
659 /* both routines preserve r4, destroy r5 and take ~16 cycles */
660);
661
662/* Invert pixels within an 8-pixel block.
663 * Address is the byte in the first bitplane, mask and bits determine which
664 * pixels to invert ('And'ed together, for matching the parameters with
665 * _writeblock) */
666static void _invertblock(unsigned char *address, unsigned mask, unsigned bits)
667{
668 bits &= mask;
669 if (!bits)
670 return;
671
672 asm volatile (
673 "mov #0,r1 \n" /* current_plane = 0 */
674
675 ".im_loop: \n"
676 "mov.b @%1,r2 \n" /* get data byte */
677 "add #1,r1 \n" /* current_plane++; */
678 "xor %2,r2 \n" /* invert bits */
679 "mov.b r2,@%1 \n" /* store data byte */
680 "add %3,%1 \n" /* advance address to next bitplane */
681 "cmp/hi r1,%0 \n" /* current_plane < depth ? */
682 "bt .im_loop \n"
683 : /* outputs */
684 : /* inputs */
685 /* %0 */ "r"(graybuf->depth),
686 /* %1 */ "r"(address),
687 /* %2 */ "r"(bits),
688 /* %3 */ "r"(graybuf->plane_size)
689 : /* clobbers */
690 "r1", "r2", "macl"
691 );
692}
693
694/* Call _writeblock with the mask modified to draw foreground pixels only */
695static void _writeblockfg(unsigned char *address, unsigned mask, unsigned bits)
696{
697 mask &= bits;
698 if (mask)
699 _writeblock(address, mask, bits);
700}
701
702/* Call _writeblock with the mask modified to draw background pixels only */
703static void _writeblockbg(unsigned char *address, unsigned mask, unsigned bits)
704{
705 mask &= ~bits;
706 if (mask)
707 _writeblock(address, mask, bits);
708}
709
710/**** public functions ****/
711
712/* Initialize the framework
713 *
714 * Every framework needs such a function, and it has to be called as
715 * the very first one */
716void gray_init(struct plugin_api* newrb)
717{
718 rb = newrb;
719}
720
721/** General functions **/
722
723/* Prepare the grayscale display buffer
724 *
725 * arguments:
726 * gbuf = pointer to the memory area to use (e.g. plugin buffer)
727 * gbuf_size = max usable size of the buffer
728 * width = width in pixels (1..112)
729 * bheight = height in 8-pixel units (1..8)
730 * depth = desired number of shades - 1 (1..32)
731 *
732 * result:
733 * = depth if there was enough memory
734 * < depth if there wasn't enough memory. The number of displayable
735 * shades is smaller than desired, but it still works
736 * = 0 if there wasn't even enough memory for 1 bitplane (black & white)
737 *
738 * You can request any depth from 1 to 32, not just powers of 2. The routine
739 * performs "graceful degradation" if the memory is not sufficient for the
740 * desired depth. As long as there is at least enough memory for 1 bitplane,
741 * it creates as many bitplanes as fit into memory, although 1 bitplane will
742 * only deliver black & white display.
743 *
744 * If you need info about the memory taken by the grayscale buffer, supply an
745 * int* as the last parameter. This int will then contain the number of bytes
746 * used. The total memory needed can be calculated as follows:
747 * total_mem =
748 * sizeof(tGraybuf) (= 64 bytes currently)
749 * + sizeof(long) (= 4 bytes)
750 * + (width * bheight + sizeof(long)) * depth
751 * + 0..3 (longword alignment of grayscale display buffer)
752 */
753int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
754 int bheight, int depth, int *buf_taken)
755{
756 int possible_depth, plane_size;
757 int i, j, align;
758
759 if ((unsigned) width > LCD_WIDTH
760 || (unsigned) bheight > (LCD_HEIGHT/8)
761 || depth < 1)
762 return 0;
763
764 /* the buffer has to be long aligned */
765 align = 3 - (((unsigned long)gbuf + 3) & 3);
766 gbuf += align;
767 gbuf_size -= align;
768
769 plane_size = MULU16(width, bheight);
770 possible_depth = (gbuf_size - sizeof(tGraybuf) - sizeof(long))
771 / (plane_size + sizeof(long));
772
773 if (possible_depth < 1)
774 return 0;
775
776 depth = MIN(depth, 32);
777 depth = MIN(depth, possible_depth);
778
779 graybuf = (tGraybuf *) gbuf; /* global pointer to buffer structure */
780
781 graybuf->x = 0;
782 graybuf->by = 0;
783 graybuf->width = width;
784 graybuf->height = bheight << 3;
785 graybuf->bheight = bheight;
786 graybuf->plane_size = plane_size;
787 graybuf->depth = depth;
788 graybuf->cur_plane = 0;
789 graybuf->flags = 0;
790 graybuf->bitpattern = (unsigned long *) (gbuf + sizeof(tGraybuf));
791 graybuf->data = (unsigned char *) (graybuf->bitpattern + depth + 1);
792
793 i = depth - 1;
794 j = 8;
795 while (i != 0)
796 {
797 i >>= 1;
798 j--;
799 }
800 graybuf->randmask = 0xFFu >> j;
801
802 /* initial state is all white */
803 rb->memset(graybuf->data, 0, MULU16(depth, plane_size));
804
805 /* Precalculate the bit patterns for all possible pixel values */
806 for (i = 0; i <= depth; i++)
807 {
808 unsigned long pattern = 0;
809 int value = 0;
810
811 for (j = 0; j < depth; j++)
812 {
813 pattern <<= 1;
814 value += i;
815
816 if (value >= depth)
817 value -= depth; /* "white" bit */
818 else
819 pattern |= 1; /* "black" bit */
820 }
821 /* now the lower <depth> bits contain the pattern */
822
823 graybuf->bitpattern[i] = pattern;
824 }
825
826 graybuf->fg_pattern = graybuf->bitpattern[0]; /* black */
827 graybuf->bg_pattern = graybuf->bitpattern[depth]; /* white */
828 graybuf->drawmode = GRAY_DRAW_SOLID;
829 graybuf->curfont = FONT_SYSFIXED;
830
831 if (buf_taken) /* caller requested info about space taken */
832 {
833 *buf_taken = sizeof(tGraybuf) + sizeof(long)
834 + MULU16(plane_size + sizeof(long), depth) + align;
835 }
836
837 return depth;
838}
839
840/* Release the grayscale display buffer
841 *
842 * Switches the grayscale overlay off at first if it is still running,
843 * then sets the pointer to NULL.
844 * DO CALL either this function or at least gray_show_display(false)
845 * before you exit, otherwise nasty things may happen.
846 */
847void gray_release_buffer(void)
848{
849 gray_show_display(false);
850 graybuf = NULL;
851}
852
853/* Set position of the top left corner of the grayscale overlay
854 *
855 * x = left margin in pixels
856 * by = top margin in 8-pixel units
857 *
858 * You may set this in a way that the overlay spills across the right or
859 * bottom display border. In this case it will simply be clipped by the
860 * LCD controller. You can even set negative values, this will clip at the
861 * left or top border. I did not test it, but the limits may be +127 / -128
862 *
863 * If you use this while the grayscale overlay is running, the now-freed area
864 * will be restored.
865 */
866void gray_position_display(int x, int by)
867{
868 graybuf->x = x;
869 graybuf->by = by;
870
871 if (graybuf->flags & GRAY_RUNNING)
872 graybuf->flags |= GRAY_DEFERRED_UPDATE;
873}
874
875/* Switch the grayscale overlay on or off
876 *
877 * enable = true: the grayscale overlay is switched on if initialized
878 * = false: the grayscale overlay is switched off and the regular lcd
879 * content is restored
880 *
881 * DO NOT call lcd_update() or any other api function that directly accesses
882 * the lcd while the grayscale overlay is running! If you need to do
883 * lcd_update() to update something outside the grayscale overlay area, use
884 * gray_deferred_update() instead.
885 *
886 * Other functions to avoid are:
887 * lcd_blit() (obviously), lcd_update_rect(), lcd_set_contrast(),
888 * lcd_set_invert_display(), lcd_set_flip(), lcd_roll()
889 *
890 * The grayscale display consumes ~50 % CPU power (for a full screen overlay,
891 * less if the overlay is smaller) when switched on. You can switch the overlay
892 * on and off as many times as you want.
893 */
894void gray_show_display(bool enable)
895{
896 if (enable)
897 {
898 graybuf->flags |= GRAY_RUNNING;
899 rb->plugin_register_timer(FREQ / 67, 1, _timer_isr);
900 }
901 else
902 {
903 rb->plugin_unregister_timer();
904 graybuf->flags &= ~GRAY_RUNNING;
905 rb->lcd_update(); /* restore whatever there was before */
906 }
907}
908
909/* Set the draw mode for subsequent drawing operations
910 *
911 * drawmode =
912 * GRAY_DRAW_INVERSE: Foreground pixels are inverted, background pixels are
913 * left untouched
914 * GRAY_DRAW_FG: Only foreground pixels are drawn
915 * GRAY_DRAW_BG: Only background pixels are drawn
916 * GRAY_DRAW_SOLID: Foreground and background pixels are drawn
917 */
918void gray_set_drawmode(int drawmode)
919{
920 if ((unsigned) drawmode <= GRAY_DRAW_SOLID)
921 graybuf->drawmode = drawmode;
922}
923
924/* Set the foreground shade for subsequent drawing operations
925 *
926 * brightness = 0 (black) .. 255 (white)
927 */
928void gray_set_foreground(int brightness)
929{
930 if ((unsigned) brightness <= 255)
931 graybuf->fg_pattern = graybuf->bitpattern[MULU16(brightness,
932 graybuf->depth + 1) >> 8];
933}
934
935/* Set the background shade for subsequent drawing operations
936 *
937 * brightness = 0 (black) .. 255 (white)
938 */
939void gray_set_background(int brightness)
940{
941 if ((unsigned) brightness <= 255)
942 graybuf->bg_pattern = graybuf->bitpattern[MULU16(brightness,
943 graybuf->depth + 1) >> 8];
944}
945
946/* Set draw mode, foreground and background shades at once
947 *
948 * If you hand it -1 (or in fact any other out-of-bounds value) for a
949 * parameter, that particular setting won't be changed
950 */
951void gray_set_drawinfo(int drawmode, int fg_brightness, int bg_brightness)
952{
953 gray_set_drawmode(drawmode);
954 gray_set_foreground(fg_brightness);
955 gray_set_background(bg_brightness);
956}
957
958/** Functions affecting the whole dsplay **/
959
960/* Clear the grayscale display (sets all pixels to white) */
961void gray_clear_display(void)
962{
963 rb->memset(graybuf->data, 0, MULU16(graybuf->depth, graybuf->plane_size));
964}
965
966/* Set the grayscale display to all black */
967void gray_black_display(void)
968{
969 rb->memset(graybuf->data, 0xFF, MULU16(graybuf->depth, graybuf->plane_size));
970}
971
972/* Do an lcd_update() to show changes done by rb->lcd_xxx() functions (in areas
973 * of the screen not covered by the grayscale overlay).
974 *
975 * If the grayscale overlay is running, the update will be done in the next
976 * call of the interrupt routine, otherwise it will be performed right away.
977 * See also comment for the gray_show_display() function.
978 */
979void gray_deferred_update(void)
980{
981 if (graybuf->flags & GRAY_RUNNING)
982 graybuf->flags |= GRAY_DEFERRED_UPDATE;
983 else
984 rb->lcd_update();
985}
986
987/** Scrolling functions **/
988
989/* Scroll the whole grayscale buffer left by <count> pixels
990 *
991 * black_border determines if the pixels scrolled in at the right are black
992 * or white
993 *
994 * Scrolling left/right by an even pixel count is almost twice as fast as
995 * scrolling by an odd pixel count.
996 */
997void gray_scroll_left(int count, bool black_border)
998{
999 int by, d;
1000 unsigned filler;
1001 unsigned char *ptr;
1002
1003 if ((unsigned) count >= (unsigned) graybuf->width)
1004 return;
1005
1006 filler = black_border ? 0xFF : 0;
1007
1008 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
1009 for (by = 0; by < graybuf->bheight; by++)
1010 {
1011 ptr = graybuf->data + MULU16(graybuf->width, by);
1012 for (d = 0; d < graybuf->depth; d++)
1013 {
1014 asm volatile (
1015 "mov %0,r1 \n" /* check if both source... */
1016 "or %2,r1 \n" /* ...and offset are even */
1017 "shlr r1 \n" /* -> lsb = 0 */
1018 "bf .sl_start2 \n" /* -> copy word-wise */
1019
1020 "add #-1,%2 \n" /* copy byte-wise */
1021 ".sl_loop1: \n"
1022 "mov.b @%0+,r1 \n"
1023 "mov.b r1,@(%2,%0) \n"
1024 "cmp/hi %0,%1 \n"
1025 "bt .sl_loop1 \n"
1026
1027 "bra .sl_end \n"
1028 "nop \n"
1029
1030 ".sl_start2: \n" /* copy word-wise */
1031 "add #-2,%2 \n"
1032 ".sl_loop2: \n"
1033 "mov.w @%0+,r1 \n"
1034 "mov.w r1,@(%2,%0) \n"
1035 "cmp/hi %0,%1 \n"
1036 "bt .sl_loop2 \n"
1037
1038 ".sl_end: \n"
1039 : /* outputs */
1040 : /* inputs */
1041 /* %0 */ "r"(ptr + count),
1042 /* %1 */ "r"(ptr + graybuf->width),
1043 /* %2 */ "z"(-count)
1044 : /* clobbers */
1045 "r1"
1046 );
1047
1048 rb->memset(ptr + graybuf->width - count, filler, count);
1049 ptr += graybuf->plane_size;
1050 }
1051 }
1052}
1053
1054/* Scroll the whole grayscale buffer right by <count> pixels
1055 *
1056 * black_border determines if the pixels scrolled in at the left are black
1057 * or white
1058 *
1059 * Scrolling left/right by an even pixel count is almost twice as fast as
1060 * scrolling by an odd pixel count.
1061 */
1062void gray_scroll_right(int count, bool black_border)
1063{
1064 int by, d;
1065 unsigned filler;
1066 unsigned char *ptr;
1067
1068 if ((unsigned) count >= (unsigned) graybuf->width)
1069 return;
1070
1071 filler = black_border ? 0xFF : 0;
1072
1073 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
1074 for (by = 0; by < graybuf->bheight; by++)
1075 {
1076 ptr = graybuf->data + MULU16(graybuf->width, by);
1077 for (d = 0; d < graybuf->depth; d++)
1078 {
1079 asm volatile (
1080 "mov %0,r1 \n" /* check if both source... */
1081 "or %2,r1 \n" /* ...and offset are even */
1082 "shlr r1 \n" /* -> lsb = 0 */
1083 "bf .sr_start2 \n" /* -> copy word-wise */
1084
1085 "add #-1,%2 \n" /* copy byte-wise */
1086 ".sr_loop1: \n"
1087 "mov.b @(%2,%0),r1 \n"
1088 "mov.b r1,@-%0 \n"
1089 "cmp/hi %1,%0 \n"
1090 "bt .sr_loop1 \n"
1091
1092 "bra .sr_end \n"
1093 "nop \n"
1094
1095 ".sr_start2: \n" /* copy word-wise */
1096 "add #-2,%2 \n"
1097 ".sr_loop2: \n"
1098 "mov.w @(%2,%0),r1 \n"
1099 "mov.w r1,@-%0 \n"
1100 "cmp/hi %1,%0 \n"
1101 "bt .sr_loop2 \n"
1102
1103 ".sr_end: \n"
1104 : /* outputs */
1105 : /* inputs */
1106 /* %0 */ "r"(ptr + graybuf->width),
1107 /* %1 */ "r"(ptr + count),
1108 /* %2 */ "z"(-count)
1109 : /* clobbers */
1110 "r1"
1111 );
1112
1113 rb->memset(ptr, filler, count);
1114 ptr += graybuf->plane_size;
1115 }
1116 }
1117}
1118
1119/* Scroll the whole grayscale buffer up by 8 pixels
1120 *
1121 * black_border determines if the pixels scrolled in at the bottom are black
1122 * or white
1123 *
1124 * Scrolling up/down by 8 pixels is very fast.
1125 */
1126void gray_scroll_up8(bool black_border)
1127{
1128 int by, d;
1129 unsigned filler;
1130 unsigned char *ptr;
1131
1132 filler = black_border ? 0xFF : 0;
1133
1134 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
1135 for (by = 1; by < graybuf->bheight; by++)
1136 {
1137 ptr = graybuf->data + MULU16(graybuf->width, by);
1138 for (d = 0; d < graybuf->depth; d++)
1139 {
1140 rb->memcpy(ptr - graybuf->width, ptr, graybuf->width);
1141 ptr += graybuf->plane_size;
1142 }
1143 }
1144 /* fill last row */
1145 ptr = graybuf->data + graybuf->plane_size - graybuf->width;
1146 for (d = 0; d < graybuf->depth; d++)
1147 {
1148 rb->memset(ptr, filler, graybuf->width);
1149 ptr += graybuf->plane_size;
1150 }
1151}
1152
1153/* Scroll the whole grayscale buffer down by 8 pixels
1154 *
1155 * black_border determines if the pixels scrolled in at the top are black
1156 * or white
1157 *
1158 * Scrolling up/down by 8 pixels is very fast.
1159 */
1160void gray_scroll_down8(bool black_border)
1161{
1162 int by, d;
1163 unsigned filler;
1164 unsigned char *ptr;
1165
1166 filler = black_border ? 0xFF : 0;
1167
1168 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
1169 for (by = graybuf->bheight - 1; by > 0; by--)
1170 {
1171 ptr = graybuf->data + MULU16(graybuf->width, by);
1172 for (d = 0; d < graybuf->depth; d++)
1173 {
1174 rb->memcpy(ptr, ptr - graybuf->width, graybuf->width);
1175 ptr += graybuf->plane_size;
1176 }
1177 }
1178 /* fill first row */
1179 ptr = graybuf->data;
1180 for (d = 0; d < graybuf->depth; d++)
1181 {
1182 rb->memset(ptr, filler, graybuf->width);
1183 ptr += graybuf->plane_size;
1184 }
1185}
1186
1187/* Scroll the whole grayscale buffer up by <count> pixels (<= 7)
1188 *
1189 * black_border determines if the pixels scrolled in at the bottom are black
1190 * or white
1191 *
1192 * Scrolling up/down pixel-wise is significantly slower than scrolling
1193 * left/right or scrolling up/down byte-wise because it involves bit
1194 * shifting. That's why it is asm optimized.
1195 */
1196void gray_scroll_up(int count, bool black_border)
1197{
1198 unsigned filler;
1199
1200 if ((unsigned) count > 7)
1201 return;
1202
1203 filler = black_border ? 0xFFu : 0;
1204
1205 /* scroll column by column to minimize flicker */
1206 asm volatile (
1207 "mov #0,r6 \n" /* x = 0 */
1208 "mova .su_shifttbl,r0 \n" /* calculate jump destination for */
1209 "mov.b @(r0,%6),%6 \n" /* shift amount from table */
1210 "bra .su_cloop \n" /* skip table */
1211 "add r0,%6 \n"
1212
1213 ".align 2 \n"
1214 ".su_shifttbl: \n" /* shift jump offset table */
1215 ".byte .su_shift0 - .su_shifttbl \n"
1216 ".byte .su_shift1 - .su_shifttbl \n"
1217 ".byte .su_shift2 - .su_shifttbl \n"
1218 ".byte .su_shift3 - .su_shifttbl \n"
1219 ".byte .su_shift4 - .su_shifttbl \n"
1220 ".byte .su_shift5 - .su_shifttbl \n"
1221 ".byte .su_shift6 - .su_shifttbl \n"
1222 ".byte .su_shift7 - .su_shifttbl \n"
1223
1224 ".su_cloop: \n" /* repeat for every column */
1225 "mov %1,r2 \n" /* get start address */
1226 "mov #0,r3 \n" /* current_plane = 0 */
1227
1228 ".su_oloop: \n" /* repeat for every bitplane */
1229 "mov r2,r4 \n" /* get start address */
1230 "mov #0,r5 \n" /* current_row = 0 */
1231 "mov %5,r1 \n" /* get filler bits */
1232
1233 ".su_iloop: \n" /* repeat for all rows */
1234 "sub %2,r4 \n" /* address -= width */
1235 "mov.b @r4,r0 \n" /* get data byte */
1236 "shll8 r1 \n" /* old data to 2nd byte */
1237 "extu.b r0,r0 \n" /* extend unsigned */
1238 "or r1,r0 \n" /* combine old data */
1239 "jmp @%6 \n" /* jump into shift "path" */
1240 "extu.b r0,r1 \n" /* store data for next round */
1241
1242 ".su_shift6: \n" /* shift right by 0..7 bits */
1243 "shlr2 r0 \n"
1244 ".su_shift4: \n"
1245 "shlr2 r0 \n"
1246 ".su_shift2: \n"
1247 "bra .su_shift0 \n"
1248 "shlr2 r0 \n"
1249 ".su_shift7: \n"
1250 "shlr2 r0 \n"
1251 ".su_shift5: \n"
1252 "shlr2 r0 \n"
1253 ".su_shift3: \n"
1254 "shlr2 r0 \n"
1255 ".su_shift1: \n"
1256 "shlr r0 \n"
1257 ".su_shift0: \n"
1258
1259 "mov.b r0,@r4 \n" /* store data */
1260 "add #1,r5 \n" /* current_row++ */
1261 "cmp/hi r5,%3 \n" /* current_row < bheight ? */
1262 "bt .su_iloop \n"
1263
1264 "add %4,r2 \n" /* start_address += plane_size */
1265 "add #1,r3 \n" /* current_plane++ */
1266 "cmp/hi r3,%0 \n" /* current_plane < depth ? */
1267 "bt .su_oloop \n"
1268
1269 "add #1,%1 \n" /* start_address++ */
1270 "add #1,r6 \n" /* x++ */
1271 "cmp/hi r6,%2 \n" /* x < width ? */
1272 "bt .su_cloop \n"
1273 : /* outputs */
1274 : /* inputs */
1275 /* %0 */ "r"(graybuf->depth),
1276 /* %1 */ "r"(graybuf->data + graybuf->plane_size),
1277 /* %2 */ "r"(graybuf->width),
1278 /* %3 */ "r"(graybuf->bheight),
1279 /* %4 */ "r"(graybuf->plane_size),
1280 /* %5 */ "r"(filler),
1281 /* %6 */ "r"(count)
1282 : /* clobbers */
1283 "r0", "r1", "r2", "r3", "r4", "r5", "r6"
1284 );
1285}
1286
1287/* Scroll the whole grayscale buffer down by <count> pixels (<= 7)
1288 *
1289 * black_border determines if the pixels scrolled in at the top are black
1290 * or white
1291 *
1292 * Scrolling up/down pixel-wise is significantly slower than scrolling
1293 * left/right or scrolling up/down byte-wise because it involves bit
1294 * shifting. That's why it is asm optimized.
1295 */
1296void gray_scroll_down(int count, bool black_border)
1297{
1298 unsigned filler;
1299
1300 if ((unsigned) count > 7)
1301 return;
1302
1303 filler = black_border ? (0xFFu << count) : 0;
1304
1305 /* scroll column by column to minimize flicker */
1306 asm volatile (
1307 "mov #0,r6 \n" /* x = 0 */
1308 "mova .sd_shifttbl,r0 \n" /* calculate jump destination for */
1309 "mov.b @(r0,%6),%6 \n" /* shift amount from table */
1310 "bra .sd_cloop \n" /* skip table */
1311 "add r0,%6 \n"
1312
1313 ".align 2 \n"
1314 ".sd_shifttbl: \n" /* shift jump offset table */
1315 ".byte .sd_shift0 - .sd_shifttbl \n"
1316 ".byte .sd_shift1 - .sd_shifttbl \n"
1317 ".byte .sd_shift2 - .sd_shifttbl \n"
1318 ".byte .sd_shift3 - .sd_shifttbl \n"
1319 ".byte .sd_shift4 - .sd_shifttbl \n"
1320 ".byte .sd_shift5 - .sd_shifttbl \n"
1321 ".byte .sd_shift6 - .sd_shifttbl \n"
1322 ".byte .sd_shift7 - .sd_shifttbl \n"
1323
1324 ".sd_cloop: \n" /* repeat for every column */
1325 "mov %1,r2 \n" /* get start address */
1326 "mov #0,r3 \n" /* current_plane = 0 */
1327
1328 ".sd_oloop: \n" /* repeat for every bitplane */
1329 "mov r2,r4 \n" /* get start address */
1330 "mov #0,r5 \n" /* current_row = 0 */
1331 "mov %5,r1 \n" /* get filler bits */
1332
1333 ".sd_iloop: \n" /* repeat for all rows */
1334 "shlr8 r1 \n" /* shift right to get residue */
1335 "mov.b @r4,r0 \n" /* get data byte */
1336 "jmp @%6 \n" /* jump into shift "path" */
1337 "extu.b r0,r0 \n" /* extend unsigned */
1338
1339 ".sd_shift6: \n" /* shift left by 0..7 bits */
1340 "shll2 r0 \n"
1341 ".sd_shift4: \n"
1342 "shll2 r0 \n"
1343 ".sd_shift2: \n"
1344 "bra .sd_shift0 \n"
1345 "shll2 r0 \n"
1346 ".sd_shift7: \n"
1347 "shll2 r0 \n"
1348 ".sd_shift5: \n"
1349 "shll2 r0 \n"
1350 ".sd_shift3: \n"
1351 "shll2 r0 \n"
1352 ".sd_shift1: \n"
1353 "shll r0 \n"
1354 ".sd_shift0: \n"
1355
1356 "or r0,r1 \n" /* combine with last residue */
1357 "mov.b r1,@r4 \n" /* store data */
1358 "add %2,r4 \n" /* address += width */
1359 "add #1,r5 \n" /* current_row++ */
1360 "cmp/hi r5,%3 \n" /* current_row < bheight ? */
1361 "bt .sd_iloop \n"
1362
1363 "add %4,r2 \n" /* start_address += plane_size */
1364 "add #1,r3 \n" /* current_plane++ */
1365 "cmp/hi r3,%0 \n" /* current_plane < depth ? */
1366 "bt .sd_oloop \n"
1367
1368 "add #1,%1 \n" /* start_address++ */
1369 "add #1,r6 \n" /* x++ */
1370 "cmp/hi r6,%2 \n" /* x < width ? */
1371 "bt .sd_cloop \n"
1372 : /* outputs */
1373 : /* inputs */
1374 /* %0 */ "r"(graybuf->depth),
1375 /* %1 */ "r"(graybuf->data),
1376 /* %2 */ "r"(graybuf->width),
1377 /* %3 */ "r"(graybuf->bheight),
1378 /* %4 */ "r"(graybuf->plane_size),
1379 /* %5 */ "r"(filler),
1380 /* %6 */ "r"(count)
1381 : /* clobbers */
1382 "r0", "r1", "r2", "r3", "r4", "r5", "r6"
1383 );
1384}
1385
1386/** Pixel and line functions **/
1387
1388/* Set a pixel with the current drawinfo
1389 *
1390 * If the drawmode is GRAY_DRAW_INVERSE, the pixel is inverted
1391 * GRAY_DRAW_FG and GRAY_DRAW_SOLID draw the pixel in the foreground shade
1392 * GRAY_DRAW_BG draws the pixel in the background shade
1393 */
1394void gray_drawpixel(int x, int y)
1395{
1396 unsigned long pattern;
1397
1398 if ((unsigned) x >= (unsigned) graybuf->width
1399 || (unsigned) y >= (unsigned) graybuf->height)
1400 return;
1401
1402 pattern = (graybuf->drawmode == GRAY_DRAW_BG) ?
1403 graybuf->bg_pattern : graybuf->fg_pattern;
1404
1405 _pixelfuncs[graybuf->drawmode](x, y, pattern);
1406}
1407
1408/* Draw a line from (x1, y1) to (x2, y2) with the current drawinfo,
1409 * See gray_drawpixel() for details
1410 */
1411void gray_drawline(int x1, int y1, int x2, int y2)
1412{
1413 int numpixels;
1414 int i;
1415 int deltax, deltay;
1416 int d, dinc1, dinc2;
1417 int x, xinc1, xinc2;
1418 int y, yinc1, yinc2;
1419 unsigned long pattern;
1420 void (*pixelfunc)(int x, int y, unsigned long pattern);
1421
1422 if ((unsigned) x1 >= (unsigned) graybuf->width
1423 || (unsigned) y1 >= (unsigned) graybuf->height
1424 || (unsigned) x2 >= (unsigned) graybuf->width
1425 || (unsigned) y2 >= (unsigned) graybuf->height)
1426 return;
1427
1428 deltax = abs(x2 - x1);
1429 deltay = abs(y2 - y1);
1430 xinc2 = 1;
1431 yinc2 = 1;
1432
1433 if (deltax >= deltay)
1434 {
1435 numpixels = deltax;
1436 d = 2 * deltay - deltax;
1437 dinc1 = deltay * 2;
1438 dinc2 = (deltay - deltax) * 2;
1439 xinc1 = 1;
1440 yinc1 = 0;
1441 }
1442 else
1443 {
1444 numpixels = deltay;
1445 d = 2 * deltax - deltay;
1446 dinc1 = deltax * 2;
1447 dinc2 = (deltax - deltay) * 2;
1448 xinc1 = 0;
1449 yinc1 = 1;
1450 }
1451 numpixels++; /* include endpoints */
1452
1453 if (x1 > x2)
1454 {
1455 xinc1 = -xinc1;
1456 xinc2 = -xinc2;
1457 }
1458
1459 if (y1 > y2)
1460 {
1461 yinc1 = -yinc1;
1462 yinc2 = -yinc2;
1463 }
1464
1465 x = x1;
1466 y = y1;
1467
1468 pixelfunc = _pixelfuncs[graybuf->drawmode];
1469 pattern = (graybuf->drawmode == GRAY_DRAW_BG) ?
1470 graybuf->bg_pattern : graybuf->fg_pattern;
1471
1472 for (i = 0; i < numpixels; i++)
1473 {
1474 pixelfunc(x, y, pattern);
1475
1476 if (d < 0)
1477 {
1478 d += dinc1;
1479 x += xinc1;
1480 y += yinc1;
1481 }
1482 else
1483 {
1484 d += dinc2;
1485 x += xinc2;
1486 y += yinc2;
1487 }
1488 }
1489}
1490
1491/* Draw a horizontal line from (x1, y) to (x2, y) with the current drawinfo,
1492 * See gray_drawpixel() for details
1493 */
1494void gray_horline(int x1, int x2, int y)
1495{
1496 int x;
1497 unsigned long pattern;
1498 void (*pixelfunc)(int x, int y, unsigned long pattern);
1499
1500 if ((unsigned) x1 >= (unsigned) graybuf->width
1501 || (unsigned) x2 >= (unsigned) graybuf->width
1502 || (unsigned) y >= (unsigned) graybuf->height)
1503 return;
1504
1505 if (x1 > x2)
1506 {
1507 x = x1;
1508 x1 = x2;
1509 x2 = x;
1510 }
1511 pixelfunc = _pixelfuncs[graybuf->drawmode];
1512 pattern = (graybuf->drawmode == GRAY_DRAW_BG) ?
1513 graybuf->bg_pattern : graybuf->fg_pattern;
1514
1515 for (x = x1; x <= x2; x++)
1516 pixelfunc(x, y, pattern);
1517
1518}
1519
1520/* Draw a vertical line from (x, y1) to (x, y2) with the current drawinfo,
1521 * See gray_drawpixel() for details
1522 *
1523 * This one uses the block drawing optimization, so it is rather fast.
1524 */
1525void gray_verline(int x, int y1, int y2)
1526{
1527 int shift, y, ny;
1528 unsigned bits, mask_top, mask_bottom;
1529 unsigned char *dst;
1530 void (*blockfunc)(unsigned char *address, unsigned mask, unsigned bits);
1531
1532 if ((unsigned) x >= (unsigned) graybuf->width
1533 || (unsigned) y1 >= (unsigned) graybuf->height
1534 || (unsigned) y2 >= (unsigned) graybuf->height)
1535 return;
1536
1537 if (y1 > y2)
1538 {
1539 y = y1;
1540 y1 = y2;
1541 y2 = y;
1542 }
1543 y = y1;
1544 ny = y2 - y1 + 1;
1545
1546 dst = graybuf->data + x + MULU16(graybuf->width, y >> 3);
1547 shift = y & 7;
1548 ny += shift;
1549
1550 mask_top = 0xFFu << (y & 7);
1551 mask_bottom = ~(0xFEu << ((ny - 1) & 7));
1552 if (ny <= 8)
1553 mask_bottom &= mask_top;
1554
1555 blockfunc = _blockfuncs[graybuf->drawmode];
1556 bits = (graybuf->drawmode == GRAY_DRAW_BG) ? 0u : 0xFFu;
1557
1558 if (ny > 8)
1559 {
1560 blockfunc(dst, mask_top, bits);
1561 dst += graybuf->width;
1562
1563 for (y = 8; y < ny - 8; y += 8)
1564 {
1565 blockfunc(dst, 0xFFu, bits);
1566 dst += graybuf->width;
1567 }
1568 }
1569
1570 blockfunc(dst, mask_bottom, bits);
1571}
1572
1573/** Rectangle functions **/
1574
1575/* Draw a (hollow) rectangle with the current drawinfo,
1576 * See gray_drawpixel() for details
1577 */
1578void gray_drawrect(int x, int y, int nx, int ny)
1579{
1580 int x2, y2;
1581
1582 if ((unsigned) x >= (unsigned) graybuf->width
1583 || (unsigned) y >= (unsigned) graybuf->height)
1584 return;
1585
1586 if ((unsigned) (y + ny) >= (unsigned) graybuf->height) /* clip bottom */
1587 ny = graybuf->height - y;
1588
1589 if ((unsigned) (x + nx) >= (unsigned) graybuf->width) /* clip right */
1590 nx = graybuf->width - x;
1591
1592 x2 = x + nx - 1;
1593 y2 = y + ny - 1;
1594
1595 gray_horline(x, x2, y);
1596 gray_horline(x, x2, y2);
1597 gray_verline(x, y, y2);
1598 gray_verline(x2, y, y2);
1599}
1600
1601/* Draw a filled rectangle with the current drawinfo,
1602 * See gray_drawpixel() for details
1603 *
1604 * This one uses the block drawing optimization, so it is rather fast.
1605 */
1606void gray_fillrect(int x, int y, int nx, int ny)
1607{
1608 int shift;
1609 unsigned bits, mask_top, mask_bottom;
1610 unsigned char *dst, *dst_row;
1611 void (*blockfunc)(unsigned char *address, unsigned mask, unsigned bits);
1612
1613 if ((unsigned) x >= (unsigned) graybuf->width
1614 || (unsigned) y >= (unsigned) graybuf->height)
1615 return;
1616
1617 if ((unsigned) (y + ny) >= (unsigned) graybuf->height) /* clip bottom */
1618 ny = graybuf->height - y;
1619
1620 if ((unsigned) (x + nx) >= (unsigned) graybuf->width) /* clip right */
1621 nx = graybuf->width - x;
1622
1623 dst = graybuf->data + x + MULU16(graybuf->width, y >> 3);
1624 shift = y & 7;
1625 ny += shift;
1626
1627 mask_top = 0xFFu << (y & 7);
1628 mask_bottom = ~(0xFEu << ((ny - 1) & 7));
1629 if (ny <= 8)
1630 mask_bottom &= mask_top;
1631
1632 blockfunc = _blockfuncs[graybuf->drawmode];
1633 bits = (graybuf->drawmode == GRAY_DRAW_BG) ? 0u : 0xFFu;
1634
1635 if (ny > 8)
1636 {
1637 dst_row = dst;
1638 for (x = 0; x < nx; x++)
1639 blockfunc(dst_row++, mask_top, bits);
1640
1641 dst += graybuf->width;
1642
1643 for (y = 8; y < ny - 8; y += 8)
1644 {
1645 dst_row = dst;
1646 for (x = 0; x < nx; x++)
1647 blockfunc(dst_row++, 0xFFu, bits);
1648
1649 dst += graybuf->width;
1650 }
1651 }
1652
1653 for (x = 0; x < nx; x++)
1654 blockfunc(dst++, mask_bottom, bits);
1655}
1656
1657/** Bitmap functions **/
1658
1659/* Copy a grayscale bitmap into the display
1660 *
1661 * A grayscale bitmap contains one byte for every pixel that defines the
1662 * brightness of the pixel (0..255). Bytes are read in row-major order.
1663 * The <stride> parameter is useful if you want to show only a part of a
1664 * bitmap. It should always be set to the "row length" of the bitmap, so
1665 * for displaying the whole bitmap, nx == stride.
1666 *
1667 * This is the only drawing function NOT using the drawinfo.
1668 */
1669void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny,
1670 int stride)
1671{
1672 int shift;
1673 unsigned mask_top, mask_bottom;
1674 unsigned char *src_row, *dst, *dst_row;
1675
1676 if ((unsigned) x >= (unsigned) graybuf->width
1677 || (unsigned) y >= (unsigned) graybuf->height)
1678 return;
1679
1680 if ((unsigned) (y + ny) >= (unsigned) graybuf->height) /* clip bottom */
1681 ny = graybuf->height - y;
1682
1683 if ((unsigned) (x + nx) >= (unsigned) graybuf->width) /* clip right */
1684 nx = graybuf->width - x;
1685
1686 dst = graybuf->data + x + MULU16(graybuf->width, y >> 3);
1687 shift = y & 7;
1688 ny += shift;
1689
1690 mask_top = 0xFFu << (y & 7);
1691 mask_bottom = ~(0xFEu << ((ny - 1) & 7));
1692 if (ny <= 8)
1693 mask_bottom &= mask_top;
1694
1695 if (ny > 8)
1696 {
1697 src_row = src;
1698 dst_row = dst;
1699
1700 for (x = 0; x < nx; x++)
1701 _writearray(dst_row++, src_row++, stride, mask_top);
1702
1703 src += MULU16(stride, 8 - shift);
1704 dst += graybuf->width;
1705
1706 for (y = 8; y < ny - 8; y += 8)
1707 {
1708 src_row = src;
1709 dst_row = dst;
1710
1711 for (x = 0; x < nx; x++)
1712 _writearray(dst_row++, src_row++, stride, 0xFFu);
1713
1714 src += stride << 3;
1715 dst += graybuf->width;
1716 }
1717 }
1718
1719 for (x = 0; x < nx; x++)
1720 _writearray(dst++, src++, stride, mask_bottom);
1721}
1722
1723/* Display a bitmap with the current drawinfo
1724 *
1725 * The drawmode is used as described for gray_set_drawmode()
1726 *
1727 * This (now) uses the same bitmap format as the core b&w graphics routines,
1728 * so you can use bmp2rb to generate bitmaps for use with this function as
1729 * well.
1730 *
1731 * A bitmap contains one bit for every pixel that defines if that pixel is
1732 * foreground (1) or background (0). Bits within a byte are arranged
1733 * vertically, LSB at top.
1734 * The bytes are stored in row-major order, with byte 0 being top left,
1735 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
1736 * 0..7, the second row defines pixel row 8..15 etc.
1737 *
1738 * The <stride> parameter is useful if you want to show only a part of a
1739 * bitmap. It should always be set to the "row length" of the bitmap.
1740 */
1741void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
1742 int stride)
1743{
1744 int shift;
1745 unsigned bits, mask_top, mask_bottom;
1746 unsigned char *src_col, *dst, *dst_col;
1747 void (*blockfunc)(unsigned char *address, unsigned mask, unsigned bits);
1748
1749 if ((unsigned) x >= (unsigned) graybuf->width
1750 || (unsigned) y >= (unsigned) graybuf->height)
1751 return;
1752
1753 if ((unsigned) (y + ny) >= (unsigned) graybuf->height) /* clip bottom */
1754 ny = graybuf->height - y;
1755
1756 if ((unsigned) (x + nx) >= (unsigned) graybuf->width) /* clip right */
1757 nx = graybuf->width - x;
1758
1759 dst = graybuf->data + x + MULU16(graybuf->width, y >> 3);
1760 shift = y & 7;
1761 ny += shift;
1762
1763 mask_top = 0xFFu << (y & 7);
1764 mask_bottom = ~(0xFEu << ((ny - 1) & 7));
1765 if (ny <= 8)
1766 mask_bottom &= mask_top;
1767
1768 blockfunc = _blockfuncs[graybuf->drawmode];
1769
1770 for(x = 0; x < nx; x++)
1771 {
1772 src_col = src++;
1773 dst_col = dst++;
1774 bits = 0;
1775 y = 0;
1776
1777 if (ny > 8)
1778 {
1779 bits = *src_col << shift;
1780 src_col += stride;
1781
1782 blockfunc(dst_col, mask_top, bits);
1783 dst_col += graybuf->width;
1784 bits >>= 8;
1785
1786 for (y = 8; y < ny - 8; y += 8)
1787 {
1788 bits |= *src_col << shift;
1789 src_col += stride;
1790
1791 blockfunc(dst_col, 0xFFu, bits);
1792 dst_col += graybuf->width;
1793 bits >>= 8;
1794 }
1795 }
1796 if (y + shift < ny)
1797 bits |= *src_col << shift;
1798
1799 blockfunc(dst_col, mask_bottom, bits);
1800 }
1801}
1802
1803/** Font support **/
1804
1805/* Set font for the font routines
1806 *
1807 * newfont can be FONT_SYSFIXED or FONT_UI the same way as with the Rockbox
1808 * core routines
1809 */
1810void gray_setfont(int newfont)
1811{
1812 graybuf->curfont = rb->font_get(newfont);
1813}
1814
1815/* Calculate width and height of the given text in pixels when rendered with
1816 * the currently selected font.
1817 *
1818 * This works exactly the same way as the core lcd_getstringsize(), only that
1819 * it uses the selected font for grayscale.
1820 */
1821int gray_getstringsize(unsigned char *str, int *w, int *h)
1822{
1823 int ch;
1824 int width = 0;
1825 struct font *pf = graybuf->curfont;
1826
1827 while ((ch = *str++))
1828 {
1829 /* check input range */
1830 if (ch < pf->firstchar || ch >= pf->firstchar + pf->size)
1831 ch = pf->defaultchar;
1832 ch -= pf->firstchar;
1833
1834 /* get proportional width */
1835 width += pf->width ? pf->width[ch] : pf->maxwidth;
1836 }
1837 if (w)
1838 *w = width;
1839 if (h)
1840 *h = pf->height;
1841 return width;
1842}
1843
1844/* Display text starting at (x, y) with the current font and drawinfo
1845 *
1846 * The drawmode is used as described for gray_set_drawmode()
1847 */
1848void gray_putsxy(int x, int y, unsigned char *str)
1849{
1850 int ch, width;
1851 bitmap_t *bits;
1852 struct font *pf = graybuf->curfont;
1853
1854 if ((unsigned) x >= (unsigned) graybuf->width
1855 || (unsigned) y >= (unsigned) graybuf->height)
1856 return;
1857
1858 while ((ch = *str++) != '\0' && x < graybuf->width)
1859 {
1860 /* check input range */
1861 if (ch < pf->firstchar || ch >= pf->firstchar + pf->size)
1862 ch = pf->defaultchar;
1863 ch -= pf->firstchar;
1864
1865 /* get proportional width and glyph bits */
1866 width = pf->width ? pf->width[ch] : pf->maxwidth;
1867 bits = pf->bits + (pf->offset ? pf->offset[ch]
1868 : MULU16(pf->height, ch));
1869
1870 gray_drawbitmap((unsigned char*) bits, x, y, width, pf->height,
1871 width);
1872 x += width;
1873 }
1874}
1875
1876#endif // #ifdef HAVE_LCD_BITMAP
1877#endif // #ifndef SIMULATOR
1878
diff --git a/apps/plugins/lib/gray.h b/apps/plugins/lib/gray.h
index 18be88a2f2..b7b0affd73 100644
--- a/apps/plugins/lib/gray.h
+++ b/apps/plugins/lib/gray.h
@@ -30,308 +30,417 @@
30 30
31#ifdef HAVE_LCD_BITMAP /* and also not for the Player */ 31#ifdef HAVE_LCD_BITMAP /* and also not for the Player */
32 32
33/* Initialize the framework 33/*===========================================================================
34 * 34 Public functions and definitions, to be used within plugins
35 * every framework needs such a function, and it has to be called as 35 ============================================================================
36 * the very first one 36 */
37
38/*---------------------------------------------------------------------------
39 Initialize the framework
40 ----------------------------------------------------------------------------
41 every framework needs such a function, and it has to be called as the very
42 first one
37 */ 43 */
38void gray_init(struct plugin_api* newrb); 44void gray_init(struct plugin_api* newrb);
39 45
40/**** general functions ****/ 46/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
41 47 General functions
42/* Prepare the grayscale display buffer 48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
43 * 49 */
44 * arguments: 50
45 * gbuf = pointer to the memory area to use (e.g. plugin buffer) 51/*---------------------------------------------------------------------------
46 * gbuf_size = max usable size of the buffer 52 Prepare the grayscale display buffer
47 * width = width in pixels (1..112) 53 ----------------------------------------------------------------------------
48 * bheight = height in 8-pixel units (1..8) 54 arguments:
49 * depth = desired number of shades - 1 (1..32) 55 gbuf = pointer to the memory area to use (e.g. plugin buffer)
50 * 56 gbuf_size = max usable size of the buffer
51 * result: 57 width = width in pixels (1..112)
52 * = depth if there was enough memory 58 bheight = height in 8-pixel units (1..8)
53 * < depth if there wasn't enough memory. The number of displayable 59 depth = desired number of shades - 1 (1..32)
54 * shades is smaller than desired, but it still works 60
55 * = 0 if there wasn't even enough memory for 1 bitplane (black & white) 61 result:
56 * 62 = depth if there was enough memory
57 * You can request any depth from 1 to 32, not just powers of 2. The routine 63 < depth if there wasn't enough memory. The number of displayable
58 * performs "graceful degradation" if the memory is not sufficient for the 64 shades is smaller than desired, but it still works
59 * desired depth. As long as there is at least enough memory for 1 bitplane, 65 = 0 if there wasn't even enough memory for 1 bitplane (black & white)
60 * it creates as many bitplanes as fit into memory, although 1 bitplane will 66
61 * only deliver black & white display. 67 You can request any depth from 1 to 32, not just powers of 2. The routine
62 * 68 performs "graceful degradation" if the memory is not sufficient for the
63 * If you need info about the memory taken by the grayscale buffer, supply an 69 desired depth. As long as there is at least enough memory for 1 bitplane,
64 * int* as the last parameter. This int will then contain the number of bytes 70 it creates as many bitplanes as fit into memory, although 1 bitplane will
65 * used. The total memory needed can be calculated as follows: 71 only deliver black & white display.
66 * total_mem = 72
67 * sizeof(tGraybuf) (= 64 bytes currently) 73 If you need info about the memory taken by the grayscale buffer, supply an
68 * + sizeof(long) (= 4 bytes) 74 int* as the last parameter. This int will then contain the number of bytes
69 * + (width * bheight + sizeof(long)) * depth 75 used. The total memory needed can be calculated as follows:
70 * + 0..3 (longword alignment of grayscale display buffer) 76 total_mem =
77 sizeof(_tGraybuf) (= 64 bytes currently)
78 + sizeof(long) (= 4 bytes)
79 + (width * bheight + sizeof(long)) * depth
80 + 0..3 (longword alignment of grayscale display buffer)
71 */ 81 */
72int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width, 82int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
73 int bheight, int depth, int *buf_taken); 83 int bheight, int depth, int *buf_taken);
74 84
75/* Release the grayscale display buffer 85/*---------------------------------------------------------------------------
76 * 86 Release the grayscale display buffer
77 * Switches the grayscale overlay off at first if it is still running, 87 ----------------------------------------------------------------------------
78 * then sets the pointer to NULL. 88 Switches the grayscale overlay off at first if it is still running,
79 * DO CALL either this function or at least gray_show_display(false) 89 then sets the pointer to NULL.
80 * before you exit, otherwise nasty things may happen. 90 DO CALL either this function or at least gray_show_display(false)
91 before you exit, otherwise nasty things may happen.
81 */ 92 */
82void gray_release_buffer(void); 93void gray_release_buffer(void);
83 94
84/* Set position of the top left corner of the grayscale overlay 95/*---------------------------------------------------------------------------
85 * 96 Switch the grayscale overlay on or off
86 * x = left margin in pixels 97 ----------------------------------------------------------------------------
87 * by = top margin in 8-pixel units 98 enable = true: the grayscale overlay is switched on if initialized
88 * 99 = false: the grayscale overlay is switched off and the regular lcd
89 * You may set this in a way that the overlay spills across the right or 100 content is restored
90 * bottom display border. In this case it will simply be clipped by the 101
91 * LCD controller. You can even set negative values, this will clip at the 102 DO NOT call lcd_update() or any other api function that directly accesses
92 * left or top border. I did not test it, but the limits may be +127 / -128 103 the lcd while the grayscale overlay is running! If you need to do
93 * 104 lcd_update() to update something outside the grayscale overlay area, use
94 * If you use this while the grayscale overlay is running, the now-freed area 105 gray_deferred_update() instead.
95 * will be restored. 106
107 Other functions to avoid are:
108 lcd_blit() (obviously), lcd_update_rect(), lcd_set_contrast(),
109 lcd_set_invert_display(), lcd_set_flip(), lcd_roll()
110
111 The grayscale display consumes ~50 % CPU power (for a full screen overlay,
112 less if the overlay is smaller) when switched on. You can switch the overlay
113 on and off as many times as you want.
96 */ 114 */
97void gray_position_display(int x, int by); 115void gray_show_display(bool enable);
98 116
99/* Switch the grayscale overlay on or off 117/*---------------------------------------------------------------------------
100 * 118 Set position of the top left corner of the grayscale overlay
101 * enable = true: the grayscale overlay is switched on if initialized 119 ----------------------------------------------------------------------------
102 * = false: the grayscale overlay is switched off and the regular lcd 120 x = left margin in pixels
103 * content is restored 121 by = top margin in 8-pixel units
104 * 122
105 * DO NOT call lcd_update() or any other api function that directly accesses 123 You may set this in a way that the overlay spills across the right or
106 * the lcd while the grayscale overlay is running! If you need to do 124 bottom display border. In this case it will simply be clipped by the
107 * lcd_update() to update something outside the grayscale overlay area, use 125 LCD controller. You can even set negative values, this will clip at the
108 * gray_deferred_update() instead. 126 left or top border. I did not test it, but the limits may be +127 / -128
109 * 127
110 * Other functions to avoid are: 128 If you use this while the grayscale overlay is running, the now-freed area
111 * lcd_blit() (obviously), lcd_update_rect(), lcd_set_contrast(), 129 will be restored.
112 * lcd_set_invert_display(), lcd_set_flip(), lcd_roll()
113 *
114 * The grayscale display consumes ~50 % CPU power (for a full screen overlay,
115 * less if the overlay is smaller) when switched on. You can switch the overlay
116 * on and off as many times as you want.
117 */ 130 */
118void gray_show_display(bool enable); 131void gray_position_display(int x, int by);
119 132
120/* Set the draw mode for subsequent drawing operations 133/*---------------------------------------------------------------------------
121 * 134 Set the draw mode for subsequent drawing operations
122 * drawmode = 135 ----------------------------------------------------------------------------
123 * GRAY_DRAW_INVERSE: Foreground pixels are inverted, background pixels are 136 drawmode =
124 * left untouched 137 GRAY_DRAW_INVERSE: Foreground pixels are inverted, background pixels are
125 * GRAY_DRAW_FG: Only foreground pixels are drawn 138 left untouched
126 * GRAY_DRAW_BG: Only background pixels are drawn 139 GRAY_DRAW_FG: Only foreground pixels are drawn
127 * GRAY_DRAW_SOLID: Foreground and background pixels are drawn 140 GRAY_DRAW_BG: Only background pixels are drawn
141 GRAY_DRAW_SOLID: Foreground and background pixels are drawn
128 */ 142 */
129void gray_set_drawmode(int drawmode); 143void gray_set_drawmode(int drawmode);
130 144
131/* Draw modes */ 145/*---------------------------------------------------------------------------
146 Draw modes, see above
147 ----------------------------------------------------------------------------
148 */
132#define GRAY_DRAW_INVERSE 0 149#define GRAY_DRAW_INVERSE 0
133#define GRAY_DRAW_FG 1 150#define GRAY_DRAW_FG 1
134#define GRAY_DRAW_BG 2 151#define GRAY_DRAW_BG 2
135#define GRAY_DRAW_SOLID 3 152#define GRAY_DRAW_SOLID 3
136 153
137/* Set the foreground shade for subsequent drawing operations 154/*---------------------------------------------------------------------------
138 * 155 Set the foreground shade for subsequent drawing operations
139 * brightness = 0 (black) .. 255 (white) 156 ----------------------------------------------------------------------------
157 brightness = 0 (black) .. 255 (white)
140 */ 158 */
141void gray_set_foreground(int brightness); 159void gray_set_foreground(int brightness);
142 160
143/* Set the background shade for subsequent drawing operations 161/*---------------------------------------------------------------------------
144 * 162 Set the background shade for subsequent drawing operations
145 * brightness = 0 (black) .. 255 (white) 163 ----------------------------------------------------------------------------
164 brightness = 0 (black) .. 255 (white)
146 */ 165 */
147void gray_set_background(int brightness); 166void gray_set_background(int brightness);
148 167
149/* Set draw mode, foreground and background shades at once 168/*---------------------------------------------------------------------------
150 * 169 Set draw mode, foreground and background shades at once
151 * If you hand it -1 (or in fact any other out-of-bounds value) for a 170 ----------------------------------------------------------------------------
152 * parameter, that particular setting won't be changed 171 If you hand it -1 (or in fact any other out-of-bounds value) for a
172 parameter, that particular setting won't be changed
153 */ 173 */
154void gray_set_drawinfo(int drawmode, int fg_brightness, int bg_brightness); 174void gray_set_drawinfo(int drawmode, int fg_brightness, int bg_brightness);
155 175
156/**** functions affecting the whole display ****/ 176/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
177 Functions affecting the whole display
178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
179 */
157 180
158/* Clear the grayscale display (sets all pixels to white) */ 181/*---------------------------------------------------------------------------
182 Clear the grayscale display (sets all pixels to white)
183 ----------------------------------------------------------------------------
184 */
159void gray_clear_display(void); 185void gray_clear_display(void);
160 186
161/* Set the grayscale display to all black */ 187/*---------------------------------------------------------------------------
188 Set the grayscale display to all black
189 ----------------------------------------------------------------------------
190 */
162void gray_black_display(void); 191void gray_black_display(void);
163 192
164/* Do an lcd_update() to show changes done by rb->lcd_xxx() functions (in areas 193/*---------------------------------------------------------------------------
165 * of the screen not covered by the grayscale overlay). 194 Do an lcd_update() to show changes done by rb->lcd_xxx() functions (in areas
166 * 195 of the screen not covered by the grayscale overlay).
167 * If the grayscale overlay is running, the update will be done in the next 196 ----------------------------------------------------------------------------
168 * call of the interrupt routine, otherwise it will be performed right away. 197 If the grayscale overlay is running, the update will be done in the next
169 * See also comment for the gray_show_display() function. 198 call of the interrupt routine, otherwise it will be performed right away.
199 See also comment for the gray_show_display() function.
170 */ 200 */
171void gray_deferred_update(void); 201void gray_deferred_update(void);
172 202
173/**** Scrolling functions ****/ 203/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
204 Scrolling functions
205 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
206 */
207
208/*---------------------------------------------------------------------------
209 Scroll the whole grayscale buffer left by <count> pixels
210 ----------------------------------------------------------------------------
211 black_border determines if the pixels scrolled in at the right are black
212 or white
174 213
175/* Scroll the whole grayscale buffer left by <count> pixels 214 Scrolling left/right by an even pixel count is almost twice as fast as
176 * 215 scrolling by an odd pixel count.
177 * black_border determines if the pixels scrolled in at the right are black
178 * or white
179 *
180 * Scrolling left/right by an even pixel count is almost twice as fast as
181 * scrolling by an odd pixel count.
182 */ 216 */
183void gray_scroll_left(int count, bool black_border); 217void gray_scroll_left(int count, bool black_border);
184 218
185/* Scroll the whole grayscale buffer right by <count> pixels 219/*---------------------------------------------------------------------------
186 * 220 Scroll the whole grayscale buffer right by <count> pixels
187 * black_border determines if the pixels scrolled in at the left are black 221 ----------------------------------------------------------------------------
188 * or white 222 black_border determines if the pixels scrolled in at the left are black
189 * 223 or white
190 * Scrolling left/right by an even pixel count is almost twice as fast as 224
191 * scrolling by an odd pixel count. 225 Scrolling left/right by an even pixel count is almost twice as fast as
226 scrolling by an odd pixel count.
192 */ 227 */
193void gray_scroll_right(int count, bool black_border); 228void gray_scroll_right(int count, bool black_border);
194 229
195/* Scroll the whole grayscale buffer up by 8 pixels 230/*---------------------------------------------------------------------------
196 * 231 Scroll the whole grayscale buffer up by 8 pixels
197 * black_border determines if the pixels scrolled in at the bottom are black 232 ----------------------------------------------------------------------------
198 * or white 233 black_border determines if the pixels scrolled in at the bottom are black
199 * 234 or white
200 * Scrolling up/down by 8 pixels is very fast. 235
236 Scrolling up/down by 8 pixels is very fast.
201 */ 237 */
202void gray_scroll_up8(bool black_border); 238void gray_scroll_up8(bool black_border);
203 239
204/* Scroll the whole grayscale buffer down by 8 pixels 240/*---------------------------------------------------------------------------
205 * 241 Scroll the whole grayscale buffer down by 8 pixels
206 * black_border determines if the pixels scrolled in at the top are black 242 ----------------------------------------------------------------------------
207 * or white 243 black_border determines if the pixels scrolled in at the top are black
208 * 244 or white
209 * Scrolling up/down by 8 pixels is very fast. 245
246 Scrolling up/down by 8 pixels is very fast.
210 */ 247 */
211void gray_scroll_down8(bool black_border); 248void gray_scroll_down8(bool black_border);
212 249
213/* Scroll the whole grayscale buffer up by <count> pixels (<= 7) 250/*---------------------------------------------------------------------------
214 * 251 Scroll the whole grayscale buffer up by <count> pixels (<= 7)
215 * black_border determines if the pixels scrolled in at the bottom are black 252 ----------------------------------------------------------------------------
216 * or white 253 black_border determines if the pixels scrolled in at the bottom are black
217 * 254 or white
218 * Scrolling up/down pixel-wise is significantly slower than scrolling 255
219 * left/right or scrolling up/down byte-wise because it involves bit 256 Scrolling up/down pixel-wise is significantly slower than scrolling
220 * shifting. That's why it is asm optimized. 257 left/right or scrolling up/down byte-wise because it involves bit
258 shifting. That's why it is asm optimized.
221 */ 259 */
222void gray_scroll_up(int count, bool black_border); 260void gray_scroll_up(int count, bool black_border);
223 261
224/* Scroll the whole grayscale buffer down by <count> pixels (<= 7) 262/*---------------------------------------------------------------------------
225 * 263 Scroll the whole grayscale buffer down by <count> pixels (<= 7)
226 * black_border determines if the pixels scrolled in at the top are black 264 ----------------------------------------------------------------------------
227 * or white 265 black_border determines if the pixels scrolled in at the top are black
228 * 266 or white
229 * Scrolling up/down pixel-wise is significantly slower than scrolling 267
230 * left/right or scrolling up/down byte-wise because it involves bit 268 Scrolling up/down pixel-wise is significantly slower than scrolling
231 * shifting. That's why it is asm optimized. 269 left/right or scrolling up/down byte-wise because it involves bit
270 shifting. That's why it is asm optimized.
232 */ 271 */
233void gray_scroll_down(int count, bool black_border); 272void gray_scroll_down(int count, bool black_border);
234 273
235/**** Pixel and line functions ****/ 274/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
275 Pixel and line functions
276 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
277 */
236 278
237/* Set a pixel with the current drawinfo 279/*---------------------------------------------------------------------------
238 * 280 Set a pixel with the current drawinfo
239 * If the drawmode is GRAY_DRAW_INVERSE, the pixel is inverted 281 ----------------------------------------------------------------------------
240 * GRAY_DRAW_FG and GRAY_DRAW_SOLID draw the pixel in the foreground shade 282 If the drawmode is GRAY_DRAW_INVERSE, the pixel is inverted
241 * GRAY_DRAW_BG draws the pixel in the background shade 283 GRAY_DRAW_FG and GRAY_DRAW_SOLID draw the pixel in the foreground shade
284 GRAY_DRAW_BG draws the pixel in the background shade
242 */ 285 */
243void gray_drawpixel(int x, int y); 286void gray_drawpixel(int x, int y);
244 287
245/* Draw a line from (x1, y1) to (x2, y2) with the current drawinfo, 288/*---------------------------------------------------------------------------
246 * See gray_drawpixel() for details 289 Draw a line from (x1, y1) to (x2, y2) with the current drawinfo
290 ----------------------------------------------------------------------------
291 See gray_drawpixel() for details
247 */ 292 */
248void gray_drawline(int x1, int y1, int x2, int y2); 293void gray_drawline(int x1, int y1, int x2, int y2);
249 294
250/* Draw a horizontal line from (x1, y) to (x2, y) with the current drawinfo, 295/*---------------------------------------------------------------------------
251 * See gray_drawpixel() for details 296 Draw a horizontal line from (x1, y) to (x2, y) with the current drawinfo
297 ----------------------------------------------------------------------------
298 See gray_drawpixel() for details
252 */ 299 */
253void gray_horline(int x1, int x2, int y); 300void gray_horline(int x1, int x2, int y);
254 301
255/* Draw a vertical line from (x, y1) to (x, y2) with the current drawinfo, 302/*---------------------------------------------------------------------------
256 * See gray_drawpixel() for details 303 Draw a vertical line from (x, y1) to (x, y2) with the current drawinfo
257 * 304 ----------------------------------------------------------------------------
258 * This one uses the block drawing optimization, so it is rather fast. 305 See gray_drawpixel() for details
306 This one uses the block drawing optimization, so it is rather fast.
259 */ 307 */
260void gray_verline(int x, int y1, int y2); 308void gray_verline(int x, int y1, int y2);
261 309
262/**** Rectangle functions ****/ 310/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
311 Rectangle functions
312 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
313 */
263 314
264/* Draw a (hollow) rectangle with the current drawinfo, 315/*---------------------------------------------------------------------------
265 * See gray_drawpixel() for details 316 Draw a (hollow) rectangle with the current drawinfo
317 ----------------------------------------------------------------------------
318 See gray_drawpixel() for details
266 */ 319 */
267void gray_drawrect(int x, int y, int nx, int ny); 320void gray_drawrect(int x, int y, int nx, int ny);
268 321
269/* Draw a filled rectangle with the current drawinfo, 322/*---------------------------------------------------------------------------
270 * See gray_drawpixel() for details 323 Draw a filled rectangle with the current drawinfo
271 * 324 ----------------------------------------------------------------------------
272 * This one uses the block drawing optimization, so it is rather fast. 325 See gray_drawpixel() for details
326 This one uses the block drawing optimization, so it is rather fast.
273 */ 327 */
274void gray_fillrect(int x, int y, int nx, int ny); 328void gray_fillrect(int x, int y, int nx, int ny);
275 329
276/**** Bitmap functions ****/ 330/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
331 Bitmap functions
332 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
333 */
277 334
278/* Copy a grayscale bitmap into the display 335/*---------------------------------------------------------------------------
279 * 336 Copy a grayscale bitmap into the display
280 * A grayscale bitmap contains one byte for every pixel that defines the 337 ----------------------------------------------------------------------------
281 * brightness of the pixel (0..255). Bytes are read in row-major order. 338 A grayscale bitmap contains one byte for every pixel that defines the
282 * The <stride> parameter is useful if you want to show only a part of a 339 brightness of the pixel (0..255). Bytes are read in row-major order.
283 * bitmap. It should always be set to the "row length" of the bitmap, so 340 The <stride> parameter is useful if you want to show only a part of a
284 * for displaying the whole bitmap, nx == stride. 341 bitmap. It should always be set to the "row length" of the bitmap, so
285 * 342 for displaying the whole bitmap, nx == stride.
286 * This is the only drawing function NOT using the drawinfo. 343
344 This is the only drawing function NOT using the drawinfo.
287 */ 345 */
288void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny, 346void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny,
289 int stride); 347 int stride);
290 348
291/* Display a bitmap with the current drawinfo 349/*---------------------------------------------------------------------------
292 * 350 Display a bitmap with the current drawinfo
293 * The drawmode is used as described for gray_set_drawmode() 351 ----------------------------------------------------------------------------
294 * 352 The drawmode is used as described for gray_set_drawmode()
295 * This (now) uses the same bitmap format as the core b&w graphics routines, 353
296 * so you can use bmp2rb to generate bitmaps for use with this function as 354 This (now) uses the same bitmap format as the core b&w graphics routines,
297 * well. 355 so you can use bmp2rb to generate bitmaps for use with this function as
298 * 356 well.
299 * A bitmap contains one bit for every pixel that defines if that pixel is 357
300 * foreground (1) or background (0). Bits within a byte are arranged 358 A bitmap contains one bit for every pixel that defines if that pixel is
301 * vertically, LSB at top. 359 foreground (1) or background (0). Bits within a byte are arranged
302 * The bytes are stored in row-major order, with byte 0 being top left, 360 vertically, LSB at top.
303 * byte 1 2nd from left etc. The first row of bytes defines pixel rows 361 The bytes are stored in row-major order, with byte 0 being top left,
304 * 0..7, the second row defines pixel row 8..15 etc. 362 byte 1 2nd from left etc. The first row of bytes defines pixel rows
305 * 363 0..7, the second row defines pixel row 8..15 etc.
306 * The <stride> parameter is useful if you want to show only a part of a 364
307 * bitmap. It should always be set to the "row length" of the bitmap. 365 The <stride> parameter is useful if you want to show only a part of a
366 bitmap. It should always be set to the "row length" of the bitmap.
308 */ 367 */
309void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny, 368void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
310 int stride); 369 int stride);
311 370
312/**** Font support ****/ 371/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
372 Font support
373 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
374 */
313 375
314/* Set font for the font routines 376/*---------------------------------------------------------------------------
315 * 377 Set font for the font routines
316 * newfont can be FONT_SYSFIXED or FONT_UI the same way as with the Rockbox 378 ----------------------------------------------------------------------------
317 * core routines 379 newfont can be FONT_SYSFIXED or FONT_UI the same way as with the Rockbox
380 core routines
318 */ 381 */
319void gray_setfont(int newfont); 382void gray_setfont(int newfont);
320 383
321/* Calculate width and height of the given text in pixels when rendered with 384/*---------------------------------------------------------------------------
322 * the currently selected font. 385 Calculate width and height of the given text in pixels when rendered with
323 * 386 the currently selected font.
324 * This works exactly the same way as the core lcd_getstringsize(), only that 387 ----------------------------------------------------------------------------
325 * it uses the selected font for grayscale. 388 This works exactly the same way as the core lcd_getstringsize(), only that
389 it uses the selected font for grayscale.
326 */ 390 */
327int gray_getstringsize(unsigned char *str, int *w, int *h); 391int gray_getstringsize(unsigned char *str, int *w, int *h);
328 392
329/* Display text starting at (x, y) with the current font and drawinfo 393/*---------------------------------------------------------------------------
330 * 394 Display text starting at (x, y) with the current font and drawinfo
331 * The drawmode is used as described for gray_set_drawmode() 395 ----------------------------------------------------------------------------
396 The drawmode is used as described for gray_set_drawmode()
332 */ 397 */
333void gray_putsxy(int x, int y, unsigned char *str); 398void gray_putsxy(int x, int y, unsigned char *str);
334 399
400/*===========================================================================
401 Private functions and definitions, for use within the grayscale core only
402 ============================================================================
403 */
404
405/* flag definitions */
406#define _GRAY_RUNNING 0x0001 /* grayscale overlay is running */
407#define _GRAY_DEFERRED_UPDATE 0x0002 /* lcd_update() requested */
408
409/* unsigned 16 bit multiplication (a single instruction on the SH) */
410#define MULU16(a, b) ((unsigned long) \
411 (((unsigned short) (a)) * ((unsigned short) (b))))
412
413/* The grayscale buffer management structure */
414typedef struct
415{
416 int x;
417 int by; /* 8-pixel units */
418 int width;
419 int height;
420 int bheight; /* 8-pixel units */
421 int plane_size;
422 int depth; /* number_of_bitplanes = (number_of_grayscales - 1) */
423 int cur_plane; /* for the timer isr */
424 unsigned long randmask; /* mask for random value in _writepixel() */
425 unsigned long flags; /* various flags, see #defines */
426 unsigned long *bitpattern; /* pointer to start of pattern table */
427 unsigned char *data; /* pointer to start of bitplane data */
428 unsigned long fg_pattern; /* current foreground pattern */
429 unsigned long bg_pattern; /* current background pattern */
430 int drawmode; /* current draw mode */
431 struct font *curfont; /* current selected font */
432} _tGraybuf;
433
434/* Global variables */
435extern struct plugin_api *_gray_rb;
436extern _tGraybuf *_graybuf;
437extern short _gray_random_buffer;
438
439/* Global function pointers */
440extern void (*_gray_pixelfuncs[4])(int x, int y, unsigned long pattern);
441extern void (*_gray_blockfuncs[4])(unsigned char *address, unsigned mask,
442 unsigned bits);
443
335#endif /* HAVE_LCD_BITMAP */ 444#endif /* HAVE_LCD_BITMAP */
336#endif /* SIMULATOR */ 445#endif /* SIMULATOR */
337#endif /* __GRAY_H__ */ 446#endif /* __GRAY_H__ */
diff --git a/apps/plugins/lib/gray_black_display.c b/apps/plugins/lib/gray_black_display.c
new file mode 100644
index 0000000000..573060eb62
--- /dev/null
+++ b/apps/plugins/lib/gray_black_display.c
@@ -0,0 +1,44 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_black_display() function
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 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/*---------------------------------------------------------------------------
33 Set the grayscale display to all black
34 ----------------------------------------------------------------------------
35 */
36void gray_black_display(void)
37{
38 _gray_rb->memset(_graybuf->data, 0xFF, MULU16(_graybuf->depth,
39 _graybuf->plane_size));
40}
41
42#endif // #ifdef HAVE_LCD_BITMAP
43#endif // #ifndef SIMULATOR
44
diff --git a/apps/plugins/lib/gray_blockfuncs.c b/apps/plugins/lib/gray_blockfuncs.c
new file mode 100644
index 0000000000..4eea73a63b
--- /dev/null
+++ b/apps/plugins/lib/gray_blockfuncs.c
@@ -0,0 +1,262 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* Low level block drawing functions
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 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/* Prototypes */
33static void _writeblock(unsigned char *address, unsigned mask, unsigned bits);
34static void _invertblock(unsigned char *address, unsigned mask, unsigned bits);
35static void _writeblockfg(unsigned char *address, unsigned mask, unsigned bits);
36static void _writeblockbg(unsigned char *address, unsigned mask, unsigned bits);
37
38/* Block function pointer array */
39void (*_gray_blockfuncs[4])(unsigned char *address, unsigned mask,
40 unsigned bits) = {
41 _invertblock, _writeblockfg, _writeblockbg, _writeblock
42};
43
44/* Write an 8-pixel block, defined by foreground and background pattern.
45 * Address is the byte in the first bitplane, mask determines which pixels to
46 * set, and bits determines if the pixel is foreground or background */
47static void _writeblock(unsigned char *address, unsigned mask, unsigned bits)
48{
49 unsigned long pat_stack[8];
50 register unsigned char *end_addr;
51 register unsigned long *pat_ptr = &pat_stack[8];
52
53 /* precalculate the bit patterns with random shifts (same RNG as _writepixel,
54 * see there for an explanation) for all 8 pixels and put them on an
55 * extra stack */
56 asm (
57 "mov #8,r3 \n" /* loop count in r3: 8 pixels */
58 "mov %6,r2 \n" /* copy mask */
59
60 ".wb_loop: \n" /** load pattern for pixel **/
61 "shlr r2 \n" /* shift out lsb of mask */
62 "bf .wb_skip \n" /* skip this pixel */
63
64 "mov %2,r4 \n" /* load foreground pattern */
65 "shlr %7 \n" /* shift out lsb of bits */
66 "bt .wb_fg \n" /* foreground? -> skip next insn */
67 "mov %3,r4 \n" /* load background pattern */
68 ".wb_fg: \n"
69
70 "mov #75,r0 \n"
71 "mulu r0,%0 \n" /* multiply by 75 */
72 "sts macl,%0 \n"
73 "add #74,%0 \n" /* add another 74 */
74 /* Since the lower bits are not very random: */
75 "swap.b %0,r1 \n" /* get bits 8..15 (need max. 5) */
76 "and %5,r1 \n" /* mask out unneeded bits */
77
78 "cmp/hs %4,r1 \n" /* random >= depth ? */
79 "bf .wb_ntrim \n"
80 "sub %4,r1 \n" /* yes: random -= depth; */
81 ".wb_ntrim: \n"
82
83 "mov.l .ashlsi3,r0 \n" /** rotate pattern **/
84 "jsr @r0 \n" /* r4 -> r0, shift left by r5 */
85 "mov r1,r5 \n"
86
87 "mov %4,r5 \n"
88 "sub r1,r5 \n" /* r5 = depth - r1 */
89 "mov.l .lshrsi3,r1 \n"
90 "jsr @r1 \n" /* r4 -> r0, shift right by r5 */
91 "mov r0,r1 \n" /* store previous result in r1 */
92
93 "bra .wb_store \n"
94 "or r1,r0 \n" /* rotated_pattern = r0 | r1 */
95
96 ".wb_skip: \n"
97 "shlr %7 \n" /* shift out lsb of bits to keep in sync */
98 "mov #0,r0 \n" /* pattern for skipped pixel must be 0 */
99
100 ".wb_store: \n"
101 "mov.l r0,@-%1 \n" /* push on pattern stack */
102
103 "add #-1,r3 \n" /* decrease loop count */
104 "cmp/pl r3 \n" /* loop count > 0? */
105 "bt .wb_loop \n" /* yes: loop */
106 : /* outputs */
107 /* %0, in & out */ "+r"(_gray_random_buffer),
108 /* %1, in & out */ "+r"(pat_ptr)
109 : /* inputs */
110 /* %2 */ "r"(_graybuf->fg_pattern),
111 /* %3 */ "r"(_graybuf->bg_pattern),
112 /* %4 */ "r"(_graybuf->depth),
113 /* %5 */ "r"(_graybuf->randmask),
114 /* %6 */ "r"(mask),
115 /* %7 */ "r"(bits)
116 : /* clobbers */
117 "r0", "r1", "r2", "r3", "r4", "r5", "macl"
118 );
119
120 end_addr = address + MULU16(_graybuf->depth, _graybuf->plane_size);
121
122 /* set the bits for all 8 pixels in all bytes according to the
123 * precalculated patterns on the pattern stack */
124 asm volatile (
125 "mov.l @%3+,r1 \n" /* pop all 8 patterns */
126 "mov.l @%3+,r2 \n"
127 "mov.l @%3+,r3 \n"
128 "mov.l @%3+,r8 \n"
129 "mov.l @%3+,r9 \n"
130 "mov.l @%3+,r10 \n"
131 "mov.l @%3+,r11 \n"
132 "mov.l @%3+,r12 \n"
133
134 "not %4,%4 \n" /* "set" mask -> "keep" mask */
135 "extu.b %4,%4 \n" /* mask out high bits */
136 "tst %4,%4 \n" /* nothing to keep? */
137 "bt .wb_sloop \n" /* yes: jump to short loop */
138
139 ".wb_floop: \n" /** full loop (there are bits to keep)**/
140 "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */
141 "rotcl r0 \n" /* rotate t bit into r0 */
142 "shlr r2 \n"
143 "rotcl r0 \n"
144 "shlr r3 \n"
145 "rotcl r0 \n"
146 "shlr r8 \n"
147 "rotcl r0 \n"
148 "shlr r9 \n"
149 "rotcl r0 \n"
150 "shlr r10 \n"
151 "rotcl r0 \n"
152 "shlr r11 \n"
153 "rotcl r0 \n"
154 "shlr r12 \n"
155 "mov.b @%0,%3 \n" /* read old value */
156 "rotcl r0 \n"
157 "and %4,%3 \n" /* mask out unneeded bits */
158 "or r0,%3 \n" /* set new bits */
159 "mov.b %3,@%0 \n" /* store value to bitplane */
160 "add %2,%0 \n" /* advance to next bitplane */
161 "cmp/hi %0,%1 \n" /* last bitplane done? */
162 "bt .wb_floop \n" /* no: loop */
163
164 "bra .wb_end \n"
165 "nop \n"
166
167 ".wb_sloop: \n" /** short loop (nothing to keep) **/
168 "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */
169 "rotcl r0 \n" /* rotate t bit into r0 */
170 "shlr r2 \n"
171 "rotcl r0 \n"
172 "shlr r3 \n"
173 "rotcl r0 \n"
174 "shlr r8 \n"
175 "rotcl r0 \n"
176 "shlr r9 \n"
177 "rotcl r0 \n"
178 "shlr r10 \n"
179 "rotcl r0 \n"
180 "shlr r11 \n"
181 "rotcl r0 \n"
182 "shlr r12 \n"
183 "rotcl r0 \n"
184 "mov.b r0,@%0 \n" /* store byte to bitplane */
185 "add %2,%0 \n" /* advance to next bitplane */
186 "cmp/hi %0,%1 \n" /* last bitplane done? */
187 "bt .wb_sloop \n" /* no: loop */
188
189 ".wb_end: \n"
190 : /* outputs */
191 : /* inputs */
192 /* %0 */ "r"(address),
193 /* %1 */ "r"(end_addr),
194 /* %2 */ "r"(_graybuf->plane_size),
195 /* %3 */ "r"(pat_ptr),
196 /* %4 */ "r"(mask)
197 : /* clobbers */
198 "r0", "r1", "r2", "r3", "r8", "r9", "r10", "r11", "r12"
199 );
200}
201
202/* References to C library routines used in _writeblock */
203asm (
204 ".align 2 \n"
205".ashlsi3: \n" /* C library routine: */
206 ".long ___ashlsi3 \n" /* shift r4 left by r5, return in r0 */
207".lshrsi3: \n" /* C library routine: */
208 ".long ___lshrsi3 \n" /* shift r4 right by r5, return in r0 */
209 /* both routines preserve r4, destroy r5 and take ~16 cycles */
210);
211
212/* Invert pixels within an 8-pixel block.
213 * Address is the byte in the first bitplane, mask and bits determine which
214 * pixels to invert ('And'ed together, for matching the parameters with
215 * _writeblock) */
216static void _invertblock(unsigned char *address, unsigned mask, unsigned bits)
217{
218 bits &= mask;
219 if (!bits)
220 return;
221
222 asm volatile (
223 "mov #0,r1 \n" /* current_plane = 0 */
224
225 ".im_loop: \n"
226 "mov.b @%1,r2 \n" /* get data byte */
227 "add #1,r1 \n" /* current_plane++; */
228 "xor %2,r2 \n" /* invert bits */
229 "mov.b r2,@%1 \n" /* store data byte */
230 "add %3,%1 \n" /* advance address to next bitplane */
231 "cmp/hi r1,%0 \n" /* current_plane < depth ? */
232 "bt .im_loop \n"
233 : /* outputs */
234 : /* inputs */
235 /* %0 */ "r"(_graybuf->depth),
236 /* %1 */ "r"(address),
237 /* %2 */ "r"(bits),
238 /* %3 */ "r"(_graybuf->plane_size)
239 : /* clobbers */
240 "r1", "r2", "macl"
241 );
242}
243
244/* Call _writeblock with the mask modified to draw foreground pixels only */
245static void _writeblockfg(unsigned char *address, unsigned mask, unsigned bits)
246{
247 mask &= bits;
248 if (mask)
249 _writeblock(address, mask, bits);
250}
251
252/* Call _writeblock with the mask modified to draw background pixels only */
253static void _writeblockbg(unsigned char *address, unsigned mask, unsigned bits)
254{
255 mask &= ~bits;
256 if (mask)
257 _writeblock(address, mask, bits);
258}
259
260#endif // #ifdef HAVE_LCD_BITMAP
261#endif // #ifndef SIMULATOR
262
diff --git a/apps/plugins/lib/gray_clear_display.c b/apps/plugins/lib/gray_clear_display.c
new file mode 100644
index 0000000000..835107a7fe
--- /dev/null
+++ b/apps/plugins/lib/gray_clear_display.c
@@ -0,0 +1,44 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_clear_display() function
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 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/*---------------------------------------------------------------------------
33 Clear the grayscale display (sets all pixels to white)
34 ----------------------------------------------------------------------------
35 */
36void gray_clear_display(void)
37{
38 _gray_rb->memset(_graybuf->data, 0, MULU16(_graybuf->depth,
39 _graybuf->plane_size));
40}
41
42#endif // #ifdef HAVE_LCD_BITMAP
43#endif // #ifndef SIMULATOR
44
diff --git a/apps/plugins/lib/gray_core.c b/apps/plugins/lib/gray_core.c
new file mode 100644
index 0000000000..b582cd801a
--- /dev/null
+++ b/apps/plugins/lib/gray_core.c
@@ -0,0 +1,252 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* Core functions
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 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/* Global variables */
33struct plugin_api *_gray_rb = NULL; /* global api struct pointer */
34_tGraybuf *_graybuf = NULL; /* pointer to grayscale buffer */
35short _gray_random_buffer; /* buffer for random number generator */
36
37/* Prototypes */
38static void _timer_isr(void);
39
40/* timer interrupt handler: display next bitplane */
41static void _timer_isr(void)
42{
43 _gray_rb->lcd_blit(_graybuf->data + MULU16(_graybuf->plane_size,
44 _graybuf->cur_plane), _graybuf->x, _graybuf->by,
45 _graybuf->width, _graybuf->bheight, _graybuf->width);
46
47 if (++_graybuf->cur_plane >= _graybuf->depth)
48 _graybuf->cur_plane = 0;
49
50 if (_graybuf->flags & _GRAY_DEFERRED_UPDATE) /* lcd_update() requested? */
51 {
52 int x1 = MAX(_graybuf->x, 0);
53 int x2 = MIN(_graybuf->x + _graybuf->width, LCD_WIDTH);
54 int y1 = MAX(_graybuf->by << 3, 0);
55 int y2 = MIN((_graybuf->by << 3) + _graybuf->height, LCD_HEIGHT);
56
57 if (y1 > 0) /* refresh part above overlay, full width */
58 _gray_rb->lcd_update_rect(0, 0, LCD_WIDTH, y1);
59
60 if (y2 < LCD_HEIGHT) /* refresh part below overlay, full width */
61 _gray_rb->lcd_update_rect(0, y2, LCD_WIDTH, LCD_HEIGHT - y2);
62
63 if (x1 > 0) /* refresh part to the left of overlay */
64 _gray_rb->lcd_update_rect(0, y1, x1, y2 - y1);
65
66 if (x2 < LCD_WIDTH) /* refresh part to the right of overlay */
67 _gray_rb->lcd_update_rect(x2, y1, LCD_WIDTH - x2, y2 - y1);
68
69 _graybuf->flags &= ~_GRAY_DEFERRED_UPDATE; /* clear request */
70 }
71}
72
73/*---------------------------------------------------------------------------
74 Initialize the framework
75 ----------------------------------------------------------------------------
76 Every framework needs such a function, and it has to be called as
77 the very first one */
78void gray_init(struct plugin_api* newrb)
79{
80 _gray_rb = newrb;
81}
82
83/*---------------------------------------------------------------------------
84 Prepare the grayscale display buffer
85 ----------------------------------------------------------------------------
86 arguments:
87 gbuf = pointer to the memory area to use (e.g. plugin buffer)
88 gbuf_size = max usable size of the buffer
89 width = width in pixels (1..112)
90 bheight = height in 8-pixel units (1..8)
91 depth = desired number of shades - 1 (1..32)
92
93 result:
94 = depth if there was enough memory
95 < depth if there wasn't enough memory. The number of displayable
96 shades is smaller than desired, but it still works
97 = 0 if there wasn't even enough memory for 1 bitplane (black & white)
98
99 You can request any depth from 1 to 32, not just powers of 2. The routine
100 performs "graceful degradation" if the memory is not sufficient for the
101 desired depth. As long as there is at least enough memory for 1 bitplane,
102 it creates as many bitplanes as fit into memory, although 1 bitplane will
103 only deliver black & white display.
104
105 If you need info about the memory taken by the grayscale buffer, supply an
106 int* as the last parameter. This int will then contain the number of bytes
107 used. The total memory needed can be calculated as follows:
108 total_mem =
109 sizeof(_tGraybuf) (= 64 bytes currently)
110 + sizeof(long) (= 4 bytes)
111 + (width * bheight + sizeof(long)) * depth
112 + 0..3 (longword alignment of grayscale display buffer)
113 */
114int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
115 int bheight, int depth, int *buf_taken)
116{
117 int possible_depth, plane_size;
118 int i, j, align;
119
120 if ((unsigned) width > LCD_WIDTH
121 || (unsigned) bheight > (LCD_HEIGHT/8)
122 || depth < 1)
123 return 0;
124
125 /* the buffer has to be long aligned */
126 align = 3 - (((unsigned long)gbuf + 3) & 3);
127 gbuf += align;
128 gbuf_size -= align;
129
130 plane_size = MULU16(width, bheight);
131 possible_depth = (gbuf_size - sizeof(_tGraybuf) - sizeof(long))
132 / (plane_size + sizeof(long));
133
134 if (possible_depth < 1)
135 return 0;
136
137 depth = MIN(depth, 32);
138 depth = MIN(depth, possible_depth);
139
140 _graybuf = (_tGraybuf *) gbuf; /* global pointer to buffer structure */
141
142 _graybuf->x = 0;
143 _graybuf->by = 0;
144 _graybuf->width = width;
145 _graybuf->height = bheight << 3;
146 _graybuf->bheight = bheight;
147 _graybuf->plane_size = plane_size;
148 _graybuf->depth = depth;
149 _graybuf->cur_plane = 0;
150 _graybuf->flags = 0;
151 _graybuf->bitpattern = (unsigned long *) (gbuf + sizeof(_tGraybuf));
152 _graybuf->data = (unsigned char *) (_graybuf->bitpattern + depth + 1);
153
154 i = depth - 1;
155 j = 8;
156 while (i != 0)
157 {
158 i >>= 1;
159 j--;
160 }
161 _graybuf->randmask = 0xFFu >> j;
162
163 /* initial state is all white */
164 _gray_rb->memset(_graybuf->data, 0, MULU16(depth, plane_size));
165
166 /* Precalculate the bit patterns for all possible pixel values */
167 for (i = 0; i <= depth; i++)
168 {
169 unsigned long pattern = 0;
170 int value = 0;
171
172 for (j = 0; j < depth; j++)
173 {
174 pattern <<= 1;
175 value += i;
176
177 if (value >= depth)
178 value -= depth; /* "white" bit */
179 else
180 pattern |= 1; /* "black" bit */
181 }
182 /* now the lower <depth> bits contain the pattern */
183
184 _graybuf->bitpattern[i] = pattern;
185 }
186
187 _graybuf->fg_pattern = _graybuf->bitpattern[0]; /* black */
188 _graybuf->bg_pattern = _graybuf->bitpattern[depth]; /* white */
189 _graybuf->drawmode = GRAY_DRAW_SOLID;
190 _graybuf->curfont = FONT_SYSFIXED;
191
192 if (buf_taken) /* caller requested info about space taken */
193 {
194 *buf_taken = sizeof(_tGraybuf) + sizeof(long)
195 + MULU16(plane_size + sizeof(long), depth) + align;
196 }
197
198 return depth;
199}
200
201/*---------------------------------------------------------------------------
202 Release the grayscale display buffer
203 ----------------------------------------------------------------------------
204 Switches the grayscale overlay off at first if it is still running,
205 then sets the pointer to NULL.
206 DO CALL either this function or at least gray_show_display(false)
207 before you exit, otherwise nasty things may happen.
208 */
209void gray_release_buffer(void)
210{
211 gray_show_display(false);
212 _graybuf = NULL;
213}
214
215/*---------------------------------------------------------------------------
216 Switch the grayscale overlay on or off
217 ----------------------------------------------------------------------------
218 enable = true: the grayscale overlay is switched on if initialized
219 = false: the grayscale overlay is switched off and the regular lcd
220 content is restored
221
222 DO NOT call lcd_update() or any other api function that directly accesses
223 the lcd while the grayscale overlay is running! If you need to do
224 lcd_update() to update something outside the grayscale overlay area, use
225 gray_deferred_update() instead.
226
227 Other functions to avoid are:
228 lcd_blit() (obviously), lcd_update_rect(), lcd_set_contrast(),
229 lcd_set_invert_display(), lcd_set_flip(), lcd_roll()
230
231 The grayscale display consumes ~50 % CPU power (for a full screen overlay,
232 less if the overlay is smaller) when switched on. You can switch the overlay
233 on and off as many times as you want.
234 */
235void gray_show_display(bool enable)
236{
237 if (enable)
238 {
239 _graybuf->flags |= _GRAY_RUNNING;
240 _gray_rb->plugin_register_timer(FREQ / 67, 1, _timer_isr);
241 }
242 else
243 {
244 _gray_rb->plugin_unregister_timer();
245 _graybuf->flags &= ~_GRAY_RUNNING;
246 _gray_rb->lcd_update(); /* restore whatever there was before */
247 }
248}
249
250#endif // #ifdef HAVE_LCD_BITMAP
251#endif // #ifndef SIMULATOR
252
diff --git a/apps/plugins/lib/gray_deferred_update.c b/apps/plugins/lib/gray_deferred_update.c
new file mode 100644
index 0000000000..3b6edd869e
--- /dev/null
+++ b/apps/plugins/lib/gray_deferred_update.c
@@ -0,0 +1,50 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_deferred_update() function
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 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/*---------------------------------------------------------------------------
33 Do an lcd_update() to show changes done by rb->lcd_xxx() functions (in areas
34 of the screen not covered by the grayscale overlay).
35 ----------------------------------------------------------------------------
36 If the grayscale overlay is running, the update will be done in the next
37 call of the interrupt routine, otherwise it will be performed right away.
38 See also comment for the gray_show_display() function.
39 */
40void gray_deferred_update(void)
41{
42 if (_graybuf->flags & _GRAY_RUNNING)
43 _graybuf->flags |= _GRAY_DEFERRED_UPDATE;
44 else
45 _gray_rb->lcd_update();
46}
47
48#endif // #ifdef HAVE_LCD_BITMAP
49#endif // #ifndef SIMULATOR
50
diff --git a/apps/plugins/lib/gray_drawbitmap.c b/apps/plugins/lib/gray_drawbitmap.c
new file mode 100644
index 0000000000..5ddb19568a
--- /dev/null
+++ b/apps/plugins/lib/gray_drawbitmap.c
@@ -0,0 +1,115 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_drawbitmap() function
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 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/*---------------------------------------------------------------------------
33 Display a bitmap with the current drawinfo
34 ----------------------------------------------------------------------------
35 The drawmode is used as described for gray_set_drawmode()
36
37 This (now) uses the same bitmap format as the core b&w graphics routines,
38 so you can use bmp2rb to generate bitmaps for use with this function as
39 well.
40
41 A bitmap contains one bit for every pixel that defines if that pixel is
42 foreground (1) or background (0). Bits within a byte are arranged
43 vertically, LSB at top.
44 The bytes are stored in row-major order, with byte 0 being top left,
45 byte 1 2nd from left etc. The first row of bytes defines pixel rows
46 0..7, the second row defines pixel row 8..15 etc.
47
48 The <stride> parameter is useful if you want to show only a part of a
49 bitmap. It should always be set to the "row length" of the bitmap.
50 */
51void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
52 int stride)
53{
54 int shift;
55 unsigned bits, mask_top, mask_bottom;
56 unsigned char *src_col, *dst, *dst_col;
57 void (*blockfunc)(unsigned char *address, unsigned mask, unsigned bits);
58
59 if ((unsigned) x >= (unsigned) _graybuf->width
60 || (unsigned) y >= (unsigned) _graybuf->height)
61 return;
62
63 if ((unsigned) (y + ny) >= (unsigned) _graybuf->height) /* clip bottom */
64 ny = _graybuf->height - y;
65
66 if ((unsigned) (x + nx) >= (unsigned) _graybuf->width) /* clip right */
67 nx = _graybuf->width - x;
68
69 dst = _graybuf->data + x + MULU16(_graybuf->width, y >> 3);
70 shift = y & 7;
71 ny += shift;
72
73 mask_top = 0xFFu << (y & 7);
74 mask_bottom = ~(0xFEu << ((ny - 1) & 7));
75 if (ny <= 8)
76 mask_bottom &= mask_top;
77
78 blockfunc = _gray_blockfuncs[_graybuf->drawmode];
79
80 for(x = 0; x < nx; x++)
81 {
82 src_col = src++;
83 dst_col = dst++;
84 bits = 0;
85 y = 0;
86
87 if (ny > 8)
88 {
89 bits = *src_col << shift;
90 src_col += stride;
91
92 blockfunc(dst_col, mask_top, bits);
93 dst_col += _graybuf->width;
94 bits >>= 8;
95
96 for (y = 8; y < ny - 8; y += 8)
97 {
98 bits |= *src_col << shift;
99 src_col += stride;
100
101 blockfunc(dst_col, 0xFFu, bits);
102 dst_col += _graybuf->width;
103 bits >>= 8;
104 }
105 }
106 if (y + shift < ny)
107 bits |= *src_col << shift;
108
109 blockfunc(dst_col, mask_bottom, bits);
110 }
111}
112
113#endif // #ifdef HAVE_LCD_BITMAP
114#endif // #ifndef SIMULATOR
115
diff --git a/apps/plugins/lib/gray_drawgraymap.c b/apps/plugins/lib/gray_drawgraymap.c
new file mode 100644
index 0000000000..5febeb27ad
--- /dev/null
+++ b/apps/plugins/lib/gray_drawgraymap.c
@@ -0,0 +1,274 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_drawgraymap() function
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 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/* Prototypes */
33static void _writearray(unsigned char *address, unsigned char *src, int stride,
34 unsigned mask);
35
36/* Write an 8-pixel block, defined by their brightnesses in a graymap.
37 * Address is the byte in the first bitplane, src is the graymap start address,
38 * stride is the increment for the graymap to get to the next pixel, mask
39 * determines which pixels of the destination block are changed. For "0" bits,
40 * the src address is not incremented! */
41static void _writearray(unsigned char *address, unsigned char *src, int stride,
42 unsigned mask)
43{
44 unsigned long pat_stack[8];
45 register unsigned char *end_addr;
46 register unsigned long *pat_ptr = &pat_stack[8];
47
48 /* precalculate the bit patterns with random shifts (same RNG as
49 * _writepixel, see there for an explanation) for all 8 pixels and put them
50 * on an extra "stack" */
51 asm (
52 "mov #8,r3 \n" /* loop count in r3: 8 pixels */
53 "mov %7,r2 \n" /* copy mask */
54
55 ".wa_loop: \n" /** load pattern for pixel **/
56 "mov #0,r0 \n" /* pattern for skipped pixel must be 0 */
57 "shlr r2 \n" /* shift out lsb of mask */
58 "bf .wa_skip \n" /* skip this pixel */
59
60 "mov.b @%2,r0 \n" /* load src byte */
61 "extu.b r0,r0 \n" /* extend unsigned */
62 "mulu %4,r0 \n" /* macl = byte * depth; */
63 "add %3,%2 \n" /* src += stride; */
64 "sts macl,r4 \n" /* r4 = macl; */
65 "add r4,r0 \n" /* byte += r4; */
66 "shlr8 r0 \n" /* byte >>= 8; */
67 "shll2 r0 \n"
68 "mov.l @(r0,%5),r4 \n" /* r4 = bitpattern[byte]; */
69
70 "mov #75,r0 \n"
71 "mulu r0,%0 \n" /* multiply by 75 */
72 "sts macl,%0 \n"
73 "add #74,%0 \n" /* add another 74 */
74 /* Since the lower bits are not very random: */
75 "swap.b %0,r1 \n" /* get bits 8..15 (need max. 5) */
76 "and %6,r1 \n" /* mask out unneeded bits */
77
78 "cmp/hs %4,r1 \n" /* random >= depth ? */
79 "bf .wa_ntrim \n"
80 "sub %4,r1 \n" /* yes: random -= depth; */
81 ".wa_ntrim: \n"
82
83 "mov.l .ashlsi3,r0 \n" /** rotate pattern **/
84 "jsr @r0 \n" /* r4 -> r0, shift left by r5 */
85 "mov r1,r5 \n"
86
87 "mov %4,r5 \n"
88 "sub r1,r5 \n" /* r5 = depth - r1 */
89 "mov.l .lshrsi3,r1 \n"
90 "jsr @r1 \n" /* r4 -> r0, shift right by r5 */
91 "mov r0,r1 \n" /* store previous result in r1 */
92
93 "or r1,r0 \n" /* rotated_pattern = r0 | r1 */
94
95 ".wa_skip: \n"
96 "mov.l r0,@-%1 \n" /* push on pattern stack */
97
98 "add #-1,r3 \n" /* decrease loop count */
99 "cmp/pl r3 \n" /* loop count > 0? */
100 "bt .wa_loop \n" /* yes: loop */
101 : /* outputs */
102 /* %0, in & out */ "+r"(_gray_random_buffer),
103 /* %1, in & out */ "+r"(pat_ptr)
104 : /* inputs */
105 /* %2 */ "r"(src),
106 /* %3 */ "r"(stride),
107 /* %4 */ "r"(_graybuf->depth),
108 /* %5 */ "r"(_graybuf->bitpattern),
109 /* %6 */ "r"(_graybuf->randmask),
110 /* %7 */ "r"(mask)
111 : /* clobbers */
112 "r0", "r1", "r2", "r3", "r4", "r5", "macl"
113 );
114
115 end_addr = address + MULU16(_graybuf->depth, _graybuf->plane_size);
116
117 /* set the bits for all 8 pixels in all bytes according to the
118 * precalculated patterns on the pattern stack */
119 asm volatile (
120 "mov.l @%3+,r1 \n" /* pop all 8 patterns */
121 "mov.l @%3+,r2 \n"
122 "mov.l @%3+,r3 \n"
123 "mov.l @%3+,r8 \n"
124 "mov.l @%3+,r9 \n"
125 "mov.l @%3+,r10 \n"
126 "mov.l @%3+,r11 \n"
127 "mov.l @%3+,r12 \n"
128
129 "not %4,%4 \n" /* "set" mask -> "keep" mask */
130 "extu.b %4,%4 \n" /* mask out high bits */
131 "tst %4,%4 \n" /* nothing to keep? */
132 "bt .wa_sloop \n" /* yes: jump to short loop */
133
134 ".wa_floop: \n" /** full loop (there are bits to keep)**/
135 "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */
136 "rotcl r0 \n" /* rotate t bit into r0 */
137 "shlr r2 \n"
138 "rotcl r0 \n"
139 "shlr r3 \n"
140 "rotcl r0 \n"
141 "shlr r8 \n"
142 "rotcl r0 \n"
143 "shlr r9 \n"
144 "rotcl r0 \n"
145 "shlr r10 \n"
146 "rotcl r0 \n"
147 "shlr r11 \n"
148 "rotcl r0 \n"
149 "shlr r12 \n"
150 "mov.b @%0,%3 \n" /* read old value */
151 "rotcl r0 \n"
152 "and %4,%3 \n" /* mask out unneeded bits */
153 "or r0,%3 \n" /* set new bits */
154 "mov.b %3,@%0 \n" /* store value to bitplane */
155 "add %2,%0 \n" /* advance to next bitplane */
156 "cmp/hi %0,%1 \n" /* last bitplane done? */
157 "bt .wa_floop \n" /* no: loop */
158
159 "bra .wa_end \n"
160 "nop \n"
161
162 ".wa_sloop: \n" /** short loop (nothing to keep) **/
163 "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */
164 "rotcl r0 \n" /* rotate t bit into r0 */
165 "shlr r2 \n"
166 "rotcl r0 \n"
167 "shlr r3 \n"
168 "rotcl r0 \n"
169 "shlr r8 \n"
170 "rotcl r0 \n"
171 "shlr r9 \n"
172 "rotcl r0 \n"
173 "shlr r10 \n"
174 "rotcl r0 \n"
175 "shlr r11 \n"
176 "rotcl r0 \n"
177 "shlr r12 \n"
178 "rotcl r0 \n"
179 "mov.b r0,@%0 \n" /* store byte to bitplane */
180 "add %2,%0 \n" /* advance to next bitplane */
181 "cmp/hi %0,%1 \n" /* last bitplane done? */
182 "bt .wa_sloop \n" /* no: loop */
183
184 ".wa_end: \n"
185 : /* outputs */
186 : /* inputs */
187 /* %0 */ "r"(address),
188 /* %1 */ "r"(end_addr),
189 /* %2 */ "r"(_graybuf->plane_size),
190 /* %3 */ "r"(pat_ptr),
191 /* %4 */ "r"(mask)
192 : /* clobbers */
193 "r0", "r1", "r2", "r3", "r8", "r9", "r10", "r11", "r12"
194 );
195}
196
197/* References to C library routines used in _writearray */
198asm (
199 ".align 2 \n"
200".ashlsi3: \n" /* C library routine: */
201 ".long ___ashlsi3 \n" /* shift r4 left by r5, return in r0 */
202".lshrsi3: \n" /* C library routine: */
203 ".long ___lshrsi3 \n" /* shift r4 right by r5, return in r0 */
204 /* both routines preserve r4, destroy r5 and take ~16 cycles */
205);
206
207/*---------------------------------------------------------------------------
208 Copy a grayscale bitmap into the display
209 ----------------------------------------------------------------------------
210 A grayscale bitmap contains one byte for every pixel that defines the
211 brightness of the pixel (0..255). Bytes are read in row-major order.
212 The <stride> parameter is useful if you want to show only a part of a
213 bitmap. It should always be set to the "row length" of the bitmap, so
214 for displaying the whole bitmap, nx == stride.
215
216 This is the only drawing function NOT using the drawinfo.
217 */
218void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny,
219 int stride)
220{
221 int shift;
222 unsigned mask_top, mask_bottom;
223 unsigned char *src_row, *dst, *dst_row;
224
225 if ((unsigned) x >= (unsigned) _graybuf->width
226 || (unsigned) y >= (unsigned) _graybuf->height)
227 return;
228
229 if ((unsigned) (y + ny) >= (unsigned) _graybuf->height) /* clip bottom */
230 ny = _graybuf->height - y;
231
232 if ((unsigned) (x + nx) >= (unsigned) _graybuf->width) /* clip right */
233 nx = _graybuf->width - x;
234
235 dst = _graybuf->data + x + MULU16(_graybuf->width, y >> 3);
236 shift = y & 7;
237 ny += shift;
238
239 mask_top = 0xFFu << (y & 7);
240 mask_bottom = ~(0xFEu << ((ny - 1) & 7));
241 if (ny <= 8)
242 mask_bottom &= mask_top;
243
244 if (ny > 8)
245 {
246 src_row = src;
247 dst_row = dst;
248
249 for (x = 0; x < nx; x++)
250 _writearray(dst_row++, src_row++, stride, mask_top);
251
252 src += MULU16(stride, 8 - shift);
253 dst += _graybuf->width;
254
255 for (y = 8; y < ny - 8; y += 8)
256 {
257 src_row = src;
258 dst_row = dst;
259
260 for (x = 0; x < nx; x++)
261 _writearray(dst_row++, src_row++, stride, 0xFFu);
262
263 src += stride << 3;
264 dst += _graybuf->width;
265 }
266 }
267
268 for (x = 0; x < nx; x++)
269 _writearray(dst++, src++, stride, mask_bottom);
270}
271
272#endif // #ifdef HAVE_LCD_BITMAP
273#endif // #ifndef SIMULATOR
274
diff --git a/apps/plugins/lib/gray_drawline.c b/apps/plugins/lib/gray_drawline.c
new file mode 100644
index 0000000000..5ec4967c14
--- /dev/null
+++ b/apps/plugins/lib/gray_drawline.c
@@ -0,0 +1,119 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_drawline() function
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 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/*---------------------------------------------------------------------------
33 Draw a line from (x1, y1) to (x2, y2) with the current drawinfo
34 ----------------------------------------------------------------------------
35 See gray_drawpixel() for details
36 */
37void gray_drawline(int x1, int y1, int x2, int y2)
38{
39 int numpixels;
40 int i;
41 int deltax, deltay;
42 int d, dinc1, dinc2;
43 int x, xinc1, xinc2;
44 int y, yinc1, yinc2;
45 unsigned long pattern;
46 void (*pixelfunc)(int x, int y, unsigned long pattern);
47
48 if ((unsigned) x1 >= (unsigned) _graybuf->width
49 || (unsigned) y1 >= (unsigned) _graybuf->height
50 || (unsigned) x2 >= (unsigned) _graybuf->width
51 || (unsigned) y2 >= (unsigned) _graybuf->height)
52 return;
53
54 deltax = abs(x2 - x1);
55 deltay = abs(y2 - y1);
56 xinc2 = 1;
57 yinc2 = 1;
58
59 if (deltax >= deltay)
60 {
61 numpixels = deltax;
62 d = 2 * deltay - deltax;
63 dinc1 = deltay * 2;
64 dinc2 = (deltay - deltax) * 2;
65 xinc1 = 1;
66 yinc1 = 0;
67 }
68 else
69 {
70 numpixels = deltay;
71 d = 2 * deltax - deltay;
72 dinc1 = deltax * 2;
73 dinc2 = (deltax - deltay) * 2;
74 xinc1 = 0;
75 yinc1 = 1;
76 }
77 numpixels++; /* include endpoints */
78
79 if (x1 > x2)
80 {
81 xinc1 = -xinc1;
82 xinc2 = -xinc2;
83 }
84
85 if (y1 > y2)
86 {
87 yinc1 = -yinc1;
88 yinc2 = -yinc2;
89 }
90
91 x = x1;
92 y = y1;
93
94 pixelfunc = _gray_pixelfuncs[_graybuf->drawmode];
95 pattern = (_graybuf->drawmode == GRAY_DRAW_BG) ?
96 _graybuf->bg_pattern : _graybuf->fg_pattern;
97
98 for (i = 0; i < numpixels; i++)
99 {
100 pixelfunc(x, y, pattern);
101
102 if (d < 0)
103 {
104 d += dinc1;
105 x += xinc1;
106 y += yinc1;
107 }
108 else
109 {
110 d += dinc2;
111 x += xinc2;
112 y += yinc2;
113 }
114 }
115}
116
117#endif // #ifdef HAVE_LCD_BITMAP
118#endif // #ifndef SIMULATOR
119
diff --git a/apps/plugins/lib/gray_drawpixel.c b/apps/plugins/lib/gray_drawpixel.c
new file mode 100644
index 0000000000..f7601f4360
--- /dev/null
+++ b/apps/plugins/lib/gray_drawpixel.c
@@ -0,0 +1,55 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_drawpixel() function
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 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/*---------------------------------------------------------------------------
33 Set a pixel with the current drawinfo
34 ----------------------------------------------------------------------------
35 If the drawmode is GRAY_DRAW_INVERSE, the pixel is inverted
36 GRAY_DRAW_FG and GRAY_DRAW_SOLID draw the pixel in the foreground shade
37 GRAY_DRAW_BG draws the pixel in the background shade
38 */
39void gray_drawpixel(int x, int y)
40{
41 unsigned long pattern;
42
43 if ((unsigned) x >= (unsigned) _graybuf->width
44 || (unsigned) y >= (unsigned) _graybuf->height)
45 return;
46
47 pattern = (_graybuf->drawmode == GRAY_DRAW_BG) ?
48 _graybuf->bg_pattern : _graybuf->fg_pattern;
49
50 _gray_pixelfuncs[_graybuf->drawmode](x, y, pattern);
51}
52
53#endif // #ifdef HAVE_LCD_BITMAP
54#endif // #ifndef SIMULATOR
55
diff --git a/apps/plugins/lib/gray_drawrect.c b/apps/plugins/lib/gray_drawrect.c
new file mode 100644
index 0000000000..bd0bb71852
--- /dev/null
+++ b/apps/plugins/lib/gray_drawrect.c
@@ -0,0 +1,62 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_drawrect() function
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 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/*---------------------------------------------------------------------------
33 Draw a (hollow) rectangle with the current drawinfo
34 ----------------------------------------------------------------------------
35 See gray_drawpixel() for details
36 */
37void gray_drawrect(int x, int y, int nx, int ny)
38{
39 int x2, y2;
40
41 if ((unsigned) x >= (unsigned) _graybuf->width
42 || (unsigned) y >= (unsigned) _graybuf->height)
43 return;
44
45 if ((unsigned) (y + ny) >= (unsigned) _graybuf->height) /* clip bottom */
46 ny = _graybuf->height - y;
47
48 if ((unsigned) (x + nx) >= (unsigned) _graybuf->width) /* clip right */
49 nx = _graybuf->width - x;
50
51 x2 = x + nx - 1;
52 y2 = y + ny - 1;
53
54 gray_horline(x, x2, y);
55 gray_horline(x, x2, y2);
56 gray_verline(x, y, y2);
57 gray_verline(x2, y, y2);
58}
59
60#endif // #ifdef HAVE_LCD_BITMAP
61#endif // #ifndef SIMULATOR
62
diff --git a/apps/plugins/lib/gray_fillrect.c b/apps/plugins/lib/gray_fillrect.c
new file mode 100644
index 0000000000..ac6d4818b9
--- /dev/null
+++ b/apps/plugins/lib/gray_fillrect.c
@@ -0,0 +1,92 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_fillrect() function
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 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/*---------------------------------------------------------------------------
33 Draw a filled rectangle with the current drawinfo
34 ----------------------------------------------------------------------------
35 See gray_drawpixel() for details
36
37 This one uses the block drawing optimization, so it is rather fast.
38 */
39void gray_fillrect(int x, int y, int nx, int ny)
40{
41 int shift;
42 unsigned bits, mask_top, mask_bottom;
43 unsigned char *dst, *dst_row;
44 void (*blockfunc)(unsigned char *address, unsigned mask, unsigned bits);
45
46 if ((unsigned) x >= (unsigned) _graybuf->width
47 || (unsigned) y >= (unsigned) _graybuf->height)
48 return;
49
50 if ((unsigned) (y + ny) >= (unsigned) _graybuf->height) /* clip bottom */
51 ny = _graybuf->height - y;
52
53 if ((unsigned) (x + nx) >= (unsigned) _graybuf->width) /* clip right */
54 nx = _graybuf->width - x;
55
56 dst = _graybuf->data + x + MULU16(_graybuf->width, y >> 3);
57 shift = y & 7;
58 ny += shift;
59
60 mask_top = 0xFFu << (y & 7);
61 mask_bottom = ~(0xFEu << ((ny - 1) & 7));
62 if (ny <= 8)
63 mask_bottom &= mask_top;
64
65 blockfunc = _gray_blockfuncs[_graybuf->drawmode];
66 bits = (_graybuf->drawmode == GRAY_DRAW_BG) ? 0u : 0xFFu;
67
68 if (ny > 8)
69 {
70 dst_row = dst;
71 for (x = 0; x < nx; x++)
72 blockfunc(dst_row++, mask_top, bits);
73
74 dst += _graybuf->width;
75
76 for (y = 8; y < ny - 8; y += 8)
77 {
78 dst_row = dst;
79 for (x = 0; x < nx; x++)
80 blockfunc(dst_row++, 0xFFu, bits);
81
82 dst += _graybuf->width;
83 }
84 }
85
86 for (x = 0; x < nx; x++)
87 blockfunc(dst++, mask_bottom, bits);
88}
89
90#endif // #ifdef HAVE_LCD_BITMAP
91#endif // #ifndef SIMULATOR
92
diff --git a/apps/plugins/lib/gray_getstringsize.c b/apps/plugins/lib/gray_getstringsize.c
new file mode 100644
index 0000000000..977b912247
--- /dev/null
+++ b/apps/plugins/lib/gray_getstringsize.c
@@ -0,0 +1,64 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_getstringsize() function
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 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/*---------------------------------------------------------------------------
33 Calculate width and height of the given text in pixels when rendered with
34 the currently selected font.
35 ----------------------------------------------------------------------------
36 This works exactly the same way as the core lcd_getstringsize(), only that
37 it uses the selected font for grayscale.
38 */
39int gray_getstringsize(unsigned char *str, int *w, int *h)
40{
41 int ch;
42 int width = 0;
43 struct font *pf = _graybuf->curfont;
44
45 while ((ch = *str++))
46 {
47 /* check input range */
48 if (ch < pf->firstchar || ch >= pf->firstchar + pf->size)
49 ch = pf->defaultchar;
50 ch -= pf->firstchar;
51
52 /* get proportional width */
53 width += pf->width ? pf->width[ch] : pf->maxwidth;
54 }
55 if (w)
56 *w = width;
57 if (h)
58 *h = pf->height;
59 return width;
60}
61
62#endif // #ifdef HAVE_LCD_BITMAP
63#endif // #ifndef SIMULATOR
64
diff --git a/apps/plugins/lib/gray_horline.c b/apps/plugins/lib/gray_horline.c
new file mode 100644
index 0000000000..c5ad0046de
--- /dev/null
+++ b/apps/plugins/lib/gray_horline.c
@@ -0,0 +1,65 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_horline() function
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 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/*---------------------------------------------------------------------------
33 Draw a horizontal line from (x1, y) to (x2, y) with the current drawinfo
34 ----------------------------------------------------------------------------
35 See gray_drawpixel() for details
36 */
37void gray_horline(int x1, int x2, int y)
38{
39 int x;
40 unsigned long pattern;
41 void (*pixelfunc)(int x, int y, unsigned long pattern);
42
43 if ((unsigned) x1 >= (unsigned) _graybuf->width
44 || (unsigned) x2 >= (unsigned) _graybuf->width
45 || (unsigned) y >= (unsigned) _graybuf->height)
46 return;
47
48 if (x1 > x2)
49 {
50 x = x1;
51 x1 = x2;
52 x2 = x;
53 }
54 pixelfunc = _gray_pixelfuncs[_graybuf->drawmode];
55 pattern = (_graybuf->drawmode == GRAY_DRAW_BG) ?
56 _graybuf->bg_pattern : _graybuf->fg_pattern;
57
58 for (x = x1; x <= x2; x++)
59 pixelfunc(x, y, pattern);
60
61}
62
63#endif // #ifdef HAVE_LCD_BITMAP
64#endif // #ifndef SIMULATOR
65
diff --git a/apps/plugins/lib/gray_pixelfuncs.c b/apps/plugins/lib/gray_pixelfuncs.c
new file mode 100644
index 0000000000..cade096405
--- /dev/null
+++ b/apps/plugins/lib/gray_pixelfuncs.c
@@ -0,0 +1,245 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* Low level pixel drawing functions
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 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/* Prototypes */
33static void _writepixel(int x, int y, unsigned long pattern);
34static void _invertpixel(int x, int y, unsigned long pattern);
35
36/* function pointer array */
37void (*_gray_pixelfuncs[4])(int x, int y, unsigned long pattern) = {
38 _invertpixel, _writepixel, _writepixel, _writepixel
39};
40
41/* Set a pixel to a specific bit pattern (low level routine) */
42static void _writepixel(int x, int y, unsigned long pattern)
43{
44 register unsigned mask, random;
45 register unsigned char *address;
46
47 /* Some (pseudo-)random function must be used here to shift the bit
48 * pattern randomly, otherwise you would get flicker and/or moire.
49 * Since rand() is relatively slow, I've implemented a simple, but very
50 * fast pseudo-random generator based on linear congruency in assembler.
51 * It delivers max. 16 pseudo-random bits in each iteration. */
52
53 /* simple but fast pseudo-random generator */
54 asm (
55 "mov #75,r1 \n"
56 "mulu %1,r1 \n" /* multiply by 75 */
57 "sts macl,%1 \n" /* get result */
58 "add #74,%1 \n" /* add another 74 */
59 /* Since the lower bits are not very random: */
60 "swap.b %1,%0 \n" /* get bits 8..15 (need max. 5) */
61 "and %2,%0 \n" /* mask out unneeded bits */
62 : /* outputs */
63 /* %0 */ "=&r"(random),
64 /* %1, in & out */ "+r"(_gray_random_buffer)
65 : /* inputs */
66 /* %2 */ "r"(_graybuf->randmask)
67 : /* clobbers */
68 "r1", "macl"
69 );
70
71 /* precalculate mask and byte address in first bitplane */
72 asm (
73 "mov %3,%0 \n" /* take y as base for address offset */
74 "shlr2 %0 \n" /* shift right by 3 (= divide by 8) */
75 "shlr %0 \n"
76 "mulu %0,%2 \n" /* multiply with width */
77 "and #7,%3 \n" /* get lower 3 bits of y */
78 "sts macl,%0 \n" /* get mulu result */
79 "add %4,%0 \n" /* add base + x to get final address */
80
81 "mov %3,%1 \n" /* move lower 3 bits of y out of r0 */
82 "mova .wp_masktable,%3\n" /* get address of mask table in r0 */
83 "bra .wp_predone \n" /* skip the table */
84 "mov.b @(%3,%1),%1 \n" /* get entry from mask table */
85
86 ".align 2 \n"
87 ".wp_masktable: \n" /* mask table */
88 ".byte 0x01 \n"
89 ".byte 0x02 \n"
90 ".byte 0x04 \n"
91 ".byte 0x08 \n"
92 ".byte 0x10 \n"
93 ".byte 0x20 \n"
94 ".byte 0x40 \n"
95 ".byte 0x80 \n"
96
97 ".wp_predone: \n"
98 : /* outputs */
99 /* %0 */ "=&r"(address),
100 /* %1 */ "=&r"(mask)
101 : /* inputs */
102 /* %2 */ "r"(_graybuf->width),
103 /* %3 = r0 */ "z"(y),
104 /* %4 */ "r"(_graybuf->data + x)
105 : /* clobbers */
106 "macl"
107 );
108
109 /* the hard part: set bits in all bitplanes according to pattern */
110 asm volatile (
111 "cmp/hs %1,%5 \n" /* random >= depth ? */
112 "bf .wp_ntrim \n"
113 "sub %1,%5 \n" /* yes: random -= depth */
114 /* it's sufficient to do this once, since the mask guarantees
115 * random < 2 * depth */
116 ".wp_ntrim: \n"
117
118 /* calculate some addresses */
119 "mulu %4,%1 \n" /* end address offset */
120 "not %3,r1 \n" /* get inverse mask (for "and") */
121 "sts macl,%1 \n" /* result of mulu */
122 "mulu %4,%5 \n" /* address offset of <random>'th plane */
123 "add %2,%1 \n" /* end offset -> end address */
124 "sts macl,%5 \n" /* result of mulu */
125 "add %2,%5 \n" /* address of <random>'th plane */
126 "bra .wp_start1 \n"
127 "mov %5,r2 \n" /* copy address */
128
129 /* first loop: set bits from <random>'th bitplane to last */
130 ".wp_loop1: \n"
131 "mov.b @r2,r3 \n" /* get data byte */
132 "shlr %0 \n" /* shift bit mask, sets t bit */
133 "and r1,r3 \n" /* reset bit (-> "white") */
134 "bf .wp_white1 \n" /* t=0? -> "white" bit */
135 "or %3,r3 \n" /* set bit ("black" bit) */
136 ".wp_white1: \n"
137 "mov.b r3,@r2 \n" /* store data byte */
138 "add %4,r2 \n" /* advance address to next bitplane */
139 ".wp_start1: \n"
140 "cmp/hi r2,%1 \n" /* address < end address ? */
141 "bt .wp_loop1 \n"
142
143 "bra .wp_start2 \n"
144 "nop \n"
145
146 /* second loop: set bits from first to <random-1>'th bitplane
147 * Bit setting works the other way round here to equalize average
148 * execution times for bright and dark pixels */
149 ".wp_loop2: \n"
150 "mov.b @%2,r3 \n" /* get data byte */
151 "shlr %0 \n" /* shift bit mask, sets t bit */
152 "or %3,r3 \n" /* set bit (-> "black") */
153 "bt .wp_black2 \n" /* t=1? -> "black" bit */
154 "and r1,r3 \n" /* reset bit ("white" bit) */
155 ".wp_black2: \n"
156 "mov.b r3,@%2 \n" /* store data byte */
157 "add %4,%2 \n" /* advance address to next bitplane */
158 ".wp_start2: \n"
159 "cmp/hi %2,%5 \n" /* address < <random>'th address ? */
160 "bt .wp_loop2 \n"
161 : /* outputs */
162 : /* inputs */
163 /* %0 */ "r"(pattern),
164 /* %1 */ "r"(_graybuf->depth),
165 /* %2 */ "r"(address),
166 /* %3 */ "r"(mask),
167 /* %4 */ "r"(_graybuf->plane_size),
168 /* %5 */ "r"(random)
169 : /* clobbers */
170 "r1", "r2", "r3", "macl"
171 );
172}
173
174/* invert all bits for one pixel (low level routine) */
175static void _invertpixel(int x, int y, unsigned long pattern)
176{
177 register unsigned mask;
178 register unsigned char *address;
179
180 (void) pattern; /* not used for invert */
181
182 /* precalculate mask and byte address in first bitplane */
183 asm (
184 "mov %3,%0 \n" /* take y as base for address offset */
185 "shlr2 %0 \n" /* shift right by 3 (= divide by 8) */
186 "shlr %0 \n"
187 "mulu %0,%2 \n" /* multiply with width */
188 "and #7,%3 \n" /* get lower 3 bits of y */
189 "sts macl,%0 \n" /* get mulu result */
190 "add %4,%0 \n" /* add base + x to get final address */
191
192 "mov %3,%1 \n" /* move lower 3 bits of y out of r0 */
193 "mova .ip_masktable,%3\n" /* get address of mask table in r0 */
194 "bra .ip_predone \n" /* skip the table */
195 "mov.b @(%3,%1),%1 \n" /* get entry from mask table */
196
197 ".align 2 \n"
198 ".ip_masktable: \n" /* mask table */
199 ".byte 0x01 \n"
200 ".byte 0x02 \n"
201 ".byte 0x04 \n"
202 ".byte 0x08 \n"
203 ".byte 0x10 \n"
204 ".byte 0x20 \n"
205 ".byte 0x40 \n"
206 ".byte 0x80 \n"
207
208 ".ip_predone: \n"
209 : /* outputs */
210 /* %0 */ "=&r"(address),
211 /* %1 */ "=&r"(mask)
212 : /* inputs */
213 /* %2 */ "r"(_graybuf->width),
214 /* %3 = r0 */ "z"(y),
215 /* %4 */ "r"(_graybuf->data + x)
216 : /* clobbers */
217 "macl"
218 );
219
220 /* invert bits in all bitplanes */
221 asm volatile (
222 "mov #0,r1 \n" /* current_plane = 0 */
223
224 ".ip_loop: \n"
225 "mov.b @%1,r2 \n" /* get data byte */
226 "add #1,r1 \n" /* current_plane++; */
227 "xor %2,r2 \n" /* invert bits */
228 "mov.b r2,@%1 \n" /* store data byte */
229 "add %3,%1 \n" /* advance address to next bitplane */
230 "cmp/hi r1,%0 \n" /* current_plane < depth ? */
231 "bt .ip_loop \n"
232 : /* outputs */
233 : /* inputs */
234 /* %0 */ "r"(_graybuf->depth),
235 /* %1 */ "r"(address),
236 /* %2 */ "r"(mask),
237 /* %3 */ "r"(_graybuf->plane_size)
238 : /* clobbers */
239 "r1", "r2"
240 );
241}
242
243#endif // #ifdef HAVE_LCD_BITMAP
244#endif // #ifndef SIMULATOR
245
diff --git a/apps/plugins/lib/gray_position_display.c b/apps/plugins/lib/gray_position_display.c
new file mode 100644
index 0000000000..4ec13ee730
--- /dev/null
+++ b/apps/plugins/lib/gray_position_display.c
@@ -0,0 +1,57 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_position_display() function
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 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/*---------------------------------------------------------------------------
33 Set position of the top left corner of the grayscale overlay
34 ----------------------------------------------------------------------------
35 x = left margin in pixels
36 by = top margin in 8-pixel units
37
38 You may set this in a way that the overlay spills across the right or
39 bottom display border. In this case it will simply be clipped by the
40 LCD controller. You can even set negative values, this will clip at the
41 left or top border. I did not test it, but the limits may be +127 / -128
42
43 If you use this while the grayscale overlay is running, the now-freed area
44 will be restored.
45 */
46void gray_position_display(int x, int by)
47{
48 _graybuf->x = x;
49 _graybuf->by = by;
50
51 if (_graybuf->flags & _GRAY_RUNNING)
52 _graybuf->flags |= _GRAY_DEFERRED_UPDATE;
53}
54
55#endif // #ifdef HAVE_LCD_BITMAP
56#endif // #ifndef SIMULATOR
57
diff --git a/apps/plugins/lib/gray_putsxy.c b/apps/plugins/lib/gray_putsxy.c
new file mode 100644
index 0000000000..18cf2bac78
--- /dev/null
+++ b/apps/plugins/lib/gray_putsxy.c
@@ -0,0 +1,67 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_putsxy() function
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 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/*---------------------------------------------------------------------------
33 Display text starting at (x, y) with the current font and drawinfo
34 ----------------------------------------------------------------------------
35 The drawmode is used as described for gray_set_drawmode()
36 */
37void gray_putsxy(int x, int y, unsigned char *str)
38{
39 int ch, width;
40 bitmap_t *bits;
41 struct font *pf = _graybuf->curfont;
42
43 if ((unsigned) x >= (unsigned) _graybuf->width
44 || (unsigned) y >= (unsigned) _graybuf->height)
45 return;
46
47 while ((ch = *str++) != '\0' && x < _graybuf->width)
48 {
49 /* check input range */
50 if (ch < pf->firstchar || ch >= pf->firstchar + pf->size)
51 ch = pf->defaultchar;
52 ch -= pf->firstchar;
53
54 /* get proportional width and glyph bits */
55 width = pf->width ? pf->width[ch] : pf->maxwidth;
56 bits = pf->bits + (pf->offset ? pf->offset[ch]
57 : MULU16(pf->height, ch));
58
59 gray_drawbitmap((unsigned char*) bits, x, y, width, pf->height,
60 width);
61 x += width;
62 }
63}
64
65#endif // #ifdef HAVE_LCD_BITMAP
66#endif // #ifndef SIMULATOR
67
diff --git a/apps/plugins/lib/gray_scroll_down.c b/apps/plugins/lib/gray_scroll_down.c
new file mode 100644
index 0000000000..3766ce1f73
--- /dev/null
+++ b/apps/plugins/lib/gray_scroll_down.c
@@ -0,0 +1,134 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_scroll_down() function
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 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/*---------------------------------------------------------------------------
33 Scroll the whole grayscale buffer down by <count> pixels (<= 7)
34 ----------------------------------------------------------------------------
35 black_border determines if the pixels scrolled in at the top are black
36 or white
37
38 Scrolling up/down pixel-wise is significantly slower than scrolling
39 left/right or scrolling up/down byte-wise because it involves bit
40 shifting. That's why it is asm optimized.
41 */
42void gray_scroll_down(int count, bool black_border)
43{
44 unsigned filler;
45
46 if ((unsigned) count > 7)
47 return;
48
49 filler = black_border ? (0xFFu << count) : 0;
50
51 /* scroll column by column to minimize flicker */
52 asm volatile (
53 "mov #0,r6 \n" /* x = 0 */
54 "mova .sd_shifttbl,r0 \n" /* calculate jump destination for */
55 "mov.b @(r0,%6),%6 \n" /* shift amount from table */
56 "bra .sd_cloop \n" /* skip table */
57 "add r0,%6 \n"
58
59 ".align 2 \n"
60 ".sd_shifttbl: \n" /* shift jump offset table */
61 ".byte .sd_shift0 - .sd_shifttbl \n"
62 ".byte .sd_shift1 - .sd_shifttbl \n"
63 ".byte .sd_shift2 - .sd_shifttbl \n"
64 ".byte .sd_shift3 - .sd_shifttbl \n"
65 ".byte .sd_shift4 - .sd_shifttbl \n"
66 ".byte .sd_shift5 - .sd_shifttbl \n"
67 ".byte .sd_shift6 - .sd_shifttbl \n"
68 ".byte .sd_shift7 - .sd_shifttbl \n"
69
70 ".sd_cloop: \n" /* repeat for every column */
71 "mov %1,r2 \n" /* get start address */
72 "mov #0,r3 \n" /* current_plane = 0 */
73
74 ".sd_oloop: \n" /* repeat for every bitplane */
75 "mov r2,r4 \n" /* get start address */
76 "mov #0,r5 \n" /* current_row = 0 */
77 "mov %5,r1 \n" /* get filler bits */
78
79 ".sd_iloop: \n" /* repeat for all rows */
80 "shlr8 r1 \n" /* shift right to get residue */
81 "mov.b @r4,r0 \n" /* get data byte */
82 "jmp @%6 \n" /* jump into shift "path" */
83 "extu.b r0,r0 \n" /* extend unsigned */
84
85 ".sd_shift6: \n" /* shift left by 0..7 bits */
86 "shll2 r0 \n"
87 ".sd_shift4: \n"
88 "shll2 r0 \n"
89 ".sd_shift2: \n"
90 "bra .sd_shift0 \n"
91 "shll2 r0 \n"
92 ".sd_shift7: \n"
93 "shll2 r0 \n"
94 ".sd_shift5: \n"
95 "shll2 r0 \n"
96 ".sd_shift3: \n"
97 "shll2 r0 \n"
98 ".sd_shift1: \n"
99 "shll r0 \n"
100 ".sd_shift0: \n"
101
102 "or r0,r1 \n" /* combine with last residue */
103 "mov.b r1,@r4 \n" /* store data */
104 "add %2,r4 \n" /* address += width */
105 "add #1,r5 \n" /* current_row++ */
106 "cmp/hi r5,%3 \n" /* current_row < bheight ? */
107 "bt .sd_iloop \n"
108
109 "add %4,r2 \n" /* start_address += plane_size */
110 "add #1,r3 \n" /* current_plane++ */
111 "cmp/hi r3,%0 \n" /* current_plane < depth ? */
112 "bt .sd_oloop \n"
113
114 "add #1,%1 \n" /* start_address++ */
115 "add #1,r6 \n" /* x++ */
116 "cmp/hi r6,%2 \n" /* x < width ? */
117 "bt .sd_cloop \n"
118 : /* outputs */
119 : /* inputs */
120 /* %0 */ "r"(_graybuf->depth),
121 /* %1 */ "r"(_graybuf->data),
122 /* %2 */ "r"(_graybuf->width),
123 /* %3 */ "r"(_graybuf->bheight),
124 /* %4 */ "r"(_graybuf->plane_size),
125 /* %5 */ "r"(filler),
126 /* %6 */ "r"(count)
127 : /* clobbers */
128 "r0", "r1", "r2", "r3", "r4", "r5", "r6"
129 );
130}
131
132#endif // #ifdef HAVE_LCD_BITMAP
133#endif // #ifndef SIMULATOR
134
diff --git a/apps/plugins/lib/gray_scroll_down8.c b/apps/plugins/lib/gray_scroll_down8.c
new file mode 100644
index 0000000000..db716baee7
--- /dev/null
+++ b/apps/plugins/lib/gray_scroll_down8.c
@@ -0,0 +1,69 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_scroll_down8() function
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 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/*---------------------------------------------------------------------------
33 Scroll the whole grayscale buffer down by 8 pixels
34 ----------------------------------------------------------------------------
35 black_border determines if the pixels scrolled in at the top are black
36 or white
37
38 Scrolling up/down by 8 pixels is very fast.
39 */
40void gray_scroll_down8(bool black_border)
41{
42 int by, d;
43 unsigned filler;
44 unsigned char *ptr;
45
46 filler = black_border ? 0xFF : 0;
47
48 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
49 for (by = _graybuf->bheight - 1; by > 0; by--)
50 {
51 ptr = _graybuf->data + MULU16(_graybuf->width, by);
52 for (d = 0; d < _graybuf->depth; d++)
53 {
54 _gray_rb->memcpy(ptr, ptr - _graybuf->width, _graybuf->width);
55 ptr += _graybuf->plane_size;
56 }
57 }
58 /* fill first row */
59 ptr = _graybuf->data;
60 for (d = 0; d < _graybuf->depth; d++)
61 {
62 _gray_rb->memset(ptr, filler, _graybuf->width);
63 ptr += _graybuf->plane_size;
64 }
65}
66
67#endif // #ifdef HAVE_LCD_BITMAP
68#endif // #ifndef SIMULATOR
69
diff --git a/apps/plugins/lib/gray_scroll_left.c b/apps/plugins/lib/gray_scroll_left.c
new file mode 100644
index 0000000000..22bcc03629
--- /dev/null
+++ b/apps/plugins/lib/gray_scroll_left.c
@@ -0,0 +1,100 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_scroll_left() function
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 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/*---------------------------------------------------------------------------
33 Scroll the whole grayscale buffer left by <count> pixels
34 ----------------------------------------------------------------------------
35 black_border determines if the pixels scrolled in at the right are black
36 or white
37
38 Scrolling left/right by an even pixel count is almost twice as fast as
39 scrolling by an odd pixel count.
40 */
41void gray_scroll_left(int count, bool black_border)
42{
43 int by, d;
44 unsigned filler;
45 unsigned char *ptr;
46
47 if ((unsigned) count >= (unsigned) _graybuf->width)
48 return;
49
50 filler = black_border ? 0xFF : 0;
51
52 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
53 for (by = 0; by < _graybuf->bheight; by++)
54 {
55 ptr = _graybuf->data + MULU16(_graybuf->width, by);
56 for (d = 0; d < _graybuf->depth; d++)
57 {
58 asm volatile (
59 "mov %0,r1 \n" /* check if both source... */
60 "or %2,r1 \n" /* ...and offset are even */
61 "shlr r1 \n" /* -> lsb = 0 */
62 "bf .sl_start2 \n" /* -> copy word-wise */
63
64 "add #-1,%2 \n" /* copy byte-wise */
65 ".sl_loop1: \n"
66 "mov.b @%0+,r1 \n"
67 "mov.b r1,@(%2,%0) \n"
68 "cmp/hi %0,%1 \n"
69 "bt .sl_loop1 \n"
70
71 "bra .sl_end \n"
72 "nop \n"
73
74 ".sl_start2: \n" /* copy word-wise */
75 "add #-2,%2 \n"
76 ".sl_loop2: \n"
77 "mov.w @%0+,r1 \n"
78 "mov.w r1,@(%2,%0) \n"
79 "cmp/hi %0,%1 \n"
80 "bt .sl_loop2 \n"
81
82 ".sl_end: \n"
83 : /* outputs */
84 : /* inputs */
85 /* %0 */ "r"(ptr + count),
86 /* %1 */ "r"(ptr + _graybuf->width),
87 /* %2 */ "z"(-count)
88 : /* clobbers */
89 "r1"
90 );
91
92 _gray_rb->memset(ptr + _graybuf->width - count, filler, count);
93 ptr += _graybuf->plane_size;
94 }
95 }
96}
97
98#endif // #ifdef HAVE_LCD_BITMAP
99#endif // #ifndef SIMULATOR
100
diff --git a/apps/plugins/lib/gray_scroll_right.c b/apps/plugins/lib/gray_scroll_right.c
new file mode 100644
index 0000000000..2b0b85aab7
--- /dev/null
+++ b/apps/plugins/lib/gray_scroll_right.c
@@ -0,0 +1,100 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_scroll_right() function
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 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/*---------------------------------------------------------------------------
33 Scroll the whole grayscale buffer right by <count> pixels
34 ----------------------------------------------------------------------------
35 black_border determines if the pixels scrolled in at the left are black
36 or white
37
38 Scrolling left/right by an even pixel count is almost twice as fast as
39 scrolling by an odd pixel count.
40 */
41void gray_scroll_right(int count, bool black_border)
42{
43 int by, d;
44 unsigned filler;
45 unsigned char *ptr;
46
47 if ((unsigned) count >= (unsigned) _graybuf->width)
48 return;
49
50 filler = black_border ? 0xFF : 0;
51
52 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
53 for (by = 0; by < _graybuf->bheight; by++)
54 {
55 ptr = _graybuf->data + MULU16(_graybuf->width, by);
56 for (d = 0; d < _graybuf->depth; d++)
57 {
58 asm volatile (
59 "mov %0,r1 \n" /* check if both source... */
60 "or %2,r1 \n" /* ...and offset are even */
61 "shlr r1 \n" /* -> lsb = 0 */
62 "bf .sr_start2 \n" /* -> copy word-wise */
63
64 "add #-1,%2 \n" /* copy byte-wise */
65 ".sr_loop1: \n"
66 "mov.b @(%2,%0),r1 \n"
67 "mov.b r1,@-%0 \n"
68 "cmp/hi %1,%0 \n"
69 "bt .sr_loop1 \n"
70
71 "bra .sr_end \n"
72 "nop \n"
73
74 ".sr_start2: \n" /* copy word-wise */
75 "add #-2,%2 \n"
76 ".sr_loop2: \n"
77 "mov.w @(%2,%0),r1 \n"
78 "mov.w r1,@-%0 \n"
79 "cmp/hi %1,%0 \n"
80 "bt .sr_loop2 \n"
81
82 ".sr_end: \n"
83 : /* outputs */
84 : /* inputs */
85 /* %0 */ "r"(ptr + _graybuf->width),
86 /* %1 */ "r"(ptr + count),
87 /* %2 */ "z"(-count)
88 : /* clobbers */
89 "r1"
90 );
91
92 _gray_rb->memset(ptr, filler, count);
93 ptr += _graybuf->plane_size;
94 }
95 }
96}
97
98#endif // #ifdef HAVE_LCD_BITMAP
99#endif // #ifndef SIMULATOR
100
diff --git a/apps/plugins/lib/gray_scroll_up.c b/apps/plugins/lib/gray_scroll_up.c
new file mode 100644
index 0000000000..4a4657bfae
--- /dev/null
+++ b/apps/plugins/lib/gray_scroll_up.c
@@ -0,0 +1,135 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_scroll_up() function
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 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/*---------------------------------------------------------------------------
33 Scroll the whole grayscale buffer up by <count> pixels (<= 7)
34 ----------------------------------------------------------------------------
35 black_border determines if the pixels scrolled in at the bottom are black
36 or white
37
38 Scrolling up/down pixel-wise is significantly slower than scrolling
39 left/right or scrolling up/down byte-wise because it involves bit
40 shifting. That's why it is asm optimized.
41 */
42void gray_scroll_up(int count, bool black_border)
43{
44 unsigned filler;
45
46 if ((unsigned) count > 7)
47 return;
48
49 filler = black_border ? 0xFFu : 0;
50
51 /* scroll column by column to minimize flicker */
52 asm volatile (
53 "mov #0,r6 \n" /* x = 0 */
54 "mova .su_shifttbl,r0 \n" /* calculate jump destination for */
55 "mov.b @(r0,%6),%6 \n" /* shift amount from table */
56 "bra .su_cloop \n" /* skip table */
57 "add r0,%6 \n"
58
59 ".align 2 \n"
60 ".su_shifttbl: \n" /* shift jump offset table */
61 ".byte .su_shift0 - .su_shifttbl \n"
62 ".byte .su_shift1 - .su_shifttbl \n"
63 ".byte .su_shift2 - .su_shifttbl \n"
64 ".byte .su_shift3 - .su_shifttbl \n"
65 ".byte .su_shift4 - .su_shifttbl \n"
66 ".byte .su_shift5 - .su_shifttbl \n"
67 ".byte .su_shift6 - .su_shifttbl \n"
68 ".byte .su_shift7 - .su_shifttbl \n"
69
70 ".su_cloop: \n" /* repeat for every column */
71 "mov %1,r2 \n" /* get start address */
72 "mov #0,r3 \n" /* current_plane = 0 */
73
74 ".su_oloop: \n" /* repeat for every bitplane */
75 "mov r2,r4 \n" /* get start address */
76 "mov #0,r5 \n" /* current_row = 0 */
77 "mov %5,r1 \n" /* get filler bits */
78
79 ".su_iloop: \n" /* repeat for all rows */
80 "sub %2,r4 \n" /* address -= width */
81 "mov.b @r4,r0 \n" /* get data byte */
82 "shll8 r1 \n" /* old data to 2nd byte */
83 "extu.b r0,r0 \n" /* extend unsigned */
84 "or r1,r0 \n" /* combine old data */
85 "jmp @%6 \n" /* jump into shift "path" */
86 "extu.b r0,r1 \n" /* store data for next round */
87
88 ".su_shift6: \n" /* shift right by 0..7 bits */
89 "shlr2 r0 \n"
90 ".su_shift4: \n"
91 "shlr2 r0 \n"
92 ".su_shift2: \n"
93 "bra .su_shift0 \n"
94 "shlr2 r0 \n"
95 ".su_shift7: \n"
96 "shlr2 r0 \n"
97 ".su_shift5: \n"
98 "shlr2 r0 \n"
99 ".su_shift3: \n"
100 "shlr2 r0 \n"
101 ".su_shift1: \n"
102 "shlr r0 \n"
103 ".su_shift0: \n"
104
105 "mov.b r0,@r4 \n" /* store data */
106 "add #1,r5 \n" /* current_row++ */
107 "cmp/hi r5,%3 \n" /* current_row < bheight ? */
108 "bt .su_iloop \n"
109
110 "add %4,r2 \n" /* start_address += plane_size */
111 "add #1,r3 \n" /* current_plane++ */
112 "cmp/hi r3,%0 \n" /* current_plane < depth ? */
113 "bt .su_oloop \n"
114
115 "add #1,%1 \n" /* start_address++ */
116 "add #1,r6 \n" /* x++ */
117 "cmp/hi r6,%2 \n" /* x < width ? */
118 "bt .su_cloop \n"
119 : /* outputs */
120 : /* inputs */
121 /* %0 */ "r"(_graybuf->depth),
122 /* %1 */ "r"(_graybuf->data + _graybuf->plane_size),
123 /* %2 */ "r"(_graybuf->width),
124 /* %3 */ "r"(_graybuf->bheight),
125 /* %4 */ "r"(_graybuf->plane_size),
126 /* %5 */ "r"(filler),
127 /* %6 */ "r"(count)
128 : /* clobbers */
129 "r0", "r1", "r2", "r3", "r4", "r5", "r6"
130 );
131}
132
133#endif // #ifdef HAVE_LCD_BITMAP
134#endif // #ifndef SIMULATOR
135
diff --git a/apps/plugins/lib/gray_scroll_up8.c b/apps/plugins/lib/gray_scroll_up8.c
new file mode 100644
index 0000000000..b181673f22
--- /dev/null
+++ b/apps/plugins/lib/gray_scroll_up8.c
@@ -0,0 +1,69 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_scroll_up8() function
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 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/*---------------------------------------------------------------------------
33 Scroll the whole grayscale buffer up by 8 pixels
34 ----------------------------------------------------------------------------
35 black_border determines if the pixels scrolled in at the bottom are black
36 or white
37
38 Scrolling up/down by 8 pixels is very fast.
39 */
40void gray_scroll_up8(bool black_border)
41{
42 int by, d;
43 unsigned filler;
44 unsigned char *ptr;
45
46 filler = black_border ? 0xFF : 0;
47
48 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
49 for (by = 1; by < _graybuf->bheight; by++)
50 {
51 ptr = _graybuf->data + MULU16(_graybuf->width, by);
52 for (d = 0; d < _graybuf->depth; d++)
53 {
54 _gray_rb->memcpy(ptr - _graybuf->width, ptr, _graybuf->width);
55 ptr += _graybuf->plane_size;
56 }
57 }
58 /* fill last row */
59 ptr = _graybuf->data + _graybuf->plane_size - _graybuf->width;
60 for (d = 0; d < _graybuf->depth; d++)
61 {
62 _gray_rb->memset(ptr, filler, _graybuf->width);
63 ptr += _graybuf->plane_size;
64 }
65}
66
67#endif // #ifdef HAVE_LCD_BITMAP
68#endif // #ifndef SIMULATOR
69
diff --git a/apps/plugins/lib/gray_set_background.c b/apps/plugins/lib/gray_set_background.c
new file mode 100644
index 0000000000..b2cbedfcc0
--- /dev/null
+++ b/apps/plugins/lib/gray_set_background.c
@@ -0,0 +1,46 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_set_background() function
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 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/*---------------------------------------------------------------------------
33 Set the background shade for subsequent drawing operations
34 ----------------------------------------------------------------------------
35 brightness = 0 (black) .. 255 (white)
36 */
37void gray_set_background(int brightness)
38{
39 if ((unsigned) brightness <= 255)
40 _graybuf->bg_pattern = _graybuf->bitpattern[MULU16(brightness,
41 _graybuf->depth + 1) >> 8];
42}
43
44#endif // #ifdef HAVE_LCD_BITMAP
45#endif // #ifndef SIMULATOR
46
diff --git a/apps/plugins/lib/gray_set_drawinfo.c b/apps/plugins/lib/gray_set_drawinfo.c
new file mode 100644
index 0000000000..123d3d8939
--- /dev/null
+++ b/apps/plugins/lib/gray_set_drawinfo.c
@@ -0,0 +1,47 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_set_drawinfo() function
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 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/*---------------------------------------------------------------------------
33 Set draw mode, foreground and background shades at once
34 ----------------------------------------------------------------------------
35 If you hand it -1 (or in fact any other out-of-bounds value) for a
36 parameter, that particular setting won't be changed
37 */
38void gray_set_drawinfo(int drawmode, int fg_brightness, int bg_brightness)
39{
40 gray_set_drawmode(drawmode);
41 gray_set_foreground(fg_brightness);
42 gray_set_background(bg_brightness);
43}
44
45#endif // #ifdef HAVE_LCD_BITMAP
46#endif // #ifndef SIMULATOR
47
diff --git a/apps/plugins/lib/gray_set_drawmode.c b/apps/plugins/lib/gray_set_drawmode.c
new file mode 100644
index 0000000000..b32f2a2211
--- /dev/null
+++ b/apps/plugins/lib/gray_set_drawmode.c
@@ -0,0 +1,50 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_set_drawmode() function
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 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/*---------------------------------------------------------------------------
33 Set the draw mode for subsequent drawing operations
34 ----------------------------------------------------------------------------
35 drawmode =
36 GRAY_DRAW_INVERSE: Foreground pixels are inverted, background pixels are
37 left untouched
38 GRAY_DRAW_FG: Only foreground pixels are drawn
39 GRAY_DRAW_BG: Only background pixels are drawn
40 GRAY_DRAW_SOLID: Foreground and background pixels are drawn
41 */
42void gray_set_drawmode(int drawmode)
43{
44 if ((unsigned) drawmode <= GRAY_DRAW_SOLID)
45 _graybuf->drawmode = drawmode;
46}
47
48#endif // #ifdef HAVE_LCD_BITMAP
49#endif // #ifndef SIMULATOR
50
diff --git a/apps/plugins/lib/gray_set_foreground.c b/apps/plugins/lib/gray_set_foreground.c
new file mode 100644
index 0000000000..994f9d6d25
--- /dev/null
+++ b/apps/plugins/lib/gray_set_foreground.c
@@ -0,0 +1,46 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_set_foreground() function
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 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/*---------------------------------------------------------------------------
33 Set the foreground shade for subsequent drawing operations
34 ----------------------------------------------------------------------------
35 brightness = 0 (black) .. 255 (white)
36 */
37void gray_set_foreground(int brightness)
38{
39 if ((unsigned) brightness <= 255)
40 _graybuf->fg_pattern = _graybuf->bitpattern[MULU16(brightness,
41 _graybuf->depth + 1) >> 8];
42}
43
44#endif // #ifdef HAVE_LCD_BITMAP
45#endif // #ifndef SIMULATOR
46
diff --git a/apps/plugins/lib/gray_setfont.c b/apps/plugins/lib/gray_setfont.c
new file mode 100644
index 0000000000..ed68362484
--- /dev/null
+++ b/apps/plugins/lib/gray_setfont.c
@@ -0,0 +1,45 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11*
12* This is a generic framework to use grayscale display within Rockbox
13* plugins. It obviously does not work for the player.
14*
15* Copyright (C) 2004 Jens Arnold
16* gray_setfont() function
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/*---------------------------------------------------------------------------
33 Set font for the font routines
34 ----------------------------------------------------------------------------
35 newfont can be FONT_SYSFIXED or FONT_UI the same way as with the Rockbox
36 core routines
37 */
38void gray_setfont(int newfont)
39{
40 _graybuf->curfont = _gray_rb->font_get(newfont);
41}
42
43#endif // #ifdef HAVE_LCD_BITMAP
44#endif // #ifndef SIMULATOR
45
diff --git a/apps/plugins/lib/gray_verline.c b/apps/plugins/lib/gray_verline.c
new file mode 100644
index 0000000000..15910b41cf
--- /dev/null
+++ b/apps/plugins/lib/gray_verline.c
@@ -0,0 +1,88 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Grayscale framework
11* gray_verline() function
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 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/*---------------------------------------------------------------------------
33 Draw a vertical line from (x, y1) to (x, y2) with the current drawinfo
34 ----------------------------------------------------------------------------
35 See gray_drawpixel() for details
36 This one uses the block drawing optimization, so it is rather fast.
37 */
38void gray_verline(int x, int y1, int y2)
39{
40 int shift, y, ny;
41 unsigned bits, mask_top, mask_bottom;
42 unsigned char *dst;
43 void (*blockfunc)(unsigned char *address, unsigned mask, unsigned bits);
44
45 if ((unsigned) x >= (unsigned) _graybuf->width
46 || (unsigned) y1 >= (unsigned) _graybuf->height
47 || (unsigned) y2 >= (unsigned) _graybuf->height)
48 return;
49
50 if (y1 > y2)
51 {
52 y = y1;
53 y1 = y2;
54 y2 = y;
55 }
56 y = y1;
57 ny = y2 - y1 + 1;
58
59 dst = _graybuf->data + x + MULU16(_graybuf->width, y >> 3);
60 shift = y & 7;
61 ny += shift;
62
63 mask_top = 0xFFu << (y & 7);
64 mask_bottom = ~(0xFEu << ((ny - 1) & 7));
65 if (ny <= 8)
66 mask_bottom &= mask_top;
67
68 blockfunc = _gray_blockfuncs[_graybuf->drawmode];
69 bits = (_graybuf->drawmode == GRAY_DRAW_BG) ? 0u : 0xFFu;
70
71 if (ny > 8)
72 {
73 blockfunc(dst, mask_top, bits);
74 dst += _graybuf->width;
75
76 for (y = 8; y < ny - 8; y += 8)
77 {
78 blockfunc(dst, 0xFFu, bits);
79 dst += _graybuf->width;
80 }
81 }
82
83 blockfunc(dst, mask_bottom, bits);
84}
85
86#endif // #ifdef HAVE_LCD_BITMAP
87#endif // #ifndef SIMULATOR
88