summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/plugins/lib/gray.c1263
-rw-r--r--apps/plugins/lib/gray.h300
2 files changed, 1027 insertions, 536 deletions
diff --git a/apps/plugins/lib/gray.c b/apps/plugins/lib/gray.c
index ed95a39dea..1b197c0eeb 100644
--- a/apps/plugins/lib/gray.c
+++ b/apps/plugins/lib/gray.c
@@ -9,6 +9,9 @@
9* 9*
10* Grayscale framework 10* Grayscale framework
11* 11*
12* This is a generic framework to use grayscale display within Rockbox
13* plugins. It obviously does not work for the player.
14*
12* Copyright (C) 2004 Jens Arnold 15* Copyright (C) 2004 Jens Arnold
13* 16*
14* All files in this archive are subject to the GNU General Public License. 17* All files in this archive are subject to the GNU General Public License.
@@ -25,10 +28,6 @@
25#ifdef HAVE_LCD_BITMAP /* and also not for the Player */ 28#ifdef HAVE_LCD_BITMAP /* and also not for the Player */
26#include "gray.h" 29#include "gray.h"
27 30
28/* This is a generic framework to use grayscale display within rockbox
29 * plugins. It obviously does not work for the player.
30 */
31
32/**** internal core functions and definitions ****/ 31/**** internal core functions and definitions ****/
33 32
34/* You do not want to touch these if you don't know exactly what you're 33/* You do not want to touch these if you don't know exactly what you're
@@ -41,29 +40,63 @@
41#define MULU16(a, b) ((unsigned long) \ 40#define MULU16(a, b) ((unsigned long) \
42 (((unsigned short) (a)) * ((unsigned short) (b)))) 41 (((unsigned short) (a)) * ((unsigned short) (b))))
43 42
43/* The grayscale buffer management structure */
44typedef struct 44typedef struct
45{ 45{
46 int x; 46 int x;
47 int by; /* 8-pixel units */ 47 int by; /* 8-pixel units */
48 int width; 48 int width;
49 int height; 49 int height;
50 int bheight; /* 8-pixel units */ 50 int bheight; /* 8-pixel units */
51 int plane_size; 51 int plane_size;
52 int depth; /* number_of_bitplanes = (number_of_grayscales - 1) */ 52 int depth; /* number_of_bitplanes = (number_of_grayscales - 1) */
53 int cur_plane; /* for the timer isr */ 53 int cur_plane; /* for the timer isr */
54 unsigned long randmask; /* mask for random value in graypixel() */ 54 unsigned long randmask; /* mask for random value in _writepixel() */
55 unsigned long flags; /* various flags, see #defines */ 55 unsigned long flags; /* various flags, see #defines */
56 unsigned long *bitpattern; /* pointer to start of pattern table */ 56 unsigned long *bitpattern; /* pointer to start of pattern table */
57 unsigned char *data; /* pointer to start of bitplane data */ 57 unsigned char *data; /* pointer to start of bitplane data */
58 int curfont; /* current selected font */ 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 */
59} tGraybuf; 62} tGraybuf;
60 63
61static struct plugin_api *rb = NULL; /* global api struct pointer */ 64/** globals **/
62static tGraybuf *graybuf = NULL; 65
63static short gray_random_buffer; 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 **/
64 97
65/* timer interrupt handler: display next bitplane */ 98/* timer interrupt handler: display next bitplane */
66static void gray_timer_isr(void) 99static void _timer_isr(void)
67{ 100{
68 rb->lcd_blit(graybuf->data + MULU16(graybuf->plane_size, graybuf->cur_plane), 101 rb->lcd_blit(graybuf->data + MULU16(graybuf->plane_size, graybuf->cur_plane),
69 graybuf->x, graybuf->by, graybuf->width, graybuf->bheight, 102 graybuf->x, graybuf->by, graybuf->width, graybuf->bheight,
@@ -95,11 +128,11 @@ static void gray_timer_isr(void)
95 } 128 }
96} 129}
97 130
98/* Set a pixel to a specific bit pattern 131/* Set a pixel to a specific bit pattern (low level routine) */
99 * This is the fundamental graphics primitive, asm optimized */ 132static void _writepixel(int x, int y, unsigned long pattern)
100static void graypixel(int x, int y, unsigned long pattern)
101{ 133{
102 register long address, mask, random; 134 register unsigned mask, random;
135 register unsigned char *address;
103 136
104 /* Some (pseudo-)random function must be used here to shift the bit 137 /* Some (pseudo-)random function must be used here to shift the bit
105 * pattern randomly, otherwise you would get flicker and/or moire. 138 * pattern randomly, otherwise you would get flicker and/or moire.
@@ -118,7 +151,7 @@ static void graypixel(int x, int y, unsigned long pattern)
118 "and %2,%0 \n" /* mask out unneeded bits */ 151 "and %2,%0 \n" /* mask out unneeded bits */
119 : /* outputs */ 152 : /* outputs */
120 /* %0 */ "=&r"(random), 153 /* %0 */ "=&r"(random),
121 /* %1, in & out */ "+r"(gray_random_buffer) 154 /* %1, in & out */ "+r"(random_buffer)
122 : /* inputs */ 155 : /* inputs */
123 /* %2 */ "r"(graybuf->randmask) 156 /* %2 */ "r"(graybuf->randmask)
124 : /* clobbers */ 157 : /* clobbers */
@@ -136,12 +169,12 @@ static void graypixel(int x, int y, unsigned long pattern)
136 "add %4,%0 \n" /* add base + x to get final address */ 169 "add %4,%0 \n" /* add base + x to get final address */
137 170
138 "mov %3,%1 \n" /* move lower 3 bits of y out of r0 */ 171 "mov %3,%1 \n" /* move lower 3 bits of y out of r0 */
139 "mova .pp_table,%3 \n" /* get address of mask table in r0 */ 172 "mova .wp_masktable,%3\n" /* get address of mask table in r0 */
140 "bra .pp_end \n" /* skip the table */ 173 "bra .wp_predone \n" /* skip the table */
141 "mov.b @(%3,%1),%1 \n" /* get entry from mask table */ 174 "mov.b @(%3,%1),%1 \n" /* get entry from mask table */
142 175
143 ".align 2 \n" 176 ".align 2 \n"
144 ".pp_table: \n" /* mask table */ 177 ".wp_masktable: \n" /* mask table */
145 ".byte 0x01 \n" 178 ".byte 0x01 \n"
146 ".byte 0x02 \n" 179 ".byte 0x02 \n"
147 ".byte 0x04 \n" 180 ".byte 0x04 \n"
@@ -151,9 +184,9 @@ static void graypixel(int x, int y, unsigned long pattern)
151 ".byte 0x40 \n" 184 ".byte 0x40 \n"
152 ".byte 0x80 \n" 185 ".byte 0x80 \n"
153 186
154 ".pp_end: \n" 187 ".wp_predone: \n"
155 : /* outputs */ 188 : /* outputs */
156 /* %0 */ "=&r"(address), 189 /* %0 */ "=&r"(address),
157 /* %1 */ "=&r"(mask) 190 /* %1 */ "=&r"(mask)
158 : /* inputs */ 191 : /* inputs */
159 /* %2 */ "r"(graybuf->width), 192 /* %2 */ "r"(graybuf->width),
@@ -166,12 +199,12 @@ static void graypixel(int x, int y, unsigned long pattern)
166 /* the hard part: set bits in all bitplanes according to pattern */ 199 /* the hard part: set bits in all bitplanes according to pattern */
167 asm volatile ( 200 asm volatile (
168 "cmp/hs %1,%5 \n" /* random >= depth ? */ 201 "cmp/hs %1,%5 \n" /* random >= depth ? */
169 "bf .p_ntrim \n" 202 "bf .wp_ntrim \n"
170 "sub %1,%5 \n" /* yes: random -= depth */ 203 "sub %1,%5 \n" /* yes: random -= depth */
171 /* it's sufficient to do this once, since the mask guarantees 204 /* it's sufficient to do this once, since the mask guarantees
172 * random < 2 * depth */ 205 * random < 2 * depth */
173 ".p_ntrim: \n" 206 ".wp_ntrim: \n"
174 207
175 /* calculate some addresses */ 208 /* calculate some addresses */
176 "mulu %4,%1 \n" /* end address offset */ 209 "mulu %4,%1 \n" /* end address offset */
177 "not %3,r1 \n" /* get inverse mask (for "and") */ 210 "not %3,r1 \n" /* get inverse mask (for "and") */
@@ -180,41 +213,41 @@ static void graypixel(int x, int y, unsigned long pattern)
180 "add %2,%1 \n" /* end offset -> end address */ 213 "add %2,%1 \n" /* end offset -> end address */
181 "sts macl,%5 \n" /* result of mulu */ 214 "sts macl,%5 \n" /* result of mulu */
182 "add %2,%5 \n" /* address of <random>'th plane */ 215 "add %2,%5 \n" /* address of <random>'th plane */
183 "bra .p_start1 \n" 216 "bra .wp_start1 \n"
184 "mov %5,r2 \n" /* copy address */ 217 "mov %5,r2 \n" /* copy address */
185 218
186 /* first loop: set bits from <random>'th bitplane to last */ 219 /* first loop: set bits from <random>'th bitplane to last */
187 ".p_loop1: \n" 220 ".wp_loop1: \n"
188 "mov.b @r2,r3 \n" /* get data byte */ 221 "mov.b @r2,r3 \n" /* get data byte */
189 "shlr %0 \n" /* shift bit mask, sets t bit */ 222 "shlr %0 \n" /* shift bit mask, sets t bit */
190 "and r1,r3 \n" /* reset bit (-> "white") */ 223 "and r1,r3 \n" /* reset bit (-> "white") */
191 "bf .p_white1 \n" /* t=0? -> "white" bit */ 224 "bf .wp_white1 \n" /* t=0? -> "white" bit */
192 "or %3,r3 \n" /* set bit ("black" bit) */ 225 "or %3,r3 \n" /* set bit ("black" bit) */
193 ".p_white1: \n" 226 ".wp_white1: \n"
194 "mov.b r3,@r2 \n" /* store data byte */ 227 "mov.b r3,@r2 \n" /* store data byte */
195 "add %4,r2 \n" /* advance address to next bitplane */ 228 "add %4,r2 \n" /* advance address to next bitplane */
196 ".p_start1: \n" 229 ".wp_start1: \n"
197 "cmp/hi r2,%1 \n" /* address < end address ? */ 230 "cmp/hi r2,%1 \n" /* address < end address ? */
198 "bt .p_loop1 \n" 231 "bt .wp_loop1 \n"
199 232
200 "bra .p_start2 \n" 233 "bra .wp_start2 \n"
201 "nop \n" 234 "nop \n"
202 235
203 /* second loop: set bits from first to <random-1>'th bitplane 236 /* second loop: set bits from first to <random-1>'th bitplane
204 * Bit setting works the other way round here to equalize average 237 * Bit setting works the other way round here to equalize average
205 * execution times for bright and dark pixels */ 238 * execution times for bright and dark pixels */
206 ".p_loop2: \n" 239 ".wp_loop2: \n"
207 "mov.b @%2,r3 \n" /* get data byte */ 240 "mov.b @%2,r3 \n" /* get data byte */
208 "shlr %0 \n" /* shift bit mask, sets t bit */ 241 "shlr %0 \n" /* shift bit mask, sets t bit */
209 "or %3,r3 \n" /* set bit (-> "black") */ 242 "or %3,r3 \n" /* set bit (-> "black") */
210 "bt .p_black2 \n" /* t=1? -> "black" bit */ 243 "bt .wp_black2 \n" /* t=1? -> "black" bit */
211 "and r1,r3 \n" /* reset bit ("white" bit) */ 244 "and r1,r3 \n" /* reset bit ("white" bit) */
212 ".p_black2: \n" 245 ".wp_black2: \n"
213 "mov.b r3,@%2 \n" /* store data byte */ 246 "mov.b r3,@%2 \n" /* store data byte */
214 "add %4,%2 \n" /* advance address to next bitplane */ 247 "add %4,%2 \n" /* advance address to next bitplane */
215 ".p_start2: \n" 248 ".wp_start2: \n"
216 "cmp/hi %2,%5 \n" /* address < <random>'th address ? */ 249 "cmp/hi %2,%5 \n" /* address < <random>'th address ? */
217 "bt .p_loop2 \n" 250 "bt .wp_loop2 \n"
218 : /* outputs */ 251 : /* outputs */
219 : /* inputs */ 252 : /* inputs */
220 /* %0 */ "r"(pattern), 253 /* %0 */ "r"(pattern),
@@ -228,31 +261,100 @@ static void graypixel(int x, int y, unsigned long pattern)
228 ); 261 );
229} 262}
230 263
231/* Set 8 pixels to specific gray values at once, asm optimized 264/* invert all bits for one pixel (low level routine) */
232 * This greatly enhances performance of gray_fillrect() and gray_drawgraymap() 265static void _invertpixel(int x, int y, unsigned long pattern)
233 * for larger rectangles and graymaps */ 266{
234static void grayblock(int x, int by, unsigned char* src, int stride) 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)
235{ 340{
236 register unsigned char *address, *end_addr;
237 unsigned long pat_stack[8]; 341 unsigned long pat_stack[8];
238 register unsigned long *pat_ptr = &pat_stack[8]; /* behind last element */ 342 register unsigned char *end_addr;
343 register unsigned long *pat_ptr = &pat_stack[8];
239 344
240 /* precalculate the bit patterns with random shifts (same RNG as graypixel, 345 /* precalculate the bit patterns with random shifts (same RNG as
241 * see there for an explanation) for all 8 pixels and put them on an 346 * _writepixel, see there for an explanation) for all 8 pixels and put them
242 * extra stack */ 347 * on an extra "stack" */
243 asm ( 348 asm (
244 "mova .gb_reload,r0 \n" /* set default loopback address */ 349 "mov #8,r3 \n" /* loop count in r3: 8 pixels */
245 "tst %3,%3 \n" /* stride == 0 ? */ 350 "mov %7,r2 \n" /* copy mask */
246 "bf .gb_needreload \n" /* no: keep that address */ 351
247 "mova .gb_reuse,r0 \n" /* yes: set shortcut (no reload) */ 352 ".wa_loop: \n" /** load pattern for pixel **/
248 ".gb_needreload: \n" 353 "mov #0,r0 \n" /* pattern for skipped pixel must be 0 */
249 "mov r0,r2 \n" /* loopback address to r2 */ 354 "shlr r2 \n" /* shift out lsb of mask */
250 "mov #7,r3 \n" /* loop count in r3: 8 pixels */ 355 "bf .wa_skip \n" /* skip this pixel */
251 356
252 ".align 2 \n" /** load pattern for pixel **/
253 ".gb_reload: \n"
254 "mov.b @%2,r0 \n" /* load src byte */ 357 "mov.b @%2,r0 \n" /* load src byte */
255 "nop \n" /* align here, saves a pipeline stall */
256 "extu.b r0,r0 \n" /* extend unsigned */ 358 "extu.b r0,r0 \n" /* extend unsigned */
257 "mulu %4,r0 \n" /* macl = byte * depth; */ 359 "mulu %4,r0 \n" /* macl = byte * depth; */
258 "add %3,%2 \n" /* src += stride; */ 360 "add %3,%2 \n" /* src += stride; */
@@ -262,20 +364,18 @@ static void grayblock(int x, int by, unsigned char* src, int stride)
262 "shll2 r0 \n" 364 "shll2 r0 \n"
263 "mov.l @(r0,%5),r4 \n" /* r4 = bitpattern[byte]; */ 365 "mov.l @(r0,%5),r4 \n" /* r4 = bitpattern[byte]; */
264 366
265 ".align 2 \n" /** RNG **/
266 ".gb_reuse: \n"
267 "mov #75,r0 \n" 367 "mov #75,r0 \n"
268 "mulu r0,%1 \n" /* multiply by 75 */ 368 "mulu r0,%0 \n" /* multiply by 75 */
269 "sts macl,%1 \n" 369 "sts macl,%0 \n"
270 "add #74,%1 \n" /* add another 74 */ 370 "add #74,%0 \n" /* add another 74 */
271 /* Since the lower bits are not very random: */ 371 /* Since the lower bits are not very random: */
272 "swap.b %1,r1 \n" /* get bits 8..15 (need max. 5) */ 372 "swap.b %0,r1 \n" /* get bits 8..15 (need max. 5) */
273 "and %6,r1 \n" /* mask out unneeded bits */ 373 "and %6,r1 \n" /* mask out unneeded bits */
274 374
275 "cmp/hs %4,r1 \n" /* random >= depth ? */ 375 "cmp/hs %4,r1 \n" /* random >= depth ? */
276 "bf .gb_ntrim \n" 376 "bf .wa_ntrim \n"
277 "sub %4,r1 \n" /* yes: random -= depth; */ 377 "sub %4,r1 \n" /* yes: random -= depth; */
278 ".gb_ntrim: \n" 378 ".wa_ntrim: \n"
279 379
280 "mov.l .ashlsi3,r0 \n" /** rotate pattern **/ 380 "mov.l .ashlsi3,r0 \n" /** rotate pattern **/
281 "jsr @r0 \n" /* r4 -> r0, shift left by r5 */ 381 "jsr @r0 \n" /* r4 -> r0, shift left by r5 */
@@ -288,37 +388,27 @@ static void grayblock(int x, int by, unsigned char* src, int stride)
288 "mov r0,r1 \n" /* store previous result in r1 */ 388 "mov r0,r1 \n" /* store previous result in r1 */
289 389
290 "or r1,r0 \n" /* rotated_pattern = r0 | r1 */ 390 "or r1,r0 \n" /* rotated_pattern = r0 | r1 */
291 "mov.l r0,@-%0 \n" /* push on pattern stack */
292 391
293 "cmp/pl r3 \n" /* loop count > 0? */ 392 ".wa_skip: \n"
294 "bf .gb_patdone \n" /* no: done */ 393 "mov.l r0,@-%1 \n" /* push on pattern stack */
295 394
296 "jmp @r2 \n" /* yes: loop */
297 "add #-1,r3 \n" /* decrease loop count */ 395 "add #-1,r3 \n" /* decrease loop count */
298 396 "cmp/pl r3 \n" /* loop count > 0? */
299 ".align 2 \n" 397 "bt .wa_loop \n" /* yes: loop */
300 ".ashlsi3: \n" /* C library routine: */
301 ".long ___ashlsi3 \n" /* shift r4 left by r5, return in r0 */
302 ".lshrsi3: \n" /* C library routine: */
303 ".long ___lshrsi3 \n" /* shift r4 right by r5, return in r0 */
304 /* both routines preserve r4, destroy r5 and take ~16 cycles */
305
306 ".gb_patdone: \n"
307 : /* outputs */ 398 : /* outputs */
308 /* %0, in & out */ "+r"(pat_ptr), 399 /* %0, in & out */ "+r"(random_buffer),
309 /* %1, in & out */ "+r"(gray_random_buffer) 400 /* %1, in & out */ "+r"(pat_ptr)
310 : /* inputs */ 401 : /* inputs */
311 /* %2 */ "r"(src), 402 /* %2 */ "r"(src),
312 /* %3 */ "r"(stride), 403 /* %3 */ "r"(stride),
313 /* %4 */ "r"(graybuf->depth), 404 /* %4 */ "r"(graybuf->depth),
314 /* %5 */ "r"(graybuf->bitpattern), 405 /* %5 */ "r"(graybuf->bitpattern),
315 /* %6 */ "r"(graybuf->randmask) 406 /* %6 */ "r"(graybuf->randmask),
407 /* %7 */ "r"(mask)
316 : /* clobbers */ 408 : /* clobbers */
317 "r0", "r1", "r2", "r3", "r4", "r5", "macl" 409 "r0", "r1", "r2", "r3", "r4", "r5", "macl"
318 ); 410 );
319 411
320 /* calculate start address in first bitplane and end address */
321 address = graybuf->data + x + MULU16(graybuf->width, by);
322 end_addr = address + MULU16(graybuf->depth, graybuf->plane_size); 412 end_addr = address + MULU16(graybuf->depth, graybuf->plane_size);
323 413
324 /* set the bits for all 8 pixels in all bytes according to the 414 /* set the bits for all 8 pixels in all bytes according to the
@@ -327,82 +417,301 @@ static void grayblock(int x, int by, unsigned char* src, int stride)
327 "mov.l @%3+,r1 \n" /* pop all 8 patterns */ 417 "mov.l @%3+,r1 \n" /* pop all 8 patterns */
328 "mov.l @%3+,r2 \n" 418 "mov.l @%3+,r2 \n"
329 "mov.l @%3+,r3 \n" 419 "mov.l @%3+,r3 \n"
330 "mov.l @%3+,r4 \n" 420 "mov.l @%3+,r8 \n"
331 "mov.l @%3+,r5 \n" 421 "mov.l @%3+,r9 \n"
332 "mov.l @%3+,r6 \n" 422 "mov.l @%3+,r10 \n"
333 "mov.l @%3+,r7 \n" 423 "mov.l @%3+,r11 \n"
334 "mov.l @%3+,%3 \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 */
335 455
336 ".gb_loop: \n" /* loop for all bitplanes */ 456 "bra .wa_end \n"
457 "nop \n"
458
459 ".wa_sloop: \n" /** short loop (nothing to keep) **/
337 "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */ 460 "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */
338 "rotcl r0 \n" /* rotate t bit into r0 */ 461 "rotcl r0 \n" /* rotate t bit into r0 */
339 "shlr r2 \n" 462 "shlr r2 \n"
340 "rotcl r0 \n" 463 "rotcl r0 \n"
341 "shlr r3 \n" 464 "shlr r3 \n"
342 "rotcl r0 \n" 465 "rotcl r0 \n"
343 "shlr r4 \n" 466 "shlr r8 \n"
344 "rotcl r0 \n" 467 "rotcl r0 \n"
345 "shlr r5 \n" 468 "shlr r9 \n"
346 "rotcl r0 \n" 469 "rotcl r0 \n"
347 "shlr r6 \n" 470 "shlr r10 \n"
348 "rotcl r0 \n" 471 "rotcl r0 \n"
349 "shlr r7 \n" 472 "shlr r11 \n"
350 "rotcl r0 \n" 473 "rotcl r0 \n"
351 "shlr %3 \n" 474 "shlr r12 \n"
352 "rotcl r0 \n" 475 "rotcl r0 \n"
353 "mov.b r0,@%0 \n" /* store byte to bitplane */ 476 "mov.b r0,@%0 \n" /* store byte to bitplane */
354 "add %2,%0 \n" /* advance to next bitplane */ 477 "add %2,%0 \n" /* advance to next bitplane */
355 "cmp/hi %0,%1 \n" /* last bitplane done? */ 478 "cmp/hi %0,%1 \n" /* last bitplane done? */
356 "bt .gb_loop \n" /* no: loop */ 479 "bt .wa_sloop \n" /* no: loop */
480
481 ".wa_end: \n"
357 : /* outputs */ 482 : /* outputs */
358 : /* inputs */ 483 : /* inputs */
359 /* %0 */ "r"(address), 484 /* %0 */ "r"(address),
360 /* %1 */ "r"(end_addr), 485 /* %1 */ "r"(end_addr),
361 /* %2 */ "r"(graybuf->plane_size), 486 /* %2 */ "r"(graybuf->plane_size),
362 /* %3 */ "r"(pat_ptr) 487 /* %3 */ "r"(pat_ptr),
488 /* %4 */ "r"(mask)
363 : /* clobbers */ 489 : /* clobbers */
364 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" 490 "r0", "r1", "r2", "r3", "r8", "r9", "r10", "r11", "r12"
365 ); 491 );
366} 492}
367 493
368/* Invert the bits for 1-8 pixels within the buffer */ 494/* Write an 8-pixel block, defined by foreground and background pattern.
369static void grayinvertmasked(int x, int by, unsigned char mask) 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)
370{ 667{
371 asm volatile ( 668 asm volatile (
372 "mulu %4,%5 \n" /* width * by (offset of row) */
373 "mov #0,r1 \n" /* current_plane = 0 */ 669 "mov #0,r1 \n" /* current_plane = 0 */
374 "sts macl,r2 \n" /* get mulu result */
375 "add r2,%1 \n" /* -> address in 1st bitplane */
376 670
377 ".i_loop: \n" 671 ".im_loop: \n"
378 "mov.b @%1,r2 \n" /* get data byte */ 672 "mov.b @%1,r2 \n" /* get data byte */
379 "add #1,r1 \n" /* current_plane++; */ 673 "add #1,r1 \n" /* current_plane++; */
380 "xor %2,r2 \n" /* invert bits */ 674 "xor %2,r2 \n" /* invert bits */
381 "mov.b r2,@%1 \n" /* store data byte */ 675 "mov.b r2,@%1 \n" /* store data byte */
382 "add %3,%1 \n" /* advance address to next bitplane */ 676 "add %3,%1 \n" /* advance address to next bitplane */
383 "cmp/hi r1,%0 \n" /* current_plane < depth ? */ 677 "cmp/hi r1,%0 \n" /* current_plane < depth ? */
384 "bt .i_loop \n" 678 "bt .im_loop \n"
385 : /* outputs */ 679 : /* outputs */
386 : /* inputs */ 680 : /* inputs */
387 /* %0 */ "r"(graybuf->depth), 681 /* %0 */ "r"(graybuf->depth),
388 /* %1 */ "r"(graybuf->data + x), 682 /* %1 */ "r"(address),
389 /* %2 */ "r"(mask), 683 /* %2 */ "r"(mask & bits),
390 /* %3 */ "r"(graybuf->plane_size), 684 /* %3 */ "r"(graybuf->plane_size)
391 /* %4 */ "r"(graybuf->width),
392 /* %5 */ "r"(by)
393 : /* clobbers */ 685 : /* clobbers */
394 "r1", "r2", "macl" 686 "r1", "r2", "macl"
395 ); 687 );
396} 688}
397 689
398/*** public core functions ***/ 690/* Call _writeblock with the mask modified to draw foreground pixels only */
691static void _writeblockfg(unsigned char *address, unsigned mask, unsigned bits)
692{
693 _writeblock(address, mask & bits, bits);
694}
399 695
400/* Initialize the framework */ 696/* Call _writeblock with the mask modified to draw background pixels only */
697static void _writeblockbg(unsigned char *address, unsigned mask, unsigned bits)
698{
699 _writeblock(address, mask & ~bits, bits);
700}
701
702/**** public functions ****/
703
704/* Initialize the framework
705 *
706 * Every framework needs such a function, and it has to be called as
707 * the very first one */
401void gray_init(struct plugin_api* newrb) 708void gray_init(struct plugin_api* newrb)
402{ 709{
403 rb = newrb; 710 rb = newrb;
404} 711}
405 712
713/** General functions **/
714
406/* Prepare the grayscale display buffer 715/* Prepare the grayscale display buffer
407 * 716 *
408 * arguments: 717 * arguments:
@@ -424,9 +733,11 @@ void gray_init(struct plugin_api* newrb)
424 * it creates as many bitplanes as fit into memory, although 1 bitplane will 733 * it creates as many bitplanes as fit into memory, although 1 bitplane will
425 * only deliver black & white display. 734 * only deliver black & white display.
426 * 735 *
427 * The total memory needed can be calculated as follows: 736 * If you need info about the memory taken by the grayscale buffer, supply an
737 * int* as the last parameter. This int will then contain the number of bytes
738 * used. The total memory needed can be calculated as follows:
428 * total_mem = 739 * total_mem =
429 * sizeof(tGraybuf) (= 48 bytes currently) 740 * sizeof(tGraybuf) (= 64 bytes currently)
430 * + sizeof(long) (= 4 bytes) 741 * + sizeof(long) (= 4 bytes)
431 * + (width * bheight + sizeof(long)) * depth 742 * + (width * bheight + sizeof(long)) * depth
432 * + 0..3 (longword alignment of grayscale display buffer) 743 * + 0..3 (longword alignment of grayscale display buffer)
@@ -437,8 +748,7 @@ int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
437 int possible_depth, plane_size; 748 int possible_depth, plane_size;
438 int i, j, align; 749 int i, j, align;
439 750
440 if (rb == NULL 751 if ((unsigned) width > LCD_WIDTH
441 || (unsigned) width > LCD_WIDTH
442 || (unsigned) bheight > (LCD_HEIGHT/8) 752 || (unsigned) bheight > (LCD_HEIGHT/8)
443 || depth < 1) 753 || depth < 1)
444 return 0; 754 return 0;
@@ -471,7 +781,6 @@ int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
471 graybuf->flags = 0; 781 graybuf->flags = 0;
472 graybuf->bitpattern = (unsigned long *) (gbuf + sizeof(tGraybuf)); 782 graybuf->bitpattern = (unsigned long *) (gbuf + sizeof(tGraybuf));
473 graybuf->data = (unsigned char *) (graybuf->bitpattern + depth + 1); 783 graybuf->data = (unsigned char *) (graybuf->bitpattern + depth + 1);
474 graybuf->curfont = FONT_SYSFIXED;
475 784
476 i = depth - 1; 785 i = depth - 1;
477 j = 8; 786 j = 8;
@@ -500,12 +809,17 @@ int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
500 value -= depth; /* "white" bit */ 809 value -= depth; /* "white" bit */
501 else 810 else
502 pattern |= 1; /* "black" bit */ 811 pattern |= 1; /* "black" bit */
503 } 812 }
504 /* now the lower <depth> bits contain the pattern */ 813 /* now the lower <depth> bits contain the pattern */
505 814
506 graybuf->bitpattern[i] = pattern; 815 graybuf->bitpattern[i] = pattern;
507 } 816 }
508 817
818 graybuf->fg_pattern = graybuf->bitpattern[0]; /* black */
819 graybuf->bg_pattern = graybuf->bitpattern[depth]; /* white */
820 graybuf->drawmode = GRAY_DRAW_SOLID;
821 graybuf->curfont = FONT_SYSFIXED;
822
509 if (buf_taken) /* caller requested info about space taken */ 823 if (buf_taken) /* caller requested info about space taken */
510 { 824 {
511 *buf_taken = sizeof(tGraybuf) + sizeof(long) 825 *buf_taken = sizeof(tGraybuf) + sizeof(long)
@@ -530,7 +844,6 @@ void gray_release_buffer(void)
530 844
531/* Set position of the top left corner of the grayscale overlay 845/* Set position of the top left corner of the grayscale overlay
532 * 846 *
533 * arguments:
534 * x = left margin in pixels 847 * x = left margin in pixels
535 * by = top margin in 8-pixel units 848 * by = top margin in 8-pixel units
536 * 849 *
@@ -544,9 +857,6 @@ void gray_release_buffer(void)
544 */ 857 */
545void gray_position_display(int x, int by) 858void gray_position_display(int x, int by)
546{ 859{
547 if (graybuf == NULL)
548 return;
549
550 graybuf->x = x; 860 graybuf->x = x;
551 graybuf->by = by; 861 graybuf->by = by;
552 862
@@ -556,7 +866,6 @@ void gray_position_display(int x, int by)
556 866
557/* Switch the grayscale overlay on or off 867/* Switch the grayscale overlay on or off
558 * 868 *
559 * arguments:
560 * enable = true: the grayscale overlay is switched on if initialized 869 * enable = true: the grayscale overlay is switched on if initialized
561 * = false: the grayscale overlay is switched off and the regular lcd 870 * = false: the grayscale overlay is switched off and the regular lcd
562 * content is restored 871 * content is restored
@@ -576,13 +885,10 @@ void gray_position_display(int x, int by)
576 */ 885 */
577void gray_show_display(bool enable) 886void gray_show_display(bool enable)
578{ 887{
579 if (graybuf == NULL)
580 return;
581
582 if (enable) 888 if (enable)
583 { 889 {
584 graybuf->flags |= GRAY_RUNNING; 890 graybuf->flags |= GRAY_RUNNING;
585 rb->plugin_register_timer(FREQ / 67, 1, gray_timer_isr); 891 rb->plugin_register_timer(FREQ / 67, 1, _timer_isr);
586 } 892 }
587 else 893 else
588 { 894 {
@@ -592,46 +898,86 @@ void gray_show_display(bool enable)
592 } 898 }
593} 899}
594 900
595/*** public optional functions ***/ 901/* Set the draw mode for subsequent drawing operations
902 *
903 * drawmode =
904 * GRAY_DRAW_INVERSE: Foreground pixels are inverted, background pixels are
905 * left untouched
906 * GRAY_DRAW_FG: Only foreground pixels are drawn
907 * GRAY_DRAW_BG: Only background pixels are drawn
908 * GRAY_DRAW_SOLID: Foreground and background pixels are drawn
909 */
910void gray_set_drawmode(int drawmode)
911{
912 if ((unsigned) drawmode <= GRAY_DRAW_SOLID)
913 graybuf->drawmode = drawmode;
914}
596 915
597/* Here are the various graphics primitives. Cut out functions you do not 916/* Set the foreground shade for subsequent drawing operations
598 * need in order to keep plugin code size down. 917 *
918 * brightness = 0 (black) .. 255 (white)
599 */ 919 */
920void gray_set_foreground(int brightness)
921{
922 if ((unsigned) brightness <= 255)
923 graybuf->fg_pattern = graybuf->bitpattern[MULU16(brightness,
924 graybuf->depth + 1) >> 8];
925}
600 926
601/* Clear the grayscale display (sets all pixels to white) 927/* Set the background shade for subsequent drawing operations
928 *
929 * brightness = 0 (black) .. 255 (white)
602 */ 930 */
603void gray_clear_display(void) 931void gray_set_background(int brightness)
604{ 932{
605 if (graybuf == NULL) 933 if ((unsigned) brightness <= 255)
606 return; 934 graybuf->bg_pattern = graybuf->bitpattern[MULU16(brightness,
935 graybuf->depth + 1) >> 8];
936}
937
938/* Set draw mode, foreground and background shades at once
939 *
940 * If you hand it -1 (or in fact any other out-of-bounds value) for a
941 * parameter, that particular setting won't be changed
942 */
943void gray_set_drawinfo(int drawmode, int fg_brightness, int bg_brightness)
944{
945 gray_set_drawmode(drawmode);
946 gray_set_foreground(fg_brightness);
947 gray_set_background(bg_brightness);
948}
607 949
950/** Functions affecting the whole dsplay **/
951
952/* Clear the grayscale display (sets all pixels to white) */
953void gray_clear_display(void)
954{
608 rb->memset(graybuf->data, 0, MULU16(graybuf->depth, graybuf->plane_size)); 955 rb->memset(graybuf->data, 0, MULU16(graybuf->depth, graybuf->plane_size));
609} 956}
610 957
611/* Set the grayscale display to all black 958/* Set the grayscale display to all black */
612 */
613void gray_black_display(void) 959void gray_black_display(void)
614{ 960{
615 if (graybuf == NULL)
616 return;
617
618 rb->memset(graybuf->data, 0xFF, MULU16(graybuf->depth, graybuf->plane_size)); 961 rb->memset(graybuf->data, 0xFF, MULU16(graybuf->depth, graybuf->plane_size));
619} 962}
620 963
621/* Do an lcd_update() to show changes done by rb->lcd_xxx() functions (in areas 964/* Do an lcd_update() to show changes done by rb->lcd_xxx() functions (in areas
622 * of the screen not covered by the grayscale overlay). If the grayscale 965 * of the screen not covered by the grayscale overlay).
623 * overlay is running, the update will be done in the next call of the 966 *
624 * interrupt routine, otherwise it will be performed right away. See also 967 * If the grayscale overlay is running, the update will be done in the next
625 * comment for the gray_show_display() function. 968 * call of the interrupt routine, otherwise it will be performed right away.
969 * See also comment for the gray_show_display() function.
626 */ 970 */
627void gray_deferred_update(void) 971void gray_deferred_update(void)
628{ 972{
629 if (graybuf != NULL && (graybuf->flags & GRAY_RUNNING)) 973 if (graybuf->flags & GRAY_RUNNING)
630 graybuf->flags |= GRAY_DEFERRED_UPDATE; 974 graybuf->flags |= GRAY_DEFERRED_UPDATE;
631 else 975 else
632 rb->lcd_update(); 976 rb->lcd_update();
633} 977}
634 978
979/** Scrolling functions **/
980
635/* Scroll the whole grayscale buffer left by <count> pixels 981/* Scroll the whole grayscale buffer left by <count> pixels
636 * 982 *
637 * black_border determines if the pixels scrolled in at the right are black 983 * black_border determines if the pixels scrolled in at the right are black
@@ -643,16 +989,13 @@ void gray_deferred_update(void)
643void gray_scroll_left(int count, bool black_border) 989void gray_scroll_left(int count, bool black_border)
644{ 990{
645 int by, d; 991 int by, d;
992 unsigned filler;
646 unsigned char *ptr; 993 unsigned char *ptr;
647 unsigned char filler;
648 994
649 if (graybuf == NULL || (unsigned) count >= (unsigned) graybuf->width) 995 if ((unsigned) count >= (unsigned) graybuf->width)
650 return; 996 return;
651 997
652 if (black_border) 998 filler = black_border ? 0xFF : 0;
653 filler = 0xFF;
654 else
655 filler = 0;
656 999
657 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */ 1000 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
658 for (by = 0; by < graybuf->bheight; by++) 1001 for (by = 0; by < graybuf->bheight; by++)
@@ -711,16 +1054,13 @@ void gray_scroll_left(int count, bool black_border)
711void gray_scroll_right(int count, bool black_border) 1054void gray_scroll_right(int count, bool black_border)
712{ 1055{
713 int by, d; 1056 int by, d;
1057 unsigned filler;
714 unsigned char *ptr; 1058 unsigned char *ptr;
715 unsigned char filler;
716 1059
717 if (graybuf == NULL || (unsigned) count >= (unsigned) graybuf->width) 1060 if ((unsigned) count >= (unsigned) graybuf->width)
718 return; 1061 return;
719 1062
720 if (black_border) 1063 filler = black_border ? 0xFF : 0;
721 filler = 0xFF;
722 else
723 filler = 0;
724 1064
725 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */ 1065 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
726 for (by = 0; by < graybuf->bheight; by++) 1066 for (by = 0; by < graybuf->bheight; by++)
@@ -778,16 +1118,10 @@ void gray_scroll_right(int count, bool black_border)
778void gray_scroll_up8(bool black_border) 1118void gray_scroll_up8(bool black_border)
779{ 1119{
780 int by, d; 1120 int by, d;
1121 unsigned filler;
781 unsigned char *ptr; 1122 unsigned char *ptr;
782 unsigned char filler;
783 1123
784 if (graybuf == NULL) 1124 filler = black_border ? 0xFF : 0;
785 return;
786
787 if (black_border)
788 filler = 0xFF;
789 else
790 filler = 0;
791 1125
792 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */ 1126 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
793 for (by = 1; by < graybuf->bheight; by++) 1127 for (by = 1; by < graybuf->bheight; by++)
@@ -818,16 +1152,10 @@ void gray_scroll_up8(bool black_border)
818void gray_scroll_down8(bool black_border) 1152void gray_scroll_down8(bool black_border)
819{ 1153{
820 int by, d; 1154 int by, d;
1155 unsigned filler;
821 unsigned char *ptr; 1156 unsigned char *ptr;
822 unsigned char filler;
823 1157
824 if (graybuf == NULL) 1158 filler = black_border ? 0xFF : 0;
825 return;
826
827 if (black_border)
828 filler = 0xFF;
829 else
830 filler = 0;
831 1159
832 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */ 1160 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
833 for (by = graybuf->bheight - 1; by > 0; by--) 1161 for (by = graybuf->bheight - 1; by > 0; by--)
@@ -859,16 +1187,13 @@ void gray_scroll_down8(bool black_border)
859 */ 1187 */
860void gray_scroll_up(int count, bool black_border) 1188void gray_scroll_up(int count, bool black_border)
861{ 1189{
862 unsigned long filler; 1190 unsigned filler;
863 1191
864 if (graybuf == NULL || (unsigned) count > 7) 1192 if ((unsigned) count > 7)
865 return; 1193 return;
866 1194
867 if (black_border) 1195 filler = black_border ? 0xFFu : 0;
868 filler = 0xFF; 1196
869 else
870 filler = 0;
871
872 /* scroll column by column to minimize flicker */ 1197 /* scroll column by column to minimize flicker */
873 asm volatile ( 1198 asm volatile (
874 "mov #0,r6 \n" /* x = 0 */ 1199 "mov #0,r6 \n" /* x = 0 */
@@ -962,16 +1287,13 @@ void gray_scroll_up(int count, bool black_border)
962 */ 1287 */
963void gray_scroll_down(int count, bool black_border) 1288void gray_scroll_down(int count, bool black_border)
964{ 1289{
965 unsigned long filler; 1290 unsigned filler;
966 1291
967 if (graybuf == NULL || (unsigned) count > 7) 1292 if ((unsigned) count > 7)
968 return; 1293 return;
969 1294
970 if (black_border) 1295 filler = black_border ? (0xFFu << count) : 0;
971 filler = 0xFF << count; /* calculate filler bits */ 1296
972 else
973 filler = 0;
974
975 /* scroll column by column to minimize flicker */ 1297 /* scroll column by column to minimize flicker */
976 asm volatile ( 1298 asm volatile (
977 "mov #0,r6 \n" /* x = 0 */ 1299 "mov #0,r6 \n" /* x = 0 */
@@ -1053,42 +1375,32 @@ void gray_scroll_down(int count, bool black_border)
1053 ); 1375 );
1054} 1376}
1055 1377
1056/* Set a pixel to a specific gray value 1378/** Pixel and line functions **/
1057 *
1058 * brightness is 0..255 (black to white) regardless of real bit depth
1059 */
1060void gray_drawpixel(int x, int y, int brightness)
1061{
1062 if (graybuf == NULL
1063 || (unsigned) x >= (unsigned) graybuf->width
1064 || (unsigned) y >= (unsigned) graybuf->height
1065 || (unsigned) brightness > 255)
1066 return;
1067 1379
1068 graypixel(x, y, graybuf->bitpattern[MULU16(brightness, 1380/* Set a pixel with the current drawinfo
1069 graybuf->depth + 1) >> 8]); 1381 *
1070} 1382 * If the drawmode is GRAY_DRAW_INVERSE, the pixel is inverted
1071 1383 * GRAY_DRAW_FG and GRAY_DRAW_SOLID draw the pixel in the foreground shade
1072/* Invert a pixel 1384 * GRAY_DRAW_BG draws the pixel in the background shade
1073 *
1074 * The bit pattern for that pixel in the buffer is inverted, so white becomes
1075 * black, light gray becomes dark gray etc.
1076 */ 1385 */
1077void gray_invertpixel(int x, int y) 1386void gray_drawpixel(int x, int y)
1078{ 1387{
1079 if (graybuf == NULL 1388 unsigned long pattern;
1080 || (unsigned) x >= (unsigned) graybuf->width 1389
1390 if ((unsigned) x >= (unsigned) graybuf->width
1081 || (unsigned) y >= (unsigned) graybuf->height) 1391 || (unsigned) y >= (unsigned) graybuf->height)
1082 return; 1392 return;
1083 1393
1084 grayinvertmasked(x, (y >> 3), 1 << (y & 7)); 1394 pattern = (graybuf->drawmode == GRAY_DRAW_BG) ?
1395 graybuf->bg_pattern : graybuf->fg_pattern;
1396
1397 _pixelfuncs[graybuf->drawmode](x, y, pattern);
1085} 1398}
1086 1399
1087/* Draw a line from (x1, y1) to (x2, y2) with a specific gray value 1400/* Draw a line from (x1, y1) to (x2, y2) with the current drawinfo,
1088 * 1401 * See gray_drawpixel() for details
1089 * brightness is 0..255 (black to white) regardless of real bit depth
1090 */ 1402 */
1091void gray_drawline(int x1, int y1, int x2, int y2, int brightness) 1403void gray_drawline(int x1, int y1, int x2, int y2)
1092{ 1404{
1093 int numpixels; 1405 int numpixels;
1094 int i; 1406 int i;
@@ -1097,17 +1409,14 @@ void gray_drawline(int x1, int y1, int x2, int y2, int brightness)
1097 int x, xinc1, xinc2; 1409 int x, xinc1, xinc2;
1098 int y, yinc1, yinc2; 1410 int y, yinc1, yinc2;
1099 unsigned long pattern; 1411 unsigned long pattern;
1412 void (*pixelfunc)(int x, int y, unsigned long pattern);
1100 1413
1101 if (graybuf == NULL 1414 if ((unsigned) x1 >= (unsigned) graybuf->width
1102 || (unsigned) x1 >= (unsigned) graybuf->width
1103 || (unsigned) y1 >= (unsigned) graybuf->height 1415 || (unsigned) y1 >= (unsigned) graybuf->height
1104 || (unsigned) x2 >= (unsigned) graybuf->width 1416 || (unsigned) x2 >= (unsigned) graybuf->width
1105 || (unsigned) y2 >= (unsigned) graybuf->height 1417 || (unsigned) y2 >= (unsigned) graybuf->height)
1106 || (unsigned) brightness > 255)
1107 return; 1418 return;
1108 1419
1109 pattern = graybuf->bitpattern[MULU16(brightness, graybuf->depth + 1) >> 8];
1110
1111 deltax = abs(x2 - x1); 1420 deltax = abs(x2 - x1);
1112 deltay = abs(y2 - y1); 1421 deltay = abs(y2 - y1);
1113 xinc2 = 1; 1422 xinc2 = 1;
@@ -1147,10 +1456,14 @@ void gray_drawline(int x1, int y1, int x2, int y2, int brightness)
1147 1456
1148 x = x1; 1457 x = x1;
1149 y = y1; 1458 y = y1;
1459
1460 pixelfunc = _pixelfuncs[graybuf->drawmode];
1461 pattern = (graybuf->drawmode == GRAY_DRAW_BG) ?
1462 graybuf->bg_pattern : graybuf->fg_pattern;
1150 1463
1151 for (i=0; i<numpixels; i++) 1464 for (i = 0; i < numpixels; i++)
1152 { 1465 {
1153 graypixel(x, y, pattern); 1466 pixelfunc(x, y, pattern);
1154 1467
1155 if (d < 0) 1468 if (d < 0)
1156 { 1469 {
@@ -1167,265 +1480,174 @@ void gray_drawline(int x1, int y1, int x2, int y2, int brightness)
1167 } 1480 }
1168} 1481}
1169 1482
1170/* Invert a line from (x1, y1) to (x2, y2) 1483/* Draw a horizontal line from (x1, y) to (x2, y) with the current drawinfo,
1171 * 1484 * See gray_drawpixel() for details
1172 * The bit patterns for the pixels of the line are inverted, so white becomes
1173 * black, light gray becomes dark gray etc.
1174 */ 1485 */
1175void gray_invertline(int x1, int y1, int x2, int y2) 1486void gray_horline(int x1, int x2, int y)
1176{ 1487{
1177 int numpixels; 1488 int x;
1178 int i; 1489 unsigned long pattern;
1179 int deltax, deltay; 1490 void (*pixelfunc)(int x, int y, unsigned long pattern);
1180 int d, dinc1, dinc2;
1181 int x, xinc1, xinc2;
1182 int y, yinc1, yinc2;
1183 1491
1184 if (graybuf == NULL 1492 if ((unsigned) x1 >= (unsigned) graybuf->width
1185 || (unsigned) x1 >= (unsigned) graybuf->width
1186 || (unsigned) y1 >= (unsigned) graybuf->height
1187 || (unsigned) x2 >= (unsigned) graybuf->width 1493 || (unsigned) x2 >= (unsigned) graybuf->width
1188 || (unsigned) y2 >= (unsigned) graybuf->height) 1494 || (unsigned) y >= (unsigned) graybuf->height)
1189 return; 1495 return;
1190 1496
1191 deltax = abs(x2 - x1);
1192 deltay = abs(y2 - y1);
1193 xinc2 = 1;
1194 yinc2 = 1;
1195
1196 if (deltax >= deltay)
1197 {
1198 numpixels = deltax;
1199 d = 2 * deltay - deltax;
1200 dinc1 = deltay * 2;
1201 dinc2 = (deltay - deltax) * 2;
1202 xinc1 = 1;
1203 yinc1 = 0;
1204 }
1205 else
1206 {
1207 numpixels = deltay;
1208 d = 2 * deltax - deltay;
1209 dinc1 = deltax * 2;
1210 dinc2 = (deltax - deltay) * 2;
1211 xinc1 = 0;
1212 yinc1 = 1;
1213 }
1214 numpixels++; /* include endpoints */
1215
1216 if (x1 > x2) 1497 if (x1 > x2)
1217 { 1498 {
1218 xinc1 = -xinc1; 1499 x = x1;
1219 xinc2 = -xinc2; 1500 x1 = x2;
1220 } 1501 x2 = x;
1221
1222 if (y1 > y2)
1223 {
1224 yinc1 = -yinc1;
1225 yinc2 = -yinc2;
1226 } 1502 }
1503 pixelfunc = _pixelfuncs[graybuf->drawmode];
1504 pattern = (graybuf->drawmode == GRAY_DRAW_BG) ?
1505 graybuf->bg_pattern : graybuf->fg_pattern;
1506
1507 for (x = x1; x <= x2; x++)
1508 pixelfunc(x, y, pattern);
1227 1509
1228 x = x1;
1229 y = y1;
1230
1231 for (i=0; i<numpixels; i++)
1232 {
1233 grayinvertmasked(x, (y >> 3), 1 << (y & 7));
1234
1235 if (d < 0)
1236 {
1237 d += dinc1;
1238 x += xinc1;
1239 y += yinc1;
1240 }
1241 else
1242 {
1243 d += dinc2;
1244 x += xinc2;
1245 y += yinc2;
1246 }
1247 }
1248} 1510}
1249 1511
1250/* Draw a (hollow) rectangle with a specific gray value, 1512/* Draw a vertical line from (x, y1) to (x, y2) with the current drawinfo,
1251 * corners are (x1, y1) and (x2, y2) 1513 * See gray_drawpixel() for details
1252 * 1514 *
1253 * brightness is 0..255 (black to white) regardless of real bit depth 1515 * This one uses the block drawing optimization, so it is rather fast.
1254 */ 1516 */
1255void gray_drawrect(int x1, int y1, int x2, int y2, int brightness) 1517void gray_verline(int x, int y1, int y2)
1256{ 1518{
1257 int x, y; 1519 int shift, y, ny;
1258 unsigned long pattern; 1520 unsigned bits, mask_top, mask_bottom;
1259 unsigned char srcpixel; 1521 unsigned char *dst;
1522 void (*blockfunc)(unsigned char *address, unsigned mask, unsigned bits);
1260 1523
1261 if (graybuf == NULL 1524 if ((unsigned) x >= (unsigned) graybuf->width
1262 || (unsigned) x1 >= (unsigned) graybuf->width
1263 || (unsigned) y1 >= (unsigned) graybuf->height 1525 || (unsigned) y1 >= (unsigned) graybuf->height
1264 || (unsigned) x2 >= (unsigned) graybuf->width 1526 || (unsigned) y2 >= (unsigned) graybuf->height)
1265 || (unsigned) y2 >= (unsigned) graybuf->height
1266 || (unsigned) brightness > 255)
1267 return; 1527 return;
1268 1528
1269 if (y1 > y2) 1529 if (y1 > y2)
1270 { 1530 {
1271 y = y1; 1531 y = y1;
1272 y1 = y2; 1532 y1 = y2;
1273 y2 = y; 1533 y2 = y;
1274 } 1534 }
1275 if (x1 > x2) 1535 y = y1;
1276 { 1536 ny = y2 - y1 + 1;
1277 x = x1; 1537
1278 x1 = x2; 1538 dst = graybuf->data + x + MULU16(graybuf->width, y >> 3);
1279 x2 = x; 1539 shift = y & 7;
1280 } 1540 ny += shift;
1281 1541
1282 pattern = graybuf->bitpattern[MULU16(brightness, graybuf->depth + 1) >> 8]; 1542 mask_top = 0xFFu << (y & 7);
1283 srcpixel = brightness; 1543 mask_bottom = ~(0xFEu << ((ny - 1) & 7));
1544 if (ny <= 8)
1545 mask_bottom &= mask_top;
1546
1547 blockfunc = _blockfuncs[graybuf->drawmode];
1548 bits = (graybuf->drawmode == GRAY_DRAW_BG) ? 0u : 0xFFu;
1284 1549
1285 for (x = x1 + 1; x < x2; x++) 1550 if (ny > 8)
1286 { 1551 {
1287 graypixel(x, y1, pattern); 1552 blockfunc(dst, mask_top, bits);
1288 graypixel(x, y2, pattern); 1553 dst += graybuf->width;
1289 } 1554
1290 for (y = y1; y <= y2; ) 1555 for (y = 8; y < ny - 8; y += 8)
1291 {
1292 if (!(y & 7) && (y2 - y >= 7))
1293 /* current row byte aligned in fb & at least 8 rows left */
1294 {
1295 /* shortcut: draw all 8 rows at once: 2..3 times faster */
1296 grayblock(x1, y >> 3, &srcpixel, 0);
1297 grayblock(x2, y >> 3, &srcpixel, 0);
1298 y += 8;
1299 }
1300 else
1301 { 1556 {
1302 graypixel(x1, y, pattern); 1557 blockfunc(dst, 0xFFu, bits);
1303 graypixel(x2, y, pattern); 1558 dst += graybuf->width;
1304 y++;
1305 } 1559 }
1306 } 1560 }
1561
1562 blockfunc(dst, mask_bottom, bits);
1307} 1563}
1308 1564
1309/* Fill a rectangle with a specific gray value 1565/** Rectangle functions **/
1310 * corners are (x1, y1) and (x2, y2) 1566
1311 * 1567/* Draw a (hollow) rectangle with the current drawinfo,
1312 * brightness is 0..255 (black to white) regardless of real bit depth 1568 * See gray_drawpixel() for details
1313 */ 1569 */
1314void gray_fillrect(int x1, int y1, int x2, int y2, int brightness) 1570void gray_drawrect(int x, int y, int nx, int ny)
1315{ 1571{
1316 int x, y; 1572 int x2, y2;
1317 unsigned long pattern;
1318 unsigned char srcpixel;
1319 1573
1320 if (graybuf == NULL 1574 if ((unsigned) x >= (unsigned) graybuf->width
1321 || (unsigned) x1 >= (unsigned) graybuf->width 1575 || (unsigned) y >= (unsigned) graybuf->height)
1322 || (unsigned) y1 >= (unsigned) graybuf->height
1323 || (unsigned) x2 >= (unsigned) graybuf->width
1324 || (unsigned) y2 >= (unsigned) graybuf->height
1325 || (unsigned) brightness > 255)
1326 return; 1576 return;
1327
1328 if (y1 > y2)
1329 {
1330 y = y1;
1331 y1 = y2;
1332 y2 = y;
1333 }
1334 if (x1 > x2)
1335 {
1336 x = x1;
1337 x1 = x2;
1338 x2 = x;
1339 }
1340 1577
1341 pattern = graybuf->bitpattern[MULU16(brightness, graybuf->depth + 1) >> 8]; 1578 if ((unsigned) (y + ny) >= (unsigned) graybuf->height) /* clip bottom */
1342 srcpixel = brightness; 1579 ny = graybuf->height - y;
1343 1580
1344 for (y = y1; y <= y2; ) 1581 if ((unsigned) (x + nx) >= (unsigned) graybuf->width) /* clip right */
1345 { 1582 nx = graybuf->width - x;
1346 if (!(y & 7) && (y2 - y >= 7)) 1583
1347 /* current row byte aligned in fb & at least 8 rows left */ 1584 x2 = x + nx - 1;
1348 { 1585 y2 = y + ny - 1;
1349 for (x = x1; x <= x2; x++) 1586
1350 { 1587 gray_horline(x, x2, y);
1351 /* shortcut: draw all 8 rows at once: 2..3 times faster */ 1588 gray_horline(x, x2, y2);
1352 grayblock(x, y >> 3, &srcpixel, 0); 1589 gray_verline(x, y, y2);
1353 } 1590 gray_verline(x2, y, y2);
1354 y += 8;
1355 }
1356 else
1357 {
1358 for (x = x1; x <= x2; x++)
1359 {
1360 graypixel(x, y, pattern);
1361 }
1362 y++;
1363 }
1364 }
1365} 1591}
1366 1592
1367/* Invert a (solid) rectangle, corners are (x1, y1) and (x2, y2) 1593/* Draw a filled rectangle with the current drawinfo,
1594 * See gray_drawpixel() for details
1368 * 1595 *
1369 * The bit patterns for all pixels of the rectangle are inverted, so white 1596 * This one uses the block drawing optimization, so it is rather fast.
1370 * becomes black, light gray becomes dark gray etc. This is the fastest of
1371 * all gray_xxxrect() functions! Perfectly suited for cursors.
1372 */ 1597 */
1373void gray_invertrect(int x1, int y1, int x2, int y2) 1598void gray_fillrect(int x, int y, int nx, int ny)
1374{ 1599{
1375 int x, yb, yb1, yb2; 1600 int shift;
1376 unsigned char mask; 1601 unsigned bits, mask_top, mask_bottom;
1377 1602 unsigned char *dst, *dst_row;
1378 if (graybuf == NULL 1603 void (*blockfunc)(unsigned char *address, unsigned mask, unsigned bits);
1379 || (unsigned) x1 >= (unsigned) graybuf->width 1604
1380 || (unsigned) y1 >= (unsigned) graybuf->height 1605 if ((unsigned) x >= (unsigned) graybuf->width
1381 || (unsigned) x2 >= (unsigned) graybuf->width 1606 || (unsigned) y >= (unsigned) graybuf->height)
1382 || (unsigned) y2 >= (unsigned) graybuf->height)
1383 return; 1607 return;
1608
1609 if ((unsigned) (y + ny) >= (unsigned) graybuf->height) /* clip bottom */
1610 ny = graybuf->height - y;
1384 1611
1385 if (y1 > y2) 1612 if ((unsigned) (x + nx) >= (unsigned) graybuf->width) /* clip right */
1386 { 1613 nx = graybuf->width - x;
1387 yb = y1;
1388 y1 = y2;
1389 y2 = yb;
1390 }
1391 if (x1 > x2)
1392 {
1393 x = x1;
1394 x1 = x2;
1395 x2 = x;
1396 }
1397
1398 yb1 = y1 >> 3;
1399 yb2 = y2 >> 3;
1400 1614
1401 if (yb1 == yb2) 1615 dst = graybuf->data + x + MULU16(graybuf->width, y >> 3);
1402 { 1616 shift = y & 7;
1403 mask = 0xFFu << (y1 & 7); 1617 ny += shift;
1404 mask &= 0xFFu >> (7 - (y2 & 7));
1405 1618
1406 for (x = x1; x <= x2; x++) 1619 mask_top = 0xFFu << (y & 7);
1407 grayinvertmasked(x, yb1, mask); 1620 mask_bottom = ~(0xFEu << ((ny - 1) & 7));
1408 } 1621 if (ny <= 8)
1409 else 1622 mask_bottom &= mask_top;
1623
1624 blockfunc = _blockfuncs[graybuf->drawmode];
1625 bits = (graybuf->drawmode == GRAY_DRAW_BG) ? 0u : 0xFFu;
1626
1627 if (ny > 8)
1410 { 1628 {
1411 mask = 0xFFu << (y1 & 7); 1629 dst_row = dst;
1630 for (x = 0; x < nx; x++)
1631 blockfunc(dst_row++, mask_top, bits);
1412 1632
1413 for (x = x1; x <= x2; x++) 1633 dst += graybuf->width;
1414 grayinvertmasked(x, yb1, mask);
1415 1634
1416 for (yb = yb1 + 1; yb < yb2; yb++) 1635 for (y = 8; y < ny - 8; y += 8)
1417 { 1636 {
1418 for (x = x1; x <= x2; x++) 1637 dst_row = dst;
1419 grayinvertmasked(x, yb, 0xFF); 1638 for (x = 0; x < nx; x++)
1420 } 1639 blockfunc(dst_row++, 0xFFu, bits);
1421
1422 mask = 0xFFu >> (7 - (y2 & 7));
1423 1640
1424 for (x = x1; x <= x2; x++) 1641 dst += graybuf->width;
1425 grayinvertmasked(x, yb2, mask); 1642 }
1426 } 1643 }
1644
1645 for (x = 0; x < nx; x++)
1646 blockfunc(dst++, mask_bottom, bits);
1427} 1647}
1428 1648
1649/** Bitmap functions **/
1650
1429/* Copy a grayscale bitmap into the display 1651/* Copy a grayscale bitmap into the display
1430 * 1652 *
1431 * A grayscale bitmap contains one byte for every pixel that defines the 1653 * A grayscale bitmap contains one byte for every pixel that defines the
@@ -1433,55 +1655,66 @@ void gray_invertrect(int x1, int y1, int x2, int y2)
1433 * The <stride> parameter is useful if you want to show only a part of a 1655 * The <stride> parameter is useful if you want to show only a part of a
1434 * bitmap. It should always be set to the "row length" of the bitmap, so 1656 * bitmap. It should always be set to the "row length" of the bitmap, so
1435 * for displaying the whole bitmap, nx == stride. 1657 * for displaying the whole bitmap, nx == stride.
1658 *
1659 * This is the only drawing function NOT using the drawinfo.
1436 */ 1660 */
1437void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny, 1661void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny,
1438 int stride) 1662 int stride)
1439{ 1663{
1440 int xi, yi, byte; 1664 int shift;
1441 unsigned char *row; 1665 unsigned mask_top, mask_bottom;
1666 unsigned char *src_row, *dst, *dst_row;
1442 1667
1443 if (graybuf == NULL 1668 if ((unsigned) x >= (unsigned) graybuf->width
1444 || (unsigned) x >= (unsigned) graybuf->width
1445 || (unsigned) y >= (unsigned) graybuf->height) 1669 || (unsigned) y >= (unsigned) graybuf->height)
1446 return; 1670 return;
1447 1671
1448 if ((y + ny) >= graybuf->height) /* clip bottom */ 1672 if ((unsigned) (y + ny) >= (unsigned) graybuf->height) /* clip bottom */
1449 ny = graybuf->height - y; 1673 ny = graybuf->height - y;
1450 1674
1451 if ((x + nx) >= graybuf->width) /* clip right */ 1675 if ((unsigned) (x + nx) >= (unsigned) graybuf->width) /* clip right */
1452 nx = graybuf->width - x; 1676 nx = graybuf->width - x;
1677
1678 dst = graybuf->data + x + MULU16(graybuf->width, y >> 3);
1679 shift = y & 7;
1680 ny += shift;
1453 1681
1454 for (yi = y; yi < y + ny; ) 1682 mask_top = 0xFFu << (y & 7);
1683 mask_bottom = ~(0xFEu << ((ny - 1) & 7));
1684 if (ny <= 8)
1685 mask_bottom &= mask_top;
1686
1687 if (ny > 8)
1455 { 1688 {
1456 row = src; 1689 src_row = src;
1690 dst_row = dst;
1457 1691
1458 if (!(yi & 7) && (y + ny - yi > 7)) 1692 for (x = 0; x < nx; x++)
1459 /* current row byte aligned in fb & at least 8 rows left */ 1693 _writearray(dst_row++, src_row++, stride, mask_top);
1694
1695 src += MULU16(stride, 8 - shift);
1696 dst += graybuf->width;
1697
1698 for (y = 8; y < ny - 8; y += 8)
1460 { 1699 {
1461 for (xi = x; xi < x + nx; xi++) 1700 src_row = src;
1462 { 1701 dst_row = dst;
1463 /* shortcut: draw all 8 rows at once: 2..3 times faster */ 1702
1464 grayblock(xi, yi >> 3, row++, stride); 1703 for (x = 0; x < nx; x++)
1465 } 1704 _writearray(dst_row++, src_row++, stride, 0xFFu);
1466 yi += 8; 1705
1467 src += stride << 3; 1706 src += stride << 3;
1468 } 1707 dst += graybuf->width;
1469 else
1470 {
1471 for (xi = x; xi < x + nx; xi++)
1472 {
1473 byte = *row++;
1474 /* separated to force GCC to use 16bit multiplication below */
1475 graypixel(xi, yi, graybuf->bitpattern[MULU16(byte,
1476 graybuf->depth + 1) >> 8]);
1477 }
1478 yi++;
1479 src += stride;
1480 } 1708 }
1481 } 1709 }
1710
1711 for (x = 0; x < nx; x++)
1712 _writearray(dst++, src++, stride, mask_bottom);
1482} 1713}
1483 1714
1484/* Display a bitmap with specific foreground and background gray values 1715/* Display a bitmap with the current drawinfo
1716 *
1717 * The drawmode is used as described for gray_set_drawmode()
1485 * 1718 *
1486 * This (now) uses the same bitmap format as the core b&w graphics routines, 1719 * This (now) uses the same bitmap format as the core b&w graphics routines,
1487 * so you can use bmp2rb to generate bitmaps for use with this function as 1720 * so you can use bmp2rb to generate bitmaps for use with this function as
@@ -1496,60 +1729,71 @@ void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny,
1496 * 1729 *
1497 * The <stride> parameter is useful if you want to show only a part of a 1730 * The <stride> parameter is useful if you want to show only a part of a
1498 * bitmap. It should always be set to the "row length" of the bitmap. 1731 * bitmap. It should always be set to the "row length" of the bitmap.
1499 *
1500 * If draw_bg is false, only foreground pixels are drawn, so the background
1501 * is transparent. In this case bg_brightness is ignored.
1502 */ 1732 */
1503void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny, 1733void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
1504 int stride, bool draw_bg, int fg_brightness, 1734 int stride)
1505 int bg_brightness)
1506{ 1735{
1507 int xi, dy; 1736 int shift;
1508 int bits = 0; /* Have to initialize to prevent warning */ 1737 unsigned bits, mask_top, mask_bottom;
1509 unsigned long fg_pattern, bg_pattern; 1738 unsigned char *src_col, *dst, *dst_col;
1510 unsigned char *col; 1739 void (*blockfunc)(unsigned char *address, unsigned mask, unsigned bits);
1511
1512 if (graybuf == NULL
1513 || (unsigned) x >= (unsigned) graybuf->width
1514 || (unsigned) y >= (unsigned) graybuf->height
1515 || (unsigned) fg_brightness > 255
1516 || (unsigned) bg_brightness > 255)
1517 return;
1518 1740
1519 if ((y + ny) >= graybuf->height) /* clip bottom */ 1741 if ((unsigned) x >= (unsigned) graybuf->width
1742 || (unsigned) y >= (unsigned) graybuf->height)
1743 return;
1744
1745 if ((unsigned) (y + ny) >= (unsigned) graybuf->height) /* clip bottom */
1520 ny = graybuf->height - y; 1746 ny = graybuf->height - y;
1521 1747
1522 if ((x + nx) >= graybuf->width) /* clip right */ 1748 if ((unsigned) (x + nx) >= (unsigned) graybuf->width) /* clip right */
1523 nx = graybuf->width - x; 1749 nx = graybuf->width - x;
1524 1750
1525 fg_pattern = graybuf->bitpattern[MULU16(fg_brightness, 1751 dst = graybuf->data + x + MULU16(graybuf->width, y >> 3);
1526 graybuf->depth + 1) >> 8]; 1752 shift = y & 7;
1753 ny += shift;
1527 1754
1528 bg_pattern = graybuf->bitpattern[MULU16(bg_brightness, 1755 mask_top = 0xFFu << (y & 7);
1529 graybuf->depth + 1) >> 8]; 1756 mask_bottom = ~(0xFEu << ((ny - 1) & 7));
1757 if (ny <= 8)
1758 mask_bottom &= mask_top;
1530 1759
1531 for (xi = x; xi < x + nx; xi++) 1760 blockfunc = _blockfuncs[graybuf->drawmode];
1761
1762 for(x = 0; x < nx; x++)
1532 { 1763 {
1533 col = src++; 1764 src_col = src++;
1534 for (dy = 0; dy < ny; dy++) 1765 dst_col = dst++;
1766 bits = 0;
1767 y = 0;
1768
1769 if (ny > 8)
1535 { 1770 {
1536 if (!(dy & 7)) /* get next 8 bits */ 1771 bits = *src_col << shift;
1537 { 1772 src_col += stride;
1538 bits = (int)(*col);
1539 col += stride;
1540 }
1541 1773
1542 if (bits & 0x01) 1774 blockfunc(dst_col, mask_top, bits);
1543 graypixel(xi, y + dy, fg_pattern); 1775 dst_col += graybuf->width;
1544 else 1776 bits >>= 8;
1545 if (draw_bg)
1546 graypixel(xi, y + dy, bg_pattern);
1547 1777
1548 bits >>= 1; 1778 for (y = 8; y < ny - 8; y += 8)
1779 {
1780 bits |= *src_col << shift;
1781 src_col += stride;
1782
1783 blockfunc(dst_col, 0xFFu, bits);
1784 dst_col += graybuf->width;
1785 bits >>= 8;
1786 }
1549 } 1787 }
1788 if (y + shift < ny)
1789 bits |= *src_col << shift;
1790
1791 blockfunc(dst_col, mask_bottom, bits);
1550 } 1792 }
1551} 1793}
1552 1794
1795/** Font support **/
1796
1553/* Set font for the font routines 1797/* Set font for the font routines
1554 * 1798 *
1555 * newfont can be FONT_SYSFIXED or FONT_UI the same way as with the Rockbox 1799 * newfont can be FONT_SYSFIXED or FONT_UI the same way as with the Rockbox
@@ -1557,7 +1801,7 @@ void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
1557 */ 1801 */
1558void gray_setfont(int newfont) 1802void gray_setfont(int newfont)
1559{ 1803{
1560 graybuf->curfont = newfont; 1804 graybuf->curfont = rb->font_get(newfont);
1561} 1805}
1562 1806
1563/* Calculate width and height of the given text in pixels when rendered with 1807/* Calculate width and height of the given text in pixels when rendered with
@@ -1570,9 +1814,9 @@ int gray_getstringsize(unsigned char *str, int *w, int *h)
1570{ 1814{
1571 int ch; 1815 int ch;
1572 int width = 0; 1816 int width = 0;
1573 struct font* pf = rb->font_get(graybuf->curfont); 1817 struct font *pf = graybuf->curfont;
1574 1818
1575 while ((ch = *str++)) 1819 while ((ch = *str++))
1576 { 1820 {
1577 /* check input range */ 1821 /* check input range */
1578 if (ch < pf->firstchar || ch >= pf->firstchar + pf->size) 1822 if (ch < pf->firstchar || ch >= pf->firstchar + pf->size)
@@ -1589,25 +1833,20 @@ int gray_getstringsize(unsigned char *str, int *w, int *h)
1589 return width; 1833 return width;
1590} 1834}
1591 1835
1592/* Display text with specified foreground and background shades 1836/* Display text starting at (x, y) with the current font and drawinfo
1593 * 1837 *
1594 * If draw_bg is false, only foreground pixels are drawn, so the background 1838 * The drawmode is used as described for gray_set_drawmode()
1595 * is transparent. In this case bg_brightness is ignored.
1596 */ 1839 */
1597void gray_putsxy(int x, int y, unsigned char *str, bool draw_bg, 1840void gray_putsxy(int x, int y, unsigned char *str)
1598 int fg_brightness, int bg_brightness)
1599{ 1841{
1600 int ch, width; 1842 int ch, width;
1601 bitmap_t *bits; 1843 bitmap_t *bits;
1602 struct font *pf = rb->font_get(graybuf->curfont); 1844 struct font *pf = graybuf->curfont;
1603 1845
1604 if (graybuf == NULL 1846 if ((unsigned) x >= (unsigned) graybuf->width
1605 || (unsigned) x >= (unsigned) graybuf->width 1847 || (unsigned) y >= (unsigned) graybuf->height)
1606 || (unsigned) y >= (unsigned) graybuf->height
1607 || (unsigned) fg_brightness > 255
1608 || (unsigned) bg_brightness > 255)
1609 return; 1848 return;
1610 1849
1611 while ((ch = *str++) != '\0' && x < graybuf->width) 1850 while ((ch = *str++) != '\0' && x < graybuf->width)
1612 { 1851 {
1613 /* check input range */ 1852 /* check input range */
@@ -1621,7 +1860,7 @@ void gray_putsxy(int x, int y, unsigned char *str, bool draw_bg,
1621 : MULU16(pf->height, ch)); 1860 : MULU16(pf->height, ch));
1622 1861
1623 gray_drawbitmap((unsigned char*) bits, x, y, width, pf->height, 1862 gray_drawbitmap((unsigned char*) bits, x, y, width, pf->height,
1624 width, draw_bg, fg_brightness, bg_brightness); 1863 width);
1625 x += width; 1864 x += width;
1626 } 1865 }
1627} 1866}
diff --git a/apps/plugins/lib/gray.h b/apps/plugins/lib/gray.h
index 218fb282c8..18be88a2f2 100644
--- a/apps/plugins/lib/gray.h
+++ b/apps/plugins/lib/gray.h
@@ -9,6 +9,9 @@
9* 9*
10* Grayscale framework 10* Grayscale framework
11* 11*
12* This is a generic framework to use grayscale display within Rockbox
13* plugins. It obviously does not work for the player.
14*
12* Copyright (C) 2004 Jens Arnold 15* Copyright (C) 2004 Jens Arnold
13* 16*
14* All files in this archive are subject to the GNU General Public License. 17* All files in this archive are subject to the GNU General Public License.
@@ -27,59 +30,308 @@
27 30
28#ifdef HAVE_LCD_BITMAP /* and also not for the Player */ 31#ifdef HAVE_LCD_BITMAP /* and also not for the Player */
29 32
30/* This is a generic framework to use grayscale display within rockbox 33/* Initialize the framework
31 * plugins. It obviously does not work for the player. 34 *
35 * every framework needs such a function, and it has to be called as
36 * the very first one
32 */ 37 */
33
34/* every framework needs such a function, and it has to be called as
35 * the very first one */
36void gray_init(struct plugin_api* newrb); 38void gray_init(struct plugin_api* newrb);
37 39
38/* general functions */ 40/**** general functions ****/
41
42/* Prepare the grayscale display buffer
43 *
44 * arguments:
45 * gbuf = pointer to the memory area to use (e.g. plugin buffer)
46 * gbuf_size = max usable size of the buffer
47 * width = width in pixels (1..112)
48 * bheight = height in 8-pixel units (1..8)
49 * depth = desired number of shades - 1 (1..32)
50 *
51 * result:
52 * = depth if there was enough memory
53 * < depth if there wasn't enough memory. The number of displayable
54 * shades is smaller than desired, but it still works
55 * = 0 if there wasn't even enough memory for 1 bitplane (black & white)
56 *
57 * You can request any depth from 1 to 32, not just powers of 2. The routine
58 * performs "graceful degradation" if the memory is not sufficient for the
59 * desired depth. As long as there is at least enough memory for 1 bitplane,
60 * it creates as many bitplanes as fit into memory, although 1 bitplane will
61 * only deliver black & white display.
62 *
63 * If you need info about the memory taken by the grayscale buffer, supply an
64 * int* as the last parameter. This int will then contain the number of bytes
65 * used. The total memory needed can be calculated as follows:
66 * total_mem =
67 * sizeof(tGraybuf) (= 64 bytes currently)
68 * + sizeof(long) (= 4 bytes)
69 * + (width * bheight + sizeof(long)) * depth
70 * + 0..3 (longword alignment of grayscale display buffer)
71 */
39int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width, 72int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
40 int bheight, int depth, int *buf_taken); 73 int bheight, int depth, int *buf_taken);
74
75/* Release the grayscale display buffer
76 *
77 * Switches the grayscale overlay off at first if it is still running,
78 * then sets the pointer to NULL.
79 * DO CALL either this function or at least gray_show_display(false)
80 * before you exit, otherwise nasty things may happen.
81 */
41void gray_release_buffer(void); 82void gray_release_buffer(void);
83
84/* Set position of the top left corner of the grayscale overlay
85 *
86 * x = left margin in pixels
87 * by = top margin in 8-pixel units
88 *
89 * You may set this in a way that the overlay spills across the right or
90 * bottom display border. In this case it will simply be clipped by the
91 * LCD controller. You can even set negative values, this will clip at the
92 * left or top border. I did not test it, but the limits may be +127 / -128
93 *
94 * If you use this while the grayscale overlay is running, the now-freed area
95 * will be restored.
96 */
42void gray_position_display(int x, int by); 97void gray_position_display(int x, int by);
98
99/* Switch the grayscale overlay on or off
100 *
101 * enable = true: the grayscale overlay is switched on if initialized
102 * = false: the grayscale overlay is switched off and the regular lcd
103 * content is restored
104 *
105 * DO NOT call lcd_update() or any other api function that directly accesses
106 * the lcd while the grayscale overlay is running! If you need to do
107 * lcd_update() to update something outside the grayscale overlay area, use
108 * gray_deferred_update() instead.
109 *
110 * Other functions to avoid are:
111 * lcd_blit() (obviously), lcd_update_rect(), lcd_set_contrast(),
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 */
43void gray_show_display(bool enable); 118void gray_show_display(bool enable);
44 119
45/* functions affecting the whole display */ 120/* Set the draw mode for subsequent drawing operations
121 *
122 * drawmode =
123 * GRAY_DRAW_INVERSE: Foreground pixels are inverted, background pixels are
124 * left untouched
125 * GRAY_DRAW_FG: Only foreground pixels are drawn
126 * GRAY_DRAW_BG: Only background pixels are drawn
127 * GRAY_DRAW_SOLID: Foreground and background pixels are drawn
128 */
129void gray_set_drawmode(int drawmode);
130
131/* Draw modes */
132#define GRAY_DRAW_INVERSE 0
133#define GRAY_DRAW_FG 1
134#define GRAY_DRAW_BG 2
135#define GRAY_DRAW_SOLID 3
136
137/* Set the foreground shade for subsequent drawing operations
138 *
139 * brightness = 0 (black) .. 255 (white)
140 */
141void gray_set_foreground(int brightness);
142
143/* Set the background shade for subsequent drawing operations
144 *
145 * brightness = 0 (black) .. 255 (white)
146 */
147void gray_set_background(int brightness);
148
149/* Set draw mode, foreground and background shades at once
150 *
151 * If you hand it -1 (or in fact any other out-of-bounds value) for a
152 * parameter, that particular setting won't be changed
153 */
154void gray_set_drawinfo(int drawmode, int fg_brightness, int bg_brightness);
155
156/**** functions affecting the whole display ****/
157
158/* Clear the grayscale display (sets all pixels to white) */
46void gray_clear_display(void); 159void gray_clear_display(void);
160
161/* Set the grayscale display to all black */
47void gray_black_display(void); 162void gray_black_display(void);
163
164/* Do an lcd_update() to show changes done by rb->lcd_xxx() functions (in areas
165 * of the screen not covered by the grayscale overlay).
166 *
167 * If the grayscale overlay is running, the update will be done in the next
168 * call of the interrupt routine, otherwise it will be performed right away.
169 * See also comment for the gray_show_display() function.
170 */
48void gray_deferred_update(void); 171void gray_deferred_update(void);
49 172
50/* scrolling functions */ 173/**** Scrolling functions ****/
174
175/* Scroll the whole grayscale buffer left by <count> pixels
176 *
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 */
51void gray_scroll_left(int count, bool black_border); 183void gray_scroll_left(int count, bool black_border);
184
185/* Scroll the whole grayscale buffer right by <count> pixels
186 *
187 * black_border determines if the pixels scrolled in at the left are black
188 * or white
189 *
190 * Scrolling left/right by an even pixel count is almost twice as fast as
191 * scrolling by an odd pixel count.
192 */
52void gray_scroll_right(int count, bool black_border); 193void gray_scroll_right(int count, bool black_border);
194
195/* Scroll the whole grayscale buffer up by 8 pixels
196 *
197 * black_border determines if the pixels scrolled in at the bottom are black
198 * or white
199 *
200 * Scrolling up/down by 8 pixels is very fast.
201 */
53void gray_scroll_up8(bool black_border); 202void gray_scroll_up8(bool black_border);
203
204/* Scroll the whole grayscale buffer down by 8 pixels
205 *
206 * black_border determines if the pixels scrolled in at the top are black
207 * or white
208 *
209 * Scrolling up/down by 8 pixels is very fast.
210 */
54void gray_scroll_down8(bool black_border); 211void gray_scroll_down8(bool black_border);
212
213/* Scroll the whole grayscale buffer up by <count> pixels (<= 7)
214 *
215 * black_border determines if the pixels scrolled in at the bottom are black
216 * or white
217 *
218 * Scrolling up/down pixel-wise is significantly slower than scrolling
219 * left/right or scrolling up/down byte-wise because it involves bit
220 * shifting. That's why it is asm optimized.
221 */
55void gray_scroll_up(int count, bool black_border); 222void gray_scroll_up(int count, bool black_border);
223
224/* Scroll the whole grayscale buffer down by <count> pixels (<= 7)
225 *
226 * black_border determines if the pixels scrolled in at the top are black
227 * or white
228 *
229 * Scrolling up/down pixel-wise is significantly slower than scrolling
230 * left/right or scrolling up/down byte-wise because it involves bit
231 * shifting. That's why it is asm optimized.
232 */
56void gray_scroll_down(int count, bool black_border); 233void gray_scroll_down(int count, bool black_border);
57 234
58/* pixel functions */ 235/**** Pixel and line functions ****/
59void gray_drawpixel(int x, int y, int brightness); 236
60void gray_invertpixel(int x, int y); 237/* Set a pixel with the current drawinfo
238 *
239 * If the drawmode is GRAY_DRAW_INVERSE, the pixel is inverted
240 * GRAY_DRAW_FG and GRAY_DRAW_SOLID draw the pixel in the foreground shade
241 * GRAY_DRAW_BG draws the pixel in the background shade
242 */
243void gray_drawpixel(int x, int y);
244
245/* Draw a line from (x1, y1) to (x2, y2) with the current drawinfo,
246 * See gray_drawpixel() for details
247 */
248void gray_drawline(int x1, int y1, int x2, int y2);
249
250/* Draw a horizontal line from (x1, y) to (x2, y) with the current drawinfo,
251 * See gray_drawpixel() for details
252 */
253void gray_horline(int x1, int x2, int y);
254
255/* Draw a vertical line from (x, y1) to (x, y2) with the current drawinfo,
256 * See gray_drawpixel() for details
257 *
258 * This one uses the block drawing optimization, so it is rather fast.
259 */
260void gray_verline(int x, int y1, int y2);
261
262/**** Rectangle functions ****/
263
264/* Draw a (hollow) rectangle with the current drawinfo,
265 * See gray_drawpixel() for details
266 */
267void gray_drawrect(int x, int y, int nx, int ny);
61 268
62/* line functions */ 269/* Draw a filled rectangle with the current drawinfo,
63void gray_drawline(int x1, int y1, int x2, int y2, int brightness); 270 * See gray_drawpixel() for details
64void gray_invertline(int x1, int y1, int x2, int y2); 271 *
272 * This one uses the block drawing optimization, so it is rather fast.
273 */
274void gray_fillrect(int x, int y, int nx, int ny);
65 275
66/* rectangle functions */ 276/**** Bitmap functions ****/
67void gray_drawrect(int x1, int y1, int x2, int y2, int brightness);
68void gray_fillrect(int x1, int y1, int x2, int y2, int brightness);
69void gray_invertrect(int x1, int y1, int x2, int y2);
70 277
71/* bitmap functions */ 278/* Copy a grayscale bitmap into the display
279 *
280 * A grayscale bitmap contains one byte for every pixel that defines the
281 * brightness of the pixel (0..255). Bytes are read in row-major order.
282 * The <stride> parameter is useful if you want to show only a part of a
283 * bitmap. It should always be set to the "row length" of the bitmap, so
284 * for displaying the whole bitmap, nx == stride.
285 *
286 * This is the only drawing function NOT using the drawinfo.
287 */
72void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny, 288void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny,
73 int stride); 289 int stride);
290
291/* Display a bitmap with the current drawinfo
292 *
293 * The drawmode is used as described for gray_set_drawmode()
294 *
295 * This (now) uses the same bitmap format as the core b&w graphics routines,
296 * so you can use bmp2rb to generate bitmaps for use with this function as
297 * well.
298 *
299 * A bitmap contains one bit for every pixel that defines if that pixel is
300 * foreground (1) or background (0). Bits within a byte are arranged
301 * vertically, LSB at top.
302 * The bytes are stored in row-major order, with byte 0 being top left,
303 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
304 * 0..7, the second row defines pixel row 8..15 etc.
305 *
306 * The <stride> parameter is useful if you want to show only a part of a
307 * bitmap. It should always be set to the "row length" of the bitmap.
308 */
74void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny, 309void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
75 int stride, bool draw_bg, int fg_brightness, 310 int stride);
76 int bg_brightness);
77 311
78/* font support */ 312/**** Font support ****/
313
314/* Set font for the font routines
315 *
316 * newfont can be FONT_SYSFIXED or FONT_UI the same way as with the Rockbox
317 * core routines
318 */
79void gray_setfont(int newfont); 319void gray_setfont(int newfont);
320
321/* Calculate width and height of the given text in pixels when rendered with
322 * the currently selected font.
323 *
324 * This works exactly the same way as the core lcd_getstringsize(), only that
325 * it uses the selected font for grayscale.
326 */
80int gray_getstringsize(unsigned char *str, int *w, int *h); 327int gray_getstringsize(unsigned char *str, int *w, int *h);
81void gray_putsxy(int x, int y, unsigned char *str, bool draw_bg, 328
82 int fg_brightness, int bg_brightness); 329/* Display text starting at (x, y) with the current font and drawinfo
330 *
331 * The drawmode is used as described for gray_set_drawmode()
332 */
333void gray_putsxy(int x, int y, unsigned char *str);
334
83#endif /* HAVE_LCD_BITMAP */ 335#endif /* HAVE_LCD_BITMAP */
84#endif /* SIMULATOR */ 336#endif /* SIMULATOR */
85#endif /* __GRAY_H__ */ 337#endif /* __GRAY_H__ */