summaryrefslogtreecommitdiff
path: root/apps/plugins/puzzles
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2017-01-13 19:11:33 -0500
committerFranklin Wei <git@fwei.tk>2017-01-13 23:22:51 -0500
commit8e4429853d1ac024ac2b8069636cc210cf5bab1b (patch)
tree13528d977018df1d5c2daf819004bd9f49f6f5b8 /apps/plugins/puzzles
parent79e8cd4cfe852836c46bea5216ab308439688689 (diff)
downloadrockbox-8e4429853d1ac024ac2b8069636cc210cf5bab1b.tar.gz
rockbox-8e4429853d1ac024ac2b8069636cc210cf5bab1b.zip
puzzles: antialiased line drawing and optional "shortcuts" for undo/redo
- line drawing should eventually be moved to xlcd, but for now it's very nonportable code - fixes a minor issue with the configuration screens Change-Id: I897f01b7210cbbec32665c2bc67920c965ea0bec
Diffstat (limited to 'apps/plugins/puzzles')
-rw-r--r--apps/plugins/puzzles/puzzles.make4
-rw-r--r--apps/plugins/puzzles/rockbox.c411
-rw-r--r--apps/plugins/puzzles/untangle.c15
3 files changed, 319 insertions, 111 deletions
diff --git a/apps/plugins/puzzles/puzzles.make b/apps/plugins/puzzles/puzzles.make
index 4052423fb9..f49b663197 100644
--- a/apps/plugins/puzzles/puzzles.make
+++ b/apps/plugins/puzzles/puzzles.make
@@ -43,8 +43,8 @@ ROCKS += $(PUZZLES_ROCKS)
43endif 43endif
44 44
45# Hack to suppress all warnings: 45# Hack to suppress all warnings:
46PUZZLESFLAGS = $(filter-out -O%,$(PLUGINFLAGS)) -Os \ 46PUZZLESFLAGS = $(filter-out -O%,$(PLUGINFLAGS)) -O3 \
47 -Wno-unused-parameter -Wno-sign-compare -Wno-strict-aliasing -w \ 47 -Wno-unused-parameter -Wno-sign-compare -Wno-strict-aliasing -w \
48 -DFOR_REAL -I$(PUZZLES_SRCDIR) 48 -DFOR_REAL -I$(PUZZLES_SRCDIR)
49ifdef PUZZLES_COMBINED 49ifdef PUZZLES_COMBINED
50PUZZLESFLAGS += -DCOMBINED 50PUZZLESFLAGS += -DCOMBINED
diff --git a/apps/plugins/puzzles/rockbox.c b/apps/plugins/puzzles/rockbox.c
index 3e3bd15f33..2884e4e775 100644
--- a/apps/plugins/puzzles/rockbox.c
+++ b/apps/plugins/puzzles/rockbox.c
@@ -30,6 +30,7 @@
30#include "lib/playback_control.h" 30#include "lib/playback_control.h"
31#endif 31#endif
32#include "lib/xlcd.h" 32#include "lib/xlcd.h"
33#include "fixedpoint.h"
33 34
34/* how many ticks between timer callbacks */ 35/* how many ticks between timer callbacks */
35#define TIMER_INTERVAL (HZ / 50) 36#define TIMER_INTERVAL (HZ / 50)
@@ -75,7 +76,7 @@ extern bool audiobuf_available;
75 76
76static struct settings_t { 77static struct settings_t {
77 int slowmo_factor; 78 int slowmo_factor;
78 bool bulk, timerflash, clipoff; 79 bool bulk, timerflash, clipoff, shortcuts, no_aa;
79} settings; 80} settings;
80 81
81/* clipping is implemented through viewports and offsetting 82/* clipping is implemented through viewports and offsetting
@@ -179,14 +180,129 @@ static void rb_draw_rect(void *handle, int x, int y, int w, int h, int color)
179 rb->lcd_fillrect(x, y, w, h); 180 rb->lcd_fillrect(x, y, w, h);
180} 181}
181 182
183#define SWAP(a, b, t) do { t = a; a = b; b = t; } while(0);
184
185#define fp_fpart(f, bits) ((f) & ((1 << (bits)) - 1))
186#define fp_rfpart(f, bits) ((1 << (bits)) - fp_fpart(f, bits))
187
188#define FRACBITS 16
189
190/* most of our time drawing lines is spent in this function! */
191static inline void plot(unsigned x, unsigned y, unsigned long a,
192 unsigned long r1, unsigned long g1, unsigned long b1,
193 unsigned cl, unsigned cr, unsigned cu, unsigned cd)
194{
195 /* This is really quite possibly the least efficient way of doing
196 this. A better way would be in draw_antialiased_line(), but the
197 problem with that is that the algorithms I investigated at
198 least were incorrect at least part of the time and didn't make
199 drawing much faster overall. */
200 if(!(cl <= x && x < cr && cu <= y && y < cd))
201 return;
202
203 fb_data *ptr = rb->lcd_framebuffer + y * LCD_WIDTH + x;
204 fb_data orig = *ptr;
205 unsigned long r2, g2, b2;
206 r2 = RGB_UNPACK_RED(orig);
207 g2 = RGB_UNPACK_GREEN(orig);
208 b2 = RGB_UNPACK_BLUE(orig);
209
210 unsigned long r, g, b;
211 r = ((r1 * a) + (r2 * (256 - a))) >> 8;
212 g = ((g1 * a) + (g2 * (256 - a))) >> 8;
213 b = ((b1 * a) + (b2 * (256 - a))) >> 8;
214
215 *ptr = LCD_RGBPACK(r, g, b);
216}
217
218#undef ABS
219#define ABS(a) ((a)<0?-(a):(a))
220
221/* speed benchmark: 34392 lines/sec vs 112687 non-antialiased
222 * lines/sec at full optimization on ipod6g */
223
224/* expects UN-OFFSET coordinates, directly access framebuffer */
225static void draw_antialiased_line(int x0, int y0, int x1, int y1)
226{
227 /* fixed-point Wu's algorithm, modified for integer-only endpoints */
228
229 /* passed to plot() to avoid re-calculation */
230 unsigned short l = 0, r = LCD_WIDTH, u = 0, d = LCD_HEIGHT;
231 if(clipped)
232 {
233 l = clip_rect.x;
234 r = clip_rect.x + clip_rect.width;
235 u = clip_rect.y;
236 d = clip_rect.y + clip_rect.height;
237 }
238
239 bool steep = ABS(y1 - y0) > ABS(x1 - x0);
240 int tmp;
241 if(steep)
242 {
243 SWAP(x0, y0, tmp);
244 SWAP(x1, y1, tmp);
245 }
246 if(x0 > x1)
247 {
248 SWAP(x0, x1, tmp);
249 SWAP(y0, y1, tmp);
250 }
251
252 int dx, dy;
253 dx = x1 - x0;
254 dy = y1 - y0;
255
256 if(!(dx << FRACBITS))
257 return; /* bail out */
258
259 long gradient = fp_div(dy << FRACBITS, dx << FRACBITS, FRACBITS);
260 long intery = (y0 << FRACBITS);
261
262 unsigned color = rb->lcd_get_foreground();
263 unsigned long r1, g1, b1;
264 r1 = RGB_UNPACK_RED(color);
265 g1 = RGB_UNPACK_GREEN(color);
266 b1 = RGB_UNPACK_BLUE(color);
267
268 /* main loop */
269 if(steep)
270 {
271 for(int x = x0; x <= x1; ++x, intery += gradient)
272 {
273 unsigned y = intery >> FRACBITS;
274 unsigned alpha = fp_fpart(intery, FRACBITS) >> (FRACBITS - 8);
275
276 plot(y, x, (1 << 8) - alpha, r1, g1, b1, l, r, u, d);
277 plot(y + 1, x, alpha, r1, g1, b1, l, r, u, d);
278 }
279 }
280 else
281 {
282 for(int x = x0; x <= x1; ++x, intery += gradient)
283 {
284 unsigned y = intery >> FRACBITS;
285 unsigned alpha = fp_fpart(intery, FRACBITS) >> (FRACBITS - 8);
286
287 plot(x, y, (1 << 8) - alpha, r1, g1, b1, l, r, u, d);
288 plot(x, y + 1, alpha, r1, g1, b1, l, r, u, d);
289 }
290 }
291}
292
182static void rb_draw_line(void *handle, int x1, int y1, int x2, int y2, 293static void rb_draw_line(void *handle, int x1, int y1, int x2, int y2,
183 int color) 294 int color)
184{ 295{
185 LOGF("rb_draw_line(%d, %d, %d, %d, %d)", x1, y1, x2, y2, color); 296 LOGF("rb_draw_line(%d, %d, %d, %d, %d)", x1, y1, x2, y2, color);
186 offset_coords(&x1, &y1);
187 offset_coords(&x2, &y2);
188 rb_color(color); 297 rb_color(color);
189 rb->lcd_drawline(x1, y1, x2, y2); 298 if(settings.no_aa)
299 {
300 offset_coords(&x1, &y1);
301 offset_coords(&x2, &y2);
302 rb->lcd_drawline(x1, y1, x2, y2);
303 }
304 else
305 draw_antialiased_line(x1, y1, x2, y2);
190} 306}
191 307
192/* 308/*
@@ -351,12 +467,15 @@ static void rb_draw_poly(void *handle, int *coords, int npoints,
351 y1 = coords[2 * (i - 1) + 1]; 467 y1 = coords[2 * (i - 1) + 1];
352 x2 = coords[2 * i]; 468 x2 = coords[2 * i];
353 y2 = coords[2 * i + 1]; 469 y2 = coords[2 * i + 1];
354 offset_coords(&x1, &y1); 470 if(settings.no_aa)
355 offset_coords(&x2, &y2); 471 {
356 rb->lcd_drawline(x1, y1, 472 offset_coords(&x1, &y1);
357 x2, y2); 473 offset_coords(&x2, &y2);
358 //rb->lcd_update(); 474 rb->lcd_drawline(x1, y1,
359 //rb->sleep(HZ/2); 475 x2, y2);
476 }
477 else
478 draw_antialiased_line(x1, y1, x2, y2);
360 } 479 }
361 480
362 int x1, y1, x2, y2; 481 int x1, y1, x2, y2;
@@ -364,11 +483,16 @@ static void rb_draw_poly(void *handle, int *coords, int npoints,
364 y1 = coords[1]; 483 y1 = coords[1];
365 x2 = coords[2 * (npoints - 1)]; 484 x2 = coords[2 * (npoints - 1)];
366 y2 = coords[2 * (npoints - 1) + 1]; 485 y2 = coords[2 * (npoints - 1) + 1];
367 offset_coords(&x1, &y1); 486 if(settings.no_aa)
368 offset_coords(&x2, &y2); 487 {
488 offset_coords(&x1, &y1);
489 offset_coords(&x2, &y2);
369 490
370 rb->lcd_drawline(x1, y1, 491 rb->lcd_drawline(x1, y1,
371 x2, y2); 492 x2, y2);
493 }
494 else
495 draw_antialiased_line(x1, y1, x2, y2);
372} 496}
373 497
374static void rb_draw_circle(void *handle, int cx, int cy, int radius, 498static void rb_draw_circle(void *handle, int cx, int cy, int radius,
@@ -394,25 +518,6 @@ struct blitter {
394 struct bitmap bmp; 518 struct bitmap bmp;
395}; 519};
396 520
397static blitter *rb_blitter_new(void *handle, int w, int h)
398{
399 LOGF("rb_blitter_new");
400 blitter *b = snew(blitter);
401 b->bmp.width = w;
402 b->bmp.height = h;
403 b->bmp.data = smalloc(w * h * sizeof(fb_data));
404 b->have_data = false;
405 return b;
406}
407
408static void rb_blitter_free(void *handle, blitter *bl)
409{
410 LOGF("rb_blitter_free");
411 sfree(bl->bmp.data);
412 sfree(bl);
413 return;
414}
415
416/* originally from emcc.c */ 521/* originally from emcc.c */
417static void trim_rect(int *x, int *y, int *w, int *h) 522static void trim_rect(int *x, int *y, int *w, int *h)
418{ 523{
@@ -430,10 +535,10 @@ static void trim_rect(int *x, int *y, int *w, int *h)
430 y1 = *y + *h; 535 y1 = *y + *h;
431 536
432 /* Clip each coordinate at both extremes of the canvas */ 537 /* Clip each coordinate at both extremes of the canvas */
433 x0 = (x0 < 0 ? 0 : x0 > LCD_WIDTH ? LCD_WIDTH : x0); 538 x0 = (x0 < 0 ? 0 : x0 > LCD_WIDTH - 1 ? LCD_WIDTH - 1: x0);
434 x1 = (x1 < 0 ? 0 : x1 > LCD_WIDTH ? LCD_WIDTH : x1); 539 x1 = (x1 < 0 ? 0 : x1 > LCD_WIDTH - 1 ? LCD_WIDTH - 1: x1);
435 y0 = (y0 < 0 ? 0 : y0 > LCD_HEIGHT ? LCD_HEIGHT : y0); 540 y0 = (y0 < 0 ? 0 : y0 > LCD_HEIGHT - 1 ? LCD_HEIGHT - 1: y0);
436 y1 = (y1 < 0 ? 0 : y1 > LCD_HEIGHT ? LCD_HEIGHT : y1); 541 y1 = (y1 < 0 ? 0 : y1 > LCD_HEIGHT - 1 ? LCD_HEIGHT - 1: y1);
437 542
438 /* Transform back into x,y,w,h to return */ 543 /* Transform back into x,y,w,h to return */
439 *x = x0; 544 *x = x0;
@@ -442,6 +547,25 @@ static void trim_rect(int *x, int *y, int *w, int *h)
442 *h = y1 - y0; 547 *h = y1 - y0;
443} 548}
444 549
550static blitter *rb_blitter_new(void *handle, int w, int h)
551{
552 LOGF("rb_blitter_new");
553 blitter *b = snew(blitter);
554 b->bmp.width = w;
555 b->bmp.height = h;
556 b->bmp.data = smalloc(w * h * sizeof(fb_data));
557 b->have_data = false;
558 return b;
559}
560
561static void rb_blitter_free(void *handle, blitter *bl)
562{
563 LOGF("rb_blitter_free");
564 sfree(bl->bmp.data);
565 sfree(bl);
566 return;
567}
568
445/* copy a section of the framebuffer */ 569/* copy a section of the framebuffer */
446static void rb_blitter_save(void *handle, blitter *bl, int x, int y) 570static void rb_blitter_save(void *handle, blitter *bl, int x, int y)
447{ 571{
@@ -623,8 +747,6 @@ void get_random_seed(void **randseed, int *randseedsize)
623 *randseed = snew(long); 747 *randseed = snew(long);
624 long seed = *rb->current_tick; 748 long seed = *rb->current_tick;
625 rb->memcpy(*randseed, &seed, sizeof(seed)); 749 rb->memcpy(*randseed, &seed, sizeof(seed));
626 //*(long*)*randseed = 42; // debug
627 //rb->splash(HZ, "DEBUG SEED ON");
628 *randseedsize = sizeof(long); 750 *randseedsize = sizeof(long);
629} 751}
630 752
@@ -683,8 +805,7 @@ static int list_choose(const char *list_str, const char *title)
683 } 805 }
684} 806}
685 807
686/* return value is only meaningful when type == C_STRING */ 808static void do_configure_item(config_item *cfg)
687static bool do_configure_item(config_item *cfg)
688{ 809{
689 switch(cfg->type) 810 switch(cfg->type)
690 { 811 {
@@ -698,11 +819,11 @@ static bool do_configure_item(config_item *cfg)
698 if(rb->kbd_input(newstr, MAX_STRLEN) < 0) 819 if(rb->kbd_input(newstr, MAX_STRLEN) < 0)
699 { 820 {
700 sfree(newstr); 821 sfree(newstr);
701 return false; 822 break;
702 } 823 }
703 sfree(cfg->sval); 824 sfree(cfg->sval);
704 cfg->sval = newstr; 825 cfg->sval = newstr;
705 return true; 826 break;
706 } 827 }
707 case C_BOOLEAN: 828 case C_BOOLEAN:
708 { 829 {
@@ -726,7 +847,6 @@ static bool do_configure_item(config_item *cfg)
726 fatal("bad type"); 847 fatal("bad type");
727 break; 848 break;
728 } 849 }
729 return false;
730} 850}
731 851
732const char *config_formatter(int sel, void *data, char *buf, size_t len) 852const char *config_formatter(int sel, void *data, char *buf, size_t len)
@@ -737,11 +857,13 @@ const char *config_formatter(int sel, void *data, char *buf, size_t len)
737 return buf; 857 return buf;
738} 858}
739 859
740static void config_menu(void) 860static bool config_menu(void)
741{ 861{
742 char *title; 862 char *title;
743 config_item *config = midend_get_config(me, CFG_SETTINGS, &title); 863 config_item *config = midend_get_config(me, CFG_SETTINGS, &title);
744 864
865 bool success = false;
866
745 if(!config) 867 if(!config)
746 { 868 {
747 rb->splash(HZ, "Nothing to configure."); 869 rb->splash(HZ, "Nothing to configure.");
@@ -782,22 +904,16 @@ static void config_menu(void)
782 config_item old; 904 config_item old;
783 int pos = rb->gui_synclist_get_sel_pos(&list); 905 int pos = rb->gui_synclist_get_sel_pos(&list);
784 memcpy(&old, config + pos, sizeof(old)); 906 memcpy(&old, config + pos, sizeof(old));
785 char *old_str; 907 do_configure_item(config + pos);
786 if(old.type == C_STRING)
787 old_str = dupstr(old.sval);
788 bool freed_str = do_configure_item(config + pos);
789 char *err = midend_set_config(me, CFG_SETTINGS, config); 908 char *err = midend_set_config(me, CFG_SETTINGS, config);
790 if(err) 909 if(err)
791 { 910 {
792 rb->splash(HZ, err); 911 rb->splash(HZ, err);
793 memcpy(config + pos, &old, sizeof(old)); 912 memcpy(config + pos, &old, sizeof(old));
794 if(freed_str)
795 config[pos].sval = old_str;
796 } 913 }
797 else if(old.type == C_STRING) 914 else
798 { 915 {
799 /* success, and we duplicated the old string, so free it */ 916 success = true;
800 sfree(old_str);
801 } 917 }
802 break; 918 break;
803 } 919 }
@@ -813,6 +929,7 @@ static void config_menu(void)
813done: 929done:
814 sfree(title); 930 sfree(title);
815 free_cfg(config); 931 free_cfg(config);
932 return success;
816} 933}
817 934
818const char *preset_formatter(int sel, void *data, char *buf, size_t len) 935const char *preset_formatter(int sel, void *data, char *buf, size_t len)
@@ -824,12 +941,12 @@ const char *preset_formatter(int sel, void *data, char *buf, size_t len)
824 return buf; 941 return buf;
825} 942}
826 943
827static void presets_menu(void) 944static bool presets_menu(void)
828{ 945{
829 if(!midend_num_presets(me)) 946 if(!midend_num_presets(me))
830 { 947 {
831 rb->splash(HZ, "No presets!"); 948 rb->splash(HZ, "No presets!");
832 return; 949 return false;
833 } 950 }
834 951
835 /* display a list */ 952 /* display a list */
@@ -843,9 +960,8 @@ static void presets_menu(void)
843 int current = midend_which_preset(me); 960 int current = midend_which_preset(me);
844 rb->gui_synclist_select_item(&list, current >= 0 ? current : 0); 961 rb->gui_synclist_select_item(&list, current >= 0 ? current : 0);
845 962
846 bool done = false;
847 rb->gui_synclist_set_title(&list, "Game Type", NOICON); 963 rb->gui_synclist_set_title(&list, "Game Type", NOICON);
848 while (!done) 964 while(1)
849 { 965 {
850 rb->gui_synclist_draw(&list); 966 rb->gui_synclist_draw(&list);
851 int button = rb->get_action(CONTEXT_LIST, TIMEOUT_BLOCK); 967 int button = rb->get_action(CONTEXT_LIST, TIMEOUT_BLOCK);
@@ -860,13 +976,11 @@ static void presets_menu(void)
860 game_params *params; 976 game_params *params;
861 midend_fetch_preset(me, sel, &junk, &params); 977 midend_fetch_preset(me, sel, &junk, &params);
862 midend_set_params(me, params); 978 midend_set_params(me, params);
863 done = true; 979 return true;
864 break;
865 } 980 }
866 case ACTION_STD_PREV: 981 case ACTION_STD_PREV:
867 case ACTION_STD_CANCEL: 982 case ACTION_STD_CANCEL:
868 done = true; 983 return false;
869 break;
870 default: 984 default:
871 break; 985 break;
872 } 986 }
@@ -948,6 +1062,37 @@ static void init_default_settings(void)
948 settings.slowmo_factor = 1; 1062 settings.slowmo_factor = 1;
949 settings.bulk = false; 1063 settings.bulk = false;
950 settings.timerflash = false; 1064 settings.timerflash = false;
1065 settings.clipoff = false;
1066 settings.shortcuts = false;
1067 settings.no_aa = false;
1068}
1069
1070static void bench_aa(void)
1071{
1072 rb->sleep(0);
1073#ifdef HAVE_ADJUSTABLE_CPU_FREQ
1074 rb->cpu_boost(true);
1075#endif
1076 int next = *rb->current_tick + HZ;
1077 int i = 0;
1078 while(*rb->current_tick < next)
1079 {
1080 draw_antialiased_line(0, 0, 20, 31);
1081 ++i;
1082 }
1083 rb->splashf(HZ, "%d AA lines/sec", i);
1084 next = *rb->current_tick + HZ;
1085 int j = 0;
1086 while(*rb->current_tick < next)
1087 {
1088 rb->lcd_drawline(0, 0, 20, 31);
1089 ++j;
1090 }
1091 rb->splashf(HZ, "%d normal lines/sec", j);
1092 rb->splashf(HZ, "Efficiency: %d%%", 100 * i / j);
1093#ifdef HAVE_ADJUSTABLE_CPU_FREQ
1094 rb->cpu_boost(false);
1095#endif
951} 1096}
952 1097
953static void debug_menu(void) 1098static void debug_menu(void)
@@ -958,6 +1103,9 @@ static void debug_menu(void)
958 "Toggle bulk update", 1103 "Toggle bulk update",
959 "Toggle flash pixel on timer", 1104 "Toggle flash pixel on timer",
960 "Toggle clip", 1105 "Toggle clip",
1106 "Toggle shortcuts",
1107 "Toggle antialias",
1108 "Benchmark antialias",
961 "Back"); 1109 "Back");
962 bool quit = false; 1110 bool quit = false;
963 int sel = 0; 1111 int sel = 0;
@@ -988,6 +1136,15 @@ static void debug_menu(void)
988 settings.clipoff = !settings.clipoff; 1136 settings.clipoff = !settings.clipoff;
989 break; 1137 break;
990 case 5: 1138 case 5:
1139 settings.shortcuts = !settings.shortcuts;
1140 break;
1141 case 6:
1142 settings.no_aa = !settings.no_aa;
1143 break;
1144 case 7:
1145 bench_aa();
1146 break;
1147 case 8:
991 default: 1148 default:
992 quit = true; 1149 quit = true;
993 break; 1150 break;
@@ -1055,6 +1212,23 @@ static int pausemenu_cb(int action, const struct menu_item_ex *this_item)
1055 return action; 1212 return action;
1056} 1213}
1057 1214
1215static void clear_and_draw(void)
1216{
1217 rb->lcd_clear_display();
1218 rb->lcd_update();
1219
1220 midend_force_redraw(me);
1221 draw_title();
1222}
1223
1224static void reset_drawing(void)
1225{
1226 rb->lcd_set_viewport(NULL);
1227 rb->lcd_set_backdrop(NULL);
1228 rb->lcd_set_foreground(LCD_BLACK);
1229 rb->lcd_set_background(BG_COLOR);
1230}
1231
1058static int pause_menu(void) 1232static int pause_menu(void)
1059{ 1233{
1060#define static auto 1234#define static auto
@@ -1139,19 +1313,27 @@ static int pause_menu(void)
1139 playback_control(NULL); 1313 playback_control(NULL);
1140 break; 1314 break;
1141 case 9: 1315 case 9:
1142 presets_menu(); 1316 if(presets_menu())
1143 midend_new_game(me); 1317 {
1144 fix_size(); 1318 midend_new_game(me);
1145 quit = true; 1319 fix_size();
1320 reset_drawing();
1321 clear_and_draw();
1322 quit = true;
1323 }
1146 break; 1324 break;
1147 case 10: 1325 case 10:
1148 debug_menu(); 1326 debug_menu();
1149 break; 1327 break;
1150 case 11: 1328 case 11:
1151 config_menu(); 1329 if(config_menu())
1152 midend_new_game(me); 1330 {
1153 fix_size(); 1331 midend_new_game(me);
1154 quit = true; 1332 fix_size();
1333 reset_drawing();
1334 clear_and_draw();
1335 quit = true;
1336 }
1155 break; 1337 break;
1156#ifdef COMBINED 1338#ifdef COMBINED
1157 case 12: 1339 case 12:
@@ -1257,8 +1439,8 @@ static int process_input(int tmo)
1257 } 1439 }
1258 LOGF("accepting event 0x%08x", button); 1440 LOGF("accepting event 0x%08x", button);
1259 } 1441 }
1260 /* not inertia: events fire on presses */ 1442 /* default is to ignore repeats except for untangle */
1261 else 1443 else if(strcmp("Untangle", midend_which_game(me)->name))
1262 { 1444 {
1263 /* start accepting input again after a release */ 1445 /* start accepting input again after a release */
1264 if(!button) 1446 if(!button)
@@ -1267,6 +1449,7 @@ static int process_input(int tmo)
1267 return 0; 1449 return 0;
1268 } 1450 }
1269 /* ignore repeats */ 1451 /* ignore repeats */
1452 /* Untangle gets special treatment */
1270 if(!accept_input) 1453 if(!accept_input)
1271 return 0; 1454 return 0;
1272 accept_input = false; 1455 accept_input = false;
@@ -1316,7 +1499,34 @@ static int process_input(int tmo)
1316 case BTN_FIRE: 1499 case BTN_FIRE:
1317 state = CURSOR_SELECT; 1500 state = CURSOR_SELECT;
1318 break; 1501 break;
1502
1503 default:
1504 break;
1319 } 1505 }
1506
1507 if(settings.shortcuts)
1508 {
1509 static bool shortcuts_ok = true;
1510 switch(button)
1511 {
1512 case BTN_LEFT | BTN_FIRE:
1513 if(shortcuts_ok)
1514 midend_process_key(me, 0, 0, 'u');
1515 shortcuts_ok = false;
1516 break;
1517 case BTN_RIGHT | BTN_FIRE:
1518 if(shortcuts_ok)
1519 midend_process_key(me, 0, 0, 'r');
1520 shortcuts_ok = false;
1521 break;
1522 case 0:
1523 shortcuts_ok = true;
1524 break;
1525 default:
1526 break;
1527 }
1528 }
1529
1320 LOGF("process_input done"); 1530 LOGF("process_input done");
1321 LOGF("------------------"); 1531 LOGF("------------------");
1322 return state; 1532 return state;
@@ -1403,13 +1613,23 @@ static void write_wrapper(void *ptr, void *buf, int len)
1403 rb->write(fd, buf, len); 1613 rb->write(fd, buf, len);
1404} 1614}
1405 1615
1406static void clear_and_draw(void) 1616static void init_colors(void)
1407{ 1617{
1408 rb->lcd_clear_display(); 1618 float *floatcolors = midend_colors(me, &ncolors);
1409 rb->lcd_update();
1410 1619
1411 midend_force_redraw(me); 1620 /* convert them to packed RGB */
1412 draw_title(); 1621 colors = smalloc(ncolors * sizeof(unsigned));
1622 unsigned *ptr = colors;
1623 float *floatptr = floatcolors;
1624 for(int i = 0; i < ncolors; ++i)
1625 {
1626 int r = 255 * *(floatptr++);
1627 int g = 255 * *(floatptr++);
1628 int b = 255 * *(floatptr++);
1629 LOGF("color %d is %d %d %d", i, r, g, b);
1630 *ptr++ = LCD_RGBPACK(r, g, b);
1631 }
1632 sfree(floatcolors);
1413} 1633}
1414 1634
1415static char *init_for_game(const game *gm, int load_fd, bool draw) 1635static char *init_for_game(const game *gm, int load_fd, bool draw)
@@ -1431,26 +1651,9 @@ static char *init_for_game(const game *gm, int load_fd, bool draw)
1431 1651
1432 fix_size(); 1652 fix_size();
1433 1653
1434 float *floatcolors = midend_colors(me, &ncolors); 1654 init_colors();
1435 1655
1436 /* convert them to packed RGB */ 1656 reset_drawing();
1437 colors = smalloc(ncolors * sizeof(unsigned));
1438 unsigned *ptr = colors;
1439 float *floatptr = floatcolors;
1440 for(int i = 0; i < ncolors; ++i)
1441 {
1442 int r = 255 * *(floatptr++);
1443 int g = 255 * *(floatptr++);
1444 int b = 255 * *(floatptr++);
1445 LOGF("color %d is %d %d %d", i, r, g, b);
1446 *ptr++ = LCD_RGBPACK(r, g, b);
1447 }
1448 sfree(floatcolors);
1449
1450 rb->lcd_set_viewport(NULL);
1451 rb->lcd_set_backdrop(NULL);
1452 rb->lcd_set_foreground(LCD_BLACK);
1453 rb->lcd_set_background(BG_COLOR);
1454 1657
1455 if(draw) 1658 if(draw)
1456 { 1659 {
@@ -1690,22 +1893,26 @@ enum plugin_status plugin_start(const void *param)
1690 playback_control(NULL); 1893 playback_control(NULL);
1691 break; 1894 break;
1692 case 5: 1895 case 5:
1693 presets_menu(); 1896 if(presets_menu())
1694 if(!load_success)
1695 { 1897 {
1898 midend_new_game(me);
1899 fix_size();
1900 init_colors();
1901 reset_drawing();
1696 clear_and_draw(); 1902 clear_and_draw();
1697 goto game_loop; 1903 goto game_loop;
1698 } 1904 }
1699 quit = true;
1700 break; 1905 break;
1701 case 6: 1906 case 6:
1702 config_menu(); 1907 if(config_menu())
1703 if(!load_success)
1704 { 1908 {
1909 midend_new_game(me);
1910 fix_size();
1911 init_colors();
1912 reset_drawing();
1705 clear_and_draw(); 1913 clear_and_draw();
1706 goto game_loop; 1914 goto game_loop;
1707 } 1915 }
1708 quit = true;
1709 break; 1916 break;
1710 case 8: 1917 case 8:
1711 if(load_success) 1918 if(load_success)
diff --git a/apps/plugins/puzzles/untangle.c b/apps/plugins/puzzles/untangle.c
index 839013809b..d46afcbe66 100644
--- a/apps/plugins/puzzles/untangle.c
+++ b/apps/plugins/puzzles/untangle.c
@@ -1162,18 +1162,17 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1162 { 1162 {
1163 if(ui->dragpoint < 0) 1163 if(ui->dragpoint < 0)
1164 { 1164 {
1165 if(ui->cursorpoint < 0)
1166 {
1167 ui->cursorpoint = 0;
1168 return "";
1169 }
1170
1171 /* We're selecting a point here. */ 1165 /* We're selecting a point here. */
1172 /* Search all the points and find the closest one (2-D) in 1166 /* Search all the points and find the closest one (2-D) in
1173 * the given direction. */ 1167 * the given direction. */
1174 int i, best; 1168 int i, best;
1175 long bestd; 1169 long bestd;
1176 1170
1171 if(ui->cursorpoint < 0)
1172 {
1173 ui->cursorpoint = 0;
1174 }
1175
1177 /* 1176 /*
1178 * Begin drag. We drag the vertex _nearest_ to the pointer, 1177 * Begin drag. We drag the vertex _nearest_ to the pointer,
1179 * just in case one is nearly on top of another and we want 1178 * just in case one is nearly on top of another and we want
@@ -1196,7 +1195,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1196 /* Figure out if this point falls into a 90 degree 1195 /* Figure out if this point falls into a 90 degree
1197 * range extending from the current point */ 1196 * range extending from the current point */
1198 1197
1199 float angle = atan2(-dy, dx); /* adjust for raster coordinates */ 1198 float angle = atan2(-dy, dx); /* negate y to adjust for raster coordinates */
1200 1199
1201 /* offset to [0..2*PI] */ 1200 /* offset to [0..2*PI] */
1202 if(angle < 0) 1201 if(angle < 0)
@@ -1494,6 +1493,8 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1494 ds->bg = bg; 1493 ds->bg = bg;
1495 1494
1496 game_compute_size(&state->params, ds->tilesize, &w, &h); 1495 game_compute_size(&state->params, ds->tilesize, &w, &h);
1496
1497 clip(dr, 0, 0, w, h);
1497 draw_rect(dr, 0, 0, w, h, bg); 1498 draw_rect(dr, 0, 0, w, h, bg);
1498 1499
1499 /* 1500 /*