Build doom on clipv2 and clip+
[kugel-rb.git] / apps / plugins / fire.c
blobe1362dc900172e6425f9bc2975529be158a34fb4
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 pla_main_ctx,
55 #if defined(HAVE_REMOTE_LCD)
56 pla_remote_ctx,
57 #endif
60 #define FIRE_QUIT PLA_CANCEL
61 #define FIRE_SWITCH_FLAMES_TYPE PLA_LEFT
62 #define FIRE_SWITCH_FLAMES_MOVING PLA_RIGHT
64 #ifdef HAVE_SCROLLWHEEL
65 #define FIRE_INCREASE_MULT PLA_SCROLL_FWD
66 #define FIRE_INCREASE_MULT_REP PLA_SCROLL_FWD_REPEAT
67 #define FIRE_DECREASE_MULT PLA_SCROLL_BACK
68 #define FIRE_DECREASE_MULT_REP PLA_SCROLL_BACK_REPEAT
69 #else
70 #define FIRE_INCREASE_MULT PLA_UP
71 #define FIRE_INCREASE_MULT_REP PLA_UP_REPEAT
72 #define FIRE_DECREASE_MULT PLA_DOWN
73 #define FIRE_DECREASE_MULT_REP PLA_DOWN_REPEAT
74 #endif
76 #define MIN_FLAME_VALUE 0
77 #define COOL_MAX (440/LCD_HEIGHT+2)
79 #ifndef HAVE_LCD_COLOR
80 static unsigned char palette[256];
82 void color_palette_init(unsigned char* palette)
84 int i;
85 for(i=0;i<=160;i++)//palette[i]=(3/2)*i
86 palette[i]=(i*3)/2;
88 /* 'regular' fire doesn't exceed this value */
89 for(;i<=255;i++)//palette[i]=(3/20)*i+216
90 palette[i]=(i*3+20*217)/20;
92 #else
94 static fb_data palette[256];
97 * Color palette generation algorithm taken from
98 * the "The Demo Effects Collection" GPL project
99 * Copyright (C) 2002 W.P. van Paassen
101 void color_palette_init(fb_data* palette)
103 int i;
104 for (i = 0; i < 32; i++){
105 /* black to blue, 32 values*/
106 palette[i]=LCD_RGBPACK(0, 0, 2*i);
108 /* blue to red, 32 values*/
109 palette[i + 32]=LCD_RGBPACK(8*i, 0, 64 - 2*i);
111 /* red to yellow, 32 values*/
112 palette[i + 64]=LCD_RGBPACK(255, 8*i, 0);
114 /* yellow to white, 162 values */
115 palette[i + 96]=LCD_RGBPACK(255, 255, 0 + 4*i);
116 palette[i + 128]=LCD_RGBPACK(255, 255, 64 + 4*i);
117 palette[i + 160]=LCD_RGBPACK(255, 255, 128 + 4*i);
118 palette[i + 192]=LCD_RGBPACK(255, 255, 192 + i);
119 palette[i + 224]=LCD_RGBPACK(255, 255, 224 + i);
121 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
122 rb->lcd_pal256_update_pal(palette);
123 #endif
126 #endif
128 static void tab_init_rand(unsigned char *tab, unsigned int tab_size,
129 int rand_max)
131 unsigned char *end = tab + tab_size;
133 while(tab < end)
134 *tab++ = (unsigned char)rb->rand() % rand_max;
137 struct fire {
138 unsigned char fire[LCD_HEIGHT+3][FIRE_WIDTH];
139 unsigned char cooling_map[LCD_HEIGHT][FIRE_WIDTH];
140 int flames_type;
141 bool moving;
142 unsigned int mult;
144 /* makes the instance a global variable since it's too big to fit on the target's stack */
145 static struct fire fire;
147 static inline void fire_convolve(struct fire* fire)
149 unsigned int pixel_value;
150 unsigned int cooling_value;
151 unsigned char *ptr, *end, *cool;
152 unsigned int mult=fire->mult;
154 rb->yield();
155 /* Convolve the pixels and handle cooling (to add nice shapes effects later) */
156 cool = &fire->cooling_map[0][0];
157 ptr = &fire->fire[0][0];
158 end = ptr + LCD_HEIGHT*FIRE_WIDTH;
160 switch (fire->flames_type){
161 case 0:
163 pixel_value = ptr[FIRE_WIDTH-1] /* fire[y+1][x-1] */
164 + ptr[2*FIRE_WIDTH] /* fire[y+2][x] */
165 + ptr[FIRE_WIDTH+1] /* fire[y+1][x+1] */
166 + ptr[3*FIRE_WIDTH]; /* fire[y+3][x] */
167 pixel_value = FMULU(pixel_value, mult) >> 10;
169 cooling_value = *cool++;
170 if (cooling_value <= pixel_value)
171 pixel_value -= cooling_value;
172 /* else it's too cold, don't frost the pixels !!! */
174 if (pixel_value > 255)
175 pixel_value = 255;
177 *ptr++ = pixel_value;
178 }while (ptr < end);
179 break;
181 case 1:
182 mult -= 2;
184 pixel_value = ptr[FIRE_WIDTH-1] /* fire[y+1][x-1] */
185 + ptr[FIRE_WIDTH] /* fire[y+1][x] */
186 + ptr[FIRE_WIDTH+1] /* fire[y+1][x+1] */
187 + ptr[2*FIRE_WIDTH]; /* fire[y+2][x] */
188 pixel_value = FMULU(pixel_value, mult) >> 10;
190 cooling_value = *cool++;
191 if (cooling_value <= pixel_value)
192 pixel_value -= cooling_value;
193 /* else it's too cold, don't frost the pixels !!! */
195 if (pixel_value > 255)
196 pixel_value = 255;
198 *ptr++ = pixel_value;
199 }while (ptr < end);
200 break;
202 default: /* We should never reach this */
203 break;
205 rb->yield();
208 static void fire_generate_bottom_seed(struct fire* fire)
210 unsigned char *ptr, *end;
211 ptr = &fire->fire[LCD_HEIGHT][0];
212 end = ptr + FIRE_WIDTH;
214 *ptr++ = (MIN_FLAME_VALUE + rb->rand() % (256-MIN_FLAME_VALUE));
215 }while (ptr < end);
218 static inline void fire_step(struct fire* fire)
220 if(fire->moving){
221 /* Randomize the bottom line */
222 fire_generate_bottom_seed(fire);
223 /* Add here further effects like fire letters, ball ... */
225 fire_convolve(fire);
228 static void fire_init(struct fire* fire)
230 fire->mult = 261;
231 fire->flames_type=0;
232 fire->moving=true;
233 rb->memset(&fire->fire[0][0], 0, sizeof(fire->fire));
234 tab_init_rand(&fire->cooling_map[0][0], LCD_HEIGHT*FIRE_WIDTH, COOL_MAX);
235 fire_generate_bottom_seed(fire);
238 static inline void fire_draw(struct fire* fire)
240 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
241 rb->lcd_blit_pal256((unsigned char*)&fire->fire[0][0],0,0,0,0,LCD_WIDTH,LCD_HEIGHT);
242 #else
243 int y;
244 unsigned char *src = &fire->fire[0][0];
246 #ifndef HAVE_LCD_COLOR
247 unsigned char *dest, *end;
248 #else
249 fb_data *dest, *end;
250 #endif
252 for (y = 0; y < LCD_HEIGHT; y++){
253 #ifndef HAVE_LCD_COLOR
254 dest = draw_buffer;
255 #else
256 dest = rb->lcd_framebuffer + LCD_WIDTH * y + FIRE_XPOS;
257 #endif
258 end = dest + FIRE_WIDTH;
261 *dest++ = palette[*src++];
262 while (dest < end);
263 #ifndef HAVE_LCD_COLOR
264 grey_ub_gray_bitmap(draw_buffer, 0, y, FIRE_WIDTH, 1);
265 #endif
267 #ifdef HAVE_LCD_COLOR
268 rb->lcd_update();
269 #endif
271 #endif
274 void cleanup(void *parameter)
276 (void)parameter;
277 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
278 rb->cpu_boost(false);
279 #endif
280 #ifndef HAVE_LCD_COLOR
281 grey_release();
282 #endif
283 /* Turn on backlight timeout (revert to settings) */
284 backlight_use_settings(); /* backlight control in lib/helper.c */
288 #ifndef HAVE_LCD_COLOR
289 int init_grey(void)
291 unsigned char *gbuf;
292 size_t gbuf_size = 0;
294 /* get the remainder of the plugin buffer */
295 gbuf = (unsigned char *) rb->plugin_get_buffer(&gbuf_size);
297 if (!grey_init(gbuf, gbuf_size, GREY_ON_COP,
298 FIRE_WIDTH, LCD_HEIGHT, NULL)){
299 rb->splash(HZ, "not enough memory");
300 return PLUGIN_ERROR;
302 /* switch on greyscale overlay */
303 grey_set_position(FIRE_XPOS, 0);
304 grey_show(true);
305 return PLUGIN_OK;
307 #endif
309 int main(void)
311 int action;
313 #ifndef HAVE_LCD_COLOR
314 if(init_grey()!=PLUGIN_OK)
315 return(PLUGIN_ERROR);
316 #endif
317 color_palette_init(palette);
319 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
320 rb->cpu_boost(true);
321 #endif
323 fire_init(&fire);
324 while (true){
325 fire_step(&fire);
326 fire_draw(&fire);
327 rb->yield();
329 action = pluginlib_getaction(0, plugin_contexts,
330 ARRAYLEN(plugin_contexts));
332 switch(action){
333 case FIRE_QUIT:
334 cleanup(NULL);
335 return PLUGIN_OK;
337 case FIRE_INCREASE_MULT:
338 ++fire.mult;
339 break;
341 case FIRE_DECREASE_MULT:
342 if (fire.mult > 0)
343 --fire.mult;
344 break;
346 case FIRE_SWITCH_FLAMES_TYPE:
347 fire.flames_type = (fire.flames_type + 1) % 2;
348 break;
350 case FIRE_SWITCH_FLAMES_MOVING:
351 fire.moving = !fire.moving;
352 break;
354 default:
355 if (rb->default_event_handler_ex(action, cleanup, NULL)
356 == SYS_USB_CONNECTED)
357 return PLUGIN_USB_CONNECTED;
362 /*************************** Plugin entry point ****************************/
364 enum plugin_status plugin_start(const void* parameter)
366 int ret;
368 (void)parameter;
369 #if LCD_DEPTH > 1
370 rb->lcd_set_backdrop(NULL);
371 #endif
372 /* Turn off backlight timeout */
373 backlight_force_on(); /* backlight control in lib/helper.c */
375 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
376 rb->lcd_set_mode(LCD_MODE_PAL256);
377 #endif
379 ret = main();
381 #if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
382 rb->lcd_set_mode(LCD_MODE_RGB565);
383 #endif
385 return ret;
388 #endif /* #ifdef HAVE_LCD_BITMAP */