summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2004-05-19 08:05:58 +0000
committerDaniel Stenberg <daniel@haxx.se>2004-05-19 08:05:58 +0000
commitf4b52b82eaa29ddddf52474cdc995af24080f933 (patch)
treea411e2f0009fdb55a80ae97132018d35eecabaff /apps/plugins
parenta08fa7142a6654ca227ade464c7af61b521b791e (diff)
downloadrockbox-f4b52b82eaa29ddddf52474cdc995af24080f933.tar.gz
rockbox-f4b52b82eaa29ddddf52474cdc995af24080f933.zip
o removed the grayscale framework, it gets linked in from the libplugin instead
o use the grayscale.h header o killed trailing whitespace git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4640 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/jpeg.c1679
1 files changed, 50 insertions, 1629 deletions
diff --git a/apps/plugins/jpeg.c b/apps/plugins/jpeg.c
index 002012ca8c..556972f768 100644
--- a/apps/plugins/jpeg.c
+++ b/apps/plugins/jpeg.c
@@ -27,1591 +27,12 @@
27#include "plugin.h" 27#include "plugin.h"
28 28
29#ifdef HAVE_LCD_BITMAP /* and also not for the Player */ 29#ifdef HAVE_LCD_BITMAP /* and also not for the Player */
30#include "grayscale.h"
30 31
31/******************************* Globals ***********************************/ 32/******************************* Globals ***********************************/
32 33
33static struct plugin_api* rb; 34static struct plugin_api* rb;
34 35
35/*********************** Begin grayscale framework *************************/
36
37/* This is a generic framework to use grayscale display within rockbox
38 * plugins. It obviously does not work for the player.
39 *
40 * If you want to use grayscale display within a plugin, copy this section
41 * (up to "End grayscale framework") into your source and you are able to use
42 * it. For detailed documentation look at the head of each public function.
43 *
44 * It requires a global Rockbox api pointer in "rb" and uses the rockbox
45 * timer api so you cannot use that timer for other purposes while
46 * displaying grayscale.
47 *
48 * The framework consists of 3 sections:
49 *
50 * - internal core functions and definitions
51 * - public core functions
52 * - public optional functions
53 *
54 * Usually you will use functions from the latter two sections in your code.
55 * You can cut out functions from the third section that you do not need in
56 * order to not waste space. Don't forget to cut the prototype as well.
57 */
58
59/**** internal core functions and definitions ****/
60
61/* You do not want to touch these if you don't know exactly what you're
62 * doing. */
63
64#define GRAY_RUNNING 0x0001 /* grayscale overlay is running */
65#define GRAY_DEFERRED_UPDATE 0x0002 /* lcd_update() requested */
66
67/* unsigned 16 bit multiplication (a single instruction on the SH) */
68#define MULU16(a, b) (((unsigned short) (a)) * ((unsigned short) (b)))
69
70typedef struct
71{
72 int x;
73 int by; /* 8-pixel units */
74 int width;
75 int height;
76 int bheight; /* 8-pixel units */
77 int plane_size;
78 int depth; /* number_of_bitplanes = (number_of_grayscales - 1) */
79 int cur_plane; /* for the timer isr */
80 unsigned long randmask; /* mask for random value in graypixel() */
81 unsigned long flags; /* various flags, see #defines */
82 unsigned char *data; /* pointer to start of bitplane data */
83 unsigned long *bitpattern; /* pointer to start of pattern table */
84} tGraybuf;
85
86static tGraybuf *graybuf = NULL;
87static short gray_random_buffer;
88
89/** prototypes **/
90
91void gray_timer_isr(void);
92void graypixel(int x, int y, unsigned long pattern);
93void grayblock(int x, int by, unsigned char* src, int stride);
94void grayinvertmasked(int x, int by, unsigned char mask);
95
96/** implementation **/
97
98/* timer interrupt handler: display next bitplane */
99void gray_timer_isr(void)
100{
101 rb->lcd_blit(graybuf->data + MULU16(graybuf->plane_size, graybuf->cur_plane),
102 graybuf->x, graybuf->by, graybuf->width, graybuf->bheight,
103 graybuf->width);
104
105 if (++graybuf->cur_plane >= graybuf->depth)
106 graybuf->cur_plane = 0;
107
108 if (graybuf->flags & GRAY_DEFERRED_UPDATE) /* lcd_update() requested? */
109 {
110 int x1 = MAX(graybuf->x, 0);
111 int x2 = MIN(graybuf->x + graybuf->width, LCD_WIDTH);
112 int y1 = MAX(graybuf->by << 3, 0);
113 int y2 = MIN((graybuf->by + graybuf->bheight) << 3, LCD_HEIGHT);
114
115 if (y1 > 0) /* refresh part above overlay, full width */
116 rb->lcd_update_rect(0, 0, LCD_WIDTH, y1);
117
118 if (y2 < LCD_HEIGHT) /* refresh part below overlay, full width */
119 rb->lcd_update_rect(0, y2, LCD_WIDTH, LCD_HEIGHT - y2);
120
121 if (x1 > 0) /* refresh part to the left of overlay */
122 rb->lcd_update_rect(0, y1, x1, y2 - y1);
123
124 if (x2 < LCD_WIDTH) /* refresh part to the right of overlay */
125 rb->lcd_update_rect(x2, y1, LCD_WIDTH - x2, y2 - y1);
126
127 graybuf->flags &= ~GRAY_DEFERRED_UPDATE; /* clear request */
128 }
129}
130
131/* Set a pixel to a specific bit pattern
132 * This is the fundamental graphics primitive, asm optimized */
133void graypixel(int x, int y, unsigned long pattern)
134{
135 register long address, mask, random;
136
137 /* Some (pseudo-)random function must be used here to shift the bit
138 * pattern randomly, otherwise you would get flicker and/or moire.
139 * Since rand() is relatively slow, I've implemented a simple, but very
140 * fast pseudo-random generator based on linear congruency in assembler.
141 * It delivers 16 pseudo-random bits in each iteration. */
142
143 /* simple but fast pseudo-random generator */
144 asm(
145 "mov.w @%1,%0 \n" /* load last value */
146 "mov #75,r1 \n"
147 "mulu %0,r1 \n" /* multiply by 75 */
148 "sts macl,%0 \n" /* get result */
149 "add #74,%0 \n" /* add another 74 */
150 "mov.w %0,@%1 \n" /* store new value */
151 /* Since the lower bits are not very random: */
152 "shlr8 %0 \n" /* get bits 8..15 (need max. 5) */
153 "and %2,%0 \n" /* mask out unneeded bits */
154 : /* outputs */
155 /* %0 */ "=&r"(random)
156 : /* inputs */
157 /* %1 */ "r"(&gray_random_buffer),
158 /* %2 */ "r"(graybuf->randmask)
159 : /* clobbers */
160 "r1","macl"
161 );
162
163 /* precalculate mask and byte address in first bitplane */
164 asm(
165 "mov %3,%0 \n" /* take y as base for address offset */
166 "shlr2 %0 \n" /* shift right by 3 (= divide by 8) */
167 "shlr %0 \n"
168 "mulu %0,%2 \n" /* multiply with width */
169 "and #7,%3 \n" /* get lower 3 bits of y */
170 "sts macl,%0 \n" /* get mulu result */
171 "add %4,%0 \n" /* add base + x to get final address */
172
173 "mov %3,%1 \n" /* move lower 3 bits of y out of r0 */
174 "mova .pp_table,%3 \n" /* get address of mask table in r0 */
175 "bra .pp_end \n" /* skip the table */
176 "mov.b @(%3,%1),%1 \n" /* get entry from mask table */
177
178 ".align 2 \n"
179 ".pp_table: \n" /* mask table */
180 ".byte 0x01 \n"
181 ".byte 0x02 \n"
182 ".byte 0x04 \n"
183 ".byte 0x08 \n"
184 ".byte 0x10 \n"
185 ".byte 0x20 \n"
186 ".byte 0x40 \n"
187 ".byte 0x80 \n"
188
189 ".pp_end: \n"
190 : /* outputs */
191 /* %0 */ "=&r"(address),
192 /* %1 */ "=&r"(mask)
193 : /* inputs */
194 /* %2 */ "r"(graybuf->width),
195 /* %3 = r0 */ "z"(y),
196 /* %4 */ "r"(graybuf->data + x)
197 : /* clobbers */
198 "macl"
199 );
200
201 /* the hard part: set bits in all bitplanes according to pattern */
202 asm(
203 "cmp/hs %1,%5 \n" /* random >= depth ? */
204 "bf .p_ntrim \n"
205 "sub %1,%5 \n" /* yes: random -= depth */
206 /* it's sufficient to do this once, since the mask guarantees
207 * random < 2 * depth */
208 ".p_ntrim: \n"
209
210 /* calculate some addresses */
211 "mulu %4,%1 \n" /* end address offset */
212 "not %3,r1 \n" /* get inverse mask (for "and") */
213 "sts macl,%1 \n" /* result of mulu */
214 "mulu %4,%5 \n" /* address offset of <random>'th plane */
215 "add %2,%1 \n" /* end offset -> end address */
216 "sts macl,%5 \n" /* result of mulu */
217 "add %2,%5 \n" /* address of <random>'th plane */
218 "bra .p_start1 \n"
219 "mov %5,r2 \n" /* copy address */
220
221 /* first loop: set bits from <random>'th bitplane to last */
222 ".p_loop1: \n"
223 "mov.b @r2,r3 \n" /* get data byte */
224 "shlr %0 \n" /* shift bit mask, sets t bit */
225 "and r1,r3 \n" /* reset bit (-> "white") */
226 "bf .p_white1 \n" /* t=0? -> "white" bit */
227 "or %3,r3 \n" /* set bit ("black" bit) */
228 ".p_white1: \n"
229 "mov.b r3,@r2 \n" /* store data byte */
230 "add %4,r2 \n" /* advance address to next bitplane */
231 ".p_start1: \n"
232 "cmp/hi r2,%1 \n" /* address < end address ? */
233 "bt .p_loop1 \n"
234
235 "bra .p_start2 \n"
236 "nop \n"
237
238 /* second loop: set bits from first to <random-1>'th bitplane
239 * Bit setting works the other way round here to equalize average
240 * execution times for bright and dark pixels */
241 ".p_loop2: \n"
242 "mov.b @%2,r3 \n" /* get data byte */
243 "shlr %0 \n" /* shift bit mask, sets t bit */
244 "or %3,r3 \n" /* set bit (-> "black") */
245 "bt .p_black2 \n" /* t=1? -> "black" bit */
246 "and r1,r3 \n" /* reset bit ("white" bit) */
247 ".p_black2: \n"
248 "mov.b r3,@%2 \n" /* store data byte */
249 "add %4,%2 \n" /* advance address to next bitplane */
250 ".p_start2: \n"
251 "cmp/hi %2,%5 \n" /* address < <random>'th address ? */
252 "bt .p_loop2 \n"
253 : /* outputs */
254 : /* inputs */
255 /* %0 */ "r"(pattern),
256 /* %1 */ "r"(graybuf->depth),
257 /* %2 */ "r"(address),
258 /* %3 */ "r"(mask),
259 /* %4 */ "r"(graybuf->plane_size),
260 /* %5 */ "r"(random)
261 : /* clobbers */
262 "r1", "r2", "r3", "macl"
263 );
264}
265
266/* Set 8 pixels to specific gray values at once, asm optimized
267 * This greatly enhances performance of gray_fillrect() and gray_drawgraymap()
268 * for larger rectangles and graymaps */
269void grayblock(int x, int by, unsigned char* src, int stride)
270{
271 /* precalculate the bit patterns with random shifts (same RNG as graypixel,
272 * see there for an explanation) for all 8 pixels and put them on the
273 * stack (!) */
274 asm(
275 "mova .gb_reload,r0 \n" /* set default loopback address */
276 "tst %1,%1 \n" /* stride == 0 ? */
277 "bf .gb_needreload \n" /* no: keep that address */
278 "mova .gb_reuse,r0 \n" /* yes: set shortcut (no reload) */
279 ".gb_needreload: \n"
280 "mov r0,r2 \n" /* loopback address to r2 */
281 "mov #7,r3 \n" /* loop count in r3: 8 pixels */
282
283 ".align 2 \n" /** load pattern for pixel **/
284 ".gb_reload: \n"
285 "mov.b @%0,r0 \n" /* load src byte */
286 "extu.b r0,r0 \n" /* extend unsigned */
287 "mulu %2,r0 \n" /* macl = byte * depth; */
288 "add %1,%0 \n" /* src += stride; */
289 "sts macl,r4 \n" /* r4 = macl; */
290 "add r4,r0 \n" /* byte += r4; */
291 "shlr8 r0 \n" /* byte >>= 8; */
292 "shll2 r0 \n"
293 "mov.l @(r0,%3),r4 \n" /* r4 = bitpattern[byte]; */
294
295 ".align 2 \n" /** RNG **/
296 ".gb_reuse: \n"
297 "mov.w @%4,r1 \n" /* load last value */
298 "mov #75,r0 \n"
299 "mulu r0,r1 \n" /* multiply by 75 */
300 "sts macl,r1 \n"
301 "add #74,r1 \n" /* add another 74 */
302 "mov.w r1,@%4 \n" /* store new value */
303 /* Since the lower bits are not very random: */
304 "shlr8 r1 \n" /* get bits 8..15 (need max. 5) */
305 "and %5,r1 \n" /* mask out unneeded bits */
306
307 "cmp/hs %2,r1 \n" /* random >= depth ? */
308 "bf .gb_ntrim \n"
309 "sub %2,r1 \n" /* yes: random -= depth; */
310 ".gb_ntrim: \n"
311
312 "mov.l .ashlsi3,r0 \n" /** rotate pattern **/
313 "jsr @r0 \n" /* shift r4 left by r1 */
314 "mov r1,r5 \n"
315
316 "mov %2,r5 \n"
317 "sub r1,r5 \n" /* r5 = depth - r1 */
318 "mov.l .lshrsi3,r1 \n"
319 "jsr @r1 \n" /* shift r4 right by r5 */
320 "mov r0,r1 \n" /* last result stored in r1 */
321
322 "or r1,r0 \n" /* rotated_pattern = r0 | r1 */
323 "mov.l r0,@-r15 \n" /* push pattern */
324
325 "cmp/pl r3 \n" /* loop count > 0? */
326 "bf .gb_patdone \n" /* no: done */
327
328 "jmp @r2 \n" /* yes: loop */
329 "add #-1,r3 \n" /* decrease loop count */
330
331 ".align 2 \n"
332 ".ashlsi3: \n" /* C library routine: */
333 ".long ___ashlsi3 \n" /* shift r4 left by r5, return in r0 */
334 ".lshrsi3: \n" /* C library routine: */
335 ".long ___lshrsi3 \n" /* shift r4 right by r5, return in r0 */
336 /* both routines preserve r4, destroy r5 and take ~16 cycles */
337
338 ".gb_patdone: \n"
339 : /* outputs */
340 : /* inputs */
341 /* %0 */ "r"(src),
342 /* %1 */ "r"(stride),
343 /* %2 */ "r"(graybuf->depth),
344 /* %3 */ "r"(graybuf->bitpattern),
345 /* %4 */ "r"(&gray_random_buffer),
346 /* %5 */ "r"(graybuf->randmask)
347 : /* clobbers */
348 "r0", "r1", "r2", "r3", "r4", "r5", "macl"
349 );
350
351 /* calculate start address in first bitplane and end address */
352 register unsigned char *address = graybuf->data + x
353 + MULU16(graybuf->width, by);
354 register unsigned char *end_addr = address
355 + MULU16(graybuf->depth, graybuf->plane_size);
356
357 /* set the bits for all 8 pixels in all bytes according to the
358 * precalculated patterns on the stack */
359 asm (
360 "mov.l @r15+,r1 \n" /* pop all 8 patterns */
361 "mov.l @r15+,r2 \n"
362 "mov.l @r15+,r3 \n"
363 "mov.l @r15+,r4 \n"
364 "mov.l @r15+,r5 \n"
365 "mov.l @r15+,r6 \n"
366 "mov.l @r15+,r7 \n"
367 "mov.l @r15+,r8 \n"
368
369 ".gb_loop: \n" /* loop for all bitplanes */
370 "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */
371 "rotcl r0 \n" /* rotate t bit into r0 */
372 "shlr r2 \n"
373 "rotcl r0 \n"
374 "shlr r3 \n"
375 "rotcl r0 \n"
376 "shlr r4 \n"
377 "rotcl r0 \n"
378 "shlr r5 \n"
379 "rotcl r0 \n"
380 "shlr r6 \n"
381 "rotcl r0 \n"
382 "shlr r7 \n"
383 "rotcl r0 \n"
384 "shlr r8 \n"
385 "rotcl r0 \n"
386 "mov.b r0,@%0 \n" /* store byte to bitplane */
387 "add %2,%0 \n" /* advance to next bitplane */
388 "cmp/hi %0,%1 \n" /* last bitplane done? */
389 "bt .gb_loop \n" /* no: loop */
390 : /* outputs */
391 : /* inputs */
392 /* %0 */ "r"(address),
393 /* %1 */ "r"(end_addr),
394 /* %2 */ "r"(graybuf->plane_size)
395 : /* clobbers */
396 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8"
397 );
398}
399
400/* Invert the bits for 1-8 pixels within the buffer */
401void grayinvertmasked(int x, int by, unsigned char mask)
402{
403 asm(
404 "mulu %4,%5 \n" /* width * by (offset of row) */
405 "mov #0,r1 \n" /* current_plane = 0 */
406 "sts macl,r2 \n" /* get mulu result */
407 "add r2,%1 \n" /* -> address in 1st bitplane */
408
409 ".i_loop: \n"
410 "mov.b @%1,r2 \n" /* get data byte */
411 "add #1,r1 \n" /* current_plane++; */
412 "xor %2,r2 \n" /* invert bits */
413 "mov.b r2,@%1 \n" /* store data byte */
414 "add %3,%1 \n" /* advance address to next bitplane */
415 "cmp/hi r1,%0 \n" /* current_plane < depth ? */
416 "bt .i_loop \n"
417 : /* outputs */
418 : /* inputs */
419 /* %0 */ "r"(graybuf->depth),
420 /* %1 */ "r"(graybuf->data + x),
421 /* %2 */ "r"(mask),
422 /* %3 */ "r"(graybuf->plane_size),
423 /* %4 */ "r"(graybuf->width),
424 /* %5 */ "r"(by)
425 : /* clobbers */
426 "r1", "r2", "macl"
427 );
428}
429
430/*** public core functions ***/
431
432/** prototypes **/
433
434int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
435 int bheight, int depth);
436void gray_release_buffer(void);
437void gray_position_display(int x, int by);
438void gray_show_display(bool enable);
439
440/** implementation **/
441
442/* Prepare the grayscale display buffer
443 *
444 * arguments:
445 * gbuf = pointer to the memory area to use (e.g. plugin buffer)
446 * gbuf_size = max usable size of the buffer
447 * width = width in pixels (1..112)
448 * bheight = height in 8-pixel units (1..8)
449 * depth = desired number of shades - 1 (1..32)
450 *
451 * result:
452 * = depth if there was enough memory
453 * < depth if there wasn't enough memory. The number of displayable
454 * shades is smaller than desired, but it still works
455 * = 0 if there wasn't even enough memory for 1 bitplane (black & white)
456 *
457 * You can request any depth from 1 to 32, not just powers of 2. The routine
458 * performs "graceful degradation" if the memory is not sufficient for the
459 * desired depth. As long as there is at least enough memory for 1 bitplane,
460 * it creates as many bitplanes as fit into memory, although 1 bitplane will
461 * only deliver black & white display.
462 *
463 * The total memory needed can be calculated as follows:
464 * total_mem =
465 * sizeof(tGraymap) (= 48 bytes currently)
466 * + sizeof(long) (= 4 bytes)
467 * + (width * bheight + sizeof(long)) * depth
468 * + 0..3 (longword alignment of grayscale display buffer)
469 */
470int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
471 int bheight, int depth)
472{
473 int possible_depth, plane_size;
474 int i, j;
475
476 if ((unsigned) width > LCD_WIDTH
477 || (unsigned) bheight > (LCD_HEIGHT >> 3)
478 || depth < 1)
479 return 0;
480
481 while ((unsigned long)gbuf & 3) /* the buffer has to be long aligned */
482 {
483 gbuf++;
484 gbuf_size--;
485 }
486
487 plane_size = width * bheight;
488 possible_depth = (gbuf_size - sizeof(tGraybuf) - sizeof(unsigned long))
489 / (plane_size + sizeof(unsigned long));
490
491 if (possible_depth < 1)
492 return 0;
493
494 depth = MIN(depth, 32);
495 depth = MIN(depth, possible_depth);
496
497 graybuf = (tGraybuf *) gbuf; /* global pointer to buffer structure */
498
499 graybuf->x = 0;
500 graybuf->by = 0;
501 graybuf->width = width;
502 graybuf->height = bheight << 3;
503 graybuf->bheight = bheight;
504 graybuf->plane_size = plane_size;
505 graybuf->depth = depth;
506 graybuf->cur_plane = 0;
507 graybuf->flags = 0;
508 graybuf->data = gbuf + sizeof(tGraybuf);
509 graybuf->bitpattern = (unsigned long *) (graybuf->data
510 + depth * plane_size);
511
512 i = depth;
513 j = 8;
514 while (i != 0)
515 {
516 i >>= 1;
517 j--;
518 }
519 graybuf->randmask = 0xFF >> j;
520
521 /* initial state is all white */
522 rb->memset(graybuf->data, 0, depth * plane_size);
523
524 /* Precalculate the bit patterns for all possible pixel values */
525 for (i = 0; i <= depth; i++)
526 {
527 unsigned long pattern = 0;
528 int value = 0;
529
530 for (j = 0; j < depth; j++)
531 {
532 pattern <<= 1;
533 value += i;
534
535 if (value >= depth)
536 value -= depth; /* "white" bit */
537 else
538 pattern |= 1; /* "black" bit */
539 }
540 /* now the lower <depth> bits contain the pattern */
541
542 graybuf->bitpattern[i] = pattern;
543 }
544
545 return depth;
546}
547
548/* Release the grayscale display buffer
549 *
550 * Switches the grayscale overlay off at first if it is still running,
551 * then sets the pointer to NULL.
552 * DO CALL either this function or at least gray_show_display(false)
553 * before you exit, otherwise nasty things may happen.
554 */
555void gray_release_buffer(void)
556{
557 gray_show_display(false);
558 graybuf = NULL;
559}
560
561/* Set position of the top left corner of the grayscale overlay
562 *
563 * arguments:
564 * x = left margin in pixels
565 * by = top margin in 8-pixel units
566 *
567 * You may set this in a way that the overlay spills across the right or
568 * bottom display border. In this case it will simply be clipped by the
569 * LCD controller. You can even set negative values, this will clip at the
570 * left or top border. I did not test it, but the limits may be +127 / -128
571 *
572 * If you use this while the grayscale overlay is running, the now-freed area
573 * will be restored.
574 */
575void gray_position_display(int x, int by)
576{
577 if (graybuf == NULL)
578 return;
579
580 graybuf->x = x;
581 graybuf->by = by;
582
583 if (graybuf->flags & GRAY_RUNNING)
584 graybuf->flags |= GRAY_DEFERRED_UPDATE;
585}
586
587/* Switch the grayscale overlay on or off
588 *
589 * arguments:
590 * enable = true: the grayscale overlay is switched on if initialized
591 * = false: the grayscale overlay is switched off and the regular lcd
592 * content is restored
593 *
594 * DO NOT call lcd_update() or any other api function that directly accesses
595 * the lcd while the grayscale overlay is running! If you need to do
596 * lcd_update() to update something outside the grayscale overlay area, use
597 * gray_deferred_update() instead.
598 *
599 * Other functions to avoid are:
600 * lcd_blit() (obviously), lcd_update_rect(), lcd_set_contrast(),
601 * lcd_set_invert_display(), lcd_set_flip(), lcd_roll()
602 *
603 * The grayscale display consumes ~50 % CPU power (for a full screen overlay,
604 * less if the overlay is smaller) when switched on. You can switch the overlay
605 * on and off as many times as you want.
606 */
607void gray_show_display(bool enable)
608{
609 if (graybuf == NULL)
610 return;
611
612 if (enable)
613 {
614 graybuf->flags |= GRAY_RUNNING;
615 rb->plugin_register_timer(FREQ / 67, 1, gray_timer_isr);
616 }
617 else
618 {
619 rb->plugin_unregister_timer();
620 graybuf->flags &= ~GRAY_RUNNING;
621 rb->lcd_update(); /* restore whatever there was before */
622 }
623}
624
625/*** public optional functions ***/
626
627/* Here are the various graphics primitives. Cut out functions you do not
628 * need in order to keep plugin code size down.
629 */
630
631/** prototypes **/
632
633/* functions affecting the whole display */
634void gray_clear_display(void);
635void gray_black_display(void);
636void gray_deferred_update(void);
637
638/* scrolling functions */
639void gray_scroll_left(int count, bool black_border);
640void gray_scroll_right(int count, bool black_border);
641void gray_scroll_up8(bool black_border);
642void gray_scroll_down8(bool black_border);
643void gray_scroll_up(int count, bool black_border);
644void gray_scroll_down(int count, bool black_border);
645
646/* pixel functions */
647void gray_drawpixel(int x, int y, int brightness);
648void gray_invertpixel(int x, int y);
649
650/* line functions */
651void gray_drawline(int x1, int y1, int x2, int y2, int brightness);
652void gray_invertline(int x1, int y1, int x2, int y2);
653
654/* rectangle functions */
655void gray_drawrect(int x1, int y1, int x2, int y2, int brightness);
656void gray_fillrect(int x1, int y1, int x2, int y2, int brightness);
657void gray_invertrect(int x1, int y1, int x2, int y2);
658
659/* bitmap functions */
660void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny,
661 int stride);
662void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
663 int stride, bool draw_bg, int fg_brightness,
664 int bg_brightness);
665
666/** implementation **/
667
668/* Clear the grayscale display (sets all pixels to white)
669 */
670void gray_clear_display(void)
671{
672 if (graybuf == NULL)
673 return;
674
675 rb->memset(graybuf->data, 0, MULU16(graybuf->depth, graybuf->plane_size));
676}
677
678/* Set the grayscale display to all black
679 */
680void gray_black_display(void)
681{
682 if (graybuf == NULL)
683 return;
684
685 rb->memset(graybuf->data, 0xFF, MULU16(graybuf->depth, graybuf->plane_size));
686}
687
688/* Do an lcd_update() to show changes done by rb->lcd_xxx() functions (in areas
689 * of the screen not covered by the grayscale overlay). If the grayscale
690 * overlay is running, the update will be done in the next call of the
691 * interrupt routine, otherwise it will be performed right away. See also
692 * comment for the gray_show_display() function.
693 */
694void gray_deferred_update(void)
695{
696 if (graybuf != NULL && (graybuf->flags & GRAY_RUNNING))
697 graybuf->flags |= GRAY_DEFERRED_UPDATE;
698 else
699 rb->lcd_update();
700}
701
702/* Scroll the whole grayscale buffer left by <count> pixels
703 *
704 * black_border determines if the pixels scrolled in at the right are black
705 * or white
706 *
707 * Scrolling left/right by an even pixel count is almost twice as fast as
708 * scrolling by an odd pixel count.
709 */
710void gray_scroll_left(int count, bool black_border)
711{
712 int by, d;
713 unsigned char *ptr;
714 unsigned char filler;
715
716 if (graybuf == NULL || (unsigned) count >= (unsigned) graybuf->width)
717 return;
718
719 if (black_border)
720 filler = 0xFF;
721 else
722 filler = 0;
723
724 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
725 for (by = 0; by < graybuf->bheight; by++)
726 {
727 ptr = graybuf->data + MULU16(graybuf->width, by);
728 for (d = 0; d < graybuf->depth; d++)
729 {
730 if (count & 1) /* odd count: scroll byte-wise */
731 asm volatile (
732 ".sl_loop1: \n"
733 "mov.b @%0+,r1 \n"
734 "mov.b r1,@(%2,%0) \n"
735 "cmp/hi %0,%1 \n"
736 "bt .sl_loop1 \n"
737 : /* outputs */
738 : /* inputs */
739 /* %0 */ "r"(ptr + count),
740 /* %1 */ "r"(ptr + graybuf->width),
741 /* %2 */ "z"(-count - 1)
742 : /* clobbers */
743 "r1"
744 );
745 else /* even count: scroll word-wise */
746 asm volatile (
747 ".sl_loop2: \n"
748 "mov.w @%0+,r1 \n"
749 "mov.w r1,@(%2,%0) \n"
750 "cmp/hi %0,%1 \n"
751 "bt .sl_loop2 \n"
752 : /* outputs */
753 : /* inputs */
754 /* %0 */ "r"(ptr + count),
755 /* %1 */ "r"(ptr + graybuf->width),
756 /* %2 */ "z"(-count - 2)
757 : /* clobbers */
758 "r1"
759 );
760
761 rb->memset(ptr + graybuf->width - count, filler, count);
762 ptr += graybuf->plane_size;
763 }
764 }
765}
766
767/* Scroll the whole grayscale buffer right by <count> pixels
768 *
769 * black_border determines if the pixels scrolled in at the left are black
770 * or white
771 *
772 * Scrolling left/right by an even pixel count is almost twice as fast as
773 * scrolling by an odd pixel count.
774 */
775void gray_scroll_right(int count, bool black_border)
776{
777 int by, d;
778 unsigned char *ptr;
779 unsigned char filler;
780
781 if (graybuf == NULL || (unsigned) count >= (unsigned) graybuf->width)
782 return;
783
784 if (black_border)
785 filler = 0xFF;
786 else
787 filler = 0;
788
789 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
790 for (by = 0; by < graybuf->bheight; by++)
791 {
792 ptr = graybuf->data + MULU16(graybuf->width, by);
793 for (d = 0; d < graybuf->depth; d++)
794 {
795 if (count & 1) /* odd count: scroll byte-wise */
796 asm volatile (
797 ".sr_loop1: \n"
798 "mov.b @(%2,%0),r1 \n"
799 "mov.b r1,@-%0 \n"
800 "cmp/hi %1,%0 \n"
801 "bt .sr_loop1 \n"
802 : /* outputs */
803 : /* inputs */
804 /* %0 */ "r"(ptr + graybuf->width),
805 /* %1 */ "r"(ptr + count),
806 /* %2 */ "z"(-count - 1)
807 : /* clobbers */
808 "r1"
809 );
810 else /* even count: scroll word-wise */
811 asm volatile (
812 ".sr_loop2: \n"
813 "mov.w @(%2,%0),r1 \n"
814 "mov.w r1,@-%0 \n"
815 "cmp/hi %1,%0 \n"
816 "bt .sr_loop2 \n"
817 : /* outputs */
818 : /* inputs */
819 /* %0 */ "r"(ptr + graybuf->width),
820 /* %1 */ "r"(ptr + count),
821 /* %2 */ "z"(-count - 2)
822 : /* clobbers */
823 "r1"
824 );
825
826 rb->memset(ptr, filler, count);
827 ptr += graybuf->plane_size;
828 }
829 }
830}
831
832/* Scroll the whole grayscale buffer up by 8 pixels
833 *
834 * black_border determines if the pixels scrolled in at the bottom are black
835 * or white
836 *
837 * Scrolling up/down by 8 pixels is very fast.
838 */
839void gray_scroll_up8(bool black_border)
840{
841 int by, d;
842 unsigned char *ptr;
843 unsigned char filler;
844
845 if (graybuf == NULL)
846 return;
847
848 if (black_border)
849 filler = 0xFF;
850 else
851 filler = 0;
852
853 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
854 for (by = 1; by < graybuf->bheight; by++)
855 {
856 ptr = graybuf->data + MULU16(graybuf->width, by);
857 for (d = 0; d < graybuf->depth; d++)
858 {
859 rb->memcpy(ptr - graybuf->width, ptr, graybuf->width);
860 ptr += graybuf->plane_size;
861 }
862 }
863 /* fill last row */
864 ptr = graybuf->data + graybuf->plane_size - graybuf->width;
865 for (d = 0; d < graybuf->depth; d++)
866 {
867 rb->memset(ptr, filler, graybuf->width);
868 ptr += graybuf->plane_size;
869 }
870}
871
872/* Scroll the whole grayscale buffer down by 8 pixels
873 *
874 * black_border determines if the pixels scrolled in at the top are black
875 * or white
876 *
877 * Scrolling up/down by 8 pixels is very fast.
878 */
879void gray_scroll_down8(bool black_border)
880{
881 int by, d;
882 unsigned char *ptr;
883 unsigned char filler;
884
885 if (graybuf == NULL)
886 return;
887
888 if (black_border)
889 filler = 0xFF;
890 else
891 filler = 0;
892
893 /* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
894 for (by = graybuf->bheight - 1; by > 0; by--)
895 {
896 ptr = graybuf->data + MULU16(graybuf->width, by);
897 for (d = 0; d < graybuf->depth; d++)
898 {
899 rb->memcpy(ptr, ptr - graybuf->width, graybuf->width);
900 ptr += graybuf->plane_size;
901 }
902 }
903 /* fill first row */
904 ptr = graybuf->data;
905 for (d = 0; d < graybuf->depth; d++)
906 {
907 rb->memset(ptr, filler, graybuf->width);
908 ptr += graybuf->plane_size;
909 }
910}
911
912/* Scroll the whole grayscale buffer up by <count> pixels (<= 7)
913 *
914 * black_border determines if the pixels scrolled in at the bottom are black
915 * or white
916 *
917 * Scrolling up/down pixel-wise is significantly slower than scrolling
918 * left/right or scrolling up/down byte-wise because it involves bit
919 * shifting. That's why it is asm optimized.
920 */
921void gray_scroll_up(int count, bool black_border)
922{
923 unsigned long filler;
924
925 if (graybuf == NULL || (unsigned) count > 7)
926 return;
927
928 if (black_border)
929 filler = 0xFF;
930 else
931 filler = 0;
932
933 /* scroll column by column to minimize flicker */
934 asm(
935 "mov #0,r6 \n" /* x = 0 */
936 "mova .su_shifttbl,r0 \n" /* calculate jump destination for */
937 "mov.b @(r0,%6),%6 \n" /* shift amount from table */
938 "bra .su_cloop \n" /* skip table */
939 "add r0,%6 \n"
940
941 ".align 2 \n"
942 ".su_shifttbl: \n" /* shift jump offset table */
943 ".byte .su_shift0 - .su_shifttbl \n"
944 ".byte .su_shift1 - .su_shifttbl \n"
945 ".byte .su_shift2 - .su_shifttbl \n"
946 ".byte .su_shift3 - .su_shifttbl \n"
947 ".byte .su_shift4 - .su_shifttbl \n"
948 ".byte .su_shift5 - .su_shifttbl \n"
949 ".byte .su_shift6 - .su_shifttbl \n"
950 ".byte .su_shift7 - .su_shifttbl \n"
951
952 ".su_cloop: \n" /* repeat for every column */
953 "mov %1,r2 \n" /* get start address */
954 "mov #0,r3 \n" /* current_plane = 0 */
955
956 ".su_oloop: \n" /* repeat for every bitplane */
957 "mov r2,r4 \n" /* get start address */
958 "mov #0,r5 \n" /* current_row = 0 */
959 "mov %5,r1 \n" /* get filler bits */
960
961 ".su_iloop: \n" /* repeat for all rows */
962 "sub %2,r4 \n" /* address -= width */
963 "mov.b @r4,r0 \n" /* get data byte */
964 "shll8 r1 \n" /* old data to 2nd byte */
965 "extu.b r0,r0 \n" /* extend unsigned */
966 "or r1,r0 \n" /* combine old data */
967 "jmp @%6 \n" /* jump into shift "path" */
968 "extu.b r0,r1 \n" /* store data for next round */
969
970 ".su_shift6: \n" /* shift right by 0..7 bits */
971 "shlr2 r0 \n"
972 ".su_shift4: \n"
973 "shlr2 r0 \n"
974 ".su_shift2: \n"
975 "bra .su_shift0 \n"
976 "shlr2 r0 \n"
977 ".su_shift7: \n"
978 "shlr2 r0 \n"
979 ".su_shift5: \n"
980 "shlr2 r0 \n"
981 ".su_shift3: \n"
982 "shlr2 r0 \n"
983 ".su_shift1: \n"
984 "shlr r0 \n"
985 ".su_shift0: \n"
986
987 "mov.b r0,@r4 \n" /* store data */
988 "add #1,r5 \n" /* current_row++ */
989 "cmp/hi r5,%3 \n" /* current_row < bheight ? */
990 "bt .su_iloop \n"
991
992 "add %4,r2 \n" /* start_address += plane_size */
993 "add #1,r3 \n" /* current_plane++ */
994 "cmp/hi r3,%0 \n" /* current_plane < depth ? */
995 "bt .su_oloop \n"
996
997 "add #1,%1 \n" /* start_address++ */
998 "add #1,r6 \n" /* x++ */
999 "cmp/hi r6,%2 \n" /* x < width ? */
1000 "bt .su_cloop \n"
1001 : /* outputs */
1002 : /* inputs */
1003 /* %0 */ "r"(graybuf->depth),
1004 /* %1 */ "r"(graybuf->data + graybuf->plane_size),
1005 /* %2 */ "r"(graybuf->width),
1006 /* %3 */ "r"(graybuf->bheight),
1007 /* %4 */ "r"(graybuf->plane_size),
1008 /* %5 */ "r"(filler),
1009 /* %6 */ "r"(count)
1010 : /* clobbers */
1011 "r0", "r1", "r2", "r3", "r4", "r5", "r6"
1012 );
1013}
1014
1015/* Scroll the whole grayscale buffer down by <count> pixels (<= 7)
1016 *
1017 * black_border determines if the pixels scrolled in at the top are black
1018 * or white
1019 *
1020 * Scrolling up/down pixel-wise is significantly slower than scrolling
1021 * left/right or scrolling up/down byte-wise because it involves bit
1022 * shifting. That's why it is asm optimized.
1023 */
1024void gray_scroll_down(int count, bool black_border)
1025{
1026 unsigned long filler;
1027
1028 if (graybuf == NULL || (unsigned) count > 7)
1029 return;
1030
1031 if (black_border)
1032 filler = 0xFF << count; /* calculate filler bits */
1033 else
1034 filler = 0;
1035
1036 /* scroll column by column to minimize flicker */
1037 asm(
1038 "mov #0,r6 \n" /* x = 0 */
1039 "mova .sd_shifttbl,r0 \n" /* calculate jump destination for */
1040 "mov.b @(r0,%6),%6 \n" /* shift amount from table */
1041 "bra .sd_cloop \n" /* skip table */
1042 "add r0,%6 \n"
1043
1044 ".align 2 \n"
1045 ".sd_shifttbl: \n" /* shift jump offset table */
1046 ".byte .sd_shift0 - .sd_shifttbl \n"
1047 ".byte .sd_shift1 - .sd_shifttbl \n"
1048 ".byte .sd_shift2 - .sd_shifttbl \n"
1049 ".byte .sd_shift3 - .sd_shifttbl \n"
1050 ".byte .sd_shift4 - .sd_shifttbl \n"
1051 ".byte .sd_shift5 - .sd_shifttbl \n"
1052 ".byte .sd_shift6 - .sd_shifttbl \n"
1053 ".byte .sd_shift7 - .sd_shifttbl \n"
1054
1055 ".sd_cloop: \n" /* repeat for every column */
1056 "mov %1,r2 \n" /* get start address */
1057 "mov #0,r3 \n" /* current_plane = 0 */
1058
1059 ".sd_oloop: \n" /* repeat for every bitplane */
1060 "mov r2,r4 \n" /* get start address */
1061 "mov #0,r5 \n" /* current_row = 0 */
1062 "mov %5,r1 \n" /* get filler bits */
1063
1064 ".sd_iloop: \n" /* repeat for all rows */
1065 "shlr8 r1 \n" /* shift right to get residue */
1066 "mov.b @r4,r0 \n" /* get data byte */
1067 "jmp @%6 \n" /* jump into shift "path" */
1068 "extu.b r0,r0 \n" /* extend unsigned */
1069
1070 ".sd_shift6: \n" /* shift left by 0..7 bits */
1071 "shll2 r0 \n"
1072 ".sd_shift4: \n"
1073 "shll2 r0 \n"
1074 ".sd_shift2: \n"
1075 "bra .sd_shift0 \n"
1076 "shll2 r0 \n"
1077 ".sd_shift7: \n"
1078 "shll2 r0 \n"
1079 ".sd_shift5: \n"
1080 "shll2 r0 \n"
1081 ".sd_shift3: \n"
1082 "shll2 r0 \n"
1083 ".sd_shift1: \n"
1084 "shll r0 \n"
1085 ".sd_shift0: \n"
1086
1087 "or r0,r1 \n" /* combine with last residue */
1088 "mov.b r1,@r4 \n" /* store data */
1089 "add %2,r4 \n" /* address += width */
1090 "add #1,r5 \n" /* current_row++ */
1091 "cmp/hi r5,%3 \n" /* current_row < bheight ? */
1092 "bt .sd_iloop \n"
1093
1094 "add %4,r2 \n" /* start_address += plane_size */
1095 "add #1,r3 \n" /* current_plane++ */
1096 "cmp/hi r3,%0 \n" /* current_plane < depth ? */
1097 "bt .sd_oloop \n"
1098
1099 "add #1,%1 \n" /* start_address++ */
1100 "add #1,r6 \n" /* x++ */
1101 "cmp/hi r6,%2 \n" /* x < width ? */
1102 "bt .sd_cloop \n"
1103 : /* outputs */
1104 : /* inputs */
1105 /* %0 */ "r"(graybuf->depth),
1106 /* %1 */ "r"(graybuf->data),
1107 /* %2 */ "r"(graybuf->width),
1108 /* %3 */ "r"(graybuf->bheight),
1109 /* %4 */ "r"(graybuf->plane_size),
1110 /* %5 */ "r"(filler),
1111 /* %6 */ "r"(count)
1112 : /* clobbers */
1113 "r0", "r1", "r2", "r3", "r4", "r5", "r6"
1114 );
1115}
1116
1117/* Set a pixel to a specific gray value
1118 *
1119 * brightness is 0..255 (black to white) regardless of real bit depth
1120 */
1121void gray_drawpixel(int x, int y, int brightness)
1122{
1123 if (graybuf == NULL
1124 || (unsigned) x >= (unsigned) graybuf->width
1125 || (unsigned) y >= (unsigned) graybuf->height
1126 || (unsigned) brightness > 255)
1127 return;
1128
1129 graypixel(x, y, graybuf->bitpattern[MULU16(brightness,
1130 graybuf->depth + 1) >> 8]);
1131}
1132
1133/* Invert a pixel
1134 *
1135 * The bit pattern for that pixel in the buffer is inverted, so white becomes
1136 * black, light gray becomes dark gray etc.
1137 */
1138void gray_invertpixel(int x, int y)
1139{
1140 if (graybuf == NULL
1141 || (unsigned) x >= (unsigned) graybuf->width
1142 || (unsigned) y >= (unsigned) graybuf->height)
1143 return;
1144
1145 grayinvertmasked(x, (y >> 3), 1 << (y & 7));
1146}
1147
1148/* Draw a line from (x1, y1) to (x2, y2) with a specific gray value
1149 *
1150 * brightness is 0..255 (black to white) regardless of real bit depth
1151 */
1152void gray_drawline(int x1, int y1, int x2, int y2, int brightness)
1153{
1154 int numpixels;
1155 int i;
1156 int deltax, deltay;
1157 int d, dinc1, dinc2;
1158 int x, xinc1, xinc2;
1159 int y, yinc1, yinc2;
1160 unsigned long pattern;
1161
1162 if (graybuf == NULL
1163 || (unsigned) x1 >= (unsigned) graybuf->width
1164 || (unsigned) y1 >= (unsigned) graybuf->height
1165 || (unsigned) x2 >= (unsigned) graybuf->width
1166 || (unsigned) y2 >= (unsigned) graybuf->height
1167 || (unsigned) brightness > 255)
1168 return;
1169
1170 pattern = graybuf->bitpattern[MULU16(brightness, graybuf->depth + 1) >> 8];
1171
1172 deltax = abs(x2 - x1);
1173 deltay = abs(y2 - y1);
1174 xinc2 = 1;
1175 yinc2 = 1;
1176
1177 if (deltax >= deltay)
1178 {
1179 numpixels = deltax;
1180 d = 2 * deltay - deltax;
1181 dinc1 = deltay * 2;
1182 dinc2 = (deltay - deltax) * 2;
1183 xinc1 = 1;
1184 yinc1 = 0;
1185 }
1186 else
1187 {
1188 numpixels = deltay;
1189 d = 2 * deltax - deltay;
1190 dinc1 = deltax * 2;
1191 dinc2 = (deltax - deltay) * 2;
1192 xinc1 = 0;
1193 yinc1 = 1;
1194 }
1195 numpixels++; /* include endpoints */
1196
1197 if (x1 > x2)
1198 {
1199 xinc1 = -xinc1;
1200 xinc2 = -xinc2;
1201 }
1202
1203 if (y1 > y2)
1204 {
1205 yinc1 = -yinc1;
1206 yinc2 = -yinc2;
1207 }
1208
1209 x = x1;
1210 y = y1;
1211
1212 for (i=0; i<numpixels; i++)
1213 {
1214 graypixel(x, y, pattern);
1215
1216 if (d < 0)
1217 {
1218 d += dinc1;
1219 x += xinc1;
1220 y += yinc1;
1221 }
1222 else
1223 {
1224 d += dinc2;
1225 x += xinc2;
1226 y += yinc2;
1227 }
1228 }
1229}
1230
1231/* Invert a line from (x1, y1) to (x2, y2)
1232 *
1233 * The bit patterns for the pixels of the line are inverted, so white becomes
1234 * black, light gray becomes dark gray etc.
1235 */
1236void gray_invertline(int x1, int y1, int x2, int y2)
1237{
1238 int numpixels;
1239 int i;
1240 int deltax, deltay;
1241 int d, dinc1, dinc2;
1242 int x, xinc1, xinc2;
1243 int y, yinc1, yinc2;
1244
1245 if (graybuf == NULL
1246 || (unsigned) x1 >= (unsigned) graybuf->width
1247 || (unsigned) y1 >= (unsigned) graybuf->height
1248 || (unsigned) x2 >= (unsigned) graybuf->width
1249 || (unsigned) y2 >= (unsigned) graybuf->height)
1250 return;
1251
1252 deltax = abs(x2 - x1);
1253 deltay = abs(y2 - y1);
1254 xinc2 = 1;
1255 yinc2 = 1;
1256
1257 if (deltax >= deltay)
1258 {
1259 numpixels = deltax;
1260 d = 2 * deltay - deltax;
1261 dinc1 = deltay * 2;
1262 dinc2 = (deltay - deltax) * 2;
1263 xinc1 = 1;
1264 yinc1 = 0;
1265 }
1266 else
1267 {
1268 numpixels = deltay;
1269 d = 2 * deltax - deltay;
1270 dinc1 = deltax * 2;
1271 dinc2 = (deltax - deltay) * 2;
1272 xinc1 = 0;
1273 yinc1 = 1;
1274 }
1275 numpixels++; /* include endpoints */
1276
1277 if (x1 > x2)
1278 {
1279 xinc1 = -xinc1;
1280 xinc2 = -xinc2;
1281 }
1282
1283 if (y1 > y2)
1284 {
1285 yinc1 = -yinc1;
1286 yinc2 = -yinc2;
1287 }
1288
1289 x = x1;
1290 y = y1;
1291
1292 for (i=0; i<numpixels; i++)
1293 {
1294 grayinvertmasked(x, (y >> 3), 1 << (y & 7));
1295
1296 if (d < 0)
1297 {
1298 d += dinc1;
1299 x += xinc1;
1300 y += yinc1;
1301 }
1302 else
1303 {
1304 d += dinc2;
1305 x += xinc2;
1306 y += yinc2;
1307 }
1308 }
1309}
1310
1311/* Draw a (hollow) rectangle with a specific gray value,
1312 * corners are (x1, y1) and (x2, y2)
1313 *
1314 * brightness is 0..255 (black to white) regardless of real bit depth
1315 */
1316void gray_drawrect(int x1, int y1, int x2, int y2, int brightness)
1317{
1318 int x, y;
1319 unsigned long pattern;
1320 unsigned char srcpixel;
1321
1322 if (graybuf == NULL
1323 || (unsigned) x1 >= (unsigned) graybuf->width
1324 || (unsigned) y1 >= (unsigned) graybuf->height
1325 || (unsigned) x2 >= (unsigned) graybuf->width
1326 || (unsigned) y2 >= (unsigned) graybuf->height
1327 || (unsigned) brightness > 255)
1328 return;
1329
1330 if (y1 > y2)
1331 {
1332 y = y1;
1333 y1 = y2;
1334 y2 = y;
1335 }
1336 if (x1 > x2)
1337 {
1338 x = x1;
1339 x1 = x2;
1340 x2 = x;
1341 }
1342
1343 pattern = graybuf->bitpattern[MULU16(brightness, graybuf->depth + 1) >> 8];
1344 srcpixel = brightness;
1345
1346 for (x = x1 + 1; x < x2; x++)
1347 {
1348 graypixel(x, y1, pattern);
1349 graypixel(x, y2, pattern);
1350 }
1351 for (y = y1; y <= y2; )
1352 {
1353 if (!(y & 7) && (y2 - y >= 7))
1354 /* current row byte aligned in fb & at least 8 rows left */
1355 {
1356 /* shortcut: draw all 8 rows at once: 2..3 times faster */
1357 grayblock(x1, y >> 3, &srcpixel, 0);
1358 grayblock(x2, y >> 3, &srcpixel, 0);
1359 y += 8;
1360 }
1361 else
1362 {
1363 graypixel(x1, y, pattern);
1364 graypixel(x2, y, pattern);
1365 y++;
1366 }
1367 }
1368}
1369
1370/* Fill a rectangle with a specific gray value
1371 * corners are (x1, y1) and (x2, y2)
1372 *
1373 * brightness is 0..255 (black to white) regardless of real bit depth
1374 */
1375void gray_fillrect(int x1, int y1, int x2, int y2, int brightness)
1376{
1377 int x, y;
1378 unsigned long pattern;
1379 unsigned char srcpixel;
1380
1381 if (graybuf == NULL
1382 || (unsigned) x1 >= (unsigned) graybuf->width
1383 || (unsigned) y1 >= (unsigned) graybuf->height
1384 || (unsigned) x2 >= (unsigned) graybuf->width
1385 || (unsigned) y2 >= (unsigned) graybuf->height
1386 || (unsigned) brightness > 255)
1387 return;
1388
1389 if (y1 > y2)
1390 {
1391 y = y1;
1392 y1 = y2;
1393 y2 = y;
1394 }
1395 if (x1 > x2)
1396 {
1397 x = x1;
1398 x1 = x2;
1399 x2 = x;
1400 }
1401
1402 pattern = graybuf->bitpattern[MULU16(brightness, graybuf->depth + 1) >> 8];
1403 srcpixel = brightness;
1404
1405 for (y = y1; y <= y2; )
1406 {
1407 if (!(y & 7) && (y2 - y >= 7))
1408 /* current row byte aligned in fb & at least 8 rows left */
1409 {
1410 for (x = x1; x <= x2; x++)
1411 {
1412 /* shortcut: draw all 8 rows at once: 2..3 times faster */
1413 grayblock(x, y >> 3, &srcpixel, 0);
1414 }
1415 y += 8;
1416 }
1417 else
1418 {
1419 for (x = x1; x <= x2; x++)
1420 {
1421 graypixel(x, y, pattern);
1422 }
1423 y++;
1424 }
1425 }
1426}
1427
1428/* Invert a (solid) rectangle, corners are (x1, y1) and (x2, y2)
1429 *
1430 * The bit patterns for all pixels of the rectangle are inverted, so white
1431 * becomes black, light gray becomes dark gray etc. This is the fastest of
1432 * all gray_xxxrect() functions! Perfectly suited for cursors.
1433 */
1434void gray_invertrect(int x1, int y1, int x2, int y2)
1435{
1436 int x, yb, yb1, yb2;
1437 unsigned char mask;
1438
1439 if (graybuf == NULL
1440 || (unsigned) x1 >= (unsigned) graybuf->width
1441 || (unsigned) y1 >= (unsigned) graybuf->height
1442 || (unsigned) x2 >= (unsigned) graybuf->width
1443 || (unsigned) y2 >= (unsigned) graybuf->height)
1444 return;
1445
1446 if (y1 > y2)
1447 {
1448 yb = y1;
1449 y1 = y2;
1450 y2 = yb;
1451 }
1452 if (x1 > x2)
1453 {
1454 x = x1;
1455 x1 = x2;
1456 x2 = x;
1457 }
1458
1459 yb1 = y1 >> 3;
1460 yb2 = y2 >> 3;
1461
1462 if (yb1 == yb2)
1463 {
1464 mask = 0xFF << (y1 & 7);
1465 mask &= 0xFF >> (7 - (y2 & 7));
1466
1467 for (x = x1; x <= x2; x++)
1468 grayinvertmasked(x, yb1, mask);
1469 }
1470 else
1471 {
1472 mask = 0xFF << (y1 & 7);
1473
1474 for (x = x1; x <= x2; x++)
1475 grayinvertmasked(x, yb1, mask);
1476
1477 for (yb = yb1 + 1; yb < yb2; yb++)
1478 {
1479 for (x = x1; x <= x2; x++)
1480 grayinvertmasked(x, yb, 0xFF);
1481 }
1482
1483 mask = 0xFF >> (7 - (y2 & 7));
1484
1485 for (x = x1; x <= x2; x++)
1486 grayinvertmasked(x, yb2, mask);
1487 }
1488}
1489
1490/* Copy a grayscale bitmap into the display
1491 *
1492 * A grayscale bitmap contains one byte for every pixel that defines the
1493 * brightness of the pixel (0..255). Bytes are read in row-major order.
1494 * The <stride> parameter is useful if you want to show only a part of a
1495 * bitmap. It should always be set to the "row length" of the bitmap, so
1496 * for displaying the whole bitmap, nx == stride.
1497 */
1498void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny,
1499 int stride)
1500{
1501 int xi, yi;
1502 unsigned char *row;
1503
1504 if (graybuf == NULL
1505 || (unsigned) x >= (unsigned) graybuf->width
1506 || (unsigned) y >= (unsigned) graybuf->height)
1507 return;
1508
1509 if ((y + ny) >= graybuf->height) /* clip bottom */
1510 ny = graybuf->height - y;
1511
1512 if ((x + nx) >= graybuf->width) /* clip right */
1513 nx = graybuf->width - x;
1514
1515 for (yi = y; yi < y + ny; )
1516 {
1517 row = src;
1518
1519 if (!(yi & 7) && (y + ny - yi > 7))
1520 /* current row byte aligned in fb & at least 8 rows left */
1521 {
1522 for (xi = x; xi < x + nx; xi++)
1523 {
1524 /* shortcut: draw all 8 rows at once: 2..3 times faster */
1525 grayblock(xi, yi >> 3, row++, stride);
1526 }
1527 yi += 8;
1528 src += stride << 3;
1529 }
1530 else
1531 {
1532 for (xi = x; xi < x + nx; xi++)
1533 {
1534 graypixel(xi, yi, graybuf->bitpattern[MULU16(*row++,
1535 graybuf->depth + 1) >> 8]);
1536 }
1537 yi++;
1538 src += stride;
1539 }
1540 }
1541}
1542
1543/* Display a bitmap with specific foreground and background gray values
1544 *
1545 * This (now) uses the same bitmap format as the core b&w graphics routines,
1546 * so you can use bmp2rb to generate bitmaps for use with this function as
1547 * well.
1548 *
1549 * A bitmap contains one bit for every pixel that defines if that pixel is
1550 * foreground (1) or background (0). Bits within a byte are arranged
1551 * vertically, LSB at top.
1552 * The bytes are stored in row-major order, with byte 0 being top left,
1553 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
1554 * 0..7, the second row defines pixel row 8..15 etc.
1555 *
1556 * The <stride> parameter is useful if you want to show only a part of a
1557 * bitmap. It should always be set to the "row length" of the bitmap.
1558 *
1559 * If draw_bg is false, only foreground pixels are drawn, so the background
1560 * is transparent. In this case bg_brightness is ignored.
1561 */
1562void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
1563 int stride, bool draw_bg, int fg_brightness,
1564 int bg_brightness)
1565{
1566 int xi, dy;
1567 int bits = 0; /* Have to initialize to prevent warning */
1568 unsigned long fg_pattern, bg_pattern;
1569 unsigned char *col;
1570
1571 if (graybuf == NULL
1572 || (unsigned) x >= (unsigned) graybuf->width
1573 || (unsigned) y >= (unsigned) graybuf->height
1574 || (unsigned) fg_brightness > 255
1575 || (unsigned) bg_brightness > 255)
1576 return;
1577
1578 if ((y + ny) >= graybuf->height) /* clip bottom */
1579 ny = graybuf->height - y;
1580
1581 if ((x + nx) >= graybuf->width) /* clip right */
1582 nx = graybuf->width - x;
1583
1584 fg_pattern = graybuf->bitpattern[MULU16(fg_brightness,
1585 graybuf->depth + 1) >> 8];
1586
1587 bg_pattern = graybuf->bitpattern[MULU16(bg_brightness,
1588 graybuf->depth + 1) >> 8];
1589
1590 for (xi = x; xi < x + nx; xi++)
1591 {
1592 col = src++;
1593 for (dy = 0; dy < ny; dy++)
1594 {
1595 if (!(dy & 7)) /* get next 8 bits */
1596 {
1597 bits = (int)(*col);
1598 col += stride;
1599 }
1600
1601 if (bits & 0x01)
1602 graypixel(xi, y + dy, fg_pattern);
1603 else
1604 if (draw_bg)
1605 graypixel(xi, y + dy, bg_pattern);
1606
1607 bits >>= 1;
1608 }
1609 }
1610}
1611
1612/*********************** end grayscale framework ***************************/
1613
1614
1615/* for portability of below JPEG code */ 36/* for portability of below JPEG code */
1616#define MEMSET(p,v,c) rb->memset(p,v,c) 37#define MEMSET(p,v,c) rb->memset(p,v,c)
1617#define INLINE static inline 38#define INLINE static inline
@@ -1622,7 +43,7 @@ void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
1622/**************** begin JPEG code ********************/ 43/**************** begin JPEG code ********************/
1623 44
1624/* LUT for IDCT, this could also be used for gamma correction */ 45/* LUT for IDCT, this could also be used for gamma correction */
1625const unsigned char range_limit[1024] = 46const unsigned char range_limit[1024] =
1626{ 47{
1627 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, 48 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
1628 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, 49 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
@@ -1822,7 +243,7 @@ void idct4x4(unsigned char* p_byte, int* inptr, int* quantptr, int skip_line)
1822 /* Pass 1: process columns from input, store into work array. */ 243 /* Pass 1: process columns from input, store into work array. */
1823 244
1824 wsptr = workspace; 245 wsptr = workspace;
1825 for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) 246 for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++)
1826 { 247 {
1827 /* Even part */ 248 /* Even part */
1828 249
@@ -1924,13 +345,13 @@ void idct8x8(unsigned char* p_byte, int* inptr, int* quantptr, int skip_line)
1924 * column DCT calculations can be simplified this way. 345 * column DCT calculations can be simplified this way.
1925 */ 346 */
1926 347
1927 if ((inptr[8*1] | inptr[8*2] | inptr[8*3] 348 if ((inptr[8*1] | inptr[8*2] | inptr[8*3]
1928 | inptr[8*4] | inptr[8*5] | inptr[8*6] | inptr[8*7]) == 0) 349 | inptr[8*4] | inptr[8*5] | inptr[8*6] | inptr[8*7]) == 0)
1929 { 350 {
1930 /* AC terms all zero */ 351 /* AC terms all zero */
1931 int dcval = DEQUANTIZE(inptr[8*0], quantptr[8*0]) << PASS1_BITS; 352 int dcval = DEQUANTIZE(inptr[8*0], quantptr[8*0]) << PASS1_BITS;
1932 353
1933 wsptr[8*0] = wsptr[8*1] = wsptr[8*2] = wsptr[8*3] = wsptr[8*4] 354 wsptr[8*0] = wsptr[8*1] = wsptr[8*2] = wsptr[8*3] = wsptr[8*4]
1934 = wsptr[8*5] = wsptr[8*6] = wsptr[8*7] = dcval; 355 = wsptr[8*5] = wsptr[8*6] = wsptr[8*7] = dcval;
1935 inptr++; /* advance pointers to next column */ 356 inptr++; /* advance pointers to next column */
1936 quantptr++; 357 quantptr++;
@@ -2011,7 +432,7 @@ void idct8x8(unsigned char* p_byte, int* inptr, int* quantptr, int skip_line)
2011 /* and also undo the PASS1_BITS scaling. */ 432 /* and also undo the PASS1_BITS scaling. */
2012 433
2013 wsptr = workspace; 434 wsptr = workspace;
2014 for (ctr = 0; ctr < 8; ctr++) 435 for (ctr = 0; ctr < 8; ctr++)
2015 { 436 {
2016 outptr = p_byte + (ctr*skip_line); 437 outptr = p_byte + (ctr*skip_line);
2017 /* Rows of zeroes can be exploited in the same way as we did with columns. 438 /* Rows of zeroes can be exploited in the same way as we did with columns.
@@ -2023,11 +444,11 @@ void idct8x8(unsigned char* p_byte, int* inptr, int* quantptr, int skip_line)
2023 */ 444 */
2024 445
2025#ifndef NO_ZERO_ROW_TEST 446#ifndef NO_ZERO_ROW_TEST
2026 if ((wsptr[1] | wsptr[2] | wsptr[3] 447 if ((wsptr[1] | wsptr[2] | wsptr[3]
2027 | wsptr[4] | wsptr[5] | wsptr[6] | wsptr[7]) == 0) 448 | wsptr[4] | wsptr[5] | wsptr[6] | wsptr[7]) == 0)
2028 { 449 {
2029 /* AC terms all zero */ 450 /* AC terms all zero */
2030 unsigned char dcval = range_limit[(int) DESCALE((long) wsptr[0], 451 unsigned char dcval = range_limit[(int) DESCALE((long) wsptr[0],
2031 PASS1_BITS+3) & RANGE_MASK]; 452 PASS1_BITS+3) & RANGE_MASK];
2032 453
2033 outptr[0] = dcval; 454 outptr[0] = dcval;
@@ -2095,21 +516,21 @@ void idct8x8(unsigned char* p_byte, int* inptr, int* quantptr, int skip_line)
2095 516
2096 /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ 517 /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
2097 518
2098 outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp3, 519 outptr[0] = range_limit[(int) DESCALE(tmp10 + tmp3,
2099 CONST_BITS+PASS1_BITS+3) & RANGE_MASK]; 520 CONST_BITS+PASS1_BITS+3) & RANGE_MASK];
2100 outptr[7] = range_limit[(int) DESCALE(tmp10 - tmp3, 521 outptr[7] = range_limit[(int) DESCALE(tmp10 - tmp3,
2101 CONST_BITS+PASS1_BITS+3) & RANGE_MASK]; 522 CONST_BITS+PASS1_BITS+3) & RANGE_MASK];
2102 outptr[1] = range_limit[(int) DESCALE(tmp11 + tmp2, 523 outptr[1] = range_limit[(int) DESCALE(tmp11 + tmp2,
2103 CONST_BITS+PASS1_BITS+3) & RANGE_MASK]; 524 CONST_BITS+PASS1_BITS+3) & RANGE_MASK];
2104 outptr[6] = range_limit[(int) DESCALE(tmp11 - tmp2, 525 outptr[6] = range_limit[(int) DESCALE(tmp11 - tmp2,
2105 CONST_BITS+PASS1_BITS+3) & RANGE_MASK]; 526 CONST_BITS+PASS1_BITS+3) & RANGE_MASK];
2106 outptr[2] = range_limit[(int) DESCALE(tmp12 + tmp1, 527 outptr[2] = range_limit[(int) DESCALE(tmp12 + tmp1,
2107 CONST_BITS+PASS1_BITS+3) & RANGE_MASK]; 528 CONST_BITS+PASS1_BITS+3) & RANGE_MASK];
2108 outptr[5] = range_limit[(int) DESCALE(tmp12 - tmp1, 529 outptr[5] = range_limit[(int) DESCALE(tmp12 - tmp1,
2109 CONST_BITS+PASS1_BITS+3) & RANGE_MASK]; 530 CONST_BITS+PASS1_BITS+3) & RANGE_MASK];
2110 outptr[3] = range_limit[(int) DESCALE(tmp13 + tmp0, 531 outptr[3] = range_limit[(int) DESCALE(tmp13 + tmp0,
2111 CONST_BITS+PASS1_BITS+3) & RANGE_MASK]; 532 CONST_BITS+PASS1_BITS+3) & RANGE_MASK];
2112 outptr[4] = range_limit[(int) DESCALE(tmp13 - tmp0, 533 outptr[4] = range_limit[(int) DESCALE(tmp13 - tmp0,
2113 CONST_BITS+PASS1_BITS+3) & RANGE_MASK]; 534 CONST_BITS+PASS1_BITS+3) & RANGE_MASK];
2114 535
2115 wsptr += 8; /* advance pointer to next row */ 536 wsptr += 8; /* advance pointer to next row */
@@ -2505,7 +926,7 @@ int process_markers(unsigned char* p_bytes, long size, struct jpeg* p_jpeg)
2505 p_dest = (unsigned char*)(((int)p_bytes + 1) & ~1); 926 p_dest = (unsigned char*)(((int)p_bytes + 1) & ~1);
2506 p_jpeg->p_entropy_data = (unsigned short*)p_dest; 927 p_jpeg->p_entropy_data = (unsigned short*)p_dest;
2507 928
2508 929
2509 /* remove byte stuffing and restart markers, if present */ 930 /* remove byte stuffing and restart markers, if present */
2510 while (p_src < p_bytes + size) 931 while (p_src < p_bytes + size)
2511 { 932 {
@@ -2538,7 +959,7 @@ int process_markers(unsigned char* p_bytes, long size, struct jpeg* p_jpeg)
2538 959
2539void default_huff_tbl(struct jpeg* p_jpeg) 960void default_huff_tbl(struct jpeg* p_jpeg)
2540{ 961{
2541 static const struct huffman_table luma_table = 962 static const struct huffman_table luma_table =
2542 { 963 {
2543 { 964 {
2544 0x00,0x01,0x05,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00, 965 0x00,0x01,0x05,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
@@ -2560,7 +981,7 @@ void default_huff_tbl(struct jpeg* p_jpeg)
2560 } 981 }
2561 }; 982 };
2562 983
2563 static const struct huffman_table chroma_table = 984 static const struct huffman_table chroma_table =
2564 { 985 {
2565 { 986 {
2566 0x00,0x03,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00, 987 0x00,0x03,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,
@@ -2679,7 +1100,7 @@ void fix_huff_tbl(int* htbl, struct derived_tbl* dtbl)
2679 * reference values beyond the end of the array. To avoid a wild store, 1100 * reference values beyond the end of the array. To avoid a wild store,
2680 * we put some extra zeroes after the real entries. 1101 * we put some extra zeroes after the real entries.
2681 */ 1102 */
2682static const int zag[] = 1103static const int zag[] =
2683{ 1104{
2684 0, 1, 8, 16, 9, 2, 3, 10, 1105 0, 1, 8, 16, 9, 2, 3, 10,
2685 17, 24, 32, 25, 18, 11, 4, 5, 1106 17, 24, 32, 25, 18, 11, 4, 5,
@@ -2696,13 +1117,13 @@ static const int zag[] =
2696void build_lut(struct jpeg* p_jpeg) 1117void build_lut(struct jpeg* p_jpeg)
2697{ 1118{
2698 int i; 1119 int i;
2699 fix_huff_tbl(p_jpeg->hufftable[0].huffmancodes_dc, 1120 fix_huff_tbl(p_jpeg->hufftable[0].huffmancodes_dc,
2700 &p_jpeg->dc_derived_tbls[0]); 1121 &p_jpeg->dc_derived_tbls[0]);
2701 fix_huff_tbl(p_jpeg->hufftable[0].huffmancodes_ac, 1122 fix_huff_tbl(p_jpeg->hufftable[0].huffmancodes_ac,
2702 &p_jpeg->ac_derived_tbls[0]); 1123 &p_jpeg->ac_derived_tbls[0]);
2703 fix_huff_tbl(p_jpeg->hufftable[1].huffmancodes_dc, 1124 fix_huff_tbl(p_jpeg->hufftable[1].huffmancodes_dc,
2704 &p_jpeg->dc_derived_tbls[1]); 1125 &p_jpeg->dc_derived_tbls[1]);
2705 fix_huff_tbl(p_jpeg->hufftable[1].huffmancodes_ac, 1126 fix_huff_tbl(p_jpeg->hufftable[1].huffmancodes_ac,
2706 &p_jpeg->ac_derived_tbls[1]); 1127 &p_jpeg->ac_derived_tbls[1]);
2707 1128
2708 /* build the dequantization tables for the IDCT (De-ZiZagged) */ 1129 /* build the dequantization tables for the IDCT (De-ZiZagged) */
@@ -2760,17 +1181,17 @@ INLINE void drop_bits(struct bitstream* pb, int nbits)
2760#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) 1181#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x))
2761 1182
2762static const int extend_test[16] = /* entry n is 2**(n-1) */ 1183static const int extend_test[16] = /* entry n is 2**(n-1) */
2763{ 1184{
2764 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 1185 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
2765 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 1186 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000
2766}; 1187};
2767 1188
2768static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ 1189static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */
2769{ 1190{
2770 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, 1191 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1,
2771 ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, 1192 ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1,
2772 ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, 1193 ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1,
2773 ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 1194 ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1
2774}; 1195};
2775 1196
2776/* Decode a single value */ 1197/* Decode a single value */
@@ -2854,7 +1275,7 @@ INLINE int huff_decode_ac(struct bitstream* bs, struct derived_tbl* tbl)
2854 1275
2855 1276
2856/* a JPEG decoder specialized in decoding only the luminance (b&w) */ 1277/* a JPEG decoder specialized in decoding only the luminance (b&w) */
2857int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel, int downscale, 1278int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel, int downscale,
2858 void (*pf_progress)(int current, int total)) 1279 void (*pf_progress)(int current, int total))
2859{ 1280{
2860 struct bitstream bs; /* bitstream "object" */ 1281 struct bitstream bs; /* bitstream "object" */
@@ -2997,7 +1418,7 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel, int downscale,
2997 1418
2998 if (ci == 0) 1419 if (ci == 0)
2999 { /* only for Y component */ 1420 { /* only for Y component */
3000 pf_idct(p_byte+store_offs[blkn], block, p_jpeg->qt_idct[ti], 1421 pf_idct(p_byte+store_offs[blkn], block, p_jpeg->qt_idct[ti],
3001 skip_line); 1422 skip_line);
3002 } 1423 }
3003 } /* for blkn */ 1424 } /* for blkn */
@@ -3032,7 +1453,7 @@ struct t_disp
3032/************************* Globals ***************************/ 1453/************************* Globals ***************************/
3033 1454
3034/* decompressed image in the possible sizes (1,2,4,8), wasting the other */ 1455/* decompressed image in the possible sizes (1,2,4,8), wasting the other */
3035struct t_disp disp[9]; 1456struct t_disp disp[9];
3036 1457
3037/* my memory pool (from the mp3 buffer) */ 1458/* my memory pool (from the mp3 buffer) */
3038char print[32]; /* use a common snprintf() buffer */ 1459char print[32]; /* use a common snprintf() buffer */
@@ -3057,7 +1478,7 @@ int scroll_bmp(struct t_disp* pdisp)
3057 /* we're unfortunately slower than key repeat, 1478 /* we're unfortunately slower than key repeat,
3058 so empty the button queue, to avoid post-scroll */ 1479 so empty the button queue, to avoid post-scroll */
3059 while(rb->button_get(false) != BUTTON_NONE); 1480 while(rb->button_get(false) != BUTTON_NONE);
3060 1481
3061 button = rb->button_get(true); 1482 button = rb->button_get(true);
3062 1483
3063 if (button == SYS_USB_CONNECTED) 1484 if (button == SYS_USB_CONNECTED)
@@ -3150,12 +1571,12 @@ int scroll_bmp(struct t_disp* pdisp)
3150int wait_for_button(void) 1571int wait_for_button(void)
3151{ 1572{
3152 int button; 1573 int button;
3153 1574
3154 do 1575 do
3155 { 1576 {
3156 button = rb->button_get(true); 1577 button = rb->button_get(true);
3157 } while ((button & BUTTON_REL) && button != SYS_USB_CONNECTED); 1578 } while ((button & BUTTON_REL) && button != SYS_USB_CONNECTED);
3158 1579
3159 return button; 1580 return button;
3160} 1581}
3161 1582
@@ -3163,7 +1584,7 @@ int wait_for_button(void)
3163void cb_progess(int current, int total) 1584void cb_progess(int current, int total)
3164{ 1585{
3165 rb->yield(); /* be nice to the other threads */ 1586 rb->yield(); /* be nice to the other threads */
3166 rb->progressbar(0, LCD_HEIGHT-8, LCD_WIDTH, 8, 1587 rb->progressbar(0, LCD_HEIGHT-8, LCD_WIDTH, 8,
3167 current*100/total, 0 /*Grow_Right*/); 1588 current*100/total, 0 /*Grow_Right*/);
3168 rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8); 1589 rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8);
3169} 1590}
@@ -3244,8 +1665,8 @@ struct t_disp* get_image(struct jpeg* p_jpg, int ds)
3244 p_disp->bitmap = buf; 1665 p_disp->bitmap = buf;
3245 buf += size; 1666 buf += size;
3246 buf_size -= size; 1667 buf_size -= size;
3247 1668
3248 rb->snprintf(print, sizeof(print), "decoding %d*%d", 1669 rb->snprintf(print, sizeof(print), "decoding %d*%d",
3249 p_jpg->x_size/ds, p_jpg->y_size/ds); 1670 p_jpg->x_size/ds, p_jpg->y_size/ds);
3250 rb->lcd_puts(0, 3, print); 1671 rb->lcd_puts(0, 3, print);
3251 rb->lcd_update(); 1672 rb->lcd_update();
@@ -3304,7 +1725,7 @@ void get_view(struct t_disp* p_disp, int* p_cx, int* p_cy)
3304 1725
3305 1726
3306/* load, decode, display the image */ 1727/* load, decode, display the image */
3307int main(char* filename) 1728int main(char* filename)
3308{ 1729{
3309 int fd; 1730 int fd;
3310 int filesize; 1731 int filesize;
@@ -3360,14 +1781,14 @@ int main(char* filename)
3360 rb->snprintf(print, sizeof(print), "loading %d bytes", filesize); 1781 rb->snprintf(print, sizeof(print), "loading %d bytes", filesize);
3361 rb->lcd_puts(0, 0, print); 1782 rb->lcd_puts(0, 0, print);
3362 rb->lcd_update(); 1783 rb->lcd_update();
3363 1784
3364 rb->read(fd, buf_jpeg, filesize); 1785 rb->read(fd, buf_jpeg, filesize);
3365 rb->close(fd); 1786 rb->close(fd);
3366 1787
3367 rb->snprintf(print, sizeof(print), "decoding markers"); 1788 rb->snprintf(print, sizeof(print), "decoding markers");
3368 rb->lcd_puts(0, 1, print); 1789 rb->lcd_puts(0, 1, print);
3369 rb->lcd_update(); 1790 rb->lcd_update();
3370 1791
3371 rb->memset(&jpg, 0, sizeof(jpg)); /* clear info struct */ 1792 rb->memset(&jpg, 0, sizeof(jpg)); /* clear info struct */
3372 /* process markers, unstuffing */ 1793 /* process markers, unstuffing */
3373 status = process_markers(buf_jpeg, filesize, &jpg); 1794 status = process_markers(buf_jpeg, filesize, &jpg);
@@ -3379,7 +1800,7 @@ int main(char* filename)
3379 if (!(status & DHT)) /* if no Huffman table present: */ 1800 if (!(status & DHT)) /* if no Huffman table present: */
3380 default_huff_tbl(&jpg); /* use default */ 1801 default_huff_tbl(&jpg); /* use default */
3381 build_lut(&jpg); /* derive Huffman and other lookup-tables */ 1802 build_lut(&jpg); /* derive Huffman and other lookup-tables */
3382 1803
3383 /* I can correct the buffer now, re-gain what the removed markers took */ 1804 /* I can correct the buffer now, re-gain what the removed markers took */
3384 buf -= filesize; /* back to before */ 1805 buf -= filesize; /* back to before */
3385 buf_size += filesize; 1806 buf_size += filesize;
@@ -3393,7 +1814,7 @@ int main(char* filename)
3393 rb->lcd_update(); 1814 rb->lcd_update();
3394 1815
3395 /* check display constraint */ 1816 /* check display constraint */
3396 ds_max = max_downscale(jpg.x_size, jpg.y_size); 1817 ds_max = max_downscale(jpg.x_size, jpg.y_size);
3397 /* check memory constraint */ 1818 /* check memory constraint */
3398 ds_min = min_downscale(jpg.x_phys, jpg.y_phys, buf_size); 1819 ds_min = min_downscale(jpg.x_phys, jpg.y_phys, buf_size);
3399 if (ds_min == 0) 1820 if (ds_min == 0)
@@ -3404,7 +1825,7 @@ int main(char* filename)
3404 ds = ds_max; /* initials setting */ 1825 ds = ds_max; /* initials setting */
3405 cx = jpg.x_size/ds/2; /* center the view */ 1826 cx = jpg.x_size/ds/2; /* center the view */
3406 cy = jpg.y_size/ds/2; 1827 cy = jpg.y_size/ds/2;
3407 1828
3408 do /* loop the image prepare and decoding when zoomed */ 1829 do /* loop the image prepare and decoding when zoomed */
3409 { 1830 {
3410 p_disp = get_image(&jpg, ds); /* decode or fetch from cache */ 1831 p_disp = get_image(&jpg, ds); /* decode or fetch from cache */
@@ -3413,7 +1834,7 @@ int main(char* filename)
3413 1834
3414 set_view(p_disp, cx, cy); 1835 set_view(p_disp, cx, cy);
3415 1836
3416 rb->snprintf(print, sizeof(print), "showing %d*%d", 1837 rb->snprintf(print, sizeof(print), "showing %d*%d",
3417 p_disp->width, p_disp->height); 1838 p_disp->width, p_disp->height);
3418 rb->lcd_puts(0, 3, print); 1839 rb->lcd_puts(0, 3, print);
3419 rb->lcd_update(); 1840 rb->lcd_update();
@@ -3421,15 +1842,15 @@ int main(char* filename)
3421 gray_clear_display(); 1842 gray_clear_display();
3422 gray_drawgraymap( 1843 gray_drawgraymap(
3423 p_disp->bitmap + p_disp->y * p_disp->stride + p_disp->x, 1844 p_disp->bitmap + p_disp->y * p_disp->stride + p_disp->x,
3424 MAX(0, (LCD_WIDTH - p_disp->width) / 2), 1845 MAX(0, (LCD_WIDTH - p_disp->width) / 2),
3425 MAX(0, (LCD_HEIGHT - p_disp->height) / 2), 1846 MAX(0, (LCD_HEIGHT - p_disp->height) / 2),
3426 MIN(LCD_WIDTH, p_disp->width), 1847 MIN(LCD_WIDTH, p_disp->width),
3427 MIN(LCD_HEIGHT, p_disp->height), 1848 MIN(LCD_HEIGHT, p_disp->height),
3428 p_disp->stride); 1849 p_disp->stride);
3429 1850
3430 gray_show_display(true); /* switch on grayscale overlay */ 1851 gray_show_display(true); /* switch on grayscale overlay */
3431 1852
3432 /* drawing is now finished, play around with scrolling 1853 /* drawing is now finished, play around with scrolling
3433 * until you press OFF or connect USB 1854 * until you press OFF or connect USB
3434 */ 1855 */
3435 while (1) 1856 while (1)
@@ -3484,7 +1905,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
3484 TEST_PLUGIN_API(api); 1905 TEST_PLUGIN_API(api);
3485 1906
3486 rb = api; /* copy to global api pointer */ 1907 rb = api; /* copy to global api pointer */
3487 1908
3488 ret = main((char*)parameter); 1909 ret = main((char*)parameter);
3489 1910
3490 if (ret == PLUGIN_USB_CONNECTED) 1911 if (ret == PLUGIN_USB_CONNECTED)