diff --git a/desktop_version/src/FileSystemUtils.cpp b/desktop_version/src/FileSystemUtils.cpp index 7d72fd48..e507e29b 100644 --- a/desktop_version/src/FileSystemUtils.cpp +++ b/desktop_version/src/FileSystemUtils.cpp @@ -1,3 +1,5 @@ +#include "FileSystemUtils.h" + #include #include #include @@ -521,8 +523,6 @@ void FILESYSTEM_loadZip(const char* filename) } } -void FILESYSTEM_unmountAssets(void); - bool FILESYSTEM_mountAssets(const char* path) { const char* real_dir = PHYSFS_getRealDir(path); @@ -1042,26 +1042,96 @@ void FILESYSTEM_enumerateLevelDirFileNames( } } -std::vector FILESYSTEM_getLanguageCodes(void) +const char* FILESYSTEM_enumerate(const char* folder, EnumHandle* handle) { - std::vector list; - char** fileList = PHYSFS_enumerateFiles("lang"); - char** item; + /* 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). + * + * Called like this: + * + * EnumHandle handle = {}; + * const char* item; + * while ((item = FILESYSTEM_enumerate("graphics", &handle)) != NULL) + * { + * puts(item); + * } + * FILESYSTEM_freeEnumerate(&handle); + */ - for (item = fileList; *item != NULL; item++) + if (handle->physfs_list == NULL) { - char fullName[128]; - SDL_snprintf(fullName, sizeof(fullName), "lang/%s", *item); + // First iteration, set things up + handle->physfs_list = PHYSFS_enumerateFiles(folder); + handle->_item = handle->physfs_list; + } - if (FILESYSTEM_isDirectory(fullName) && *item[0] != '.') + /* Return the next item, and increment the pointer. + * (once we return NULL, handle->_item points to 1 past end of array) */ + return *(handle->_item++); +} + +const char* FILESYSTEM_enumerateAssets(const char* folder, EnumHandle* 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; + } + + char mounted_path[MAX_PATH]; + getMountedPath(mounted_path, sizeof(mounted_path), folder); + + const char* item; + while ((item = FILESYSTEM_enumerate(mounted_path, handle)) != NULL) + { + char full_name[128]; + SDL_snprintf(full_name, sizeof(full_name), "%s/%s", mounted_path, item); + if (FILESYSTEM_isFile(full_name) && item[0] != '.') { - list.push_back(*item); + return item; } } - PHYSFS_freeList(fileList); + return NULL; +} - return list; +const char* FILESYSTEM_enumerateLanguageCodes(EnumHandle* handle) +{ + /* This function enumerates all the language codes. + * + * This function is called the same way as FILESYSTEM_enumerate, see above. */ + + const char* item; + while ((item = FILESYSTEM_enumerate("lang", handle)) != NULL) + { + char full_name[128]; + SDL_snprintf(full_name, sizeof(full_name), "lang/%s", item); + + if (FILESYSTEM_isDirectory(full_name) && item[0] != '.') + { + return item; + } + } + + return NULL; +} + +void FILESYSTEM_freeEnumerate(EnumHandle* handle) +{ + /* Call this function after enumerating with FILESYSTEM_enumerate or friends. */ + if (handle == NULL) + { + return; + } + + PHYSFS_freeList(handle->physfs_list); } static int PLATFORM_getOSDirectory(char* output, const size_t output_size) diff --git a/desktop_version/src/FileSystemUtils.h b/desktop_version/src/FileSystemUtils.h index 2701b231..f986c6db 100644 --- a/desktop_version/src/FileSystemUtils.h +++ b/desktop_version/src/FileSystemUtils.h @@ -5,8 +5,6 @@ class binaryBlob; #include -#include -#include // Forward declaration, including the entirety of tinyxml2.h across all files this file is included in is unnecessary namespace tinyxml2 { class XMLDocument; } @@ -49,7 +47,16 @@ bool FILESYSTEM_loadAssetTiXml2Document(const char *name, tinyxml2::XMLDocument& void FILESYSTEM_enumerateLevelDirFileNames(void (*callback)(const char* filename)); -std::vector FILESYSTEM_getLanguageCodes(void); +struct EnumHandle +{ + char** physfs_list; + char** _item; +}; + +const char* FILESYSTEM_enumerate(const char* folder, EnumHandle* handle); +const char* FILESYSTEM_enumerateAssets(const char* folder, EnumHandle* handle); +const char* FILESYSTEM_enumerateLanguageCodes(EnumHandle* handle); +void FILESYSTEM_freeEnumerate(EnumHandle* handle); bool FILESYSTEM_levelDirHasError(void); void FILESYSTEM_clearLevelDirError(void); diff --git a/desktop_version/src/Font.cpp b/desktop_version/src/Font.cpp index 3822e701..2edb986a 100644 --- a/desktop_version/src/Font.cpp +++ b/desktop_version/src/Font.cpp @@ -9,6 +9,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 @@ -17,7 +18,14 @@ SDL_Texture* LoadImage(const char *filename, const TextureLoadType loadtype); namespace font { -Font temp_bfont; // replace with like, a vector of all loaded fonts +static FontContainer fonts_main = {}; +static FontContainer fonts_custom = {}; + +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, @@ -134,8 +142,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]; @@ -180,7 +199,7 @@ static void load_font(Font* f, const char* name) if (f->image == NULL) { - return; + return f_idx; } /* We may have a 2.3-style font.txt with all the characters. @@ -300,17 +319,63 @@ 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 + EnumHandle handle = {}; + const char* item; + while ((item = FILESYSTEM_enumerate("graphics", &handle)) != NULL) + { + load_font_filename(false, item); + } + FILESYSTEM_freeEnumerate(&handle); } void load_custom(void) { - // Custom (level-specific assets) fonts NYI + // Load all custom (level-specific assets) fonts + unload_custom(); + EnumHandle handle = {}; + const char* item; + while ((item = FILESYSTEM_enumerateAssets("graphics", &handle)) != NULL) + { + load_font_filename(true, item); + } + FILESYSTEM_freeEnumerate(&handle); + + // TODO: decide font_idx_custom } void unload_custom(void) @@ -322,7 +387,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_DestroyTexture, f->image); for (int i = 0; i < FONT_N_PAGES; i++) @@ -358,7 +423,7 @@ static 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]) { @@ -581,7 +646,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 ee84c2bb..693e84c4 100644 --- a/desktop_version/src/Font.h +++ b/desktop_version/src/Font.h @@ -60,6 +60,12 @@ struct Font GlyphInfo* glyph_page[FONT_N_PAGES]; }; +struct FontContainer +{ + size_t count; + Font* fonts; +}; + struct PrintFlags { uint8_t scale; @@ -97,8 +103,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); diff --git a/desktop_version/src/LocalizationStorage.cpp b/desktop_version/src/LocalizationStorage.cpp index 61bd3b86..45c2acc3 100644 --- a/desktop_version/src/LocalizationStorage.cpp +++ b/desktop_version/src/LocalizationStorage.cpp @@ -1033,24 +1033,26 @@ void loadlanguagelist(void) // Load the list of languages for the language screen languagelist.clear(); - std::vector codes = FILESYSTEM_getLanguageCodes(); size_t opt = 0; languagelist_curlang = 0; - for (size_t i = 0; i < codes.size(); i++) + EnumHandle handle = {}; + const char* code; + while ((code = FILESYSTEM_enumerateLanguageCodes(&handle)) != NULL) { LangMeta meta; - loadmeta(meta, codes[i]); + loadmeta(meta, code); if (meta.active) { languagelist.push_back(meta); - if (lang == codes[i]) + if (SDL_strcmp(lang.c_str(), code) == 0) { languagelist_curlang = opt; } opt++; } } + FILESYSTEM_freeEnumerate(&handle); }