summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Nielsen Feltzing <linus@haxx.se>2004-04-21 07:32:42 +0000
committerLinus Nielsen Feltzing <linus@haxx.se>2004-04-21 07:32:42 +0000
commit75b575a75014f886caef57a8faf6582252bfb9ed (patch)
tree375628feed109dfe051d62fbf5c1ffe06f68cbcf
parent1de3dd570de9a223ef6294159047ce272859e388 (diff)
downloadrockbox-75b575a75014f886caef57a8faf6582252bfb9ed.tar.gz
rockbox-75b575a75014f886caef57a8faf6582252bfb9ed.zip
Now uses grayscalescvs diff -u apps/plugins/mandelbrot.c! Plus some internal changes, like removing TAB chars, and preventing unnecessary redraws etc.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4535 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugins/mandelbrot.c801
1 files changed, 705 insertions, 96 deletions
diff --git a/apps/plugins/mandelbrot.c b/apps/plugins/mandelbrot.c
index 3c948e8130..11c51bb556 100644
--- a/apps/plugins/mandelbrot.c
+++ b/apps/plugins/mandelbrot.c
@@ -9,8 +9,6 @@
9 * 9 *
10 * Copyright (C) 2004 Matthias Wientapper 10 * Copyright (C) 2004 Matthias Wientapper
11 * 11 *
12 * Thanks to Jens Arnold and Joerg Hohensohn for the speed tips.
13 * Boy, that was a hell of a code review ;-)
14 * 12 *
15 * All files in this archive are subject to the GNU General Public License. 13 * All files in this archive are subject to the GNU General Public License.
16 * See the file COPYING in the source tree root for full license agreement. 14 * See the file COPYING in the source tree root for full license agreement.
@@ -18,11 +16,8 @@
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied. 17 * KIND, either express or implied.
20 * 18 *
21 *
22 * further optimization ideas:
23 * - incremental recalculation when moving
24 *
25 ****************************************************************************/ 19 ****************************************************************************/
20#ifndef SIMULATOR
26#include "plugin.h" 21#include "plugin.h"
27 22
28#ifdef HAVE_LCD_BITMAP // this is not fun on the player 23#ifdef HAVE_LCD_BITMAP // this is not fun on the player
@@ -36,9 +31,603 @@ static int y_min;
36static int y_max; 31static int y_max;
37static int delta; 32static int delta;
38static int max_iter; 33static int max_iter;
34static unsigned char *gbuf;
35static unsigned int gbuf_size = 0;
36
37/**************** Begin grayscale framework ******************/
38
39/* This is a generic framework to use grayscale display within
40 * rockbox plugins. It obviously does not work for the player.
41 *
42 * If you want to use grayscale display within a plugin, copy
43 * this section (up to "End grayscale framework") into your
44 * source and you are able to use it. For detailed documentation
45 * look at the head of each public function.
46 *
47 * It requires a global Rockbox api pointer in "rb" and uses
48 * timer 4 so you cannot use timer 4 for other purposes while
49 * displaying grayscale.
50 *
51 * The framework consists of 3 sections:
52 *
53 * - internal core functions and definitions
54 * - public core functions
55 * - public optional functions
56 *
57 * Usually you will use functions from the latter two sections
58 * in your code. You can cut out functions from the third section
59 * that you do not need in order to not waste space. Don't forget
60 * to cut the prototype as well.
61 */
62
63/**** internal core functions and definitions ****/
64
65/* You do not want to touch these if you don't know exactly what
66 * you're doing.
67 */
68
69#define IMIA4 (*((volatile unsigned long*)0x09000180)) /* timer 4 */
70
71#define GRAY_RUNNING 0x0001 /* grayscale overlay is running */
72#define GRAY_DEFERRED_UPDATE 0x0002 /* lcd_update() requested */
73
74typedef struct
75{
76 int x;
77 int by; /* 8-pixel units */
78 int width;
79 int height;
80 int bheight; /* 8-pixel units */
81 int plane_size;
82 int depth; /* number_of_bitplanes = (number_of_grayscales - 1) */
83 int cur_plane; /* for the timer isr */
84 unsigned long randmask; /* mask for random value in graypixel() */
85 unsigned long flags; /* various flags, see #defines */
86 unsigned char *data; /* pointer to start of bitplane data */
87 unsigned long *bitpattern; /* pointer to start of pattern table */
88} tGraybuf;
89
90static tGraybuf *graybuf = NULL;
91
92/** prototypes **/
93
94void timer_set(unsigned period);
95void timer4_isr(void) __attribute__((interrupt_handler));
96void graypixel(int x, int y, unsigned long pattern);
97void grayinvertmasked(int x, int yb, unsigned char mask);
98
99/** implementation **/
100
101/* setup ISR and timer registers */
102void timer_set(unsigned period)
103{
104 if (period)
105 {
106 and_b(~0x10, &TSTR); /* Stop the timer 4 */
107 and_b(~0x10, &TSNC); /* No synchronization */
108 and_b(~0x10, &TMDR); /* Operate normally */
109
110 IMIA4 = (unsigned long) timer4_isr; /* install ISR */
111
112 and_b(~0x01, &TSR4);
113 TIER4 = 0xF9; /* Enable GRA match interrupt */
114
115 GRA4 = (unsigned short)(period/4 - 1);
116 TCR4 = 0x22; /* clear at GRA match, sysclock/4 */
117 IPRD = (IPRD & 0xFF0F) | 0x0010; /* interrupt priority 1 (lowest) */
118 or_b(0x10, &TSTR); /* start timer 4 */
119 }
120 else
121 {
122 and_b(~0x10, &TSTR); /* stop the timer 4 */
123 IPRD = (IPRD & 0xFF0F); /* disable interrupt */
124 }
125}
126
127/* timer interrupt handler: display next bitplane */
128void timer4_isr(void) /* IMIA4 */
129{
130 and_b(~0x01, &TSR4); /* clear the interrupt */
131
132 rb->lcd_blit(graybuf->data + (graybuf->plane_size * graybuf->cur_plane),
133 graybuf->x, graybuf->by, graybuf->width, graybuf->bheight,
134 graybuf->width);
135
136 if (++graybuf->cur_plane >= graybuf->depth)
137 graybuf->cur_plane = 0;
138
139 if (graybuf->flags & GRAY_DEFERRED_UPDATE) /* lcd_update() requested? */
140 {
141 int x1 = MAX(graybuf->x, 0);
142 int x2 = MIN(graybuf->x + graybuf->width, LCD_WIDTH);
143 int y1 = MAX(graybuf->by << 3, 0);
144 int y2 = MIN((graybuf->by + graybuf->bheight) << 3, LCD_HEIGHT);
145
146 if(y1 > 0) /* refresh part above overlay, full width */
147 rb->lcd_update_rect(0, 0, LCD_WIDTH, y1);
148
149 if(y2 < LCD_HEIGHT) /* refresh part below overlay, full width */
150 rb->lcd_update_rect(0, y2, LCD_WIDTH, LCD_HEIGHT - y2);
151
152 if(x1 > 0) /* refresh part to the left of overlay */
153 rb->lcd_update_rect(0, y1, x1, y2 - y1);
154
155 if(x2 < LCD_WIDTH) /* refresh part to the right of overlay */
156 rb->lcd_update_rect(x2, y1, LCD_WIDTH - x2, y2 - y1);
157
158 graybuf->flags &= ~GRAY_DEFERRED_UPDATE; /* clear request */
159 }
160}
161
162/* Set a pixel to a specific bit pattern
163 * This is the fundamental graphics primitive, asm optimized */
164void graypixel(int x, int y, unsigned long pattern)
165{
166 static short random_buffer;
167 register long address, mask, random;
168
169 /* Some (pseudo-)random function must be used here to shift
170 * the bit pattern randomly, otherwise you would get flicker
171 * and/or moire.
172 * Since rand() is relatively slow, I've implemented a simple,
173 * but very fast pseudo-random generator based on linear
174 * congruency in assembler. It delivers 16 pseudo-random bits
175 * in each iteration.
176 */
177
178 /* simple but fast pseudo-random generator */
179 asm(
180 "mov.w @%1,%0 \n" /* load last value */
181 "mov #75,r1 \n"
182 "mulu %0,r1 \n" /* multiply by 75 */
183 "sts macl,%0 \n" /* get result */
184 "add #74,%0 \n" /* add another 74 */
185 "mov.w %0,@%1 \n" /* store new value */
186 /* Since the lower bits are not very random: */
187 "shlr8 %0 \n" /* get bits 8..15 (need max. 5) */
188 "and %2,%0 \n" /* mask out unneeded bits */
189 : /* outputs */
190 /* %0 */ "=&r"(random)
191 : /* inputs */
192 /* %1 */ "r"(&random_buffer),
193 /* %2 */ "r"(graybuf->randmask)
194 : /* clobbers */
195 "r1","macl"
196 );
197
198 /* precalculate mask and byte address in first bitplane */
199 asm(
200 "mov %3,%0 \n" /* take y as base for address offset */
201 "shlr2 %0 \n" /* shift right by 3 (= divide by 8) */
202 "shlr %0 \n"
203 "mulu %0,%2 \n" /* multiply with width */
204 "and #7,%3 \n" /* get lower 3 bits of y */
205 "sts macl,%0 \n" /* get mulu result */
206 "add %4,%0 \n" /* add base + x to get final address */
207
208 "mov %3,%1 \n" /* move lower 3 bits of y out of r0 */
209 "mova .pp_table,%3 \n" /* get address of mask table in r0 */
210 "bra .pp_end \n" /* skip the table */
211 "mov.b @(%3,%1),%1 \n" /* get entry from mask table */
212
213 ".align 2 \n"
214 ".pp_table: \n" /* mask table */
215 ".byte 0x01 \n"
216 ".byte 0x02 \n"
217 ".byte 0x04 \n"
218 ".byte 0x08 \n"
219 ".byte 0x10 \n"
220 ".byte 0x20 \n"
221 ".byte 0x40 \n"
222 ".byte 0x80 \n"
223
224 ".pp_end: \n"
225 : /* outputs */
226 /* %0 */ "=&r"(address),
227 /* %1 */ "=&r"(mask)
228 : /* inputs */
229 /* %2 */ "r"(graybuf->width),
230 /* %3 = r0 */ "z"(y),
231 /* %4 */ "r"(graybuf->data + x)
232 : /* clobbers */
233 "macl"
234 );
235
236 /* the hard part: set bits in all bitplanes according to pattern */
237 asm(
238 "cmp/hs %1,%5 \n" /* random >= depth ? */
239 "bf .p_ntrim \n"
240 "sub %1,%5 \n" /* yes: random -= depth */
241 /* it's sufficient to do this once, since the mask guarantees
242 * random < 2 * depth */
243 ".p_ntrim: \n"
244
245 /* calculate some addresses */
246 "mulu %4,%1 \n" /* end address offset */
247 "not %3,r1 \n" /* get inverse mask (for "and") */
248 "sts macl,%1 \n" /* result of mulu */
249 "mulu %4,%5 \n" /* address offset of <random>'th plane */
250 "add %2,%1 \n" /* end offset -> end address */
251 "sts macl,%5 \n" /* result of mulu */
252 "add %2,%5 \n" /* address of <random>'th plane */
253 "bra .p_start1 \n"
254 "mov %5,r2 \n" /* copy address */
255
256 /* first loop: set bits from <random>'th bitplane to last */
257 ".p_loop1: \n"
258 "mov.b @r2,r3 \n" /* get data byte */
259 "shlr %0 \n" /* shift bit mask, sets t bit */
260 "and r1,r3 \n" /* reset bit (-> "white") */
261 "bf .p_white1 \n" /* t=0? -> "white" bit */
262 "or %3,r3 \n" /* set bit ("black" bit) */
263 ".p_white1: \n"
264 "mov.b r3,@r2 \n" /* store data byte */
265 "add %4,r2 \n" /* advance address to next bitplane */
266 ".p_start1: \n"
267 "cmp/hi r2,%1 \n" /* address < end address ? */
268 "bt .p_loop1 \n"
269
270 "bra .p_start2 \n"
271 "nop \n"
272
273 /* second loop: set bits from first to <random-1>'th bitplane
274 * Bit setting works the other way round here to equalize average
275 * execution times for bright and dark pixels */
276 ".p_loop2: \n"
277 "mov.b @%2,r3 \n" /* get data byte */
278 "shlr %0 \n" /* shift bit mask, sets t bit */
279 "or %3,r3 \n" /* set bit (-> "black") */
280 "bt .p_black2 \n" /* t=1? -> "black" bit */
281 "and r1,r3 \n" /* reset bit ("white" bit) */
282 ".p_black2: \n"
283 "mov.b r3,@%2 \n" /* store data byte */
284 "add %4,%2 \n" /* advance address to next bitplane */
285 ".p_start2: \n"
286 "cmp/hi %2,%5 \n" /* address < <random>'th address ? */
287 "bt .p_loop2 \n"
288 : /* outputs */
289 : /* inputs */
290 /* %0 */ "r"(pattern),
291 /* %1 */ "r"(graybuf->depth),
292 /* %2 */ "r"(address),
293 /* %3 */ "r"(mask),
294 /* %4 */ "r"(graybuf->plane_size),
295 /* %5 */ "r"(random)
296 : /* clobbers */
297 "r1", "r2", "r3", "macl"
298 );
299}
300
301/* Invert the bits for 1-8 pixels within the buffer */
302void grayinvertmasked(int x, int yb, unsigned char mask)
303{
304 asm(
305 "mulu %4,%5 \n" /* width * by (offset of row) */
306 "mov #0,r1 \n" /* current_plane = 0 */
307 "sts macl,r2 \n" /* get mulu result */
308 "add r2,%1 \n" /* -> address in 1st bitplane */
309
310 ".i_loop: \n"
311 "mov.b @%1,r2 \n" /* get data byte */
312 "add #1,r1 \n" /* current_plane++; */
313 "xor %2,r2 \n" /* invert bits */
314 "mov.b r2,@%1 \n" /* store data byte */
315 "add %3,%1 \n" /* advance address to next bitplane */
316 "cmp/hi r1,%0 \n" /* current_plane < depth ? */
317 "bt .i_loop \n"
318 : /* outputs */
319 : /* inputs */
320 /* %0 */ "r"(graybuf->depth),
321 /* %1 */ "r"(graybuf->data + x),
322 /* %2 */ "r"(mask),
323 /* %3 */ "r"(graybuf->plane_size),
324 /* %4 */ "r"(graybuf->width),
325 /* %5 */ "r"(yb)
326 : /* clobbers */
327 "r1", "r2", "macl"
328 );
329}
330
331/*** public core functions ***/
332
333/** prototypes **/
334
335int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
336 int bheight, int depth);
337void gray_release_buffer(void);
338void gray_position_display(int x, int by);
339void gray_show_display(bool enable);
340
341/** implementation **/
342
343/* Prepare the grayscale display buffer
344 *
345 * arguments:
346 * gbuf = pointer to the memory area to use (e.g. plugin buffer)
347 * gbuf_size = max usable size of the buffer
348 * width = width in pixels (1..112)
349 * bheight = height in 8-pixel units (1..8)
350 * depth = desired number of grayscales - 1 (1..32)
351 *
352 * result:
353 * = depth if there was enough memory
354 * < depth if there wasn't enough memory. The number of displayable
355 * grayscales is smaller than desired, but it still works
356 * = 0 if there wasn't even enough memory for 1 bitplane (black & white)
357 *
358 * You can request any depth from 1 to 32, not just powers of 2. The routine
359 * performs "graceful degradation" if the memory is not sufficient for the
360 * desired depth. As long as there is at least enough memory for 1 bitplane,
361 * it creates as many bitplanes as fit into memory, although 1 bitplane will
362 * only deliver black & white display.
363 *
364 * The total memory needed can be calculated as follows:
365 * total_mem =
366 * sizeof(tGraymap) (= 48 bytes currently)
367 * + sizeof(long) (= 4 bytes)
368 * + (width * bheight + sizeof(long)) * depth
369 */
370int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
371 int bheight, int depth)
372{
373 int plane_size;
374 int possible_depth;
375 int i, j;
376
377 if (width > LCD_WIDTH || bheight > (LCD_HEIGHT >> 3) || depth < 1)
378 return 0;
379
380 plane_size = width * bheight;
381 possible_depth = (gbuf_size - sizeof(tGraybuf) - sizeof(unsigned long))
382 / (plane_size + sizeof(unsigned long));
383
384 if (possible_depth < 1)
385 return 0;
386
387 depth = MIN(depth, 32);
388 depth = MIN(depth, possible_depth);
389
390 graybuf = (tGraybuf *) gbuf; /* global pointer to buffer structure */
391
392 graybuf->x = 0;
393 graybuf->by = 0;
394 graybuf->width = width;
395 graybuf->height = bheight << 3;
396 graybuf->bheight = bheight;
397 graybuf->plane_size = plane_size;
398 graybuf->depth = depth;
399 graybuf->cur_plane = 0;
400 graybuf->flags = 0;
401 graybuf->data = gbuf + sizeof(tGraybuf);
402 graybuf->bitpattern = (unsigned long *) (graybuf->data
403 + depth * plane_size);
404
405 i = depth;
406 j = 8;
407 while (i != 0)
408 {
409 i >>= 1;
410 j--;
411 }
412 graybuf->randmask = 0xFF >> j;
413
414 /* initial state is all white */
415 rb->memset(graybuf->data, 0, depth * plane_size);
416
417 /* Precalculate the bit patterns for all possible pixel values */
418 for (i = 0; i <= depth; i++)
419 {
420 unsigned long pattern = 0;
421 int value = 0;
422
423 for (j = 0; j < depth; j++)
424 {
425 pattern <<= 1;
426 value += i;
427
428 if (value >= depth)
429 value -= depth; /* "white" bit */
430 else
431 pattern |= 1; /* "black" bit */
432 }
433 /* now the lower <depth> bits contain the pattern */
434
435 graybuf->bitpattern[i] = pattern;
436 }
437
438 return depth;
439}
440
441/* Release the grayscale display buffer
442 *
443 * Switches the grayscale overlay off at first if it is still running,
444 * then sets the pointer to NULL.
445 * DO CALL either this function or at least gray_show_display(false)
446 * before you exit, otherwise nasty things may happen.
447 */
448void gray_release_buffer(void)
449{
450 gray_show_display(false);
451 graybuf = NULL;
452}
453
454/* Set position of the top left corner of the grayscale overlay
455 *
456 * arguments:
457 * x = left margin in pixels
458 * by = top margin in 8-pixel units
459 *
460 * You may set this in a way that the overlay spills across the right or
461 * bottom display border. In this case it will simply be clipped by the
462 * LCD controller. You can even set negative values, this will clip at the
463 * left or top border. I did not test it, but the limits may be +127 / -128
464 *
465 * If you use this while the grayscale overlay is running, the now-freed area
466 * will be restored.
467 */
468void gray_position_display(int x, int by)
469{
470 if (graybuf == NULL)
471 return;
472
473 graybuf->x = x;
474 graybuf->by = by;
475
476 if (graybuf->flags & GRAY_RUNNING)
477 graybuf->flags |= GRAY_DEFERRED_UPDATE;
478}
479
480/* Switch the grayscale overlay on or off
481 *
482 * arguments:
483 * enable = true: the grayscale overlay is switched on if initialized
484 * = false: the grayscale overlay is switched off and the regular lcd
485 * content is restored
486 *
487 * DO NOT call lcd_update() or any other api function that directly accesses
488 * the lcd while the grayscale overlay is running! If you need to do
489 * lcd_update() to update something outside the grayscale overlay area, use
490 * gray_deferred_update() instead.
491 *
492 * Other functions to avoid are:
493 * lcd_blit() (obviously), lcd_update_rect(), lcd_set_contrast(),
494 * lcd_set_invert_display(), lcd_set_flip(), lcd_roll()
495 *
496 * The grayscale display consumes ~50 % CPU power (for a full screen overlay,
497 * less if the overlay is smaller) when switched on. You can switch the overlay
498 * on and off as many times as you want.
499 */
500void gray_show_display(bool enable)
501{
502 if (graybuf == NULL)
503 return;
504
505 if (enable)
506 {
507 graybuf->flags |= GRAY_RUNNING;
508 timer_set(FREQ / 67);
509 }
510 else
511 {
512 timer_set(0);
513 graybuf->flags &= ~GRAY_RUNNING;
514 rb->lcd_update(); /* restore whatever there was before */
515 }
516}
517
518/*** public optional functions ***/
519
520/* Here are the various graphics primitives. Cut out functions you do not
521 * need in order to keep plugin code size down.
522 */
523
524/** prototypes **/
525
526/* functions affecting the whole display */
527void gray_clear_display(void);
528//void gray_black_display(void);
529//void gray_deferred_update(void);
530
531/* scrolling functions */
532//void gray_scroll_left(int count, bool black_border);
533//void gray_scroll_right(int count, bool black_border);
534//void gray_scroll_up8(bool black_border);
535//void gray_scroll_down8(bool black_border);
536//void gray_scroll_up1(bool black_border);
537//void gray_scroll_down1(bool black_border);
538//
539/* pixel functions */
540void gray_drawpixel(int x, int y, int brightness);
541//void gray_invertpixel(int x, int y);
542
543/* line functions */
544//void gray_drawline(int x1, int y1, int x2, int y2, int brightness);
545//void gray_invertline(int x1, int y1, int x2, int y2);
546
547/* rectangle functions */
548//void gray_drawrect(int x1, int y1, int x2, int y2, int brightness);
549//void gray_fillrect(int x1, int y1, int x2, int y2, int brightness);
550//void gray_invertrect(int x1, int y1, int x2, int y2);
551
552/* bitmap functions */
553//void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny);
554//void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
555// bool draw_bg, int fg_brightness, int bg_brightness);
556
557/** implementation **/
558
559/* Clear the grayscale display (sets all pixels to white)
560 */
561void gray_clear_display(void)
562{
563 if (graybuf == NULL)
564 return;
565
566 rb->memset(graybuf->data, 0, graybuf->depth * graybuf->plane_size);
567}
568
569/* Set the grayscale display to all black
570 */
571void gray_black_display(void)
572{
573 if (graybuf == NULL)
574 return;
575
576 rb->memset(graybuf->data, 0xFF, graybuf->depth * graybuf->plane_size);
577}
578
579/* Do a lcd_update() to show changes done by rb->lcd_xxx() functions (in areas
580 * of the screen not covered by the grayscale overlay). If the grayscale
581 * overlay is running, the update will be done in the next call of the
582 * interrupt routine, otherwise it will be performed right away. See also
583 * comment for the gray_show_display() function.
584 */
585void gray_deferred_update(void)
586{
587 if (graybuf != NULL && (graybuf->flags & GRAY_RUNNING))
588 graybuf->flags |= GRAY_DEFERRED_UPDATE;
589 else
590 rb->lcd_update();
591}
592
593
594/* Set a pixel to a specific gray value
595 *
596 * brightness is 0..255 (black to white) regardless of real bit depth
597 */
598void gray_drawpixel(int x, int y, int brightness)
599{
600 if (graybuf == NULL || x >= graybuf->width || y >= graybuf->height
601 || brightness > 255)
602 return;
603
604 graypixel(x, y, graybuf->bitpattern[(brightness
605 * (graybuf->depth + 1)) >> 8]);
606}
607
608/* Invert a pixel
609 *
610 * The bit pattern for that pixel in the buffer is inverted, so white
611 * becomes black, light gray becomes dark gray etc.
612 */
613void gray_invertpixel(int x, int y)
614{
615 if (graybuf == NULL || x >= graybuf->width || y >= graybuf->height)
616 return;
617
618 grayinvertmasked(x, (y >> 3), 1 << (y & 7));
619}
620
621
622
623
624
625/**************** end grayscale framework ********************/
626
627
39 628
40void init_mandelbrot_set(void){ 629void init_mandelbrot_set(void){
41 x_min = -5<<25; // -2.5<<26 630 x_min = -5<<25; // -2.0<<26
42 x_max = 1<<26; // 1.0<<26 631 x_max = 1<<26; // 1.0<<26
43 y_min = -1<<26; // -1.0<<26 632 y_min = -1<<26; // -1.0<<26
44 y_max = 1<<26; // 1.0<<26 633 y_max = 1<<26; // 1.0<<26
@@ -53,11 +642,14 @@ void calc_mandelbrot_set(void){
53 int x_pixel, y_pixel; 642 int x_pixel, y_pixel;
54 int x, x2, y, y2, a, b; 643 int x, x2, y, y2, a, b;
55 int x_fact, y_fact; 644 int x_fact, y_fact;
645 int brightness;
56 646
57 start_tick = *rb->current_tick; 647 start_tick = *rb->current_tick;
58 648
59 rb->lcd_clear_display(); 649// rb->lcd_clear_display();
60 rb->lcd_update(); 650// rb->lcd_update();
651
652 gray_clear_display();
61 653
62 x_fact = (x_max - x_min) / LCD_WIDTH; 654 x_fact = (x_max - x_min) / LCD_WIDTH;
63 y_fact = (y_max - y_min) / LCD_HEIGHT; 655 y_fact = (y_max - y_min) / LCD_HEIGHT;
@@ -81,115 +673,132 @@ void calc_mandelbrot_set(void){
81 y = 2 * x * y + b; 673 y = 2 * x * y + b;
82 x = x2 - y2 + a; 674 x = x2 - y2 + a;
83 } 675 }
84 676
85 // "coloring" 677 // "coloring"
86 if ( (n_iter > max_iter) || 678 brightness = 0;
87 (n_iter == (max_iter >> 1)) || 679 if (n_iter > max_iter){
88 (n_iter == (max_iter >> 2)) || 680 brightness = 0; // black
89 (n_iter == (max_iter >> 3)) 681 } else {
90 ){ 682 brightness = 255 - (31 * (n_iter & 7));
91 rb->lcd_drawpixel(x_pixel,y_pixel); 683 }
92 } 684
93 } 685 gray_drawpixel( x_pixel, y_pixel, brightness);
94 686 }
95 /* update block of 8 lines */
96 if ((y_pixel & 0x7) == 0)
97 rb->lcd_update_rect(0, y_pixel, LCD_WIDTH, 8);
98 } 687 }
99
100 /* we want to know how long we had to wait */
101 rb->lcd_setfont(FONT_SYSFIXED);
102 rb->snprintf(buff, sizeof(buff), "%d", (*rb->current_tick - start_tick));
103 rb->lcd_puts(0,0,buff);
104 rb->snprintf(buff, sizeof(buff), "%d", max_iter);
105 rb->lcd_puts(0,1,buff);
106 rb->lcd_update_rect(0,0,24,16);
107} 688}
108 689
690
109enum plugin_status plugin_start(struct plugin_api* api, void* parameter) 691enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
110{ 692{
693 int grayscales;
694 bool redraw = true;
111 695
112 TEST_PLUGIN_API(api); 696 TEST_PLUGIN_API(api);
113 (void)parameter;
114 rb = api; 697 rb = api;
698 (void)parameter;
699
700 /* get the remainder of the plugin buffer */
701 gbuf = (unsigned char *) rb->plugin_get_buffer(&gbuf_size);
702
703 /* initialize the grayscale buffer:
704 * 112 pixels wide, 8 rows (64 pixels) high, (try to) reserve
705 * 16 bitplanes for 17 shades of gray.*/
706 grayscales = gray_init_buffer(gbuf, gbuf_size, 112, 8, 16) + 1;
707 if (grayscales != 17){
708 rb->snprintf(buff, sizeof(buff), "%d", grayscales);
709 rb->lcd_puts(0, 1, buff);
710 rb->lcd_update();
711 rb->sleep(HZ*2);
712 return(0);
713 }
714
715 gray_show_display(true); /* switch on grayscale overlay */
115 716
116 init_mandelbrot_set(); 717 init_mandelbrot_set();
117 lcd_aspect_ratio = ((LCD_WIDTH<<13) / LCD_HEIGHT)<<13; 718 lcd_aspect_ratio = ((LCD_WIDTH<<13) / LCD_HEIGHT)<<13;
118 719
119 /* main loop */ 720 /* main loop */
120 while (true){ 721 while (true){
722 if(redraw)
723 calc_mandelbrot_set();
121 724
122 calc_mandelbrot_set(); 725 redraw = false;
726
727 switch (rb->button_get(true)) {
728 case BUTTON_OFF:
729 gray_release_buffer();
730 return PLUGIN_OK;
123 731
124 /* FIXME: is this the right way to empty the key-queue? 732 case BUTTON_ON:
125 (Otherwise we have to process things twice :-/ ?! */ 733 x_min -= ((delta>>13)*(lcd_aspect_ratio>>13));
126 734 x_max += ((delta>>13)*(lcd_aspect_ratio>>13));
127 rb->button_get(true); 735 y_min -= delta;
736 y_max += delta;
737 delta = (x_max - x_min) >> 3;
738 redraw = true;
739 break;
740
128 741
742 case BUTTON_PLAY:
743 x_min += ((delta>>13)*(lcd_aspect_ratio>>13));
744 x_max -= ((delta>>13)*(lcd_aspect_ratio>>13));
745 y_min += delta;
746 y_max -= delta;
747 delta = (x_max - x_min) >> 3;
748 redraw = true;
749 break;
750
751 case BUTTON_UP:
752 y_min -= delta;
753 y_max -= delta;
754 redraw = true;
755 break;
129 756
130 switch (rb->button_get(true)) { 757 case BUTTON_DOWN:
131 case BUTTON_OFF: 758 y_min += delta;
132 return PLUGIN_OK; 759 y_max += delta;
760 redraw = true;
761 break;
133 762
134 case BUTTON_ON: 763 case BUTTON_LEFT:
135 x_min -= ((delta>>13)*(lcd_aspect_ratio>>13)); 764 x_min -= delta;
136 x_max += ((delta>>13)*(lcd_aspect_ratio>>13)); 765 x_max -= delta;
137 y_min -= delta; 766 redraw = true;
138 y_max += delta; 767 break;
139 delta = (x_max - x_min) >> 3;
140 break;
141
142 768
143 case BUTTON_PLAY: 769 case BUTTON_RIGHT:
144 x_min += ((delta>>13)*(lcd_aspect_ratio>>13)); 770 x_min += delta;
145 x_max -= ((delta>>13)*(lcd_aspect_ratio>>13)); 771 x_max += delta;
146 y_min += delta; 772 redraw = true;
147 y_max -= delta; 773 break;
148 delta = (x_max - x_min) >> 3; 774
149 break; 775 case BUTTON_F1:
150 776 if (max_iter>5){
151 case BUTTON_UP: 777 max_iter -= 5;
152 y_min -= delta; 778 redraw = true;
153 y_max -= delta; 779 }
154 break; 780 break;
155 781
156 case BUTTON_DOWN: 782 case BUTTON_F2:
157 y_min += delta; 783 if (max_iter < 195){
158 y_max += delta; 784 max_iter += 5;
159 break; 785 redraw = true;
160 786 }
161 case BUTTON_LEFT: 787 break;
162 x_min -= delta; 788
163 x_max -= delta; 789 case BUTTON_F3:
164 break; 790 init_mandelbrot_set();
165 791 redraw = true;
166 case BUTTON_RIGHT: 792 break;
167 x_min += delta; 793
168 x_max += delta; 794 case SYS_USB_CONNECTED:
169 break; 795 gray_release_buffer();
170 796 rb->usb_screen();
171 case BUTTON_F1: 797 return PLUGIN_USB_CONNECTED;
172 if (max_iter>5){ 798 }
173 max_iter -= 5;
174 }
175 break;
176
177 case BUTTON_F2:
178 if (max_iter < 195){
179 max_iter += 5;
180 }
181 break;
182
183 case BUTTON_F3:
184 init_mandelbrot_set();
185 break;
186
187
188 case SYS_USB_CONNECTED:
189 rb->usb_screen();
190 return PLUGIN_USB_CONNECTED;
191 }
192 } 799 }
800 gray_release_buffer();
193 return false; 801 return false;
194} 802}
195#endif 803#endif
804#endif