diff options
author | Jens Arnold <amiconn@rockbox.org> | 2004-06-02 23:53:27 +0000 |
---|---|---|
committer | Jens Arnold <amiconn@rockbox.org> | 2004-06-02 23:53:27 +0000 |
commit | ca2bb463d3312f83afdd27d1098390bc6372a7da (patch) | |
tree | 4e212aa22b6592fa4ef18317378e966d751a498b /apps/plugins/lib | |
parent | 0600cb13f1bf693b067291a3c90d6bd42972b591 (diff) | |
download | rockbox-ca2bb463d3312f83afdd27d1098390bc6372a7da.tar.gz rockbox-ca2bb463d3312f83afdd27d1098390bc6372a7da.zip |
Major rework of the grayscale framework:
* api change - all drawing functions now use draw mode, foreground and
background shades set globally by separate functions
* There are now 4 draw modes for all drawing functions, no more separate
functions for inverse drawing
* Significant speedup of 1-bit bitmap (and font) drawing (2..3 times)
* Some more speed tweaks
* Additional functions for horizontal and vertical lines
* Copied describing comments to the header file for easier reference
* The safety net against an uninitialized grayscale buffer is gone
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4711 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/lib')
-rw-r--r-- | apps/plugins/lib/gray.c | 1263 | ||||
-rw-r--r-- | apps/plugins/lib/gray.h | 300 |
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 */ | ||
44 | typedef struct | 44 | typedef 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 | ||
61 | static struct plugin_api *rb = NULL; /* global api struct pointer */ | 64 | /** globals **/ |
62 | static tGraybuf *graybuf = NULL; | 65 | |
63 | static short gray_random_buffer; | 66 | static struct plugin_api *rb = NULL; /* global api struct pointer */ |
67 | static tGraybuf *graybuf = NULL; /* pointer to grayscale buffer */ | ||
68 | static short random_buffer; | ||
69 | |||
70 | /** prototypes **/ | ||
71 | |||
72 | static void _timer_isr(void); | ||
73 | |||
74 | static void _writepixel(int x, int y, unsigned long pattern); | ||
75 | static void _invertpixel(int x, int y, unsigned long pattern); | ||
76 | |||
77 | static void _writearray(unsigned char *address, unsigned char *src, int stride, | ||
78 | unsigned mask); | ||
79 | |||
80 | static void _writeblock(unsigned char *address, unsigned mask, unsigned bits); | ||
81 | static void _invertblock(unsigned char *address, unsigned mask, unsigned bits); | ||
82 | static void _writeblockfg(unsigned char *address, unsigned mask, unsigned bits); | ||
83 | static void _writeblockbg(unsigned char *address, unsigned mask, unsigned bits); | ||
84 | |||
85 | /** function pointer arrays **/ | ||
86 | |||
87 | static void (*_pixelfuncs[4])(int x, int y, unsigned long pattern) = { | ||
88 | _invertpixel, _writepixel, _writepixel, _writepixel | ||
89 | }; | ||
90 | |||
91 | static 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 */ |
66 | static void gray_timer_isr(void) | 99 | static 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 */ | 132 | static void _writepixel(int x, int y, unsigned long pattern) |
100 | static 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() | 265 | static void _invertpixel(int x, int y, unsigned long pattern) |
233 | * for larger rectangles and graymaps */ | 266 | { |
234 | static 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! */ | ||
338 | static 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. |
369 | static 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 */ | ||
497 | static 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 */ | ||
653 | asm ( | ||
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) */ | ||
666 | static 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 */ |
691 | static 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 */ |
697 | static 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 */ | ||
401 | void gray_init(struct plugin_api* newrb) | 708 | void 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 | */ |
545 | void gray_position_display(int x, int by) | 858 | void 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 | */ |
577 | void gray_show_display(bool enable) | 886 | void 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 | */ | ||
910 | void 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 | */ |
920 | void 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 | */ |
603 | void gray_clear_display(void) | 931 | void 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 | */ | ||
943 | void 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) */ | ||
953 | void 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 | */ | ||
613 | void gray_black_display(void) | 959 | void 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 | */ |
627 | void gray_deferred_update(void) | 971 | void 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) | |||
643 | void gray_scroll_left(int count, bool black_border) | 989 | void 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) | |||
711 | void gray_scroll_right(int count, bool black_border) | 1054 | void 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) | |||
778 | void gray_scroll_up8(bool black_border) | 1118 | void 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) | |||
818 | void gray_scroll_down8(bool black_border) | 1152 | void 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 | */ |
860 | void gray_scroll_up(int count, bool black_border) | 1188 | void 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 | */ |
963 | void gray_scroll_down(int count, bool black_border) | 1288 | void 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 | */ | ||
1060 | void 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 | */ |
1077 | void gray_invertpixel(int x, int y) | 1386 | void 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 | */ |
1091 | void gray_drawline(int x1, int y1, int x2, int y2, int brightness) | 1403 | void 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 | */ |
1175 | void gray_invertline(int x1, int y1, int x2, int y2) | 1486 | void 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 | */ |
1255 | void gray_drawrect(int x1, int y1, int x2, int y2, int brightness) | 1517 | void 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 | */ |
1314 | void gray_fillrect(int x1, int y1, int x2, int y2, int brightness) | 1570 | void 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 | */ |
1373 | void gray_invertrect(int x1, int y1, int x2, int y2) | 1598 | void 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 | */ |
1437 | void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny, | 1661 | void 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 | */ |
1503 | void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny, | 1733 | void 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 | */ |
1558 | void gray_setfont(int newfont) | 1802 | void 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 | */ |
1597 | void gray_putsxy(int x, int y, unsigned char *str, bool draw_bg, | 1840 | void 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 */ | ||
36 | void gray_init(struct plugin_api* newrb); | 38 | void 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 | */ | ||
39 | int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width, | 72 | int 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 | */ | ||
41 | void gray_release_buffer(void); | 82 | void 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 | */ | ||
42 | void gray_position_display(int x, int by); | 97 | void 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 | */ | ||
43 | void gray_show_display(bool enable); | 118 | void 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 | */ | ||
129 | void 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 | */ | ||
141 | void gray_set_foreground(int brightness); | ||
142 | |||
143 | /* Set the background shade for subsequent drawing operations | ||
144 | * | ||
145 | * brightness = 0 (black) .. 255 (white) | ||
146 | */ | ||
147 | void 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 | */ | ||
154 | void 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) */ | ||
46 | void gray_clear_display(void); | 159 | void gray_clear_display(void); |
160 | |||
161 | /* Set the grayscale display to all black */ | ||
47 | void gray_black_display(void); | 162 | void 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 | */ | ||
48 | void gray_deferred_update(void); | 171 | void 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 | */ | ||
51 | void gray_scroll_left(int count, bool black_border); | 183 | void 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 | */ | ||
52 | void gray_scroll_right(int count, bool black_border); | 193 | void 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 | */ | ||
53 | void gray_scroll_up8(bool black_border); | 202 | void 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 | */ | ||
54 | void gray_scroll_down8(bool black_border); | 211 | void 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 | */ | ||
55 | void gray_scroll_up(int count, bool black_border); | 222 | void 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 | */ | ||
56 | void gray_scroll_down(int count, bool black_border); | 233 | void gray_scroll_down(int count, bool black_border); |
57 | 234 | ||
58 | /* pixel functions */ | 235 | /**** Pixel and line functions ****/ |
59 | void gray_drawpixel(int x, int y, int brightness); | 236 | |
60 | void 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 | */ | ||
243 | void 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 | */ | ||
248 | void 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 | */ | ||
253 | void 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 | */ | ||
260 | void 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 | */ | ||
267 | void gray_drawrect(int x, int y, int nx, int ny); | ||
61 | 268 | ||
62 | /* line functions */ | 269 | /* Draw a filled rectangle with the current drawinfo, |
63 | void gray_drawline(int x1, int y1, int x2, int y2, int brightness); | 270 | * See gray_drawpixel() for details |
64 | void 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 | */ | ||
274 | void gray_fillrect(int x, int y, int nx, int ny); | ||
65 | 275 | ||
66 | /* rectangle functions */ | 276 | /**** Bitmap functions ****/ |
67 | void gray_drawrect(int x1, int y1, int x2, int y2, int brightness); | ||
68 | void gray_fillrect(int x1, int y1, int x2, int y2, int brightness); | ||
69 | void 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 | */ | ||
72 | void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny, | 288 | void 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 | */ | ||
74 | void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny, | 309 | void 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 | */ | ||
79 | void gray_setfont(int newfont); | 319 | void 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 | */ | ||
80 | int gray_getstringsize(unsigned char *str, int *w, int *h); | 327 | int gray_getstringsize(unsigned char *str, int *w, int *h); |
81 | void 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 | */ | ||
333 | void 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__ */ |