/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2005 Kevin Ferrare * * Mystify 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 "lib/pluginlib_exit.h" #include "lib/pluginlib_actions.h" #include "lib/helper.h" #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_CANCEL #ifdef HAVE_SCROLLWHEEL #define DEMYSTIFY_INCREASE_SPEED PLA_SCROLL_FWD #define DEMYSTIFY_DECREASE_SPEED PLA_SCROLL_BACK #define DEMYSTIFY_INCREASE_SPEED_REPEAT PLA_SCROLL_FWD_REPEAT #define DEMYSTIFY_DECREASE_SPEED_REPEAT PLA_SCROLL_BACK_REPEAT #else #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 #endif #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[] = {pla_main_ctx, #if defined(HAVE_REMOTE_LCD) pla_remote_ctx, #endif }; #ifdef HAVE_LCD_COLOR struct line_color { int r,g,b; int current_r,current_g,current_b; }; #endif /******************************* Globals ***********************************/ /* * Compute a new random step to make the point bounce the borders of the screen */ static 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) */ static void polygon_init(struct polygon * polygon, struct screen * display) { int i; for(i=0;ipoints[i].x=(rb->rand() % (display->getwidth())); polygon->points[i].y=(rb->rand() % (display->getheight())); } } /* * Draw the given polygon onto the screen */ static void polygon_draw(struct polygon * polygon, struct screen * display) { int i; for(i=0;idrawline(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]; }; static void polygon_move_init(struct polygon_move * polygon_move) { int i; for(i=0;imove_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) */ static void polygon_update(struct polygon *polygon, struct screen * display, struct polygon_move *polygon_move) { int i, x, y, step; for(i=0;ipoints[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->getwidth()) { x=display->getwidth()-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->getheight()) { y=display->getheight()-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]; }; static void fifo_init(struct polygon_fifo * fifo) { fifo->fifo_tail=0; fifo->fifo_head=0; fifo->nb_items=0; } static 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; } static 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 */ static void polygons_draw(struct polygon_fifo * polygons, struct screen * display) { int i, j; for(i=0, j=polygons->fifo_tail;inb_items;++i, ++j) { if(j>=MAX_POLYGONS) j=0; polygon_draw(&(polygons->tab[j]), display); } } static void cleanup(void) { backlight_use_settings(); #ifdef HAVE_REMOTE_LCD remote_backlight_use_settings(); #endif } #ifdef HAVE_LCD_COLOR static void color_randomize(struct line_color * color) { color->r = rb->rand()%255; color->g = rb->rand()%255; color->b = rb->rand()%255; } static 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; } static void color_change(struct line_color * color) { if(color->current_rr) ++color->current_r; else if(color->current_r>color->r) --color->current_r; if(color->current_gg) ++color->current_g; else if(color->current_g>color->g) --color->current_g; if(color->current_bb) ++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) static 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 */ static int plugin_main(void) { int action; int sleep_time=DEFAULT_WAIT_TIME; int nb_wanted_polygons=DEFAULT_NB_POLYGONS; 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(TIMEOUT_NOBLOCK, plugin_contexts, ARRAYLEN(plugin_contexts)); switch(action) { case DEMYSTIFY_QUIT: return PLUGIN_OK; case DEMYSTIFY_ADD_POLYGON: case DEMYSTIFY_ADD_POLYGON_REPEAT: if(nb_wanted_polygonsMIN_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: exit_on_usb(action); break; } } } /*************************** Plugin entry point ****************************/ enum plugin_status plugin_start(const void* parameter) { int ret; (void)parameter; atexit(cleanup); #if LCD_DEPTH > 1 rb->lcd_set_backdrop(NULL); #endif backlight_ignore_timeout(); #ifdef HAVE_REMOTE_LCD remote_backlight_ignore_timeout(); #endif ret = plugin_main(); return ret; } > { lua_pushnil(L); lua_pushfstring(L, "%s: %s", filename, strerror(en)); lua_pushinteger(L, en); return 3; } } static int os_remove (lua_State *L) { const char *filename = luaL_checkstring(L, 1); return os_pushresult(L, rb->remove(filename) == 0, filename); } static int os_rename (lua_State *L) { const char *fromname = luaL_checkstring(L, 1); const char *toname = luaL_checkstring(L, 2); return os_pushresult(L, rb->rename(fromname, toname) == 0, fromname); } /* ** {====================================================== ** Time/Date operations ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, ** wday=%w+1, yday=%j, isdst=? } ** ======================================================= */ static void setfield (lua_State *L, const char *key, int value) { lua_pushinteger(L, value); lua_setfield(L, -2, key); } static void setboolfield (lua_State *L, const char *key, int value) { if (value < 0) /* undefined? */ return; /* does not set field */ lua_pushboolean(L, value); lua_setfield(L, -2, key); } #if CONFIG_RTC static int getboolfield (lua_State *L, const char *key) { int res; lua_getfield(L, -1, key); res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); lua_pop(L, 1); return res; } static int getfield (lua_State *L, const char *key, int d) { int res; lua_getfield(L, -1, key); if (lua_isnumber(L, -1)) res = (int)lua_tointeger(L, -1); else { if (d < 0) return luaL_error(L, "field " LUA_QS " missing in date table", key); res = d; } lua_pop(L, 1); return res; } #endif static int os_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, #if CONFIG_RTC rb->mktime(rb->get_time()) #else 0 #endif ); struct tm *stm; if (*s == '!') /* UTC? */ /* Rockbox doesn't support timezones */ s++; /* skip `!' */ stm = gmtime(&t); if (stm == NULL) /* invalid date? */ lua_pushnil(L); else if (strcmp(s, "*t") == 0) { lua_createtable(L, 0, 9); /* 9 = number of fields */ setfield(L, "sec", stm->tm_sec); setfield(L, "min", stm->tm_min); setfield(L, "hour", stm->tm_hour); setfield(L, "day", stm->tm_mday); setfield(L, "month", stm->tm_mon+1); setfield(L, "year", stm->tm_year+1900); setfield(L, "wday", stm->tm_wday+1); setfield(L, "yday", stm->tm_yday+1); setboolfield(L, "isdst", stm->tm_isdst); } else { char cc[3]; luaL_Buffer b; cc[0] = '%'; cc[2] = '\0'; luaL_buffinit(L, &b); for (; *s; s++) { if (*s != '%' || *(s + 1) == '\0') /* no conversion specifier? */ luaL_addchar(&b, *s); else { size_t reslen; char buff[200]; /* should be big enough for any conversion result */ cc[1] = *(++s); reslen = strftime(buff, sizeof(buff), cc, stm); luaL_addlstring(&b, buff, reslen); } } luaL_pushresult(&b); } return 1; } static int os_time (lua_State *L) { time_t t = -1; #if CONFIG_RTC if (lua_isnoneornil(L, 1)) /* called without args? */ t = rb->mktime(rb->get_time()); /* get current time */ else { struct tm ts; luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 1); /* make sure table is at the top */ ts.tm_sec = getfield(L, "sec", 0); ts.tm_min = getfield(L, "min", 0); ts.tm_hour = getfield(L, "hour", 12); ts.tm_mday = getfield(L, "day", -1); ts.tm_mon = getfield(L, "month", -1) - 1; ts.tm_year = getfield(L, "year", -1) - 1900; ts.tm_isdst = getboolfield(L, "isdst"); t = rb->mktime(&ts); } #endif if (t == (time_t)(-1)) lua_pushnil(L); else lua_pushnumber(L, (lua_Number)t); return 1; } /* }====================================================== */ static int os_exit (lua_State *L) { exit(luaL_optint(L, 1, EXIT_SUCCESS)); return EXIT_SUCCESS; /* never reached, surpress warning */ } static const luaL_Reg syslib[] = { //{"clock", os_clock}, {"date", os_date}, //{"difftime", os_difftime}, //{"execute", os_execute}, {"exit", os_exit}, //{"getenv", os_getenv}, {"remove", os_remove}, {"rename", os_rename}, //{"setlocale", os_setlocale}, {"time", os_time}, //{"tmpname", os_tmpname}, {NULL, NULL} }; /* }====================================================== */ LUALIB_API int luaopen_os (lua_State *L) { luaL_register(L, LUA_OSLIBNAME, syslib); return 1; }