diff options
-rw-r--r-- | apps/plugins/mandelbrot.c | 163 |
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; | |||
34 | static unsigned char *gbuf; | 34 | static unsigned char *gbuf; |
35 | static unsigned int gbuf_size = 0; | 35 | static 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 | ||
92 | void timer4_isr(void); | 89 | void timer_isr(void); |
93 | void graypixel(int x, int y, unsigned long pattern); | 90 | void graypixel(int x, int y, unsigned long pattern); |
94 | void grayinvertmasked(int x, int yb, unsigned char mask); | 91 | void 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 */ |
99 | void timer4_isr(void) /* IMIA4 */ | 96 | void 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 */ |
271 | void grayinvertmasked(int x, int yb, unsigned char mask) | 265 | void 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 | */ |
339 | int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width, | 334 | int 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 */ |
509 | void gray_drawpixel(int x, int y, int brightness); | 509 | void 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 | */ | ||
540 | void 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 | */ | ||
554 | void 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 | */ | ||
582 | void 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; |