rockbox/apps/plugins/mandelbrot.c
Jens Arnold bf8c3056f9 Overflow error fix
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4531 a1c6a512-1295-4272-9138-f99709370657
2004-04-20 23:11:12 +00:00

195 lines
5 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2004 Matthias Wientapper
*
* Thanks to Jens Arnold and Joerg Hohensohn for the speed tips.
* Boy, that was a hell of a code review ;-)
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
*
* further optimization ideas:
* - incremental recalculation when moving
*
****************************************************************************/
#include "plugin.h"
#ifdef HAVE_LCD_BITMAP // this is not fun on the player
static struct plugin_api* rb;
static char buff[32];
static int lcd_aspect_ratio;
static int x_min;
static int x_max;
static int y_min;
static int y_max;
static int delta;
static int max_iter;
void init_mandelbrot_set(void){
x_min = -5<<25; // -2.5<<26
x_max = 1<<26; // 1.0<<26
y_min = -1<<26; // -1.0<<26
y_max = 1<<26; // 1.0<<26
delta = (x_max - x_min) >> 3; // /8
max_iter = 25;
}
void calc_mandelbrot_set(void){
unsigned int start_tick;
int n_iter;
int x_pixel, y_pixel;
int x, x2, y, y2, a, b;
int x_fact, y_fact;
start_tick = *rb->current_tick;
rb->lcd_clear_display();
rb->lcd_update();
x_fact = (x_max - x_min) / LCD_WIDTH;
y_fact = (y_max - y_min) / LCD_HEIGHT;
for(y_pixel = LCD_HEIGHT-1; y_pixel>=0; y_pixel--){
b = (y_pixel * y_fact) + y_min;
for (x_pixel = LCD_WIDTH-1; x_pixel>=0; x_pixel--){
a = (x_pixel * x_fact) + x_min;
x = 0;
y = 0;
n_iter = 0;
while (++n_iter<=max_iter) {
x >>= 13;
y >>= 13;
x2 = x * x;
y2 = y * y;
if (x2 + y2 > (4<<26)) break;
y = 2 * x * y + b;
x = x2 - y2 + a;
}
// "coloring"
if ( (n_iter > max_iter) ||
(n_iter == (max_iter >> 1)) ||
(n_iter == (max_iter >> 2)) ||
(n_iter == (max_iter >> 3))
){
rb->lcd_drawpixel(x_pixel,y_pixel);
}
}
/* update block of 8 lines */
if ((y_pixel & 0x7) == 0)
rb->lcd_update_rect(0, y_pixel, LCD_WIDTH, 8);
}
/* we want to know how long we had to wait */
rb->lcd_setfont(FONT_SYSFIXED);
rb->snprintf(buff, sizeof(buff), "%d", (*rb->current_tick - start_tick));
rb->lcd_puts(0,0,buff);
rb->snprintf(buff, sizeof(buff), "%d", max_iter);
rb->lcd_puts(0,1,buff);
rb->lcd_update_rect(0,0,24,16);
}
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
TEST_PLUGIN_API(api);
(void)parameter;
rb = api;
init_mandelbrot_set();
lcd_aspect_ratio = ((LCD_WIDTH<<13) / LCD_HEIGHT)<<13;
/* main loop */
while (true){
calc_mandelbrot_set();
/* FIXME: is this the right way to empty the key-queue?
(Otherwise we have to process things twice :-/ ?! */
rb->button_get(true);
switch (rb->button_get(true)) {
case BUTTON_OFF:
return PLUGIN_OK;
case BUTTON_ON:
x_min -= ((delta>>13)*(lcd_aspect_ratio>>13));
x_max += ((delta>>13)*(lcd_aspect_ratio>>13));
y_min -= delta;
y_max += delta;
delta = (x_max - x_min) >> 3;
break;
case BUTTON_PLAY:
x_min += ((delta>>13)*(lcd_aspect_ratio>>13));
x_max -= ((delta>>13)*(lcd_aspect_ratio>>13));
y_min += delta;
y_max -= delta;
delta = (x_max - x_min) >> 3;
break;
case BUTTON_UP:
y_min -= delta;
y_max -= delta;
break;
case BUTTON_DOWN:
y_min += delta;
y_max += delta;
break;
case BUTTON_LEFT:
x_min -= delta;
x_max -= delta;
break;
case BUTTON_RIGHT:
x_min += delta;
x_max += delta;
break;
case BUTTON_F1:
if (max_iter>5){
max_iter -= 5;
}
break;
case BUTTON_F2:
if (max_iter < 195){
max_iter += 5;
}
break;
case BUTTON_F3:
init_mandelbrot_set();
break;
case SYS_USB_CONNECTED:
rb->usb_screen();
return PLUGIN_USB_CONNECTED;
}
}
return false;
}
#endif