Prepare new maemo release
[maemo-rb.git] / apps / plugins / fire.c
blob5813894d4f5d40464ce4f78a4642db61537fe7f8
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 Kevin Ferrare
12 * Fire demo plugin
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 ****************************************************************************/
24 #include "plugin.h"
25 #include "lib/helper.h"
27 #include "lib/pluginlib_actions.h"
28 #include "lib/fixedpoint.h"
30 #ifndef HAVE_LCD_COLOR
31 #include "lib/grey.h"
32 #endif
34 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
35 /* Archos has not enough plugin RAM for full-width fire :( */
36 #define FIRE_WIDTH 106
37 #define FIRE_XPOS 3
38 #else
39 #define FIRE_WIDTH LCD_WIDTH
40 #define FIRE_XPOS 0
41 #endif
43 #ifndef HAVE_LCD_COLOR
44 GREY_INFO_STRUCT
45 static unsigned char draw_buffer[FIRE_WIDTH];
47 #endif
49 /* Key assignement */
50 const struct button_mapping* plugin_contexts[]= {
51 pla_main_ctx,
52 #if defined(HAVE_REMOTE_LCD)
53 pla_remote_ctx,
54 #endif
57 #define FIRE_QUIT PLA_CANCEL
58 #define FIRE_SWITCH_FLAMES_TYPE PLA_LEFT
59 #define FIRE_SWITCH_FLAMES_MOVING PLA_RIGHT
61 #ifdef HAVE_SCROLLWHEEL
62 #define FIRE_INCREASE_MULT PLA_SCROLL_FWD
63 #define FIRE_INCREASE_MULT_REP PLA_SCROLL_FWD_REPEAT
64 #define FIRE_DECREASE_MULT PLA_SCROLL_BACK
65 #define FIRE_DECREASE_MULT_REP PLA_SCROLL_BACK_REPEAT
66 #else
67 #define FIRE_INCREASE_MULT PLA_UP
68 #define FIRE_INCREASE_MULT_REP PLA_UP_REPEAT
69 #define FIRE_DECREASE_MULT PLA_DOWN
70 #define FIRE_DECREASE_MULT_REP PLA_DOWN_REPEAT
71 #endif
73 #define MIN_FLAME_VALUE 0
74 #define COOL_MAX (440/LCD_HEIGHT+2)
76 #ifndef HAVE_LCD_COLOR
77 static unsigned char palette[256];
79 static void color_palette_init(unsigned char* palette)
81 int i;
82 for(i=0;i<=160;i++)//palette[i]=(3/2)*i
83 palette[i]=(i*3)/2;
85 /* 'regular' fire doesn't exceed this value */
86 for(;i<=255;i++)//palette[i]=(3/20)*i+216
87 palette[i]=(i*3+20*217)/20;
89 #else
91 static fb_data palette[256];
94 * Color palette generation algorithm taken from
95 * the "The Demo Effects Collection" GPL project
96 * Copyright (C) 2002 W.P. van Paassen
98 static void color_palette_init(fb_data* palette)
100 int i;
101 for (i = 0; i < 32; i++){
102 /* black to blue, 32 values*/
103 palette[i]=LCD_RGBPACK(0, 0, 2*i);
105 /* blue to red, 32 values*/
106 palette[i + 32]=LCD_RGBPACK(8*i, 0, 64 - 2*i);
108 /* red to yellow, 32 values*/
109 palette[i + 64]=LCD_RGBPACK(255, 8*i, 0);
111 /* yellow to white, 162 values */
112 palette[i + 96]=LCD_RGBPACK(255, 255, 0 + 4*i);
113 palette[i + 128]=LCD_RGBPACK(255, 255, 64 + 4*i);
114 palette[i + 160]=LCD_RGBPACK(255, 255, 128 + 4*i);
115 palette[i + 192]=LCD_RGBPACK(255, 255, 192 + i);
116 palette[i + 224]=LCD_RGBPACK(255, 255, 224 + i);
118 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
119 rb->lcd_pal256_update_pal(palette);
120 #endif
123 #endif
125 static void tab_init_rand(unsigned char *tab, unsigned int tab_size,
126 int rand_max)
128 unsigned char *end = tab + tab_size;
130 while(tab < end)
131 *tab++ = (unsigned char)rb->rand() % rand_max;
134 struct fire {
135 unsigned char fire[LCD_HEIGHT+3][FIRE_WIDTH];
136 unsigned char cooling_map[LCD_HEIGHT][FIRE_WIDTH];
137 int flames_type;
138 bool moving;
139 unsigned int mult;
141 /* makes the instance a global variable since it's too big to fit on the target's stack */
142 static struct fire fire;
144 static inline void fire_convolve(struct fire* fire)
146 unsigned int pixel_value;
147 unsigned int cooling_value;
148 unsigned char *ptr, *end, *cool;
149 unsigned int mult=fire->mult;
151 rb->yield();
152 /* Convolve the pixels and handle cooling (to add nice shapes effects later) */
153 cool = &fire->cooling_map[0][0];
154 ptr = &fire->fire[0][0];
155 end = ptr + LCD_HEIGHT*FIRE_WIDTH;
157 switch (fire->flames_type){
158 case 0:
160 pixel_value = ptr[FIRE_WIDTH-1] /* fire[y+1][x-1] */
161 + ptr[2*FIRE_WIDTH] /* fire[y+2][x] */
162 + ptr[FIRE_WIDTH+1] /* fire[y+1][x+1] */
163 + ptr[3*FIRE_WIDTH]; /* fire[y+3][x] */
164 pixel_value = FMULU(pixel_value, mult) >> 10;
166 cooling_value = *cool++;
167 if (cooling_value <= pixel_value)
168 pixel_value -= cooling_value;
169 /* else it's too cold, don't frost the pixels !!! */
171 if (pixel_value > 255)
172 pixel_value = 255;
174 *ptr++ = pixel_value;
175 }while (ptr < end);
176 break;
178 case 1:
179 mult -= 2;
181 pixel_value = ptr[FIRE_WIDTH-1] /* fire[y+1][x-1] */
182 + ptr[FIRE_WIDTH] /* fire[y+1][x] */
183 + ptr[FIRE_WIDTH+1] /* fire[y+1][x+1] */
184 + ptr[2*FIRE_WIDTH]; /* fire[y+2][x] */
185 pixel_value = FMULU(pixel_value, mult) >> 10;
187 cooling_value = *cool++;
188 if (cooling_value <= pixel_value)
189 pixel_value -= cooling_value;
190 /* else it's too cold, don't frost the pixels !!! */
192 if (pixel_value > 255)
193 pixel_value = 255;
195 *ptr++ = pixel_value;
196 }while (ptr < end);
197 break;
199 default: /* We should never reach this */
200 break;
202 rb->yield();
205 static void fire_generate_bottom_seed(struct fire* fire)
207 unsigned char *ptr, *end;
208 ptr = &fire->fire[LCD_HEIGHT][0];
209 end = ptr + FIRE_WIDTH;
211 *ptr++ = (MIN_FLAME_VALUE + rb->rand() % (256-MIN_FLAME_VALUE));
212 }while (ptr < end);
215 static inline void fire_step(struct fire* fire)
217 if(fire->moving){
218 /* Randomize the bottom line */
219 fire_generate_bottom_seed(fire);
220 /* Add here further effects like fire letters, ball ... */
222 fire_convolve(fire);
225 static void fire_init(struct fire* fire)
227 fire->mult = 261;
228 fire->flames_type=0;
229 fire->moving=true;
230 rb->memset(&fire->fire[0][0], 0, sizeof(fire->fire));
231 tab_init_rand(&fire->cooling_map[0][0], LCD_HEIGHT*FIRE_WIDTH, COOL_MAX);
232 fire_generate_bottom_seed(fire);
235 static inline void fire_draw(struct fire* fire)
237 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
238 rb->lcd_blit_pal256((unsigned char*)&fire->fire[0][0],0,0,0,0,LCD_WIDTH,LCD_HEIGHT);
239 #else
240 int y;
241 unsigned char *src = &fire->fire[0][0];
243 #ifndef HAVE_LCD_COLOR
244 unsigned char *dest, *end;
245 #else
246 fb_data *dest, *end;
247 #endif
249 for (y = 0; y < LCD_HEIGHT; y++){
250 #ifndef HAVE_LCD_COLOR
251 dest = draw_buffer;
252 #else
253 dest = rb->lcd_framebuffer + LCD_WIDTH * y + FIRE_XPOS;
254 #endif
255 end = dest + FIRE_WIDTH;
258 *dest++ = palette[*src++];
259 while (dest < end);
260 #ifndef HAVE_LCD_COLOR
261 grey_ub_gray_bitmap(draw_buffer, 0, y, FIRE_WIDTH, 1);
262 #endif
264 #ifdef HAVE_LCD_COLOR
265 rb->lcd_update();
266 #endif
268 #endif
271 static void cleanup(void *parameter)
273 (void)parameter;
274 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
275 rb->cpu_boost(false);
276 #endif
277 #ifndef HAVE_LCD_COLOR
278 grey_release();
279 #endif
280 /* Turn on backlight timeout (revert to settings) */
281 backlight_use_settings();
285 #ifndef HAVE_LCD_COLOR
286 static int init_grey(void)
288 unsigned char *gbuf;
289 size_t gbuf_size = 0;
291 /* get the remainder of the plugin buffer */
292 gbuf = (unsigned char *) rb->plugin_get_buffer(&gbuf_size);
294 if (!grey_init(gbuf, gbuf_size, GREY_ON_COP,
295 FIRE_WIDTH, LCD_HEIGHT, NULL)){
296 rb->splash(HZ, "not enough memory");
297 return PLUGIN_ERROR;
299 /* switch on greyscale overlay */
300 grey_set_position(FIRE_XPOS, 0);
301 grey_show(true);
302 return PLUGIN_OK;
304 #endif
306 int main(void)
308 int action;
310 #ifndef HAVE_LCD_COLOR
311 if(init_grey()!=PLUGIN_OK)
312 return(PLUGIN_ERROR);
313 #endif
314 color_palette_init(palette);
316 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
317 rb->cpu_boost(true);
318 #endif
320 fire_init(&fire);
321 while (true){
322 fire_step(&fire);
323 fire_draw(&fire);
324 rb->yield();
326 action = pluginlib_getaction(0, plugin_contexts,
327 ARRAYLEN(plugin_contexts));
329 switch(action){
330 case FIRE_QUIT:
331 cleanup(NULL);
332 return PLUGIN_OK;
334 case FIRE_INCREASE_MULT:
335 ++fire.mult;
336 break;
338 case FIRE_DECREASE_MULT:
339 if (fire.mult > 0)
340 --fire.mult;
341 break;
343 case FIRE_SWITCH_FLAMES_TYPE:
344 fire.flames_type = (fire.flames_type + 1) % 2;
345 break;
347 case FIRE_SWITCH_FLAMES_MOVING:
348 fire.moving = !fire.moving;
349 break;
351 default:
352 if (rb->default_event_handler_ex(action, cleanup, NULL)
353 == SYS_USB_CONNECTED)
354 return PLUGIN_USB_CONNECTED;
359 /*************************** Plugin entry point ****************************/
361 enum plugin_status plugin_start(const void* parameter)
363 int ret;
365 (void)parameter;
366 #if LCD_DEPTH > 1
367 rb->lcd_set_backdrop(NULL);
368 #endif
369 /* Turn off backlight timeout */
370 backlight_ignore_timeout();
372 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
373 rb->lcd_set_mode(LCD_MODE_PAL256);
374 #endif
376 ret = main();
378 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
379 rb->lcd_set_mode(LCD_MODE_RGB565);
380 #endif
382 return ret;