rockbox/apps/plugins/demystify.c

407 lines
11 KiB
C

/***************************************************************************
* __________ __ ___.
* 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
PLUGIN_HEADER
/* Key assignement */
#if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
(CONFIG_KEYPAD == IPOD_3G_PAD)
#define DEMYSTIFY_QUIT BUTTON_MENU
#define DEMYSTIFY_ADD_POLYGON BUTTON_RIGHT
#define DEMYSTIFY_REMOVE_POLYGON BUTTON_LEFT
#define DEMYSTIFY_INCREASE_SPEED BUTTON_SCROLL_FWD
#define DEMYSTIFY_DECREASE_SPEED BUTTON_SCROLL_BACK
#elif (CONFIG_KEYPAD == SANSA_E200_PAD)
#define DEMYSTIFY_QUIT BUTTON_POWER
#define DEMYSTIFY_ADD_POLYGON BUTTON_RIGHT
#define DEMYSTIFY_REMOVE_POLYGON BUTTON_LEFT
#define DEMYSTIFY_INCREASE_SPEED BUTTON_SCROLL_UP
#define DEMYSTIFY_DECREASE_SPEED BUTTON_SCROLL_DOWN
#elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
#define DEMYSTIFY_QUIT BUTTON_POWER
#define DEMYSTIFY_ADD_POLYGON BUTTON_RIGHT
#define DEMYSTIFY_REMOVE_POLYGON BUTTON_LEFT
#define DEMYSTIFY_INCREASE_SPEED BUTTON_SCROLL_UP
#define DEMYSTIFY_DECREASE_SPEED BUTTON_SCROLL_DOWN
#elif (CONFIG_KEYPAD == IAUDIO_X5_PAD)
#define DEMYSTIFY_QUIT BUTTON_POWER
#define DEMYSTIFY_ADD_POLYGON BUTTON_RIGHT
#define DEMYSTIFY_REMOVE_POLYGON BUTTON_LEFT
#define DEMYSTIFY_INCREASE_SPEED BUTTON_UP
#define DEMYSTIFY_DECREASE_SPEED BUTTON_DOWN
#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
#define DEMYSTIFY_QUIT BUTTON_A
#define DEMYSTIFY_ADD_POLYGON BUTTON_RIGHT
#define DEMYSTIFY_REMOVE_POLYGON BUTTON_LEFT
#define DEMYSTIFY_INCREASE_SPEED BUTTON_UP
#define DEMYSTIFY_DECREASE_SPEED BUTTON_DOWN
#else
#define DEMYSTIFY_QUIT BUTTON_OFF
#define DEMYSTIFY_ADD_POLYGON BUTTON_UP
#define DEMYSTIFY_REMOVE_POLYGON BUTTON_DOWN
#define DEMYSTIFY_INCREASE_SPEED BUTTON_RIGHT
#define DEMYSTIFY_DECREASE_SPEED BUTTON_LEFT
#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
(CONFIG_KEYPAD == IRIVER_H300_PAD)
#define DEMYSTIFY_RC_QUIT BUTTON_RC_STOP
#define DEMYSTIFY_RC_ADD_POLYGON BUTTON_RC_BITRATE
#define DEMYSTIFY_RC_REMOVE_POLYGON BUTTON_RC_SOURCE
#define DEMYSTIFY_RC_INCREASE_SPEED BUTTON_RC_VOL_UP
#define DEMYSTIFY_RC_DECREASE_SPEED BUTTON_RC_VOL_DOWN
#endif
#endif
#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
/******************************* 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
}
/*
* Main function
*/
int plugin_main(void)
{
int button;
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)
{
fifo_init(&polygons[i]);
polygon_move_init(&move[i]);
polygon_init(&leading_polygon[i], rb->screens[i]);
}
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 */
display->clear_display();
polygons_draw(&polygons[i], display);
display->update();
}
/* Speed handling*/
if (sleep_time<0)/* full speed */
rb->yield();
else
rb->sleep(sleep_time);
/* Handle the user events */
button = rb->button_get(false);
switch(button)
{
#ifdef DEMYSTIFY_RC_QUIT
case DEMYSTIFY_RC_QUIT :
#endif
case DEMYSTIFY_QUIT:
cleanup(NULL);
return PLUGIN_OK;
#ifdef DEMYSTIFY_RC_ADD_POLYGON
case DEMYSTIFY_RC_ADD_POLYGON:
#endif
case DEMYSTIFY_ADD_POLYGON:
if(nb_wanted_polygons<MAX_POLYGONS)
++nb_wanted_polygons;
break;
#ifdef DEMYSTIFY_RC_REMOVE_POLYGON
case DEMYSTIFY_RC_REMOVE_POLYGON:
#endif
case DEMYSTIFY_REMOVE_POLYGON:
if(nb_wanted_polygons>MIN_POLYGONS)
--nb_wanted_polygons;
break;
#ifdef DEMYSTIFY_RC_INCREASE_SPEED
case DEMYSTIFY_RC_INCREASE_SPEED:
#endif
case DEMYSTIFY_INCREASE_SPEED:
if(sleep_time>=0)
--sleep_time;
break;
#ifdef DEMYSTIFY_RC_DECREASE_SPEED
case DEMYSTIFY_RC_DECREASE_SPEED:
#endif
case DEMYSTIFY_DECREASE_SPEED:
++sleep_time;
break;
default:
if (rb->default_event_handler_ex(button, 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 */
(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 */