Strip trailing directory slash
[kugel-rb.git] / apps / plugins / mandelbrot.c
blob2e9cb97eececd7645ead3c0c1a13220242eb6b83
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2004 Matthias Wientapper
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
20 #ifndef SIMULATOR
21 #include "plugin.h"
23 #ifdef HAVE_LCD_BITMAP // this is not fun on the player
24 # include "gray.h"
26 /* variable button definitions */
27 #if CONFIG_KEYPAD == RECORDER_PAD
28 #define MANDELBROT_QUIT BUTTON_OFF
29 #define MANDELBROT_ZOOM_IN BUTTON_PLAY
30 #define MANDELBROT_ZOOM_OUT BUTTON_ON
31 #define MANDELBROT_MAXITER_INC BUTTON_F2
32 #define MANDELBROT_MAXITER_DEC BUTTON_F1
33 #define MANDELBROT_RESET BUTTON_F3
35 #elif CONFIG_KEYPAD == ONDIO_PAD
36 #define MANDELBROT_QUIT BUTTON_OFF
37 #define MANDELBROT_ZOOM_IN_PRE BUTTON_MENU
38 #define MANDELBROT_ZOOM_IN (BUTTON_MENU | BUTTON_REL)
39 #define MANDELBROT_ZOOM_IN2 (BUTTON_MENU | BUTTON_UP)
40 #define MANDELBROT_ZOOM_OUT (BUTTON_MENU | BUTTON_DOWN)
41 #define MANDELBROT_MAXITER_INC (BUTTON_MENU | BUTTON_RIGHT)
42 #define MANDELBROT_MAXITER_DEC (BUTTON_MENU | BUTTON_LEFT)
43 #define MANDELBROT_RESET (BUTTON_MENU | BUTTON_OFF)
45 #endif
47 static struct plugin_api* rb;
48 static char buff[32];
49 static int lcd_aspect_ratio;
50 static int x_min;
51 static int x_max;
52 static int y_min;
53 static int y_max;
54 static int delta;
55 static int max_iter;
56 static unsigned char *gbuf;
57 static unsigned int gbuf_size = 0;
58 static unsigned char graybuffer[LCD_HEIGHT];
61 void init_mandelbrot_set(void){
62 x_min = -5<<25; // -2.0<<26
63 x_max = 1<<26; // 1.0<<26
64 y_min = -1<<26; // -1.0<<26
65 y_max = 1<<26; // 1.0<<26
66 delta = (x_max - x_min) >> 3; // /8
67 max_iter = 25;
70 void calc_mandelbrot_set(void){
72 long start_tick, last_yield;
73 int n_iter;
74 int x_pixel, y_pixel;
75 int x, x2, y, y2, a, b;
76 int x_fact, y_fact;
77 int brightness;
79 start_tick = last_yield = *rb->current_tick;
81 gray_clear_display();
83 x_fact = (x_max - x_min) / LCD_WIDTH;
84 y_fact = (y_max - y_min) / LCD_HEIGHT;
86 for (x_pixel = 0; x_pixel<LCD_WIDTH; x_pixel++){
87 a = (x_pixel * x_fact) + x_min;
88 for(y_pixel = LCD_HEIGHT-1; y_pixel>=0; y_pixel--){
89 b = (y_pixel * y_fact) + y_min;
90 x = 0;
91 y = 0;
92 n_iter = 0;
94 while (++n_iter<=max_iter) {
95 x >>= 13;
96 y >>= 13;
97 x2 = x * x;
98 y2 = y * y;
100 if (x2 + y2 > (4<<26)) break;
102 y = 2 * x * y + b;
103 x = x2 - y2 + a;
106 // "coloring"
107 brightness = 0;
108 if (n_iter > max_iter){
109 brightness = 0; // black
110 } else {
111 brightness = 255 - (31 * (n_iter & 7));
113 graybuffer[y_pixel]=brightness;
114 /* be nice to other threads:
115 * if at least one tick has passed, yield */
116 if (*rb->current_tick > last_yield){
117 rb->yield();
118 last_yield = *rb->current_tick;
121 gray_drawgraymap(graybuffer, x_pixel, 0, 1, LCD_HEIGHT, 1);
125 void cleanup(void *parameter)
127 (void)parameter;
129 gray_release_buffer();
132 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
134 int button;
135 int lastbutton = BUTTON_NONE;
136 int grayscales;
137 bool redraw = true;
139 TEST_PLUGIN_API(api);
140 rb = api;
141 (void)parameter;
143 /* This plugin uses the grayscale framework, so initialize */
144 gray_init(api);
146 /* get the remainder of the plugin buffer */
147 gbuf = (unsigned char *) rb->plugin_get_buffer(&gbuf_size);
149 /* initialize the grayscale buffer:
150 * 112 pixels wide, 8 rows (64 pixels) high, (try to) reserve
151 * 16 bitplanes for 17 shades of gray.*/
152 grayscales = gray_init_buffer(gbuf, gbuf_size, 112, 8, 16, NULL) + 1;
153 if (grayscales != 17){
154 rb->snprintf(buff, sizeof(buff), "%d", grayscales);
155 rb->lcd_puts(0, 1, buff);
156 rb->lcd_update();
157 rb->sleep(HZ*2);
158 return(0);
161 gray_show_display(true); /* switch on grayscale overlay */
163 init_mandelbrot_set();
164 lcd_aspect_ratio = ((LCD_WIDTH<<13) / LCD_HEIGHT)<<13;
166 /* main loop */
167 while (true){
168 if(redraw)
169 calc_mandelbrot_set();
171 redraw = false;
173 button = rb->button_get(true);
174 switch (button) {
175 case MANDELBROT_QUIT:
176 gray_release_buffer();
177 return PLUGIN_OK;
179 case MANDELBROT_ZOOM_OUT:
180 x_min -= ((delta>>13)*(lcd_aspect_ratio>>13));
181 x_max += ((delta>>13)*(lcd_aspect_ratio>>13));
182 y_min -= delta;
183 y_max += delta;
184 delta = (x_max - x_min) >> 3;
185 redraw = true;
186 break;
189 case MANDELBROT_ZOOM_IN:
190 #ifdef MANDELBROT_ZOOM_IN_PRE
191 if (lastbutton != MANDELBROT_ZOOM_IN_PRE)
192 break;
193 #endif
194 #ifdef MANDELBROT_ZOOM_IN2
195 case MANDELBROT_ZOOM_IN2:
196 #endif
197 x_min += ((delta>>13)*(lcd_aspect_ratio>>13));
198 x_max -= ((delta>>13)*(lcd_aspect_ratio>>13));
199 y_min += delta;
200 y_max -= delta;
201 delta = (x_max - x_min) >> 3;
202 redraw = true;
203 break;
205 case BUTTON_UP:
206 y_min -= delta;
207 y_max -= delta;
208 redraw = true;
209 break;
211 case BUTTON_DOWN:
212 y_min += delta;
213 y_max += delta;
214 redraw = true;
215 break;
217 case BUTTON_LEFT:
218 x_min -= delta;
219 x_max -= delta;
220 redraw = true;
221 break;
223 case BUTTON_RIGHT:
224 x_min += delta;
225 x_max += delta;
226 redraw = true;
227 break;
229 case MANDELBROT_MAXITER_DEC:
230 if (max_iter>5){
231 max_iter -= 5;
232 redraw = true;
234 break;
236 case MANDELBROT_MAXITER_INC:
237 if (max_iter < 195){
238 max_iter += 5;
239 redraw = true;
241 break;
243 case MANDELBROT_RESET:
244 init_mandelbrot_set();
245 redraw = true;
246 break;
248 default:
249 if (rb->default_event_handler_ex(button, cleanup, NULL)
250 == SYS_USB_CONNECTED)
251 return PLUGIN_USB_CONNECTED;
252 break;
254 if (button != BUTTON_NONE)
255 lastbutton = button;
257 gray_release_buffer();
258 return PLUGIN_OK;
260 #endif
261 #endif