diff options
Diffstat (limited to 'apps/plugins/puzzles/rockbox.c')
-rw-r--r-- | apps/plugins/puzzles/rockbox.c | 445 |
1 files changed, 359 insertions, 86 deletions
diff --git a/apps/plugins/puzzles/rockbox.c b/apps/plugins/puzzles/rockbox.c index 44df35027a..f77b538019 100644 --- a/apps/plugins/puzzles/rockbox.c +++ b/apps/plugins/puzzles/rockbox.c | |||
@@ -44,6 +44,8 @@ | |||
44 | 44 | ||
45 | #include "fixedpoint.h" | 45 | #include "fixedpoint.h" |
46 | 46 | ||
47 | #include "pluginbitmaps/puzzles_cursor.h" | ||
48 | |||
47 | /* how many ticks between timer callbacks */ | 49 | /* how many ticks between timer callbacks */ |
48 | #define TIMER_INTERVAL (HZ / 50) | 50 | #define TIMER_INTERVAL (HZ / 50) |
49 | 51 | ||
@@ -122,12 +124,14 @@ static int help_times = 0; | |||
122 | 124 | ||
123 | /* clipping stuff */ | 125 | /* clipping stuff */ |
124 | static struct viewport clip_rect; | 126 | static struct viewport clip_rect; |
125 | static bool clipped = false, zoom_enabled = false, view_mode = true; | 127 | static bool clipped = false, zoom_enabled = false, view_mode = true, mouse_mode = false; |
128 | |||
129 | static int mouse_x, mouse_y; | ||
126 | 130 | ||
127 | extern bool audiobuf_available; /* defined in rbmalloc.c */ | 131 | extern bool audiobuf_available; /* defined in rbmalloc.c */ |
128 | 132 | ||
129 | static fb_data *zoom_fb; /* dynamically allocated */ | 133 | static fb_data *zoom_fb; /* dynamically allocated */ |
130 | static int zoom_w, zoom_h, zoom_clipu, zoom_clipd, zoom_clipl, zoom_clipr; | 134 | static int zoom_x, zoom_y, zoom_w, zoom_h, zoom_clipu, zoom_clipd, zoom_clipl, zoom_clipr; |
131 | static int cur_font = FONT_UI; | 135 | static int cur_font = FONT_UI; |
132 | 136 | ||
133 | static bool need_draw_update = false; | 137 | static bool need_draw_update = false; |
@@ -135,7 +139,12 @@ static int ud_l = 0, ud_u = 0, ud_r = LCD_WIDTH, ud_d = LCD_HEIGHT; | |||
135 | 139 | ||
136 | static char *titlebar = NULL; | 140 | static char *titlebar = NULL; |
137 | 141 | ||
138 | static bool want_redraw = true, accept_input = true; | 142 | /* how to process the input (custom, per-game) */ |
143 | static struct { | ||
144 | bool want_spacebar, falling_edge, ignore_repeats, rclick_on_hold; | ||
145 | } input_settings; | ||
146 | |||
147 | static bool accept_input = true; | ||
139 | 148 | ||
140 | /* last timer call */ | 149 | /* last timer call */ |
141 | static long last_tstamp; | 150 | static long last_tstamp; |
@@ -145,10 +154,10 @@ static bool load_success; | |||
145 | 154 | ||
146 | /* debug settings */ | 155 | /* debug settings */ |
147 | /* did I mention there's a secret debug menu? */ | 156 | /* did I mention there's a secret debug menu? */ |
148 | static struct settings_t { | 157 | static struct { |
149 | int slowmo_factor; | 158 | int slowmo_factor; |
150 | bool timerflash, clipoff, shortcuts, no_aa, polyanim; | 159 | bool timerflash, clipoff, shortcuts, no_aa, polyanim; |
151 | } settings; | 160 | } debug_settings; |
152 | 161 | ||
153 | /* re-implementations of many rockbox primitives, adapted to draw into | 162 | /* re-implementations of many rockbox primitives, adapted to draw into |
154 | * a custom framebuffer. */ | 163 | * a custom framebuffer. */ |
@@ -469,7 +478,7 @@ static void rb_clip(void *handle, int x, int y, int w, int h) | |||
469 | { | 478 | { |
470 | if(!zoom_enabled) | 479 | if(!zoom_enabled) |
471 | { | 480 | { |
472 | if(!settings.clipoff) | 481 | if(!debug_settings.clipoff) |
473 | { | 482 | { |
474 | LOGF("rb_clip(%d %d %d %d)", x, y, w, h); | 483 | LOGF("rb_clip(%d %d %d %d)", x, y, w, h); |
475 | clip_rect.x = MAX(0, x); | 484 | clip_rect.x = MAX(0, x); |
@@ -736,7 +745,7 @@ static void rb_draw_line(void *handle, int x1, int y1, int x2, int y2, | |||
736 | { | 745 | { |
737 | LOGF("rb_draw_line(%d, %d, %d, %d, %d)", x1, y1, x2, y2, color); | 746 | LOGF("rb_draw_line(%d, %d, %d, %d, %d)", x1, y1, x2, y2, color); |
738 | rb_color(color); | 747 | rb_color(color); |
739 | if(settings.no_aa) | 748 | if(debug_settings.no_aa) |
740 | { | 749 | { |
741 | offset_coords(&x1, &y1); | 750 | offset_coords(&x1, &y1); |
742 | offset_coords(&x2, &y2); | 751 | offset_coords(&x2, &y2); |
@@ -968,7 +977,7 @@ static void rb_draw_poly(void *handle, int *coords, int npoints, | |||
968 | x3, y3); | 977 | x3, y3); |
969 | 978 | ||
970 | #ifdef DEBUG_MENU | 979 | #ifdef DEBUG_MENU |
971 | if(settings.polyanim) | 980 | if(debug_settings.polyanim) |
972 | { | 981 | { |
973 | rb->lcd_update(); | 982 | rb->lcd_update(); |
974 | rb->sleep(HZ/4); | 983 | rb->sleep(HZ/4); |
@@ -1014,7 +1023,7 @@ static void rb_draw_poly(void *handle, int *coords, int npoints, | |||
1014 | y1 = coords[2 * (i - 1) + 1]; | 1023 | y1 = coords[2 * (i - 1) + 1]; |
1015 | x2 = coords[2 * i]; | 1024 | x2 = coords[2 * i]; |
1016 | y2 = coords[2 * i + 1]; | 1025 | y2 = coords[2 * i + 1]; |
1017 | if(settings.no_aa) | 1026 | if(debug_settings.no_aa) |
1018 | { | 1027 | { |
1019 | offset_coords(&x1, &y1); | 1028 | offset_coords(&x1, &y1); |
1020 | offset_coords(&x2, &y2); | 1029 | offset_coords(&x2, &y2); |
@@ -1025,7 +1034,7 @@ static void rb_draw_poly(void *handle, int *coords, int npoints, | |||
1025 | draw_antialiased_line(rb->lcd_framebuffer, LCD_WIDTH, LCD_HEIGHT, x1, y1, x2, y2); | 1034 | draw_antialiased_line(rb->lcd_framebuffer, LCD_WIDTH, LCD_HEIGHT, x1, y1, x2, y2); |
1026 | 1035 | ||
1027 | #ifdef DEBUG_MENU | 1036 | #ifdef DEBUG_MENU |
1028 | if(settings.polyanim) | 1037 | if(debug_settings.polyanim) |
1029 | { | 1038 | { |
1030 | rb->lcd_update(); | 1039 | rb->lcd_update(); |
1031 | rb->sleep(HZ/4); | 1040 | rb->sleep(HZ/4); |
@@ -1038,7 +1047,7 @@ static void rb_draw_poly(void *handle, int *coords, int npoints, | |||
1038 | y1 = coords[1]; | 1047 | y1 = coords[1]; |
1039 | x2 = coords[2 * (npoints - 1)]; | 1048 | x2 = coords[2 * (npoints - 1)]; |
1040 | y2 = coords[2 * (npoints - 1) + 1]; | 1049 | y2 = coords[2 * (npoints - 1) + 1]; |
1041 | if(settings.no_aa) | 1050 | if(debug_settings.no_aa) |
1042 | { | 1051 | { |
1043 | offset_coords(&x1, &y1); | 1052 | offset_coords(&x1, &y1); |
1044 | offset_coords(&x2, &y2); | 1053 | offset_coords(&x2, &y2); |
@@ -1193,7 +1202,7 @@ static void rb_blitter_save(void *handle, blitter *bl, int x, int y) | |||
1193 | #if defined(LCD_STRIDEFORMAT) && (LCD_STRIDEFORMAT == VERTICAL_STRIDE) | 1202 | #if defined(LCD_STRIDEFORMAT) && (LCD_STRIDEFORMAT == VERTICAL_STRIDE) |
1194 | #error no vertical stride | 1203 | #error no vertical stride |
1195 | #else | 1204 | #else |
1196 | if(bl->bmp.data) | 1205 | if(bl && bl->bmp.data) |
1197 | { | 1206 | { |
1198 | int w = bl->bmp.width, h = bl->bmp.height; | 1207 | int w = bl->bmp.width, h = bl->bmp.height; |
1199 | int screen_w = zoom_enabled ? zoom_w : LCD_WIDTH; | 1208 | int screen_w = zoom_enabled ? zoom_w : LCD_WIDTH; |
@@ -1282,6 +1291,8 @@ static void rb_start_draw(void *handle) | |||
1282 | static void rb_end_draw(void *handle) | 1291 | static void rb_end_draw(void *handle) |
1283 | { | 1292 | { |
1284 | (void) handle; | 1293 | (void) handle; |
1294 | /* we ignore the backend's redraw requests and just unconditionally update everything */ | ||
1295 | #if 0 | ||
1285 | if(!zoom_enabled) | 1296 | if(!zoom_enabled) |
1286 | { | 1297 | { |
1287 | LOGF("rb_end_draw"); | 1298 | LOGF("rb_end_draw"); |
@@ -1293,6 +1304,7 @@ static void rb_end_draw(void *handle) | |||
1293 | { | 1304 | { |
1294 | /* stubbed */ | 1305 | /* stubbed */ |
1295 | } | 1306 | } |
1307 | #endif | ||
1296 | } | 1308 | } |
1297 | 1309 | ||
1298 | static void rb_status_bar(void *handle, const char *text) | 1310 | static void rb_status_bar(void *handle, const char *text) |
@@ -1347,6 +1359,54 @@ static void draw_title(bool clear_first) | |||
1347 | } | 1359 | } |
1348 | } | 1360 | } |
1349 | 1361 | ||
1362 | #define MOUSE_W BMPWIDTH_puzzles_cursor | ||
1363 | #define MOUSE_H BMPHEIGHT_puzzles_cursor | ||
1364 | |||
1365 | static blitter *mouse_bl = NULL; | ||
1366 | |||
1367 | static void clear_mouse(void) | ||
1368 | { | ||
1369 | bool orig_clipped = clipped; | ||
1370 | if(!zoom_enabled) | ||
1371 | { | ||
1372 | if(orig_clipped) | ||
1373 | rb_unclip(NULL); | ||
1374 | } | ||
1375 | |||
1376 | if(mouse_bl) | ||
1377 | rb_blitter_load(NULL, mouse_bl, BLITTER_FROMSAVED, BLITTER_FROMSAVED); | ||
1378 | |||
1379 | if(!zoom_enabled) | ||
1380 | { | ||
1381 | if(orig_clipped) | ||
1382 | rb_clip(NULL, clip_rect.x, clip_rect.y, clip_rect.width, clip_rect.height); | ||
1383 | } | ||
1384 | } | ||
1385 | |||
1386 | static void draw_mouse(void) | ||
1387 | { | ||
1388 | bool orig_clipped = clipped; | ||
1389 | if(!zoom_enabled) | ||
1390 | { | ||
1391 | if(orig_clipped) | ||
1392 | rb_unclip(NULL); | ||
1393 | } | ||
1394 | |||
1395 | if(!mouse_bl) | ||
1396 | mouse_bl = rb_blitter_new(NULL, MOUSE_W, MOUSE_H); | ||
1397 | |||
1398 | /* save area being covered (will be restored elsewhere) */ | ||
1399 | rb_blitter_save(NULL, mouse_bl, mouse_x, mouse_y); | ||
1400 | |||
1401 | rb->lcd_bitmap_transparent(puzzles_cursor, mouse_x, mouse_y, BMPWIDTH_puzzles_cursor, BMPHEIGHT_puzzles_cursor); | ||
1402 | |||
1403 | if(!zoom_enabled) | ||
1404 | { | ||
1405 | if(orig_clipped) | ||
1406 | rb_clip(NULL, clip_rect.x, clip_rect.y, clip_rect.width, clip_rect.height); | ||
1407 | } | ||
1408 | } | ||
1409 | |||
1350 | static char *rb_text_fallback(void *handle, const char *const *strings, | 1410 | static char *rb_text_fallback(void *handle, const char *const *strings, |
1351 | int nstrings) | 1411 | int nstrings) |
1352 | { | 1412 | { |
@@ -1403,7 +1463,7 @@ void get_random_seed(void **randseed, int *randseedsize) | |||
1403 | static void timer_cb(void) | 1463 | static void timer_cb(void) |
1404 | { | 1464 | { |
1405 | #if LCD_DEPTH != 24 | 1465 | #if LCD_DEPTH != 24 |
1406 | if(settings.timerflash) | 1466 | if(debug_settings.timerflash) |
1407 | { | 1467 | { |
1408 | static bool what = false; | 1468 | static bool what = false; |
1409 | what = !what; | 1469 | what = !what; |
@@ -1416,7 +1476,7 @@ static void timer_cb(void) | |||
1416 | #endif | 1476 | #endif |
1417 | 1477 | ||
1418 | LOGF("timer callback"); | 1478 | LOGF("timer callback"); |
1419 | midend_timer(me, ((float)(*rb->current_tick - last_tstamp) / (float)HZ) / settings.slowmo_factor); | 1479 | midend_timer(me, ((float)(*rb->current_tick - last_tstamp) / (float)HZ) / debug_settings.slowmo_factor); |
1420 | last_tstamp = *rb->current_tick; | 1480 | last_tstamp = *rb->current_tick; |
1421 | } | 1481 | } |
1422 | 1482 | ||
@@ -1440,12 +1500,27 @@ void frontend_default_color(frontend *fe, float *out) | |||
1440 | 1500 | ||
1441 | /** frontend code -- mostly UI stuff **/ | 1501 | /** frontend code -- mostly UI stuff **/ |
1442 | 1502 | ||
1443 | /* set do_pausemenu to false to just return -1 on BTN_PAUSE and do | 1503 | static void send_click(int button, bool release) |
1444 | * nothing else. */ | 1504 | { |
1505 | int x = (zoom_enabled ? zoom_x : 0) + mouse_x, | ||
1506 | y = (zoom_enabled ? zoom_y : 0) + mouse_y; | ||
1507 | assert(LEFT_BUTTON + 6 == LEFT_RELEASE); | ||
1508 | |||
1509 | midend_process_key(me, x, y, button); | ||
1510 | |||
1511 | if(release) | ||
1512 | midend_process_key(me, x, y, button + 6); | ||
1513 | } | ||
1514 | |||
1515 | /* This function handles most user input. It has specific workarounds | ||
1516 | * and fixes for certain games to allow them to work well on | ||
1517 | * Rockbox. It will either return a positive value that can be passed | ||
1518 | * to the midend, or a negative flag value. Set do_pausemenu to false | ||
1519 | * to just return -1 on BTN_PAUSE and do nothing else. */ | ||
1445 | static int process_input(int tmo, bool do_pausemenu) | 1520 | static int process_input(int tmo, bool do_pausemenu) |
1446 | { | 1521 | { |
1447 | LOGF("process_input start"); | 1522 | LOGF("process_input start"); |
1448 | LOGF("------------------"); | 1523 | LOGF("-------------------"); |
1449 | int state = 0; | 1524 | int state = 0; |
1450 | 1525 | ||
1451 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 1526 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
@@ -1457,13 +1532,24 @@ static int process_input(int tmo, bool do_pausemenu) | |||
1457 | /* weird stuff */ | 1532 | /* weird stuff */ |
1458 | exit_on_usb(button); | 1533 | exit_on_usb(button); |
1459 | 1534 | ||
1460 | /* these games require a second input on long-press */ | 1535 | /* See if the button is a long-press. */ |
1461 | if(accept_input && (button == (BTN_FIRE | BUTTON_REPEAT)) && | 1536 | if(accept_input && (button == (BTN_FIRE | BUTTON_REPEAT))) |
1462 | (strcmp("Mines", midend_which_game(me)->name) != 0 || | ||
1463 | strcmp("Magnets", midend_which_game(me)->name) != 0)) | ||
1464 | { | 1537 | { |
1538 | LOGF("button is long-press, ignoring subsequent input until release"); | ||
1539 | /* Ignore repeated long presses. */ | ||
1465 | accept_input = false; | 1540 | accept_input = false; |
1466 | return ' '; | 1541 | |
1542 | if(mouse_mode && input_settings.rclick_on_hold) | ||
1543 | { | ||
1544 | /* simulate right-click */ | ||
1545 | LOGF("sending right click"); | ||
1546 | send_click(RIGHT_BUTTON, true); | ||
1547 | return 0; | ||
1548 | } | ||
1549 | |||
1550 | /* These games want a spacebar in this event. */ | ||
1551 | if(!mouse_mode && input_settings.want_spacebar) | ||
1552 | return ' '; | ||
1467 | } | 1553 | } |
1468 | 1554 | ||
1469 | button = rb->button_status(); | 1555 | button = rb->button_status(); |
@@ -1476,7 +1562,6 @@ static int process_input(int tmo, bool do_pausemenu) | |||
1476 | { | 1562 | { |
1477 | if(do_pausemenu) | 1563 | if(do_pausemenu) |
1478 | { | 1564 | { |
1479 | want_redraw = false; | ||
1480 | /* quick hack to preserve the clipping state */ | 1565 | /* quick hack to preserve the clipping state */ |
1481 | bool orig_clipped = clipped; | 1566 | bool orig_clipped = clipped; |
1482 | if(orig_clipped) | 1567 | if(orig_clipped) |
@@ -1496,13 +1581,99 @@ static int process_input(int tmo, bool do_pausemenu) | |||
1496 | return -1; | 1581 | return -1; |
1497 | } | 1582 | } |
1498 | 1583 | ||
1499 | /* these games require, for one reason or another, that events | 1584 | /* Mouse movement (if enabled). This goes here since none of the |
1585 | * following code is needed for mouse mode. */ | ||
1586 | if(mouse_mode) | ||
1587 | { | ||
1588 | if(button & BTN_UP) | ||
1589 | state = CURSOR_UP; | ||
1590 | else if(button & BTN_DOWN) | ||
1591 | state = CURSOR_DOWN; | ||
1592 | else if(button & BTN_LEFT) | ||
1593 | state = CURSOR_LEFT; | ||
1594 | else if(button & BTN_RIGHT) | ||
1595 | state = CURSOR_RIGHT; | ||
1596 | |||
1597 | unsigned released = ~button & last_keystate, | ||
1598 | pressed = button & ~last_keystate; | ||
1599 | |||
1600 | last_keystate = button; | ||
1601 | |||
1602 | /* rclick on hold requires that we fire left-click on a | ||
1603 | * release, otherwise it's impossible to distinguish the | ||
1604 | * two. */ | ||
1605 | if(input_settings.rclick_on_hold) | ||
1606 | { | ||
1607 | if(accept_input && released == BTN_FIRE) | ||
1608 | { | ||
1609 | LOGF("sending left click"); | ||
1610 | send_click(LEFT_BUTTON, true); /* right-click is handled earlier */ | ||
1611 | } | ||
1612 | } | ||
1613 | else | ||
1614 | { | ||
1615 | if(pressed & BTN_FIRE) | ||
1616 | send_click(LEFT_BUTTON, false); | ||
1617 | else if(released & BTN_FIRE) | ||
1618 | send_click(LEFT_RELEASE, false); | ||
1619 | else if(button & BTN_FIRE) | ||
1620 | send_click(LEFT_DRAG, false); | ||
1621 | } | ||
1622 | |||
1623 | static int last_mousedir = 0, held_count = 0, v = 0; | ||
1624 | |||
1625 | /* acceleration */ | ||
1626 | if(state && state == last_mousedir) | ||
1627 | { | ||
1628 | if(++held_count % 5 == 0 && v < 15) | ||
1629 | v++; | ||
1630 | } | ||
1631 | else | ||
1632 | { | ||
1633 | if(!button) | ||
1634 | { | ||
1635 | LOGF("all keys released, accepting further input"); | ||
1636 | accept_input = true; | ||
1637 | } | ||
1638 | last_mousedir = state; | ||
1639 | v = 1; | ||
1640 | held_count = 0; | ||
1641 | } | ||
1642 | |||
1643 | /* get the direction vector the cursor is moving in. */ | ||
1644 | int new_x = mouse_x, new_y = mouse_y; | ||
1645 | |||
1646 | /* in src/misc.c */ | ||
1647 | move_cursor(state, &new_x, &new_y, LCD_WIDTH, LCD_HEIGHT, FALSE); | ||
1648 | |||
1649 | int dx = new_x - mouse_x, dy = new_y - mouse_y; | ||
1650 | |||
1651 | mouse_x += dx * v; | ||
1652 | mouse_y += dy * v; | ||
1653 | |||
1654 | /* The % operator with negative operands is messy; this is much | ||
1655 | * simpler. */ | ||
1656 | if(mouse_x < 0) | ||
1657 | mouse_x = 0; | ||
1658 | if(mouse_y < 0) | ||
1659 | mouse_y = 0; | ||
1660 | |||
1661 | if(mouse_x >= LCD_WIDTH) | ||
1662 | mouse_x = LCD_WIDTH - 1; | ||
1663 | if(mouse_y >= LCD_HEIGHT) | ||
1664 | mouse_y = LCD_HEIGHT - 1; | ||
1665 | |||
1666 | /* no buttons are sent to the midend in mouse mode */ | ||
1667 | return 0; | ||
1668 | } | ||
1669 | |||
1670 | /* These games require, for one reason or another, that events | ||
1500 | * fire upon buttons being released rather than when they are | 1671 | * fire upon buttons being released rather than when they are |
1501 | * pressed */ | 1672 | * pressed. For Inertia, it is because it needs to be able to |
1502 | if(strcmp("Inertia", midend_which_game(me)->name) == 0 || | 1673 | * sense multiple simultaneous keypresses (to move diagonally), |
1503 | strcmp("Mines", midend_which_game(me)->name) == 0 || | 1674 | * and the others require a long press to map to a secondary |
1504 | strcmp("Magnets", midend_which_game(me)->name) == 0 || | 1675 | * "action" key. */ |
1505 | strcmp("Map", midend_which_game(me)->name) == 0) | 1676 | if(input_settings.falling_edge) |
1506 | { | 1677 | { |
1507 | LOGF("received button 0x%08x", button); | 1678 | LOGF("received button 0x%08x", button); |
1508 | 1679 | ||
@@ -1536,8 +1707,8 @@ static int process_input(int tmo, bool do_pausemenu) | |||
1536 | button |= released; | 1707 | button |= released; |
1537 | LOGF("accepting event 0x%08x", button); | 1708 | LOGF("accepting event 0x%08x", button); |
1538 | } | 1709 | } |
1539 | /* default is to ignore repeats except for untangle */ | 1710 | /* Ignore repeats in all games which are not Untangle. */ |
1540 | else if(strcmp("Untangle", midend_which_game(me)->name) != 0) | 1711 | else if(input_settings.ignore_repeats) |
1541 | { | 1712 | { |
1542 | /* start accepting input again after a release */ | 1713 | /* start accepting input again after a release */ |
1543 | if(!button) | 1714 | if(!button) |
@@ -1545,10 +1716,11 @@ static int process_input(int tmo, bool do_pausemenu) | |||
1545 | accept_input = true; | 1716 | accept_input = true; |
1546 | return 0; | 1717 | return 0; |
1547 | } | 1718 | } |
1548 | /* ignore repeats */ | 1719 | |
1549 | /* Untangle gets special treatment */ | 1720 | /* ignore repeats (in mouse mode, only ignore repeats of BTN_FIRE) */ |
1550 | if(!accept_input) | 1721 | if(!accept_input) |
1551 | return 0; | 1722 | return 0; |
1723 | |||
1552 | accept_input = false; | 1724 | accept_input = false; |
1553 | } | 1725 | } |
1554 | 1726 | ||
@@ -1604,7 +1776,7 @@ static int process_input(int tmo, bool do_pausemenu) | |||
1604 | break; | 1776 | break; |
1605 | } | 1777 | } |
1606 | 1778 | ||
1607 | if(settings.shortcuts) | 1779 | if(debug_settings.shortcuts) |
1608 | { | 1780 | { |
1609 | static bool shortcuts_ok = true; | 1781 | static bool shortcuts_ok = true; |
1610 | switch(button) | 1782 | switch(button) |
@@ -1665,9 +1837,9 @@ static void zoom(void) | |||
1665 | /* draws go to the zoom framebuffer */ | 1837 | /* draws go to the zoom framebuffer */ |
1666 | midend_force_redraw(me); | 1838 | midend_force_redraw(me); |
1667 | 1839 | ||
1668 | int x = 0, y = 0; | 1840 | zoom_x = zoom_y = 0; |
1669 | 1841 | ||
1670 | rb->lcd_bitmap_part(zoom_fb, x, y, STRIDE(SCREEN_MAIN, zoom_w, zoom_h), | 1842 | rb->lcd_bitmap_part(zoom_fb, zoom_x, zoom_y, STRIDE(SCREEN_MAIN, zoom_w, zoom_h), |
1671 | 0, 0, LCD_WIDTH, LCD_HEIGHT); | 1843 | 0, 0, LCD_WIDTH, LCD_HEIGHT); |
1672 | 1844 | ||
1673 | draw_title(false); /* false since we don't want to use more screen space than we need. */ | 1845 | draw_title(false); /* false since we don't want to use more screen space than we need. */ |
@@ -1693,16 +1865,16 @@ static void zoom(void) | |||
1693 | switch(button) | 1865 | switch(button) |
1694 | { | 1866 | { |
1695 | case BTN_UP: | 1867 | case BTN_UP: |
1696 | y -= PAN_Y; /* clamped later */ | 1868 | zoom_y -= PAN_Y; /* clamped later */ |
1697 | break; | 1869 | break; |
1698 | case BTN_DOWN: | 1870 | case BTN_DOWN: |
1699 | y += PAN_Y; /* clamped later */ | 1871 | zoom_y += PAN_Y; /* clamped later */ |
1700 | break; | 1872 | break; |
1701 | case BTN_LEFT: | 1873 | case BTN_LEFT: |
1702 | x -= PAN_X; /* clamped later */ | 1874 | zoom_x -= PAN_X; /* clamped later */ |
1703 | break; | 1875 | break; |
1704 | case BTN_RIGHT: | 1876 | case BTN_RIGHT: |
1705 | x += PAN_X; /* clamped later */ | 1877 | zoom_x += PAN_X; /* clamped later */ |
1706 | break; | 1878 | break; |
1707 | case BTN_PAUSE: | 1879 | case BTN_PAUSE: |
1708 | zoom_enabled = false; | 1880 | zoom_enabled = false; |
@@ -1716,15 +1888,15 @@ static void zoom(void) | |||
1716 | break; | 1888 | break; |
1717 | } | 1889 | } |
1718 | 1890 | ||
1719 | if(y < 0) | 1891 | if(zoom_y < 0) |
1720 | y = 0; | 1892 | zoom_y = 0; |
1721 | if(x < 0) | 1893 | if(zoom_x < 0) |
1722 | x = 0; | 1894 | zoom_x = 0; |
1723 | 1895 | ||
1724 | if(y + LCD_HEIGHT >= zoom_h) | 1896 | if(zoom_y + LCD_HEIGHT >= zoom_h) |
1725 | y = zoom_h - LCD_HEIGHT; | 1897 | zoom_y = zoom_h - LCD_HEIGHT; |
1726 | if(x + LCD_WIDTH >= zoom_w) | 1898 | if(zoom_x + LCD_WIDTH >= zoom_w) |
1727 | x = zoom_w - LCD_WIDTH; | 1899 | zoom_x = zoom_w - LCD_WIDTH; |
1728 | 1900 | ||
1729 | if(timer_on) | 1901 | if(timer_on) |
1730 | timer_cb(); | 1902 | timer_cb(); |
@@ -1732,7 +1904,7 @@ static void zoom(void) | |||
1732 | /* goes to zoom_fb */ | 1904 | /* goes to zoom_fb */ |
1733 | midend_redraw(me); | 1905 | midend_redraw(me); |
1734 | 1906 | ||
1735 | rb->lcd_bitmap_part(zoom_fb, x, y, STRIDE(SCREEN_MAIN, zoom_w, zoom_h), | 1907 | rb->lcd_bitmap_part(zoom_fb, zoom_x, zoom_y, STRIDE(SCREEN_MAIN, zoom_w, zoom_h), |
1736 | 0, 0, LCD_WIDTH, LCD_HEIGHT); | 1908 | 0, 0, LCD_WIDTH, LCD_HEIGHT); |
1737 | draw_title(false); | 1909 | draw_title(false); |
1738 | rb->lcd_update(); | 1910 | rb->lcd_update(); |
@@ -1755,13 +1927,26 @@ static void zoom(void) | |||
1755 | if(timer_on) | 1927 | if(timer_on) |
1756 | timer_cb(); | 1928 | timer_cb(); |
1757 | 1929 | ||
1758 | if(want_redraw) | 1930 | midend_redraw(me); |
1759 | midend_redraw(me); | ||
1760 | 1931 | ||
1761 | rb->lcd_bitmap_part(zoom_fb, x, y, STRIDE(SCREEN_MAIN, zoom_w, zoom_h), | 1932 | /* blit */ |
1933 | rb->lcd_bitmap_part(zoom_fb, zoom_x, zoom_y, STRIDE(SCREEN_MAIN, zoom_w, zoom_h), | ||
1762 | 0, 0, LCD_WIDTH, LCD_HEIGHT); | 1934 | 0, 0, LCD_WIDTH, LCD_HEIGHT); |
1935 | |||
1763 | draw_title(false); | 1936 | draw_title(false); |
1937 | |||
1938 | /* The cursor is always in screenspace coordinates; when | ||
1939 | * zoomed, this means the mouse is always restricted to | ||
1940 | * the bounds of the physical display, not the virtual | ||
1941 | * zoom framebuffer. */ | ||
1942 | if(mouse_mode) | ||
1943 | draw_mouse(); | ||
1944 | |||
1764 | rb->lcd_update(); | 1945 | rb->lcd_update(); |
1946 | |||
1947 | if(mouse_mode) | ||
1948 | clear_mouse(); | ||
1949 | |||
1765 | rb->yield(); | 1950 | rb->yield(); |
1766 | } | 1951 | } |
1767 | } | 1952 | } |
@@ -2202,12 +2387,12 @@ static void full_help(const char *name) | |||
2202 | 2387 | ||
2203 | static void init_default_settings(void) | 2388 | static void init_default_settings(void) |
2204 | { | 2389 | { |
2205 | settings.slowmo_factor = 1; | 2390 | debug_settings.slowmo_factor = 1; |
2206 | settings.timerflash = false; | 2391 | debug_settings.timerflash = false; |
2207 | settings.clipoff = false; | 2392 | debug_settings.clipoff = false; |
2208 | settings.shortcuts = false; | 2393 | debug_settings.shortcuts = false; |
2209 | settings.no_aa = false; | 2394 | debug_settings.no_aa = false; |
2210 | settings.polyanim = false; | 2395 | debug_settings.polyanim = false; |
2211 | } | 2396 | } |
2212 | 2397 | ||
2213 | #ifdef DEBUG_MENU | 2398 | #ifdef DEBUG_MENU |
@@ -2250,6 +2435,11 @@ static void debug_menu(void) | |||
2250 | "Toggle antialias", | 2435 | "Toggle antialias", |
2251 | "Benchmark antialias", | 2436 | "Benchmark antialias", |
2252 | "Toggle show poly steps", | 2437 | "Toggle show poly steps", |
2438 | "Toggle mouse mode", | ||
2439 | "Toggle spacebar on long click", | ||
2440 | "Toggle send keys on release", | ||
2441 | "Toggle ignore repeats", | ||
2442 | "Toggle right-click on hold vs. dragging", | ||
2253 | "Back"); | 2443 | "Back"); |
2254 | bool quit = false; | 2444 | bool quit = false; |
2255 | int sel = 0; | 2445 | int sel = 0; |
@@ -2258,7 +2448,7 @@ static void debug_menu(void) | |||
2258 | switch(rb->do_menu(&menu, &sel, NULL, false)) | 2448 | switch(rb->do_menu(&menu, &sel, NULL, false)) |
2259 | { | 2449 | { |
2260 | case 0: | 2450 | case 0: |
2261 | rb->set_int("Slowmo factor", "", UNIT_INT, &settings.slowmo_factor, NULL, 1, 1, 15, NULL); | 2451 | rb->set_int("Slowmo factor", "", UNIT_INT, &debug_settings.slowmo_factor, NULL, 1, 1, 15, NULL); |
2262 | break; | 2452 | break; |
2263 | case 1: | 2453 | case 1: |
2264 | { | 2454 | { |
@@ -2271,24 +2461,38 @@ static void debug_menu(void) | |||
2271 | break; | 2461 | break; |
2272 | } | 2462 | } |
2273 | case 2: | 2463 | case 2: |
2274 | settings.timerflash = !settings.timerflash; | 2464 | debug_settings.timerflash = !debug_settings.timerflash; |
2275 | break; | 2465 | break; |
2276 | case 3: | 2466 | case 3: |
2277 | settings.clipoff = !settings.clipoff; | 2467 | debug_settings.clipoff = !debug_settings.clipoff; |
2278 | break; | 2468 | break; |
2279 | case 4: | 2469 | case 4: |
2280 | settings.shortcuts = !settings.shortcuts; | 2470 | debug_settings.shortcuts = !debug_settings.shortcuts; |
2281 | break; | 2471 | break; |
2282 | case 5: | 2472 | case 5: |
2283 | settings.no_aa = !settings.no_aa; | 2473 | debug_settings.no_aa = !debug_settings.no_aa; |
2284 | break; | 2474 | break; |
2285 | case 6: | 2475 | case 6: |
2286 | bench_aa(); | 2476 | bench_aa(); |
2287 | break; | 2477 | break; |
2288 | case 7: | 2478 | case 7: |
2289 | settings.polyanim = !settings.polyanim; | 2479 | debug_settings.polyanim = !debug_settings.polyanim; |
2290 | break; | 2480 | break; |
2291 | case 8: | 2481 | case 8: |
2482 | mouse_mode = !mouse_mode; | ||
2483 | break; | ||
2484 | case 9: | ||
2485 | input_settings.want_spacebar = !input_settings.want_spacebar; | ||
2486 | break; | ||
2487 | case 10: | ||
2488 | input_settings.falling_edge = !input_settings.falling_edge; | ||
2489 | break; | ||
2490 | case 11: | ||
2491 | input_settings.ignore_repeats = !input_settings.ignore_repeats; | ||
2492 | break; | ||
2493 | case 12: | ||
2494 | input_settings.rclick_on_hold = !input_settings.rclick_on_hold; | ||
2495 | break; | ||
2292 | default: | 2496 | default: |
2293 | quit = true; | 2497 | quit = true; |
2294 | break; | 2498 | break; |
@@ -2316,8 +2520,6 @@ static int pausemenu_cb(int action, const struct menu_item_ex *this_item) | |||
2316 | if(!midend_which_game(me)->can_solve) | 2520 | if(!midend_which_game(me)->can_solve) |
2317 | return ACTION_EXIT_MENUITEM; | 2521 | return ACTION_EXIT_MENUITEM; |
2318 | break; | 2522 | break; |
2319 | case 7: | ||
2320 | break; | ||
2321 | case 9: | 2523 | case 9: |
2322 | if(audiobuf_available) | 2524 | if(audiobuf_available) |
2323 | break; | 2525 | break; |
@@ -2349,10 +2551,18 @@ static int pausemenu_cb(int action, const struct menu_item_ex *this_item) | |||
2349 | static void clear_and_draw(void) | 2551 | static void clear_and_draw(void) |
2350 | { | 2552 | { |
2351 | rb->lcd_clear_display(); | 2553 | rb->lcd_clear_display(); |
2352 | rb->lcd_update(); | ||
2353 | 2554 | ||
2354 | midend_force_redraw(me); | 2555 | midend_force_redraw(me); |
2556 | |||
2355 | draw_title(true); | 2557 | draw_title(true); |
2558 | |||
2559 | if(mouse_mode) | ||
2560 | draw_mouse(); | ||
2561 | |||
2562 | rb->lcd_update(); | ||
2563 | |||
2564 | if(mouse_mode) | ||
2565 | clear_mouse(); | ||
2356 | } | 2566 | } |
2357 | 2567 | ||
2358 | static void reset_drawing(void) | 2568 | static void reset_drawing(void) |
@@ -2482,8 +2692,8 @@ static int pause_menu(void) | |||
2482 | } | 2692 | } |
2483 | rb->lcd_set_background(BG_COLOR); | 2693 | rb->lcd_set_background(BG_COLOR); |
2484 | rb->lcd_clear_display(); | 2694 | rb->lcd_clear_display(); |
2485 | rb->lcd_update(); | ||
2486 | midend_force_redraw(me); | 2695 | midend_force_redraw(me); |
2696 | rb->lcd_update(); | ||
2487 | return 0; | 2697 | return 0; |
2488 | } | 2698 | } |
2489 | 2699 | ||
@@ -2542,6 +2752,72 @@ static void init_colors(void) | |||
2542 | sfree(floatcolors); | 2752 | sfree(floatcolors); |
2543 | } | 2753 | } |
2544 | 2754 | ||
2755 | static bool string_in_list(const char *target, const char **list) | ||
2756 | { | ||
2757 | /* list is terminated with NULL */ | ||
2758 | const char *i; | ||
2759 | |||
2760 | while((i = *list++)) | ||
2761 | { | ||
2762 | if(!strcmp(target, i)) | ||
2763 | return true; | ||
2764 | } | ||
2765 | |||
2766 | return false; | ||
2767 | } | ||
2768 | |||
2769 | static void tune_input(const char *name) | ||
2770 | { | ||
2771 | /* game-specific stuff */ | ||
2772 | |||
2773 | static const char *want_spacebar[] = { | ||
2774 | "Magnets", | ||
2775 | "Mines", | ||
2776 | "Palisade", | ||
2777 | NULL | ||
2778 | }; | ||
2779 | |||
2780 | /* these get a spacebar on long click */ | ||
2781 | input_settings.want_spacebar = string_in_list(name, want_spacebar); | ||
2782 | |||
2783 | static const char *falling_edge[] = { | ||
2784 | "Inertia", | ||
2785 | "Magnets", | ||
2786 | "Map", | ||
2787 | "Mines", | ||
2788 | "Palisade", | ||
2789 | NULL | ||
2790 | }; | ||
2791 | |||
2792 | /* wait until a key is released to send an action */ | ||
2793 | input_settings.falling_edge = string_in_list(name, falling_edge); | ||
2794 | |||
2795 | /* in all games but untangle (mouse mode overrides this) */ | ||
2796 | static const char *ignore_repeats[] = { | ||
2797 | "Untangle", | ||
2798 | NULL | ||
2799 | }; | ||
2800 | |||
2801 | input_settings.ignore_repeats = !string_in_list(name, falling_edge); | ||
2802 | |||
2803 | /* set to false if you want dragging to be possible */ | ||
2804 | static const char *rclick_on_hold[] = { | ||
2805 | "Map", | ||
2806 | "Signpost", | ||
2807 | "Untangle", | ||
2808 | NULL | ||
2809 | }; | ||
2810 | |||
2811 | input_settings.rclick_on_hold = !string_in_list(name, falling_edge); | ||
2812 | |||
2813 | static const char *mouse_games[] = { | ||
2814 | "Loopy", | ||
2815 | NULL | ||
2816 | }; | ||
2817 | |||
2818 | mouse_mode = string_in_list(name, mouse_games); | ||
2819 | } | ||
2820 | |||
2545 | static const char *init_for_game(const game *gm, int load_fd, bool draw) | 2821 | static const char *init_for_game(const game *gm, int load_fd, bool draw) |
2546 | { | 2822 | { |
2547 | me = midend_new(NULL, gm, &rb_drawing, NULL); | 2823 | me = midend_new(NULL, gm, &rb_drawing, NULL); |
@@ -2555,6 +2831,11 @@ static const char *init_for_game(const game *gm, int load_fd, bool draw) | |||
2555 | return ret; | 2831 | return ret; |
2556 | } | 2832 | } |
2557 | 2833 | ||
2834 | tune_input(gm->name); | ||
2835 | |||
2836 | mouse_x = LCD_WIDTH / 2; | ||
2837 | mouse_y = LCD_HEIGHT / 2; | ||
2838 | |||
2558 | fix_size(); | 2839 | fix_size(); |
2559 | 2840 | ||
2560 | init_colors(); | 2841 | init_colors(); |
@@ -2845,12 +3126,6 @@ enum plugin_status plugin_start(const void *param) | |||
2845 | 3126 | ||
2846 | init_tlsf(); | 3127 | init_tlsf(); |
2847 | 3128 | ||
2848 | /* sanity check */ | ||
2849 | if(fabs(sqrt(3)/2 - sin(PI/3)) > .01) | ||
2850 | { | ||
2851 | return PLUGIN_ERROR; | ||
2852 | } | ||
2853 | |||
2854 | init_default_settings(); | 3129 | init_default_settings(); |
2855 | 3130 | ||
2856 | init_fonttab(); | 3131 | init_fonttab(); |
@@ -2964,12 +3239,6 @@ enum plugin_status plugin_start(const void *param) | |||
2964 | game_loop: | 3239 | game_loop: |
2965 | while(1) | 3240 | while(1) |
2966 | { | 3241 | { |
2967 | want_redraw = true; | ||
2968 | |||
2969 | int theight = get_titleheight(); | ||
2970 | draw_title(true); | ||
2971 | rb->lcd_update_rect(0, LCD_HEIGHT - theight, LCD_WIDTH, theight); | ||
2972 | |||
2973 | int button = process_input(timer_on ? TIMER_INTERVAL : -1, true); | 3242 | int button = process_input(timer_on ? TIMER_INTERVAL : -1, true); |
2974 | 3243 | ||
2975 | if(button < 0) | 3244 | if(button < 0) |
@@ -3008,16 +3277,20 @@ enum plugin_status plugin_start(const void *param) | |||
3008 | if(button) | 3277 | if(button) |
3009 | midend_process_key(me, 0, 0, button); | 3278 | midend_process_key(me, 0, 0, button); |
3010 | 3279 | ||
3280 | if(timer_on) | ||
3281 | timer_cb(); | ||
3282 | |||
3283 | midend_redraw(me); | ||
3284 | |||
3011 | draw_title(true); /* will draw to fb */ | 3285 | draw_title(true); /* will draw to fb */ |
3012 | 3286 | ||
3013 | if(want_redraw) | 3287 | if(mouse_mode) |
3014 | midend_redraw(me); | 3288 | draw_mouse(); |
3015 | 3289 | ||
3016 | /* push title to screen as well */ | 3290 | rb->lcd_update(); |
3017 | rb->lcd_update_rect(0, LCD_HEIGHT - theight, LCD_WIDTH, theight); | ||
3018 | 3291 | ||
3019 | if(timer_on) | 3292 | if(mouse_mode) |
3020 | timer_cb(); | 3293 | clear_mouse(); |
3021 | 3294 | ||
3022 | rb->yield(); | 3295 | rb->yield(); |
3023 | } | 3296 | } |