diff options
Diffstat (limited to 'editor/import')
36 files changed, 1259 insertions, 1991 deletions
diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp index c34379f1ec..fe32399fc6 100644 --- a/editor/import/collada.cpp +++ b/editor/import/collada.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -287,7 +287,7 @@ void Collada::_parse_image(XMLParser &parser) { if (state.version < State::Version(1, 4, 0)) { /* <1.4 */ String path = parser.get_attribute_value("source").strip_edges(); - if (path.find("://") == -1 && path.is_relative_path()) { + if (!path.contains("://") && path.is_relative_path()) { // path is relative to file being loaded, so convert to a resource path image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path.uri_decode())); } @@ -300,7 +300,7 @@ void Collada::_parse_image(XMLParser &parser) { parser.read(); String path = parser.get_node_data().strip_edges().uri_decode(); - if (path.find("://") == -1 && path.is_relative_path()) { + if (!path.contains("://") && path.is_relative_path()) { // path is relative to file being loaded, so convert to a resource path path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path)); @@ -411,8 +411,9 @@ Vector<String> Collada::_read_string_array(XMLParser &parser) { } Transform3D Collada::_read_transform(XMLParser &parser) { - if (parser.is_empty()) + if (parser.is_empty()) { return Transform3D(); + } Vector<String> array; while (parser.read() == OK) { @@ -1008,11 +1009,6 @@ void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name String source = _uri_to_id(parser.get_attribute_value("source")); if (semantic == "TEXCOORD") { - /* - if (parser.has_attribute("set"))// a texcoord - semantic+=parser.get_attribute_value("set"); - else - semantic="TEXCOORD0";*/ semantic = "TEXCOORD" + itos(last_ref++); } int offset = parser.get_attribute_value("offset").to_int(); @@ -1193,11 +1189,6 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) { skindata.weights = weights; } - /* - else if (!parser.is_empty()) - parser.skip_section(); - */ - } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "skin") { break; } @@ -1257,19 +1248,8 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) { } } else if (section == "Name_array" || section == "IDREF_array") { // create a new array and read it. - - /* - if (section=="IDREF_array") - morphdata.use_idrefs=true; - */ if (morphdata.sources.has(current_source)) { morphdata.sources[current_source].sarray = _read_string_array(parser); - /* - if (section=="IDREF_array") { - Vector<String> sa = morphdata.sources[current_source].sarray; - for(int i=0;i<sa.size();i++) - state.idref_joints.insert(sa[i]); - }*/ COLLADA_PRINT("section: " + current_source + " read " + itos(morphdata.sources[current_source].array.size()) + " values."); } } else if (section == "technique_common") { @@ -1302,11 +1282,6 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) { } } } - /* - else if (!parser.is_empty()) - parser.skip_section(); - */ - } else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "morph") { break; } @@ -1362,7 +1337,7 @@ Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) { } else if (parser.get_node_name() == "skeleton") { parser.read(); String uri = _uri_to_id(parser.get_node_data()); - if (uri != "") { + if (!uri.is_empty()) { geom->skeletons.push_back(uri); } } @@ -1464,7 +1439,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) { bool found_name = false; - if (id == "") { + if (id.is_empty()) { id = "%NODEID%" + itos(Math::rand()); } else { @@ -1479,7 +1454,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) { Node *node = nullptr; name = parser.has_attribute("name") ? parser.get_attribute_value_safe("name") : parser.get_attribute_value_safe("id"); - if (name == "") { + if (name.is_empty()) { name = id; } else { found_name = true; @@ -1499,7 +1474,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) { joint->sid = parser.get_attribute_value_safe("name"); } - if (joint->sid != "") { + if (!joint->sid.is_empty()) { state.sid_to_node_map[joint->sid] = id; } @@ -1696,16 +1671,16 @@ void Collada::_parse_animation(XMLParser &parser) { source_param_types[current_source] = Vector<String>(); } else if (name == "float_array") { - if (current_source != "") { + if (!current_source.is_empty()) { float_sources[current_source] = _read_float_array(parser); } } else if (name == "Name_array") { - if (current_source != "") { + if (!current_source.is_empty()) { string_sources[current_source] = _read_string_array(parser); } } else if (name == "accessor") { - if (current_source != "" && parser.has_attribute("stride")) { + if (!current_source.is_empty() && parser.has_attribute("stride")) { source_strides[current_source] = parser.get_attribute_value("stride").to_int(); } } else if (name == "sampler") { @@ -1725,7 +1700,7 @@ void Collada::_parse_animation(XMLParser &parser) { } } else if (name == "input") { - if (current_sampler != "") { + if (!current_sampler.is_empty()) { samplers[current_sampler][parser.get_attribute_value("semantic")] = parser.get_attribute_value("source"); } @@ -1831,14 +1806,14 @@ void Collada::_parse_animation(XMLParser &parser) { } } - if (target.find("/") != -1) { //transform component + if (target.contains("/")) { //transform component track.target = target.get_slicec('/', 0); track.param = target.get_slicec('/', 1); - if (track.param.find(".") != -1) { + if (track.param.contains(".")) { track.component = track.param.get_slice(".", 1).to_upper(); } track.param = track.param.get_slice(".", 0); - if (names.size() > 1 && track.component == "") { + if (names.size() > 1 && track.component.is_empty()) { //this is a guess because the collada spec is ambiguous here... //i suppose if you have many names (outputs) you can't use a component and i should abide to that. track.component = name; @@ -1855,7 +1830,7 @@ void Collada::_parse_animation(XMLParser &parser) { state.referenced_tracks[target].push_back(state.animation_tracks.size() - 1); - if (id != "") { + if (!id.is_empty()) { if (!state.by_id_tracks.has(id)) { state.by_id_tracks[id] = Vector<int>(); } @@ -1953,10 +1928,10 @@ void Collada::_parse_library(XMLParser &parser) { while (parser.read() == OK) { if (parser.get_node_type() == XMLParser::NODE_ELEMENT) { if (parser.get_node_name() == "mesh") { - state.mesh_name_map[id] = (name2 != "") ? name2 : id; + state.mesh_name_map[id] = (!name2.is_empty()) ? name2 : id; _parse_mesh_geometry(parser, id, name2); } else if (parser.get_node_name() == "spline") { - state.mesh_name_map[id] = (name2 != "") ? name2 : id; + state.mesh_name_map[id] = (!name2.is_empty()) ? name2 : id; _parse_curve_geometry(parser, id, name2); } else if (!parser.is_empty()) { parser.skip_section(); @@ -2286,7 +2261,7 @@ void Collada::_find_morph_nodes(VisualScene *p_vscene, Node *p_node) { if (nj->controller) { String base = nj->source; - while (base != "" && !state.mesh_data_map.has(base)) { + while (!base.is_empty() && !state.mesh_data_map.has(base)) { if (state.skin_controller_data_map.has(base)) { SkinControllerData &sk = state.skin_controller_data_map[base]; base = sk.base; diff --git a/editor/import/collada.h b/editor/import/collada.h index 5e38637504..b5e4cd9983 100644 --- a/editor/import/collada.h +++ b/editor/import/collada.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/editor/import/dynamicfont_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp index 45937e20bc..20349e8ccb 100644 --- a/editor/import/dynamicfont_import_settings.cpp +++ b/editor/import/dynamic_font_import_settings.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* dynamicfont_import_settings.cpp */ +/* dynamic_font_import_settings.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,8 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "dynamicfont_import_settings.h" +#include "dynamic_font_import_settings.h" +#include "editor/editor_file_dialog.h" +#include "editor/editor_file_system.h" +#include "editor/editor_inspector.h" +#include "editor/editor_locale_dialog.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" @@ -427,6 +431,7 @@ void DynamicFontImportSettings::_add_glyph_range_item(int32_t p_start, int32_t p for (int i = 0; i < pages; i++) { TreeItem *item = glyph_tree->create_item(glyph_root); ERR_FAIL_NULL(item); + item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); item->set_text(0, _pad_zeros(String::num_int64(start, 16)) + " - " + _pad_zeros(String::num_int64(start + page_size, 16))); item->set_text(1, p_name); item->set_metadata(0, Vector2i(start, start + page_size)); @@ -435,6 +440,7 @@ void DynamicFontImportSettings::_add_glyph_range_item(int32_t p_start, int32_t p if (remain > 0) { TreeItem *item = glyph_tree->create_item(glyph_root); ERR_FAIL_NULL(item); + item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); item->set_text(0, _pad_zeros(String::num_int64(start, 16)) + " - " + _pad_zeros(String::num_int64(p_end, 16))); item->set_text(1, p_name); item->set_metadata(0, Vector2i(start, p_end)); @@ -442,398 +448,6 @@ void DynamicFontImportSettings::_add_glyph_range_item(int32_t p_start, int32_t p } /*************************************************************************/ -/* Languages and scripts */ -/*************************************************************************/ - -struct CodeInfo { - String name; - String code; -}; - -static CodeInfo langs[] = { - { U"Custom", U"xx" }, - { U"-", U"-" }, - { U"Abkhazian", U"ab" }, - { U"Afar", U"aa" }, - { U"Afrikaans", U"af" }, - { U"Akan", U"ak" }, - { U"Albanian", U"sq" }, - { U"Amharic", U"am" }, - { U"Arabic", U"ar" }, - { U"Aragonese", U"an" }, - { U"Armenian", U"hy" }, - { U"Assamese", U"as" }, - { U"Avaric", U"av" }, - { U"Avestan", U"ae" }, - { U"Aymara", U"ay" }, - { U"Azerbaijani", U"az" }, - { U"Bambara", U"bm" }, - { U"Bashkir", U"ba" }, - { U"Basque", U"eu" }, - { U"Belarusian", U"be" }, - { U"Bengali", U"bn" }, - { U"Bihari", U"bh" }, - { U"Bislama", U"bi" }, - { U"Bosnian", U"bs" }, - { U"Breton", U"br" }, - { U"Bulgarian", U"bg" }, - { U"Burmese", U"my" }, - { U"Catalan", U"ca" }, - { U"Chamorro", U"ch" }, - { U"Chechen", U"ce" }, - { U"Chichewa", U"ny" }, - { U"Chinese", U"zh" }, - { U"Chuvash", U"cv" }, - { U"Cornish", U"kw" }, - { U"Corsican", U"co" }, - { U"Cree", U"cr" }, - { U"Croatian", U"hr" }, - { U"Czech", U"cs" }, - { U"Danish", U"da" }, - { U"Divehi", U"dv" }, - { U"Dutch", U"nl" }, - { U"Dzongkha", U"dz" }, - { U"English", U"en" }, - { U"Esperanto", U"eo" }, - { U"Estonian", U"et" }, - { U"Ewe", U"ee" }, - { U"Faroese", U"fo" }, - { U"Fijian", U"fj" }, - { U"Finnish", U"fi" }, - { U"French", U"fr" }, - { U"Fulah", U"ff" }, - { U"Galician", U"gl" }, - { U"Georgian", U"ka" }, - { U"German", U"de" }, - { U"Greek", U"el" }, - { U"Guarani", U"gn" }, - { U"Gujarati", U"gu" }, - { U"Haitian", U"ht" }, - { U"Hausa", U"ha" }, - { U"Hebrew", U"he" }, - { U"Herero", U"hz" }, - { U"Hindi", U"hi" }, - { U"Hiri Motu", U"ho" }, - { U"Hungarian", U"hu" }, - { U"Interlingua", U"ia" }, - { U"Indonesian", U"id" }, - { U"Interlingue", U"ie" }, - { U"Irish", U"ga" }, - { U"Igbo", U"ig" }, - { U"Inupiaq", U"ik" }, - { U"Ido", U"io" }, - { U"Icelandic", U"is" }, - { U"Italian", U"it" }, - { U"Inuktitut", U"iu" }, - { U"Japanese", U"ja" }, - { U"Javanese", U"jv" }, - { U"Kalaallisut", U"kl" }, - { U"Kannada", U"kn" }, - { U"Kanuri", U"kr" }, - { U"Kashmiri", U"ks" }, - { U"Kazakh", U"kk" }, - { U"Central Khmer", U"km" }, - { U"Kikuyu", U"ki" }, - { U"Kinyarwanda", U"rw" }, - { U"Kirghiz", U"ky" }, - { U"Komi", U"kv" }, - { U"Kongo", U"kg" }, - { U"Korean", U"ko" }, - { U"Kurdish", U"ku" }, - { U"Kuanyama", U"kj" }, - { U"Latin", U"la" }, - { U"Luxembourgish", U"lb" }, - { U"Ganda", U"lg" }, - { U"Limburgan", U"li" }, - { U"Lingala", U"ln" }, - { U"Lao", U"lo" }, - { U"Lithuanian", U"lt" }, - { U"Luba-Katanga", U"lu" }, - { U"Latvian", U"lv" }, - { U"Man", U"gv" }, - { U"Macedonian", U"mk" }, - { U"Malagasy", U"mg" }, - { U"Malay", U"ms" }, - { U"Malayalam", U"ml" }, - { U"Maltese", U"mt" }, - { U"Maori", U"mi" }, - { U"Marathi", U"mr" }, - { U"Marshallese", U"mh" }, - { U"Mongolian", U"mn" }, - { U"Nauru", U"na" }, - { U"Navajo", U"nv" }, - { U"North Ndebele", U"nd" }, - { U"Nepali", U"ne" }, - { U"Ndonga", U"ng" }, - { U"Norwegian Bokmål", U"nb" }, - { U"Norwegian Nynorsk", U"nn" }, - { U"Norwegian", U"no" }, - { U"Sichuan Yi, Nuosu", U"ii" }, - { U"South Ndebele", U"nr" }, - { U"Occitan", U"oc" }, - { U"Ojibwa", U"oj" }, - { U"Church Slavic", U"cu" }, - { U"Oromo", U"om" }, - { U"Oriya", U"or" }, - { U"Ossetian", U"os" }, - { U"Punjabi", U"pa" }, - { U"Pali", U"pi" }, - { U"Persian", U"fa" }, - { U"Polish", U"pl" }, - { U"Pashto", U"ps" }, - { U"Portuguese", U"pt" }, - { U"Quechua", U"qu" }, - { U"Romansh", U"rm" }, - { U"Rundi", U"rn" }, - { U"Romanian", U"ro" }, - { U"Russian", U"ru" }, - { U"Sanskrit", U"sa" }, - { U"Sardinian", U"sc" }, - { U"Sindhi", U"sd" }, - { U"Northern Sami", U"se" }, - { U"Samoan", U"sm" }, - { U"Sango", U"sg" }, - { U"Serbian", U"sr" }, - { U"Gaelic", U"gd" }, - { U"Shona", U"sn" }, - { U"Sinhala", U"si" }, - { U"Slovak", U"sk" }, - { U"Slovenian", U"sl" }, - { U"Somali", U"so" }, - { U"Southern Sotho", U"st" }, - { U"Spanish", U"es" }, - { U"Sundanese", U"su" }, - { U"Swahili", U"sw" }, - { U"Swati", U"ss" }, - { U"Swedish", U"sv" }, - { U"Tamil", U"ta" }, - { U"Telugu", U"te" }, - { U"Tajik", U"tg" }, - { U"Thai", U"th" }, - { U"Tigrinya", U"ti" }, - { U"Tibetan", U"bo" }, - { U"Turkmen", U"tk" }, - { U"Tagalog", U"tl" }, - { U"Tswana", U"tn" }, - { U"Tonga", U"to" }, - { U"Turkish", U"tr" }, - { U"Tsonga", U"ts" }, - { U"Tatar", U"tt" }, - { U"Twi", U"tw" }, - { U"Tahitian", U"ty" }, - { U"Uighur", U"ug" }, - { U"Ukrainian", U"uk" }, - { U"Urdu", U"ur" }, - { U"Uzbek", U"uz" }, - { U"Venda", U"ve" }, - { U"Vietnamese", U"vi" }, - { U"Volapük", U"vo" }, - { U"Walloon", U"wa" }, - { U"Welsh", U"cy" }, - { U"Wolof", U"wo" }, - { U"Western Frisian", U"fy" }, - { U"Xhosa", U"xh" }, - { U"Yiddish", U"yi" }, - { U"Yoruba", U"yo" }, - { U"Zhuang", U"za" }, - { U"Zulu", U"zu" }, - { String(), String() } -}; - -static CodeInfo scripts[] = { - { U"Custom", U"Qaaa" }, - { U"-", U"-" }, - { U"Adlam", U"Adlm" }, - { U"Afaka", U"Afak" }, - { U"Caucasian Albanian", U"Aghb" }, - { U"Ahom", U"Ahom" }, - { U"Arabic", U"Arab" }, - { U"Imperial Aramaic", U"Armi" }, - { U"Armenian", U"Armn" }, - { U"Avestan", U"Avst" }, - { U"Balinese", U"Bali" }, - { U"Bamum", U"Bamu" }, - { U"Bassa Vah", U"Bass" }, - { U"Batak", U"Batk" }, - { U"Bengali", U"Beng" }, - { U"Bhaiksuki", U"Bhks" }, - { U"Blissymbols", U"Blis" }, - { U"Bopomofo", U"Bopo" }, - { U"Brahmi", U"Brah" }, - { U"Braille", U"Brai" }, - { U"Buginese", U"Bugi" }, - { U"Buhid", U"Buhd" }, - { U"Chakma", U"Cakm" }, - { U"Unified Canadian Aboriginal", U"Cans" }, - { U"Carian", U"Cari" }, - { U"Cham", U"Cham" }, - { U"Cherokee", U"Cher" }, - { U"Chorasmian", U"Chrs" }, - { U"Cirth", U"Cirt" }, - { U"Coptic", U"Copt" }, - { U"Cypro-Minoan", U"Cpmn" }, - { U"Cypriot", U"Cprt" }, - { U"Cyrillic", U"Cyrl" }, - { U"Devanagari", U"Deva" }, - { U"Dives Akuru", U"Diak" }, - { U"Dogra", U"Dogr" }, - { U"Deseret", U"Dsrt" }, - { U"Duployan", U"Dupl" }, - { U"Egyptian demotic", U"Egyd" }, - { U"Egyptian hieratic", U"Egyh" }, - { U"Egyptian hieroglyphs", U"Egyp" }, - { U"Elbasan", U"Elba" }, - { U"Elymaic", U"Elym" }, - { U"Ethiopic", U"Ethi" }, - { U"Khutsuri", U"Geok" }, - { U"Georgian", U"Geor" }, - { U"Glagolitic", U"Glag" }, - { U"Gunjala Gondi", U"Gong" }, - { U"Masaram Gondi", U"Gonm" }, - { U"Gothic", U"Goth" }, - { U"Grantha", U"Gran" }, - { U"Greek", U"Grek" }, - { U"Gujarati", U"Gujr" }, - { U"Gurmukhi", U"Guru" }, - { U"Hangul", U"Hang" }, - { U"Han", U"Hani" }, - { U"Hanunoo", U"Hano" }, - { U"Hatran", U"Hatr" }, - { U"Hebrew", U"Hebr" }, - { U"Hiragana", U"Hira" }, - { U"Anatolian Hieroglyphs", U"Hluw" }, - { U"Pahawh Hmong", U"Hmng" }, - { U"Nyiakeng Puachue Hmong", U"Hmnp" }, - { U"Old Hungarian", U"Hung" }, - { U"Indus", U"Inds" }, - { U"Old Italic", U"Ital" }, - { U"Javanese", U"Java" }, - { U"Jurchen", U"Jurc" }, - { U"Kayah Li", U"Kali" }, - { U"Katakana", U"Kana" }, - { U"Kharoshthi", U"Khar" }, - { U"Khmer", U"Khmr" }, - { U"Khojki", U"Khoj" }, - { U"Khitan large script", U"Kitl" }, - { U"Khitan small script", U"Kits" }, - { U"Kannada", U"Knda" }, - { U"Kpelle", U"Kpel" }, - { U"Kaithi", U"Kthi" }, - { U"Tai Tham", U"Lana" }, - { U"Lao", U"Laoo" }, - { U"Latin", U"Latn" }, - { U"Leke", U"Leke" }, - { U"Lepcha", U"Lepc" }, - { U"Limbu", U"Limb" }, - { U"Linear A", U"Lina" }, - { U"Linear B", U"Linb" }, - { U"Lisu", U"Lisu" }, - { U"Loma", U"Loma" }, - { U"Lycian", U"Lyci" }, - { U"Lydian", U"Lydi" }, - { U"Mahajani", U"Mahj" }, - { U"Makasar", U"Maka" }, - { U"Mandaic", U"Mand" }, - { U"Manichaean", U"Mani" }, - { U"Marchen", U"Marc" }, - { U"Mayan Hieroglyphs", U"Maya" }, - { U"Medefaidrin", U"Medf" }, - { U"Mende Kikakui", U"Mend" }, - { U"Meroitic Cursive", U"Merc" }, - { U"Meroitic Hieroglyphs", U"Mero" }, - { U"Malayalam", U"Mlym" }, - { U"Modi", U"Modi" }, - { U"Mongolian", U"Mong" }, - { U"Moon", U"Moon" }, - { U"Mro", U"Mroo" }, - { U"Meitei Mayek", U"Mtei" }, - { U"Multani", U"Mult" }, - { U"Myanmar (Burmese)", U"Mymr" }, - { U"Nandinagari", U"Nand" }, - { U"Old North Arabian", U"Narb" }, - { U"Nabataean", U"Nbat" }, - { U"Newa", U"Newa" }, - { U"Naxi Dongba", U"Nkdb" }, - { U"Nakhi Geba", U"Nkgb" }, - { U"N’Ko", U"Nkoo" }, - { U"Nüshu", U"Nshu" }, - { U"Ogham", U"Ogam" }, - { U"Ol Chiki", U"Olck" }, - { U"Old Turkic", U"Orkh" }, - { U"Oriya", U"Orya" }, - { U"Osage", U"Osge" }, - { U"Osmanya", U"Osma" }, - { U"Old Uyghur", U"Ougr" }, - { U"Palmyrene", U"Palm" }, - { U"Pau Cin Hau", U"Pauc" }, - { U"Proto-Cuneiform", U"Pcun" }, - { U"Proto-Elamite", U"Pelm" }, - { U"Old Permic", U"Perm" }, - { U"Phags-pa", U"Phag" }, - { U"Inscriptional Pahlavi", U"Phli" }, - { U"Psalter Pahlavi", U"Phlp" }, - { U"Book Pahlavi", U"Phlv" }, - { U"Phoenician", U"Phnx" }, - { U"Klingon", U"Piqd" }, - { U"Miao", U"Plrd" }, - { U"Inscriptional Parthian", U"Prti" }, - { U"Proto-Sinaitic", U"Psin" }, - { U"Ranjana", U"Ranj" }, - { U"Rejang", U"Rjng" }, - { U"Hanifi Rohingya", U"Rohg" }, - { U"Rongorongo", U"Roro" }, - { U"Runic", U"Runr" }, - { U"Samaritan", U"Samr" }, - { U"Sarati", U"Sara" }, - { U"Old South Arabian", U"Sarb" }, - { U"Saurashtra", U"Saur" }, - { U"SignWriting", U"Sgnw" }, - { U"Shavian", U"Shaw" }, - { U"Sharada", U"Shrd" }, - { U"Shuishu", U"Shui" }, - { U"Siddham", U"Sidd" }, - { U"Khudawadi", U"Sind" }, - { U"Sinhala", U"Sinh" }, - { U"Sogdian", U"Sogd" }, - { U"Old Sogdian", U"Sogo" }, - { U"Sora Sompeng", U"Sora" }, - { U"Soyombo", U"Soyo" }, - { U"Sundanese", U"Sund" }, - { U"Syloti Nagri", U"Sylo" }, - { U"Syriac", U"Syrc" }, - { U"Tagbanwa", U"Tagb" }, - { U"Takri", U"Takr" }, - { U"Tai Le", U"Tale" }, - { U"New Tai Lue", U"Talu" }, - { U"Tamil", U"Taml" }, - { U"Tangut", U"Tang" }, - { U"Tai Viet", U"Tavt" }, - { U"Telugu", U"Telu" }, - { U"Tengwar", U"Teng" }, - { U"Tifinagh", U"Tfng" }, - { U"Tagalog", U"Tglg" }, - { U"Thaana", U"Thaa" }, - { U"Thai", U"Thai" }, - { U"Tibetan", U"Tibt" }, - { U"Tirhuta", U"Tirh" }, - { U"Tangsa", U"Tnsa" }, - { U"Toto", U"Toto" }, - { U"Ugaritic", U"Ugar" }, - { U"Vai", U"Vaii" }, - { U"Visible Speech", U"Visp" }, - { U"Vithkuqi", U"Vith" }, - { U"Warang Citi", U"Wara" }, - { U"Wancho", U"Wcho" }, - { U"Woleai", U"Wole" }, - { U"Old Persian", U"Xpeo" }, - { U"Cuneiform", U"Xsux" }, - { U"Yezidi", U"Yezi" }, - { U"Yi", U"Yiii" }, - { U"Zanabazar Square", U"Zanb" }, - { String(), String() } -}; - -/*************************************************************************/ /* Page 1 callbacks: Rendering Options */ /*************************************************************************/ @@ -866,6 +480,18 @@ void DynamicFontImportSettings::_main_prop_changed(const String &p_edited_proper if (font_preview->get_data_count() > 0) { font_preview->get_data(0)->set_hinting((TextServer::Hinting)import_settings_data->get("hinting").operator int()); } + } else if (p_edited_property == "subpixel_positioning") { + if (font_preview->get_data_count() > 0) { + font_preview->get_data(0)->set_subpixel_positioning((TextServer::SubpixelPositioning)import_settings_data->get("subpixel_positioning").operator int()); + } + } else if (p_edited_property == "embolden") { + if (font_preview->get_data_count() > 0) { + font_preview->get_data(0)->set_embolden(import_settings_data->get("embolden")); + } + } else if (p_edited_property == "transform") { + if (font_preview->get_data_count() > 0) { + font_preview->get_data(0)->set_transform(import_settings_data->get("transform")); + } } else if (p_edited_property == "oversampling") { if (font_preview->get_data_count() > 0) { font_preview->get_data(0)->set_oversampling(import_settings_data->get("oversampling")); @@ -885,7 +511,7 @@ void DynamicFontImportSettings::_variation_add() { vars_item->set_text(0, TTR("New configuration")); vars_item->set_editable(0, true); - vars_item->add_button(1, vars_list->get_theme_icon("Remove", "EditorIcons"), BUTTON_REMOVE_VAR, false, TTR("Remove Variation")); + vars_item->add_button(1, vars_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove Variation")); vars_item->set_button_color(1, 0, Color(1, 1, 1, 0.75)); Ref<DynamicFontImportSettingsData> import_variation_data; @@ -942,7 +568,7 @@ void DynamicFontImportSettings::_variation_changed(const String &p_edited_proper void DynamicFontImportSettings::_variations_validate() { String warn; if (!vars_list_root->get_first_child()) { - warn = TTR("Warinig: There are no configurations specified, no glyphs will be pre-rendered."); + warn = TTR("Warning: There are no configurations specified, no glyphs will be pre-rendered."); } for (TreeItem *vars_item_a = vars_list_root->get_first_child(); vars_item_a; vars_item_a = vars_item_a->get_next()) { Ref<DynamicFontImportSettingsData> import_variation_data_a = vars_item_a->get_metadata(0); @@ -957,7 +583,7 @@ void DynamicFontImportSettings::_variations_validate() { match = match && (import_variation_data_b->settings[E->key()] == E->get()); } if (match) { - warn = TTR("Warinig: Multiple configurations have identical settings. Duplicates will be ignored."); + warn = TTR("Warning: Multiple configurations have identical settings. Duplicates will be ignored."); break; } } @@ -1019,7 +645,7 @@ void DynamicFontImportSettings::_glyph_text_selected() { selected_glyphs.insert(gl[i].index); } } - TS->free(text_rid); + TS->free_rid(text_rid); label_glyphs->set_text(TTR("Preloaded glyphs: ") + itos(selected_glyphs.size())); } _range_selected(); @@ -1033,8 +659,8 @@ void DynamicFontImportSettings::_glyph_selected() { TreeItem *item = glyph_table->get_selected(); ERR_FAIL_NULL(item); - Color scol = glyph_table->get_theme_color("box_selection_fill_color", "Editor"); - Color fcol = glyph_table->get_theme_color("font_selected_color", "Editor"); + Color scol = glyph_table->get_theme_color(SNAME("box_selection_fill_color"), SNAME("Editor")); + Color fcol = glyph_table->get_theme_color(SNAME("font_selected_color"), SNAME("Editor")); scol.a = 1.f; int32_t c = item->get_metadata(glyph_table->get_selected_column()); @@ -1048,6 +674,30 @@ void DynamicFontImportSettings::_glyph_selected() { } } label_glyphs->set_text(TTR("Preloaded glyphs: ") + itos(selected_glyphs.size())); + + item = glyph_tree->get_selected(); + ERR_FAIL_NULL(item); + Vector2i range = item->get_metadata(0); + + int total_chars = range.y - range.x; + int selected_count = 0; + for (int i = range.x; i < range.y; i++) { + if (!font_main->has_char(i)) { + total_chars--; + } + + if (selected_chars.has(i)) { + selected_count++; + } + } + + if (selected_count == total_chars) { + item->set_checked(0, true); + } else if (selected_count > 0) { + item->set_indeterminate(0, true); + } else { + item->set_checked(0, false); + } } void DynamicFontImportSettings::_range_edited() { @@ -1071,8 +721,8 @@ void DynamicFontImportSettings::_edit_range(int32_t p_start, int32_t p_end) { TreeItem *root = glyph_table->create_item(); ERR_FAIL_NULL(root); - Color scol = glyph_table->get_theme_color("box_selection_fill_color", "Editor"); - Color fcol = glyph_table->get_theme_color("font_selected_color", "Editor"); + Color scol = glyph_table->get_theme_color(SNAME("box_selection_fill_color"), SNAME("Editor")); + Color fcol = glyph_table->get_theme_color(SNAME("font_selected_color"), SNAME("Editor")); scol.a = 1.f; TreeItem *item = nullptr; @@ -1083,14 +733,14 @@ void DynamicFontImportSettings::_edit_range(int32_t p_start, int32_t p_end) { item = glyph_table->create_item(root); ERR_FAIL_NULL(item); item->set_text(0, _pad_zeros(String::num_int64(c, 16))); - item->set_text_align(0, TreeItem::ALIGN_LEFT); + item->set_text_alignment(0, HORIZONTAL_ALIGNMENT_LEFT); item->set_selectable(0, false); - item->set_custom_bg_color(0, glyph_table->get_theme_color("dark_color_3", "Editor")); + item->set_custom_bg_color(0, glyph_table->get_theme_color(SNAME("dark_color_3"), SNAME("Editor"))); } if (font_main->has_char(c)) { item->set_text(col + 1, String::chr(c)); item->set_custom_color(col + 1, Color(1, 1, 1)); - if (selected_chars.has(c) || (font_main->get_data(0).is_valid() && selected_glyphs.has(font_main->get_data(0)->get_glyph_index(get_theme_font_size("font_size") * 2, c)))) { + if (selected_chars.has(c) || (font_main->get_data(0).is_valid() && selected_glyphs.has(font_main->get_data(0)->get_glyph_index(get_theme_font_size(SNAME("font_size")) * 2, c)))) { item->set_custom_color(col + 1, fcol); item->set_custom_bg_color(col + 1, scol); } else { @@ -1098,13 +748,13 @@ void DynamicFontImportSettings::_edit_range(int32_t p_start, int32_t p_end) { item->clear_custom_bg_color(col + 1); } } else { - item->set_custom_bg_color(col + 1, glyph_table->get_theme_color("dark_color_2", "Editor")); + item->set_custom_bg_color(col + 1, glyph_table->get_theme_color(SNAME("dark_color_2"), SNAME("Editor"))); } item->set_metadata(col + 1, c); - item->set_text_align(col + 1, TreeItem::ALIGN_CENTER); + item->set_text_alignment(col + 1, HORIZONTAL_ALIGNMENT_CENTER); item->set_selectable(col + 1, true); item->set_custom_font(col + 1, font_main); - item->set_custom_font_size(col + 1, get_theme_font_size("font_size") * 2); + item->set_custom_font_size(col + 1, get_theme_font_size(SNAME("font_size")) * 2); col++; if (col == 16) { @@ -1118,14 +768,13 @@ bool DynamicFontImportSettings::_char_update(int32_t p_char) { if (selected_chars.has(p_char)) { selected_chars.erase(p_char); return false; - } else if (font_main->get_data(0).is_valid() && selected_glyphs.has(font_main->get_data(0)->get_glyph_index(get_theme_font_size("font_size") * 2, p_char))) { - selected_glyphs.erase(font_main->get_data(0)->get_glyph_index(get_theme_font_size("font_size") * 2, p_char)); + } else if (font_main->get_data(0).is_valid() && selected_glyphs.has(font_main->get_data(0)->get_glyph_index(get_theme_font_size(SNAME("font_size")) * 2, p_char))) { + selected_glyphs.erase(font_main->get_data(0)->get_glyph_index(get_theme_font_size(SNAME("font_size")) * 2, p_char)); return false; } else { selected_chars.insert(p_char); return true; } - label_glyphs->set_text(TTR("Preloaded glyphs: ") + itos(selected_glyphs.size())); } void DynamicFontImportSettings::_range_update(int32_t p_start, int32_t p_end) { @@ -1133,7 +782,7 @@ void DynamicFontImportSettings::_range_update(int32_t p_start, int32_t p_end) { for (int32_t i = p_start; i <= p_end; i++) { if (font_main->has_char(i)) { if (font_main->get_data(0).is_valid()) { - all_selected = all_selected && (selected_chars.has(i) || (font_main->get_data(0).is_valid() && selected_glyphs.has(font_main->get_data(0)->get_glyph_index(get_theme_font_size("font_size") * 2, i)))); + all_selected = all_selected && (selected_chars.has(i) || (font_main->get_data(0).is_valid() && selected_glyphs.has(font_main->get_data(0)->get_glyph_index(get_theme_font_size(SNAME("font_size")) * 2, i)))); } else { all_selected = all_selected && selected_chars.has(i); } @@ -1146,12 +795,16 @@ void DynamicFontImportSettings::_range_update(int32_t p_start, int32_t p_end) { } else { selected_chars.erase(i); if (font_main->get_data(0).is_valid()) { - selected_glyphs.erase(font_main->get_data(0)->get_glyph_index(get_theme_font_size("font_size") * 2, i)); + selected_glyphs.erase(font_main->get_data(0)->get_glyph_index(get_theme_font_size(SNAME("font_size")) * 2, i)); } } } } _edit_range(p_start, p_end); + + TreeItem *item = glyph_tree->get_selected(); + ERR_FAIL_NULL(item); + item->set_checked(0, !all_selected); } /*************************************************************************/ @@ -1159,21 +812,19 @@ void DynamicFontImportSettings::_range_update(int32_t p_start, int32_t p_end) { /*************************************************************************/ void DynamicFontImportSettings::_lang_add() { - menu_langs->set_position(lang_list->get_screen_transform().xform(lang_list->get_local_mouse_position())); - menu_langs->reset_size(); - menu_langs->popup(); + locale_select->popup_locale_dialog(); } -void DynamicFontImportSettings::_lang_add_item(int p_option) { +void DynamicFontImportSettings::_lang_add_item(const String &p_locale) { TreeItem *lang_item = lang_list->create_item(lang_list_root); ERR_FAIL_NULL(lang_item); lang_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); lang_item->set_editable(0, true); lang_item->set_checked(0, false); - lang_item->set_text(1, langs[p_option].code); + lang_item->set_text(1, p_locale); lang_item->set_editable(1, true); - lang_item->add_button(2, lang_list->get_theme_icon("Remove", "EditorIcons"), BUTTON_REMOVE_VAR, false, TTR("Remove")); + lang_item->add_button(2, lang_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove")); lang_item->set_button_color(2, 0, Color(1, 1, 1, 0.75)); } @@ -1185,8 +836,40 @@ void DynamicFontImportSettings::_lang_remove(Object *p_item, int p_column, int p memdelete(lang_item); } +void DynamicFontImportSettings::_ot_add() { + menu_ot->set_position(ot_list->get_screen_transform().xform(ot_list->get_local_mouse_position())); + menu_ot->set_size(Vector2(1, 1)); + menu_ot->popup(); +} + +void DynamicFontImportSettings::_ot_add_item(int p_option) { + String name = TS->tag_to_name(p_option); + for (TreeItem *ot_item = ot_list_root->get_first_child(); ot_item; ot_item = ot_item->get_next()) { + if (ot_item->get_text(0) == name) { + return; + } + } + TreeItem *ot_item = ot_list->create_item(ot_list_root); + ERR_FAIL_NULL(ot_item); + + ot_item->set_text(0, name); + ot_item->set_editable(0, false); + ot_item->set_text(1, "1"); + ot_item->set_editable(1, true); + ot_item->add_button(2, ot_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove")); + ot_item->set_button_color(2, 0, Color(1, 1, 1, 0.75)); +} + +void DynamicFontImportSettings::_ot_remove(Object *p_item, int p_column, int p_id) { + TreeItem *ot_item = (TreeItem *)p_item; + ERR_FAIL_NULL(ot_item); + + ot_list_root->remove_child(ot_item); + memdelete(ot_item); +} + void DynamicFontImportSettings::_script_add() { - menu_scripts->set_position(script_list->get_screen_transform().xform(script_list->get_local_mouse_position())); + menu_scripts->set_position(script_list->get_screen_position() + script_list->get_local_mouse_position()); menu_scripts->reset_size(); menu_scripts->popup(); } @@ -1198,9 +881,9 @@ void DynamicFontImportSettings::_script_add_item(int p_option) { script_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); script_item->set_editable(0, true); script_item->set_checked(0, false); - script_item->set_text(1, scripts[p_option].code); + script_item->set_text(1, script_codes[p_option]); script_item->set_editable(1, true); - script_item->add_button(2, lang_list->get_theme_icon("Remove", "EditorIcons"), BUTTON_REMOVE_VAR, false, TTR("Remove")); + script_item->add_button(2, lang_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove")); script_item->set_button_color(2, 0, Color(1, 1, 1, 0.75)); } @@ -1224,12 +907,18 @@ String DynamicFontImportSettings::_pad_zeros(const String &p_hex) const { } void DynamicFontImportSettings::_notification(int p_what) { - if (p_what == NOTIFICATION_READY) { - connect("confirmed", callable_mp(this, &DynamicFontImportSettings::_re_import)); - } else if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { - add_lang->set_icon(add_var->get_theme_icon("Add", "EditorIcons")); - add_script->set_icon(add_var->get_theme_icon("Add", "EditorIcons")); - add_var->set_icon(add_var->get_theme_icon("Add", "EditorIcons")); + switch (p_what) { + case NOTIFICATION_READY: { + connect("confirmed", callable_mp(this, &DynamicFontImportSettings::_re_import)); + } break; + + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + add_lang->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + add_script->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + add_var->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + add_ot->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + } break; } } @@ -1242,6 +931,9 @@ void DynamicFontImportSettings::_re_import() { main_settings["msdf_size"] = import_settings_data->get("msdf_size"); main_settings["force_autohinter"] = import_settings_data->get("force_autohinter"); main_settings["hinting"] = import_settings_data->get("hinting"); + main_settings["subpixel_positioning"] = import_settings_data->get("subpixel_positioning"); + main_settings["embolden"] = import_settings_data->get("embolden"); + main_settings["transform"] = import_settings_data->get("transform"); main_settings["oversampling"] = import_settings_data->get("oversampling"); main_settings["compress"] = import_settings_data->get("compress"); @@ -1317,6 +1009,14 @@ void DynamicFontImportSettings::_re_import() { main_settings["preload/glyph_ranges"] = ranges; } + Dictionary ot_ov; + for (TreeItem *ot_item = ot_list_root->get_first_child(); ot_item; ot_item = ot_item->get_next()) { + String tag = ot_item->get_text(0); + int32_t value = ot_item->get_text(1).to_int(); + ot_ov[tag] = value; + } + main_settings["opentype_feature_overrides"] = ot_ov; + if (OS::get_singleton()->is_stdout_verbose()) { print_line("Import settings:"); for (Map<StringName, Variant>::Element *E = main_settings.front(); E; E = E->next()) { @@ -1366,13 +1066,14 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { inspector_vars->edit(nullptr); inspector_general->edit(nullptr); - int gww = get_theme_font("font")->get_string_size("00000", get_theme_font_size("font_size")).x + 50; + int gww = get_theme_font(SNAME("font"))->get_string_size("00000", get_theme_font_size(SNAME("font_size"))).x + 50; glyph_table->set_column_custom_minimum_width(0, gww); glyph_table->clear(); vars_list->clear(); lang_list->clear(); script_list->clear(); + ot_list->clear(); selected_chars.clear(); selected_glyphs.clear(); @@ -1381,6 +1082,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { vars_list_root = vars_list->create_item(); lang_list_root = lang_list->create_item(); script_list_root = script_list->create_item(); + ot_list_root = ot_list->create_item(); options_variations.clear(); Dictionary var_list = dfont_main->get_supported_variation_list(); @@ -1467,7 +1169,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { vars_item->set_text(0, TTR("Configuration") + " " + itos(i)); vars_item->set_editable(0, true); - vars_item->add_button(1, vars_list->get_theme_icon("Remove", "EditorIcons"), BUTTON_REMOVE_VAR, false, TTR("Remove Variation")); + vars_item->add_button(1, vars_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove Variation")); vars_item->set_button_color(1, 0, Color(1, 1, 1, 0.75)); Ref<DynamicFontImportSettingsData> import_variation_data_custom; @@ -1505,7 +1207,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { lang_item->set_checked(0, true); lang_item->set_text(1, _langs[i]); lang_item->set_editable(1, true); - lang_item->add_button(2, lang_list->get_theme_icon("Remove", "EditorIcons"), BUTTON_REMOVE_VAR, false, TTR("Remove")); + lang_item->add_button(2, lang_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove")); } } else if (key == "support_overrides/language_disabled") { PackedStringArray _langs = config->get_value("params", key); @@ -1518,7 +1220,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { lang_item->set_checked(0, false); lang_item->set_text(1, _langs[i]); lang_item->set_editable(1, true); - lang_item->add_button(2, lang_list->get_theme_icon("Remove", "EditorIcons"), BUTTON_REMOVE_VAR, false, TTR("Remove")); + lang_item->add_button(2, lang_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove")); } } else if (key == "support_overrides/script_enabled") { PackedStringArray _scripts = config->get_value("params", key); @@ -1531,7 +1233,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { script_item->set_checked(0, true); script_item->set_text(1, _scripts[i]); script_item->set_editable(1, true); - script_item->add_button(2, lang_list->get_theme_icon("Remove", "EditorIcons"), BUTTON_REMOVE_VAR, false, TTR("Remove")); + script_item->add_button(2, lang_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove")); } } else if (key == "support_overrides/script_disabled") { PackedStringArray _scripts = config->get_value("params", key); @@ -1544,7 +1246,24 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { script_item->set_checked(0, false); script_item->set_text(1, _scripts[i]); script_item->set_editable(1, true); - script_item->add_button(2, lang_list->get_theme_icon("Remove", "EditorIcons"), BUTTON_REMOVE_VAR, false, TTR("Remove")); + script_item->add_button(2, lang_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove")); + } + } else if (key == "opentype_feature_overrides") { + Dictionary features = config->get_value("params", key); + for (const Variant *ftr = features.next(nullptr); ftr != nullptr; ftr = features.next(ftr)) { + TreeItem *ot_item = ot_list->create_item(ot_list_root); + ERR_FAIL_NULL(ot_item); + int32_t value = features[*ftr]; + if (ftr->get_type() == Variant::STRING) { + ot_item->set_text(0, *ftr); + } else { + ot_item->set_text(0, TS->tag_to_name(*ftr)); + } + ot_item->set_editable(0, false); + ot_item->set_text(1, itos(value)); + ot_item->set_editable(1, true); + ot_item->add_button(2, ot_list->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), BUTTON_REMOVE_VAR, false, TTR("Remove")); + ot_item->set_button_color(2, 0, Color(1, 1, 1, 0.75)); } } else { Variant value = config->get_value("params", key); @@ -1565,11 +1284,47 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { font_preview->get_data(0)->set_msdf_size(import_settings_data->get("msdf_size")); font_preview->get_data(0)->set_force_autohinter(import_settings_data->get("force_autohinter")); font_preview->get_data(0)->set_hinting((TextServer::Hinting)import_settings_data->get("hinting").operator int()); + font_preview->get_data(0)->set_subpixel_positioning((TextServer::SubpixelPositioning)import_settings_data->get("subpixel_positioning").operator int()); + font_preview->get_data(0)->set_embolden(import_settings_data->get("embolden")); + font_preview->get_data(0)->set_transform(import_settings_data->get("transform")); font_preview->get_data(0)->set_oversampling(import_settings_data->get("oversampling")); } font_preview_label->add_theme_font_override("font", font_preview); font_preview_label->update(); + menu_ot->clear(); + menu_ot_ss->clear(); + menu_ot_cv->clear(); + menu_ot_cu->clear(); + bool have_ss = false; + bool have_cv = false; + bool have_cu = false; + Dictionary features = font_preview->get_feature_list(); + for (const Variant *ftr = features.next(nullptr); ftr != nullptr; ftr = features.next(ftr)) { + String ftr_name = TS->tag_to_name(*ftr); + if (ftr_name.begins_with("stylistic_set_")) { + menu_ot_ss->add_item(ftr_name.capitalize(), (int32_t)*ftr); + have_ss = true; + } else if (ftr_name.begins_with("character_variant_")) { + menu_ot_cv->add_item(ftr_name.capitalize(), (int32_t)*ftr); + have_cv = true; + } else if (ftr_name.begins_with("custom_")) { + menu_ot_cu->add_item(ftr_name.replace("custom_", ""), (int32_t)*ftr); + have_cu = true; + } else { + menu_ot->add_item(ftr_name.capitalize(), (int32_t)*ftr); + } + } + if (have_ss) { + menu_ot->add_submenu_item(RTR("Stylistic Sets"), "SSMenu"); + } + if (have_cv) { + menu_ot->add_submenu_item(RTR("Character Variants"), "CVMenu"); + } + if (have_cu) { + menu_ot->add_submenu_item(RTR("Custom"), "CUMenu"); + } + _variations_validate(); popup_centered_ratio(); @@ -1590,36 +1345,47 @@ DynamicFontImportSettings::DynamicFontImportSettings() { options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "msdf_size", PROPERTY_HINT_RANGE, "1,250,1"), 48)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "force_autohinter"), false)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), 1)); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel"), 1)); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "embolden", PROPERTY_HINT_RANGE, "-2,2,0.01"), 0.f)); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::TRANSFORM2D, "transform"), Transform2D())); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_RANGE, "0,10,0.1"), 0.0)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "compress", PROPERTY_HINT_NONE, ""), false)); // Popup menus - menu_langs = memnew(PopupMenu); - menu_langs->set_name("Language"); - for (int i = 0; langs[i].name != String(); i++) { - if (langs[i].name == "-") { - menu_langs->add_separator(); - } else { - menu_langs->add_item(langs[i].name + " (" + langs[i].code + ")", i); - } - } - add_child(menu_langs); - menu_langs->connect("id_pressed", callable_mp(this, &DynamicFontImportSettings::_lang_add_item)); + locale_select = memnew(EditorLocaleDialog); + locale_select->connect("locale_selected", callable_mp(this, &DynamicFontImportSettings::_lang_add_item)); + add_child(locale_select); menu_scripts = memnew(PopupMenu); menu_scripts->set_name("Script"); - for (int i = 0; scripts[i].name != String(); i++) { - if (scripts[i].name == "-") { - menu_scripts->add_separator(); - } else { - menu_scripts->add_item(scripts[i].name + " (" + scripts[i].code + ")", i); - } + script_codes = TranslationServer::get_singleton()->get_all_scripts(); + for (int i = 0; i < script_codes.size(); i++) { + menu_scripts->add_item(TranslationServer::get_singleton()->get_script_name(script_codes[i]) + " (" + script_codes[i] + ")", i); } add_child(menu_scripts); menu_scripts->connect("id_pressed", callable_mp(this, &DynamicFontImportSettings::_script_add_item)); - Color warn_color = (EditorNode::get_singleton()) ? EditorNode::get_singleton()->get_gui_base()->get_theme_color("warning_color", "Editor") : Color(1, 1, 0); + menu_ot = memnew(PopupMenu); + add_child(menu_ot); + menu_ot->connect("id_pressed", callable_mp(this, &DynamicFontImportSettings::_ot_add_item)); + + menu_ot_cv = memnew(PopupMenu); + menu_ot_cv->set_name("CVMenu"); + menu_ot->add_child(menu_ot_cv); + menu_ot_cv->connect("id_pressed", callable_mp(this, &DynamicFontImportSettings::_ot_add_item)); + + menu_ot_ss = memnew(PopupMenu); + menu_ot_ss->set_name("SSMenu"); + menu_ot->add_child(menu_ot_ss); + menu_ot_ss->connect("id_pressed", callable_mp(this, &DynamicFontImportSettings::_ot_add_item)); + + menu_ot_cu = memnew(PopupMenu); + menu_ot_cu->set_name("CUMenu"); + menu_ot->add_child(menu_ot_cu); + menu_ot_cu->connect("id_pressed", callable_mp(this, &DynamicFontImportSettings::_ot_add_item)); + + Color warn_color = (EditorNode::get_singleton()) ? EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), SNAME("Editor")) : Color(1, 1, 0); // Root layout @@ -1627,12 +1393,13 @@ DynamicFontImportSettings::DynamicFontImportSettings() { add_child(root_vb); main_pages = memnew(TabContainer); + main_pages->set_tab_alignment(TabBar::ALIGNMENT_CENTER); main_pages->set_v_size_flags(Control::SIZE_EXPAND_FILL); main_pages->set_h_size_flags(Control::SIZE_EXPAND_FILL); root_vb->add_child(main_pages); label_warn = memnew(Label); - label_warn->set_align(Label::ALIGN_CENTER); + label_warn->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); label_warn->set_text(""); root_vb->add_child(label_warn); label_warn->add_theme_color_override("font_color", warn_color); @@ -1641,7 +1408,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { // Page 1 layout: Rendering Options VBoxContainer *page1_vb = memnew(VBoxContainer); - page1_vb->set_meta("_tab_name", TTR("Rendering options")); + page1_vb->set_name(TTR("Rendering Options")); main_pages->add_child(page1_vb); page1_description = memnew(Label); @@ -1656,8 +1423,8 @@ DynamicFontImportSettings::DynamicFontImportSettings() { font_preview_label = memnew(Label); font_preview_label->add_theme_font_size_override("font_size", 200 * EDSCALE); - font_preview_label->set_align(Label::ALIGN_CENTER); - font_preview_label->set_valign(Label::VALIGN_CENTER); + font_preview_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); + font_preview_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); font_preview_label->set_autowrap_mode(Label::AUTOWRAP_ARBITRARY); font_preview_label->set_clip_text(true); font_preview_label->set_v_size_flags(Control::SIZE_EXPAND_FILL); @@ -1672,7 +1439,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { // Page 2 layout: Configurations VBoxContainer *page2_vb = memnew(VBoxContainer); - page2_vb->set_meta("_tab_name", TTR("Sizes and variations")); + page2_vb->set_name(TTR("Sizes and Variations")); main_pages->add_child(page2_vb); page2_description = memnew(Label); @@ -1694,14 +1461,14 @@ DynamicFontImportSettings::DynamicFontImportSettings() { label_vars = memnew(Label); page2_hb_vars->add_child(label_vars); - label_vars->set_align(Label::ALIGN_CENTER); + label_vars->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); label_vars->set_h_size_flags(Control::SIZE_EXPAND_FILL); label_vars->set_text(TTR("Configuration:")); add_var = memnew(Button); page2_hb_vars->add_child(add_var); add_var->set_tooltip(TTR("Add configuration")); - add_var->set_icon(add_var->get_theme_icon("Add", "EditorIcons")); + add_var->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); add_var->connect("pressed", callable_mp(this, &DynamicFontImportSettings::_variation_add)); vars_list = memnew(Tree); @@ -1724,7 +1491,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { // Page 3 layout: Text to select glyphs VBoxContainer *page3_vb = memnew(VBoxContainer); - page3_vb->set_meta("_tab_name", TTR("Glyphs from the text")); + page3_vb->set_name(TTR("Glyphs from the Text")); main_pages->add_child(page3_vb); page3_description = memnew(Label); @@ -1781,7 +1548,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { // Page 4 layout: Character map VBoxContainer *page4_vb = memnew(VBoxContainer); - page4_vb->set_meta("_tab_name", TTR("Glyphs from the character map")); + page4_vb->set_name(TTR("Glyphs from the Character Map")); main_pages->add_child(page4_vb); page4_description = memnew(Label); @@ -1808,8 +1575,8 @@ DynamicFontImportSettings::DynamicFontImportSettings() { for (int i = 0; i < 16; i++) { glyph_table->set_column_title(i + 1, String::num_int64(i, 16)); } - glyph_table->add_theme_style_override("selected", glyph_table->get_theme_stylebox("bg")); - glyph_table->add_theme_style_override("selected_focus", glyph_table->get_theme_stylebox("bg")); + glyph_table->add_theme_style_override("selected", glyph_table->get_theme_stylebox(SNAME("bg"))); + glyph_table->add_theme_style_override("selected_focus", glyph_table->get_theme_stylebox(SNAME("bg"))); glyph_table->add_theme_constant_override("hseparation", 0); glyph_table->set_h_size_flags(Control::SIZE_EXPAND_FILL); glyph_table->set_v_size_flags(Control::SIZE_EXPAND_FILL); @@ -1826,13 +1593,13 @@ DynamicFontImportSettings::DynamicFontImportSettings() { glyph_tree->connect("item_selected", callable_mp(this, &DynamicFontImportSettings::_range_selected)); glyph_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); glyph_root = glyph_tree->create_item(); - for (int i = 0; unicode_ranges[i].name != String(); i++) { + for (int i = 0; !unicode_ranges[i].name.is_empty(); i++) { _add_glyph_range_item(unicode_ranges[i].start, unicode_ranges[i].end, unicode_ranges[i].name); } // Page 4 layout: Metadata override VBoxContainer *page5_vb = memnew(VBoxContainer); - page5_vb->set_meta("_tab_name", TTR("Metadata override")); + page5_vb->set_name(TTR("Metadata Override")); main_pages->add_child(page5_vb); page5_description = memnew(Label); @@ -1845,7 +1612,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { page5_vb->add_child(hb_lang); label_langs = memnew(Label); - label_langs->set_align(Label::ALIGN_CENTER); + label_langs->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); label_langs->set_h_size_flags(Control::SIZE_EXPAND_FILL); label_langs->set_text(TTR("Language support overrides")); hb_lang->add_child(label_langs); @@ -1853,7 +1620,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { add_lang = memnew(Button); hb_lang->add_child(add_lang); add_lang->set_tooltip(TTR("Add language override")); - add_lang->set_icon(add_var->get_theme_icon("Add", "EditorIcons")); + add_lang->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); add_lang->connect("pressed", callable_mp(this, &DynamicFontImportSettings::_lang_add)); lang_list = memnew(Tree); @@ -1873,7 +1640,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { page5_vb->add_child(hb_script); label_script = memnew(Label); - label_script->set_align(Label::ALIGN_CENTER); + label_script->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); label_script->set_h_size_flags(Control::SIZE_EXPAND_FILL); label_script->set_text(TTR("Script support overrides")); hb_script->add_child(label_script); @@ -1881,7 +1648,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { add_script = memnew(Button); hb_script->add_child(add_script); add_script->set_tooltip(TTR("Add script override")); - add_script->set_icon(add_var->get_theme_icon("Add", "EditorIcons")); + add_script->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); add_script->connect("pressed", callable_mp(this, &DynamicFontImportSettings::_script_add)); script_list = memnew(Tree); @@ -1897,6 +1664,34 @@ DynamicFontImportSettings::DynamicFontImportSettings() { script_list->connect("button_pressed", callable_mp(this, &DynamicFontImportSettings::_script_remove)); script_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); + HBoxContainer *hb_ot = memnew(HBoxContainer); + page5_vb->add_child(hb_ot); + + label_ot = memnew(Label); + label_ot->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); + label_ot->set_h_size_flags(Control::SIZE_EXPAND_FILL); + label_ot->set_text(TTR("OpenType feature overrides")); + hb_ot->add_child(label_ot); + + add_ot = memnew(Button); + hb_ot->add_child(add_ot); + add_ot->set_tooltip(TTR("Add feature override")); + add_ot->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons"))); + add_ot->connect("pressed", callable_mp(this, &DynamicFontImportSettings::_ot_add)); + + ot_list = memnew(Tree); + page5_vb->add_child(ot_list); + ot_list->set_hide_root(true); + ot_list->set_columns(3); + ot_list->set_column_expand(0, true); + ot_list->set_column_custom_minimum_width(0, 80 * EDSCALE); + ot_list->set_column_expand(1, true); + ot_list->set_column_custom_minimum_width(1, 80 * EDSCALE); + ot_list->set_column_expand(2, false); + ot_list->set_column_custom_minimum_width(2, 50 * EDSCALE); + ot_list->connect("button_pressed", callable_mp(this, &DynamicFontImportSettings::_ot_remove)); + ot_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); + // Common import_settings_data.instantiate(); diff --git a/editor/import/dynamicfont_import_settings.h b/editor/import/dynamic_font_import_settings.h index 05f5e8e00b..c1e868403f 100644 --- a/editor/import/dynamicfont_import_settings.h +++ b/editor/import/dynamic_font_import_settings.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* dynamicfont_import_settings.h */ +/* dynamic_font_import_settings.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,13 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef FONTDATA_IMPORT_SETTINGS_H -#define FONTDATA_IMPORT_SETTINGS_H +#ifndef DYNAMIC_FONT_IMPORT_SETTINGS_H +#define DYNAMIC_FONT_IMPORT_SETTINGS_H -#include "editor/editor_file_dialog.h" -#include "editor/editor_inspector.h" - -#include "editor/import/resource_importer_dynamicfont.h" +#include "editor/import/resource_importer_dynamic_font.h" #include "scene/gui/dialogs.h" #include "scene/gui/item_list.h" @@ -44,11 +41,13 @@ #include "scene/gui/tab_container.h" #include "scene/gui/text_edit.h" #include "scene/gui/tree.h" - #include "scene/resources/font.h" #include "servers/text_server.h" class DynamicFontImportSettingsData; +class EditorFileDialog; +class EditorInspector; +class EditorLocaleDialog; class DynamicFontImportSettings : public ConfirmationDialog { GDCLASS(DynamicFontImportSettings, ConfirmationDialog) @@ -67,6 +66,9 @@ class DynamicFontImportSettings : public ConfirmationDialog { List<ResourceImporter::ImportOption> options_variations; List<ResourceImporter::ImportOption> options_general; + EditorLocaleDialog *locale_select = nullptr; + Vector<String> script_codes; + // Root layout Label *label_warn = nullptr; TabContainer *main_pages = nullptr; @@ -120,26 +122,38 @@ class DynamicFontImportSettings : public ConfirmationDialog { Label *page5_description = nullptr; Button *add_lang = nullptr; Button *add_script = nullptr; + Button *add_ot = nullptr; - PopupMenu *menu_langs = nullptr; PopupMenu *menu_scripts = nullptr; + PopupMenu *menu_ot = nullptr; + PopupMenu *menu_ot_ss = nullptr; + PopupMenu *menu_ot_cv = nullptr; + PopupMenu *menu_ot_cu = nullptr; Tree *lang_list = nullptr; TreeItem *lang_list_root = nullptr; + Label *label_langs = nullptr; Tree *script_list = nullptr; TreeItem *script_list_root = nullptr; - Label *label_langs = nullptr; Label *label_script = nullptr; + Tree *ot_list = nullptr; + TreeItem *ot_list_root = nullptr; + Label *label_ot = nullptr; + void _lang_add(); - void _lang_add_item(int p_option); + void _lang_add_item(const String &p_locale); void _lang_remove(Object *p_item, int p_column, int p_id); void _script_add(); void _script_add_item(int p_option); void _script_remove(Object *p_item, int p_column, int p_id); + void _ot_add(); + void _ot_add_item(int p_option); + void _ot_remove(Object *p_item, int p_column, int p_id); + // Common void _add_glyph_range_item(int32_t p_start, int32_t p_end, const String &p_name); @@ -164,4 +178,4 @@ public: DynamicFontImportSettings(); }; -#endif // FONTDATA_IMPORT_SETTINGS_H +#endif // DYNAMIC_FONT_IMPORT_SETTINGS_H diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index 076c0cc62b..013dcb5deb 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -303,7 +303,7 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Node3D *p_parent) { } break; } - if (p_node->name != "") { + if (!p_node->name.is_empty()) { node->set_name(p_node->name); } NodeMap nm; @@ -317,7 +317,7 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Node3D *p_parent) { p_parent->add_child(node, true); node->set_owner(scene); - if (p_node->empty_draw_type != "") { + if (!p_node->empty_draw_type.is_empty()) { node->set_meta("empty_draw_type", Variant(p_node->empty_draw_type)); } @@ -340,9 +340,9 @@ Error ColladaImport::_create_material(const String &p_target) { Ref<StandardMaterial3D> material = memnew(StandardMaterial3D); String base_name; - if (src_mat.name != "") { + if (!src_mat.name.is_empty()) { base_name = src_mat.name; - } else if (effect.name != "") { + } else if (!effect.name.is_empty()) { base_name = effect.name; } else { base_name = "Material"; @@ -360,9 +360,9 @@ Error ColladaImport::_create_material(const String &p_target) { // DIFFUSE - if (effect.diffuse.texture != "") { + if (!effect.diffuse.texture.is_empty()) { String texfile = effect.get_texture_path(effect.diffuse.texture, collada); - if (texfile != "") { + if (!texfile.is_empty()) { if (texfile.begins_with("/")) { texfile = texfile.replace_first("/", "res://"); } @@ -381,9 +381,9 @@ Error ColladaImport::_create_material(const String &p_target) { // SPECULAR - if (effect.specular.texture != "") { + if (!effect.specular.texture.is_empty()) { String texfile = effect.get_texture_path(effect.specular.texture, collada); - if (texfile != "") { + if (!texfile.is_empty()) { if (texfile.begins_with("/")) { texfile = texfile.replace_first("/", "res://"); } @@ -406,9 +406,9 @@ Error ColladaImport::_create_material(const String &p_target) { // EMISSION - if (effect.emission.texture != "") { + if (!effect.emission.texture.is_empty()) { String texfile = effect.get_texture_path(effect.emission.texture, collada); - if (texfile != "") { + if (!texfile.is_empty()) { if (texfile.begins_with("/")) { texfile = texfile.replace_first("/", "res://"); } @@ -433,9 +433,9 @@ Error ColladaImport::_create_material(const String &p_target) { // NORMAL - if (effect.bump.texture != "") { + if (!effect.bump.texture.is_empty()) { String texfile = effect.get_texture_path(effect.bump.texture, collada); - if (texfile != "") { + if (!texfile.is_empty()) { if (texfile.begins_with("/")) { texfile = texfile.replace_first("/", "res://"); } @@ -471,7 +471,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p bool local_xform_mirror = p_local_xform.basis.determinant() < 0; if (p_morph_data) { - //add morphie target + //add morph target ERR_FAIL_COND_V(!p_morph_data->targets.has("MORPH_TARGET"), ERR_INVALID_DATA); String mt = p_morph_data->targets["MORPH_TARGET"]; ERR_FAIL_COND_V(!p_morph_data->sources.has(mt), ERR_INVALID_DATA); @@ -525,7 +525,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p normal_ofs = vertex_ofs; } - if (normal_source_id != "") { + if (!normal_source_id.is_empty()) { ERR_FAIL_COND_V(!meshdata.sources.has(normal_source_id), ERR_INVALID_DATA); normal_src = &meshdata.sources[normal_source_id]; } @@ -545,7 +545,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p binormal_ofs = vertex_ofs; } - if (binormal_source_id != "") { + if (!binormal_source_id.is_empty()) { ERR_FAIL_COND_V(!meshdata.sources.has(binormal_source_id), ERR_INVALID_DATA); binormal_src = &meshdata.sources[binormal_source_id]; } @@ -565,7 +565,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p tangent_ofs = vertex_ofs; } - if (tangent_source_id != "") { + if (!tangent_source_id.is_empty()) { ERR_FAIL_COND_V(!meshdata.sources.has(tangent_source_id), ERR_INVALID_DATA); tangent_src = &meshdata.sources[tangent_source_id]; } @@ -585,7 +585,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p uv_ofs = vertex_ofs; } - if (uv_source_id != "") { + if (!uv_source_id.is_empty()) { ERR_FAIL_COND_V(!meshdata.sources.has(uv_source_id), ERR_INVALID_DATA); uv_src = &meshdata.sources[uv_source_id]; } @@ -605,7 +605,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p uv2_ofs = vertex_ofs; } - if (uv2_source_id != "") { + if (!uv2_source_id.is_empty()) { ERR_FAIL_COND_V(!meshdata.sources.has(uv2_source_id), ERR_INVALID_DATA); uv2_src = &meshdata.sources[uv2_source_id]; } @@ -625,7 +625,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p color_ofs = vertex_ofs; } - if (color_source_id != "") { + if (!color_source_id.is_empty()) { ERR_FAIL_COND_V(!meshdata.sources.has(color_source_id), ERR_INVALID_DATA); color_src = &meshdata.sources[color_source_id]; } @@ -914,7 +914,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p material = material_cache[target]; } - } else if (p.material != "") { + } else if (!p.material.is_empty()) { WARN_PRINT("Collada: Unreferenced material in geometry instance: " + p.material); } } @@ -994,13 +994,12 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p Array a = p_morph_meshes[mi]->get_surface_arrays(surface); //add valid weight and bone arrays if they exist, TODO check if they are unique to shape (generally not) - if (has_weights) { - a[Mesh::ARRAY_WEIGHTS] = d[Mesh::ARRAY_WEIGHTS]; - a[Mesh::ARRAY_BONES] = d[Mesh::ARRAY_BONES]; + // Enforce blend shape mask array format + for (int mj = 0; mj < Mesh::ARRAY_MAX; mj++) { + if (!(Mesh::ARRAY_FORMAT_BLEND_SHAPE_MASK & (1 << mj))) { + a[mj] = Variant(); + } } - - a[Mesh::ARRAY_INDEX] = Variant(); - //a.resize(Mesh::ARRAY_MAX); //no need for index mr.push_back(a); } @@ -1198,7 +1197,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres } } - ERR_FAIL_COND_V_MSG(ngsource != "", ERR_INVALID_DATA, "Controller instance source '" + ngsource + "' is neither skin or morph!"); + ERR_FAIL_COND_V_MSG(!ngsource.is_empty(), ERR_INVALID_DATA, "Controller instance source '" + ngsource + "' is neither skin or morph!"); } else { meshid = ng2->source; @@ -1215,13 +1214,13 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres mesh = Ref<ImporterMesh>(memnew(ImporterMesh)); const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid]; String name = meshdata.name; - if (name == "") { + if (name.is_empty()) { name = "Mesh"; } int counter = 2; while (mesh_unique_names.has(name)) { name = meshdata.name; - if (name == "") { + if (name.is_empty()) { name = "Mesh"; } name += itos(counter++); @@ -1261,7 +1260,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres } mi->set_surface_material(i, material); - } else if (matname != "") { + } else if (!matname.is_empty()) { WARN_PRINT("Collada: Unreferenced material in geometry instance: " + matname); } } @@ -1343,7 +1342,7 @@ void ColladaImport::_fix_param_animation_tracks() { // test source(s) String source = ng->source; - while (source != "") { + while (!source.is_empty()) { if (collada.state.skin_controller_data_map.has(source)) { const Collada::SkinControllerData &skin = collada.state.skin_controller_data_map[source]; @@ -1535,7 +1534,7 @@ void ColladaImport::create_animation(int p_clip, bool p_import_value_tracks) { bool has_rotation = false; bool has_scale = false; - for (int i = 0; cn->xform_list.size(); i++) { + for (int i = 0; i < cn->xform_list.size(); i++) { switch (cn->xform_list[i].op) { case Collada::Node::XForm::OP_ROTATE: { has_rotation = true; @@ -1755,7 +1754,7 @@ void EditorSceneFormatImporterCollada::get_extensions(List<String> *r_extensions r_extensions->push_back("dae"); } -Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { +Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { if (r_err) { *r_err = OK; } @@ -1796,13 +1795,20 @@ Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint3 AnimationPlayer *ap = memnew(AnimationPlayer); for (int i = 0; i < state.animations.size(); i++) { String name; - if (state.animations[i]->get_name() == "") { + if (state.animations[i]->get_name().is_empty()) { name = "default"; } else { name = state.animations[i]->get_name(); } - ap->add_animation(name, state.animations[i]); + Ref<AnimationLibrary> library; + if (!ap->has_animation_library("")) { + library.instantiate(); + ap->add_animation_library("", library); + } else { + library = ap->get_animation_library(""); + } + library->add_animation(name, state.animations[i]); } state.scene->add_child(ap, true); ap->set_owner(state.scene); @@ -1811,26 +1817,5 @@ Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint3 return state.scene; } -Ref<Animation> EditorSceneFormatImporterCollada::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) { - ColladaImport state; - - state.use_mesh_builtin_materials = false; - - Error err = state.load(p_path, Collada::IMPORT_FLAG_ANIMATION, p_flags & EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS); - ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot load animation from file '" + p_path + "'."); - - state.create_animations(true); - if (state.scene) { - memdelete(state.scene); - } - - if (state.animations.size() == 0) { - return Ref<Animation>(); - } - Ref<Animation> anim = state.animations[0]; - - return anim; -} - EditorSceneFormatImporterCollada::EditorSceneFormatImporterCollada() { } diff --git a/editor/import/editor_import_collada.h b/editor/import/editor_import_collada.h index 055a6fe178..be3f74d821 100644 --- a/editor/import/editor_import_collada.h +++ b/editor/import/editor_import_collada.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -39,8 +39,7 @@ class EditorSceneFormatImporterCollada : public EditorSceneFormatImporter { public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps = nullptr, Error *r_err = nullptr) override; - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps = nullptr, Error *r_err = nullptr) override; EditorSceneFormatImporterCollada(); }; diff --git a/editor/import/editor_import_plugin.cpp b/editor/import/editor_import_plugin.cpp index 1a002569c5..f7d373ef60 100644 --- a/editor/import/editor_import_plugin.cpp +++ b/editor/import/editor_import_plugin.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,6 +29,7 @@ /*************************************************************************/ #include "editor_import_plugin.h" + #include "core/object/script_language.h" EditorImportPlugin::EditorImportPlugin() { diff --git a/editor/import/editor_import_plugin.h b/editor/import/editor_import_plugin.h index 6c5f4f6005..6cff8fb917 100644 --- a/editor/import/editor_import_plugin.h +++ b/editor/import/editor_import_plugin.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/editor/import/resource_importer_bitmask.cpp b/editor/import/resource_importer_bitmask.cpp index c43052593d..46d15e8989 100644 --- a/editor/import/resource_importer_bitmask.cpp +++ b/editor/import/resource_importer_bitmask.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,13 +29,11 @@ /*************************************************************************/ #include "resource_importer_bitmask.h" -#include "core/io/config_file.h" + #include "core/io/image.h" #include "core/io/image_loader.h" -#include "editor/editor_file_system.h" -#include "editor/editor_node.h" +#include "core/io/resource_saver.h" #include "scene/resources/bit_map.h" -#include "scene/resources/texture.h" String ResourceImporterBitMap::get_importer_name() const { return "bitmap"; diff --git a/editor/import/resource_importer_bitmask.h b/editor/import/resource_importer_bitmask.h index f3da5f9a31..6dd6843171 100644 --- a/editor/import/resource_importer_bitmask.h +++ b/editor/import/resource_importer_bitmask.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,11 +31,8 @@ #ifndef RESOURCE_IMPORTER_BITMASK_H #define RESOURCE_IMPORTER_BITMASK_H -#include "core/io/image.h" #include "core/io/resource_importer.h" -class StreamBitMap; - class ResourceImporterBitMap : public ResourceImporter { GDCLASS(ResourceImporterBitMap, ResourceImporter); diff --git a/editor/import/resource_importer_bmfont.cpp b/editor/import/resource_importer_bmfont.cpp index f54065416e..8a655fbc0c 100644 --- a/editor/import/resource_importer_bmfont.cpp +++ b/editor/import/resource_importer_bmfont.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,7 +30,6 @@ #include "resource_importer_bmfont.h" -#include "core/io/image_loader.h" #include "core/io/resource_saver.h" String ResourceImporterBMFont::get_importer_name() const { @@ -64,749 +63,14 @@ void ResourceImporterBMFont::get_import_options(const String &p_path, List<Impor r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress"), true)); } -void _convert_packed_8bit(Ref<FontData> &r_font, Ref<Image> &p_source, int p_page, int p_sz) { - int w = p_source->get_width(); - int h = p_source->get_height(); - - PackedByteArray imgdata = p_source->get_data(); - const uint8_t *r = imgdata.ptr(); - - PackedByteArray imgdata_r; - imgdata_r.resize(w * h * 2); - uint8_t *wr = imgdata_r.ptrw(); - - PackedByteArray imgdata_g; - imgdata_g.resize(w * h * 2); - uint8_t *wg = imgdata_g.ptrw(); - - PackedByteArray imgdata_b; - imgdata_b.resize(w * h * 2); - uint8_t *wb = imgdata_b.ptrw(); - - PackedByteArray imgdata_a; - imgdata_a.resize(w * h * 2); - uint8_t *wa = imgdata_a.ptrw(); - - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - int ofs_src = (i * w + j) * 4; - int ofs_dst = (i * w + j) * 2; - wr[ofs_dst + 0] = 255; - wr[ofs_dst + 1] = r[ofs_src + 0]; - wg[ofs_dst + 0] = 255; - wg[ofs_dst + 1] = r[ofs_src + 1]; - wb[ofs_dst + 0] = 255; - wb[ofs_dst + 1] = r[ofs_src + 2]; - wa[ofs_dst + 0] = 255; - wa[ofs_dst + 1] = r[ofs_src + 3]; - } - } - Ref<Image> img_r = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_r)); - r_font->set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 0, img_r); - Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_g)); - r_font->set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 1, img_g); - Ref<Image> img_b = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_b)); - r_font->set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 2, img_b); - Ref<Image> img_a = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_a)); - r_font->set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 3, img_a); -} - -void _convert_packed_4bit(Ref<FontData> &r_font, Ref<Image> &p_source, int p_page, int p_sz) { - int w = p_source->get_width(); - int h = p_source->get_height(); - - PackedByteArray imgdata = p_source->get_data(); - const uint8_t *r = imgdata.ptr(); - - PackedByteArray imgdata_r; - imgdata_r.resize(w * h * 2); - uint8_t *wr = imgdata_r.ptrw(); - - PackedByteArray imgdata_g; - imgdata_g.resize(w * h * 2); - uint8_t *wg = imgdata_g.ptrw(); - - PackedByteArray imgdata_b; - imgdata_b.resize(w * h * 2); - uint8_t *wb = imgdata_b.ptrw(); - - PackedByteArray imgdata_a; - imgdata_a.resize(w * h * 2); - uint8_t *wa = imgdata_a.ptrw(); - - PackedByteArray imgdata_ro; - imgdata_ro.resize(w * h * 2); - uint8_t *wro = imgdata_ro.ptrw(); - - PackedByteArray imgdata_go; - imgdata_go.resize(w * h * 2); - uint8_t *wgo = imgdata_go.ptrw(); - - PackedByteArray imgdata_bo; - imgdata_bo.resize(w * h * 2); - uint8_t *wbo = imgdata_bo.ptrw(); - - PackedByteArray imgdata_ao; - imgdata_ao.resize(w * h * 2); - uint8_t *wao = imgdata_ao.ptrw(); - - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - int ofs_src = (i * w + j) * 4; - int ofs_dst = (i * w + j) * 2; - wr[ofs_dst + 0] = 255; - wro[ofs_dst + 0] = 255; - if (r[ofs_src + 0] > 0x0F) { - wr[ofs_dst + 1] = (r[ofs_src + 0] - 0x0F) * 2; - wro[ofs_dst + 1] = 0; - } else { - wr[ofs_dst + 1] = 0; - wro[ofs_dst + 1] = r[ofs_src + 0] * 2; - } - wg[ofs_dst + 0] = 255; - wgo[ofs_dst + 0] = 255; - if (r[ofs_src + 1] > 0x0F) { - wg[ofs_dst + 1] = (r[ofs_src + 1] - 0x0F) * 2; - wgo[ofs_dst + 1] = 0; - } else { - wg[ofs_dst + 1] = 0; - wgo[ofs_dst + 1] = r[ofs_src + 1] * 2; - } - wb[ofs_dst + 0] = 255; - wbo[ofs_dst + 0] = 255; - if (r[ofs_src + 2] > 0x0F) { - wb[ofs_dst + 1] = (r[ofs_src + 2] - 0x0F) * 2; - wbo[ofs_dst + 1] = 0; - } else { - wb[ofs_dst + 1] = 0; - wbo[ofs_dst + 1] = r[ofs_src + 2] * 2; - } - wa[ofs_dst + 0] = 255; - wao[ofs_dst + 0] = 255; - if (r[ofs_src + 3] > 0x0F) { - wa[ofs_dst + 1] = (r[ofs_src + 3] - 0x0F) * 2; - wao[ofs_dst + 1] = 0; - } else { - wa[ofs_dst + 1] = 0; - wao[ofs_dst + 1] = r[ofs_src + 3] * 2; - } - } - } - Ref<Image> img_r = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_r)); - r_font->set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 0, img_r); - Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_g)); - r_font->set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 1, img_g); - Ref<Image> img_b = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_b)); - r_font->set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 2, img_b); - Ref<Image> img_a = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_a)); - r_font->set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 3, img_a); - - Ref<Image> img_ro = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_ro)); - r_font->set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 0, img_ro); - Ref<Image> img_go = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_go)); - r_font->set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 1, img_go); - Ref<Image> img_bo = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_bo)); - r_font->set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 2, img_bo); - Ref<Image> img_ao = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_ao)); - r_font->set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 3, img_ao); -} - -void _convert_rgba_4bit(Ref<FontData> &r_font, Ref<Image> &p_source, int p_page, int p_sz) { - int w = p_source->get_width(); - int h = p_source->get_height(); - - PackedByteArray imgdata = p_source->get_data(); - const uint8_t *r = imgdata.ptr(); - - PackedByteArray imgdata_g; - imgdata_g.resize(w * h * 4); - uint8_t *wg = imgdata_g.ptrw(); - - PackedByteArray imgdata_o; - imgdata_o.resize(w * h * 4); - uint8_t *wo = imgdata_o.ptrw(); - - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - int ofs = (i * w + j) * 4; - - if (r[ofs + 0] > 0x7F) { - wg[ofs + 0] = r[ofs + 0]; - wo[ofs + 0] = 0; - } else { - wg[ofs + 0] = 0; - wo[ofs + 0] = r[ofs + 0] * 2; - } - if (r[ofs + 1] > 0x7F) { - wg[ofs + 1] = r[ofs + 1]; - wo[ofs + 1] = 0; - } else { - wg[ofs + 1] = 0; - wo[ofs + 1] = r[ofs + 1] * 2; - } - if (r[ofs + 2] > 0x7F) { - wg[ofs + 2] = r[ofs + 2]; - wo[ofs + 2] = 0; - } else { - wg[ofs + 2] = 0; - wo[ofs + 2] = r[ofs + 2] * 2; - } - if (r[ofs + 3] > 0x7F) { - wg[ofs + 3] = r[ofs + 3]; - wo[ofs + 3] = 0; - } else { - wg[ofs + 3] = 0; - wo[ofs + 3] = r[ofs + 3] * 2; - } - } - } - Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_RGBA8, imgdata_g)); - r_font->set_texture_image(0, Vector2i(p_sz, 0), p_page, img_g); - - Ref<Image> img_o = memnew(Image(w, h, 0, Image::FORMAT_RGBA8, imgdata_o)); - r_font->set_texture_image(0, Vector2i(p_sz, 1), p_page, img_o); -} - -void _convert_mono_8bit(Ref<FontData> &r_font, Ref<Image> &p_source, int p_page, int p_ch, int p_sz, int p_ol) { - int w = p_source->get_width(); - int h = p_source->get_height(); - - PackedByteArray imgdata = p_source->get_data(); - const uint8_t *r = imgdata.ptr(); - - int size = 4; - if (p_source->get_format() == Image::FORMAT_L8) { - size = 1; - p_ch = 0; - } - - PackedByteArray imgdata_g; - imgdata_g.resize(w * h * 2); - uint8_t *wg = imgdata_g.ptrw(); - - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - int ofs_src = (i * w + j) * size; - int ofs_dst = (i * w + j) * 2; - wg[ofs_dst + 0] = 255; - wg[ofs_dst + 1] = r[ofs_src + p_ch]; - } - } - Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_g)); - r_font->set_texture_image(0, Vector2i(p_sz, p_ol), p_page, img_g); -} - -void _convert_mono_4bit(Ref<FontData> &r_font, Ref<Image> &p_source, int p_page, int p_ch, int p_sz, int p_ol) { - int w = p_source->get_width(); - int h = p_source->get_height(); - - PackedByteArray imgdata = p_source->get_data(); - const uint8_t *r = imgdata.ptr(); - - int size = 4; - if (p_source->get_format() == Image::FORMAT_L8) { - size = 1; - p_ch = 0; - } - - PackedByteArray imgdata_g; - imgdata_g.resize(w * h * 2); - uint8_t *wg = imgdata_g.ptrw(); - - PackedByteArray imgdata_o; - imgdata_o.resize(w * h * 2); - uint8_t *wo = imgdata_o.ptrw(); - - for (int i = 0; i < h; i++) { - for (int j = 0; j < w; j++) { - int ofs_src = (i * w + j) * size; - int ofs_dst = (i * w + j) * 2; - wg[ofs_dst + 0] = 255; - wo[ofs_dst + 0] = 255; - if (r[ofs_src + p_ch] > 0x7F) { - wg[ofs_dst + 1] = r[ofs_src + p_ch]; - wo[ofs_dst + 1] = 0; - } else { - wg[ofs_dst + 1] = 0; - wo[ofs_dst + 1] = r[ofs_src + p_ch] * 2; - } - } - } - Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_g)); - r_font->set_texture_image(0, Vector2i(p_sz, 0), p_page, img_g); - - Ref<Image> img_o = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_o)); - r_font->set_texture_image(0, Vector2i(p_sz, p_ol), p_page, img_o); -} - Error ResourceImporterBMFont::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { print_verbose("Importing BMFont font from: " + p_source_file); Ref<FontData> font; font.instantiate(); - font->set_antialiased(false); - font->set_multichannel_signed_distance_field(false); - font->set_force_autohinter(false); - font->set_hinting(TextServer::HINTING_NONE); - font->set_oversampling(1.0f); - - FileAccessRef f = FileAccess::open(p_source_file, FileAccess::READ); - if (f == nullptr) { - ERR_FAIL_V_MSG(ERR_CANT_CREATE, TTR("Cannot open font from file ") + "\"" + p_source_file + "\"."); - } - - int base_size = 16; - int height = 0; - int ascent = 0; - int outline = 0; - uint32_t st_flags = 0; - String font_name; - - bool packed = false; - uint8_t ch[4] = { 0, 0, 0, 0 }; // RGBA - int first_gl_ch = -1; - int first_ol_ch = -1; - int first_cm_ch = -1; - - unsigned char magic[4]; - f->get_buffer((unsigned char *)&magic, 4); - if (magic[0] == 'B' && magic[1] == 'M' && magic[2] == 'F') { - // Binary BMFont file. - ERR_FAIL_COND_V_MSG(magic[3] != 3, ERR_CANT_CREATE, vformat(TTR("Version %d of BMFont is not supported."), (int)magic[3])); - - uint8_t block_type = f->get_8(); - uint32_t block_size = f->get_32(); - while (!f->eof_reached()) { - uint64_t off = f->get_position(); - switch (block_type) { - case 1: /* info */ { - ERR_FAIL_COND_V_MSG(block_size < 15, ERR_CANT_CREATE, TTR("Invalid BMFont info block size.")); - base_size = f->get_16(); - uint8_t flags = f->get_8(); - ERR_FAIL_COND_V_MSG(flags & 0x02, ERR_CANT_CREATE, TTR("Non-unicode version of BMFont is not supported.")); - if (flags & (1 << 3)) { - st_flags |= TextServer::FONT_BOLD; - } - if (flags & (1 << 2)) { - st_flags |= TextServer::FONT_ITALIC; - } - f->get_8(); // non-unicode charset, skip - f->get_16(); // stretch_h, skip - f->get_8(); // aa, skip - f->get_32(); // padding, skip - f->get_16(); // spacing, skip - outline = f->get_8(); - // font name - PackedByteArray name_data; - name_data.resize(block_size - 14); - f->get_buffer(name_data.ptrw(), block_size - 14); - font_name = String::utf8((const char *)name_data.ptr(), block_size - 14); - font->set_fixed_size(base_size); - } break; - case 2: /* common */ { - ERR_FAIL_COND_V_MSG(block_size != 15, ERR_CANT_CREATE, TTR("Invalid BMFont common block size.")); - height = f->get_16(); - ascent = f->get_16(); - f->get_32(); // scale, skip - f->get_16(); // pages, skip - uint8_t flags = f->get_8(); - packed = (flags & 0x01); - ch[3] = f->get_8(); - ch[0] = f->get_8(); - ch[1] = f->get_8(); - ch[2] = f->get_8(); - for (int i = 0; i < 4; i++) { - if (ch[i] == 0 && first_gl_ch == -1) { - first_gl_ch = i; - } - if (ch[i] == 1 && first_ol_ch == -1) { - first_ol_ch = i; - } - if (ch[i] == 2 && first_cm_ch == -1) { - first_cm_ch = i; - } - } - } break; - case 3: /* pages */ { - int page = 0; - CharString cs; - char32_t c = f->get_8(); - while (!f->eof_reached() && f->get_position() <= off + block_size) { - if (c == '\0') { - String base_dir = p_source_file.get_base_dir(); - String file = base_dir.plus_file(String::utf8(cs.ptr(), cs.length())); - if (RenderingServer::get_singleton() != nullptr) { - Ref<Image> img; - img.instantiate(); - Error err = ImageLoader::load_image(file, img); - ERR_FAIL_COND_V_MSG(err != OK, ERR_FILE_CANT_READ, TTR("Can't load font texture: ") + "\"" + file + "\"."); - - if (packed) { - if (ch[3] == 0) { // 4 x 8 bit monochrome, no outline - outline = 0; - ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); - _convert_packed_8bit(font, img, page, base_size); - } else if ((ch[3] == 2) && (outline > 0)) { // 4 x 4 bit monochrome, gl + outline - ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); - _convert_packed_4bit(font, img, page, base_size); - } else { - ERR_FAIL_V_MSG(ERR_CANT_CREATE, TTR("Unsupported BMFont texture format.")); - } - } else { - if ((ch[0] == 0) && (ch[1] == 0) && (ch[2] == 0) && (ch[3] == 0)) { // RGBA8 color, no outline - outline = 0; - ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); - font->set_texture_image(0, Vector2i(base_size, 0), page, img); - } else if ((ch[0] == 2) && (ch[1] == 2) && (ch[2] == 2) && (ch[3] == 2) && (outline > 0)) { // RGBA4 color, gl + outline - ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); - _convert_rgba_4bit(font, img, page, base_size); - } else if ((first_gl_ch >= 0) && (first_ol_ch >= 0) && (outline > 0)) { // 1 x 8 bit monochrome, gl + outline - ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); - _convert_mono_8bit(font, img, page, first_gl_ch, base_size, 0); - _convert_mono_8bit(font, img, page, first_ol_ch, base_size, 1); - } else if ((first_cm_ch >= 0) && (outline > 0)) { // 1 x 4 bit monochrome, gl + outline - ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); - _convert_mono_4bit(font, img, page, first_cm_ch, base_size, 1); - } else if (first_gl_ch >= 0) { // 1 x 8 bit monochrome, no outline - outline = 0; - ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); - _convert_mono_8bit(font, img, page, first_gl_ch, base_size, 0); - } else { - ERR_FAIL_V_MSG(ERR_CANT_CREATE, TTR("Unsupported BMFont texture format.")); - } - } - } - page++; - cs = ""; - } else { - cs += c; - } - c = f->get_8(); - } - } break; - case 4: /* chars */ { - int char_count = block_size / 20; - for (int i = 0; i < char_count; i++) { - Vector2 advance; - Vector2 size; - Vector2 offset; - Rect2 uv_rect; - - char32_t idx = f->get_32(); - uv_rect.position.x = (int16_t)f->get_16(); - uv_rect.position.y = (int16_t)f->get_16(); - uv_rect.size.width = (int16_t)f->get_16(); - size.width = uv_rect.size.width; - uv_rect.size.height = (int16_t)f->get_16(); - size.height = uv_rect.size.height; - offset.x = (int16_t)f->get_16(); - offset.y = (int16_t)f->get_16() - ascent; - advance.x = (int16_t)f->get_16(); - if (advance.x < 0) { - advance.x = size.width + 1; - } - - int texture_idx = f->get_8(); - uint8_t channel = f->get_8(); - - ERR_FAIL_COND_V_MSG(!packed && channel != 15, ERR_CANT_CREATE, TTR("Invalid glyph channel.")); - int ch_off = 0; - switch (channel) { - case 1: - ch_off = 2; - break; // B - case 2: - ch_off = 1; - break; // G - case 4: - ch_off = 0; - break; // R - case 8: - ch_off = 3; - break; // A - default: - ch_off = 0; - break; - } - font->set_glyph_advance(0, base_size, idx, advance); - font->set_glyph_offset(0, Vector2i(base_size, 0), idx, offset); - font->set_glyph_size(0, Vector2i(base_size, 0), idx, size); - font->set_glyph_uv_rect(0, Vector2i(base_size, 0), idx, uv_rect); - font->set_glyph_texture_idx(0, Vector2i(base_size, 0), idx, texture_idx * (packed ? 4 : 1) + ch_off); - if (outline > 0) { - font->set_glyph_offset(0, Vector2i(base_size, 1), idx, offset); - font->set_glyph_size(0, Vector2i(base_size, 1), idx, size); - font->set_glyph_uv_rect(0, Vector2i(base_size, 1), idx, uv_rect); - font->set_glyph_texture_idx(0, Vector2i(base_size, 1), idx, texture_idx * (packed ? 4 : 1) + ch_off); - } - } - } break; - case 5: /* kerning */ { - int pair_count = block_size / 10; - for (int i = 0; i < pair_count; i++) { - Vector2i kpk; - kpk.x = f->get_32(); - kpk.y = f->get_32(); - font->set_kerning(0, base_size, kpk, Vector2((int16_t)f->get_16(), 0)); - } - } break; - default: { - ERR_FAIL_V_MSG(ERR_CANT_CREATE, TTR("Invalid BMFont block type.")); - } break; - } - f->seek(off + block_size); - block_type = f->get_8(); - block_size = f->get_32(); - } - - } else { - // Text BMFont file. - f->seek(0); - while (true) { - String line = f->get_line(); - - int delimiter = line.find(" "); - String type = line.substr(0, delimiter); - int pos = delimiter + 1; - Map<String, String> keys; - - while (pos < line.size() && line[pos] == ' ') { - pos++; - } - - while (pos < line.size()) { - int eq = line.find("=", pos); - if (eq == -1) { - break; - } - String key = line.substr(pos, eq - pos); - int end = -1; - String value; - if (line[eq + 1] == '"') { - end = line.find("\"", eq + 2); - if (end == -1) { - break; - } - value = line.substr(eq + 2, end - 1 - eq - 1); - pos = end + 1; - } else { - end = line.find(" ", eq + 1); - if (end == -1) { - end = line.size(); - } - value = line.substr(eq + 1, end - eq); - pos = end; - } - - while (pos < line.size() && line[pos] == ' ') { - pos++; - } - - keys[key] = value; - } - - if (type == "info") { - if (keys.has("size")) { - base_size = keys["size"].to_int(); - font->set_fixed_size(base_size); - } - if (keys.has("outline")) { - outline = keys["outline"].to_int(); - } - if (keys.has("bold")) { - if (keys["bold"].to_int()) { - st_flags |= TextServer::FONT_BOLD; - } - } - if (keys.has("italic")) { - if (keys["italic"].to_int()) { - st_flags |= TextServer::FONT_ITALIC; - } - } - if (keys.has("face")) { - font_name = keys["face"]; - } - ERR_FAIL_COND_V_MSG((!keys.has("unicode") || keys["unicode"].to_int() != 1), ERR_CANT_CREATE, TTR("Non-unicode version of BMFont is not supported.")); - } else if (type == "common") { - if (keys.has("lineHeight")) { - height = keys["lineHeight"].to_int(); - } - if (keys.has("base")) { - ascent = keys["base"].to_int(); - } - if (keys.has("packed")) { - packed = (keys["packed"].to_int() == 1); - } - if (keys.has("alphaChnl")) { - ch[3] = keys["alphaChnl"].to_int(); - } - if (keys.has("redChnl")) { - ch[0] = keys["redChnl"].to_int(); - } - if (keys.has("greenChnl")) { - ch[1] = keys["greenChnl"].to_int(); - } - if (keys.has("blueChnl")) { - ch[2] = keys["blueChnl"].to_int(); - } - for (int i = 0; i < 4; i++) { - if (ch[i] == 0 && first_gl_ch == -1) { - first_gl_ch = i; - } - if (ch[i] == 1 && first_ol_ch == -1) { - first_ol_ch = i; - } - if (ch[i] == 2 && first_cm_ch == -1) { - first_cm_ch = i; - } - } - } else if (type == "page") { - int page = 0; - if (keys.has("id")) { - page = keys["id"].to_int(); - } - if (keys.has("file")) { - String base_dir = p_source_file.get_base_dir(); - String file = base_dir.plus_file(keys["file"]); - if (RenderingServer::get_singleton() != nullptr) { - Ref<Image> img; - img.instantiate(); - Error err = ImageLoader::load_image(file, img); - ERR_FAIL_COND_V_MSG(err != OK, ERR_FILE_CANT_READ, TTR("Can't load font texture: ") + "\"" + file + "\"."); - if (packed) { - if (ch[3] == 0) { // 4 x 8 bit monochrome, no outline - outline = 0; - ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); - _convert_packed_8bit(font, img, page, base_size); - } else if ((ch[3] == 2) && (outline > 0)) { // 4 x 4 bit monochrome, gl + outline - ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); - _convert_packed_4bit(font, img, page, base_size); - } else { - ERR_FAIL_V_MSG(ERR_CANT_CREATE, TTR("Unsupported BMFont texture format.")); - } - } else { - if ((ch[0] == 0) && (ch[1] == 0) && (ch[2] == 0) && (ch[3] == 0)) { // RGBA8 color, no outline - outline = 0; - ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); - font->set_texture_image(0, Vector2i(base_size, 0), page, img); - } else if ((ch[0] == 2) && (ch[1] == 2) && (ch[2] == 2) && (ch[3] == 2) && (outline > 0)) { // RGBA4 color, gl + outline - ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); - _convert_rgba_4bit(font, img, page, base_size); - } else if ((first_gl_ch >= 0) && (first_ol_ch >= 0) && (outline > 0)) { // 1 x 8 bit monochrome, gl + outline - ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); - _convert_mono_8bit(font, img, page, first_gl_ch, base_size, 0); - _convert_mono_8bit(font, img, page, first_ol_ch, base_size, 1); - } else if ((first_cm_ch >= 0) && (outline > 0)) { // 1 x 4 bit monochrome, gl + outline - ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); - _convert_mono_4bit(font, img, page, first_cm_ch, base_size, 1); - } else if (first_gl_ch >= 0) { // 1 x 8 bit monochrome, no outline - outline = 0; - ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, TTR("Unsupported BMFont texture format.")); - _convert_mono_8bit(font, img, page, first_gl_ch, base_size, 0); - } else { - ERR_FAIL_V_MSG(ERR_CANT_CREATE, TTR("Unsupported BMFont texture format.")); - } - } - } - } - } else if (type == "char") { - char32_t idx = 0; - Vector2 advance; - Vector2 size; - Vector2 offset; - Rect2 uv_rect; - int texture_idx = -1; - uint8_t channel = 15; - - if (keys.has("id")) { - idx = keys["id"].to_int(); - } - if (keys.has("x")) { - uv_rect.position.x = keys["x"].to_int(); - } - if (keys.has("y")) { - uv_rect.position.y = keys["y"].to_int(); - } - if (keys.has("width")) { - uv_rect.size.width = keys["width"].to_int(); - size.width = keys["width"].to_int(); - } - if (keys.has("height")) { - uv_rect.size.height = keys["height"].to_int(); - size.height = keys["height"].to_int(); - } - if (keys.has("xoffset")) { - offset.x = keys["xoffset"].to_int(); - } - if (keys.has("yoffset")) { - offset.y = keys["yoffset"].to_int() - ascent; - } - if (keys.has("page")) { - texture_idx = keys["page"].to_int(); - } - if (keys.has("xadvance")) { - advance.x = keys["xadvance"].to_int(); - } - if (advance.x < 0) { - advance.x = size.width + 1; - } - if (keys.has("chnl")) { - channel = keys["chnl"].to_int(); - } - - ERR_FAIL_COND_V_MSG(!packed && channel != 15, ERR_CANT_CREATE, TTR("Invalid glyph channel.")); - int ch_off = 0; - switch (channel) { - case 1: - ch_off = 2; - break; // B - case 2: - ch_off = 1; - break; // G - case 4: - ch_off = 0; - break; // R - case 8: - ch_off = 3; - break; // A - default: - ch_off = 0; - break; - } - font->set_glyph_advance(0, base_size, idx, advance); - font->set_glyph_offset(0, Vector2i(base_size, 0), idx, offset); - font->set_glyph_size(0, Vector2i(base_size, 0), idx, size); - font->set_glyph_uv_rect(0, Vector2i(base_size, 0), idx, uv_rect); - font->set_glyph_texture_idx(0, Vector2i(base_size, 0), idx, texture_idx * (packed ? 4 : 1) + ch_off); - if (outline > 0) { - font->set_glyph_offset(0, Vector2i(base_size, 1), idx, offset); - font->set_glyph_size(0, Vector2i(base_size, 1), idx, size); - font->set_glyph_uv_rect(0, Vector2i(base_size, 1), idx, uv_rect); - font->set_glyph_texture_idx(0, Vector2i(base_size, 1), idx, texture_idx * (packed ? 4 : 1) + ch_off); - } - } else if (type == "kerning") { - Vector2i kpk; - if (keys.has("first")) { - kpk.x = keys["first"].to_int(); - } - if (keys.has("second")) { - kpk.y = keys["second"].to_int(); - } - if (keys.has("amount")) { - font->set_kerning(0, base_size, kpk, Vector2(keys["amount"].to_int(), 0)); - } - } - - if (f->eof_reached()) { - break; - } - } - } - font->set_font_name(font_name); - font->set_font_style(st_flags); - font->set_ascent(0, base_size, ascent); - font->set_descent(0, base_size, height - ascent); + Error err = font->load_bitmap_font(p_source_file); + ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot load font to file \"" + p_source_file + "\"."); int flg = ResourceSaver::SaverFlags::FLAG_BUNDLE_RESOURCES | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS; if ((bool)p_options["compress"]) { @@ -814,7 +78,7 @@ Error ResourceImporterBMFont::import(const String &p_source_file, const String & } print_verbose("Saving to: " + p_save_path + ".fontdata"); - Error err = ResourceSaver::save(p_save_path + ".fontdata", font, flg); + err = ResourceSaver::save(p_save_path + ".fontdata", font, flg); ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save font to file \"" + p_save_path + ".res\"."); print_verbose("Done saving to: " + p_save_path + ".fontdata"); return OK; diff --git a/editor/import/resource_importer_bmfont.h b/editor/import/resource_importer_bmfont.h index 64d536535c..e5a96e2c40 100644 --- a/editor/import/resource_importer_bmfont.h +++ b/editor/import/resource_importer_bmfont.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp index 7948d9e577..ee6500a643 100644 --- a/editor/import/resource_importer_csv_translation.cpp +++ b/editor/import/resource_importer_csv_translation.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -88,9 +88,8 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const break; } - FileAccessRef f = FileAccess::open(p_source_file, FileAccess::READ); - - ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot open file from path '" + p_source_file + "'."); + Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot open file from path '" + p_source_file + "'."); Vector<String> line = f->get_csv_line(delimiter); ERR_FAIL_COND_V(line.size() <= 1, ERR_PARSE_ERROR); @@ -99,8 +98,7 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const Vector<Ref<Translation>> translations; for (int i = 1; i < line.size(); i++) { - String locale = line[i]; - ERR_FAIL_COND_V_MSG(!TranslationServer::is_locale_valid(locale), ERR_PARSE_ERROR, "Error importing CSV translation: '" + locale + "' is not a valid locale."); + String locale = TranslationServer::get_singleton()->standardize_locale(line[i]); locales.push_back(locale); Ref<Translation> translation; @@ -113,7 +111,7 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const while (line.size() == locales.size() + 1) { String key = line[0]; - if (key != "") { + if (!key.is_empty()) { for (int i = 1; i < line.size(); i++) { translations.write[i - 1]->add_message(key, line[i].c_unescape()); } diff --git a/editor/import/resource_importer_csv_translation.h b/editor/import/resource_importer_csv_translation.h index de7ba3e3a0..8f6cf94984 100644 --- a/editor/import/resource_importer_csv_translation.h +++ b/editor/import/resource_importer_csv_translation.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/editor/import/resource_importer_dynamicfont.cpp b/editor/import/resource_importer_dynamic_font.cpp index f7363a565d..a7f6d09aed 100644 --- a/editor/import/resource_importer_dynamicfont.cpp +++ b/editor/import/resource_importer_dynamic_font.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* resource_importer_dynamicfont.cpp */ +/* resource_importer_dynamic_font.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,12 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "resource_importer_dynamicfont.h" +#include "resource_importer_dynamic_font.h" #include "core/io/file_access.h" #include "core/io/resource_saver.h" -#include "dynamicfont_import_settings.h" -#include "editor/editor_node.h" +#include "editor/import/dynamic_font_import_settings.h" +#include "scene/resources/font.h" +#include "servers/text_server.h" #include "modules/modules_enabled.gen.h" // For freetype. @@ -51,7 +52,7 @@ void ResourceImporterDynamicFont::get_recognized_extensions(List<String> *p_exte p_extensions->push_back("ttf"); p_extensions->push_back("otf"); p_extensions->push_back("woff"); - //p_extensions->push_back("woff2"); + p_extensions->push_back("woff2"); p_extensions->push_back("pfb"); p_extensions->push_back("pfm"); #endif @@ -76,6 +77,9 @@ bool ResourceImporterDynamicFont::get_option_visibility(const String &p_path, co if (p_option == "oversampling" && bool(p_options["multichannel_signed_distance_field"])) { return false; } + if (p_option == "subpixel_positioning" && bool(p_options["multichannel_signed_distance_field"])) { + return false; + } return true; } @@ -104,9 +108,13 @@ void ResourceImporterDynamicFont::get_import_options(const String &p_path, List< r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force_autohinter"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), 1)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel"), 1)); + r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "embolden", PROPERTY_HINT_RANGE, "-2,2,0.01"), 0.f)); + r_options->push_back(ImportOption(PropertyInfo(Variant::TRANSFORM2D, "transform"), Transform2D())); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_RANGE, "0,10,0.1"), 0.0)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress"), true)); + r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "opentype_feature_overrides"), Dictionary())); r_options->push_back(ImportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "preload/char_ranges"), Vector<String>())); r_options->push_back(ImportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "preload/glyph_ranges"), Vector<String>())); @@ -174,10 +182,14 @@ Error ResourceImporterDynamicFont::import(const String &p_source_file, const Str bool msdf = p_options["multichannel_signed_distance_field"]; int px_range = p_options["msdf_pixel_range"]; int px_size = p_options["msdf_size"]; + Dictionary ot_ov = p_options["opentype_feature_overrides"]; bool autohinter = p_options["force_autohinter"]; int hinting = p_options["hinting"]; + int subpixel_positioning = p_options["subpixel_positioning"]; real_t oversampling = p_options["oversampling"]; + real_t embolden = p_options["embolden"]; + Transform2D transform = p_options["transform"]; // Load base font data. Vector<uint8_t> data = FileAccess::get_file_as_array(p_source_file); @@ -190,8 +202,12 @@ Error ResourceImporterDynamicFont::import(const String &p_source_file, const Str font->set_multichannel_signed_distance_field(msdf); font->set_msdf_pixel_range(px_range); font->set_msdf_size(px_size); + font->set_opentype_feature_overrides(ot_ov); font->set_fixed_size(0); font->set_force_autohinter(autohinter); + font->set_subpixel_positioning((TextServer::SubpixelPositioning)subpixel_positioning); + font->set_embolden(embolden); + font->set_transform(transform); font->set_hinting((TextServer::Hinting)hinting); font->set_oversampling(oversampling); diff --git a/editor/import/resource_importer_dynamicfont.h b/editor/import/resource_importer_dynamic_font.h index cb5294b9dd..2761b418e1 100644 --- a/editor/import/resource_importer_dynamicfont.h +++ b/editor/import/resource_importer_dynamic_font.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* resource_importer_dynamicfont.h */ +/* resource_importer_dynamic_font.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,12 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RESOURCE_IMPORTER_FONT_DATA_H -#define RESOURCE_IMPORTER_FONT_DATA_H +#ifndef RESOURCE_IMPORTER_DYNAMIC_FONT_H +#define RESOURCE_IMPORTER_DYNAMIC_FONT_H #include "core/io/resource_importer.h" -#include "scene/resources/font.h" -#include "servers/text_server.h" class ResourceImporterDynamicFont : public ResourceImporter { GDCLASS(ResourceImporterDynamicFont, ResourceImporter); @@ -68,4 +66,4 @@ public: ResourceImporterDynamicFont(); }; -#endif // RESOURCE_IMPORTER_FONTDATA_H +#endif // RESOURCE_IMPORTER_DYNAMIC_FONT_H diff --git a/editor/import/resource_importer_image.cpp b/editor/import/resource_importer_image.cpp index 45cb5e2f9d..8514df76bb 100644 --- a/editor/import/resource_importer_image.cpp +++ b/editor/import/resource_importer_image.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -71,10 +71,9 @@ void ResourceImporterImage::get_import_options(const String &p_path, List<Import } Error ResourceImporterImage::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { - FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ); - - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file from path '" + p_source_file + "'."); + Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, "Cannot open file from path '" + p_source_file + "'."); uint64_t len = f->get_length(); Vector<uint8_t> data; @@ -82,10 +81,8 @@ Error ResourceImporterImage::import(const String &p_source_file, const String &p f->get_buffer(data.ptrw(), len); - memdelete(f); - f = FileAccess::open(p_save_path + ".image", FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_CREATE, "Cannot create file in path '" + p_save_path + ".image'."); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_CREATE, "Cannot create file in path '" + p_save_path + ".image'."); //save the header GDIM const uint8_t header[4] = { 'G', 'D', 'I', 'M' }; @@ -95,8 +92,6 @@ Error ResourceImporterImage::import(const String &p_source_file, const String &p //SAVE the actual image f->store_buffer(data.ptr(), len); - memdelete(f); - return OK; } diff --git a/editor/import/resource_importer_image.h b/editor/import/resource_importer_image.h index b7131ec850..81aedc91e8 100644 --- a/editor/import/resource_importer_image.h +++ b/editor/import/resource_importer_image.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/editor/import/resource_importer_imagefont.cpp b/editor/import/resource_importer_imagefont.cpp index 04a68e4a53..1338cf03a8 100644 --- a/editor/import/resource_importer_imagefont.cpp +++ b/editor/import/resource_importer_imagefont.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -98,6 +98,7 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin font->set_antialiased(false); font->set_multichannel_signed_distance_field(false); font->set_fixed_size(base_size); + font->set_subpixel_positioning(TextServer::SUBPIXEL_POSITIONING_DISABLED); font->set_force_autohinter(false); font->set_hinting(TextServer::HINTING_NONE); font->set_oversampling(1.0f); diff --git a/editor/import/resource_importer_imagefont.h b/editor/import/resource_importer_imagefont.h index d600c35e1c..c1116d5a83 100644 --- a/editor/import/resource_importer_imagefont.h +++ b/editor/import/resource_importer_imagefont.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp index 89c62ab5cb..7c0c99cd29 100644 --- a/editor/import/resource_importer_layered_texture.cpp +++ b/editor/import/resource_importer_layered_texture.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,10 +30,11 @@ #include "resource_importer_layered_texture.h" -#include "resource_importer_texture.h" - +#include "core/config/project_settings.h" +#include "core/error/error_macros.h" #include "core/io/config_file.h" #include "core/io/image_loader.h" +#include "core/object/ref_counted.h" #include "editor/editor_file_system.h" #include "editor/editor_node.h" #include "resource_importer_texture.h" @@ -84,16 +85,16 @@ void ResourceImporterLayeredTexture::get_recognized_extensions(List<String> *p_e String ResourceImporterLayeredTexture::get_save_extension() const { switch (mode) { case MODE_CUBEMAP: { - return "scube"; + return "ccube"; } break; case MODE_2D_ARRAY: { - return "stexarray"; + return "ctexarray"; } break; case MODE_CUBEMAP_ARRAY: { - return "scubearray"; + return "ccubearray"; } break; case MODE_3D: { - return "stex3d"; + return "ctex3d"; } break; } @@ -103,16 +104,16 @@ String ResourceImporterLayeredTexture::get_save_extension() const { String ResourceImporterLayeredTexture::get_resource_type() const { switch (mode) { case MODE_CUBEMAP: { - return "StreamCubemap"; + return "CompressedCubemap"; } break; case MODE_2D_ARRAY: { - return "StreamTexture2DArray"; + return "CompressedTexture2DArray"; } break; case MODE_CUBEMAP_ARRAY: { - return "StreamCubemapArray"; + return "CompressedCubemapArray"; } break; case MODE_3D: { - return "StreamTexture3D"; + return "CompressedTexture3D"; } break; } ERR_FAIL_V(String()); @@ -256,31 +257,29 @@ void ResourceImporterLayeredTexture::_save_tex(Vector<Ref<Image>> p_images, cons } } - FileAccessRef f = FileAccess::open(p_to_path, FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open(p_to_path, FileAccess::WRITE); f->store_8('G'); f->store_8('S'); f->store_8('T'); f->store_8('L'); - f->store_32(StreamTextureLayered::FORMAT_VERSION); - f->store_32(p_images.size()); //2d layers or 3d depth + f->store_32(CompressedTextureLayered::FORMAT_VERSION); + f->store_32(p_images.size()); // For 2d layers or 3d depth. f->store_32(mode); f->store_32(0); f->store_32(0); - f->store_32(mipmap_images.size()); // amount of mipmaps + f->store_32(mipmap_images.size()); // Adjust the amount of mipmaps. f->store_32(0); f->store_32(0); for (int i = 0; i < p_images.size(); i++) { - ResourceImporterTexture::save_to_stex_format(f, p_images[i], ResourceImporterTexture::CompressMode(p_compress_mode), used_channels, p_vram_compression, p_lossy); + ResourceImporterTexture::save_to_ctex_format(f, p_images[i], ResourceImporterTexture::CompressMode(p_compress_mode), used_channels, p_vram_compression, p_lossy); } for (int i = 0; i < mipmap_images.size(); i++) { - ResourceImporterTexture::save_to_stex_format(f, mipmap_images[i], ResourceImporterTexture::CompressMode(p_compress_mode), used_channels, p_vram_compression, p_lossy); + ResourceImporterTexture::save_to_ctex_format(f, mipmap_images[i], ResourceImporterTexture::CompressMode(p_compress_mode), used_channels, p_vram_compression, p_lossy); } - - f->close(); } Error ResourceImporterLayeredTexture::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { @@ -289,7 +288,6 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const int hdr_compression = p_options["compress/hdr_compression"]; int bptc_ldr = p_options["compress/bptc_ldr"]; bool mipmaps = p_options["mipmaps/generate"]; - //bool mipmap_limit = p_options["mipmaps/limit"]; int channel_pack = p_options["compress/channel_pack"]; int hslices = (p_options.has("slices/horizontal")) ? int(p_options["slices/horizontal"]) : 0; @@ -377,93 +375,23 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const slices.push_back(slice); } } - - String extension = get_save_extension(); Array formats_imported; - - if (compress_mode == COMPRESS_VRAM_COMPRESSED) { - //must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc). - //Android, GLES 2.x - - bool ok_on_pc = false; - bool is_hdr = (image->get_format() >= Image::FORMAT_RF && image->get_format() <= Image::FORMAT_RGBE9995); - bool is_ldr = (image->get_format() >= Image::FORMAT_L8 && image->get_format() <= Image::FORMAT_RGB565); - bool can_bptc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_bptc"); - bool can_s3tc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_s3tc"); - - if (can_bptc) { - formats_imported.push_back("bptc"); //needs to be aded anyway - } - bool can_compress_hdr = hdr_compression > 0; - - if (is_hdr && can_compress_hdr) { - if (used_channels == Image::USED_CHANNELS_LA || used_channels == Image::USED_CHANNELS_RGBA) { - //can compress hdr, but hdr with alpha is not compressible - - if (hdr_compression == 2) { - //but user selected to compress hdr anyway, so force an alpha-less format. - if (image->get_format() == Image::FORMAT_RGBAF) { - for (int i = 0; i < slices.size(); i++) { - slices.write[i]->convert(Image::FORMAT_RGBF); - } - - } else if (image->get_format() == Image::FORMAT_RGBAH) { - for (int i = 0; i < slices.size(); i++) { - slices.write[i]->convert(Image::FORMAT_RGBH); - } - } - } else { - can_compress_hdr = false; - } - } - - if (can_compress_hdr) { - if (!can_bptc) { - //default to rgbe - if (image->get_format() != Image::FORMAT_RGBE9995) { - for (int i = 0; i < slices.size(); i++) { - slices.write[i]->convert(Image::FORMAT_RGBE9995); - } - } - } - } else { - can_bptc = false; - } - } - - if (is_ldr && can_bptc) { - if (bptc_ldr == 0 || (bptc_ldr == 1 && !(used_channels == Image::USED_CHANNELS_LA || used_channels == Image::USED_CHANNELS_RGBA))) { - can_bptc = false; - } - } - - if (can_bptc || can_s3tc) { - _save_tex(slices, p_save_path + ".s3tc." + extension, compress_mode, lossy, can_bptc ? Image::COMPRESS_BPTC : Image::COMPRESS_S3TC, csource, used_channels, mipmaps, false); - r_platform_variants->push_back("s3tc"); - formats_imported.push_back("s3tc"); - ok_on_pc = true; - } - - if (ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc2")) { - _save_tex(slices, p_save_path + ".etc2." + extension, compress_mode, lossy, Image::COMPRESS_ETC2, csource, used_channels, mipmaps, true); - r_platform_variants->push_back("etc2"); - formats_imported.push_back("etc2"); - } - - if (ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_pvrtc")) { - _save_tex(slices, p_save_path + ".etc2." + extension, compress_mode, lossy, Image::COMPRESS_ETC2, csource, used_channels, mipmaps, true); - r_platform_variants->push_back("pvrtc"); - formats_imported.push_back("pvrtc"); - } - - if (!ok_on_pc) { - EditorNode::add_io_error("Warning, no suitable PC VRAM compression enabled in Project Settings. This texture will not display correctly on PC."); - } - } else { - //import normally - _save_tex(slices, p_save_path + "." + extension, compress_mode, lossy, Image::COMPRESS_S3TC /* IGNORED */, csource, used_channels, mipmaps, false); - } - + Ref<LayeredTextureImport> texture_import; + texture_import.instantiate(); + texture_import->csource = &csource; + texture_import->save_path = p_save_path; + texture_import->options = p_options; + texture_import->platform_variants = r_platform_variants; + texture_import->image = image; + texture_import->formats_imported = formats_imported; + texture_import->slices = &slices; + texture_import->compress_mode = compress_mode; + texture_import->lossy = lossy; + texture_import->hdr_compression = hdr_compression; + texture_import->bptc_ldr = bptc_ldr; + texture_import->mipmaps = mipmaps; + texture_import->used_channels = used_channels; + _check_compress_ctex(texture_import); if (r_metadata) { Dictionary metadata; metadata["vram_texture"] = compress_mode == COMPRESS_VRAM_COMPRESSED; @@ -481,7 +409,6 @@ const char *ResourceImporterLayeredTexture::compression_formats[] = { "s3tc", "etc", "etc2", - "pvrtc", nullptr }; String ResourceImporterLayeredTexture::get_import_settings_string() const { @@ -524,7 +451,7 @@ bool ResourceImporterLayeredTexture::are_import_settings_valid(const String &p_p String setting_path = "rendering/textures/vram_compression/import_" + String(compression_formats[index]); bool test = ProjectSettings::get_singleton()->get(setting_path); if (test) { - if (formats_imported.find(compression_formats[index]) == -1) { + if (!formats_imported.has(compression_formats[index])) { valid = false; break; } @@ -544,3 +471,76 @@ ResourceImporterLayeredTexture::ResourceImporterLayeredTexture() { ResourceImporterLayeredTexture::~ResourceImporterLayeredTexture() { } + +void ResourceImporterLayeredTexture::_check_compress_ctex(Ref<LayeredTextureImport> r_texture_import) { + String extension = get_save_extension(); + ERR_FAIL_NULL(r_texture_import->csource); + if (r_texture_import->compress_mode != COMPRESS_VRAM_COMPRESSED) { + // Import normally. + _save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + extension, r_texture_import->compress_mode, r_texture_import->lossy, Image::COMPRESS_S3TC /* IGNORED */, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, false); + return; + } + // Must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc). + // Android, GLES 2.x + + bool can_bptc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_bptc"); + if (can_bptc) { + r_texture_import->formats_imported.push_back("bptc"); // BPTC needs to be added anyway. + } + bool can_compress_hdr = r_texture_import->hdr_compression > 0; + ERR_FAIL_NULL(r_texture_import->image); + bool is_hdr = (r_texture_import->image->get_format() >= Image::FORMAT_RF && r_texture_import->image->get_format() <= Image::FORMAT_RGBE9995); + bool is_ldr = (r_texture_import->image->get_format() >= Image::FORMAT_L8 && r_texture_import->image->get_format() <= Image::FORMAT_RGB565); + bool can_s3tc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_s3tc"); + ERR_FAIL_NULL(r_texture_import->slices); + // Can compress hdr, but hdr with alpha is not compressible. + if (r_texture_import->hdr_compression == 2) { + // The user selected to compress hdr anyway, so force an alpha-less format. + if (r_texture_import->image->get_format() == Image::FORMAT_RGBAF) { + for (int i = 0; i < r_texture_import->slices->size(); i++) { + r_texture_import->slices->write[i]->convert(Image::FORMAT_RGBF); + } + + } else if (r_texture_import->image->get_format() == Image::FORMAT_RGBAH) { + for (int i = 0; i < r_texture_import->slices->size(); i++) { + r_texture_import->slices->write[i]->convert(Image::FORMAT_RGBH); + } + } + } else { + can_compress_hdr = false; + } + + if (is_hdr && can_compress_hdr) { + if (!can_bptc) { + //default to rgbe + if (r_texture_import->image->get_format() != Image::FORMAT_RGBE9995) { + for (int i = 0; i < r_texture_import->slices->size(); i++) { + r_texture_import->slices->write[i]->convert(Image::FORMAT_RGBE9995); + } + } + } + } else { + can_bptc = false; + } + + if (is_ldr && can_bptc) { + if (r_texture_import->bptc_ldr == 0 || (r_texture_import->bptc_ldr == 1 && !(r_texture_import->used_channels == Image::USED_CHANNELS_LA || r_texture_import->used_channels == Image::USED_CHANNELS_RGBA))) { + can_bptc = false; + } + } + if (!(r_texture_import->used_channels == Image::USED_CHANNELS_LA || r_texture_import->used_channels == Image::USED_CHANNELS_RGBA)) { + if (ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc2")) { + _save_tex(*r_texture_import->slices, r_texture_import->save_path + ".etc2." + extension, r_texture_import->compress_mode, r_texture_import->lossy, Image::COMPRESS_ETC2, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, true); + r_texture_import->platform_variants->push_back("etc2"); + r_texture_import->formats_imported.push_back("etc2"); + } + + if (can_bptc || can_s3tc) { + _save_tex(*r_texture_import->slices, r_texture_import->save_path + ".s3tc." + extension, r_texture_import->compress_mode, r_texture_import->lossy, can_bptc ? Image::COMPRESS_BPTC : Image::COMPRESS_S3TC, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, false); + r_texture_import->platform_variants->push_back("s3tc"); + r_texture_import->formats_imported.push_back("s3tc"); + } + return; + } + EditorNode::add_io_error(TTR("Warning, no suitable PC VRAM compression enabled in Project Settings. This texture will not display correctly on PC.")); +} diff --git a/editor/import/resource_importer_layered_texture.h b/editor/import/resource_importer_layered_texture.h index 29dfe7263a..5791914a9b 100644 --- a/editor/import/resource_importer_layered_texture.h +++ b/editor/import/resource_importer_layered_texture.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,8 +33,29 @@ #include "core/io/image.h" #include "core/io/resource_importer.h" +#include "core/object/ref_counted.h" -class StreamTexture2D; +class CompressedTexture2D; + +class LayeredTextureImport : public RefCounted { + GDCLASS(LayeredTextureImport, RefCounted); + +public: + Image::CompressSource *csource = nullptr; + String save_path; + Map<StringName, Variant> options; + List<String> *platform_variants = nullptr; + Ref<Image> image = nullptr; + Array formats_imported; + Vector<Ref<Image>> *slices = nullptr; + int compress_mode = 0; + float lossy = 1.0; + int hdr_compression = 0; + int bptc_ldr = 0; + bool mipmaps = true; + Image::UsedChannels used_channels = Image::USED_CHANNELS_RGBA; + virtual ~LayeredTextureImport() {} +}; class ResourceImporterLayeredTexture : public ResourceImporter { GDCLASS(ResourceImporterLayeredTexture, ResourceImporter); @@ -66,6 +87,8 @@ protected: static ResourceImporterLayeredTexture *singleton; public: + void _check_compress_ctex(Ref<LayeredTextureImport> r_texture_import); + static ResourceImporterLayeredTexture *get_singleton() { return singleton; } virtual String get_importer_name() const override; virtual String get_visible_name() const override; diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index bb68de99b1..88837d089a 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -44,8 +44,8 @@ uint32_t EditorOBJImporter::get_import_flags() const { } static Error _parse_material_library(const String &p_path, Map<String, Ref<StandardMaterial3D>> &material_map, List<String> *r_missing_deps) { - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Couldn't open MTL file '%s', it may not exist or not be readable.", p_path)); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Couldn't open MTL file '%s', it may not exist or not be readable.", p_path)); Ref<StandardMaterial3D> current; String current_name; @@ -203,8 +203,8 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Stand } static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, Vector3 p_offset_mesh, List<String> *r_missing_deps) { - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path)); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path)); Ref<ArrayMesh> mesh; mesh.instantiate(); @@ -235,7 +235,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ while (l.length() && l[l.length() - 1] == '\\') { String add = f->get_line().strip_edges(); l += add; - if (add == String()) { + if (add.is_empty()) { break; } } @@ -301,7 +301,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ surf_tool->set_normal(normals[norm]); } - if (face[idx].size() >= 2 && face[idx][1] != String()) { + if (face[idx].size() >= 2 && !face[idx][1].is_empty()) { int uv = face[idx][1].to_int() - 1; if (uv < 0) { uv += uvs.size() + 1; @@ -317,8 +317,6 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ ERR_FAIL_INDEX_V(vtx, vertices.size(), ERR_FILE_CORRUPT); Vector3 vertex = vertices[vtx]; - //if (weld_vertices) - // vertex.snap(Vector3(weld_tolerance, weld_tolerance, weld_tolerance)); if (!smoothing) { smooth_group++; } @@ -363,9 +361,9 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ mesh = surf_tool->commit(mesh, mesh_flags); - if (current_material != String()) { + if (!current_material.is_empty()) { mesh->surface_set_name(mesh->get_surface_count() - 1, current_material.get_basename()); - } else if (current_group != String()) { + } else if (!current_group.is_empty()) { mesh->surface_set_name(mesh->get_surface_count() - 1, current_group); } @@ -424,7 +422,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ return OK; } -Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { +Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { List<Ref<Mesh>> meshes; Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, false, Vector3(1, 1, 1), Vector3(0, 0, 0), r_missing_deps); @@ -459,10 +457,6 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in return scene; } -Ref<Animation> EditorOBJImporter::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) { - return Ref<Animation>(); -} - void EditorOBJImporter::get_extensions(List<String> *r_extensions) const { r_extensions->push_back("obj"); } diff --git a/editor/import/resource_importer_obj.h b/editor/import/resource_importer_obj.h index c3e46b6eb5..1b5e8bbdc1 100644 --- a/editor/import/resource_importer_obj.h +++ b/editor/import/resource_importer_obj.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -39,8 +39,7 @@ class EditorOBJImporter : public EditorSceneFormatImporter { public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; EditorOBJImporter(); }; diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index a25b694a60..bdb0c3c493 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,15 +30,16 @@ #include "resource_importer_scene.h" +#include "core/error/error_macros.h" #include "core/io/resource_saver.h" #include "editor/editor_node.h" - #include "editor/import/scene_import_settings.h" #include "scene/3d/area_3d.h" #include "scene/3d/collision_shape_3d.h" #include "scene/3d/importer_mesh_instance_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/navigation_region_3d.h" +#include "scene/3d/occluder_instance_3d.h" #include "scene/3d/physics_body_3d.h" #include "scene/3d/vehicle_body_3d.h" #include "scene/animation/animation_player.h" @@ -73,19 +74,14 @@ void EditorSceneFormatImporter::get_extensions(List<String> *r_extensions) const ERR_FAIL(); } -Node *EditorSceneFormatImporter::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { - Object *ret; - if (GDVIRTUAL_CALL(_import_scene, p_path, p_flags, p_bake_fps, ret)) { - return Object::cast_to<Node>(ret); +Node *EditorSceneFormatImporter::import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { + Dictionary options_dict; + for (const KeyValue<StringName, Variant> &elem : p_options) { + options_dict[elem.key] = elem.value; } - - ERR_FAIL_V(nullptr); -} - -Ref<Animation> EditorSceneFormatImporter::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) { - Ref<Animation> ret; - if (GDVIRTUAL_CALL(_import_animation, p_path, p_flags, p_bake_fps, ret)) { - return ret; + Object *ret = nullptr; + if (GDVIRTUAL_CALL(_import_scene, p_path, p_flags, options_dict, p_bake_fps, ret)) { + return Object::cast_to<Node>(ret); } ERR_FAIL_V(nullptr); @@ -95,39 +91,25 @@ void EditorSceneFormatImporter::get_import_options(const String &p_path, List<Re GDVIRTUAL_CALL(_get_import_options, p_path); } -Variant EditorSceneFormatImporter::get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) { +Variant EditorSceneFormatImporter::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const Map<StringName, Variant> &p_options) { Variant ret; - GDVIRTUAL_CALL(_get_option_visibility, p_path, p_option, ret); + GDVIRTUAL_CALL(_get_option_visibility, p_path, p_for_animation, p_option, ret); return ret; } -//for documenters, these functions are useful when an importer calls an external conversion helper (like, fbx2gltf), -//and you want to load the resulting file - -Node *EditorSceneFormatImporter::import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) { - return ResourceImporterScene::get_singleton()->import_scene_from_other_importer(this, p_path, p_flags, p_bake_fps); -} - -Ref<Animation> EditorSceneFormatImporter::import_animation_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) { - return ResourceImporterScene::get_singleton()->import_animation_from_other_importer(this, p_path, p_flags, p_bake_fps); -} - void EditorSceneFormatImporter::_bind_methods() { - ClassDB::bind_method(D_METHOD("import_scene_from_other_importer", "path", "flags", "bake_fps"), &EditorSceneFormatImporter::import_scene_from_other_importer); - ClassDB::bind_method(D_METHOD("import_animation_from_other_importer", "path", "flags", "bake_fps"), &EditorSceneFormatImporter::import_animation_from_other_importer); - GDVIRTUAL_BIND(_get_import_flags); GDVIRTUAL_BIND(_get_extensions); - GDVIRTUAL_BIND(_import_scene, "path", "flags", "bake_fps"); - GDVIRTUAL_BIND(_import_animation, "path", "flags", "bake_fps"); + GDVIRTUAL_BIND(_import_scene, "path", "flags", "options", "bake_fps"); GDVIRTUAL_BIND(_get_import_options, "path"); - GDVIRTUAL_BIND(_get_option_visibility, "path", "option"); + GDVIRTUAL_BIND(_get_option_visibility, "path", "for_animation", "option"); BIND_CONSTANT(IMPORT_SCENE); BIND_CONSTANT(IMPORT_ANIMATION); BIND_CONSTANT(IMPORT_FAIL_ON_MISSING_DEPENDENCIES); BIND_CONSTANT(IMPORT_GENERATE_TANGENT_ARRAYS); BIND_CONSTANT(IMPORT_USE_NAMED_SKIN_BINDS); + BIND_CONSTANT(IMPORT_DISCARD_MESHES_AND_MATERIALS); } ///////////////////////////////// @@ -184,10 +166,10 @@ void EditorScenePostImportPlugin::get_internal_import_options(InternalImportCate GDVIRTUAL_CALL(_get_internal_import_options, p_category); current_option_list = nullptr; } -Variant EditorScenePostImportPlugin::get_internal_option_visibility(InternalImportCategory p_category, const String &p_option, const Map<StringName, Variant> &p_options) const { +Variant EditorScenePostImportPlugin::get_internal_option_visibility(InternalImportCategory p_category, bool p_for_animation, const String &p_option, const Map<StringName, Variant> &p_options) const { current_options = &p_options; Variant ret; - GDVIRTUAL_CALL(_get_internal_option_visibility, p_category, p_option, ret); + GDVIRTUAL_CALL(_get_internal_option_visibility, p_category, p_for_animation, p_option, ret); current_options = nullptr; return ret; } @@ -210,10 +192,10 @@ void EditorScenePostImportPlugin::get_import_options(const String &p_path, List< GDVIRTUAL_CALL(_get_import_options, p_path); current_option_list = nullptr; } -Variant EditorScenePostImportPlugin::get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) const { +Variant EditorScenePostImportPlugin::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const Map<StringName, Variant> &p_options) const { current_options = &p_options; Variant ret; - GDVIRTUAL_CALL(_get_option_visibility, p_path, p_option, ret); + GDVIRTUAL_CALL(_get_option_visibility, p_path, p_for_animation, p_option, ret); current_options = nullptr; return ret; } @@ -236,11 +218,11 @@ void EditorScenePostImportPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("add_import_option_advanced", "type", "name", "default_value", "hint", "hint_string", "usage_flags"), &EditorScenePostImportPlugin::add_import_option_advanced, DEFVAL(PROPERTY_HINT_NONE), DEFVAL(""), DEFVAL(PROPERTY_USAGE_DEFAULT)); GDVIRTUAL_BIND(_get_internal_import_options, "category"); - GDVIRTUAL_BIND(_get_internal_option_visibility, "category", "option"); + GDVIRTUAL_BIND(_get_internal_option_visibility, "category", "for_animation", "option"); GDVIRTUAL_BIND(_get_internal_option_update_view_required, "category", "option"); GDVIRTUAL_BIND(_internal_process, "category", "base_node", "node", "resource"); GDVIRTUAL_BIND(_get_import_options, "path"); - GDVIRTUAL_BIND(_get_option_visibility, "path", "option"); + GDVIRTUAL_BIND(_get_option_visibility, "path", "for_animation", "option"); GDVIRTUAL_BIND(_pre_process, "scene"); GDVIRTUAL_BIND(_post_process, "scene"); @@ -256,25 +238,25 @@ void EditorScenePostImportPlugin::_bind_methods() { ///////////////////////////////////////////////////////// String ResourceImporterScene::get_importer_name() const { - return "scene"; + return animation_importer ? "animation_library" : "scene"; } String ResourceImporterScene::get_visible_name() const { - return "Scene"; + return animation_importer ? "Animation Library" : "Scene"; } void ResourceImporterScene::get_recognized_extensions(List<String> *p_extensions) const { - for (Set<Ref<EditorSceneFormatImporter>>::Element *E = importers.front(); E; E = E->next()) { - E->get()->get_extensions(p_extensions); + for (Ref<EditorSceneFormatImporter> importer_elem : importers) { + importer_elem->get_extensions(p_extensions); } } String ResourceImporterScene::get_save_extension() const { - return "scn"; + return animation_importer ? "res" : "scn"; } String ResourceImporterScene::get_resource_type() const { - return "PackedScene"; + return animation_importer ? "AnimationLibrary" : "PackedScene"; } int ResourceImporterScene::get_format_version() const { @@ -282,25 +264,34 @@ int ResourceImporterScene::get_format_version() const { } bool ResourceImporterScene::get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) const { - if (p_option.begins_with("animation/")) { + if (animation_importer) { + if (p_option == "animation/import") { // Option ignored, animation always imported. + return false; + } + } else if (p_option.begins_with("animation/")) { if (p_option != "animation/import" && !bool(p_options["animation/import"])) { return false; } } - if (p_option == "meshes/lightmap_texel_size" && int(p_options["meshes/light_baking"]) < 3) { + if (animation_importer && (p_option.begins_with("nodes/") || p_option.begins_with("meshes/") || p_option.begins_with("skins/"))) { + return false; // Nothing to do here for animations. + } + + if (p_option == "meshes/lightmap_texel_size" && int(p_options["meshes/light_baking"]) != 2) { + // Only display the lightmap texel size import option when using the Static Lightmaps light baking mode. return false; } for (int i = 0; i < post_importer_plugins.size(); i++) { - Variant ret = post_importer_plugins.write[i]->get_option_visibility(p_path, p_option, p_options); + Variant ret = post_importer_plugins.write[i]->get_option_visibility(p_path, animation_importer, p_option, p_options); if (ret.get_type() == Variant::BOOL) { return ret; } } for (Ref<EditorSceneFormatImporter> importer : importers) { - Variant ret = importer->get_option_visibility(p_path, p_option, p_options); + Variant ret = importer->get_option_visibility(p_path, animation_importer, p_option, p_options); if (ret.get_type() == Variant::BOOL) { return ret; } @@ -321,7 +312,7 @@ static bool _teststr(const String &p_what, const String &p_str) { String what = p_what; //remove trailing spaces and numbers, some apps like blender add ".number" to duplicates so also compensate for this - while (what.length() && ((what[what.length() - 1] >= '0' && what[what.length() - 1] <= '9') || what[what.length() - 1] <= 32 || what[what.length() - 1] == '.')) { + while (what.length() && (is_digit(what[what.length() - 1]) || what[what.length() - 1] <= 32 || what[what.length() - 1] == '.')) { what = what.substr(0, what.length() - 1); } @@ -341,7 +332,7 @@ static String _fixstr(const String &p_what, const String &p_str) { String what = p_what; //remove trailing spaces and numbers, some apps like blender add ".number" to duplicates so also compensate for this - while (what.length() && ((what[what.length() - 1] >= '0' && what[what.length() - 1] <= '9') || what[what.length() - 1] <= 32 || what[what.length() - 1] == '.')) { + while (what.length() && (is_digit(what[what.length() - 1]) || what[what.length() - 1] <= 32 || what[what.length() - 1] == '.')) { what = what.substr(0, what.length() - 1); } @@ -376,16 +367,17 @@ static void _pre_gen_shape_list(Ref<ImporterMesh> &mesh, Vector<Ref<Shape3D>> &r } } -Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map) { - // children first +Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &r_collision_map, Pair<PackedVector3Array, PackedInt32Array> *r_occluder_arrays, List<Pair<NodePath, Node *>> &r_node_renames) { + // Children first. for (int i = 0; i < p_node->get_child_count(); i++) { - Node *r = _pre_fix_node(p_node->get_child(i), p_root, collision_map); + Node *r = _pre_fix_node(p_node->get_child(i), p_root, r_collision_map, r_occluder_arrays, r_node_renames); if (!r) { - i--; //was erased + i--; // Was erased. } } String name = p_node->get_name(); + NodePath original_path = p_root->get_path_to(p_node); // Used to detect renames due to import hints. bool isroot = p_node == p_root; @@ -420,14 +412,21 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I } if (Object::cast_to<AnimationPlayer>(p_node)) { - //remove animations referencing non-importable nodes AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node); + // Node paths in animation tracks are relative to the following path (this is used to fix node paths below). + Node *ap_root = ap->get_node(ap->get_root()); + NodePath path_prefix = p_root->get_path_to(ap_root); + + bool nodes_were_renamed = r_node_renames.size() != 0; + List<StringName> anims; ap->get_animation_list(&anims); for (const StringName &E : anims) { Ref<Animation> anim = ap->get_animation(E); ERR_CONTINUE(anim.is_null()); + + // Remove animation tracks referencing non-importable nodes. for (int i = 0; i < anim->get_track_count(); i++) { NodePath path = anim->track_get_path(i); @@ -441,6 +440,27 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I } } + // Fix node paths in animations, in case nodes were renamed earlier due to import hints. + if (nodes_were_renamed) { + for (int i = 0; i < anim->get_track_count(); i++) { + NodePath path = anim->track_get_path(i); + // Convert track path to absolute node path without subnames (some manual work because we are not in the scene tree). + Vector<StringName> absolute_path_names = path_prefix.get_names(); + absolute_path_names.append_array(path.get_names()); + NodePath absolute_path(absolute_path_names, false); + absolute_path.simplify(); + // Fix paths to renamed nodes. + for (const Pair<NodePath, Node *> &F : r_node_renames) { + if (F.first == absolute_path) { + NodePath new_path(ap_root->get_path_to(F.second).get_names(), path.get_subnames(), false); + print_verbose(vformat("Fix: Correcting node path in animation track: %s should be %s", path, new_path)); + anim->track_set_path(i, new_path); + break; // Only one match is possible. + } + } + } + } + String animname = E; const int loop_string_count = 3; static const char *loop_strings[loop_string_count] = { "loop_mode", "loop", "cycle" }; @@ -448,7 +468,9 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I if (_teststr(animname, loop_strings[i])) { anim->set_loop_mode(Animation::LoopMode::LOOP_LINEAR); animname = _fixstr(animname, loop_strings[i]); - ap->rename_animation(E, animname); + + Ref<AnimationLibrary> library = ap->get_animation_library(ap->find_animation_library(anim)); + library->rename_animation(E, animname); } } } @@ -458,31 +480,32 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I if (isroot) { return p_node; } + + String fixed_name; + if (_teststr(name, "colonly")) { + fixed_name = _fixstr(name, "colonly"); + } else if (_teststr(name, "convcolonly")) { + fixed_name = _fixstr(name, "convcolonly"); + } + + ERR_FAIL_COND_V(fixed_name.is_empty(), nullptr); + ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node); if (mi) { Ref<ImporterMesh> mesh = mi->get_mesh(); if (mesh.is_valid()) { Vector<Ref<Shape3D>> shapes; - String fixed_name; - if (collision_map.has(mesh)) { - shapes = collision_map[mesh]; + if (r_collision_map.has(mesh)) { + shapes = r_collision_map[mesh]; } else if (_teststr(name, "colonly")) { _pre_gen_shape_list(mesh, shapes, false); - collision_map[mesh] = shapes; + r_collision_map[mesh] = shapes; } else if (_teststr(name, "convcolonly")) { _pre_gen_shape_list(mesh, shapes, true); - collision_map[mesh] = shapes; + r_collision_map[mesh] = shapes; } - if (_teststr(name, "colonly")) { - fixed_name = _fixstr(name, "colonly"); - } else if (_teststr(name, "convcolonly")) { - fixed_name = _fixstr(name, "convcolonly"); - } - - ERR_FAIL_COND_V(fixed_name == String(), nullptr); - if (shapes.size()) { StaticBody3D *col = memnew(StaticBody3D); col->set_transform(mi->get_transform()); @@ -498,11 +521,11 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I } else if (p_node->has_meta("empty_draw_type")) { String empty_draw_type = String(p_node->get_meta("empty_draw_type")); StaticBody3D *sb = memnew(StaticBody3D); - sb->set_name(_fixstr(name, "colonly")); + sb->set_name(fixed_name); Object::cast_to<Node3D>(sb)->set_transform(Object::cast_to<Node3D>(p_node)->get_transform()); p_node->replace_by(sb); memdelete(p_node); - p_node = nullptr; + p_node = sb; CollisionShape3D *colshape = memnew(CollisionShape3D); if (empty_draw_type == "CUBE") { BoxShape3D *boxShape = memnew(BoxShape3D); @@ -535,8 +558,8 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I if (mesh.is_valid()) { Vector<Ref<Shape3D>> shapes; - if (collision_map.has(mesh)) { - shapes = collision_map[mesh]; + if (r_collision_map.has(mesh)) { + shapes = r_collision_map[mesh]; } else { _pre_gen_shape_list(mesh, shapes, true); } @@ -561,14 +584,14 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I if (mesh.is_valid()) { Vector<Ref<Shape3D>> shapes; String fixed_name; - if (collision_map.has(mesh)) { - shapes = collision_map[mesh]; + if (r_collision_map.has(mesh)) { + shapes = r_collision_map[mesh]; } else if (_teststr(name, "col")) { _pre_gen_shape_list(mesh, shapes, false); - collision_map[mesh] = shapes; + r_collision_map[mesh] = shapes; } else if (_teststr(name, "convcol")) { _pre_gen_shape_list(mesh, shapes, true); - collision_map[mesh] = shapes; + r_collision_map[mesh] = shapes; } if (_teststr(name, "col")) { @@ -577,7 +600,7 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I fixed_name = _fixstr(name, "convcol"); } - if (fixed_name != String()) { + if (!fixed_name.is_empty()) { if (mi->get_parent() && !mi->get_parent()->has_node(fixed_name)) { mi->set_name(fixed_name); } @@ -610,7 +633,31 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I p_node->replace_by(nmi); memdelete(p_node); p_node = nmi; + } else if (_teststr(name, "occ") || _teststr(name, "occonly")) { + if (isroot) { + return p_node; + } + ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node); + if (mi) { + Ref<ImporterMesh> mesh = mi->get_mesh(); + if (mesh.is_valid()) { + if (r_occluder_arrays) { + OccluderInstance3D::bake_single_node(mi, 0.0f, r_occluder_arrays->first, r_occluder_arrays->second); + } + if (_teststr(name, "occ")) { + String fixed_name = _fixstr(name, "occ"); + if (!fixed_name.is_empty()) { + if (mi->get_parent() && !mi->get_parent()->has_node(fixed_name)) { + mi->set_name(fixed_name); + } + } + } else { + memdelete(p_node); + p_node = nullptr; + } + } + } } else if (Object::cast_to<ImporterMeshInstance3D>(p_node)) { //last attempt, maybe collision inside the mesh data @@ -619,16 +666,21 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I Ref<ImporterMesh> mesh = mi->get_mesh(); if (!mesh.is_null()) { Vector<Ref<Shape3D>> shapes; - if (collision_map.has(mesh)) { - shapes = collision_map[mesh]; + if (r_collision_map.has(mesh)) { + shapes = r_collision_map[mesh]; } else if (_teststr(mesh->get_name(), "col")) { _pre_gen_shape_list(mesh, shapes, false); - collision_map[mesh] = shapes; + r_collision_map[mesh] = shapes; mesh->set_name(_fixstr(mesh->get_name(), "col")); } else if (_teststr(mesh->get_name(), "convcol")) { _pre_gen_shape_list(mesh, shapes, true); - collision_map[mesh] = shapes; + r_collision_map[mesh] = shapes; mesh->set_name(_fixstr(mesh->get_name(), "convcol")); + } else if (_teststr(mesh->get_name(), "occ")) { + if (r_occluder_arrays) { + OccluderInstance3D::bake_single_node(mi, 0.0f, r_occluder_arrays->first, r_occluder_arrays->second); + } + mesh->set_name(_fixstr(mesh->get_name(), "occ")); } if (shapes.size()) { @@ -641,13 +693,21 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I } } + if (p_node) { + NodePath new_path = p_root->get_path_to(p_node); + if (new_path != original_path) { + print_verbose(vformat("Fix: Renamed %s to %s", original_path, new_path)); + r_node_renames.push_back({ original_path, p_node }); + } + } + return p_node; } -Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Set<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps) { +Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Pair<PackedVector3Array, PackedInt32Array> &r_occluder_arrays, Set<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps) { // children first for (int i = 0; i < p_node->get_child_count(); i++) { - Node *r = _post_fix_node(p_node->get_child(i), p_root, collision_map, r_scanned_meshes, p_node_data, p_material_data, p_animation_data, p_animation_fps); + Node *r = _post_fix_node(p_node->get_child(i), p_root, collision_map, r_occluder_arrays, r_scanned_meshes, p_node_data, p_material_data, p_animation_data, p_animation_fps); if (!r) { i--; //was erased } @@ -710,7 +770,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref< mat_id = mat->get_name(); } - if (mat_id != String() && p_material_data.has(mat_id)) { + if (!mat_id.is_empty() && p_material_data.has(mat_id)) { Dictionary matdata = p_material_data[mat_id]; for (int j = 0; j < post_importer_plugins.size(); j++) { @@ -850,6 +910,32 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref< } } + if (Object::cast_to<ImporterMeshInstance3D>(p_node)) { + ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node); + + Ref<ImporterMesh> m = mi->get_mesh(); + + if (m.is_valid()) { + if (node_settings.has("generate/occluder")) { + int occluder_mode = node_settings["generate/occluder"]; + + if (occluder_mode != OCCLUDER_DISABLED) { + float simplification_dist = 0.0f; + if (node_settings.has("occluder/simplification_distance")) { + simplification_dist = node_settings["occluder/simplification_distance"]; + } + + OccluderInstance3D::bake_single_node(mi, simplification_dist, r_occluder_arrays.first, r_occluder_arrays.second); + + if (occluder_mode == OCCLUDER_OCCLUDER_ONLY) { + memdelete(p_node); + p_node = nullptr; + } + } + } + } + } + if (Object::cast_to<AnimationPlayer>(p_node)) { AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node); @@ -930,7 +1016,8 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref< Ref<Animation> saved_anim = _save_animation_to_file(anim, save, path, keep_custom); if (saved_anim != anim) { - ap->add_animation(name, saved_anim); //replace + Ref<AnimationLibrary> al = ap->get_animation_library(ap->find_animation_library(anim)); + al->add_animation(name, saved_anim); //replace } } } @@ -1015,10 +1102,12 @@ Ref<Animation> ResourceImporterScene::_save_animation_to_file(Ref<Animation> ani void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_clips, bool p_bake_all) { if (!anim->has_animation("default")) { + ERR_FAIL_COND_MSG(p_clips.size() > 0, "To create clips, animations must be named \"default\"."); return; } Ref<Animation> default_anim = anim->get_animation("default"); + Ref<AnimationLibrary> al = anim->get_animation_library(anim->find_animation(default_anim)); for (int i = 0; i < p_clips.size(); i += 7) { String name = p_clips[i]; @@ -1156,15 +1245,16 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_ new_anim->set_loop_mode(loop_mode); new_anim->set_length(to - from); - anim->add_animation(name, new_anim); + + al->add_animation(name, new_anim); Ref<Animation> saved_anim = _save_animation_to_file(new_anim, save_to_file, save_to_path, keep_current); if (saved_anim != new_anim) { - anim->add_animation(name, saved_anim); + al->add_animation(name, saved_anim); } } - anim->remove_animation("default"); //remove default (no longer needed) + al->remove_animation("default"); // Remove default (no longer needed). } void ResourceImporterScene::_optimize_animations(AnimationPlayer *anim, float p_max_lin_error, float p_max_ang_error, float p_max_angle) { @@ -1221,6 +1311,9 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "primitive/radius", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 1.0)); r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "primitive/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), Vector3())); r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "primitive/rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), Vector3())); + + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "generate/occluder", PROPERTY_HINT_ENUM, "Disabled,Mesh + Occluder,Occluder Only", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "occluder/simplification_distance", PROPERTY_HINT_RANGE, "0.0,2.0,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0.1f)); } break; case INTERNAL_IMPORT_CATEGORY_MESH: { r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false)); @@ -1342,6 +1435,11 @@ bool ResourceImporterScene::get_internal_option_visibility(InternalImportCategor (physics_shape == SHAPE_TYPE_CYLINDER || physics_shape == SHAPE_TYPE_CAPSULE); } + + if (p_option == "occluder/simplification_distance") { + // Show only if occluder generation is enabled + return p_options.has("generate/occluder") && p_options["generate/occluder"].operator signed int() != OCCLUDER_DISABLED; + } } break; case INTERNAL_IMPORT_CATEGORY_MESH: { if (p_option == "save_to_file/path" || p_option == "save_to_file/make_streamable") { @@ -1379,7 +1477,7 @@ bool ResourceImporterScene::get_internal_option_visibility(InternalImportCategor } for (int i = 0; i < post_importer_plugins.size(); i++) { - Variant ret = post_importer_plugins.write[i]->get_internal_option_visibility(EditorScenePostImportPlugin::InternalImportCategory(p_category), p_option, p_options); + Variant ret = post_importer_plugins.write[i]->get_internal_option_visibility(EditorScenePostImportPlugin::InternalImportCategory(p_category), animation_importer, p_option, p_options); if (ret.get_type() == Variant::BOOL) { return ret; } @@ -1433,7 +1531,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import String script_ext_hint; for (const String &E : script_extentions) { - if (script_ext_hint != "") { + if (!script_ext_hint.is_empty()) { script_ext_hint += ","; } script_ext_hint += "*." + E; @@ -1443,7 +1541,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/generate_lods"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/create_shadow_meshes"), true)); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Dynamic,Static,Static Lightmaps", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 2)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Static (VoxelGI/SDFGI),Static Lightmaps (VoxelGI/SDFGI/LightmapGI),Dynamic (VoxelGI only)", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 1)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.1)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import"), true)); @@ -1456,8 +1554,8 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import post_importer_plugins.write[i]->get_import_options(p_path, r_options); } - for (Ref<EditorSceneFormatImporter> importer : importers) { - importer->get_import_options(p_path, r_options); + for (Ref<EditorSceneFormatImporter> importer_elem : importers) { + importer_elem->get_import_options(p_path, r_options); } } @@ -1472,64 +1570,6 @@ void ResourceImporterScene::_replace_owner(Node *p_node, Node *p_scene, Node *p_ } } -Node *ResourceImporterScene::import_scene_from_other_importer(EditorSceneFormatImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps) { - Ref<EditorSceneFormatImporter> importer; - String ext = p_path.get_extension().to_lower(); - - for (Set<Ref<EditorSceneFormatImporter>>::Element *E = importers.front(); E; E = E->next()) { - if (E->get().ptr() == p_exception) { - continue; - } - List<String> extensions; - E->get()->get_extensions(&extensions); - - for (const String &F : extensions) { - if (F.to_lower() == ext) { - importer = E->get(); - break; - } - } - - if (importer.is_valid()) { - break; - } - } - - ERR_FAIL_COND_V(!importer.is_valid(), nullptr); - - List<String> missing; - Error err; - return importer->import_scene(p_path, p_flags, p_bake_fps, &missing, &err); -} - -Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(EditorSceneFormatImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps) { - Ref<EditorSceneFormatImporter> importer; - String ext = p_path.get_extension().to_lower(); - - for (Set<Ref<EditorSceneFormatImporter>>::Element *E = importers.front(); E; E = E->next()) { - if (E->get().ptr() == p_exception) { - continue; - } - List<String> extensions; - E->get()->get_extensions(&extensions); - - for (const String &F : extensions) { - if (F.to_lower() == ext) { - importer = E->get(); - break; - } - } - - if (importer.is_valid()) { - break; - } - } - - ERR_FAIL_COND_V(!importer.is_valid(), nullptr); - - return importer->import_animation(p_path, p_flags, p_bake_fps); -} - void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches) { ImporterMeshInstance3D *src_mesh_node = Object::cast_to<ImporterMeshInstance3D>(p_node); if (src_mesh_node) { @@ -1559,7 +1599,7 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m mesh_id = src_mesh_node->get_mesh()->get_name(); } - if (mesh_id != String() && p_mesh_data.has(mesh_id)) { + if (!mesh_id.is_empty() && p_mesh_data.has(mesh_id)) { Dictionary mesh_settings = p_mesh_data[mesh_id]; if (mesh_settings.has("generate/shadow_meshes")) { @@ -1609,14 +1649,6 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m } } - if (generate_lods) { - src_mesh_node->get_mesh()->generate_lods(merge_angle, split_angle); - } - - if (create_shadow_meshes) { - src_mesh_node->get_mesh()->create_shadow_mesh(); - } - if (bake_lightmaps) { Transform3D xf; Node3D *n = src_mesh_node; @@ -1649,7 +1681,15 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m } } - if (save_to_file != String()) { + if (generate_lods) { + src_mesh_node->get_mesh()->generate_lods(merge_angle, split_angle); + } + + if (create_shadow_meshes) { + src_mesh_node->get_mesh()->create_shadow_mesh(); + } + + if (!save_to_file.is_empty()) { Ref<Mesh> existing = Ref<Resource>(ResourceCache::get(save_to_file)); if (existing.is_valid()) { //if somehow an existing one is useful, create @@ -1685,7 +1725,7 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m } break; case LIGHT_BAKE_STATIC: case LIGHT_BAKE_STATIC_LIGHTMAPS: { - mesh_node->set_gi_mode(GeometryInstance3D::GI_MODE_BAKED); + mesh_node->set_gi_mode(GeometryInstance3D::GI_MODE_STATIC); } break; } @@ -1801,7 +1841,8 @@ void ResourceImporterScene::_optimize_track_usage(AnimationPlayer *p_player, Ani if (bone_idx == -1) { continue; } - skel->get_bone_pose(bone_idx); + // Note that this is using get_bone_pose to update the bone pose cache. + _ALLOW_DISCARD_ skel->get_bone_pose(bone_idx); loc = skel->get_bone_pose_position(bone_idx); rot = skel->get_bone_pose_rotation(bone_idx); scale = skel->get_bone_pose_scale(bone_idx); @@ -1866,13 +1907,13 @@ Node *ResourceImporterScene::pre_import(const String &p_source_file) { EditorProgress progress("pre-import", TTR("Pre-Import Scene"), 0); progress.step(TTR("Importing Scene..."), 0); - for (Set<Ref<EditorSceneFormatImporter>>::Element *E = importers.front(); E; E = E->next()) { + for (Ref<EditorSceneFormatImporter> importer_elem : importers) { List<String> extensions; - E->get()->get_extensions(&extensions); + importer_elem->get_extensions(&extensions); for (const String &F : extensions) { if (F.to_lower() == ext) { - importer = E->get(); + importer = importer_elem; break; } } @@ -1885,14 +1926,14 @@ Node *ResourceImporterScene::pre_import(const String &p_source_file) { ERR_FAIL_COND_V(!importer.is_valid(), nullptr); Error err = OK; - Node *scene = importer->import_scene(p_source_file, EditorSceneFormatImporter::IMPORT_ANIMATION | EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS, 15, nullptr, &err); + Node *scene = importer->import_scene(p_source_file, EditorSceneFormatImporter::IMPORT_ANIMATION | EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS, Map<StringName, Variant>(), 15, nullptr, &err); if (!scene || err != OK) { return nullptr; } Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> collision_map; - - _pre_fix_node(scene, scene, collision_map); + List<Pair<NodePath, Node *>> node_renames; + _pre_fix_node(scene, scene, collision_map, nullptr, node_renames); return scene; } @@ -1906,13 +1947,13 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p EditorProgress progress("import", TTR("Import Scene"), 104); progress.step(TTR("Importing Scene..."), 0); - for (Set<Ref<EditorSceneFormatImporter>>::Element *E = importers.front(); E; E = E->next()) { + for (Ref<EditorSceneFormatImporter> importer_elem : importers) { List<String> extensions; - E->get()->get_extensions(&extensions); + importer_elem->get_extensions(&extensions); for (const String &F : extensions) { if (F.to_lower() == ext) { - importer = E->get(); + importer = importer_elem; break; } } @@ -1928,8 +1969,13 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p int import_flags = 0; - if (bool(p_options["animation/import"])) { + if (animation_importer) { import_flags |= EditorSceneFormatImporter::IMPORT_ANIMATION; + import_flags |= EditorSceneFormatImporter::IMPORT_DISCARD_MESHES_AND_MATERIALS; + } else { + if (bool(p_options["animation/import"])) { + import_flags |= EditorSceneFormatImporter::IMPORT_ANIMATION; + } } if (bool(p_options["skins/use_named_skins"])) { @@ -1943,7 +1989,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p Error err = OK; List<String> missing_deps; // for now, not much will be done with this - Node *scene = importer->import_scene(src_path, import_flags, fps, &missing_deps, &err); + Node *scene = importer->import_scene(src_path, import_flags, p_options, fps, &missing_deps, &err); if (!scene || err != OK) { return err; } @@ -1967,14 +2013,16 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p Set<Ref<ImporterMesh>> scanned_meshes; Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> collision_map; + Pair<PackedVector3Array, PackedInt32Array> occluder_arrays; + List<Pair<NodePath, Node *>> node_renames; - _pre_fix_node(scene, scene, collision_map); + _pre_fix_node(scene, scene, collision_map, &occluder_arrays, node_renames); for (int i = 0; i < post_importer_plugins.size(); i++) { post_importer_plugins.write[i]->pre_process(scene, p_options); } - _post_fix_node(scene, scene, collision_map, scanned_meshes, node_data, material_data, animation_data, fps); + _post_fix_node(scene, scene, collision_map, occluder_arrays, scanned_meshes, node_data, material_data, animation_data, fps); String root_type = p_options["nodes/root_type"]; root_type = root_type.split(" ")[0]; // full root_type is "ClassName (filename.gd)" for a script global class. @@ -2011,6 +2059,15 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p scene->set_name(p_save_path.get_file().get_basename()); } + if (!occluder_arrays.first.is_empty() && !occluder_arrays.second.is_empty()) { + Ref<ArrayOccluder3D> occ = memnew(ArrayOccluder3D); + occ->set_arrays(occluder_arrays.first, occluder_arrays.second); + OccluderInstance3D *occluder_instance = memnew(OccluderInstance3D); + occluder_instance->set_occluder(occ); + scene->add_child(occluder_instance, true); + occluder_instance->set_owner(scene); + } + bool gen_lods = bool(p_options["meshes/generate_lods"]); bool create_shadow_meshes = bool(p_options["meshes/create_shadow_meshes"]); int light_bake_mode = p_options["meshes/light_baking"]; @@ -2034,14 +2091,13 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p _generate_meshes(scene, mesh_data, gen_lods, create_shadow_meshes, LightBakeMode(light_bake_mode), lightmap_texel_size, src_lightmap_cache, mesh_lightmap_caches); if (mesh_lightmap_caches.size()) { - FileAccessRef f = FileAccess::open(p_source_file + ".unwrap_cache", FileAccess::WRITE); - if (f) { + Ref<FileAccess> f = FileAccess::open(p_source_file + ".unwrap_cache", FileAccess::WRITE); + if (f.is_valid()) { f->store_32(mesh_lightmap_caches.size()); for (int i = 0; i < mesh_lightmap_caches.size(); i++) { String md5 = String::md5(mesh_lightmap_caches[i].ptr()); f->store_buffer(mesh_lightmap_caches[i].ptr(), mesh_lightmap_caches[i].size()); } - f->close(); } } err = OK; @@ -2051,7 +2107,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p String post_import_script_path = p_options["import_script/path"]; Ref<EditorScenePostImport> post_import_script; - if (post_import_script_path != "") { + if (!post_import_script_path.is_empty()) { Ref<Script> scr = ResourceLoader::load(post_import_script_path); if (!scr.is_valid()) { EditorNode::add_io_error(TTR("Couldn't load post-import script:") + " " + post_import_script_path); @@ -2083,11 +2139,35 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p progress.step(TTR("Saving..."), 104); - Ref<PackedScene> packer = memnew(PackedScene); - packer->pack(scene); - print_verbose("Saving scene to: " + p_save_path + ".scn"); - err = ResourceSaver::save(p_save_path + ".scn", packer); //do not take over, let the changed files reload themselves - ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save scene to file '" + p_save_path + ".scn'."); + if (animation_importer) { + Ref<AnimationLibrary> library; + for (int i = 0; i < scene->get_child_count(); i++) { + AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(scene->get_child(i)); + if (ap) { + List<StringName> libs; + ap->get_animation_library_list(&libs); + if (libs.size()) { + library = ap->get_animation_library(libs.front()->get()); + break; + } + } + } + + if (!library.is_valid()) { + library.instantiate(); // Will be empty + } + + print_verbose("Saving animation to: " + p_save_path + ".scn"); + err = ResourceSaver::save(p_save_path + ".res", library); //do not take over, let the changed files reload themselves + ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save animation to file '" + p_save_path + ".res'."); + + } else { + Ref<PackedScene> packer = memnew(PackedScene); + packer->pack(scene); + print_verbose("Saving scene to: " + p_save_path + ".scn"); + err = ResourceSaver::save(p_save_path + ".scn", packer); //do not take over, let the changed files reload themselves + ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save scene to file '" + p_save_path + ".scn'."); + } memdelete(scene); @@ -2097,17 +2177,57 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p return OK; } -ResourceImporterScene *ResourceImporterScene::singleton = nullptr; +ResourceImporterScene *ResourceImporterScene::scene_singleton = nullptr; +ResourceImporterScene *ResourceImporterScene::animation_singleton = nullptr; + +Vector<Ref<EditorSceneFormatImporter>> ResourceImporterScene::importers; +Vector<Ref<EditorScenePostImportPlugin>> ResourceImporterScene::post_importer_plugins; bool ResourceImporterScene::ResourceImporterScene::has_advanced_options() const { return true; } void ResourceImporterScene::ResourceImporterScene::show_advanced_options(const String &p_path) { - SceneImportSettings::get_singleton()->open_settings(p_path); + SceneImportSettings::get_singleton()->open_settings(p_path, animation_importer); +} + +ResourceImporterScene::ResourceImporterScene(bool p_animation_import) { + if (p_animation_import) { + animation_singleton = this; + } else { + scene_singleton = this; + } + animation_importer = p_animation_import; +} + +void ResourceImporterScene::add_importer(Ref<EditorSceneFormatImporter> p_importer, bool p_first_priority) { + ERR_FAIL_COND(p_importer.is_null()); + if (p_first_priority) { + importers.insert(0, p_importer); + } else { + importers.push_back(p_importer); + } } -ResourceImporterScene::ResourceImporterScene() { - singleton = this; +void ResourceImporterScene::remove_post_importer_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin) { + post_importer_plugins.erase(p_plugin); +} + +void ResourceImporterScene::add_post_importer_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin, bool p_first_priority) { + ERR_FAIL_COND(p_plugin.is_null()); + if (p_first_priority) { + post_importer_plugins.insert(0, p_plugin); + } else { + post_importer_plugins.push_back(p_plugin); + } +} + +void ResourceImporterScene::remove_importer(Ref<EditorSceneFormatImporter> p_importer) { + importers.erase(p_importer); +} + +void ResourceImporterScene::clean_up_importer_plugins() { + importers.clear(); + post_importer_plugins.clear(); } /////////////////////////////////////// @@ -2120,7 +2240,7 @@ void EditorSceneFormatImporterESCN::get_extensions(List<String> *r_extensions) c r_extensions->push_back("escn"); } -Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { +Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { Error error; Ref<PackedScene> ps = ResourceFormatLoaderText::singleton->load(p_path, p_path, &error); ERR_FAIL_COND_V_MSG(!ps.is_valid(), nullptr, "Cannot load scene as text resource from path '" + p_path + "'."); @@ -2130,7 +2250,3 @@ Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t return scene; } - -Ref<Animation> EditorSceneFormatImporterESCN::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) { - ERR_FAIL_V(Ref<Animation>()); -} diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index 5437ecd159..368f68ae8f 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,7 +31,9 @@ #ifndef RESOURCEIMPORTERSCENE_H #define RESOURCEIMPORTERSCENE_H +#include "core/error/error_macros.h" #include "core/io/resource_importer.h" +#include "core/variant/dictionary.h" #include "scene/3d/node_3d.h" #include "scene/resources/animation.h" #include "scene/resources/mesh.h" @@ -48,15 +50,14 @@ class EditorSceneFormatImporter : public RefCounted { protected: static void _bind_methods(); - Node *import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps); - Ref<Animation> import_animation_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps); + Node *import_scene_wrapper(const String &p_path, uint32_t p_flags, Dictionary p_options, int p_bake_fps); + Ref<Animation> import_animation_wrapper(const String &p_path, uint32_t p_flags, Dictionary p_options, int p_bake_fps); GDVIRTUAL0RC(int, _get_import_flags) GDVIRTUAL0RC(Vector<String>, _get_extensions) - GDVIRTUAL3R(Object *, _import_scene, String, uint32_t, uint32_t) - GDVIRTUAL3R(Ref<Animation>, _import_animation, String, uint32_t, uint32_t) + GDVIRTUAL4R(Object *, _import_scene, String, uint32_t, Dictionary, uint32_t) GDVIRTUAL1(_get_import_options, String) - GDVIRTUAL2RC(Variant, _get_option_visibility, String, String) + GDVIRTUAL3RC(Variant, _get_option_visibility, String, bool, String) public: enum ImportFlags { @@ -65,14 +66,14 @@ public: IMPORT_FAIL_ON_MISSING_DEPENDENCIES = 4, IMPORT_GENERATE_TANGENT_ARRAYS = 8, IMPORT_USE_NAMED_SKIN_BINDS = 16, + IMPORT_DISCARD_MESHES_AND_MATERIALS = 32, //used for optimizing animation import }; virtual uint32_t get_import_flags() const; virtual void get_extensions(List<String> *r_extensions) const; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr); - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps); + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr); virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options); - virtual Variant get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options); + virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const Map<StringName, Variant> &p_options); EditorSceneFormatImporter() {} }; @@ -116,11 +117,11 @@ private: protected: GDVIRTUAL1(_get_internal_import_options, int) - GDVIRTUAL2RC(Variant, _get_internal_option_visibility, int, String) + GDVIRTUAL3RC(Variant, _get_internal_option_visibility, int, bool, String) GDVIRTUAL2RC(Variant, _get_internal_option_update_view_required, int, String) GDVIRTUAL4(_internal_process, int, Node *, Node *, RES) GDVIRTUAL1(_get_import_options, String) - GDVIRTUAL2RC(Variant, _get_option_visibility, String, String) + GDVIRTUAL3RC(Variant, _get_option_visibility, String, bool, String) GDVIRTUAL1(_pre_process, Node *) GDVIRTUAL1(_post_process, Node *) @@ -132,13 +133,13 @@ public: void add_import_option_advanced(Variant::Type p_type, const String &p_name, Variant p_default_value, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = String(), int p_usage_flags = PROPERTY_USAGE_DEFAULT); virtual void get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options); - virtual Variant get_internal_option_visibility(InternalImportCategory p_category, const String &p_option, const Map<StringName, Variant> &p_options) const; + virtual Variant get_internal_option_visibility(InternalImportCategory p_category, bool p_for_animation, const String &p_option, const Map<StringName, Variant> &p_options) const; virtual Variant get_internal_option_update_view_required(InternalImportCategory p_category, const String &p_option, const Map<StringName, Variant> &p_options) const; virtual void internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, RES p_resource, const Dictionary &p_options); virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options); - virtual Variant get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) const; + virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const Map<StringName, Variant> &p_options) const; virtual void pre_process(Node *p_scene, const Map<StringName, Variant> &p_options); virtual void post_process(Node *p_scene, const Map<StringName, Variant> &p_options); @@ -151,15 +152,17 @@ VARIANT_ENUM_CAST(EditorScenePostImportPlugin::InternalImportCategory) class ResourceImporterScene : public ResourceImporter { GDCLASS(ResourceImporterScene, ResourceImporter); - Set<Ref<EditorSceneFormatImporter>> importers; + static Vector<Ref<EditorSceneFormatImporter>> importers; + static Vector<Ref<EditorScenePostImportPlugin>> post_importer_plugins; - static ResourceImporterScene *singleton; + static ResourceImporterScene *scene_singleton; + static ResourceImporterScene *animation_singleton; enum LightBakeMode { LIGHT_BAKE_DISABLED, - LIGHT_BAKE_DYNAMIC, LIGHT_BAKE_STATIC, - LIGHT_BAKE_STATIC_LIGHTMAPS + LIGHT_BAKE_STATIC_LIGHTMAPS, + LIGHT_BAKE_DYNAMIC, }; enum MeshPhysicsMode { @@ -176,6 +179,12 @@ class ResourceImporterScene : public ResourceImporter { NAVMESH_NAVMESH_ONLY, }; + enum OccluderMode { + OCCLUDER_DISABLED, + OCCLUDER_MESH_AND_OCCLUDER, + OCCLUDER_OCCLUDER_ONLY, + }; + enum MeshOverride { MESH_OVERRIDE_DEFAULT, MESH_OVERRIDE_ENABLE, @@ -217,18 +226,21 @@ class ResourceImporterScene : public ResourceImporter { void _optimize_track_usage(AnimationPlayer *p_player, AnimationImportTracks *p_track_actions); - mutable Vector<Ref<EditorScenePostImportPlugin>> post_importer_plugins; + bool animation_importer = false; public: - static ResourceImporterScene *get_singleton() { return singleton; } + static ResourceImporterScene *get_scene_singleton() { return scene_singleton; } + static ResourceImporterScene *get_animation_singleton() { return animation_singleton; } + + static void add_post_importer_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin, bool p_first_priority = false); + static void remove_post_importer_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin); - void add_post_importer_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin) { post_importer_plugins.push_back(p_plugin); } - void remove_post_importer_plugin(const Ref<EditorScenePostImportPlugin> &p_plugin) { post_importer_plugins.erase(p_plugin); } + const Vector<Ref<EditorSceneFormatImporter>> &get_importers() const { return importers; } - const Set<Ref<EditorSceneFormatImporter>> &get_importers() const { return importers; } + static void add_importer(Ref<EditorSceneFormatImporter> p_importer, bool p_first_priority = false); + static void remove_importer(Ref<EditorSceneFormatImporter> p_importer); - void add_importer(Ref<EditorSceneFormatImporter> p_importer) { importers.insert(p_importer); } - void remove_importer(Ref<EditorSceneFormatImporter> p_importer) { importers.erase(p_importer); } + static void clean_up_importer_plugins(); virtual String get_importer_name() const override; virtual String get_visible_name() const override; @@ -259,8 +271,8 @@ public: // Import scenes *after* everything else (such as textures). virtual int get_import_order() const override { return ResourceImporter::IMPORT_ORDER_SCENE; } - Node *_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map); - Node *_post_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Set<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps); + Node *_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &r_collision_map, Pair<PackedVector3Array, PackedInt32Array> *r_occluder_arrays, List<Pair<NodePath, Node *>> &r_node_renames); + Node *_post_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Pair<PackedVector3Array, PackedInt32Array> &r_occluder_arrays, Set<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps); Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks); void _create_clips(AnimationPlayer *anim, const Array &p_clips, bool p_bake_all); @@ -270,15 +282,12 @@ public: Node *pre_import(const String &p_source_file); virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override; - Node *import_scene_from_other_importer(EditorSceneFormatImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps); - Ref<Animation> import_animation_from_other_importer(EditorSceneFormatImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps); - virtual bool has_advanced_options() const override; virtual void show_advanced_options(const String &p_path) override; virtual bool can_import_threaded() const override { return false; } - ResourceImporterScene(); + ResourceImporterScene(bool p_animation_import = false); template <class M> static Vector<Ref<Shape3D>> get_collision_shapes(const Ref<Mesh> &p_mesh, const M &p_options); @@ -293,8 +302,7 @@ class EditorSceneFormatImporterESCN : public EditorSceneFormatImporter { public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; }; #include "scene/resources/box_shape_3d.h" diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp index 797e11f5ea..1d70a47daa 100644 --- a/editor/import/resource_importer_shader_file.cpp +++ b/editor/import/resource_importer_shader_file.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -82,7 +82,7 @@ static String _include_function(const String &p_path, void *userpointer) { include = base_path->plus_file(include); } - FileAccessRef file_inc = FileAccess::open(include, FileAccess::READ, &err); + Ref<FileAccess> file_inc = FileAccess::open(include, FileAccess::READ, &err); if (err != OK) { return String(); } @@ -93,7 +93,7 @@ Error ResourceImporterShaderFile::import(const String &p_source_file, const Stri /* STEP 1, Read shader code */ Error err; - FileAccessRef file = FileAccess::open(p_source_file, FileAccess::READ, &err); + Ref<FileAccess> file = FileAccess::open(p_source_file, FileAccess::READ, &err); ERR_FAIL_COND_V(err != OK, ERR_CANT_OPEN); ERR_FAIL_COND_V(!file.operator->(), ERR_CANT_OPEN); diff --git a/editor/import/resource_importer_shader_file.h b/editor/import/resource_importer_shader_file.h index 3ed489e9fb..858c2e783c 100644 --- a/editor/import/resource_importer_shader_file.h +++ b/editor/import/resource_importer_shader_file.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index b1fa2eda28..de51a28c5a 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,13 +30,16 @@ #include "resource_importer_texture.h" +#include "core/config/project_settings.h" #include "core/io/config_file.h" #include "core/io/image_loader.h" #include "core/version.h" #include "editor/editor_file_system.h" #include "editor/editor_node.h" -void ResourceImporterTexture::_texture_reimport_roughness(const Ref<StreamTexture2D> &p_tex, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_channel) { +void ResourceImporterTexture::_texture_reimport_roughness(const Ref<CompressedTexture2D> &p_tex, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_channel) { + ERR_FAIL_COND(p_tex.is_null()); + MutexLock lock(singleton->mutex); StringName path = p_tex->get_path(); @@ -50,7 +53,9 @@ void ResourceImporterTexture::_texture_reimport_roughness(const Ref<StreamTextur singleton->make_flags[path].normal_path_for_roughness = p_normal_path; } -void ResourceImporterTexture::_texture_reimport_3d(const Ref<StreamTexture2D> &p_tex) { +void ResourceImporterTexture::_texture_reimport_3d(const Ref<CompressedTexture2D> &p_tex) { + ERR_FAIL_COND(p_tex.is_null()); + MutexLock lock(singleton->mutex); StringName path = p_tex->get_path(); @@ -62,7 +67,9 @@ void ResourceImporterTexture::_texture_reimport_3d(const Ref<StreamTexture2D> &p singleton->make_flags[path].flags |= MAKE_3D_FLAG; } -void ResourceImporterTexture::_texture_reimport_normal(const Ref<StreamTexture2D> &p_tex) { +void ResourceImporterTexture::_texture_reimport_normal(const Ref<CompressedTexture2D> &p_tex) { + ERR_FAIL_COND(p_tex.is_null()); + MutexLock lock(singleton->mutex); StringName path = p_tex->get_path(); @@ -146,11 +153,11 @@ void ResourceImporterTexture::get_recognized_extensions(List<String> *p_extensio } String ResourceImporterTexture::get_save_extension() const { - return "stex"; + return "ctex"; } String ResourceImporterTexture::get_resource_type() const { - return "StreamTexture2D"; + return "CompressedTexture2D"; } bool ResourceImporterTexture::get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) const { @@ -164,6 +171,11 @@ bool ResourceImporterTexture::get_option_visibility(const String &p_path, const if (compress_mode < COMPRESS_VRAM_COMPRESSED) { return false; } + } else if (p_option == "compress/normal_map") { + int compress_mode = int(p_options["compress/mode"]); + if (compress_mode == COMPRESS_LOSSLESS) { + return false; + } } else if (p_option == "mipmaps/limit") { return p_options["mipmaps/generate"]; @@ -201,27 +213,29 @@ void ResourceImporterTexture::get_import_options(const String &p_path, List<Impo r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/bptc_ldr", PROPERTY_HINT_ENUM, "Disabled,Enabled,RGBA Only"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/normal_map", PROPERTY_HINT_ENUM, "Detect,Enable,Disabled"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/channel_pack", PROPERTY_HINT_ENUM, "sRGB Friendly,Optimized"), 0)); - r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress/streamed"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "mipmaps/generate"), (p_preset == PRESET_3D ? true : false))); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "mipmaps/limit", PROPERTY_HINT_RANGE, "-1,256"), -1)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "roughness/mode", PROPERTY_HINT_ENUM, "Detect,Disabled,Red,Green,Blue,Alpha,Gray"), 0)); - r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "roughness/src_normal", PROPERTY_HINT_FILE, "*.bmp,*.dds,*.exr,*.jpeg,*.jpg,*.hdr,*.png,*.svg,*.svgz,*.tga,*.webp"), "")); + r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "roughness/src_normal", PROPERTY_HINT_FILE, "*.bmp,*.dds,*.exr,*.jpeg,*.jpg,*.hdr,*.png,*.svg,*.tga,*.webp"), "")); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/fix_alpha_border"), p_preset != PRESET_3D)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/premult_alpha"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/normal_map_invert_y"), false)); - r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/HDR_as_SRGB"), false)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/hdr_as_srgb"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "process/size_limit", PROPERTY_HINT_RANGE, "0,4096,1"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "detect_3d/compress_to", PROPERTY_HINT_ENUM, "Disabled,VRAM Compressed,Basis Universal"), (p_preset == PRESET_DETECT) ? 1 : 0)); - r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "svg/scale", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 1.0)); + + if (p_path.get_extension() == "svg") { + r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "svg/scale", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 1.0)); + } } -void ResourceImporterTexture::save_to_stex_format(FileAccess *f, const Ref<Image> &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality) { +void ResourceImporterTexture::save_to_ctex_format(Ref<FileAccess> f, const Ref<Image> &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality) { switch (p_compress_mode) { case COMPRESS_LOSSLESS: { bool lossless_force_png = ProjectSettings::get_singleton()->get("rendering/textures/lossless_compression/force_png") || !Image::_webp_mem_loader_func; // WebP module disabled. bool use_webp = !lossless_force_png && p_image->get_width() <= 16383 && p_image->get_height() <= 16383; // WebP has a size limit - f->store_32(use_webp ? StreamTexture2D::DATA_FORMAT_WEBP : StreamTexture2D::DATA_FORMAT_PNG); + f->store_32(use_webp ? CompressedTexture2D::DATA_FORMAT_WEBP : CompressedTexture2D::DATA_FORMAT_PNG); f->store_16(p_image->get_width()); f->store_16(p_image->get_height()); f->store_32(p_image->get_mipmap_count()); @@ -243,7 +257,7 @@ void ResourceImporterTexture::save_to_stex_format(FileAccess *f, const Ref<Image } break; case COMPRESS_LOSSY: { - f->store_32(StreamTexture2D::DATA_FORMAT_WEBP); + f->store_32(CompressedTexture2D::DATA_FORMAT_WEBP); f->store_16(p_image->get_width()); f->store_16(p_image->get_height()); f->store_32(p_image->get_mipmap_count()); @@ -263,7 +277,7 @@ void ResourceImporterTexture::save_to_stex_format(FileAccess *f, const Ref<Image image->compress_from_channels(p_compress_format, p_channels, p_lossy_quality); - f->store_32(StreamTexture2D::DATA_FORMAT_IMAGE); + f->store_32(CompressedTexture2D::DATA_FORMAT_IMAGE); f->store_16(image->get_width()); f->store_16(image->get_height()); f->store_32(image->get_mipmap_count()); @@ -275,7 +289,7 @@ void ResourceImporterTexture::save_to_stex_format(FileAccess *f, const Ref<Image f->store_buffer(r, dl); } break; case COMPRESS_VRAM_UNCOMPRESSED: { - f->store_32(StreamTexture2D::DATA_FORMAT_IMAGE); + f->store_32(CompressedTexture2D::DATA_FORMAT_IMAGE); f->store_16(p_image->get_width()); f->store_16(p_image->get_height()); f->store_32(p_image->get_mipmap_count()); @@ -289,7 +303,7 @@ void ResourceImporterTexture::save_to_stex_format(FileAccess *f, const Ref<Image } break; case COMPRESS_BASIS_UNIVERSAL: { - f->store_32(StreamTexture2D::DATA_FORMAT_BASIS_UNIVERSAL); + f->store_32(CompressedTexture2D::DATA_FORMAT_BASIS_UNIVERSAL); f->store_16(p_image->get_width()); f->store_16(p_image->get_height()); f->store_32(p_image->get_mipmap_count()); @@ -307,35 +321,35 @@ void ResourceImporterTexture::save_to_stex_format(FileAccess *f, const Ref<Image } } -void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String &p_to_path, CompressMode p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, bool p_streamable, bool p_detect_3d, bool p_detect_roughness, bool p_detect_normal, bool p_force_normal, bool p_srgb_friendly, bool p_force_po2_for_compressed, uint32_t p_limit_mipmap, const Ref<Image> &p_normal, Image::RoughnessChannel p_roughness_channel) { - FileAccess *f = FileAccess::open(p_to_path, FileAccess::WRITE); - ERR_FAIL_NULL(f); +void ResourceImporterTexture::_save_ctex(const Ref<Image> &p_image, const String &p_to_path, CompressMode p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, bool p_streamable, bool p_detect_3d, bool p_detect_roughness, bool p_detect_normal, bool p_force_normal, bool p_srgb_friendly, bool p_force_po2_for_compressed, uint32_t p_limit_mipmap, const Ref<Image> &p_normal, Image::RoughnessChannel p_roughness_channel) { + Ref<FileAccess> f = FileAccess::open(p_to_path, FileAccess::WRITE); + ERR_FAIL_COND(f.is_null()); f->store_8('G'); f->store_8('S'); f->store_8('T'); f->store_8('2'); //godot streamable texture 2D //format version - f->store_32(StreamTexture2D::FORMAT_VERSION); + f->store_32(CompressedTexture2D::FORMAT_VERSION); //texture may be resized later, so original size must be saved first f->store_32(p_image->get_width()); f->store_32(p_image->get_height()); uint32_t flags = 0; if (p_streamable) { - flags |= StreamTexture2D::FORMAT_BIT_STREAM; + flags |= CompressedTexture2D::FORMAT_BIT_STREAM; } if (p_mipmaps) { - flags |= StreamTexture2D::FORMAT_BIT_HAS_MIPMAPS; //mipmaps bit + flags |= CompressedTexture2D::FORMAT_BIT_HAS_MIPMAPS; //mipmaps bit } if (p_detect_3d) { - flags |= StreamTexture2D::FORMAT_BIT_DETECT_3D; + flags |= CompressedTexture2D::FORMAT_BIT_DETECT_3D; } if (p_detect_roughness) { - flags |= StreamTexture2D::FORMAT_BIT_DETECT_ROUGNESS; + flags |= CompressedTexture2D::FORMAT_BIT_DETECT_ROUGNESS; } if (p_detect_normal) { - flags |= StreamTexture2D::FORMAT_BIT_DETECT_NORMAL; + flags |= CompressedTexture2D::FORMAT_BIT_DETECT_NORMAL; } f->store_32(flags); @@ -384,29 +398,31 @@ void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String Image::UsedChannels used_channels = image->detect_used_channels(csource); - save_to_stex_format(f, image, p_compress_mode, used_channels, p_vram_compression, p_lossy_quality); - - memdelete(f); + save_to_ctex_format(f, image, p_compress_mode, used_channels, p_vram_compression, p_lossy_quality); } Error ResourceImporterTexture::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { CompressMode compress_mode = CompressMode(int(p_options["compress/mode"])); - float lossy = p_options["compress/lossy_quality"]; - int pack_channels = p_options["compress/channel_pack"]; - bool mipmaps = p_options["mipmaps/generate"]; - uint32_t mipmap_limit = mipmaps ? uint32_t(p_options["mipmaps/limit"]) : uint32_t(-1); - bool fix_alpha_border = p_options["process/fix_alpha_border"]; - bool premult_alpha = p_options["process/premult_alpha"]; - bool normal_map_invert_y = p_options["process/normal_map_invert_y"]; - bool stream = p_options["compress/streamed"]; - int size_limit = p_options["process/size_limit"]; - bool hdr_as_srgb = p_options["process/HDR_as_SRGB"]; - int normal = p_options["compress/normal_map"]; - float scale = p_options["svg/scale"]; - int hdr_compression = p_options["compress/hdr_compression"]; - int bptc_ldr = p_options["compress/bptc_ldr"]; - int roughness = p_options["roughness/mode"]; - String normal_map = p_options["roughness/src_normal"]; + const float lossy = p_options["compress/lossy_quality"]; + const int pack_channels = p_options["compress/channel_pack"]; + const bool mipmaps = p_options["mipmaps/generate"]; + const uint32_t mipmap_limit = mipmaps ? uint32_t(p_options["mipmaps/limit"]) : uint32_t(-1); + const bool fix_alpha_border = p_options["process/fix_alpha_border"]; + const bool premult_alpha = p_options["process/premult_alpha"]; + const bool normal_map_invert_y = p_options["process/normal_map_invert_y"]; + // Support for texture streaming is not implemented yet. + const bool stream = false; + const int size_limit = p_options["process/size_limit"]; + const bool hdr_as_srgb = p_options["process/hdr_as_srgb"]; + const int normal = p_options["compress/normal_map"]; + const int hdr_compression = p_options["compress/hdr_compression"]; + const int bptc_ldr = p_options["compress/bptc_ldr"]; + const int roughness = p_options["roughness/mode"]; + const String normal_map = p_options["roughness/src_normal"]; + float scale = 1.0; + if (p_options.has("svg/scale")) { + scale = p_options["svg/scale"]; + } Ref<Image> normal_image; Image::RoughnessChannel roughness_channel = Image::ROUGHNESS_CHANNEL_R; @@ -484,11 +500,10 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String //must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc). //Android, GLES 2.x - bool ok_on_pc = false; - bool is_hdr = (image->get_format() >= Image::FORMAT_RF && image->get_format() <= Image::FORMAT_RGBE9995); + const bool is_hdr = (image->get_format() >= Image::FORMAT_RF && image->get_format() <= Image::FORMAT_RGBE9995); bool is_ldr = (image->get_format() >= Image::FORMAT_L8 && image->get_format() <= Image::FORMAT_RGB565); - bool can_bptc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_bptc"); - bool can_s3tc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_s3tc"); + const bool can_bptc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_bptc"); + const bool can_s3tc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_s3tc"); if (can_bptc) { //add to the list anyway @@ -513,55 +528,44 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String } } - if (can_compress_hdr) { - if (!can_bptc) { - //fallback to RGBE99995 - if (image->get_format() != Image::FORMAT_RGBE9995) { - image->convert(Image::FORMAT_RGBE9995); - } + if (!can_compress_hdr) { + //fallback to RGBE99995 + if (image->get_format() != Image::FORMAT_RGBE9995) { + image->convert(Image::FORMAT_RGBE9995); } - } else { - can_bptc = false; - } - } - - if (is_ldr && can_bptc) { - if (bptc_ldr == 0 || (bptc_ldr == 1 && !has_alpha)) { - can_bptc = false; } } + bool ok_on_pc = false; if (can_bptc || can_s3tc) { - _save_stex(image, p_save_path + ".s3tc.stex", compress_mode, lossy, can_bptc ? Image::COMPRESS_BPTC : Image::COMPRESS_S3TC, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel); + ok_on_pc = true; + Image::CompressMode image_compress_mode = Image::COMPRESS_BPTC; + if (!bptc_ldr && can_s3tc && is_ldr) { + image_compress_mode = Image::COMPRESS_S3TC; + } + _save_ctex(image, p_save_path + ".s3tc.ctex", compress_mode, lossy, image_compress_mode, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel); r_platform_variants->push_back("s3tc"); formats_imported.push_back("s3tc"); - ok_on_pc = true; } if (ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc2")) { - _save_stex(image, p_save_path + ".etc2.stex", compress_mode, lossy, Image::COMPRESS_ETC2, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel); + _save_ctex(image, p_save_path + ".etc2.ctex", compress_mode, lossy, Image::COMPRESS_ETC2, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel); r_platform_variants->push_back("etc2"); formats_imported.push_back("etc2"); } if (ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc")) { - _save_stex(image, p_save_path + ".etc.stex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel); + _save_ctex(image, p_save_path + ".etc.ctex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel); r_platform_variants->push_back("etc"); formats_imported.push_back("etc"); } - if (ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_pvrtc")) { - _save_stex(image, p_save_path + ".pvrtc.stex", compress_mode, lossy, Image::COMPRESS_PVRTC1_4, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel); - r_platform_variants->push_back("pvrtc"); - formats_imported.push_back("pvrtc"); - } - if (!ok_on_pc) { - EditorNode::add_io_error("Warning, no suitable PC VRAM compression enabled in Project Settings. This texture will not display correctly on PC."); + EditorNode::add_io_error(TTR("Warning, no suitable PC VRAM compression enabled in Project Settings. This texture will not display correctly on PC.")); } } else { //import normally - _save_stex(image, p_save_path + ".stex", compress_mode, lossy, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel); + _save_ctex(image, p_save_path + ".ctex", compress_mode, lossy, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel); } if (r_metadata) { @@ -580,7 +584,6 @@ const char *ResourceImporterTexture::compression_formats[] = { "s3tc", "etc", "etc2", - "pvrtc", nullptr }; String ResourceImporterTexture::get_import_settings_string() const { @@ -623,7 +626,7 @@ bool ResourceImporterTexture::are_import_settings_valid(const String &p_path) co String setting_path = "rendering/textures/vram_compression/import_" + String(compression_formats[index]); bool test = ProjectSettings::get_singleton()->get(setting_path); if (test) { - if (formats_imported.find(compression_formats[index]) == -1) { + if (!formats_imported.has(compression_formats[index])) { valid = false; break; } @@ -638,9 +641,9 @@ ResourceImporterTexture *ResourceImporterTexture::singleton = nullptr; ResourceImporterTexture::ResourceImporterTexture() { singleton = this; - StreamTexture2D::request_3d_callback = _texture_reimport_3d; - StreamTexture2D::request_roughness_callback = _texture_reimport_roughness; - StreamTexture2D::request_normal_callback = _texture_reimport_normal; + CompressedTexture2D::request_3d_callback = _texture_reimport_3d; + CompressedTexture2D::request_roughness_callback = _texture_reimport_roughness; + CompressedTexture2D::request_normal_callback = _texture_reimport_normal; } ResourceImporterTexture::~ResourceImporterTexture() { diff --git a/editor/import/resource_importer_texture.h b/editor/import/resource_importer_texture.h index cb9d1b08cd..b932c598a2 100644 --- a/editor/import/resource_importer_texture.h +++ b/editor/import/resource_importer_texture.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -37,7 +37,7 @@ #include "scene/resources/texture.h" #include "servers/rendering_server.h" -class StreamTexture2D; +class CompressedTexture2D; class ResourceImporterTexture : public ResourceImporter { GDCLASS(ResourceImporterTexture, ResourceImporter); @@ -67,17 +67,17 @@ protected: Map<StringName, MakeInfo> make_flags; - static void _texture_reimport_roughness(const Ref<StreamTexture2D> &p_tex, const String &p_normal_path, RenderingServer::TextureDetectRoughnessChannel p_channel); - static void _texture_reimport_3d(const Ref<StreamTexture2D> &p_tex); - static void _texture_reimport_normal(const Ref<StreamTexture2D> &p_tex); + static void _texture_reimport_roughness(const Ref<CompressedTexture2D> &p_tex, const String &p_normal_path, RenderingServer::TextureDetectRoughnessChannel p_channel); + static void _texture_reimport_3d(const Ref<CompressedTexture2D> &p_tex); + static void _texture_reimport_normal(const Ref<CompressedTexture2D> &p_tex); static ResourceImporterTexture *singleton; static const char *compression_formats[]; - void _save_stex(const Ref<Image> &p_image, const String &p_to_path, CompressMode p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_detect_normal, bool p_force_normal, bool p_srgb_friendly, bool p_force_po2_for_compressed, uint32_t p_limit_mipmap, const Ref<Image> &p_normal, Image::RoughnessChannel p_roughness_channel); + void _save_ctex(const Ref<Image> &p_image, const String &p_to_path, CompressMode p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_detect_normal, bool p_force_normal, bool p_srgb_friendly, bool p_force_po2_for_compressed, uint32_t p_limit_mipmap, const Ref<Image> &p_normal, Image::RoughnessChannel p_roughness_channel); public: - static void save_to_stex_format(FileAccess *f, const Ref<Image> &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality); + static void save_to_ctex_format(Ref<FileAccess> f, const Ref<Image> &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality); static ResourceImporterTexture *get_singleton() { return singleton; } virtual String get_importer_name() const override; diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp index 048d84d1f9..cd481e009e 100644 --- a/editor/import/resource_importer_texture_atlas.cpp +++ b/editor/import/resource_importer_texture_atlas.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -75,6 +75,7 @@ void ResourceImporterTextureAtlas::get_import_options(const String &p_path, List r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "atlas_file", PROPERTY_HINT_SAVE_FILE, "*.png"), "")); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_mode", PROPERTY_HINT_ENUM, "Region,Mesh2D"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "crop_to_region"), false)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "trim_alpha_border_from_region"), true)); } String ResourceImporterTextureAtlas::get_option_group_file() const { @@ -210,14 +211,18 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file pack_data.is_cropped = options["crop_to_region"]; int mode = options["import_mode"]; + bool trim_alpha_border_from_region = options["trim_alpha_border_from_region"]; if (mode == IMPORT_MODE_REGION) { pack_data.is_mesh = false; EditorAtlasPacker::Chart chart; - //clip a region from the image - Rect2 used_rect = image->get_used_rect(); + Rect2 used_rect = Rect2(Vector2(), image->get_size()); + if (trim_alpha_border_from_region) { + // Clip a region from the image. + used_rect = image->get_used_rect(); + } pack_data.region = used_rect; chart.vertices.push_back(used_rect.position); diff --git a/editor/import/resource_importer_texture_atlas.h b/editor/import/resource_importer_texture_atlas.h index 177ef949ac..a5e47dee99 100644 --- a/editor/import/resource_importer_texture_atlas.h +++ b/editor/import/resource_importer_texture_atlas.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp index 820eba951f..154970f7ed 100644 --- a/editor/import/resource_importer_wav.cpp +++ b/editor/import/resource_importer_wav.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -63,6 +63,11 @@ bool ResourceImporterWAV::get_option_visibility(const String &p_path, const Stri return false; } + // Don't show begin/end loop points if loop mode is auto-detected or disabled. + if ((int)p_options["edit/loop_mode"] < 2 && (p_option == "edit/loop_begin" || p_option == "edit/loop_end")) { + return false; + } + return true; } @@ -81,7 +86,10 @@ void ResourceImporterWAV::get_import_options(const String &p_path, List<ImportOp r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "force/max_rate_hz", PROPERTY_HINT_RANGE, "11025,192000,1,exp"), 44100)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/trim"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/normalize"), false)); - r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/loop"), false)); + // Keep the `edit/loop_mode` enum in sync with AudioStreamSample::LoopMode (note: +1 offset due to "Detect From WAV"). + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "edit/loop_mode", PROPERTY_HINT_ENUM, "Detect From WAV,Disabled,Forward,Ping-Pong,Backward", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "edit/loop_begin"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "edit/loop_end"), -1)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Disabled,RAM (Ima-ADPCM)"), 0)); } @@ -89,7 +97,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s /* STEP 1, READ WAVE FILE */ Error err; - FileAccess *file = FileAccess::open(p_source_file, FileAccess::READ, &err); + Ref<FileAccess> file = FileAccess::open(p_source_file, FileAccess::READ, &err); ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_OPEN, "Cannot open file '" + p_source_file + "'."); @@ -99,8 +107,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s file->get_buffer((uint8_t *)&riff, 4); //RIFF if (riff[0] != 'R' || riff[1] != 'I' || riff[2] != 'F' || riff[3] != 'F') { - file->close(); - memdelete(file); ERR_FAIL_V(ERR_FILE_UNRECOGNIZED); } @@ -114,15 +120,17 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s file->get_buffer((uint8_t *)&wave, 4); //RIFF if (wave[0] != 'W' || wave[1] != 'A' || wave[2] != 'V' || wave[3] != 'E') { - file->close(); - memdelete(file); ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Not a WAV file (no WAVE RIFF header)."); } + // Let users override potential loop points from the WAV. + // We parse the WAV loop points only with "Detect From WAV" (0). + int import_loop_mode = p_options["edit/loop_mode"]; + int format_bits = 0; int format_channels = 0; - AudioStreamSample::LoopMode loop = AudioStreamSample::LOOP_DISABLED; + AudioStreamSample::LoopMode loop_mode = AudioStreamSample::LOOP_DISABLED; uint16_t compression_code = 1; bool format_found = false; bool data_found = false; @@ -154,15 +162,11 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s //Consider revision for engine version 3.0 compression_code = file->get_16(); if (compression_code != 1 && compression_code != 3) { - file->close(); - memdelete(file); ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Format not supported for WAVE file (not PCM). Save WAVE files as uncompressed PCM instead."); } format_channels = file->get_16(); if (format_channels != 1 && format_channels != 2) { - file->close(); - memdelete(file); ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Format not supported for WAVE file (not stereo or mono)."); } @@ -173,8 +177,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s format_bits = file->get_16(); // bits per sample if (format_bits % 8 || format_bits == 0) { - file->close(); - memdelete(file); ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Invalid amount of bits in the sample (should be one of 8, 16, 24 or 32)."); } @@ -194,8 +196,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s frames = chunksize; if (format_channels == 0) { - file->close(); - memdelete(file); ERR_FAIL_COND_V(format_channels == 0, ERR_INVALID_DATA); } frames /= format_channels; @@ -242,14 +242,12 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s } if (file->eof_reached()) { - file->close(); - memdelete(file); ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Premature end of file."); } } - if (chunkID[0] == 's' && chunkID[1] == 'm' && chunkID[2] == 'p' && chunkID[3] == 'l') { - //loop point info! + if (import_loop_mode == 0 && chunkID[0] == 's' && chunkID[1] == 'm' && chunkID[2] == 'p' && chunkID[3] == 'l') { + // Loop point info! /** * Consider exploring next document: @@ -270,11 +268,11 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s int loop_type = file->get_32(); if (loop_type == 0x00 || loop_type == 0x01 || loop_type == 0x02) { if (loop_type == 0x00) { - loop = AudioStreamSample::LOOP_FORWARD; + loop_mode = AudioStreamSample::LOOP_FORWARD; } else if (loop_type == 0x01) { - loop = AudioStreamSample::LOOP_PINGPONG; + loop_mode = AudioStreamSample::LOOP_PINGPONG; } else if (loop_type == 0x02) { - loop = AudioStreamSample::LOOP_BACKWARD; + loop_mode = AudioStreamSample::LOOP_BACKWARD; } loop_begin = file->get_32(); loop_end = file->get_32(); @@ -283,9 +281,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s file->seek(file_pos + chunksize); } - file->close(); - memdelete(file); - // STEP 2, APPLY CONVERSIONS bool is16 = format_bits != 8; @@ -346,7 +341,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s } } - if (loop) { + if (loop_mode) { loop_begin = (int)(loop_begin * (float)new_data_frames / (float)frames); loop_end = (int)(loop_end * (float)new_data_frames / (float)frames); } @@ -377,7 +372,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s bool trim = p_options["edit/trim"]; - if (trim && !loop && format_channels > 0) { + if (trim && (loop_mode != AudioStreamSample::LOOP_DISABLED) && format_channels > 0) { int first = 0; int last = (frames / format_channels) - 1; bool found = false; @@ -421,12 +416,17 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s } } - bool make_loop = p_options["edit/loop"]; - - if (make_loop && !loop) { - loop = AudioStreamSample::LOOP_FORWARD; - loop_begin = 0; - loop_end = frames; + if (import_loop_mode >= 2) { + loop_mode = (AudioStreamSample::LoopMode)(import_loop_mode - 1); + loop_begin = p_options["edit/loop_begin"]; + loop_end = p_options["edit/loop_end"]; + // Wrap around to max frames, so `-1` can be used to select the end, etc. + if (loop_begin < 0) { + loop_begin = CLAMP(loop_begin + frames + 1, 0, frames); + } + if (loop_end < 0) { + loop_end = CLAMP(loop_end + frames + 1, 0, frames); + } } int compression = p_options["compress/mode"]; @@ -512,7 +512,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s sample->set_data(dst_data); sample->set_format(dst_format); sample->set_mix_rate(rate); - sample->set_loop_mode(loop); + sample->set_loop_mode(loop_mode); sample->set_loop_begin(loop_begin); sample->set_loop_end(loop_end); sample->set_stereo(format_channels == 2); diff --git a/editor/import/resource_importer_wav.h b/editor/import/resource_importer_wav.h index e3e605aeb2..2316ce80e5 100644 --- a/editor/import/resource_importer_wav.h +++ b/editor/import/resource_importer_wav.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RESOURCEIMPORTWAV_H -#define RESOURCEIMPORTWAV_H +#ifndef RESOURCE_IMPORTER_WAV_H +#define RESOURCE_IMPORTER_WAV_H #include "core/io/resource_importer.h" @@ -50,9 +50,6 @@ public: virtual bool get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) const override; static void _compress_ima_adpcm(const Vector<float> &p_data, Vector<uint8_t> &dst_data) { - /*p_sample_data->data = (void*)malloc(len); - xm_s8 *dataptr=(xm_s8*)p_sample_data->data;*/ - static const int16_t _ima_adpcm_step_table[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, @@ -81,15 +78,14 @@ public: int i, step_idx = 0, prev = 0; uint8_t *out = w; - //int16_t xm_prev=0; const float *in = p_data.ptr(); - /* initial value is zero */ + // Initial value is zero. *(out++) = 0; *(out++) = 0; - /* Table index initial value */ + // Table index initial value. *(out++) = 0; - /* unused */ + // Unused. *(out++) = 0; for (i = 0; i < datalen; i++) { @@ -101,15 +97,8 @@ public: xm_sample = 0; } else { xm_sample = CLAMP(in[i] * 32767.0, -32768, 32767); - /* - if (xm_sample==32767 || xm_sample==-32768) - printf("clippy!\n",xm_sample); - */ } - //xm_sample=xm_sample+xm_prev; - //xm_prev=xm_sample; - diff = (int)xm_sample - prev; nibble = 0; @@ -129,7 +118,7 @@ public: step >>= 1; mask >>= 1; - }; + } if (nibble & 8) { prev -= vpdiff; @@ -137,20 +126,10 @@ public: prev += vpdiff; } - if (prev > 32767) { - //printf("%i,xms %i, prev %i,diff %i, vpdiff %i, clip up %i\n",i,xm_sample,prev,diff,vpdiff,prev); - prev = 32767; - } else if (prev < -32768) { - //printf("%i,xms %i, prev %i,diff %i, vpdiff %i, clip down %i\n",i,xm_sample,prev,diff,vpdiff,prev); - prev = -32768; - } + prev = CLAMP(prev, -32768, 32767); step_idx += _ima_adpcm_index_table[nibble]; - if (step_idx < 0) { - step_idx = 0; - } else if (step_idx > 88) { - step_idx = 88; - } + step_idx = CLAMP(step_idx, 0, 88); if (i & 1) { *out |= nibble << 4; @@ -158,7 +137,6 @@ public: } else { *out = nibble; } - /*dataptr[i]=prev>>8;*/ } } @@ -167,4 +145,4 @@ public: ResourceImporterWAV(); }; -#endif // RESOURCEIMPORTWAV_H +#endif // RESOURCE_IMPORTER_WAV_H diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp index 5690d49a55..4e53a644ee 100644 --- a/editor/import/scene_import_settings.cpp +++ b/editor/import/scene_import_settings.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,9 +29,14 @@ /*************************************************************************/ #include "scene_import_settings.h" + +#include "editor/editor_file_dialog.h" +#include "editor/editor_file_system.h" +#include "editor/editor_inspector.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "scene/3d/importer_mesh_instance_3d.h" +#include "scene/animation/animation_player.h" #include "scene/resources/importer_mesh.h" #include "scene/resources/surface_tool.h" @@ -42,6 +47,8 @@ class SceneImportSettingsData : public Object { Map<StringName, Variant> current; Map<StringName, Variant> defaults; List<ResourceImporter::ImportOption> options; + bool hide_options = false; + String path; ResourceImporterScene::InternalImportCategory category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX; @@ -55,8 +62,26 @@ class SceneImportSettingsData : public Object { current[p_name] = p_value; - if (ResourceImporterScene::get_singleton()->get_internal_option_update_view_required(category, p_name, current)) { - SceneImportSettings::get_singleton()->update_view(); + if (SceneImportSettings::get_singleton()->is_editing_animation()) { + if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) { + if (ResourceImporterScene::get_animation_singleton()->get_option_visibility(path, p_name, current)) { + SceneImportSettings::get_singleton()->update_view(); + } + } else { + if (ResourceImporterScene::get_animation_singleton()->get_internal_option_update_view_required(category, p_name, current)) { + SceneImportSettings::get_singleton()->update_view(); + } + } + } else { + if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) { + if (ResourceImporterScene::get_scene_singleton()->get_option_visibility(path, p_name, current)) { + SceneImportSettings::get_singleton()->update_view(); + } + } else { + if (ResourceImporterScene::get_scene_singleton()->get_internal_option_update_view_required(category, p_name, current)) { + SceneImportSettings::get_singleton()->update_view(); + } + } } return true; @@ -77,9 +102,30 @@ class SceneImportSettingsData : public Object { return false; } void _get_property_list(List<PropertyInfo> *p_list) const { + if (hide_options) { + return; + } for (const ResourceImporter::ImportOption &E : options) { - if (ResourceImporterScene::get_singleton()->get_internal_option_visibility(category, E.option.name, current)) { - p_list->push_back(E.option); + if (SceneImportSettings::get_singleton()->is_editing_animation()) { + if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) { + if (ResourceImporterScene::get_animation_singleton()->get_option_visibility(path, E.option.name, current)) { + p_list->push_back(E.option); + } + } else { + if (ResourceImporterScene::get_animation_singleton()->get_internal_option_visibility(category, E.option.name, current)) { + p_list->push_back(E.option); + } + } + } else { + if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) { + if (ResourceImporterScene::get_scene_singleton()->get_option_visibility(path, E.option.name, current)) { + p_list->push_back(E.option); + } + } else { + if (ResourceImporterScene::get_scene_singleton()->get_internal_option_visibility(category, E.option.name, current)) { + p_list->push_back(E.option); + } + } } } } @@ -92,7 +138,7 @@ void SceneImportSettings::_fill_material(Tree *p_tree, const Ref<Material> &p_ma if (p_material->has_meta("import_id")) { import_id = p_material->get_meta("import_id"); has_import_id = true; - } else if (p_material->get_name() != "") { + } else if (!p_material->get_name().is_empty()) { import_id = p_material->get_name(); has_import_id = true; } else { @@ -148,7 +194,7 @@ void SceneImportSettings::_fill_mesh(Tree *p_tree, const Ref<Mesh> &p_mesh, Tree if (p_mesh->has_meta("import_id")) { import_id = p_mesh->get_meta("import_id"); has_import_id = true; - } else if (p_mesh->get_name() != String()) { + } else if (!p_mesh->get_name().is_empty()) { import_id = p_mesh->get_name(); has_import_id = true; } else { @@ -321,7 +367,9 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) { } MeshInstance3D *mesh_node = Object::cast_to<MeshInstance3D>(p_node); if (mesh_node && mesh_node->get_mesh().is_valid()) { - _fill_mesh(scene_tree, mesh_node->get_mesh(), item); + if (!editing_animation) { + _fill_mesh(scene_tree, mesh_node->get_mesh(), item); + } // Add the collider view. MeshInstance3D *collider_view = memnew(MeshInstance3D); @@ -360,6 +408,9 @@ void SceneImportSettings::_update_scene() { } void SceneImportSettings::_update_view_gizmos() { + if (!is_visible()) { + return; + } for (const KeyValue<String, NodeData> &e : node_map) { bool generate_collider = false; if (e.value.settings.has(SNAME("generate/physics"))) { @@ -372,9 +423,11 @@ void SceneImportSettings::_update_view_gizmos() { continue; } - MeshInstance3D *collider_view = static_cast<MeshInstance3D *>(mesh_node->find_node("collider_view")); - CRASH_COND_MSG(collider_view == nullptr, "This is unreachable, since the collider view is always created even when the collision is not used! If this is triggered there is a bug on the function `_fill_scene`."); + TypedArray<Node> descendants = mesh_node->find_nodes("collider_view", "MeshInstance3D"); + + CRASH_COND_MSG(descendants.is_empty(), "This is unreachable, since the collider view is always created even when the collision is not used! If this is triggered there is a bug on the function `_fill_scene`."); + MeshInstance3D *collider_view = static_cast<MeshInstance3D *>(descendants[0].operator Object *()); collider_view->set_visible(generate_collider); if (generate_collider) { // This collider_view doesn't have a mesh so we need to generate a new one. @@ -414,7 +467,7 @@ void SceneImportSettings::_update_camera() { float rot_y = cam_rot_y; float zoom = cam_zoom; - if (selected_type == "Node" || selected_type == "") { + if (selected_type == "Node" || selected_type.is_empty()) { camera_aabb = contents_aabb; } else { if (mesh_preview->get_mesh().is_valid()) { @@ -441,7 +494,7 @@ void SceneImportSettings::_update_camera() { camera->set_orthogonal(camera_size * zoom, 0.0001, camera_size * 2); Transform3D xf; - xf.basis = Basis(Vector3(0, 1, 0), rot_y) * Basis(Vector3(1, 0, 0), rot_x); + xf.basis = Basis(Vector3(1, 0, 0), rot_x) * Basis(Vector3(0, 1, 0), rot_y); xf.origin = center; xf.translate(0, 0, camera_size); @@ -454,7 +507,11 @@ void SceneImportSettings::_load_default_subresource_settings(Map<StringName, Var if (d.has(p_import_id)) { d = d[p_import_id]; List<ResourceImporterScene::ImportOption> options; - ResourceImporterScene::get_singleton()->get_internal_import_options(p_category, &options); + if (editing_animation) { + ResourceImporterScene::get_animation_singleton()->get_internal_import_options(p_category, &options); + } else { + ResourceImporterScene::get_scene_singleton()->get_internal_import_options(p_category, &options); + } for (const ResourceImporterScene::ImportOption &E : options) { String key = E.option.name; if (d.has(key)) { @@ -466,21 +523,32 @@ void SceneImportSettings::_load_default_subresource_settings(Map<StringName, Var } void SceneImportSettings::update_view() { - _update_view_gizmos(); + update_view_timer->start(); } -void SceneImportSettings::open_settings(const String &p_path) { +void SceneImportSettings::open_settings(const String &p_path, bool p_for_animation) { if (scene) { memdelete(scene); scene = nullptr; } + + editing_animation = p_for_animation; scene_import_settings_data->settings = nullptr; - scene = ResourceImporterScene::get_singleton()->pre_import(p_path); + scene_import_settings_data->path = p_path; + + scene = ResourceImporterScene::get_scene_singleton()->pre_import(p_path); // Use the scene singleton here because we want to see the full thing. if (scene == nullptr) { EditorNode::get_singleton()->show_warning(TTR("Error opening scene")); return; } + // Visibility + data_mode->set_tab_hidden(1, p_for_animation); + data_mode->set_tab_hidden(2, p_for_animation); + + action_menu->get_popup()->set_item_disabled(action_menu->get_popup()->get_item_id(ACTION_EXTRACT_MATERIALS), p_for_animation); + action_menu->get_popup()->set_item_disabled(action_menu->get_popup()->get_item_id(ACTION_CHOOSE_MESH_SAVE_PATHS), p_for_animation); + base_path = p_path; material_set.clear(); @@ -523,6 +591,8 @@ void SceneImportSettings::open_settings(const String &p_path) { base_viewport->add_child(scene); + inspector->edit(nullptr); + if (first_aabb) { contents_aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2)); first_aabb = false; @@ -532,7 +602,11 @@ void SceneImportSettings::open_settings(const String &p_path) { _update_view_gizmos(); _update_camera(); - set_title(vformat(TTR("Advanced Import Settings for '%s'"), base_path.get_file())); + if (p_for_animation) { + set_title(vformat(TTR("Advanced Import Settings for AnimationLibrary '%s'"), base_path.get_file())); + } else { + set_title(vformat(TTR("Advanced Import Settings for Scene '%s'"), base_path.get_file())); + } } SceneImportSettings *SceneImportSettings::singleton = nullptr; @@ -543,6 +617,7 @@ SceneImportSettings *SceneImportSettings::get_singleton() { void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) { selecting = true; + scene_import_settings_data->hide_options = false; if (p_type == "Node") { node_selected->hide(); //always hide just in case @@ -577,10 +652,12 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) { scene_import_settings_data->settings = &nd.settings; if (mi) { scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE; + scene_import_settings_data->hide_options = editing_animation; } else if (Object::cast_to<AnimationPlayer>(nd.node)) { scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE; } else { scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE; + scene_import_settings_data->hide_options = editing_animation; } } } else if (p_type == "Animation") { @@ -663,24 +740,36 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) { List<ResourceImporter::ImportOption> options; - if (scene_import_settings_data->category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) { - ResourceImporterScene::get_singleton()->get_import_options(base_path, &options); + if (editing_animation) { + if (scene_import_settings_data->category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) { + ResourceImporterScene::get_animation_singleton()->get_import_options(base_path, &options); + } else { + ResourceImporterScene::get_animation_singleton()->get_internal_import_options(scene_import_settings_data->category, &options); + } + } else { - ResourceImporterScene::get_singleton()->get_internal_import_options(scene_import_settings_data->category, &options); + if (scene_import_settings_data->category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) { + ResourceImporterScene::get_scene_singleton()->get_import_options(base_path, &options); + } else { + ResourceImporterScene::get_scene_singleton()->get_internal_import_options(scene_import_settings_data->category, &options); + } } scene_import_settings_data->defaults.clear(); scene_import_settings_data->current.clear(); - for (const ResourceImporter::ImportOption &E : options) { - scene_import_settings_data->defaults[E.option.name] = E.default_value; - //needed for visibility toggling (fails if something is missing) - if (scene_import_settings_data->settings->has(E.option.name)) { - scene_import_settings_data->current[E.option.name] = (*scene_import_settings_data->settings)[E.option.name]; - } else { - scene_import_settings_data->current[E.option.name] = E.default_value; + if (scene_import_settings_data->settings) { + for (const ResourceImporter::ImportOption &E : options) { + scene_import_settings_data->defaults[E.option.name] = E.default_value; + //needed for visibility toggling (fails if something is missing) + if (scene_import_settings_data->settings->has(E.option.name)) { + scene_import_settings_data->current[E.option.name] = (*scene_import_settings_data->settings)[E.option.name]; + } else { + scene_import_settings_data->current[E.option.name] = E.default_value; + } } } + scene_import_settings_data->options = options; inspector->edit(scene_import_settings_data); scene_import_settings_data->notify_property_list_changed(); @@ -828,12 +917,18 @@ void SceneImportSettings::_re_import() { main_settings["_subresources"] = subresources; } - EditorFileSystem::get_singleton()->reimport_file_with_custom_parameters(base_path, "scene", main_settings); + EditorFileSystem::get_singleton()->reimport_file_with_custom_parameters(base_path, editing_animation ? "animation_library" : "scene", main_settings); } void SceneImportSettings::_notification(int p_what) { - if (p_what == NOTIFICATION_READY) { - connect("confirmed", callable_mp(this, &SceneImportSettings::_re_import)); + switch (p_what) { + case NOTIFICATION_READY: { + connect("confirmed", callable_mp(this, &SceneImportSettings::_re_import)); + } break; + + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + inspector->set_property_name_style(EditorPropertyNameProcessor::get_settings_style()); + } break; } } @@ -1221,6 +1316,7 @@ SceneImportSettings::SceneImportSettings() { inspector = memnew(EditorInspector); inspector->set_custom_minimum_size(Size2(300 * EDSCALE, 0)); + inspector->set_property_name_style(EditorPropertyNameProcessor::get_settings_style()); property_split->add_child(inspector); @@ -1261,12 +1357,17 @@ SceneImportSettings::SceneImportSettings() { item_save_path = memnew(EditorFileDialog); item_save_path->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); - item_save_path->add_filter("*.tres;Text Resource"); - item_save_path->add_filter("*.res;Binary Resource"); + item_save_path->add_filter("*.tres; " + TTR("Text Resource")); + item_save_path->add_filter("*.res; " + TTR("Binary Resource")); add_child(item_save_path); item_save_path->connect("file_selected", callable_mp(this, &SceneImportSettings::_save_path_changed)); save_path->connect("dir_selected", callable_mp(this, &SceneImportSettings::_save_dir_callback)); + + update_view_timer = memnew(Timer); + update_view_timer->set_wait_time(0.2); + update_view_timer->connect("timeout", callable_mp(this, &SceneImportSettings::_update_view_gizmos)); + add_child(update_view_timer); } SceneImportSettings::~SceneImportSettings() { diff --git a/editor/import/scene_import_settings.h b/editor/import/scene_import_settings.h index c7c94af493..55cfba3275 100644 --- a/editor/import/scene_import_settings.h +++ b/editor/import/scene_import_settings.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,8 +31,6 @@ #ifndef SCENEIMPORTSETTINGS_H #define SCENEIMPORTSETTINGS_H -#include "editor/editor_file_dialog.h" -#include "editor/editor_inspector.h" #include "editor/import/resource_importer_scene.h" #include "scene/3d/camera_3d.h" #include "scene/3d/light_3d.h" @@ -47,6 +45,8 @@ #include "scene/gui/tree.h" #include "scene/resources/primitive_meshes.h" +class EditorFileDialog; +class EditorInspector; class SceneImportSettingsData; class SceneImportSettings : public ConfirmationDialog { @@ -62,26 +62,26 @@ class SceneImportSettings : public ConfirmationDialog { Node *scene = nullptr; - HSplitContainer *tree_split; - HSplitContainer *property_split; - TabContainer *data_mode; - Tree *scene_tree; - Tree *mesh_tree; - Tree *material_tree; + HSplitContainer *tree_split = nullptr; + HSplitContainer *property_split = nullptr; + TabContainer *data_mode = nullptr; + Tree *scene_tree = nullptr; + Tree *mesh_tree = nullptr; + Tree *material_tree = nullptr; - EditorInspector *inspector; + EditorInspector *inspector = nullptr; - SubViewport *base_viewport; + SubViewport *base_viewport = nullptr; - Camera3D *camera; + Camera3D *camera = nullptr; bool first_aabb = false; AABB contents_aabb; - DirectionalLight3D *light; + DirectionalLight3D *light = nullptr; Ref<ArrayMesh> selection_mesh; - MeshInstance3D *node_selected; + MeshInstance3D *node_selected = nullptr; - MeshInstance3D *mesh_preview; + MeshInstance3D *mesh_preview = nullptr; Ref<SphereMesh> material_preview; Ref<StandardMaterial3D> collider_mat; @@ -95,9 +95,9 @@ class SceneImportSettings : public ConfirmationDialog { struct MaterialData { bool has_import_id; Ref<Material> material; - TreeItem *scene_node; - TreeItem *mesh_node; - TreeItem *material_node; + TreeItem *scene_node = nullptr; + TreeItem *mesh_node = nullptr; + TreeItem *material_node = nullptr; float cam_rot_x = -Math_PI / 4; float cam_rot_y = -Math_PI / 4; @@ -110,8 +110,8 @@ class SceneImportSettings : public ConfirmationDialog { struct MeshData { bool has_import_id; Ref<Mesh> mesh; - TreeItem *scene_node; - TreeItem *mesh_node; + TreeItem *scene_node = nullptr; + TreeItem *mesh_node = nullptr; float cam_rot_x = -Math_PI / 4; float cam_rot_y = -Math_PI / 4; @@ -122,14 +122,14 @@ class SceneImportSettings : public ConfirmationDialog { struct AnimationData { Ref<Animation> animation; - TreeItem *scene_node; + TreeItem *scene_node = nullptr; Map<StringName, Variant> settings; }; Map<String, AnimationData> animation_map; struct NodeData { - Node *node; - TreeItem *scene_node; + Node *node = nullptr; + TreeItem *scene_node = nullptr; Map<StringName, Variant> settings; }; Map<String, NodeData> node_map; @@ -158,20 +158,20 @@ class SceneImportSettings : public ConfirmationDialog { Map<StringName, Variant> defaults; - SceneImportSettingsData *scene_import_settings_data; + SceneImportSettingsData *scene_import_settings_data = nullptr; void _re_import(); String base_path; - MenuButton *action_menu; + MenuButton *action_menu = nullptr; - ConfirmationDialog *external_paths; - Tree *external_path_tree; - EditorFileDialog *save_path; - OptionButton *external_extension_type; + ConfirmationDialog *external_paths = nullptr; + Tree *external_path_tree = nullptr; + EditorFileDialog *save_path = nullptr; + OptionButton *external_extension_type = nullptr; - EditorFileDialog *item_save_path; + EditorFileDialog *item_save_path = nullptr; void _menu_callback(int p_id); void _save_dir_callback(const String &p_path); @@ -189,12 +189,17 @@ class SceneImportSettings : public ConfirmationDialog { void _load_default_subresource_settings(Map<StringName, Variant> &settings, const String &p_type, const String &p_import_id, ResourceImporterScene::InternalImportCategory p_category); + bool editing_animation = false; + + Timer *update_view_timer; + protected: void _notification(int p_what); public: + bool is_editing_animation() const { return editing_animation; } void update_view(); - void open_settings(const String &p_path); + void open_settings(const String &p_path, bool p_for_animation = false); static SceneImportSettings *get_singleton(); SceneImportSettings(); ~SceneImportSettings(); |