Fix some quotation marks. Thanks to Alexander Levin for pointing it out.
[Rockbox.git] / apps / plugins / fire.c
blob35432377f946940cb29b87d2bd6d81dc342c07ce
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 Kevin Ferrare
12 * Fire demo plugin
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 ****************************************************************************/
22 #include "plugin.h"
23 #include "helper.h"
24 #ifdef HAVE_LCD_BITMAP
26 #include "pluginlib_actions.h"
27 #include "fixedpoint.h"
29 #ifndef HAVE_LCD_COLOR
30 #include "grey.h"
31 #endif
33 #if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
34 /* Archos has not enough plugin RAM for full-width fire :( */
35 #define FIRE_WIDTH 106
36 #define FIRE_XPOS 3
37 #else
38 #define FIRE_WIDTH LCD_WIDTH
39 #define FIRE_XPOS 0
40 #endif
42 PLUGIN_HEADER
44 static struct plugin_api* rb; /* global api struct pointer */
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);
116 #endif
118 static void tab_init_rand(unsigned char *tab, unsigned int tab_size,
119 int rand_max)
121 unsigned char *end = tab + tab_size;
123 while(tab < end)
124 *tab++ = (unsigned char)rb->rand() % rand_max;
127 struct fire {
128 unsigned char fire[LCD_HEIGHT+3][FIRE_WIDTH];
129 unsigned char cooling_map[LCD_HEIGHT][FIRE_WIDTH];
130 int flames_type;
131 bool moving;
132 unsigned int mult;
134 /* makes the instance a global variable since it's too big to fit on the target's stack */
135 static struct fire fire;
137 static inline void fire_convolve(struct fire* fire)
139 unsigned int pixel_value;
140 unsigned int cooling_value;
141 unsigned char *ptr, *end, *cool;
142 unsigned int mult=fire->mult;
144 rb->yield();
145 /* Convolve the pixels and handle cooling (to add nice shapes effects later) */
146 cool = &fire->cooling_map[0][0];
147 ptr = &fire->fire[0][0];
148 end = ptr + LCD_HEIGHT*FIRE_WIDTH;
150 switch (fire->flames_type){
151 case 0:
153 pixel_value = ptr[FIRE_WIDTH-1] /* fire[y+1][x-1] */
154 + ptr[2*FIRE_WIDTH] /* fire[y+2][x] */
155 + ptr[FIRE_WIDTH+1] /* fire[y+1][x+1] */
156 + ptr[3*FIRE_WIDTH]; /* fire[y+3][x] */
157 pixel_value = FMULU(pixel_value, mult) >> 10;
159 cooling_value = *cool++;
160 if (cooling_value <= pixel_value)
161 pixel_value -= cooling_value;
162 /* else it's too cold, don't frost the pixels !!! */
164 if (pixel_value > 255)
165 pixel_value = 255;
167 *ptr++ = pixel_value;
168 }while (ptr < end);
169 break;
171 case 1:
172 mult -= 2;
174 pixel_value = ptr[FIRE_WIDTH-1] /* fire[y+1][x-1] */
175 + ptr[FIRE_WIDTH] /* fire[y+1][x] */
176 + ptr[FIRE_WIDTH+1] /* fire[y+1][x+1] */
177 + ptr[2*FIRE_WIDTH]; /* fire[y+2][x] */
178 pixel_value = FMULU(pixel_value, mult) >> 10;
180 cooling_value = *cool++;
181 if (cooling_value <= pixel_value)
182 pixel_value -= cooling_value;
183 /* else it's too cold, don't frost the pixels !!! */
185 if (pixel_value > 255)
186 pixel_value = 255;
188 *ptr++ = pixel_value;
189 }while (ptr < end);
190 break;
192 default: /* We should never reach this */
193 break;
195 rb->yield();
198 static void fire_generate_bottom_seed(struct fire* fire)
200 unsigned char *ptr, *end;
201 ptr = &fire->fire[LCD_HEIGHT][0];
202 end = ptr + FIRE_WIDTH;
204 *ptr++ = (MIN_FLAME_VALUE + rb->rand() % (256-MIN_FLAME_VALUE));
205 }while (ptr < end);
208 static inline void fire_step(struct fire* fire)
210 if(fire->moving){
211 /* Randomize the bottom line */
212 fire_generate_bottom_seed(fire);
213 /* Add here further effects like fire letters, ball ... */
215 fire_convolve(fire);
218 static void fire_init(struct fire* fire)
220 fire->mult = 261;
221 fire->flames_type=0;
222 fire->moving=true;
223 rb->memset(&fire->fire[0][0], 0, sizeof(fire->fire));
224 tab_init_rand(&fire->cooling_map[0][0], LCD_HEIGHT*FIRE_WIDTH, COOL_MAX);
225 fire_generate_bottom_seed(fire);
228 static inline void fire_draw(struct fire* fire)
230 int y;
231 unsigned char *src = &fire->fire[0][0];
232 #ifndef HAVE_LCD_COLOR
233 unsigned char *dest, *end;
234 #else
235 fb_data *dest, *end;
236 #endif
238 for (y = 0; y < LCD_HEIGHT; y++){
239 #ifndef HAVE_LCD_COLOR
240 dest = draw_buffer;
241 #else
242 dest = rb->lcd_framebuffer + LCD_WIDTH * y + FIRE_XPOS;
243 #endif
244 end = dest + FIRE_WIDTH;
247 *dest++ = palette[*src++];
248 while (dest < end);
249 #ifndef HAVE_LCD_COLOR
250 grey_ub_gray_bitmap(draw_buffer, 0, y, FIRE_WIDTH, 1);
251 #endif
253 #ifdef HAVE_LCD_COLOR
254 rb->lcd_update();
255 #endif
258 void cleanup(void *parameter)
260 (void)parameter;
261 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
262 rb->cpu_boost(false);
263 #endif
264 #ifndef HAVE_LCD_COLOR
265 grey_release();
266 #endif
267 /* Turn on backlight timeout (revert to settings) */
268 backlight_use_settings(rb); /* backlight control in lib/helper.c */
272 #ifndef HAVE_LCD_COLOR
273 int init_grey(void)
275 unsigned char *gbuf;
276 size_t gbuf_size = 0;
278 /* get the remainder of the plugin buffer */
279 gbuf = (unsigned char *) rb->plugin_get_buffer(&gbuf_size);
281 if (!grey_init(rb, gbuf, gbuf_size, 0, FIRE_WIDTH, LCD_HEIGHT, NULL)){
282 rb->splash(HZ, "not enough memory");
283 return PLUGIN_ERROR;
285 /* switch on greyscale overlay */
286 grey_set_position(FIRE_XPOS, 0);
287 grey_show(true);
288 return PLUGIN_OK;
290 #endif
292 int main(void)
294 int action;
296 #ifndef HAVE_LCD_COLOR
297 if(init_grey()!=PLUGIN_OK)
298 return(PLUGIN_ERROR);
299 #endif
300 color_palette_init(palette);
302 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
303 rb->cpu_boost(true);
304 #endif
306 fire_init(&fire);
307 while (true){
308 fire_step(&fire);
309 fire_draw(&fire);
310 rb->yield();
312 action = pluginlib_getaction(rb, 0, plugin_contexts, PLA_ARRAY_COUNT);
314 switch(action){
315 case FIRE_QUIT:
316 cleanup(NULL);
317 return PLUGIN_OK;
319 case FIRE_INCREASE_MULT:
320 ++fire.mult;
321 break;
323 case FIRE_DECREASE_MULT:
324 if (fire.mult > 0)
325 --fire.mult;
326 break;
328 case FIRE_SWITCH_FLAMES_TYPE:
329 fire.flames_type = (fire.flames_type + 1) % 2;
330 break;
332 case FIRE_SWITCH_FLAMES_MOVING:
333 fire.moving = !fire.moving;
334 break;
336 default:
337 if (rb->default_event_handler_ex(action, cleanup, NULL)
338 == SYS_USB_CONNECTED)
339 return PLUGIN_USB_CONNECTED;
344 /*************************** Plugin entry point ****************************/
346 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
348 int ret;
350 rb = api; //copy to global api pointer
351 (void)parameter;
352 #if LCD_DEPTH > 1
353 rb->lcd_set_backdrop(NULL);
354 #endif
355 /* Turn off backlight timeout */
356 backlight_force_on(rb); /* backlight control in lib/helper.c */
358 ret = main();
360 return ret;
363 #endif /* #ifdef HAVE_LCD_BITMAP */