summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorFranklin Wei <franklin@rockbox.org>2020-10-09 21:59:57 -0400
committerFranklin Wei <franklin@rockbox.org>2020-10-09 22:01:00 -0400
commit7c00e9b30bab95c51f002037efd55a69c916368b (patch)
tree5b2a3df20f4a592929bf48bfde3fb7b707e7642f /apps
parent4b10aacbc2a8736dc7b2e24c1926dbca323741c9 (diff)
downloadrockbox-7c00e9b30bab95c51f002037efd55a69c916368b.tar.gz
rockbox-7c00e9b30bab95c51f002037efd55a69c916368b.zip
puzzles: improve frontend documentation
What it says on the tin. Change-Id: Idf8f520e0c8c1fab98d292f4ad94e5231578f9ce
Diffstat (limited to 'apps')
-rw-r--r--apps/plugins/puzzles/rockbox.c202
1 files changed, 195 insertions, 7 deletions
diff --git a/apps/plugins/puzzles/rockbox.c b/apps/plugins/puzzles/rockbox.c
index daeca3ccd7..9fabbf25d2 100644
--- a/apps/plugins/puzzles/rockbox.c
+++ b/apps/plugins/puzzles/rockbox.c
@@ -19,15 +19,194 @@
19 * 19 *
20 ***************************************************************************/ 20 ***************************************************************************/
21 21
22/* rockbox frontend for puzzles */ 22/* ================================
23 23 * Rockbox frontend for sgt-puzzles
24/* This file contains the majority of the rockbox-specific code for 24 * ================================
25 *
26 * This file contains the majority of the rockbox-specific code for
25 * the sgt-puzzles port. It implements a set of functions for the 27 * the sgt-puzzles port. It implements a set of functions for the
26 * backend to call to actually run the games, as well as rockbox UI 28 * backend to call to actually run the games, as well as rockbox UI
27 * code (menus, input, etc). For a good overview of the rest of the 29 * code (menus, input, etc). For a good overview of the rest of the
28 * puzzles code, see: 30 * puzzles code, see:
29 * 31 *
30 * <https://www.chiark.greenend.org.uk/~sgtatham/puzzles/devel/>. 32 * <https://www.chiark.greenend.org.uk/~sgtatham/puzzles/devel/>.
33 *
34 * For documentation of the contents of this file, read on.
35 *
36 * ---------------------
37 * Contents of this file
38 * ---------------------
39 *
40 * By rough order of appearnce in this file:
41 *
42 * 1) "Zoom" feature
43 *
44 * This file contains re-implementations of drawing primitives
45 * (lines, fills, text drawing, etc.) adapted to draw into a
46 * custom `zoom_fb' framebuffer at a magnification of ZOOM_FACTOR
47 * (compile-time constant, currently 3x). These are used if the
48 * global `zoom_enabled' switch is true.
49 *
50 * The zoom feature uses a modal interface with two modes: viewing
51 * mode, and interaction mode.
52 *
53 * Viewing mode is entered by default and is used to pan around the
54 * game viewport without interacting with the backend game at
55 * all. Pressing "select" while in viewing mode activates
56 * interaction mode. Instead of panning around, interaction mode
57 * sends keystrokes directly to the backend game.
58 *
59 * It used to be that the zoomed viewport would remain entirely
60 * static while the user was in interaction mode. This made the
61 * zoom feature rather klunky to use because it required frequent
62 * mode switching. In commit 5094aaa, this behavior was changed so
63 * that the frontend can now query the backend for the on-screen
64 * cursor location and move the viewport accordingly through the
65 * new midend_get_cursor_location() API (which is not yet merged
66 * into Simon's tree as of October 2020).
67 *
68 * 2) Font management
69 *
70 * Rockbox's bitmap fonts don't allow for easy rendering of text
71 * of arbitrary size. We work around this by shipping a "font
72 * pack" of pre-rendered fonts in a continuous size range spanning
73 * 10px to 36px. The code here facilitates dynamic
74 * loading/unloading of fonts from this font pack.
75 *
76 * Font loading efficiency is enhanced by a feature called the
77 * "font table" which remembers the set of fonts used by each
78 * individual puzzle to allow for pre-loading during subsequent
79 * runs. On targets with physical hard drives, this enhances
80 * startup time by loading the fonts while the disk is already
81 * spinning (from loading the plugin).
82 *
83 * 3) Drawing API
84 *
85 * The sgt-puzzles backend wants a set of function pointers to the
86 * usual drawing primitives. [1] If the `zoom_enabled' switch is
87 * on, these call upon the "zoomed" drawing routines in (1).
88 *
89 * In the normal un-zoomed case, these functions generally rely on
90 * the usual lcd_* or the pluginlib's xlcd_* API, with some
91 * exceptions: we implement a fixed-point antialiased line
92 * algorithm function and a hacky approximation of a polygon fill
93 * using triangles. [2]
94 *
95 * Some things to note: "blitters" are used to save and restore a
96 * rectangular region of the screen; "clipping" refers to
97 * temporarily bounding draw operations to a rectangular region
98 * (this is implemented with rockbox viewports).
99 *
100 * 4) Input tuning and game-specific modes
101 *
102 * The input schemes of most of the games in the sgt-puzzles
103 * collection are able to be played fairly well with only
104 * directional keys and a "select" button. Other games, however,
105 * need some special accommodations. These are enabled by
106 * `tune_input()' based on the game name and are listed below:
107 *
108 * a) Mouse mode
109 *
110 * This mode is designed to accommodate puzzles without a
111 * keyboard or cursor interface (currently only "Loopy"). We
112 * remap the cursor keys to move an on-screen cursor rather
113 * than sending arrow keys to the game.
114 *
115 * We also have the option of sending a right-click event when
116 * the "select" key is held; unfortunately, this conflicts with
117 * being able to drag the cursor while the virtual "mouse
118 * button" is depressed. This restriction is enforced by
119 * `tune_input()'.
120 *
121 * b) Numerical chooser spinbox
122 *
123 * Games that require keyboard input beyond the arrow keys and
124 * "select" (currently Filling, Keen, Solo, Towers, Undead, and
125 * Unequal) are accommodated via a spinbox-like interface.
126 *
127 * In these games, the user first uses the directional keys to
128 * position the cursor, and then presses "select" to activate
129 * the spinbox mode. Then, the left and right keys are remapped
130 * to scroll through the list of possible keystrokes accepted
131 * by the game (retrieved through the midend_request_keys() API
132 * call). Once the user is happy with their selection, they
133 * press "select" again to deactivate the chooser, and the
134 * arrow keys regain their original function.
135 *
136 * c) Force centering while zoomed
137 *
138 * (This isn't an input adaptation but it doesn't quite fit
139 * anywhere else.)
140 *
141 * In Inertia, we want to keep the ball centered on screen so
142 * that the user can see everything in all directions.
143 *
144 * d) Long-press maps to spacebar; chording; falling edge events
145 *
146 * These are grouped because the first features two are
147 * dependent on the last. This dependency is enforced with an
148 * `assert()'.
149 *
150 * Some games want a spacebar event -- so we send one on a
151 * long-press of "select". However, we usually send key events
152 * to the game immediately after the key is depressed, so we
153 * can't distinguish a hold vs. a short click.
154 *
155 * A similar issue arises when we want to allow chording of
156 * multiple keypresses (this is only used for Untangle, which
157 * allows diagonal movements by chording two arrow keys) -- if
158 * we detect that a key has just been pressed, we don't know if
159 * the user is going to press more keys later on to form a
160 * chorded input.
161 *
162 * In both of these scenarios we disambiguate the possible
163 * cases by waiting until a key has been released before we
164 * send the input keystroke(s) to the game.
165 *
166 * 5) Game configuration and preset management
167 *
168 * The backend games specify a hierarchy of user-adjustable game
169 * configuration parameters that control aspects of puzzle
170 * generation, etc. Also supplied are a set of "presets" that
171 * specify a predetermined set of configuration parameters.
172 *
173 * 6) In-game help
174 *
175 * The sgt-puzzles manual (src/puzzles.but) contains a chapter
176 * describing each game. To aid the user in learning each puzzle,
177 * each game plugin contains a compiled-in version of each
178 * puzzle's corresponding manual chapter.
179 *
180 * The compiled-in help text is automatically generated from the
181 * puzzles.but file with a system of shell scripts (genhelp.sh),
182 * which also performs LZ4 compression on the text to conserve
183 * memory on smaller targets. The output of this script is found
184 * in the help/ directory. On-target LZ4 decompression is handled
185 * by lz4tiny.c.
186 *
187 * 7) Debug menu
188 *
189 * The debug menu is activated by clicking "Quick help" five times
190 * in a row. Sorry, Android. This is helpful for benchmarking
191 * optimizations and selecting the activating the input
192 * accommodations described in (4).
193 *
194 * --------------------
195 * Building and linking
196 * --------------------
197 *
198 * Each sgt-*.rock executable is produced by statically compiling the
199 * backend (i.e. game-specific) source file and help file (see (6)
200 * above) against a set of common source files.
201 *
202 * The backend source files are listed in SOURCES.games; the common
203 * source files are in SOURCES.
204 *
205 * ----------
206 * References
207 * ----------
208 * [1]: https://www.chiark.greenend.org.uk/~sgtatham/puzzles/devel/drawing.html#drawing
209 * [2]: https://en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm
31 */ 210 */
32 211
33#include "plugin.h" 212#include "plugin.h"
@@ -1643,6 +1822,12 @@ static void send_click(int button, bool release)
1643 midend_process_key(me, x, y, button + 6); 1822 midend_process_key(me, x, y, button + 6);
1644} 1823}
1645 1824
1825/*
1826 * Numerical chooser ("spinbox")
1827 *
1828 * Let the user scroll through the options for the keys they can
1829 * press.
1830 */
1646static int choose_key(void) 1831static int choose_key(void)
1647{ 1832{
1648 int options = 0; 1833 int options = 0;
@@ -3120,7 +3305,9 @@ static void tune_input(const char *name)
3120 NULL 3305 NULL
3121 }; 3306 };
3122 3307
3123 /* wait until a key is released to send an action */ 3308 /* wait until a key is released to send an action (useful for
3309 * chording in Inertia; must be enabled if the game needs a
3310 * spacebar) */
3124 input_settings.falling_edge = string_in_list(name, falling_edge); 3311 input_settings.falling_edge = string_in_list(name, falling_edge);
3125 3312
3126 /* For want_spacebar to work, events must be sent on the falling 3313 /* For want_spacebar to work, events must be sent on the falling
@@ -3136,15 +3323,16 @@ static void tune_input(const char *name)
3136 3323
3137 input_settings.ignore_repeats = !string_in_list(name, allow_repeats); 3324 input_settings.ignore_repeats = !string_in_list(name, allow_repeats);
3138 3325
3139 /* set to false if you want dragging to be possible */ 3326 /* disable right-click on hold if you want dragging in mouse
3140 static const char *rclick_on_hold[] = { 3327 * mode */
3328 static const char *no_rclick_on_hold[] = {
3141 "Map", 3329 "Map",
3142 "Signpost", 3330 "Signpost",
3143 "Untangle", 3331 "Untangle",
3144 NULL 3332 NULL
3145 }; 3333 };
3146 3334
3147 input_settings.rclick_on_hold = !string_in_list(name, rclick_on_hold); 3335 input_settings.rclick_on_hold = !string_in_list(name, no_rclick_on_hold);
3148 3336
3149 static const char *mouse_games[] = { 3337 static const char *mouse_games[] = {
3150 "Loopy", 3338 "Loopy",