1
0
Fork 0
forked from len0rd/rockbox

puzzles: clarify code and documentation

This adds no functionality, but instead cleans up the source and adds
some more substantial documentation.

Change-Id: I77328c171a61db7729bdf928ba094cfbed4ec0dd
This commit is contained in:
Franklin Wei 2017-11-04 11:12:45 -04:00
parent 9f62373735
commit 7f1dd6f593
2 changed files with 229 additions and 163 deletions

View file

@ -1,25 +1,40 @@
Introduction
============
This is the readme for the Rockbox port of Simon Tatham's Portable This is the readme for the Rockbox port of Simon Tatham's Portable
Puzzle Collection. Puzzle Collection.
Upstream version used is 7cae89fb4b22c305b3fd98b4e1be065ad527a9f7 from The upstream version used is subject to change, as it should be
December 2016. It should be relatively trivial to update it to a newer relatively trivial to update it to a newer version. Simply copying the
version, and should probably be done periodically as changes are made. upstream repo's contents into src/ and running genhelp.sh ought to do
it (watch out for API changes, though!).
Most of the upstream files are essentially untouched, apart from some Source structure
minor adjustments to make it compile happily on Rockbox. Some games ================
still don't work due to issues with their cursor-only control scheme
(untangle being the big culprit here) but the ones that don't are
commented out in SOURCES.games. I'll get around to fixing them
eventually.
Building is done rather hackily, with a rule for every puzzle to be Most of the upstream files in src/ are essentially untouched, apart
built... almost 40 at the time of writing. Mr. Someone ought to figure from some minor adjustments to make them compile and run happily on
out how to do that with a wildcard or something. Rockbox. The majority of the rockbox-specific code is found in
rockbox.c, with some minor stuff in rbwrappers.c and rbmalloc.c.
Help feature
============
The Help feature is implemented by compiling each puzzle against a
compressed version of each puzzle's section from the upstream
documentation. These files are stored under help/, and are generated
by genhelp.sh from the puzzles.but file in the source
distribution. The compression is LZ4, implemented in lz4tiny.c (for
decompression on target), and compress.c (for generation). genhelp.sh
should be run whenever the documentation is chagned.
Kudos to Simon (duh), and Frank, for telling me about it. Kudos to Simon (duh), and Frank, for telling me about it.
Franklin Wei (__builtin) Franklin Wei (__builtin)
Changelog
=========
April 2017: Changes made to move upstream sources to a separate April 2017: Changes made to move upstream sources to a separate
subdirectory, where they are completely unmodified from the subdirectory, where they are completely unmodified from the
original. Updating the upstream version is now as simple as copying a original. Updating the upstream version is now as simple as copying a
@ -29,3 +44,5 @@ of dummy header files.
August 2017: Every game that can be played with only the cursor keys August 2017: Every game that can be played with only the cursor keys
is now functional. is now functional.
October 2017: Added zoom feature.

View file

@ -21,6 +21,15 @@
/* rockbox frontend for puzzles */ /* rockbox frontend for puzzles */
/* This file contains the majority of the rockbox-specific code for
* the sgt-puzzles port. It implements a set of functions for the
* backend to call to actually run the games, as well as rockbox UI
* code (menus, input, etc). For a good overview of the rest of the
* puzzles code, see:
*
* <https://www.chiark.greenend.org.uk/~sgtatham/puzzles/devel/>.
*/
#include "plugin.h" #include "plugin.h"
#include "help.h" #include "help.h"
@ -44,6 +53,7 @@
#define FONT_CACHING #define FONT_CACHING
#endif #endif
/* background color (mimicking from the JS frontend) */
#define BG_R .9f /* very light gray */ #define BG_R .9f /* very light gray */
#define BG_G .9f #define BG_G .9f
#define BG_B .9f #define BG_B .9f
@ -52,9 +62,23 @@
#define ERROR_COLOR LCD_RGBPACK(255, 0, 0) #define ERROR_COLOR LCD_RGBPACK(255, 0, 0)
#define MAX_FONTS (MAXUSERFONTS - 2) #define MAX_FONTS (MAXUSERFONTS - 2)
#define FONT_TABLE PLUGIN_GAMES_DATA_DIR "/.sgt-puzzles.fnttab" #define FONT_TABLE PLUGIN_GAMES_DATA_DIR "/.sgt-puzzles.fnttab"
/* font bundle size range */
#define BUNDLE_MIN 7
#define BUNDLE_MAX 36
#define BUNDLE_COUNT (BUNDLE_MAX - BUNDLE_MIN + 1)
/* max length of C_STRING config vals */
#define MAX_STRLEN 128
/* try to increment a numeric config value up to this much */
#define CHOOSER_MAX_INCR 2
/* max font table line */
#define MAX_LINE 128
/* Sorry. */
#define MURICA #define MURICA
#ifdef MURICA #ifdef MURICA
@ -64,10 +88,25 @@
#define midend_colors midend_colours #define midend_colors midend_colours
#endif #endif
/* zoom stuff */
#define ZOOM_FACTOR 3
#define PAN_X (MIN(LCD_HEIGHT, LCD_WIDTH) / 4) #define PAN_X (MIN(LCD_HEIGHT, LCD_WIDTH) / 4)
#define PAN_Y (MIN(LCD_HEIGHT, LCD_WIDTH) / 4) #define PAN_Y (MIN(LCD_HEIGHT, LCD_WIDTH) / 4)
#define ZOOM_FACTOR 3 /* utility macros */
#undef ABS
#define ABS(a) ((a)<0?-(a):(a))
#define SWAP(a, b, t) do { t = a; a = b; b = t; } while(0);
#define fp_fpart(f, bits) ((f) & ((1 << (bits)) - 1))
#define fp_rfpart(f, bits) ((1 << (bits)) - fp_fpart(f, bits))
#define FRACBITS 16
static void fix_size(void);
static int pause_menu(void);
static inline void plot(fb_data *fb, int w, int h,
unsigned x, unsigned y, unsigned long a,
unsigned long r1, unsigned long g1, unsigned long b1,
unsigned cl, unsigned cr, unsigned cu, unsigned cd);
static midend *me = NULL; static midend *me = NULL;
static unsigned *colors = NULL; static unsigned *colors = NULL;
@ -81,29 +120,36 @@ static bool debug_mode = false;
static int help_times = 0; static int help_times = 0;
#endif #endif
static void fix_size(void); /* clipping stuff */
static int pause_menu(void);
static struct viewport clip_rect; static struct viewport clip_rect;
static bool clipped = false, zoom_enabled = false, view_mode = true; static bool clipped = false, zoom_enabled = false, view_mode = true;
extern bool audiobuf_available; extern bool audiobuf_available; /* defined in rbmalloc.c */
static fb_data *zoom_fb; static fb_data *zoom_fb; /* dynamically allocated */
static int zoom_w, zoom_h, zoom_clipu, zoom_clipd, zoom_clipl, zoom_clipr; static int zoom_w, zoom_h, zoom_clipu, zoom_clipd, zoom_clipl, zoom_clipr;
static int cur_font = FONT_UI; static int cur_font = FONT_UI;
static bool need_draw_update = false;
static int ud_l = 0, ud_u = 0, ud_r = LCD_WIDTH, ud_d = LCD_HEIGHT;
static char *titlebar = NULL;
static bool want_redraw = true, accept_input = true;
/* last timer call */
static long last_tstamp;
static volatile bool timer_on = false;
static bool load_success;
/* debug settings */
/* did I mention there's a secret debug menu? */
static struct settings_t { static struct settings_t {
int slowmo_factor; int slowmo_factor;
bool timerflash, clipoff, shortcuts, no_aa, polyanim; bool timerflash, clipoff, shortcuts, no_aa, polyanim;
} settings; } settings;
static inline void plot(fb_data *fb, int w, int h,
unsigned x, unsigned y, unsigned long a,
unsigned long r1, unsigned long g1, unsigned long b1,
unsigned cl, unsigned cr, unsigned cu, unsigned cd);
/* re-implementations of many rockbox primitives, adapted to draw into /* re-implementations of many rockbox primitives, adapted to draw into
* a custom framebuffer. */ * a custom framebuffer. */
static void zoom_drawpixel(int x, int y) static void zoom_drawpixel(int x, int y)
@ -268,78 +314,7 @@ static void zoom_alpha_bitmap(const unsigned char *bits, int x, int y, int w, in
} }
} }
/* clipping is implemented through viewports and offsetting /* font management */
* coordinates */
static void rb_clip(void *handle, int x, int y, int w, int h)
{
if(!zoom_enabled)
{
if(!settings.clipoff)
{
LOGF("rb_clip(%d %d %d %d)", x, y, w, h);
clip_rect.x = MAX(0, x);
clip_rect.y = MAX(0, y);
clip_rect.width = MIN(LCD_WIDTH, w);
clip_rect.height = MIN(LCD_HEIGHT, h);
clip_rect.font = FONT_UI;
clip_rect.drawmode = DRMODE_SOLID;
#if LCD_DEPTH > 1
clip_rect.fg_pattern = LCD_DEFAULT_FG;
clip_rect.bg_pattern = LCD_DEFAULT_BG;
#endif
rb->lcd_set_viewport(&clip_rect);
clipped = true;
}
}
else
{
zoom_clipu = y;
zoom_clipd = y + h;
zoom_clipl = x;
zoom_clipr = x + w;
}
}
static void rb_unclip(void *handle)
{
if(!zoom_enabled)
{
LOGF("rb_unclip");
rb->lcd_set_viewport(NULL);
clipped = false;
}
else
{
zoom_clipu = 0;
zoom_clipd = zoom_h;
zoom_clipl = 0;
zoom_clipr = zoom_w;
}
}
static void offset_coords(int *x, int *y)
{
if(clipped)
{
*x -= clip_rect.x;
*y -= clip_rect.y;
}
}
static void rb_color(int n)
{
if(n < 0)
{
fatal("bad color %d", n);
return;
}
rb->lcd_set_foreground(colors[n]);
}
/* font bundle size range */
#define BUNDLE_MIN 7
#define BUNDLE_MAX 36
#define BUNDLE_COUNT (BUNDLE_MAX - BUNDLE_MIN + 1)
static struct bundled_font { static struct bundled_font {
int status; /* -3 = never tried loading, or unloaded, -2 = failed to load, >= -1: loaded successfully */ int status; /* -3 = never tried loading, or unloaded, -2 = failed to load, >= -1: loaded successfully */
@ -467,6 +442,76 @@ fallback:
return; return;
} }
/*** Drawing API ***/
static void offset_coords(int *x, int *y)
{
if(clipped)
{
*x -= clip_rect.x;
*y -= clip_rect.y;
}
}
static void rb_color(int n)
{
if(n < 0)
{
fatal("bad color %d", n);
return;
}
rb->lcd_set_foreground(colors[n]);
}
/* clipping is implemented through viewports and offsetting
* coordinates */
static void rb_clip(void *handle, int x, int y, int w, int h)
{
if(!zoom_enabled)
{
if(!settings.clipoff)
{
LOGF("rb_clip(%d %d %d %d)", x, y, w, h);
clip_rect.x = MAX(0, x);
clip_rect.y = MAX(0, y);
clip_rect.width = MIN(LCD_WIDTH, w);
clip_rect.height = MIN(LCD_HEIGHT, h);
clip_rect.font = FONT_UI;
clip_rect.drawmode = DRMODE_SOLID;
#if LCD_DEPTH > 1
clip_rect.fg_pattern = LCD_DEFAULT_FG;
clip_rect.bg_pattern = LCD_DEFAULT_BG;
#endif
rb->lcd_set_viewport(&clip_rect);
clipped = true;
}
}
else
{
zoom_clipu = y;
zoom_clipd = y + h;
zoom_clipl = x;
zoom_clipr = x + w;
}
}
static void rb_unclip(void *handle)
{
if(!zoom_enabled)
{
LOGF("rb_unclip");
rb->lcd_set_viewport(NULL);
clipped = false;
}
else
{
zoom_clipu = 0;
zoom_clipd = zoom_h;
zoom_clipl = 0;
zoom_clipr = zoom_w;
}
}
static void rb_draw_text(void *handle, int x, int y, int fonttype, static void rb_draw_text(void *handle, int x, int y, int fonttype,
int fontsize, int align, int color, const char *text) int fontsize, int align, int color, const char *text)
{ {
@ -563,13 +608,6 @@ static void rb_draw_rect(void *handle, int x, int y, int w, int h, int color)
} }
} }
#define SWAP(a, b, t) do { t = a; a = b; b = t; } while(0);
#define fp_fpart(f, bits) ((f) & ((1 << (bits)) - 1))
#define fp_rfpart(f, bits) ((1 << (bits)) - fp_fpart(f, bits))
#define FRACBITS 16
/* a goes from 0-255, with a = 255 being fully opaque and a = 0 transparent */ /* a goes from 0-255, with a = 255 being fully opaque and a = 0 transparent */
static inline void plot(fb_data *fb, int w, int h, static inline void plot(fb_data *fb, int w, int h,
unsigned x, unsigned y, unsigned long a, unsigned x, unsigned y, unsigned long a,
@ -609,9 +647,6 @@ static inline void plot(fb_data *fb, int w, int h,
#endif #endif
} }
#undef ABS
#define ABS(a) ((a)<0?-(a):(a))
/* speed benchmark: 34392 lines/sec vs 112687 non-antialiased /* speed benchmark: 34392 lines/sec vs 112687 non-antialiased
* lines/sec at full optimization on ipod6g */ * lines/sec at full optimization on ipod6g */
@ -902,6 +937,7 @@ static void zoom_filltriangle(int x1, int y1,
} }
} }
/* Should probably refactor this */
static void rb_draw_poly(void *handle, int *coords, int npoints, static void rb_draw_poly(void *handle, int *coords, int npoints,
int fillcolor, int outlinecolor) int fillcolor, int outlinecolor)
{ {
@ -1207,10 +1243,6 @@ static void rb_blitter_load(void *handle, blitter *bl, int x, int y)
} }
} }
static bool need_draw_update = false;
static int ud_l = 0, ud_u = 0, ud_r = LCD_WIDTH, ud_d = LCD_HEIGHT;
static void rb_draw_update(void *handle, int x, int y, int w, int h) static void rb_draw_update(void *handle, int x, int y, int w, int h)
{ {
LOGF("rb_draw_update(%d, %d, %d, %d)", x, y, w, h); LOGF("rb_draw_update(%d, %d, %d, %d)", x, y, w, h);
@ -1260,8 +1292,6 @@ static void rb_end_draw(void *handle)
} }
} }
static char *titlebar = NULL;
static void rb_status_bar(void *handle, const char *text) static void rb_status_bar(void *handle, const char *text)
{ {
if(titlebar) if(titlebar)
@ -1342,8 +1372,70 @@ const drawing_api rb_drawing = {
NULL, NULL,
}; };
static bool want_redraw = true; /** functions exported to puzzles code **/
static bool accept_input = true;
void fatal(const char *fmt, ...)
{
va_list ap;
rb->splash(HZ, "FATAL");
va_start(ap, fmt);
char buf[80];
rb->vsnprintf(buf, 80, fmt, ap);
rb->splash(HZ * 2, buf);
va_end(ap);
exit(1);
}
void get_random_seed(void **randseed, int *randseedsize)
{
*randseed = snew(long);
long seed = *rb->current_tick;
rb->memcpy(*randseed, &seed, sizeof(seed));
*randseedsize = sizeof(long);
}
static void timer_cb(void)
{
#if LCD_DEPTH != 24
if(settings.timerflash)
{
static bool what = false;
what = !what;
if(what)
rb->lcd_framebuffer[0] = LCD_BLACK;
else
rb->lcd_framebuffer[0] = LCD_WHITE;
rb->lcd_update();
}
#endif
LOGF("timer callback");
midend_timer(me, ((float)(*rb->current_tick - last_tstamp) / (float)HZ) / settings.slowmo_factor);
last_tstamp = *rb->current_tick;
}
void activate_timer(frontend *fe)
{
last_tstamp = *rb->current_tick;
timer_on = true;
}
void deactivate_timer(frontend *fe)
{
timer_on = false;
}
void frontend_default_color(frontend *fe, float *out)
{
*out++ = BG_R;
*out++ = BG_G;
*out++ = BG_B;
}
/** frontend code -- mostly UI stuff **/
/* set do_pausemenu to false to just return -1 on BTN_PAUSE and do /* set do_pausemenu to false to just return -1 on BTN_PAUSE and do
* nothing else. */ * nothing else. */
@ -1537,42 +1629,7 @@ static int process_input(int tmo, bool do_pausemenu)
return state; return state;
} }
static long last_tstamp; /* either pan around a zoomed-in image or play zoomed-in */
static void timer_cb(void)
{
#if LCD_DEPTH != 24
if(settings.timerflash)
{
static bool what = false;
what = !what;
if(what)
rb->lcd_framebuffer[0] = LCD_BLACK;
else
rb->lcd_framebuffer[0] = LCD_WHITE;
rb->lcd_update();
}
#endif
LOGF("timer callback");
midend_timer(me, ((float)(*rb->current_tick - last_tstamp) / (float)HZ) / settings.slowmo_factor);
last_tstamp = *rb->current_tick;
}
static volatile bool timer_on = false;
void activate_timer(frontend *fe)
{
last_tstamp = *rb->current_tick;
timer_on = true;
}
void deactivate_timer(frontend *fe)
{
timer_on = false;
}
/* render to a virtual framebuffer and let the user pan (but not make any moves) */
static void zoom(void) static void zoom(void)
{ {
rb->splash(0, "Please wait..."); rb->splash(0, "Please wait...");
@ -1773,9 +1830,6 @@ static bool is_integer(const char *str)
return true; return true;
} }
/* max length of C_STRING config vals */
#define MAX_STRLEN 128
static void int_chooser(config_item *cfgs, int idx, int val) static void int_chooser(config_item *cfgs, int idx, int val)
{ {
config_item *cfg = cfgs + idx; config_item *cfg = cfgs + idx;
@ -1819,9 +1873,6 @@ static void int_chooser(config_item *cfgs, int idx, int val)
} }
if(d) if(d)
{ {
/* we try to increment the value up to this much (mainly
* a workaround for Unruly): */
#define CHOOSER_MAX_INCR 2
const char *ret; const char *ret;
for(int i = 0; i < CHOOSER_MAX_INCR; ++i) for(int i = 0; i < CHOOSER_MAX_INCR; ++i)
@ -2026,7 +2077,7 @@ done:
return success; return success;
} }
const char *preset_formatter(int sel, void *data, char *buf, size_t len) static const char *preset_formatter(int sel, void *data, char *buf, size_t len)
{ {
struct preset_menu *menu = data; struct preset_menu *menu = data;
rb->snprintf(buf, len, "%s", menu->entries[sel].title); rb->snprintf(buf, len, "%s", menu->entries[sel].title);
@ -2433,7 +2484,9 @@ static int pause_menu(void)
return 0; return 0;
} }
/* points to pluginbuf */ /* points to pluginbuf, used by rbmalloc.c */
/* useless side note: originally giant_buffer was a statically
* allocated giant array (4096KB IIRC), hence its name. */
char *giant_buffer = NULL; char *giant_buffer = NULL;
static size_t giant_buffer_len = 0; /* set on start */ static size_t giant_buffer_len = 0; /* set on start */
@ -2528,8 +2581,6 @@ static void exit_handler(void)
#endif #endif
} }
#define MAX_LINE 128
#ifdef FONT_CACHING #ifdef FONT_CACHING
/* try loading the fonts indicated in the on-disk font table */ /* try loading the fonts indicated in the on-disk font table */
static void load_fonts(void) static void load_fonts(void)
@ -2742,8 +2793,6 @@ static void save_game(void)
rb->lcd_update(); rb->lcd_update();
} }
static bool load_success;
static int mainmenu_cb(int action, const struct menu_item_ex *this_item) static int mainmenu_cb(int action, const struct menu_item_ex *this_item)
{ {
int i = (intptr_t) this_item; int i = (intptr_t) this_item;