Path: blob/master/editor/import/resource_importer_dynamic_font.cpp
9903 views
/**************************************************************************/1/* resource_importer_dynamic_font.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "resource_importer_dynamic_font.h"3132#include "core/io/file_access.h"33#include "core/io/resource_saver.h"34#include "editor/import/dynamic_font_import_settings.h"35#include "scene/resources/font.h"36#include "servers/text_server.h"3738String ResourceImporterDynamicFont::get_importer_name() const {39return "font_data_dynamic";40}4142String ResourceImporterDynamicFont::get_visible_name() const {43return "Font Data (Dynamic Font)";44}4546void ResourceImporterDynamicFont::get_recognized_extensions(List<String> *p_extensions) const {47if (p_extensions) {48p_extensions->push_back("ttf");49p_extensions->push_back("ttc");50p_extensions->push_back("otf");51p_extensions->push_back("otc");52p_extensions->push_back("woff");53p_extensions->push_back("woff2");54p_extensions->push_back("pfb");55p_extensions->push_back("pfm");56}57}5859String ResourceImporterDynamicFont::get_save_extension() const {60return "fontdata";61}6263String ResourceImporterDynamicFont::get_resource_type() const {64return "FontFile";65}6667void ResourceImporterDynamicFont::get_build_dependencies(const String &p_path, HashSet<String> *r_dependencies) {68Ref<FontFile> font = ResourceLoader::load(p_path);69if (font.is_valid() && font->is_multichannel_signed_distance_field()) {70r_dependencies->insert("module_msdfgen_enabled");71}72}7374bool ResourceImporterDynamicFont::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const {75if (p_option == "msdf_pixel_range" && !bool(p_options["multichannel_signed_distance_field"])) {76return false;77}78if (p_option == "msdf_size" && !bool(p_options["multichannel_signed_distance_field"])) {79return false;80}81if (p_option == "antialiasing" && bool(p_options["multichannel_signed_distance_field"])) {82return false;83}84if (p_option == "oversampling" && bool(p_options["multichannel_signed_distance_field"])) {85return false;86}87if (p_option == "subpixel_positioning" && bool(p_options["multichannel_signed_distance_field"])) {88return false;89}90if (p_option == "keep_rounding_remainders" && bool(p_options["multichannel_signed_distance_field"])) {91return false;92}93return true;94}9596int ResourceImporterDynamicFont::get_preset_count() const {97return PRESET_MAX;98}99100String ResourceImporterDynamicFont::get_preset_name(int p_idx) const {101switch (p_idx) {102case PRESET_DYNAMIC:103return TTR("Dynamically rendered TrueType/OpenType font");104case PRESET_MSDF:105return TTR("Prerendered multichannel(+true) signed distance field");106default:107return String();108}109}110111void ResourceImporterDynamicFont::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const {112bool msdf = p_preset == PRESET_MSDF;113114r_options->push_back(ImportOption(PropertyInfo(Variant::NIL, "Rendering", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant()));115116r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD Subpixel"), 1));117r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_mipmaps"), false));118r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "disable_embedded_bitmaps"), true));119r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), (msdf) ? true : false));120r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), 8));121r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "msdf_size", PROPERTY_HINT_RANGE, "1,250,1"), 48));122123r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "allow_system_fallback"), true));124r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force_autohinter"), false));125r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "modulate_color_glyphs"), false));126r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), 1));127r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel,Auto (Except Pixel Fonts)"), 4));128r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "keep_rounding_remainders"), true));129r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_RANGE, "0,10,0.1"), 0.0));130131r_options->push_back(ImportOption(PropertyInfo(Variant::NIL, "Fallbacks", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant()));132r_options->push_back(ImportOption(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("Font")), Array()));133134r_options->push_back(ImportOption(PropertyInfo(Variant::NIL, "Compress", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant()));135r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress"), true));136137// Hide from the main UI, only for advanced import dialog.138r_options->push_back(ImportOption(PropertyInfo(Variant::ARRAY, "preload", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), Array()));139r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "language_support", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), Dictionary()));140r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "script_support", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), Dictionary()));141r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "opentype_features", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), Dictionary()));142}143144bool ResourceImporterDynamicFont::has_advanced_options() const {145return true;146}147void ResourceImporterDynamicFont::show_advanced_options(const String &p_path) {148DynamicFontImportSettingsDialog::get_singleton()->open_settings(p_path);149}150151Error ResourceImporterDynamicFont::import(ResourceUID::ID p_source_id, const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {152print_verbose("Importing dynamic font from: " + p_source_file);153154int antialiasing = p_options["antialiasing"];155bool generate_mipmaps = p_options["generate_mipmaps"];156bool disable_embedded_bitmaps = p_options["disable_embedded_bitmaps"];157bool msdf = p_options["multichannel_signed_distance_field"];158int px_range = p_options["msdf_pixel_range"];159int px_size = p_options["msdf_size"];160Dictionary ot_ov = p_options["opentype_features"];161162bool autohinter = p_options["force_autohinter"];163bool modulate_color_glyphs = p_options["modulate_color_glyphs"];164bool allow_system_fallback = p_options["allow_system_fallback"];165int hinting = p_options["hinting"];166int subpixel_positioning = p_options["subpixel_positioning"];167bool keep_rounding_remainders = p_options["keep_rounding_remainders"];168real_t oversampling = p_options["oversampling"];169Array fallbacks = p_options["fallbacks"];170171// Load base font data.172Vector<uint8_t> data = FileAccess::get_file_as_bytes(p_source_file);173174// Create font.175Ref<FontFile> font;176font.instantiate();177font->set_data(data);178font->set_antialiasing((TextServer::FontAntialiasing)antialiasing);179font->set_disable_embedded_bitmaps(disable_embedded_bitmaps);180font->set_generate_mipmaps(generate_mipmaps);181font->set_multichannel_signed_distance_field(msdf);182font->set_msdf_pixel_range(px_range);183font->set_msdf_size(px_size);184font->set_opentype_feature_overrides(ot_ov);185font->set_fixed_size(0);186font->set_force_autohinter(autohinter);187font->set_modulate_color_glyphs(modulate_color_glyphs);188font->set_allow_system_fallback(allow_system_fallback);189font->set_hinting((TextServer::Hinting)hinting);190font->set_oversampling(oversampling);191font->set_fallbacks(fallbacks);192193if (subpixel_positioning == 4 /* Auto (Except Pixel Fonts) */) {194Array rids = font->get_rids();195if (!rids.is_empty()) {196PackedInt32Array glyphs = TS->font_get_supported_glyphs(rids[0]);197bool is_pixel = true;198for (int32_t gl : glyphs) {199Dictionary ct = TS->font_get_glyph_contours(rids[0], 16, gl);200PackedInt32Array contours = ct["contours"];201PackedVector3Array points = ct["points"];202int prev_start = 0;203for (int i = 0; i < contours.size(); i++) {204for (int j = prev_start; j <= contours[i]; j++) {205int next_point = (j < contours[i]) ? (j + 1) : prev_start;206if ((points[j].z != (real_t)TextServer::CONTOUR_CURVE_TAG_ON) || (!Math::is_equal_approx(points[j].x, points[next_point].x) && !Math::is_equal_approx(points[j].y, points[next_point].y))) {207is_pixel = false;208break;209}210}211prev_start = contours[i] + 1;212if (!is_pixel) {213break;214}215}216if (!is_pixel) {217break;218}219}220if (is_pixel && !glyphs.is_empty()) {221print_line(vformat("%s: Pixel font detected, disabling subpixel positioning.", p_source_file));222subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED;223} else {224subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO;225}226}227}228font->set_subpixel_positioning((TextServer::SubpixelPositioning)subpixel_positioning);229font->set_keep_rounding_remainders(keep_rounding_remainders);230231Dictionary langs = p_options["language_support"];232for (const KeyValue<Variant, Variant> &kv : langs) {233String key = kv.key;234bool enabled = kv.value;235font->set_language_support_override(key, enabled);236}237238Dictionary scripts = p_options["script_support"];239for (const KeyValue<Variant, Variant> &kv : scripts) {240String key = kv.key;241bool enabled = kv.value;242font->set_script_support_override(key, enabled);243}244245Array preload_configurations = p_options["preload"];246247for (int i = 0; i < preload_configurations.size(); i++) {248Dictionary preload_config = preload_configurations[i];249250Dictionary variation = preload_config.has("variation_opentype") ? preload_config["variation_opentype"].operator Dictionary() : Dictionary();251double embolden = preload_config.has("variation_embolden") ? preload_config["variation_embolden"].operator double() : 0;252int face_index = preload_config.has("variation_face_index") ? preload_config["variation_face_index"].operator int() : 0;253Transform2D transform = preload_config.has("variation_transform") ? preload_config["variation_transform"].operator Transform2D() : Transform2D();254Vector2i size = preload_config.has("size") ? preload_config["size"].operator Vector2i() : Vector2i(16, 0);255String name = preload_config.has("name") ? preload_config["name"].operator String() : vformat("Configuration %d", i);256257RID conf_rid = font->find_variation(variation, face_index, embolden, transform);258259Array chars = preload_config["chars"];260for (int j = 0; j < chars.size(); j++) {261char32_t c = chars[j].operator int();262TS->font_render_range(conf_rid, size, c, c);263}264265Array glyphs = preload_config["glyphs"];266for (int j = 0; j < glyphs.size(); j++) {267int32_t c = glyphs[j];268TS->font_render_glyph(conf_rid, size, c);269}270}271272int flg = 0;273if ((bool)p_options["compress"]) {274flg |= ResourceSaver::SaverFlags::FLAG_COMPRESS;275}276277print_verbose("Saving to: " + p_save_path + ".fontdata");278Error err = ResourceSaver::save(font, p_save_path + ".fontdata", flg);279ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save font to file \"" + p_save_path + ".res\".");280print_verbose("Done saving to: " + p_save_path + ".fontdata");281return OK;282}283284285