diff options
Diffstat (limited to 'apps/plugins/puzzles/rockbox.c')
| -rw-r--r-- | apps/plugins/puzzles/rockbox.c | 285 |
1 files changed, 263 insertions, 22 deletions
diff --git a/apps/plugins/puzzles/rockbox.c b/apps/plugins/puzzles/rockbox.c index 32fc38e..c03088f 100644 --- a/apps/plugins/puzzles/rockbox.c +++ b/apps/plugins/puzzles/rockbox.c @@ -27,7 +27,12 @@ #include "lib/xlcd.h" /* how many ticks between timer callbacks */ -#define TIMER_INTERVAL (HZ / 33) +#define TIMER_INTERVAL (HZ / 50) +#define BG_R .9f +#define BG_G .9f +#define BG_B .9f + +#define BG_COLOR LCD_RGBPACK((int)(255*BG_R), (int)(255*BG_R), (int)(255*BG_B)) static midend *me = NULL; static unsigned *colors = NULL; @@ -90,6 +95,7 @@ static void rb_color(int n) static void rb_draw_text(void *handle, int x, int y, int fonttype, int fontsize, int align, int colour, char *text) { + (void) fontsize; LOGF("rb_draw_text(%d %d %s)", x, y, text); offset_coords(&x, &y); @@ -148,13 +154,112 @@ static void rb_draw_line(void *handle, int x1, int y1, int x2, int y2, rb->lcd_drawline(x1, y1, x2, y2); } +/* + * draw filled polygon + * originally by Sebastian Leonhardt (ulmutul) + * 'count' : number of coordinate pairs + * 'pxy': array of coordinates. pxy[0]=x0,pxy[1]=y0,... + * note: provide space for one extra coordinate, because the starting point + * will automatically be inserted as end point. + */ + +/* + * helper function: + * find points of intersection between polygon and scanline + */ + +#define MAX_INTERSECTION 32 + +static void fill_poly_line(int scanline, int count, int *pxy) +{ + int i; + int j; + int num_of_intersects; + int direct, old_direct; + //intersections of every line with scanline (y-coord) + int intersection[MAX_INTERSECTION]; + /* add starting point as ending point */ + pxy[count*2] = pxy[0]; + pxy[count*2+1] = pxy[1]; + + old_direct=0; + num_of_intersects=0; + for (i=0; i<count*2; i+=2) { + int x1=pxy[i]; + int y1=pxy[i+1]; + int x2=pxy[i+2]; + int y2=pxy[i+3]; + // skip if line is outside of scanline + if (y1 < y2) { + if (scanline < y1 || scanline > y2) + continue; + } + else { + if (scanline < y2 || scanline > y1) + continue; + } + // calculate x-coord of intersection + if (y1==y2) { + direct=0; + } + else { + direct = y1>y2 ? 1 : -1; + // omit double intersections, if both lines lead in the same direction + intersection[num_of_intersects] = + x1+((scanline-y1)*(x2-x1))/(y2-y1); + if ( (direct!=old_direct) + || (intersection[num_of_intersects] != intersection[num_of_intersects-1]) + ) + ++num_of_intersects; + } + old_direct = direct; + } + + // sort points of intersection + for (i=0; i<num_of_intersects-1; ++i) { + for (j=i+1; j<num_of_intersects; ++j) { + if (intersection[j]<intersection[i]) { + int temp=intersection[i]; + intersection[i]=intersection[j]; + intersection[j]=temp; + } + } + } + // draw + for (i=0; i<num_of_intersects; i+=2) { + rb->lcd_hline(intersection[i], intersection[i+1], scanline); + } +} + +/* two extra elements at end of pxy needed */ +static void v_fillarea(int count, int *pxy) +{ + int i; + int y1, y2; + + // find min and max y coords + y1=y2=pxy[1]; + for (i=3; i<count*2; i+=2) { + if (pxy[i] < y1) y1 = pxy[i]; + else if (pxy[i] > y2) y2 = pxy[i]; + } + + for (i=y1; i<=y2; ++i) { + fill_poly_line(i, count, pxy); + } +} + static void rb_draw_poly(void *handle, int *coords, int npoints, int fillcolour, int outlinecolour) { LOGF("rb_draw_poly"); + if(fillcolour >= 0) { rb_color(fillcolour); +#if 1 + /* serious hack: draw a bunch of triangles between adjacent points */ + /* this generally works, even with some concave polygons */ for(int i = 2; i < npoints; ++i) { int x1, y1, x2, y2, x3, y3; @@ -170,9 +275,36 @@ static void rb_draw_poly(void *handle, int *coords, int npoints, xlcd_filltriangle(x1, y1, x2, y2, x3, y3); + +#if 0 + rb->lcd_set_foreground(LCD_RGBPACK(255,0,0)); + rb->lcd_drawpixel(x1, y1); + rb->lcd_drawpixel(x2, y2); + rb->lcd_drawpixel(x3, y3); + rb->lcd_update(); + rb->sleep(HZ); + rb_color(fillcolour); + rb->lcd_drawpixel(x1, y1); + rb->lcd_drawpixel(x2, y2); + rb->lcd_drawpixel(x3, y3); + rb->lcd_update(); +#endif + } +#else + int *pxy = smalloc(sizeof(int) * 2 * npoints + 2); + /* copy points, offsetted */ + for(int i = 0; i < npoints; ++i) + { + pxy[2 * i + 0] = coords[2 * i + 0]; + pxy[2 * i + 1] = coords[2 * i + 1]; + offset_coords(&pxy[2*i+0], &pxy[2*i+1]); } + v_fillarea(npoints, pxy); + sfree(pxy); +#endif } + /* draw outlines last so they're not covered by the fill */ assert(outlinecolour >= 0); rb_color(outlinecolour); @@ -187,6 +319,8 @@ static void rb_draw_poly(void *handle, int *coords, int npoints, offset_coords(&x2, &y2); rb->lcd_drawline(x1, y1, x2, y2); + //rb->lcd_update(); + //rb->sleep(HZ/2); } int x1, y1, x2, y2; @@ -206,14 +340,16 @@ static void rb_draw_circle(void *handle, int cx, int cy, int radius, { LOGF("rb_draw_circle(%d, %d, %d)", cx, cy, radius); offset_coords(&cx, &cy); + if(fillcolour >= 0) { rb_color(fillcolour); - xlcd_fillcircle(cx, cy, radius); + xlcd_fillcircle(cx, cy, radius - 1); } + assert(outlinecolour >= 0); rb_color(outlinecolour); - xlcd_drawcircle(cx, cy, radius); + xlcd_drawcircle(cx, cy, radius - 1); } struct blitter { @@ -238,7 +374,6 @@ static void rb_blitter_free(void *handle, blitter *bl) LOGF("rb_blitter_free"); sfree(bl->bmp.data); sfree(bl); - bl->bmp.data = NULL; return; } @@ -270,6 +405,7 @@ static void trim_rect(int *x, int *y, int *w, int *h) *h = y1 - y0; } +/* copy a section of the framebuffer */ static void rb_blitter_save(void *handle, blitter *bl, int x, int y) { /* no viewport offset */ @@ -284,7 +420,7 @@ static void rb_blitter_save(void *handle, blitter *bl, int x, int y) for(int i = 0; i < h; ++i) { /* copy line-by-line */ - rb->memcpy(bl->bmp.data + sizeof(fb_data) * (y + i) * w, + rb->memcpy(bl->bmp.data + sizeof(fb_data) * i * w, rb->lcd_framebuffer + (y + i) * LCD_WIDTH + x, w * sizeof(fb_data)); } @@ -307,7 +443,7 @@ static void rb_blitter_load(void *handle, blitter *bl, int x, int y) trim_rect(&x, &y, &w, &h); offset_coords(&x, &y); - rb->lcd_bitmap(bl->bmp.data, x, y, w, h); + rb->lcd_bitmap((fb_data*)bl->bmp.data, x, y, w, h); } static void rb_draw_update(void *handle, int x, int y, int w, int h) @@ -321,11 +457,44 @@ static void rb_end_draw(void *handle) LOGF("rb_end_draw"); } +static char *titlebar = NULL; + static void rb_status_bar(void *handle, char *text) { + if(titlebar) + sfree(titlebar); + titlebar = dupstr(text); LOGF("game title is %s\n", text); } +static void draw_title(void) +{ + const char *str = NULL; + if(titlebar) + str = titlebar; + else + str = midend_which_game(me)->name; + + /* quick hack */ + bool orig_clipped = clipped; + if(orig_clipped) + rb_unclip(NULL); + + int h; + rb->lcd_setfont(FONT_UI); + rb->lcd_getstringsize(str, NULL, &h); + + rb->lcd_set_foreground(BG_COLOR); + rb->lcd_fillrect(0, LCD_HEIGHT - h, LCD_WIDTH, h); + + rb->lcd_set_foreground(LCD_BLACK); + rb->lcd_putsxy(0, LCD_HEIGHT - h, str); + rb->lcd_update_rect(0, LCD_HEIGHT - h, LCD_WIDTH, h); + + if(orig_clipped) + rb_clip(NULL, clip_rect.x, clip_rect.y, clip_rect.width, clip_rect.height); +} + static char *rb_text_fallback(void *handle, const char *const *strings, int nstrings) { @@ -356,9 +525,9 @@ const drawing_api rb_drawing = { void frontend_default_colour(frontend *fe, float *out) { - *out++ = 1.0; - *out++ = 1.0; - *out++ = 1.0; + *out++ = 0.9; + *out++ = 0.9; + *out++ = 0.9; } void fatal(char *fmt, ...) @@ -381,6 +550,8 @@ void get_random_seed(void **randseed, int *randseedsize) *randseed = snew(long); long seed = *rb->current_tick; rb->memcpy(*randseed, &seed, sizeof(seed)); + //*(long*)*randseed = 42; // debug + //rb->splash(HZ, "DEBUG SEED ON"); *randseedsize = sizeof(long); } @@ -412,14 +583,14 @@ static int list_choose(const char *list_str, const char *title) struct gui_synclist list; - rb->gui_synclist_init(&list, &config_choices_formatter, list_str, false, 1, NULL); + rb->gui_synclist_init(&list, &config_choices_formatter, (void*)list_str, false, 1, NULL); rb->gui_synclist_set_icon_callback(&list, NULL); rb->gui_synclist_set_nb_items(&list, n); rb->gui_synclist_limit_scroll(&list, false); rb->gui_synclist_select_item(&list, 0); - rb->gui_synclist_set_title(&list, title, NOICON); + rb->gui_synclist_set_title(&list, (char*)title, NOICON); while (1) { rb->gui_synclist_draw(&list); @@ -555,6 +726,16 @@ done: free_cfg(config); } +static void quick_help(void) +{ + /* TODO */ +} + +static void full_help(void) +{ + /* TODO */ +} + static int pause_menu(void) { MENUITEM_STRINGLIST(menu, "Paused", NULL, @@ -563,6 +744,8 @@ static int pause_menu(void) "Undo", "Redo", "Solve", + "Quick Help", + "Extensive Help", "Configure Game", "Select Another Game", "Quit"); @@ -588,7 +771,7 @@ static int pause_menu(void) quit = true; break; case 3: - if(!midend_can_undo(me)) + if(!midend_can_redo(me)) rb->splash(HZ, "Cannot redo."); else midend_process_key(me, 0, 0, 'r'); @@ -603,17 +786,23 @@ static int pause_menu(void) break; } case 5: - config_menu(); + quick_help(); break; case 6: - return -1; + full_help(); + break; case 7: + config_menu(); + break; + case 8: + return -1; + case 9: return -2; default: break; } } - rb->lcd_set_background(LCD_WHITE); + rb->lcd_set_background(BG_COLOR); rb->lcd_clear_display(); rb->lcd_update(); midend_force_redraw(me); @@ -626,7 +815,17 @@ static int process_input(int tmo) { int state = 0; static const struct button_mapping *plugin_contexts[] = { pla_main_ctx }; + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(false); /* about to block for button input */ +#endif + int button = pluginlib_getaction(tmo, plugin_contexts, ARRAYLEN(plugin_contexts)); + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(true); +#endif + switch(button) { case PLA_UP: @@ -645,8 +844,19 @@ static int process_input(int tmo) state |= CURSOR_SELECT; break; case PLA_CANCEL: + { want_redraw = false; - return pause_menu(); + /* quick hack to preserve the clipping state */ + bool orig_clipped = clipped; + if(orig_clipped) + rb_unclip(NULL); + + int rc = pause_menu(); + + if(orig_clipped) + rb_clip(NULL, clip_rect.x, clip_rect.y, clip_rect.width, clip_rect.height); + return rc; + } default: exit_on_usb(button); break; @@ -687,12 +897,20 @@ const char *formatter(char *buf, size_t n, int i, const char *unit) static void fix_size(void) { - int w = LCD_WIDTH, h = LCD_HEIGHT; + int w = LCD_WIDTH, h = LCD_HEIGHT, h_x; + rb->lcd_setfont(FONT_UI); + rb->lcd_getstringsize("X", NULL, &h_x); + h -= h_x; midend_size(me, &w, &h, TRUE); } static void init_for_game(const game *gm) { + /* reset tlsf by nuking the signature */ + /* will make any already-allocated memory point to garbage */ + memset(giant_buffer, 0, 4); + init_memory_pool(sizeof(giant_buffer), giant_buffer); + me = midend_new(NULL, gm, &rb_drawing, NULL); midend_new_game(me); @@ -713,25 +931,38 @@ static void init_for_game(const game *gm) } /* seems to crash */ + /* actually it doesn't matter if this memory is leaked as + * resetting tlsf makes it forget about it anyway */ //sfree(floatcolors); rb->lcd_set_viewport(NULL); rb->lcd_set_backdrop(NULL); rb->lcd_set_foreground(LCD_BLACK); - rb->lcd_set_background(LCD_WHITE); + rb->lcd_set_background(BG_COLOR); rb->lcd_clear_display(); rb->lcd_update(); midend_force_redraw(me); + draw_title(); +} + +static void exit_handler(void) +{ +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(false); +#endif } enum plugin_status plugin_start(const void *param) { (void) param; - /* reset tlsf by nuking the signature */ - /* will make any already-allocated memory point to garbage */ - memset(giant_buffer, 0, 4); - init_memory_pool(sizeof(giant_buffer), giant_buffer); + rb_atexit(exit_handler); +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + rb->cpu_boost(true); +#endif + + LOGF("acos(.5) = %f", acos(.5)); + LOGF("sqrt(3)/2 = sin(60) = %f = %f", sqrt(3)/2, sin(PI/3)); int gm = 0; while(1) @@ -744,12 +975,21 @@ enum plugin_status plugin_start(const void *param) while(1) { want_redraw = true; + + draw_title(); + int button = process_input(timer_on ? TIMER_INTERVAL : -1); + if(button < 0) { rb_unclip(NULL); deactivate_timer(NULL); midend_free(me); + if(titlebar) + { + sfree(titlebar); + titlebar = NULL; + } /* new game */ if(button == -1) break; @@ -762,6 +1002,7 @@ enum plugin_status plugin_start(const void *param) if(button) midend_process_key(me, 0, 0, button); + if(want_redraw) midend_redraw(me); |