summaryrefslogtreecommitdiff
path: root/apps/plugins/mandelbrot.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/mandelbrot.c')
-rw-r--r--apps/plugins/mandelbrot.c163
1 files changed, 62 insertions, 101 deletions
diff --git a/apps/plugins/mandelbrot.c b/apps/plugins/mandelbrot.c
index 2f5bc53ab0..3d6774a882 100644
--- a/apps/plugins/mandelbrot.c
+++ b/apps/plugins/mandelbrot.c
@@ -34,18 +34,17 @@ static int max_iter;
34static unsigned char *gbuf; 34static unsigned char *gbuf;
35static unsigned int gbuf_size = 0; 35static unsigned int gbuf_size = 0;
36 36
37/**************** Begin grayscale framework ******************/ 37/*********************** Begin grayscale framework *************************/
38 38
39/* This is a generic framework to use grayscale display within 39/* This is a generic framework to use grayscale display within rockbox
40 * rockbox plugins. It obviously does not work for the player. 40 * plugins. It obviously does not work for the player.
41 * 41 *
42 * If you want to use grayscale display within a plugin, copy 42 * If you want to use grayscale display within a plugin, copy this section
43 * this section (up to "End grayscale framework") into your 43 * (up to "End grayscale framework") into your source and you are able to use
44 * source and you are able to use it. For detailed documentation 44 * it. For detailed documentation look at the head of each public function.
45 * look at the head of each public function.
46 * 45 *
47 * It requires a global Rockbox api pointer in "rb" and uses 46 * It requires a global Rockbox api pointer in "rb" and uses the rockbox
48 * timer 4 so you cannot use timer 4 for other purposes while 47 * timer api so you cannot use that timer for other purposes while
49 * displaying grayscale. 48 * displaying grayscale.
50 * 49 *
51 * The framework consists of 3 sections: 50 * The framework consists of 3 sections:
@@ -54,17 +53,15 @@ static unsigned int gbuf_size = 0;
54 * - public core functions 53 * - public core functions
55 * - public optional functions 54 * - public optional functions
56 * 55 *
57 * Usually you will use functions from the latter two sections 56 * Usually you will use functions from the latter two sections in your code.
58 * in your code. You can cut out functions from the third section 57 * You can cut out functions from the third section that you do not need in
59 * that you do not need in order to not waste space. Don't forget 58 * order to not waste space. Don't forget to cut the prototype as well.
60 * to cut the prototype as well.
61 */ 59 */
62 60
63/**** internal core functions and definitions ****/ 61/**** internal core functions and definitions ****/
64 62
65/* You do not want to touch these if you don't know exactly what 63/* You do not want to touch these if you don't know exactly what you're
66 * you're doing. 64 * doing. */
67 */
68 65
69#define GRAY_RUNNING 0x0001 /* grayscale overlay is running */ 66#define GRAY_RUNNING 0x0001 /* grayscale overlay is running */
70#define GRAY_DEFERRED_UPDATE 0x0002 /* lcd_update() requested */ 67#define GRAY_DEFERRED_UPDATE 0x0002 /* lcd_update() requested */
@@ -89,14 +86,14 @@ static tGraybuf *graybuf = NULL;
89 86
90/** prototypes **/ 87/** prototypes **/
91 88
92void timer4_isr(void); 89void timer_isr(void);
93void graypixel(int x, int y, unsigned long pattern); 90void graypixel(int x, int y, unsigned long pattern);
94void grayinvertmasked(int x, int yb, unsigned char mask); 91void grayinvertmasked(int x, int yb, unsigned char mask);
95 92
96/** implementation **/ 93/** implementation **/
97 94
98/* timer interrupt handler: display next bitplane */ 95/* timer interrupt handler: display next bitplane */
99void timer4_isr(void) /* IMIA4 */ 96void timer_isr(void)
100{ 97{
101 rb->lcd_blit(graybuf->data + (graybuf->plane_size * graybuf->cur_plane), 98 rb->lcd_blit(graybuf->data + (graybuf->plane_size * graybuf->cur_plane),
102 graybuf->x, graybuf->by, graybuf->width, graybuf->bheight, 99 graybuf->x, graybuf->by, graybuf->width, graybuf->bheight,
@@ -107,24 +104,24 @@ void timer4_isr(void) /* IMIA4 */
107 104
108 if (graybuf->flags & GRAY_DEFERRED_UPDATE) /* lcd_update() requested? */ 105 if (graybuf->flags & GRAY_DEFERRED_UPDATE) /* lcd_update() requested? */
109 { 106 {
110 int x1 = MAX(graybuf->x, 0); 107 int x1 = MAX(graybuf->x, 0);
111 int x2 = MIN(graybuf->x + graybuf->width, LCD_WIDTH); 108 int x2 = MIN(graybuf->x + graybuf->width, LCD_WIDTH);
112 int y1 = MAX(graybuf->by << 3, 0); 109 int y1 = MAX(graybuf->by << 3, 0);
113 int y2 = MIN((graybuf->by + graybuf->bheight) << 3, LCD_HEIGHT); 110 int y2 = MIN((graybuf->by + graybuf->bheight) << 3, LCD_HEIGHT);
114 111
115 if(y1 > 0) /* refresh part above overlay, full width */ 112 if (y1 > 0) /* refresh part above overlay, full width */
116 rb->lcd_update_rect(0, 0, LCD_WIDTH, y1); 113 rb->lcd_update_rect(0, 0, LCD_WIDTH, y1);
117 114
118 if(y2 < LCD_HEIGHT) /* refresh part below overlay, full width */ 115 if (y2 < LCD_HEIGHT) /* refresh part below overlay, full width */
119 rb->lcd_update_rect(0, y2, LCD_WIDTH, LCD_HEIGHT - y2); 116 rb->lcd_update_rect(0, y2, LCD_WIDTH, LCD_HEIGHT - y2);
120 117
121 if(x1 > 0) /* refresh part to the left of overlay */ 118 if (x1 > 0) /* refresh part to the left of overlay */
122 rb->lcd_update_rect(0, y1, x1, y2 - y1); 119 rb->lcd_update_rect(0, y1, x1, y2 - y1);
123 120
124 if(x2 < LCD_WIDTH) /* refresh part to the right of overlay */ 121 if (x2 < LCD_WIDTH) /* refresh part to the right of overlay */
125 rb->lcd_update_rect(x2, y1, LCD_WIDTH - x2, y2 - y1); 122 rb->lcd_update_rect(x2, y1, LCD_WIDTH - x2, y2 - y1);
126 123
127 graybuf->flags &= ~GRAY_DEFERRED_UPDATE; /* clear request */ 124 graybuf->flags &= ~GRAY_DEFERRED_UPDATE; /* clear request */
128 } 125 }
129} 126}
130 127
@@ -135,14 +132,11 @@ void graypixel(int x, int y, unsigned long pattern)
135 static short random_buffer; 132 static short random_buffer;
136 register long address, mask, random; 133 register long address, mask, random;
137 134
138 /* Some (pseudo-)random function must be used here to shift 135 /* Some (pseudo-)random function must be used here to shift the bit
139 * the bit pattern randomly, otherwise you would get flicker 136 * pattern randomly, otherwise you would get flicker and/or moire.
140 * and/or moire. 137 * Since rand() is relatively slow, I've implemented a simple, but very
141 * Since rand() is relatively slow, I've implemented a simple, 138 * fast pseudo-random generator based on linear congruency in assembler.
142 * but very fast pseudo-random generator based on linear 139 * It delivers 16 pseudo-random bits in each iteration. */
143 * congruency in assembler. It delivers 16 pseudo-random bits
144 * in each iteration.
145 */
146 140
147 /* simple but fast pseudo-random generator */ 141 /* simple but fast pseudo-random generator */
148 asm( 142 asm(
@@ -192,7 +186,7 @@ void graypixel(int x, int y, unsigned long pattern)
192 186
193 ".pp_end: \n" 187 ".pp_end: \n"
194 : /* outputs */ 188 : /* outputs */
195 /* %0 */ "=&r"(address), 189 /* %0 */ "=&r"(address),
196 /* %1 */ "=&r"(mask) 190 /* %1 */ "=&r"(mask)
197 : /* inputs */ 191 : /* inputs */
198 /* %2 */ "r"(graybuf->width), 192 /* %2 */ "r"(graybuf->width),
@@ -268,7 +262,7 @@ void graypixel(int x, int y, unsigned long pattern)
268} 262}
269 263
270/* Invert the bits for 1-8 pixels within the buffer */ 264/* Invert the bits for 1-8 pixels within the buffer */
271void grayinvertmasked(int x, int yb, unsigned char mask) 265void grayinvertmasked(int x, int by, unsigned char mask)
272{ 266{
273 asm( 267 asm(
274 "mulu %4,%5 \n" /* width * by (offset of row) */ 268 "mulu %4,%5 \n" /* width * by (offset of row) */
@@ -291,7 +285,7 @@ void grayinvertmasked(int x, int yb, unsigned char mask)
291 /* %2 */ "r"(mask), 285 /* %2 */ "r"(mask),
292 /* %3 */ "r"(graybuf->plane_size), 286 /* %3 */ "r"(graybuf->plane_size),
293 /* %4 */ "r"(graybuf->width), 287 /* %4 */ "r"(graybuf->width),
294 /* %5 */ "r"(yb) 288 /* %5 */ "r"(by)
295 : /* clobbers */ 289 : /* clobbers */
296 "r1", "r2", "macl" 290 "r1", "r2", "macl"
297 ); 291 );
@@ -316,12 +310,12 @@ void gray_show_display(bool enable);
316 * gbuf_size = max usable size of the buffer 310 * gbuf_size = max usable size of the buffer
317 * width = width in pixels (1..112) 311 * width = width in pixels (1..112)
318 * bheight = height in 8-pixel units (1..8) 312 * bheight = height in 8-pixel units (1..8)
319 * depth = desired number of grayscales - 1 (1..32) 313 * depth = desired number of shades - 1 (1..32)
320 * 314 *
321 * result: 315 * result:
322 * = depth if there was enough memory 316 * = depth if there was enough memory
323 * < depth if there wasn't enough memory. The number of displayable 317 * < depth if there wasn't enough memory. The number of displayable
324 * grayscales is smaller than desired, but it still works 318 * shades is smaller than desired, but it still works
325 * = 0 if there wasn't even enough memory for 1 bitplane (black & white) 319 * = 0 if there wasn't even enough memory for 1 bitplane (black & white)
326 * 320 *
327 * You can request any depth from 1 to 32, not just powers of 2. The routine 321 * You can request any depth from 1 to 32, not just powers of 2. The routine
@@ -335,17 +329,23 @@ void gray_show_display(bool enable);
335 * sizeof(tGraymap) (= 48 bytes currently) 329 * sizeof(tGraymap) (= 48 bytes currently)
336 * + sizeof(long) (= 4 bytes) 330 * + sizeof(long) (= 4 bytes)
337 * + (width * bheight + sizeof(long)) * depth 331 * + (width * bheight + sizeof(long)) * depth
332 * + 0..3 (longword alignment of grayscale display buffer)
338 */ 333 */
339int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width, 334int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
340 int bheight, int depth) 335 int bheight, int depth)
341{ 336{
342 int plane_size; 337 int possible_depth, plane_size;
343 int possible_depth;
344 int i, j; 338 int i, j;
345 339
346 if (width > LCD_WIDTH || bheight > (LCD_HEIGHT >> 3) || depth < 1) 340 if (width > LCD_WIDTH || bheight > (LCD_HEIGHT >> 3) || depth < 1)
347 return 0; 341 return 0;
348 342
343 while ((unsigned long)gbuf & 3) /* the buffer has to be long aligned */
344 {
345 gbuf++;
346 gbuf_size--;
347 }
348
349 plane_size = width * bheight; 349 plane_size = width * bheight;
350 possible_depth = (gbuf_size - sizeof(tGraybuf) - sizeof(unsigned long)) 350 possible_depth = (gbuf_size - sizeof(tGraybuf) - sizeof(unsigned long))
351 / (plane_size + sizeof(unsigned long)); 351 / (plane_size + sizeof(unsigned long));
@@ -375,8 +375,8 @@ int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
375 j = 8; 375 j = 8;
376 while (i != 0) 376 while (i != 0)
377 { 377 {
378 i >>= 1; 378 i >>= 1;
379 j--; 379 j--;
380 } 380 }
381 graybuf->randmask = 0xFF >> j; 381 graybuf->randmask = 0xFF >> j;
382 382
@@ -386,11 +386,11 @@ int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
386 /* Precalculate the bit patterns for all possible pixel values */ 386 /* Precalculate the bit patterns for all possible pixel values */
387 for (i = 0; i <= depth; i++) 387 for (i = 0; i <= depth; i++)
388 { 388 {
389 unsigned long pattern = 0; 389 unsigned long pattern = 0;
390 int value = 0; 390 int value = 0;
391 391
392 for (j = 0; j < depth; j++) 392 for (j = 0; j < depth; j++)
393 { 393 {
394 pattern <<= 1; 394 pattern <<= 1;
395 value += i; 395 value += i;
396 396
@@ -398,10 +398,10 @@ int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
398 value -= depth; /* "white" bit */ 398 value -= depth; /* "white" bit */
399 else 399 else
400 pattern |= 1; /* "black" bit */ 400 pattern |= 1; /* "black" bit */
401 } 401 }
402 /* now the lower <depth> bits contain the pattern */ 402 /* now the lower <depth> bits contain the pattern */
403 403
404 graybuf->bitpattern[i] = pattern; 404 graybuf->bitpattern[i] = pattern;
405 } 405 }
406 406
407 return depth; 407 return depth;
@@ -474,7 +474,7 @@ void gray_show_display(bool enable)
474 if (enable) 474 if (enable)
475 { 475 {
476 graybuf->flags |= GRAY_RUNNING; 476 graybuf->flags |= GRAY_RUNNING;
477 rb->plugin_register_timer(FREQ / 67, 1, timer4_isr); 477 rb->plugin_register_timer(FREQ / 67, 1, timer_isr);
478 } 478 }
479 else 479 else
480 { 480 {
@@ -504,7 +504,7 @@ void gray_clear_display(void);
504//void gray_scroll_down8(bool black_border); 504//void gray_scroll_down8(bool black_border);
505//void gray_scroll_up1(bool black_border); 505//void gray_scroll_up1(bool black_border);
506//void gray_scroll_down1(bool black_border); 506//void gray_scroll_down1(bool black_border);
507// 507
508/* pixel functions */ 508/* pixel functions */
509void gray_drawpixel(int x, int y, int brightness); 509void gray_drawpixel(int x, int y, int brightness);
510//void gray_invertpixel(int x, int y); 510//void gray_invertpixel(int x, int y);
@@ -519,9 +519,11 @@ void gray_drawpixel(int x, int y, int brightness);
519//void gray_invertrect(int x1, int y1, int x2, int y2); 519//void gray_invertrect(int x1, int y1, int x2, int y2);
520 520
521/* bitmap functions */ 521/* bitmap functions */
522//void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny); 522//void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny,
523// int stride);
523//void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny, 524//void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
524// bool draw_bg, int fg_brightness, int bg_brightness); 525// int stride, bool draw_bg, int fg_brightness,
526// int bg_brightness);
525 527
526/** implementation **/ 528/** implementation **/
527 529
@@ -535,31 +537,6 @@ void gray_clear_display(void)
535 rb->memset(graybuf->data, 0, graybuf->depth * graybuf->plane_size); 537 rb->memset(graybuf->data, 0, graybuf->depth * graybuf->plane_size);
536} 538}
537 539
538/* Set the grayscale display to all black
539 */
540void gray_black_display(void)
541{
542 if (graybuf == NULL)
543 return;
544
545 rb->memset(graybuf->data, 0xFF, graybuf->depth * graybuf->plane_size);
546}
547
548/* Do a lcd_update() to show changes done by rb->lcd_xxx() functions (in areas
549 * of the screen not covered by the grayscale overlay). If the grayscale
550 * overlay is running, the update will be done in the next call of the
551 * interrupt routine, otherwise it will be performed right away. See also
552 * comment for the gray_show_display() function.
553 */
554void gray_deferred_update(void)
555{
556 if (graybuf != NULL && (graybuf->flags & GRAY_RUNNING))
557 graybuf->flags |= GRAY_DEFERRED_UPDATE;
558 else
559 rb->lcd_update();
560}
561
562
563/* Set a pixel to a specific gray value 540/* Set a pixel to a specific gray value
564 * 541 *
565 * brightness is 0..255 (black to white) regardless of real bit depth 542 * brightness is 0..255 (black to white) regardless of real bit depth
@@ -574,24 +551,8 @@ void gray_drawpixel(int x, int y, int brightness)
574 * (graybuf->depth + 1)) >> 8]); 551 * (graybuf->depth + 1)) >> 8]);
575} 552}
576 553
577/* Invert a pixel
578 *
579 * The bit pattern for that pixel in the buffer is inverted, so white
580 * becomes black, light gray becomes dark gray etc.
581 */
582void gray_invertpixel(int x, int y)
583{
584 if (graybuf == NULL || x >= graybuf->width || y >= graybuf->height)
585 return;
586
587 grayinvertmasked(x, (y >> 3), 1 << (y & 7));
588}
589
590
591 554
592 555/*********************** end grayscale framework ***************************/
593
594/**************** end grayscale framework ********************/
595 556
596 557
597 558
@@ -630,7 +591,7 @@ void calc_mandelbrot_set(void){
630 x = 0; 591 x = 0;
631 y = 0; 592 y = 0;
632 n_iter = 0; 593 n_iter = 0;
633 594
634 while (++n_iter<=max_iter) { 595 while (++n_iter<=max_iter) {
635 x >>= 13; 596 x >>= 13;
636 y >>= 13; 597 y >>= 13;