#include "../include/ResourceLoader.hpp" #include "../include/Program.hpp" #include "../include/Path.hpp" #include "../include/StringUtils.hpp" #include "../include/Config.hpp" #include #include #include #include #include #include #include static std::string resource_root; static std::array, 5> font_file_cache; // font_cache[(unsigned int)font_type][character_size] static std::array>, 5> font_cache; static std::unordered_map> texture_cache; 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(); } // If absolute, use the path; otherwise use fc-match to find the font static bool find_font(const std::string &font_name, std::string &font_filepath_result) { if(font_name[0] == '/') { font_filepath_result = font_name; return true; } std::string output; const char *args[] = { "fc-match", font_name.c_str(), "file", nullptr }; if(exec_program(args, accumulate_string, &output) == 0 && output.size() > 6) { output = strip(output); font_filepath_result = output.substr(6); return true; } return false; } } namespace QuickMedia::FontLoader { static const char *font_type_str(FontType font_type) { switch(font_type) { case FontType::LATIN: return "LATIN"; case FontType::LATIN_BOLD: return "LATIN_BOLD"; case FontType::LATIN_MONOSPACE: return "LATIN_MONOSPACE"; case FontType::CJK: return "CJK"; case FontType::SYMBOLS: return "SYMBOLS"; default: return "UNKNOWN"; } } mgl::Font* get_font(FontType font_type, unsigned int character_size) { // Make mgl font size match sfml font size character_size += 5; mgl::MemoryMappedFile *mapped_file = font_file_cache[(unsigned int)font_type].get(); if(!mapped_file) { std::vector noto_directories; std::string font_file_name; std::string found_font_filepath; std::string output; switch(font_type) { case FontType::LATIN: { const char *args[] = { "fc-match", "sans:lang=en", "file", nullptr }; if(get_config().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 if(!get_config().font.latin.empty() && find_font(get_config().font.latin, found_font_filepath)) { const Path font_path = found_font_filepath; noto_directories.push_back(font_path.parent().data); font_file_name = font_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: { const char *args[] = { "fc-match", "sans:bold:lang=en", "file", nullptr }; if(get_config().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 if(!get_config().font.latin_bold.empty() && find_font(get_config().font.latin_bold, found_font_filepath)) { const Path font_path = found_font_filepath; noto_directories.push_back(font_path.parent().data); font_file_name = font_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::LATIN_MONOSPACE: { const char *args[] = { "fc-match", "monospace:lang=en", "file", nullptr }; if(get_config().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 if(!get_config().font.latin_monospace.empty() && find_font(get_config().font.latin_monospace, found_font_filepath)) { const Path font_path = found_font_filepath; noto_directories.push_back(font_path.parent().data); font_file_name = font_path.filename(); } else { noto_directories.push_back("/usr/share/fonts/noto"); noto_directories.push_back("/usr/share/fonts/truetype/noto"); font_file_name = "NotoSansMono-Regular.ttf"; } break; } case FontType::CJK: { const char *args[] = { "fc-match", "sans:lang=ja", "file", nullptr }; if(get_config().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 if(!get_config().font.cjk.empty() && find_font(get_config().font.cjk, found_font_filepath)) { const Path font_path = found_font_filepath; noto_directories.push_back(font_path.parent().data); font_file_name = font_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 if(!get_config().font.symbols.empty() && find_font(get_config().font.symbols, found_font_filepath)) { const Path font_path = found_font_filepath; noto_directories.push_back(font_path.parent().data); font_file_name = font_path.filename(); } else { 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_file = false; auto new_memory_mapped_file = std::make_unique(); for(const std::string ¬o_dir : noto_directories) { if(new_memory_mapped_file->load((noto_dir + "/" + font_file_name).c_str(), mgl::MemoryMappedFile::LoadOptions{true, false})) { successfully_loaded_file = true; break; } } if(!successfully_loaded_file) { fprintf(stderr, "Warning: Failed to load font file: %s\n", font_file_name.c_str()); } mapped_file = new_memory_mapped_file.get(); font_file_cache[(unsigned int)font_type] = std::move(new_memory_mapped_file); } if(!mapped_file->data()) { return nullptr; } mgl::Font *font = font_cache[(unsigned int)font_type][character_size].get(); if(!font) { auto new_font = std::make_unique(); if(!new_font->load_from_file(*mapped_file, character_size)) { fprintf(stderr, "Warning: Failed to load font at character size %u\n", character_size); } font = new_font.get(); font_cache[(unsigned int)font_type][character_size] = std::move(new_font); } return font; } } namespace QuickMedia::TextureLoader { mgl::Texture* get_texture(const char *filepath, bool pixel_coordinates) { 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(); mgl::Texture *result = new_texture.get(); if(!new_texture->load_from_file((resource_root + str).c_str(), mgl::Texture::LoadOptions{ false, pixel_coordinates })) fprintf(stderr, "Failed to load image: %s%s\n", resource_root.c_str(), filepath); texture_cache[str] = std::move(new_texture); malloc_trim(0); return result; } }