diff --git a/desktop_version/src/FileSystemUtils.cpp b/desktop_version/src/FileSystemUtils.cpp index 7d72fd48e5..08143a1532 100644 --- a/desktop_version/src/FileSystemUtils.cpp +++ b/desktop_version/src/FileSystemUtils.cpp @@ -1042,6 +1042,92 @@ void FILESYSTEM_enumerateLevelDirFileNames( } } +typedef struct _enum_handle +{ + char** physfs_list; + char** item; + char* mounted_path; +} +enum_handle; + +const char* FILESYSTEM_enumerate(const char* folder, void** p_handle) +{ + /* List all files in a folder with PHYSFS_enumerateFiles. + * + * Doing it this way means we can decide and filter what's in the lists (in + * wrapper functions), and the caller does not have to PHYSFS_freeList. + * + * Called like this: + * + * void* handle = NULL; + * const char* item; + * while ((item = FILESYSTEM_enumerate("graphics", &handle)) != NULL) + * { + * puts(item); + * } + */ + + enum_handle* handle = (enum_handle*) *p_handle; + if (*p_handle == NULL) + { + /* First iteration, set things up */ + handle = (enum_handle*) SDL_malloc(sizeof(enum_handle)); + char* mounted_path = (char*) SDL_malloc(MAX_PATH); + if (handle == NULL || mounted_path == NULL) + { + VVV_free(handle); + VVV_free(mounted_path); + return NULL; + } + handle->mounted_path = mounted_path; + getMountedPath(handle->mounted_path, MAX_PATH, folder); + handle->physfs_list = PHYSFS_enumerateFiles(handle->mounted_path); + handle->item = handle->physfs_list; + + *p_handle = handle; + } + + if (*handle->item == NULL) + { + /* We're done! */ + PHYSFS_freeList(handle->physfs_list); + VVV_free(handle->mounted_path); + VVV_free(handle); + return NULL; + } + + /* Return the next item, and increment the pointer */ + return *(handle->item++); +} + +const char* FILESYSTEM_enumerateAssets(const char* folder, void** p_handle) +{ + /* This function enumerates ONLY level-specific assets. + * If there are only global assets and no level-specific ones, + * we want an empty list. + * + * This function is called the same way as FILESYSTEM_enumerate, see above. */ + + if (!FILESYSTEM_isAssetMounted(folder)) + { + return NULL; + } + + const char* item; + while ((item = FILESYSTEM_enumerate(folder, p_handle)) != NULL) + { + enum_handle* handle = (enum_handle*) *p_handle; + char full_name[128]; + SDL_snprintf(full_name, sizeof(full_name), "%s/%s", handle->mounted_path, item); + if (FILESYSTEM_isFile(full_name) && item[0] != '.') + { + return item; + } + } + + return NULL; +} + std::vector FILESYSTEM_getLanguageCodes(void) { std::vector list; diff --git a/desktop_version/src/FileSystemUtils.h b/desktop_version/src/FileSystemUtils.h index 2701b23120..81dca33fe5 100644 --- a/desktop_version/src/FileSystemUtils.h +++ b/desktop_version/src/FileSystemUtils.h @@ -49,6 +49,9 @@ bool FILESYSTEM_loadAssetTiXml2Document(const char *name, tinyxml2::XMLDocument& void FILESYSTEM_enumerateLevelDirFileNames(void (*callback)(const char* filename)); +const char* FILESYSTEM_enumerate(const char* folder, void** p_handle); +const char* FILESYSTEM_enumerateAssets(const char* folder, void** p_handle); + std::vector FILESYSTEM_getLanguageCodes(void); bool FILESYSTEM_levelDirHasError(void); diff --git a/desktop_version/src/Font.cpp b/desktop_version/src/Font.cpp index def88228b8..5d2205c842 100644 --- a/desktop_version/src/Font.cpp +++ b/desktop_version/src/Font.cpp @@ -8,6 +8,7 @@ #include "Graphics.h" #include "Localization.h" #include "UtilityClass.h" +#include "Vlogging.h" #include "XMLUtils.h" // Sigh... This is the second forward-declaration, we need to put this in a header file @@ -16,7 +17,14 @@ SDL_Surface* LoadImage(const char *filename); namespace font { -Font temp_bfont; // replace with like, a vector of all loaded fonts +static FontContainer fonts_main = {0}; +static FontContainer fonts_custom = {0}; + +static size_t font_idx_interface = 0; +static size_t font_idx_8x8 = 0; + +static bool font_idx_custom_is_custom = false; +static size_t font_idx_custom = 0; static void codepoint_split( const uint32_t codepoint, @@ -130,8 +138,19 @@ static bool decode_xml_range(tinyxml2::XMLElement* elem, unsigned* start, unsign return true; } -static void load_font(Font* f, const char* name) +static size_t load_font(FontContainer* container, const char* name) { + Font* new_fonts = (Font*) SDL_realloc(container->fonts, sizeof(Font)*(container->count+1)); + if (new_fonts == NULL) + { + return 0; + } + container->fonts = new_fonts; + size_t f_idx = container->count++; + Font* f = &container->fonts[f_idx]; + + vlog_info("Loading font \"%s\"...", name); + char name_png[256]; char name_txt[256]; char name_xml[256]; @@ -171,7 +190,7 @@ static void load_font(Font* f, const char* name) if (f->image == NULL || f->scratch_1x == NULL || f->scratch_8x == NULL) { - return; + return f_idx; } f->n_x_glyphs = f->image->w / f->glyph_w; @@ -293,17 +312,60 @@ static void load_font(Font* f, const char* name) } } } + + return f_idx; +} + +static void load_font_filename(bool is_custom, const char* filename) +{ + /* Load font.png, and everything that matches *.fontmeta (but not font.fontmeta) */ + size_t expected_ext_start; + bool is_fontpng = SDL_strcmp(filename, "font.png") == 0; + if (is_fontpng) + { + expected_ext_start = SDL_strlen(filename)-4; + } + else + { + expected_ext_start = SDL_strlen(filename)-9; + } + if (is_fontpng || (endsWith(filename, ".fontmeta") && SDL_strcmp(filename, "font.fontmeta") != 0)) + { + char font_name[128]; + SDL_strlcpy(font_name, filename, sizeof(font_name)); + font_name[SDL_min(127, expected_ext_start)] = '\0'; + + size_t f_idx = load_font(is_custom ? &fonts_custom : &fonts_main, font_name); + + if (is_fontpng && !is_custom) + { + font_idx_8x8 = f_idx; + } + } } void load_main(void) { - // TODO PHYSFS_enumerateFiles, load everything that matches *.fontmeta or font.png (but not font.fontmeta) - load_font(&temp_bfont, "font"); + /* Load all global fonts */ + void* handle = NULL; + const char* item; + while ((item = FILESYSTEM_enumerate("graphics", &handle)) != NULL) + { + load_font_filename(false, item); + } } void load_custom(void) { - // Custom (level-specific assets) fonts NYI + /* Load all custom (level-specific assets) fonts */ + void* handle = NULL; + const char* item; + while ((item = FILESYSTEM_enumerateAssets("graphics", &handle)) != NULL) + { + load_font_filename(true, item); + } + + // TODO: decide font_idx_custom } void unload_custom(void) @@ -315,7 +377,7 @@ void unload_custom(void) void destroy(void) { /* Unload all fonts (main and custom) for exiting */ - Font* f = &temp_bfont; + Font* f = &fonts_main.fonts[font_idx_8x8]; // TODO! VVV_freefunc(SDL_FreeSurface, f->image); for (int i = 0; i < FONT_N_PAGES; i++) @@ -352,7 +414,7 @@ bool next_wrap( goto next; } - linewidth += get_advance(&font::temp_bfont, str[idx]); + linewidth += get_advance(&fonts_main.fonts[font_idx_8x8], str[idx]); // TODO get font via argument! switch (str[idx]) { @@ -621,7 +683,7 @@ static Font* fontsel_to_font(int sel) { /* Take font selection integer (0-31) and turn it into the correct Font */ // TODO handle all these cases here like 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 etc - return &font::temp_bfont; + return &fonts_main.fonts[font_idx_8x8]; } #define FLAG_PART(start, count) ((flags >> start) % (1 << count)) diff --git a/desktop_version/src/Font.h b/desktop_version/src/Font.h index e06bc80c77..4375dfc378 100644 --- a/desktop_version/src/Font.h +++ b/desktop_version/src/Font.h @@ -66,6 +66,12 @@ struct Font GlyphInfo* glyph_page[FONT_N_PAGES]; }; +struct FontContainer +{ + size_t count; + Font* fonts; +}; + struct PrintFlags { uint8_t scale; @@ -103,8 +109,6 @@ struct PrintFlags #define PR_CJK_LOW (1 << 20) /* larger fonts should stick out fully on the bottom (draw at Y) */ #define PR_CJK_HIGH (2 << 20) /* larger fonts should stick out fully on the top */ -extern Font temp_bfont; - void load_main(void); void load_custom(void); void unload_custom(void);