1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 "fractal_sets.h"
24 #include "mandelbrot_set.h"
26 #define BUTTON_YIELD_TIMEOUT (HZ / 4)
29 static unsigned char imgbuffer
[LCD_HEIGHT
];
31 static fb_data imgbuffer
[LCD_HEIGHT
];
35 #define LCOLOR(iter) ((iter ^ 7) << 5)
38 * Spread iter's colors over color range.
39 * 345 (=15*26-45) is max_iter maximal value
40 * This implementation ignores pixel format, thus it is not uniformly spread
42 #define LCOLOR(iter) ((iter << LCD_DEPTH) / 345)
46 #define COLOR(iter) (fb_data)LCOLOR(iter)
47 #define CONVERGENCE_COLOR LCD_RGBPACK(0, 0, 0)
49 #define COLOR(iter) (unsigned char)LCOLOR(iter)
50 #define CONVERGENCE_COLOR 0
53 #if CONFIG_LCD == LCD_SSD1815
54 /* Recorder, Ondio: pixel_height == 1.25 * pixel_width */
55 #define MB_HEIGHT (LCD_HEIGHT*5/4)
58 #define MB_HEIGHT LCD_HEIGHT
61 #define MB_XOFS (-0x03000000L) /* -0.75 (s5.26) */
62 #if (3000 * MB_HEIGHT / LCD_WIDTH) >= 2400 /* width is limiting factor */
63 #define MB_XFAC (0x06000000LL) /* 1.5 (s5.26) */
64 #define MB_YFAC (MB_XFAC*MB_HEIGHT / LCD_WIDTH)
65 #else /* height is limiting factor */
66 #define MB_YFAC (0x04cccccdLL) /* 1.2 (s5.26) */
67 #define MB_XFAC (MB_YFAC*LCD_WIDTH / MB_HEIGHT)
71 #define UPDATE_FREQ (HZ/50)
74 /* fixed point format s5.26: sign, 5 bits integer part, 26 bits fractional part */
75 struct fractal_ops
*ops
;
87 static void mandelbrot_init(void);
89 static int mandelbrot_calc_low_prec(struct fractal_rect
*rect
,
90 int (*button_yield_cb
)(void *), void *button_yield_ctx
);
92 static int mandelbrot_calc_high_prec(struct fractal_rect
*rect
,
93 int (*button_yield_cb
)(void *), void *button_yield_ctx
);
95 static void mandelbrot_move(int dx
, int dy
);
97 static int mandelbrot_zoom(int factor
);
99 static int mandelbrot_precision(int d
);
101 struct fractal_ops mandelbrot_ops
=
103 .init
= mandelbrot_init
,
105 .move
= mandelbrot_move
,
106 .zoom
= mandelbrot_zoom
,
107 .precision
= mandelbrot_precision
,
110 #define LOG2_OUT_OF_BOUNDS -32767
112 static int ilog2_fp(long value
) /* calculate integer log2(value_fp_6.26) */
118 return LOG2_OUT_OF_BOUNDS
;
120 else if (value
> (1L << 26))
122 while (value
>= (2L << 26))
130 while (value
< (1L << 26))
139 static int recalc_parameters(void)
141 x_step
= (x_max
- x_min
) / LCD_WIDTH
;
142 y_step
= (y_max
- y_min
) / LCD_HEIGHT
;
143 step_log2
= ilog2_fp(MIN(x_step
, y_step
));
145 if (step_log2
== LOG2_OUT_OF_BOUNDS
)
146 return 1; /* out of bounds */
148 x_delta
= X_DELTA(x_step
);
149 y_delta
= Y_DELTA(y_step
);
150 max_iter
= MAX(15, -15 * step_log2
- 45);
152 ops
->calc
= (step_log2
<= -10) ?
153 mandelbrot_calc_high_prec
: mandelbrot_calc_low_prec
;
158 static void mandelbrot_init(void)
160 ops
= &mandelbrot_ops
;
162 x_min
= MB_XOFS
- MB_XFAC
;
163 x_max
= MB_XOFS
+ MB_XFAC
;
170 static int mandelbrot_calc_low_prec(struct fractal_rect
*rect
,
171 int (*button_yield_cb
)(void *), void *button_yield_ctx
)
174 long next_update
= *rb
->current_tick
;
175 int last_px
= rect
->px_min
;
179 short x
, x2
, y
, y2
, a
, b
;
181 unsigned long last_yield
= *rb
->current_tick
;
182 unsigned long last_button_yield
= *rb
->current_tick
;
184 a32
= x_min
+ x_step
* rect
->px_min
;
186 for (p_x
= rect
->px_min
; p_x
< rect
->px_max
; p_x
++)
190 b32
= y_min
+ y_step
* (LCD_HEIGHT
- rect
->py_max
);
192 for (p_y
= rect
->py_max
- 1; p_y
>= rect
->py_min
; p_y
--)
199 while (++n_iter
<= max_iter
)
201 x2
= MULS16_ASR10(x
, x
);
202 y2
= MULS16_ASR10(y
, y
);
204 if (x2
+ y2
> (4<<10)) break;
206 y
= 2 * MULS16_ASR10(x
, y
) + b
;
210 if (n_iter
> max_iter
)
211 imgbuffer
[p_y
] = CONVERGENCE_COLOR
;
213 imgbuffer
[p_y
] = COLOR(n_iter
);
215 /* be nice to other threads:
216 * if at least one tick has passed, yield */
217 if (TIME_AFTER(*rb
->current_tick
, last_yield
))
220 last_yield
= *rb
->current_tick
;
223 if (TIME_AFTER(*rb
->current_tick
, last_button_yield
))
225 if (button_yield_cb(button_yield_ctx
))
228 /* update screen part that was changed since last yield */
229 rb
->lcd_update_rect(last_px
, rect
->py_min
,
230 p_x
- last_px
+ 1, rect
->py_max
- rect
->py_min
);
232 rect
->px_min
= (p_x
== 0) ? 0 : p_x
- 1;
237 last_button_yield
= *rb
->current_tick
+ BUTTON_YIELD_TIMEOUT
;
243 grey_ub_gray_bitmap_part(imgbuffer
, 0, rect
->py_min
, 1,
244 p_x
, rect
->py_min
, 1, rect
->py_max
- rect
->py_min
);
246 rb
->lcd_bitmap_part(imgbuffer
, 0, rect
->py_min
, 1,
247 p_x
, rect
->py_min
, 1, rect
->py_max
- rect
->py_min
);
249 if ((p_x
== rect
->px_max
- 1) ||
250 TIME_AFTER(*rb
->current_tick
, next_update
))
252 next_update
= *rb
->current_tick
+ UPDATE_FREQ
;
254 /* update screen part that was changed since last yield */
255 rb
->lcd_update_rect(last_px
, rect
->py_min
,
256 p_x
- last_px
+ 1, rect
->py_max
- rect
->py_min
);
269 static int mandelbrot_calc_high_prec(struct fractal_rect
*rect
,
270 int (*button_yield_cb
)(void *), void *button_yield_ctx
)
273 long next_update
= *rb
->current_tick
;
274 int last_px
= rect
->px_min
;
277 long x
, x2
, y
, y2
, a
, b
;
279 unsigned long last_yield
= *rb
->current_tick
;
280 unsigned long last_button_yield
= *rb
->current_tick
;
284 a
= x_min
+ x_step
* rect
->px_min
;
286 for (p_x
= rect
->px_min
; p_x
< rect
->px_max
; p_x
++)
288 b
= y_min
+ y_step
* (LCD_HEIGHT
- rect
->py_max
);
290 for (p_y
= rect
->py_max
- 1; p_y
>= rect
->py_min
; p_y
--)
296 while (++n_iter
<= max_iter
)
298 x2
= MULS32_ASR26(x
, x
);
299 y2
= MULS32_ASR26(y
, y
);
301 if (x2
+ y2
> (4L<<26)) break;
303 y
= 2 * MULS32_ASR26(x
, y
) + b
;
307 if (n_iter
> max_iter
)
308 imgbuffer
[p_y
] = CONVERGENCE_COLOR
;
310 imgbuffer
[p_y
] = COLOR(n_iter
);
312 /* be nice to other threads:
313 * if at least one tick has passed, yield */
314 if (TIME_AFTER(*rb
->current_tick
, last_yield
))
317 last_yield
= *rb
->current_tick
;
320 if (TIME_AFTER(*rb
->current_tick
, last_button_yield
))
322 if (button_yield_cb(button_yield_ctx
))
325 /* update screen part that was changed since last yield */
326 rb
->lcd_update_rect(last_px
, rect
->py_min
,
327 p_x
- last_px
+ 1, rect
->py_max
- rect
->py_min
);
329 rect
->px_min
= (p_x
== 0) ? 0 : p_x
- 1;
334 last_button_yield
= *rb
->current_tick
+ BUTTON_YIELD_TIMEOUT
;
340 grey_ub_gray_bitmap_part(imgbuffer
, 0, rect
->py_min
, 1,
341 p_x
, rect
->py_min
, 1, rect
->py_max
- rect
->py_min
);
343 rb
->lcd_bitmap_part(imgbuffer
, 0, rect
->py_min
, 1,
344 p_x
, rect
->py_min
, 1, rect
->py_max
- rect
->py_min
);
346 if ((p_x
== rect
->px_max
- 1) ||
347 TIME_AFTER(*rb
->current_tick
, next_update
))
349 next_update
= *rb
->current_tick
+ UPDATE_FREQ
;
351 /* update screen part that was changed since last yield */
352 rb
->lcd_update_rect(last_px
, rect
->py_min
,
353 p_x
- last_px
+ 1, rect
->py_max
- rect
->py_min
);
365 static void mandelbrot_move(int x_factor
, int y_factor
)
367 long dx
= (long)x_factor
* x_delta
;
368 long dy
= (long)y_factor
* y_delta
;
376 static int mandelbrot_zoom(int factor
)
379 long factor_x
= (long)factor
* x_delta
;
380 long factor_y
= (long)factor
* y_delta
;
387 res
= recalc_parameters();
388 if (res
) /* zoom not possible, revert */
390 mandelbrot_zoom(-factor
);
396 static int mandelbrot_precision(int d
)
400 /* Increase precision */
403 max_iter
+= max_iter
/ 2;
407 /* Decrease precision */
408 for (; d
< 0 && max_iter
>= 15; d
++)
410 max_iter
-= max_iter
/ 3;