1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2004 Matthias Wientapper
11 * Heavily extended 2005 Jens Arnold
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 #ifdef HAVE_LCD_BITMAP
29 /* variable button definitions */
30 #if CONFIG_KEYPAD == RECORDER_PAD
31 #define MANDELBROT_QUIT BUTTON_OFF
32 #define MANDELBROT_UP BUTTON_UP
33 #define MANDELBROT_DOWN BUTTON_DOWN
34 #define MANDELBROT_LEFT BUTTON_LEFT
35 #define MANDELBROT_RIGHT BUTTON_RIGHT
36 #define MANDELBROT_ZOOM_IN BUTTON_PLAY
37 #define MANDELBROT_ZOOM_OUT BUTTON_ON
38 #define MANDELBROT_MAXITER_INC BUTTON_F2
39 #define MANDELBROT_MAXITER_DEC BUTTON_F1
40 #define MANDELBROT_RESET BUTTON_F3
42 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
43 #define MANDELBROT_QUIT BUTTON_OFF
44 #define MANDELBROT_UP BUTTON_UP
45 #define MANDELBROT_DOWN BUTTON_DOWN
46 #define MANDELBROT_LEFT BUTTON_LEFT
47 #define MANDELBROT_RIGHT BUTTON_RIGHT
48 #define MANDELBROT_ZOOM_IN BUTTON_SELECT
49 #define MANDELBROT_ZOOM_OUT BUTTON_ON
50 #define MANDELBROT_MAXITER_INC BUTTON_F2
51 #define MANDELBROT_MAXITER_DEC BUTTON_F1
52 #define MANDELBROT_RESET BUTTON_F3
54 #elif CONFIG_KEYPAD == ONDIO_PAD
55 #define MANDELBROT_QUIT BUTTON_OFF
56 #define MANDELBROT_UP BUTTON_UP
57 #define MANDELBROT_DOWN BUTTON_DOWN
58 #define MANDELBROT_LEFT BUTTON_LEFT
59 #define MANDELBROT_RIGHT BUTTON_RIGHT
60 #define MANDELBROT_ZOOM_IN_PRE BUTTON_MENU
61 #define MANDELBROT_ZOOM_IN (BUTTON_MENU | BUTTON_REL)
62 #define MANDELBROT_ZOOM_IN2 (BUTTON_MENU | BUTTON_UP)
63 #define MANDELBROT_ZOOM_OUT (BUTTON_MENU | BUTTON_DOWN)
64 #define MANDELBROT_MAXITER_INC (BUTTON_MENU | BUTTON_RIGHT)
65 #define MANDELBROT_MAXITER_DEC (BUTTON_MENU | BUTTON_LEFT)
66 #define MANDELBROT_RESET (BUTTON_MENU | BUTTON_OFF)
68 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
69 (CONFIG_KEYPAD == IRIVER_H300_PAD)
70 #define MANDELBROT_QUIT BUTTON_OFF
71 #define MANDELBROT_UP BUTTON_UP
72 #define MANDELBROT_DOWN BUTTON_DOWN
73 #define MANDELBROT_LEFT BUTTON_LEFT
74 #define MANDELBROT_RIGHT BUTTON_RIGHT
75 #define MANDELBROT_ZOOM_IN BUTTON_SELECT
76 #define MANDELBROT_ZOOM_OUT BUTTON_MODE
77 #define MANDELBROT_MAXITER_INC (BUTTON_ON | BUTTON_RIGHT)
78 #define MANDELBROT_MAXITER_DEC (BUTTON_ON | BUTTON_LEFT)
79 #define MANDELBROT_RESET BUTTON_REC
81 #define MANDELBROT_RC_QUIT BUTTON_RC_STOP
83 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
84 (CONFIG_KEYPAD == IPOD_3G_PAD)
85 #define MANDELBROT_QUIT (BUTTON_SELECT | BUTTON_MENU)
86 #define MANDELBROT_UP BUTTON_MENU
87 #define MANDELBROT_DOWN BUTTON_PLAY
88 #define MANDELBROT_LEFT BUTTON_LEFT
89 #define MANDELBROT_RIGHT BUTTON_RIGHT
90 #define MANDELBROT_ZOOM_IN BUTTON_SCROLL_FWD
91 #define MANDELBROT_ZOOM_OUT BUTTON_SCROLL_BACK
92 #define MANDELBROT_MAXITER_INC (BUTTON_SELECT | BUTTON_RIGHT)
93 #define MANDELBROT_MAXITER_DEC (BUTTON_SELECT | BUTTON_LEFT)
94 #define MANDELBROT_RESET (BUTTON_SELECT | BUTTON_PLAY)
96 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
97 #define MANDELBROT_QUIT BUTTON_POWER
98 #define MANDELBROT_UP BUTTON_UP
99 #define MANDELBROT_DOWN BUTTON_DOWN
100 #define MANDELBROT_LEFT BUTTON_LEFT
101 #define MANDELBROT_RIGHT BUTTON_RIGHT
102 #define MANDELBROT_ZOOM_IN_PRE BUTTON_SELECT
103 #define MANDELBROT_ZOOM_IN (BUTTON_SELECT | BUTTON_REL)
104 #define MANDELBROT_ZOOM_OUT (BUTTON_SELECT | BUTTON_REPEAT)
105 #define MANDELBROT_MAXITER_INC (BUTTON_PLAY | BUTTON_RIGHT)
106 #define MANDELBROT_MAXITER_DEC (BUTTON_PLAY | BUTTON_LEFT)
107 #define MANDELBROT_RESET BUTTON_REC
109 #elif CONFIG_KEYPAD == GIGABEAT_PAD
110 #define MANDELBROT_QUIT BUTTON_A
111 #define MANDELBROT_UP BUTTON_UP
112 #define MANDELBROT_DOWN BUTTON_DOWN
113 #define MANDELBROT_LEFT BUTTON_LEFT
114 #define MANDELBROT_RIGHT BUTTON_RIGHT
115 #define MANDELBROT_ZOOM_IN_PRE BUTTON_MENU
116 #define MANDELBROT_ZOOM_IN (BUTTON_MENU | BUTTON_REL)
117 #define MANDELBROT_ZOOM_OUT (BUTTON_MENU | BUTTON_REPEAT)
118 #define MANDELBROT_MAXITER_INC (BUTTON_POWER | BUTTON_RIGHT)
119 #define MANDELBROT_MAXITER_DEC (BUTTON_POWER | BUTTON_LEFT)
120 #define MANDELBROT_RESET BUTTON_SELECT
122 #elif CONFIG_KEYPAD == SANSA_E200_PAD
123 #define MANDELBROT_QUIT BUTTON_POWER
124 #define MANDELBROT_UP BUTTON_UP
125 #define MANDELBROT_DOWN BUTTON_DOWN
126 #define MANDELBROT_LEFT BUTTON_LEFT
127 #define MANDELBROT_RIGHT BUTTON_RIGHT
128 #define MANDELBROT_ZOOM_IN BUTTON_SCROLL_DOWN
129 #define MANDELBROT_ZOOM_OUT BUTTON_SCROLL_UP
130 #define MANDELBROT_MAXITER_INC (BUTTON_SELECT | BUTTON_RIGHT)
131 #define MANDELBROT_MAXITER_DEC (BUTTON_SELECT | BUTTON_LEFT)
132 #define MANDELBROT_RESET BUTTON_REC
134 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
135 #define MANDELBROT_QUIT BUTTON_POWER
136 #define MANDELBROT_UP BUTTON_SCROLL_UP
137 #define MANDELBROT_DOWN BUTTON_SCROLL_DOWN
138 #define MANDELBROT_LEFT BUTTON_LEFT
139 #define MANDELBROT_RIGHT BUTTON_RIGHT
140 #define MANDELBROT_ZOOM_IN_PRE BUTTON_PLAY
141 #define MANDELBROT_ZOOM_IN (BUTTON_PLAY | BUTTON_REL)
142 #define MANDELBROT_ZOOM_OUT (BUTTON_PLAY | BUTTON_REPEAT)
143 #define MANDELBROT_MAXITER_INC BUTTON_FF
144 #define MANDELBROT_MAXITER_DEC BUTTON_REW
145 #define MANDELBROT_RESET (BUTTON_PLAY | BUTTON_REW)
151 #define MYLCD(fn) gray_ub_ ## fn
152 #define MYLCD_UPDATE()
153 #define MYXLCD(fn) gray_ub_ ## fn
155 #define MYLCD(fn) rb->lcd_ ## fn
156 #define MYLCD_UPDATE() rb->lcd_update();
157 #define MYXLCD(fn) xlcd_ ## fn
160 static struct plugin_api
* rb
;
162 /* Fixed point format s5.26: sign, 5 bits integer part, 26 bits fractional part */
172 static int px_min
= 0;
173 static int px_max
= LCD_WIDTH
;
174 static int py_min
= 0;
175 static int py_max
= LCD_HEIGHT
;
177 static int step_log2
;
178 static unsigned max_iter
;
181 static unsigned char *gbuf
;
182 static size_t gbuf_size
= 0;
183 static unsigned char imgbuffer
[LCD_HEIGHT
];
185 static fb_data imgbuffer
[LCD_HEIGHT
];
188 /* 8 entries cyclical, last entry is black (convergence) */
189 #ifdef HAVE_LCD_COLOR
190 static const fb_data color
[9] = {
191 LCD_RGBPACK(255, 0, 159), LCD_RGBPACK(159, 0, 255), LCD_RGBPACK(0, 0, 255),
192 LCD_RGBPACK(0, 159, 255), LCD_RGBPACK(0, 255, 128), LCD_RGBPACK(128, 255, 0),
193 LCD_RGBPACK(255, 191, 0), LCD_RGBPACK(255, 0, 0), LCD_RGBPACK(0, 0, 0)
195 #else /* greyscale */
196 static const fb_data color
[9] = {
197 255, 223, 191, 159, 128, 96, 64, 32, 0
201 #if CONFIG_CPU == SH7034
203 #define MULS16_ASR10(a, b) muls16_asr10(a, b)
204 static inline short muls16_asr10(short a
, short b
)
221 #define MULS32_ASR26(a, b) muls32_asr26(a, b)
222 static inline long muls32_asr26(long a
, long b
)
226 /* Signed 32bit * 32bit -> 64bit multiplication.
227 Notation: xxab * xxcd, where each letter represents 16 bits.
228 xx is the 64 bit sign extension. */
229 "swap.w %[a],%[t1] \n" /* t1 = ba */
230 "mulu %[t1],%[b] \n" /* a * d */
231 "swap.w %[b],%[t3] \n" /* t3 = dc */
232 "sts macl,%[t2] \n" /* t2 = a * d */
233 "mulu %[t1],%[t3] \n" /* a * c */
234 "sts macl,%[r] \n" /* hi = a * c */
235 "mulu %[a],%[t3] \n" /* b * c */
237 "sts macl,%[t3] \n" /* t3 = b * c */
238 "addc %[t2],%[t3] \n" /* t3 += t2, carry -> t2 */
240 "mulu %[a],%[b] \n" /* b * d */
241 "mov %[t3],%[t1] \n" /* t2t3 <<= 16 */
242 "xtrct %[t2],%[t1] \n"
245 "sts macl,%[t1] \n" /* lo = b * d */
246 "clrt \n" /* hi.lo += t2t3 */
247 "addc %[t3],%[t1] \n"
249 "cmp/pz %[a] \n" /* ab >= 0 ? */
251 "sub %[b],%[r] \n" /* no: hi -= cd (sign extension of ab is -1) */
253 "cmp/pz %[b] \n" /* cd >= 0 ? */
255 "sub %[a],%[r] \n" /* no: hi -= ab (sign extension of cd is -1) */
257 /* Shift right by 26 and return low 32 bits */
258 "shll2 %[r] \n" /* hi <<= 6 */
261 "shlr16 %[t1] \n" /* (unsigned)lo >>= 26 */
264 "or %[t1],%[r] \n" /* combine result */
277 #elif defined CPU_COLDFIRE
279 #define MULS16_ASR10(a, b) muls16_asr10(a, b)
280 static inline short muls16_asr10(short a
, short b
)
283 "muls.w %[a],%[b] \n"
294 /* Needs the EMAC initialised to fractional mode w/o rounding and saturation */
295 #define MULS32_INIT() coldfire_set_macsr(EMAC_FRACTIONAL)
296 #define MULS32_ASR26(a, b) muls32_asr26(a, b)
297 static inline long muls32_asr26(long a
, long b
)
301 "mac.l %[a],%[b],%%acc0\n" /* multiply */
302 "mulu.l %[a],%[b] \n" /* get lower half */
303 "movclr.l %%acc0,%[r] \n" /* get higher half */
304 "asl.l #5,%[r] \n" /* hi <<= 5, plus one free */
305 "moveq.l #26,%[t1] \n"
306 "lsr.l %[t1],%[b] \n" /* (unsigned)lo >>= 26 */
307 "or.l %[b],%[r] \n" /* combine result */
318 #elif defined CPU_ARM
320 #define MULS32_ASR26(a, b) muls32_asr26(a, b)
321 static inline long muls32_asr26(long a
, long b
)
325 "smull %[r], %[t1], %[a], %[b] \n"
326 "mov %[r], %[r], lsr #26 \n"
327 "orr %[r], %[r], %[t1], lsl #6 \n"
342 #define MULS16_ASR10(a, b) ((short)(((long)(a) * (long)(b)) >> 10))
345 #define MULS32_ASR26(a, b) ((long)(((long long)(a) * (long long)(b)) >> 26))
348 #define MULS32_INIT()
351 int ilog2_fp(long value
) /* calculate integer log2(value_fp_6.26) */
357 } else if (value
> (1L<<26)) {
358 while (value
>= (2L<<26)) {
363 while (value
< (1L<<26)) {
371 void recalc_parameters(void)
373 x_step
= (x_max
- x_min
) / LCD_WIDTH
;
374 x_delta
= (x_step
* LCD_WIDTH
) / 8;
375 y_step
= (y_max
- y_min
) / LCD_HEIGHT
;
376 y_delta
= (y_step
* LCD_HEIGHT
) / 8;
377 step_log2
= ilog2_fp(MIN(x_step
, y_step
));
378 max_iter
= MAX(15, -15 * step_log2
- 45);
381 #if CONFIG_LCD == LCD_SSD1815
382 /* Recorder, Ondio: pixel_height == 1.25 * pixel_width */
383 #define MB_HEIGHT (LCD_HEIGHT*5/4)
386 #define MB_HEIGHT LCD_HEIGHT
389 #define MB_XOFS (-0x03000000L) /* -0.75 (s5.26) */
390 #if 3000*MB_HEIGHT/LCD_WIDTH >= 2400 /* width is limiting factor */
391 #define MB_XFAC (0x06000000LL) /* 1.5 (s5.26) */
392 #define MB_YFAC (MB_XFAC*MB_HEIGHT/LCD_WIDTH)
393 #else /* height is limiting factor */
394 #define MB_YFAC (0x04cccccdLL) /* 1.2 (s5.26) */
395 #define MB_XFAC (MB_YFAC*LCD_WIDTH/MB_HEIGHT)
398 void init_mandelbrot_set(void)
400 x_min
= MB_XOFS
-MB_XFAC
;
401 x_max
= MB_XOFS
+MB_XFAC
;
407 void calc_mandelbrot_low_prec(void)
409 long start_tick
, last_yield
;
412 short x
, x2
, y
, y2
, a
, b
;
415 start_tick
= last_yield
= *rb
->current_tick
;
417 for (p_x
= 0, a32
= x_min
; p_x
< px_max
; p_x
++, a32
+= x_step
) {
421 for (p_y
= LCD_HEIGHT
-1, b32
= y_min
; p_y
>= py_min
; p_y
--, b32
+= y_step
) {
429 while (++n_iter
<= max_iter
) {
430 x2
= MULS16_ASR10(x
, x
);
431 y2
= MULS16_ASR10(y
, y
);
433 if (x2
+ y2
> (4<<10)) break;
435 y
= 2 * MULS16_ASR10(x
, y
) + b
;
439 if (n_iter
> max_iter
)
440 imgbuffer
[p_y
] = color
[8];
442 imgbuffer
[p_y
] = color
[n_iter
& 7];
444 /* be nice to other threads:
445 * if at least one tick has passed, yield */
446 if (*rb
->current_tick
> last_yield
) {
448 last_yield
= *rb
->current_tick
;
452 gray_ub_gray_bitmap_part(imgbuffer
, 0, py_min
, 1,
453 p_x
, py_min
, 1, py_max
-py_min
);
455 rb
->lcd_bitmap_part(imgbuffer
, 0, py_min
, 1,
456 p_x
, py_min
, 1, py_max
-py_min
);
457 rb
->lcd_update_rect(p_x
, py_min
, 1, py_max
-py_min
);
462 void calc_mandelbrot_high_prec(void)
464 long start_tick
, last_yield
;
466 long x
, x2
, y
, y2
, a
, b
;
470 start_tick
= last_yield
= *rb
->current_tick
;
472 for (p_x
= 0, a
= x_min
; p_x
< px_max
; p_x
++, a
+= x_step
) {
475 for (p_y
= LCD_HEIGHT
-1, b
= y_min
; p_y
>= py_min
; p_y
--, b
+= y_step
) {
482 while (++n_iter
<= max_iter
) {
483 x2
= MULS32_ASR26(x
, x
);
484 y2
= MULS32_ASR26(y
, y
);
486 if (x2
+ y2
> (4L<<26)) break;
488 y
= 2 * MULS32_ASR26(x
, y
) + b
;
492 if (n_iter
> max_iter
)
493 imgbuffer
[p_y
] = color
[8];
495 imgbuffer
[p_y
] = color
[n_iter
& 7];
497 /* be nice to other threads:
498 * if at least one tick has passed, yield */
499 if (*rb
->current_tick
> last_yield
) {
501 last_yield
= *rb
->current_tick
;
505 gray_ub_gray_bitmap_part(imgbuffer
, 0, py_min
, 1,
506 p_x
, py_min
, 1, py_max
-py_min
);
508 rb
->lcd_bitmap_part(imgbuffer
, 0, py_min
, 1,
509 p_x
, py_min
, 1, py_max
-py_min
);
510 rb
->lcd_update_rect(p_x
, py_min
, 1, py_max
-py_min
);
515 void cleanup(void *parameter
)
523 #define REDRAW_NONE 0
524 #define REDRAW_PARTIAL 1
525 #define REDRAW_FULL 2
527 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
530 int lastbutton
= BUTTON_NONE
;
531 int redraw
= REDRAW_FULL
;
541 /* get the remainder of the plugin buffer */
542 gbuf
= (unsigned char *) rb
->plugin_get_buffer(&gbuf_size
);
544 /* initialize the grayscale buffer:
545 * 8 bitplanes for 9 shades of gray.*/
546 grayscales
= gray_init(rb
, gbuf
, gbuf_size
, false, LCD_WIDTH
, LCD_HEIGHT
,
548 if (grayscales
!= 9) {
549 rb
->snprintf(buff
, sizeof(buff
), "%d", grayscales
);
550 rb
->lcd_puts(0, 1, buff
);
556 gray_show(true); /* switch on grayscale overlay */
562 rb
->lcd_set_backdrop(NULL
);
565 init_mandelbrot_set();
569 if (redraw
> REDRAW_NONE
) {
570 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
573 if (redraw
== REDRAW_FULL
) {
574 MYLCD(clear_display
)();
578 if (step_log2
<= -10) /* select precision */
579 calc_mandelbrot_high_prec();
581 calc_mandelbrot_low_prec();
583 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
584 rb
->cpu_boost(false);
590 redraw
= REDRAW_NONE
;
593 button
= rb
->button_get(true);
595 #ifdef MANDELBROT_RC_QUIT
596 case MANDELBROT_RC_QUIT
:
598 case MANDELBROT_QUIT
:
604 case MANDELBROT_ZOOM_OUT
:
610 redraw
= REDRAW_FULL
;
614 case MANDELBROT_ZOOM_IN
:
615 #ifdef MANDELBROT_ZOOM_IN_PRE
616 if (lastbutton
!= MANDELBROT_ZOOM_IN_PRE
)
619 #ifdef MANDELBROT_ZOOM_IN2
620 case MANDELBROT_ZOOM_IN2
:
627 redraw
= REDRAW_FULL
;
633 MYXLCD(scroll_down
)(LCD_HEIGHT
/8);
635 py_max
= (LCD_HEIGHT
/8);
636 redraw
= REDRAW_PARTIAL
;
639 case MANDELBROT_DOWN
:
642 MYXLCD(scroll_up
)(LCD_HEIGHT
/8);
644 py_min
= (LCD_HEIGHT
-LCD_HEIGHT
/8);
645 redraw
= REDRAW_PARTIAL
;
648 case MANDELBROT_LEFT
:
651 MYXLCD(scroll_right
)(LCD_WIDTH
/8);
653 px_max
= (LCD_WIDTH
/8);
654 redraw
= REDRAW_PARTIAL
;
657 case MANDELBROT_RIGHT
:
660 MYXLCD(scroll_left
)(LCD_WIDTH
/8);
662 px_min
= (LCD_WIDTH
-LCD_WIDTH
/8);
663 redraw
= REDRAW_PARTIAL
;
666 case MANDELBROT_MAXITER_DEC
:
667 if (max_iter
>= 15) {
668 max_iter
-= max_iter
/ 3;
669 redraw
= REDRAW_FULL
;
673 case MANDELBROT_MAXITER_INC
:
674 max_iter
+= max_iter
/ 2;
675 redraw
= REDRAW_FULL
;
678 case MANDELBROT_RESET
:
679 init_mandelbrot_set();
680 redraw
= REDRAW_FULL
;
684 if (rb
->default_event_handler_ex(button
, cleanup
, NULL
)
685 == SYS_USB_CONNECTED
)
686 return PLUGIN_USB_CONNECTED
;
689 if (button
!= BUTTON_NONE
)