/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2004 Matthias Wientapper * Heavily extended 2005 Jens Arnold * * * 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. * ****************************************************************************/ #include "plugin.h" #ifdef HAVE_LCD_BITMAP #include "grey.h" #include "xlcd.h" PLUGIN_HEADER /* variable button definitions */ #if CONFIG_KEYPAD == RECORDER_PAD #define MANDELBROT_QUIT BUTTON_OFF #define MANDELBROT_UP BUTTON_UP #define MANDELBROT_DOWN BUTTON_DOWN #define MANDELBROT_LEFT BUTTON_LEFT #define MANDELBROT_RIGHT BUTTON_RIGHT #define MANDELBROT_ZOOM_IN BUTTON_PLAY #define MANDELBROT_ZOOM_OUT BUTTON_ON #define MANDELBROT_MAXITER_INC BUTTON_F2 #define MANDELBROT_MAXITER_DEC BUTTON_F1 #define MANDELBROT_RESET BUTTON_F3 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD #define MANDELBROT_QUIT BUTTON_OFF #define MANDELBROT_UP BUTTON_UP #define MANDELBROT_DOWN BUTTON_DOWN #define MANDELBROT_LEFT BUTTON_LEFT #define MANDELBROT_RIGHT BUTTON_RIGHT #define MANDELBROT_ZOOM_IN BUTTON_SELECT #define MANDELBROT_ZOOM_OUT BUTTON_ON #define MANDELBROT_MAXITER_INC BUTTON_F2 #define MANDELBROT_MAXITER_DEC BUTTON_F1 #define MANDELBROT_RESET BUTTON_F3 #elif CONFIG_KEYPAD == ONDIO_PAD #define MANDELBROT_QUIT BUTTON_OFF #define MANDELBROT_UP BUTTON_UP #define MANDELBROT_DOWN BUTTON_DOWN #define MANDELBROT_LEFT BUTTON_LEFT #define MANDELBROT_RIGHT BUTTON_RIGHT #define MANDELBROT_ZOOM_IN_PRE BUTTON_MENU #define MANDELBROT_ZOOM_IN (BUTTON_MENU | BUTTON_REL) #define MANDELBROT_ZOOM_IN2 (BUTTON_MENU | BUTTON_UP) #define MANDELBROT_ZOOM_OUT (BUTTON_MENU | BUTTON_DOWN) #define MANDELBROT_MAXITER_INC (BUTTON_MENU | BUTTON_RIGHT) #define MANDELBROT_MAXITER_DEC (BUTTON_MENU | BUTTON_LEFT) #define MANDELBROT_RESET (BUTTON_MENU | BUTTON_OFF) #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ (CONFIG_KEYPAD == IRIVER_H300_PAD) #define MANDELBROT_QUIT BUTTON_OFF #define MANDELBROT_UP BUTTON_UP #define MANDELBROT_DOWN BUTTON_DOWN #define MANDELBROT_LEFT BUTTON_LEFT #define MANDELBROT_RIGHT BUTTON_RIGHT #define MANDELBROT_ZOOM_IN BUTTON_SELECT #define MANDELBROT_ZOOM_OUT BUTTON_MODE #define MANDELBROT_MAXITER_INC (BUTTON_ON | BUTTON_RIGHT) #define MANDELBROT_MAXITER_DEC (BUTTON_ON | BUTTON_LEFT) #define MANDELBROT_RESET BUTTON_REC #define MANDELBROT_RC_QUIT BUTTON_RC_STOP #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) #define MANDELBROT_QUIT (BUTTON_SELECT | BUTTON_MENU) #define MANDELBROT_UP BUTTON_MENU #define MANDELBROT_DOWN BUTTON_PLAY #define MANDELBROT_LEFT BUTTON_LEFT #define MANDELBROT_RIGHT BUTTON_RIGHT #define MANDELBROT_ZOOM_IN BUTTON_SCROLL_FWD #define MANDELBROT_ZOOM_OUT BUTTON_SCROLL_BACK #define MANDELBROT_MAXITER_INC (BUTTON_SELECT | BUTTON_RIGHT) #define MANDELBROT_MAXITER_DEC (BUTTON_SELECT | BUTTON_LEFT) #define MANDELBROT_RESET (BUTTON_SELECT | BUTTON_PLAY) #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD #define MANDELBROT_QUIT BUTTON_POWER #define MANDELBROT_UP BUTTON_UP #define MANDELBROT_DOWN BUTTON_DOWN #define MANDELBROT_LEFT BUTTON_LEFT #define MANDELBROT_RIGHT BUTTON_RIGHT #define MANDELBROT_ZOOM_IN_PRE BUTTON_SELECT #define MANDELBROT_ZOOM_IN (BUTTON_SELECT | BUTTON_REL) #define MANDELBROT_ZOOM_OUT_PRE BUTTON_SELECT #define MANDELBROT_ZOOM_OUT (BUTTON_SELECT | BUTTON_REPEAT) #define MANDELBROT_MAXITER_INC_PRE BUTTON_PLAY #define MANDELBROT_MAXITER_INC (BUTTON_PLAY | BUTTON_REL) #define MANDELBROT_MAXITER_DEC_PRE BUTTON_PLAY #define MANDELBROT_MAXITER_DEC (BUTTON_PLAY | BUTTON_REPEAT) #define MANDELBROT_RESET BUTTON_REC #elif CONFIG_KEYPAD == GIGABEAT_PAD #define MANDELBROT_QUIT BUTTON_POWER #define MANDELBROT_UP BUTTON_UP #define MANDELBROT_DOWN BUTTON_DOWN #define MANDELBROT_LEFT BUTTON_LEFT #define MANDELBROT_RIGHT BUTTON_RIGHT #define MANDELBROT_ZOOM_IN_PRE BUTTON_SELECT #define MANDELBROT_ZOOM_IN (BUTTON_SELECT | BUTTON_REL) #define MANDELBROT_ZOOM_OUT_PRE BUTTON_SELECT #define MANDELBROT_ZOOM_OUT (BUTTON_SELECT | BUTTON_REPEAT) #define MANDELBROT_MAXITER_INC BUTTON_VOL_UP #define MANDELBROT_MAXITER_DEC BUTTON_VOL_DOWN #define MANDELBROT_RESET BUTTON_A #elif CONFIG_KEYPAD == SANSA_E200_PAD #define MANDELBROT_QUIT BUTTON_POWER #define MANDELBROT_UP BUTTON_UP #define MANDELBROT_DOWN BUTTON_DOWN #define MANDELBROT_LEFT BUTTON_LEFT #define MANDELBROT_RIGHT BUTTON_RIGHT #define MANDELBROT_ZOOM_IN BUTTON_SCROLL_FWD #define MANDELBROT_ZOOM_OUT BUTTON_SCROLL_BACK #define MANDELBROT_MAXITER_INC (BUTTON_SELECT | BUTTON_RIGHT) #define MANDELBROT_MAXITER_DEC (BUTTON_SELECT | BUTTON_LEFT) #define MANDELBROT_RESET BUTTON_REC #elif CONFIG_KEYPAD == SANSA_C200_PAD #define MANDELBROT_QUIT BUTTON_POWER #define MANDELBROT_UP BUTTON_UP #define MANDELBROT_DOWN BUTTON_DOWN #define MANDELBROT_LEFT BUTTON_LEFT #define MANDELBROT_RIGHT BUTTON_RIGHT #define MANDELBROT_ZOOM_IN BUTTON_VOL_UP #define MANDELBROT_ZOOM_OUT BUTTON_VOL_DOWN #define MANDELBROT_MAXITER_INC (BUTTON_SELECT | BUTTON_RIGHT) #define MANDELBROT_MAXITER_DEC (BUTTON_SELECT | BUTTON_LEFT) #define MANDELBROT_RESET BUTTON_REC #elif CONFIG_KEYPAD == IRIVER_H10_PAD #define MANDELBROT_QUIT BUTTON_POWER #define MANDELBROT_UP BUTTON_SCROLL_UP #define MANDELBROT_DOWN BUTTON_SCROLL_DOWN #define MANDELBROT_LEFT BUTTON_LEFT #define MANDELBROT_RIGHT BUTTON_RIGHT #define MANDELBROT_ZOOM_IN_PRE BUTTON_PLAY #define MANDELBROT_ZOOM_IN (BUTTON_PLAY | BUTTON_REL) #define MANDELBROT_ZOOM_OUT_PRE BUTTON_PLAY #define MANDELBROT_ZOOM_OUT (BUTTON_PLAY | BUTTON_REPEAT) #define MANDELBROT_MAXITER_INC BUTTON_FF #define MANDELBROT_MAXITER_DEC BUTTON_REW #define MANDELBROT_RESET (BUTTON_PLAY | BUTTON_REW) #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD #define MANDELBROT_QUIT BUTTON_EQ #define MANDELBROT_UP BUTTON_UP #define MANDELBROT_DOWN BUTTON_DOWN #define MANDELBROT_LEFT BUTTON_LEFT #define MANDELBROT_RIGHT BUTTON_RIGHT #define MANDELBROT_ZOOM_IN_PRE BUTTON_SELECT #define MANDELBROT_ZOOM_IN (BUTTON_SELECT | BUTTON_REL) #define MANDELBROT_ZOOM_OUT_PRE BUTTON_SELECT #define MANDELBROT_ZOOM_OUT (BUTTON_SELECT | BUTTON_REPEAT) #define MANDELBROT_MAXITER_INC (BUTTON_PLAY | BUTTON_RIGHT) #define MANDELBROT_MAXITER_DEC (BUTTON_PLAY | BUTTON_LEFT) #define MANDELBROT_RESET BUTTON_MODE #elif CONFIG_KEYPAD == GIGABEAT_S_PAD #define MANDELBROT_QUIT BUTTON_BACK #define MANDELBROT_UP BUTTON_UP #define MANDELBROT_DOWN BUTTON_DOWN #define MANDELBROT_LEFT BUTTON_LEFT #define MANDELBROT_RIGHT BUTTON_RIGHT #define MANDELBROT_ZOOM_IN BUTTON_VOL_UP #define MANDELBROT_ZOOM_OUT BUTTON_VOL_DOWN #define MANDELBROT_MAXITER_INC BUTTON_PREV #define MANDELBROT_MAXITER_DEC BUTTON_NEXT #define MANDELBROT_RESET BUTTON_MENU #elif CONFIG_KEYPAD == MROBE100_PAD #define MANDELBROT_QUIT BUTTON_POWER #define MANDELBROT_UP BUTTON_UP #define MANDELBROT_DOWN BUTTON_DOWN #define MANDELBROT_LEFT BUTTON_LEFT #define MANDELBROT_RIGHT BUTTON_RIGHT #define MANDELBROT_ZOOM_IN_PRE BUTTON_SELECT #define MANDELBROT_ZOOM_IN (BUTTON_SELECT | BUTTON_REL) #define MANDELBROT_ZOOM_OUT_PRE BUTTON_SELECT #define MANDELBROT_ZOOM_OUT (BUTTON_SELECT | BUTTON_REPEAT) #define MANDELBROT_MAXITER_INC BUTTON_MENU #define MANDELBROT_MAXITER_DEC BUTTON_PLAY #define MANDELBROT_RESET BUTTON_DISPLAY #elif CONFIG_KEYPAD == IAUDIO_M3_PAD #define MANDELBROT_QUIT BUTTON_RC_REC #define MANDELBROT_UP BUTTON_RC_VOL_UP #define MANDELBROT_DOWN BUTTON_RC_VOL_DOWN #define MANDELBROT_LEFT BUTTON_RC_REW #define MANDELBROT_RIGHT BUTTON_RC_FF #define MANDELBROT_ZOOM_IN_PRE BUTTON_RC_PLAY #define MANDELBROT_ZOOM_IN (BUTTON_RC_PLAY | BUTTON_REL) #define MANDELBROT_ZOOM_OUT_PRE BUTTON_RC_PLAY #define MANDELBROT_ZOOM_OUT (BUTTON_RC_PLAY | BUTTON_REPEAT) #define MANDELBROT_MAXITER_INC_PRE BUTTON_RC_MODE #define MANDELBROT_MAXITER_INC (BUTTON_RC_MODE|BUTTON_REL) #define MANDELBROT_MAXITER_DEC_PRE BUTTON_RC_MODE #define MANDELBROT_MAXITER_DEC (BUTTON_RC_MODE|BUTTON_REPEAT) #define MANDELBROT_RESET BUTTON_RC_MENU #elif CONFIG_KEYPAD == COWOND2_PAD #define MANDELBROT_QUIT BUTTON_POWER #else #error No keymap defined! #endif #ifdef HAVE_TOUCHPAD #ifndef MANDELBROT_UP #define MANDELBROT_UP BUTTON_TOPMIDDLE #endif #ifndef MANDELBROT_DOWN #define MANDELBROT_DOWN BUTTON_BOTTOMMIDDLE #endif #ifndef MANDELBROT_LEFT #define MANDELBROT_LEFT BUTTON_MIDLEFT #endif #ifndef MANDELBROT_RIGHT #define MANDELBROT_RIGHT BUTTON_MIDRIGHT #endif #ifndef MANDELBROT_ZOOM_IN_PRE #define MANDELBROT_ZOOM_IN_PRE BUTTON_TOPRIGHT #endif #ifndef MANDELBROT_ZOOM_IN #define MANDELBROT_ZOOM_IN (BUTTON_TOPRIGHT | BUTTON_REL) #endif #ifndef MANDELBROT_ZOOM_OUT_PRE #define MANDELBROT_ZOOM_OUT_PRE BUTTON_TOPLEFT #endif #ifndef MANDELBROT_ZOOM_OUT #define MANDELBROT_ZOOM_OUT (BUTTON_TOPLEFT | BUTTON_REL) #endif #ifndef MANDELBROT_MAXITER_INC #define MANDELBROT_MAXITER_INC BUTTON_BOTTOMRIGHT #endif #ifndef MANDELBROT_MAXITER_DEC #define MANDELBROT_MAXITER_DEC BUTTON_BOTTOMLEFT #endif #ifndef MANDELBROT_RESET #define MANDELBROT_RESET BUTTON_CENTER #endif #endif #if LCD_DEPTH < 8 #define USEGSLIB #define MYLCD(fn) grey_ub_ ## fn #define MYLCD_UPDATE() #define MYXLCD(fn) grey_ub_ ## fn #else #define UPDATE_FREQ (HZ/50) #define MYLCD(fn) rb->lcd_ ## fn #define MYLCD_UPDATE() rb->lcd_update(); #define MYXLCD(fn) xlcd_ ## fn #endif static struct plugin_api* rb; /* Fixed point format s5.26: sign, 5 bits integer part, 26 bits fractional part */ static long x_min; static long x_max; static long x_step; static long x_delta; static long y_min; static long y_max; static long y_step; static long y_delta; static int px_min = 0; static int px_max = LCD_WIDTH; static int py_min = 0; static int py_max = LCD_HEIGHT; static int step_log2; static unsigned max_iter; #ifdef USEGSLIB GREY_INFO_STRUCT static unsigned char *gbuf; static size_t gbuf_size = 0; static unsigned char imgbuffer[LCD_HEIGHT]; #else static fb_data imgbuffer[LCD_HEIGHT]; #endif /* 8 entries cyclical, last entry is black (convergence) */ #ifdef HAVE_LCD_COLOR static const fb_data color[9] = { LCD_RGBPACK(255, 0, 159), LCD_RGBPACK(159, 0, 255), LCD_RGBPACK(0, 0, 255), LCD_RGBPACK(0, 159, 255), LCD_RGBPACK(0, 255, 128), LCD_RGBPACK(128, 255, 0), LCD_RGBPACK(255, 191, 0), LCD_RGBPACK(255, 0, 0), LCD_RGBPACK(0, 0, 0) }; #else /* greyscale */ static const fb_data color[9] = { 255, 223, 191, 159, 128, 96, 64, 32, 0 }; #endif #if CONFIG_CPU == SH7034 #define MULS16_ASR10(a, b) muls16_asr10(a, b) static inline short muls16_asr10(short a, short b) { short r; asm ( "muls %[a],%[b] \n" "sts macl,%[r] \n" "shlr8 %[r] \n" "shlr2 %[r] \n" : /* outputs */ [r]"=r"(r) : /* inputs */ [a]"r"(a), [b]"r"(b) ); return r; } #define MULS32_ASR26(a, b) muls32_asr26(a, b) static inline long muls32_asr26(long a, long b) { long r, t1, t2, t3; asm ( /* Signed 32bit * 32bit -> 64bit multiplication. Notation: xxab * xxcd, where each letter represents 16 bits. xx is the 64 bit sign extension. */ "swap.w %[a],%[t1] \n" /* t1 = ba */ "mulu %[t1],%[b] \n" /* a * d */ "swap.w %[b],%[t3] \n" /* t3 = dc */ "sts macl,%[t2] \n" /* t2 = a * d */ "mulu %[t1],%[t3] \n" /* a * c */ "sts macl,%[r] \n" /* hi = a * c */ "mulu %[a],%[t3] \n" /* b * c */ "clrt \n" "sts macl,%[t3] \n" /* t3 = b * c */ "addc %[t2],%[t3] \n" /* t3 += t2, carry -> t2 */ "movt %[t2] \n" "mulu %[a],%[b] \n" /* b * d */ "mov %[t3],%[t1] \n" /* t2t3 <<= 16 */ "xtrct %[t2],%[t1] \n" "mov %[t1],%[t2] \n" "shll16 %[t3] \n" "sts macl,%[t1] \n" /* lo = b * d */ "clrt \n" /* hi.lo += t2t3 */ "addc %[t3],%[t1] \n" "addc %[t2],%[r] \n" "cmp/pz %[a] \n" /* ab >= 0 ? */ "bt 1f \n" "sub %[b],%[r] \n" /* no: hi -= cd (sign extension of ab is -1) */ "1: \n" "cmp/pz %[b] \n" /* cd >= 0 ? */ "bt 2f \n" "sub %[a],%[r] \n" /* no: hi -= ab (sign extension of cd is -1) */ "2: \n" /* Shift right by 26 and return low 32 bits */ "shll2 %[r] \n" /* hi <<= 6 */ "shll2 %[r] \n" "shll2 %[r] \n" "shlr16 %[t1] \n" /* (unsigned)lo >>= 26 */ "shlr8 %[t1] \n" "shlr2 %[t1] \n" "or %[t1],%[r] \n" /* combine result */ : /* outputs */ [r] "=&r"(r), [t1]"=&r"(t1), [t2]"=&r"(t2), [t3]"=&r"(t3) : /* inputs */ [a] "r" (a), [b] "r" (b) ); return r; } #elif defined CPU_COLDFIRE #define MULS16_ASR10(a, b) muls16_asr10(a, b) static inline short muls16_asr10(short a, short b) { asm ( "muls.w %[a],%[b] \n" "asr.l #8,%[b] \n" "asr.l #2,%[b] \n" : /* outputs */ [b]"+d"(b) : /* inputs */ [a]"d" (a) ); return b; } /* Needs the EMAC initialised to fractional mode w/o rounding and saturation */ #define MULS32_INIT() coldfire_set_macsr(EMAC_FRACTIONAL) #define MULS32_ASR26(a, b) muls32_asr26(a, b) static inline long muls32_asr26(long a, long b) { long r, t1; asm ( "mac.l %[a], %[b], %%acc0 \n" /* multiply */ "move.l %%accext01, %[t1] \n" /* get low part */ "movclr.l %%acc0, %[r] \n" /* get high part */ "asl.l #5, %[r] \n" /* hi <<= 5, plus one free */ "lsr.l #3, %[t1] \n" /* lo >>= 3 */ "and.l #0x1f, %[t1] \n" /* mask out unrelated bits */ "or.l %[t1], %[r] \n" /* combine result */ : /* outputs */ [r] "=d"(r), [t1]"=d"(t1) : /* inputs */ [a] "d" (a), [b] "d" (b) ); return r; } #elif defined CPU_ARM #define MULS32_ASR26(a, b) muls32_asr26(a, b) static inline long muls32_asr26(long a, long b) { long r, t1; asm ( "smull %[r], %[t1], %[a], %[b] \n" "mov %[r], %[r], lsr #26 \n" "orr %[r], %[r], %[t1], lsl #6 \n" : /* outputs */ [r] "=&r"(r), [t1]"=&r"(t1) : /* inputs */ [a] "r" (a), [b] "r" (b) ); return r; } #endif /* CPU */ /* default macros */ #ifndef MULS16_ASR10 #define MULS16_ASR10(a, b) ((short)(((long)(a) * (long)(b)) >> 10)) #endif #ifndef MULS32_ASR26 #define MULS32_ASR26(a, b) ((long)(((long long)(a) * (long long)(b)) >> 26)) #endif #ifndef MULS32_INIT #define MULS32_INIT() #endif int ilog2_fp(long value) /* calculate integer log2(value_fp_6.26) */ { int i = 0; if (value <= 0) { return -32767; } else if (value > (1L<<26)) { while (value >= (2L<<26)) { value >>= 1; i++; } } else { while (value < (1L<<26)) { value <<= 1; i--; } } return i; } void recalc_parameters(void) { x_step = (x_max - x_min) / LCD_WIDTH; x_delta = (x_step * LCD_WIDTH) / 8; y_step = (y_max - y_min) / LCD_HEIGHT; y_delta = (y_step * LCD_HEIGHT) / 8; step_log2 = ilog2_fp(MIN(x_step, y_step)); max_iter = MAX(15, -15 * step_log2 - 45); } #if CONFIG_LCD == LCD_SSD1815 /* Recorder, Ondio: pixel_height == 1.25 * pixel_width */ #define MB_HEIGHT (LCD_HEIGHT*5/4) #else /* square pixels */ #define MB_HEIGHT LCD_HEIGHT #endif #define MB_XOFS (-0x03000000L) /* -0.75 (s5.26) */ #if 3000*MB_HEIGHT/LCD_WIDTH >= 2400 /* width is limiting factor */ #define MB_XFAC (0x06000000LL) /* 1.5 (s5.26) */ #define MB_YFAC (MB_XFAC*MB_HEIGHT/LCD_WIDTH) #else /* height is limiting factor */ #define MB_YFAC (0x04cccccdLL) /* 1.2 (s5.26) */ #define MB_XFAC (MB_YFAC*LCD_WIDTH/MB_HEIGHT) #endif void init_mandelbrot_set(void) { x_min = MB_XOFS-MB_XFAC; x_max = MB_XOFS+MB_XFAC; y_min = -MB_YFAC; y_max = MB_YFAC; recalc_parameters(); } void calc_mandelbrot_low_prec(void) { long start_tick, last_yield; #ifndef USEGSLIB long next_update = *rb->current_tick; int last_px = px_min; #endif unsigned n_iter; long a32, b32; short x, x2, y, y2, a, b; int p_x, p_y; start_tick = last_yield = *rb->current_tick; for (p_x = 0, a32 = x_min; p_x < px_max; p_x++, a32 += x_step) { if (p_x < px_min) continue; a = a32 >> 16; for (p_y = LCD_HEIGHT-1, b32 = y_min; p_y >= py_min; p_y--, b32 += y_step) { if (p_y >= py_max) continue; b = b32 >> 16; x = a; y = b; n_iter = 0; while (++n_iter <= max_iter) { x2 = MULS16_ASR10(x, x); y2 = MULS16_ASR10(y, y); if (x2 + y2 > (4<<10)) break; y = 2 * MULS16_ASR10(x, y) + b; x = x2 - y2 + a; } if (n_iter > max_iter) imgbuffer[p_y] = color[8]; else imgbuffer[p_y] = color[n_iter & 7]; /* be nice to other threads: * if at least one tick has passed, yield */ if (*rb->current_tick > last_yield) { rb->yield(); last_yield = *rb->current_tick; } } #ifdef USEGSLIB grey_ub_gray_bitmap_part(imgbuffer, 0, py_min, 1, p_x, py_min, 1, py_max - py_min); #else rb->lcd_bitmap_part(imgbuffer, 0, py_min, 1, p_x, py_min, 1, py_max - py_min); if ((p_x == px_max - 1) || TIME_AFTER(*rb->current_tick, next_update)) { next_update = *rb->current_tick + UPDATE_FREQ; rb->lcd_update_rect(last_px, py_min, p_x - last_px + 1, py_max - py_min); last_px = p_x; } #endif } } void calc_mandelbrot_high_prec(void) { long start_tick, last_yield; #ifndef USEGSLIB long next_update = *rb->current_tick; int last_px = px_min; #endif unsigned n_iter; long x, x2, y, y2, a, b; int p_x, p_y; MULS32_INIT(); start_tick = last_yield = *rb->current_tick; for (p_x = 0, a = x_min; p_x < px_max; p_x++, a += x_step) { if (p_x < px_min) continue; for (p_y = LCD_HEIGHT-1, b = y_min; p_y >= py_min; p_y--, b += y_step) { if (p_y >= py_max) continue; x = a; y = b; n_iter = 0; while (++n_iter <= max_iter) { x2 = MULS32_ASR26(x, x); y2 = MULS32_ASR26(y, y); if (x2 + y2 > (4L<<26)) break; y = 2 * MULS32_ASR26(x, y) + b; x = x2 - y2 + a; } if (n_iter > max_iter) imgbuffer[p_y] = color[8]; else imgbuffer[p_y] = color[n_iter & 7]; /* be nice to other threads: * if at least one tick has passed, yield */ if (*rb->current_tick > last_yield) { rb->yield(); last_yield = *rb->current_tick; } } #ifdef USEGSLIB grey_ub_gray_bitmap_part(imgbuffer, 0, py_min, 1, p_x, py_min, 1, py_max - py_min); #else rb->lcd_bitmap_part(imgbuffer, 0, py_min, 1, p_x, py_min, 1, py_max-py_min); if ((p_x == px_max - 1) || TIME_AFTER(*rb->current_tick, next_update)) { next_update = *rb->current_tick + UPDATE_FREQ; rb->lcd_update_rect(last_px, py_min, p_x - last_px + 1, py_max - py_min); last_px = p_x; } #endif } } void cleanup(void *parameter) { (void)parameter; #ifdef USEGSLIB grey_release(); #endif } #define REDRAW_NONE 0 #define REDRAW_PARTIAL 1 #define REDRAW_FULL 2 enum plugin_status plugin_start(struct plugin_api* api, void* parameter) { int button; int lastbutton = BUTTON_NONE; int redraw = REDRAW_FULL; rb = api; (void)parameter; #ifdef USEGSLIB /* get the remainder of the plugin buffer */ gbuf = (unsigned char *) rb->plugin_get_buffer(&gbuf_size); /* initialize the greyscale buffer.*/ if (!grey_init(rb, gbuf, gbuf_size, GREY_ON_COP, LCD_WIDTH, LCD_HEIGHT, NULL)) { rb->splash(HZ, "Couldn't init greyscale display"); return 0; } grey_show(true); /* switch on greyscale overlay */ #else xlcd_init(rb); #endif #if LCD_DEPTH > 1 rb->lcd_set_backdrop(NULL); #endif init_mandelbrot_set(); /* main loop */ while (true) { if (redraw > REDRAW_NONE) { #ifdef HAVE_ADJUSTABLE_CPU_FREQ rb->cpu_boost(true); #endif if (redraw == REDRAW_FULL) { MYLCD(clear_display)(); MYLCD_UPDATE(); } if (step_log2 <= -10) /* select precision */ calc_mandelbrot_high_prec(); else calc_mandelbrot_low_prec(); #ifdef HAVE_ADJUSTABLE_CPU_FREQ rb->cpu_boost(false); #endif px_min = 0; px_max = LCD_WIDTH; py_min = 0; py_max = LCD_HEIGHT; redraw = REDRAW_NONE; } button = rb->button_get(true); switch (button) { #ifdef MANDELBROT_RC_QUIT case MANDELBROT_RC_QUIT: #endif case MANDELBROT_QUIT: #ifdef USEGSLIB grey_release(); #endif return PLUGIN_OK; case MANDELBROT_ZOOM_OUT: #ifdef MANDELBROT_ZOOM_OUT_PRE if (lastbutton != MANDELBROT_ZOOM_OUT_PRE) break; #endif x_min -= x_delta; x_max += x_delta; y_min -= y_delta; y_max += y_delta; recalc_parameters(); redraw = REDRAW_FULL; break; case MANDELBROT_ZOOM_IN: #ifdef MANDELBROT_ZOOM_IN_PRE if (lastbutton != MANDELBROT_ZOOM_IN_PRE) break; #endif #ifdef MANDELBROT_ZOOM_IN2 case MANDELBROT_ZOOM_IN2: #endif x_min += x_delta; x_max -= x_delta; y_min += y_delta; y_max -= y_delta; recalc_parameters(); redraw = REDRAW_FULL; break; case MANDELBROT_UP: y_min += y_delta; y_max += y_delta; MYXLCD(scroll_down)(LCD_HEIGHT/8); MYLCD_UPDATE(); py_max = (LCD_HEIGHT/8); redraw = REDRAW_PARTIAL; break; case MANDELBROT_DOWN: y_min -= y_delta; y_max -= y_delta; MYXLCD(scroll_up)(LCD_HEIGHT/8); MYLCD_UPDATE(); py_min = (LCD_HEIGHT-LCD_HEIGHT/8); redraw = REDRAW_PARTIAL; break; case MANDELBROT_LEFT: x_min -= x_delta; x_max -= x_delta; MYXLCD(scroll_right)(LCD_WIDTH/8); MYLCD_UPDATE(); px_max = (LCD_WIDTH/8); redraw = REDRAW_PARTIAL; break; case MANDELBROT_RIGHT: x_min += x_delta; x_max += x_delta; MYXLCD(scroll_left)(LCD_WIDTH/8); MYLCD_UPDATE(); px_min = (LCD_WIDTH-LCD_WIDTH/8); redraw = REDRAW_PARTIAL; break; case MANDELBROT_MAXITER_DEC: #ifdef MANDELBROT_MAXITER_DEC_PRE if (lastbutton != MANDELBROT_MAXITER_DEC_PRE) break; #endif if (max_iter >= 15) { max_iter -= max_iter / 3; redraw = REDRAW_FULL; } break; case MANDELBROT_MAXITER_INC: #ifdef MANDELBROT_MAXITER_INC_PRE if (lastbutton != MANDELBROT_MAXITER_INC_PRE) break; #endif max_iter += max_iter / 2; redraw = REDRAW_FULL; break; case MANDELBROT_RESET: init_mandelbrot_set(); redraw = REDRAW_FULL; break; default: if (rb->default_event_handler_ex(button, cleanup, NULL) == SYS_USB_CONNECTED) return PLUGIN_USB_CONNECTED; break; } if (button != BUTTON_NONE) lastbutton = button; } #ifdef USEGSLIB grey_release(); #endif return PLUGIN_OK; } #endif