#include "../include/ResourceLoader.hpp" #include "../include/Program.hpp" #include "../include/Path.hpp" #include "../include/StringUtils.hpp" #include #include #include #include #include #include static std::string resource_root; static std::array, 4> font_cache; static std::unordered_map> texture_cache; static bool use_system_fonts = false; namespace QuickMedia { void set_resource_loader_root_path(const char *new_resource_root) { resource_root = new_resource_root; } const char* get_resource_loader_root_path() { return resource_root.c_str(); } void set_use_system_fonts(bool use) { use_system_fonts = use; } } namespace QuickMedia::FontLoader { static int accumulate_string(char *data, int size, void *userdata) { std::string *str = (std::string*)userdata; if(str->size() + size > 1024 * 1024 * 100) // 100mb sane limit, TODO: make configurable return 1; str->append(data, size); return 0; } sf::Font* get_font(FontType font_type) { sf::Font *font = font_cache[(size_t)font_type].get(); if(!font) { auto new_font = std::make_unique(); std::vector noto_directories; std::string font_file_name; switch(font_type) { case FontType::LATIN: { std::string output; const char *args[] = { "fc-match", "sans:lang=en", "file", nullptr }; if(use_system_fonts && exec_program(args, accumulate_string, &output) == 0 && output.size() > 6) { Path path = strip(output.substr(6)); noto_directories.push_back(path.parent().data); font_file_name = path.filename(); } else { noto_directories.push_back("/usr/share/fonts/noto"); noto_directories.push_back("/usr/share/fonts/truetype/noto"); font_file_name = "NotoSans-Regular.ttf"; } break; } case FontType::LATIN_BOLD: { std::string output; const char *args[] = { "fc-match", "sans:bold:lang=en", "file", nullptr }; if(use_system_fonts && exec_program(args, accumulate_string, &output) == 0 && output.size() > 6) { Path path = strip(output.substr(6)); noto_directories.push_back(path.parent().data); font_file_name = path.filename(); } else { noto_directories.push_back("/usr/share/fonts/noto"); noto_directories.push_back("/usr/share/fonts/truetype/noto"); font_file_name = "NotoSans-Bold.ttf"; } break; } case FontType::CJK: { std::string output; const char *args[] = { "fc-match", "sans:lang=ja", "file", nullptr }; if(use_system_fonts && exec_program(args, accumulate_string, &output) == 0 && output.size() > 6) { Path path = strip(output.substr(6)); noto_directories.push_back(path.parent().data); font_file_name = path.filename(); } else { noto_directories.push_back("/usr/share/fonts/noto-cjk"); noto_directories.push_back("/usr/share/fonts/truetype/noto-cjk"); font_file_name = "NotoSansCJK-Regular.ttc"; } break; } case FontType::SYMBOLS: { // TODO: Allow changing with system font setting noto_directories.push_back("/usr/share/fonts/noto"); noto_directories.push_back("/usr/share/fonts/truetype/noto"); font_file_name = "NotoSansSymbols2-Regular.ttf"; break; } } bool successfully_loaded_font = false; for(const std::string ¬o_dir : noto_directories) { if(new_font->loadFromFile(noto_dir + "/" + font_file_name)) { successfully_loaded_font = true; break; } } if(!successfully_loaded_font) fprintf(stderr, "Warning: Failed to load font: %s\n", font_file_name.c_str()); font = new_font.get(); font_cache[(size_t)font_type] = std::move(new_font); malloc_trim(0); } return font; } } namespace QuickMedia::TextureLoader { sf::Texture* get_texture(const char *filepath) { assert(!resource_root.empty()); std::string str = filepath; auto it = texture_cache.find(str); if(it != texture_cache.end()) return it->second.get(); auto new_texture = std::make_unique(); sf::Texture *result = new_texture.get(); if(!new_texture->loadFromFile(resource_root + str)) fprintf(stderr, "Failed to load image: %s%s\n", resource_root.c_str(), filepath); new_texture->setSmooth(true); texture_cache[str] = std::move(new_texture); malloc_trim(0); return result; } }