summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
authorFranklin Wei <franklin@rockbox.org>2024-08-11 23:34:57 -0400
committerFranklin Wei <franklin@rockbox.org>2024-08-16 16:31:28 -0400
commitea0e3704a8aacf87f20ba87e3b33bc4b3966c731 (patch)
tree8db0a329800cffd661f6a80767ce2f956eb57ab8 /apps/plugins
parent903e8c5b32285e50907e6525388162bd459cbef8 (diff)
downloadrockbox-ea0e3704a8aacf87f20ba87e3b33bc4b3966c731.tar.gz
rockbox-ea0e3704a8aacf87f20ba87e3b33bc4b3966c731.zip
puzzles: resync with upstream 262f709.
This is the first resync with a fully unmodified upstream repo. This includes a new scanline polygon renderer in the upstream puzzles distribution. This allows us to get rid of the monstrosity of a polygon renderer we had been shipping in rockbox.c. Change-Id: I23628c74bb5ff7a9e7932bf16d68a1c867c49969
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/puzzles/README.rockbox26
-rw-r--r--apps/plugins/puzzles/SOURCES1
-rw-r--r--apps/plugins/puzzles/help/tracks.c274
-rw-r--r--apps/plugins/puzzles/rockbox.c379
-rw-r--r--apps/plugins/puzzles/src/CMakeLists.txt10
-rw-r--r--apps/plugins/puzzles/src/draw-poly.c302
-rw-r--r--apps/plugins/puzzles/src/drawing.c196
-rw-r--r--apps/plugins/puzzles/src/inertia.c21
-rw-r--r--apps/plugins/puzzles/src/mines.c12
-rw-r--r--apps/plugins/puzzles/src/misc.c11
-rw-r--r--apps/plugins/puzzles/src/puzzles.but20
-rw-r--r--apps/plugins/puzzles/src/puzzles.h88
-rw-r--r--apps/plugins/puzzles/src/signpost.c5
-rw-r--r--apps/plugins/puzzles/src/twiddle.c14
-rw-r--r--apps/plugins/puzzles/src/unequal.c24
15 files changed, 700 insertions, 683 deletions
diff --git a/apps/plugins/puzzles/README.rockbox b/apps/plugins/puzzles/README.rockbox
index 117383eacb..c7ecc540a1 100644
--- a/apps/plugins/puzzles/README.rockbox
+++ b/apps/plugins/puzzles/README.rockbox
@@ -4,11 +4,6 @@ Introduction
4This is the readme for the Rockbox port of Simon Tatham's Portable 4This is the readme for the Rockbox port of Simon Tatham's Portable
5Puzzle Collection. 5Puzzle Collection.
6 6
7The upstream version used is subject to change, as it should be
8relatively trivial to update it to a newer version. Simply copying the
9upstream repo's contents into src/ and running genhelp.sh ought to do
10it (watch out for API changes, though!).
11
12Source structure 7Source structure
13================ 8================
14 9
@@ -44,16 +39,8 @@ to Untangle and Palisade). These divergent changes complicated
44maintenance of this port, as merge conflicts often arose when upstream 39maintenance of this port, as merge conflicts often arose when upstream
45changes to these games conflicted with our changes. To remedy this, I 40changes to these games conflicted with our changes. To remedy this, I
46sent most of these patches back upstream in summer 2024, and since 41sent most of these patches back upstream in summer 2024, and since
47then, Simon has merged the majority of them into his tree. 42then, Simon has merged them into his repo. We are now able to run with
48 43a fully unmodified puzzles source tree.
49This leaves us with a very small set of places where our branch of the
50puzzles source diverges from Simon's. That branch lives here:
51
52https://github.com/built1n/puzzles/tree/rockbox-devel
53
54Notably, there are several hacks which work around Rockbox's lack of a
55proper polygon filling algorithm. Eliminating this deficiency would
56enable us to use a totally unmodified upstream source tree.
57 44
58Maintenance 45Maintenance
59=========== 46===========
@@ -62,7 +49,7 @@ Simon's upstream tree sees continued development. The port is
62structured so that integrating new upstream versions is 49structured so that integrating new upstream versions is
63straightforward: all the upstream sources live in the src/ 50straightforward: all the upstream sources live in the src/
64subdirectory; all of the Rockbox frontend lives in the root 51subdirectory; all of the Rockbox frontend lives in the root
65apps/pluginspuzzles/ directory. 52apps/plugins/puzzles/ directory.
66 53
67The `resync.sh' shell script automates the resyncing process. It 54The `resync.sh' shell script automates the resyncing process. It
68copies the upstream sources (point it to a local copy of the 55copies the upstream sources (point it to a local copy of the
@@ -77,9 +64,7 @@ The LZ4 library and GCC are necessary as well.
77Wishlist 64Wishlist
78======== 65========
79 66
80- Proper polygon filling algorithm. The current algorithm is a hack 67- Nothing!
81 that uses overdrawn triangles. This will enable us to eliminate the
82 last of the Rockbox-specific modifications.
83 68
84Kudos to Simon (duh), and Frank, for telling me about it. 69Kudos to Simon (duh), and Frank, for telling me about it.
85 70
@@ -120,3 +105,6 @@ Implement user preferences menu. Introduced "Mosaic".
120 105
121August 2024: Resync to ee5e327 (branched from Simon's 106August 2024: Resync to ee5e327 (branched from Simon's
1221c1899e). Changes default Map stipple size to "Small". 1071c1899e). Changes default Map stipple size to "Small".
108
109August 2024: Resync to Simon's 262f709 (unmodified). Uses new scanline
110polygon filling algorithm. Updates drawing API.
diff --git a/apps/plugins/puzzles/SOURCES b/apps/plugins/puzzles/SOURCES
index 6fd787b3f1..f0d2ed27f7 100644
--- a/apps/plugins/puzzles/SOURCES
+++ b/apps/plugins/puzzles/SOURCES
@@ -7,6 +7,7 @@ lz4tiny.c
7/* puzzles core sources */ 7/* puzzles core sources */
8src/combi.c 8src/combi.c
9src/divvy.c 9src/divvy.c
10src/draw-poly.c
10src/drawing.c 11src/drawing.c
11src/dsf.c 12src/dsf.c
12src/findloop.c 13src/findloop.c
diff --git a/apps/plugins/puzzles/help/tracks.c b/apps/plugins/puzzles/help/tracks.c
index 752b9dd457..c088145a09 100644
--- a/apps/plugins/puzzles/help/tracks.c
+++ b/apps/plugins/puzzles/help/tracks.c
@@ -6,148 +6,148 @@
6 6
7struct style_text help_text_style[] = { 7struct style_text help_text_style[] = {
8 { 0, TEXT_CENTER | C_RED }, 8 { 0, TEXT_CENTER | C_RED },
9 { 88, TEXT_CENTER | C_RED }, 9 { 87, TEXT_CENTER | C_RED },
10 { 209, TEXT_CENTER | C_RED }, 10 { 208, TEXT_CENTER | C_RED },
11 { 225, TEXT_UNDERLINE },
11 { 226, TEXT_UNDERLINE }, 12 { 226, TEXT_UNDERLINE },
12 { 227, TEXT_UNDERLINE }, 13 { 237, TEXT_UNDERLINE },
13 { 238, TEXT_UNDERLINE }, 14 { 269, TEXT_UNDERLINE },
14 { 270, TEXT_UNDERLINE },
15 LAST_STYLE_ITEM 15 LAST_STYLE_ITEM
16}; 16};
17 17
18/* orig 1917 comp 1289 ratio 0.672405 level 10 saved 628 */ 18/* orig 1881 comp 1282 ratio 0.681552 level 10 saved 599 */
19const char help_text[] = { 19const char help_text[] = {
200xf0, 0x02, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20, 200xfd, 0x06, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
210x34, 0x30, 0x3a, 0x20, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x06, 210x34, 0x30, 0x3a, 0x20, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x73,
220x00, 0x6f, 0x63, 0x6b, 0x73, 0x20, 0x00, 0x2d, 0x01, 0x00, 220x20, 0x00, 0x2d, 0x01, 0x00, 0xf0, 0x19, 0x00, 0x00, 0x00,
230x04, 0xf0, 0x19, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00, 230x59, 0x6f, 0x75, 0x00, 0x61, 0x72, 0x65, 0x00, 0x67, 0x69,
240x61, 0x72, 0x65, 0x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x00, 240x76, 0x65, 0x6e, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64,
250x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00, 250x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65,
260x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 0x73, 260x73, 0x2c, 0x00, 0x73, 0x6f, 0x6d, 0x65, 0x11, 0x00, 0x51,
270x6f, 0x6d, 0x65, 0x11, 0x00, 0x51, 0x77, 0x68, 0x69, 0x63, 270x77, 0x68, 0x69, 0x63, 0x68, 0x2b, 0x00, 0xf1, 0x04, 0x66,
280x68, 0x2b, 0x00, 0xd0, 0x66, 0x69, 0x6c, 0x6c, 0x65, 0x64, 280x69, 0x6c, 0x6c, 0x65, 0x64, 0x00, 0x77, 0x69, 0x74, 0x68,
290x00, 0x77, 0x69, 0x74, 0x68, 0x00, 0x74, 0x68, 0x00, 0x21, 290x00, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x00, 0x74, 0x62, 0x00,
300x00, 0x74, 0x68, 0x00, 0x11, 0x2e, 0x4d, 0x00, 0xf2, 0x05, 300x11, 0x2e, 0x4d, 0x00, 0xf2, 0x05, 0x6e, 0x65, 0x65, 0x64,
310x6e, 0x65, 0x65, 0x64, 0x00, 0x74, 0x6f, 0x00, 0x63, 0x6f, 310x00, 0x74, 0x6f, 0x00, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65,
320x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x00, 0x74, 0x68, 0x65, 320x74, 0x65, 0x00, 0x74, 0x68, 0x65, 0x21, 0x00, 0x70, 0x00,
330x21, 0x00, 0x70, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x00, 0x41, 330x66, 0x72, 0x6f, 0x6d, 0x00, 0x41, 0x1d, 0x00, 0x91, 0x42,
340x1d, 0x00, 0x91, 0x42, 0x00, 0x73, 0x6f, 0x00, 0x74, 0x68, 340x00, 0x73, 0x6f, 0x00, 0x74, 0x68, 0x61, 0x74, 0x1e, 0x00,
350x61, 0x74, 0x1e, 0x00, 0xf1, 0x06, 0x72, 0x6f, 0x77, 0x73, 350xf1, 0x06, 0x72, 0x6f, 0x77, 0x73, 0x00, 0x61, 0x6e, 0x64,
360x00, 0x61, 0x6e, 0x64, 0x00, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 360x00, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x00, 0x63,
370x6e, 0x73, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x58, 0x00, 0xe0, 370x6f, 0x6e, 0x74, 0x58, 0x00, 0xe0, 0x68, 0x65, 0x00, 0x73,
380x68, 0x65, 0x00, 0x73, 0x61, 0x6d, 0x65, 0x00, 0x6e, 0x75, 380x61, 0x6d, 0x65, 0x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72,
390x6d, 0x62, 0x65, 0x72, 0x87, 0x00, 0x02, 0x4a, 0x00, 0xb1, 390x87, 0x00, 0x02, 0x4a, 0x00, 0xb1, 0x73, 0x65, 0x67, 0x6d,
400x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x00, 0x61, 400x65, 0x6e, 0x74, 0x73, 0x00, 0x61, 0x73, 0x93, 0x00, 0xa3,
410x73, 0x93, 0x00, 0xa3, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 410x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x00,
420x74, 0x65, 0x64, 0x00, 0x36, 0x00, 0x50, 0x63, 0x6c, 0x75, 420x36, 0x00, 0x50, 0x63, 0x6c, 0x75, 0x65, 0x73, 0x6a, 0x00,
430x65, 0x73, 0x6a, 0x00, 0x01, 0x7e, 0x00, 0x21, 0x6f, 0x70, 430x01, 0x7e, 0x00, 0x21, 0x6f, 0x70, 0x5f, 0x00, 0x51, 0x72,
440x5f, 0x00, 0x51, 0x72, 0x69, 0x67, 0x68, 0x74, 0x45, 0x00, 440x69, 0x67, 0x68, 0x74, 0x45, 0x00, 0x21, 0x68, 0x65, 0xe9,
450x21, 0x68, 0x65, 0xe9, 0x00, 0x91, 0x2e, 0x00, 0x00, 0x00, 450x00, 0x91, 0x2e, 0x00, 0x00, 0x00, 0x54, 0x68, 0x65, 0x72,
460x54, 0x68, 0x65, 0x72, 0x65, 0x45, 0x00, 0x60, 0x6f, 0x6e, 460x65, 0x45, 0x00, 0x60, 0x6f, 0x6e, 0x6c, 0x79, 0x00, 0x73,
470x6c, 0x79, 0x00, 0x73, 0xd2, 0x00, 0x00, 0x27, 0x00, 0x00, 470xd2, 0x00, 0x00, 0x27, 0x00, 0x00, 0x31, 0x00, 0xf1, 0x08,
480x31, 0x00, 0xf1, 0x08, 0x39, 0x30, 0x00, 0x64, 0x65, 0x67, 480x39, 0x30, 0x00, 0x64, 0x65, 0x67, 0x72, 0x65, 0x65, 0x00,
490x72, 0x65, 0x65, 0x00, 0x63, 0x75, 0x72, 0x76, 0x65, 0x64, 490x63, 0x75, 0x72, 0x76, 0x65, 0x64, 0x00, 0x72, 0x61, 0x69,
500x00, 0x72, 0x61, 0x69, 0x6c, 0x73, 0x2c, 0x1c, 0x00, 0x06, 500x6c, 0x73, 0x2c, 0x1c, 0x00, 0x06, 0xd7, 0x00, 0xf1, 0x05,
510xd7, 0x00, 0xf1, 0x05, 0x6d, 0x61, 0x79, 0x00, 0x6e, 0x6f, 510x6d, 0x61, 0x79, 0x00, 0x6e, 0x6f, 0x74, 0x00, 0x63, 0x72,
520x74, 0x00, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x00, 0x69, 0x74, 520x6f, 0x73, 0x73, 0x00, 0x69, 0x74, 0x73, 0x65, 0x6c, 0x66,
530x73, 0x65, 0x6c, 0x66, 0x5a, 0x00, 0x01, 0x1c, 0x01, 0x02, 530x5a, 0x00, 0x01, 0x16, 0x01, 0x32, 0x00, 0x77, 0x61, 0xd1,
540x84, 0x01, 0x32, 0x00, 0x77, 0x61, 0xd7, 0x00, 0x40, 0x72, 540x00, 0x40, 0x72, 0x69, 0x62, 0x75, 0xa2, 0x00, 0x01, 0x95,
550x69, 0x62, 0x75, 0xa8, 0x00, 0x01, 0x9b, 0x00, 0x20, 0x69, 550x00, 0x20, 0x69, 0x73, 0xed, 0x00, 0xf0, 0x08, 0x6c, 0x65,
560x73, 0xf3, 0x00, 0xf0, 0x08, 0x6c, 0x65, 0x63, 0x74, 0x69, 560x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x62, 0x79, 0x00, 0x4a,
570x6f, 0x6e, 0x00, 0x62, 0x79, 0x00, 0x4a, 0x61, 0x6d, 0x65, 570x61, 0x6d, 0x65, 0x73, 0x00, 0x48, 0x61, 0x72, 0x76, 0x65,
580x73, 0x00, 0x48, 0x61, 0x72, 0x76, 0x65, 0x79, 0x43, 0x00, 580x79, 0x3d, 0x00, 0x44, 0x34, 0x30, 0x2e, 0x31, 0xba, 0x01,
590x4a, 0x34, 0x30, 0x2e, 0x31, 0xcc, 0x01, 0x01, 0x44, 0x00, 590x01, 0x3e, 0x00, 0xf4, 0x1c, 0x6f, 0x6c, 0x73, 0x20, 0x00,
600xf4, 0x1c, 0x6f, 0x6c, 0x73, 0x20, 0x00, 0x00, 0x00, 0x4c, 600x00, 0x00, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69,
610x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x69, 610x63, 0x6b, 0x69, 0x6e, 0x67, 0x00, 0x6f, 0x6e, 0x00, 0x61,
620x6e, 0x67, 0x00, 0x6f, 0x6e, 0x00, 0x61, 0x6e, 0x00, 0x65, 620x6e, 0x00, 0x65, 0x64, 0x67, 0x65, 0x00, 0x62, 0x65, 0x74,
630x64, 0x67, 0x65, 0x00, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 630x77, 0x65, 0x65, 0x6e, 0x00, 0x74, 0x77, 0x6f, 0xbd, 0x01,
640x6e, 0x00, 0x74, 0x77, 0x6f, 0xc9, 0x01, 0x7a, 0x00, 0x61, 640x7a, 0x00, 0x61, 0x64, 0x64, 0x73, 0x00, 0x61, 0x34, 0x01,
650x64, 0x64, 0x73, 0x00, 0x61, 0x40, 0x01, 0x06, 0x29, 0x00, 650x06, 0x29, 0x00, 0x28, 0x68, 0x65, 0x2d, 0x00, 0x30, 0x2e,
660x28, 0x68, 0x65, 0x2d, 0x00, 0x30, 0x2e, 0x00, 0x52, 0x04, 660x00, 0x52, 0xf8, 0x00, 0x0f, 0x5c, 0x00, 0x02, 0x03, 0x48,
670x01, 0x0f, 0x5c, 0x00, 0x02, 0x03, 0x48, 0x00, 0x02, 0xed, 670x00, 0x02, 0xe1, 0x00, 0x12, 0x6f, 0x3b, 0x00, 0x00, 0x19,
680x00, 0x12, 0x6f, 0x3b, 0x00, 0x00, 0x19, 0x00, 0x14, 0x2c, 680x00, 0x14, 0x2c, 0x79, 0x01, 0x00, 0x30, 0x00, 0x23, 0x6e,
690x85, 0x01, 0x00, 0x30, 0x00, 0x23, 0x6e, 0x6f, 0x69, 0x00, 690x6f, 0x69, 0x00, 0xa1, 0x69, 0x73, 0x00, 0x70, 0x6f, 0x73,
700xa1, 0x69, 0x73, 0x00, 0x70, 0x6f, 0x73, 0x73, 0x69, 0x62, 700x73, 0x69, 0x62, 0x6c, 0xfd, 0x01, 0x3d, 0x72, 0x65, 0x2e,
710x6c, 0x09, 0x02, 0x3d, 0x72, 0x65, 0x2e, 0xb8, 0x00, 0x10, 710xb8, 0x00, 0x10, 0x69, 0x6b, 0x02, 0x02, 0x79, 0x00, 0x05,
720x69, 0x77, 0x02, 0x02, 0x79, 0x00, 0x05, 0x5d, 0x00, 0x54, 720x5d, 0x00, 0x54, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x51, 0x00,
730x6f, 0x6c, 0x6f, 0x75, 0x72, 0x51, 0x00, 0x70, 0x6f, 0x72, 730x70, 0x6f, 0x72, 0x00, 0x73, 0x68, 0x6f, 0x77, 0x2c, 0x00,
740x00, 0x73, 0x68, 0x6f, 0x77, 0x2c, 0x00, 0x01, 0x33, 0x02, 740x01, 0x27, 0x02, 0x82, 0x79, 0x6f, 0x75, 0x00, 0x6b, 0x6e,
750x82, 0x79, 0x6f, 0x75, 0x00, 0x6b, 0x6e, 0x6f, 0x77, 0x1f, 750x6f, 0x77, 0x13, 0x02, 0x02, 0x39, 0x00, 0x45, 0x6d, 0x75,
760x02, 0x02, 0x39, 0x00, 0x45, 0x6d, 0x75, 0x73, 0x74, 0x37, 760x73, 0x74, 0x2b, 0x02, 0x03, 0xe6, 0x00, 0x30, 0x2c, 0x00,
770x02, 0x03, 0xe6, 0x00, 0x30, 0x2c, 0x00, 0x65, 0xd4, 0x02, 770x65, 0xc8, 0x02, 0x21, 0x69, 0x66, 0x32, 0x00, 0x52, 0x64,
780x21, 0x69, 0x66, 0x32, 0x00, 0x52, 0x64, 0x6f, 0x6e, 0x27, 780x6f, 0x6e, 0x27, 0x74, 0x38, 0x00, 0x02, 0xbf, 0x02, 0x00,
790x74, 0x38, 0x00, 0x02, 0xcb, 0x02, 0x00, 0xb5, 0x00, 0x00, 790xb5, 0x00, 0x00, 0xa3, 0x01, 0x02, 0xcb, 0x00, 0x6d, 0x65,
800xaf, 0x01, 0x02, 0xcb, 0x00, 0x6d, 0x65, 0x73, 0x00, 0x79, 800x73, 0x00, 0x79, 0x65, 0x74, 0xf9, 0x00, 0x0e, 0x9d, 0x00,
810x65, 0x74, 0xf9, 0x00, 0x0e, 0x9d, 0x00, 0x04, 0xe7, 0x01, 810x04, 0xdb, 0x01, 0x06, 0xed, 0x00, 0x15, 0x69, 0x7a, 0x00,
820x06, 0xed, 0x00, 0x15, 0x69, 0x7a, 0x00, 0x16, 0x73, 0xf9, 820x16, 0x73, 0xf9, 0x00, 0x03, 0x62, 0x01, 0x05, 0xef, 0x00,
830x00, 0x03, 0x62, 0x01, 0x05, 0xef, 0x00, 0x32, 0x00, 0x6f, 830x32, 0x00, 0x6f, 0x72, 0x74, 0x02, 0x60, 0x2d, 0x64, 0x72,
840x72, 0x80, 0x02, 0x60, 0x2d, 0x64, 0x72, 0x61, 0x67, 0x67, 840x61, 0x67, 0x67, 0x38, 0x00, 0x04, 0x7d, 0x01, 0x05, 0xa2,
850x38, 0x00, 0x04, 0x7d, 0x01, 0x05, 0xa2, 0x01, 0x20, 0x6c, 850x01, 0x20, 0x6c, 0x6c, 0xfd, 0x02, 0x00, 0xad, 0x00, 0x86,
860x6c, 0x09, 0x03, 0x00, 0xad, 0x00, 0x86, 0x74, 0x6f, 0x00, 860x74, 0x6f, 0x00, 0x6c, 0x61, 0x79, 0x00, 0x61, 0x83, 0x02,
870x6c, 0x61, 0x79, 0x00, 0x61, 0x8f, 0x02, 0x31, 0x6c, 0x69, 870x31, 0x6c, 0x69, 0x6e, 0x7b, 0x03, 0x32, 0x69, 0x73, 0x2d,
880x6e, 0x87, 0x03, 0x32, 0x69, 0x73, 0x2d, 0x61, 0x00, 0x20, 880x61, 0x00, 0x20, 0x6f, 0x72, 0x0c, 0x00, 0x33, 0x6e, 0x6f,
890x6f, 0x72, 0x0c, 0x00, 0x33, 0x6e, 0x6f, 0x74, 0x10, 0x00, 890x74, 0x10, 0x00, 0x05, 0x2d, 0x01, 0xd1, 0x73, 0x2c, 0x00,
900x05, 0x2d, 0x01, 0xd1, 0x73, 0x2c, 0x00, 0x75, 0x73, 0x65, 900x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x00, 0x66, 0x6f, 0x72,
910x66, 0x75, 0x6c, 0x00, 0x66, 0x6f, 0x72, 0xad, 0x03, 0x03, 910xa1, 0x03, 0x03, 0xc9, 0x00, 0x01, 0x5b, 0x03, 0x25, 0x6f,
920xc9, 0x00, 0x01, 0x67, 0x03, 0x25, 0x6f, 0x72, 0x66, 0x03, 920x72, 0x5a, 0x03, 0x85, 0x74, 0x6f, 0x00, 0x6d, 0x61, 0x74,
930x85, 0x74, 0x6f, 0x00, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x31, 930x63, 0x68, 0x25, 0x03, 0x00, 0xad, 0x00, 0x41, 0x28, 0x41,
940x03, 0x00, 0xad, 0x00, 0x41, 0x28, 0x41, 0x6c, 0x6c, 0x11, 940x6c, 0x6c, 0x11, 0x00, 0x11, 0x61, 0x8f, 0x02, 0x92, 0x73,
950x00, 0x11, 0x61, 0x95, 0x02, 0x92, 0x73, 0x00, 0x64, 0x65, 950x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x4f, 0x03,
960x73, 0x63, 0x72, 0x69, 0x62, 0x5b, 0x03, 0x13, 0x73, 0xab, 960x13, 0x73, 0xa5, 0x02, 0x41, 0x32, 0x2e, 0x31, 0x00, 0x13,
970x02, 0x41, 0x32, 0x2e, 0x31, 0x00, 0x13, 0x01, 0xf2, 0x00, 970x01, 0xf2, 0x00, 0x6c, 0x73, 0x6f, 0x00, 0x61, 0x76, 0x61,
980x6c, 0x73, 0x6f, 0x00, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 980x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0xad, 0x02,
990x62, 0x6c, 0x65, 0x2e, 0x29, 0xb3, 0x02, 0x1a, 0x32, 0xb3, 990x14, 0x32, 0xad, 0x02, 0xb2, 0x70, 0x61, 0x72, 0x61, 0x6d,
1000x02, 0xb2, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 1000x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x5e, 0x03, 0x36, 0x73,
1010x72, 0x73, 0x20, 0x70, 0x03, 0x36, 0x73, 0x65, 0x00, 0x14, 1010x65, 0x00, 0x14, 0x00, 0x02, 0x42, 0x00, 0x04, 0x3d, 0x00,
1020x00, 0x02, 0x48, 0x00, 0x04, 0x43, 0x00, 0x02, 0x24, 0x04, 1020x02, 0x12, 0x04, 0x00, 0x7a, 0x00, 0xe1, 0x60, 0x43, 0x75,
1030x00, 0x80, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f, 1030x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f,
1040x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x76, 0x00, 1040x70, 0x70, 0x00, 0x03, 0x68, 0x02, 0xb0, 0x60, 0x54, 0x79,
1050x03, 0x6e, 0x02, 0xb0, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27, 1050x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0xac, 0x00,
1060x00, 0x6d, 0x65, 0x6e, 0x75, 0xb2, 0x00, 0x91, 0x57, 0x69, 1060x91, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65,
1070x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0x28, 0x01, 0x68, 1070x22, 0x01, 0x68, 0x00, 0x00, 0x53, 0x69, 0x7a, 0x65, 0xd3,
1080x00, 0x00, 0x53, 0x69, 0x7a, 0x65, 0xe5, 0x03, 0x00, 0x99, 1080x03, 0x00, 0x93, 0x02, 0x06, 0xd3, 0x02, 0xf3, 0x01, 0x00,
1090x02, 0x06, 0xd9, 0x02, 0xf3, 0x01, 0x00, 0x00, 0x44, 0x69, 1090x00, 0x44, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74,
1100x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x00, 0x00, 1100x79, 0x00, 0x00, 0x00, 0x43, 0x49, 0x03, 0x01, 0x2e, 0x00,
1110x00, 0x43, 0x4f, 0x03, 0x01, 0x2e, 0x00, 0x16, 0x64, 0x1a, 1110x16, 0x64, 0x1a, 0x00, 0x04, 0x40, 0x00, 0x41, 0x65, 0x6e,
1120x00, 0x04, 0x40, 0x00, 0x41, 0x65, 0x6e, 0x65, 0x72, 0x58, 1120x65, 0x72, 0x46, 0x04, 0xf3, 0x0b, 0x70, 0x75, 0x7a, 0x7a,
1130x04, 0xf3, 0x0b, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x3a, 1130x6c, 0x65, 0x3a, 0x00, 0x61, 0x74, 0x00, 0x54, 0x72, 0x69,
1140x00, 0x61, 0x74, 0x00, 0x54, 0x72, 0x69, 0x63, 0x6b, 0x79, 1140x63, 0x6b, 0x79, 0x00, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2c,
1150x00, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2c, 0x00, 0x79, 0x41, 1150x00, 0x79, 0x2f, 0x05, 0x82, 0x72, 0x65, 0x71, 0x75, 0x69,
1160x05, 0x82, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 1160x72, 0x65, 0x64, 0x51, 0x01, 0xc3, 0x6b, 0x65, 0x00, 0x6d,
1170x57, 0x01, 0xc3, 0x6b, 0x65, 0x00, 0x6d, 0x6f, 0x72, 0x65, 1170x6f, 0x72, 0x65, 0x00, 0x64, 0x65, 0x64, 0x75, 0x43, 0x01,
1180x00, 0x64, 0x65, 0x64, 0x75, 0x49, 0x01, 0x60, 0x72, 0x65, 1180x60, 0x72, 0x65, 0x67, 0x61, 0x72, 0x64, 0x86, 0x01, 0x36,
1190x67, 0x61, 0x72, 0x64, 0x8c, 0x01, 0x36, 0x64, 0x69, 0x73, 1190x64, 0x69, 0x73, 0x0d, 0x00, 0x52, 0x6d, 0x6f, 0x76, 0x65,
1200x0d, 0x00, 0x52, 0x6d, 0x6f, 0x76, 0x65, 0x73, 0xd9, 0x02, 1200x73, 0xd3, 0x02, 0x91, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x00,
1210x91, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x00, 0x6c, 0x65, 0x61, 1210x6c, 0x65, 0x61, 0x45, 0x00, 0x25, 0x69, 0x6d, 0x34, 0x03,
1220x45, 0x00, 0x25, 0x69, 0x6d, 0x3a, 0x03, 0x01, 0x73, 0x02, 1220x01, 0x6d, 0x02, 0xa2, 0x69, 0x6e, 0x67, 0x73, 0x00, 0x6c,
1230xa2, 0x69, 0x6e, 0x67, 0x73, 0x00, 0x6c, 0x61, 0x74, 0x65, 1230x61, 0x74, 0x65, 0x72, 0xc6, 0x00, 0x11, 0x73, 0x2a, 0x02,
1240x72, 0xc6, 0x00, 0x11, 0x73, 0x30, 0x02, 0x00, 0x11, 0x04, 1240x00, 0x0b, 0x04, 0xb2, 0x73, 0x65, 0x63, 0x75, 0x74, 0x69,
1250xb2, 0x73, 0x65, 0x63, 0x75, 0x74, 0x69, 0x76, 0x65, 0x20, 1250x76, 0x65, 0x20, 0x31, 0x20, 0xe6, 0x04, 0x07, 0xd8, 0x00,
1260x31, 0x20, 0xf8, 0x04, 0x07, 0xd8, 0x00, 0x30, 0x77, 0x68, 1260x30, 0x77, 0x68, 0x65, 0x72, 0x03, 0x01, 0xce, 0x00, 0x03,
1270x65, 0x78, 0x03, 0x01, 0xce, 0x00, 0x09, 0x91, 0x04, 0x35, 1270x7f, 0x04, 0x35, 0x67, 0x61, 0x6d, 0xda, 0x00, 0x00, 0x57,
1280x67, 0x61, 0x6d, 0xe0, 0x00, 0x00, 0x5d, 0x01, 0x71, 0x70, 1280x01, 0x71, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x73, 0xfb,
1290x65, 0x72, 0x6d, 0x69, 0x74, 0x73, 0x07, 0x04, 0x50, 0x61, 1290x03, 0x50, 0x61, 0x64, 0x6a, 0x61, 0x63, 0x14, 0x04, 0x0f,
1300x64, 0x6a, 0x61, 0x63, 0x20, 0x04, 0x0f, 0x33, 0x02, 0x00, 1300x27, 0x02, 0x00, 0x81, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61,
1310x81, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x31, 0x32, 1310x00, 0x31, 0x26, 0x02, 0x10, 0x2c, 0x1d, 0x00, 0x05, 0x3a,
1320x02, 0x10, 0x2c, 0x1d, 0x00, 0x05, 0x3a, 0x00, 0x02, 0xcb, 1320x00, 0x02, 0xb3, 0x05, 0x06, 0x30, 0x00, 0x04, 0x40, 0x01,
1330x05, 0x06, 0x30, 0x00, 0x04, 0x46, 0x01, 0x01, 0xa1, 0x02, 1330x01, 0x95, 0x02, 0xbd, 0x27, 0x73, 0x00, 0x65, 0x6e, 0x64,
1340xbd, 0x27, 0x73, 0x00, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 1340x70, 0x6f, 0x69, 0x6e, 0x74, 0x47, 0x00, 0xc2, 0x2e, 0x00,
1350x6e, 0x74, 0x47, 0x00, 0xc2, 0x2e, 0x00, 0x42, 0x79, 0x00, 1350x42, 0x79, 0x00, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74,
1360x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x17, 0x05, 0x21, 1360x05, 0x05, 0x21, 0x69, 0x73, 0x3b, 0x05, 0x02, 0x5b, 0x00,
1370x69, 0x73, 0x53, 0x05, 0x02, 0x5b, 0x00, 0x60, 0x74, 0x65, 1370x60, 0x74, 0x65, 0x64, 0x2c, 0x00, 0x74, 0x5d, 0x02, 0x86,
1380x64, 0x2c, 0x00, 0x74, 0x69, 0x02, 0x86, 0x6f, 0x69, 0x64, 1380x6f, 0x69, 0x64, 0x00, 0x6c, 0x6f, 0x6e, 0x67, 0x0c, 0x03,
1390x00, 0x6c, 0x6f, 0x6e, 0x67, 0x18, 0x03, 0x30, 0x62, 0x6f, 1390x30, 0x62, 0x6f, 0x72, 0x40, 0x01, 0x05, 0xf9, 0x05, 0x05,
1400x72, 0x46, 0x01, 0x05, 0x11, 0x06, 0x05, 0x23, 0x06, 0x00, 1400x0b, 0x06, 0x00, 0x8c, 0x05, 0x01, 0x82, 0x01, 0x01, 0xc2,
1410xa4, 0x05, 0x01, 0x88, 0x01, 0x01, 0xc8, 0x01, 0x01, 0x58, 1410x01, 0x01, 0x46, 0x05, 0x01, 0x8c, 0x01, 0x71, 0x74, 0x77,
1420x05, 0x01, 0x92, 0x01, 0x71, 0x74, 0x77, 0x69, 0x64, 0x64, 1420x69, 0x64, 0x64, 0x6c, 0x79, 0x20, 0x00, 0x70, 0x69, 0x6e,
1430x6c, 0x79, 0x20, 0x00, 0x70, 0x69, 0x6e, 0x74, 0x65, 0x72, 1430x74, 0x65, 0x72, 0x65, 0x73, 0xba, 0x03, 0x32, 0x2e, 0x00,
1440x65, 0x73, 0xc6, 0x03, 0x32, 0x2e, 0x00, 0x49, 0x28, 0x04, 1440x49, 0x1c, 0x04, 0x22, 0x77, 0x61, 0xa1, 0x00, 0x00, 0x18,
1450x22, 0x77, 0x61, 0xa1, 0x00, 0x00, 0x18, 0x00, 0x22, 0x6f, 1450x00, 0x22, 0x6f, 0x72, 0x3f, 0x00, 0x02, 0x83, 0x01, 0xb2,
1460x72, 0x3f, 0x00, 0x02, 0x89, 0x01, 0xb2, 0x69, 0x6c, 0x69, 1460x69, 0x6c, 0x69, 0x74, 0x79, 0x2c, 0x00, 0x74, 0x75, 0x72,
1470x74, 0x79, 0x2c, 0x00, 0x74, 0x75, 0x72, 0x6e, 0xa5, 0x00, 1470x6e, 0xa5, 0x00, 0x03, 0x91, 0x02, 0x50, 0x6f, 0x66, 0x66,
1480x03, 0x97, 0x02, 0x50, 0x6f, 0x66, 0x66, 0x2e, 0x00, 1480x2e, 0x00,
149}; 149};
150 150
151const unsigned short help_text_len = 1917; 151const unsigned short help_text_len = 1881;
152const unsigned short help_text_words = 339; 152const unsigned short help_text_words = 337;
153const char quick_help_text[] = "Fill in the railway track according to the clues."; 153const char quick_help_text[] = "Fill in the railway track according to the clues.";
diff --git a/apps/plugins/puzzles/rockbox.c b/apps/plugins/puzzles/rockbox.c
index 60e6548826..27005a447d 100644
--- a/apps/plugins/puzzles/rockbox.c
+++ b/apps/plugins/puzzles/rockbox.c
@@ -753,7 +753,7 @@ static void rb_color(int n)
753 753
754/* clipping is implemented through viewports and offsetting 754/* clipping is implemented through viewports and offsetting
755 * coordinates */ 755 * coordinates */
756static void rb_clip(void *handle, int x, int y, int w, int h) 756static void rb_clip(drawing *dr, int x, int y, int w, int h)
757{ 757{
758 if(!zoom_enabled) 758 if(!zoom_enabled)
759 { 759 {
@@ -783,7 +783,7 @@ static void rb_clip(void *handle, int x, int y, int w, int h)
783 } 783 }
784} 784}
785 785
786static void rb_unclip(void *handle) 786static void rb_unclip(drawing *dr)
787{ 787{
788 if(!zoom_enabled) 788 if(!zoom_enabled)
789 { 789 {
@@ -800,7 +800,7 @@ static void rb_unclip(void *handle)
800 } 800 }
801} 801}
802 802
803static void rb_draw_text(void *handle, int x, int y, int fonttype, 803static void rb_draw_text(drawing *dr, int x, int y, int fonttype,
804 int fontsize, int align, int color, const char *text) 804 int fontsize, int align, int color, const char *text)
805{ 805{
806 (void) fontsize; 806 (void) fontsize;
@@ -865,7 +865,7 @@ static void rb_draw_text(void *handle, int x, int y, int fonttype,
865 } 865 }
866} 866}
867 867
868static void rb_draw_rect(void *handle, int x, int y, int w, int h, int color) 868static void rb_draw_rect(drawing *dr, int x, int y, int w, int h, int color)
869{ 869{
870 rb_color(color); 870 rb_color(color);
871 if(!zoom_enabled) 871 if(!zoom_enabled)
@@ -1007,7 +1007,7 @@ static void draw_antialiased_line(fb_data *fb, int w, int h, int x0, int y0, int
1007 } 1007 }
1008} 1008}
1009 1009
1010static void rb_draw_line(void *handle, int x1, int y1, int x2, int y2, 1010static void rb_draw_line(drawing *dr, int x1, int y1, int x2, int y2,
1011 int color) 1011 int color)
1012{ 1012{
1013 rb_color(color); 1013 rb_color(color);
@@ -1035,349 +1035,7 @@ static void rb_draw_line(void *handle, int x1, int y1, int x2, int y2,
1035 } 1035 }
1036} 1036}
1037 1037
1038#if 0 1038static void rb_draw_circle(drawing *dr, int cx, int cy, int radius,
1039/*
1040 * draw filled polygon
1041 * originally by Sebastian Leonhardt (ulmutul)
1042 * 'count' : number of coordinate pairs
1043 * 'pxy': array of coordinates. pxy[0]=x0,pxy[1]=y0,...
1044 * note: provide space for one extra coordinate, because the starting point
1045 * will automatically be inserted as end point.
1046 */
1047
1048/*
1049 * helper function:
1050 * find points of intersection between polygon and scanline
1051 */
1052
1053#define MAX_INTERSECTION 32
1054
1055static void fill_poly_line(int scanline, int count, int *pxy)
1056{
1057 int i;
1058 int j;
1059 int num_of_intersects;
1060 int direct, old_direct;
1061 //intersections of every line with scanline (y-coord)
1062 int intersection[MAX_INTERSECTION];
1063 /* add starting point as ending point */
1064 pxy[count*2] = pxy[0];
1065 pxy[count*2+1] = pxy[1];
1066
1067 old_direct=0;
1068 num_of_intersects=0;
1069 for (i=0; i<count*2; i+=2) {
1070 int x1=pxy[i];
1071 int y1=pxy[i+1];
1072 int x2=pxy[i+2];
1073 int y2=pxy[i+3];
1074 // skip if line is outside of scanline
1075 if (y1 < y2) {
1076 if (scanline < y1 || scanline > y2)
1077 continue;
1078 }
1079 else {
1080 if (scanline < y2 || scanline > y1)
1081 continue;
1082 }
1083 // calculate x-coord of intersection
1084 if (y1==y2) {
1085 direct=0;
1086 }
1087 else {
1088 direct = y1>y2 ? 1 : -1;
1089 // omit double intersections, if both lines lead in the same direction
1090 intersection[num_of_intersects] =
1091 x1+((scanline-y1)*(x2-x1))/(y2-y1);
1092 if ( (direct!=old_direct)
1093 || (intersection[num_of_intersects] != intersection[num_of_intersects-1])
1094 )
1095 ++num_of_intersects;
1096 }
1097 old_direct = direct;
1098 }
1099
1100 // sort points of intersection
1101 for (i=0; i<num_of_intersects-1; ++i) {
1102 for (j=i+1; j<num_of_intersects; ++j) {
1103 if (intersection[j]<intersection[i]) {
1104 int temp=intersection[i];
1105 intersection[i]=intersection[j];
1106 intersection[j]=temp;
1107 }
1108 }
1109 }
1110 // draw
1111 for (i=0; i<num_of_intersects; i+=2) {
1112 rb->lcd_hline(intersection[i], intersection[i+1], scanline);
1113 }
1114}
1115
1116/* two extra elements at end of pxy needed */
1117static void v_fillarea(int count, int *pxy)
1118{
1119 int i;
1120 int y1, y2;
1121
1122 // find min and max y coords
1123 y1=y2=pxy[1];
1124 for (i=3; i<count*2; i+=2) {
1125 if (pxy[i] < y1) y1 = pxy[i];
1126 else if (pxy[i] > y2) y2 = pxy[i];
1127 }
1128
1129 for (i=y1; i<=y2; ++i) {
1130 fill_poly_line(i, count, pxy);
1131 }
1132}
1133#endif
1134
1135/* I'm a horrible person: this was copy-pasta'd straight from
1136 * xlcd_draw.c */
1137
1138/* sort the given coordinates by increasing x value */
1139static void sort_points_by_increasing_x(int* x1, int* y1,
1140 int* x2, int* y2,
1141 int* x3, int* y3)
1142{
1143 int x, y;
1144 if (*x1 > *x3)
1145 {
1146 if (*x2 < *x3) /* x2 < x3 < x1 */
1147 {
1148 x = *x1; *x1 = *x2; *x2 = *x3; *x3 = x;
1149 y = *y1; *y1 = *y2; *y2 = *y3; *y3 = y;
1150 }
1151 else if (*x2 > *x1) /* x3 < x1 < x2 */
1152 {
1153 x = *x1; *x1 = *x3; *x3 = *x2; *x2 = x;
1154 y = *y1; *y1 = *y3; *y3 = *y2; *y2 = y;
1155 }
1156 else /* x3 <= x2 <= x1 */
1157 {
1158 x = *x1; *x1 = *x3; *x3 = x;
1159 y = *y1; *y1 = *y3; *y3 = y;
1160 }
1161 }
1162 else
1163 {
1164 if (*x2 < *x1) /* x2 < x1 <= x3 */
1165 {
1166 x = *x1; *x1 = *x2; *x2 = x;
1167 y = *y1; *y1 = *y2; *y2 = y;
1168 }
1169 else if (*x2 > *x3) /* x1 <= x3 < x2 */
1170 {
1171 x = *x2; *x2 = *x3; *x3 = x;
1172 y = *y2; *y2 = *y3; *y3 = y;
1173 }
1174 /* else already sorted */
1175 }
1176}
1177
1178#define sort_points_by_increasing_y(x1, y1, x2, y2, x3, y3) \
1179 sort_points_by_increasing_x(y1, x1, y2, x2, y3, x3)
1180
1181/* draw a filled triangle, using horizontal lines for speed */
1182static void zoom_filltriangle(int x1, int y1,
1183 int x2, int y2,
1184 int x3, int y3)
1185{
1186 long fp_x1, fp_x2, fp_dx1, fp_dx2;
1187 int y;
1188 sort_points_by_increasing_y(&x1, &y1, &x2, &y2, &x3, &y3);
1189
1190 if (y1 < y3) /* draw */
1191 {
1192 fp_dx1 = ((x3 - x1) << 16) / (y3 - y1);
1193 fp_x1 = (x1 << 16) + (1<<15) + (fp_dx1 >> 1);
1194
1195 if (y1 < y2) /* first part */
1196 {
1197 fp_dx2 = ((x2 - x1) << 16) / (y2 - y1);
1198 fp_x2 = (x1 << 16) + (1<<15) + (fp_dx2 >> 1);
1199 for (y = y1; y < y2; y++)
1200 {
1201 zoom_hline(fp_x1 >> 16, fp_x2 >> 16, y);
1202 fp_x1 += fp_dx1;
1203 fp_x2 += fp_dx2;
1204 }
1205 }
1206 if (y2 < y3) /* second part */
1207 {
1208 fp_dx2 = ((x3 - x2) << 16) / (y3 - y2);
1209 fp_x2 = (x2 << 16) + (1<<15) + (fp_dx2 >> 1);
1210 for (y = y2; y < y3; y++)
1211 {
1212 zoom_hline(fp_x1 >> 16, fp_x2 >> 16, y);
1213 fp_x1 += fp_dx1;
1214 fp_x2 += fp_dx2;
1215 }
1216 }
1217 }
1218}
1219
1220/* Should probably refactor this */
1221static void rb_draw_poly(void *handle, const int *coords, int npoints,
1222 int fillcolor, int outlinecolor)
1223{
1224 if(!zoom_enabled)
1225 {
1226 LOGF("rb_draw_poly");
1227
1228 if(fillcolor >= 0)
1229 {
1230 rb_color(fillcolor);
1231#if 1
1232 /* serious hack: draw a bunch of triangles between adjacent points */
1233 /* this generally works, even with some concave polygons */
1234 for(int i = 2; i < npoints; ++i)
1235 {
1236 int x1, y1, x2, y2, x3, y3;
1237 x1 = coords[0];
1238 y1 = coords[1];
1239 x2 = coords[(i - 1) * 2];
1240 y2 = coords[(i - 1) * 2 + 1];
1241 x3 = coords[i * 2];
1242 y3 = coords[i * 2 + 1];
1243 offset_coords(&x1, &y1);
1244 offset_coords(&x2, &y2);
1245 offset_coords(&x3, &y3);
1246 xlcd_filltriangle(x1, y1,
1247 x2, y2,
1248 x3, y3);
1249
1250#ifdef DEBUG_MENU
1251 if(debug_settings.polyanim)
1252 {
1253 rb->lcd_update();
1254 rb->sleep(HZ/4);
1255 }
1256#endif
1257#if 0
1258 /* debug code */
1259 rb->lcd_set_foreground(LCD_RGBPACK(255,0,0));
1260 rb->lcd_drawpixel(x1, y1);
1261 rb->lcd_drawpixel(x2, y2);
1262 rb->lcd_drawpixel(x3, y3);
1263 rb->lcd_update();
1264 rb->sleep(HZ);
1265 rb_color(fillcolor);
1266 rb->lcd_drawpixel(x1, y1);
1267 rb->lcd_drawpixel(x2, y2);
1268 rb->lcd_drawpixel(x3, y3);
1269 rb->lcd_update();
1270#endif
1271 }
1272#else
1273 int *pxy = smalloc(sizeof(int) * 2 * npoints + 2);
1274 /* copy points, offsetted */
1275 for(int i = 0; i < npoints; ++i)
1276 {
1277 pxy[2 * i + 0] = coords[2 * i + 0];
1278 pxy[2 * i + 1] = coords[2 * i + 1];
1279 offset_coords(&pxy[2*i+0], &pxy[2*i+1]);
1280 }
1281 v_fillarea(npoints, pxy);
1282 sfree(pxy);
1283#endif
1284 }
1285
1286 /* draw outlines last so they're not covered by the fill */
1287 assert(outlinecolor >= 0);
1288 rb_color(outlinecolor);
1289
1290 for(int i = 1; i < npoints; ++i)
1291 {
1292 int x1, y1, x2, y2;
1293 x1 = coords[2 * (i - 1)];
1294 y1 = coords[2 * (i - 1) + 1];
1295 x2 = coords[2 * i];
1296 y2 = coords[2 * i + 1];
1297 if(debug_settings.no_aa)
1298 {
1299 offset_coords(&x1, &y1);
1300 offset_coords(&x2, &y2);
1301 rb->lcd_drawline(x1, y1,
1302 x2, y2);
1303 }
1304 else
1305 draw_antialiased_line(lcd_fb, LCD_WIDTH, LCD_HEIGHT, x1, y1, x2, y2);
1306
1307#ifdef DEBUG_MENU
1308 if(debug_settings.polyanim)
1309 {
1310 rb->lcd_update();
1311 rb->sleep(HZ/4);
1312 }
1313#endif
1314 }
1315
1316 int x1, y1, x2, y2;
1317 x1 = coords[0];
1318 y1 = coords[1];
1319 x2 = coords[2 * (npoints - 1)];
1320 y2 = coords[2 * (npoints - 1) + 1];
1321 if(debug_settings.no_aa)
1322 {
1323 offset_coords(&x1, &y1);
1324 offset_coords(&x2, &y2);
1325
1326 rb->lcd_drawline(x1, y1,
1327 x2, y2);
1328 }
1329 else
1330 draw_antialiased_line(lcd_fb, LCD_WIDTH, LCD_HEIGHT, x1, y1, x2, y2);
1331 }
1332 else
1333 {
1334 LOGF("rb_draw_poly");
1335
1336 if(fillcolor >= 0)
1337 {
1338 rb_color(fillcolor);
1339
1340 /* serious hack: draw a bunch of triangles between adjacent points */
1341 /* this generally works, even with some concave polygons */
1342 for(int i = 2; i < npoints; ++i)
1343 {
1344 int x1, y1, x2, y2, x3, y3;
1345 x1 = coords[0];
1346 y1 = coords[1];
1347 x2 = coords[(i - 1) * 2];
1348 y2 = coords[(i - 1) * 2 + 1];
1349 x3 = coords[i * 2];
1350 y3 = coords[i * 2 + 1];
1351 zoom_filltriangle(x1, y1,
1352 x2, y2,
1353 x3, y3);
1354 }
1355 }
1356
1357 /* draw outlines last so they're not covered by the fill */
1358 assert(outlinecolor >= 0);
1359 rb_color(outlinecolor);
1360
1361 for(int i = 1; i < npoints; ++i)
1362 {
1363 int x1, y1, x2, y2;
1364 x1 = coords[2 * (i - 1)];
1365 y1 = coords[2 * (i - 1) + 1];
1366 x2 = coords[2 * i];
1367 y2 = coords[2 * i + 1];
1368 draw_antialiased_line(zoom_fb, zoom_w, zoom_h, x1, y1, x2, y2);
1369 }
1370
1371 int x1, y1, x2, y2;
1372 x1 = coords[0];
1373 y1 = coords[1];
1374 x2 = coords[2 * (npoints - 1)];
1375 y2 = coords[2 * (npoints - 1) + 1];
1376 draw_antialiased_line(zoom_fb, zoom_w, zoom_h, x1, y1, x2, y2);
1377 }
1378}
1379
1380static void rb_draw_circle(void *handle, int cx, int cy, int radius,
1381 int fillcolor, int outlinecolor) 1039 int fillcolor, int outlinecolor)
1382{ 1040{
1383 if(!zoom_enabled) 1041 if(!zoom_enabled)
@@ -1449,7 +1107,7 @@ static void trim_rect(int *x, int *y, int *w, int *h)
1449 *h = y1 - y0; 1107 *h = y1 - y0;
1450} 1108}
1451 1109
1452static blitter *rb_blitter_new(void *handle, int w, int h) 1110static blitter *rb_blitter_new(drawing *dr, int w, int h)
1453{ 1111{
1454 LOGF("rb_blitter_new"); 1112 LOGF("rb_blitter_new");
1455 blitter *b = snew(blitter); 1113 blitter *b = snew(blitter);
@@ -1460,7 +1118,7 @@ static blitter *rb_blitter_new(void *handle, int w, int h)
1460 return b; 1118 return b;
1461} 1119}
1462 1120
1463static void rb_blitter_free(void *handle, blitter *bl) 1121static void rb_blitter_free(drawing *dr, blitter *bl)
1464{ 1122{
1465 LOGF("rb_blitter_free"); 1123 LOGF("rb_blitter_free");
1466 sfree(bl->bmp.data); 1124 sfree(bl->bmp.data);
@@ -1469,7 +1127,7 @@ static void rb_blitter_free(void *handle, blitter *bl)
1469} 1127}
1470 1128
1471/* copy a section of the framebuffer */ 1129/* copy a section of the framebuffer */
1472static void rb_blitter_save(void *handle, blitter *bl, int x, int y) 1130static void rb_blitter_save(drawing *dr, blitter *bl, int x, int y)
1473{ 1131{
1474 /* no viewport offset */ 1132 /* no viewport offset */
1475#if LCD_STRIDEFORMAT == VERTICAL_STRIDE 1133#if LCD_STRIDEFORMAT == VERTICAL_STRIDE
@@ -1498,7 +1156,7 @@ static void rb_blitter_save(void *handle, blitter *bl, int x, int y)
1498#endif 1156#endif
1499} 1157}
1500 1158
1501static void rb_blitter_load(void *handle, blitter *bl, int x, int y) 1159static void rb_blitter_load(drawing *dr, blitter *bl, int x, int y)
1502{ 1160{
1503 LOGF("rb_blitter_load"); 1161 LOGF("rb_blitter_load");
1504 if(!bl->have_data) 1162 if(!bl->have_data)
@@ -1528,7 +1186,7 @@ static void rb_blitter_load(void *handle, blitter *bl, int x, int y)
1528 } 1186 }
1529} 1187}
1530 1188
1531static void rb_draw_update(void *handle, int x, int y, int w, int h) 1189static void rb_draw_update(drawing *dr, int x, int y, int w, int h)
1532{ 1190{
1533 LOGF("rb_draw_update(%d, %d, %d, %d)", x, y, w, h); 1191 LOGF("rb_draw_update(%d, %d, %d, %d)", x, y, w, h);
1534 1192
@@ -1552,9 +1210,9 @@ static void rb_draw_update(void *handle, int x, int y, int w, int h)
1552 need_draw_update = true; 1210 need_draw_update = true;
1553} 1211}
1554 1212
1555static void rb_start_draw(void *handle) 1213static void rb_start_draw(drawing *dr)
1556{ 1214{
1557 (void) handle; 1215 (void) dr;
1558 1216
1559 /* ... mumble mumble ... not ... reentrant ... mumble mumble ... */ 1217 /* ... mumble mumble ... not ... reentrant ... mumble mumble ... */
1560 1218
@@ -1565,9 +1223,9 @@ static void rb_start_draw(void *handle)
1565 ud_d = LCD_HEIGHT; 1223 ud_d = LCD_HEIGHT;
1566} 1224}
1567 1225
1568static void rb_end_draw(void *handle) 1226static void rb_end_draw(drawing *dr)
1569{ 1227{
1570 (void) handle; 1228 (void) dr;
1571 1229
1572 if(debug_settings.highlight_cursor) 1230 if(debug_settings.highlight_cursor)
1573 { 1231 {
@@ -1594,7 +1252,7 @@ static void rb_end_draw(void *handle)
1594#endif 1252#endif
1595} 1253}
1596 1254
1597static void rb_status_bar(void *handle, const char *text) 1255static void rb_status_bar(drawing *dr, const char *text)
1598{ 1256{
1599 if(titlebar) 1257 if(titlebar)
1600 sfree(titlebar); 1258 sfree(titlebar);
@@ -1692,7 +1350,7 @@ static void draw_mouse(void)
1692 * glyph exists in a font) */ 1350 * glyph exists in a font) */
1693#if 0 1351#if 0
1694/* See: https://www.chiark.greenend.org.uk/~sgtatham/puzzles/devel/drawing.html#drawing-text-fallback */ 1352/* See: https://www.chiark.greenend.org.uk/~sgtatham/puzzles/devel/drawing.html#drawing-text-fallback */
1695static char *rb_text_fallback(void *handle, const char *const *strings, 1353static char *rb_text_fallback(drawing *dr, const char *const *strings,
1696 int nstrings) 1354 int nstrings)
1697{ 1355{
1698 struct font *pf = rb->font_get(cur_font); 1356 struct font *pf = rb->font_get(cur_font);
@@ -1725,10 +1383,11 @@ static char *rb_text_fallback(void *handle, const char *const *strings,
1725#endif 1383#endif
1726 1384
1727const drawing_api rb_drawing = { 1385const drawing_api rb_drawing = {
1386 1,
1728 rb_draw_text, 1387 rb_draw_text,
1729 rb_draw_rect, 1388 rb_draw_rect,
1730 rb_draw_line, 1389 rb_draw_line,
1731 rb_draw_poly, 1390 draw_polygon_fallback,
1732 rb_draw_circle, 1391 rb_draw_circle,
1733 rb_draw_update, 1392 rb_draw_update,
1734 rb_clip, 1393 rb_clip,
diff --git a/apps/plugins/puzzles/src/CMakeLists.txt b/apps/plugins/puzzles/src/CMakeLists.txt
index 4153efc246..ce3ce3d3df 100644
--- a/apps/plugins/puzzles/src/CMakeLists.txt
+++ b/apps/plugins/puzzles/src/CMakeLists.txt
@@ -6,13 +6,17 @@ project(puzzles
6include(cmake/setup.cmake) 6include(cmake/setup.cmake)
7 7
8add_library(core_obj OBJECT 8add_library(core_obj OBJECT
9 combi.c divvy.c drawing.c dsf.c findloop.c grid.c latin.c 9 combi.c divvy.c draw-poly.c drawing.c dsf.c findloop.c grid.c
10 laydomino.c loopgen.c malloc.c matching.c midend.c misc.c penrose.c 10 latin.c laydomino.c loopgen.c malloc.c matching.c midend.c misc.c
11 penrose-legacy.c ps.c random.c sort.c tdq.c tree234.c version.c 11 penrose.c penrose-legacy.c ps.c random.c sort.c tdq.c tree234.c
12 version.c
12 ${platform_common_sources}) 13 ${platform_common_sources})
13add_library(core $<TARGET_OBJECTS:core_obj>) 14add_library(core $<TARGET_OBJECTS:core_obj>)
14add_library(common $<TARGET_OBJECTS:core_obj> hat.c spectre.c) 15add_library(common $<TARGET_OBJECTS:core_obj> hat.c spectre.c)
15 16
17cliprogram(polygon-test draw-poly.c
18 SDL2_LIB COMPILE_DEFINITIONS STANDALONE_POLYGON)
19
16include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 20include_directories(${CMAKE_CURRENT_SOURCE_DIR})
17 21
18puzzle(blackbox 22puzzle(blackbox
diff --git a/apps/plugins/puzzles/src/draw-poly.c b/apps/plugins/puzzles/src/draw-poly.c
new file mode 100644
index 0000000000..d4c9975d97
--- /dev/null
+++ b/apps/plugins/puzzles/src/draw-poly.c
@@ -0,0 +1,302 @@
1/*
2 * draw-poly.c: Fallback polygon drawing function.
3 */
4
5#include <assert.h>
6
7#include "puzzles.h"
8
9struct edge {
10 int x1, y1;
11 int x2, y2;
12 bool active;
13
14 /* whether y1 is a closed endpoint (i.e. this edge should be
15 * active when y == y1) */
16 bool closed_y1;
17
18 /* (x2 - x1) / (y2 - y1) as 16.16 signed fixed point; precomputed
19 * for speed */
20 long inverse_slope;
21};
22
23#define FRACBITS 16
24#define ONEHALF (1 << (FRACBITS-1))
25
26void draw_polygon_fallback(drawing *dr, const int *coords, int npoints,
27 int fillcolour, int outlinecolour)
28{
29 struct edge *edges;
30 int min_y = INT_MAX, max_y = INT_MIN, i, y;
31 int n_edges = 0;
32 int *intersections;
33
34 if(npoints < 3)
35 return;
36
37 if(fillcolour < 0)
38 goto draw_outline;
39
40 /* This uses a basic scanline rasterization algorithm for polygon
41 * filling. First, an "edge table" is constructed for each pair of
42 * neighboring points. Horizontal edges are excluded. Then, the
43 * algorithm iterates a horizontal "scan line" over the vertical
44 * (Y) extent of the polygon. At each Y level, it maintains a set
45 * of "active" edges, which are those which intersect the scan
46 * line at the current Y level. The X coordinates where the scan
47 * line intersects each active edge are then computed via
48 * fixed-point arithmetic and stored. Finally, horizontal lines
49 * are drawn between each successive pair of intersection points,
50 * in the order of ascending X coordinate. This has the effect of
51 * "even-odd" filling when the polygon is self-intersecting.
52 *
53 * I (vaguely) based this implementation off the slides below:
54 *
55 * https://www.khoury.northeastern.edu/home/fell/CS4300/Lectures/CS4300F2012-9-ScanLineFill.pdf
56 *
57 * I'm fairly confident that this current implementation is
58 * correct (i.e. draws the right polygon, free from artifacts),
59 * but it isn't quite as efficient as it could be. Namely, it
60 * currently maintains the active edge set by setting the `active`
61 * flag in the `edge` array, which is quite inefficient. Perhaps
62 * future optimization could see this replaced with a tree
63 * set. Additionally, one could perhaps replace the current linear
64 * search for edge endpoints (i.e. the inner loop over `edges`) by
65 * sorting the edge table by upper and lower Y coordinate.
66 *
67 * A final caveat comes from the use of fixed point arithmetic,
68 * which is motivated by performance considerations on FPU-less
69 * platforms (e.g. most Rockbox devices, and maybe others?). I'm
70 * currently using 16 fractional bits to compute the edge
71 * intersections, which (in the case of a 32-bit int) limits the
72 * acceptable range of coordinates to roughly (-2^14, +2^14). This
73 * ought to be acceptable for the forseeable future, but
74 * ultra-high DPI screens might one day exceed this. In that case,
75 * options include switching to int64_t (but that comes with its
76 * own portability headaches), reducing the number of fractional
77 * bits, or just giving up and using floating point.
78 */
79
80 /* Build edge table from coords. Horizontal edges are filtered
81 * out, so n_edges <= n_points in general. */
82 edges = smalloc(npoints * sizeof(struct edge));
83
84 for(i = 0; i < npoints; i++) {
85 int x1, y1, x2, y2;
86
87 x1 = coords[(2*i+0)];
88 y1 = coords[(2*i+1)];
89 x2 = coords[(2*i+2) % (npoints * 2)];
90 y2 = coords[(2*i+3) % (npoints * 2)];
91
92 if(y1 < min_y)
93 min_y = y1;
94 if(y1 > max_y)
95 max_y = y1;
96
97#define COORD_LIMIT (1<<(sizeof(int)*CHAR_BIT-2 - FRACBITS))
98 /* Prevent integer overflow when computing `inverse_slope',
99 * which shifts the coordinates left by FRACBITS, and for
100 * which we'd like to avoid relying on `long long'. */
101 /* If this ever causes issues, see the above comment about
102 possible solutions. */
103 assert(x1 < COORD_LIMIT && y1 < COORD_LIMIT);
104
105 /* Only create non-horizontal edges, and require y1 < y2. */
106 if(y1 != y2) {
107 bool swap = y1 > y2;
108 int lower_endpoint = swap ? (i + 1) : i;
109
110 /* Compute index of the point adjacent to lower end of
111 * this edge (which is not the upper end of this edge). */
112 int lower_neighbor = swap ? (lower_endpoint + 1) % npoints : (lower_endpoint + npoints - 1) % npoints;
113
114 struct edge *edge = edges + (n_edges++);
115
116 edge->active = false;
117 edge->x1 = swap ? x2 : x1;
118 edge->y1 = swap ? y2 : y1;
119 edge->x2 = swap ? x1 : x2;
120 edge->y2 = swap ? y1 : y2;
121 edge->inverse_slope = ((edge->x2 - edge->x1) << FRACBITS) / (edge->y2 - edge->y1);
122 edge->closed_y1 = edge->y1 < coords[2*lower_neighbor+1];
123 }
124 }
125
126 /* a generous upper bound on number of intersections is n_edges */
127 intersections = smalloc(n_edges * sizeof(int));
128
129 for(y = min_y; y <= max_y; y++) {
130 int n_intersections = 0;
131 for(i = 0; i < n_edges; i++) {
132 struct edge *edge = edges + i;
133 /* Update active edge set. These conditions are mutually
134 * exclusive because of the invariant that y1 < y2. */
135 if(edge->y1 + (edge->closed_y1 ? 0 : 1) == y)
136 edge->active = true;
137 else if(edge->y2 + 1 == y)
138 edge->active = false;
139
140 if(edge->active) {
141 int x = edges[i].x1;
142 x += (edges[i].inverse_slope * (y - edges[i].y1) + ONEHALF) >> FRACBITS;
143 intersections[n_intersections++] = x;
144 }
145 }
146
147 qsort(intersections, n_intersections, sizeof(int), compare_integers);
148
149 assert(n_intersections % 2 == 0);
150 assert(n_intersections <= n_edges);
151
152 /* Draw horizontal lines between successive pairs of
153 * intersections of the scanline with active edges. */
154 for(i = 0; i + 1 < n_intersections; i += 2) {
155 draw_line(dr,
156 intersections[i], y,
157 intersections[i+1], y,
158 fillcolour);
159 }
160 }
161
162 sfree(intersections);
163 sfree(edges);
164
165draw_outline:
166 assert(outlinecolour >= 0);
167 for (i = 0; i < 2 * npoints; i += 2)
168 draw_line(dr,
169 coords[i], coords[i+1],
170 coords[(i+2)%(2*npoints)], coords[(i+3)%(2*npoints)],
171 outlinecolour);
172}
173
174#ifdef STANDALONE_POLYGON
175
176/*
177 * Standalone program to test draw_polygon_fallback(). By default,
178 * creates a window and allows clicking points to build a
179 * polygon. Optionally, can draw a randomly growing polygon in
180 * "screensaver" mode.
181 */
182
183#include <SDL.h>
184
185void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour)
186{
187 SDL_Renderer *renderer = GET_HANDLE_AS_TYPE(dr, SDL_Renderer);
188 SDL_RenderDrawLine(renderer, x1, y1, x2, y2);
189}
190
191#define WINDOW_WIDTH 800
192#define WINDOW_HEIGHT 600
193#define MAX_SCREENSAVER_POINTS 1000
194
195int main(int argc, char *argv[]) {
196 SDL_Window* window = NULL;
197 SDL_Event event;
198 SDL_Renderer *renderer = NULL;
199 int running = 1;
200 int i;
201 drawing dr;
202 bool screensaver = false;
203
204 if(argc >= 2) {
205 if(!strcmp(argv[1], "--screensaver"))
206 screensaver = true;
207 else
208 printf("usage: %s [--screensaver]\n", argv[0]);
209 }
210
211 int *poly = NULL;
212 int n_points = 0;
213
214 /* Initialize SDL */
215 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
216 printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
217 return 1;
218 }
219
220 /* Create window */
221 window = SDL_CreateWindow("Polygon Drawing Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
222 if (!window) {
223 printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
224 SDL_Quit();
225 return 1;
226 }
227
228 /* Create renderer */
229 renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
230 if (!renderer) {
231 printf("Renderer could not be created! SDL_Error: %s\n", SDL_GetError());
232 SDL_DestroyWindow(window);
233 SDL_Quit();
234 return 1;
235 }
236
237 dr.handle = renderer;
238
239 if(!screensaver)
240 printf("Click points in the window to create vertices. Pressing C resets.\n");
241
242 while (running) {
243 while (SDL_PollEvent(&event) != 0) {
244 if (event.type == SDL_QUIT) {
245 running = 0;
246 }
247 else if (event.type == SDL_MOUSEBUTTONDOWN) {
248 if (event.button.button == SDL_BUTTON_LEFT) {
249 int mouseX = event.button.x;
250 int mouseY = event.button.y;
251
252 poly = realloc(poly, ++n_points * 2 * sizeof(int));
253 poly[2 * (n_points - 1)] = mouseX;
254 poly[2 * (n_points - 1) + 1] = mouseY;
255 }
256 }
257 else if (event.type == SDL_KEYDOWN) {
258 if (event.key.keysym.sym == SDLK_c) {
259 free(poly);
260 poly = NULL;
261 n_points = 0;
262 }
263 }
264 }
265
266 if(screensaver) {
267 poly = realloc(poly, ++n_points * 2 * sizeof(int));
268 poly[2 * (n_points - 1)] = rand() % WINDOW_WIDTH;
269 poly[2 * (n_points - 1) + 1] = rand() % WINDOW_HEIGHT;
270
271 if(n_points >= MAX_SCREENSAVER_POINTS) {
272 free(poly);
273 poly = NULL;
274 n_points = 0;
275 }
276 }
277
278 /* Clear the screen with a black color */
279 SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
280 SDL_RenderClear(renderer);
281
282 /* Set draw color to white */
283 SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
284
285 draw_polygon_fallback(&dr, poly, n_points, 1, 1);
286
287 SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
288 for(i = 0; i < 2*n_points; i+=2)
289 SDL_RenderDrawPoint(renderer, poly[i], poly[i+1]);
290
291 /* Present the back buffer */
292 SDL_RenderPresent(renderer);
293 }
294
295 /* Clean up and quit SDL */
296 SDL_DestroyRenderer(renderer);
297 SDL_DestroyWindow(window);
298 SDL_Quit();
299
300 return 0;
301}
302#endif
diff --git a/apps/plugins/puzzles/src/drawing.c b/apps/plugins/puzzles/src/drawing.c
index 2c8816c31a..a754b068f3 100644
--- a/apps/plugins/puzzles/src/drawing.c
+++ b/apps/plugins/puzzles/src/drawing.c
@@ -42,9 +42,12 @@ struct print_colour {
42 float grey; 42 float grey;
43}; 43};
44 44
45struct drawing { 45typedef struct drawing_internal {
46 const drawing_api *api; 46 /* we implement data hiding by casting `struct drawing*` pointers
47 void *handle; 47 * to `struct drawing_internal*` */
48 struct drawing pub;
49
50 /* private data */
48 struct print_colour *colours; 51 struct print_colour *colours;
49 int ncolours, coloursize; 52 int ncolours, coloursize;
50 float scale; 53 float scale;
@@ -52,53 +55,70 @@ struct drawing {
52 * this may set it to NULL. */ 55 * this may set it to NULL. */
53 midend *me; 56 midend *me;
54 char *laststatus; 57 char *laststatus;
55}; 58} drawing_internal;
59
60#define PRIVATE_CAST(dr) ((drawing_internal*)(dr))
61#define PUBLIC_CAST(dri) ((drawing*)(dri))
62
63/* See puzzles.h for a description of the version number. */
64#define DRAWING_API_VERSION 1
56 65
57drawing *drawing_new(const drawing_api *api, midend *me, void *handle) 66drawing *drawing_new(const drawing_api *api, midend *me, void *handle)
58{ 67{
59 drawing *dr = snew(drawing); 68 if(api->version != DRAWING_API_VERSION) {
60 dr->api = api; 69 fatal("Drawing API version mismatch: expected: %d, actual: %d\n", DRAWING_API_VERSION, api->version);
61 dr->handle = handle; 70 /* shouldn't get here */
62 dr->colours = NULL; 71 return NULL;
63 dr->ncolours = dr->coloursize = 0; 72 }
64 dr->scale = 1.0F; 73
65 dr->me = me; 74 drawing_internal *dri = snew(drawing_internal);
66 dr->laststatus = NULL; 75 dri->pub.api = api;
67 return dr; 76 dri->pub.handle = handle;
77 dri->colours = NULL;
78 dri->ncolours = dri->coloursize = 0;
79 dri->scale = 1.0F;
80 dri->me = me;
81 dri->laststatus = NULL;
82 return PUBLIC_CAST(dri);
68} 83}
69 84
70void drawing_free(drawing *dr) 85void drawing_free(drawing *dr)
71{ 86{
72 sfree(dr->laststatus); 87 drawing_internal *dri = PRIVATE_CAST(dr);
73 sfree(dr->colours); 88 sfree(dri->laststatus);
74 sfree(dr); 89 sfree(dri->colours);
90 sfree(dri);
75} 91}
76 92
77void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, 93void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize,
78 int align, int colour, const char *text) 94 int align, int colour, const char *text)
79{ 95{
80 dr->api->draw_text(dr->handle, x, y, fonttype, fontsize, align, 96 drawing_internal *dri = PRIVATE_CAST(dr);
81 colour, text); 97 dri->pub.api->draw_text(dr, x, y, fonttype, fontsize, align,
98 colour, text);
82} 99}
83 100
84void draw_rect(drawing *dr, int x, int y, int w, int h, int colour) 101void draw_rect(drawing *dr, int x, int y, int w, int h, int colour)
85{ 102{
86 dr->api->draw_rect(dr->handle, x, y, w, h, colour); 103 drawing_internal *dri = PRIVATE_CAST(dr);
104 dri->pub.api->draw_rect(dr, x, y, w, h, colour);
87} 105}
88 106
89void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) 107void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour)
90{ 108{
91 dr->api->draw_line(dr->handle, x1, y1, x2, y2, colour); 109 drawing_internal *dri = PRIVATE_CAST(dr);
110 dri->pub.api->draw_line(dr, x1, y1, x2, y2, colour);
92} 111}
93 112
94void draw_thick_line(drawing *dr, float thickness, 113void draw_thick_line(drawing *dr, float thickness,
95 float x1, float y1, float x2, float y2, int colour) 114 float x1, float y1, float x2, float y2, int colour)
96{ 115{
116 drawing_internal *dri = PRIVATE_CAST(dr);
97 if (thickness < 1.0F) 117 if (thickness < 1.0F)
98 thickness = 1.0F; 118 thickness = 1.0F;
99 if (dr->api->draw_thick_line) { 119 if (dri->pub.api->draw_thick_line) {
100 dr->api->draw_thick_line(dr->handle, thickness, 120 dri->pub.api->draw_thick_line(dr, thickness,
101 x1, y1, x2, y2, colour); 121 x1, y1, x2, y2, colour);
102 } else { 122 } else {
103 /* We'll fake it up with a filled polygon. The tweak to the 123 /* We'll fake it up with a filled polygon. The tweak to the
104 * thickness empirically compensates for rounding errors, because 124 * thickness empirically compensates for rounding errors, because
@@ -117,59 +137,67 @@ void draw_thick_line(drawing *dr, float thickness,
117 p[5] = y2 - tvhatx; 137 p[5] = y2 - tvhatx;
118 p[6] = x1 + tvhaty; 138 p[6] = x1 + tvhaty;
119 p[7] = y1 - tvhatx; 139 p[7] = y1 - tvhatx;
120 dr->api->draw_polygon(dr->handle, p, 4, colour, colour); 140 dri->pub.api->draw_polygon(dr, p, 4, colour, colour);
121 } 141 }
122} 142}
123 143
124void draw_polygon(drawing *dr, const int *coords, int npoints, 144void draw_polygon(drawing *dr, const int *coords, int npoints,
125 int fillcolour, int outlinecolour) 145 int fillcolour, int outlinecolour)
126{ 146{
127 dr->api->draw_polygon(dr->handle, coords, npoints, fillcolour, 147 drawing_internal *dri = PRIVATE_CAST(dr);
128 outlinecolour); 148 dri->pub.api->draw_polygon(dr, coords, npoints, fillcolour,
149 outlinecolour);
129} 150}
130 151
131void draw_circle(drawing *dr, int cx, int cy, int radius, 152void draw_circle(drawing *dr, int cx, int cy, int radius,
132 int fillcolour, int outlinecolour) 153 int fillcolour, int outlinecolour)
133{ 154{
134 dr->api->draw_circle(dr->handle, cx, cy, radius, fillcolour, 155 drawing_internal *dri = PRIVATE_CAST(dr);
135 outlinecolour); 156 dri->pub.api->draw_circle(dr, cx, cy, radius, fillcolour,
157 outlinecolour);
136} 158}
137 159
138void draw_update(drawing *dr, int x, int y, int w, int h) 160void draw_update(drawing *dr, int x, int y, int w, int h)
139{ 161{
140 if (dr->api->draw_update) 162 drawing_internal *dri = PRIVATE_CAST(dr);
141 dr->api->draw_update(dr->handle, x, y, w, h); 163 if (dri->pub.api->draw_update)
164 dri->pub.api->draw_update(dr, x, y, w, h);
142} 165}
143 166
144void clip(drawing *dr, int x, int y, int w, int h) 167void clip(drawing *dr, int x, int y, int w, int h)
145{ 168{
146 dr->api->clip(dr->handle, x, y, w, h); 169 drawing_internal *dri = PRIVATE_CAST(dr);
170 dri->pub.api->clip(dr, x, y, w, h);
147} 171}
148 172
149void unclip(drawing *dr) 173void unclip(drawing *dr)
150{ 174{
151 dr->api->unclip(dr->handle); 175 drawing_internal *dri = PRIVATE_CAST(dr);
176 dri->pub.api->unclip(dr);
152} 177}
153 178
154void start_draw(drawing *dr) 179void start_draw(drawing *dr)
155{ 180{
156 dr->api->start_draw(dr->handle); 181 drawing_internal *dri = PRIVATE_CAST(dr);
182 dri->pub.api->start_draw(dr);
157} 183}
158 184
159void end_draw(drawing *dr) 185void end_draw(drawing *dr)
160{ 186{
161 dr->api->end_draw(dr->handle); 187 drawing_internal *dri = PRIVATE_CAST(dr);
188 dri->pub.api->end_draw(dr);
162} 189}
163 190
164char *text_fallback(drawing *dr, const char *const *strings, int nstrings) 191char *text_fallback(drawing *dr, const char *const *strings, int nstrings)
165{ 192{
193 drawing_internal *dri = PRIVATE_CAST(dr);
166 int i; 194 int i;
167 195
168 /* 196 /*
169 * If the drawing implementation provides one of these, use it. 197 * If the drawing implementation provides one of these, use it.
170 */ 198 */
171 if (dr && dr->api->text_fallback) 199 if (dr && dri->pub.api->text_fallback)
172 return dr->api->text_fallback(dr->handle, strings, nstrings); 200 return dri->pub.api->text_fallback(dr, strings, nstrings);
173 201
174 /* 202 /*
175 * Otherwise, do the simple thing and just pick the first string 203 * Otherwise, do the simple thing and just pick the first string
@@ -196,18 +224,19 @@ char *text_fallback(drawing *dr, const char *const *strings, int nstrings)
196 224
197void status_bar(drawing *dr, const char *text) 225void status_bar(drawing *dr, const char *text)
198{ 226{
227 drawing_internal *dri = PRIVATE_CAST(dr);
199 char *rewritten; 228 char *rewritten;
200 229
201 if (!dr->api->status_bar) 230 if (!dri->pub.api->status_bar)
202 return; 231 return;
203 232
204 assert(dr->me); 233 assert(dri->me);
205 234
206 rewritten = midend_rewrite_statusbar(dr->me, text); 235 rewritten = midend_rewrite_statusbar(dri->me, text);
207 if (!dr->laststatus || strcmp(rewritten, dr->laststatus)) { 236 if (!dri->laststatus || strcmp(rewritten, dri->laststatus)) {
208 dr->api->status_bar(dr->handle, rewritten); 237 dri->pub.api->status_bar(dr, rewritten);
209 sfree(dr->laststatus); 238 sfree(dri->laststatus);
210 dr->laststatus = rewritten; 239 dri->laststatus = rewritten;
211 } else { 240 } else {
212 sfree(rewritten); 241 sfree(rewritten);
213 } 242 }
@@ -215,74 +244,85 @@ void status_bar(drawing *dr, const char *text)
215 244
216blitter *blitter_new(drawing *dr, int w, int h) 245blitter *blitter_new(drawing *dr, int w, int h)
217{ 246{
218 return dr->api->blitter_new(dr->handle, w, h); 247 drawing_internal *dri = PRIVATE_CAST(dr);
248 return dri->pub.api->blitter_new(dr, w, h);
219} 249}
220 250
221void blitter_free(drawing *dr, blitter *bl) 251void blitter_free(drawing *dr, blitter *bl)
222{ 252{
223 dr->api->blitter_free(dr->handle, bl); 253 drawing_internal *dri = PRIVATE_CAST(dr);
254 dri->pub.api->blitter_free(dr, bl);
224} 255}
225 256
226void blitter_save(drawing *dr, blitter *bl, int x, int y) 257void blitter_save(drawing *dr, blitter *bl, int x, int y)
227{ 258{
228 dr->api->blitter_save(dr->handle, bl, x, y); 259 drawing_internal *dri = PRIVATE_CAST(dr);
260 dri->pub.api->blitter_save(dr, bl, x, y);
229} 261}
230 262
231void blitter_load(drawing *dr, blitter *bl, int x, int y) 263void blitter_load(drawing *dr, blitter *bl, int x, int y)
232{ 264{
233 dr->api->blitter_load(dr->handle, bl, x, y); 265 drawing_internal *dri = PRIVATE_CAST(dr);
266 dri->pub.api->blitter_load(dr, bl, x, y);
234} 267}
235 268
236void print_begin_doc(drawing *dr, int pages) 269void print_begin_doc(drawing *dr, int pages)
237{ 270{
238 dr->api->begin_doc(dr->handle, pages); 271 drawing_internal *dri = PRIVATE_CAST(dr);
272 dri->pub.api->begin_doc(dr, pages);
239} 273}
240 274
241void print_begin_page(drawing *dr, int number) 275void print_begin_page(drawing *dr, int number)
242{ 276{
243 dr->api->begin_page(dr->handle, number); 277 drawing_internal *dri = PRIVATE_CAST(dr);
278 dri->pub.api->begin_page(dr, number);
244} 279}
245 280
246void print_begin_puzzle(drawing *dr, float xm, float xc, 281void print_begin_puzzle(drawing *dr, float xm, float xc,
247 float ym, float yc, int pw, int ph, float wmm, 282 float ym, float yc, int pw, int ph, float wmm,
248 float scale) 283 float scale)
249{ 284{
250 dr->scale = scale; 285 drawing_internal *dri = PRIVATE_CAST(dr);
251 dr->ncolours = 0; 286 dri->scale = scale;
252 dr->api->begin_puzzle(dr->handle, xm, xc, ym, yc, pw, ph, wmm); 287 dri->ncolours = 0;
288 dri->pub.api->begin_puzzle(dr, xm, xc, ym, yc, pw, ph, wmm);
253} 289}
254 290
255void print_end_puzzle(drawing *dr) 291void print_end_puzzle(drawing *dr)
256{ 292{
257 dr->api->end_puzzle(dr->handle); 293 drawing_internal *dri = PRIVATE_CAST(dr);
258 dr->scale = 1.0F; 294 dri->pub.api->end_puzzle(dr);
295 dri->scale = 1.0F;
259} 296}
260 297
261void print_end_page(drawing *dr, int number) 298void print_end_page(drawing *dr, int number)
262{ 299{
263 dr->api->end_page(dr->handle, number); 300 drawing_internal *dri = PRIVATE_CAST(dr);
301 dri->pub.api->end_page(dr, number);
264} 302}
265 303
266void print_end_doc(drawing *dr) 304void print_end_doc(drawing *dr)
267{ 305{
268 dr->api->end_doc(dr->handle); 306 drawing_internal *dri = PRIVATE_CAST(dr);
307 dri->pub.api->end_doc(dr);
269} 308}
270 309
271void print_get_colour(drawing *dr, int colour, bool printing_in_colour, 310void print_get_colour(drawing *dr, int colour, bool printing_in_colour,
272 int *hatch, float *r, float *g, float *b) 311 int *hatch, float *r, float *g, float *b)
273{ 312{
274 assert(colour >= 0 && colour < dr->ncolours); 313 drawing_internal *dri = PRIVATE_CAST(dr);
275 if (dr->colours[colour].hatch_when == 2 || 314 assert(colour >= 0 && colour < dri->ncolours);
276 (dr->colours[colour].hatch_when == 1 && !printing_in_colour)) { 315 if (dri->colours[colour].hatch_when == 2 ||
277 *hatch = dr->colours[colour].hatch; 316 (dri->colours[colour].hatch_when == 1 && !printing_in_colour)) {
317 *hatch = dri->colours[colour].hatch;
278 } else { 318 } else {
279 *hatch = -1; 319 *hatch = -1;
280 if (printing_in_colour) { 320 if (printing_in_colour) {
281 *r = dr->colours[colour].r; 321 *r = dri->colours[colour].r;
282 *g = dr->colours[colour].g; 322 *g = dri->colours[colour].g;
283 *b = dr->colours[colour].b; 323 *b = dri->colours[colour].b;
284 } else { 324 } else {
285 *r = *g = *b = dr->colours[colour].grey; 325 *r = *g = *b = dri->colours[colour].grey;
286 } 326 }
287 } 327 }
288} 328}
@@ -290,18 +330,19 @@ void print_get_colour(drawing *dr, int colour, bool printing_in_colour,
290static int print_generic_colour(drawing *dr, float r, float g, float b, 330static int print_generic_colour(drawing *dr, float r, float g, float b,
291 float grey, int hatch, int hatch_when) 331 float grey, int hatch, int hatch_when)
292{ 332{
293 if (dr->ncolours >= dr->coloursize) { 333 drawing_internal *dri = PRIVATE_CAST(dr);
294 dr->coloursize = dr->ncolours + 16; 334 if (dri->ncolours >= dri->coloursize) {
295 dr->colours = sresize(dr->colours, dr->coloursize, 335 dri->coloursize = dri->ncolours + 16;
336 dri->colours = sresize(dri->colours, dri->coloursize,
296 struct print_colour); 337 struct print_colour);
297 } 338 }
298 dr->colours[dr->ncolours].hatch = hatch; 339 dri->colours[dri->ncolours].hatch = hatch;
299 dr->colours[dr->ncolours].hatch_when = hatch_when; 340 dri->colours[dri->ncolours].hatch_when = hatch_when;
300 dr->colours[dr->ncolours].r = r; 341 dri->colours[dri->ncolours].r = r;
301 dr->colours[dr->ncolours].g = g; 342 dri->colours[dri->ncolours].g = g;
302 dr->colours[dr->ncolours].b = b; 343 dri->colours[dri->ncolours].b = b;
303 dr->colours[dr->ncolours].grey = grey; 344 dri->colours[dri->ncolours].grey = grey;
304 return dr->ncolours++; 345 return dri->ncolours++;
305} 346}
306 347
307int print_mono_colour(drawing *dr, int grey) 348int print_mono_colour(drawing *dr, int grey)
@@ -336,6 +377,8 @@ int print_rgb_hatched_colour(drawing *dr, float r, float g, float b, int hatch)
336 377
337void print_line_width(drawing *dr, int width) 378void print_line_width(drawing *dr, int width)
338{ 379{
380 drawing_internal *dri = PRIVATE_CAST(dr);
381
339 /* 382 /*
340 * I don't think it's entirely sensible to have line widths be 383 * I don't think it's entirely sensible to have line widths be
341 * entirely relative to the puzzle size; there is a point 384 * entirely relative to the puzzle size; there is a point
@@ -348,10 +391,11 @@ void print_line_width(drawing *dr, int width)
348 * _square root_ of the main puzzle scale. Double the puzzle 391 * _square root_ of the main puzzle scale. Double the puzzle
349 * size, and the line width multiplies by 1.4. 392 * size, and the line width multiplies by 1.4.
350 */ 393 */
351 dr->api->line_width(dr->handle, (float)sqrt(dr->scale) * width); 394 dri->pub.api->line_width(dr, (float)sqrt(dri->scale) * width);
352} 395}
353 396
354void print_line_dotted(drawing *dr, bool dotted) 397void print_line_dotted(drawing *dr, bool dotted)
355{ 398{
356 dr->api->line_dotted(dr->handle, dotted); 399 drawing_internal *dri = PRIVATE_CAST(dr);
400 dri->pub.api->line_dotted(dr, dotted);
357} 401}
diff --git a/apps/plugins/puzzles/src/inertia.c b/apps/plugins/puzzles/src/inertia.c
index 1d5a028add..fe174f3b56 100644
--- a/apps/plugins/puzzles/src/inertia.c
+++ b/apps/plugins/puzzles/src/inertia.c
@@ -722,18 +722,6 @@ static int move_goes_to(int w, int h, char *grid, int x, int y, int d)
722 return (y*w+x)*DP1+dr; 722 return (y*w+x)*DP1+dr;
723} 723}
724 724
725static int compare_integers(const void *av, const void *bv)
726{
727 const int *a = (const int *)av;
728 const int *b = (const int *)bv;
729 if (*a < *b)
730 return -1;
731 else if (*a > *b)
732 return +1;
733 else
734 return 0;
735}
736
737static char *solve_game(const game_state *state, const game_state *currstate, 725static char *solve_game(const game_state *state, const game_state *currstate,
738 const char *aux, const char **error) 726 const char *aux, const char **error)
739{ 727{
@@ -1886,11 +1874,6 @@ static void draw_player(drawing *dr, game_drawstate *ds, int x, int y,
1886 coords[d*4+2] = x + TILESIZE/2 + (int)((TILESIZE*3/7) * x2); 1874 coords[d*4+2] = x + TILESIZE/2 + (int)((TILESIZE*3/7) * x2);
1887 coords[d*4+3] = y + TILESIZE/2 + (int)((TILESIZE*3/7) * y2); 1875 coords[d*4+3] = y + TILESIZE/2 + (int)((TILESIZE*3/7) * y2);
1888 } 1876 }
1889 /* rockbox hack */
1890 int tmp[2] = { coords[0], coords[1] };
1891 memmove(coords, coords + 2, sizeof(int) * DIRECTIONS * 4 - 2);
1892 memcpy(coords + DIRECTIONS * 4 - 2, tmp, 2 * sizeof(int));
1893
1894 draw_polygon(dr, coords, DIRECTIONS*2, COL_DEAD_PLAYER, COL_OUTLINE); 1877 draw_polygon(dr, coords, DIRECTIONS*2, COL_DEAD_PLAYER, COL_OUTLINE);
1895 } else { 1878 } else {
1896 draw_circle(dr, x + TILESIZE/2, y + TILESIZE/2, 1879 draw_circle(dr, x + TILESIZE/2, y + TILESIZE/2,
@@ -1906,6 +1889,8 @@ static void draw_player(drawing *dr, game_drawstate *ds, int x, int y,
1906 int coords[14], *c; 1889 int coords[14], *c;
1907 1890
1908 c = coords; 1891 c = coords;
1892 *c++ = ox + px/9;
1893 *c++ = oy + py/9;
1909 *c++ = ox + px/9 + ax*2/3; 1894 *c++ = ox + px/9 + ax*2/3;
1910 *c++ = oy + py/9 + ay*2/3; 1895 *c++ = oy + py/9 + ay*2/3;
1911 *c++ = ox + px/3 + ax*2/3; 1896 *c++ = ox + px/3 + ax*2/3;
@@ -1918,8 +1903,6 @@ static void draw_player(drawing *dr, game_drawstate *ds, int x, int y,
1918 *c++ = oy - py/9 + ay*2/3; 1903 *c++ = oy - py/9 + ay*2/3;
1919 *c++ = ox - px/9; 1904 *c++ = ox - px/9;
1920 *c++ = oy - py/9; 1905 *c++ = oy - py/9;
1921 *c++ = ox + px/9;
1922 *c++ = oy + py/9;
1923 draw_polygon(dr, coords, 7, COL_HINT, COL_OUTLINE); 1906 draw_polygon(dr, coords, 7, COL_HINT, COL_OUTLINE);
1924 } 1907 }
1925 1908
diff --git a/apps/plugins/puzzles/src/mines.c b/apps/plugins/puzzles/src/mines.c
index eec898ac6f..e1441fae13 100644
--- a/apps/plugins/puzzles/src/mines.c
+++ b/apps/plugins/puzzles/src/mines.c
@@ -2867,12 +2867,12 @@ static void draw_tile(drawing *dr, game_drawstate *ds,
2867 coords[(n)*2+0] = x + (int)(TILE_SIZE * (dx)); \ 2867 coords[(n)*2+0] = x + (int)(TILE_SIZE * (dx)); \
2868 coords[(n)*2+1] = y + (int)(TILE_SIZE * (dy)); \ 2868 coords[(n)*2+1] = y + (int)(TILE_SIZE * (dy)); \
2869} while (0) 2869} while (0)
2870 SETCOORD(0, 0.6F, 0.7F); 2870 SETCOORD(0, 0.6F, 0.35F);
2871 SETCOORD(1, 0.8F, 0.8F); 2871 SETCOORD(1, 0.6F, 0.7F);
2872 SETCOORD(2, 0.25F, 0.8F); 2872 SETCOORD(2, 0.8F, 0.8F);
2873 SETCOORD(3, 0.55F, 0.7F); 2873 SETCOORD(3, 0.25F, 0.8F);
2874 SETCOORD(4, 0.55F, 0.35F); 2874 SETCOORD(4, 0.55F, 0.7F);
2875 SETCOORD(5, 0.6F, 0.35F); 2875 SETCOORD(5, 0.55F, 0.35F);
2876 draw_polygon(dr, coords, 6, COL_FLAGBASE, COL_FLAGBASE); 2876 draw_polygon(dr, coords, 6, COL_FLAGBASE, COL_FLAGBASE);
2877 2877
2878 SETCOORD(0, 0.6F, 0.2F); 2878 SETCOORD(0, 0.6F, 0.2F);
diff --git a/apps/plugins/puzzles/src/misc.c b/apps/plugins/puzzles/src/misc.c
index f9eaf5d9b8..8e96d67039 100644
--- a/apps/plugins/puzzles/src/misc.c
+++ b/apps/plugins/puzzles/src/misc.c
@@ -351,6 +351,17 @@ void draw_rect_corners(drawing *dr, int cx, int cy, int r, int col)
351 draw_line(dr, cx + r, cy + r, cx + r/2, cy + r, col); 351 draw_line(dr, cx + r, cy + r, cx + r/2, cy + r, col);
352} 352}
353 353
354int compare_integers(const void *av, const void *bv) {
355 const int *a = (const int *)av;
356 const int *b = (const int *)bv;
357 if (*a < *b)
358 return -1;
359 else if (*a > *b)
360 return +1;
361 else
362 return 0;
363}
364
354char *move_cursor(int button, int *x, int *y, int maxw, int maxh, bool wrap, 365char *move_cursor(int button, int *x, int *y, int maxw, int maxh, bool wrap,
355 bool *visible) 366 bool *visible)
356{ 367{
diff --git a/apps/plugins/puzzles/src/puzzles.but b/apps/plugins/puzzles/src/puzzles.but
index fa9384252e..0eb3511cc0 100644
--- a/apps/plugins/puzzles/src/puzzles.but
+++ b/apps/plugins/puzzles/src/puzzles.but
@@ -3442,7 +3442,7 @@ real challenge, set this value to 0 and then try to solve a grid in
3442 3442
3443} 3443}
3444 3444
3445\C{tracks} \i{Train Tracks} 3445\C{tracks} \i{Tracks}
3446 3446
3447\cfg{winhelp-topic}{games.tracks} 3447\cfg{winhelp-topic}{games.tracks}
3448 3448
@@ -3454,9 +3454,9 @@ clues to the top and right of the grid.
3454There are only straight and 90 degree curved rails, and the track may not 3454There are only straight and 90 degree curved rails, and the track may not
3455cross itself. 3455cross itself.
3456 3456
3457Train Tracks was contributed to this collection by James Harvey. 3457Tracks was contributed to this collection by James Harvey.
3458 3458
3459\H{tracks-controls} \I{controls, for Tracks}Train Tracks controls 3459\H{tracks-controls} \I{controls, for Tracks}Tracks controls
3460 3460
3461Left-clicking on an edge between two squares adds a track segment between 3461Left-clicking on an edge between two squares adds a track segment between
3462the two squares. Right-clicking on an edge adds a cross on the edge, 3462the two squares. Right-clicking on an edge adds a cross on the edge,
@@ -3473,7 +3473,7 @@ columns to match the clue.
3473 3473
3474(All the actions described in \k{common-actions} are also available.) 3474(All the actions described in \k{common-actions} are also available.)
3475 3475
3476\H{tracks-parameters} \I{parameters, for Tracks}Train Tracks parameters 3476\H{tracks-parameters} \I{parameters, for Tracks}Tracks parameters
3477 3477
3478These parameters are available from the \q{Custom...} option on the 3478These parameters are available from the \q{Custom...} option on the
3479\q{Type} menu. 3479\q{Type} menu.
@@ -3490,12 +3490,12 @@ that would lead to impossible crossings later.
3490 3490
3491\dt \e{Disallow consecutive 1 clues} 3491\dt \e{Disallow consecutive 1 clues}
3492 3492
3493\dd Controls whether the Train Tracks game generation permits two 3493\dd Controls whether the Tracks game generation permits two adjacent
3494adjacent rows or columns to have a 1 clue, or permits the row or 3494rows or columns to have a 1 clue, or permits the row or column of the
3495column of the track's endpoint to have a 1 clue. By default this is 3495track's endpoint to have a 1 clue. By default this is not permitted,
3496not permitted, to avoid long straight boring segments of track and 3496to avoid long straight boring segments of track and make the games
3497make the games more twiddly and interesting. If you want to restore 3497more twiddly and interesting. If you want to restore the possibility,
3498the possibility, turn this option off. 3498turn this option off.
3499 3499
3500 3500
3501\C{palisade} \i{Palisade} 3501\C{palisade} \i{Palisade}
diff --git a/apps/plugins/puzzles/src/puzzles.h b/apps/plugins/puzzles/src/puzzles.h
index 2c52bc6cde..44a056d78f 100644
--- a/apps/plugins/puzzles/src/puzzles.h
+++ b/apps/plugins/puzzles/src/puzzles.h
@@ -266,6 +266,8 @@ void draw_rect(drawing *dr, int x, int y, int w, int h, int colour);
266void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour); 266void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour);
267void draw_polygon(drawing *dr, const int *coords, int npoints, 267void draw_polygon(drawing *dr, const int *coords, int npoints,
268 int fillcolour, int outlinecolour); 268 int fillcolour, int outlinecolour);
269void draw_polygon_fallback(drawing *dr, const int *coords, int npoints,
270 int fillcolour, int outlinecolour);
269void draw_circle(drawing *dr, int cx, int cy, int radius, 271void draw_circle(drawing *dr, int cx, int cy, int radius,
270 int fillcolour, int outlinecolour); 272 int fillcolour, int outlinecolour);
271void draw_thick_line(drawing *dr, float thickness, 273void draw_thick_line(drawing *dr, float thickness,
@@ -454,6 +456,9 @@ char *button2label(int button);
454 * standard per clause 7.26.11.1.) */ 456 * standard per clause 7.26.11.1.) */
455void swap_regions(void *av, void *bv, size_t size); 457void swap_regions(void *av, void *bv, size_t size);
456 458
459/* comparator for sorting ints with qsort() */
460int compare_integers(const void *av, const void *bv);
461
457/* 462/*
458 * dsf.c 463 * dsf.c
459 */ 464 */
@@ -752,43 +757,76 @@ struct game {
752 int flags; 757 int flags;
753}; 758};
754 759
760#define GET_HANDLE_AS_TYPE(dr, type) ((type*)((dr)->handle))
761
762struct drawing {
763 const drawing_api *api;
764 void *handle;
765};
766
755/* 767/*
756 * Data structure containing the drawing API implemented by the 768 * Data structure containing the drawing API implemented by the
757 * front end and also by cross-platform printing modules such as 769 * front end and also by cross-platform printing modules such as
758 * PostScript. 770 * PostScript.
759 */ 771 */
760struct drawing_api { 772struct drawing_api {
761 void (*draw_text)(void *handle, int x, int y, int fonttype, int fontsize, 773 /*
774 * API version. Increment this when there is a breaking change to
775 * this API which requires front ends to change.
776 *
777 * There is expliclty not a public LATEST_API_VERSION define, so
778 * that front end authors will need to manually intervene when the
779 * version number changes. Naturally, this should be done
780 * sparingly.
781 *
782 * If a function is ever added to this API, please move this field
783 * to the _end_ of the structure, so that changes thereafter will
784 * shift the position of the version and lead to a compilation
785 * error if old implementations are not updated. Then remove this
786 * comment.
787 *
788 * The latest version number is 1.
789 *
790 * Change log:
791 *
792 * Version 1 (2024-08-14): Introduction of version number, in
793 * conjunction with changing every API function to take `drawing
794 * *` instead of `void *`. See commit f379130 for the detailed
795 * rationale behind this change.
796 */
797 int version;
798
799 void (*draw_text)(drawing *dr, int x, int y, int fonttype, int fontsize,
762 int align, int colour, const char *text); 800 int align, int colour, const char *text);
763 void (*draw_rect)(void *handle, int x, int y, int w, int h, int colour); 801 void (*draw_rect)(drawing *dr, int x, int y, int w, int h, int colour);
764 void (*draw_line)(void *handle, int x1, int y1, int x2, int y2, 802 void (*draw_line)(drawing *dr, int x1, int y1, int x2, int y2,
765 int colour); 803 int colour);
766 void (*draw_polygon)(void *handle, const int *coords, int npoints, 804 void (*draw_polygon)(drawing *dr, const int *coords, int npoints,
767 int fillcolour, int outlinecolour); 805 int fillcolour, int outlinecolour);
768 void (*draw_circle)(void *handle, int cx, int cy, int radius, 806 void (*draw_circle)(drawing *dr, int cx, int cy, int radius,
769 int fillcolour, int outlinecolour); 807 int fillcolour, int outlinecolour);
770 void (*draw_update)(void *handle, int x, int y, int w, int h); 808 void (*draw_update)(drawing *dr, int x, int y, int w, int h);
771 void (*clip)(void *handle, int x, int y, int w, int h); 809 void (*clip)(drawing *dr, int x, int y, int w, int h);
772 void (*unclip)(void *handle); 810 void (*unclip)(drawing *dr);
773 void (*start_draw)(void *handle); 811 void (*start_draw)(drawing *dr);
774 void (*end_draw)(void *handle); 812 void (*end_draw)(drawing *dr);
775 void (*status_bar)(void *handle, const char *text); 813 void (*status_bar)(drawing *dr, const char *text);
776 blitter *(*blitter_new)(void *handle, int w, int h); 814 blitter *(*blitter_new)(drawing *dr, int w, int h);
777 void (*blitter_free)(void *handle, blitter *bl); 815 void (*blitter_free)(drawing *dr, blitter *bl);
778 void (*blitter_save)(void *handle, blitter *bl, int x, int y); 816 void (*blitter_save)(drawing *dr, blitter *bl, int x, int y);
779 void (*blitter_load)(void *handle, blitter *bl, int x, int y); 817 void (*blitter_load)(drawing *dr, blitter *bl, int x, int y);
780 void (*begin_doc)(void *handle, int pages); 818 void (*begin_doc)(drawing *dr, int pages);
781 void (*begin_page)(void *handle, int number); 819 void (*begin_page)(drawing *dr, int number);
782 void (*begin_puzzle)(void *handle, float xm, float xc, 820 void (*begin_puzzle)(drawing *dr, float xm, float xc,
783 float ym, float yc, int pw, int ph, float wmm); 821 float ym, float yc, int pw, int ph, float wmm);
784 void (*end_puzzle)(void *handle); 822 void (*end_puzzle)(drawing *dr);
785 void (*end_page)(void *handle, int number); 823 void (*end_page)(drawing *dr, int number);
786 void (*end_doc)(void *handle); 824 void (*end_doc)(drawing *dr);
787 void (*line_width)(void *handle, float width); 825 void (*line_width)(drawing *dr, float width);
788 void (*line_dotted)(void *handle, bool dotted); 826 void (*line_dotted)(drawing *dr, bool dotted);
789 char *(*text_fallback)(void *handle, const char *const *strings, 827 char *(*text_fallback)(drawing *dr, const char *const *strings,
790 int nstrings); 828 int nstrings);
791 void (*draw_thick_line)(void *handle, float thickness, 829 void (*draw_thick_line)(drawing *dr, float thickness,
792 float x1, float y1, float x2, float y2, 830 float x1, float y1, float x2, float y2,
793 int colour); 831 int colour);
794}; 832};
diff --git a/apps/plugins/puzzles/src/signpost.c b/apps/plugins/puzzles/src/signpost.c
index 4d2f5849fd..9aed67bb4a 100644
--- a/apps/plugins/puzzles/src/signpost.c
+++ b/apps/plugins/puzzles/src/signpost.c
@@ -1895,9 +1895,8 @@ static void draw_star(drawing *dr, int cx, int cy, int rad, int npoints,
1895 coords = snewn(npoints * 2 * 2, int); 1895 coords = snewn(npoints * 2 * 2, int);
1896 1896
1897 for (n = 0; n < npoints * 2; n++) { 1897 for (n = 0; n < npoints * 2; n++) {
1898 /* hack to accomodate rockbox's concave polygon drawing */ 1898 a = 2.0 * PI * ((double)n / ((double)npoints * 2.0)) + angle_offset;
1899 a = 2.0 * PI * ((double)n / ((double)npoints * 2.0)) + angle_offset - PI / npoints; 1899 r = (n % 2) ? (double)rad/2.0 : (double)rad;
1900 r = (n % 2 == 0) ? (double)rad/2.0 : (double)rad;
1901 1900
1902 /* We're rotating the point at (0, -r) by a degrees */ 1901 /* We're rotating the point at (0, -r) by a degrees */
1903 coords[2*n+0] = cx + (int)( r * sin(a)); 1902 coords[2*n+0] = cx + (int)( r * sin(a));
diff --git a/apps/plugins/puzzles/src/twiddle.c b/apps/plugins/puzzles/src/twiddle.c
index b3aa06f1d5..49d8db7825 100644
--- a/apps/plugins/puzzles/src/twiddle.c
+++ b/apps/plugins/puzzles/src/twiddle.c
@@ -532,18 +532,6 @@ static void free_game(game_state *state)
532 sfree(state); 532 sfree(state);
533} 533}
534 534
535static int compare_int(const void *av, const void *bv)
536{
537 const int *a = (const int *)av;
538 const int *b = (const int *)bv;
539 if (*a < *b)
540 return -1;
541 else if (*a > *b)
542 return +1;
543 else
544 return 0;
545}
546
547static char *solve_game(const game_state *state, const game_state *currstate, 535static char *solve_game(const game_state *state, const game_state *currstate,
548 const char *aux, const char **error) 536 const char *aux, const char **error)
549{ 537{
@@ -758,7 +746,7 @@ static game_state *execute_move(const game_state *from, const char *move)
758 * conveniently being able to get hold of a clean state from 746 * conveniently being able to get hold of a clean state from
759 * which to practise manoeuvres. 747 * which to practise manoeuvres.
760 */ 748 */
761 qsort(ret->grid, ret->w*ret->h, sizeof(int), compare_int); 749 qsort(ret->grid, ret->w*ret->h, sizeof(int), compare_integers);
762 for (i = 0; i < ret->w*ret->h; i++) 750 for (i = 0; i < ret->w*ret->h; i++)
763 ret->grid[i] &= ~3; 751 ret->grid[i] &= ~3;
764 ret->used_solve = true; 752 ret->used_solve = true;
diff --git a/apps/plugins/puzzles/src/unequal.c b/apps/plugins/puzzles/src/unequal.c
index 008dab3a0b..ab32e4ab79 100644
--- a/apps/plugins/puzzles/src/unequal.c
+++ b/apps/plugins/puzzles/src/unequal.c
@@ -1844,18 +1844,18 @@ static void draw_gt(drawing *dr, int ox, int oy,
1844{ 1844{
1845 int coords[12]; 1845 int coords[12];
1846 int xdx = (dx1+dx2 ? 0 : 1), xdy = (dx1+dx2 ? 1 : 0); 1846 int xdx = (dx1+dx2 ? 0 : 1), xdy = (dx1+dx2 ? 1 : 0);
1847 coords[0] = ox + xdx + dx1; 1847 coords[0] = ox + xdx;
1848 coords[1] = oy + xdy + dy1; 1848 coords[1] = oy + xdy;
1849 coords[2] = ox + xdx + dx1 + dx2; 1849 coords[2] = ox + xdx + dx1;
1850 coords[3] = oy + xdy + dy1 + dy2; 1850 coords[3] = oy + xdy + dy1;
1851 coords[4] = ox - xdx + dx1 + dx2; 1851 coords[4] = ox + xdx + dx1 + dx2;
1852 coords[5] = oy - xdy + dy1 + dy2; 1852 coords[5] = oy + xdy + dy1 + dy2;
1853 coords[6] = ox - xdx + dx1; 1853 coords[6] = ox - xdx + dx1 + dx2;
1854 coords[7] = oy - xdy + dy1; 1854 coords[7] = oy - xdy + dy1 + dy2;
1855 coords[8] = ox - xdx; 1855 coords[8] = ox - xdx + dx1;
1856 coords[9] = oy - xdy; 1856 coords[9] = oy - xdy + dy1;
1857 coords[10] = ox + xdx; 1857 coords[10] = ox - xdx;
1858 coords[11] = oy + xdy; 1858 coords[11] = oy - xdy;
1859 draw_polygon(dr, coords, 6, col, col); 1859 draw_polygon(dr, coords, 6, col, col);
1860} 1860}
1861 1861