1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Franklin Wei 2024-08-11 23:34:57 -04:00
parent 903e8c5b32
commit ea0e3704a8
15 changed files with 700 additions and 683 deletions

View file

@ -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.

View file

@ -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

View file

@ -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.";

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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)
{

View file

@ -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}

View file

@ -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);
};

View file

@ -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));

View file

@ -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;

View file

@ -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);
}