blob: 1ea9806a7bfde8965985ee933a72c00af9c7669e [file] [log] [blame]
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 Kevin Ferrare
*
* Mystify demo plugin
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "plugin.h"
#ifdef HAVE_LCD_BITMAP
#include "pluginlib_actions.h"
PLUGIN_HEADER
#define DEFAULT_WAIT_TIME 3
#define DEFAULT_NB_POLYGONS 7
#define NB_POINTS 4
#define MAX_STEP_RANGE 7
#define MIN_STEP_RANGE 3
#define MAX_POLYGONS 40
#define MIN_POLYGONS 1
/* Key assignement */
#define DEMYSTIFY_QUIT PLA_QUIT
#define DEMYSTIFY_INCREASE_SPEED PLA_RIGHT
#define DEMYSTIFY_DECREASE_SPEED PLA_LEFT
#define DEMYSTIFY_INCREASE_SPEED_REPEAT PLA_RIGHT_REPEAT
#define DEMYSTIFY_DECREASE_SPEED_REPEAT PLA_LEFT_REPEAT
#define DEMYSTIFY_ADD_POLYGON PLA_UP
#define DEMYSTIFY_REMOVE_POLYGON PLA_DOWN
#define DEMYSTIFY_ADD_POLYGON_REPEAT PLA_UP_REPEAT
#define DEMYSTIFY_REMOVE_POLYGON_REPEAT PLA_DOWN_REPEAT
const struct button_mapping *plugin_contexts[]
= {generic_directions, generic_actions,
#if defined(HAVE_REMOTE_LCD)
remote_directions
#endif
};
#ifdef HAVE_LCD_COLOR
struct line_color
{
int r,g,b;
int current_r,current_g,current_b;
};
#endif
/******************************* Globals ***********************************/
static struct plugin_api* rb; /* global api struct pointer */
/*
* Compute a new random step to make the point bounce the borders of the screen
*/
int get_new_step(int step)
{
if(step>0)
return -(MIN_STEP_RANGE + rb->rand() % (MAX_STEP_RANGE-MIN_STEP_RANGE));
else
return (MIN_STEP_RANGE + rb->rand() % (MAX_STEP_RANGE-MIN_STEP_RANGE));
}
/*
* Point Stuffs
*/
struct point
{
int x;
int y;
};
/*
* Polygon Stuffs
*/
struct polygon
{
struct point points[NB_POINTS];
};
/*
* Generates a random polygon (which fits the screen size though)
*/
void polygon_init(struct polygon * polygon, struct screen * display)
{
int i;
for(i=0;i<NB_POINTS;++i)
{
polygon->points[i].x=(rb->rand() % (display->width));
polygon->points[i].y=(rb->rand() % (display->height));
}
}
/*
* Draw the given polygon onto the screen
*/
void polygon_draw(struct polygon * polygon, struct screen * display)
{
int i;
for(i=0;i<NB_POINTS-1;++i)
{
display->drawline(polygon->points[i].x, polygon->points[i].y,
polygon->points[i+1].x, polygon->points[i+1].y);
}
display->drawline(polygon->points[0].x, polygon->points[0].y,
polygon->points[NB_POINTS-1].x,
polygon->points[NB_POINTS-1].y);
}
/*
* Polygon moving data Stuffs
*/
struct polygon_move
{
struct point move_steps[NB_POINTS];
};
void polygon_move_init(struct polygon_move * polygon_move)
{
int i;
for(i=0;i<NB_POINTS;++i)
{
polygon_move->move_steps[i].x=get_new_step(-1);
/* -1 because we want a positive random step */
polygon_move->move_steps[i].y=get_new_step(-1);
}
}
/*
* Update the given polygon's position according to the given informations in
* polygon_move (polygon_move may be updated)
*/
void polygon_update(struct polygon *polygon, struct screen * display, struct polygon_move *polygon_move)
{
int i, x, y, step;
for(i=0;i<NB_POINTS;++i)
{
x=polygon->points[i].x;
step=polygon_move->move_steps[i].x;
x+=step;
if(x<=0)
{
x=1;
polygon_move->move_steps[i].x=get_new_step(step);
}
else if(x>=display->width)
{
x=display->width-1;
polygon_move->move_steps[i].x=get_new_step(step);
}
polygon->points[i].x=x;
y=polygon->points[i].y;
step=polygon_move->move_steps[i].y;
y+=step;
if(y<=0)
{
y=1;
polygon_move->move_steps[i].y=get_new_step(step);
}
else if(y>=display->height)
{
y=display->height-1;
polygon_move->move_steps[i].y=get_new_step(step);
}
polygon->points[i].y=y;
}
}
/*
* Polygon fifo Stuffs
*/
struct polygon_fifo
{
int fifo_tail;
int fifo_head;
int nb_items;
struct polygon tab[MAX_POLYGONS];
};
void fifo_init(struct polygon_fifo * fifo)
{
fifo->fifo_tail=0;
fifo->fifo_head=0;
fifo->nb_items=0;
}
void fifo_push(struct polygon_fifo * fifo, struct polygon * polygon)
{
if(fifo->nb_items>=MAX_POLYGONS)
return;
++(fifo->nb_items);
/*
* Workaround for gcc (which uses memcpy internally) to avoid link error
* fifo->tab[fifo->fifo_head]=polygon
*/
rb->memcpy(&(fifo->tab[fifo->fifo_head]), polygon, sizeof(struct polygon));
++(fifo->fifo_head);
if(fifo->fifo_head>=MAX_POLYGONS)
fifo->fifo_head=0;
}
struct polygon * fifo_pop(struct polygon_fifo * fifo)
{
int index;
if(fifo->nb_items==0)
return(NULL);
--(fifo->nb_items);
index=fifo->fifo_tail;
++(fifo->fifo_tail);
if(fifo->fifo_tail>=MAX_POLYGONS)
fifo->fifo_tail=0;
return(&(fifo->tab[index]));
}
/*
* Drawing stuffs
*/
void polygons_draw(struct polygon_fifo * polygons, struct screen * display)
{
int i, j;
for(i=0, j=polygons->fifo_tail;i<polygons->nb_items;++i, ++j)
{
if(j>=MAX_POLYGONS)
j=0;
polygon_draw(&(polygons->tab[j]), display);
}
}
void cleanup(void *parameter)
{
(void)parameter;
rb->screens[SCREEN_MAIN]->backlight_set_timeout(rb->global_settings->backlight_timeout);
#if NB_SCREENS==2
rb->screens[SCREEN_REMOTE]->backlight_set_timeout(rb->global_settings->remote_backlight_timeout);
#endif
}
#ifdef HAVE_LCD_COLOR
void color_randomize(struct line_color * color)
{
color->r = rb->rand()%255;
color->g = rb->rand()%255;
color->b = rb->rand()%255;
}
void color_init(struct line_color * color)
{
color_randomize(color);
color->current_r=color->r;
color->current_g=color->g;
color->current_b=color->b;
}
void color_change(struct line_color * color)
{
if(color->current_r<color->r)
++color->current_r;
else if(color->current_r>color->r)
--color->current_r;
if(color->current_g<color->g)
++color->current_g;
else if(color->current_g>color->g)
--color->current_g;
if(color->current_b<color->b)
++color->current_b;
else if(color->current_b>color->b)
--color->current_b;
if(color->current_r==color->r &&
color->current_g==color->g &&
color->current_b==color->b)
color_randomize(color);
}
#define COLOR_RGBPACK(color) \
LCD_RGBPACK((color)->current_r, (color)->current_g, (color)->current_b)
void color_apply(struct line_color * color, struct screen * display)
{
if (display->is_color){
unsigned foreground=
SCREEN_COLOR_TO_NATIVE(display,COLOR_RGBPACK(color));
display->set_foreground(foreground);
}
}
#endif
/*
* Main function
*/
int plugin_main(void)
{
int action;
int sleep_time=DEFAULT_WAIT_TIME;
int nb_wanted_polygons=DEFAULT_NB_POLYGONS;
int i;
struct polygon_fifo polygons[NB_SCREENS];
struct polygon_move move[NB_SCREENS]; /* This describes the movement of the leading
polygon, the others just follow */
struct polygon leading_polygon[NB_SCREENS];
FOR_NB_SCREENS(i)
{
#ifdef HAVE_LCD_COLOR
struct screen *display = rb->screens[i];
if (display->is_color)
display->set_background(LCD_BLACK);
#endif
fifo_init(&polygons[i]);
polygon_move_init(&move[i]);
polygon_init(&leading_polygon[i], rb->screens[i]);
}
#ifdef HAVE_LCD_COLOR
struct line_color color;
color_init(&color);
#endif
while (true)
{
FOR_NB_SCREENS(i)
{
struct screen * display=rb->screens[i];
if(polygons[i].nb_items>nb_wanted_polygons)
{ /* We have too many polygons, we must drop some of them */
fifo_pop(&polygons[i]);
}
if(nb_wanted_polygons==polygons[i].nb_items)
{ /* We have the good number of polygons, we can safely drop
the last one to add the new one later */
fifo_pop(&polygons[i]);
}
fifo_push(&polygons[i], &leading_polygon[i]);
/*
* Then we update the leading polygon for the next round acording to
* current move (the move may be altered in case of sreen border
* collision)
*/
polygon_update(&leading_polygon[i], display, &move[i]);
/* Now the drawing part */
#ifdef HAVE_LCD_COLOR
color_apply(&color, display);
#endif
display->clear_display();
polygons_draw(&polygons[i], display);
display->update();
}
#ifdef HAVE_LCD_COLOR
color_change(&color);
#endif
/* Speed handling*/
if (sleep_time<0)/* full speed */
rb->yield();
else
rb->sleep(sleep_time);
action = pluginlib_getaction(rb, TIMEOUT_NOBLOCK, plugin_contexts, 3);
switch(action)
{
case DEMYSTIFY_QUIT:
cleanup(NULL);
return PLUGIN_OK;
case DEMYSTIFY_ADD_POLYGON:
case DEMYSTIFY_ADD_POLYGON_REPEAT:
if(nb_wanted_polygons<MAX_POLYGONS)
++nb_wanted_polygons;
break;
case DEMYSTIFY_REMOVE_POLYGON:
case DEMYSTIFY_REMOVE_POLYGON_REPEAT:
if(nb_wanted_polygons>MIN_POLYGONS)
--nb_wanted_polygons;
break;
case DEMYSTIFY_INCREASE_SPEED:
case DEMYSTIFY_INCREASE_SPEED_REPEAT:
if(sleep_time>=0)
--sleep_time;
break;
case DEMYSTIFY_DECREASE_SPEED:
case DEMYSTIFY_DECREASE_SPEED_REPEAT:
++sleep_time;
break;
default:
if (rb->default_event_handler_ex(action, cleanup, NULL)
== SYS_USB_CONNECTED)
return PLUGIN_USB_CONNECTED;
break;
}
}
}
/*************************** Plugin entry point ****************************/
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
int ret;
rb = api; /* copy to global api pointer */
#if LCD_DEPTH > 1
rb->lcd_set_backdrop(NULL);
#endif
(void)parameter;
if (rb->global_settings->backlight_timeout > 0)
{
int i;
FOR_NB_SCREENS(i)
rb->screens[i]->backlight_set_timeout(1);/* keep the light on */
}
ret = plugin_main();
return ret;
}
#endif /* #ifdef HAVE_LCD_BITMAP */