diff --git a/desktop_version/src/FileSystemUtils.cpp b/desktop_version/src/FileSystemUtils.cpp index 7d72fd48e5..bba50e0273 100644 --- a/desktop_version/src/FileSystemUtils.cpp +++ b/desktop_version/src/FileSystemUtils.cpp @@ -1042,26 +1042,120 @@ void FILESYSTEM_enumerateLevelDirFileNames( } } -std::vector FILESYSTEM_getLanguageCodes(void) +typedef struct _enum_handle { - std::vector list; - char** fileList = PHYSFS_enumerateFiles("lang"); + char** physfs_list; char** item; + char* mounted_path; +} +enum_handle; - for (item = fileList; *item != NULL; item++) +void FILESYSTEM_freeEnumerate(void** p_handle) +{ + /* Call this function after enumerating with FILESYSTEM_enumerate or friends. */ + if (p_handle != NULL) { - char fullName[128]; - SDL_snprintf(fullName, sizeof(fullName), "lang/%s", *item); + enum_handle* handle = (enum_handle*) *p_handle; + if (handle != NULL) + { + PHYSFS_freeList(handle->physfs_list); + VVV_free(handle->mounted_path); + VVV_free(handle); + } + } +} - if (FILESYSTEM_isDirectory(fullName) && *item[0] != '.') +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). + * + * Called like this: + * + * void* handle = NULL; + * const char* item; + * while ((item = FILESYSTEM_enumerate("graphics", &handle)) != NULL) + * { + * puts(item); + * } + * FILESYSTEM_freeEnumerate(&handle); + */ + + 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) { - list.push_back(*item); + 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; } - PHYSFS_freeList(fileList); + /* 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, 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; +} + +const char* FILESYSTEM_enumerateLanguageCodes(void** p_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", p_handle)) != NULL) + { + enum_handle* handle = (enum_handle*) *p_handle; + char full_name[128]; + SDL_snprintf(full_name, sizeof(full_name), "lang/%s", item); + + if (FILESYSTEM_isDirectory(full_name) && item[0] != '.') + { + return item; + } + } - return list; + return NULL; } 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 2701b23120..47eeff4fbb 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,10 @@ bool FILESYSTEM_loadAssetTiXml2Document(const char *name, tinyxml2::XMLDocument& void FILESYSTEM_enumerateLevelDirFileNames(void (*callback)(const char* filename)); -std::vector FILESYSTEM_getLanguageCodes(void); +void FILESYSTEM_freeEnumerate(void** p_handle); +const char* FILESYSTEM_enumerate(const char* folder, void** p_handle); +const char* FILESYSTEM_enumerateAssets(const char* folder, void** p_handle); +const char* FILESYSTEM_enumerateLanguageCodes(void** p_handle); bool FILESYSTEM_levelDirHasError(void); void FILESYSTEM_clearLevelDirError(void); diff --git a/desktop_version/src/Font.cpp b/desktop_version/src/Font.cpp index fa3d64b4d0..83cae7f938 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_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 = {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, @@ -131,8 +139,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]; @@ -177,7 +196,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. @@ -296,17 +315,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 + void* handle = NULL; + 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(); + void* handle = NULL; + 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) @@ -318,7 +383,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++) @@ -354,7 +419,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]) { @@ -577,7 +642,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 ee84c2bbf9..693e84c4be 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 61bd3b86ed..12c7192681 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++) + void* handle = NULL; + 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); }