From ea0e3704a8aacf87f20ba87e3b33bc4b3966c731 Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Sun, 11 Aug 2024 23:34:57 -0400 Subject: 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 --- apps/plugins/puzzles/README.rockbox | 26 +-- apps/plugins/puzzles/SOURCES | 1 + apps/plugins/puzzles/help/tracks.c | 274 +++++++++++------------ apps/plugins/puzzles/rockbox.c | 379 ++------------------------------ apps/plugins/puzzles/src/CMakeLists.txt | 10 +- apps/plugins/puzzles/src/draw-poly.c | 302 +++++++++++++++++++++++++ apps/plugins/puzzles/src/drawing.c | 196 ++++++++++------- apps/plugins/puzzles/src/inertia.c | 21 +- apps/plugins/puzzles/src/mines.c | 12 +- apps/plugins/puzzles/src/misc.c | 11 + apps/plugins/puzzles/src/puzzles.but | 20 +- apps/plugins/puzzles/src/puzzles.h | 88 +++++--- apps/plugins/puzzles/src/signpost.c | 5 +- apps/plugins/puzzles/src/twiddle.c | 14 +- apps/plugins/puzzles/src/unequal.c | 24 +- 15 files changed, 700 insertions(+), 683 deletions(-) create mode 100644 apps/plugins/puzzles/src/draw-poly.c (limited to 'apps/plugins') 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 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; ilcd_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 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 $) add_library(common $ 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 + +#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 + +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); } -- cgit v1.2.3