summaryrefslogtreecommitdiff
path: root/apps/plugins/puzzles/rockbox.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/puzzles/rockbox.c')
-rw-r--r--apps/plugins/puzzles/rockbox.c285
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);