/*************************************************************************/ /* editor_texture_import_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ /* Copyright (c) 2014-2018 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 */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "editor_texture_import_plugin.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "editor_atlas.h" #include "globals.h" #include "io/image_loader.h" #include "io/marshalls.h" #include "io/resource_saver.h" #include "scene/gui/button_group.h" #include "scene/gui/check_button.h" #include "scene/gui/margin_container.h" #include "scene/io/resource_format_image.h" #include "thirdparty/misc/md5.h" static const char *flag_names[] = { ("Streaming Format"), ("Fix Border Alpha"), ("Alpha Bit Hint"), ("Compress Extra (PVRTC2)"), ("No MipMaps"), ("Repeat"), ("Filter (Magnifying)"), ("Premultiply Alpha"), ("Convert SRGB->Linear"), ("Convert NormalMap to XY"), ("Use Anisotropy"), NULL }; #if 0 // not used static const char *flag_short_names[]={ "Stream", "FixBorder", "AlphBit", "ExtComp", "NoMipMap", "Repeat", "Filter", "PMAlpha", "ToLinear", "ToRG", "Anisoropic", NULL }; #endif void EditorImportTextureOptions::set_format(EditorTextureImportPlugin::ImageFormat p_format) { updating = true; format->select(p_format); if (p_format == EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSY) { quality_vb->show(); } else { quality_vb->hide(); } updating = false; } EditorTextureImportPlugin::ImageFormat EditorImportTextureOptions::get_format() const { return (EditorTextureImportPlugin::ImageFormat)format->get_selected(); } void EditorImportTextureOptions::set_flags(uint32_t p_flags) { updating = true; for (int i = 0; i < items.size(); i++) { items[i]->set_checked(0, p_flags & (1 << i)); } updating = false; } void EditorImportTextureOptions::set_quality(float p_quality) { quality->set_val(p_quality); } float EditorImportTextureOptions::get_quality() const { return quality->get_val(); } uint32_t EditorImportTextureOptions::get_flags() const { uint32_t f = 0; for (int i = 0; i < items.size(); i++) { if (items[i]->is_checked(0)) f |= (1 << i); } return f; } void EditorImportTextureOptions::_changedp(int p_value) { _changed(); } void EditorImportTextureOptions::_changed() { if (updating) return; if (format->get_selected() == EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSY) { quality_vb->show(); } else { quality_vb->hide(); } emit_signal("changed"); } void EditorImportTextureOptions::_bind_methods() { ObjectTypeDB::bind_method("_changed", &EditorImportTextureOptions::_changed); ObjectTypeDB::bind_method("_changedp", &EditorImportTextureOptions::_changedp); ADD_SIGNAL(MethodInfo("changed")); } void EditorImportTextureOptions::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { flags->connect("item_edited", this, "_changed"); format->connect("item_selected", this, "_changedp"); } } void EditorImportTextureOptions::show_2d_notice() { //notice_for_2d->show(); } EditorImportTextureOptions::EditorImportTextureOptions() { add_constant_override("separation", 3); updating = false; format = memnew(OptionButton); format->add_item(TTR("Uncompressed"), EditorTextureImportPlugin::IMAGE_FORMAT_UNCOMPRESSED); format->add_item(TTR("Compress Lossless (PNG)"), EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS); format->add_item(TTR("Compress Lossy (WebP)"), EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSY); format->add_item(TTR("Compress (VRAM)"), EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_RAM); add_margin_child(TTR("Texture Format"), format); quality_vb = memnew(VBoxContainer); HBoxContainer *quality_hb = memnew(HBoxContainer); HSlider *hs = memnew(HSlider); hs->set_h_size_flags(SIZE_EXPAND_FILL); hs->set_stretch_ratio(0.8); quality_hb->add_child(hs); quality_hb->set_h_size_flags(SIZE_EXPAND_FILL); SpinBox *sb = memnew(SpinBox); sb->set_h_size_flags(SIZE_EXPAND_FILL); sb->set_stretch_ratio(0.2); quality_hb->add_child(sb); sb->share(hs); hs->set_min(0); hs->set_max(1.0); hs->set_step(0.01); hs->set_val(0.7); quality = hs; quality_vb->add_margin_child(TTR("Texture Compression Quality (WebP):"), quality_hb); add_child(quality_vb); flags = memnew(Tree); flags->set_hide_root(true); TreeItem *root = flags->create_item(); const char **fname = flag_names; while (*fname) { TreeItem *ti = flags->create_item(root); ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); ti->set_text(0, *fname); ti->set_editable(0, true); items.push_back(ti); fname++; } add_margin_child(TTR("Texture Options"), flags, true); } /////////////////////////////////////////////////////////// class EditorTextureImportDialog : public ConfirmationDialog { OBJ_TYPE(EditorTextureImportDialog, ConfirmationDialog); HBoxContainer *mode_hb; CheckBox *mode_check[EditorTextureImportPlugin::MODE_MAX]; EditorImportTextureOptions *texture_options; EditorTextureImportPlugin::Mode mode; //EditorNode *editor; LineEdit *import_path; LineEdit *save_path; EditorFileDialog *file_select; EditorFileDialog *save_file_select; EditorDirDialog *save_select; OptionButton *texture_action; ConfirmationDialog *error_dialog; CheckButton *crop_source; SpinBox *size; MarginContainer *size_mc; Label *size_label; Label *source_label; Label *notice_for_2d; EditorTextureImportPlugin *plugin; void _mode_changed(int p_mode); void _choose_files(const Vector &p_path); void _choose_file(const String &p_path); void _choose_save_dir(const String &p_path); void _browse(); void _browse_target(); void _import(); protected: void _notification(int p_what); static void _bind_methods(); public: void setup_multiple_import_3d(const Vector &p_path, const String &p_dest) { _mode_changed(EditorTextureImportPlugin::MODE_TEXTURE_3D); _choose_files(p_path); _choose_save_dir(p_dest); } void add_sources_and_dest(const Vector &p_path, const String &p_dest) { _choose_files(p_path); _choose_save_dir(p_dest); } Error import(const String &p_from, const String &p_to, const String &p_preset); void popup_import(const String &p_from = String()); EditorTextureImportDialog(EditorTextureImportPlugin *p_plugin = NULL); }; ///////////////////////////////////////////////////////// void EditorTextureImportDialog::_choose_files(const Vector &p_path) { String files; for (int i = 0; i < p_path.size(); i++) { if (i > 0) files += ","; files += p_path[i]; } /* if (p_path.size()) { String srctex=p_path[0]; String ipath = EditorImportDB::get_singleton()->find_source_path(srctex); if (ipath!="") save_path->set_text(ipath.get_base_dir()); }*/ import_path->set_text(files); } void EditorTextureImportDialog::_choose_file(const String &p_path) { import_path->set_text(p_path); } void EditorTextureImportDialog::_choose_save_dir(const String &p_path) { save_path->set_text(p_path); } void EditorTextureImportDialog::_import() { // ImportMonitorBlock imb; Vector files = import_path->get_text().split(","); if (!files.size()) { error_dialog->set_text(TTR("Please specify some files!")); error_dialog->popup_centered(Size2(200, 100) * EDSCALE); return; } String dst_path = save_path->get_text(); if (save_path->get_text().strip_edges() == "") { error_dialog->set_text(TTR("Target path is empty.")); error_dialog->popup_centered_minsize(); return; } if (!save_path->get_text().begins_with("res://")) { error_dialog->set_text(TTR("Target path must be a complete resource path.")); error_dialog->popup_centered_minsize(); return; } if (mode != EditorTextureImportPlugin::MODE_ATLAS && mode != EditorTextureImportPlugin::MODE_LARGE && !DirAccess::exists(save_path->get_text())) { error_dialog->set_text(TTR("Target path must exist.")); error_dialog->popup_centered_minsize(); return; } if (mode == EditorTextureImportPlugin::MODE_ATLAS) { //atlas if (files.size() == 0) { error_dialog->set_text(TTR("At least one file needed for Atlas.")); error_dialog->popup_centered(Size2(200, 100) * EDSCALE); return; } String dst_file = dst_path; //dst_file=dst_file.basename()+".tex"; Ref imd = memnew(ResourceImportMetadata); //imd->set_editor(); for (int i = 0; i < files.size(); i++) { imd->add_source(EditorImportPlugin::validate_source_path(files[i])); } imd->set_option("format", texture_options->get_format()); imd->set_option("flags", texture_options->get_flags()); imd->set_option("quality", texture_options->get_quality()); imd->set_option("atlas", true); imd->set_option("atlas_size", int(size->get_val())); imd->set_option("large", false); imd->set_option("crop", crop_source->is_pressed()); imd->set_option("mode", mode); Error err = plugin->import(dst_file, imd); if (err) { error_dialog->set_text(TTR("Error importing:") + " " + dst_file.get_file()); error_dialog->popup_centered(Size2(200, 100) * EDSCALE); return; } } else if (mode == EditorTextureImportPlugin::MODE_LARGE) { //large if (files.size() != 1) { error_dialog->set_text(TTR("Only one file is required for large texture.")); error_dialog->popup_centered(Size2(200, 100) * EDSCALE); return; } String dst_file = dst_path; //dst_file=dst_file.basename()+".tex"; Ref imd = memnew(ResourceImportMetadata); //imd->set_editor(); for (int i = 0; i < files.size(); i++) { imd->add_source(EditorImportPlugin::validate_source_path(files[i])); } imd->set_option("format", texture_options->get_format()); imd->set_option("flags", texture_options->get_flags()); imd->set_option("quality", texture_options->get_quality()); imd->set_option("atlas", false); imd->set_option("large", true); imd->set_option("large_cell_size", int(size->get_val())); imd->set_option("crop", crop_source->is_pressed()); imd->set_option("mode", mode); Error err = plugin->import(dst_file, imd); if (err) { error_dialog->set_text(TTR("Error importing:") + " " + dst_file.get_file()); error_dialog->popup_centered(Size2(200, 100) * EDSCALE); return; } } else { for (int i = 0; i < files.size(); i++) { String dst_file = dst_path.plus_file(files[i].get_file()); dst_file = dst_file.basename() + ".tex"; Ref imd = memnew(ResourceImportMetadata); //imd->set_editor(); imd->add_source(EditorImportPlugin::validate_source_path(files[i])); imd->set_option("format", texture_options->get_format()); imd->set_option("flags", texture_options->get_flags()); imd->set_option("quality", texture_options->get_quality()); imd->set_option("atlas", false); imd->set_option("large", false); imd->set_option("mode", mode); Error err = plugin->import(dst_file, imd); if (err) { error_dialog->set_text(TTR("Error importing:") + " " + dst_file.get_file()); error_dialog->popup_centered(Size2(200, 100) * EDSCALE); return; } } } hide(); } void EditorTextureImportDialog::_browse() { file_select->popup_centered_ratio(); } void EditorTextureImportDialog::_browse_target() { if (mode == EditorTextureImportPlugin::MODE_ATLAS || mode == EditorTextureImportPlugin::MODE_LARGE) { save_file_select->popup_centered_ratio(); } else { save_select->popup_centered_ratio(); } } void EditorTextureImportDialog::popup_import(const String &p_from) { popup_centered(Size2(600, 500) * EDSCALE); if (p_from != "") { Ref rimd = ResourceLoader::load_import_metadata(p_from); ERR_FAIL_COND(!rimd.is_valid()); if (rimd->has_option("mode")) { //new imported stuff uses this option _mode_changed(rimd->get_option("mode")); } else { //this one is for compatibility, will have to guess it if (rimd->has_option("atlas") && rimd->get_option("atlas")) { _mode_changed(EditorTextureImportPlugin::MODE_ATLAS); } else if (rimd->has_option("large") && rimd->get_option("large")) { _mode_changed(EditorTextureImportPlugin::MODE_LARGE); } else { //guess by usage of mipmaps..? _mode_changed(EditorTextureImportPlugin::MODE_TEXTURE_2D); } } if (mode == EditorTextureImportPlugin::MODE_ATLAS || mode == EditorTextureImportPlugin::MODE_LARGE) save_path->set_text(p_from); else save_path->set_text(p_from.get_base_dir()); texture_options->set_format(EditorTextureImportPlugin::ImageFormat(int(rimd->get_option("format")))); texture_options->set_flags(rimd->get_option("flags")); texture_options->set_quality(rimd->get_option("quality")); String src = ""; for (int i = 0; i < rimd->get_source_count(); i++) { if (i > 0) src += ","; src += EditorImportPlugin::expand_source_path(rimd->get_source_path(i)); } import_path->set_text(src); } } void EditorTextureImportDialog::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { List extensions; ImageLoader::get_recognized_extensions(&extensions); // ResourceLoader::get_recognized_extensions_for_type("PackedTexture",&extensions); file_select->clear_filters(); for (int i = 0; i < extensions.size(); i++) { file_select->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); } } } Error EditorTextureImportDialog::import(const String &p_from, const String &p_to, const String &p_preset) { import_path->set_text(p_from); save_path->set_text(p_to); _import(); return OK; } void EditorTextureImportDialog::_mode_changed(int p_mode) { mode = EditorTextureImportPlugin::Mode(p_mode); for (int i = 0; i < EditorTextureImportPlugin::MODE_MAX; i++) { mode_check[i]->set_pressed(i == mode); } if (p_mode == EditorTextureImportPlugin::MODE_ATLAS) { size_label->set_text(TTR("Max Texture Size:")); size->set_val(2048); crop_source->show(); size_label->show(); size->show(); texture_options->set_flags(EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA | EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS | EditorTextureImportPlugin::IMAGE_FLAG_FILTER); texture_options->set_quality(0.7); texture_options->set_format(EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSY); set_title(TTR("Import Textures for Atlas (2D)")); } else { crop_source->hide(); } if (p_mode == EditorTextureImportPlugin::MODE_LARGE) { size_label->set_text(TTR("Cell Size:")); size->set_val(256); size_label->show(); size->show(); file_select->set_mode(EditorFileDialog::MODE_OPEN_FILE); save_file_select->add_filter("*.ltex;" + TTR("Large Texture")); texture_options->set_flags(EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA | EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS | EditorTextureImportPlugin::IMAGE_FLAG_FILTER); texture_options->set_quality(0.7); texture_options->set_format(EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS); set_title(TTR("Import Large Textures (2D)")); source_label->set_text(TTR("Source Texture")); } else { file_select->set_mode(EditorFileDialog::MODE_OPEN_FILES); save_file_select->add_filter("*.tex;" + TTR("Base Atlas Texture")); source_label->set_text(TTR("Source Texture(s)")); } if (p_mode == EditorTextureImportPlugin::MODE_TEXTURE_2D) { size_label->hide(); size->hide(); texture_options->set_flags(EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS | EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA | EditorTextureImportPlugin::IMAGE_FLAG_FILTER); texture_options->set_quality(0.7); texture_options->set_format(EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSY); notice_for_2d->show(); set_title(TTR("Import Textures for 2D")); } else { notice_for_2d->hide(); } if (p_mode == EditorTextureImportPlugin::MODE_TEXTURE_3D) { size_label->hide(); size->hide(); //texture_options->set_flags(EditorTextureImportPlugin::IMAGE_FLAG_); //texture_options->set_flags(EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS); texture_options->set_flags(EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA | EditorTextureImportPlugin::IMAGE_FLAG_FILTER | EditorTextureImportPlugin::IMAGE_FLAG_REPEAT); texture_options->set_format(EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_RAM); set_title(TTR("Import Textures for 3D")); } } void EditorTextureImportDialog::_bind_methods() { ObjectTypeDB::bind_method("_choose_files", &EditorTextureImportDialog::_choose_files); ObjectTypeDB::bind_method("_choose_file", &EditorTextureImportDialog::_choose_file); ObjectTypeDB::bind_method("_choose_save_dir", &EditorTextureImportDialog::_choose_save_dir); ObjectTypeDB::bind_method("_import", &EditorTextureImportDialog::_import); ObjectTypeDB::bind_method("_browse", &EditorTextureImportDialog::_browse); ObjectTypeDB::bind_method("_browse_target", &EditorTextureImportDialog::_browse_target); ObjectTypeDB::bind_method("_mode_changed", &EditorTextureImportDialog::_mode_changed); // ADD_SIGNAL( MethodInfo("imported",PropertyInfo(Variant::OBJECT,"scene")) ); } EditorTextureImportDialog::EditorTextureImportDialog(EditorTextureImportPlugin *p_plugin) { plugin = p_plugin; set_title(TTR("Import Textures")); mode_hb = memnew(HBoxContainer); add_child(mode_hb); set_child_rect(mode_hb); VBoxContainer *vbcg = memnew(VBoxContainer); mode_hb->add_child(vbcg); mode_hb->add_constant_override("separation", 15); ButtonGroup *bg = memnew(ButtonGroup); vbcg->add_margin_child("Import Mode", bg); for (int i = 0; i < EditorTextureImportPlugin::MODE_MAX; i++) { String mode_name[EditorTextureImportPlugin::MODE_MAX] = { TTR("2D Texture"), TTR("3D Texture"), TTR("Atlas Texture"), TTR("Large Texture") }; mode_check[i] = memnew(CheckBox); bg->add_child(mode_check[i]); mode_check[i]->set_text(mode_name[i]); mode_check[i]->connect("pressed", this, "_mode_changed", varray(i)); } VBoxContainer *vbc = memnew(VBoxContainer); mode_hb->add_child(vbc); vbc->set_h_size_flags(SIZE_EXPAND_FILL); vbc->add_constant_override("separation", 4); notice_for_2d = memnew(Label); notice_for_2d->set_text(TTR("NOTICE: Importing 2D textures is not mandatory. Just copy png/jpg files to the project.")); //notice_for_2d->set_custom_minimum_size(Size2(0,50)); notice_for_2d->set_autowrap(true); notice_for_2d->hide(); vbcg->add_child(notice_for_2d); notice_for_2d->set_v_size_flags(SIZE_EXPAND_FILL); notice_for_2d->set_valign(Label::VALIGN_BOTTOM); VBoxContainer *source_vb = memnew(VBoxContainer); MarginContainer *source_mc = vbc->add_margin_child(TTR("Source Texture(s):"), source_vb); source_label = vbc->get_child(source_mc->get_index() - 1)->cast_to