summaryrefslogtreecommitdiffstats
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
parent903e8c5b32285e50907e6525388162bd459cbef8 (diff)
downloadrockbox-ea0e3704a8.tar.gz
rockbox-ea0e3704a8.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
-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
This is the readme for the Rockbox port of Simon Tatham's Portable
Puzzle Collection.
-The upstream version used is subject to change, as it should be
-relatively trivial to update it to a newer version. Simply copying the
-upstream repo's contents into src/ and running genhelp.sh ought to do
-it (watch out for API changes, though!).
-
Source structure
================
@@ -44,16 +39,8 @@ to Untangle and Palisade). These divergent changes complicated
maintenance of this port, as merge conflicts often arose when upstream
changes to these games conflicted with our changes. To remedy this, I
sent most of these patches back upstream in summer 2024, and since
-then, Simon has merged the majority of them into his tree.
-
-This leaves us with a very small set of places where our branch of the
-puzzles source diverges from Simon's. That branch lives here:
-
-https://github.com/built1n/puzzles/tree/rockbox-devel
-
-Notably, there are several hacks which work around Rockbox's lack of a
-proper polygon filling algorithm. Eliminating this deficiency would
-enable us to use a totally unmodified upstream source tree.
+then, Simon has merged them into his repo. We are now able to run with
+a fully unmodified puzzles source tree.
Maintenance
===========
@@ -62,7 +49,7 @@ Simon's upstream tree sees continued development. The port is
structured so that integrating new upstream versions is
straightforward: all the upstream sources live in the src/
subdirectory; all of the Rockbox frontend lives in the root
-apps/pluginspuzzles/ directory.
+apps/plugins/puzzles/ directory.
The `resync.sh' shell script automates the resyncing process. It
copies the upstream sources (point it to a local copy of the
@@ -77,9 +64,7 @@ The LZ4 library and GCC are necessary as well.
Wishlist
========
-- Proper polygon filling algorithm. The current algorithm is a hack
- that uses overdrawn triangles. This will enable us to eliminate the
- last of the Rockbox-specific modifications.
+- Nothing!
Kudos to Simon (duh), and Frank, for telling me about it.
@@ -120,3 +105,6 @@ Implement user preferences menu. Introduced "Mosaic".
August 2024: Resync to ee5e327 (branched from Simon's
1c1899e). Changes default Map stipple size to "Small".
+
+August 2024: Resync to Simon's 262f709 (unmodified). Uses new scanline
+polygon 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
/* puzzles core sources */
src/combi.c
src/divvy.c
+src/draw-poly.c
src/drawing.c
src/dsf.c
src/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 @@
struct style_text help_text_style[] = {
{ 0, TEXT_CENTER | C_RED },
- { 88, TEXT_CENTER | C_RED },
- { 209, TEXT_CENTER | C_RED },
+ { 87, TEXT_CENTER | C_RED },
+ { 208, TEXT_CENTER | C_RED },
+ { 225, TEXT_UNDERLINE },
{ 226, TEXT_UNDERLINE },
- { 227, TEXT_UNDERLINE },
- { 238, TEXT_UNDERLINE },
- { 270, TEXT_UNDERLINE },
+ { 237, TEXT_UNDERLINE },
+ { 269, TEXT_UNDERLINE },
LAST_STYLE_ITEM
};
-/* orig 1917 comp 1289 ratio 0.672405 level 10 saved 628 */
+/* orig 1881 comp 1282 ratio 0.681552 level 10 saved 599 */
const char help_text[] = {
-0xf0, 0x02, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
-0x34, 0x30, 0x3a, 0x20, 0x54, 0x72, 0x61, 0x69, 0x6e, 0x06,
-0x00, 0x6f, 0x63, 0x6b, 0x73, 0x20, 0x00, 0x2d, 0x01, 0x00,
-0x04, 0xf0, 0x19, 0x00, 0x00, 0x00, 0x59, 0x6f, 0x75, 0x00,
-0x61, 0x72, 0x65, 0x00, 0x67, 0x69, 0x76, 0x65, 0x6e, 0x00,
-0x61, 0x00, 0x67, 0x72, 0x69, 0x64, 0x00, 0x6f, 0x66, 0x00,
-0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x2c, 0x00, 0x73,
-0x6f, 0x6d, 0x65, 0x11, 0x00, 0x51, 0x77, 0x68, 0x69, 0x63,
-0x68, 0x2b, 0x00, 0xd0, 0x66, 0x69, 0x6c, 0x6c, 0x65, 0x64,
-0x00, 0x77, 0x69, 0x74, 0x68, 0x00, 0x74, 0x68, 0x00, 0x21,
-0x00, 0x74, 0x68, 0x00, 0x11, 0x2e, 0x4d, 0x00, 0xf2, 0x05,
-0x6e, 0x65, 0x65, 0x64, 0x00, 0x74, 0x6f, 0x00, 0x63, 0x6f,
-0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x00, 0x74, 0x68, 0x65,
-0x21, 0x00, 0x70, 0x00, 0x66, 0x72, 0x6f, 0x6d, 0x00, 0x41,
-0x1d, 0x00, 0x91, 0x42, 0x00, 0x73, 0x6f, 0x00, 0x74, 0x68,
-0x61, 0x74, 0x1e, 0x00, 0xf1, 0x06, 0x72, 0x6f, 0x77, 0x73,
-0x00, 0x61, 0x6e, 0x64, 0x00, 0x63, 0x6f, 0x6c, 0x75, 0x6d,
-0x6e, 0x73, 0x00, 0x63, 0x6f, 0x6e, 0x74, 0x58, 0x00, 0xe0,
-0x68, 0x65, 0x00, 0x73, 0x61, 0x6d, 0x65, 0x00, 0x6e, 0x75,
-0x6d, 0x62, 0x65, 0x72, 0x87, 0x00, 0x02, 0x4a, 0x00, 0xb1,
-0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x00, 0x61,
-0x73, 0x93, 0x00, 0xa3, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61,
-0x74, 0x65, 0x64, 0x00, 0x36, 0x00, 0x50, 0x63, 0x6c, 0x75,
-0x65, 0x73, 0x6a, 0x00, 0x01, 0x7e, 0x00, 0x21, 0x6f, 0x70,
-0x5f, 0x00, 0x51, 0x72, 0x69, 0x67, 0x68, 0x74, 0x45, 0x00,
-0x21, 0x68, 0x65, 0xe9, 0x00, 0x91, 0x2e, 0x00, 0x00, 0x00,
-0x54, 0x68, 0x65, 0x72, 0x65, 0x45, 0x00, 0x60, 0x6f, 0x6e,
-0x6c, 0x79, 0x00, 0x73, 0xd2, 0x00, 0x00, 0x27, 0x00, 0x00,
-0x31, 0x00, 0xf1, 0x08, 0x39, 0x30, 0x00, 0x64, 0x65, 0x67,
-0x72, 0x65, 0x65, 0x00, 0x63, 0x75, 0x72, 0x76, 0x65, 0x64,
-0x00, 0x72, 0x61, 0x69, 0x6c, 0x73, 0x2c, 0x1c, 0x00, 0x06,
-0xd7, 0x00, 0xf1, 0x05, 0x6d, 0x61, 0x79, 0x00, 0x6e, 0x6f,
-0x74, 0x00, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x00, 0x69, 0x74,
-0x73, 0x65, 0x6c, 0x66, 0x5a, 0x00, 0x01, 0x1c, 0x01, 0x02,
-0x84, 0x01, 0x32, 0x00, 0x77, 0x61, 0xd7, 0x00, 0x40, 0x72,
-0x69, 0x62, 0x75, 0xa8, 0x00, 0x01, 0x9b, 0x00, 0x20, 0x69,
-0x73, 0xf3, 0x00, 0xf0, 0x08, 0x6c, 0x65, 0x63, 0x74, 0x69,
-0x6f, 0x6e, 0x00, 0x62, 0x79, 0x00, 0x4a, 0x61, 0x6d, 0x65,
-0x73, 0x00, 0x48, 0x61, 0x72, 0x76, 0x65, 0x79, 0x43, 0x00,
-0x4a, 0x34, 0x30, 0x2e, 0x31, 0xcc, 0x01, 0x01, 0x44, 0x00,
-0xf4, 0x1c, 0x6f, 0x6c, 0x73, 0x20, 0x00, 0x00, 0x00, 0x4c,
-0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x69,
-0x6e, 0x67, 0x00, 0x6f, 0x6e, 0x00, 0x61, 0x6e, 0x00, 0x65,
-0x64, 0x67, 0x65, 0x00, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65,
-0x6e, 0x00, 0x74, 0x77, 0x6f, 0xc9, 0x01, 0x7a, 0x00, 0x61,
-0x64, 0x64, 0x73, 0x00, 0x61, 0x40, 0x01, 0x06, 0x29, 0x00,
-0x28, 0x68, 0x65, 0x2d, 0x00, 0x30, 0x2e, 0x00, 0x52, 0x04,
-0x01, 0x0f, 0x5c, 0x00, 0x02, 0x03, 0x48, 0x00, 0x02, 0xed,
-0x00, 0x12, 0x6f, 0x3b, 0x00, 0x00, 0x19, 0x00, 0x14, 0x2c,
-0x85, 0x01, 0x00, 0x30, 0x00, 0x23, 0x6e, 0x6f, 0x69, 0x00,
-0xa1, 0x69, 0x73, 0x00, 0x70, 0x6f, 0x73, 0x73, 0x69, 0x62,
-0x6c, 0x09, 0x02, 0x3d, 0x72, 0x65, 0x2e, 0xb8, 0x00, 0x10,
-0x69, 0x77, 0x02, 0x02, 0x79, 0x00, 0x05, 0x5d, 0x00, 0x54,
-0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x51, 0x00, 0x70, 0x6f, 0x72,
-0x00, 0x73, 0x68, 0x6f, 0x77, 0x2c, 0x00, 0x01, 0x33, 0x02,
-0x82, 0x79, 0x6f, 0x75, 0x00, 0x6b, 0x6e, 0x6f, 0x77, 0x1f,
-0x02, 0x02, 0x39, 0x00, 0x45, 0x6d, 0x75, 0x73, 0x74, 0x37,
-0x02, 0x03, 0xe6, 0x00, 0x30, 0x2c, 0x00, 0x65, 0xd4, 0x02,
-0x21, 0x69, 0x66, 0x32, 0x00, 0x52, 0x64, 0x6f, 0x6e, 0x27,
-0x74, 0x38, 0x00, 0x02, 0xcb, 0x02, 0x00, 0xb5, 0x00, 0x00,
-0xaf, 0x01, 0x02, 0xcb, 0x00, 0x6d, 0x65, 0x73, 0x00, 0x79,
-0x65, 0x74, 0xf9, 0x00, 0x0e, 0x9d, 0x00, 0x04, 0xe7, 0x01,
-0x06, 0xed, 0x00, 0x15, 0x69, 0x7a, 0x00, 0x16, 0x73, 0xf9,
-0x00, 0x03, 0x62, 0x01, 0x05, 0xef, 0x00, 0x32, 0x00, 0x6f,
-0x72, 0x80, 0x02, 0x60, 0x2d, 0x64, 0x72, 0x61, 0x67, 0x67,
-0x38, 0x00, 0x04, 0x7d, 0x01, 0x05, 0xa2, 0x01, 0x20, 0x6c,
-0x6c, 0x09, 0x03, 0x00, 0xad, 0x00, 0x86, 0x74, 0x6f, 0x00,
-0x6c, 0x61, 0x79, 0x00, 0x61, 0x8f, 0x02, 0x31, 0x6c, 0x69,
-0x6e, 0x87, 0x03, 0x32, 0x69, 0x73, 0x2d, 0x61, 0x00, 0x20,
-0x6f, 0x72, 0x0c, 0x00, 0x33, 0x6e, 0x6f, 0x74, 0x10, 0x00,
-0x05, 0x2d, 0x01, 0xd1, 0x73, 0x2c, 0x00, 0x75, 0x73, 0x65,
-0x66, 0x75, 0x6c, 0x00, 0x66, 0x6f, 0x72, 0xad, 0x03, 0x03,
-0xc9, 0x00, 0x01, 0x67, 0x03, 0x25, 0x6f, 0x72, 0x66, 0x03,
-0x85, 0x74, 0x6f, 0x00, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x31,
-0x03, 0x00, 0xad, 0x00, 0x41, 0x28, 0x41, 0x6c, 0x6c, 0x11,
-0x00, 0x11, 0x61, 0x95, 0x02, 0x92, 0x73, 0x00, 0x64, 0x65,
-0x73, 0x63, 0x72, 0x69, 0x62, 0x5b, 0x03, 0x13, 0x73, 0xab,
-0x02, 0x41, 0x32, 0x2e, 0x31, 0x00, 0x13, 0x01, 0xf2, 0x00,
-0x6c, 0x73, 0x6f, 0x00, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61,
-0x62, 0x6c, 0x65, 0x2e, 0x29, 0xb3, 0x02, 0x1a, 0x32, 0xb3,
-0x02, 0xb2, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65,
-0x72, 0x73, 0x20, 0x70, 0x03, 0x36, 0x73, 0x65, 0x00, 0x14,
-0x00, 0x02, 0x48, 0x00, 0x04, 0x43, 0x00, 0x02, 0x24, 0x04,
-0x00, 0x80, 0x00, 0xe1, 0x60, 0x43, 0x75, 0x73, 0x74, 0x6f,
-0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f, 0x70, 0x76, 0x00,
-0x03, 0x6e, 0x02, 0xb0, 0x60, 0x54, 0x79, 0x70, 0x65, 0x27,
-0x00, 0x6d, 0x65, 0x6e, 0x75, 0xb2, 0x00, 0x91, 0x57, 0x69,
-0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65, 0x28, 0x01, 0x68,
-0x00, 0x00, 0x53, 0x69, 0x7a, 0x65, 0xe5, 0x03, 0x00, 0x99,
-0x02, 0x06, 0xd9, 0x02, 0xf3, 0x01, 0x00, 0x00, 0x44, 0x69,
-0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x00, 0x00,
-0x00, 0x43, 0x4f, 0x03, 0x01, 0x2e, 0x00, 0x16, 0x64, 0x1a,
-0x00, 0x04, 0x40, 0x00, 0x41, 0x65, 0x6e, 0x65, 0x72, 0x58,
-0x04, 0xf3, 0x0b, 0x70, 0x75, 0x7a, 0x7a, 0x6c, 0x65, 0x3a,
-0x00, 0x61, 0x74, 0x00, 0x54, 0x72, 0x69, 0x63, 0x6b, 0x79,
-0x00, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2c, 0x00, 0x79, 0x41,
-0x05, 0x82, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64,
-0x57, 0x01, 0xc3, 0x6b, 0x65, 0x00, 0x6d, 0x6f, 0x72, 0x65,
-0x00, 0x64, 0x65, 0x64, 0x75, 0x49, 0x01, 0x60, 0x72, 0x65,
-0x67, 0x61, 0x72, 0x64, 0x8c, 0x01, 0x36, 0x64, 0x69, 0x73,
-0x0d, 0x00, 0x52, 0x6d, 0x6f, 0x76, 0x65, 0x73, 0xd9, 0x02,
-0x91, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x00, 0x6c, 0x65, 0x61,
-0x45, 0x00, 0x25, 0x69, 0x6d, 0x3a, 0x03, 0x01, 0x73, 0x02,
-0xa2, 0x69, 0x6e, 0x67, 0x73, 0x00, 0x6c, 0x61, 0x74, 0x65,
-0x72, 0xc6, 0x00, 0x11, 0x73, 0x30, 0x02, 0x00, 0x11, 0x04,
-0xb2, 0x73, 0x65, 0x63, 0x75, 0x74, 0x69, 0x76, 0x65, 0x20,
-0x31, 0x20, 0xf8, 0x04, 0x07, 0xd8, 0x00, 0x30, 0x77, 0x68,
-0x65, 0x78, 0x03, 0x01, 0xce, 0x00, 0x09, 0x91, 0x04, 0x35,
-0x67, 0x61, 0x6d, 0xe0, 0x00, 0x00, 0x5d, 0x01, 0x71, 0x70,
-0x65, 0x72, 0x6d, 0x69, 0x74, 0x73, 0x07, 0x04, 0x50, 0x61,
-0x64, 0x6a, 0x61, 0x63, 0x20, 0x04, 0x0f, 0x33, 0x02, 0x00,
-0x81, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61, 0x00, 0x31, 0x32,
-0x02, 0x10, 0x2c, 0x1d, 0x00, 0x05, 0x3a, 0x00, 0x02, 0xcb,
-0x05, 0x06, 0x30, 0x00, 0x04, 0x46, 0x01, 0x01, 0xa1, 0x02,
-0xbd, 0x27, 0x73, 0x00, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69,
-0x6e, 0x74, 0x47, 0x00, 0xc2, 0x2e, 0x00, 0x42, 0x79, 0x00,
-0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x17, 0x05, 0x21,
-0x69, 0x73, 0x53, 0x05, 0x02, 0x5b, 0x00, 0x60, 0x74, 0x65,
-0x64, 0x2c, 0x00, 0x74, 0x69, 0x02, 0x86, 0x6f, 0x69, 0x64,
-0x00, 0x6c, 0x6f, 0x6e, 0x67, 0x18, 0x03, 0x30, 0x62, 0x6f,
-0x72, 0x46, 0x01, 0x05, 0x11, 0x06, 0x05, 0x23, 0x06, 0x00,
-0xa4, 0x05, 0x01, 0x88, 0x01, 0x01, 0xc8, 0x01, 0x01, 0x58,
-0x05, 0x01, 0x92, 0x01, 0x71, 0x74, 0x77, 0x69, 0x64, 0x64,
-0x6c, 0x79, 0x20, 0x00, 0x70, 0x69, 0x6e, 0x74, 0x65, 0x72,
-0x65, 0x73, 0xc6, 0x03, 0x32, 0x2e, 0x00, 0x49, 0x28, 0x04,
-0x22, 0x77, 0x61, 0xa1, 0x00, 0x00, 0x18, 0x00, 0x22, 0x6f,
-0x72, 0x3f, 0x00, 0x02, 0x89, 0x01, 0xb2, 0x69, 0x6c, 0x69,
-0x74, 0x79, 0x2c, 0x00, 0x74, 0x75, 0x72, 0x6e, 0xa5, 0x00,
-0x03, 0x97, 0x02, 0x50, 0x6f, 0x66, 0x66, 0x2e, 0x00,
+0xfd, 0x06, 0x43, 0x68, 0x61, 0x70, 0x74, 0x65, 0x72, 0x20,
+0x34, 0x30, 0x3a, 0x20, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x73,
+0x20, 0x00, 0x2d, 0x01, 0x00, 0xf0, 0x19, 0x00, 0x00, 0x00,
+0x59, 0x6f, 0x75, 0x00, 0x61, 0x72, 0x65, 0x00, 0x67, 0x69,
+0x76, 0x65, 0x6e, 0x00, 0x61, 0x00, 0x67, 0x72, 0x69, 0x64,
+0x00, 0x6f, 0x66, 0x00, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65,
+0x73, 0x2c, 0x00, 0x73, 0x6f, 0x6d, 0x65, 0x11, 0x00, 0x51,
+0x77, 0x68, 0x69, 0x63, 0x68, 0x2b, 0x00, 0xf1, 0x04, 0x66,
+0x69, 0x6c, 0x6c, 0x65, 0x64, 0x00, 0x77, 0x69, 0x74, 0x68,
+0x00, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x00, 0x74, 0x62, 0x00,
+0x11, 0x2e, 0x4d, 0x00, 0xf2, 0x05, 0x6e, 0x65, 0x65, 0x64,
+0x00, 0x74, 0x6f, 0x00, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65,
+0x74, 0x65, 0x00, 0x74, 0x68, 0x65, 0x21, 0x00, 0x70, 0x00,
+0x66, 0x72, 0x6f, 0x6d, 0x00, 0x41, 0x1d, 0x00, 0x91, 0x42,
+0x00, 0x73, 0x6f, 0x00, 0x74, 0x68, 0x61, 0x74, 0x1e, 0x00,
+0xf1, 0x06, 0x72, 0x6f, 0x77, 0x73, 0x00, 0x61, 0x6e, 0x64,
+0x00, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x00, 0x63,
+0x6f, 0x6e, 0x74, 0x58, 0x00, 0xe0, 0x68, 0x65, 0x00, 0x73,
+0x61, 0x6d, 0x65, 0x00, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72,
+0x87, 0x00, 0x02, 0x4a, 0x00, 0xb1, 0x73, 0x65, 0x67, 0x6d,
+0x65, 0x6e, 0x74, 0x73, 0x00, 0x61, 0x73, 0x93, 0x00, 0xa3,
+0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x00,
+0x36, 0x00, 0x50, 0x63, 0x6c, 0x75, 0x65, 0x73, 0x6a, 0x00,
+0x01, 0x7e, 0x00, 0x21, 0x6f, 0x70, 0x5f, 0x00, 0x51, 0x72,
+0x69, 0x67, 0x68, 0x74, 0x45, 0x00, 0x21, 0x68, 0x65, 0xe9,
+0x00, 0x91, 0x2e, 0x00, 0x00, 0x00, 0x54, 0x68, 0x65, 0x72,
+0x65, 0x45, 0x00, 0x60, 0x6f, 0x6e, 0x6c, 0x79, 0x00, 0x73,
+0xd2, 0x00, 0x00, 0x27, 0x00, 0x00, 0x31, 0x00, 0xf1, 0x08,
+0x39, 0x30, 0x00, 0x64, 0x65, 0x67, 0x72, 0x65, 0x65, 0x00,
+0x63, 0x75, 0x72, 0x76, 0x65, 0x64, 0x00, 0x72, 0x61, 0x69,
+0x6c, 0x73, 0x2c, 0x1c, 0x00, 0x06, 0xd7, 0x00, 0xf1, 0x05,
+0x6d, 0x61, 0x79, 0x00, 0x6e, 0x6f, 0x74, 0x00, 0x63, 0x72,
+0x6f, 0x73, 0x73, 0x00, 0x69, 0x74, 0x73, 0x65, 0x6c, 0x66,
+0x5a, 0x00, 0x01, 0x16, 0x01, 0x32, 0x00, 0x77, 0x61, 0xd1,
+0x00, 0x40, 0x72, 0x69, 0x62, 0x75, 0xa2, 0x00, 0x01, 0x95,
+0x00, 0x20, 0x69, 0x73, 0xed, 0x00, 0xf0, 0x08, 0x6c, 0x65,
+0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x62, 0x79, 0x00, 0x4a,
+0x61, 0x6d, 0x65, 0x73, 0x00, 0x48, 0x61, 0x72, 0x76, 0x65,
+0x79, 0x3d, 0x00, 0x44, 0x34, 0x30, 0x2e, 0x31, 0xba, 0x01,
+0x01, 0x3e, 0x00, 0xf4, 0x1c, 0x6f, 0x6c, 0x73, 0x20, 0x00,
+0x00, 0x00, 0x4c, 0x65, 0x66, 0x74, 0x2d, 0x63, 0x6c, 0x69,
+0x63, 0x6b, 0x69, 0x6e, 0x67, 0x00, 0x6f, 0x6e, 0x00, 0x61,
+0x6e, 0x00, 0x65, 0x64, 0x67, 0x65, 0x00, 0x62, 0x65, 0x74,
+0x77, 0x65, 0x65, 0x6e, 0x00, 0x74, 0x77, 0x6f, 0xbd, 0x01,
+0x7a, 0x00, 0x61, 0x64, 0x64, 0x73, 0x00, 0x61, 0x34, 0x01,
+0x06, 0x29, 0x00, 0x28, 0x68, 0x65, 0x2d, 0x00, 0x30, 0x2e,
+0x00, 0x52, 0xf8, 0x00, 0x0f, 0x5c, 0x00, 0x02, 0x03, 0x48,
+0x00, 0x02, 0xe1, 0x00, 0x12, 0x6f, 0x3b, 0x00, 0x00, 0x19,
+0x00, 0x14, 0x2c, 0x79, 0x01, 0x00, 0x30, 0x00, 0x23, 0x6e,
+0x6f, 0x69, 0x00, 0xa1, 0x69, 0x73, 0x00, 0x70, 0x6f, 0x73,
+0x73, 0x69, 0x62, 0x6c, 0xfd, 0x01, 0x3d, 0x72, 0x65, 0x2e,
+0xb8, 0x00, 0x10, 0x69, 0x6b, 0x02, 0x02, 0x79, 0x00, 0x05,
+0x5d, 0x00, 0x54, 0x6f, 0x6c, 0x6f, 0x75, 0x72, 0x51, 0x00,
+0x70, 0x6f, 0x72, 0x00, 0x73, 0x68, 0x6f, 0x77, 0x2c, 0x00,
+0x01, 0x27, 0x02, 0x82, 0x79, 0x6f, 0x75, 0x00, 0x6b, 0x6e,
+0x6f, 0x77, 0x13, 0x02, 0x02, 0x39, 0x00, 0x45, 0x6d, 0x75,
+0x73, 0x74, 0x2b, 0x02, 0x03, 0xe6, 0x00, 0x30, 0x2c, 0x00,
+0x65, 0xc8, 0x02, 0x21, 0x69, 0x66, 0x32, 0x00, 0x52, 0x64,
+0x6f, 0x6e, 0x27, 0x74, 0x38, 0x00, 0x02, 0xbf, 0x02, 0x00,
+0xb5, 0x00, 0x00, 0xa3, 0x01, 0x02, 0xcb, 0x00, 0x6d, 0x65,
+0x73, 0x00, 0x79, 0x65, 0x74, 0xf9, 0x00, 0x0e, 0x9d, 0x00,
+0x04, 0xdb, 0x01, 0x06, 0xed, 0x00, 0x15, 0x69, 0x7a, 0x00,
+0x16, 0x73, 0xf9, 0x00, 0x03, 0x62, 0x01, 0x05, 0xef, 0x00,
+0x32, 0x00, 0x6f, 0x72, 0x74, 0x02, 0x60, 0x2d, 0x64, 0x72,
+0x61, 0x67, 0x67, 0x38, 0x00, 0x04, 0x7d, 0x01, 0x05, 0xa2,
+0x01, 0x20, 0x6c, 0x6c, 0xfd, 0x02, 0x00, 0xad, 0x00, 0x86,
+0x74, 0x6f, 0x00, 0x6c, 0x61, 0x79, 0x00, 0x61, 0x83, 0x02,
+0x31, 0x6c, 0x69, 0x6e, 0x7b, 0x03, 0x32, 0x69, 0x73, 0x2d,
+0x61, 0x00, 0x20, 0x6f, 0x72, 0x0c, 0x00, 0x33, 0x6e, 0x6f,
+0x74, 0x10, 0x00, 0x05, 0x2d, 0x01, 0xd1, 0x73, 0x2c, 0x00,
+0x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x00, 0x66, 0x6f, 0x72,
+0xa1, 0x03, 0x03, 0xc9, 0x00, 0x01, 0x5b, 0x03, 0x25, 0x6f,
+0x72, 0x5a, 0x03, 0x85, 0x74, 0x6f, 0x00, 0x6d, 0x61, 0x74,
+0x63, 0x68, 0x25, 0x03, 0x00, 0xad, 0x00, 0x41, 0x28, 0x41,
+0x6c, 0x6c, 0x11, 0x00, 0x11, 0x61, 0x8f, 0x02, 0x92, 0x73,
+0x00, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x62, 0x4f, 0x03,
+0x13, 0x73, 0xa5, 0x02, 0x41, 0x32, 0x2e, 0x31, 0x00, 0x13,
+0x01, 0xf2, 0x00, 0x6c, 0x73, 0x6f, 0x00, 0x61, 0x76, 0x61,
+0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x29, 0xad, 0x02,
+0x14, 0x32, 0xad, 0x02, 0xb2, 0x70, 0x61, 0x72, 0x61, 0x6d,
+0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x5e, 0x03, 0x36, 0x73,
+0x65, 0x00, 0x14, 0x00, 0x02, 0x42, 0x00, 0x04, 0x3d, 0x00,
+0x02, 0x12, 0x04, 0x00, 0x7a, 0x00, 0xe1, 0x60, 0x43, 0x75,
+0x73, 0x74, 0x6f, 0x6d, 0x2e, 0x2e, 0x2e, 0x27, 0x00, 0x6f,
+0x70, 0x70, 0x00, 0x03, 0x68, 0x02, 0xb0, 0x60, 0x54, 0x79,
+0x70, 0x65, 0x27, 0x00, 0x6d, 0x65, 0x6e, 0x75, 0xac, 0x00,
+0x91, 0x57, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x00, 0x48, 0x65,
+0x22, 0x01, 0x68, 0x00, 0x00, 0x53, 0x69, 0x7a, 0x65, 0xd3,
+0x03, 0x00, 0x93, 0x02, 0x06, 0xd3, 0x02, 0xf3, 0x01, 0x00,
+0x00, 0x44, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74,
+0x79, 0x00, 0x00, 0x00, 0x43, 0x49, 0x03, 0x01, 0x2e, 0x00,
+0x16, 0x64, 0x1a, 0x00, 0x04, 0x40, 0x00, 0x41, 0x65, 0x6e,
+0x65, 0x72, 0x46, 0x04, 0xf3, 0x0b, 0x70, 0x75, 0x7a, 0x7a,
+0x6c, 0x65, 0x3a, 0x00, 0x61, 0x74, 0x00, 0x54, 0x72, 0x69,
+0x63, 0x6b, 0x79, 0x00, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x2c,
+0x00, 0x79, 0x2f, 0x05, 0x82, 0x72, 0x65, 0x71, 0x75, 0x69,
+0x72, 0x65, 0x64, 0x51, 0x01, 0xc3, 0x6b, 0x65, 0x00, 0x6d,
+0x6f, 0x72, 0x65, 0x00, 0x64, 0x65, 0x64, 0x75, 0x43, 0x01,
+0x60, 0x72, 0x65, 0x67, 0x61, 0x72, 0x64, 0x86, 0x01, 0x36,
+0x64, 0x69, 0x73, 0x0d, 0x00, 0x52, 0x6d, 0x6f, 0x76, 0x65,
+0x73, 0xd3, 0x02, 0x91, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x00,
+0x6c, 0x65, 0x61, 0x45, 0x00, 0x25, 0x69, 0x6d, 0x34, 0x03,
+0x01, 0x6d, 0x02, 0xa2, 0x69, 0x6e, 0x67, 0x73, 0x00, 0x6c,
+0x61, 0x74, 0x65, 0x72, 0xc6, 0x00, 0x11, 0x73, 0x2a, 0x02,
+0x00, 0x0b, 0x04, 0xb2, 0x73, 0x65, 0x63, 0x75, 0x74, 0x69,
+0x76, 0x65, 0x20, 0x31, 0x20, 0xe6, 0x04, 0x07, 0xd8, 0x00,
+0x30, 0x77, 0x68, 0x65, 0x72, 0x03, 0x01, 0xce, 0x00, 0x03,
+0x7f, 0x04, 0x35, 0x67, 0x61, 0x6d, 0xda, 0x00, 0x00, 0x57,
+0x01, 0x71, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x73, 0xfb,
+0x03, 0x50, 0x61, 0x64, 0x6a, 0x61, 0x63, 0x14, 0x04, 0x0f,
+0x27, 0x02, 0x00, 0x81, 0x68, 0x61, 0x76, 0x65, 0x00, 0x61,
+0x00, 0x31, 0x26, 0x02, 0x10, 0x2c, 0x1d, 0x00, 0x05, 0x3a,
+0x00, 0x02, 0xb3, 0x05, 0x06, 0x30, 0x00, 0x04, 0x40, 0x01,
+0x01, 0x95, 0x02, 0xbd, 0x27, 0x73, 0x00, 0x65, 0x6e, 0x64,
+0x70, 0x6f, 0x69, 0x6e, 0x74, 0x47, 0x00, 0xc2, 0x2e, 0x00,
+0x42, 0x79, 0x00, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74,
+0x05, 0x05, 0x21, 0x69, 0x73, 0x3b, 0x05, 0x02, 0x5b, 0x00,
+0x60, 0x74, 0x65, 0x64, 0x2c, 0x00, 0x74, 0x5d, 0x02, 0x86,
+0x6f, 0x69, 0x64, 0x00, 0x6c, 0x6f, 0x6e, 0x67, 0x0c, 0x03,
+0x30, 0x62, 0x6f, 0x72, 0x40, 0x01, 0x05, 0xf9, 0x05, 0x05,
+0x0b, 0x06, 0x00, 0x8c, 0x05, 0x01, 0x82, 0x01, 0x01, 0xc2,
+0x01, 0x01, 0x46, 0x05, 0x01, 0x8c, 0x01, 0x71, 0x74, 0x77,
+0x69, 0x64, 0x64, 0x6c, 0x79, 0x20, 0x00, 0x70, 0x69, 0x6e,
+0x74, 0x65, 0x72, 0x65, 0x73, 0xba, 0x03, 0x32, 0x2e, 0x00,
+0x49, 0x1c, 0x04, 0x22, 0x77, 0x61, 0xa1, 0x00, 0x00, 0x18,
+0x00, 0x22, 0x6f, 0x72, 0x3f, 0x00, 0x02, 0x83, 0x01, 0xb2,
+0x69, 0x6c, 0x69, 0x74, 0x79, 0x2c, 0x00, 0x74, 0x75, 0x72,
+0x6e, 0xa5, 0x00, 0x03, 0x91, 0x02, 0x50, 0x6f, 0x66, 0x66,
+0x2e, 0x00,
};
-const unsigned short help_text_len = 1917;
-const unsigned short help_text_words = 339;
+const unsigned short help_text_len = 1881;
+const unsigned short help_text_words = 337;
const 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)
/* clipping is implemented through viewports and offsetting
* coordinates */
-static void rb_clip(void *handle, int x, int y, int w, int h)
+static void rb_clip(drawing *dr, int x, int y, int w, int h)
{
if(!zoom_enabled)
{
@@ -783,7 +783,7 @@ static void rb_clip(void *handle, int x, int y, int w, int h)
}
}
-static void rb_unclip(void *handle)
+static void rb_unclip(drawing *dr)
{
if(!zoom_enabled)
{
@@ -800,7 +800,7 @@ static void rb_unclip(void *handle)
}
}
-static void rb_draw_text(void *handle, int x, int y, int fonttype,
+static void rb_draw_text(drawing *dr, int x, int y, int fonttype,
int fontsize, int align, int color, const char *text)
{
(void) fontsize;
@@ -865,7 +865,7 @@ static void rb_draw_text(void *handle, int x, int y, int fonttype,
}
}
-static void rb_draw_rect(void *handle, int x, int y, int w, int h, int color)
+static void rb_draw_rect(drawing *dr, int x, int y, int w, int h, int color)
{
rb_color(color);
if(!zoom_enabled)
@@ -1007,7 +1007,7 @@ static void draw_antialiased_line(fb_data *fb, int w, int h, int x0, int y0, int
}
}
-static void rb_draw_line(void *handle, int x1, int y1, int x2, int y2,
+static void rb_draw_line(drawing *dr, int x1, int y1, int x2, int y2,
int color)
{
rb_color(color);
@@ -1035,349 +1035,7 @@ static void rb_draw_line(void *handle, int x1, int y1, int x2, int y2,
}
}
-#if 0
-/*
- * draw filled polygon
- * originally by Sebastian Leonhardt (ulmutul)
- * 'count' : number of coordinate pairs
- * 'pxy': array of coordinates. pxy[0]=x0,pxy[1]=y0,...
- * note: provide space for one extra coordinate, because the starting point
- * will automatically be inserted as end point.
- */
-
-/*
- * helper function:
- * find points of intersection between polygon and scanline
- */
-
-#define MAX_INTERSECTION 32
-
-static void fill_poly_line(int scanline, int count, int *pxy)
-{
- int i;
- int j;
- int num_of_intersects;
- int direct, old_direct;
- //intersections of every line with scanline (y-coord)
- int intersection[MAX_INTERSECTION];
- /* add starting point as ending point */
- pxy[count*2] = pxy[0];
- pxy[count*2+1] = pxy[1];
-
- old_direct=0;
- num_of_intersects=0;
- for (i=0; i<count*2; i+=2) {
- int x1=pxy[i];
- int y1=pxy[i+1];
- int x2=pxy[i+2];
- int y2=pxy[i+3];
- // skip if line is outside of scanline
- if (y1 < y2) {
- if (scanline < y1 || scanline > y2)
- continue;
- }
- else {
- if (scanline < y2 || scanline > y1)
- continue;
- }
- // calculate x-coord of intersection
- if (y1==y2) {
- direct=0;
- }
- else {
- direct = y1>y2 ? 1 : -1;
- // omit double intersections, if both lines lead in the same direction
- intersection[num_of_intersects] =
- x1+((scanline-y1)*(x2-x1))/(y2-y1);
- if ( (direct!=old_direct)
- || (intersection[num_of_intersects] != intersection[num_of_intersects-1])
- )
- ++num_of_intersects;
- }
- old_direct = direct;
- }
-
- // sort points of intersection
- for (i=0; i<num_of_intersects-1; ++i) {
- for (j=i+1; j<num_of_intersects; ++j) {
- if (intersection[j]<intersection[i]) {
- int temp=intersection[i];
- intersection[i]=intersection[j];
- intersection[j]=temp;
- }
- }
- }
- // draw
- for (i=0; i<num_of_intersects; i+=2) {
- rb->lcd_hline(intersection[i], intersection[i+1], scanline);
- }
-}
-
-/* two extra elements at end of pxy needed */
-static void v_fillarea(int count, int *pxy)
-{
- int i;
- int y1, y2;
-
- // find min and max y coords
- y1=y2=pxy[1];
- for (i=3; i<count*2; i+=2) {
- if (pxy[i] < y1) y1 = pxy[i];
- else if (pxy[i] > y2) y2 = pxy[i];
- }
-
- for (i=y1; i<=y2; ++i) {
- fill_poly_line(i, count, pxy);
- }
-}
-#endif
-
-/* I'm a horrible person: this was copy-pasta'd straight from
- * xlcd_draw.c */
-
-/* sort the given coordinates by increasing x value */
-static void sort_points_by_increasing_x(int* x1, int* y1,
- int* x2, int* y2,
- int* x3, int* y3)
-{
- int x, y;
- if (*x1 > *x3)
- {
- if (*x2 < *x3) /* x2 < x3 < x1 */
- {
- x = *x1; *x1 = *x2; *x2 = *x3; *x3 = x;
- y = *y1; *y1 = *y2; *y2 = *y3; *y3 = y;
- }
- else if (*x2 > *x1) /* x3 < x1 < x2 */
- {
- x = *x1; *x1 = *x3; *x3 = *x2; *x2 = x;
- y = *y1; *y1 = *y3; *y3 = *y2; *y2 = y;
- }
- else /* x3 <= x2 <= x1 */
- {
- x = *x1; *x1 = *x3; *x3 = x;
- y = *y1; *y1 = *y3; *y3 = y;
- }
- }
- else
- {
- if (*x2 < *x1) /* x2 < x1 <= x3 */
- {
- x = *x1; *x1 = *x2; *x2 = x;
- y = *y1; *y1 = *y2; *y2 = y;
- }
- else if (*x2 > *x3) /* x1 <= x3 < x2 */
- {
- x = *x2; *x2 = *x3; *x3 = x;
- y = *y2; *y2 = *y3; *y3 = y;
- }
- /* else already sorted */
- }
-}
-
-#define sort_points_by_increasing_y(x1, y1, x2, y2, x3, y3) \
- sort_points_by_increasing_x(y1, x1, y2, x2, y3, x3)
-
-/* draw a filled triangle, using horizontal lines for speed */
-static void zoom_filltriangle(int x1, int y1,
- int x2, int y2,
- int x3, int y3)
-{
- long fp_x1, fp_x2, fp_dx1, fp_dx2;
- int y;
- sort_points_by_increasing_y(&x1, &y1, &x2, &y2, &x3, &y3);
-
- if (y1 < y3) /* draw */
- {
- fp_dx1 = ((x3 - x1) << 16) / (y3 - y1);
- fp_x1 = (x1 << 16) + (1<<15) + (fp_dx1 >> 1);
-
- if (y1 < y2) /* first part */
- {
- fp_dx2 = ((x2 - x1) << 16) / (y2 - y1);
- fp_x2 = (x1 << 16) + (1<<15) + (fp_dx2 >> 1);
- for (y = y1; y < y2; y++)
- {
- zoom_hline(fp_x1 >> 16, fp_x2 >> 16, y);
- fp_x1 += fp_dx1;
- fp_x2 += fp_dx2;
- }
- }
- if (y2 < y3) /* second part */
- {
- fp_dx2 = ((x3 - x2) << 16) / (y3 - y2);
- fp_x2 = (x2 << 16) + (1<<15) + (fp_dx2 >> 1);
- for (y = y2; y < y3; y++)
- {
- zoom_hline(fp_x1 >> 16, fp_x2 >> 16, y);
- fp_x1 += fp_dx1;
- fp_x2 += fp_dx2;
- }
- }
- }
-}
-
-/* Should probably refactor this */
-static void rb_draw_poly(void *handle, const int *coords, int npoints,
- int fillcolor, int outlinecolor)
-{
- if(!zoom_enabled)
- {
- LOGF("rb_draw_poly");
-
- if(fillcolor >= 0)
- {
- rb_color(fillcolor);
-#if 1
- /* serious hack: draw a bunch of triangles between adjacent points */
- /* this generally works, even with some concave polygons */
- for(int i = 2; i < npoints; ++i)
- {
- int x1, y1, x2, y2, x3, y3;
- x1 = coords[0];
- y1 = coords[1];
- x2 = coords[(i - 1) * 2];
- y2 = coords[(i - 1) * 2 + 1];
- x3 = coords[i * 2];
- y3 = coords[i * 2 + 1];
- offset_coords(&x1, &y1);
- offset_coords(&x2, &y2);
- offset_coords(&x3, &y3);
- xlcd_filltriangle(x1, y1,
- x2, y2,
- x3, y3);
-
-#ifdef DEBUG_MENU
- if(debug_settings.polyanim)
- {
- rb->lcd_update();
- rb->sleep(HZ/4);
- }
-#endif
-#if 0
- /* debug code */
- rb->lcd_set_foreground(LCD_RGBPACK(255,0,0));
- rb->lcd_drawpixel(x1, y1);
- rb->lcd_drawpixel(x2, y2);
- rb->lcd_drawpixel(x3, y3);
- rb->lcd_update();
- rb->sleep(HZ);
- rb_color(fillcolor);
- rb->lcd_drawpixel(x1, y1);
- rb->lcd_drawpixel(x2, y2);
- rb->lcd_drawpixel(x3, y3);
- rb->lcd_update();
-#endif
- }
-#else
- int *pxy = smalloc(sizeof(int) * 2 * npoints + 2);
- /* copy points, offsetted */
- for(int i = 0; i < npoints; ++i)
- {
- pxy[2 * i + 0] = coords[2 * i + 0];
- pxy[2 * i + 1] = coords[2 * i + 1];
- offset_coords(&pxy[2*i+0], &pxy[2*i+1]);
- }
- v_fillarea(npoints, pxy);
- sfree(pxy);
-#endif
- }
-
- /* draw outlines last so they're not covered by the fill */
- assert(outlinecolor >= 0);
- rb_color(outlinecolor);
-
- for(int i = 1; i < npoints; ++i)
- {
- int x1, y1, x2, y2;
- x1 = coords[2 * (i - 1)];
- y1 = coords[2 * (i - 1) + 1];
- x2 = coords[2 * i];
- y2 = coords[2 * i + 1];
- if(debug_settings.no_aa)
- {
- offset_coords(&x1, &y1);
- offset_coords(&x2, &y2);
- rb->lcd_drawline(x1, y1,
- x2, y2);
- }
- else
- draw_antialiased_line(lcd_fb, LCD_WIDTH, LCD_HEIGHT, x1, y1, x2, y2);
-
-#ifdef DEBUG_MENU
- if(debug_settings.polyanim)
- {
- rb->lcd_update();
- rb->sleep(HZ/4);
- }
-#endif
- }
-
- int x1, y1, x2, y2;
- x1 = coords[0];
- y1 = coords[1];
- x2 = coords[2 * (npoints - 1)];
- y2 = coords[2 * (npoints - 1) + 1];
- if(debug_settings.no_aa)
- {
- offset_coords(&x1, &y1);
- offset_coords(&x2, &y2);
-
- rb->lcd_drawline(x1, y1,
- x2, y2);
- }
- else
- draw_antialiased_line(lcd_fb, LCD_WIDTH, LCD_HEIGHT, x1, y1, x2, y2);
- }
- else
- {
- LOGF("rb_draw_poly");
-
- if(fillcolor >= 0)
- {
- rb_color(fillcolor);
-
- /* serious hack: draw a bunch of triangles between adjacent points */
- /* this generally works, even with some concave polygons */
- for(int i = 2; i < npoints; ++i)
- {
- int x1, y1, x2, y2, x3, y3;
- x1 = coords[0];
- y1 = coords[1];
- x2 = coords[(i - 1) * 2];
- y2 = coords[(i - 1) * 2 + 1];
- x3 = coords[i * 2];
- y3 = coords[i * 2 + 1];
- zoom_filltriangle(x1, y1,
- x2, y2,
- x3, y3);
- }
- }
-
- /* draw outlines last so they're not covered by the fill */
- assert(outlinecolor >= 0);
- rb_color(outlinecolor);
-
- for(int i = 1; i < npoints; ++i)
- {
- int x1, y1, x2, y2;
- x1 = coords[2 * (i - 1)];
- y1 = coords[2 * (i - 1) + 1];
- x2 = coords[2 * i];
- y2 = coords[2 * i + 1];
- draw_antialiased_line(zoom_fb, zoom_w, zoom_h, x1, y1, x2, y2);
- }
-
- int x1, y1, x2, y2;
- x1 = coords[0];
- y1 = coords[1];
- x2 = coords[2 * (npoints - 1)];
- y2 = coords[2 * (npoints - 1) + 1];
- draw_antialiased_line(zoom_fb, zoom_w, zoom_h, x1, y1, x2, y2);
- }
-}
-
-static void rb_draw_circle(void *handle, int cx, int cy, int radius,
+static void rb_draw_circle(drawing *dr, int cx, int cy, int radius,
int fillcolor, int outlinecolor)
{
if(!zoom_enabled)
@@ -1449,7 +1107,7 @@ static void trim_rect(int *x, int *y, int *w, int *h)
*h = y1 - y0;
}
-static blitter *rb_blitter_new(void *handle, int w, int h)
+static blitter *rb_blitter_new(drawing *dr, int w, int h)
{
LOGF("rb_blitter_new");
blitter *b = snew(blitter);
@@ -1460,7 +1118,7 @@ static blitter *rb_blitter_new(void *handle, int w, int h)
return b;
}
-static void rb_blitter_free(void *handle, blitter *bl)
+static void rb_blitter_free(drawing *dr, blitter *bl)
{
LOGF("rb_blitter_free");
sfree(bl->bmp.data);
@@ -1469,7 +1127,7 @@ static void rb_blitter_free(void *handle, blitter *bl)
}
/* copy a section of the framebuffer */
-static void rb_blitter_save(void *handle, blitter *bl, int x, int y)
+static void rb_blitter_save(drawing *dr, blitter *bl, int x, int y)
{
/* no viewport offset */
#if LCD_STRIDEFORMAT == VERTICAL_STRIDE
@@ -1498,7 +1156,7 @@ static void rb_blitter_save(void *handle, blitter *bl, int x, int y)
#endif
}
-static void rb_blitter_load(void *handle, blitter *bl, int x, int y)
+static void rb_blitter_load(drawing *dr, blitter *bl, int x, int y)
{
LOGF("rb_blitter_load");
if(!bl->have_data)
@@ -1528,7 +1186,7 @@ static void rb_blitter_load(void *handle, blitter *bl, int x, int y)
}
}
-static void rb_draw_update(void *handle, int x, int y, int w, int h)
+static void rb_draw_update(drawing *dr, int x, int y, int w, int h)
{
LOGF("rb_draw_update(%d, %d, %d, %d)", x, y, w, h);
@@ -1552,9 +1210,9 @@ static void rb_draw_update(void *handle, int x, int y, int w, int h)
need_draw_update = true;
}
-static void rb_start_draw(void *handle)
+static void rb_start_draw(drawing *dr)
{
- (void) handle;
+ (void) dr;
/* ... mumble mumble ... not ... reentrant ... mumble mumble ... */
@@ -1565,9 +1223,9 @@ static void rb_start_draw(void *handle)
ud_d = LCD_HEIGHT;
}
-static void rb_end_draw(void *handle)
+static void rb_end_draw(drawing *dr)
{
- (void) handle;
+ (void) dr;
if(debug_settings.highlight_cursor)
{
@@ -1594,7 +1252,7 @@ static void rb_end_draw(void *handle)
#endif
}
-static void rb_status_bar(void *handle, const char *text)
+static void rb_status_bar(drawing *dr, const char *text)
{
if(titlebar)
sfree(titlebar);
@@ -1692,7 +1350,7 @@ static void draw_mouse(void)
* glyph exists in a font) */
#if 0
/* See: https://www.chiark.greenend.org.uk/~sgtatham/puzzles/devel/drawing.html#drawing-text-fallback */
-static char *rb_text_fallback(void *handle, const char *const *strings,
+static char *rb_text_fallback(drawing *dr, const char *const *strings,
int nstrings)
{
struct font *pf = rb->font_get(cur_font);
@@ -1725,10 +1383,11 @@ static char *rb_text_fallback(void *handle, const char *const *strings,
#endif
const drawing_api rb_drawing = {
+ 1,
rb_draw_text,
rb_draw_rect,
rb_draw_line,
- rb_draw_poly,
+ draw_polygon_fallback,
rb_draw_circle,
rb_draw_update,
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
include(cmake/setup.cmake)
add_library(core_obj OBJECT
- combi.c divvy.c drawing.c dsf.c findloop.c grid.c latin.c
- laydomino.c loopgen.c malloc.c matching.c midend.c misc.c penrose.c
- penrose-legacy.c ps.c random.c sort.c tdq.c tree234.c version.c
+ combi.c divvy.c draw-poly.c drawing.c dsf.c findloop.c grid.c
+ latin.c laydomino.c loopgen.c malloc.c matching.c midend.c misc.c
+ penrose.c penrose-legacy.c ps.c random.c sort.c tdq.c tree234.c
+ version.c
${platform_common_sources})
add_library(core $<TARGET_OBJECTS:core_obj>)
add_library(common $<TARGET_OBJECTS:core_obj> hat.c spectre.c)
+cliprogram(polygon-test draw-poly.c
+ SDL2_LIB COMPILE_DEFINITIONS STANDALONE_POLYGON)
+
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
puzzle(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 @@
+/*
+ * draw-poly.c: Fallback polygon drawing function.
+ */
+
+#include <assert.h>
+
+#include "puzzles.h"
+
+struct edge {
+ int x1, y1;
+ int x2, y2;
+ bool active;
+
+ /* whether y1 is a closed endpoint (i.e. this edge should be
+ * active when y == y1) */
+ bool closed_y1;
+
+ /* (x2 - x1) / (y2 - y1) as 16.16 signed fixed point; precomputed
+ * for speed */
+ long inverse_slope;
+};
+
+#define FRACBITS 16
+#define ONEHALF (1 << (FRACBITS-1))
+
+void draw_polygon_fallback(drawing *dr, const int *coords, int npoints,
+ int fillcolour, int outlinecolour)
+{
+ struct edge *edges;
+ int min_y = INT_MAX, max_y = INT_MIN, i, y;
+ int n_edges = 0;
+ int *intersections;
+
+ if(npoints < 3)
+ return;
+
+ if(fillcolour < 0)
+ goto draw_outline;
+
+ /* This uses a basic scanline rasterization algorithm for polygon
+ * filling. First, an "edge table" is constructed for each pair of
+ * neighboring points. Horizontal edges are excluded. Then, the
+ * algorithm iterates a horizontal "scan line" over the vertical
+ * (Y) extent of the polygon. At each Y level, it maintains a set
+ * of "active" edges, which are those which intersect the scan
+ * line at the current Y level. The X coordinates where the scan
+ * line intersects each active edge are then computed via
+ * fixed-point arithmetic and stored. Finally, horizontal lines
+ * are drawn between each successive pair of intersection points,
+ * in the order of ascending X coordinate. This has the effect of
+ * "even-odd" filling when the polygon is self-intersecting.
+ *
+ * I (vaguely) based this implementation off the slides below:
+ *
+ * https://www.khoury.northeastern.edu/home/fell/CS4300/Lectures/CS4300F2012-9-ScanLineFill.pdf
+ *
+ * I'm fairly confident that this current implementation is
+ * correct (i.e. draws the right polygon, free from artifacts),
+ * but it isn't quite as efficient as it could be. Namely, it
+ * currently maintains the active edge set by setting the `active`
+ * flag in the `edge` array, which is quite inefficient. Perhaps
+ * future optimization could see this replaced with a tree
+ * set. Additionally, one could perhaps replace the current linear
+ * search for edge endpoints (i.e. the inner loop over `edges`) by
+ * sorting the edge table by upper and lower Y coordinate.
+ *
+ * A final caveat comes from the use of fixed point arithmetic,
+ * which is motivated by performance considerations on FPU-less
+ * platforms (e.g. most Rockbox devices, and maybe others?). I'm
+ * currently using 16 fractional bits to compute the edge
+ * intersections, which (in the case of a 32-bit int) limits the
+ * acceptable range of coordinates to roughly (-2^14, +2^14). This
+ * ought to be acceptable for the forseeable future, but
+ * ultra-high DPI screens might one day exceed this. In that case,
+ * options include switching to int64_t (but that comes with its
+ * own portability headaches), reducing the number of fractional
+ * bits, or just giving up and using floating point.
+ */
+
+ /* Build edge table from coords. Horizontal edges are filtered
+ * out, so n_edges <= n_points in general. */
+ edges = smalloc(npoints * sizeof(struct edge));
+
+ for(i = 0; i < npoints; i++) {
+ int x1, y1, x2, y2;
+
+ x1 = coords[(2*i+0)];
+ y1 = coords[(2*i+1)];
+ x2 = coords[(2*i+2) % (npoints * 2)];
+ y2 = coords[(2*i+3) % (npoints * 2)];
+
+ if(y1 < min_y)
+ min_y = y1;
+ if(y1 > max_y)
+ max_y = y1;
+
+#define COORD_LIMIT (1<<(sizeof(int)*CHAR_BIT-2 - FRACBITS))
+ /* Prevent integer overflow when computing `inverse_slope',
+ * which shifts the coordinates left by FRACBITS, and for
+ * which we'd like to avoid relying on `long long'. */
+ /* If this ever causes issues, see the above comment about
+ possible solutions. */
+ assert(x1 < COORD_LIMIT && y1 < COORD_LIMIT);
+
+ /* Only create non-horizontal edges, and require y1 < y2. */
+ if(y1 != y2) {
+ bool swap = y1 > y2;
+ int lower_endpoint = swap ? (i + 1) : i;
+
+ /* Compute index of the point adjacent to lower end of
+ * this edge (which is not the upper end of this edge). */
+ int lower_neighbor = swap ? (lower_endpoint + 1) % npoints : (lower_endpoint + npoints - 1) % npoints;
+
+ struct edge *edge = edges + (n_edges++);
+
+ edge->active = false;
+ edge->x1 = swap ? x2 : x1;
+ edge->y1 = swap ? y2 : y1;
+ edge->x2 = swap ? x1 : x2;
+ edge->y2 = swap ? y1 : y2;
+ edge->inverse_slope = ((edge->x2 - edge->x1) << FRACBITS) / (edge->y2 - edge->y1);
+ edge->closed_y1 = edge->y1 < coords[2*lower_neighbor+1];
+ }
+ }
+
+ /* a generous upper bound on number of intersections is n_edges */
+ intersections = smalloc(n_edges * sizeof(int));
+
+ for(y = min_y; y <= max_y; y++) {
+ int n_intersections = 0;
+ for(i = 0; i < n_edges; i++) {
+ struct edge *edge = edges + i;
+ /* Update active edge set. These conditions are mutually
+ * exclusive because of the invariant that y1 < y2. */
+ if(edge->y1 + (edge->closed_y1 ? 0 : 1) == y)
+ edge->active = true;
+ else if(edge->y2 + 1 == y)
+ edge->active = false;
+
+ if(edge->active) {
+ int x = edges[i].x1;
+ x += (edges[i].inverse_slope * (y - edges[i].y1) + ONEHALF) >> FRACBITS;
+ intersections[n_intersections++] = x;
+ }
+ }
+
+ qsort(intersections, n_intersections, sizeof(int), compare_integers);
+
+ assert(n_intersections % 2 == 0);
+ assert(n_intersections <= n_edges);
+
+ /* Draw horizontal lines between successive pairs of
+ * intersections of the scanline with active edges. */
+ for(i = 0; i + 1 < n_intersections; i += 2) {
+ draw_line(dr,
+ intersections[i], y,
+ intersections[i+1], y,
+ fillcolour);
+ }
+ }
+
+ sfree(intersections);
+ sfree(edges);
+
+draw_outline:
+ assert(outlinecolour >= 0);
+ for (i = 0; i < 2 * npoints; i += 2)
+ draw_line(dr,
+ coords[i], coords[i+1],
+ coords[(i+2)%(2*npoints)], coords[(i+3)%(2*npoints)],
+ outlinecolour);
+}
+
+#ifdef STANDALONE_POLYGON
+
+/*
+ * Standalone program to test draw_polygon_fallback(). By default,
+ * creates a window and allows clicking points to build a
+ * polygon. Optionally, can draw a randomly growing polygon in
+ * "screensaver" mode.
+ */
+
+#include <SDL.h>
+
+void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour)
+{
+ SDL_Renderer *renderer = GET_HANDLE_AS_TYPE(dr, SDL_Renderer);
+ SDL_RenderDrawLine(renderer, x1, y1, x2, y2);
+}
+
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+#define MAX_SCREENSAVER_POINTS 1000
+
+int main(int argc, char *argv[]) {
+ SDL_Window* window = NULL;
+ SDL_Event event;
+ SDL_Renderer *renderer = NULL;
+ int running = 1;
+ int i;
+ drawing dr;
+ bool screensaver = false;
+
+ if(argc >= 2) {
+ if(!strcmp(argv[1], "--screensaver"))
+ screensaver = true;
+ else
+ printf("usage: %s [--screensaver]\n", argv[0]);
+ }
+
+ int *poly = NULL;
+ int n_points = 0;
+
+ /* Initialize SDL */
+ if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+ printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ /* Create window */
+ window = SDL_CreateWindow("Polygon Drawing Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
+ if (!window) {
+ printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
+ SDL_Quit();
+ return 1;
+ }
+
+ /* Create renderer */
+ renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
+ if (!renderer) {
+ printf("Renderer could not be created! SDL_Error: %s\n", SDL_GetError());
+ SDL_DestroyWindow(window);
+ SDL_Quit();
+ return 1;
+ }
+
+ dr.handle = renderer;
+
+ if(!screensaver)
+ printf("Click points in the window to create vertices. Pressing C resets.\n");
+
+ while (running) {
+ while (SDL_PollEvent(&event) != 0) {
+ if (event.type == SDL_QUIT) {
+ running = 0;
+ }
+ else if (event.type == SDL_MOUSEBUTTONDOWN) {
+ if (event.button.button == SDL_BUTTON_LEFT) {
+ int mouseX = event.button.x;
+ int mouseY = event.button.y;
+
+ poly = realloc(poly, ++n_points * 2 * sizeof(int));
+ poly[2 * (n_points - 1)] = mouseX;
+ poly[2 * (n_points - 1) + 1] = mouseY;
+ }
+ }
+ else if (event.type == SDL_KEYDOWN) {
+ if (event.key.keysym.sym == SDLK_c) {
+ free(poly);
+ poly = NULL;
+ n_points = 0;
+ }
+ }
+ }
+
+ if(screensaver) {
+ poly = realloc(poly, ++n_points * 2 * sizeof(int));
+ poly[2 * (n_points - 1)] = rand() % WINDOW_WIDTH;
+ poly[2 * (n_points - 1) + 1] = rand() % WINDOW_HEIGHT;
+
+ if(n_points >= MAX_SCREENSAVER_POINTS) {
+ free(poly);
+ poly = NULL;
+ n_points = 0;
+ }
+ }
+
+ /* Clear the screen with a black color */
+ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
+ SDL_RenderClear(renderer);
+
+ /* Set draw color to white */
+ SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
+
+ draw_polygon_fallback(&dr, poly, n_points, 1, 1);
+
+ SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
+ for(i = 0; i < 2*n_points; i+=2)
+ SDL_RenderDrawPoint(renderer, poly[i], poly[i+1]);
+
+ /* Present the back buffer */
+ SDL_RenderPresent(renderer);
+ }
+
+ /* Clean up and quit SDL */
+ SDL_DestroyRenderer(renderer);
+ SDL_DestroyWindow(window);
+ SDL_Quit();
+
+ return 0;
+}
+#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 {
float grey;
};
-struct drawing {
- const drawing_api *api;
- void *handle;
+typedef struct drawing_internal {
+ /* we implement data hiding by casting `struct drawing*` pointers
+ * to `struct drawing_internal*` */
+ struct drawing pub;
+
+ /* private data */
struct print_colour *colours;
int ncolours, coloursize;
float scale;
@@ -52,53 +55,70 @@ struct drawing {
* this may set it to NULL. */
midend *me;
char *laststatus;
-};
+} drawing_internal;
+
+#define PRIVATE_CAST(dr) ((drawing_internal*)(dr))
+#define PUBLIC_CAST(dri) ((drawing*)(dri))
+
+/* See puzzles.h for a description of the version number. */
+#define DRAWING_API_VERSION 1
drawing *drawing_new(const drawing_api *api, midend *me, void *handle)
{
- drawing *dr = snew(drawing);
- dr->api = api;
- dr->handle = handle;
- dr->colours = NULL;
- dr->ncolours = dr->coloursize = 0;
- dr->scale = 1.0F;
- dr->me = me;
- dr->laststatus = NULL;
- return dr;
+ if(api->version != DRAWING_API_VERSION) {
+ fatal("Drawing API version mismatch: expected: %d, actual: %d\n", DRAWING_API_VERSION, api->version);
+ /* shouldn't get here */
+ return NULL;
+ }
+
+ drawing_internal *dri = snew(drawing_internal);
+ dri->pub.api = api;
+ dri->pub.handle = handle;
+ dri->colours = NULL;
+ dri->ncolours = dri->coloursize = 0;
+ dri->scale = 1.0F;
+ dri->me = me;
+ dri->laststatus = NULL;
+ return PUBLIC_CAST(dri);
}
void drawing_free(drawing *dr)
{
- sfree(dr->laststatus);
- sfree(dr->colours);
- sfree(dr);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ sfree(dri->laststatus);
+ sfree(dri->colours);
+ sfree(dri);
}
void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize,
int align, int colour, const char *text)
{
- dr->api->draw_text(dr->handle, x, y, fonttype, fontsize, align,
- colour, text);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->draw_text(dr, x, y, fonttype, fontsize, align,
+ colour, text);
}
void draw_rect(drawing *dr, int x, int y, int w, int h, int colour)
{
- dr->api->draw_rect(dr->handle, x, y, w, h, colour);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->draw_rect(dr, x, y, w, h, colour);
}
void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour)
{
- dr->api->draw_line(dr->handle, x1, y1, x2, y2, colour);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->draw_line(dr, x1, y1, x2, y2, colour);
}
void draw_thick_line(drawing *dr, float thickness,
float x1, float y1, float x2, float y2, int colour)
{
+ drawing_internal *dri = PRIVATE_CAST(dr);
if (thickness < 1.0F)
thickness = 1.0F;
- if (dr->api->draw_thick_line) {
- dr->api->draw_thick_line(dr->handle, thickness,
- x1, y1, x2, y2, colour);
+ if (dri->pub.api->draw_thick_line) {
+ dri->pub.api->draw_thick_line(dr, thickness,
+ x1, y1, x2, y2, colour);
} else {
/* We'll fake it up with a filled polygon. The tweak to the
* thickness empirically compensates for rounding errors, because
@@ -117,59 +137,67 @@ void draw_thick_line(drawing *dr, float thickness,
p[5] = y2 - tvhatx;
p[6] = x1 + tvhaty;
p[7] = y1 - tvhatx;
- dr->api->draw_polygon(dr->handle, p, 4, colour, colour);
+ dri->pub.api->draw_polygon(dr, p, 4, colour, colour);
}
}
void draw_polygon(drawing *dr, const int *coords, int npoints,
int fillcolour, int outlinecolour)
{
- dr->api->draw_polygon(dr->handle, coords, npoints, fillcolour,
- outlinecolour);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->draw_polygon(dr, coords, npoints, fillcolour,
+ outlinecolour);
}
void draw_circle(drawing *dr, int cx, int cy, int radius,
int fillcolour, int outlinecolour)
{
- dr->api->draw_circle(dr->handle, cx, cy, radius, fillcolour,
- outlinecolour);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->draw_circle(dr, cx, cy, radius, fillcolour,
+ outlinecolour);
}
void draw_update(drawing *dr, int x, int y, int w, int h)
{
- if (dr->api->draw_update)
- dr->api->draw_update(dr->handle, x, y, w, h);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ if (dri->pub.api->draw_update)
+ dri->pub.api->draw_update(dr, x, y, w, h);
}
void clip(drawing *dr, int x, int y, int w, int h)
{
- dr->api->clip(dr->handle, x, y, w, h);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->clip(dr, x, y, w, h);
}
void unclip(drawing *dr)
{
- dr->api->unclip(dr->handle);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->unclip(dr);
}
void start_draw(drawing *dr)
{
- dr->api->start_draw(dr->handle);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->start_draw(dr);
}
void end_draw(drawing *dr)
{
- dr->api->end_draw(dr->handle);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->end_draw(dr);
}
char *text_fallback(drawing *dr, const char *const *strings, int nstrings)
{
+ drawing_internal *dri = PRIVATE_CAST(dr);
int i;
/*
* If the drawing implementation provides one of these, use it.
*/
- if (dr && dr->api->text_fallback)
- return dr->api->text_fallback(dr->handle, strings, nstrings);
+ if (dr && dri->pub.api->text_fallback)
+ return dri->pub.api->text_fallback(dr, strings, nstrings);
/*
* 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)
void status_bar(drawing *dr, const char *text)
{
+ drawing_internal *dri = PRIVATE_CAST(dr);
char *rewritten;
- if (!dr->api->status_bar)
+ if (!dri->pub.api->status_bar)
return;
- assert(dr->me);
+ assert(dri->me);
- rewritten = midend_rewrite_statusbar(dr->me, text);
- if (!dr->laststatus || strcmp(rewritten, dr->laststatus)) {
- dr->api->status_bar(dr->handle, rewritten);
- sfree(dr->laststatus);
- dr->laststatus = rewritten;
+ rewritten = midend_rewrite_statusbar(dri->me, text);
+ if (!dri->laststatus || strcmp(rewritten, dri->laststatus)) {
+ dri->pub.api->status_bar(dr, rewritten);
+ sfree(dri->laststatus);
+ dri->laststatus = rewritten;
} else {
sfree(rewritten);
}
@@ -215,74 +244,85 @@ void status_bar(drawing *dr, const char *text)
blitter *blitter_new(drawing *dr, int w, int h)
{
- return dr->api->blitter_new(dr->handle, w, h);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ return dri->pub.api->blitter_new(dr, w, h);
}
void blitter_free(drawing *dr, blitter *bl)
{
- dr->api->blitter_free(dr->handle, bl);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->blitter_free(dr, bl);
}
void blitter_save(drawing *dr, blitter *bl, int x, int y)
{
- dr->api->blitter_save(dr->handle, bl, x, y);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->blitter_save(dr, bl, x, y);
}
void blitter_load(drawing *dr, blitter *bl, int x, int y)
{
- dr->api->blitter_load(dr->handle, bl, x, y);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->blitter_load(dr, bl, x, y);
}
void print_begin_doc(drawing *dr, int pages)
{
- dr->api->begin_doc(dr->handle, pages);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->begin_doc(dr, pages);
}
void print_begin_page(drawing *dr, int number)
{
- dr->api->begin_page(dr->handle, number);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->begin_page(dr, number);
}
void print_begin_puzzle(drawing *dr, float xm, float xc,
float ym, float yc, int pw, int ph, float wmm,
float scale)
{
- dr->scale = scale;
- dr->ncolours = 0;
- dr->api->begin_puzzle(dr->handle, xm, xc, ym, yc, pw, ph, wmm);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->scale = scale;
+ dri->ncolours = 0;
+ dri->pub.api->begin_puzzle(dr, xm, xc, ym, yc, pw, ph, wmm);
}
void print_end_puzzle(drawing *dr)
{
- dr->api->end_puzzle(dr->handle);
- dr->scale = 1.0F;
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->end_puzzle(dr);
+ dri->scale = 1.0F;
}
void print_end_page(drawing *dr, int number)
{
- dr->api->end_page(dr->handle, number);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->end_page(dr, number);
}
void print_end_doc(drawing *dr)
{
- dr->api->end_doc(dr->handle);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->end_doc(dr);
}
void print_get_colour(drawing *dr, int colour, bool printing_in_colour,
int *hatch, float *r, float *g, float *b)
{
- assert(colour >= 0 && colour < dr->ncolours);
- if (dr->colours[colour].hatch_when == 2 ||
- (dr->colours[colour].hatch_when == 1 && !printing_in_colour)) {
- *hatch = dr->colours[colour].hatch;
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ assert(colour >= 0 && colour < dri->ncolours);
+ if (dri->colours[colour].hatch_when == 2 ||
+ (dri->colours[colour].hatch_when == 1 && !printing_in_colour)) {
+ *hatch = dri->colours[colour].hatch;
} else {
*hatch = -1;
if (printing_in_colour) {
- *r = dr->colours[colour].r;
- *g = dr->colours[colour].g;
- *b = dr->colours[colour].b;
+ *r = dri->colours[colour].r;
+ *g = dri->colours[colour].g;
+ *b = dri->colours[colour].b;
} else {
- *r = *g = *b = dr->colours[colour].grey;
+ *r = *g = *b = dri->colours[colour].grey;
}
}
}
@@ -290,18 +330,19 @@ void print_get_colour(drawing *dr, int colour, bool printing_in_colour,
static int print_generic_colour(drawing *dr, float r, float g, float b,
float grey, int hatch, int hatch_when)
{
- if (dr->ncolours >= dr->coloursize) {
- dr->coloursize = dr->ncolours + 16;
- dr->colours = sresize(dr->colours, dr->coloursize,
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ if (dri->ncolours >= dri->coloursize) {
+ dri->coloursize = dri->ncolours + 16;
+ dri->colours = sresize(dri->colours, dri->coloursize,
struct print_colour);
}
- dr->colours[dr->ncolours].hatch = hatch;
- dr->colours[dr->ncolours].hatch_when = hatch_when;
- dr->colours[dr->ncolours].r = r;
- dr->colours[dr->ncolours].g = g;
- dr->colours[dr->ncolours].b = b;
- dr->colours[dr->ncolours].grey = grey;
- return dr->ncolours++;
+ dri->colours[dri->ncolours].hatch = hatch;
+ dri->colours[dri->ncolours].hatch_when = hatch_when;
+ dri->colours[dri->ncolours].r = r;
+ dri->colours[dri->ncolours].g = g;
+ dri->colours[dri->ncolours].b = b;
+ dri->colours[dri->ncolours].grey = grey;
+ return dri->ncolours++;
}
int 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)
void print_line_width(drawing *dr, int width)
{
+ drawing_internal *dri = PRIVATE_CAST(dr);
+
/*
* I don't think it's entirely sensible to have line widths be
* entirely relative to the puzzle size; there is a point
@@ -348,10 +391,11 @@ void print_line_width(drawing *dr, int width)
* _square root_ of the main puzzle scale. Double the puzzle
* size, and the line width multiplies by 1.4.
*/
- dr->api->line_width(dr->handle, (float)sqrt(dr->scale) * width);
+ dri->pub.api->line_width(dr, (float)sqrt(dri->scale) * width);
}
void print_line_dotted(drawing *dr, bool dotted)
{
- dr->api->line_dotted(dr->handle, dotted);
+ drawing_internal *dri = PRIVATE_CAST(dr);
+ dri->pub.api->line_dotted(dr, dotted);
}
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)
return (y*w+x)*DP1+dr;
}
-static int compare_integers(const void *av, const void *bv)
-{
- const int *a = (const int *)av;
- const int *b = (const int *)bv;
- if (*a < *b)
- return -1;
- else if (*a > *b)
- return +1;
- else
- return 0;
-}
-
static char *solve_game(const game_state *state, const game_state *currstate,
const char *aux, const char **error)
{
@@ -1886,11 +1874,6 @@ static void draw_player(drawing *dr, game_drawstate *ds, int x, int y,
coords[d*4+2] = x + TILESIZE/2 + (int)((TILESIZE*3/7) * x2);
coords[d*4+3] = y + TILESIZE/2 + (int)((TILESIZE*3/7) * y2);
}
- /* rockbox hack */
- int tmp[2] = { coords[0], coords[1] };
- memmove(coords, coords + 2, sizeof(int) * DIRECTIONS * 4 - 2);
- memcpy(coords + DIRECTIONS * 4 - 2, tmp, 2 * sizeof(int));
-
draw_polygon(dr, coords, DIRECTIONS*2, COL_DEAD_PLAYER, COL_OUTLINE);
} else {
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,
int coords[14], *c;
c = coords;
+ *c++ = ox + px/9;
+ *c++ = oy + py/9;
*c++ = ox + px/9 + ax*2/3;
*c++ = oy + py/9 + ay*2/3;
*c++ = ox + px/3 + ax*2/3;
@@ -1918,8 +1903,6 @@ static void draw_player(drawing *dr, game_drawstate *ds, int x, int y,
*c++ = oy - py/9 + ay*2/3;
*c++ = ox - px/9;
*c++ = oy - py/9;
- *c++ = ox + px/9;
- *c++ = oy + py/9;
draw_polygon(dr, coords, 7, COL_HINT, COL_OUTLINE);
}
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,
coords[(n)*2+0] = x + (int)(TILE_SIZE * (dx)); \
coords[(n)*2+1] = y + (int)(TILE_SIZE * (dy)); \
} while (0)
- SETCOORD(0, 0.6F, 0.7F);
- SETCOORD(1, 0.8F, 0.8F);
- SETCOORD(2, 0.25F, 0.8F);
- SETCOORD(3, 0.55F, 0.7F);
- SETCOORD(4, 0.55F, 0.35F);
- SETCOORD(5, 0.6F, 0.35F);
+ SETCOORD(0, 0.6F, 0.35F);
+ SETCOORD(1, 0.6F, 0.7F);
+ SETCOORD(2, 0.8F, 0.8F);
+ SETCOORD(3, 0.25F, 0.8F);
+ SETCOORD(4, 0.55F, 0.7F);
+ SETCOORD(5, 0.55F, 0.35F);
draw_polygon(dr, coords, 6, COL_FLAGBASE, COL_FLAGBASE);
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)
draw_line(dr, cx + r, cy + r, cx + r/2, cy + r, col);
}
+int compare_integers(const void *av, const void *bv) {
+ const int *a = (const int *)av;
+ const int *b = (const int *)bv;
+ if (*a < *b)
+ return -1;
+ else if (*a > *b)
+ return +1;
+ else
+ return 0;
+}
+
char *move_cursor(int button, int *x, int *y, int maxw, int maxh, bool wrap,
bool *visible)
{
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
}
-\C{tracks} \i{Train Tracks}
+\C{tracks} \i{Tracks}
\cfg{winhelp-topic}{games.tracks}
@@ -3454,9 +3454,9 @@ clues to the top and right of the grid.
There are only straight and 90 degree curved rails, and the track may not
cross itself.
-Train Tracks was contributed to this collection by James Harvey.
+Tracks was contributed to this collection by James Harvey.
-\H{tracks-controls} \I{controls, for Tracks}Train Tracks controls
+\H{tracks-controls} \I{controls, for Tracks}Tracks controls
Left-clicking on an edge between two squares adds a track segment between
the two squares. Right-clicking on an edge adds a cross on the edge,
@@ -3473,7 +3473,7 @@ columns to match the clue.
(All the actions described in \k{common-actions} are also available.)
-\H{tracks-parameters} \I{parameters, for Tracks}Train Tracks parameters
+\H{tracks-parameters} \I{parameters, for Tracks}Tracks parameters
These parameters are available from the \q{Custom...} option on the
\q{Type} menu.
@@ -3490,12 +3490,12 @@ that would lead to impossible crossings later.
\dt \e{Disallow consecutive 1 clues}
-\dd Controls whether the Train Tracks game generation permits two
-adjacent rows or columns to have a 1 clue, or permits the row or
-column of the track's endpoint to have a 1 clue. By default this is
-not permitted, to avoid long straight boring segments of track and
-make the games more twiddly and interesting. If you want to restore
-the possibility, turn this option off.
+\dd Controls whether the Tracks game generation permits two adjacent
+rows or columns to have a 1 clue, or permits the row or column of the
+track's endpoint to have a 1 clue. By default this is not permitted,
+to avoid long straight boring segments of track and make the games
+more twiddly and interesting. If you want to restore the possibility,
+turn this option off.
\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);
void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour);
void draw_polygon(drawing *dr, const int *coords, int npoints,
int fillcolour, int outlinecolour);
+void draw_polygon_fallback(drawing *dr, const int *coords, int npoints,
+ int fillcolour, int outlinecolour);
void draw_circle(drawing *dr, int cx, int cy, int radius,
int fillcolour, int outlinecolour);
void draw_thick_line(drawing *dr, float thickness,
@@ -454,6 +456,9 @@ char *button2label(int button);
* standard per clause 7.26.11.1.) */
void swap_regions(void *av, void *bv, size_t size);
+/* comparator for sorting ints with qsort() */
+int compare_integers(const void *av, const void *bv);
+
/*
* dsf.c
*/
@@ -752,43 +757,76 @@ struct game {
int flags;
};
+#define GET_HANDLE_AS_TYPE(dr, type) ((type*)((dr)->handle))
+
+struct drawing {
+ const drawing_api *api;
+ void *handle;
+};
+
/*
* Data structure containing the drawing API implemented by the
* front end and also by cross-platform printing modules such as
* PostScript.
*/
struct drawing_api {
- void (*draw_text)(void *handle, int x, int y, int fonttype, int fontsize,
+ /*
+ * API version. Increment this when there is a breaking change to
+ * this API which requires front ends to change.
+ *
+ * There is expliclty not a public LATEST_API_VERSION define, so
+ * that front end authors will need to manually intervene when the
+ * version number changes. Naturally, this should be done
+ * sparingly.
+ *
+ * If a function is ever added to this API, please move this field
+ * to the _end_ of the structure, so that changes thereafter will
+ * shift the position of the version and lead to a compilation
+ * error if old implementations are not updated. Then remove this
+ * comment.
+ *
+ * The latest version number is 1.
+ *
+ * Change log:
+ *
+ * Version 1 (2024-08-14): Introduction of version number, in
+ * conjunction with changing every API function to take `drawing
+ * *` instead of `void *`. See commit f379130 for the detailed
+ * rationale behind this change.
+ */
+ int version;
+
+ void (*draw_text)(drawing *dr, int x, int y, int fonttype, int fontsize,
int align, int colour, const char *text);
- void (*draw_rect)(void *handle, int x, int y, int w, int h, int colour);
- void (*draw_line)(void *handle, int x1, int y1, int x2, int y2,
+ void (*draw_rect)(drawing *dr, int x, int y, int w, int h, int colour);
+ void (*draw_line)(drawing *dr, int x1, int y1, int x2, int y2,
int colour);
- void (*draw_polygon)(void *handle, const int *coords, int npoints,
+ void (*draw_polygon)(drawing *dr, const int *coords, int npoints,
int fillcolour, int outlinecolour);
- void (*draw_circle)(void *handle, int cx, int cy, int radius,
+ void (*draw_circle)(drawing *dr, int cx, int cy, int radius,
int fillcolour, int outlinecolour);
- void (*draw_update)(void *handle, int x, int y, int w, int h);
- void (*clip)(void *handle, int x, int y, int w, int h);
- void (*unclip)(void *handle);
- void (*start_draw)(void *handle);
- void (*end_draw)(void *handle);
- void (*status_bar)(void *handle, const char *text);
- blitter *(*blitter_new)(void *handle, int w, int h);
- void (*blitter_free)(void *handle, blitter *bl);
- void (*blitter_save)(void *handle, blitter *bl, int x, int y);
- void (*blitter_load)(void *handle, blitter *bl, int x, int y);
- void (*begin_doc)(void *handle, int pages);
- void (*begin_page)(void *handle, int number);
- void (*begin_puzzle)(void *handle, float xm, float xc,
+ void (*draw_update)(drawing *dr, int x, int y, int w, int h);
+ void (*clip)(drawing *dr, int x, int y, int w, int h);
+ void (*unclip)(drawing *dr);
+ void (*start_draw)(drawing *dr);
+ void (*end_draw)(drawing *dr);
+ void (*status_bar)(drawing *dr, const char *text);
+ blitter *(*blitter_new)(drawing *dr, int w, int h);
+ void (*blitter_free)(drawing *dr, blitter *bl);
+ void (*blitter_save)(drawing *dr, blitter *bl, int x, int y);
+ void (*blitter_load)(drawing *dr, blitter *bl, int x, int y);
+ void (*begin_doc)(drawing *dr, int pages);
+ void (*begin_page)(drawing *dr, int number);
+ void (*begin_puzzle)(drawing *dr, float xm, float xc,
float ym, float yc, int pw, int ph, float wmm);
- void (*end_puzzle)(void *handle);
- void (*end_page)(void *handle, int number);
- void (*end_doc)(void *handle);
- void (*line_width)(void *handle, float width);
- void (*line_dotted)(void *handle, bool dotted);
- char *(*text_fallback)(void *handle, const char *const *strings,
+ void (*end_puzzle)(drawing *dr);
+ void (*end_page)(drawing *dr, int number);
+ void (*end_doc)(drawing *dr);
+ void (*line_width)(drawing *dr, float width);
+ void (*line_dotted)(drawing *dr, bool dotted);
+ char *(*text_fallback)(drawing *dr, const char *const *strings,
int nstrings);
- void (*draw_thick_line)(void *handle, float thickness,
+ void (*draw_thick_line)(drawing *dr, float thickness,
float x1, float y1, float x2, float y2,
int colour);
};
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,
coords = snewn(npoints * 2 * 2, int);
for (n = 0; n < npoints * 2; n++) {
- /* hack to accomodate rockbox's concave polygon drawing */
- a = 2.0 * PI * ((double)n / ((double)npoints * 2.0)) + angle_offset - PI / npoints;
- r = (n % 2 == 0) ? (double)rad/2.0 : (double)rad;
+ a = 2.0 * PI * ((double)n / ((double)npoints * 2.0)) + angle_offset;
+ r = (n % 2) ? (double)rad/2.0 : (double)rad;
/* We're rotating the point at (0, -r) by a degrees */
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)
sfree(state);
}
-static int compare_int(const void *av, const void *bv)
-{
- const int *a = (const int *)av;
- const int *b = (const int *)bv;
- if (*a < *b)
- return -1;
- else if (*a > *b)
- return +1;
- else
- return 0;
-}
-
static char *solve_game(const game_state *state, const game_state *currstate,
const char *aux, const char **error)
{
@@ -758,7 +746,7 @@ static game_state *execute_move(const game_state *from, const char *move)
* conveniently being able to get hold of a clean state from
* which to practise manoeuvres.
*/
- qsort(ret->grid, ret->w*ret->h, sizeof(int), compare_int);
+ qsort(ret->grid, ret->w*ret->h, sizeof(int), compare_integers);
for (i = 0; i < ret->w*ret->h; i++)
ret->grid[i] &= ~3;
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,
{
int coords[12];
int xdx = (dx1+dx2 ? 0 : 1), xdy = (dx1+dx2 ? 1 : 0);
- coords[0] = ox + xdx + dx1;
- coords[1] = oy + xdy + dy1;
- coords[2] = ox + xdx + dx1 + dx2;
- coords[3] = oy + xdy + dy1 + dy2;
- coords[4] = ox - xdx + dx1 + dx2;
- coords[5] = oy - xdy + dy1 + dy2;
- coords[6] = ox - xdx + dx1;
- coords[7] = oy - xdy + dy1;
- coords[8] = ox - xdx;
- coords[9] = oy - xdy;
- coords[10] = ox + xdx;
- coords[11] = oy + xdy;
+ coords[0] = ox + xdx;
+ coords[1] = oy + xdy;
+ coords[2] = ox + xdx + dx1;
+ coords[3] = oy + xdy + dy1;
+ coords[4] = ox + xdx + dx1 + dx2;
+ coords[5] = oy + xdy + dy1 + dy2;
+ coords[6] = ox - xdx + dx1 + dx2;
+ coords[7] = oy - xdy + dy1 + dy2;
+ coords[8] = ox - xdx + dx1;
+ coords[9] = oy - xdy + dy1;
+ coords[10] = ox - xdx;
+ coords[11] = oy - xdy;
draw_polygon(dr, coords, 6, col, col);
}