New makefile solution: A single invocation of 'make' to build the entire tree. Fully...
[kugel-rb.git] / apps / plugins / fire.c
blobf1b62f5b266041d11333706c65cc0ae549c7170e
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"
26 #ifdef HAVE_LCD_BITMAP
28 #include "lib/pluginlib_actions.h"
29 #include "lib/fixedpoint.h"
31 #ifndef HAVE_LCD_COLOR
32 #include "lib/grey.h"
33 #endif
35 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
36 /* Archos has not enough plugin RAM for full-width fire :( */
37 #define FIRE_WIDTH 106
38 #define FIRE_XPOS 3
39 #else
40 #define FIRE_WIDTH LCD_WIDTH
41 #define FIRE_XPOS 0
42 #endif
44 PLUGIN_HEADER
46 static const struct plugin_api* rb; /* global api struct pointer */
48 #ifndef HAVE_LCD_COLOR
49 GREY_INFO_STRUCT
50 static unsigned char draw_buffer[FIRE_WIDTH];
52 #endif
54 /* Key assignement */
55 const struct button_mapping* plugin_contexts[]= {
56 generic_increase_decrease,
57 generic_directions,
58 #if defined(HAVE_REMOTE_LCD)
59 remote_directions,
60 #endif
61 generic_actions
63 #define PLA_ARRAY_COUNT sizeof(plugin_contexts)/sizeof(plugin_contexts[0])
65 #define FIRE_QUIT PLA_QUIT
66 #define FIRE_SWITCH_FLAMES_TYPE PLA_LEFT
67 #define FIRE_SWITCH_FLAMES_MOVING PLA_RIGHT
68 #define FIRE_INCREASE_MULT PLA_INC
69 #define FIRE_DECREASE_MULT PLA_DEC
71 #define MIN_FLAME_VALUE 0
72 #define COOL_MAX (440/LCD_HEIGHT+2)
74 #ifndef HAVE_LCD_COLOR
75 static unsigned char palette[256];
77 void color_palette_init(unsigned char* palette)
79 int i;
80 for(i=0;i<=160;i++)//palette[i]=(3/2)*i
81 palette[i]=(i*3)/2;
83 /* 'regular' fire doesn't exceed this value */
84 for(;i<=255;i++)//palette[i]=(3/20)*i+216
85 palette[i]=(i*3+20*217)/20;
87 #else
89 static fb_data palette[256];
92 * Color palette generation algorithm taken from
93 * the "The Demo Effects Collection" GPL project
94 * Copyright (C) 2002 W.P. van Paassen
96 void color_palette_init(fb_data* palette)
98 int i;
99 for (i = 0; i < 32; i++){
100 /* black to blue, 32 values*/
101 palette[i]=LCD_RGBPACK(0, 0, 2*i);
103 /* blue to red, 32 values*/
104 palette[i + 32]=LCD_RGBPACK(8*i, 0, 64 - 2*i);
106 /* red to yellow, 32 values*/
107 palette[i + 64]=LCD_RGBPACK(255, 8*i, 0);
109 /* yellow to white, 162 values */
110 palette[i + 96]=LCD_RGBPACK(255, 255, 0 + 4*i);
111 palette[i + 128]=LCD_RGBPACK(255, 255, 64 + 4*i);
112 palette[i + 160]=LCD_RGBPACK(255, 255, 128 + 4*i);
113 palette[i + 192]=LCD_RGBPACK(255, 255, 192 + i);
114 palette[i + 224]=LCD_RGBPACK(255, 255, 224 + i);
118 #endif
120 static void tab_init_rand(unsigned char *tab, unsigned int tab_size,
121 int rand_max)
123 unsigned char *end = tab + tab_size;
125 while(tab < end)
126 *tab++ = (unsigned char)rb->rand() % rand_max;
129 struct fire {
130 unsigned char fire[LCD_HEIGHT+3][FIRE_WIDTH];
131 unsigned char cooling_map[LCD_HEIGHT][FIRE_WIDTH];
132 int flames_type;
133 bool moving;
134 unsigned int mult;
136 /* makes the instance a global variable since it's too big to fit on the target's stack */
137 static struct fire fire;
139 static inline void fire_convolve(struct fire* fire)
141 unsigned int pixel_value;
142 unsigned int cooling_value;
143 unsigned char *ptr, *end, *cool;
144 unsigned int mult=fire->mult;
146 rb->yield();
147 /* Convolve the pixels and handle cooling (to add nice shapes effects later) */
148 cool = &fire->cooling_map[0][0];
149 ptr = &fire->fire[0][0];
150 end = ptr + LCD_HEIGHT*FIRE_WIDTH;
152 switch (fire->flames_type){
153 case 0:
155 pixel_value = ptr[FIRE_WIDTH-1] /* fire[y+1][x-1] */
156 + ptr[2*FIRE_WIDTH] /* fire[y+2][x] */
157 + ptr[FIRE_WIDTH+1] /* fire[y+1][x+1] */
158 + ptr[3*FIRE_WIDTH]; /* fire[y+3][x] */
159 pixel_value = FMULU(pixel_value, mult) >> 10;
161 cooling_value = *cool++;
162 if (cooling_value <= pixel_value)
163 pixel_value -= cooling_value;
164 /* else it's too cold, don't frost the pixels !!! */
166 if (pixel_value > 255)
167 pixel_value = 255;
169 *ptr++ = pixel_value;
170 }while (ptr < end);
171 break;
173 case 1:
174 mult -= 2;
176 pixel_value = ptr[FIRE_WIDTH-1] /* fire[y+1][x-1] */
177 + ptr[FIRE_WIDTH] /* fire[y+1][x] */
178 + ptr[FIRE_WIDTH+1] /* fire[y+1][x+1] */
179 + ptr[2*FIRE_WIDTH]; /* fire[y+2][x] */
180 pixel_value = FMULU(pixel_value, mult) >> 10;
182 cooling_value = *cool++;
183 if (cooling_value <= pixel_value)
184 pixel_value -= cooling_value;
185 /* else it's too cold, don't frost the pixels !!! */
187 if (pixel_value > 255)
188 pixel_value = 255;
190 *ptr++ = pixel_value;
191 }while (ptr < end);
192 break;
194 default: /* We should never reach this */
195 break;
197 rb->yield();
200 static void fire_generate_bottom_seed(struct fire* fire)
202 unsigned char *ptr, *end;
203 ptr = &fire->fire[LCD_HEIGHT][0];
204 end = ptr + FIRE_WIDTH;
206 *ptr++ = (MIN_FLAME_VALUE + rb->rand() % (256-MIN_FLAME_VALUE));
207 }while (ptr < end);
210 static inline void fire_step(struct fire* fire)
212 if(fire->moving){
213 /* Randomize the bottom line */
214 fire_generate_bottom_seed(fire);
215 /* Add here further effects like fire letters, ball ... */
217 fire_convolve(fire);
220 static void fire_init(struct fire* fire)
222 fire->mult = 261;
223 fire->flames_type=0;
224 fire->moving=true;
225 rb->memset(&fire->fire[0][0], 0, sizeof(fire->fire));
226 tab_init_rand(&fire->cooling_map[0][0], LCD_HEIGHT*FIRE_WIDTH, COOL_MAX);
227 fire_generate_bottom_seed(fire);
230 static inline void fire_draw(struct fire* fire)
232 int y;
233 unsigned char *src = &fire->fire[0][0];
234 #ifndef HAVE_LCD_COLOR
235 unsigned char *dest, *end;
236 #else
237 fb_data *dest, *end;
238 #endif
240 for (y = 0; y < LCD_HEIGHT; y++){
241 #ifndef HAVE_LCD_COLOR
242 dest = draw_buffer;
243 #else
244 dest = rb->lcd_framebuffer + LCD_WIDTH * y + FIRE_XPOS;
245 #endif
246 end = dest + FIRE_WIDTH;
249 *dest++ = palette[*src++];
250 while (dest < end);
251 #ifndef HAVE_LCD_COLOR
252 grey_ub_gray_bitmap(draw_buffer, 0, y, FIRE_WIDTH, 1);
253 #endif
255 #ifdef HAVE_LCD_COLOR
256 rb->lcd_update();
257 #endif
260 void cleanup(void *parameter)
262 (void)parameter;
263 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
264 rb->cpu_boost(false);
265 #endif
266 #ifndef HAVE_LCD_COLOR
267 grey_release();
268 #endif
269 /* Turn on backlight timeout (revert to settings) */
270 backlight_use_settings(rb); /* backlight control in lib/helper.c */
274 #ifndef HAVE_LCD_COLOR
275 int init_grey(void)
277 unsigned char *gbuf;
278 size_t gbuf_size = 0;
280 /* get the remainder of the plugin buffer */
281 gbuf = (unsigned char *) rb->plugin_get_buffer(&gbuf_size);
283 if (!grey_init(rb, gbuf, gbuf_size, GREY_ON_COP,
284 FIRE_WIDTH, LCD_HEIGHT, NULL)){
285 rb->splash(HZ, "not enough memory");
286 return PLUGIN_ERROR;
288 /* switch on greyscale overlay */
289 grey_set_position(FIRE_XPOS, 0);
290 grey_show(true);
291 return PLUGIN_OK;
293 #endif
295 int main(void)
297 int action;
299 #ifndef HAVE_LCD_COLOR
300 if(init_grey()!=PLUGIN_OK)
301 return(PLUGIN_ERROR);
302 #endif
303 color_palette_init(palette);
305 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
306 rb->cpu_boost(true);
307 #endif
309 fire_init(&fire);
310 while (true){
311 fire_step(&fire);
312 fire_draw(&fire);
313 rb->yield();
315 action = pluginlib_getaction(rb, 0, plugin_contexts, PLA_ARRAY_COUNT);
317 switch(action){
318 case FIRE_QUIT:
319 cleanup(NULL);
320 return PLUGIN_OK;
322 case FIRE_INCREASE_MULT:
323 ++fire.mult;
324 break;
326 case FIRE_DECREASE_MULT:
327 if (fire.mult > 0)
328 --fire.mult;
329 break;
331 case FIRE_SWITCH_FLAMES_TYPE:
332 fire.flames_type = (fire.flames_type + 1) % 2;
333 break;
335 case FIRE_SWITCH_FLAMES_MOVING:
336 fire.moving = !fire.moving;
337 break;
339 default:
340 if (rb->default_event_handler_ex(action, cleanup, NULL)
341 == SYS_USB_CONNECTED)
342 return PLUGIN_USB_CONNECTED;
347 /*************************** Plugin entry point ****************************/
349 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
351 int ret;
353 rb = api; //copy to global api pointer
354 (void)parameter;
355 #if LCD_DEPTH > 1
356 rb->lcd_set_backdrop(NULL);
357 #endif
358 /* Turn off backlight timeout */
359 backlight_force_on(rb); /* backlight control in lib/helper.c */
361 ret = main();
363 return ret;
366 #endif /* #ifdef HAVE_LCD_BITMAP */