Update the discussion of themeing in the manual, and put a note in the wps tags appen...
[kugel-rb.git] / apps / plugins / fire.c
blobfff39b38c9ce0f864b3eb2e24c154ba898683a81
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 #ifndef HAVE_LCD_COLOR
47 GREY_INFO_STRUCT
48 static unsigned char draw_buffer[FIRE_WIDTH];
50 #endif
52 /* Key assignement */
53 const struct button_mapping* plugin_contexts[]= {
54 generic_increase_decrease,
55 generic_directions,
56 #if defined(HAVE_REMOTE_LCD)
57 remote_directions,
58 #endif
59 generic_actions
61 #define PLA_ARRAY_COUNT sizeof(plugin_contexts)/sizeof(plugin_contexts[0])
63 #define FIRE_QUIT PLA_QUIT
64 #define FIRE_SWITCH_FLAMES_TYPE PLA_LEFT
65 #define FIRE_SWITCH_FLAMES_MOVING PLA_RIGHT
66 #define FIRE_INCREASE_MULT PLA_INC
67 #define FIRE_DECREASE_MULT PLA_DEC
69 #define MIN_FLAME_VALUE 0
70 #define COOL_MAX (440/LCD_HEIGHT+2)
72 #ifndef HAVE_LCD_COLOR
73 static unsigned char palette[256];
75 void color_palette_init(unsigned char* palette)
77 int i;
78 for(i=0;i<=160;i++)//palette[i]=(3/2)*i
79 palette[i]=(i*3)/2;
81 /* 'regular' fire doesn't exceed this value */
82 for(;i<=255;i++)//palette[i]=(3/20)*i+216
83 palette[i]=(i*3+20*217)/20;
85 #else
87 static fb_data palette[256];
90 * Color palette generation algorithm taken from
91 * the "The Demo Effects Collection" GPL project
92 * Copyright (C) 2002 W.P. van Paassen
94 void color_palette_init(fb_data* palette)
96 int i;
97 for (i = 0; i < 32; i++){
98 /* black to blue, 32 values*/
99 palette[i]=LCD_RGBPACK(0, 0, 2*i);
101 /* blue to red, 32 values*/
102 palette[i + 32]=LCD_RGBPACK(8*i, 0, 64 - 2*i);
104 /* red to yellow, 32 values*/
105 palette[i + 64]=LCD_RGBPACK(255, 8*i, 0);
107 /* yellow to white, 162 values */
108 palette[i + 96]=LCD_RGBPACK(255, 255, 0 + 4*i);
109 palette[i + 128]=LCD_RGBPACK(255, 255, 64 + 4*i);
110 palette[i + 160]=LCD_RGBPACK(255, 255, 128 + 4*i);
111 palette[i + 192]=LCD_RGBPACK(255, 255, 192 + i);
112 palette[i + 224]=LCD_RGBPACK(255, 255, 224 + i);
114 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
115 rb->lcd_pal256_update_pal(palette);
116 #endif
119 #endif
121 static void tab_init_rand(unsigned char *tab, unsigned int tab_size,
122 int rand_max)
124 unsigned char *end = tab + tab_size;
126 while(tab < end)
127 *tab++ = (unsigned char)rb->rand() % rand_max;
130 struct fire {
131 unsigned char fire[LCD_HEIGHT+3][FIRE_WIDTH];
132 unsigned char cooling_map[LCD_HEIGHT][FIRE_WIDTH];
133 int flames_type;
134 bool moving;
135 unsigned int mult;
137 /* makes the instance a global variable since it's too big to fit on the target's stack */
138 static struct fire fire;
140 static inline void fire_convolve(struct fire* fire)
142 unsigned int pixel_value;
143 unsigned int cooling_value;
144 unsigned char *ptr, *end, *cool;
145 unsigned int mult=fire->mult;
147 rb->yield();
148 /* Convolve the pixels and handle cooling (to add nice shapes effects later) */
149 cool = &fire->cooling_map[0][0];
150 ptr = &fire->fire[0][0];
151 end = ptr + LCD_HEIGHT*FIRE_WIDTH;
153 switch (fire->flames_type){
154 case 0:
156 pixel_value = ptr[FIRE_WIDTH-1] /* fire[y+1][x-1] */
157 + ptr[2*FIRE_WIDTH] /* fire[y+2][x] */
158 + ptr[FIRE_WIDTH+1] /* fire[y+1][x+1] */
159 + ptr[3*FIRE_WIDTH]; /* fire[y+3][x] */
160 pixel_value = FMULU(pixel_value, mult) >> 10;
162 cooling_value = *cool++;
163 if (cooling_value <= pixel_value)
164 pixel_value -= cooling_value;
165 /* else it's too cold, don't frost the pixels !!! */
167 if (pixel_value > 255)
168 pixel_value = 255;
170 *ptr++ = pixel_value;
171 }while (ptr < end);
172 break;
174 case 1:
175 mult -= 2;
177 pixel_value = ptr[FIRE_WIDTH-1] /* fire[y+1][x-1] */
178 + ptr[FIRE_WIDTH] /* fire[y+1][x] */
179 + ptr[FIRE_WIDTH+1] /* fire[y+1][x+1] */
180 + ptr[2*FIRE_WIDTH]; /* fire[y+2][x] */
181 pixel_value = FMULU(pixel_value, mult) >> 10;
183 cooling_value = *cool++;
184 if (cooling_value <= pixel_value)
185 pixel_value -= cooling_value;
186 /* else it's too cold, don't frost the pixels !!! */
188 if (pixel_value > 255)
189 pixel_value = 255;
191 *ptr++ = pixel_value;
192 }while (ptr < end);
193 break;
195 default: /* We should never reach this */
196 break;
198 rb->yield();
201 static void fire_generate_bottom_seed(struct fire* fire)
203 unsigned char *ptr, *end;
204 ptr = &fire->fire[LCD_HEIGHT][0];
205 end = ptr + FIRE_WIDTH;
207 *ptr++ = (MIN_FLAME_VALUE + rb->rand() % (256-MIN_FLAME_VALUE));
208 }while (ptr < end);
211 static inline void fire_step(struct fire* fire)
213 if(fire->moving){
214 /* Randomize the bottom line */
215 fire_generate_bottom_seed(fire);
216 /* Add here further effects like fire letters, ball ... */
218 fire_convolve(fire);
221 static void fire_init(struct fire* fire)
223 fire->mult = 261;
224 fire->flames_type=0;
225 fire->moving=true;
226 rb->memset(&fire->fire[0][0], 0, sizeof(fire->fire));
227 tab_init_rand(&fire->cooling_map[0][0], LCD_HEIGHT*FIRE_WIDTH, COOL_MAX);
228 fire_generate_bottom_seed(fire);
231 static inline void fire_draw(struct fire* fire)
233 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
234 rb->lcd_blit_pal256((unsigned char*)&fire->fire[0][0],0,0,0,0,LCD_WIDTH,LCD_HEIGHT);
235 #else
236 int y;
237 unsigned char *src = &fire->fire[0][0];
239 #ifndef HAVE_LCD_COLOR
240 unsigned char *dest, *end;
241 #else
242 fb_data *dest, *end;
243 #endif
245 for (y = 0; y < LCD_HEIGHT; y++){
246 #ifndef HAVE_LCD_COLOR
247 dest = draw_buffer;
248 #else
249 dest = rb->lcd_framebuffer + LCD_WIDTH * y + FIRE_XPOS;
250 #endif
251 end = dest + FIRE_WIDTH;
254 *dest++ = palette[*src++];
255 while (dest < end);
256 #ifndef HAVE_LCD_COLOR
257 grey_ub_gray_bitmap(draw_buffer, 0, y, FIRE_WIDTH, 1);
258 #endif
260 #ifdef HAVE_LCD_COLOR
261 rb->lcd_update();
262 #endif
264 #endif
267 void cleanup(void *parameter)
269 (void)parameter;
270 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
271 rb->cpu_boost(false);
272 #endif
273 #ifndef HAVE_LCD_COLOR
274 grey_release();
275 #endif
276 /* Turn on backlight timeout (revert to settings) */
277 backlight_use_settings(); /* backlight control in lib/helper.c */
281 #ifndef HAVE_LCD_COLOR
282 int init_grey(void)
284 unsigned char *gbuf;
285 size_t gbuf_size = 0;
287 /* get the remainder of the plugin buffer */
288 gbuf = (unsigned char *) rb->plugin_get_buffer(&gbuf_size);
290 if (!grey_init(gbuf, gbuf_size, GREY_ON_COP,
291 FIRE_WIDTH, LCD_HEIGHT, NULL)){
292 rb->splash(HZ, "not enough memory");
293 return PLUGIN_ERROR;
295 /* switch on greyscale overlay */
296 grey_set_position(FIRE_XPOS, 0);
297 grey_show(true);
298 return PLUGIN_OK;
300 #endif
302 int main(void)
304 int action;
306 #ifndef HAVE_LCD_COLOR
307 if(init_grey()!=PLUGIN_OK)
308 return(PLUGIN_ERROR);
309 #endif
310 color_palette_init(palette);
312 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
313 rb->cpu_boost(true);
314 #endif
316 fire_init(&fire);
317 while (true){
318 fire_step(&fire);
319 fire_draw(&fire);
320 rb->yield();
322 action = pluginlib_getaction(0, plugin_contexts, PLA_ARRAY_COUNT);
324 switch(action){
325 case FIRE_QUIT:
326 cleanup(NULL);
327 return PLUGIN_OK;
329 case FIRE_INCREASE_MULT:
330 ++fire.mult;
331 break;
333 case FIRE_DECREASE_MULT:
334 if (fire.mult > 0)
335 --fire.mult;
336 break;
338 case FIRE_SWITCH_FLAMES_TYPE:
339 fire.flames_type = (fire.flames_type + 1) % 2;
340 break;
342 case FIRE_SWITCH_FLAMES_MOVING:
343 fire.moving = !fire.moving;
344 break;
346 default:
347 if (rb->default_event_handler_ex(action, cleanup, NULL)
348 == SYS_USB_CONNECTED)
349 return PLUGIN_USB_CONNECTED;
354 /*************************** Plugin entry point ****************************/
356 enum plugin_status plugin_start(const void* parameter)
358 int ret;
360 (void)parameter;
361 #if LCD_DEPTH > 1
362 rb->lcd_set_backdrop(NULL);
363 #endif
364 /* Turn off backlight timeout */
365 backlight_force_on(); /* backlight control in lib/helper.c */
367 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
368 rb->lcd_set_mode(LCD_MODE_PAL256);
369 #endif
371 ret = main();
373 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
374 rb->lcd_set_mode(LCD_MODE_RGB565);
375 #endif
377 return ret;
380 #endif /* #ifdef HAVE_LCD_BITMAP */