fix some problems with the menu code:
[kugel-rb.git] / apps / plugins / mandelbrot.c
blobca7f708fc8d709bb1843335c13eb4ed90310475f
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2004 Matthias Wientapper
11 * Heavily extended 2005 Jens Arnold
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
23 #include "plugin.h"
25 #ifdef HAVE_LCD_BITMAP
26 #include "grey.h"
27 #include "xlcd.h"
29 PLUGIN_HEADER
31 /* variable button definitions */
32 #if CONFIG_KEYPAD == RECORDER_PAD
33 #define MANDELBROT_QUIT BUTTON_OFF
34 #define MANDELBROT_UP BUTTON_UP
35 #define MANDELBROT_DOWN BUTTON_DOWN
36 #define MANDELBROT_LEFT BUTTON_LEFT
37 #define MANDELBROT_RIGHT BUTTON_RIGHT
38 #define MANDELBROT_ZOOM_IN BUTTON_PLAY
39 #define MANDELBROT_ZOOM_OUT BUTTON_ON
40 #define MANDELBROT_MAXITER_INC BUTTON_F2
41 #define MANDELBROT_MAXITER_DEC BUTTON_F1
42 #define MANDELBROT_RESET BUTTON_F3
44 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
45 #define MANDELBROT_QUIT BUTTON_OFF
46 #define MANDELBROT_UP BUTTON_UP
47 #define MANDELBROT_DOWN BUTTON_DOWN
48 #define MANDELBROT_LEFT BUTTON_LEFT
49 #define MANDELBROT_RIGHT BUTTON_RIGHT
50 #define MANDELBROT_ZOOM_IN BUTTON_SELECT
51 #define MANDELBROT_ZOOM_OUT BUTTON_ON
52 #define MANDELBROT_MAXITER_INC BUTTON_F2
53 #define MANDELBROT_MAXITER_DEC BUTTON_F1
54 #define MANDELBROT_RESET BUTTON_F3
56 #elif CONFIG_KEYPAD == ONDIO_PAD
57 #define MANDELBROT_QUIT BUTTON_OFF
58 #define MANDELBROT_UP BUTTON_UP
59 #define MANDELBROT_DOWN BUTTON_DOWN
60 #define MANDELBROT_LEFT BUTTON_LEFT
61 #define MANDELBROT_RIGHT BUTTON_RIGHT
62 #define MANDELBROT_ZOOM_IN_PRE BUTTON_MENU
63 #define MANDELBROT_ZOOM_IN (BUTTON_MENU | BUTTON_REL)
64 #define MANDELBROT_ZOOM_IN2 (BUTTON_MENU | BUTTON_UP)
65 #define MANDELBROT_ZOOM_OUT (BUTTON_MENU | BUTTON_DOWN)
66 #define MANDELBROT_MAXITER_INC (BUTTON_MENU | BUTTON_RIGHT)
67 #define MANDELBROT_MAXITER_DEC (BUTTON_MENU | BUTTON_LEFT)
68 #define MANDELBROT_RESET (BUTTON_MENU | BUTTON_OFF)
70 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
71 (CONFIG_KEYPAD == IRIVER_H300_PAD)
72 #define MANDELBROT_QUIT BUTTON_OFF
73 #define MANDELBROT_UP BUTTON_UP
74 #define MANDELBROT_DOWN BUTTON_DOWN
75 #define MANDELBROT_LEFT BUTTON_LEFT
76 #define MANDELBROT_RIGHT BUTTON_RIGHT
77 #define MANDELBROT_ZOOM_IN BUTTON_SELECT
78 #define MANDELBROT_ZOOM_OUT BUTTON_MODE
79 #define MANDELBROT_MAXITER_INC (BUTTON_ON | BUTTON_RIGHT)
80 #define MANDELBROT_MAXITER_DEC (BUTTON_ON | BUTTON_LEFT)
81 #define MANDELBROT_RESET BUTTON_REC
83 #define MANDELBROT_RC_QUIT BUTTON_RC_STOP
85 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
86 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
87 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
88 #define MANDELBROT_QUIT (BUTTON_SELECT | BUTTON_MENU)
89 #define MANDELBROT_UP BUTTON_MENU
90 #define MANDELBROT_DOWN BUTTON_PLAY
91 #define MANDELBROT_LEFT BUTTON_LEFT
92 #define MANDELBROT_RIGHT BUTTON_RIGHT
93 #define MANDELBROT_ZOOM_IN BUTTON_SCROLL_FWD
94 #define MANDELBROT_ZOOM_OUT BUTTON_SCROLL_BACK
95 #define MANDELBROT_MAXITER_INC (BUTTON_SELECT | BUTTON_RIGHT)
96 #define MANDELBROT_MAXITER_DEC (BUTTON_SELECT | BUTTON_LEFT)
97 #define MANDELBROT_RESET (BUTTON_SELECT | BUTTON_PLAY)
99 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
100 #define MANDELBROT_QUIT BUTTON_POWER
101 #define MANDELBROT_UP BUTTON_UP
102 #define MANDELBROT_DOWN BUTTON_DOWN
103 #define MANDELBROT_LEFT BUTTON_LEFT
104 #define MANDELBROT_RIGHT BUTTON_RIGHT
105 #define MANDELBROT_ZOOM_IN_PRE BUTTON_SELECT
106 #define MANDELBROT_ZOOM_IN (BUTTON_SELECT | BUTTON_REL)
107 #define MANDELBROT_ZOOM_OUT_PRE BUTTON_SELECT
108 #define MANDELBROT_ZOOM_OUT (BUTTON_SELECT | BUTTON_REPEAT)
109 #define MANDELBROT_MAXITER_INC_PRE BUTTON_PLAY
110 #define MANDELBROT_MAXITER_INC (BUTTON_PLAY | BUTTON_REL)
111 #define MANDELBROT_MAXITER_DEC_PRE BUTTON_PLAY
112 #define MANDELBROT_MAXITER_DEC (BUTTON_PLAY | BUTTON_REPEAT)
113 #define MANDELBROT_RESET BUTTON_REC
115 #elif CONFIG_KEYPAD == GIGABEAT_PAD
116 #define MANDELBROT_QUIT BUTTON_POWER
117 #define MANDELBROT_UP BUTTON_UP
118 #define MANDELBROT_DOWN BUTTON_DOWN
119 #define MANDELBROT_LEFT BUTTON_LEFT
120 #define MANDELBROT_RIGHT BUTTON_RIGHT
121 #define MANDELBROT_ZOOM_IN_PRE BUTTON_SELECT
122 #define MANDELBROT_ZOOM_IN (BUTTON_SELECT | BUTTON_REL)
123 #define MANDELBROT_ZOOM_OUT_PRE BUTTON_SELECT
124 #define MANDELBROT_ZOOM_OUT (BUTTON_SELECT | BUTTON_REPEAT)
125 #define MANDELBROT_MAXITER_INC BUTTON_VOL_UP
126 #define MANDELBROT_MAXITER_DEC BUTTON_VOL_DOWN
127 #define MANDELBROT_RESET BUTTON_A
129 #elif CONFIG_KEYPAD == SANSA_E200_PAD
130 #define MANDELBROT_QUIT BUTTON_POWER
131 #define MANDELBROT_UP BUTTON_UP
132 #define MANDELBROT_DOWN BUTTON_DOWN
133 #define MANDELBROT_LEFT BUTTON_LEFT
134 #define MANDELBROT_RIGHT BUTTON_RIGHT
135 #define MANDELBROT_ZOOM_IN BUTTON_SCROLL_FWD
136 #define MANDELBROT_ZOOM_OUT BUTTON_SCROLL_BACK
137 #define MANDELBROT_MAXITER_INC (BUTTON_SELECT | BUTTON_RIGHT)
138 #define MANDELBROT_MAXITER_DEC (BUTTON_SELECT | BUTTON_LEFT)
139 #define MANDELBROT_RESET BUTTON_REC
141 #elif CONFIG_KEYPAD == SANSA_C200_PAD
142 #define MANDELBROT_QUIT BUTTON_POWER
143 #define MANDELBROT_UP BUTTON_UP
144 #define MANDELBROT_DOWN BUTTON_DOWN
145 #define MANDELBROT_LEFT BUTTON_LEFT
146 #define MANDELBROT_RIGHT BUTTON_RIGHT
147 #define MANDELBROT_ZOOM_IN BUTTON_VOL_UP
148 #define MANDELBROT_ZOOM_OUT BUTTON_VOL_DOWN
149 #define MANDELBROT_MAXITER_INC (BUTTON_SELECT | BUTTON_RIGHT)
150 #define MANDELBROT_MAXITER_DEC (BUTTON_SELECT | BUTTON_LEFT)
151 #define MANDELBROT_RESET BUTTON_REC
153 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
154 #define MANDELBROT_QUIT BUTTON_POWER
155 #define MANDELBROT_UP BUTTON_SCROLL_UP
156 #define MANDELBROT_DOWN BUTTON_SCROLL_DOWN
157 #define MANDELBROT_LEFT BUTTON_LEFT
158 #define MANDELBROT_RIGHT BUTTON_RIGHT
159 #define MANDELBROT_ZOOM_IN_PRE BUTTON_PLAY
160 #define MANDELBROT_ZOOM_IN (BUTTON_PLAY | BUTTON_REL)
161 #define MANDELBROT_ZOOM_OUT_PRE BUTTON_PLAY
162 #define MANDELBROT_ZOOM_OUT (BUTTON_PLAY | BUTTON_REPEAT)
163 #define MANDELBROT_MAXITER_INC BUTTON_FF
164 #define MANDELBROT_MAXITER_DEC BUTTON_REW
165 #define MANDELBROT_RESET (BUTTON_PLAY | BUTTON_REW)
167 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
168 #define MANDELBROT_QUIT BUTTON_EQ
169 #define MANDELBROT_UP BUTTON_UP
170 #define MANDELBROT_DOWN BUTTON_DOWN
171 #define MANDELBROT_LEFT BUTTON_LEFT
172 #define MANDELBROT_RIGHT BUTTON_RIGHT
173 #define MANDELBROT_ZOOM_IN_PRE BUTTON_SELECT
174 #define MANDELBROT_ZOOM_IN (BUTTON_SELECT | BUTTON_REL)
175 #define MANDELBROT_ZOOM_OUT_PRE BUTTON_SELECT
176 #define MANDELBROT_ZOOM_OUT (BUTTON_SELECT | BUTTON_REPEAT)
177 #define MANDELBROT_MAXITER_INC (BUTTON_PLAY | BUTTON_RIGHT)
178 #define MANDELBROT_MAXITER_DEC (BUTTON_PLAY | BUTTON_LEFT)
179 #define MANDELBROT_RESET BUTTON_MODE
181 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
182 #define MANDELBROT_QUIT BUTTON_BACK
183 #define MANDELBROT_UP BUTTON_UP
184 #define MANDELBROT_DOWN BUTTON_DOWN
185 #define MANDELBROT_LEFT BUTTON_LEFT
186 #define MANDELBROT_RIGHT BUTTON_RIGHT
187 #define MANDELBROT_ZOOM_IN BUTTON_VOL_UP
188 #define MANDELBROT_ZOOM_OUT BUTTON_VOL_DOWN
189 #define MANDELBROT_MAXITER_INC BUTTON_PREV
190 #define MANDELBROT_MAXITER_DEC BUTTON_NEXT
191 #define MANDELBROT_RESET BUTTON_MENU
193 #elif CONFIG_KEYPAD == MROBE100_PAD
194 #define MANDELBROT_QUIT BUTTON_POWER
195 #define MANDELBROT_UP BUTTON_UP
196 #define MANDELBROT_DOWN BUTTON_DOWN
197 #define MANDELBROT_LEFT BUTTON_LEFT
198 #define MANDELBROT_RIGHT BUTTON_RIGHT
199 #define MANDELBROT_ZOOM_IN_PRE BUTTON_SELECT
200 #define MANDELBROT_ZOOM_IN (BUTTON_SELECT | BUTTON_REL)
201 #define MANDELBROT_ZOOM_OUT_PRE BUTTON_SELECT
202 #define MANDELBROT_ZOOM_OUT (BUTTON_SELECT | BUTTON_REPEAT)
203 #define MANDELBROT_MAXITER_INC BUTTON_MENU
204 #define MANDELBROT_MAXITER_DEC BUTTON_PLAY
205 #define MANDELBROT_RESET BUTTON_DISPLAY
207 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
208 #define MANDELBROT_QUIT BUTTON_RC_REC
209 #define MANDELBROT_UP BUTTON_RC_VOL_UP
210 #define MANDELBROT_DOWN BUTTON_RC_VOL_DOWN
211 #define MANDELBROT_LEFT BUTTON_RC_REW
212 #define MANDELBROT_RIGHT BUTTON_RC_FF
213 #define MANDELBROT_ZOOM_IN_PRE BUTTON_RC_PLAY
214 #define MANDELBROT_ZOOM_IN (BUTTON_RC_PLAY | BUTTON_REL)
215 #define MANDELBROT_ZOOM_OUT_PRE BUTTON_RC_PLAY
216 #define MANDELBROT_ZOOM_OUT (BUTTON_RC_PLAY | BUTTON_REPEAT)
217 #define MANDELBROT_MAXITER_INC_PRE BUTTON_RC_MODE
218 #define MANDELBROT_MAXITER_INC (BUTTON_RC_MODE|BUTTON_REL)
219 #define MANDELBROT_MAXITER_DEC_PRE BUTTON_RC_MODE
220 #define MANDELBROT_MAXITER_DEC (BUTTON_RC_MODE|BUTTON_REPEAT)
221 #define MANDELBROT_RESET BUTTON_RC_MENU
223 #elif CONFIG_KEYPAD == COWOND2_PAD
224 #define MANDELBROT_QUIT BUTTON_POWER
226 #else
227 #error No keymap defined!
228 #endif
230 #ifdef HAVE_TOUCHSCREEN
231 #ifndef MANDELBROT_UP
232 #define MANDELBROT_UP BUTTON_TOPMIDDLE
233 #endif
234 #ifndef MANDELBROT_DOWN
235 #define MANDELBROT_DOWN BUTTON_BOTTOMMIDDLE
236 #endif
237 #ifndef MANDELBROT_LEFT
238 #define MANDELBROT_LEFT BUTTON_MIDLEFT
239 #endif
240 #ifndef MANDELBROT_RIGHT
241 #define MANDELBROT_RIGHT BUTTON_MIDRIGHT
242 #endif
243 #ifndef MANDELBROT_ZOOM_IN_PRE
244 #define MANDELBROT_ZOOM_IN_PRE BUTTON_TOPRIGHT
245 #endif
246 #ifndef MANDELBROT_ZOOM_IN
247 #define MANDELBROT_ZOOM_IN (BUTTON_TOPRIGHT | BUTTON_REL)
248 #endif
249 #ifndef MANDELBROT_ZOOM_OUT_PRE
250 #define MANDELBROT_ZOOM_OUT_PRE BUTTON_TOPLEFT
251 #endif
252 #ifndef MANDELBROT_ZOOM_OUT
253 #define MANDELBROT_ZOOM_OUT (BUTTON_TOPLEFT | BUTTON_REL)
254 #endif
255 #ifndef MANDELBROT_MAXITER_INC
256 #define MANDELBROT_MAXITER_INC BUTTON_BOTTOMRIGHT
257 #endif
258 #ifndef MANDELBROT_MAXITER_DEC
259 #define MANDELBROT_MAXITER_DEC BUTTON_BOTTOMLEFT
260 #endif
261 #ifndef MANDELBROT_RESET
262 #define MANDELBROT_RESET BUTTON_CENTER
263 #endif
264 #endif
266 #if LCD_DEPTH < 8
267 #define USEGSLIB
268 #define MYLCD(fn) grey_ub_ ## fn
269 #define MYLCD_UPDATE()
270 #define MYXLCD(fn) grey_ub_ ## fn
271 #else
272 #define UPDATE_FREQ (HZ/50)
273 #define MYLCD(fn) rb->lcd_ ## fn
274 #define MYLCD_UPDATE() rb->lcd_update();
275 #define MYXLCD(fn) xlcd_ ## fn
276 #endif
278 static const struct plugin_api* rb;
280 /* Fixed point format s5.26: sign, 5 bits integer part, 26 bits fractional part */
281 static long x_min;
282 static long x_max;
283 static long x_step;
284 static long x_delta;
285 static long y_min;
286 static long y_max;
287 static long y_step;
288 static long y_delta;
290 static int px_min = 0;
291 static int px_max = LCD_WIDTH;
292 static int py_min = 0;
293 static int py_max = LCD_HEIGHT;
295 static int step_log2;
296 static unsigned max_iter;
298 #ifdef USEGSLIB
299 GREY_INFO_STRUCT
300 static unsigned char *gbuf;
301 static size_t gbuf_size = 0;
302 static unsigned char imgbuffer[LCD_HEIGHT];
303 #else
304 static fb_data imgbuffer[LCD_HEIGHT];
305 #endif
307 /* 8 entries cyclical, last entry is black (convergence) */
308 #ifdef HAVE_LCD_COLOR
309 static const fb_data color[9] = {
310 LCD_RGBPACK(255, 0, 159), LCD_RGBPACK(159, 0, 255), LCD_RGBPACK(0, 0, 255),
311 LCD_RGBPACK(0, 159, 255), LCD_RGBPACK(0, 255, 128), LCD_RGBPACK(128, 255, 0),
312 LCD_RGBPACK(255, 191, 0), LCD_RGBPACK(255, 0, 0), LCD_RGBPACK(0, 0, 0)
314 #else /* greyscale */
315 static const fb_data color[9] = {
316 255, 223, 191, 159, 128, 96, 64, 32, 0
318 #endif
320 #if CONFIG_CPU == SH7034
322 #define MULS16_ASR10(a, b) muls16_asr10(a, b)
323 static inline short muls16_asr10(short a, short b)
325 short r;
326 asm (
327 "muls %[a],%[b] \n"
328 "sts macl,%[r] \n"
329 "shlr8 %[r] \n"
330 "shlr2 %[r] \n"
331 : /* outputs */
332 [r]"=r"(r)
333 : /* inputs */
334 [a]"r"(a),
335 [b]"r"(b)
337 return r;
340 #define MULS32_ASR26(a, b) muls32_asr26(a, b)
341 static inline long muls32_asr26(long a, long b)
343 long r, t1, t2, t3;
344 asm (
345 /* Signed 32bit * 32bit -> 64bit multiplication.
346 Notation: xxab * xxcd, where each letter represents 16 bits.
347 xx is the 64 bit sign extension. */
348 "swap.w %[a],%[t1] \n" /* t1 = ba */
349 "mulu %[t1],%[b] \n" /* a * d */
350 "swap.w %[b],%[t3] \n" /* t3 = dc */
351 "sts macl,%[t2] \n" /* t2 = a * d */
352 "mulu %[t1],%[t3] \n" /* a * c */
353 "sts macl,%[r] \n" /* hi = a * c */
354 "mulu %[a],%[t3] \n" /* b * c */
355 "clrt \n"
356 "sts macl,%[t3] \n" /* t3 = b * c */
357 "addc %[t2],%[t3] \n" /* t3 += t2, carry -> t2 */
358 "movt %[t2] \n"
359 "mulu %[a],%[b] \n" /* b * d */
360 "mov %[t3],%[t1] \n" /* t2t3 <<= 16 */
361 "xtrct %[t2],%[t1] \n"
362 "mov %[t1],%[t2] \n"
363 "shll16 %[t3] \n"
364 "sts macl,%[t1] \n" /* lo = b * d */
365 "clrt \n" /* hi.lo += t2t3 */
366 "addc %[t3],%[t1] \n"
367 "addc %[t2],%[r] \n"
368 "cmp/pz %[a] \n" /* ab >= 0 ? */
369 "bt 1f \n"
370 "sub %[b],%[r] \n" /* no: hi -= cd (sign extension of ab is -1) */
371 "1: \n"
372 "cmp/pz %[b] \n" /* cd >= 0 ? */
373 "bt 2f \n"
374 "sub %[a],%[r] \n" /* no: hi -= ab (sign extension of cd is -1) */
375 "2: \n"
376 /* Shift right by 26 and return low 32 bits */
377 "shll2 %[r] \n" /* hi <<= 6 */
378 "shll2 %[r] \n"
379 "shll2 %[r] \n"
380 "shlr16 %[t1] \n" /* (unsigned)lo >>= 26 */
381 "shlr8 %[t1] \n"
382 "shlr2 %[t1] \n"
383 "or %[t1],%[r] \n" /* combine result */
384 : /* outputs */
385 [r] "=&r"(r),
386 [t1]"=&r"(t1),
387 [t2]"=&r"(t2),
388 [t3]"=&r"(t3)
389 : /* inputs */
390 [a] "r" (a),
391 [b] "r" (b)
393 return r;
396 #elif defined CPU_COLDFIRE
398 #define MULS16_ASR10(a, b) muls16_asr10(a, b)
399 static inline short muls16_asr10(short a, short b)
401 asm (
402 "muls.w %[a],%[b] \n"
403 "asr.l #8,%[b] \n"
404 "asr.l #2,%[b] \n"
405 : /* outputs */
406 [b]"+d"(b)
407 : /* inputs */
408 [a]"d" (a)
410 return b;
413 /* Needs the EMAC initialised to fractional mode w/o rounding and saturation */
414 #define MULS32_INIT() coldfire_set_macsr(EMAC_FRACTIONAL)
415 #define MULS32_ASR26(a, b) muls32_asr26(a, b)
416 static inline long muls32_asr26(long a, long b)
418 long r, t1;
419 asm (
420 "mac.l %[a], %[b], %%acc0 \n" /* multiply */
421 "move.l %%accext01, %[t1] \n" /* get low part */
422 "movclr.l %%acc0, %[r] \n" /* get high part */
423 "asl.l #5, %[r] \n" /* hi <<= 5, plus one free */
424 "lsr.l #3, %[t1] \n" /* lo >>= 3 */
425 "and.l #0x1f, %[t1] \n" /* mask out unrelated bits */
426 "or.l %[t1], %[r] \n" /* combine result */
427 : /* outputs */
428 [r] "=d"(r),
429 [t1]"=d"(t1)
430 : /* inputs */
431 [a] "d" (a),
432 [b] "d" (b)
434 return r;
437 #elif defined CPU_ARM
439 #define MULS32_ASR26(a, b) muls32_asr26(a, b)
440 static inline long muls32_asr26(long a, long b)
442 long r, t1;
443 asm (
444 "smull %[r], %[t1], %[a], %[b] \n"
445 "mov %[r], %[r], lsr #26 \n"
446 "orr %[r], %[r], %[t1], lsl #6 \n"
447 : /* outputs */
448 [r] "=&r,&r,&r"(r),
449 [t1]"=&r,&r,&r"(t1)
450 : /* inputs */
451 [a] "%r,%r,%r" (a),
452 [b] "r,0,1" (b)
454 return r;
457 #endif /* CPU */
459 /* default macros */
460 #ifndef MULS16_ASR10
461 #define MULS16_ASR10(a, b) ((short)(((long)(a) * (long)(b)) >> 10))
462 #endif
463 #ifndef MULS32_ASR26
464 #define MULS32_ASR26(a, b) ((long)(((long long)(a) * (long long)(b)) >> 26))
465 #endif
466 #ifndef MULS32_INIT
467 #define MULS32_INIT()
468 #endif
470 int ilog2_fp(long value) /* calculate integer log2(value_fp_6.26) */
472 int i = 0;
474 if (value <= 0) {
475 return -32767;
476 } else if (value > (1L<<26)) {
477 while (value >= (2L<<26)) {
478 value >>= 1;
479 i++;
481 } else {
482 while (value < (1L<<26)) {
483 value <<= 1;
484 i--;
487 return i;
490 void recalc_parameters(void)
492 x_step = (x_max - x_min) / LCD_WIDTH;
493 x_delta = (x_step * LCD_WIDTH) / 8;
494 y_step = (y_max - y_min) / LCD_HEIGHT;
495 y_delta = (y_step * LCD_HEIGHT) / 8;
496 step_log2 = ilog2_fp(MIN(x_step, y_step));
497 max_iter = MAX(15, -15 * step_log2 - 45);
500 #if CONFIG_LCD == LCD_SSD1815
501 /* Recorder, Ondio: pixel_height == 1.25 * pixel_width */
502 #define MB_HEIGHT (LCD_HEIGHT*5/4)
503 #else
504 /* square pixels */
505 #define MB_HEIGHT LCD_HEIGHT
506 #endif
508 #define MB_XOFS (-0x03000000L) /* -0.75 (s5.26) */
509 #if 3000*MB_HEIGHT/LCD_WIDTH >= 2400 /* width is limiting factor */
510 #define MB_XFAC (0x06000000LL) /* 1.5 (s5.26) */
511 #define MB_YFAC (MB_XFAC*MB_HEIGHT/LCD_WIDTH)
512 #else /* height is limiting factor */
513 #define MB_YFAC (0x04cccccdLL) /* 1.2 (s5.26) */
514 #define MB_XFAC (MB_YFAC*LCD_WIDTH/MB_HEIGHT)
515 #endif
517 void init_mandelbrot_set(void)
519 x_min = MB_XOFS-MB_XFAC;
520 x_max = MB_XOFS+MB_XFAC;
521 y_min = -MB_YFAC;
522 y_max = MB_YFAC;
523 recalc_parameters();
526 void calc_mandelbrot_low_prec(void)
528 long start_tick, last_yield;
529 #ifndef USEGSLIB
530 long next_update = *rb->current_tick;
531 int last_px = px_min;
532 #endif
533 unsigned n_iter;
534 long a32, b32;
535 short x, x2, y, y2, a, b;
536 int p_x, p_y;
538 start_tick = last_yield = *rb->current_tick;
540 for (p_x = 0, a32 = x_min; p_x < px_max; p_x++, a32 += x_step) {
541 if (p_x < px_min)
542 continue;
543 a = a32 >> 16;
544 for (p_y = LCD_HEIGHT-1, b32 = y_min; p_y >= py_min; p_y--, b32 += y_step) {
545 if (p_y >= py_max)
546 continue;
547 b = b32 >> 16;
548 x = a;
549 y = b;
550 n_iter = 0;
552 while (++n_iter <= max_iter) {
553 x2 = MULS16_ASR10(x, x);
554 y2 = MULS16_ASR10(y, y);
556 if (x2 + y2 > (4<<10)) break;
558 y = 2 * MULS16_ASR10(x, y) + b;
559 x = x2 - y2 + a;
562 if (n_iter > max_iter)
563 imgbuffer[p_y] = color[8];
564 else
565 imgbuffer[p_y] = color[n_iter & 7];
567 /* be nice to other threads:
568 * if at least one tick has passed, yield */
569 if (*rb->current_tick > last_yield) {
570 rb->yield();
571 last_yield = *rb->current_tick;
574 #ifdef USEGSLIB
575 grey_ub_gray_bitmap_part(imgbuffer, 0, py_min, 1,
576 p_x, py_min, 1, py_max - py_min);
577 #else
578 rb->lcd_bitmap_part(imgbuffer, 0, py_min, 1,
579 p_x, py_min, 1, py_max - py_min);
580 if ((p_x == px_max - 1) || TIME_AFTER(*rb->current_tick, next_update))
582 next_update = *rb->current_tick + UPDATE_FREQ;
583 rb->lcd_update_rect(last_px, py_min, p_x - last_px + 1,
584 py_max - py_min);
585 last_px = p_x;
587 #endif
591 void calc_mandelbrot_high_prec(void)
593 long start_tick, last_yield;
594 #ifndef USEGSLIB
595 long next_update = *rb->current_tick;
596 int last_px = px_min;
597 #endif
598 unsigned n_iter;
599 long x, x2, y, y2, a, b;
600 int p_x, p_y;
602 MULS32_INIT();
603 start_tick = last_yield = *rb->current_tick;
605 for (p_x = 0, a = x_min; p_x < px_max; p_x++, a += x_step) {
606 if (p_x < px_min)
607 continue;
608 for (p_y = LCD_HEIGHT-1, b = y_min; p_y >= py_min; p_y--, b += y_step) {
609 if (p_y >= py_max)
610 continue;
611 x = a;
612 y = b;
613 n_iter = 0;
615 while (++n_iter <= max_iter) {
616 x2 = MULS32_ASR26(x, x);
617 y2 = MULS32_ASR26(y, y);
619 if (x2 + y2 > (4L<<26)) break;
621 y = 2 * MULS32_ASR26(x, y) + b;
622 x = x2 - y2 + a;
625 if (n_iter > max_iter)
626 imgbuffer[p_y] = color[8];
627 else
628 imgbuffer[p_y] = color[n_iter & 7];
630 /* be nice to other threads:
631 * if at least one tick has passed, yield */
632 if (*rb->current_tick > last_yield) {
633 rb->yield();
634 last_yield = *rb->current_tick;
637 #ifdef USEGSLIB
638 grey_ub_gray_bitmap_part(imgbuffer, 0, py_min, 1,
639 p_x, py_min, 1, py_max - py_min);
640 #else
641 rb->lcd_bitmap_part(imgbuffer, 0, py_min, 1,
642 p_x, py_min, 1, py_max-py_min);
643 if ((p_x == px_max - 1) || TIME_AFTER(*rb->current_tick, next_update))
645 next_update = *rb->current_tick + UPDATE_FREQ;
646 rb->lcd_update_rect(last_px, py_min, p_x - last_px + 1,
647 py_max - py_min);
648 last_px = p_x;
650 #endif
654 void cleanup(void *parameter)
656 (void)parameter;
657 #ifdef USEGSLIB
658 grey_release();
659 #endif
662 #define REDRAW_NONE 0
663 #define REDRAW_PARTIAL 1
664 #define REDRAW_FULL 2
666 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
668 int button;
669 int lastbutton = BUTTON_NONE;
670 int redraw = REDRAW_FULL;
672 rb = api;
673 (void)parameter;
675 #ifdef USEGSLIB
676 /* get the remainder of the plugin buffer */
677 gbuf = (unsigned char *) rb->plugin_get_buffer(&gbuf_size);
679 /* initialize the greyscale buffer.*/
680 if (!grey_init(rb, gbuf, gbuf_size, GREY_ON_COP,
681 LCD_WIDTH, LCD_HEIGHT, NULL))
683 rb->splash(HZ, "Couldn't init greyscale display");
684 return 0;
686 grey_show(true); /* switch on greyscale overlay */
687 #else
688 xlcd_init(rb);
689 #endif
691 #if LCD_DEPTH > 1
692 rb->lcd_set_backdrop(NULL);
693 #endif
695 init_mandelbrot_set();
697 /* main loop */
698 while (true) {
699 if (redraw > REDRAW_NONE) {
700 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
701 rb->cpu_boost(true);
702 #endif
703 if (redraw == REDRAW_FULL) {
704 MYLCD(clear_display)();
705 MYLCD_UPDATE();
708 if (step_log2 <= -10) /* select precision */
709 calc_mandelbrot_high_prec();
710 else
711 calc_mandelbrot_low_prec();
713 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
714 rb->cpu_boost(false);
715 #endif
716 px_min = 0;
717 px_max = LCD_WIDTH;
718 py_min = 0;
719 py_max = LCD_HEIGHT;
720 redraw = REDRAW_NONE;
723 button = rb->button_get(true);
724 switch (button) {
725 #ifdef MANDELBROT_RC_QUIT
726 case MANDELBROT_RC_QUIT:
727 #endif
728 case MANDELBROT_QUIT:
729 #ifdef USEGSLIB
730 grey_release();
731 #endif
732 return PLUGIN_OK;
734 case MANDELBROT_ZOOM_OUT:
735 #ifdef MANDELBROT_ZOOM_OUT_PRE
736 if (lastbutton != MANDELBROT_ZOOM_OUT_PRE)
737 break;
738 #endif
739 x_min -= x_delta;
740 x_max += x_delta;
741 y_min -= y_delta;
742 y_max += y_delta;
743 recalc_parameters();
744 redraw = REDRAW_FULL;
745 break;
748 case MANDELBROT_ZOOM_IN:
749 #ifdef MANDELBROT_ZOOM_IN_PRE
750 if (lastbutton != MANDELBROT_ZOOM_IN_PRE)
751 break;
752 #endif
753 #ifdef MANDELBROT_ZOOM_IN2
754 case MANDELBROT_ZOOM_IN2:
755 #endif
756 x_min += x_delta;
757 x_max -= x_delta;
758 y_min += y_delta;
759 y_max -= y_delta;
760 recalc_parameters();
761 redraw = REDRAW_FULL;
762 break;
764 case MANDELBROT_UP:
765 y_min += y_delta;
766 y_max += y_delta;
767 MYXLCD(scroll_down)(LCD_HEIGHT/8);
768 MYLCD_UPDATE();
769 py_max = (LCD_HEIGHT/8);
770 redraw = REDRAW_PARTIAL;
771 break;
773 case MANDELBROT_DOWN:
774 y_min -= y_delta;
775 y_max -= y_delta;
776 MYXLCD(scroll_up)(LCD_HEIGHT/8);
777 MYLCD_UPDATE();
778 py_min = (LCD_HEIGHT-LCD_HEIGHT/8);
779 redraw = REDRAW_PARTIAL;
780 break;
782 case MANDELBROT_LEFT:
783 x_min -= x_delta;
784 x_max -= x_delta;
785 MYXLCD(scroll_right)(LCD_WIDTH/8);
786 MYLCD_UPDATE();
787 px_max = (LCD_WIDTH/8);
788 redraw = REDRAW_PARTIAL;
789 break;
791 case MANDELBROT_RIGHT:
792 x_min += x_delta;
793 x_max += x_delta;
794 MYXLCD(scroll_left)(LCD_WIDTH/8);
795 MYLCD_UPDATE();
796 px_min = (LCD_WIDTH-LCD_WIDTH/8);
797 redraw = REDRAW_PARTIAL;
798 break;
800 case MANDELBROT_MAXITER_DEC:
801 #ifdef MANDELBROT_MAXITER_DEC_PRE
802 if (lastbutton != MANDELBROT_MAXITER_DEC_PRE)
803 break;
804 #endif
805 if (max_iter >= 15) {
806 max_iter -= max_iter / 3;
807 redraw = REDRAW_FULL;
809 break;
811 case MANDELBROT_MAXITER_INC:
812 #ifdef MANDELBROT_MAXITER_INC_PRE
813 if (lastbutton != MANDELBROT_MAXITER_INC_PRE)
814 break;
815 #endif
816 max_iter += max_iter / 2;
817 redraw = REDRAW_FULL;
818 break;
820 case MANDELBROT_RESET:
821 init_mandelbrot_set();
822 redraw = REDRAW_FULL;
823 break;
825 default:
826 if (rb->default_event_handler_ex(button, cleanup, NULL)
827 == SYS_USB_CONNECTED)
828 return PLUGIN_USB_CONNECTED;
829 break;
831 if (button != BUTTON_NONE)
832 lastbutton = button;
834 #ifdef USEGSLIB
835 grey_release();
836 #endif
837 return PLUGIN_OK;
839 #endif