rockbox/apps/plugins/fire.c
Daniel Stenberg 2acc0ac542 Updated our source code header to explicitly mention that we are GPL v2 or
later. We still need to hunt down snippets used that are not. 1324 modified
files...
http://www.rockbox.org/mail/archive/rockbox-dev-archive-2008-06/0060.shtml


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17847 a1c6a512-1295-4272-9138-f99709370657
2008-06-28 18:10:04 +00:00

366 lines
9.5 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 Kevin Ferrare
*
* Fire demo plugin
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#include "helper.h"
#ifdef HAVE_LCD_BITMAP
#include "pluginlib_actions.h"
#include "fixedpoint.h"
#ifndef HAVE_LCD_COLOR
#include "grey.h"
#endif
#if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
/* Archos has not enough plugin RAM for full-width fire :( */
#define FIRE_WIDTH 106
#define FIRE_XPOS 3
#else
#define FIRE_WIDTH LCD_WIDTH
#define FIRE_XPOS 0
#endif
PLUGIN_HEADER
static const struct plugin_api* rb; /* global api struct pointer */
#ifndef HAVE_LCD_COLOR
GREY_INFO_STRUCT
static unsigned char draw_buffer[FIRE_WIDTH];
#endif
/* Key assignement */
const struct button_mapping* plugin_contexts[]= {
generic_increase_decrease,
generic_directions,
#if defined(HAVE_REMOTE_LCD)
remote_directions,
#endif
generic_actions
};
#define PLA_ARRAY_COUNT sizeof(plugin_contexts)/sizeof(plugin_contexts[0])
#define FIRE_QUIT PLA_QUIT
#define FIRE_SWITCH_FLAMES_TYPE PLA_LEFT
#define FIRE_SWITCH_FLAMES_MOVING PLA_RIGHT
#define FIRE_INCREASE_MULT PLA_INC
#define FIRE_DECREASE_MULT PLA_DEC
#define MIN_FLAME_VALUE 0
#define COOL_MAX (440/LCD_HEIGHT+2)
#ifndef HAVE_LCD_COLOR
static unsigned char palette[256];
void color_palette_init(unsigned char* palette)
{
int i;
for(i=0;i<=160;i++)//palette[i]=(3/2)*i
palette[i]=(i*3)/2;
/* 'regular' fire doesn't exceed this value */
for(;i<=255;i++)//palette[i]=(3/20)*i+216
palette[i]=(i*3+20*217)/20;
}
#else
static fb_data palette[256];
/*
* Color palette generation algorithm taken from
* the "The Demo Effects Collection" GPL project
* Copyright (C) 2002 W.P. van Paassen
*/
void color_palette_init(fb_data* palette)
{
int i;
for (i = 0; i < 32; i++){
/* black to blue, 32 values*/
palette[i]=LCD_RGBPACK(0, 0, 2*i);
/* blue to red, 32 values*/
palette[i + 32]=LCD_RGBPACK(8*i, 0, 64 - 2*i);
/* red to yellow, 32 values*/
palette[i + 64]=LCD_RGBPACK(255, 8*i, 0);
/* yellow to white, 162 values */
palette[i + 96]=LCD_RGBPACK(255, 255, 0 + 4*i);
palette[i + 128]=LCD_RGBPACK(255, 255, 64 + 4*i);
palette[i + 160]=LCD_RGBPACK(255, 255, 128 + 4*i);
palette[i + 192]=LCD_RGBPACK(255, 255, 192 + i);
palette[i + 224]=LCD_RGBPACK(255, 255, 224 + i);
}
}
#endif
static void tab_init_rand(unsigned char *tab, unsigned int tab_size,
int rand_max)
{
unsigned char *end = tab + tab_size;
while(tab < end)
*tab++ = (unsigned char)rb->rand() % rand_max;
}
struct fire {
unsigned char fire[LCD_HEIGHT+3][FIRE_WIDTH];
unsigned char cooling_map[LCD_HEIGHT][FIRE_WIDTH];
int flames_type;
bool moving;
unsigned int mult;
};
/* makes the instance a global variable since it's too big to fit on the target's stack */
static struct fire fire;
static inline void fire_convolve(struct fire* fire)
{
unsigned int pixel_value;
unsigned int cooling_value;
unsigned char *ptr, *end, *cool;
unsigned int mult=fire->mult;
rb->yield();
/* Convolve the pixels and handle cooling (to add nice shapes effects later) */
cool = &fire->cooling_map[0][0];
ptr = &fire->fire[0][0];
end = ptr + LCD_HEIGHT*FIRE_WIDTH;
switch (fire->flames_type){
case 0:
do{
pixel_value = ptr[FIRE_WIDTH-1] /* fire[y+1][x-1] */
+ ptr[2*FIRE_WIDTH] /* fire[y+2][x] */
+ ptr[FIRE_WIDTH+1] /* fire[y+1][x+1] */
+ ptr[3*FIRE_WIDTH]; /* fire[y+3][x] */
pixel_value = FMULU(pixel_value, mult) >> 10;
cooling_value = *cool++;
if (cooling_value <= pixel_value)
pixel_value -= cooling_value;
/* else it's too cold, don't frost the pixels !!! */
if (pixel_value > 255)
pixel_value = 255;
*ptr++ = pixel_value;
}while (ptr < end);
break;
case 1:
mult -= 2;
do{
pixel_value = ptr[FIRE_WIDTH-1] /* fire[y+1][x-1] */
+ ptr[FIRE_WIDTH] /* fire[y+1][x] */
+ ptr[FIRE_WIDTH+1] /* fire[y+1][x+1] */
+ ptr[2*FIRE_WIDTH]; /* fire[y+2][x] */
pixel_value = FMULU(pixel_value, mult) >> 10;
cooling_value = *cool++;
if (cooling_value <= pixel_value)
pixel_value -= cooling_value;
/* else it's too cold, don't frost the pixels !!! */
if (pixel_value > 255)
pixel_value = 255;
*ptr++ = pixel_value;
}while (ptr < end);
break;
default: /* We should never reach this */
break;
}
rb->yield();
}
static void fire_generate_bottom_seed(struct fire* fire)
{
unsigned char *ptr, *end;
ptr = &fire->fire[LCD_HEIGHT][0];
end = ptr + FIRE_WIDTH;
do{
*ptr++ = (MIN_FLAME_VALUE + rb->rand() % (256-MIN_FLAME_VALUE));
}while (ptr < end);
}
static inline void fire_step(struct fire* fire)
{
if(fire->moving){
/* Randomize the bottom line */
fire_generate_bottom_seed(fire);
/* Add here further effects like fire letters, ball ... */
}
fire_convolve(fire);
}
static void fire_init(struct fire* fire)
{
fire->mult = 261;
fire->flames_type=0;
fire->moving=true;
rb->memset(&fire->fire[0][0], 0, sizeof(fire->fire));
tab_init_rand(&fire->cooling_map[0][0], LCD_HEIGHT*FIRE_WIDTH, COOL_MAX);
fire_generate_bottom_seed(fire);
}
static inline void fire_draw(struct fire* fire)
{
int y;
unsigned char *src = &fire->fire[0][0];
#ifndef HAVE_LCD_COLOR
unsigned char *dest, *end;
#else
fb_data *dest, *end;
#endif
for (y = 0; y < LCD_HEIGHT; y++){
#ifndef HAVE_LCD_COLOR
dest = draw_buffer;
#else
dest = rb->lcd_framebuffer + LCD_WIDTH * y + FIRE_XPOS;
#endif
end = dest + FIRE_WIDTH;
do
*dest++ = palette[*src++];
while (dest < end);
#ifndef HAVE_LCD_COLOR
grey_ub_gray_bitmap(draw_buffer, 0, y, FIRE_WIDTH, 1);
#endif
}
#ifdef HAVE_LCD_COLOR
rb->lcd_update();
#endif
}
void cleanup(void *parameter)
{
(void)parameter;
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(false);
#endif
#ifndef HAVE_LCD_COLOR
grey_release();
#endif
/* Turn on backlight timeout (revert to settings) */
backlight_use_settings(rb); /* backlight control in lib/helper.c */
}
#ifndef HAVE_LCD_COLOR
int init_grey(void)
{
unsigned char *gbuf;
size_t gbuf_size = 0;
/* get the remainder of the plugin buffer */
gbuf = (unsigned char *) rb->plugin_get_buffer(&gbuf_size);
if (!grey_init(rb, gbuf, gbuf_size, GREY_ON_COP,
FIRE_WIDTH, LCD_HEIGHT, NULL)){
rb->splash(HZ, "not enough memory");
return PLUGIN_ERROR;
}
/* switch on greyscale overlay */
grey_set_position(FIRE_XPOS, 0);
grey_show(true);
return PLUGIN_OK;
}
#endif
int main(void)
{
int action;
#ifndef HAVE_LCD_COLOR
if(init_grey()!=PLUGIN_OK)
return(PLUGIN_ERROR);
#endif
color_palette_init(palette);
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(true);
#endif
fire_init(&fire);
while (true){
fire_step(&fire);
fire_draw(&fire);
rb->yield();
action = pluginlib_getaction(rb, 0, plugin_contexts, PLA_ARRAY_COUNT);
switch(action){
case FIRE_QUIT:
cleanup(NULL);
return PLUGIN_OK;
case FIRE_INCREASE_MULT:
++fire.mult;
break;
case FIRE_DECREASE_MULT:
if (fire.mult > 0)
--fire.mult;
break;
case FIRE_SWITCH_FLAMES_TYPE:
fire.flames_type = (fire.flames_type + 1) % 2;
break;
case FIRE_SWITCH_FLAMES_MOVING:
fire.moving = !fire.moving;
break;
default:
if (rb->default_event_handler_ex(action, cleanup, NULL)
== SYS_USB_CONNECTED)
return PLUGIN_USB_CONNECTED;
}
}
}
/*************************** Plugin entry point ****************************/
enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
{
int ret;
rb = api; //copy to global api pointer
(void)parameter;
#if LCD_DEPTH > 1
rb->lcd_set_backdrop(NULL);
#endif
/* Turn off backlight timeout */
backlight_force_on(rb); /* backlight control in lib/helper.c */
ret = main();
return ret;
}
#endif /* #ifdef HAVE_LCD_BITMAP */