mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-08 20:55:17 -05:00
puzzles: font caching
This lets puzzles remember which fonts were loaded previously so they can be preloaded when the puzzle is started (and the disk is spinning), instead of while the game is being played.
This commit is contained in:
parent
eb43bce106
commit
aa7b168fd7
1 changed files with 200 additions and 37 deletions
|
|
@ -47,6 +47,8 @@
|
||||||
|
|
||||||
#define ERROR_COLOR LCD_RGBPACK(255, 0, 0)
|
#define ERROR_COLOR LCD_RGBPACK(255, 0, 0)
|
||||||
|
|
||||||
|
#define MAX_FONTS (MAXUSERFONTS - 2)
|
||||||
|
|
||||||
#ifdef COMBINED
|
#ifdef COMBINED
|
||||||
#define SAVE_FILE PLUGIN_GAMES_DATA_DIR "/puzzles.sav"
|
#define SAVE_FILE PLUGIN_GAMES_DATA_DIR "/puzzles.sav"
|
||||||
#else
|
#else
|
||||||
|
|
@ -54,6 +56,7 @@ static char save_file_path[MAX_PATH];
|
||||||
#define SAVE_FILE ((const char*)save_file_path)
|
#define SAVE_FILE ((const char*)save_file_path)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define FONT_TABLE PLUGIN_GAMES_DATA_DIR "/.sgt-puzzles.fnttab"
|
||||||
|
|
||||||
#define MURICA
|
#define MURICA
|
||||||
|
|
||||||
|
|
@ -147,6 +150,8 @@ static struct bundled_font {
|
||||||
|
|
||||||
static int n_fonts, access_counter = -1;
|
static int n_fonts, access_counter = -1;
|
||||||
|
|
||||||
|
/* called on exit and before entering help viewer (workaround for a
|
||||||
|
possible bug in simple_viewer) */
|
||||||
static void unload_fonts(void)
|
static void unload_fonts(void)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < 2 * BUNDLE_COUNT; ++i)
|
for(int i = 0; i < 2 * BUNDLE_COUNT; ++i)
|
||||||
|
|
@ -159,27 +164,16 @@ static void unload_fonts(void)
|
||||||
rb->lcd_setfont(FONT_UI);
|
rb->lcd_setfont(FONT_UI);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rb_setfont(int type, int size)
|
static void init_fonttab(void)
|
||||||
{
|
{
|
||||||
if(access_counter < 0)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < 2 * BUNDLE_COUNT; ++i)
|
for(int i = 0; i < 2 * BUNDLE_COUNT; ++i)
|
||||||
loaded_fonts[i].status = -3;
|
loaded_fonts[i].status = -3;
|
||||||
access_counter = 0;
|
access_counter = 0;
|
||||||
n_fonts = 0;
|
n_fonts = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* out of range */
|
static void font_path(char *buf, int type, int size)
|
||||||
if(BUNDLE_MAX < size)
|
{
|
||||||
size = BUNDLE_MAX;
|
|
||||||
|
|
||||||
int font_idx = (type == FONT_FIXED ? 0 : BUNDLE_COUNT) + size - BUNDLE_MIN;
|
|
||||||
switch(loaded_fonts[font_idx].status)
|
|
||||||
{
|
|
||||||
case -3:
|
|
||||||
{
|
|
||||||
/* never loaded */
|
|
||||||
char buf[MAX_PATH];
|
|
||||||
if(size < 10) /* Deja Vu only goes down to 10px, below that it's a giant blob */
|
if(size < 10) /* Deja Vu only goes down to 10px, below that it's a giant blob */
|
||||||
{
|
{
|
||||||
if(size < 7)
|
if(size < 7)
|
||||||
|
|
@ -188,22 +182,45 @@ static void rb_setfont(int type, int size)
|
||||||
switch(size)
|
switch(size)
|
||||||
{
|
{
|
||||||
case 7:
|
case 7:
|
||||||
rb->snprintf(buf, sizeof(buf), FONT_DIR "/07-Fixed.fnt");
|
rb->snprintf(buf, MAX_PATH, FONT_DIR "/07-Fixed.fnt");
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
rb->snprintf(buf, sizeof(buf), FONT_DIR "/08-Rockfont.fnt");
|
rb->snprintf(buf, MAX_PATH, FONT_DIR "/08-Rockfont.fnt");
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
rb->snprintf(buf, sizeof(buf), FONT_DIR "/09-Fixed.fnt");
|
rb->snprintf(buf, MAX_PATH, FONT_DIR "/09-Fixed.fnt");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rb->snprintf(buf, sizeof(buf), FONT_DIR "/%02d-%s.fnt", size, type == FONT_FIXED ? "DejaVuSansMono" : "DejaVuSans");
|
rb->snprintf(buf, MAX_PATH, FONT_DIR "/%02d-%s.fnt", size, type == FONT_FIXED ? "DejaVuSansMono" : "DejaVuSans");
|
||||||
|
}
|
||||||
|
|
||||||
if(n_fonts >= MAXUSERFONTS - 3) /* safety margin, FIXME */
|
static void rb_setfont(int type, int size)
|
||||||
|
{
|
||||||
|
/* out of range (besides, no puzzle should ever need this large
|
||||||
|
of a font, anyways) */
|
||||||
|
if(BUNDLE_MAX < size)
|
||||||
|
size = BUNDLE_MAX;
|
||||||
|
if(size < 10)
|
||||||
|
{
|
||||||
|
if(size < 7) /* no teeny-tiny fonts */
|
||||||
|
size = 7;
|
||||||
|
/* assume monospace for these */
|
||||||
|
type = FONT_FIXED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int font_idx = (type == FONT_FIXED ? 0 : BUNDLE_COUNT) + size - BUNDLE_MIN;
|
||||||
|
switch(loaded_fonts[font_idx].status)
|
||||||
|
{
|
||||||
|
case -3:
|
||||||
|
{
|
||||||
|
/* never loaded */
|
||||||
|
char buf[MAX_PATH];
|
||||||
|
font_path(buf, type, size);
|
||||||
|
if(n_fonts >= MAX_FONTS) /* safety margin, FIXME */
|
||||||
{
|
{
|
||||||
/* unload an old font */
|
/* unload an old font */
|
||||||
int oldest_use = -1, oldest_idx = -1;
|
int oldest_use = -1, oldest_idx = -1;
|
||||||
|
|
@ -1911,6 +1928,139 @@ static void exit_handler(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MAX_LINE 128
|
||||||
|
|
||||||
|
/* try loading the fonts indicated in the on-disk font table */
|
||||||
|
static void load_fonts(void)
|
||||||
|
{
|
||||||
|
int fd = rb->open(FONT_TABLE, O_RDONLY);
|
||||||
|
if(fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint64_t fontmask = 0;
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
char linebuf[MAX_LINE], *ptr = linebuf;
|
||||||
|
int len = rb->read_line(fd, linebuf, sizeof(linebuf));
|
||||||
|
if(len <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
char *tok, *save;
|
||||||
|
tok = rb->strtok_r(ptr, ":", &save);
|
||||||
|
ptr = NULL;
|
||||||
|
|
||||||
|
if(!strcmp(tok, midend_which_game(me)->name))
|
||||||
|
{
|
||||||
|
uint32_t left, right;
|
||||||
|
tok = rb->strtok_r(ptr, ":", &save);
|
||||||
|
left = atoi(tok);
|
||||||
|
tok = rb->strtok_r(ptr, ":", &save);
|
||||||
|
right = atoi(tok);
|
||||||
|
fontmask = ((uint64_t)left << 31) | right;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* nothing to do */
|
||||||
|
if(!fontmask)
|
||||||
|
{
|
||||||
|
rb->close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* loop through each bit of the mask and try loading the
|
||||||
|
corresponding font */
|
||||||
|
for(int i = 0; i < 2 * BUNDLE_COUNT; ++i)
|
||||||
|
{
|
||||||
|
if(fontmask & ((uint64_t)1 << i))
|
||||||
|
{
|
||||||
|
int size = (i > BUNDLE_COUNT ? i - BUNDLE_COUNT : i) + BUNDLE_MIN;
|
||||||
|
int type = i > BUNDLE_COUNT ? FONT_VARIABLE : FONT_FIXED;
|
||||||
|
rb_setfont(type, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rb->close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remember which fonts were loaded */
|
||||||
|
static void save_fonts(void)
|
||||||
|
{
|
||||||
|
#if 2*BUNDLE_COUNT > 62
|
||||||
|
#error too many fonts for 62-bit mask
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* first assemble the bitmask */
|
||||||
|
uint64_t fontmask = 0;
|
||||||
|
for(int i = 0; i < 2 * BUNDLE_COUNT; ++i)
|
||||||
|
{
|
||||||
|
/* try loading if we attempted to load */
|
||||||
|
if(loaded_fonts[i].status >= -2)
|
||||||
|
{
|
||||||
|
fontmask |= (uint64_t)1 << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fontmask)
|
||||||
|
{
|
||||||
|
/* font table format is as follows:
|
||||||
|
* [GAME NAME]:[32-halves of bit mask in decimal][newline]
|
||||||
|
*/
|
||||||
|
int fd = rb->open(FONT_TABLE, O_RDONLY);
|
||||||
|
int outfd = rb->open(FONT_TABLE ".tmp", O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||||
|
if(outfd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint64_t oldmask = 0;
|
||||||
|
|
||||||
|
if(fd >= 0)
|
||||||
|
{
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
char linebuf[MAX_LINE], *ptr = linebuf;
|
||||||
|
char origbuf[MAX_LINE];
|
||||||
|
int len = rb->read_line(fd, linebuf, sizeof(linebuf));
|
||||||
|
if(len <= 0)
|
||||||
|
break;
|
||||||
|
rb->memcpy(origbuf, linebuf, len);
|
||||||
|
|
||||||
|
char *tok, *save;
|
||||||
|
tok = rb->strtok_r(ptr, ":", &save);
|
||||||
|
ptr = NULL;
|
||||||
|
|
||||||
|
/* copy line if not matching */
|
||||||
|
if(strcmp(tok, midend_which_game(me)->name) != 0)
|
||||||
|
{
|
||||||
|
rb->write(outfd, origbuf, len);
|
||||||
|
rb->fdprintf(outfd, "\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* matching, remember the old mask */
|
||||||
|
assert(oldmask == 0);
|
||||||
|
uint32_t left, right;
|
||||||
|
tok = rb->strtok_r(ptr, ":", &save);
|
||||||
|
left = atoi(tok);
|
||||||
|
tok = rb->strtok_r(ptr, ":", &save);
|
||||||
|
right = atoi(tok);
|
||||||
|
oldmask = ((uint64_t)left << 31) | right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rb->close(fd);
|
||||||
|
}
|
||||||
|
uint64_t final = fontmask;
|
||||||
|
if(n_fonts < MAX_FONTS)
|
||||||
|
final |= oldmask;
|
||||||
|
uint32_t left = final >> 31;
|
||||||
|
uint32_t right = final & 0x7fffffff;
|
||||||
|
if(fd < 0)
|
||||||
|
rb->fdprintf(outfd, "# Please do not edit this file!\n");
|
||||||
|
rb->fdprintf(outfd, "%s:%u:%u\n", midend_which_game(me)->name, left, right);
|
||||||
|
rb->close(outfd);
|
||||||
|
rb->rename(FONT_TABLE ".tmp", FONT_TABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* expects a totally free me* pointer */
|
/* expects a totally free me* pointer */
|
||||||
static bool load_game(void)
|
static bool load_game(void)
|
||||||
{
|
{
|
||||||
|
|
@ -1922,8 +2072,6 @@ static bool load_game(void)
|
||||||
|
|
||||||
rb->splash(0, "Loading...");
|
rb->splash(0, "Loading...");
|
||||||
|
|
||||||
LOGF("opening %s", SAVE_FILE);
|
|
||||||
|
|
||||||
char *game;
|
char *game;
|
||||||
char *ret = identify_game(&game, read_wrapper, (void*)fd);
|
char *ret = identify_game(&game, read_wrapper, (void*)fd);
|
||||||
|
|
||||||
|
|
@ -1955,7 +2103,6 @@ static bool load_game(void)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
rb->close(fd);
|
rb->close(fd);
|
||||||
/* success, we delete the save */
|
|
||||||
rb->remove(SAVE_FILE);
|
rb->remove(SAVE_FILE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1973,14 +2120,23 @@ static bool load_game(void)
|
||||||
rb->splash(HZ, ret);
|
rb->splash(HZ, ret);
|
||||||
sfree(ret);
|
sfree(ret);
|
||||||
rb->close(fd);
|
rb->close(fd);
|
||||||
|
rb->remove(SAVE_FILE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
rb->close(fd);
|
rb->close(fd);
|
||||||
/* success, we delete the save */
|
|
||||||
rb->remove(SAVE_FILE);
|
rb->remove(SAVE_FILE);
|
||||||
|
|
||||||
|
load_fonts();
|
||||||
|
|
||||||
|
/* success */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
rb->splashf(HZ, "Cannot load save game for %s!", game);
|
rb->splashf(HZ, "Cannot load save game for %s!", game);
|
||||||
|
|
||||||
|
/* clean up, even on failure */
|
||||||
|
rb->close(fd);
|
||||||
|
rb->remove(SAVE_FILE);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
@ -1989,9 +2145,14 @@ static bool load_game(void)
|
||||||
static void save_game(void)
|
static void save_game(void)
|
||||||
{
|
{
|
||||||
rb->splash(0, "Saving...");
|
rb->splash(0, "Saving...");
|
||||||
|
|
||||||
|
/* save game */
|
||||||
int fd = rb->open(SAVE_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
int fd = rb->open(SAVE_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||||
midend_serialize(me, write_wrapper, (void*) fd);
|
midend_serialize(me, write_wrapper, (void*) fd);
|
||||||
rb->close(fd);
|
rb->close(fd);
|
||||||
|
|
||||||
|
save_fonts();
|
||||||
|
|
||||||
rb->lcd_update();
|
rb->lcd_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2064,6 +2225,8 @@ enum plugin_status plugin_start(const void *param)
|
||||||
|
|
||||||
init_default_settings();
|
init_default_settings();
|
||||||
|
|
||||||
|
init_fonttab();
|
||||||
|
|
||||||
load_success = load_game();
|
load_success = load_game();
|
||||||
|
|
||||||
#ifndef COMBINED
|
#ifndef COMBINED
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue