diff options
Diffstat (limited to 'editor')
81 files changed, 5885 insertions, 3815 deletions
diff --git a/editor/SCsub b/editor/SCsub index a9343f7f36..4fa287c33b 100644 --- a/editor/SCsub +++ b/editor/SCsub @@ -5,149 +5,14 @@ env.editor_sources = [] import os import os.path -from compat import encode_utf8, byte_to_str, open_utf8, escape_string - -def make_certs_header(target, source, env): - - src = source[0].srcnode().abspath - dst = target[0].srcnode().abspath - f = open(src, "rb") - g = open_utf8(dst, "w") - buf = f.read() - decomp_size = len(buf) - import zlib - buf = zlib.compress(buf) - - g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - g.write("#ifndef _CERTS_RAW_H\n") - g.write("#define _CERTS_RAW_H\n") - g.write("static const int _certs_compressed_size = " + str(len(buf)) + ";\n") - g.write("static const int _certs_uncompressed_size = " + str(decomp_size) + ";\n") - g.write("static const unsigned char _certs_compressed[] = {\n") - for i in range(len(buf)): - g.write("\t" + byte_to_str(buf[i]) + ",\n") - g.write("};\n") - g.write("#endif") - - g.close() - f.close() - - -def make_doc_header(target, source, env): - - dst = target[0].srcnode().abspath - g = open_utf8(dst, "w") - buf = "" - docbegin = "" - docend = "" - for s in source: - src = s.srcnode().abspath - if not src.endswith(".xml"): - continue - with open_utf8(src, "r") as f: - content = f.read() - buf += content - - buf = encode_utf8(docbegin + buf + docend) - decomp_size = len(buf) - import zlib - buf = zlib.compress(buf) - - g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - g.write("#ifndef _DOC_DATA_RAW_H\n") - g.write("#define _DOC_DATA_RAW_H\n") - g.write("static const int _doc_data_compressed_size = " + str(len(buf)) + ";\n") - g.write("static const int _doc_data_uncompressed_size = " + str(decomp_size) + ";\n") - g.write("static const unsigned char _doc_data_compressed[] = {\n") - for i in range(len(buf)): - g.write("\t" + byte_to_str(buf[i]) + ",\n") - g.write("};\n") - - g.write("#endif") - - g.close() - - -def make_fonts_header(target, source, env): - - dst = target[0].srcnode().abspath - - g = open_utf8(dst, "w") - - g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - g.write("#ifndef _EDITOR_FONTS_H\n") - g.write("#define _EDITOR_FONTS_H\n") - - # saving uncompressed, since freetype will reference from memory pointer - xl_names = [] - for i in range(len(source)): - with open(source[i].srcnode().abspath, "rb")as f: - buf = f.read() - - name = os.path.splitext(os.path.basename(source[i].srcnode().abspath))[0] - - g.write("static const int _font_" + name + "_size = " + str(len(buf)) + ";\n") - g.write("static const unsigned char _font_" + name + "[] = {\n") - for i in range(len(buf)): - g.write("\t" + byte_to_str(buf[i]) + ",\n") - - g.write("};\n") - - g.write("#endif") - - g.close() - +from platform_methods import run_in_subprocess +from compat import open_utf8 +import editor_builders -def make_translations_header(target, source, env): - - dst = target[0].srcnode().abspath - - g = open_utf8(dst, "w") - - g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - g.write("#ifndef _EDITOR_TRANSLATIONS_H\n") - g.write("#define _EDITOR_TRANSLATIONS_H\n") - - import zlib - import os.path - - paths = [node.srcnode().abspath for node in source] - sorted_paths = sorted(paths, key=lambda path: os.path.splitext(os.path.basename(path))[0]) - - xl_names = [] - for i in range(len(sorted_paths)): - with open(sorted_paths[i], "rb") as f: - buf = f.read() - decomp_size = len(buf) - buf = zlib.compress(buf) - name = os.path.splitext(os.path.basename(sorted_paths[i]))[0] - - g.write("static const unsigned char _translation_" + name + "_compressed[] = {\n") - for i in range(len(buf)): - g.write("\t" + byte_to_str(buf[i]) + ",\n") - - g.write("};\n") - - xl_names.append([name, len(buf), str(decomp_size)]) - - g.write("struct EditorTranslationList {\n") - g.write("\tconst char* lang;\n") - g.write("\tint comp_size;\n") - g.write("\tint uncomp_size;\n") - g.write("\tconst unsigned char* data;\n") - g.write("};\n\n") - g.write("static EditorTranslationList _editor_translations[] = {\n") - for x in xl_names: - g.write("\t{ \"" + x[0] + "\", " + str(x[1]) + ", " + str(x[2]) + ", _translation_" + x[0] + "_compressed},\n") - g.write("\t{NULL, 0, 0, NULL}\n") - g.write("};\n") - - g.write("#endif") - - g.close() def _make_doc_data_class_path(to_path): - g = open_utf8(os.path.join(to_path,"doc_data_class_path.gen.h"), "w") + # NOTE: It is safe to generate this file here, since this is still executed serially + g = open_utf8(os.path.join(to_path, "doc_data_class_path.gen.h"), "w") g.write("static const int _doc_data_class_path_count = " + str(len(env.doc_class_path)) + ";\n") g.write("struct _DocDataClassPath { const char* name; const char* path; };\n") @@ -169,6 +34,8 @@ if env['tools']: reg_exporters += '\tregister_' + e + '_exporter();\n' reg_exporters_inc += '#include "platform/' + e + '/export/export.h"\n' reg_exporters += '}\n' + + # NOTE: It is safe to generate this file here, since this is still executed serially with open_utf8("register_exporters.gen.cpp", "w") as f: f.write(reg_exporters_inc) f.write(reg_exporters) @@ -192,24 +59,38 @@ if env['tools']: docs = sorted(docs) env.Depends("#editor/doc_data_compressed.gen.h", docs) - env.CommandNoCache("#editor/doc_data_compressed.gen.h", docs, make_doc_header) + env.CommandNoCache("#editor/doc_data_compressed.gen.h", docs, run_in_subprocess(editor_builders.make_doc_header)) + # Certificates env.Depends("#editor/certs_compressed.gen.h", "#thirdparty/certs/ca-certificates.crt") - env.CommandNoCache("#editor/certs_compressed.gen.h", "#thirdparty/certs/ca-certificates.crt", make_certs_header) + env.CommandNoCache("#editor/certs_compressed.gen.h", "#thirdparty/certs/ca-certificates.crt", run_in_subprocess(editor_builders.make_certs_header)) import glob + path = env.Dir('.').abspath # Translations tlist = glob.glob(path + "/translations/*.po") env.Depends('#editor/translations.gen.h', tlist) - env.CommandNoCache('#editor/translations.gen.h', tlist, make_translations_header) + env.CommandNoCache('#editor/translations.gen.h', tlist, run_in_subprocess(editor_builders.make_translations_header)) # Fonts flist = glob.glob(path + "/../thirdparty/fonts/*.ttf") flist.append(glob.glob(path + "/../thirdparty/fonts/*.otf")) env.Depends('#editor/builtin_fonts.gen.h', flist) - env.CommandNoCache('#editor/builtin_fonts.gen.h', flist, make_fonts_header) + env.CommandNoCache('#editor/builtin_fonts.gen.h', flist, run_in_subprocess(editor_builders.make_fonts_header)) + + # Authors + env.Depends('#editor/authors.gen.h', "../AUTHORS.md") + env.CommandNoCache('#editor/authors.gen.h', "../AUTHORS.md", run_in_subprocess(editor_builders.make_authors_header)) + + # Donors + env.Depends('#editor/donors.gen.h', "../DONORS.md") + env.CommandNoCache('#editor/donors.gen.h', "../DONORS.md", run_in_subprocess(editor_builders.make_donors_header)) + + # License + env.Depends('#editor/license.gen.h', ["../COPYRIGHT.txt", "../LICENSE.txt"]) + env.CommandNoCache('#editor/license.gen.h', ["../COPYRIGHT.txt", "../LICENSE.txt"], run_in_subprocess(editor_builders.make_license_header)) env.add_source_files(env.editor_sources, "*.cpp") env.add_source_files(env.editor_sources, ["#thirdparty/misc/clipper.cpp"]) diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 4ce8556add..9d4333bc29 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -745,7 +745,7 @@ bool CodeTextEditor::_add_font_size(int p_delta) { if (font.is_valid()) { int new_size = CLAMP(font->get_size() + p_delta, 8 * EDSCALE, 96 * EDSCALE); - zoom_nb->set_text(itos(100 * new_size / 14) + "%"); + zoom_nb->set_text(itos(100 * new_size / (14 * EDSCALE)) + "%"); if (new_size != font->get_size()) { EditorSettings::get_singleton()->set("interface/editor/code_font_size", new_size / EDSCALE); @@ -1246,6 +1246,29 @@ CodeTextEditor::CodeTextEditor() { status_bar->add_child(memnew(Label)); //to keep the height if the other labels are not visible + warning_label = memnew(Label); + status_bar->add_child(warning_label); + warning_label->set_align(Label::ALIGN_RIGHT); + warning_label->set_valign(Label::VALIGN_CENTER); + warning_label->set_v_size_flags(SIZE_FILL); + warning_label->set_default_cursor_shape(CURSOR_POINTING_HAND); + warning_label->set_mouse_filter(MOUSE_FILTER_STOP); + warning_label->set_text(TTR("Warnings:")); + warning_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); + + warning_count_label = memnew(Label); + status_bar->add_child(warning_count_label); + warning_count_label->set_valign(Label::VALIGN_CENTER); + warning_count_label->set_v_size_flags(SIZE_FILL); + warning_count_label->set_autowrap(true); // workaround to prevent resizing the label on each change, do not touch + warning_count_label->set_clip_text(true); // workaround to prevent resizing the label on each change, do not touch + warning_count_label->set_custom_minimum_size(Size2(40, 1) * EDSCALE); + warning_count_label->set_align(Label::ALIGN_RIGHT); + warning_count_label->set_default_cursor_shape(CURSOR_POINTING_HAND); + warning_count_label->set_mouse_filter(MOUSE_FILTER_STOP); + warning_count_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); + warning_count_label->set_text("0"); + Label *zoom_txt = memnew(Label); status_bar->add_child(zoom_txt); zoom_txt->set_align(Label::ALIGN_RIGHT); @@ -1318,7 +1341,7 @@ CodeTextEditor::CodeTextEditor() { font_resize_val = 0; font_size = EditorSettings::get_singleton()->get("interface/editor/code_font_size"); - zoom_nb->set_text(itos(100 * font_size / 14) + "%"); + zoom_nb->set_text(itos(100 * font_size / (14 * EDSCALE)) + "%"); font_resize_timer = memnew(Timer); add_child(font_resize_timer); font_resize_timer->set_one_shot(true); diff --git a/editor/code_editor.h b/editor/code_editor.h index 903f61d87d..ee47eff9a8 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -142,6 +142,8 @@ class CodeTextEditor : public VBoxContainer { TextEdit *text_editor; FindReplaceBar *find_replace_bar; HBoxContainer *status_bar; + Label *warning_label; + Label *warning_count_label; Label *line_nb; Label *col_nb; @@ -214,6 +216,8 @@ public: void update_line_and_column() { _line_col_changed(); } TextEdit *get_text_edit() { return text_editor; } FindReplaceBar *get_find_replace_bar() { return find_replace_bar; } + Label *get_warning_label() const { return warning_label; } + Label *get_warning_count_label() const { return warning_count_label; } virtual void apply_code() {} void set_code_complete_func(CodeTextEditorCodeCompleteFunc p_code_complete_func, void *p_ud); diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 3e0c1f2d53..5dd5b7fcc5 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -86,7 +86,7 @@ void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode) { memdelete(f); } - _update_favorite_list(); + _save_and_update_favorite_list(); // Restore valid window bounds or pop up at default size. if (EditorSettings::get_singleton()->has_setting("interface/dialogs/create_new_node_bounds")) { @@ -425,6 +425,8 @@ void CreateDialog::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { connect("confirmed", this, "_confirmed"); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); favorite->set_icon(get_icon("Favorites", "EditorIcons")); } break; case NOTIFICATION_EXIT_TREE: { @@ -543,8 +545,7 @@ void CreateDialog::_favorite_toggled() { favorite->set_pressed(false); } - _save_favorite_list(); - _update_favorite_list(); + _save_and_update_favorite_list(); } void CreateDialog::_save_favorite_list() { @@ -554,8 +555,11 @@ void CreateDialog::_save_favorite_list() { if (f) { for (int i = 0; i < favorite_list.size(); i++) { - - f->store_line(favorite_list[i]); + String l = favorite_list[i]; + String name = l.split(" ")[0]; + if (!(ClassDB::class_exists(name) || ScriptServer::is_global_class(name))) + continue; + f->store_line(l); } memdelete(f); } @@ -566,11 +570,15 @@ void CreateDialog::_update_favorite_list() { favorites->clear(); TreeItem *root = favorites->create_item(); for (int i = 0; i < favorite_list.size(); i++) { - TreeItem *ti = favorites->create_item(root); String l = favorite_list[i]; + String name = l.split(" ")[0]; + if (!(ClassDB::class_exists(name) || ScriptServer::is_global_class(name))) + continue; + TreeItem *ti = favorites->create_item(root); ti->set_text(0, l); ti->set_icon(0, _get_editor_icon(l)); } + emit_signal("favorites_updated"); } void CreateDialog::_history_selected() { @@ -673,6 +681,10 @@ void CreateDialog::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co } } + _save_and_update_favorite_list(); +} + +void CreateDialog::_save_and_update_favorite_list() { _save_favorite_list(); _update_favorite_list(); } @@ -688,12 +700,14 @@ void CreateDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_favorite_selected"), &CreateDialog::_favorite_selected); ClassDB::bind_method(D_METHOD("_history_activated"), &CreateDialog::_history_activated); ClassDB::bind_method(D_METHOD("_favorite_activated"), &CreateDialog::_favorite_activated); + ClassDB::bind_method(D_METHOD("_save_and_update_favorite_list"), &CreateDialog::_save_and_update_favorite_list); ClassDB::bind_method("get_drag_data_fw", &CreateDialog::get_drag_data_fw); ClassDB::bind_method("can_drop_data_fw", &CreateDialog::can_drop_data_fw); ClassDB::bind_method("drop_data_fw", &CreateDialog::drop_data_fw); ADD_SIGNAL(MethodInfo("create")); + ADD_SIGNAL(MethodInfo("favorites_updated")); } CreateDialog::CreateDialog() { diff --git a/editor/create_dialog.h b/editor/create_dialog.h index f8eec231a4..6df9eebc8c 100644 --- a/editor/create_dialog.h +++ b/editor/create_dialog.h @@ -90,6 +90,8 @@ protected: void _notification(int p_what); static void _bind_methods(); + void _save_and_update_favorite_list(); + public: Object *instance_selected(); String get_selected_type(); diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp index 2803762973..91a29f5717 100644 --- a/editor/doc/doc_data.cpp +++ b/editor/doc/doc_data.cpp @@ -535,13 +535,14 @@ void DocData::generate(bool p_basic_types) { } List<StringName> constants; - Variant::get_numeric_constants_for_type(Variant::Type(i), &constants); + Variant::get_constants_for_type(Variant::Type(i), &constants); for (List<StringName>::Element *E = constants.front(); E; E = E->next()) { ConstantDoc constant; constant.name = E->get(); - constant.value = itos(Variant::get_numeric_constant_value(Variant::Type(i), E->get())); + Variant value = Variant::get_constant_value(Variant::Type(i), E->get()); + constant.value = value.get_type() == Variant::INT ? itos(value) : value.get_construct_string(); c.constants.push_back(constant); } } diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index 4b09db0a9e..e4602f0f94 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -113,7 +113,7 @@ ScrollContainer *EditorAbout::_populate_list(const String &p_name, const List<St EditorAbout::EditorAbout() { set_title(TTR("Thanks from the Godot community!")); - get_ok()->set_text(TTR("Thanks!")); + get_ok()->set_text(TTR("OK")); set_hide_on_ok(true); set_resizable(true); diff --git a/editor/editor_builders.py b/editor/editor_builders.py new file mode 100644 index 0000000000..6c2f9e298e --- /dev/null +++ b/editor/editor_builders.py @@ -0,0 +1,412 @@ +"""Functions used to generate source files during build time + +All such functions are invoked in a subprocess on Windows to prevent build flakiness. + +""" +import os +import os.path +from platform_methods import subprocess_main +from compat import encode_utf8, byte_to_str, open_utf8, escape_string + + +def make_certs_header(target, source, env): + + src = source[0] + dst = target[0] + f = open(src, "rb") + g = open_utf8(dst, "w") + buf = f.read() + decomp_size = len(buf) + import zlib + buf = zlib.compress(buf) + + g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + g.write("#ifndef _CERTS_RAW_H\n") + g.write("#define _CERTS_RAW_H\n") + g.write("static const int _certs_compressed_size = " + str(len(buf)) + ";\n") + g.write("static const int _certs_uncompressed_size = " + str(decomp_size) + ";\n") + g.write("static const unsigned char _certs_compressed[] = {\n") + for i in range(len(buf)): + g.write("\t" + byte_to_str(buf[i]) + ",\n") + g.write("};\n") + g.write("#endif") + + g.close() + f.close() + + +def make_doc_header(target, source, env): + + dst = target[0] + g = open_utf8(dst, "w") + buf = "" + docbegin = "" + docend = "" + for src in source: + if not src.endswith(".xml"): + continue + with open_utf8(src, "r") as f: + content = f.read() + buf += content + + buf = encode_utf8(docbegin + buf + docend) + decomp_size = len(buf) + import zlib + buf = zlib.compress(buf) + + g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + g.write("#ifndef _DOC_DATA_RAW_H\n") + g.write("#define _DOC_DATA_RAW_H\n") + g.write("static const int _doc_data_compressed_size = " + str(len(buf)) + ";\n") + g.write("static const int _doc_data_uncompressed_size = " + str(decomp_size) + ";\n") + g.write("static const unsigned char _doc_data_compressed[] = {\n") + for i in range(len(buf)): + g.write("\t" + byte_to_str(buf[i]) + ",\n") + g.write("};\n") + + g.write("#endif") + + g.close() + + +def make_fonts_header(target, source, env): + + dst = target[0] + + g = open_utf8(dst, "w") + + g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + g.write("#ifndef _EDITOR_FONTS_H\n") + g.write("#define _EDITOR_FONTS_H\n") + + # saving uncompressed, since freetype will reference from memory pointer + xl_names = [] + for i in range(len(source)): + with open(source[i], "rb")as f: + buf = f.read() + + name = os.path.splitext(os.path.basename(source[i]))[0] + + g.write("static const int _font_" + name + "_size = " + str(len(buf)) + ";\n") + g.write("static const unsigned char _font_" + name + "[] = {\n") + for i in range(len(buf)): + g.write("\t" + byte_to_str(buf[i]) + ",\n") + + g.write("};\n") + + g.write("#endif") + + g.close() + + +def make_translations_header(target, source, env): + + dst = target[0] + + g = open_utf8(dst, "w") + + g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + g.write("#ifndef _EDITOR_TRANSLATIONS_H\n") + g.write("#define _EDITOR_TRANSLATIONS_H\n") + + import zlib + import os.path + + sorted_paths = sorted(source, key=lambda path: os.path.splitext(os.path.basename(path))[0]) + + xl_names = [] + for i in range(len(sorted_paths)): + with open(sorted_paths[i], "rb") as f: + buf = f.read() + decomp_size = len(buf) + buf = zlib.compress(buf) + name = os.path.splitext(os.path.basename(sorted_paths[i]))[0] + + g.write("static const unsigned char _translation_" + name + "_compressed[] = {\n") + for i in range(len(buf)): + g.write("\t" + byte_to_str(buf[i]) + ",\n") + + g.write("};\n") + + xl_names.append([name, len(buf), str(decomp_size)]) + + g.write("struct EditorTranslationList {\n") + g.write("\tconst char* lang;\n") + g.write("\tint comp_size;\n") + g.write("\tint uncomp_size;\n") + g.write("\tconst unsigned char* data;\n") + g.write("};\n\n") + g.write("static EditorTranslationList _editor_translations[] = {\n") + for x in xl_names: + g.write("\t{ \"" + x[0] + "\", " + str(x[1]) + ", " + str(x[2]) + ", _translation_" + x[0] + "_compressed},\n") + g.write("\t{NULL, 0, 0, NULL}\n") + g.write("};\n") + + g.write("#endif") + + g.close() + + +def make_authors_header(target, source, env): + + sections = ["Project Founders", "Lead Developer", "Project Manager", "Developers"] + sections_id = ["dev_founders", "dev_lead", "dev_manager", "dev_names"] + + src = source[0] + dst = target[0] + f = open_utf8(src, "r") + g = open_utf8(dst, "w") + + g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + g.write("#ifndef _EDITOR_AUTHORS_H\n") + g.write("#define _EDITOR_AUTHORS_H\n") + + current_section = "" + reading = False + + def close_section(): + g.write("\t0\n") + g.write("};\n") + + for line in f: + if reading: + if line.startswith(" "): + g.write("\t\"" + escape_string(line.strip()) + "\",\n") + continue + if line.startswith("## "): + if reading: + close_section() + reading = False + for i in range(len(sections)): + if line.strip().endswith(sections[i]): + current_section = escape_string(sections_id[i]) + reading = True + g.write("static const char *" + current_section + "[] = {\n") + break + + if reading: + close_section() + + g.write("#endif\n") + + g.close() + f.close() + +def make_donors_header(target, source, env): + + sections = ["Platinum sponsors", "Gold sponsors", "Mini sponsors", "Gold donors", "Silver donors", "Bronze donors"] + sections_id = ["donor_s_plat", "donor_s_gold", "donor_s_mini", "donor_gold", "donor_silver", "donor_bronze"] + + src = source[0] + dst = target[0] + f = open_utf8(src, "r") + g = open_utf8(dst, "w") + + g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + g.write("#ifndef _EDITOR_DONORS_H\n") + g.write("#define _EDITOR_DONORS_H\n") + + current_section = "" + reading = False + + def close_section(): + g.write("\t0\n") + g.write("};\n") + + for line in f: + if reading >= 0: + if line.startswith(" "): + g.write("\t\"" + escape_string(line.strip()) + "\",\n") + continue + if line.startswith("## "): + if reading: + close_section() + reading = False + for i in range(len(sections)): + if line.strip().endswith(sections[i]): + current_section = escape_string(sections_id[i]) + reading = True + g.write("static const char *" + current_section + "[] = {\n") + break + + if reading: + close_section() + + g.write("#endif\n") + + g.close() + f.close() + + +def make_license_header(target, source, env): + + src_copyright = source[0] + src_license = source[1] + dst = target[0] + f = open_utf8(src_license, "r") + fc = open_utf8(src_copyright, "r") + g = open_utf8(dst, "w") + + g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + g.write("#ifndef _EDITOR_LICENSE_H\n") + g.write("#define _EDITOR_LICENSE_H\n") + g.write("static const char *about_license =") + + for line in f: + escaped_string = escape_string(line.strip()) + g.write("\n\t\"" + escaped_string + "\\n\"") + + g.write(";\n") + + tp_current = 0 + tp_file = "" + tp_comment = "" + tp_copyright = "" + tp_license = "" + + tp_licensename = "" + tp_licensebody = "" + + tp = [] + tp_licensetext = [] + for line in fc: + if line.startswith("#"): + continue + + if line.startswith("Files:"): + tp_file = line[6:].strip() + tp_current = 1 + elif line.startswith("Comment:"): + tp_comment = line[8:].strip() + tp_current = 2 + elif line.startswith("Copyright:"): + tp_copyright = line[10:].strip() + tp_current = 3 + elif line.startswith("License:"): + if tp_current != 0: + tp_license = line[8:].strip() + tp_current = 4 + else: + tp_licensename = line[8:].strip() + tp_current = 5 + elif line.startswith(" "): + if tp_current == 1: + tp_file += "\n" + line.strip() + elif tp_current == 3: + tp_copyright += "\n" + line.strip() + elif tp_current == 5: + if line.strip() == ".": + tp_licensebody += "\n" + else: + tp_licensebody += line[1:] + else: + if tp_current != 0: + if tp_current == 5: + tp_licensetext.append([tp_licensename, tp_licensebody]) + + tp_licensename = "" + tp_licensebody = "" + else: + added = False + for i in tp: + if i[0] == tp_comment: + i[1].append([tp_file, tp_copyright, tp_license]) + added = True + break + if not added: + tp.append([tp_comment,[[tp_file, tp_copyright, tp_license]]]) + + tp_file = [] + tp_comment = "" + tp_copyright = [] + tp_license = "" + tp_current = 0 + + tp_licensetext.append([tp_licensename, tp_licensebody]) + + about_thirdparty = "" + about_tp_copyright_count = "" + about_tp_license = "" + about_tp_copyright = "" + about_tp_file = "" + + for i in tp: + about_thirdparty += "\t\"" + i[0] + "\",\n" + about_tp_copyright_count += str(len(i[1])) + ", " + for j in i[1]: + file_body = "" + copyright_body = "" + for k in j[0].split("\n"): + if file_body != "": + file_body += "\\n\"\n" + escaped_string = escape_string(k.strip()) + file_body += "\t\"" + escaped_string + for k in j[1].split("\n"): + if copyright_body != "": + copyright_body += "\\n\"\n" + escaped_string = escape_string(k.strip()) + copyright_body += "\t\"" + escaped_string + + about_tp_file += "\t" + file_body + "\",\n" + about_tp_copyright += "\t" + copyright_body + "\",\n" + about_tp_license += "\t\"" + j[2] + "\",\n" + + about_license_name = "" + about_license_body = "" + + for i in tp_licensetext: + body = "" + for j in i[1].split("\n"): + if body != "": + body += "\\n\"\n" + escaped_string = escape_string(j.strip()) + body += "\t\"" + escaped_string + + about_license_name += "\t\"" + i[0] + "\",\n" + about_license_body += "\t" + body + "\",\n" + + g.write("static const char *about_thirdparty[] = {\n") + g.write(about_thirdparty) + g.write("\t0\n") + g.write("};\n") + g.write("#define THIRDPARTY_COUNT " + str(len(tp)) + "\n") + + g.write("static const int about_tp_copyright_count[] = {\n\t") + g.write(about_tp_copyright_count) + g.write("0\n};\n") + + g.write("static const char *about_tp_file[] = {\n") + g.write(about_tp_file) + g.write("\t0\n") + g.write("};\n") + + g.write("static const char *about_tp_copyright[] = {\n") + g.write(about_tp_copyright) + g.write("\t0\n") + g.write("};\n") + + g.write("static const char *about_tp_license[] = {\n") + g.write(about_tp_license) + g.write("\t0\n") + g.write("};\n") + + g.write("static const char *about_license_name[] = {\n") + g.write(about_license_name) + g.write("\t0\n") + g.write("};\n") + g.write("#define LICENSE_COUNT " + str(len(tp_licensetext)) + "\n") + + g.write("static const char *about_license_body[] = {\n") + g.write(about_license_body) + g.write("\t0\n") + g.write("};\n") + + g.write("#endif\n") + + g.close() + fc.close() + f.close() + + +if __name__ == '__main__': + subprocess_main(globals()) diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 7d56c4985a..d240f4ed25 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -558,7 +558,9 @@ void EditorFileDialog::_item_list_item_rmb_selected(int p_item, const Vector2 &p } if (single_item_selected) { item_menu->add_separator(); - item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Show In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER); + Dictionary item_meta = item_list->get_item_metadata(p_item); + String item_text = item_meta["dir"] ? TTR("Open In File Manager") : TTR("Show In File Manager"); + item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), item_text, ITEM_MENU_SHOW_IN_EXPLORER); } if (item_menu->get_item_count() > 0) { @@ -582,7 +584,7 @@ void EditorFileDialog::_item_list_rmb_clicked(const Vector2 &p_pos) { } item_menu->add_icon_item(get_icon("Reload", "EditorIcons"), TTR("Refresh"), ITEM_MENU_REFRESH, KEY_F5); item_menu->add_separator(); - item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Show In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER); + item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Open In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER); item_menu->set_position(item_list->get_global_position() + p_pos); item_menu->popup(); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index d8ab41fa05..671ac755b2 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1366,6 +1366,7 @@ void EditorFileSystem::update_script_classes() { } ScriptServer::save_global_classes(); + emit_signal("script_classes_updated"); } void EditorFileSystem::_queue_update_script_classes() { @@ -1704,6 +1705,7 @@ void EditorFileSystem::_bind_methods() { ADD_SIGNAL(MethodInfo("filesystem_changed")); ADD_SIGNAL(MethodInfo("sources_changed", PropertyInfo(Variant::BOOL, "exist"))); ADD_SIGNAL(MethodInfo("resources_reimported", PropertyInfo(Variant::POOL_STRING_ARRAY, "resources"))); + ADD_SIGNAL(MethodInfo("script_classes_updated")); } void EditorFileSystem::_update_extensions() { diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 727383b960..60826aa81b 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -253,7 +253,8 @@ void EditorHelpSearch::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { //_update_icons - search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); connect("confirmed", this, "_confirmed"); _update_search(); @@ -267,7 +268,8 @@ void EditorHelpSearch::_notification(int p_what) { } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { //_update_icons - search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); } else if (p_what == NOTIFICATION_PROCESS) { if (search.is_valid()) { @@ -381,7 +383,8 @@ void EditorHelpIndex::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { //_update_icons - search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); _update_class_list(); connect("confirmed", this, "_tree_item_selected"); @@ -392,7 +395,8 @@ void EditorHelpIndex::_notification(int p_what) { } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { //_update_icons - search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); } } @@ -541,6 +545,7 @@ void EditorHelp::_class_desc_select(const String &p_select) { String class_name; if (select.find(".") != -1) { class_name = select.get_slice(".", 0); + select = select.get_slice(".", 1); } else { class_name = "@GlobalScope"; } @@ -713,16 +718,22 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { if (p_class == edited_class) return OK; //already there + edited_class = p_class; + _update_doc(); + return OK; +} + +void EditorHelp::_update_doc() { + scroll_locked = true; class_desc->clear(); method_line.clear(); section_line.clear(); - edited_class = p_class; _init_colors(); - DocData::ClassDoc cd = doc->class_list[p_class]; //make a copy, so we can sort without worrying + DocData::ClassDoc cd = doc->class_list[edited_class]; //make a copy, so we can sort without worrying Ref<Font> doc_font = get_font("doc", "EditorFonts"); Ref<Font> doc_title_font = get_font("doc_title", "EditorFonts"); @@ -734,7 +745,7 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { class_desc->push_color(title_color); class_desc->add_text(TTR("Class:") + " "); class_desc->push_color(headline_color); - _add_text(p_class); + _add_text(edited_class); class_desc->pop(); class_desc->pop(); class_desc->pop(); @@ -1214,6 +1225,18 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { constant_line[constants[i].name] = class_desc->get_line_count() - 2; class_desc->push_font(doc_code_font); + + if (constants[i].value.begins_with("Color(") && constants[i].value.ends_with(")")) { + String stripped = constants[i].value.replace(" ", "").replace("Color(", "").replace(")", ""); + Vector<float> color = stripped.split_floats(","); + if (color.size() >= 3) { + class_desc->push_color(Color(color[0], color[1], color[2])); + static const CharType prefix[3] = { 0x25CF /* filled circle */, ' ', 0 }; + class_desc->add_text(String(prefix)); + class_desc->pop(); + } + } + class_desc->push_color(headline_color); _add_text(constants[i].name); class_desc->pop(); @@ -1223,6 +1246,7 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { class_desc->push_color(value_color); _add_text(constants[i].value); class_desc->pop(); + class_desc->pop(); if (constants[i].description != "") { class_desc->push_font(doc_font); @@ -1440,8 +1464,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { } scroll_locked = false; - - return OK; } void EditorHelp::_request_help(const String &p_string) { @@ -1738,9 +1760,6 @@ void EditorHelp::_add_text(const String &p_bbcode) { _add_text_to_rt(p_bbcode, class_desc); } -void EditorHelp::_update_doc() { -} - void EditorHelp::generate_doc() { doc = memnew(DocData); @@ -1763,6 +1782,7 @@ void EditorHelp::_notification(int p_what) { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { class_desc->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor")); + _update_doc(); } break; diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 488980db07..99a2b2aa67 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -43,6 +43,9 @@ Size2 EditorProperty::get_minimum_size() const { Size2 ms; + Ref<Font> font = get_font("font", "Tree"); + ms.height = font->get_height(); + for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); @@ -70,12 +73,10 @@ Size2 EditorProperty::get_minimum_size() const { ms.width += check->get_width() + get_constant("hseparator", "Tree"); } - if (bottom_editor != NULL) { - Ref<Font> font = get_font("font", "Tree"); - ms.height += font->get_height(); + if (bottom_editor != NULL && bottom_editor->is_visible()) { ms.height += get_constant("vseparation", "Tree"); Size2 bems = bottom_editor->get_combined_minimum_size(); - bems.width += get_constant("item_margin", "Tree"); + //bems.width += get_constant("item_margin", "Tree"); ms.height += bems.height; ms.width = MAX(ms.width, bems.width); } @@ -98,6 +99,7 @@ void EditorProperty::_notification(int p_what) { int child_room = size.width * (1.0 - split_ratio); Ref<Font> font = get_font("font", "Tree"); int height = font->get_height(); + bool no_children = true; //compute room needed for (int i = 0; i < get_child_count(); i++) { @@ -113,11 +115,16 @@ void EditorProperty::_notification(int p_what) { Size2 minsize = c->get_combined_minimum_size(); child_room = MAX(child_room, minsize.width); height = MAX(height, minsize.height); + no_children = false; } - text_size = MAX(0, size.width - child_room + 4 * EDSCALE); - - rect = Rect2(text_size, 0, size.width - text_size, height); + if (no_children) { + text_size = size.width; + rect = Rect2(size.width - 1, 0, 1, height); + } else { + text_size = MAX(0, size.width - (child_room + 4 * EDSCALE)); + rect = Rect2(size.width - child_room, 0, child_room, height); + } if (bottom_editor) { @@ -178,7 +185,7 @@ void EditorProperty::_notification(int p_what) { draw_style_box(sb, Rect2(Vector2(), size)); } - if (right_child_rect != Rect2()) { + if (draw_top_bg && right_child_rect != Rect2()) { draw_rect(right_child_rect, dark_color); } if (bottom_child_rect != Rect2()) { @@ -189,7 +196,7 @@ void EditorProperty::_notification(int p_what) { if (draw_red) { color = get_color("error_color", "Editor"); } else { - color = get_color("font_color", "Tree"); + color = get_color("property_color", "Editor"); } if (label.find(".") != -1) { color.a = 0.5; //this should be un-hacked honestly, as it's used for editor overrides @@ -787,6 +794,8 @@ void EditorProperty::_bind_methods() { EditorProperty::EditorProperty() { + draw_top_bg = true; + object = NULL; split_ratio = 0.5; selectable = true; text_size = 0; @@ -1613,32 +1622,10 @@ void EditorInspector::update_tree() { for (List<EditorInspectorPlugin::AddedEditor>::Element *F = editors.front(); F; F = F->next()) { EditorProperty *ep = Object::cast_to<EditorProperty>(F->get().property_editor); - current_vbox->add_child(F->get().property_editor); if (ep) { - + //set all this before the control gets the ENTER_TREE notification ep->object = object; - ep->connect("property_changed", this, "_property_changed"); - if (p.usage & PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED) { - ep->connect("property_changed", this, "_property_changed_update_all", varray(), CONNECT_DEFERRED); - } - ep->connect("property_keyed", this, "_property_keyed"); - ep->connect("property_keyed_with_value", this, "_property_keyed_with_value"); - ep->connect("property_checked", this, "_property_checked"); - ep->connect("selected", this, "_property_selected"); - ep->connect("multiple_properties_changed", this, "_multiple_properties_changed"); - ep->connect("resource_selected", this, "_resource_selected", varray(), CONNECT_DEFERRED); - ep->connect("object_id_selected", this, "_object_id_selected", varray(), CONNECT_DEFERRED); - if (doc_hint != String()) { - ep->set_tooltip(property_prefix + p.name + "::" + doc_hint); - } else { - ep->set_tooltip(property_prefix + p.name); - } - ep->set_draw_red(draw_red); - ep->set_use_folding(use_folding); - ep->set_checkable(checkable); - ep->set_checked(checked); - ep->set_keying(keying); if (F->get().properties.size()) { @@ -1664,8 +1651,35 @@ void EditorInspector::update_tree() { editor_property_map[prop].push_back(ep); } } + ep->set_draw_red(draw_red); + ep->set_use_folding(use_folding); + ep->set_checkable(checkable); + ep->set_checked(checked); + ep->set_keying(keying); ep->set_read_only(read_only); + } + + current_vbox->add_child(F->get().property_editor); + + if (ep) { + + ep->connect("property_changed", this, "_property_changed"); + if (p.usage & PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED) { + ep->connect("property_changed", this, "_property_changed_update_all", varray(), CONNECT_DEFERRED); + } + ep->connect("property_keyed", this, "_property_keyed"); + ep->connect("property_keyed_with_value", this, "_property_keyed_with_value"); + ep->connect("property_checked", this, "_property_checked"); + ep->connect("selected", this, "_property_selected"); + ep->connect("multiple_properties_changed", this, "_multiple_properties_changed"); + ep->connect("resource_selected", this, "_resource_selected", varray(), CONNECT_DEFERRED); + ep->connect("object_id_selected", this, "_object_id_selected", varray(), CONNECT_DEFERRED); + if (doc_hint != String()) { + ep->set_tooltip(property_prefix + p.name + "::" + doc_hint); + } else { + ep->set_tooltip(property_prefix + p.name); + } ep->update_property(); ep->update_reload_status(); diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 454622d662..ebe2124a40 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -68,6 +68,7 @@ private: bool can_revert; bool use_folding; + bool draw_top_bg; bool _might_be_in_instance(); bool _is_property_different(const Variant &p_current, const Variant &p_orig, int p_usage); @@ -149,6 +150,8 @@ public: String get_tooltip_text() const; + void set_draw_top_bg(bool p_draw) { draw_top_bg = p_draw; } + EditorProperty(); }; diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index 158eedfb0f..b3ec717d85 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -54,7 +54,11 @@ void EditorLog::_error_handler(void *p_self, const char *p_func, const char *p_f self->emit_signal("show_request"); */ - self->add_message(err_str, true); + if (p_type == ERR_HANDLER_WARNING) { + self->add_message(err_str, MSG_TYPE_WARNING); + } else { + self->add_message(err_str, MSG_TYPE_ERROR); + } } void EditorLog::_notification(int p_what) { @@ -95,22 +99,32 @@ void EditorLog::clear() { _clear_request(); } -void EditorLog::add_message(const String &p_msg, bool p_error) { +void EditorLog::add_message(const String &p_msg, MessageType p_type) { log->add_newline(); - if (p_error) { - log->push_color(get_color("error_color", "Editor")); - Ref<Texture> icon = get_icon("Error", "EditorIcons"); - log->add_image(icon); - log->add_text(" "); - tool_button->set_icon(icon); + bool restore = p_type != MSG_TYPE_STD; + switch (p_type) { + case MSG_TYPE_ERROR: { + log->push_color(get_color("error_color", "Editor")); + Ref<Texture> icon = get_icon("Error", "EditorIcons"); + log->add_image(icon); + log->add_text(" "); + tool_button->set_icon(icon); + } break; + case MSG_TYPE_WARNING: { + log->push_color(get_color("warning_color", "Editor")); + Ref<Texture> icon = get_icon("Warning", "EditorIcons"); + log->add_image(icon); + log->add_text(" "); + tool_button->set_icon(icon); + } break; } log->add_text(p_msg); //button->set_text(p_msg); - if (p_error) + if (restore) log->pop(); } diff --git a/editor/editor_log.h b/editor/editor_log.h index f9bc82de7d..8d0310d914 100644 --- a/editor/editor_log.h +++ b/editor/editor_log.h @@ -42,6 +42,7 @@ #include "scene/gui/panel_container.h" #include "scene/gui/texture_rect.h" #include "scene/gui/tool_button.h" + class EditorLog : public VBoxContainer { GDCLASS(EditorLog, VBoxContainer); @@ -68,7 +69,13 @@ protected: void _notification(int p_what); public: - void add_message(const String &p_msg, bool p_error = false); + enum MessageType { + MSG_TYPE_STD, + MSG_TYPE_ERROR, + MSG_TYPE_WARNING + }; + + void add_message(const String &p_msg, MessageType p_type = MSG_TYPE_STD); void set_tool_button(ToolButton *p_tool_button); void deinit(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 20e8a7915f..4e6f3853c6 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -62,6 +62,8 @@ #include "editor/import/editor_scene_importer_gltf.h" #include "editor/import/resource_importer_bitmask.h" #include "editor/import/resource_importer_csv_translation.h" +#include "editor/import/resource_importer_image.h" +#include "editor/import/resource_importer_layered_texture.h" #include "editor/import/resource_importer_obj.h" #include "editor/import/resource_importer_scene.h" #include "editor/import/resource_importer_texture.h" @@ -108,6 +110,7 @@ #include "editor/plugins/shader_graph_editor_plugin.h" #include "editor/plugins/skeleton_2d_editor_plugin.h" #include "editor/plugins/skeleton_editor_plugin.h" +#include "editor/plugins/skeleton_ik_editor_plugin.h" #include "editor/plugins/spatial_editor_plugin.h" #include "editor/plugins/sprite_editor_plugin.h" #include "editor/plugins/sprite_frames_editor_plugin.h" @@ -598,7 +601,7 @@ void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const St Error err = ResourceSaver::save(path, p_resource, flg | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS); if (err != OK) { - show_accept(TTR("Error saving resource!"), TTR("I see...")); + show_accept(TTR("Error saving resource!"), TTR("OK")); return; } @@ -688,15 +691,15 @@ void EditorNode::_dialog_display_save_error(String p_file, Error p_error) { case ERR_FILE_CANT_WRITE: { - show_accept(TTR("Can't open file for writing:") + " " + p_file.get_extension(), TTR("I see...")); + show_accept(TTR("Can't open file for writing:") + " " + p_file.get_extension(), TTR("OK")); } break; case ERR_FILE_UNRECOGNIZED: { - show_accept(TTR("Requested file format unknown:") + " " + p_file.get_extension(), TTR("I see...")); + show_accept(TTR("Requested file format unknown:") + " " + p_file.get_extension(), TTR("OK")); } break; default: { - show_accept(TTR("Error while saving."), TTR("I see...")); + show_accept(TTR("Error while saving."), TTR("OK")); } break; } } @@ -710,23 +713,23 @@ void EditorNode::_dialog_display_load_error(String p_file, Error p_error) { case ERR_CANT_OPEN: { - show_accept(vformat(TTR("Can't open '%s'. The file could have been moved or deleted."), p_file.get_file()), TTR("I see...")); + show_accept(vformat(TTR("Can't open '%s'. The file could have been moved or deleted."), p_file.get_file()), TTR("OK")); } break; case ERR_PARSE_ERROR: { - show_accept(vformat(TTR("Error while parsing '%s'."), p_file.get_file()), TTR("I see...")); + show_accept(vformat(TTR("Error while parsing '%s'."), p_file.get_file()), TTR("OK")); } break; case ERR_FILE_CORRUPT: { - show_accept(vformat(TTR("Unexpected end of file '%s'."), p_file.get_file()), TTR("I see...")); + show_accept(vformat(TTR("Unexpected end of file '%s'."), p_file.get_file()), TTR("OK")); } break; case ERR_FILE_NOT_FOUND: { - show_accept(vformat(TTR("Missing '%s' or its dependencies."), p_file.get_file()), TTR("I see...")); + show_accept(vformat(TTR("Missing '%s' or its dependencies."), p_file.get_file()), TTR("OK")); } break; default: { - show_accept(vformat(TTR("Error while loading '%s'."), p_file.get_file()), TTR("I see...")); + show_accept(vformat(TTR("Error while loading '%s'."), p_file.get_file()), TTR("OK")); } break; } } @@ -988,7 +991,7 @@ void EditorNode::_save_scene(String p_file, int idx) { if (!scene) { - show_accept(TTR("This operation can't be done without a tree root."), TTR("I see...")); + show_accept(TTR("This operation can't be done without a tree root."), TTR("OK")); return; } @@ -1016,7 +1019,7 @@ void EditorNode::_save_scene(String p_file, int idx) { if (err != OK) { - show_accept(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."), TTR("I see...")); + show_accept(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."), TTR("OK")); return; } @@ -1024,7 +1027,7 @@ void EditorNode::_save_scene(String p_file, int idx) { // (hacky but needed for the tree to update properly) Node *dummy_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); if (!dummy_scene) { - show_accept(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."), TTR("I see...")); + show_accept(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."), TTR("OK")); return; } memdelete(dummy_scene); @@ -1186,7 +1189,7 @@ void EditorNode::_dialog_action(String p_file) { ml = ResourceLoader::load(p_file, "MeshLibrary"); if (ml.is_null()) { - show_accept(TTR("Can't load MeshLibrary for merging!"), TTR("I see...")); + show_accept(TTR("Can't load MeshLibrary for merging!"), TTR("OK")); return; } } @@ -1199,7 +1202,7 @@ void EditorNode::_dialog_action(String p_file) { Error err = ResourceSaver::save(p_file, ml); if (err) { - show_accept(TTR("Error saving MeshLibrary!"), TTR("I see...")); + show_accept(TTR("Error saving MeshLibrary!"), TTR("OK")); return; } @@ -1211,7 +1214,7 @@ void EditorNode::_dialog_action(String p_file) { tileset = ResourceLoader::load(p_file, "TileSet"); if (tileset.is_null()) { - show_accept(TTR("Can't load TileSet for merging!"), TTR("I see...")); + show_accept(TTR("Can't load TileSet for merging!"), TTR("OK")); return; } @@ -1224,7 +1227,7 @@ void EditorNode::_dialog_action(String p_file) { Error err = ResourceSaver::save(p_file, tileset); if (err) { - show_accept("Error saving TileSet!", "I see..."); + show_accept(TTR("Error saving TileSet!"), TTR("OK")); return; } } break; @@ -1578,7 +1581,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) { Node *scene = editor_data.get_edited_scene_root(); if (!scene) { - show_accept(TTR("There is no defined scene to run."), TTR("I see...")); + show_accept(TTR("There is no defined scene to run."), TTR("OK")); return; } @@ -1632,7 +1635,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) { if (scene->get_filename() == "") { - show_accept(TTR("Current scene was never saved, please save it prior to running."), TTR("I see...")); + show_accept(TTR("Current scene was never saved, please save it prior to running."), TTR("OK")); return; } @@ -1663,7 +1666,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) { if (error != OK) { - show_accept(TTR("Could not start subprocess!"), TTR("I see...")); + show_accept(TTR("Could not start subprocess!"), TTR("OK")); return; } @@ -1752,6 +1755,11 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } else { tab_closing = editor_data.get_edited_scene(); } + if (!editor_data.get_edited_scene_root(tab_closing)) { + // empty tab + _scene_tab_closed(tab_closing); + break; + } } // fallthrough case SCENE_TAB_CLOSE: @@ -1781,7 +1789,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if (!scene) { - show_accept(TTR("This operation can't be done without a tree root."), TTR("I see...")); + show_accept(TTR("This operation can't be done without a tree root."), TTR("OK")); break; } @@ -1844,7 +1852,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if (!editor_data.get_edited_scene_root()) { - show_accept(TTR("This operation can't be done without a scene."), TTR("I see...")); + show_accept(TTR("This operation can't be done without a scene."), TTR("OK")); break; } @@ -1864,7 +1872,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { //Make sure that the scene has a root before trying to convert to tileset if (!editor_data.get_edited_scene_root()) { - show_accept(TTR("This operation can't be done without a root node."), TTR("I see...")); + show_accept(TTR("This operation can't be done without a root node."), TTR("OK")); break; } @@ -1885,7 +1893,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if (!editor_data.get_edited_scene_root()) { - show_accept(TTR("This operation can't be done without a selected node."), TTR("I see...")); + show_accept(TTR("This operation can't be done without a selected node."), TTR("OK")); break; } @@ -2162,7 +2170,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { OS::get_singleton()->set_low_processor_usage_mode(false); EditorSettings::get_singleton()->set_project_metadata("editor_options", "update_always", true); - show_accept(TTR("This option is deprecated. Situations where refresh must be forced are now considered a bug. Please report."), TTR("I see...")); + show_accept(TTR("This option is deprecated. Situations where refresh must be forced are now considered a bug. Please report."), TTR("OK")); } break; case SETTINGS_UPDATE_CHANGES: { @@ -2776,7 +2784,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b if (!lpath.begins_with("res://")) { - show_accept(TTR("Error loading scene, it must be inside the project path. Use 'Import' to open the scene, then save it inside the project path."), TTR("Ugh")); + show_accept(TTR("Error loading scene, it must be inside the project path. Use 'Import' to open the scene, then save it inside the project path."), TTR("OK")); opening_prev = false; return ERR_FILE_NOT_FOUND; } @@ -3844,6 +3852,7 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) { Ref<InputEventMouseButton> mb = p_input; if (mb.is_valid()) { + if (scene_tabs->get_hovered_tab() >= 0) { if (mb->get_button_index() == BUTTON_MIDDLE && mb->is_pressed()) { _scene_tab_closed(scene_tabs->get_hovered_tab()); @@ -3853,6 +3862,26 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) { _menu_option_confirm(FILE_NEW_SCENE, true); } } + if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) { + + // context menu + scene_tabs_context_menu->clear(); + scene_tabs_context_menu->set_size(Size2(1, 1)); + + scene_tabs_context_menu->add_shortcut(ED_GET_SHORTCUT("editor/new_scene"), FILE_NEW_SCENE); + if (scene_tabs->get_hovered_tab() >= 0) { + scene_tabs_context_menu->add_shortcut(ED_GET_SHORTCUT("editor/save_scene"), FILE_SAVE_SCENE); + scene_tabs_context_menu->add_shortcut(ED_GET_SHORTCUT("editor/save_scene_as"), FILE_SAVE_AS_SCENE); + } + scene_tabs_context_menu->add_shortcut(ED_GET_SHORTCUT("editor/save_all_scenes"), FILE_SAVE_ALL_SCENES); + if (scene_tabs->get_hovered_tab() >= 0) { + scene_tabs_context_menu->add_separator(); + scene_tabs_context_menu->add_item(TTR("Play This Scene"), RUN_PLAY_SCENE); + scene_tabs_context_menu->add_item(TTR("Close Tab"), FILE_CLOSE); + } + scene_tabs_context_menu->set_position(mb->get_global_position()); + scene_tabs_context_menu->popup(); + } } } @@ -4537,7 +4566,7 @@ static Node *_resource_get_edited_scene() { void EditorNode::_print_handler(void *p_this, const String &p_string, bool p_error) { EditorNode *en = (EditorNode *)p_this; - en->log->add_message(p_string, p_error); + en->log->add_message(p_string, p_error ? EditorLog::MSG_TYPE_ERROR : EditorLog::MSG_TYPE_STD); } EditorNode::EditorNode() { @@ -4638,6 +4667,20 @@ EditorNode::EditorNode() { import_texture.instance(); ResourceFormatImporter::get_singleton()->add_importer(import_texture); + Ref<ResourceImporterLayeredTexture> import_3d; + import_3d.instance(); + import_3d->set_3d(true); + ResourceFormatImporter::get_singleton()->add_importer(import_3d); + + Ref<ResourceImporterLayeredTexture> import_array; + import_array.instance(); + import_array->set_3d(false); + ResourceFormatImporter::get_singleton()->add_importer(import_array); + + Ref<ResourceImporterImage> import_image; + import_image.instance(); + ResourceFormatImporter::get_singleton()->add_importer(import_image); + Ref<ResourceImporterCSVTranslation> import_csv_translation; import_csv_translation.instance(); ResourceFormatImporter::get_singleton()->add_importer(import_csv_translation); @@ -4730,8 +4773,10 @@ EditorNode::EditorNode() { EDITOR_DEF_RST("interface/scene_tabs/show_thumbnail_on_hover", true); EDITOR_DEF_RST("interface/inspector/capitalize_properties", true); EDITOR_DEF_RST("interface/inspector/disable_folding", false); + EDITOR_DEF("interface/inspector/horizontal_vector2_editing", false); + EDITOR_DEF("interface/inspector/horizontal_vector3_editing", true); EDITOR_DEF("interface/inspector/open_resources_in_current_inspector", true); - EDITOR_DEF("interface/inspector/resources_types_to_open_in_new_inspector", "SpatialMaterial"); + EDITOR_DEF("interface/inspector/resources_types_to_open_in_new_inspector", "SpatialMaterial,Script"); EDITOR_DEF("run/auto_save/save_before_running", true); theme_base = memnew(Control); @@ -4908,6 +4953,7 @@ EditorNode::EditorNode() { scene_tabs = memnew(Tabs); scene_tabs->add_style_override("tab_fg", gui_base->get_stylebox("SceneTabFG", "EditorStyles")); scene_tabs->add_style_override("tab_bg", gui_base->get_stylebox("SceneTabBG", "EditorStyles")); + scene_tabs->set_select_with_rmb(true); scene_tabs->add_tab("unsaved"); scene_tabs->set_tab_align(Tabs::ALIGN_LEFT); scene_tabs->set_tab_close_display_policy((bool(EDITOR_DEF("interface/scene_tabs/always_show_close_button", false)) ? Tabs::CLOSE_BUTTON_SHOW_ALWAYS : Tabs::CLOSE_BUTTON_SHOW_ACTIVE_ONLY)); @@ -4925,6 +4971,11 @@ EditorNode::EditorNode() { tabbar_container = memnew(HBoxContainer); scene_tabs->set_h_size_flags(Control::SIZE_EXPAND_FILL); + scene_tabs_context_menu = memnew(PopupMenu); + tabbar_container->add_child(scene_tabs_context_menu); + scene_tabs_context_menu->connect("id_pressed", this, "_menu_option"); + scene_tabs_context_menu->set_hide_on_window_lose_focus(true); + srt->add_child(tabbar_container); tabbar_container->add_child(scene_tabs); distraction_free = memnew(ToolButton); @@ -5031,6 +5082,7 @@ EditorNode::EditorNode() { file_menu->set_tooltip(TTR("Operations with scene files.")); p = file_menu->get_popup(); + p->set_hide_on_window_lose_focus(true); p->add_shortcut(ED_SHORTCUT("editor/new_scene", TTR("New Scene")), FILE_NEW_SCENE); p->add_shortcut(ED_SHORTCUT("editor/new_inherited_scene", TTR("New Inherited Scene...")), FILE_NEW_INHERITED_SCENE); p->add_shortcut(ED_SHORTCUT("editor/open_scene", TTR("Open Scene..."), KEY_MASK_CMD + KEY_O), FILE_OPEN_SCENE); @@ -5076,6 +5128,7 @@ EditorNode::EditorNode() { left_menu_hb->add_child(project_menu); p = project_menu->get_popup(); + p->set_hide_on_window_lose_focus(true); p->add_item(TTR("Project Settings"), RUN_SETTINGS); p->add_separator(); p->connect("id_pressed", this, "_menu_option"); @@ -5111,6 +5164,7 @@ EditorNode::EditorNode() { left_menu_hb->add_child(debug_menu); p = debug_menu->get_popup(); + p->set_hide_on_window_lose_focus(true); p->set_hide_on_item_selection(false); p->add_check_item(TTR("Deploy with Remote Debug"), RUN_DEPLOY_REMOTE_DEBUG); p->set_item_tooltip(p->get_item_count() - 1, TTR("When exporting or deploying, the resulting executable will attempt to connect to the IP of this computer in order to be debugged.")); @@ -5135,8 +5189,9 @@ EditorNode::EditorNode() { settings_menu->set_text(TTR("Editor")); settings_menu->add_style_override("hover", gui_base->get_stylebox("MenuHover", "EditorStyles")); left_menu_hb->add_child(settings_menu); - p = settings_menu->get_popup(); + p = settings_menu->get_popup(); + p->set_hide_on_window_lose_focus(true); p->add_item(TTR("Editor Settings"), SETTINGS_PREFERENCES); p->add_separator(); @@ -5172,6 +5227,7 @@ EditorNode::EditorNode() { left_menu_hb->add_child(help_menu); p = help_menu->get_popup(); + p->set_hide_on_window_lose_focus(true); p->connect("id_pressed", this, "_menu_option"); p->add_icon_item(gui_base->get_icon("ClassList", "EditorIcons"), TTR("Classes"), HELP_CLASSES); p->add_icon_item(gui_base->get_icon("HelpSearch", "EditorIcons"), TTR("Search"), HELP_SEARCH); @@ -5392,6 +5448,7 @@ EditorNode::EditorNode() { bottom_panel->add_child(bottom_panel_vb); bottom_panel_hb = memnew(HBoxContainer); + bottom_panel_hb->set_custom_minimum_size(Size2(0, 24)); // Adjust for the height of the "Expand Bottom Dock" icon. bottom_panel_vb->add_child(bottom_panel_hb); bottom_panel_hb_editors = memnew(HBoxContainer); @@ -5554,6 +5611,7 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor))); add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor))); add_editor_plugin(memnew(SkeletonEditorPlugin(this))); + add_editor_plugin(memnew(SkeletonIKEditorPlugin(this))); add_editor_plugin(memnew(PhysicalBonePlugin(this))); // FIXME: Disabled as (according to reduz) users were complaining that it gets in the way diff --git a/editor/editor_node.h b/editor/editor_node.h index b7224c9393..85aa37ec7e 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -223,6 +223,7 @@ private: //main tabs Tabs *scene_tabs; + PopupMenu *scene_tabs_context_menu; Panel *tab_preview_panel; TextureRect *tab_preview; int tab_closing; diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 843267d673..a926401558 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -479,15 +479,6 @@ void EditorPlugin::notify_resource_saved(const Ref<Resource> &p_resource) { emit_signal("resource_saved", p_resource); } -Ref<SpatialEditorGizmo> EditorPlugin::create_spatial_gizmo(Spatial *p_spatial) { - //?? - if (get_script_instance() && get_script_instance()->has_method("create_spatial_gizmo")) { - return get_script_instance()->call("create_spatial_gizmo", p_spatial); - } - - return Ref<SpatialEditorGizmo>(); -} - bool EditorPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { if (get_script_instance() && get_script_instance()->has_method("forward_canvas_gui_input")) { @@ -765,10 +756,6 @@ void EditorPlugin::_bind_methods() { ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control"))); ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_force_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control"))); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_spatial_gui_input", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); - MethodInfo gizmo = MethodInfo(Variant::OBJECT, "create_spatial_gizmo", PropertyInfo(Variant::OBJECT, "for_spatial", PROPERTY_HINT_RESOURCE_TYPE, "Spatial")); - gizmo.return_val.hint = PROPERTY_HINT_RESOURCE_TYPE; - gizmo.return_val.hint_string = "EditorSpatialGizmo"; - ClassDB::add_virtual_method(get_class_static(), gizmo); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_plugin_name")); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::OBJECT, "get_plugin_icon")); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "has_main_screen")); diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 72e21b2f7f..c417f487dc 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -51,7 +51,6 @@ class Camera; class EditorSelection; class EditorExport; class EditorSettings; -class SpatialEditorGizmo; class EditorImportPlugin; class EditorExportPlugin; class EditorResourcePreview; @@ -171,7 +170,6 @@ public: void notify_scene_closed(const String &scene_filepath); void notify_resource_saved(const Ref<Resource> &p_resource); - virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial); virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event); virtual void forward_draw_over_viewport(Control *p_overlay); virtual void forward_force_draw_over_viewport(Control *p_overlay); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 4fae8467b4..59798bfab3 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -46,11 +46,22 @@ EditorPropertyNil::EditorPropertyNil() { } ///////////////////// TEXT ///////////////////////// + +void EditorPropertyText::_text_entered(const String &p_string) { + if (updating) + return; + + if (text->has_focus()) { + text->release_focus(); + _text_changed(p_string); + } +} + void EditorPropertyText::_text_changed(const String &p_string) { if (updating) return; - emit_signal("property_changed", get_edited_property(), p_string, true); + emit_signal("property_changed", get_edited_property(), p_string); } void EditorPropertyText::update_property() { @@ -64,6 +75,7 @@ void EditorPropertyText::update_property() { void EditorPropertyText::_bind_methods() { ClassDB::bind_method(D_METHOD("_text_changed", "txt"), &EditorPropertyText::_text_changed); + ClassDB::bind_method(D_METHOD("_text_entered", "txt"), &EditorPropertyText::_text_entered); } EditorPropertyText::EditorPropertyText() { @@ -71,6 +83,8 @@ EditorPropertyText::EditorPropertyText() { add_child(text); add_focusable(text); text->connect("text_changed", this, "_text_changed"); + text->connect("text_entered", this, "_text_entered"); + updating = false; } @@ -78,12 +92,12 @@ EditorPropertyText::EditorPropertyText() { void EditorPropertyMultilineText::_big_text_changed() { text->set_text(big_text->get_text()); - emit_signal("property_changed", get_edited_property(), big_text->get_text(), true); + emit_signal("property_changed", get_edited_property(), big_text->get_text()); } void EditorPropertyMultilineText::_text_changed() { - emit_signal("property_changed", get_edited_property(), text->get_text(), true); + emit_signal("property_changed", get_edited_property(), text->get_text()); } void EditorPropertyMultilineText::_open_big_text() { @@ -568,6 +582,7 @@ public: uint32_t value; Vector<Rect2> flag_rects; Vector<String> names; + Vector<String> tooltips; virtual Size2 get_minimum_size() const { Ref<Font> font = get_font("font", "Label"); @@ -576,8 +591,8 @@ public: virtual String get_tooltip(const Point2 &p_pos) const { for (int i = 0; i < flag_rects.size(); i++) { - if (i < names.size() && flag_rects[i].has_point(p_pos)) { - return names[i]; + if (i < tooltips.size() && flag_rects[i].has_point(p_pos)) { + return tooltips[i]; } } return String(); @@ -681,6 +696,7 @@ void EditorPropertyLayers::setup(LayerType p_layer_type) { } Vector<String> names; + Vector<String> tooltips; for (int i = 0; i < 20; i++) { String name; @@ -692,12 +708,12 @@ void EditorPropertyLayers::setup(LayerType p_layer_type) { name = TTR("Layer") + " " + itos(i + 1); } - name += "\n" + vformat(TTR("Bit %d, value %d"), i, 1 << i); - names.push_back(name); + tooltips.push_back(name + "\n" + vformat(TTR("Bit %d, value %d"), i, 1 << i)); } grid->names = names; + grid->tooltips = tooltips; } void EditorPropertyLayers::_button_pressed() { @@ -1067,18 +1083,35 @@ void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, boo } EditorPropertyVector2::EditorPropertyVector2() { - VBoxContainer *vb = memnew(VBoxContainer); - add_child(vb); + bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector2_editing"); + + BoxContainer *bc; + + if (horizontal) { + bc = memnew(HBoxContainer); + add_child(bc); + set_bottom_editor(bc); + } else { + bc = memnew(VBoxContainer); + add_child(bc); + } + static const char *desc[2] = { "x", "y" }; for (int i = 0; i < 2; i++) { spin[i] = memnew(EditorSpinSlider); spin[i]->set_flat(true); spin[i]->set_label(desc[i]); - vb->add_child(spin[i]); + bc->add_child(spin[i]); add_focusable(spin[i]); spin[i]->connect("value_changed", this, "_value_changed"); + if (horizontal) { + spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); + } + } + + if (!horizontal) { + set_label_reference(spin[0]); //show text and buttons around this } - set_label_reference(spin[0]); //show text and buttons around this setting = false; } @@ -1193,19 +1226,35 @@ void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, boo } EditorPropertyVector3::EditorPropertyVector3() { - VBoxContainer *vb = memnew(VBoxContainer); - add_child(vb); + bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector3_editing"); + + BoxContainer *bc; + + if (horizontal) { + bc = memnew(HBoxContainer); + add_child(bc); + set_bottom_editor(bc); + } else { + bc = memnew(VBoxContainer); + add_child(bc); + } + static const char *desc[3] = { "x", "y", "z" }; for (int i = 0; i < 3; i++) { spin[i] = memnew(EditorSpinSlider); - spin[i]->set_label(desc[i]); spin[i]->set_flat(true); - - vb->add_child(spin[i]); + spin[i]->set_label(desc[i]); + bc->add_child(spin[i]); add_focusable(spin[i]); spin[i]->connect("value_changed", this, "_value_changed"); + if (horizontal) { + spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); + } + } + + if (!horizontal) { + set_label_reference(spin[0]); //show text and buttons around this } - set_label_reference(spin[0]); //show text and buttons around this setting = false; } ///////////////////// PLANE ///////////////////////// @@ -1257,18 +1306,36 @@ void EditorPropertyPlane::setup(double p_min, double p_max, double p_step, bool } EditorPropertyPlane::EditorPropertyPlane() { - VBoxContainer *vb = memnew(VBoxContainer); - add_child(vb); + + bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector3_editing"); + + BoxContainer *bc; + + if (horizontal) { + bc = memnew(HBoxContainer); + add_child(bc); + set_bottom_editor(bc); + } else { + bc = memnew(VBoxContainer); + add_child(bc); + } + static const char *desc[4] = { "x", "y", "z", "d" }; for (int i = 0; i < 4; i++) { spin[i] = memnew(EditorSpinSlider); - spin[i]->set_label(desc[i]); spin[i]->set_flat(true); - vb->add_child(spin[i]); + spin[i]->set_label(desc[i]); + bc->add_child(spin[i]); add_focusable(spin[i]); spin[i]->connect("value_changed", this, "_value_changed"); + if (horizontal) { + spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); + } + } + + if (!horizontal) { + set_label_reference(spin[0]); //show text and buttons around this } - set_label_reference(spin[0]); //show text and buttons around this setting = false; } @@ -1321,19 +1388,35 @@ void EditorPropertyQuat::setup(double p_min, double p_max, double p_step, bool p } EditorPropertyQuat::EditorPropertyQuat() { - VBoxContainer *vb = memnew(VBoxContainer); - add_child(vb); + bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector3_editing"); + + BoxContainer *bc; + + if (horizontal) { + bc = memnew(HBoxContainer); + add_child(bc); + set_bottom_editor(bc); + } else { + bc = memnew(VBoxContainer); + add_child(bc); + } + static const char *desc[4] = { "x", "y", "z", "w" }; for (int i = 0; i < 4; i++) { spin[i] = memnew(EditorSpinSlider); - spin[i]->set_label(desc[i]); spin[i]->set_flat(true); - - vb->add_child(spin[i]); + spin[i]->set_label(desc[i]); + bc->add_child(spin[i]); add_focusable(spin[i]); spin[i]->connect("value_changed", this, "_value_changed"); + if (horizontal) { + spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); + } + } + + if (!horizontal) { + set_label_reference(spin[0]); //show text and buttons around this } - set_label_reference(spin[0]); //show text and buttons around this setting = false; } @@ -2171,7 +2254,7 @@ void EditorPropertyResource::_sub_inspector_object_id_selected(int p_id) { void EditorPropertyResource::_open_editor_pressed() { RES res = get_edited_object()->get(get_edited_property()); if (res.is_valid()) { - EditorNode::get_singleton()->edit_resource(res.ptr()); + EditorNode::get_singleton()->edit_item(res.ptr()); } } diff --git a/editor/editor_properties.h b/editor/editor_properties.h index ccd73d2539..d5fac9c1a0 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -54,6 +54,7 @@ class EditorPropertyText : public EditorProperty { bool updating; void _text_changed(const String &p_string); + void _text_entered(const String &p_string); protected: static void _bind_methods(); diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 2bd28170e7..8203c85c6a 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -210,8 +210,8 @@ void EditorPropertyArray::update_property() { default: {} } - if (!array.is_array()) { - edit->set_text(arrtype + "[" + Variant::get_type_name(array.get_type()) + "]"); + if (array.get_type() == Variant::NIL) { + edit->set_text(String("(Nil) ") + arrtype); edit->set_pressed(false); if (vbox) { memdelete(vbox); @@ -219,7 +219,7 @@ void EditorPropertyArray::update_property() { return; } - edit->set_text(arrtype + "[" + itos(array.call("size")) + "]"); + edit->set_text(arrtype + "(size " + itos(array.call("size")) + ")"); #ifdef TOOLS_ENABLED @@ -613,7 +613,13 @@ void EditorPropertyDictionary::_change_type(Object *p_button, int p_index) { void EditorPropertyDictionary::_add_key_value() { + // Do not allow nil as valid key. I experienced errors with this + if (object->get_new_item_key().get_type() == Variant::NIL) { + return; + } + Dictionary dict = object->get_dict(); + dict[object->get_new_item_key()] = object->get_new_item_value(); object->set_new_item_key(Variant()); object->set_new_item_value(Variant()); @@ -663,9 +669,20 @@ void EditorPropertyDictionary::_change_type_menu(int p_index) { void EditorPropertyDictionary::update_property() { - Dictionary dict = get_edited_object()->get(get_edited_property()); + Variant updated_val = get_edited_object()->get(get_edited_property()); + + if (updated_val.get_type() == Variant::NIL) { + edit->set_text("Dictionary (Nil)"); //This provides symmetry with the array property. + edit->set_pressed(false); + if (vbox) { + memdelete(vbox); + } + return; + } + + Dictionary dict = updated_val; - edit->set_text("Dict[" + itos(dict.size()) + "]"); + edit->set_text("Dictionary (size " + itos(dict.size()) + ")"); #ifdef TOOLS_ENABLED @@ -695,9 +712,9 @@ void EditorPropertyDictionary::update_property() { page->set_h_size_flags(SIZE_EXPAND_FILL); page->connect("value_changed", this, "_page_changed"); } else { - //bye bye children of the box - while (vbox->get_child_count() > 1) { - memdelete(vbox->get_child(1)); + // Queue childs for deletion, delete immediately might cause errors. + for (size_t i = 1; i < vbox->get_child_count(); i++) { + vbox->get_child(i)->queue_delete(); } } @@ -941,10 +958,10 @@ void EditorPropertyDictionary::update_property() { prop->update_property(); if (i == amount + 1) { - Button *add_item = memnew(Button); - add_item->set_text(TTR("Add Key/Value Pair")); - add_vbox->add_child(add_item); - add_item->connect("pressed", this, "_add_key_value"); + Button *butt_add_item = memnew(Button); + butt_add_item->set_text(TTR("Add Key/Value Pair")); + butt_add_item->connect("pressed", this, "_add_key_value"); + add_vbox->add_child(butt_add_item); } } @@ -965,8 +982,16 @@ void EditorPropertyDictionary::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { } } + void EditorPropertyDictionary::_edit_pressed() { + Variant prop_val = get_edited_object()->get(get_edited_property()); + if (prop_val.get_type() == Variant::NIL) { + Variant::CallError ce; + prop_val = Variant::construct(Variant::DICTIONARY, NULL, 0, ce); + get_edited_object()->set(get_edited_property(), prop_val); + } + get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed()); update_property(); } diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 02e121b5f1..8e079b1f67 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -396,7 +396,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("text_editor/cursor/block_caret", false); _initial_set("text_editor/cursor/caret_blink", true); - _initial_set("text_editor/cursor/caret_blink_speed", 0.65); + _initial_set("text_editor/cursor/caret_blink_speed", 0.5); hints["text_editor/cursor/caret_blink_speed"] = PropertyInfo(Variant::REAL, "text_editor/cursor/caret_blink_speed", PROPERTY_HINT_RANGE, "0.1, 10, 0.01"); _initial_set("text_editor/cursor/right_click_moves_caret", true); @@ -755,7 +755,7 @@ void EditorSettings::create() { } if (dir->change_dir(data_dir) != OK) { - dir->make_dir(data_dir); + dir->make_dir_recursive(data_dir); if (dir->change_dir(data_dir) != OK) { ERR_PRINT("Cannot create data directory!"); memdelete(dir); @@ -771,14 +771,8 @@ void EditorSettings::create() { // Validate/create cache dir - if (dir->change_dir(cache_path) != OK) { - ERR_PRINT("Cannot find path for cache directory!"); - memdelete(dir); - goto fail; - } - if (dir->change_dir(cache_dir) != OK) { - dir->make_dir(cache_dir); + dir->make_dir_recursive(cache_dir); if (dir->change_dir(cache_dir) != OK) { ERR_PRINT("Cannot create cache directory!"); memdelete(dir); @@ -788,14 +782,8 @@ void EditorSettings::create() { // Validate/create config dir and subdirectories - if (dir->change_dir(config_path) != OK) { - ERR_PRINT("Cannot find path for config directory!"); - memdelete(dir); - goto fail; - } - if (dir->change_dir(config_dir) != OK) { - dir->make_dir(config_dir); + dir->make_dir_recursive(config_dir); if (dir->change_dir(config_dir) != OK) { ERR_PRINT("Cannot create config directory!"); memdelete(dir); diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index 0e6d81d13b..b2c9f9865a 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -30,7 +30,13 @@ #include "editor_spin_slider.h" #include "editor_scale.h" +#include "math/expression.h" #include "os/input.h" + +String EditorSpinSlider::get_tooltip(const Point2 &p_pos) const { + return rtos(get_value()); +} + String EditorSpinSlider::get_text_value() const { int zeros = Math::step_decimals(get_step()); return String::num(get_value(), zeros); @@ -270,10 +276,12 @@ void EditorSpinSlider::_notification(int p_what) { if (p_what == NOTIFICATION_FOCUS_ENTER) { /* Sorry, I dont like this, it makes navigating the different fields with arrows more difficult. * Just press enter to edit. - * if (!Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && !value_input_just_closed) { + * if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && !value_input_just_closed) { _focus_entered(); }*/ - + if ((Input::get_singleton()->is_action_pressed("ui_focus_next") || Input::get_singleton()->is_action_pressed("ui_focus_prev")) && !value_input_just_closed) { + _focus_entered(); + } value_input_just_closed = false; } } @@ -307,6 +315,21 @@ String EditorSpinSlider::get_label() const { return label; } +void EditorSpinSlider::_evaluate_input_text() { + String text = value_input->get_text(); + Ref<Expression> expr; + expr.instance(); + Error err = expr->parse(text); + if (err != OK) { + return; + } + + Variant v = expr->execute(Array(), NULL, false); + if (v.get_type() == Variant::NIL) + return; + set_value(v); +} + //text_entered signal void EditorSpinSlider::_value_input_entered(const String &p_text) { value_input_just_closed = true; @@ -315,13 +338,13 @@ void EditorSpinSlider::_value_input_entered(const String &p_text) { //modal_closed signal void EditorSpinSlider::_value_input_closed() { - set_value(value_input->get_text().to_double()); + _evaluate_input_text(); value_input_just_closed = true; } //focus_exited signal void EditorSpinSlider::_value_focus_exited() { - set_value(value_input->get_text().to_double()); + _evaluate_input_text(); // focus is not on the same element after the vlalue_input was exited // -> focus is on next element // -> TAB was pressed diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h index fb32534ef4..e48eb171b8 100644 --- a/editor/editor_spin_slider.h +++ b/editor/editor_spin_slider.h @@ -73,6 +73,8 @@ class EditorSpinSlider : public Range { bool use_custom_label_color; Color custom_label_color; + void _evaluate_input_text(); + protected: void _notification(int p_what); void _gui_input(const Ref<InputEvent> &p_event); @@ -82,6 +84,8 @@ protected: void _focus_entered(); public: + String get_tooltip(const Point2 &p_pos) const; + String get_text_value() const; void set_label(const String &p_label); String get_label() const; diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 18cc52a5c6..3995eb3dd6 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -175,7 +175,7 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = const Color warning_color = p_theme->get_color("warning_color", "Editor"); dark_icon_color_dictionary[Color::html("#ff5d5d")] = error_color; dark_icon_color_dictionary[Color::html("#45ff8b")] = success_color; - dark_icon_color_dictionary[Color::html("#ffdd65")] = warning_color; + dark_icon_color_dictionary[Color::html("#dbab09")] = warning_color; List<String> exceptions; exceptions.push_back("EditorPivot"); @@ -365,11 +365,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("mono_color", "Editor", mono_color); Color success_color = accent_color.linear_interpolate(Color(0.2, 1, 0.2), 0.6) * 1.2; - Color warning_color = accent_color.linear_interpolate(Color(1, 1, 0), 0.7) * 1.2; + Color warning_color = accent_color.linear_interpolate(Color(1, 1, 0), 0.7) * 1.0; Color error_color = accent_color.linear_interpolate(Color(1, 0, 0), 0.8) * 1.7; + Color property_color = font_color.linear_interpolate(Color(0.5, 0.5, 0.5), 0.5); + if (!dark_theme) { // yellow on white themes is a P.I.T.A. - warning_color = accent_color.linear_interpolate(Color(1, 0.8, 0), 0.9); + warning_color = accent_color.linear_interpolate(Color(0.9, 0.7, 0), 0.9); warning_color = warning_color.linear_interpolate(mono_color, 0.2); success_color = success_color.linear_interpolate(mono_color, 0.2); error_color = error_color.linear_interpolate(mono_color, 0.2); @@ -377,6 +379,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("success_color", "Editor", success_color); theme->set_color("warning_color", "Editor", warning_color); theme->set_color("error_color", "Editor", error_color); + theme->set_color("property_color", "Editor", property_color); // 2d grid color const Color grid_minor_color = mono_color * Color(1.0, 1.0, 1.0, 0.07); @@ -825,6 +828,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color", "LineEdit", font_color); theme->set_color("cursor_color", "LineEdit", font_color); theme->set_color("selection_color", "LineEdit", font_color_selection); + theme->set_color("clear_button_color", "LineEdit", font_color); + theme->set_color("clear_button_color_pressed", "LineEdit", accent_color); // TextEdit theme->set_stylebox("normal", "TextEdit", style_widget); diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index 931785333f..6c9d1568fa 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -178,7 +178,7 @@ void ExportTemplateManager::_uninstall_template_confirm() { _update_template_list(); } -void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_progress) { +bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_progress) { FileAccess *fa = NULL; zlib_filefunc_def io = zipio_create_io_from_file(&fa); @@ -187,7 +187,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ if (!pkg) { EditorNode::get_singleton()->show_warning(TTR("Can't open export templates zip.")); - return; + return false; } int ret = unzGoToFirstFile(pkg); @@ -221,7 +221,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ if (data_str.get_slice_count(".") < 3) { EditorNode::get_singleton()->show_warning(vformat(TTR("Invalid version.txt format inside templates: %s."), data_str)); unzClose(pkg); - return; + return false; } version = data_str; @@ -237,7 +237,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ if (version == String()) { EditorNode::get_singleton()->show_warning(TTR("No version.txt found inside templates.")); unzClose(pkg); - return; + return false; } String template_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(version); @@ -247,7 +247,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ if (err != OK) { EditorNode::get_singleton()->show_warning(TTR("Error creating path for templates:") + "\n" + template_path); unzClose(pkg); - return; + return false; } memdelete(d); @@ -310,6 +310,8 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ unzClose(pkg); _update_template_list(); + + return true; } void ExportTemplateManager::popup_manager() { @@ -401,7 +403,15 @@ void ExportTemplateManager::_http_download_templates_completed(int p_status, int String path = download_templates->get_download_file(); template_list_state->set_text(TTR("Download Complete.")); template_downloader->hide(); - _install_from_file(path, false); + int ret = _install_from_file(path, false); + if (ret) { + Error err = OS::get_singleton()->move_to_trash(path); + if (err != OK) { + EditorNode::get_singleton()->add_io_error(TTR("Cannot remove:") + "\n" + path + "\n"); + } + } else { + WARN_PRINTS(vformat(TTR("Templates installation failed. The problematic templates archives can be found at '%s'."), path)); + } } } break; } diff --git a/editor/export_template_manager.h b/editor/export_template_manager.h index 54a645c69f..bd43fe5dc5 100644 --- a/editor/export_template_manager.h +++ b/editor/export_template_manager.h @@ -70,7 +70,7 @@ class ExportTemplateManager : public ConfirmationDialog { void _uninstall_template_confirm(); virtual void ok_pressed(); - void _install_from_file(const String &p_file, bool p_use_progress = true); + bool _install_from_file(const String &p_file, bool p_use_progress = true); void _http_download_mirror_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); void _http_download_templates_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 37f86cc912..f2c8cde151 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -196,7 +196,8 @@ void FileSystemDock::_notification(int p_what) { files->connect("item_activated", this, "_select_file"); button_hist_next->connect("pressed", this, "_fw_history"); button_hist_prev->connect("pressed", this, "_bw_history"); - search_box->add_icon_override("right_icon", get_icon("Search", ei)); + search_box->set_right_icon(get_icon("Search", ei)); + search_box->set_clear_button_enabled(true); button_hist_next->set_icon(get_icon("Forward", ei)); button_hist_prev->set_icon(get_icon("Back", ei)); @@ -252,7 +253,8 @@ void FileSystemDock::_notification(int p_what) { button_hist_next->set_icon(get_icon("Forward", ei)); button_hist_prev->set_icon(get_icon("Back", ei)); - search_box->add_icon_override("right_icon", get_icon("Search", ei)); + search_box->set_right_icon(get_icon("Search", ei)); + search_box->set_clear_button_enabled(true); if (new_mode != display_mode) { set_display_mode(new_mode); @@ -1408,7 +1410,7 @@ void FileSystemDock::_resource_created() const { RES current_res = RES(r); - editor->save_resource_as(current_res); + editor->save_resource_as(current_res, path); } void FileSystemDock::_go_to_file_list() { @@ -1448,7 +1450,7 @@ void FileSystemDock::_dir_rmb_pressed(const Vector2 &p_pos) { } folder_options->add_separator(); folder_options->add_item(TTR("New Folder..."), FOLDER_NEW_FOLDER); - folder_options->add_item(TTR("Show In File Manager"), FOLDER_SHOW_IN_EXPLORER); + folder_options->add_item(TTR("Open In File Manager"), FOLDER_SHOW_IN_EXPLORER); } folder_options->set_position(tree->get_global_position() + p_pos); folder_options->popup(); @@ -1757,7 +1759,10 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) { file_options->add_item(TTR("New Folder..."), FILE_NEW_FOLDER); file_options->add_item(TTR("New Script..."), FILE_NEW_SCRIPT); file_options->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE); - file_options->add_item(TTR("Show In File Manager"), FILE_SHOW_IN_EXPLORER); + + String fpath = files->get_item_metadata(p_item); + String item_text = fpath.ends_with("/") ? TTR("Open In File Manager") : TTR("Show In File Manager"); + file_options->add_item(item_text, FILE_SHOW_IN_EXPLORER); file_options->set_position(files->get_global_position() + p_pos); file_options->popup(); @@ -1983,9 +1988,11 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { */ file_options = memnew(PopupMenu); + file_options->set_hide_on_window_lose_focus(true); add_child(file_options); folder_options = memnew(PopupMenu); + folder_options->set_hide_on_window_lose_focus(true); add_child(folder_options); split_box = memnew(VSplitContainer); diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index 2bfd2eb5c3..0efd14e932 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -287,8 +287,10 @@ void GroupDialog::_notification(int p_what) { add_button->set_icon(get_icon("Forward", "EditorIcons")); remove_button->set_icon(get_icon("Back", "EditorIcons")); - add_filter->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); - remove_filter->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + add_filter->set_right_icon(get_icon("Search", "EditorIcons")); + add_filter->set_clear_button_enabled(true); + remove_filter->set_right_icon(get_icon("Search", "EditorIcons")); + remove_filter->set_clear_button_enabled(true); } break; } } diff --git a/editor/icons/SCsub b/editor/icons/SCsub index 7f94073e01..31bf8f116a 100644 --- a/editor/icons/SCsub +++ b/editor/icons/SCsub @@ -1,96 +1,14 @@ #!/usr/bin/env python Import('env') -from compat import StringIO +from platform_methods import run_in_subprocess +import editor_icons_builders -def make_editor_icons_action(target, source, env): - import os - - dst = target[0].srcnode().abspath - svg_icons = source - - icons_string = StringIO() - - for f in svg_icons: - - fname = str(f) - - icons_string.write('\t"') - - with open(fname, 'rb') as svgf: - b = svgf.read(1) - while(len(b) == 1): - icons_string.write("\\" + str(hex(ord(b)))[1:]) - b = svgf.read(1) - - - icons_string.write('"') - if fname != svg_icons[-1]: - icons_string.write(",") - icons_string.write('\n') - - s = StringIO() - s.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") - s.write("#ifndef _EDITOR_ICONS_H\n") - s.write("#define _EDITOR_ICONS_H\n") - s.write("static const int editor_icons_count = {};\n".format(len(svg_icons))) - s.write("static const char *editor_icons_sources[] = {\n") - s.write(icons_string.getvalue()) - s.write('};\n\n') - s.write("static const char *editor_icons_names[] = {\n") - - # this is used to store the indices of thumbnail icons - thumb_medium_indices = []; - thumb_big_indices = []; - index = 0 - for f in svg_icons: - - fname = str(f) - - icon_name = os.path.basename(fname)[5:-4].title().replace("_", "") - # some special cases - if icon_name in ['Int', 'Bool', 'Float']: - icon_name = icon_name.lower() - if icon_name.endswith("MediumThumb"): # don't know a better way to handle this - thumb_medium_indices.append(str(index)) - if icon_name.endswith("BigThumb"): # don't know a better way to handle this - thumb_big_indices.append(str(index)) - - s.write('\t"{0}"'.format(icon_name)) - - if fname != svg_icons[-1]: - s.write(",") - s.write('\n') - - index += 1 - - s.write('};\n') - - if thumb_medium_indices: - s.write("\n\n") - s.write("static const int editor_md_thumbs_count = {};\n".format(len(thumb_medium_indices))) - s.write("static const int editor_md_thumbs_indices[] = {") - s.write(", ".join(thumb_medium_indices)) - s.write("};\n") - if thumb_big_indices: - s.write("\n\n") - s.write("static const int editor_bg_thumbs_count = {};\n".format(len(thumb_big_indices))) - s.write("static const int editor_bg_thumbs_indices[] = {") - s.write(", ".join(thumb_big_indices)) - s.write("};\n") - - s.write("#endif\n") - - with open(dst, "w") as f: - f.write(s.getvalue()) - - s.close() - icons_string.close() - -make_editor_icons_builder = Builder(action=make_editor_icons_action, +make_editor_icons_builder = Builder(action=run_in_subprocess(editor_icons_builders.make_editor_icons_action), suffix='.h', src_suffix='.svg') + env['BUILDERS']['MakeEditorIconsBuilder'] = make_editor_icons_builder env.Alias('editor_icons', [env.MakeEditorIconsBuilder('#editor/editor_icons.gen.h', Glob("*.svg"))]) diff --git a/editor/icons/editor_icons_builders.py b/editor/icons/editor_icons_builders.py new file mode 100644 index 0000000000..dfd0802ce9 --- /dev/null +++ b/editor/icons/editor_icons_builders.py @@ -0,0 +1,96 @@ +"""Functions used to generate source files during build time + +All such functions are invoked in a subprocess on Windows to prevent build flakiness. + +""" +import os +from platform_methods import subprocess_main +from compat import StringIO + + +def make_editor_icons_action(target, source, env): + + dst = target[0] + svg_icons = source + + icons_string = StringIO() + + for f in svg_icons: + + fname = str(f) + + icons_string.write('\t"') + + with open(fname, 'rb') as svgf: + b = svgf.read(1) + while(len(b) == 1): + icons_string.write("\\" + str(hex(ord(b)))[1:]) + b = svgf.read(1) + + + icons_string.write('"') + if fname != svg_icons[-1]: + icons_string.write(",") + icons_string.write('\n') + + s = StringIO() + s.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") + s.write("#ifndef _EDITOR_ICONS_H\n") + s.write("#define _EDITOR_ICONS_H\n") + s.write("static const int editor_icons_count = {};\n".format(len(svg_icons))) + s.write("static const char *editor_icons_sources[] = {\n") + s.write(icons_string.getvalue()) + s.write('};\n\n') + s.write("static const char *editor_icons_names[] = {\n") + + # this is used to store the indices of thumbnail icons + thumb_medium_indices = []; + thumb_big_indices = []; + index = 0 + for f in svg_icons: + + fname = str(f) + + icon_name = os.path.basename(fname)[5:-4].title().replace("_", "") + # some special cases + if icon_name in ['Int', 'Bool', 'Float']: + icon_name = icon_name.lower() + if icon_name.endswith("MediumThumb"): # don't know a better way to handle this + thumb_medium_indices.append(str(index)) + if icon_name.endswith("BigThumb"): # don't know a better way to handle this + thumb_big_indices.append(str(index)) + + s.write('\t"{0}"'.format(icon_name)) + + if fname != svg_icons[-1]: + s.write(",") + s.write('\n') + + index += 1 + + s.write('};\n') + + if thumb_medium_indices: + s.write("\n\n") + s.write("static const int editor_md_thumbs_count = {};\n".format(len(thumb_medium_indices))) + s.write("static const int editor_md_thumbs_indices[] = {") + s.write(", ".join(thumb_medium_indices)) + s.write("};\n") + if thumb_big_indices: + s.write("\n\n") + s.write("static const int editor_bg_thumbs_count = {};\n".format(len(thumb_big_indices))) + s.write("static const int editor_bg_thumbs_indices[] = {") + s.write(", ".join(thumb_big_indices)) + s.write("};\n") + + s.write("#endif\n") + + with open(dst, "w") as f: + f.write(s.getvalue()) + + s.close() + icons_string.close() + + +if __name__ == '__main__': + subprocess_main(globals()) diff --git a/editor/icons/icon_add_atlas_tile.svg b/editor/icons/icon_add_atlas_tile.svg new file mode 100644 index 0000000000..912a0ce2c9 --- /dev/null +++ b/editor/icons/icon_add_atlas_tile.svg @@ -0,0 +1,3 @@ +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<path d="m7 1v6h-6v2h6v6h2v-6h6v-2h-6v-6h-2z" fill="#c9cfd4"/> +</svg> diff --git a/editor/icons/icon_add_autotile.svg b/editor/icons/icon_add_autotile.svg new file mode 100644 index 0000000000..2cc34d53b1 --- /dev/null +++ b/editor/icons/icon_add_autotile.svg @@ -0,0 +1,3 @@ +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<path d="m7 1v6h-6v2h6v6h2v-6h6v-2h-6v-6h-2z" fill="#4490fc"/> +</svg> diff --git a/editor/icons/icon_add_single_tile.svg b/editor/icons/icon_add_single_tile.svg new file mode 100644 index 0000000000..01af8e0649 --- /dev/null +++ b/editor/icons/icon_add_single_tile.svg @@ -0,0 +1,3 @@ +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<path d="m7 1v6h-6v2h6v6h2v-6h6v-2h-6v-6h-2z" fill="#fce844"/> +</svg> diff --git a/editor/icons/icon_information_sign.svg b/editor/icons/icon_information_sign.svg new file mode 100644 index 0000000000..95002b6948 --- /dev/null +++ b/editor/icons/icon_information_sign.svg @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_information_sign.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1047" + inkscape:window-height="603" + id="namedview10" + showgrid="false" + inkscape:zoom="14.521571" + inkscape:cx="12.730205" + inkscape:cy="8.6526495" + inkscape:window-x="654" + inkscape:window-y="156" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <path + style="fill:#ffb65d;fill-opacity:1;fill-rule:evenodd;stroke-width:0.57024062" + inkscape:connector-curvature="0" + id="path2" + d="m 4.5291945,14.892249 h 6.8428865 l 3.421444,-3.421444 V 4.6279186 L 11.372081,1.2064749 H 4.5291945 L 1.1077509,4.6279186 v 6.8428864 z" /> + <rect + style="fill:#ffffff;fill-opacity:1;stroke-width:0.57024062" + id="rect829" + width="2.6243541" + height="6.5062103" + x="6.6998501" + y="6.3477535" /> + <ellipse + style="fill:#ffffff;fill-opacity:1;stroke-width:0.57024062" + id="path831" + cx="8.0393629" + cy="4.2154655" + rx="1.3941878" + ry="1.3668507" /> +</svg> diff --git a/editor/icons/icon_texture_3_d.svg b/editor/icons/icon_texture_3_d.svg new file mode 100644 index 0000000000..dafdc8c68d --- /dev/null +++ b/editor/icons/icon_texture_3_d.svg @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg6" + sodipodi:docname="icon_texture_3_d.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata12"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs10" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1853" + inkscape:window-height="1016" + id="namedview8" + showgrid="false" + inkscape:zoom="29.5" + inkscape:cx="15.226978" + inkscape:cy="9.4909723" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="1" + inkscape:current-layer="svg6" /> + <g + id="g830" + transform="translate(0.35954582,-0.28763666)"> + <path + d="M 2,1 C 1.4477153,1 1,1.4477153 1,2 v 12 c 0,0.552285 0.4477153,1 1,1 h 12 c 0.552285,0 1,-0.447715 1,-1 V 2 C 15,1.4477153 14.552285,1 14,1 Z m 1,2 h 10 v 8 H 3 Z" + id="path2" + inkscape:connector-curvature="0" + style="fill:#e0e0e0;fill-opacity:0.99607999" + sodipodi:nodetypes="sssssssssccccc" /> + </g> + <g + aria-label="3D" + transform="scale(0.9167105,1.0908569)" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.12847996px;line-height:1.25;font-family:Ubuntu;-inkscape-font-specification:'Ubuntu Bold';letter-spacing:0px;word-spacing:0px;fill:#e0e0e0;fill-opacity:0.99607843;stroke:none;stroke-width:0.20321201" + id="text834"> + <path + d="m 5.8175194,8.9717502 q -0.2194689,0 -0.4633233,-0.032514 Q 5.1103417,8.9148508 4.8827442,8.86608 4.6551468,8.8173091 4.4681918,8.7604097 4.2812367,8.7035104 4.1755665,8.6547395 L 4.4112924,7.646808 q 0.2113405,0.089413 0.5364797,0.1950835 0.3332677,0.097542 0.8209765,0.097542 0.5608651,0 0.8209764,-0.2113404 0.2601114,-0.2113405 0.2601114,-0.5689936 0,-0.219469 -0.097542,-0.3657816 Q 6.6628814,6.6388764 6.5003118,6.5494632 6.3377422,6.4519214 6.1101447,6.4194075 5.8906758,6.3787651 5.6386929,6.3787651 H 5.167241 V 5.4033475 h 0.5364797 q 0.1788266,0 0.3413962,-0.032514 0.1706981,-0.032514 0.3007537,-0.1056703 0.1300557,-0.081285 0.203212,-0.2113404 0.081285,-0.1381842 0.081285,-0.3413962 0,-0.1544411 -0.065028,-0.2682398 Q 6.5003118,4.3303881 6.3946415,4.2572318 6.2970998,4.1840755 6.1589156,4.1515616 6.0288599,4.1109192 5.8906758,4.1109192 q -0.3495247,0 -0.6502784,0.1056702 Q 4.9477721,4.3222597 4.7039177,4.4767008 L 4.2731082,3.5906965 Q 4.4031639,3.5094117 4.573862,3.4199984 4.7526886,3.3305851 4.964029,3.2574288 5.1753695,3.1842725 5.4110954,3.1355016 q 0.2438544,-0.048771 0.5120943,-0.048771 0.4958373,0 0.8534904,0.1219272 0.3657816,0.1137987 0.6015075,0.3332677 0.2357259,0.2113405 0.3495246,0.5039657 0.1137987,0.2844968 0.1137987,0.625893 0,0.3332677 -0.186955,0.6502784 -0.186955,0.3088822 -0.5039657,0.4714518 0.4389379,0.1788266 0.6746638,0.5364797 0.2438544,0.3495246 0.2438544,0.8453619 0,0.3901671 -0.1300557,0.7234347 Q 7.808997,8.22393 7.5326287,8.4677844 7.2562604,8.7035104 6.825451,8.8416945 6.40277,8.9717502 5.8175194,8.9717502 Z" + style="fill:#e0e0e0;fill-opacity:0.99607843;stroke-width:0.20321201" + id="path836" /> + <path + d="m 10.502445,7.817506 q 0.08941,0.00813 0.203212,0.016257 0.121927,0 0.284497,0 0.951032,0 1.406227,-0.4795803 0.463323,-0.4795803 0.463323,-1.3249422 0,-0.8860044 -0.438938,-1.3411992 -0.438938,-0.4551949 -1.38997,-0.4551949 -0.130055,0 -0.26824,0.00813 -0.138184,0 -0.260111,0.016257 z M 14.16839,6.0292405 q 0,0.7315631 -0.227598,1.2761713 -0.227597,0.5446082 -0.650278,0.9022613 -0.414553,0.3576531 -1.01606,0.5364797 -0.601508,0.1788265 -1.349328,0.1788265 -0.341396,0 -0.796591,-0.032514 Q 9.6733402,8.86608 9.2344022,8.7766667 v -5.486724 q 0.438938,-0.081285 0.9103898,-0.1056702 0.47958,-0.032514 0.820976,-0.032514 0.723435,0 1.308686,0.1625696 0.593379,0.1625696 1.01606,0.5120943 0.422681,0.3495246 0.650278,0.8941328 0.227598,0.5446081 0.227598,1.3086853 z" + style="fill:#e0e0e0;fill-opacity:0.99607843;stroke-width:0.20321201" + id="path838" /> + </g> +</svg> diff --git a/editor/icons/icon_texture_array.svg b/editor/icons/icon_texture_array.svg new file mode 100644 index 0000000000..8297fc0f5d --- /dev/null +++ b/editor/icons/icon_texture_array.svg @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg6" + sodipodi:docname="icon_texture_array.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata12"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs10" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1526" + inkscape:window-height="766" + id="namedview8" + showgrid="false" + inkscape:zoom="29.5" + inkscape:cx="8.3117238" + inkscape:cy="9.4909723" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg6" /> + <g + id="g830" + transform="translate(0.35954582,-0.28763666)"> + <path + d="M 2,1 C 1.4477153,1 1,1.4477153 1,2 v 12 c 0,0.552285 0.4477153,1 1,1 h 12 c 0.552285,0 1,-0.447715 1,-1 V 2 C 15,1.4477153 14.552285,1 14,1 Z m 1,2 h 10 v 8 H 3 Z" + id="path2" + inkscape:connector-curvature="0" + style="fill:#e0e0e0;fill-opacity:0.99607999" + sodipodi:nodetypes="sssssssssccccc" /> + </g> + <g + aria-label="[]" + transform="matrix(1.6197742,0,0,0.750929,-3.7231532,1.8329569)" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.29580784px;line-height:1.25;font-family:Ubuntu;-inkscape-font-specification:'Ubuntu Bold';letter-spacing:0px;word-spacing:0px;fill:#e0e0e0;fill-opacity:0.99607843;stroke:none;stroke-width:0.2073952" + id="text834"> + <path + d="M 4.7302951,2.4553483 H 6.978459 V 3.4425495 H 5.9082998 V 9.4984892 H 6.978459 V 10.48569 H 4.7302951 Z" + style="fill:#e0e0e0;fill-opacity:0.99607843;stroke-width:0.2073952" + id="path862" + inkscape:connector-curvature="0" /> + <path + d="M 10.138643,10.48569 H 7.8904794 V 9.4984892 H 8.9606386 V 3.4425495 H 7.8904794 V 2.4553483 h 2.2481636 z" + style="fill:#e0e0e0;fill-opacity:0.99607843;stroke-width:0.2073952" + id="path864" + inkscape:connector-curvature="0" /> + </g> +</svg> diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index 7cfaa9070f..906d902b4a 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -203,7 +203,6 @@ Error EditorSceneImporterGLTF::_parse_nodes(GLTFState &state) { GLTFNode *node = memnew(GLTFNode); Dictionary n = nodes[i]; - print_line("node " + itos(i) + ": " + String(Variant(n))); if (n.has("name")) { node->name = n["name"]; } @@ -1657,6 +1656,7 @@ void EditorSceneImporterGLTF::_generate_node(GLTFState &state, int p_node, Node if (n->mesh >= 0) { ERR_FAIL_INDEX(n->mesh, state.meshes.size()); MeshInstance *mi = memnew(MeshInstance); + print_line("**creating mesh for: " + n->name); GLTFMesh &mesh = state.meshes.write[n->mesh]; mi->set_mesh(mesh.mesh); if (mesh.mesh->get_name() == "") { @@ -1686,20 +1686,22 @@ void EditorSceneImporterGLTF::_generate_node(GLTFState &state, int p_node, Node node->set_name(n->name); - p_parent->add_child(node); - node->set_owner(p_owner); - node->set_transform(n->xform); - n->godot_nodes.push_back(node); if (n->skin >= 0 && Object::cast_to<MeshInstance>(node)) { MeshInstance *mi = Object::cast_to<MeshInstance>(node); - //move skeleton around and place it on node, as the node _is_ a skeleton. + Skeleton *s = skeletons[n->skin]; - state.paths_to_skeleton[mi] = s; - //move it later, as skeleton may be moved around first + s->add_child(node); //According to spec, mesh should actually act as a child of the skeleton, as it inherits its transform + mi->set_skeleton_path(String("..")); + + } else { + p_parent->add_child(node); + node->set_transform(n->xform); } + node->set_owner(p_owner); + #if 0 for (int i = 0; i < n->skeleton_children.size(); i++) { @@ -1729,6 +1731,10 @@ void EditorSceneImporterGLTF::_generate_bone(GLTFState &state, int p_node, Vecto skeletons[i]->get_parent()->remove_child(skeletons[i]); p_parent_node->add_child(skeletons[i]); skeletons[i]->set_owner(owner); + //may have meshes as children, set owner in them too + for (int j = 0; j < skeletons[i]->get_child_count(); j++) { + skeletons[i]->get_child(j)->set_owner(owner); + } } } @@ -1744,10 +1750,8 @@ void EditorSceneImporterGLTF::_generate_bone(GLTFState &state, int p_node, Vecto const int parent = gltf_bone_node->parent; const int parent_index = s->find_bone(state.nodes[parent]->name); - s->add_bone(bone_name); const int bone_index = s->find_bone(bone_name); s->set_bone_parent(bone_index, parent_index); - s->set_bone_rest(bone_index, state.skins[skin].bones[n->joints[i].bone].inverse_bind.affine_inverse()); n->godot_nodes.push_back(s); n->joints.write[i].godot_bone_index = bone_index; @@ -1979,8 +1983,9 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye if (node->joints.size()) { Transform xform; - xform.basis = Basis(rot); - xform.basis.scale(scale); + //xform.basis = Basis(rot); + //xform.basis.scale(scale); + xform.basis.set_quat_scale(rot, scale); xform.origin = pos; Skeleton *skeleton = skeletons[node->joints[i].skin]; @@ -2061,6 +2066,10 @@ Spatial *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, int p_bake_f if (name == "") { name = _gen_unique_name(state, "Skeleton"); } + for (int j = 0; j < state.skins[i].bones.size(); j++) { + s->add_bone(state.nodes[state.skins[i].bones[j].node]->name); + s->set_bone_rest(j, state.skins[i].bones[j].inverse_bind.affine_inverse()); + } s->set_name(name); root->add_child(s); s->set_owner(root); @@ -2074,12 +2083,6 @@ Spatial *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, int p_bake_f } } - for (Map<Node *, Skeleton *>::Element *E = state.paths_to_skeleton.front(); E; E = E->next()) { - MeshInstance *mi = Object::cast_to<MeshInstance>(E->key()); - ERR_CONTINUE(!mi); - mi->set_skeleton_path(mi->get_path_to(E->get())); - } - for (int i = 0; i < skeletons.size(); i++) { skeletons[i]->localize_rests(); } diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h index e8f3bdff62..8258ec41fd 100644 --- a/editor/import/editor_scene_importer_gltf.h +++ b/editor/import/editor_scene_importer_gltf.h @@ -275,7 +275,6 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { Vector<GLTFAnimation> animations; Map<int, Vector<int> > skeleton_nodes; - Map<Node *, Skeleton *> paths_to_skeleton; //Map<int, Vector<int> > skin_users; //cache skin users diff --git a/editor/import/resource_importer_image.cpp b/editor/import/resource_importer_image.cpp new file mode 100644 index 0000000000..b6a67c0cd3 --- /dev/null +++ b/editor/import/resource_importer_image.cpp @@ -0,0 +1,79 @@ +#include "resource_importer_image.h" + +#include "io/image_loader.h" +#include "io/resource_saver.h" +#include "os/file_access.h" +#include "scene/resources/texture.h" + +String ResourceImporterImage::get_importer_name() const { + + return "image"; +} + +String ResourceImporterImage::get_visible_name() const { + + return "Image"; +} +void ResourceImporterImage::get_recognized_extensions(List<String> *p_extensions) const { + + ImageLoader::get_recognized_extensions(p_extensions); +} + +String ResourceImporterImage::get_save_extension() const { + return "image"; +} + +String ResourceImporterImage::get_resource_type() const { + + return "Image"; +} + +bool ResourceImporterImage::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const { + + return true; +} + +int ResourceImporterImage::get_preset_count() const { + return 0; +} +String ResourceImporterImage::get_preset_name(int p_idx) const { + + return String(); +} + +void ResourceImporterImage::get_import_options(List<ImportOption> *r_options, int p_preset) const { +} + +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) { + + FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ); + if (!f) { + ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + } + + size_t len = f->get_len(); + + Vector<uint8_t> data; + data.resize(len); + + f->get_buffer(data.ptrw(), len); + + memdelete(f); + + f = FileAccess::open(p_save_path + ".image", FileAccess::WRITE); + + //save the header GDIM + const uint8_t header[4] = { 'G', 'D', 'I', 'M' }; + f->store_buffer(header, 4); + //SAVE the extension (so it can be recognized by the loader later + f->store_pascal_string(p_source_file.get_extension().to_lower()); + //SAVE the actual image + f->store_buffer(data.ptr(), len); + + memdelete(f); + + return OK; +} + +ResourceImporterImage::ResourceImporterImage() { +} diff --git a/editor/import/resource_importer_image.h b/editor/import/resource_importer_image.h new file mode 100644 index 0000000000..5aadd00a35 --- /dev/null +++ b/editor/import/resource_importer_image.h @@ -0,0 +1,27 @@ +#ifndef RESOURCE_IMPORTER_IMAGE_H +#define RESOURCE_IMPORTER_IMAGE_H + +#include "image.h" +#include "io/resource_import.h" + +class ResourceImporterImage : public ResourceImporter { + GDCLASS(ResourceImporterImage, ResourceImporter) +public: + virtual String get_importer_name() const; + virtual String get_visible_name() const; + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual String get_save_extension() const; + virtual String get_resource_type() const; + + virtual int get_preset_count() const; + virtual String get_preset_name(int p_idx) const; + + virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const; + virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const; + + 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 = NULL); + + ResourceImporterImage(); +}; + +#endif // RESOURCE_IMPORTER_IMAGE_H diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp new file mode 100644 index 0000000000..2f958a6fdd --- /dev/null +++ b/editor/import/resource_importer_layered_texture.cpp @@ -0,0 +1,274 @@ +#include "resource_importer_layered_texture.h" + +#include "resource_importer_texture.h" + +#include "editor/editor_file_system.h" +#include "editor/editor_node.h" +#include "io/config_file.h" +#include "io/image_loader.h" +#include "scene/resources/texture.h" + +String ResourceImporterLayeredTexture::get_importer_name() const { + + return is_3d ? "texture_3d" : "texture_array"; +} + +String ResourceImporterLayeredTexture::get_visible_name() const { + + return is_3d ? "Texture3D" : "TextureArray"; +} +void ResourceImporterLayeredTexture::get_recognized_extensions(List<String> *p_extensions) const { + + ImageLoader::get_recognized_extensions(p_extensions); +} +String ResourceImporterLayeredTexture::get_save_extension() const { + return is_3d ? "tex3d" : "texarr"; +} + +String ResourceImporterLayeredTexture::get_resource_type() const { + + return is_3d ? "Texture3D" : "TextureArray"; +} + +bool ResourceImporterLayeredTexture::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const { + + return true; +} + +int ResourceImporterLayeredTexture::get_preset_count() const { + return 3; +} +String ResourceImporterLayeredTexture::get_preset_name(int p_idx) const { + + static const char *preset_names[] = { + "3D", + "2D", + "ColorCorrect" + }; + + return preset_names[p_idx]; +} + +void ResourceImporterLayeredTexture::get_import_options(List<ImportOption> *r_options, int p_preset) const { + + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Video RAM,Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), p_preset == PRESET_3D ? 1 : 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirrored"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/filter"), true)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/mipmaps"), p_preset == PRESET_COLOR_CORRECT ? 0 : 1)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/srgb", PROPERTY_HINT_ENUM, "Disable,Enable"), p_preset == PRESET_3D ? 1 : 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/horizontal", PROPERTY_HINT_RANGE, "1,256,1"), p_preset == PRESET_COLOR_CORRECT ? 16 : 8)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/vertical", PROPERTY_HINT_RANGE, "1,256,1"), p_preset == PRESET_COLOR_CORRECT ? 1 : 8)); +} + +void ResourceImporterLayeredTexture::_save_tex(const Vector<Ref<Image> > &p_images, const String &p_to_path, int p_compress_mode, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags) { + + FileAccess *f = FileAccess::open(p_to_path, FileAccess::WRITE); + f->store_8('G'); + f->store_8('D'); + if (is_3d) { + f->store_8('3'); + } else { + f->store_8('A'); + } + f->store_8('T'); //godot streamable texture + + f->store_32(p_images[0]->get_width()); + f->store_32(p_images[0]->get_height()); + f->store_32(p_images.size()); //depth + f->store_32(p_texture_flags); + if (p_compress_mode != COMPRESS_VIDEO_RAM) { + //vram needs to do a first compression to tell what the format is, for the rest its ok + f->store_32(p_images[0]->get_format()); + f->store_32(p_compress_mode); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed + } + + if ((p_compress_mode == COMPRESS_LOSSLESS) && p_images[0]->get_format() > Image::FORMAT_RGBA8) { + p_compress_mode = COMPRESS_UNCOMPRESSED; //these can't go as lossy + } + + for (int i = 0; i < p_images.size(); i++) { + + switch (p_compress_mode) { + case COMPRESS_LOSSLESS: { + + Ref<Image> image = p_images[i]->duplicate(); + if (p_mipmaps) { + image->generate_mipmaps(); + } else { + image->clear_mipmaps(); + } + + int mmc = image->get_mipmap_count() + 1; + f->store_32(mmc); + + for (int i = 0; i < mmc; i++) { + + if (i > 0) { + image->shrink_x2(); + } + + PoolVector<uint8_t> data = Image::lossless_packer(image); + int data_len = data.size(); + f->store_32(data_len); + + PoolVector<uint8_t>::Read r = data.read(); + f->store_buffer(r.ptr(), data_len); + } + + } break; + case COMPRESS_VIDEO_RAM: { + + Ref<Image> image = p_images[i]->duplicate(); + image->generate_mipmaps(false); + + Image::CompressSource csource = Image::COMPRESS_SOURCE_LAYERED; + image->compress(p_vram_compression, csource, 0.7); + + if (i == 0) { + //hack so we can properly tell the format + f->store_32(image->get_format()); + f->store_32(p_compress_mode); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed + } + + PoolVector<uint8_t> data = image->get_data(); + int dl = data.size(); + + PoolVector<uint8_t>::Read r = data.read(); + f->store_buffer(r.ptr(), dl); + } break; + case COMPRESS_UNCOMPRESSED: { + + Ref<Image> image = p_images[i]->duplicate(); + + if (p_mipmaps) { + image->generate_mipmaps(); + } else { + image->clear_mipmaps(); + } + + PoolVector<uint8_t> data = image->get_data(); + int dl = data.size(); + + PoolVector<uint8_t>::Read r = data.read(); + + f->store_buffer(r.ptr(), dl); + + } break; + } + } + + memdelete(f); +} + +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) { + + int compress_mode = p_options["compress/mode"]; + int repeat = p_options["flags/repeat"]; + bool filter = p_options["flags/filter"]; + bool mipmaps = p_options["flags/mipmaps"]; + int srgb = p_options["flags/srgb"]; + int hslices = p_options["slices/horizontal"]; + int vslices = p_options["slices/vertical"]; + + Ref<Image> image; + image.instance(); + Error err = ImageLoader::load_image(p_source_file, image, NULL, false, 1.0); + if (err != OK) + return err; + + int tex_flags = 0; + if (repeat > 0) + tex_flags |= Texture::FLAG_REPEAT; + if (repeat == 2) + tex_flags |= Texture::FLAG_MIRRORED_REPEAT; + if (filter) + tex_flags |= Texture::FLAG_FILTER; + if (mipmaps || compress_mode == COMPRESS_VIDEO_RAM) + tex_flags |= Texture::FLAG_MIPMAPS; + if (srgb == 1) + tex_flags |= Texture::FLAG_CONVERT_TO_LINEAR; + + Vector<Ref<Image> > slices; + + int slice_w = image->get_width() / hslices; + int slice_h = image->get_height() / vslices; + + //optimize + if (compress_mode == COMPRESS_VIDEO_RAM) { + //if using video ram, optimize + if (srgb) { + //remove alpha if not needed, so compression is more efficient + if (image->get_format() == Image::FORMAT_RGBA8 && !image->detect_alpha()) { + image->convert(Image::FORMAT_RGB8); + } + } else { + image->optimize_channels(); + } + } + + for (int i = 0; i < vslices; i++) { + for (int j = 0; j < hslices; j++) { + int x = slice_w * j; + int y = slice_h * i; + Ref<Image> slice = image->get_rect(Rect2(x, y, slice_w, slice_h)); + ERR_CONTINUE(slice.is_null() || slice->empty()); + if (slice->get_width() != slice_w || slice->get_height() != slice_h) { + slice->resize(slice_w, slice_h); + } + slices.push_back(slice); + } + } + + String extension = get_save_extension(); + + if (compress_mode == COMPRESS_VIDEO_RAM) { + //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; + + if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_s3tc")) { + + _save_tex(slices, p_save_path + ".s3tc." + extension, compress_mode, Image::COMPRESS_S3TC, mipmaps, tex_flags); + r_platform_variants->push_back("s3tc"); + ok_on_pc = true; + } + + if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2")) { + + _save_tex(slices, p_save_path + ".etc2." + extension, compress_mode, Image::COMPRESS_ETC2, mipmaps, tex_flags); + r_platform_variants->push_back("etc2"); + } + + if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc")) { + _save_tex(slices, p_save_path + ".etc." + extension, compress_mode, Image::COMPRESS_ETC, mipmaps, tex_flags); + r_platform_variants->push_back("etc"); + } + + if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc")) { + + _save_tex(slices, p_save_path + ".pvrtc." + extension, compress_mode, Image::COMPRESS_PVRTC4, mipmaps, tex_flags); + r_platform_variants->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 correcly on PC."); + } + } else { + //import normally + _save_tex(slices, p_save_path + "." + extension, compress_mode, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, tex_flags); + } + + return OK; +} + +ResourceImporterLayeredTexture *ResourceImporterLayeredTexture::singleton = NULL; + +ResourceImporterLayeredTexture::ResourceImporterLayeredTexture() { + + singleton = this; + is_3d = true; +} + +ResourceImporterLayeredTexture::~ResourceImporterLayeredTexture() { +} diff --git a/editor/import/resource_importer_layered_texture.h b/editor/import/resource_importer_layered_texture.h new file mode 100644 index 0000000000..ec73b2624d --- /dev/null +++ b/editor/import/resource_importer_layered_texture.h @@ -0,0 +1,57 @@ +#ifndef RESOURCE_IMPORTER_LAYERED_TEXTURE_H +#define RESOURCE_IMPORTER_LAYERED_TEXTURE_H + +#include "image.h" +#include "io/resource_import.h" + +class StreamTexture; + +class ResourceImporterLayeredTexture : public ResourceImporter { + GDCLASS(ResourceImporterLayeredTexture, ResourceImporter) + + bool is_3d; + +protected: + static void _texture_reimport_srgb(const Ref<StreamTexture> &p_tex); + static void _texture_reimport_3d(const Ref<StreamTexture> &p_tex); + static void _texture_reimport_normal(const Ref<StreamTexture> &p_tex); + + static ResourceImporterLayeredTexture *singleton; + +public: + static ResourceImporterLayeredTexture *get_singleton() { return singleton; } + virtual String get_importer_name() const; + virtual String get_visible_name() const; + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual String get_save_extension() const; + virtual String get_resource_type() const; + + enum Preset { + PRESET_3D, + PRESET_2D, + PRESET_COLOR_CORRECT, + }; + + enum CompressMode { + COMPRESS_LOSSLESS, + COMPRESS_VIDEO_RAM, + COMPRESS_UNCOMPRESSED + }; + + virtual int get_preset_count() const; + virtual String get_preset_name(int p_idx) const; + + virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const; + virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const; + + void _save_tex(const Vector<Ref<Image> > &p_images, const String &p_to_path, int p_compress_mode, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags); + + 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 = NULL); + + void update_imports(); + + void set_3d(bool p_3d) { is_3d = p_3d; } + ResourceImporterLayeredTexture(); + ~ResourceImporterLayeredTexture(); +}; +#endif // RESOURCE_IMPORTER_LAYERED_TEXTURE_H diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index b8dd4a87b7..5babf6419c 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -224,6 +224,13 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p while (true) { String l = f->get_line().strip_edges(); + while (l.length() && l[l.length() - 1] == '\\') { + String add = f->get_line().strip_edges(); + l += add; + if (add == String()) { + break; + } + } if (l.begins_with("v ")) { //vertex @@ -264,10 +271,12 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p face[0] = v[1].split("/"); face[1] = v[2].split("/"); ERR_FAIL_COND_V(face[0].size() == 0, ERR_FILE_CORRUPT); + ERR_FAIL_COND_V(face[0].size() != face[1].size(), ERR_FILE_CORRUPT); for (int i = 2; i < v.size() - 1; i++) { face[2] = v[i + 1].split("/"); + ERR_FAIL_COND_V(face[0].size() != face[2].size(), ERR_FILE_CORRUPT); for (int j = 0; j < 3; j++) { diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 43baabe2f5..615e9df043 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -142,7 +142,7 @@ void InspectorDock::_resource_file_selected(String p_file) { RES res = ResourceLoader::load(p_file); if (res.is_null()) { - warning_dialog->get_ok()->set_text("Ugh"); + warning_dialog->get_ok()->set_text(TTR("OK")); warning_dialog->set_text(TTR("Failed to load resource.")); return; }; @@ -529,7 +529,8 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) { search = memnew(LineEdit); search->set_h_size_flags(Control::SIZE_EXPAND_FILL); search->set_placeholder(TTR("Filter properties")); - search->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + search->set_right_icon(get_icon("Search", "EditorIcons")); + search->set_clear_button_enabled(true); add_child(search); warning = memnew(Button); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index e98dfceb90..4ed2b051aa 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -384,14 +384,11 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int return; } - progress->set_max(download->get_body_size()); - progress->set_value(download->get_downloaded_bytes()); - install->set_disabled(false); + status->set_text(TTR("Success!")); + // Make the progress bar invisible but don't reflow other Controls around it + progress->set_modulate(Color(0, 0, 0, 0)); - progress->set_value(download->get_downloaded_bytes()); - - status->set_text(TTR("Success!") + " (" + String::humanize_size(download->get_downloaded_bytes()) + ")"); set_process(false); } @@ -413,25 +410,37 @@ void EditorAssetLibraryItemDownload::_notification(int p_what) { if (p_what == NOTIFICATION_PROCESS) { - progress->set_max(download->get_body_size()); - progress->set_value(download->get_downloaded_bytes()); + // Make the progress bar visible again when retrying the download + progress->set_modulate(Color(1, 1, 1, 1)); + + if (download->get_downloaded_bytes() > 0) { + progress->set_max(download->get_body_size()); + progress->set_value(download->get_downloaded_bytes()); + } int cstatus = download->get_http_client_status(); - if (cstatus == HTTPClient::STATUS_BODY) - status->set_text(TTR("Fetching:") + " " + String::humanize_size(download->get_downloaded_bytes())); + if (cstatus == HTTPClient::STATUS_BODY) { + status->set_text(vformat(TTR("Downloading (%s / %s)..."), String::humanize_size(download->get_downloaded_bytes()), String::humanize_size(download->get_body_size()))); + } if (cstatus != prev_status) { switch (cstatus) { case HTTPClient::STATUS_RESOLVING: { status->set_text(TTR("Resolving...")); + progress->set_max(1); + progress->set_value(0); } break; case HTTPClient::STATUS_CONNECTING: { status->set_text(TTR("Connecting...")); + progress->set_max(1); + progress->set_value(0); } break; case HTTPClient::STATUS_REQUESTING: { status->set_text(TTR("Requesting...")); + progress->set_max(1); + progress->set_value(0); } break; default: {} } @@ -527,7 +536,7 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() { hb2->add_child(retry); hb2->add_child(install); - set_custom_minimum_size(Size2(250, 0)); + set_custom_minimum_size(Size2(310, 0)); download = memnew(HTTPRequest); add_child(download); @@ -554,6 +563,8 @@ void EditorAssetLibrary::_notification(int p_what) { error_tr->set_texture(get_icon("Error", "EditorIcons")); reverse->set_icon(get_icon("Sort", "EditorIcons")); + filter->set_right_icon(get_icon("Search", "EditorIcons")); + filter->set_clear_button_enabled(true); error_label->raise(); } break; @@ -604,6 +615,8 @@ void EditorAssetLibrary::_notification(int p_what) { library_scroll_bg->add_style_override("panel", get_stylebox("bg", "Tree")); error_tr->set_texture(get_icon("Error", "EditorIcons")); reverse->set_icon(get_icon("Sort", "EditorIcons")); + filter->set_right_icon(get_icon("Search", "EditorIcons")); + filter->set_clear_button_enabled(true); } break; } } diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index eed6b5a95c..145a2ef9bb 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -375,33 +375,24 @@ Rect2 CanvasItemEditor::_get_encompassing_rect_from_list(List<CanvasItem *> p_li // Handles the first element CanvasItem *canvas_item = p_list.front()->get(); - Rect2 rect; - if (canvas_item->_edit_use_rect()) { - rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_rect().position + canvas_item->_edit_get_rect().size / 2), Size2()); - } else { - rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(Point2()), Size2()); - } + Rect2 rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_rect().position + canvas_item->_edit_get_rect().size / 2), Size2()); // Expand with the other ones for (List<CanvasItem *>::Element *E = p_list.front(); E; E = E->next()) { CanvasItem *canvas_item = E->get(); Transform2D xform = canvas_item->get_global_transform_with_canvas(); - if (canvas_item->_edit_use_rect()) { - Rect2 current_rect = canvas_item->_edit_get_rect(); - rect.expand_to(xform.xform(current_rect.position)); - rect.expand_to(xform.xform(current_rect.position + Vector2(current_rect.size.x, 0))); - rect.expand_to(xform.xform(current_rect.position + current_rect.size)); - rect.expand_to(xform.xform(current_rect.position + Vector2(0, current_rect.size.y))); - } else { - rect.expand_to(xform.xform(Point2())); - } + Rect2 current_rect = canvas_item->_edit_get_rect(); + rect.expand_to(xform.xform(current_rect.position)); + rect.expand_to(xform.xform(current_rect.position + Vector2(current_rect.size.x, 0))); + rect.expand_to(xform.xform(current_rect.position + current_rect.size)); + rect.expand_to(xform.xform(current_rect.position + Vector2(0, current_rect.size.y))); } return rect; } -void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) { +void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, bool include_locked_nodes) { if (!p_node) return; if (Object::cast_to<Viewport>(p_node)) @@ -409,12 +400,6 @@ void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, c const CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node); - /*bool inherited = p_node != get_tree()->get_edited_scene_root() && p_node->get_filename() != ""; - bool editable = !inherited || EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node); - bool lock_children = p_node->has_meta("_edit_group_") && p_node->get_meta("_edit_group_"); - - if (!lock_children && editable) {}*/ - for (int i = p_node->get_child_count() - 1; i >= 0; i--) { if (canvas_item && !canvas_item->is_set_as_toplevel()) { _expand_encompassing_rect_using_children(r_rect, p_node->get_child(i), r_first, p_parent_xform * canvas_item->get_transform(), p_canvas_xform); @@ -424,28 +409,17 @@ void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, c } } - if (canvas_item && canvas_item->is_visible_in_tree() && !canvas_item->has_meta("_edit_lock_")) { + if (canvas_item && canvas_item->is_visible_in_tree() && (include_locked_nodes || !canvas_item->has_meta("_edit_lock_"))) { Transform2D xform = p_parent_xform * p_canvas_xform * canvas_item->get_transform(); - if (canvas_item->_edit_use_rect()) { - Rect2 rect = canvas_item->_edit_get_rect(); - if (r_first) { - r_rect = Rect2(xform.xform(rect.position + rect.size / 2), Size2()); - r_first = false; - } - if (r_rect.size != Size2()) { - r_rect.expand_to(xform.xform(rect.position)); - r_rect.expand_to(xform.xform(rect.position + Point2(rect.size.x, 0))); - r_rect.expand_to(xform.xform(rect.position + Point2(0, rect.size.y))); - r_rect.expand_to(xform.xform(rect.position + rect.size)); - } - } else { - if (r_first) { - r_rect = Rect2(xform.xform(Point2()), Size2()); - r_first = false; - } else { - r_rect.expand_to(xform.xform(Point2())); - } + Rect2 rect = canvas_item->_edit_get_rect(); + if (r_first) { + r_rect = Rect2(xform.xform(rect.position + rect.size / 2), Size2()); + r_first = false; } + r_rect.expand_to(xform.xform(rect.position)); + r_rect.expand_to(xform.xform(rect.position + Point2(rect.size.x, 0))); + r_rect.expand_to(xform.xform(rect.position + Point2(0, rect.size.y))); + r_rect.expand_to(xform.xform(rect.position + rect.size)); } } @@ -4879,7 +4853,7 @@ void CanvasItemEditorViewport::_perform_drop_data() { files_str += error_files[i].get_file().get_basename() + ","; } files_str = files_str.substr(0, files_str.length() - 1); - accept->get_ok()->set_text(TTR("Ugh")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str())); accept->popup_centered_minsize(); } diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index adc4010f39..2c943385ad 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -390,7 +390,7 @@ class CanvasItemEditor : public VBoxContainer { List<CanvasItem *> _get_edited_canvas_items(bool retreive_locked = false, bool remove_canvas_item_if_parent_in_selection = true); Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list); - void _expand_encompassing_rect_using_children(Rect2 &p_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D()); + void _expand_encompassing_rect_using_children(Rect2 &p_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D(), bool include_locked_nodes = true); Rect2 _get_encompassing_rect(const Node *p_node); Object *_get_editor_data(Object *p_what); diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 0d25b3685a..9acbceec92 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -78,7 +78,7 @@ bool EditorTexturePreviewPlugin::handles(const String &p_type) const { return ClassDB::is_parent_class(p_type, "Texture"); } -Ref<Texture> EditorTexturePreviewPlugin::generate(const RES &p_from) { +Ref<Texture> EditorTexturePreviewPlugin::generate(const RES &p_from) const { Ref<Image> img; Ref<AtlasTexture> atex = p_from; @@ -138,12 +138,66 @@ EditorTexturePreviewPlugin::EditorTexturePreviewPlugin() { //////////////////////////////////////////////////////////////////////////// +bool EditorImagePreviewPlugin::handles(const String &p_type) const { + + return p_type == "Image"; +} + +Ref<Texture> EditorImagePreviewPlugin::generate(const RES &p_from) const { + + Ref<Image> img = p_from; + + if (img.is_null() || img->empty()) + return Ref<Image>(); + + img = img->duplicate(); + img->clear_mipmaps(); + + int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size"); + thumbnail_size *= EDSCALE; + if (img->is_compressed()) { + if (img->decompress() != OK) + return Ref<Image>(); + } else if (img->get_format() != Image::FORMAT_RGB8 && img->get_format() != Image::FORMAT_RGBA8) { + img->convert(Image::FORMAT_RGBA8); + } + + int width, height; + if (img->get_width() > thumbnail_size && img->get_width() >= img->get_height()) { + + width = thumbnail_size; + height = img->get_height() * thumbnail_size / img->get_width(); + } else if (img->get_height() > thumbnail_size && img->get_height() >= img->get_width()) { + + height = thumbnail_size; + width = img->get_width() * thumbnail_size / img->get_height(); + } else { + + width = img->get_width(); + height = img->get_height(); + } + + img->resize(width, height); + post_process_preview(img); + + Ref<ImageTexture> ptex; + ptex.instance(); + + ptex->create_from_image(img, 0); + return ptex; +} + +EditorImagePreviewPlugin::EditorImagePreviewPlugin() { +} + +//////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////// bool EditorBitmapPreviewPlugin::handles(const String &p_type) const { return ClassDB::is_parent_class(p_type, "BitMap"); } -Ref<Texture> EditorBitmapPreviewPlugin::generate(const RES &p_from) { +Ref<Texture> EditorBitmapPreviewPlugin::generate(const RES &p_from) const { Ref<BitMap> bm = p_from; @@ -215,12 +269,12 @@ bool EditorPackedScenePreviewPlugin::handles(const String &p_type) const { return ClassDB::is_parent_class(p_type, "PackedScene"); } -Ref<Texture> EditorPackedScenePreviewPlugin::generate(const RES &p_from) { +Ref<Texture> EditorPackedScenePreviewPlugin::generate(const RES &p_from) const { return generate_from_path(p_from->get_path()); } -Ref<Texture> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path) { +Ref<Texture> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path) const { String temp_path = EditorSettings::get_singleton()->get_cache_dir(); String cache_base = ProjectSettings::get_singleton()->globalize_path(p_path).md5_text(); @@ -269,7 +323,7 @@ bool EditorMaterialPreviewPlugin::handles(const String &p_type) const { return ClassDB::is_parent_class(p_type, "Material"); //any material } -Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES &p_from) { +Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES &p_from) const { Ref<Material> material = p_from; ERR_FAIL_COND_V(material.is_null(), Ref<Texture>()); @@ -281,7 +335,7 @@ Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES &p_from) { VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture preview_done = false; - VS::get_singleton()->request_frame_drawn_callback(this, "_preview_done", Variant()); + VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMaterialPreviewPlugin *>(this), "_preview_done", Variant()); while (!preview_done) { OS::get_singleton()->delay_usec(10); @@ -436,7 +490,7 @@ bool EditorScriptPreviewPlugin::handles(const String &p_type) const { return ClassDB::is_parent_class(p_type, "Script"); } -Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from) { +Ref<Texture> EditorScriptPreviewPlugin::generate(const RES &p_from) const { Ref<Script> scr = p_from; if (scr.is_null()) @@ -559,7 +613,7 @@ bool EditorAudioStreamPreviewPlugin::handles(const String &p_type) const { return ClassDB::is_parent_class(p_type, "AudioStream"); } -Ref<Texture> EditorAudioStreamPreviewPlugin::generate(const RES &p_from) { +Ref<Texture> EditorAudioStreamPreviewPlugin::generate(const RES &p_from) const { Ref<AudioStream> stream = p_from; ERR_FAIL_COND_V(stream.is_null(), Ref<Texture>()); @@ -657,7 +711,7 @@ bool EditorMeshPreviewPlugin::handles(const String &p_type) const { return ClassDB::is_parent_class(p_type, "Mesh"); //any Mesh } -Ref<Texture> EditorMeshPreviewPlugin::generate(const RES &p_from) { +Ref<Texture> EditorMeshPreviewPlugin::generate(const RES &p_from) const { Ref<Mesh> mesh = p_from; ERR_FAIL_COND_V(mesh.is_null(), Ref<Texture>()); @@ -684,7 +738,7 @@ Ref<Texture> EditorMeshPreviewPlugin::generate(const RES &p_from) { VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture preview_done = false; - VS::get_singleton()->request_frame_drawn_callback(this, "_preview_done", Variant()); + VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMeshPreviewPlugin *>(this), "_preview_done", Variant()); while (!preview_done) { OS::get_singleton()->delay_usec(10); @@ -771,16 +825,7 @@ bool EditorFontPreviewPlugin::handles(const String &p_type) const { return ClassDB::is_parent_class(p_type, "DynamicFontData"); } -Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path) { - if (canvas.is_valid()) { - VS::get_singleton()->viewport_remove_canvas(viewport, canvas); - } - - canvas = VS::get_singleton()->canvas_create(); - canvas_item = VS::get_singleton()->canvas_item_create(); - - VS::get_singleton()->viewport_attach_canvas(viewport, canvas); - VS::get_singleton()->canvas_item_set_parent(canvas_item, canvas); +Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path) const { Ref<DynamicFontData> SampledFont; SampledFont.instance(); @@ -809,7 +854,7 @@ Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path) { VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture preview_done = false; - VS::get_singleton()->request_frame_drawn_callback(this, "_preview_done", Variant()); + VS::get_singleton()->request_frame_drawn_callback(const_cast<EditorFontPreviewPlugin *>(this), "_preview_done", Variant()); while (!preview_done) { OS::get_singleton()->delay_usec(10); @@ -829,7 +874,7 @@ Ref<Texture> EditorFontPreviewPlugin::generate_from_path(const String &p_path) { return ptex; } -Ref<Texture> EditorFontPreviewPlugin::generate(const RES &p_from) { +Ref<Texture> EditorFontPreviewPlugin::generate(const RES &p_from) const { return generate_from_path(p_from->get_path()); } @@ -842,6 +887,12 @@ EditorFontPreviewPlugin::EditorFontPreviewPlugin() { VS::get_singleton()->viewport_set_size(viewport, 128, 128); VS::get_singleton()->viewport_set_active(viewport, true); viewport_texture = VS::get_singleton()->viewport_get_texture(viewport); + + canvas = VS::get_singleton()->canvas_create(); + canvas_item = VS::get_singleton()->canvas_item_create(); + + VS::get_singleton()->viewport_attach_canvas(viewport, canvas); + VS::get_singleton()->canvas_item_set_parent(canvas_item, canvas); } EditorFontPreviewPlugin::~EditorFontPreviewPlugin() { diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h index 140d9f849f..8bd7943383 100644 --- a/editor/plugins/editor_preview_plugins.h +++ b/editor/plugins/editor_preview_plugins.h @@ -39,16 +39,25 @@ class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator { GDCLASS(EditorTexturePreviewPlugin, EditorResourcePreviewGenerator) public: virtual bool handles(const String &p_type) const; - virtual Ref<Texture> generate(const RES &p_from); + virtual Ref<Texture> generate(const RES &p_from) const; EditorTexturePreviewPlugin(); }; +class EditorImagePreviewPlugin : public EditorResourcePreviewGenerator { + GDCLASS(EditorImagePreviewPlugin, EditorResourcePreviewGenerator) +public: + virtual bool handles(const String &p_type) const; + virtual Ref<Texture> generate(const RES &p_from) const; + + EditorImagePreviewPlugin(); +}; + class EditorBitmapPreviewPlugin : public EditorResourcePreviewGenerator { GDCLASS(EditorBitmapPreviewPlugin, EditorResourcePreviewGenerator) public: virtual bool handles(const String &p_type) const; - virtual Ref<Texture> generate(const RES &p_from); + virtual Ref<Texture> generate(const RES &p_from) const; EditorBitmapPreviewPlugin(); }; @@ -57,8 +66,8 @@ class EditorPackedScenePreviewPlugin : public EditorResourcePreviewGenerator { public: virtual bool handles(const String &p_type) const; - virtual Ref<Texture> generate(const RES &p_from); - virtual Ref<Texture> generate_from_path(const String &p_path); + virtual Ref<Texture> generate(const RES &p_from) const; + virtual Ref<Texture> generate_from_path(const String &p_path) const; EditorPackedScenePreviewPlugin(); }; @@ -77,7 +86,7 @@ class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator { RID light2; RID light_instance2; RID camera; - volatile bool preview_done; + mutable volatile bool preview_done; void _preview_done(const Variant &p_udata); @@ -86,7 +95,7 @@ protected: public: virtual bool handles(const String &p_type) const; - virtual Ref<Texture> generate(const RES &p_from); + virtual Ref<Texture> generate(const RES &p_from) const; EditorMaterialPreviewPlugin(); ~EditorMaterialPreviewPlugin(); @@ -95,7 +104,7 @@ public: class EditorScriptPreviewPlugin : public EditorResourcePreviewGenerator { public: virtual bool handles(const String &p_type) const; - virtual Ref<Texture> generate(const RES &p_from); + virtual Ref<Texture> generate(const RES &p_from) const; EditorScriptPreviewPlugin(); }; @@ -103,7 +112,7 @@ public: class EditorAudioStreamPreviewPlugin : public EditorResourcePreviewGenerator { public: virtual bool handles(const String &p_type) const; - virtual Ref<Texture> generate(const RES &p_from); + virtual Ref<Texture> generate(const RES &p_from) const; EditorAudioStreamPreviewPlugin(); }; @@ -121,7 +130,7 @@ class EditorMeshPreviewPlugin : public EditorResourcePreviewGenerator { RID light2; RID light_instance2; RID camera; - volatile bool preview_done; + mutable volatile bool preview_done; void _preview_done(const Variant &p_udata); @@ -130,7 +139,7 @@ protected: public: virtual bool handles(const String &p_type) const; - virtual Ref<Texture> generate(const RES &p_from); + virtual Ref<Texture> generate(const RES &p_from) const; EditorMeshPreviewPlugin(); ~EditorMeshPreviewPlugin(); @@ -144,7 +153,7 @@ class EditorFontPreviewPlugin : public EditorResourcePreviewGenerator { RID viewport_texture; RID canvas; RID canvas_item; - volatile bool preview_done; + mutable volatile bool preview_done; void _preview_done(const Variant &p_udata); @@ -153,8 +162,8 @@ protected: public: virtual bool handles(const String &p_type) const; - virtual Ref<Texture> generate(const RES &p_from); - virtual Ref<Texture> generate_from_path(const String &p_path); + virtual Ref<Texture> generate(const RES &p_from) const; + virtual Ref<Texture> generate_from_path(const String &p_path) const; EditorFontPreviewPlugin(); ~EditorFontPreviewPlugin(); diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp index 1f5a4a8a36..7732103220 100644 --- a/editor/plugins/particles_editor_plugin.cpp +++ b/editor/plugins/particles_editor_plugin.cpp @@ -270,6 +270,12 @@ void ParticlesEditor::_menu_option(int p_option) { switch (p_option) { case MENU_OPTION_GENERATE_AABB: { + float gen_time = node->get_lifetime(); + + if (gen_time < 1.0) + generate_seconds->set_value(1.0); + else + generate_seconds->set_value(trunc(gen_time) + 1.0); generate_aabb->popup_centered_minsize(); } break; case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH: { @@ -323,7 +329,15 @@ void ParticlesEditor::_generate_aabb() { EditorProgress ep("gen_aabb", TTR("Generating AABB"), int(time)); + bool was_emitting = node->is_emitting(); + if (!was_emitting) { + node->set_emitting(true); + OS::get_singleton()->delay_usec(1000); + } + + running = 0.0; AABB rect; + while (running < time) { uint64_t ticks = OS::get_singleton()->get_ticks_usec(); @@ -339,6 +353,10 @@ void ParticlesEditor::_generate_aabb() { running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0; } + if (!was_emitting) { + node->set_emitting(false); + } + node->set_visibility_aabb(rect); } diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp index 72a8b55a52..618c70d1a1 100644 --- a/editor/plugins/path_editor_plugin.cpp +++ b/editor/plugins/path_editor_plugin.cpp @@ -215,6 +215,10 @@ void PathSpatialGizmo::redraw() { clear(); + Ref<SpatialMaterial> path_material = gizmo_plugin->get_material("path_material"); + Ref<SpatialMaterial> path_thin_material = gizmo_plugin->get_material("path_thin_material"); + Ref<SpatialMaterial> handles_material = gizmo_plugin->get_material("handles"); + Ref<Curve3D> c = path->get_curve(); if (c.is_null()) return; @@ -238,7 +242,7 @@ void PathSpatialGizmo::redraw() { } if (v3p.size() > 1) { - add_lines(v3p, PathEditorPlugin::singleton->path_material); + add_lines(v3p, path_material); add_collision_segments(v3p); } @@ -265,13 +269,13 @@ void PathSpatialGizmo::redraw() { } if (v3p.size() > 1) { - add_lines(v3p, PathEditorPlugin::singleton->path_thin_material); + add_lines(v3p, path_thin_material); } if (handles.size()) { - add_handles(handles); + add_handles(handles, handles_material); } if (sec_handles.size()) { - add_handles(sec_handles, false, true); + add_handles(sec_handles, handles_material, false, true); } } } @@ -282,16 +286,6 @@ PathSpatialGizmo::PathSpatialGizmo(Path *p_path) { set_spatial_node(p_path); } -Ref<SpatialEditorGizmo> PathEditorPlugin::create_spatial_gizmo(Spatial *p_spatial) { - - if (Object::cast_to<Path>(p_spatial)) { - - return memnew(PathSpatialGizmo(Object::cast_to<Path>(p_spatial))); - } - - return Ref<SpatialEditorGizmo>(); -} - bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { if (!path) @@ -567,21 +561,9 @@ PathEditorPlugin::PathEditorPlugin(EditorNode *p_node) { mirror_handle_angle = true; mirror_handle_length = true; - path_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - path_material->set_albedo(Color(0.5, 0.5, 1.0, 0.8)); - path_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - path_material->set_line_width(3); - path_material->set_cull_mode(SpatialMaterial::CULL_DISABLED); - path_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - - path_thin_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - path_thin_material->set_albedo(Color(0.5, 0.5, 1.0, 0.4)); - path_thin_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - path_thin_material->set_line_width(1); - path_thin_material->set_cull_mode(SpatialMaterial::CULL_DISABLED); - path_thin_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - - //SpatialEditor::get_singleton()->add_gizmo_plugin(this); + Ref<PathSpatialGizmoPlugin> gizmo_plugin; + gizmo_plugin.instance(); + SpatialEditor::get_singleton()->register_gizmo_plugin(gizmo_plugin); sep = memnew(VSeparator); sep->hide(); @@ -630,18 +612,53 @@ PathEditorPlugin::PathEditorPlugin(EditorNode *p_node) { curve_edit->set_pressed(true); /* - collision_polygon_editor = memnew( PathEditor(p_node) ); - editor->get_viewport()->add_child(collision_polygon_editor); + collision_polygon_editor = memnew( PathEditor(p_node) ); + editor->get_viewport()->add_child(collision_polygon_editor); + collision_polygon_editor->set_margin(MARGIN_LEFT,200); + collision_polygon_editor->set_margin(MARGIN_RIGHT,230); + collision_polygon_editor->set_margin(MARGIN_TOP,0); + collision_polygon_editor->set_margin(MARGIN_BOTTOM,10); + collision_polygon_editor->hide(); + */ +} - collision_polygon_editor->set_margin(MARGIN_LEFT,200); - collision_polygon_editor->set_margin(MARGIN_RIGHT,230); - collision_polygon_editor->set_margin(MARGIN_TOP,0); - collision_polygon_editor->set_margin(MARGIN_BOTTOM,10); +PathEditorPlugin::~PathEditorPlugin() { +} + +Ref<EditorSpatialGizmo> PathSpatialGizmoPlugin::create_gizmo(Spatial *p_spatial) { + Ref<PathSpatialGizmo> ref; + Path *path = Object::cast_to<Path>(p_spatial); + if (path) ref = Ref<PathSpatialGizmo>(memnew(PathSpatialGizmo(path))); - collision_polygon_editor->hide(); - */ + return ref; } -PathEditorPlugin::~PathEditorPlugin() { +String PathSpatialGizmoPlugin::get_name() const { + return "Path"; +} + +PathSpatialGizmoPlugin::PathSpatialGizmoPlugin() { + + Color path_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/path", Color(0.5, 0.5, 1.0, 0.8)); + + Ref<SpatialMaterial> path_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + path_color.a = 0.8; + path_material->set_albedo(path_color); + path_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + path_material->set_line_width(3); + path_material->set_cull_mode(SpatialMaterial::CULL_DISABLED); + path_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + + Ref<SpatialMaterial> path_thin_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + path_color.a = 0.4; + path_thin_material->set_albedo(path_color); + path_thin_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + path_thin_material->set_line_width(1); + path_thin_material->set_cull_mode(SpatialMaterial::CULL_DISABLED); + path_thin_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + + add_material("path_material", path_material); + add_material("path_thin_material", path_thin_material); + create_handle_material("handles"); } diff --git a/editor/plugins/path_editor_plugin.h b/editor/plugins/path_editor_plugin.h index 52dfb78b61..61f309e794 100644 --- a/editor/plugins/path_editor_plugin.h +++ b/editor/plugins/path_editor_plugin.h @@ -49,10 +49,22 @@ public: virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); - void redraw(); + virtual void redraw(); PathSpatialGizmo(Path *p_path = NULL); }; +class PathSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { + + GDCLASS(PathSpatialGizmoPlugin, EditorSpatialGizmoPlugin); + +protected: + Ref<EditorSpatialGizmo> create_gizmo(Spatial *p_spatial); + +public: + String get_name() const; + PathSpatialGizmoPlugin(); +}; + class PathEditorPlugin : public EditorPlugin { GDCLASS(PathEditorPlugin, EditorPlugin); @@ -88,12 +100,10 @@ public: Path *get_edited_path() { return path; } static PathEditorPlugin *singleton; - Ref<SpatialMaterial> path_material; - Ref<SpatialMaterial> path_thin_material; virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event); //virtual bool forward_gui_input(const InputEvent& p_event) { return collision_polygon_editor->forward_gui_input(p_event); } - virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial); + //virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial); virtual String get_name() const { return "Path"; } bool has_main_screen() const { return false; } virtual void edit(Object *p_object); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 3b82e6578b..7d72537e32 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -219,6 +219,9 @@ void ScriptEditorQuickOpen::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { connect("confirmed", this, "_confirmed"); + + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); } break; } } @@ -2402,26 +2405,25 @@ void ScriptEditor::_make_script_list_context_menu() { if (se) { context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/save"), FILE_SAVE); context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/save_as"), FILE_SAVE_AS); - context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_file"), FILE_CLOSE); - context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_all"), CLOSE_ALL); - context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_other_tabs"), CLOSE_OTHER_TABS); - context_menu->add_separator(); - context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/copy_path"), FILE_COPY_PATH); - context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/show_in_file_system"), SHOW_IN_FILE_SYSTEM); - + } + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_file"), FILE_CLOSE); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_all"), CLOSE_ALL); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_other_tabs"), CLOSE_OTHER_TABS); + context_menu->add_separator(); + if (se) { Ref<Script> scr = se->get_edited_resource(); if (scr != NULL) { context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/reload_script_soft"), FILE_TOOL_RELOAD_SOFT); if (!scr.is_null() && scr->is_tool()) { - context_menu->add_separator(); context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/run_file"), FILE_RUN); + context_menu->add_separator(); } } - } else { - context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_file"), FILE_CLOSE); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/copy_path"), FILE_COPY_PATH); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/show_in_file_system"), SHOW_IN_FILE_SYSTEM); + context_menu->add_separator(); } - context_menu->add_separator(); context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_move_up"), WINDOW_MOVE_UP); context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_move_down"), WINDOW_MOVE_DOWN); context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_sort"), WINDOW_SORT); @@ -2895,13 +2897,14 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { script_list->set_v_size_flags(SIZE_EXPAND_FILL); script_split->set_split_offset(140); _sort_list_on_update = true; - script_list->connect("gui_input", this, "_script_list_gui_input"); + script_list->connect("gui_input", this, "_script_list_gui_input", varray(), CONNECT_DEFERRED); script_list->set_allow_rmb_select(true); script_list->set_drag_forwarding(this); context_menu = memnew(PopupMenu); add_child(context_menu); context_menu->connect("id_pressed", this, "_menu_option"); + context_menu->set_hide_on_window_lose_focus(true); overview_vbox = memnew(VBoxContainer); overview_vbox->set_custom_minimum_size(Size2(0, 90)); @@ -2956,6 +2959,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { file_menu = memnew(MenuButton); menu_hb->add_child(file_menu); file_menu->set_text(TTR("File")); + file_menu->get_popup()->set_hide_on_window_lose_focus(true); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new", TTR("New")), FILE_NEW); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/open", TTR("Open")), FILE_OPEN); file_menu->get_popup()->add_submenu_item(TTR("Open Recent"), "RecentScripts", FILE_OPEN_RECENT); @@ -3005,6 +3009,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { script_search_menu = memnew(MenuButton); menu_hb->add_child(script_search_menu); script_search_menu->set_text(TTR("Search")); + script_search_menu->get_popup()->set_hide_on_window_lose_focus(true); script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find", TTR("Find..."), KEY_MASK_CMD | KEY_F), HELP_SEARCH_FIND); script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_next", TTR("Find Next"), KEY_F3), HELP_SEARCH_FIND_NEXT); script_search_menu->get_popup()->connect("id_pressed", this, "_menu_option"); @@ -3013,6 +3018,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { debug_menu = memnew(MenuButton); menu_hb->add_child(debug_menu); debug_menu->set_text(TTR("Debug")); + debug_menu->get_popup()->set_hide_on_window_lose_focus(true); debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("debugger/step_over", TTR("Step Over"), KEY_F10), DEBUG_NEXT); debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("debugger/step_into", TTR("Step Into"), KEY_F11), DEBUG_STEP); debug_menu->get_popup()->add_separator(); @@ -3094,7 +3100,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { error_dialog = memnew(AcceptDialog); add_child(error_dialog); - error_dialog->get_ok()->set_text(TTR("I see...")); + error_dialog->get_ok()->set_text(TTR("OK")); debugger = memnew(ScriptEditorDebugger(editor)); debugger->connect("goto_script_line", this, "_goto_script_line"); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 165d7e32b9..522ce52234 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -274,6 +274,23 @@ void ScriptTextEditor::_set_theme_for_script() { } } +void ScriptTextEditor::_toggle_warning_pannel(const Ref<InputEvent> &p_event) { + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + warnings_panel->set_visible(!warnings_panel->is_visible()); + } +} + +void ScriptTextEditor::_warning_clicked(Variant p_line) { + if (p_line.get_type() == Variant::INT) { + code_editor->get_text_edit()->cursor_set_line(p_line.operator int64_t()); + } else if (p_line.get_type() == Variant::DICTIONARY) { + Dictionary meta = p_line.operator Dictionary(); + code_editor->get_text_edit()->insert_at("#warning-ignore:" + meta["code"].operator String(), meta["line"].operator int64_t() - 1); + _validate_script(); + } +} + void ScriptTextEditor::reload_text() { ERR_FAIL_COND(script.is_null()); @@ -421,8 +438,9 @@ void ScriptTextEditor::_validate_script() { String text = te->get_text(); List<String> fnc; Set<int> safe_lines; + List<ScriptLanguage::Warning> warnings; - if (!script->get_language()->validate(text, line, col, errortxt, script->get_path(), &fnc, &safe_lines)) { + if (!script->get_language()->validate(text, line, col, errortxt, script->get_path(), &fnc, &warnings, &safe_lines)) { String error_text = "error(" + itos(line) + "," + itos(col) + "): " + errortxt; code_editor->set_error(error_text); } else { @@ -442,6 +460,37 @@ void ScriptTextEditor::_validate_script() { } } + code_editor->get_warning_count_label()->set_text(itos(warnings.size())); + warnings_panel->clear(); + warnings_panel->push_table(3); + for (List<ScriptLanguage::Warning>::Element *E = warnings.front(); E; E = E->next()) { + ScriptLanguage::Warning w = E->get(); + + warnings_panel->push_cell(); + warnings_panel->push_meta(w.line - 1); + warnings_panel->push_color(warnings_panel->get_color("warning_color", "Editor")); + warnings_panel->add_text(TTR("Line") + " " + itos(w.line)); + warnings_panel->add_text(" (" + w.string_code + "):"); + warnings_panel->pop(); // Color + warnings_panel->pop(); // Meta goto + warnings_panel->pop(); // Cell + + warnings_panel->push_cell(); + warnings_panel->add_text(w.message); + warnings_panel->pop(); // Cell + + Dictionary ignore_meta; + ignore_meta["line"] = w.line; + ignore_meta["code"] = w.string_code.to_lower(); + warnings_panel->push_cell(); + warnings_panel->push_meta(ignore_meta); + warnings_panel->add_text(TTR("(ignore)")); + warnings_panel->pop(); // Meta ignore + warnings_panel->pop(); // Cell + //warnings_panel->add_newline(); + } + warnings_panel->pop(); // Table + line--; bool highlight_safe = EDITOR_DEF("text_editor/highlighting/highlight_type_safe_lines", true); bool last_is_safe = false; @@ -967,7 +1016,6 @@ void ScriptTextEditor::_edit_option(int p_op) { } } break; - case HELP_CONTEXTUAL: { String text = tx->get_selection_text(); @@ -977,6 +1025,15 @@ void ScriptTextEditor::_edit_option(int p_op) { emit_signal("request_help_search", text); } } break; + case LOOKUP_SYMBOL: { + + String text = tx->get_word_under_cursor(); + if (text == "") + text = tx->get_selection_text(); + if (text != "") { + _lookup_symbol(text, tx->cursor_get_line(), tx->cursor_get_column()); + } + } break; } } @@ -1014,6 +1071,8 @@ void ScriptTextEditor::_bind_methods() { ClassDB::bind_method("_goto_line", &ScriptTextEditor::_goto_line); ClassDB::bind_method("_lookup_symbol", &ScriptTextEditor::_lookup_symbol); ClassDB::bind_method("_text_edit_gui_input", &ScriptTextEditor::_text_edit_gui_input); + ClassDB::bind_method("_toggle_warning_pannel", &ScriptTextEditor::_toggle_warning_pannel); + ClassDB::bind_method("_warning_clicked", &ScriptTextEditor::_warning_clicked); ClassDB::bind_method("_color_changed", &ScriptTextEditor::_color_changed); ClassDB::bind_method("get_drag_data_fw", &ScriptTextEditor::get_drag_data_fw); @@ -1182,19 +1241,13 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { if (mb.is_valid()) { - if (mb->get_button_index() == BUTTON_RIGHT) { - + if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) { int col, row; TextEdit *tx = code_editor->get_text_edit(); tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col); Vector2 mpos = mb->get_global_position() - tx->get_global_position(); tx->set_right_click_moves_caret(EditorSettings::get_singleton()->get("text_editor/cursor/right_click_moves_caret")); - bool has_color = (tx->get_word_at_pos(mpos) == "Color"); - int fold_state = 0; - bool can_fold = tx->can_fold(row); - bool is_folded = tx->is_folded(row); - if (tx->is_right_click_moving_caret()) { if (tx->is_selection_active()) { @@ -1214,38 +1267,62 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { } } - if (!mb->is_pressed()) { - if (has_color) { - String line = tx->get_line(row); - color_line = row; - int begin = 0; - int end = 0; - bool valid = false; - for (int i = col; i < line.length(); i++) { - if (line[i] == '(') { - begin = i; - continue; - } else if (line[i] == ')') { - end = i + 1; - valid = true; - break; - } + String word_at_mouse = tx->get_word_at_pos(mpos); + if (word_at_mouse == "") + word_at_mouse = tx->get_word_under_cursor(); + if (word_at_mouse == "") + word_at_mouse = tx->get_selection_text(); + + bool has_color = (word_at_mouse == "Color"); + int fold_state = 0; + bool foldable = tx->can_fold(row) || tx->is_folded(row); + bool open_docs = false; + bool goto_definition = false; + + if (word_at_mouse.is_resource_file()) { + open_docs = true; + } else { + + Node *base = get_tree()->get_edited_scene_root(); + if (base) { + base = _find_node_for_script(base, base, script); + } + ScriptLanguage::LookupResult result; + if (script->get_language()->lookup_code(code_editor->get_text_edit()->get_text_for_lookup_completion(), word_at_mouse, script->get_path().get_base_dir(), base, result) == OK) { + open_docs = true; + } + } + + if (has_color) { + String line = tx->get_line(row); + color_line = row; + int begin = 0; + int end = 0; + bool valid = false; + for (int i = col; i < line.length(); i++) { + if (line[i] == '(') { + begin = i; + continue; + } else if (line[i] == ')') { + end = i + 1; + valid = true; + break; } - if (valid) { - color_args = line.substr(begin, end - begin); - String stripped = color_args.replace(" ", "").replace("(", "").replace(")", ""); - Vector<float> color = stripped.split_floats(","); - if (color.size() > 2) { - float alpha = color.size() > 3 ? color[3] : 1.0f; - color_picker->set_pick_color(Color(color[0], color[1], color[2], alpha)); - } - color_panel->set_position(get_global_transform().xform(get_local_mouse_position())); - } else { - has_color = false; + } + if (valid) { + color_args = line.substr(begin, end - begin); + String stripped = color_args.replace(" ", "").replace("(", "").replace(")", ""); + Vector<float> color = stripped.split_floats(","); + if (color.size() > 2) { + float alpha = color.size() > 3 ? color[3] : 1.0f; + color_picker->set_pick_color(Color(color[0], color[1], color[2], alpha)); } + color_panel->set_position(get_global_transform().xform(get_local_mouse_position())); + } else { + has_color = false; } - _make_context_menu(tx->is_selection_active(), has_color, can_fold, is_folded); } + _make_context_menu(tx->is_selection_active(), has_color, foldable, open_docs, goto_definition); } } } @@ -1264,7 +1341,7 @@ void ScriptTextEditor::_color_changed(const Color &p_color) { code_editor->get_text_edit()->set_line(color_line, new_line); } -void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p_can_fold, bool p_is_folded) { +void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p_foldable, bool p_open_docs, bool p_goto_definition) { context_menu->clear(); if (p_selection) { @@ -1287,13 +1364,17 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_uppercase"), EDIT_TO_UPPERCASE); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_lowercase"), EDIT_TO_LOWERCASE); } - if (p_can_fold || p_is_folded) + if (p_foldable) context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE); - if (p_color) { + if (p_color || p_open_docs || p_goto_definition) { context_menu->add_separator(); - context_menu->add_item(TTR("Pick Color"), EDIT_PICK_COLOR); + if (p_open_docs) + context_menu->add_item(TTR("Lookup Symbol"), LOOKUP_SYMBOL); + if (p_color) + context_menu->add_item(TTR("Pick Color"), EDIT_PICK_COLOR); } + context_menu->set_position(get_global_transform().xform(get_local_mouse_position())); context_menu->set_size(Vector2(1, 1)); context_menu->popup(); @@ -1303,8 +1384,13 @@ ScriptTextEditor::ScriptTextEditor() { theme_loaded = false; + VSplitContainer *editor_box = memnew(VSplitContainer); + add_child(editor_box); + editor_box->set_anchors_and_margins_preset(Control::PRESET_WIDE); + editor_box->set_v_size_flags(SIZE_EXPAND_FILL); + code_editor = memnew(CodeTextEditor); - add_child(code_editor); + editor_box->add_child(code_editor); code_editor->add_constant_override("separation", 0); code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); code_editor->connect("validate_script", this, "_validate_script"); @@ -1312,7 +1398,20 @@ ScriptTextEditor::ScriptTextEditor() { code_editor->set_code_complete_func(_code_complete_scripts, this); code_editor->get_text_edit()->connect("breakpoint_toggled", this, "_breakpoint_toggled"); code_editor->get_text_edit()->connect("symbol_lookup", this, "_lookup_symbol"); - code_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); + code_editor->set_v_size_flags(SIZE_EXPAND_FILL); + + warnings_panel = memnew(RichTextLabel); + editor_box->add_child(warnings_panel); + warnings_panel->set_custom_minimum_size(Size2(0, 100 * EDSCALE)); + warnings_panel->set_h_size_flags(SIZE_EXPAND_FILL); + warnings_panel->set_meta_underline(true); + warnings_panel->set_selection_enabled(true); + warnings_panel->set_focus_mode(FOCUS_CLICK); + warnings_panel->hide(); + + code_editor->get_warning_label()->connect("gui_input", this, "_toggle_warning_pannel"); + code_editor->get_warning_count_label()->connect("gui_input", this, "_toggle_warning_pannel"); + warnings_panel->connect("meta_clicked", this, "_warning_clicked"); update_settings(); @@ -1327,6 +1426,7 @@ ScriptTextEditor::ScriptTextEditor() { context_menu = memnew(PopupMenu); add_child(context_menu); context_menu->connect("id_pressed", this, "_edit_option"); + context_menu->set_hide_on_window_lose_focus(true); color_panel = memnew(PopupPanel); add_child(color_panel); @@ -1338,6 +1438,7 @@ ScriptTextEditor::ScriptTextEditor() { edit_menu = memnew(MenuButton); edit_menu->set_text(TTR("Edit")); + edit_menu->get_popup()->set_hide_on_window_lose_focus(true); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); edit_menu->get_popup()->add_separator(); @@ -1391,6 +1492,7 @@ ScriptTextEditor::ScriptTextEditor() { search_menu = memnew(MenuButton); edit_hb->add_child(search_menu); search_menu->set_text(TTR("Search")); + search_menu->get_popup()->set_hide_on_window_lose_focus(true); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index f0b00a9117..837201a947 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -39,6 +39,7 @@ class ScriptTextEditor : public ScriptEditorBase { GDCLASS(ScriptTextEditor, ScriptEditorBase); CodeTextEditor *code_editor; + RichTextLabel *warnings_panel; Ref<Script> script; @@ -112,6 +113,7 @@ class ScriptTextEditor : public ScriptEditorBase { DEBUG_GOTO_NEXT_BREAKPOINT, DEBUG_GOTO_PREV_BREAKPOINT, HELP_CONTEXTUAL, + LOOKUP_SYMBOL, }; protected: @@ -123,6 +125,8 @@ protected: void _code_complete_script(const String &p_code, List<String> *r_options, bool &r_force); void _load_theme_settings(); void _set_theme_for_script(); + void _toggle_warning_pannel(const Ref<InputEvent> &p_event); + void _warning_clicked(Variant p_line); void _notification(int p_what); static void _bind_methods(); @@ -131,7 +135,7 @@ protected: void _change_syntax_highlighter(int p_idx); void _edit_option(int p_op); - void _make_context_menu(bool p_selection, bool p_color, bool p_can_fold, bool p_is_folded); + void _make_context_menu(bool p_selection, bool p_color, bool p_foldable, bool p_open_docs, bool p_goto_definition); void _text_edit_gui_input(const Ref<InputEvent> &ev); void _color_changed(const Color &p_color); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 7650cd6ae7..ea1876c27a 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -465,7 +465,7 @@ void ShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { if (mb.is_valid()) { - if (mb->get_button_index() == BUTTON_RIGHT) { + if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) { int col, row; TextEdit *tx = shader_editor->get_text_edit(); @@ -491,10 +491,7 @@ void ShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { tx->cursor_set_column(col); } } - - if (!mb->is_pressed()) { - _make_context_menu(tx->is_selection_active()); - } + _make_context_menu(tx->is_selection_active()); } } } @@ -546,6 +543,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) { context_menu = memnew(PopupMenu); add_child(context_menu); context_menu->connect("id_pressed", this, "_menu_option"); + context_menu->set_hide_on_window_lose_focus(true); VBoxContainer *main_container = memnew(VBoxContainer); HBoxContainer *hbc = memnew(HBoxContainer); @@ -554,6 +552,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) { //edit_menu->set_position(Point2(5, -1)); edit_menu->set_text(TTR("Edit")); + edit_menu->get_popup()->set_hide_on_window_lose_focus(true); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); edit_menu->get_popup()->add_separator(); @@ -578,7 +577,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) { search_menu = memnew(MenuButton); //search_menu->set_position(Point2(38, -1)); search_menu->set_text(TTR("Search")); - + search_menu->get_popup()->set_hide_on_window_lose_focus(true); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV); diff --git a/editor/plugins/skeleton_ik_editor_plugin.cpp b/editor/plugins/skeleton_ik_editor_plugin.cpp new file mode 100644 index 0000000000..2d343d3edd --- /dev/null +++ b/editor/plugins/skeleton_ik_editor_plugin.cpp @@ -0,0 +1,110 @@ +/*************************************************************************/ +/* skeleton_ik_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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 "skeleton_ik_editor_plugin.h" + +#include "scene/animation/skeleton_ik.h" + +void SkeletonIKEditorPlugin::_play() { + + if (!skeleton_ik) + return; + + if (!skeleton_ik->get_parent_skeleton()) + return; + + if (play_btn->is_pressed()) { + + initial_bone_poses.resize(skeleton_ik->get_parent_skeleton()->get_bone_count()); + for (int i = 0; i < skeleton_ik->get_parent_skeleton()->get_bone_count(); ++i) { + initial_bone_poses.write[i] = skeleton_ik->get_parent_skeleton()->get_bone_pose(i); + } + + skeleton_ik->start(); + } else { + skeleton_ik->stop(); + + if (initial_bone_poses.size() != skeleton_ik->get_parent_skeleton()->get_bone_count()) + return; + + for (int i = 0; i < skeleton_ik->get_parent_skeleton()->get_bone_count(); ++i) { + skeleton_ik->get_parent_skeleton()->set_bone_pose(i, initial_bone_poses[i]); + } + } +} + +void SkeletonIKEditorPlugin::edit(Object *p_object) { + + if (p_object != skeleton_ik) { + if (skeleton_ik) { + play_btn->set_pressed(false); + _play(); + } + } + + SkeletonIK *s = Object::cast_to<SkeletonIK>(p_object); + if (!s) + return; + + skeleton_ik = s; +} + +bool SkeletonIKEditorPlugin::handles(Object *p_object) const { + + return p_object->is_class("SkeletonIK"); +} + +void SkeletonIKEditorPlugin::make_visible(bool p_visible) { + + if (p_visible) + play_btn->show(); + else + play_btn->hide(); +} + +void SkeletonIKEditorPlugin::_bind_methods() { + + ClassDB::bind_method("_play", &SkeletonIKEditorPlugin::_play); +} + +SkeletonIKEditorPlugin::SkeletonIKEditorPlugin(EditorNode *p_node) { + + editor = p_node; + play_btn = memnew(Button); + play_btn->set_icon(editor->get_gui_base()->get_icon("Play", "EditorIcons")); + play_btn->set_text(TTR("Play IK")); + play_btn->set_toggle_mode(true); + play_btn->hide(); + play_btn->connect("pressed", this, "_play"); + add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, play_btn); + skeleton_ik = NULL; +} + +SkeletonIKEditorPlugin::~SkeletonIKEditorPlugin() {} diff --git a/editor/plugins/skeleton_ik_editor_plugin.h b/editor/plugins/skeleton_ik_editor_plugin.h new file mode 100644 index 0000000000..e645bea39a --- /dev/null +++ b/editor/plugins/skeleton_ik_editor_plugin.h @@ -0,0 +1,65 @@ +/*************************************************************************/ +/* skeleton_ik_editor_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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. */ +/*************************************************************************/ + +#ifndef SKELETON_IK_EDITOR_PLUGIN_H +#define SKELETON_IK_EDITOR_PLUGIN_H + +#include "editor/editor_node.h" +#include "editor/editor_plugin.h" + +class SkeletonIK; + +class SkeletonIKEditorPlugin : public EditorPlugin { + + GDCLASS(SkeletonIKEditorPlugin, EditorPlugin); + + SkeletonIK *skeleton_ik; + + Button *play_btn; + EditorNode *editor; + Vector<Transform> initial_bone_poses; + + void _play(); + +protected: + static void _bind_methods(); + +public: + virtual String get_name() const { return "SkeletonIK"; } + bool has_main_screen() const { return false; } + virtual void edit(Object *p_object); + virtual bool handles(Object *p_object) const; + virtual void make_visible(bool p_visible); + + SkeletonIKEditorPlugin(EditorNode *p_node); + ~SkeletonIKEditorPlugin(); +}; + +#endif // SKELETON_IK_EDITOR_PLUGIN_H diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index eab1588a55..c3d48d498c 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -184,49 +184,6 @@ Transform SpatialEditorViewport::to_camera_transform(const Cursor &p_cursor) con return camera_transform; } -String SpatialEditorGizmo::get_handle_name(int p_idx) const { - - if (get_script_instance() && get_script_instance()->has_method("get_handle_name")) - return get_script_instance()->call("get_handle_name", p_idx); - - return ""; -} - -Variant SpatialEditorGizmo::get_handle_value(int p_idx) const { - - if (get_script_instance() && get_script_instance()->has_method("get_handle_value")) - return get_script_instance()->call("get_handle_value", p_idx); - - return Variant(); -} - -void SpatialEditorGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { - - if (get_script_instance() && get_script_instance()->has_method("set_handle")) - get_script_instance()->call("set_handle", p_idx, p_camera, p_point); -} - -void SpatialEditorGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { - - if (get_script_instance() && get_script_instance()->has_method("commit_handle")) - get_script_instance()->call("commit_handle", p_idx, p_restore, p_cancel); -} - -bool SpatialEditorGizmo::intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum) { - - return false; -} - -bool SpatialEditorGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle, bool p_sec_first) { - - return false; -} - -SpatialEditorGizmo::SpatialEditorGizmo() { - - selected = false; -} - int SpatialEditorViewport::get_selected_count() const { Map<Node *, Object *> &selection = editor_selection->get_selection(); @@ -346,7 +303,7 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, Vector3 pos = _get_ray_pos(p_pos); Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario()); - Set<Ref<SpatialEditorGizmo> > found_gizmos; + Set<Ref<EditorSpatialGizmo> > found_gizmos; Node *edited_scene = get_tree()->get_edited_scene_root(); ObjectID closest = 0; @@ -361,7 +318,7 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, if (!spat) continue; - Ref<SpatialEditorGizmo> seg = spat->get_gizmo(); + Ref<EditorSpatialGizmo> seg = spat->get_gizmo(); if ((!seg.is_valid()) || found_gizmos.has(seg)) { continue; @@ -418,7 +375,7 @@ void SpatialEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_incl Vector3 pos = _get_ray_pos(p_pos); Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario()); - Set<Ref<SpatialEditorGizmo> > found_gizmos; + Set<Ref<EditorSpatialGizmo> > found_gizmos; r_includes_current = false; @@ -429,7 +386,7 @@ void SpatialEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_incl if (!spat) continue; - Ref<SpatialEditorGizmo> seg = spat->get_gizmo(); + Ref<EditorSpatialGizmo> seg = spat->get_gizmo(); if (!seg.is_valid()) continue; @@ -559,7 +516,7 @@ void SpatialEditorViewport::_select_region() { if (selected.find(root_sp) != -1) continue; - Ref<SpatialEditorGizmo> seg = sp->get_gizmo(); + Ref<EditorSpatialGizmo> seg = sp->get_gizmo(); if (!seg.is_valid()) continue; @@ -963,7 +920,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (b->is_pressed() && _edit.gizmo.is_valid()) { //restore _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, true); - _edit.gizmo = Ref<SpatialEditorGizmo>(); + _edit.gizmo = Ref<EditorSpatialGizmo>(); } if (_edit.mode == TRANSFORM_NONE && b->is_pressed()) { @@ -1079,7 +1036,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (can_select_gizmos && spatial_editor->get_selected()) { - Ref<SpatialEditorGizmo> seg = spatial_editor->get_selected()->get_gizmo(); + Ref<EditorSpatialGizmo> seg = spatial_editor->get_selected()->get_gizmo(); if (seg.is_valid()) { int handle = -1; Vector3 point; @@ -1158,7 +1115,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { Spatial *spa = Object::cast_to<Spatial>(ObjectDB::get_instance(clicked)); if (spa) { - Ref<SpatialEditorGizmo> seg = spa->get_gizmo(); + Ref<EditorSpatialGizmo> seg = spa->get_gizmo(); if (seg.is_valid()) { _edit.gizmo = seg; @@ -1175,7 +1132,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (_edit.gizmo.is_valid()) { _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, false); - _edit.gizmo = Ref<SpatialEditorGizmo>(); + _edit.gizmo = Ref<EditorSpatialGizmo>(); break; } if (clicked) { @@ -1233,7 +1190,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (spatial_editor->get_selected()) { - Ref<SpatialEditorGizmo> seg = spatial_editor->get_selected()->get_gizmo(); + Ref<EditorSpatialGizmo> seg = spatial_editor->get_selected()->get_gizmo(); if (seg.is_valid()) { int selected_handle = -1; @@ -2867,7 +2824,7 @@ void SpatialEditorViewport::update_transform_gizmo_view() { dd = 0.0001; float gsize = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_size"); - gizmo_scale = (gsize / Math::abs(dd)); + gizmo_scale = (gsize / Math::abs(dd)) * MAX(1, EDSCALE) / viewport_container->get_stretch_shrink(); Vector3 scale = Vector3(1, 1, 1) * gizmo_scale; xform.basis.scale(scale); @@ -3099,7 +3056,7 @@ Vector3 SpatialEditorViewport::_get_instance_position(const Point2 &p_pos) const Vector3 world_pos = _get_ray_pos(p_pos); Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(world_pos, world_ray, get_tree()->get_root()->get_world()->get_scenario()); - Set<Ref<SpatialEditorGizmo> > found_gizmos; + Set<Ref<EditorSpatialGizmo> > found_gizmos; float closest_dist = MAX_DISTANCE; @@ -3113,7 +3070,7 @@ Vector3 SpatialEditorViewport::_get_instance_position(const Point2 &p_pos) const if (!mesh_instance) continue; - Ref<SpatialEditorGizmo> seg = mesh_instance->get_gizmo(); + Ref<EditorSpatialGizmo> seg = mesh_instance->get_gizmo(); if ((!seg.is_valid()) || found_gizmos.has(seg)) { continue; @@ -3308,7 +3265,7 @@ void SpatialEditorViewport::_perform_drop_data() { files_str += error_files[i].get_file().get_basename() + ","; } files_str = files_str.substr(0, files_str.length() - 1); - accept->get_ok()->set_text(TTR("Ugh")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str())); accept->popup_centered_minsize(); } @@ -3389,7 +3346,7 @@ void SpatialEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p if (root_node) { list.push_back(root_node); } else { - accept->get_ok()->set_text(TTR("OK :(")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("No parent to instance a child at.")); accept->popup_centered_minsize(); _remove_preview(); @@ -3397,7 +3354,7 @@ void SpatialEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p } } if (list.size() != 1) { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("This operation requires a single selected node.")); accept->popup_centered_minsize(); _remove_preview(); @@ -3429,6 +3386,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed clicked = 0; clicked_includes_current = false; orthogonal = false; + lock_rotation = false; message_time = 0; zoom_indicator_delay = 0.0; @@ -3892,10 +3850,6 @@ void SpatialEditor::select_gizmo_highlight_axis(int p_axis) { } } -int SpatialEditor::get_skeleton_visibility_state() const { - return view_menu->get_popup()->get_item_state(view_menu->get_popup()->get_item_index(MENU_VISIBILITY_SKELETON)); -} - void SpatialEditor::update_transform_gizmo() { List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -4048,6 +4002,16 @@ Dictionary SpatialEditor::get_state() const { d["znear"] = get_znear(); d["zfar"] = get_zfar(); + Dictionary gizmos_status; + for (int i = 0; i < gizmo_plugins.size(); i++) { + if (!gizmo_plugins[i]->can_be_hidden()) continue; + int state = gizmos_menu->get_item_state(gizmos_menu->get_item_index(i)); + String name = gizmo_plugins[i]->get_name(); + gizmos_status[name] = state; + } + + d["gizmos_status"] = gizmos_status; + return d; } void SpatialEditor::set_state(const Dictionary &p_state) { @@ -4121,6 +4085,39 @@ void SpatialEditor::set_state(const Dictionary &p_state) { VisualServer::get_singleton()->instance_set_visible(origin_instance, use); } } + + if (d.has("gizmos_status")) { + Dictionary gizmos_status = d["gizmos_status"]; + List<Variant> keys; + gizmos_status.get_key_list(&keys); + + for (int j = 0; j < gizmo_plugins.size(); ++j) { + if (!gizmo_plugins[j]->can_be_hidden()) continue; + int state = EditorSpatialGizmoPlugin::ON_TOP; + for (uint32_t i = 0; i < keys.size(); i++) { + if (gizmo_plugins.write[j]->get_name() == keys[i]) { + state = gizmos_status[keys[i]]; + } + } + + const int idx = gizmos_menu->get_item_index(j); + + gizmos_menu->set_item_multistate(idx, state); + gizmo_plugins.write[j]->set_state(state); + + switch (state) { + case EditorSpatialGizmoPlugin::ON_TOP: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_visible")); + break; + case EditorSpatialGizmoPlugin::VISIBLE: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_xray")); + break; + case EditorSpatialGizmoPlugin::HIDDEN: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_hidden")); + break; + } + } + } } void SpatialEditor::edit(Spatial *p_spatial) { @@ -4128,7 +4125,7 @@ void SpatialEditor::edit(Spatial *p_spatial) { if (p_spatial != selected) { if (selected) { - Ref<SpatialEditorGizmo> seg = selected->get_gizmo(); + Ref<EditorSpatialGizmo> seg = selected->get_gizmo(); if (seg.is_valid()) { seg->set_selected(false); selected->update_gizmo(); @@ -4140,7 +4137,7 @@ void SpatialEditor::edit(Spatial *p_spatial) { if (selected) { - Ref<SpatialEditorGizmo> seg = selected->get_gizmo(); + Ref<EditorSpatialGizmo> seg = selected->get_gizmo(); if (seg.is_valid()) { seg->set_selected(true); selected->update_gizmo(); @@ -4214,6 +4211,30 @@ void SpatialEditor::_menu_item_toggled(bool pressed, int p_option) { } } +void SpatialEditor::_menu_gizmo_toggled(int p_option) { + + const int idx = gizmos_menu->get_item_index(p_option); + gizmos_menu->toggle_item_multistate(idx); + + // Change icon + const int state = gizmos_menu->get_item_state(idx); + switch (state) { + case EditorSpatialGizmoPlugin::ON_TOP: + gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_visible")); + break; + case EditorSpatialGizmoPlugin::VISIBLE: + gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_xray")); + break; + case EditorSpatialGizmoPlugin::HIDDEN: + gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_hidden")); + break; + } + + gizmo_plugins.write[p_option]->set_state(state); + + update_all_gizmos(); +} + void SpatialEditor::_menu_item_pressed(int p_option) { switch (p_option) { @@ -4388,28 +4409,6 @@ void SpatialEditor::_menu_item_pressed(int p_option) { _refresh_menu_icons(); } break; - case MENU_VISIBILITY_SKELETON: { - - const int idx = view_menu->get_popup()->get_item_index(MENU_VISIBILITY_SKELETON); - view_menu->get_popup()->toggle_item_multistate(idx); - - // Change icon - const int state = view_menu->get_popup()->get_item_state(idx); - switch (state) { - case 0: - view_menu->get_popup()->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_hidden")); - break; - case 1: - view_menu->get_popup()->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_visible")); - break; - case 2: - view_menu->get_popup()->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_xray")); - break; - } - - update_all_gizmos(); - - } break; } } @@ -4519,9 +4518,9 @@ void SpatialEditor::_init_indicators() { nivec * 0.0 + ivec * (GIZMO_ARROW_OFFSET + GIZMO_ARROW_SIZE), }; - int arrow_sides = 6; + int arrow_sides = 16; - for (int k = 0; k < 6; k++) { + for (int k = 0; k < arrow_sides; k++) { Basis ma(ivec, Math_PI * 2 * float(k) / arrow_sides); Basis mb(ivec, Math_PI * 2 * float(k + 1) / arrow_sides); @@ -4605,10 +4604,10 @@ void SpatialEditor::_init_indicators() { ivec * 0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE, }; - for (int k = 0; k < 32; k++) { + for (int k = 0; k < 64; k++) { - Basis ma(ivec, Math_PI * 2 * float(k) / 32); - Basis mb(ivec, Math_PI * 2 * float(k + 1) / 32); + Basis ma(ivec, Math_PI * 2 * float(k) / 64); + Basis mb(ivec, Math_PI * 2 * float(k + 1) / 64); for (int j = 0; j < 4; j++) { @@ -4725,6 +4724,26 @@ void SpatialEditor::_init_indicators() { _generate_selection_box(); } +struct _GizmoPluginComparator { + + bool operator()(const Ref<EditorSpatialGizmoPlugin> &p_a, const Ref<EditorSpatialGizmoPlugin> &p_b) const { + return p_a->get_name() < p_b->get_name(); + } +}; + +void SpatialEditor::_init_gizmos_menu() { + _register_all_gizmos(); + + gizmo_plugins.sort_custom<_GizmoPluginComparator>(); + + for (int i = 0; i < gizmo_plugins.size(); ++i) { + if (!gizmo_plugins[i]->can_be_hidden()) continue; + String plugin_name = gizmo_plugins[i]->get_name(); + gizmos_menu->add_multistate_item(TTR(plugin_name), 3, EditorSpatialGizmoPlugin::ON_TOP, i); + gizmos_menu->set_item_icon(gizmos_menu->get_item_index(i), gizmos_menu->get_icon("visibility_visible")); + } +} + void SpatialEditor::_init_grid() { PoolVector<Color> grid_colors[3]; @@ -5005,7 +5024,6 @@ void SpatialEditor::_notification(int p_what) { view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_icon("Panels3", "EditorIcons")); view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_icon("Panels3Alt", "EditorIcons")); view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_icon("Panels4", "EditorIcons")); - view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VISIBILITY_SKELETON), view_menu->get_popup()->get_icon("visibility_visible")); _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT); @@ -5018,14 +5036,13 @@ void SpatialEditor::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { - gizmos = memnew(SpatialEditorGizmos); + _init_gizmos_menu(); _init_indicators(); } if (p_what == NOTIFICATION_EXIT_TREE) { _finish_indicators(); - memdelete(gizmos); } if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { tool_button[SpatialEditor::TOOL_MODE_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons")); @@ -5084,25 +5101,21 @@ void SpatialEditor::_request_gizmo(Object *p_obj) { return; if (editor->get_edited_scene() && (sp == editor->get_edited_scene() || (sp->get_owner() && editor->get_edited_scene()->is_a_parent_of(sp)))) { - Ref<SpatialEditorGizmo> seg; + Ref<EditorSpatialGizmo> seg; - for (int i = 0; i < EditorNode::get_singleton()->get_editor_data().get_editor_plugin_count(); i++) { + for (int i = 0; i < gizmo_plugins.size(); ++i) { + seg = gizmo_plugins.write[i]->get_gizmo(sp); - seg = EditorNode::get_singleton()->get_editor_data().get_editor_plugin(i)->create_spatial_gizmo(sp); - if (seg.is_valid()) - break; - } + if (seg.is_valid()) { + sp->set_gizmo(seg); - if (!seg.is_valid()) { - seg = gizmos->get_gizmo(sp); - } - if (seg.is_valid()) { - sp->set_gizmo(seg); - } + if (sp == selected) { + seg->set_selected(true); + selected->update_gizmo(); + } - if (seg.is_valid() && sp == selected) { - seg->set_selected(true); - selected->update_gizmo(); + break; + } } } } @@ -5158,11 +5171,35 @@ void SpatialEditor::_node_removed(Node *p_node) { selected = NULL; } +void SpatialEditor::_register_all_gizmos() { + register_gizmo_plugin(Ref<CameraSpatialGizmoPlugin>(memnew(CameraSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<LightSpatialGizmoPlugin>(memnew(LightSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<AudioStreamPlayer3DSpatialGizmoPlugin>(memnew(AudioStreamPlayer3DSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<MeshInstanceSpatialGizmoPlugin>(memnew(MeshInstanceSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<SoftBodySpatialGizmoPlugin>(memnew(SoftBodySpatialGizmoPlugin))); + register_gizmo_plugin(Ref<Sprite3DSpatialGizmoPlugin>(memnew(Sprite3DSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<Position3DSpatialGizmoPlugin>(memnew(Position3DSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<SkeletonSpatialGizmoPlugin>(memnew(SkeletonSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<RayCastSpatialGizmoPlugin>(memnew(RayCastSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<VehicleWheelSpatialGizmoPlugin>(memnew(VehicleWheelSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<VisibilityNotifierGizmoPlugin>(memnew(VisibilityNotifierGizmoPlugin))); + register_gizmo_plugin(Ref<ParticlesGizmoPlugin>(memnew(ParticlesGizmoPlugin))); + register_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin))); + register_gizmo_plugin(Ref<GIProbeGizmoPlugin>(memnew(GIProbeGizmoPlugin))); + register_gizmo_plugin(Ref<BakedIndirectLightGizmoPlugin>(memnew(BakedIndirectLightGizmoPlugin))); + register_gizmo_plugin(Ref<CollisionShapeSpatialGizmoPlugin>(memnew(CollisionShapeSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<CollisionPolygonSpatialGizmoPlugin>(memnew(CollisionPolygonSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<NavigationMeshSpatialGizmoPlugin>(memnew(NavigationMeshSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<JointSpatialGizmoPlugin>(memnew(JointSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<PhysicalBoneSpatialGizmoPlugin>(memnew(PhysicalBoneSpatialGizmoPlugin))); +} + void SpatialEditor::_bind_methods() { ClassDB::bind_method("_unhandled_key_input", &SpatialEditor::_unhandled_key_input); ClassDB::bind_method("_node_removed", &SpatialEditor::_node_removed); ClassDB::bind_method("_menu_item_pressed", &SpatialEditor::_menu_item_pressed); + ClassDB::bind_method("_menu_gizmo_toggled", &SpatialEditor::_menu_gizmo_toggled); ClassDB::bind_method("_menu_item_toggled", &SpatialEditor::_menu_item_toggled); ClassDB::bind_method("_xform_dialog_action", &SpatialEditor::_xform_dialog_action); ClassDB::bind_method("_get_editor_data", &SpatialEditor::_get_editor_data); @@ -5363,19 +5400,26 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/4_viewports", TTR("4 Viewports"), KEY_MASK_CMD + KEY_4), MENU_VIEW_USE_4_VIEWPORTS); p->add_separator(); + p->add_submenu_item(TTR("Gizmos"), "GizmosMenu"); + + p->add_separator(); + p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN); p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid")), MENU_VIEW_GRID); p->add_separator(); p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings")), MENU_VIEW_CAMERA_SETTINGS); - p->add_separator(); - p->add_multistate_item(TTR("Skeleton Gizmo visibility"), 3, 1, MENU_VISIBILITY_SKELETON); - p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true); p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true); p->connect("id_pressed", this, "_menu_item_pressed"); + gizmos_menu = memnew(PopupMenu); + p->add_child(gizmos_menu); + gizmos_menu->set_name("GizmosMenu"); + gizmos_menu->set_hide_on_checkable_item_selection(false); + gizmos_menu->connect("id_pressed", this, "_menu_gizmo_toggled"); + /* REST OF MENU */ palette_split = memnew(HSplitContainer); @@ -5583,6 +5627,10 @@ void SpatialEditorPlugin::snap_cursor_to_plane(const Plane &p_plane) { spatial_editor->snap_cursor_to_plane(p_plane); } +void SpatialEditor::register_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> ref) { + gizmo_plugins.push_back(ref); +} + SpatialEditorPlugin::SpatialEditorPlugin(EditorNode *p_node) { editor = p_node; @@ -5596,3 +5644,182 @@ SpatialEditorPlugin::SpatialEditorPlugin(EditorNode *p_node) { SpatialEditorPlugin::~SpatialEditorPlugin() { } + +void EditorSpatialGizmoPlugin::create_material(const String &p_name, const Color &p_color, bool p_billboard, bool p_on_top, bool p_use_vertex_color) { + + Color instanced_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/instanced"); + + Vector<Ref<SpatialMaterial> > mats; + + for (int i = 0; i < 4; i++) { + bool selected = i % 2 == 1; + bool instanced = i < 2; + + Ref<SpatialMaterial> material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + + Color color = instanced ? instanced_color : p_color; + + if (!selected) { + color.a *= 0.3; + } + + material->set_albedo(color); + material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + material->set_render_priority(SpatialMaterial::RENDER_PRIORITY_MIN + 1); + + if (p_use_vertex_color) { + material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + } + + if (p_billboard) { + material->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); + } + + if (p_on_top && selected) { + material->set_on_top_of_alpha(); + } + + mats.push_back(material); + } + + materials[p_name] = mats; +} + +void EditorSpatialGizmoPlugin::create_icon_material(const String &p_name, const Ref<Texture> &p_texture, bool p_on_top, const Color &p_albedo) { + + Color instanced_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/instanced"); + + Vector<Ref<SpatialMaterial> > icons; + + for (int i = 0; i < 4; i++) { + bool selected = i % 2 == 1; + bool instanced = i < 2; + + Ref<SpatialMaterial> icon = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + + Color color = instanced ? instanced_color : p_albedo; + + if (!selected) { + color.a *= 0.3; + } + + icon->set_albedo(color); + + icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + icon->set_cull_mode(SpatialMaterial::CULL_DISABLED); + icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); + icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, p_texture); + icon->set_flag(SpatialMaterial::FLAG_FIXED_SIZE, true); + icon->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); + icon->set_render_priority(SpatialMaterial::RENDER_PRIORITY_MIN); + + if (p_on_top && selected) { + icon->set_on_top_of_alpha(); + } + + icons.push_back(icon); + } + + materials[p_name] = icons; +} + +void EditorSpatialGizmoPlugin::create_handle_material(const String &p_name, bool p_billboard) { + Ref<SpatialMaterial> handle_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + + handle_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + handle_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + handle_material->set_flag(SpatialMaterial::FLAG_USE_POINT_SIZE, true); + Ref<Texture> handle_t = SpatialEditor::get_singleton()->get_icon("Editor3DHandle", "EditorIcons"); + handle_material->set_point_size(handle_t->get_width()); + handle_material->set_texture(SpatialMaterial::TEXTURE_ALBEDO, handle_t); + handle_material->set_albedo(Color(1, 1, 1)); + handle_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + handle_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + handle_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + handle_material->set_on_top_of_alpha(); + if (p_billboard) { + handle_material->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); + handle_material->set_on_top_of_alpha(); + } + + materials[p_name] = Vector<Ref<SpatialMaterial> >(); + materials[p_name].push_back(handle_material); +} + +void EditorSpatialGizmoPlugin::add_material(const String &p_name, Ref<SpatialMaterial> p_material) { + materials[p_name] = Vector<Ref<SpatialMaterial> >(); + materials[p_name].push_back(p_material); +} + +Ref<SpatialMaterial> EditorSpatialGizmoPlugin::get_material(const String &p_name, EditorSpatialGizmo *p_gizmo) { + ERR_FAIL_COND_V(!materials.has(p_name), Ref<SpatialMaterial>()); + ERR_FAIL_COND_V(materials[p_name].size() == 0, Ref<SpatialMaterial>()); + + if (p_gizmo == NULL) return materials[p_name][0]; + + int index = (p_gizmo->is_selected() ? 1 : 0) + (p_gizmo->is_editable() ? 2 : 0); + + Ref<SpatialMaterial> mat = materials[p_name][index]; + + if (current_state == ON_TOP && p_gizmo->is_selected()) { + mat->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, true); + } else { + mat->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, false); + } + + return mat; +} + +Ref<EditorSpatialGizmo> EditorSpatialGizmoPlugin::get_gizmo(Spatial *p_spatial) { + + Ref<EditorSpatialGizmo> ref = create_gizmo(p_spatial); + + if (ref.is_null()) return ref; + + ref->set_plugin(this); + ref->set_spatial_node(p_spatial); + ref->set_hidden(current_state == HIDDEN); + + current_gizmos.push_back(ref.ptr()); + return ref; +} + +bool EditorSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return false; +} + +Ref<EditorSpatialGizmo> EditorSpatialGizmoPlugin::create_gizmo(Spatial *p_spatial) { + + Ref<EditorSpatialGizmo> ref; + if (has_gizmo(p_spatial)) ref.instance(); + return ref; +} + +bool EditorSpatialGizmoPlugin::can_be_hidden() const { + return true; +} + +bool EditorSpatialGizmoPlugin::is_selectable_when_hidden() const { + return false; +} + +void EditorSpatialGizmoPlugin::set_state(int p_state) { + current_state = p_state; + for (int i = 0; i < current_gizmos.size(); ++i) { + current_gizmos[i]->set_hidden(current_state == HIDDEN); + } +} + +void EditorSpatialGizmoPlugin::unregister_gizmo(EditorSpatialGizmo *p_gizmo) { + current_gizmos.erase(p_gizmo); +} + +EditorSpatialGizmoPlugin::EditorSpatialGizmoPlugin() { + current_state = ON_TOP; +} + +EditorSpatialGizmoPlugin::~EditorSpatialGizmoPlugin() { +} diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index bd449a28df..0ebc11e5df 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -43,11 +43,11 @@ class Camera; class SpatialEditor; -class SpatialEditorGizmos; +class EditorSpatialGizmoPlugin; -class SpatialEditorGizmo : public SpatialGizmo { +class EditorSpatialGizmo : public SpatialGizmo { - GDCLASS(SpatialEditorGizmo, SpatialGizmo); + GDCLASS(EditorSpatialGizmo, SpatialGizmo); bool selected; bool instanced; @@ -56,15 +56,86 @@ public: void set_selected(bool p_selected) { selected = p_selected; } bool is_selected() const { return selected; } + struct Instance { + + RID instance; + Ref<ArrayMesh> mesh; + RID skeleton; + bool billboard; + bool unscaled; + bool can_intersect; + bool extra_margin; + Instance() { + + billboard = false; + unscaled = false; + can_intersect = false; + extra_margin = false; + } + + void create_instance(Spatial *p_base, bool p_hidden = false); + }; + + Vector<Vector3> collision_segments; + Ref<TriangleMesh> collision_mesh; + + struct Handle { + Vector3 pos; + bool billboard; + }; + + Vector<Vector3> handles; + Vector<Vector3> secondary_handles; + float selectable_icon_size = -1.0f; + bool billboard_handle; + + bool valid; + bool hidden; + Spatial *base; + Vector<Instance> instances; + Spatial *spatial_node; + EditorSpatialGizmoPlugin *gizmo_plugin; + + void _set_spatial_node(Node *p_node) { set_spatial_node(Object::cast_to<Spatial>(p_node)); } + +protected: + static void _bind_methods(); + +public: + void add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard = false); + void add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard = false, const RID &p_skeleton = RID()); + void add_collision_segments(const Vector<Vector3> &p_lines); + void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh); + void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1); + void add_handles(const Vector<Vector3> &p_handles, const Ref<Material> &p_material, bool p_billboard = false, bool p_secondary = false); + void add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position = Vector3()); + virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; + virtual Variant get_handle_value(int p_idx); virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); - virtual bool is_gizmo_handle_highlighted(int idx) const { return false; } - virtual bool intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum); - virtual bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false); - SpatialEditorGizmo(); + void set_spatial_node(Spatial *p_node); + Spatial *get_spatial_node() const { return spatial_node; } + Vector3 get_handle_pos(int p_idx) const; + bool intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum); + bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false); + + virtual void clear(); + virtual void create(); + virtual void transform(); + virtual void redraw(); + virtual void free(); + + //TODO remove (?) + virtual bool is_editable() const; + virtual bool can_draw() const; + + void set_hidden(bool p_hidden); + void set_plugin(EditorSpatialGizmoPlugin *p_gizmo); + + EditorSpatialGizmo(); + ~EditorSpatialGizmo(); }; class SpatialEditorViewport : public Control { @@ -233,7 +304,7 @@ private: int edited_gizmo; Point2 mouse_pos; bool snap; - Ref<SpatialEditorGizmo> gizmo; + Ref<EditorSpatialGizmo> gizmo; int gizmo_handle; Variant gizmo_initial_value; Vector3 gizmo_initial_pos; @@ -489,10 +560,10 @@ private: MENU_VIEW_USE_4_VIEWPORTS, MENU_VIEW_ORIGIN, MENU_VIEW_GRID, + MENU_VIEW_GIZMOS_3D_ICONS, MENU_VIEW_CAMERA_SETTINGS, MENU_LOCK_SELECTED, MENU_UNLOCK_SELECTED, - MENU_VISIBILITY_SKELETON, MENU_SNAP_TO_FLOOR }; @@ -500,6 +571,7 @@ private: Button *tool_option_button[TOOL_OPT_MAX]; MenuButton *transform_menu; + PopupMenu *gizmos_menu; MenuButton *view_menu; ToolButton *lock_button; @@ -531,6 +603,7 @@ private: void _xform_dialog_action(); void _menu_item_pressed(int p_option); void _menu_item_toggled(bool pressed, int p_option); + void _menu_gizmo_toggled(int p_option); HBoxContainer *hbc_menu; @@ -539,6 +612,7 @@ private: void _instance_scene(); void _init_indicators(); + void _init_gizmos_menu(); void _init_grid(); void _finish_indicators(); void _finish_grid(); @@ -558,7 +632,10 @@ private: static SpatialEditor *singleton; void _node_removed(Node *p_node); - SpatialEditorGizmos *gizmos; + Vector<Ref<EditorSpatialGizmoPlugin> > gizmo_plugins; + + void _register_all_gizmos(); + SpatialEditor(); bool is_any_freelook_active() const; @@ -598,8 +675,6 @@ public: Ref<ArrayMesh> get_scale_gizmo(int idx) const { return scale_gizmo[idx]; } Ref<ArrayMesh> get_scale_plane_gizmo(int idx) const { return scale_plane_gizmo[idx]; } - int get_skeleton_visibility_state() const; - void update_transform_gizmo(); void update_all_gizmos(); void snap_selected_nodes_to_floor(); @@ -632,6 +707,8 @@ public: return viewports[p_idx]; } + void register_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> ref); + Camera *get_camera() { return NULL; } void edit(Spatial *p_spatial); void clear(); @@ -668,4 +745,49 @@ public: ~SpatialEditorPlugin(); }; +class EditorSpatialGizmoPlugin : public Resource { + + GDCLASS(EditorSpatialGizmoPlugin, Resource); + +public: + static const int ON_TOP = 0; + static const int VISIBLE = 1; + static const int HIDDEN = 2; + +private: + int current_state; + List<EditorSpatialGizmo *> current_gizmos; + HashMap<String, Vector<Ref<SpatialMaterial> > > materials; + +protected: + virtual bool has_gizmo(Spatial *p_spatial); + virtual Ref<EditorSpatialGizmo> create_gizmo(Spatial *p_spatial); + +public: + void create_material(const String &p_name, const Color &p_color, bool p_billboard = false, bool p_on_top = false, bool p_use_vertex_color = false); + void create_icon_material(const String &p_name, const Ref<Texture> &p_texture, bool p_on_top = false, const Color &p_albedo = Color(1, 1, 1, 1)); + void create_handle_material(const String &p_name, bool p_billboard = false); + void add_material(const String &p_name, Ref<SpatialMaterial> p_material); + + Ref<SpatialMaterial> get_material(const String &p_name, EditorSpatialGizmo *p_gizmo = NULL); + + virtual String get_name() const = 0; + virtual bool can_be_hidden() const; + virtual bool is_selectable_when_hidden() const; + + virtual void redraw(EditorSpatialGizmo *p_gizmo) {} + virtual String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { return ""; } + virtual Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { return Variant(); } + virtual void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {} + virtual void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false) {} + virtual bool is_gizmo_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int idx) const { return false; } + + Ref<EditorSpatialGizmo> get_gizmo(Spatial *p_spatial); + void set_state(int p_state); + void unregister_gizmo(EditorSpatialGizmo *p_gizmo); + + EditorSpatialGizmoPlugin(); + virtual ~EditorSpatialGizmoPlugin(); +}; + #endif diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index e4fdd1f251..0419c3d4b1 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -57,8 +57,6 @@ void TextureRegionEditor::_region_draw() { base_tex = obj_styleBox->get_texture(); else if (atlas_tex.is_valid()) base_tex = atlas_tex->get_atlas(); - else if (tile_set.is_valid() && selected_tile != -1 && tile_set->has_tile(selected_tile)) - base_tex = tile_set->tile_get_texture(selected_tile); if (base_tex.is_null()) return; @@ -284,8 +282,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { r = obj_styleBox->get_region_rect(); else if (atlas_tex.is_valid()) r = atlas_tex->get_region(); - else if (tile_set.is_valid() && selected_tile != -1) - r = tile_set->tile_get_region(selected_tile); rect.expand_to(r.position); rect.expand_to(r.position + r.size); } @@ -302,9 +298,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { } else if (atlas_tex.is_valid()) { undo_redo->add_do_method(atlas_tex.ptr(), "set_region", rect); undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region()); - } else if (tile_set.is_valid() && selected_tile != -1) { - undo_redo->add_do_method(tile_set.ptr(), "tile_set_region", selected_tile, rect); - undo_redo->add_undo_method(tile_set.ptr(), "tile_set_region", selected_tile, tile_set->tile_get_region(selected_tile)); } undo_redo->add_do_method(edit_draw, "update"); undo_redo->add_undo_method(edit_draw, "update"); @@ -327,8 +320,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { rect_prev = obj_styleBox->get_region_rect(); else if (atlas_tex.is_valid()) rect_prev = atlas_tex->get_region(); - else if (tile_set.is_valid() && selected_tile != -1) - rect_prev = tile_set->tile_get_region(selected_tile); for (int i = 0; i < 8; i++) { Vector2 tuv = endpoints[i]; @@ -372,9 +363,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { } else if (obj_styleBox.is_valid()) { undo_redo->add_do_method(obj_styleBox.ptr(), "set_region_rect", obj_styleBox->get_region_rect()); undo_redo->add_undo_method(obj_styleBox.ptr(), "set_region_rect", rect_prev); - } else if (tile_set.is_valid()) { - undo_redo->add_do_method(tile_set.ptr(), "tile_set_region", selected_tile, tile_set->tile_get_region(selected_tile)); - undo_redo->add_undo_method(tile_set.ptr(), "tile_set_region", selected_tile, rect_prev); } drag_index = -1; } @@ -595,8 +583,6 @@ void TextureRegionEditor::apply_rect(const Rect2 &rect) { obj_styleBox->set_region_rect(rect); else if (atlas_tex.is_valid()) atlas_tex->set_region(rect); - else if (tile_set.is_valid() && selected_tile != -1) - tile_set->tile_set_region(selected_tile, rect); } void TextureRegionEditor::_notification(int p_what) { @@ -623,12 +609,11 @@ void TextureRegionEditor::_notification(int p_what) { } void TextureRegionEditor::_node_removed(Object *p_obj) { - if (p_obj == node_sprite || p_obj == node_ninepatch || p_obj == obj_styleBox.ptr() || p_obj == atlas_tex.ptr() || p_obj == tile_set.ptr()) { + if (p_obj == node_sprite || p_obj == node_ninepatch || p_obj == obj_styleBox.ptr() || p_obj == atlas_tex.ptr()) { node_ninepatch = NULL; node_sprite = NULL; obj_styleBox = Ref<StyleBox>(NULL); atlas_tex = Ref<AtlasTexture>(NULL); - tile_set = Ref<TileSet>(NULL); hide(); } } @@ -677,8 +662,6 @@ void TextureRegionEditor::edit(Object *p_obj) { obj_styleBox->remove_change_receptor(this); if (atlas_tex.is_valid()) atlas_tex->remove_change_receptor(this); - if (tile_set.is_valid()) - tile_set->remove_change_receptor(this); if (p_obj) { node_sprite = Object::cast_to<Sprite>(p_obj); node_ninepatch = Object::cast_to<NinePatchRect>(p_obj); @@ -686,8 +669,6 @@ void TextureRegionEditor::edit(Object *p_obj) { obj_styleBox = Ref<StyleBoxTexture>(Object::cast_to<StyleBoxTexture>(p_obj)); if (Object::cast_to<AtlasTexture>(p_obj)) atlas_tex = Ref<AtlasTexture>(Object::cast_to<AtlasTexture>(p_obj)); - if (Object::cast_to<TileSet>(p_obj)) - tile_set = Ref<TileSet>(Object::cast_to<TileSet>(p_obj)); p_obj->add_change_receptor(this); _edit_region(); } else { @@ -695,7 +676,6 @@ void TextureRegionEditor::edit(Object *p_obj) { node_ninepatch = NULL; obj_styleBox = Ref<StyleBoxTexture>(NULL); atlas_tex = Ref<AtlasTexture>(NULL); - tile_set = Ref<TileSet>(NULL); } edit_draw->update(); if (node_sprite && !node_sprite->is_region()) { @@ -724,8 +704,6 @@ void TextureRegionEditor::_edit_region() { texture = obj_styleBox->get_texture(); else if (atlas_tex.is_valid()) texture = atlas_tex->get_atlas(); - else if (tile_set.is_valid() && selected_tile != -1 && tile_set->has_tile(selected_tile)) - texture = tile_set->tile_get_texture(selected_tile); if (texture.is_null()) { edit_draw->update(); @@ -794,8 +772,6 @@ void TextureRegionEditor::_edit_region() { rect = obj_styleBox->get_region_rect(); else if (atlas_tex.is_valid()) rect = atlas_tex->get_region(); - else if (tile_set.is_valid() && selected_tile != -1) - rect = tile_set->tile_get_region(selected_tile); edit_draw->update(); } @@ -814,10 +790,8 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { node_ninepatch = NULL; obj_styleBox = Ref<StyleBoxTexture>(NULL); atlas_tex = Ref<AtlasTexture>(NULL); - tile_set = Ref<TileSet>(NULL); editor = p_editor; undo_redo = editor->get_undo_redo(); - selected_tile = -1; snap_step = Vector2(10, 10); snap_separation = Vector2(0, 0); diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h index eeba1987a6..bd93be9267 100644 --- a/editor/plugins/texture_region_editor_plugin.h +++ b/editor/plugins/texture_region_editor_plugin.h @@ -38,7 +38,6 @@ #include "scene/gui/nine_patch_rect.h" #include "scene/resources/style_box.h" #include "scene/resources/texture.h" -#include "scene/resources/tile_set.h" /** @author Mariano Suligoy @@ -56,8 +55,6 @@ class TextureRegionEditor : public Control { }; friend class TextureRegionEditorPlugin; - friend class TileSetEditor; - friend class TileSetEditorPlugin; MenuButton *snap_mode_button; TextureRect *icon_zoom; ToolButton *zoom_in; @@ -91,14 +88,12 @@ class TextureRegionEditor : public Control { Sprite *node_sprite; Ref<StyleBoxTexture> obj_styleBox; Ref<AtlasTexture> atlas_tex; - Ref<TileSet> tile_set; Rect2 rect; Rect2 rect_prev; float prev_margin; int edited_margin; List<Rect2> autoslice_cache; - int selected_tile; bool drag; bool creating; diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 435ef229c5..101dc3037f 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -73,7 +73,8 @@ void TileMapEditor::_notification(int p_what) { rotate_180->set_icon(get_icon("Rotate180", "EditorIcons")); rotate_270->set_icon(get_icon("Rotate270", "EditorIcons")); - search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); PopupMenu *p = options->get_popup(); p->set_item_icon(p->get_item_index(OPTION_PAINTING), get_icon("Edit", "EditorIcons")); @@ -168,10 +169,11 @@ void TileMapEditor::_menu_option(int p_option) { } void TileMapEditor::_palette_selected(int index) { + _update_palette(); +} - if (manual_autotile) { - _update_palette(); - } +void TileMapEditor::_palette_multi_selected(int index, bool selected) { + _update_palette(); } void TileMapEditor::_canvas_mouse_enter() { @@ -296,7 +298,7 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, Vector<int> p_values, bool p } node->set_cell(p_pos.x, p_pos.y, p_value, p_flip_h, p_flip_v, p_transpose); - if (manual_autotile) { + if (manual_autotile || node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE) { if (current != -1) { node->set_cell_autotile_coord(p_pos.x, p_pos.y, position); } @@ -317,7 +319,6 @@ void TileMapEditor::_text_entered(const String &p_text) { } void TileMapEditor::_text_changed(const String &p_text) { - _update_palette(); } @@ -427,7 +428,7 @@ void TileMapEditor::_update_palette() { if (tex.is_valid()) { Rect2 region = tileset->tile_get_region(entries[i].id); - if (tileset->tile_get_tile_mode(entries[i].id) == TileSet::AUTO_TILE) { + if (tileset->tile_get_tile_mode(entries[i].id) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(entries[i].id) == TileSet::ATLAS_TILE) { int spacing = tileset->autotile_get_spacing(entries[i].id); region.size = tileset->autotile_get_size(entries[i].id); region.position += (region.size + Vector2(spacing, spacing)) * tileset->autotile_get_icon_coordinate(entries[i].id); @@ -450,7 +451,7 @@ void TileMapEditor::_update_palette() { palette->select(0); } - if (manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) { + if ((manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) || tileset->tile_get_tile_mode(sel_tile) == TileSet::ATLAS_TILE) { const Map<Vector2, uint16_t> &tiles = tileset->autotile_get_bitmask_map(sel_tile); @@ -676,10 +677,10 @@ void TileMapEditor::_draw_cell(int p_cell, const Point2i &p_point, bool p_flip_h Vector2 tile_ofs = node->get_tileset()->tile_get_texture_offset(p_cell); Rect2 r = node->get_tileset()->tile_get_region(p_cell); - if (node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::AUTO_TILE) { + if (node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::AUTO_TILE || node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::ATLAS_TILE) { Vector2 offset; int selected = manual_palette->get_current(); - if (manual_autotile && selected != -1) { + if ((manual_autotile || node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::ATLAS_TILE) && selected != -1) { offset = manual_palette->get_item_metadata(selected); } else { offset = node->get_tileset()->autotile_get_icon_coordinate(p_cell); @@ -1673,6 +1674,7 @@ void TileMapEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_tileset_settings_changed"), &TileMapEditor::_tileset_settings_changed); ClassDB::bind_method(D_METHOD("_update_transform_buttons"), &TileMapEditor::_update_transform_buttons); ClassDB::bind_method(D_METHOD("_palette_selected"), &TileMapEditor::_palette_selected); + ClassDB::bind_method(D_METHOD("_palette_multi_selected"), &TileMapEditor::_palette_multi_selected); ClassDB::bind_method(D_METHOD("_fill_points"), &TileMapEditor::_fill_points); ClassDB::bind_method(D_METHOD("_erase_points"), &TileMapEditor::_erase_points); @@ -1800,6 +1802,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { palette->set_max_text_lines(2); palette->set_select_mode(ItemList::SELECT_MULTI); palette->connect("item_selected", this, "_palette_selected"); + palette->connect("multi_selected", this, "_palette_multi_selected"); palette_container->add_child(palette); // Add autotile override palette diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h index b8443ca962..bb76879b02 100644 --- a/editor/plugins/tile_map_editor_plugin.h +++ b/editor/plugins/tile_map_editor_plugin.h @@ -184,6 +184,7 @@ class TileMapEditor : public VBoxContainer { void _update_palette(); void _menu_option(int p_option); void _palette_selected(int index); + void _palette_multi_selected(int index, bool selected); void _start_undo(const String &p_action); void _finish_undo(); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 087c4293f1..8d1db5de8f 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -30,6 +30,8 @@ #include "tile_set_editor_plugin.h" +#include "core/os/input.h" +#include "core/os/keyboard.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "scene/2d/physics_body_2d.h" #include "scene/2d/sprite.h" @@ -39,7 +41,9 @@ void TileSetEditor::edit(const Ref<TileSet> &p_tileset) { tileset = p_tileset; tileset->add_change_receptor(this); - update_tile_list(); + texture_list->clear(); + texture_map.clear(); + update_texture_list(); } void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { @@ -161,75 +165,6 @@ void TileSetEditor::_import_scene(Node *p_scene, Ref<TileSet> p_library, bool p_ _import_node(p_scene, p_library); } -void TileSetEditor::_menu_confirm() { - - switch (option) { - - case MENU_OPTION_MERGE_FROM_SCENE: - case MENU_OPTION_CREATE_FROM_SCENE: { - - EditorNode *en = editor; - Node *scene = en->get_edited_scene(); - if (!scene) - break; - - _import_scene(scene, tileset, option == MENU_OPTION_MERGE_FROM_SCENE); - - } break; - } -} - -void TileSetEditor::_name_dialog_confirm(const String &name) { - - switch (option) { - - case MENU_OPTION_REMOVE_ITEM: { - - int id = tileset->find_tile_by_name(name); - - if (id < 0 && name.is_valid_integer()) - id = name.to_int(); - - if (tileset->has_tile(id)) { - tileset->remove_tile(id); - update_tile_list(); - } else { - err_dialog->set_text(TTR("Could not find tile:") + " " + name); - err_dialog->popup_centered(Size2(300, 60)); - } - } break; - } -} - -void TileSetEditor::_menu_cbk(int p_option) { - - option = p_option; - switch (p_option) { - - case MENU_OPTION_ADD_ITEM: { - tileset->create_tile(tileset->get_last_unused_tile_id()); - tileset->tile_set_name(tileset->get_last_unused_tile_id() - 1, itos(tileset->get_last_unused_tile_id() - 1)); - update_tile_list(); - } break; - case MENU_OPTION_REMOVE_ITEM: { - - nd->set_title(TTR("Remove Item")); - nd->set_text(TTR("Item name or ID:")); - nd->popup_centered(Size2(300, 95)); - } break; - case MENU_OPTION_CREATE_FROM_SCENE: { - - cd->set_text(TTR("Create from scene?")); - cd->popup_centered(Size2(300, 60)); - } break; - case MENU_OPTION_MERGE_FROM_SCENE: { - - cd->set_text(TTR("Merge from scene?")); - cd->popup_centered(Size2(300, 60)); - } break; - } -} - Error TileSetEditor::update_library_file(Node *p_base_scene, Ref<TileSet> ml, bool p_merge) { _import_scene(p_base_scene, ml, p_merge); @@ -237,28 +172,36 @@ Error TileSetEditor::update_library_file(Node *p_base_scene, Ref<TileSet> ml, bo } void TileSetEditor::_bind_methods() { - - ClassDB::bind_method("_menu_cbk", &TileSetEditor::_menu_cbk); - ClassDB::bind_method("_menu_confirm", &TileSetEditor::_menu_confirm); - ClassDB::bind_method("_name_dialog_confirm", &TileSetEditor::_name_dialog_confirm); - ClassDB::bind_method("_on_tile_list_selected", &TileSetEditor::_on_tile_list_selected); + ClassDB::bind_method("_on_tileset_toolbar_button_pressed", &TileSetEditor::_on_tileset_toolbar_button_pressed); + ClassDB::bind_method("_on_textures_added", &TileSetEditor::_on_textures_added); + ClassDB::bind_method("_on_tileset_toolbar_confirm", &TileSetEditor::_on_tileset_toolbar_confirm); + ClassDB::bind_method("_on_texture_list_selected", &TileSetEditor::_on_texture_list_selected); ClassDB::bind_method("_on_edit_mode_changed", &TileSetEditor::_on_edit_mode_changed); + ClassDB::bind_method("_on_workspace_mode_changed", &TileSetEditor::_on_workspace_mode_changed); ClassDB::bind_method("_on_workspace_overlay_draw", &TileSetEditor::_on_workspace_overlay_draw); + ClassDB::bind_method("_on_workspace_process", &TileSetEditor::_on_workspace_process); ClassDB::bind_method("_on_workspace_draw", &TileSetEditor::_on_workspace_draw); ClassDB::bind_method("_on_workspace_input", &TileSetEditor::_on_workspace_input); ClassDB::bind_method("_on_tool_clicked", &TileSetEditor::_on_tool_clicked); ClassDB::bind_method("_on_priority_changed", &TileSetEditor::_on_priority_changed); ClassDB::bind_method("_on_grid_snap_toggled", &TileSetEditor::_on_grid_snap_toggled); - ClassDB::bind_method("_set_snap_step_x", &TileSetEditor::_set_snap_step_x); - ClassDB::bind_method("_set_snap_step_y", &TileSetEditor::_set_snap_step_y); - ClassDB::bind_method("_set_snap_off_x", &TileSetEditor::_set_snap_off_x); - ClassDB::bind_method("_set_snap_off_y", &TileSetEditor::_set_snap_off_y); - ClassDB::bind_method("_set_snap_sep_x", &TileSetEditor::_set_snap_sep_x); - ClassDB::bind_method("_set_snap_sep_y", &TileSetEditor::_set_snap_sep_y); + ClassDB::bind_method("_set_snap_step", &TileSetEditor::_set_snap_step); + ClassDB::bind_method("_set_snap_off", &TileSetEditor::_set_snap_off); + ClassDB::bind_method("_set_snap_sep", &TileSetEditor::_set_snap_sep); } void TileSetEditor::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + + tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_icon(get_icon("ToolAddNode", "EditorIcons")); + tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_icon(get_icon("Remove", "EditorIcons")); + tileset_toolbar_tools->set_icon(get_icon("Tools", "EditorIcons")); + + tool_workspacemode[WORKSPACE_EDIT]->set_icon(get_icon("Edit", "EditorIcons")); + tool_workspacemode[WORKSPACE_CREATE_SINGLE]->set_icon(get_icon("AddSingleTile", "EditorIcons")); + tool_workspacemode[WORKSPACE_CREATE_AUTOTILE]->set_icon(get_icon("AddAutotile", "EditorIcons")); + tool_workspacemode[WORKSPACE_CREATE_ATLAS]->set_icon(get_icon("AddAtlasTile", "EditorIcons")); + tools[TOOL_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons")); tools[BITMASK_COPY]->set_icon(get_icon("Duplicate", "EditorIcons")); tools[BITMASK_PASTE]->set_icon(get_icon("Override", "EditorIcons")); @@ -266,91 +209,126 @@ void TileSetEditor::_notification(int p_what) { tools[SHAPE_NEW_POLYGON]->set_icon(get_icon("CollisionPolygon2D", "EditorIcons")); tools[SHAPE_DELETE]->set_icon(get_icon("Remove", "EditorIcons")); tools[SHAPE_KEEP_INSIDE_TILE]->set_icon(get_icon("Snap", "EditorIcons")); - tools[SHAPE_GRID_SNAP]->set_icon(get_icon("SnapGrid", "EditorIcons")); + tools[TOOL_GRID_SNAP]->set_icon(get_icon("SnapGrid", "EditorIcons")); tools[ZOOM_OUT]->set_icon(get_icon("ZoomLess", "EditorIcons")); tools[ZOOM_1]->set_icon(get_icon("ZoomReset", "EditorIcons")); tools[ZOOM_IN]->set_icon(get_icon("ZoomMore", "EditorIcons")); + tools[VISIBLE_INFO]->set_icon(get_icon("InformationSign", "EditorIcons")); + + tool_editmode[EDITMODE_REGION]->set_icon(get_icon("RegionEdit", "EditorIcons")); + tool_editmode[EDITMODE_COLLISION]->set_icon(get_icon("StaticBody2D", "EditorIcons")); + tool_editmode[EDITMODE_OCCLUSION]->set_icon(get_icon("LightOccluder2D", "EditorIcons")); + tool_editmode[EDITMODE_NAVIGATION]->set_icon(get_icon("Navigation2D", "EditorIcons")); + tool_editmode[EDITMODE_BITMASK]->set_icon(get_icon("PackedDataContainer", "EditorIcons")); + tool_editmode[EDITMODE_PRIORITY]->set_icon(get_icon("MaterialPreviewLight1", "EditorIcons")); + tool_editmode[EDITMODE_ICON]->set_icon(get_icon("LargeTexture", "EditorIcons")); } } -void TileSetEditor::_changed_callback(Object *p_changed, const char *p_prop) { - if (p_prop == StringName("region")) { - update_tile_list_icon(); - preview->set_region_rect(tileset->tile_get_region(get_current_tile())); - } else if (p_prop == StringName("name")) { - update_tile_list_icon(); - } else if (p_prop == StringName("texture") || p_prop == StringName("modulate") || p_prop == StringName("tile_mode")) { - _on_tile_list_selected(get_current_tile()); - workspace->update(); - preview->set_texture(tileset->tile_get_texture(get_current_tile())); - preview->set_modulate(tileset->tile_get_modulate(get_current_tile())); - preview->set_region_rect(tileset->tile_get_region(get_current_tile())); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) - property_editor->show(); - else - property_editor->hide(); - texture_region_editor->_edit_region(); - update_tile_list_icon(); - } else if (p_prop == StringName("autotile")) { - workspace->update(); - } -} +TileSetEditor::TileSetEditor(EditorNode *p_editor) { -void TileSetEditor::initialize_bottom_editor() { + editor = p_editor; + set_name("Tile Set Bottom Editor"); - //Side Panel - side_panel = memnew(Control); - side_panel->set_name("Tile Set"); + HSplitContainer *split = memnew(HSplitContainer); + split->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_MINSIZE, 10); + add_child(split); - VSplitContainer *split = memnew(VSplitContainer); - side_panel->add_child(split); - split->set_anchors_and_margins_preset(Control::PRESET_WIDE); + VBoxContainer *left_container = memnew(VBoxContainer); + split->add_child(left_container); - tile_list = memnew(ItemList); - tile_list->set_v_size_flags(SIZE_EXPAND_FILL); - tile_list->set_h_size_flags(SIZE_EXPAND_FILL); - tile_list->set_custom_minimum_size(Size2(10, 200)); - tile_list->connect("item_selected", this, "_on_tile_list_selected"); - split->add_child(tile_list); + texture_list = memnew(ItemList); + left_container->add_child(texture_list); + texture_list->set_v_size_flags(SIZE_EXPAND_FILL); + texture_list->set_custom_minimum_size(Size2(200, 0)); + texture_list->connect("item_selected", this, "_on_texture_list_selected"); - property_editor = memnew(PropertyEditor); - property_editor->set_v_size_flags(SIZE_EXPAND_FILL); - property_editor->set_h_size_flags(SIZE_EXPAND_FILL); - property_editor->set_custom_minimum_size(Size2(10, 70)); - split->add_child(property_editor); + HBoxContainer *tileset_toolbar_container = memnew(HBoxContainer); + left_container->add_child(tileset_toolbar_container); - helper = memnew(TileSetEditorHelper(this)); - property_editor->call_deferred("edit", helper); - helper->add_change_receptor(this); + tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE] = memnew(ToolButton); + Vector<Variant> p; + p.push_back((int)TOOL_TILESET_ADD_TEXTURE); + tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->connect("pressed", this, "_on_tileset_toolbar_button_pressed", p); + tileset_toolbar_container->add_child(tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]); + tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_tooltip(TTR("Add Texture(s) to TileSet")); + + tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE] = memnew(ToolButton); + p = Vector<Variant>(); + p.push_back((int)TOOL_TILESET_REMOVE_TEXTURE); + tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->connect("pressed", this, "_on_tileset_toolbar_button_pressed", p); + tileset_toolbar_container->add_child(tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]); + tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_tooltip(TTR("Remove current Texture from TileSet")); + + Control *toolbar_separator = memnew(Control); + toolbar_separator->set_h_size_flags(Control::SIZE_EXPAND_FILL); + tileset_toolbar_container->add_child(toolbar_separator); + + tileset_toolbar_tools = memnew(MenuButton); + tileset_toolbar_tools->set_text("Tools"); + p = Vector<Variant>(); + p.push_back((int)TOOL_TILESET_CREATE_SCENE); + tileset_toolbar_tools->get_popup()->add_item(TTR("Create from Scene"), TOOL_TILESET_CREATE_SCENE); + p = Vector<Variant>(); + p.push_back((int)TOOL_TILESET_MERGE_SCENE); + tileset_toolbar_tools->get_popup()->add_item(TTR("Merge from Scene"), TOOL_TILESET_MERGE_SCENE); - //Editor - //Bottom Panel - bottom_panel = memnew(Control); - bottom_panel->set_name("Tile Set Bottom Editor"); + tileset_toolbar_tools->get_popup()->connect("id_pressed", this, "_on_tileset_toolbar_button_pressed"); + tileset_toolbar_container->add_child(tileset_toolbar_tools); + + //--------------- + VBoxContainer *right_container = memnew(VBoxContainer); + right_container->set_v_size_flags(SIZE_EXPAND_FILL); + split->add_child(right_container); dragging_point = -1; creating_shape = false; snap_step = Vector2(32, 32); + snap_offset = WORKSPACE_MARGIN; - bottom_panel->set_custom_minimum_size(Size2(0, 150)); + set_custom_minimum_size(Size2(0, 150)); VBoxContainer *main_vb = memnew(VBoxContainer); - bottom_panel->add_child(main_vb); - main_vb->set_anchors_and_margins_preset(Control::PRESET_WIDE); + right_container->add_child(main_vb); + main_vb->set_v_size_flags(SIZE_EXPAND_FILL); HBoxContainer *tool_hb = memnew(HBoxContainer); Ref<ButtonGroup> g(memnew(ButtonGroup)); - String label[EDITMODE_MAX] = { "Collision", "Occlusion", "Navigation", "Bitmask", "Priority", "Icon" }; + String workspace_label[WORKSPACE_MODE_MAX] = { "Edit", "New Single Tile", "New Autotile", "New Atlas" }; + + for (int i = 0; i < (int)WORKSPACE_MODE_MAX; i++) { + tool_workspacemode[i] = memnew(Button); + tool_workspacemode[i]->set_text(workspace_label[i]); + tool_workspacemode[i]->set_toggle_mode(true); + tool_workspacemode[i]->set_button_group(g); + Vector<Variant> p; + p.push_back(i); + tool_workspacemode[i]->connect("pressed", this, "_on_workspace_mode_changed", p); + tool_hb->add_child(tool_workspacemode[i]); + } + tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true); + workspace_mode = WORKSPACE_EDIT; + + main_vb->add_child(tool_hb); + main_vb->add_child(memnew(HSeparator)); + + tool_hb = memnew(HBoxContainer); + Control *spacer = memnew(Control); + spacer->set_custom_minimum_size(Size2(30, 0)); + tool_hb->add_child(spacer); + + g = Ref<ButtonGroup>(memnew(ButtonGroup)); + String label[EDITMODE_MAX] = { "Region", "Collision", "Occlusion", "Navigation", "Bitmask", "Priority", "Icon" }; for (int i = 0; i < (int)EDITMODE_MAX; i++) { tool_editmode[i] = memnew(Button); tool_editmode[i]->set_text(label[i]); tool_editmode[i]->set_toggle_mode(true); tool_editmode[i]->set_button_group(g); - Vector<Variant> args; - args.push_back(i); - tool_editmode[i]->connect("pressed", this, "_on_edit_mode_changed", args); + Vector<Variant> p; + p.push_back(i); + tool_editmode[i]->connect("pressed", this, "_on_edit_mode_changed", p); tool_hb->add_child(tool_editmode[i]); } tool_editmode[EDITMODE_COLLISION]->set_pressed(true); @@ -360,127 +338,52 @@ void TileSetEditor::initialize_bottom_editor() { main_vb->add_child(memnew(HSeparator)); toolbar = memnew(HBoxContainer); - for (int i = 0; i < (int)TOOLBAR_MAX; i++) { - tool_containers[i] = memnew(HBoxContainer); - toolbar->add_child(tool_containers[i]); - tool_containers[i]->hide(); - } - Ref<ButtonGroup> tg(memnew(ButtonGroup)); - Vector<Variant> p; + p = Vector<Variant>(); tools[TOOL_SELECT] = memnew(ToolButton); - tool_containers[TOOLBAR_DUMMY]->add_child(tools[TOOL_SELECT]); + toolbar->add_child(tools[TOOL_SELECT]); tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings.")); tools[TOOL_SELECT]->set_toggle_mode(true); tools[TOOL_SELECT]->set_button_group(tg); tools[TOOL_SELECT]->set_pressed(true); p.push_back((int)TOOL_SELECT); tools[TOOL_SELECT]->connect("pressed", this, "_on_tool_clicked", p); - tool_containers[TOOLBAR_DUMMY]->show(); tools[BITMASK_COPY] = memnew(ToolButton); p.push_back((int)BITMASK_COPY); tools[BITMASK_COPY]->connect("pressed", this, "_on_tool_clicked", p); - tool_containers[TOOLBAR_BITMASK]->add_child(tools[BITMASK_COPY]); + toolbar->add_child(tools[BITMASK_COPY]); tools[BITMASK_PASTE] = memnew(ToolButton); p = Vector<Variant>(); p.push_back((int)BITMASK_PASTE); tools[BITMASK_PASTE]->connect("pressed", this, "_on_tool_clicked", p); - tool_containers[TOOLBAR_BITMASK]->add_child(tools[BITMASK_PASTE]); + toolbar->add_child(tools[BITMASK_PASTE]); tools[BITMASK_CLEAR] = memnew(ToolButton); p = Vector<Variant>(); p.push_back((int)BITMASK_CLEAR); tools[BITMASK_CLEAR]->connect("pressed", this, "_on_tool_clicked", p); - tool_containers[TOOLBAR_BITMASK]->add_child(tools[BITMASK_CLEAR]); + toolbar->add_child(tools[BITMASK_CLEAR]); tools[SHAPE_NEW_POLYGON] = memnew(ToolButton); - tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_NEW_POLYGON]); + toolbar->add_child(tools[SHAPE_NEW_POLYGON]); tools[SHAPE_NEW_POLYGON]->set_toggle_mode(true); tools[SHAPE_NEW_POLYGON]->set_button_group(tg); - tool_containers[TOOLBAR_SHAPE]->add_child(memnew(VSeparator)); + toolbar->add_child(memnew(VSeparator)); tools[SHAPE_DELETE] = memnew(ToolButton); p = Vector<Variant>(); p.push_back((int)SHAPE_DELETE); tools[SHAPE_DELETE]->connect("pressed", this, "_on_tool_clicked", p); - tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_DELETE]); - tool_containers[TOOLBAR_SHAPE]->add_child(memnew(VSeparator)); + toolbar->add_child(tools[SHAPE_DELETE]); + toolbar->add_child(memnew(VSeparator)); tools[SHAPE_KEEP_INSIDE_TILE] = memnew(ToolButton); tools[SHAPE_KEEP_INSIDE_TILE]->set_toggle_mode(true); tools[SHAPE_KEEP_INSIDE_TILE]->set_pressed(true); - tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_KEEP_INSIDE_TILE]); - tools[SHAPE_GRID_SNAP] = memnew(ToolButton); - tools[SHAPE_GRID_SNAP]->set_toggle_mode(true); - tools[SHAPE_GRID_SNAP]->connect("toggled", this, "_on_grid_snap_toggled"); - tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_GRID_SNAP]); - - hb_grid = memnew(HBoxContainer); - tool_containers[TOOLBAR_SHAPE]->add_child(hb_grid); - - hb_grid->add_child(memnew(VSeparator)); - hb_grid->add_child(memnew(Label(TTR("Offset:")))); - - sb_off_x = memnew(SpinBox); - sb_off_x->set_min(-256); - sb_off_x->set_max(256); - sb_off_x->set_step(1); - sb_off_x->set_value(snap_offset.x); - sb_off_x->set_suffix("px"); - sb_off_x->connect("value_changed", this, "_set_snap_off_x"); - hb_grid->add_child(sb_off_x); - - sb_off_y = memnew(SpinBox); - sb_off_y->set_min(-256); - sb_off_y->set_max(256); - sb_off_y->set_step(1); - sb_off_y->set_value(snap_offset.y); - sb_off_y->set_suffix("px"); - sb_off_y->connect("value_changed", this, "_set_snap_off_y"); - hb_grid->add_child(sb_off_y); - - hb_grid->add_child(memnew(VSeparator)); - hb_grid->add_child(memnew(Label(TTR("Step:")))); - - sb_step_x = memnew(SpinBox); - sb_step_x->set_min(-256); - sb_step_x->set_max(256); - sb_step_x->set_step(1); - sb_step_x->set_value(snap_step.x); - sb_step_x->set_suffix("px"); - sb_step_x->connect("value_changed", this, "_set_snap_step_x"); - hb_grid->add_child(sb_step_x); - - sb_step_y = memnew(SpinBox); - sb_step_y->set_min(-256); - sb_step_y->set_max(256); - sb_step_y->set_step(1); - sb_step_y->set_value(snap_step.y); - sb_step_y->set_suffix("px"); - sb_step_y->connect("value_changed", this, "_set_snap_step_y"); - hb_grid->add_child(sb_step_y); - - hb_grid->add_child(memnew(VSeparator)); - hb_grid->add_child(memnew(Label(TTR("Separation:")))); - - sb_sep_x = memnew(SpinBox); - sb_sep_x->set_min(0); - sb_sep_x->set_max(256); - sb_sep_x->set_step(1); - sb_sep_x->set_value(snap_separation.x); - sb_sep_x->set_suffix("px"); - sb_sep_x->connect("value_changed", this, "_set_snap_sep_x"); - hb_grid->add_child(sb_sep_x); - - sb_sep_y = memnew(SpinBox); - sb_sep_y->set_min(0); - sb_sep_y->set_max(256); - sb_sep_y->set_step(1); - sb_sep_y->set_value(snap_separation.y); - sb_sep_y->set_suffix("px"); - sb_sep_y->connect("value_changed", this, "_set_snap_sep_y"); - hb_grid->add_child(sb_sep_y); - - hb_grid->hide(); + toolbar->add_child(tools[SHAPE_KEEP_INSIDE_TILE]); + tools[TOOL_GRID_SNAP] = memnew(ToolButton); + tools[TOOL_GRID_SNAP]->set_toggle_mode(true); + tools[TOOL_GRID_SNAP]->connect("toggled", this, "_on_grid_snap_toggled"); + toolbar->add_child(tools[TOOL_GRID_SNAP]); spin_priority = memnew(SpinBox); spin_priority->set_min(1); @@ -491,8 +394,6 @@ void TileSetEditor::initialize_bottom_editor() { spin_priority->hide(); toolbar->add_child(spin_priority); - tool_containers[TOOLBAR_SHAPE]->show(); - Control *separator = memnew(Control); separator->set_h_size_flags(SIZE_EXPAND_FILL); toolbar->add_child(separator); @@ -502,22 +403,31 @@ void TileSetEditor::initialize_bottom_editor() { p.push_back((int)ZOOM_OUT); tools[ZOOM_OUT]->connect("pressed", this, "_on_tool_clicked", p); toolbar->add_child(tools[ZOOM_OUT]); + tools[ZOOM_OUT]->set_tooltip(TTR("Zoom Out")); tools[ZOOM_1] = memnew(ToolButton); p = Vector<Variant>(); p.push_back((int)ZOOM_1); tools[ZOOM_1]->connect("pressed", this, "_on_tool_clicked", p); toolbar->add_child(tools[ZOOM_1]); + tools[ZOOM_1]->set_tooltip(TTR("Reset Zoom")); tools[ZOOM_IN] = memnew(ToolButton); p = Vector<Variant>(); p.push_back((int)ZOOM_IN); tools[ZOOM_IN]->connect("pressed", this, "_on_tool_clicked", p); toolbar->add_child(tools[ZOOM_IN]); + tools[ZOOM_IN]->set_tooltip(TTR("Zoom In")); + + tools[VISIBLE_INFO] = memnew(ToolButton); + tools[VISIBLE_INFO]->set_toggle_mode(true); + tools[VISIBLE_INFO]->set_tooltip(TTR("Display tile's names (hold Alt Key)")); + toolbar->add_child(tools[VISIBLE_INFO]); main_vb->add_child(toolbar); scroll = memnew(ScrollContainer); main_vb->add_child(scroll); scroll->set_v_size_flags(SIZE_EXPAND_FILL); + scroll->set_clip_contents(true); workspace_container = memnew(Control); scroll->add_child(workspace_container); @@ -527,6 +437,7 @@ void TileSetEditor::initialize_bottom_editor() { workspace_container->add_child(workspace_overlay); workspace = memnew(Control); + workspace->set_focus_mode(FOCUS_ALL); workspace->connect("draw", this, "_on_workspace_draw"); workspace->connect("gui_input", this, "_on_workspace_input"); workspace->set_draw_behind_parent(true); @@ -536,39 +447,35 @@ void TileSetEditor::initialize_bottom_editor() { workspace->add_child(preview); preview->set_centered(false); preview->set_draw_behind_parent(true); - preview->set_region(true); -} + preview->set_position(WORKSPACE_MARGIN); -TileSetEditor::TileSetEditor(EditorNode *p_editor) { - - menu = memnew(MenuButton); - CanvasItemEditor::get_singleton()->add_control_to_menu_panel(menu); - menu->hide(); - menu->set_text(TTR("Tile Set")); - menu->get_popup()->add_item(TTR("Add Item"), MENU_OPTION_ADD_ITEM); - menu->get_popup()->add_item(TTR("Remove Item"), MENU_OPTION_REMOVE_ITEM); - menu->get_popup()->add_separator(); - menu->get_popup()->add_item(TTR("Create from Scene"), MENU_OPTION_CREATE_FROM_SCENE); - menu->get_popup()->add_item(TTR("Merge from Scene"), MENU_OPTION_MERGE_FROM_SCENE); - menu->get_popup()->connect("id_pressed", this, "_menu_cbk"); - editor = p_editor; + //--------------- cd = memnew(ConfirmationDialog); add_child(cd); - cd->get_ok()->connect("pressed", this, "_menu_confirm"); - - nd = memnew(EditorNameDialog); - add_child(nd); - nd->set_hide_on_ok(true); - nd->get_line_edit()->set_margin(MARGIN_TOP, 28); - nd->connect("name_confirmed", this, "_name_dialog_confirm"); + cd->connect("confirmed", this, "_on_tileset_toolbar_confirm"); + //--------------- err_dialog = memnew(AcceptDialog); add_child(err_dialog); - err_dialog->set_title(TTR("Error")); - draw_handles = false; + //--------------- + texture_dialog = memnew(EditorFileDialog); + texture_dialog->set_access(EditorFileDialog::ACCESS_RESOURCES); + texture_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILES); + texture_dialog->clear_filters(); + List<String> extensions; + + ResourceLoader::get_recognized_extensions_for_type("Texture", &extensions); + for (List<String>::Element *E = extensions.front(); E; E = E->next()) { - initialize_bottom_editor(); + texture_dialog->add_filter("*." + E->get() + " ; " + E->get().to_upper()); + } + add_child(texture_dialog); + texture_dialog->connect("files_selected", this, "_on_textures_added"); + + //--------------- + helper = memnew(TilesetEditorContext(this)); + tile_names_opacity = 0; } TileSetEditor::~TileSetEditor() { @@ -576,57 +483,166 @@ TileSetEditor::~TileSetEditor() { memdelete(helper); } -void TileSetEditor::_on_tile_list_selected(int p_index) { - if (get_current_tile() >= 0) { +void TileSetEditor::_on_tileset_toolbar_button_pressed(int p_index) { + option = p_index; + switch (option) { + case TOOL_TILESET_ADD_TEXTURE: { + texture_dialog->popup_centered_ratio(); + } break; + case TOOL_TILESET_REMOVE_TEXTURE: { + if (get_current_texture().is_valid()) { + cd->set_text(TTR("Remove Selected Textue and ALL TILES wich uses it?")); + cd->popup_centered(Size2(300, 60)); + } else { + err_dialog->set_text(TTR("You haven't selected a texture to remove.")); + err_dialog->popup_centered(Size2(300, 60)); + } + } break; + case TOOL_TILESET_CREATE_SCENE: { + + cd->set_text(TTR("Create from scene?")); + cd->popup_centered(Size2(300, 60)); + } break; + case TOOL_TILESET_MERGE_SCENE: { + + cd->set_text(TTR("Merge from scene?")); + cd->popup_centered(Size2(300, 60)); + } break; + } +} + +void TileSetEditor::_on_tileset_toolbar_confirm() { + switch (option) { + case TOOL_TILESET_REMOVE_TEXTURE: { + RID current_rid = get_current_texture()->get_rid(); + List<int> ids; + tileset->get_tile_list(&ids); + for (List<int>::Element *E = ids.front(); E; E = E->next()) { + if (tileset->tile_get_texture(E->get())->get_rid() == current_rid) { + tileset->remove_tile(E->get()); + } + } + texture_list->remove_item(texture_list->find_metadata(current_rid)); + texture_map.erase(current_rid); + _on_texture_list_selected(-1); + } break; + case TOOL_TILESET_MERGE_SCENE: + case TOOL_TILESET_CREATE_SCENE: { + + EditorNode *en = editor; + Node *scene = en->get_edited_scene(); + if (!scene) + break; + _import_scene(scene, tileset, option == TOOL_TILESET_MERGE_SCENE); + + edit(tileset); + } break; + } +} + +void TileSetEditor::_on_texture_list_selected(int p_index) { + if (get_current_texture().is_valid()) { current_item_index = p_index; - preview->set_texture(tileset->tile_get_texture(get_current_tile())); - preview->set_modulate(tileset->tile_get_modulate(get_current_tile())); - preview->set_region_rect(tileset->tile_get_region(get_current_tile())); - workspace->set_custom_minimum_size(tileset->tile_get_region(get_current_tile()).size); + preview->set_texture(get_current_texture()); + workspace->set_custom_minimum_size(get_current_texture()->get_size() + WORKSPACE_MARGIN * 2); + workspace_container->set_custom_minimum_size(get_current_texture()->get_size() + WORKSPACE_MARGIN * 2); + workspace_overlay->set_custom_minimum_size(get_current_texture()->get_size() + WORKSPACE_MARGIN * 2); update_workspace_tile_mode(); } else { current_item_index = -1; preview->set_texture(NULL); workspace->set_custom_minimum_size(Size2i()); + update_workspace_tile_mode(); } - texture_region_editor->selected_tile = get_current_tile(); - texture_region_editor->_edit_region(); - helper->selected_tile = get_current_tile(); - helper->_change_notify(""); + set_current_tile(-1); workspace->update(); } +void TileSetEditor::_on_textures_added(const PoolStringArray &p_paths) { + int invalid_count = 0; + for (int i = 0; i < p_paths.size(); i++) { + Ref<Texture> t = Ref<Texture>(ResourceLoader::load(p_paths[i])); + if (texture_map.has(t->get_rid())) { + invalid_count++; + } else { + texture_list->add_item(t->get_path().get_file()); + texture_map.insert(t->get_rid(), t); + texture_list->set_item_metadata(texture_list->get_item_count() - 1, t->get_rid()); + } + } + update_texture_list_icon(); + texture_list->select(texture_list->get_item_count() - 1); + _on_texture_list_selected(texture_list->get_item_count() - 1); + if (invalid_count > 0) { + err_dialog->set_text(String::num(invalid_count, 0) + TTR(" file(s) was not added because was already on the list.")); + err_dialog->popup_centered(Size2(300, 60)); + } +} + void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { edit_mode = (EditMode)p_edit_mode; switch (edit_mode) { + case EDITMODE_REGION: { + tools[TOOL_SELECT]->show(); + tools[BITMASK_COPY]->hide(); + tools[BITMASK_PASTE]->hide(); + tools[BITMASK_CLEAR]->hide(); + tools[SHAPE_NEW_POLYGON]->hide(); + if (workspace_mode == WORKSPACE_EDIT) + tools[SHAPE_DELETE]->show(); + else + tools[SHAPE_DELETE]->hide(); + tools[SHAPE_KEEP_INSIDE_TILE]->hide(); + tools[TOOL_GRID_SNAP]->show(); + + tools[TOOL_SELECT]->set_pressed(true); + tools[TOOL_SELECT]->set_tooltip(TTR("Drag handles to edit Rect.\nClick on another Tile to edit it.")); + spin_priority->hide(); + } break; case EDITMODE_BITMASK: { - tool_containers[TOOLBAR_DUMMY]->show(); - tool_containers[TOOLBAR_BITMASK]->show(); - tool_containers[TOOLBAR_SHAPE]->hide(); + tools[TOOL_SELECT]->show(); + tools[BITMASK_COPY]->show(); + tools[BITMASK_PASTE]->show(); + tools[BITMASK_CLEAR]->show(); + tools[SHAPE_NEW_POLYGON]->hide(); + tools[SHAPE_DELETE]->hide(); + tools[SHAPE_KEEP_INSIDE_TILE]->hide(); + tools[TOOL_GRID_SNAP]->hide(); + tools[TOOL_SELECT]->set_pressed(true); - tools[TOOL_SELECT]->set_tooltip(TTR("LMB: set bit on.\nRMB: set bit off.")); + tools[TOOL_SELECT]->set_tooltip(TTR("LMB: set bit on.\nRMB: set bit off.\nClick on another Tile to edit it.")); spin_priority->hide(); } break; case EDITMODE_COLLISION: case EDITMODE_NAVIGATION: case EDITMODE_OCCLUSION: { - tool_containers[TOOLBAR_DUMMY]->show(); - tool_containers[TOOLBAR_BITMASK]->hide(); - tool_containers[TOOLBAR_SHAPE]->show(); - tools[TOOL_SELECT]->set_tooltip(TTR("Select current edited sub-tile.")); + tools[TOOL_SELECT]->show(); + tools[BITMASK_COPY]->hide(); + tools[BITMASK_PASTE]->hide(); + tools[BITMASK_CLEAR]->hide(); + tools[SHAPE_NEW_POLYGON]->show(); + tools[SHAPE_DELETE]->show(); + tools[SHAPE_KEEP_INSIDE_TILE]->show(); + tools[TOOL_GRID_SNAP]->show(); + + tools[TOOL_SELECT]->set_tooltip(TTR("Select current edited sub-tile.\nClick on another Tile to edit it.")); spin_priority->hide(); - select_coord(edited_shape_coord); } break; default: { - tool_containers[TOOLBAR_DUMMY]->show(); - tool_containers[TOOLBAR_BITMASK]->hide(); - tool_containers[TOOLBAR_SHAPE]->hide(); + tools[TOOL_SELECT]->show(); + tools[BITMASK_COPY]->hide(); + tools[BITMASK_PASTE]->hide(); + tools[BITMASK_CLEAR]->hide(); + tools[SHAPE_NEW_POLYGON]->hide(); + tools[SHAPE_DELETE]->hide(); + tools[SHAPE_KEEP_INSIDE_TILE]->hide(); + tools[TOOL_GRID_SNAP]->show(); if (edit_mode == EDITMODE_ICON) { - tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings.")); + tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings.\nClick on another Tile to edit it.")); spin_priority->hide(); } else { - tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to change its priority.")); + tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to change its priority.\nClick on another Tile to edit it.")); spin_priority->show(); } } break; @@ -634,25 +650,52 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { workspace->update(); } +void TileSetEditor::_on_workspace_mode_changed(int p_workspace_mode) { + workspace_mode = (WorkspaceMode)p_workspace_mode; + if (p_workspace_mode == WORKSPACE_EDIT) { + update_workspace_tile_mode(); + } else { + for (int i = 0; i < EDITMODE_MAX; i++) { + tool_editmode[i]->hide(); + } + tool_editmode[EDITMODE_REGION]->show(); + tool_editmode[EDITMODE_REGION]->set_pressed(true); + _on_edit_mode_changed(EDITMODE_REGION); + } +} + void TileSetEditor::_on_workspace_draw() { - if (get_current_tile() >= 0 && !tileset.is_null()) { + const Color COLOR_AUTOTILE = Color(0.266373, 0.565288, 0.988281); + const Color COLOR_SINGLE = Color(0.988281, 0.909323, 0.266373); + const Color COLOR_ATLAS = Color(0.78653, 0.812835, 0.832031); + + if (tileset.is_null()) + return; + if (!get_current_texture().is_valid()) + return; + + draw_highlight_current_tile(); + + draw_grid_snap(); + if (get_current_tile() >= 0) { int spacing = tileset->autotile_get_spacing(get_current_tile()); Vector2 size = tileset->autotile_get_size(get_current_tile()); Rect2i region = tileset->tile_get_region(get_current_tile()); - Color c(0.347214, 0.722656, 0.617063); switch (edit_mode) { case EDITMODE_ICON: { Vector2 coord = tileset->autotile_get_icon_coordinate(get_current_tile()); - draw_highlight_tile(coord); + draw_highlight_subtile(coord); } break; case EDITMODE_BITMASK: { - c = Color(1, 0, 0, 0.5); + Color c(1, 0, 0, 0.5); for (float x = 0; x < region.size.x / (spacing + size.x); x++) { for (float y = 0; y < region.size.y / (spacing + size.y); y++) { Vector2 coord(x, y); Point2 anchor(coord.x * (spacing + size.x), coord.y * (spacing + size.y)); + anchor += WORKSPACE_MARGIN; + anchor += region.position; uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord); if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { if (mask & TileSet::BIND_TOPLEFT) { @@ -702,9 +745,9 @@ void TileSetEditor::_on_workspace_draw() { case EDITMODE_COLLISION: case EDITMODE_OCCLUSION: case EDITMODE_NAVIGATION: { - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { Vector2 coord = edited_shape_coord; - draw_highlight_tile(coord); + draw_highlight_subtile(coord); } draw_polygon_shapes(); draw_grid_snap(); @@ -723,89 +766,334 @@ void TileSetEditor::_on_workspace_draw() { } } spin_priority->set_suffix(" / " + String::num(total, 0)); - draw_highlight_tile(edited_shape_coord, queue_others); + draw_highlight_subtile(edited_shape_coord, queue_others); } break; } - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { - float j = -size.x; //make sure to draw at 0 - while (j < region.size.x) { - j += size.x; - if (spacing <= 0) { - workspace->draw_line(Point2(j, 0), Point2(j, region.size.y), c); - } else { - workspace->draw_rect(Rect2(Point2(j, 0), Size2(spacing, region.size.y)), c); - } - j += spacing; - } - j = -size.y; //make sure to draw at 0 - while (j < region.size.y) { - j += size.y; - if (spacing <= 0) { - workspace->draw_line(Point2(0, j), Point2(region.size.x, j), c); - } else { - workspace->draw_rect(Rect2(Point2(0, j), Size2(region.size.x, spacing)), c); - } - j += spacing; + draw_tile_subdivision(get_current_tile(), Color(0.347214, 0.722656, 0.617063)); + } + + RID current_texture_rid = get_current_texture()->get_rid(); + List<int> *tiles = new List<int>(); + tileset->get_tile_list(tiles); + for (List<int>::Element *E = tiles->front(); E; E = E->next()) { + int t_id = E->get(); + if (tileset->tile_get_texture(t_id)->get_rid() == current_texture_rid && (t_id != get_current_tile() || edit_mode != EDITMODE_REGION)) { + Rect2i region = tileset->tile_get_region(t_id); + region.position += WORKSPACE_MARGIN; + Color c; + if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) + c = COLOR_SINGLE; + else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) + c = COLOR_AUTOTILE; + else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) + c = COLOR_ATLAS; + draw_tile_subdivision(t_id, Color(0.347214, 0.722656, 0.617063, 0.5)); + workspace->draw_rect(region, c, false); + } + } + if (edit_mode == EDITMODE_REGION) { + if (workspace_mode != WORKSPACE_EDIT) { + Rect2i region = edited_region; + Color c; + if (workspace_mode == WORKSPACE_CREATE_SINGLE) + c = COLOR_SINGLE; + else if (workspace_mode == WORKSPACE_CREATE_AUTOTILE) + c = COLOR_AUTOTILE; + else if (workspace_mode == WORKSPACE_CREATE_ATLAS) + c = COLOR_ATLAS; + workspace->draw_rect(region, c, false); + draw_edited_region_subdivision(); + } else { + int t_id = get_current_tile(); + Rect2i region; + if (draw_edited_region) + region = edited_region; + else { + region = tileset->tile_get_region(t_id); + region.position += WORKSPACE_MARGIN; } + Color c; + if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) + c = COLOR_SINGLE; + else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) + c = COLOR_AUTOTILE; + else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) + c = COLOR_ATLAS; + if (draw_edited_region) + draw_edited_region_subdivision(); + else + draw_tile_subdivision(t_id, Color(0.347214, 0.722656, 0.617063, 1)); + workspace->draw_rect(region, c, false); } } workspace_overlay->update(); } +void TileSetEditor::_on_workspace_process() { + float a = tile_names_opacity; + if (Input::get_singleton()->is_key_pressed(KEY_ALT) || tools[VISIBLE_INFO]->is_pressed()) { + a += get_tree()->get_idle_process_time() * 2; + } else { + a -= get_tree()->get_idle_process_time() * 2; + } + + a = CLAMP(a, 0, 1); + if (a != tile_names_opacity) + workspace_overlay->update(); + tile_names_opacity = a; +} + void TileSetEditor::_on_workspace_overlay_draw() { + if (!tileset.is_valid()) + return; + if (!get_current_texture().is_valid()) + return; + + const Color COLOR_AUTOTILE = Color(0.266373, 0.565288, 0.988281); + const Color COLOR_SINGLE = Color(0.988281, 0.909323, 0.266373); + const Color COLOR_ATLAS = Color(0.78653, 0.812835, 0.832031); + + if (tile_names_opacity > 0) { + RID current_texture_rid = get_current_texture()->get_rid(); + List<int> *tiles = new List<int>(); + tileset->get_tile_list(tiles); + for (List<int>::Element *E = tiles->front(); E; E = E->next()) { + int t_id = E->get(); + if (tileset->tile_get_texture(t_id)->get_rid() == current_texture_rid) { + Rect2i region = tileset->tile_get_region(t_id); + region.position += WORKSPACE_MARGIN; + region.position *= workspace->get_scale().x; + Color c; + if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) + c = COLOR_SINGLE; + else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) + c = COLOR_AUTOTILE; + else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) + c = COLOR_ATLAS; + c.a = tile_names_opacity; + Ref<Font> font = get_font("font", "Label"); + region.set_size(font->get_string_size(tileset->tile_get_name(t_id))); + workspace_overlay->draw_rect(region, c); + region.position.y += region.size.y - 2; + c = Color(0.1, 0.1, 0.1, tile_names_opacity); + workspace_overlay->draw_string(font, region.position, tileset->tile_get_name(t_id), c); + } + } + } + int t_id = get_current_tile(); - if (t_id < 0 || !draw_handles) + if (t_id < 0) return; Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons"); - - for (int i = 0; i < current_shape.size(); i++) { - workspace_overlay->draw_texture(handle, current_shape[i] * workspace->get_scale().x - handle->get_size() * 0.5); + if (draw_handles) { + for (int i = 0; i < current_shape.size(); i++) { + workspace_overlay->draw_texture(handle, current_shape[i] * workspace->get_scale().x - handle->get_size() * 0.5); + } } } #define MIN_DISTANCE_SQUARED 6 void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { + if (tileset.is_null()) + return; + if (!get_current_texture().is_valid()) + return; - if (get_current_tile() >= 0 && !tileset.is_null()) { - Ref<InputEventMouseButton> mb = p_ie; - Ref<InputEventMouseMotion> mm = p_ie; + static bool dragging; + static bool erasing; + draw_edited_region = false; - static bool dragging; - static bool erasing; + Rect2 current_tile_region = Rect2(); + if (get_current_tile() >= 0) { + current_tile_region = tileset->tile_get_region(get_current_tile()); + } + current_tile_region.position += WORKSPACE_MARGIN; + + Ref<InputEventMouseButton> mb = p_ie; + Ref<InputEventMouseMotion> mm = p_ie; + + if (mb.is_valid()) { + if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (!current_tile_region.has_point(mb->get_position())) { + List<int> *tiles = new List<int>(); + tileset->get_tile_list(tiles); + for (List<int>::Element *E = tiles->front(); E; E = E->next()) { + int t_id = E->get(); + if (get_current_texture()->get_rid() == tileset->tile_get_texture(t_id)->get_rid()) { + Rect2 r = tileset->tile_get_region(t_id); + r.position += WORKSPACE_MARGIN; + if (r.has_point(mb->get_position())) { + set_current_tile(t_id); + workspace->update(); + workspace_overlay->update(); + return; + } + } + } + } + } + } + // Drag Middle Mouse + if (mm.is_valid()) { + if (mm->get_button_mask() & BUTTON_MASK_MIDDLE) { + Vector2 dragged(mm->get_relative().x, mm->get_relative().y); + scroll->set_h_scroll(scroll->get_h_scroll() - dragged.x * workspace->get_scale().x); + scroll->set_v_scroll(scroll->get_v_scroll() - dragged.y * workspace->get_scale().x); + } + } - int spacing = tileset->autotile_get_spacing(get_current_tile()); - Vector2 size = tileset->autotile_get_size(get_current_tile()); - switch (edit_mode) { - case EDITMODE_ICON: { - if (mb.is_valid()) { - if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - Vector2 coord((int)(mb->get_position().x / (spacing + size.x)), (int)(mb->get_position().y / (spacing + size.y))); - tileset->autotile_set_icon_coordinate(get_current_tile(), coord); - Rect2 region = tileset->tile_get_region(get_current_tile()); - region.size = size; - coord.x *= (spacing + size.x); - coord.y *= (spacing + size.y); - region.position += coord; - tile_list->set_item_icon_region(current_item_index, region); - workspace->update(); + if (edit_mode == EDITMODE_REGION) { + if (mb.is_valid()) { + if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (get_current_tile() >= 0 || workspace_mode != WORKSPACE_EDIT) { + dragging = true; + region_from = mb->get_position(); + edited_region = Rect2(region_from, Size2()); + workspace->update(); + workspace_overlay->update(); + return; + } + } else if (dragging && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) { + dragging = false; + edited_region = Rect2(); + workspace->update(); + workspace_overlay->update(); + return; + } else if (dragging && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + dragging = false; + update_edited_region(mb->get_position()); + edited_region.position -= WORKSPACE_MARGIN; + if (!edited_region.has_no_area()) { + if (get_current_tile() >= 0 && workspace_mode == WORKSPACE_EDIT) { + tileset->tile_set_region(get_current_tile(), edited_region); + } else { + int t_id = tileset->get_last_unused_tile_id(); + tileset->create_tile(t_id); + tileset->tile_set_texture(t_id, get_current_texture()); + tileset->tile_set_region(t_id, edited_region); + tileset->tile_set_name(t_id, get_current_texture()->get_path().get_file() + " " + String::num(t_id, 0)); + if (workspace_mode != WORKSPACE_CREATE_SINGLE) { + tileset->autotile_set_size(t_id, snap_step); + tileset->autotile_set_spacing(t_id, snap_separation.x); + tileset->tile_set_tile_mode(t_id, workspace_mode == WORKSPACE_CREATE_AUTOTILE ? TileSet::AUTO_TILE : TileSet::ATLAS_TILE); + } + set_current_tile(t_id); + tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true); + _on_workspace_mode_changed(WORKSPACE_EDIT); } } - } break; - case EDITMODE_BITMASK: { - if (mb.is_valid()) { - if (mb->is_pressed()) { - if (dragging) { - return; + workspace->update(); + workspace_overlay->update(); + return; + } + } else if (mm.is_valid()) { + if (dragging) { + update_edited_region(mm->get_position()); + draw_edited_region = true; + workspace->update(); + workspace_overlay->update(); + return; + } + } + } + if (workspace_mode == WORKSPACE_EDIT) { + + if (get_current_tile() >= 0) { + int spacing = tileset->autotile_get_spacing(get_current_tile()); + Vector2 size = tileset->autotile_get_size(get_current_tile()); + switch (edit_mode) { + case EDITMODE_ICON: { + if (mb.is_valid()) { + if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && current_tile_region.has_point(mb->get_position())) { + Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y))); + tileset->autotile_set_icon_coordinate(get_current_tile(), coord); + Rect2 region = tileset->tile_get_region(get_current_tile()); + region.size = size; + coord.x *= (spacing + size.x); + coord.y *= (spacing + size.y); + region.position += coord; + workspace->update(); + } + } + } break; + case EDITMODE_BITMASK: { + if (mb.is_valid()) { + if (mb->is_pressed()) { + if (dragging) { + return; + } + if ((mb->get_button_index() == BUTTON_RIGHT || mb->get_button_index() == BUTTON_LEFT) && current_tile_region.has_point(mb->get_position())) { + dragging = true; + erasing = (mb->get_button_index() == BUTTON_RIGHT); + Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y))); + Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y)); + pos = mb->get_position() - (pos + current_tile_region.position); + uint16_t bit = 0; + if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { + if (pos.x < size.x / 2) { + if (pos.y < size.y / 2) { + bit = TileSet::BIND_TOPLEFT; + } else { + bit = TileSet::BIND_BOTTOMLEFT; + } + } else { + if (pos.y < size.y / 2) { + bit = TileSet::BIND_TOPRIGHT; + } else { + bit = TileSet::BIND_BOTTOMRIGHT; + } + } + } else { + if (pos.x < size.x / 3) { + if (pos.y < size.y / 3) { + bit = TileSet::BIND_TOPLEFT; + } else if (pos.y > (size.y / 3) * 2) { + bit = TileSet::BIND_BOTTOMLEFT; + } else { + bit = TileSet::BIND_LEFT; + } + } else if (pos.x > (size.x / 3) * 2) { + if (pos.y < size.y / 3) { + bit = TileSet::BIND_TOPRIGHT; + } else if (pos.y > (size.y / 3) * 2) { + bit = TileSet::BIND_BOTTOMRIGHT; + } else { + bit = TileSet::BIND_RIGHT; + } + } else { + if (pos.y < size.y / 3) { + bit = TileSet::BIND_TOP; + } else if (pos.y > (size.y / 3) * 2) { + bit = TileSet::BIND_BOTTOM; + } else { + bit = TileSet::BIND_CENTER; + } + } + } + uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord); + if (erasing) { + mask &= ~bit; + } else { + mask |= bit; + } + tileset->autotile_set_bitmask(get_current_tile(), coord, mask); + workspace->update(); + } + } else { + if ((erasing && mb->get_button_index() == BUTTON_RIGHT) || (!erasing && mb->get_button_index() == BUTTON_LEFT)) { + dragging = false; + erasing = false; + } } - if (mb->get_button_index() == BUTTON_RIGHT || mb->get_button_index() == BUTTON_LEFT) { - dragging = true; - erasing = (mb->get_button_index() == BUTTON_RIGHT); - Vector2 coord((int)(mb->get_position().x / (spacing + size.x)), (int)(mb->get_position().y / (spacing + size.y))); + } + if (mm.is_valid()) { + if (dragging && current_tile_region.has_point(mm->get_position())) { + Vector2 coord((int)((mm->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mm->get_position().y - current_tile_region.position.y) / (spacing + size.y))); Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y)); - pos = mb->get_position() - pos; + pos = mm->get_position() - (pos + current_tile_region.position); uint16_t bit = 0; if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { if (pos.x < size.x / 2) { @@ -857,269 +1145,198 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { tileset->autotile_set_bitmask(get_current_tile(), coord, mask); workspace->update(); } - } else { - if ((erasing && mb->get_button_index() == BUTTON_RIGHT) || (!erasing && mb->get_button_index() == BUTTON_LEFT)) { - dragging = false; - erasing = false; - } } - } - if (mm.is_valid()) { - if (dragging) { - Vector2 coord((int)(mm->get_position().x / (spacing + size.x)), (int)(mm->get_position().y / (spacing + size.y))); - Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y)); - pos = mm->get_position() - pos; - uint16_t bit = 0; - if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { - if (pos.x < size.x / 2) { - if (pos.y < size.y / 2) { - bit = TileSet::BIND_TOPLEFT; - } else { - bit = TileSet::BIND_BOTTOMLEFT; - } - } else { - if (pos.y < size.y / 2) { - bit = TileSet::BIND_TOPRIGHT; - } else { - bit = TileSet::BIND_BOTTOMRIGHT; - } - } - } else { - if (pos.x < size.x / 3) { - if (pos.y < size.y / 3) { - bit = TileSet::BIND_TOPLEFT; - } else if (pos.y > (size.y / 3) * 2) { - bit = TileSet::BIND_BOTTOMLEFT; - } else { - bit = TileSet::BIND_LEFT; - } - } else if (pos.x > (size.x / 3) * 2) { - if (pos.y < size.y / 3) { - bit = TileSet::BIND_TOPRIGHT; - } else if (pos.y > (size.y / 3) * 2) { - bit = TileSet::BIND_BOTTOMRIGHT; - } else { - bit = TileSet::BIND_RIGHT; - } - } else { - if (pos.y < size.y / 3) { - bit = TileSet::BIND_TOP; - } else if (pos.y > (size.y / 3) * 2) { - bit = TileSet::BIND_BOTTOM; - } else { - bit = TileSet::BIND_CENTER; - } - } - } - uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord); - if (erasing) { - mask &= ~bit; - } else { - mask |= bit; - } - tileset->autotile_set_bitmask(get_current_tile(), coord, mask); - workspace->update(); + } break; + case EDITMODE_COLLISION: + case EDITMODE_OCCLUSION: + case EDITMODE_NAVIGATION: + case EDITMODE_PRIORITY: { + Vector2 shape_anchor = Vector2(0, 0); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { + shape_anchor = edited_shape_coord; + shape_anchor.x *= (size.x + spacing); + shape_anchor.y *= (size.y + spacing); } - } - } break; - case EDITMODE_COLLISION: - case EDITMODE_OCCLUSION: - case EDITMODE_NAVIGATION: - case EDITMODE_PRIORITY: { - Vector2 shape_anchor = Vector2(0, 0); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { - shape_anchor = edited_shape_coord; - shape_anchor.x *= (size.x + spacing); - shape_anchor.y *= (size.y + spacing); - } - if (tools[TOOL_SELECT]->is_pressed()) { - if (mb.is_valid()) { - if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - if (edit_mode != EDITMODE_PRIORITY && current_shape.size() > 0) { - for (int i = 0; i < current_shape.size(); i++) { - if ((current_shape[i] - mb->get_position()).length_squared() <= MIN_DISTANCE_SQUARED) { - dragging_point = i; - workspace->update(); - return; + shape_anchor += current_tile_region.position; + if (tools[TOOL_SELECT]->is_pressed()) { + if (mb.is_valid()) { + if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (edit_mode != EDITMODE_PRIORITY && current_shape.size() > 0) { + for (int i = 0; i < current_shape.size(); i++) { + if ((current_shape[i] - mb->get_position()).length_squared() <= MIN_DISTANCE_SQUARED) { + dragging_point = i; + workspace->update(); + return; + } } } - } - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { - Vector2 coord((int)(mb->get_position().x / (spacing + size.x)), (int)(mb->get_position().y / (spacing + size.y))); - if (edited_shape_coord != coord) { - edited_shape_coord = coord; - edited_occlusion_shape = tileset->autotile_get_light_occluder(get_current_tile(), edited_shape_coord); - edited_navigation_shape = tileset->autotile_get_navigation_polygon(get_current_tile(), edited_shape_coord); - Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile()); - bool found_collision_shape = false; - for (int i = 0; i < sd.size(); i++) { - if (sd[i].autotile_coord == coord) { - edited_collision_shape = sd[i].shape; - found_collision_shape = true; - break; + if ((tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) && current_tile_region.has_point(mb->get_position())) { + Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y))); + if (edited_shape_coord != coord) { + edited_shape_coord = coord; + edited_occlusion_shape = tileset->autotile_get_light_occluder(get_current_tile(), edited_shape_coord); + edited_navigation_shape = tileset->autotile_get_navigation_polygon(get_current_tile(), edited_shape_coord); + Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile()); + bool found_collision_shape = false; + for (int i = 0; i < sd.size(); i++) { + if (sd[i].autotile_coord == coord) { + edited_collision_shape = sd[i].shape; + found_collision_shape = true; + break; + } } + if (!found_collision_shape) + edited_collision_shape = Ref<ConvexPolygonShape2D>(NULL); + select_coord(edited_shape_coord); } - if (!found_collision_shape) - edited_collision_shape = Ref<ConvexPolygonShape2D>(NULL); - select_coord(edited_shape_coord); } - } - workspace->update(); - } else if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - if (edit_mode == EDITMODE_COLLISION) { - if (dragging_point >= 0) { - dragging_point = -1; + workspace->update(); + } else if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (edit_mode == EDITMODE_COLLISION) { + if (dragging_point >= 0) { + dragging_point = -1; - Vector<Vector2> points; + Vector<Vector2> points; - for (int i = 0; i < current_shape.size(); i++) { - Vector2 p = current_shape[i]; - if (tools[SHAPE_GRID_SNAP]->is_pressed() || tools[SHAPE_KEEP_INSIDE_TILE]->is_pressed()) { - p = snap_point(p); + for (int i = 0; i < current_shape.size(); i++) { + Vector2 p = current_shape[i]; + if (tools[TOOL_GRID_SNAP]->is_pressed() || tools[SHAPE_KEEP_INSIDE_TILE]->is_pressed()) { + p = snap_point(p); + } + points.push_back(p - shape_anchor); } - points.push_back(p - shape_anchor); - } - edited_collision_shape->set_points(points); + edited_collision_shape->set_points(points); - workspace->update(); - } - } else if (edit_mode == EDITMODE_OCCLUSION) { - if (dragging_point >= 0) { - dragging_point = -1; - - PoolVector<Vector2> polygon; - polygon.resize(current_shape.size()); - PoolVector<Vector2>::Write w = polygon.write(); - - for (int i = 0; i < current_shape.size(); i++) { - w[i] = current_shape[i] - shape_anchor; + workspace->update(); } + } else if (edit_mode == EDITMODE_OCCLUSION) { + if (dragging_point >= 0) { + dragging_point = -1; - w = PoolVector<Vector2>::Write(); - edited_occlusion_shape->set_polygon(polygon); + PoolVector<Vector2> polygon; + polygon.resize(current_shape.size()); + PoolVector<Vector2>::Write w = polygon.write(); - workspace->update(); - } - } else if (edit_mode == EDITMODE_NAVIGATION) { - if (dragging_point >= 0) { - dragging_point = -1; + for (int i = 0; i < current_shape.size(); i++) { + w[i] = current_shape[i] - shape_anchor; + } - PoolVector<Vector2> polygon; - Vector<int> indices; - polygon.resize(current_shape.size()); - PoolVector<Vector2>::Write w = polygon.write(); + w = PoolVector<Vector2>::Write(); + edited_occlusion_shape->set_polygon(polygon); - for (int i = 0; i < current_shape.size(); i++) { - w[i] = current_shape[i] - shape_anchor; - indices.push_back(i); + workspace->update(); } + } else if (edit_mode == EDITMODE_NAVIGATION) { + if (dragging_point >= 0) { + dragging_point = -1; + + PoolVector<Vector2> polygon; + Vector<int> indices; + polygon.resize(current_shape.size()); + PoolVector<Vector2>::Write w = polygon.write(); + + for (int i = 0; i < current_shape.size(); i++) { + w[i] = current_shape[i] - shape_anchor; + indices.push_back(i); + } - w = PoolVector<Vector2>::Write(); - edited_navigation_shape->set_vertices(polygon); - edited_navigation_shape->add_polygon(indices); - - workspace->update(); - } - } - } - } else if (mm.is_valid()) { - if (dragging_point >= 0) { - current_shape.set(dragging_point, snap_point(mm->get_position())); - workspace->update(); - } - } - } else if (tools[SHAPE_NEW_POLYGON]->is_pressed()) { + w = PoolVector<Vector2>::Write(); + edited_navigation_shape->set_vertices(polygon); + edited_navigation_shape->add_polygon(indices); - if (mb.is_valid()) { - if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - Vector2 pos = mb->get_position(); - pos = snap_point(pos); - if (creating_shape) { - if (current_shape.size() > 0) { - if ((pos - current_shape[0]).length_squared() <= MIN_DISTANCE_SQUARED) { - if (current_shape.size() > 2) { - close_shape(shape_anchor); - workspace->update(); - return; - } + workspace->update(); } } - current_shape.push_back(pos); + } + } else if (mm.is_valid()) { + if (dragging_point >= 0) { + current_shape.set(dragging_point, snap_point(mm->get_position())); workspace->update(); - } else { - int t_id = get_current_tile(); - if (t_id >= 0) { - if (edit_mode == EDITMODE_COLLISION) { - Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(t_id); - for (int i = 0; i < sd.size(); i++) { - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE || sd[i].autotile_coord == edited_shape_coord) { - Ref<ConvexPolygonShape2D> shape = sd[i].shape; - - if (!shape.is_null()) { - sd.remove(i); - tileset->tile_set_shapes(get_current_tile(), sd); - edited_collision_shape = Ref<Shape2D>(); - workspace->update(); - } - break; + } + } + } else if (tools[SHAPE_NEW_POLYGON]->is_pressed()) { + + if (mb.is_valid()) { + if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + Vector2 pos = mb->get_position(); + pos = snap_point(pos); + if (creating_shape) { + if (current_shape.size() > 0) { + if ((pos - current_shape[0]).length_squared() <= MIN_DISTANCE_SQUARED) { + if (current_shape.size() > 2) { + close_shape(shape_anchor); + workspace->update(); + return; } } - } else if (edit_mode == EDITMODE_OCCLUSION) { - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { - Map<Vector2, Ref<OccluderPolygon2D> > map = tileset->autotile_get_light_oclusion_map(t_id); - for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = map.front(); E; E = E->next()) { - if (E->key() == edited_shape_coord) { - tileset->autotile_set_light_occluder(get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord); + } + current_shape.push_back(pos); + workspace->update(); + } else { + int t_id = get_current_tile(); + if (t_id >= 0) { + if (edit_mode == EDITMODE_COLLISION) { + Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(t_id); + for (int i = 0; i < sd.size(); i++) { + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE || sd[i].autotile_coord == edited_shape_coord) { + Ref<ConvexPolygonShape2D> shape = sd[i].shape; + + if (!shape.is_null()) { + sd.remove(i); + tileset->tile_set_shapes(get_current_tile(), sd); + edited_collision_shape = Ref<Shape2D>(); + workspace->update(); + } break; } } - } else - tileset->tile_set_light_occluder(t_id, Ref<OccluderPolygon2D>()); + } else if (edit_mode == EDITMODE_OCCLUSION) { + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { + Map<Vector2, Ref<OccluderPolygon2D> > map = tileset->autotile_get_light_oclusion_map(t_id); + for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = map.front(); E; E = E->next()) { + if (E->key() == edited_shape_coord) { + tileset->autotile_set_light_occluder(get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord); + break; + } + } + } else + tileset->tile_set_light_occluder(t_id, Ref<OccluderPolygon2D>()); - edited_occlusion_shape = Ref<OccluderPolygon2D>(); - workspace->update(); - } else if (edit_mode == EDITMODE_NAVIGATION) { - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { - Map<Vector2, Ref<NavigationPolygon> > map = tileset->autotile_get_navigation_map(t_id); - for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = map.front(); E; E = E->next()) { - if (E->key() == edited_shape_coord) { - tileset->autotile_set_navigation_polygon(t_id, Ref<NavigationPolygon>(), edited_shape_coord); - break; + edited_occlusion_shape = Ref<OccluderPolygon2D>(); + workspace->update(); + } else if (edit_mode == EDITMODE_NAVIGATION) { + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { + Map<Vector2, Ref<NavigationPolygon> > map = tileset->autotile_get_navigation_map(t_id); + for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = map.front(); E; E = E->next()) { + if (E->key() == edited_shape_coord) { + tileset->autotile_set_navigation_polygon(t_id, Ref<NavigationPolygon>(), edited_shape_coord); + break; + } } - } - } else - tileset->tile_set_navigation_polygon(t_id, Ref<NavigationPolygon>()); - edited_navigation_shape = Ref<NavigationPolygon>(); - workspace->update(); + } else + tileset->tile_set_navigation_polygon(t_id, Ref<NavigationPolygon>()); + edited_navigation_shape = Ref<NavigationPolygon>(); + workspace->update(); + } } - } - creating_shape = true; - current_shape.resize(0); - current_shape.push_back(snap_point(pos)); + creating_shape = true; + current_shape.resize(0); + current_shape.push_back(snap_point(pos)); + } + } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT && current_shape.size() > 2) { + if (creating_shape) { + close_shape(shape_anchor); + } } - } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT && current_shape.size() > 2) { + } else if (mm.is_valid()) { if (creating_shape) { - close_shape(shape_anchor); + workspace->update(); } } - } else if (mm.is_valid()) { - if (creating_shape) { - workspace->update(); - } } - } - } break; - } - - //Drag Middle Mouse - if (mm.is_valid()) { - if (mm->get_button_mask() & BUTTON_MASK_MIDDLE) { - - Vector2 dragged(mm->get_relative().x, mm->get_relative().y); - scroll->set_h_scroll(scroll->get_h_scroll() - dragged.x * workspace->get_scale().x); - scroll->set_v_scroll(scroll->get_v_scroll() - dragged.y * workspace->get_scale().x); + } break; } } } @@ -1144,6 +1361,16 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { workspace->update(); } else { switch (edit_mode) { + case EDITMODE_REGION: { + if (workspace_mode == WORKSPACE_EDIT && get_current_tile() >= 0) { + tileset->remove_tile(get_current_tile()); + workspace->update(); + workspace_overlay->update(); + } + tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true); + workspace_mode = WORKSPACE_EDIT; + update_workspace_tile_mode(); + } break; case EDITMODE_COLLISION: { if (!edited_collision_shape.is_null()) { Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile()); @@ -1186,22 +1413,22 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { if (scale > 0.1) { scale /= 2; workspace->set_scale(Vector2(scale, scale)); - workspace_container->set_custom_minimum_size(preview->get_region_rect().size * scale); - workspace_overlay->set_custom_minimum_size(preview->get_region_rect().size * scale); + workspace_container->set_custom_minimum_size(workspace->get_rect().size * scale); + workspace_overlay->set_custom_minimum_size(workspace->get_rect().size * scale); } } else if (p_tool == ZOOM_1) { workspace->set_scale(Vector2(1, 1)); - workspace_container->set_custom_minimum_size(preview->get_region_rect().size); - workspace_overlay->set_custom_minimum_size(preview->get_region_rect().size); + workspace_container->set_custom_minimum_size(workspace->get_rect().size); + workspace_overlay->set_custom_minimum_size(workspace->get_rect().size); } else if (p_tool == ZOOM_IN) { float scale = workspace->get_scale().x; scale *= 2; workspace->set_scale(Vector2(scale, scale)); - workspace_container->set_custom_minimum_size(preview->get_region_rect().size * scale); - workspace_overlay->set_custom_minimum_size(preview->get_region_rect().size * scale); + workspace_container->set_custom_minimum_size(workspace->get_rect().size * scale); + workspace_overlay->set_custom_minimum_size(workspace->get_rect().size * scale); } else if (p_tool == TOOL_SELECT) { if (creating_shape) { - //Cancel Creation + // Cancel Creation creating_shape = false; current_shape.resize(0); workspace->update(); @@ -1215,66 +1442,140 @@ void TileSetEditor::_on_priority_changed(float val) { } void TileSetEditor::_on_grid_snap_toggled(bool p_val) { - if (p_val) - hb_grid->show(); - else - hb_grid->hide(); + helper->set_snap_options_visible(p_val); workspace->update(); } -void TileSetEditor::_set_snap_step_x(float p_val) { - snap_step.x = p_val; +void TileSetEditor::_set_snap_step(Vector2 p_val) { + snap_step.x = CLAMP(p_val.x, 0, 256); + snap_step.y = CLAMP(p_val.y, 0, 256); workspace->update(); } -void TileSetEditor::_set_snap_step_y(float p_val) { - snap_step.y = p_val; +void TileSetEditor::_set_snap_off(Vector2 p_val) { + snap_offset.x = CLAMP(p_val.x, 0, 256 + WORKSPACE_MARGIN.x); + snap_offset.y = CLAMP(p_val.y, 0, 256 + WORKSPACE_MARGIN.y); workspace->update(); } -void TileSetEditor::_set_snap_off_x(float p_val) { - snap_offset.x = p_val; +void TileSetEditor::_set_snap_sep(Vector2 p_val) { + snap_separation.x = CLAMP(p_val.x, 0, 256); + snap_separation.y = CLAMP(p_val.y, 0, 256); workspace->update(); } -void TileSetEditor::_set_snap_off_y(float p_val) { - snap_offset.y = p_val; - workspace->update(); -} -void TileSetEditor::_set_snap_sep_x(float p_val) { - snap_separation.x = p_val; - workspace->update(); -} +void TileSetEditor::draw_highlight_current_tile() { -void TileSetEditor::_set_snap_sep_y(float p_val) { - snap_separation.y = p_val; - workspace->update(); + if (get_current_tile() >= 0) { + Rect2 region = tileset->tile_get_region(get_current_tile()); + region.position += WORKSPACE_MARGIN; + workspace->draw_rect(Rect2(0, 0, workspace->get_rect().size.x, region.position.y), Color(0.3, 0.3, 0.3, 0.3)); + workspace->draw_rect(Rect2(0, region.position.y, region.position.x, region.size.y), Color(0.3, 0.3, 0.3, 0.3)); + workspace->draw_rect(Rect2(region.position.x + region.size.x, region.position.y, workspace->get_rect().size.x - region.position.x - region.size.x, region.size.y), Color(0.3, 0.3, 0.3, 0.3)); + workspace->draw_rect(Rect2(0, region.position.y + region.size.y, workspace->get_rect().size.x, workspace->get_rect().size.y - region.size.y - region.position.y), Color(0.3, 0.3, 0.3, 0.3)); + } else { + workspace->draw_rect(Rect2(Point2(0, 0), workspace->get_rect().size), Color(0.3, 0.3, 0.3, 0.3)); + } } -void TileSetEditor::draw_highlight_tile(Vector2 coord, const Vector<Vector2> &other_highlighted) { +void TileSetEditor::draw_highlight_subtile(Vector2 coord, const Vector<Vector2> &other_highlighted) { Vector2 size = tileset->autotile_get_size(get_current_tile()); int spacing = tileset->autotile_get_spacing(get_current_tile()); Rect2 region = tileset->tile_get_region(get_current_tile()); coord.x *= (size.x + spacing); coord.y *= (size.y + spacing); - workspace->draw_rect(Rect2(0, 0, region.size.x, coord.y), Color(0.5, 0.5, 0.5, 0.5)); - workspace->draw_rect(Rect2(0, coord.y, coord.x, size.y), Color(0.5, 0.5, 0.5, 0.5)); - workspace->draw_rect(Rect2(coord.x + size.x, coord.y, region.size.x - coord.x - size.x, size.y), Color(0.5, 0.5, 0.5, 0.5)); - workspace->draw_rect(Rect2(0, coord.y + size.y, region.size.x, region.size.y - size.y - coord.y), Color(0.5, 0.5, 0.5, 0.5)); + coord += region.position; + coord += WORKSPACE_MARGIN; + workspace->draw_rect(Rect2(0, 0, workspace->get_rect().size.x, coord.y), Color(0.3, 0.3, 0.3, 0.3)); + workspace->draw_rect(Rect2(0, coord.y, coord.x, size.y), Color(0.3, 0.3, 0.3, 0.3)); + workspace->draw_rect(Rect2(coord.x + size.x, coord.y, workspace->get_rect().size.x - coord.x - size.x, size.y), Color(0.3, 0.3, 0.3, 0.3)); + workspace->draw_rect(Rect2(0, coord.y + size.y, workspace->get_rect().size.x, workspace->get_rect().size.y - size.y - coord.y), Color(0.3, 0.3, 0.3, 0.3)); coord += Vector2(1, 1) / workspace->get_scale().x; workspace->draw_rect(Rect2(coord, size - Vector2(2, 2) / workspace->get_scale().x), Color(1, 0, 0), false); for (int i = 0; i < other_highlighted.size(); i++) { coord = other_highlighted[i]; coord.x *= (size.x + spacing); coord.y *= (size.y + spacing); + coord += region.position; + coord += WORKSPACE_MARGIN; coord += Vector2(1, 1) / workspace->get_scale().x; - workspace->draw_rect(Rect2(coord, size - Vector2(2, 2) / workspace->get_scale().x), Color(1, 0, 0), false); + workspace->draw_rect(Rect2(coord, size - Vector2(2, 2) / workspace->get_scale().x), Color(1, 0.5, 0.5), false); + } +} + +void TileSetEditor::draw_tile_subdivision(int p_id, Color p_color) const { + Color c = p_color; + if (tileset->tile_get_tile_mode(p_id) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(p_id) == TileSet::ATLAS_TILE) { + Rect2 region = tileset->tile_get_region(p_id); + Size2 size = tileset->autotile_get_size(p_id); + int spacing = tileset->autotile_get_spacing(p_id); + float j = 0; + while (j < region.size.x) { + j += size.x; + if (spacing <= 0) { + workspace->draw_line(region.position + WORKSPACE_MARGIN + Point2(j, 0), region.position + WORKSPACE_MARGIN + Point2(j, region.size.y), c); + } else { + workspace->draw_rect(Rect2(region.position + WORKSPACE_MARGIN + Point2(j, 0), Size2(spacing, region.size.y)), c); + } + j += spacing; + } + j = 0; + while (j < region.size.y) { + j += size.y; + if (spacing <= 0) { + workspace->draw_line(region.position + WORKSPACE_MARGIN + Point2(0, j), region.position + WORKSPACE_MARGIN + Point2(region.size.x, j), c); + } else { + workspace->draw_rect(Rect2(region.position + WORKSPACE_MARGIN + Point2(0, j), Size2(region.size.x, spacing)), c); + } + j += spacing; + } + } +} + +void TileSetEditor::draw_edited_region_subdivision() const { + Color c = Color(0.347214, 0.722656, 0.617063, 1); + Rect2 region = edited_region; + Size2 size; + int spacing; + bool draw; + if (workspace_mode == WORKSPACE_EDIT) { + int p_id = get_current_tile(); + size = tileset->autotile_get_size(p_id); + spacing = tileset->autotile_get_spacing(p_id); + draw = tileset->tile_get_tile_mode(p_id) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(p_id) == TileSet::ATLAS_TILE; + } else { + size = snap_step; + spacing = snap_separation.x; + draw = workspace_mode != WORKSPACE_CREATE_SINGLE; + } + if (draw) { + + float j = 0; + while (j < region.size.x) { + j += size.x; + if (spacing <= 0) { + workspace->draw_line(region.position + Point2(j, 0), region.position + Point2(j, region.size.y), c); + } else { + workspace->draw_rect(Rect2(region.position + Point2(j, 0), Size2(spacing, region.size.y)), c); + } + j += spacing; + } + j = 0; + while (j < region.size.y) { + j += size.y; + if (spacing <= 0) { + workspace->draw_line(region.position + Point2(0, j), region.position + Point2(region.size.x, j), c); + } else { + workspace->draw_rect(Rect2(region.position + Point2(0, j), Size2(region.size.x, spacing)), c); + } + j += spacing; + } } } void TileSetEditor::draw_grid_snap() { - if (tools[SHAPE_GRID_SNAP]->is_pressed()) { + if (tools[TOOL_GRID_SNAP]->is_pressed()) { Color grid_color = Color(0.39, 0, 1, 0.2f); Size2 s = workspace->get_size(); @@ -1328,7 +1629,7 @@ void TileSetEditor::draw_polygon_shapes() { for (int i = 0; i < sd.size(); i++) { Vector2 coord = Vector2(0, 0); Vector2 anchor = Vector2(0, 0); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { coord = sd[i].autotile_coord; anchor = tileset->autotile_get_size(t_id); anchor.x += tileset->autotile_get_spacing(t_id); @@ -1336,6 +1637,8 @@ void TileSetEditor::draw_polygon_shapes() { anchor.x *= coord.x; anchor.y *= coord.y; } + anchor += WORKSPACE_MARGIN; + anchor += tileset->tile_get_region(t_id).position; Ref<ConvexPolygonShape2D> shape = sd[i].shape; if (shape.is_valid()) { Color c_bg; @@ -1407,6 +1710,8 @@ void TileSetEditor::draw_polygon_shapes() { anchor.y += tileset->autotile_get_spacing(t_id); anchor.x *= coord.x; anchor.y *= coord.y; + anchor += WORKSPACE_MARGIN; + anchor += tileset->tile_get_region(t_id).position; Ref<OccluderPolygon2D> shape = E->value(); if (shape.is_valid()) { Color c_bg; @@ -1483,6 +1788,8 @@ void TileSetEditor::draw_polygon_shapes() { anchor.y += tileset->autotile_get_spacing(t_id); anchor.x *= coord.x; anchor.y *= coord.y; + anchor += WORKSPACE_MARGIN; + anchor += tileset->tile_get_region(t_id).position; Ref<NavigationPolygon> shape = E->value(); if (shape.is_valid()) { Color c_bg; @@ -1558,10 +1865,10 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { shape->set_points(segments); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) tileset->tile_add_shape(get_current_tile(), shape, Transform2D(), false, edited_shape_coord); else - tileset->tile_set_shape(get_current_tile(), 0, shape); + tileset->tile_add_shape(get_current_tile(), shape, Transform2D()); edited_collision_shape = shape; } @@ -1582,7 +1889,7 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { w = PoolVector<Vector2>::Write(); shape->set_polygon(polygon); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) tileset->autotile_set_light_occluder(get_current_tile(), shape, edited_shape_coord); else tileset->tile_set_light_occluder(get_current_tile(), shape); @@ -1606,7 +1913,7 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { shape->set_vertices(polygon); shape->add_polygon(indices); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) tileset->autotile_set_navigation_polygon(get_current_tile(), shape, edited_shape_coord); else tileset->tile_set_navigation_polygon(get_current_tile(), shape); @@ -1619,6 +1926,8 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { void TileSetEditor::select_coord(const Vector2 &coord) { current_shape = PoolVector2Array(); + Rect2 current_tile_region = tileset->tile_get_region(get_current_tile()); + current_tile_region.position += WORKSPACE_MARGIN; if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { if (edited_collision_shape != tileset->tile_get_shape(get_current_tile(), 0)) edited_collision_shape = tileset->tile_get_shape(get_current_tile(), 0); @@ -1631,14 +1940,14 @@ void TileSetEditor::select_coord(const Vector2 &coord) { current_shape.resize(0); if (edited_collision_shape.is_valid()) { for (int i = 0; i < edited_collision_shape->get_points().size(); i++) { - current_shape.push_back(edited_collision_shape->get_points()[i]); + current_shape.push_back(edited_collision_shape->get_points()[i] + current_tile_region.position); } } } else if (edit_mode == EDITMODE_OCCLUSION) { current_shape.resize(0); if (edited_occlusion_shape.is_valid()) { for (int i = 0; i < edited_occlusion_shape->get_polygon().size(); i++) { - current_shape.push_back(edited_occlusion_shape->get_polygon()[i]); + current_shape.push_back(edited_occlusion_shape->get_polygon()[i] + current_tile_region.position); } } } else if (edit_mode == EDITMODE_NAVIGATION) { @@ -1647,7 +1956,7 @@ void TileSetEditor::select_coord(const Vector2 &coord) { if (edited_navigation_shape->get_polygon_count() > 0) { PoolVector<Vector2> vertices = edited_navigation_shape->get_vertices(); for (int i = 0; i < edited_navigation_shape->get_polygon(0).size(); i++) { - current_shape.push_back(vertices[edited_navigation_shape->get_polygon(0)[i]]); + current_shape.push_back(vertices[edited_navigation_shape->get_polygon(0)[i]] + current_tile_region.position); } } } @@ -1658,6 +1967,7 @@ void TileSetEditor::select_coord(const Vector2 &coord) { Vector2 shape_anchor = coord; shape_anchor.x *= (size.x + spacing); shape_anchor.y *= (size.y + spacing); + shape_anchor += current_tile_region.position; if (edit_mode == EDITMODE_COLLISION) { current_shape.resize(0); if (edited_collision_shape.is_valid()) { @@ -1684,6 +1994,9 @@ void TileSetEditor::select_coord(const Vector2 &coord) { } } } + workspace->update(); + workspace_container->update(); + helper->_change_notify(""); } Vector2 TileSetEditor::snap_point(const Vector2 &point) { @@ -1694,11 +2007,13 @@ Vector2 TileSetEditor::snap_point(const Vector2 &point) { Vector2 anchor = coord; anchor.x *= (tile_size.x + spacing); anchor.y *= (tile_size.y + spacing); + anchor += tileset->tile_get_region(get_current_tile()).position; + anchor += WORKSPACE_MARGIN; Rect2 region(anchor, tile_size); if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) - region.position = Point2(0, 0); + region.position = tileset->tile_get_region(get_current_tile()).position + WORKSPACE_MARGIN; - if (tools[SHAPE_GRID_SNAP]->is_pressed()) { + if (tools[TOOL_GRID_SNAP]->is_pressed()) { p.x = Math::snap_scalar_seperation(snap_offset.x, snap_step.x, p.x, snap_separation.x); p.y = Math::snap_scalar_seperation(snap_offset.y, snap_step.y, p.y, snap_separation.y); } @@ -1715,211 +2030,332 @@ Vector2 TileSetEditor::snap_point(const Vector2 &point) { return p; } -void TileSetEditor::update_tile_list() { - int selected_tile = get_current_tile(); - - if (selected_tile < 0) - selected_tile = 0; +void TileSetEditor::update_texture_list() { + Ref<Texture> selected_texture = get_current_texture(); helper->set_tileset(tileset); - tile_list->clear(); List<int> ids; tileset->get_tile_list(&ids); for (List<int>::Element *E = ids.front(); E; E = E->next()) { - tile_list->add_item(tileset->tile_get_name(E->get())); - tile_list->set_item_metadata(tile_list->get_item_count() - 1, E->get()); - tile_list->set_item_icon(tile_list->get_item_count() - 1, tileset->tile_get_texture(E->get())); - Rect2 region = tileset->tile_get_region(E->get()); - if (tileset->tile_get_tile_mode(E->get()) == TileSet::AUTO_TILE) { - region.size = tileset->autotile_get_size(E->get()); - Vector2 pos = tileset->autotile_get_icon_coordinate(E->get()); - pos.x *= (tileset->autotile_get_spacing(E->get()) + region.size.x); - pos.y *= (tileset->autotile_get_spacing(E->get()) + region.size.y); - region.position += pos; + if (!texture_map.has(tileset->tile_get_texture(E->get())->get_rid())) { + texture_list->add_item(tileset->tile_get_texture(E->get())->get_path().get_file()); + texture_map.insert(tileset->tile_get_texture(E->get())->get_rid(), tileset->tile_get_texture(E->get())); + texture_list->set_item_metadata(texture_list->get_item_count() - 1, tileset->tile_get_texture(E->get())->get_rid()); } - tile_list->set_item_icon_region(tile_list->get_item_count() - 1, region); - tile_list->set_item_icon_modulate(tile_list->get_item_count() - 1, tileset->tile_get_modulate(E->get())); } - if (tile_list->get_item_count() > 0 && selected_tile < tile_list->get_item_count()) { - tile_list->select(selected_tile); - _on_tile_list_selected(selected_tile); + if (texture_list->get_item_count() > 0 && selected_texture.is_valid()) { + texture_list->select(texture_list->find_metadata(selected_texture->get_rid())); + if (texture_list->get_selected_items().size() > 0) + _on_texture_list_selected(texture_list->get_selected_items()[0]); + } else if (get_current_texture().is_valid()) { + _on_texture_list_selected(texture_list->find_metadata(get_current_texture()->get_rid())); + } else { + _on_texture_list_selected(-1); } + update_texture_list_icon(); helper->_change_notify(""); } -void TileSetEditor::update_tile_list_icon() { - List<int> ids; - tileset->get_tile_list(&ids); - int current_idx = 0; - for (List<int>::Element *E = ids.front(); E; E = E->next()) { - if (current_idx >= tile_list->get_item_count()) - break; - - Rect2 region = tileset->tile_get_region(E->get()); - if (tileset->tile_get_tile_mode(E->get()) == TileSet::AUTO_TILE) { - region.size = tileset->autotile_get_size(E->get()); - Vector2 pos = tileset->autotile_get_icon_coordinate(E->get()); - pos.x *= (tileset->autotile_get_spacing(E->get()) + region.size.x); - pos.y *= (tileset->autotile_get_spacing(E->get()) + region.size.y); - region.position += pos; - } - tile_list->set_item_metadata(current_idx, E->get()); - tile_list->set_item_icon(current_idx, tileset->tile_get_texture(E->get())); - tile_list->set_item_icon_region(current_idx, region); - tile_list->set_item_icon_modulate(current_idx, tileset->tile_get_modulate(E->get())); - tile_list->set_item_text(current_idx, tileset->tile_get_name(E->get())); - current_idx += 1; +void TileSetEditor::update_texture_list_icon() { + + for (int current_idx = 0; current_idx < texture_list->get_item_count(); current_idx++) { + RID rid = texture_list->get_item_metadata(current_idx); + texture_list->set_item_icon(current_idx, texture_map[rid]); + texture_list->set_item_icon_region(current_idx, Rect2(0, 0, 150, 100)); } - tile_list->update(); + texture_list->update(); } void TileSetEditor::update_workspace_tile_mode() { - if (get_current_tile() < 0) + + if (workspace_mode != WORKSPACE_EDIT) { + for (int i = 0; i < EDITMODE_MAX; i++) { + tool_editmode[i]->hide(); + } + tool_editmode[EDITMODE_REGION]->show(); + tool_editmode[EDITMODE_REGION]->set_pressed(true); + _on_edit_mode_changed(EDITMODE_REGION); + return; + } + + if (get_current_tile() < 0) { + for (int i = 0; i < EDITMODE_MAX; i++) { + tool_editmode[i]->hide(); + } + for (int i = 0; i < ZOOM_OUT; i++) { + tools[i]->hide(); + } return; + } + + for (int i = 0; i < EDITMODE_MAX; i++) { + tool_editmode[i]->show(); + } + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { if (tool_editmode[EDITMODE_ICON]->is_pressed() || tool_editmode[EDITMODE_PRIORITY]->is_pressed() || tool_editmode[EDITMODE_BITMASK]->is_pressed()) { tool_editmode[EDITMODE_COLLISION]->set_pressed(true); - _on_edit_mode_changed(EDITMODE_COLLISION); - } else { - select_coord(Vector2(0, 0)); + edit_mode = EDITMODE_COLLISION; } + select_coord(Vector2(0, 0)); tool_editmode[EDITMODE_ICON]->hide(); tool_editmode[EDITMODE_BITMASK]->hide(); tool_editmode[EDITMODE_PRIORITY]->hide(); - property_editor->hide(); + } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { + if (edit_mode == EDITMODE_ICON) + select_coord(tileset->autotile_get_icon_coordinate(get_current_tile())); + else + select_coord(edited_shape_coord); + } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { + if (tool_editmode[EDITMODE_PRIORITY]->is_pressed() || tool_editmode[EDITMODE_BITMASK]->is_pressed()) { + tool_editmode[EDITMODE_COLLISION]->set_pressed(true); + edit_mode = EDITMODE_COLLISION; + } + if (edit_mode == EDITMODE_ICON) + select_coord(tileset->autotile_get_icon_coordinate(get_current_tile())); + else + select_coord(edited_shape_coord); + + tool_editmode[EDITMODE_BITMASK]->hide(); + tool_editmode[EDITMODE_PRIORITY]->hide(); + } + _on_edit_mode_changed(edit_mode); +} + +void TileSetEditor::update_edited_region(const Vector2 &end_point) { + edited_region = Rect2(region_from, Size2()); + if (tools[TOOL_GRID_SNAP]->is_pressed()) { + Vector2 grid_coord; + grid_coord.x = Math::floor((region_from.x - snap_offset.x) / (snap_step.x + snap_separation.x)); + grid_coord.y = Math::floor((region_from.y - snap_offset.y) / (snap_step.y + snap_separation.y)); + grid_coord.x *= (snap_step.x + snap_separation.x); + grid_coord.y *= (snap_step.y + snap_separation.y); + grid_coord += snap_offset; + edited_region.expand_to(grid_coord); + grid_coord += snap_step; + edited_region.expand_to(grid_coord); + grid_coord.x = Math::floor((end_point.x - snap_offset.x) / (snap_step.x + snap_separation.x)); + grid_coord.y = Math::floor((end_point.y - snap_offset.y) / (snap_step.y + snap_separation.y)); + grid_coord.x *= (snap_step.x + snap_separation.x); + grid_coord.y *= (snap_step.y + snap_separation.y); + grid_coord += snap_offset; + edited_region.expand_to(grid_coord); + grid_coord += snap_step; + if (grid_coord.x < end_point.x) + grid_coord.x += snap_separation.x; + if (grid_coord.y < end_point.y) + grid_coord.y += snap_separation.y; + edited_region.expand_to(grid_coord); } else { - tool_editmode[EDITMODE_ICON]->show(); - tool_editmode[EDITMODE_BITMASK]->show(); - tool_editmode[EDITMODE_PRIORITY]->show(); - property_editor->show(); + edited_region.expand_to(end_point); } } -int TileSetEditor::get_current_tile() { - if (tile_list->get_selected_items().size() == 0) - return -1; +int TileSetEditor::get_current_tile() const { + return current_tile; +} + +void TileSetEditor::set_current_tile(int p_id) { + if (current_tile != p_id) { + current_tile = p_id; + helper->_change_notify(""); + select_coord(Vector2(0, 0)); + update_workspace_tile_mode(); + } +} + +Ref<Texture> TileSetEditor::get_current_texture() { + if (texture_list->get_selected_items().size() == 0) + return Ref<Texture>(); else - return tile_list->get_item_metadata(tile_list->get_selected_items()[0]); + return texture_map[texture_list->get_item_metadata(texture_list->get_selected_items()[0])]; } -void TileSetEditorHelper::set_tileset(const Ref<TileSet> &p_tileset) { +void TilesetEditorContext::set_tileset(const Ref<TileSet> &p_tileset) { tileset = p_tileset; } -bool TileSetEditorHelper::_set(const StringName &p_name, const Variant &p_value) { +void TilesetEditorContext::set_snap_options_visible(bool p_visible) { + snap_options_visible = p_visible; + _change_notify(""); +} - if (selected_tile < 0 || tileset.is_null()) - return false; +bool TilesetEditorContext::_set(const StringName &p_name, const Variant &p_value) { String name = p_name.operator String(); - bool v = false; - if (name == "bitmask_mode") { - tileset->set(String::num(selected_tile, 0) + "/autotile/bitmask_mode", p_value, &v); - } else if (name.left(7) == "layout/") { - tileset->set(String::num(selected_tile, 0) + "/autotile" + name.right(6), p_value, &v); - } - if (v) { - tileset->_change_notify("autotile"); + + if (name == "options_offset") { + Vector2 snap = p_value; + tileset_editor->_set_snap_off(snap + WORKSPACE_MARGIN); + return true; + } else if (name == "options_step") { + Vector2 snap = p_value; + tileset_editor->_set_snap_step(snap); + return true; + } else if (name == "options_separation") { + Vector2 snap = p_value; + tileset_editor->_set_snap_sep(snap); + return true; + } else if (p_name.operator String().left(5) == "tile_") { + String name = p_name.operator String().right(5); + bool v = false; + + if (tileset_editor->get_current_tile() < 0 || tileset.is_null()) + return false; + + if (name == "autotile_bitmask_mode") { + tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/bitmask_mode", p_value, &v); + } else if (name == "subtile_size") { + tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/tile_size", p_value, &v); + } else if (name == "subtile_spacing") { + tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/spacing", p_value, &v); + } else { + tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/" + name, p_value, &v); + } + if (v) { + tileset->_change_notify(""); + tileset_editor->workspace->update(); + tileset_editor->workspace_overlay->update(); + } + return v; } - return v; -} -bool TileSetEditorHelper::_get(const StringName &p_name, Variant &r_ret) const { + tileset_editor->err_dialog->set_text(TTR("This property can't be changed.")); + tileset_editor->err_dialog->popup_centered(Size2(300, 60)); + return false; +} - if (selected_tile < 0 || tileset.is_null()) - return false; - if (!tileset->has_tile(selected_tile)) - return false; +bool TilesetEditorContext::_get(const StringName &p_name, Variant &r_ret) const { String name = p_name.operator String(); bool v = false; - if (name == "bitmask_mode") { - r_ret = tileset->get(String::num(selected_tile, 0) + "/autotile/bitmask_mode", &v); - } else if (name.left(7) == "layout/") { - r_ret = tileset->get(String::num(selected_tile, 0) + "/autotile" + name.right(6), &v); + + if (name == "options_offset") { + r_ret = tileset_editor->snap_offset - WORKSPACE_MARGIN; + v = true; + } else if (name == "options_step") { + r_ret = tileset_editor->snap_step; + v = true; + } else if (name == "options_separation") { + r_ret = tileset_editor->snap_separation; + v = true; + } else if (name.left(5) == "tile_") { + name = name.right(5); + + if (tileset_editor->get_current_tile() < 0 || tileset.is_null()) + return false; + if (!tileset->has_tile(tileset_editor->get_current_tile())) + return false; + + if (name == "autotile_bitmask_mode") { + r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/bitmask_mode", &v); + } else if (name == "subtile_size") { + r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/tile_size", &v); + } else if (name == "subtile_spacing") { + r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/spacing", &v); + } else { + r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/" + name, &v); + } + return v; + } else if (name == "selected_collision") { + r_ret = tileset_editor->edited_collision_shape; + v = true; + } else if (name == "selected_navigation") { + r_ret = tileset_editor->edited_navigation_shape; + v = true; + } else if (name == "selected_occlusion") { + r_ret = tileset_editor->edited_occlusion_shape; + v = true; } return v; } -void TileSetEditorHelper::_get_property_list(List<PropertyInfo> *p_list) const { - - if (selected_tile < 0 || tileset.is_null()) - return; +void TilesetEditorContext::_get_property_list(List<PropertyInfo> *p_list) const { - p_list->push_back(PropertyInfo(Variant::INT, "bitmask_mode", PROPERTY_HINT_ENUM, "2x2,3x3 (minimal),3x3")); - p_list->push_back(PropertyInfo(Variant::VECTOR2, "layout/tile_size")); - p_list->push_back(PropertyInfo(Variant::INT, "layout/spacing", PROPERTY_HINT_RANGE, "0,256,1")); + if (snap_options_visible) { + p_list->push_back(PropertyInfo(Variant::NIL, "Snap Options", PROPERTY_HINT_NONE, "options_", PROPERTY_USAGE_GROUP)); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "options_offset")); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "options_step")); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "options_separation")); + } + if (tileset_editor->get_current_tile() >= 0 && !tileset.is_null()) { + int id = tileset_editor->get_current_tile(); + p_list->push_back(PropertyInfo(Variant::NIL, "Selected Tile", PROPERTY_HINT_NONE, "tile_", PROPERTY_USAGE_GROUP)); + p_list->push_back(PropertyInfo(Variant::STRING, "tile_name")); + p_list->push_back(PropertyInfo(Variant::OBJECT, "tile_normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture")); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_tex_offset")); + p_list->push_back(PropertyInfo(Variant::OBJECT, "tile_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial")); + p_list->push_back(PropertyInfo(Variant::COLOR, "tile_modulate")); + p_list->push_back(PropertyInfo(Variant::INT, "tile_tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE,ATLAS_TILE")); + if (tileset->tile_get_tile_mode(id) == TileSet::AUTO_TILE) { + p_list->push_back(PropertyInfo(Variant::INT, "tile_autotile_bitmask_mode", PROPERTY_HINT_ENUM, "2X2,3X3 (minimal),3X3")); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_subtile_size")); + p_list->push_back(PropertyInfo(Variant::INT, "tile_subtile_spacing", PROPERTY_HINT_RANGE, "0, 256, 1")); + } else if (tileset->tile_get_tile_mode(id) == TileSet::ATLAS_TILE) { + p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_subtile_size")); + p_list->push_back(PropertyInfo(Variant::INT, "tile_subtile_spacing", PROPERTY_HINT_RANGE, "0, 256, 1")); + } + p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_occluder_offset")); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_navigation_offset")); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_shape_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_shape_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); + p_list->push_back(PropertyInfo(Variant::INT, "tile_z_index", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1")); + } + if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_COLLISION && tileset_editor->edited_collision_shape.is_valid()) { + p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_collision", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_collision_shape->get_class())); + } + if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_NAVIGATION && tileset_editor->edited_navigation_shape.is_valid()) { + p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_navigation", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_navigation_shape->get_class())); + } + if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_OCCLUSION && tileset_editor->edited_occlusion_shape.is_valid()) { + p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_occlusion", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_occlusion_shape->get_class())); + } } -TileSetEditorHelper::TileSetEditorHelper(TileSetEditor *p_tileset_editor) { - +TilesetEditorContext::TilesetEditorContext(TileSetEditor *p_tileset_editor) { tileset_editor = p_tileset_editor; - selected_tile = -1; } void TileSetEditorPlugin::edit(Object *p_node) { if (Object::cast_to<TileSet>(p_node)) { tileset_editor->edit(Object::cast_to<TileSet>(p_node)); - tileset_editor->show(); - tileset_editor->texture_region_editor->edit(p_node); - } else - tileset_editor->hide(); + editor->get_inspector()->edit(tileset_editor->helper); + } } bool TileSetEditorPlugin::handles(Object *p_node) const { - return p_node->is_class("TileSet"); + return p_node->is_class("TileSet") || + p_node->is_class("TilesetEditorContext"); } void TileSetEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { - tileset_editor->show(); - tileset_editor->menu->show(); tileset_editor_button->show(); - tileset_editor->side_panel->show(); if (tileset_editor_button->is_pressed()) { - tileset_editor->bottom_panel->show(); + tileset_editor->show(); } - texture_region_button->show(); - if (texture_region_button->is_pressed()) - tileset_editor->texture_region_editor->show(); + get_tree()->connect("idle_frame", tileset_editor, "_on_workspace_process"); } else { tileset_editor->hide(); - tileset_editor->menu->hide(); - tileset_editor->side_panel->hide(); - tileset_editor->bottom_panel->hide(); tileset_editor_button->hide(); - texture_region_button->hide(); - tileset_editor->texture_region_editor->hide(); + get_tree()->disconnect("idle_frame", tileset_editor, "_on_workspace_process"); } } TileSetEditorPlugin::TileSetEditorPlugin(EditorNode *p_node) { - + editor = p_node; tileset_editor = memnew(TileSetEditor(p_node)); - add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, tileset_editor); - tileset_editor->set_anchors_and_margins_preset(Control::PRESET_TOP_WIDE); - tileset_editor->set_end(Point2(0, 22)); - tileset_editor->hide(); - - tileset_editor->texture_region_editor = memnew(TextureRegionEditor(p_node)); - texture_region_button = p_node->add_bottom_panel_item(TTR("Texture Region"), tileset_editor->texture_region_editor); - texture_region_button->set_tooltip(TTR("Texture Region Editor")); - - tileset_editor->texture_region_editor->set_custom_minimum_size(Size2(0, 200)); - tileset_editor->texture_region_editor->hide(); - texture_region_button->hide(); + tileset_editor_button = + p_node->add_bottom_panel_item(TTR("Tile Set"), tileset_editor); + tileset_editor_button->set_tooltip(TTR("Tile Set Editor")); - add_control_to_container(CONTAINER_CANVAS_EDITOR_SIDE, tileset_editor->side_panel); - tileset_editor->side_panel->set_anchors_and_margins_preset(Control::PRESET_WIDE); - tileset_editor->side_panel->set_custom_minimum_size(Size2(200, 0)); - tileset_editor->side_panel->hide(); - tileset_editor_button = p_node->add_bottom_panel_item(TTR("Tile Set"), tileset_editor->bottom_panel); + tileset_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE); + tileset_editor->hide(); tileset_editor_button->hide(); } diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h index 4894d641a3..0c175e718c 100644 --- a/editor/plugins/tile_set_editor_plugin.h +++ b/editor/plugins/tile_set_editor_plugin.h @@ -33,21 +33,38 @@ #include "editor/editor_name_dialog.h" #include "editor/editor_node.h" -#include "editor/plugins/texture_region_editor_plugin.h" #include "scene/2d/sprite.h" #include "scene/resources/convex_polygon_shape_2d.h" #include "scene/resources/tile_set.h" -class TileSetEditorHelper; +#define WORKSPACE_MARGIN Vector2(10, 10) +class TilesetEditorContext; -class TileSetEditor : public Control { +class TileSetEditor : public Panel { friend class TileSetEditorPlugin; - friend class TextureRegionEditor; + friend class TilesetEditorContext; - GDCLASS(TileSetEditor, Control); + GDCLASS(TileSetEditor, Panel) + + enum TextureToolButtons { + TOOL_TILESET_ADD_TEXTURE, + TOOL_TILESET_REMOVE_TEXTURE, + TOOL_TILESET_CREATE_SCENE, + TOOL_TILESET_MERGE_SCENE, + TOOL_TILESET_MAX + }; + + enum WorkspaceMode { + WORKSPACE_EDIT, + WORKSPACE_CREATE_SINGLE, + WORKSPACE_CREATE_AUTOTILE, + WORKSPACE_CREATE_ATLAS, + WORKSPACE_MODE_MAX + }; enum EditMode { + EDITMODE_REGION, EDITMODE_COLLISION, EDITMODE_OCCLUSION, EDITMODE_NAVIGATION, @@ -57,13 +74,6 @@ class TileSetEditor : public Control { EDITMODE_MAX }; - enum TileSetToolbar { - TOOLBAR_DUMMY, - TOOLBAR_BITMASK, - TOOLBAR_SHAPE, - TOOLBAR_MAX - }; - enum TileSetTools { TOOL_SELECT, BITMASK_COPY, @@ -71,17 +81,42 @@ class TileSetEditor : public Control { BITMASK_CLEAR, SHAPE_NEW_POLYGON, SHAPE_DELETE, - SHAPE_CREATE_FROM_BITMASK, - SHAPE_CREATE_FROM_NOT_BITMASK, SHAPE_KEEP_INSIDE_TILE, - SHAPE_GRID_SNAP, + TOOL_GRID_SNAP, ZOOM_OUT, ZOOM_1, ZOOM_IN, + VISIBLE_INFO, TOOL_MAX }; Ref<TileSet> tileset; + TilesetEditorContext *helper; + EditorNode *editor; + + ConfirmationDialog *cd; + AcceptDialog *err_dialog; + EditorFileDialog *texture_dialog; + + ItemList *texture_list; + int option; + ToolButton *tileset_toolbar_buttons[TOOL_TILESET_MAX]; + MenuButton *tileset_toolbar_tools; + Map<RID, Ref<Texture> > texture_map; + + bool creating_shape; + int dragging_point; + float tile_names_opacity; + Vector2 region_from; + Rect2 edited_region; + bool draw_edited_region; + Vector2 edited_shape_coord; + PoolVector2Array current_shape; + Map<Vector2, uint16_t> bitmask_map_copy; + + Vector2 snap_step; + Vector2 snap_offset; + Vector2 snap_separation; Ref<ConvexPolygonShape2D> edited_collision_shape; Ref<OccluderPolygon2D> edited_occlusion_shape; @@ -94,55 +129,19 @@ class TileSetEditor : public Control { bool draw_handles; Control *workspace_overlay; Control *workspace; + Button *tool_workspacemode[WORKSPACE_MODE_MAX]; Button *tool_editmode[EDITMODE_MAX]; - HBoxContainer *tool_containers[TOOLBAR_MAX]; HBoxContainer *toolbar; - HBoxContainer *hb_grid; ToolButton *tools[TOOL_MAX]; SpinBox *spin_priority; - SpinBox *sb_step_y; - SpinBox *sb_step_x; - SpinBox *sb_off_y; - SpinBox *sb_off_x; - SpinBox *sb_sep_y; - SpinBox *sb_sep_x; + WorkspaceMode workspace_mode; EditMode edit_mode; + int current_tile; - Vector2 snap_step; - Vector2 snap_offset; - Vector2 snap_separation; + void update_texture_list(); + void update_texture_list_icon(); - bool creating_shape; - int dragging_point; - Vector2 edited_shape_coord; - PoolVector2Array current_shape; - Map<Vector2, uint16_t> bitmask_map_copy; - - EditorNode *editor; - TextureRegionEditor *texture_region_editor; - Control *bottom_panel; - Control *side_panel; - ItemList *tile_list; - PropertyEditor *property_editor; - TileSetEditorHelper *helper; - - MenuButton *menu; - ConfirmationDialog *cd; - EditorNameDialog *nd; - AcceptDialog *err_dialog; - - enum { - - MENU_OPTION_ADD_ITEM, - MENU_OPTION_REMOVE_ITEM, - MENU_OPTION_CREATE_FROM_SCENE, - MENU_OPTION_MERGE_FROM_SCENE - }; - - int option; - void _menu_cbk(int p_option); - void _menu_confirm(); - void _name_dialog_confirm(const String &name); + Ref<Texture> get_current_texture(); static void _import_node(Node *p_node, Ref<TileSet> p_library); static void _import_scene(Node *p_scene, Ref<TileSet> p_library, bool p_merge); @@ -150,7 +149,6 @@ class TileSetEditor : public Control { protected: static void _bind_methods(); void _notification(int p_what); - virtual void _changed_callback(Object *p_changed, const char *p_prop); public: void edit(const Ref<TileSet> &p_tileset); @@ -160,53 +158,61 @@ public: ~TileSetEditor(); private: - void _on_tile_list_selected(int p_index); + void _on_tileset_toolbar_button_pressed(int p_index); + void _on_tileset_toolbar_confirm(); + void _on_texture_list_selected(int p_index); + void _on_textures_added(const PoolStringArray &p_paths); void _on_edit_mode_changed(int p_edit_mode); + void _on_workspace_mode_changed(int p_workspace_mode); void _on_workspace_overlay_draw(); void _on_workspace_draw(); + void _on_workspace_process(); void _on_workspace_input(const Ref<InputEvent> &p_ie); void _on_tool_clicked(int p_tool); void _on_priority_changed(float val); void _on_grid_snap_toggled(bool p_val); - void _set_snap_step_x(float p_val); - void _set_snap_step_y(float p_val); - void _set_snap_off_x(float p_val); - void _set_snap_off_y(float p_val); - void _set_snap_sep_x(float p_val); - void _set_snap_sep_y(float p_val); - - void initialize_bottom_editor(); - void draw_highlight_tile(Vector2 coord, const Vector<Vector2> &other_highlighted = Vector<Vector2>()); + void _set_snap_step(Vector2 p_val); + void _set_snap_off(Vector2 p_val); + void _set_snap_sep(Vector2 p_val); + + void draw_highlight_current_tile(); + void draw_highlight_subtile(Vector2 coord, const Vector<Vector2> &other_highlighted = Vector<Vector2>()); + void draw_tile_subdivision(int p_id, Color p_color) const; + void draw_edited_region_subdivision() const; void draw_grid_snap(); void draw_polygon_shapes(); void close_shape(const Vector2 &shape_anchor); void select_coord(const Vector2 &coord); Vector2 snap_point(const Vector2 &point); - void update_tile_list(); - void update_tile_list_icon(); void update_workspace_tile_mode(); + void update_edited_region(const Vector2 &end_point); - int get_current_tile(); + int get_current_tile() const; + void set_current_tile(int p_id); }; -class TileSetEditorHelper : public Object { +class TilesetEditorContext : public Object { friend class TileSetEditor; - GDCLASS(TileSetEditorHelper, Object); + GDCLASS(TilesetEditorContext, Object); Ref<TileSet> tileset; TileSetEditor *tileset_editor; - int selected_tile; + bool snap_options_visible; public: void set_tileset(const Ref<TileSet> &p_tileset); +private: + void set_snap_options_visible(bool p_visible); + protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; - TileSetEditorHelper(TileSetEditor *p_tileset_editor); +public: + TilesetEditorContext(TileSetEditor *p_tileset_editor); }; class TileSetEditorPlugin : public EditorPlugin { @@ -214,11 +220,9 @@ class TileSetEditorPlugin : public EditorPlugin { GDCLASS(TileSetEditorPlugin, EditorPlugin); TileSetEditor *tileset_editor; + Button *tileset_editor_button; EditorNode *editor; - ToolButton *tileset_editor_button; - ToolButton *texture_region_button; - public: virtual String get_name() const { return "TileSet"; } bool has_main_screen() const { return false; } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 9218fed907..63e89b78ea 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -119,6 +119,9 @@ void VisualShaderEditor::_update_graph() { if (updating) return; + if (visual_shader.is_null()) + return; + graph->set_scroll_ofs(visual_shader->get_graph_offset() * EDSCALE); VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 95d39953cf..aad9258ed9 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -915,12 +915,6 @@ void ProjectManager::_update_project_buttons() { CanvasItem *item = Object::cast_to<CanvasItem>(scroll_children->get_child(i)); item->update(); - - Button *show = Object::cast_to<Button>(item->get_node(NodePath("project/path_box/show"))); - if (show) { - String current = item->get_meta("name"); - show->set_visible(selected_list.has(current)); - } } bool empty_selection = selected_list.empty(); @@ -1316,7 +1310,6 @@ void ProjectManager::_load_recent_projects() { path_hb->add_child(show); show->connect("pressed", this, "_show_project", varray(path)); show->set_tooltip(TTR("Show In File Manager")); - show->set_visible(false); Label *fpath = memnew(Label(path)); fpath->set_name("path"); @@ -1757,6 +1750,8 @@ ProjectManager::ProjectManager() { editor_set_scale(custom_display_scale); } break; } + + OS::get_singleton()->set_window_size(OS::get_singleton()->get_window_size() * MAX(1, EDSCALE)); } FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files")); @@ -1782,7 +1777,6 @@ ProjectManager::ProjectManager() { String cp; cp += 0xA9; - cp += '0'; OS::get_singleton()->set_window_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + cp + " 2007-2018 Juan Linietsky, Ariel Manzur & Godot Contributors"); HBoxContainer *top_hb = memnew(HBoxContainer); @@ -1825,7 +1819,7 @@ ProjectManager::ProjectManager() { project_filter = memnew(ProjectListFilter); search_box->add_child(project_filter); project_filter->connect("filter_changed", this, "_load_recent_projects"); - project_filter->set_custom_minimum_size(Size2(250, 10)); + project_filter->set_custom_minimum_size(Size2(280, 10) * EDSCALE); search_tree_vb->add_child(search_box); PanelContainer *pc = memnew(PanelContainer); @@ -2023,18 +2017,6 @@ void ProjectListFilter::_setup_filters() { filter_option->add_item(TTR("Path")); } -void ProjectListFilter::_command(int p_command) { - switch (p_command) { - - case CMD_CLEAR_FILTER: { - if (search_box->get_text() != "") { - search_box->clear(); - emit_signal("filter_changed"); - } - } break; - } -} - void ProjectListFilter::_search_text_changed(const String &p_newtext) { emit_signal("filter_changed"); } @@ -2057,13 +2039,14 @@ void ProjectListFilter::_filter_option_selected(int p_idx) { void ProjectListFilter::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) - clear_search_button->set_icon(get_icon("Close", "EditorIcons")); + if (p_what == NOTIFICATION_ENTER_TREE) { + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); + } } void ProjectListFilter::_bind_methods() { - ClassDB::bind_method(D_METHOD("_command"), &ProjectListFilter::_command); ClassDB::bind_method(D_METHOD("_search_text_changed"), &ProjectListFilter::_search_text_changed); ClassDB::bind_method(D_METHOD("_filter_option_selected"), &ProjectListFilter::_filter_option_selected); @@ -2088,8 +2071,4 @@ ProjectListFilter::ProjectListFilter() { search_box->connect("text_changed", this, "_search_text_changed"); search_box->set_h_size_flags(SIZE_EXPAND_FILL); add_child(search_box); - - clear_search_button = memnew(ToolButton); - clear_search_button->connect("pressed", this, "_command", make_binds(CMD_CLEAR_FILTER)); - add_child(clear_search_button); } diff --git a/editor/project_manager.h b/editor/project_manager.h index a9d23b1f71..ad21e00b0d 100644 --- a/editor/project_manager.h +++ b/editor/project_manager.h @@ -128,13 +128,8 @@ class ProjectListFilter : public HBoxContainer { private: friend class ProjectManager; - enum Command { - CMD_CLEAR_FILTER, - }; - OptionButton *filter_option; LineEdit *search_box; - ToolButton *clear_search_button; enum FilterOption { FILTER_NAME, @@ -142,7 +137,6 @@ private: }; FilterOption _current_filter; - void _command(int p_command); void _search_text_changed(const String &p_newtext); void _setup_filters(); void _filter_option_selected(int p_idx); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 2b2e03ce38..ea697f5da2 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -81,7 +81,8 @@ void ProjectSettingsEditor::_notification(int p_what) { globals_editor->edit(ProjectSettings::get_singleton()); search_button->set_icon(get_icon("Search", "EditorIcons")); - clear_button->set_icon(get_icon("Close", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); action_add_error->add_color_override("font_color", get_color("error_color", "Editor")); @@ -119,7 +120,8 @@ void ProjectSettingsEditor::_notification(int p_what) { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { search_button->set_icon(get_icon("Search", "EditorIcons")); - clear_button->set_icon(get_icon("Close", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); action_add_error->add_color_override("font_color", get_color("error_color", "Editor")); popup_add->set_item_icon(popup_add->get_item_index(INPUT_KEY), get_icon("Keyboard", "EditorIcons")); popup_add->set_item_icon(popup_add->get_item_index(INPUT_JOY_BUTTON), get_icon("JoyButton", "EditorIcons")); @@ -213,10 +215,8 @@ void ProjectSettingsEditor::_action_edited() { undo_redo->create_action(TTR("Change Action deadzone")); undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, new_action); - undo_redo->add_do_method(this, "_update_actions"); undo_redo->add_do_method(this, "_settings_changed"); undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", name, old_action); - undo_redo->add_undo_method(this, "_update_actions"); undo_redo->add_undo_method(this, "_settings_changed"); undo_redo->commit_action(); } @@ -1591,15 +1591,6 @@ void ProjectSettingsEditor::_toggle_search_bar(bool p_pressed) { } } -void ProjectSettingsEditor::_clear_search_box() { - - if (search_box->get_text() == "") - return; - - search_box->clear(); - globals_editor->get_inspector()->update_tree(); -} - void ProjectSettingsEditor::set_plugins_page() { tab_container->set_current_tab(plugin_settings->get_index()); @@ -1662,7 +1653,6 @@ void ProjectSettingsEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_translation_filter_option_changed"), &ProjectSettingsEditor::_translation_filter_option_changed); ClassDB::bind_method(D_METHOD("_translation_filter_mode_changed"), &ProjectSettingsEditor::_translation_filter_mode_changed); - ClassDB::bind_method(D_METHOD("_clear_search_box"), &ProjectSettingsEditor::_clear_search_box); ClassDB::bind_method(D_METHOD("_toggle_search_bar"), &ProjectSettingsEditor::_toggle_search_bar); ClassDB::bind_method(D_METHOD("_copy_to_platform_about_to_show"), &ProjectSettingsEditor::_copy_to_platform_about_to_show); @@ -1753,10 +1743,6 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); search_bar->add_child(search_box); - clear_button = memnew(ToolButton); - search_bar->add_child(clear_button); - clear_button->connect("pressed", this, "_clear_search_box"); - globals_editor = memnew(SectionedInspector); props_base->add_child(globals_editor); globals_editor->get_inspector()->set_undo_redo(EditorNode::get_singleton()->get_undo_redo()); diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h index 3b74ae1909..b738c4ae20 100644 --- a/editor/project_settings_editor.h +++ b/editor/project_settings_editor.h @@ -69,7 +69,6 @@ class ProjectSettingsEditor : public AcceptDialog { HBoxContainer *search_bar; Button *search_button; LineEdit *search_box; - ToolButton *clear_button; HBoxContainer *add_prop_bar; AcceptDialog *message; @@ -158,7 +157,6 @@ class ProjectSettingsEditor : public AcceptDialog { void _translation_filter_mode_changed(int p_mode); void _toggle_search_bar(bool p_pressed); - void _clear_search_box(); void _copy_to_platform_about_to_show(); diff --git a/editor/quick_open.cpp b/editor/quick_open.cpp index 907bb50f7e..d2101f1e00 100644 --- a/editor/quick_open.cpp +++ b/editor/quick_open.cpp @@ -258,6 +258,9 @@ void EditorQuickOpen::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { connect("confirmed", this, "_confirmed"); + + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); } } diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index d8982c751c..d17bcef92b 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -119,7 +119,7 @@ void SceneTreeDock::instance(const String &p_file) { if (!edited_scene) { current_option = -1; - accept->get_ok()->set_text(TTR("OK :(")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("No parent to instance a child at.")); accept->popup_centered_minsize(); return; @@ -164,7 +164,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node Ref<PackedScene> sdata = ResourceLoader::load(p_files[i]); if (!sdata.is_valid()) { current_option = -1; - accept->get_ok()->set_text(TTR("Ugh")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(vformat(TTR("Error loading scene from %s"), p_files[i])); accept->popup_centered_minsize(); error = true; @@ -174,7 +174,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); if (!instanced_scene) { current_option = -1; - accept->get_ok()->set_text(TTR("Ugh")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(vformat(TTR("Error instancing scene from %s"), p_files[i])); accept->popup_centered_minsize(); error = true; @@ -233,7 +233,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) { Ref<PackedScene> sdata = ResourceLoader::load(p_file); if (!sdata.is_valid()) { - accept->get_ok()->set_text(TTR("Ugh")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(vformat(TTR("Error loading scene from %s"), p_file)); accept->popup_centered_minsize(); return; @@ -241,7 +241,7 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); if (!instanced_scene) { - accept->get_ok()->set_text(TTR("Ugh")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(vformat(TTR("Error instancing scene from %s"), p_file)); accept->popup_centered_minsize(); return; @@ -413,7 +413,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (scene_tree->get_selected() == edited_scene) { current_option = -1; - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("This operation can't be done on the tree root.")); accept->popup_centered_minsize(); break; @@ -474,7 +474,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (editor_selection->is_selected(edited_scene)) { current_option = -1; - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("This operation can't be done on the tree root.")); accept->popup_centered_minsize(); break; @@ -544,7 +544,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (editor_selection->is_selected(edited_scene)) { current_option = -1; - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("This operation can't be done on the tree root.")); accept->popup_centered_minsize(); break; @@ -631,7 +631,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { Node *scene = editor_data->get_edited_scene_root(); if (!scene) { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("This operation can't be done without a scene.")); accept->popup_centered_minsize(); break; @@ -640,7 +640,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { List<Node *> selection = editor_selection->get_selected_node_list(); if (selection.size() != 1) { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("This operation requires a single selected node.")); accept->popup_centered_minsize(); break; @@ -649,14 +649,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { Node *tocopy = selection.front()->get(); if (tocopy == scene) { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("Can not perform with the root node.")); accept->popup_centered_minsize(); break; } if (tocopy != editor_data->get_edited_scene_root() && tocopy->get_filename() != "") { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("This operation can't be done on instanced scenes.")); accept->popup_centered_minsize(); break; @@ -797,13 +797,38 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } break; case TOOL_CREATE_2D_SCENE: case TOOL_CREATE_3D_SCENE: - case TOOL_CREATE_USER_INTERFACE: { + case TOOL_CREATE_USER_INTERFACE: + case TOOL_CREATE_FAVORITE: { Node *new_node; - switch (p_tool) { - case TOOL_CREATE_2D_SCENE: new_node = memnew(Node2D); break; - case TOOL_CREATE_3D_SCENE: new_node = memnew(Spatial); break; - case TOOL_CREATE_USER_INTERFACE: new_node = memnew(Control); break; + + if (TOOL_CREATE_FAVORITE == p_tool) { + String name = selected_favorite_root.get_slicec(' ', 0); + if (ScriptServer::is_global_class(name)) { + new_node = Object::cast_to<Node>(ClassDB::instance(ScriptServer::get_global_class_base(name))); + Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(name), "Script"); + if (new_node && script.is_valid()) { + new_node->set_script(script.get_ref_ptr()); + new_node->set_name(name); + } + } else { + new_node = Object::cast_to<Node>(ClassDB::instance(selected_favorite_root)); + } + if (!new_node) { + ERR_EXPLAIN("Creating root from favorite '" + selected_favorite_root + "' failed. Creating 'Node' instead."); + new_node = memnew(Node); + } + } else { + switch (p_tool) { + case TOOL_CREATE_2D_SCENE: new_node = memnew(Node2D); break; + case TOOL_CREATE_3D_SCENE: new_node = memnew(Spatial); break; + case TOOL_CREATE_USER_INTERFACE: { + Control *node = memnew(Control); + node->set_anchors_and_margins_preset(PRESET_WIDE); //more useful for resizable UIs. + new_node = node; + + } break; + } } editor_data->get_undo_redo().create_action("New Scene Root"); @@ -857,39 +882,67 @@ void SceneTreeDock::_notification(int p_what) { button_create_script->set_icon(get_icon("ScriptCreate", "EditorIcons")); button_clear_script->set_icon(get_icon("ScriptRemove", "EditorIcons")); - filter->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + filter->set_right_icon(get_icon("Search", "EditorIcons")); + filter->set_clear_button_enabled(true); EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", this, "_selection_changed"); - create_root_dialog->add_child(memnew(Label(TTR("Create Root Node:")))); + // create_root_dialog + HBoxContainer *top_row = memnew(HBoxContainer); + top_row->set_name("NodeShortcutsTopRow"); + top_row->set_h_size_flags(SIZE_EXPAND_FILL); + top_row->add_child(memnew(Label(TTR("Create Root Node:")))); + top_row->add_spacer(); - Button *button_2d = memnew(Button); - create_root_dialog->add_child(button_2d); + ToolButton *node_shortcuts_toggle = memnew(ToolButton); + node_shortcuts_toggle->set_name("NodeShortcutsToggle"); + node_shortcuts_toggle->set_icon(get_icon("Favorites", "EditorIcons")); + node_shortcuts_toggle->set_toggle_mode(true); + node_shortcuts_toggle->set_pressed(EDITOR_GET("_use_favorites_root_selection")); + node_shortcuts_toggle->set_anchors_and_margins_preset(Control::PRESET_CENTER_RIGHT); + node_shortcuts_toggle->connect("pressed", this, "_update_create_root_dialog"); + top_row->add_child(node_shortcuts_toggle); + + create_root_dialog->add_child(top_row); + + VBoxContainer *node_shortcuts = memnew(VBoxContainer); + node_shortcuts->set_name("NodeShortcuts"); + + VBoxContainer *beginner_node_shortcuts = memnew(VBoxContainer); + beginner_node_shortcuts->set_name("BeginnerNodeShortcuts"); + node_shortcuts->add_child(beginner_node_shortcuts); + Button *button_2d = memnew(Button); + beginner_node_shortcuts->add_child(button_2d); button_2d->set_text(TTR("2D Scene")); button_2d->set_icon(get_icon("Node2D", "EditorIcons")); button_2d->connect("pressed", this, "_tool_selected", make_binds(TOOL_CREATE_2D_SCENE, false)); Button *button_3d = memnew(Button); - create_root_dialog->add_child(button_3d); + beginner_node_shortcuts->add_child(button_3d); button_3d->set_text(TTR("3D Scene")); button_3d->set_icon(get_icon("Spatial", "EditorIcons")); button_3d->connect("pressed", this, "_tool_selected", make_binds(TOOL_CREATE_3D_SCENE, false)); Button *button_ui = memnew(Button); - create_root_dialog->add_child(button_ui); + beginner_node_shortcuts->add_child(button_ui); button_ui->set_text(TTR("User Interface")); button_ui->set_icon(get_icon("Control", "EditorIcons")); button_ui->connect("pressed", this, "_tool_selected", make_binds(TOOL_CREATE_USER_INTERFACE, false)); + VBoxContainer *favorite_node_shortcuts = memnew(VBoxContainer); + favorite_node_shortcuts->set_name("FavoriteNodeShortcuts"); + node_shortcuts->add_child(favorite_node_shortcuts); + Button *button_custom = memnew(Button); - create_root_dialog->add_child(button_custom); + node_shortcuts->add_child(button_custom); button_custom->set_text(TTR("Custom Node")); button_custom->set_icon(get_icon("Add", "EditorIcons")); button_custom->connect("pressed", this, "_tool_selected", make_binds(TOOL_NEW, false)); - create_root_dialog->add_spacer(); - + node_shortcuts->add_spacer(); + create_root_dialog->add_child(node_shortcuts); + _update_create_root_dialog(); } break; case NOTIFICATION_ENTER_TREE: { @@ -905,7 +958,8 @@ void SceneTreeDock::_notification(int p_what) { button_create_script->set_icon(get_icon("ScriptCreate", "EditorIcons")); button_clear_script->set_icon(get_icon("ScriptRemove", "EditorIcons")); - filter->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + filter->set_right_icon(get_icon("Search", "EditorIcons")); + filter->set_clear_button_enabled(true); } break; case NOTIFICATION_PROCESS: { @@ -1244,7 +1298,7 @@ bool SceneTreeDock::_validate_no_foreign() { if (E->get() != edited_scene && E->get()->get_owner() != edited_scene) { - accept->get_ok()->set_text(TTR("Makes Sense!")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("Can't operate on nodes from a foreign scene!")); accept->popup_centered_minsize(); return false; @@ -1252,7 +1306,7 @@ bool SceneTreeDock::_validate_no_foreign() { if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene->get_scene_inherited_state()->find_node_by_path(edited_scene->get_path_to(E->get())) >= 0) { - accept->get_ok()->set_text(TTR("Makes Sense!")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("Can't operate on nodes the current scene inherits from!")); accept->popup_centered_minsize(); return false; @@ -1732,7 +1786,7 @@ void SceneTreeDock::_new_scene_from(String p_file) { List<Node *> selection = editor_selection->get_selected_node_list(); if (selection.size() != 1) { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("This operation requires a single selected node.")); accept->popup_centered_minsize(); return; @@ -1750,7 +1804,7 @@ void SceneTreeDock::_new_scene_from(String p_file) { memdelete(copy); if (err != OK) { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("Couldn't save new scene. Likely dependencies (instances) couldn't be satisfied.")); accept->popup_centered_minsize(); return; @@ -1762,14 +1816,14 @@ void SceneTreeDock::_new_scene_from(String p_file) { err = ResourceSaver::save(p_file, sdata, flg); if (err != OK) { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("Error saving scene.")); accept->popup_centered_minsize(); return; } _replace_with_branch_scene(p_file, base); } else { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("Error duplicating scene to save it.")); accept->popup_centered_minsize(); return; @@ -1985,6 +2039,8 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { if (selection.size() == 1) { + Node *selected = selection[0]; + subresources.clear(); menu_subresources->clear(); menu_subresources->set_size(Size2(1, 1)); @@ -1995,18 +2051,23 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_icon_shortcut(get_icon("Add", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW); menu->add_icon_shortcut(get_icon("Instance", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANCE); menu->add_separator(); + menu->add_icon_shortcut(get_icon("ScriptCreate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT); - menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT); + Ref<Script> existing = selected->get_script(); + if (existing.is_valid()) { + menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT); + } menu->add_separator(); menu->add_icon_shortcut(get_icon("Rename", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/rename"), TOOL_RENAME); } menu->add_icon_shortcut(get_icon("Reload", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/change_node_type"), TOOL_REPLACE); - menu->add_separator(); - menu->add_icon_shortcut(get_icon("MoveUp", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/move_up"), TOOL_MOVE_UP); - menu->add_icon_shortcut(get_icon("MoveDown", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/move_down"), TOOL_MOVE_DOWN); - menu->add_icon_shortcut(get_icon("Duplicate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/duplicate"), TOOL_DUPLICATE); - menu->add_icon_shortcut(get_icon("Reparent", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/reparent"), TOOL_REPARENT); - + if (scene_tree->get_selected() != edited_scene) { + menu->add_separator(); + menu->add_icon_shortcut(get_icon("MoveUp", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/move_up"), TOOL_MOVE_UP); + menu->add_icon_shortcut(get_icon("MoveDown", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/move_down"), TOOL_MOVE_DOWN); + menu->add_icon_shortcut(get_icon("Duplicate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/duplicate"), TOOL_DUPLICATE); + menu->add_icon_shortcut(get_icon("Reparent", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/reparent"), TOOL_REPARENT); + } if (selection.size() == 1) { menu->add_icon_shortcut(get_icon("NewRoot", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/make_root"), TOOL_MAKE_ROOT); @@ -2136,6 +2197,67 @@ void SceneTreeDock::_local_tree_selected() { edit_local->set_pressed(true); } +void SceneTreeDock::_update_create_root_dialog() { + + BaseButton *toggle = Object::cast_to<BaseButton>(create_root_dialog->get_node(String("NodeShortcutsTopRow/NodeShortcutsToggle"))); + Node *node_shortcuts = create_root_dialog->get_node(String("NodeShortcuts")); + + if (!toggle || !node_shortcuts) + return; + + Control *beginner_nodes = Object::cast_to<Control>(node_shortcuts->get_node(String("BeginnerNodeShortcuts"))); + Control *favorite_nodes = Object::cast_to<Control>(node_shortcuts->get_node(String("FavoriteNodeShortcuts"))); + + if (!beginner_nodes || !favorite_nodes) + return; + + EditorSettings::get_singleton()->set_setting("_use_favorites_root_selection", toggle->is_pressed()); + EditorSettings::get_singleton()->save(); + if (toggle->is_pressed()) { + + for (int i = 0; i < favorite_nodes->get_child_count(); i++) { + favorite_nodes->get_child(i)->queue_delete(); + } + + FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites.Node"), FileAccess::READ); + + if (f) { + + while (!f->eof_reached()) { + String l = f->get_line().strip_edges(); + + if (l != String()) { + Button *button = memnew(Button); + favorite_nodes->add_child(button); + button->set_text(TTR(l)); + String name = l.get_slicec(' ', 0); + if (ScriptServer::is_global_class(name)) + name = ScriptServer::get_global_class_base(name); + button->set_icon(get_icon(name, "EditorIcons")); + button->connect("pressed", this, "_favorite_root_selected", make_binds(l)); + } + } + + memdelete(f); + } + + if (!favorite_nodes->is_visible_in_tree()) { + favorite_nodes->show(); + beginner_nodes->hide(); + } + } else { + if (!beginner_nodes->is_visible_in_tree()) { + beginner_nodes->show(); + favorite_nodes->hide(); + } + } +} + +void SceneTreeDock::_favorite_root_selected(const String &p_class) { + selected_favorite_root = p_class; + _tool_selected(TOOL_CREATE_FAVORITE, false); +} + void SceneTreeDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_tool_selected"), &SceneTreeDock::_tool_selected, DEFVAL(false)); @@ -2164,6 +2286,8 @@ void SceneTreeDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_remote_tree_selected"), &SceneTreeDock::_remote_tree_selected); ClassDB::bind_method(D_METHOD("_local_tree_selected"), &SceneTreeDock::_local_tree_selected); ClassDB::bind_method(D_METHOD("_update_script_button"), &SceneTreeDock::_update_script_button); + ClassDB::bind_method(D_METHOD("_favorite_root_selected"), &SceneTreeDock::_favorite_root_selected); + ClassDB::bind_method(D_METHOD("_update_create_root_dialog"), &SceneTreeDock::_update_create_root_dialog); ClassDB::bind_method(D_METHOD("instance"), &SceneTreeDock::instance); @@ -2289,6 +2413,8 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel create_dialog->set_base_type("Node"); add_child(create_dialog); create_dialog->connect("create", this, "_create"); + create_dialog->connect("favorites_updated", this, "_update_create_root_dialog"); + EditorFileSystem::get_singleton()->connect("script_classes_updated", create_dialog, "_save_and_update_favorite_list"); rename_dialog = memnew(RenameDialog(scene_tree, &editor_data->get_undo_redo())); add_child(rename_dialog); @@ -2325,6 +2451,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel menu = memnew(PopupMenu); add_child(menu); menu->connect("id_pressed", this, "_tool_selected"); + menu->set_hide_on_window_lose_focus(true); menu_subresources = memnew(PopupMenu); menu_subresources->set_name("Sub-Resources"); menu_subresources->connect("id_pressed", this, "_tool_selected"); @@ -2334,11 +2461,12 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel clear_inherit_confirm = memnew(ConfirmationDialog); clear_inherit_confirm->set_text(TTR("Clear Inheritance? (No Undo!)")); - clear_inherit_confirm->get_ok()->set_text(TTR("Clear!")); + clear_inherit_confirm->get_ok()->set_text(TTR("Clear")); add_child(clear_inherit_confirm); set_process_input(true); set_process(true); EDITOR_DEF("interface/editors/show_scene_tree_root_selection", true); + EDITOR_DEF("_use_favorites_root_selection", false); } diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index 57f4759747..34a7c98d11 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -86,6 +86,7 @@ class SceneTreeDock : public VBoxContainer { TOOL_CREATE_2D_SCENE, TOOL_CREATE_3D_SCENE, TOOL_CREATE_USER_INTERFACE, + TOOL_CREATE_FAVORITE, }; @@ -141,6 +142,7 @@ class SceneTreeDock : public VBoxContainer { EditorNode *editor; VBoxContainer *create_root_dialog; + String selected_favorite_root; void _add_children_to_popup(Object *p_obj, int p_depth); @@ -201,6 +203,9 @@ class SceneTreeDock : public VBoxContainer { void _remote_tree_selected(); void _local_tree_selected(); + void _update_create_root_dialog(); + void _favorite_root_selected(const String &p_class); + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index e483fde4bc..bd661ade53 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -1198,7 +1198,7 @@ void ScriptEditorDebugger::start() { int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port"); if (server->listen(remote_port) != OK) { - EditorNode::get_log()->add_message(String("Error listening on port ") + itos(remote_port), true); + EditorNode::get_log()->add_message(String("Error listening on port ") + itos(remote_port), EditorLog::MSG_TYPE_ERROR); return; } diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp index fe379703e5..4ebba73cb3 100644 --- a/editor/settings_config_dialog.cpp +++ b/editor/settings_config_dialog.cpp @@ -114,22 +114,6 @@ void EditorSettingsDialog::popup_edit_settings() { _focus_current_search_box(); } -void EditorSettingsDialog::_clear_search_box() { - - if (search_box->get_text() == "") - return; - - search_box->clear(); - inspector->get_inspector()->update_tree(); -} - -void EditorSettingsDialog::_clear_shortcut_search_box() { - if (shortcut_search_box->get_text() == "") - return; - - shortcut_search_box->clear(); -} - void EditorSettingsDialog::_filter_shortcuts(const String &p_filter) { shortcut_filter = p_filter; _update_shortcuts(); @@ -198,10 +182,10 @@ void EditorSettingsDialog::_unhandled_input(const Ref<InputEvent> &p_event) { void EditorSettingsDialog::_update_icons() { - search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); - shortcut_search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); - clear_button->set_icon(get_icon("Close", "EditorIcons")); - shortcut_clear_button->set_icon(get_icon("Close", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); + shortcut_search_box->set_right_icon(get_icon("Search", "EditorIcons")); + shortcut_search_box->set_clear_button_enabled(true); restart_close_button->set_icon(get_icon("Close", "EditorIcons")); restart_container->add_style_override("panel", get_stylebox("bg", "Tree")); @@ -411,8 +395,6 @@ void EditorSettingsDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_settings_save"), &EditorSettingsDialog::_settings_save); ClassDB::bind_method(D_METHOD("_settings_changed"), &EditorSettingsDialog::_settings_changed); ClassDB::bind_method(D_METHOD("_settings_property_edited"), &EditorSettingsDialog::_settings_property_edited); - ClassDB::bind_method(D_METHOD("_clear_search_box"), &EditorSettingsDialog::_clear_search_box); - ClassDB::bind_method(D_METHOD("_clear_shortcut_search_box"), &EditorSettingsDialog::_clear_shortcut_search_box); ClassDB::bind_method(D_METHOD("_shortcut_button_pressed"), &EditorSettingsDialog::_shortcut_button_pressed); ClassDB::bind_method(D_METHOD("_filter_shortcuts"), &EditorSettingsDialog::_filter_shortcuts); ClassDB::bind_method(D_METHOD("_update_shortcuts"), &EditorSettingsDialog::_update_shortcuts); @@ -451,10 +433,6 @@ EditorSettingsDialog::EditorSettingsDialog() { search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); hbc->add_child(search_box); - clear_button = memnew(ToolButton); - hbc->add_child(clear_button); - clear_button->connect("pressed", this, "_clear_search_box"); - inspector = memnew(SectionedInspector); //inspector->hide_top_label(); inspector->get_inspector()->set_use_filter(true); @@ -500,10 +478,6 @@ EditorSettingsDialog::EditorSettingsDialog() { hbc->add_child(shortcut_search_box); shortcut_search_box->connect("text_changed", this, "_filter_shortcuts"); - shortcut_clear_button = memnew(ToolButton); - hbc->add_child(shortcut_clear_button); - shortcut_clear_button->connect("pressed", this, "_clear_shortcut_search_box"); - shortcuts = memnew(Tree); tab_shortcuts->add_child(shortcuts, true); shortcuts->set_v_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/settings_config_dialog.h b/editor/settings_config_dialog.h index 6cf2eb6bdf..37d32e401d 100644 --- a/editor/settings_config_dialog.h +++ b/editor/settings_config_dialog.h @@ -52,8 +52,6 @@ class EditorSettingsDialog : public AcceptDialog { LineEdit *search_box; LineEdit *shortcut_search_box; - ToolButton *clear_button; - ToolButton *shortcut_clear_button; SectionedInspector *inspector; Timer *timer; diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index c450c0fd4c..64fdc778d0 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -47,7 +47,10 @@ // Keep small children away from this file. // It's so ugly it will eat them alive -#define HANDLE_HALF_SIZE 0.05 +// The previous comment is kept only for historical reasons. +// No children will be harmed by the viewing of this file... hopefully. + +#define HANDLE_HALF_SIZE 9.5 bool EditorSpatialGizmo::can_draw() const { return is_editable(); @@ -85,11 +88,37 @@ void EditorSpatialGizmo::clear() { void EditorSpatialGizmo::redraw() { - if (get_script_instance() && get_script_instance()->has_method("redraw")) - get_script_instance()->call("redraw"); + ERR_FAIL_COND(!gizmo_plugin); + gizmo_plugin->redraw(this); +} + +String EditorSpatialGizmo::get_handle_name(int p_idx) const { + ERR_FAIL_COND_V(!gizmo_plugin, ""); + return gizmo_plugin->get_handle_name(this, p_idx); +} + +Variant EditorSpatialGizmo::get_handle_value(int p_idx) { + ERR_FAIL_COND_V(!gizmo_plugin, Variant()); + return gizmo_plugin->get_handle_value(this, p_idx); +} + +void EditorSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { + ERR_FAIL_COND(!gizmo_plugin); + return gizmo_plugin->set_handle(this, p_idx, p_camera, p_point); +} + +void EditorSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { + ERR_FAIL_COND(!gizmo_plugin); + return gizmo_plugin->commit_handle(this, p_idx, p_restore, p_cancel); +} + +void EditorSpatialGizmo::set_spatial_node(Spatial *p_node) { + + ERR_FAIL_NULL(p_node); + spatial_node = p_node; } -void EditorSpatialGizmo::Instance::create_instance(Spatial *p_base) { +void EditorSpatialGizmo::Instance::create_instance(Spatial *p_base, bool p_hidden) { instance = VS::get_singleton()->instance_create2(mesh->get_rid(), p_base->get_world()->get_scenario()); VS::get_singleton()->instance_attach_object_instance_id(instance, p_base->get_instance_id()); @@ -98,7 +127,8 @@ void EditorSpatialGizmo::Instance::create_instance(Spatial *p_base) { if (extra_margin) VS::get_singleton()->instance_set_extra_visibility_margin(instance, 1); VS::get_singleton()->instance_geometry_set_cast_shadows_setting(instance, VS::SHADOW_CASTING_SETTING_OFF); - VS::get_singleton()->instance_set_layer_mask(instance, 1 << SpatialEditorViewport::GIZMO_EDIT_LAYER); //gizmos are 26 + int layer = p_hidden ? 0 : 1 << SpatialEditorViewport::GIZMO_EDIT_LAYER; + VS::get_singleton()->instance_set_layer_mask(instance, layer); //gizmos are 26 } void EditorSpatialGizmo::add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard, const RID &p_skeleton) { @@ -110,7 +140,7 @@ void EditorSpatialGizmo::add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard ins.mesh = p_mesh; ins.skeleton = p_skeleton; if (valid) { - ins.create_instance(spatial_node); + ins.create_instance(spatial_node, hidden); VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform()); } @@ -159,7 +189,7 @@ void EditorSpatialGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Mat ins.billboard = p_billboard; ins.mesh = mesh; if (valid) { - ins.create_instance(spatial_node); + ins.create_instance(spatial_node, hidden); VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform()); } @@ -210,7 +240,7 @@ void EditorSpatialGizmo::add_unscaled_billboard(const Ref<Material> &p_material, ins.unscaled = true; ins.billboard = true; if (valid) { - ins.create_instance(spatial_node); + ins.create_instance(spatial_node, hidden); VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform()); } @@ -233,7 +263,7 @@ void EditorSpatialGizmo::add_collision_segments(const Vector<Vector3> &p_lines) } } -void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_billboard, bool p_secondary) { +void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, const Ref<Material> &p_material, bool p_billboard, bool p_secondary) { billboard_handle = p_billboard; @@ -257,7 +287,7 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi for (int i = 0; i < p_handles.size(); i++) { Color col(1, 1, 1, 1); - if (is_gizmo_handle_highlighted(i)) + if (gizmo_plugin->is_gizmo_handle_highlighted(this, i)) col = Color(0, 0, 1, 0.9); if (SpatialEditor::get_singleton()->get_over_gizmo_handle() != i) @@ -268,10 +298,7 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi } a[VS::ARRAY_COLOR] = colors; mesh->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS, a); - if (p_billboard) - mesh->surface_set_material(0, SpatialEditorGizmos::singleton->handle2_material_billboard); - else - mesh->surface_set_material(0, SpatialEditorGizmos::singleton->handle2_material); + mesh->surface_set_material(0, p_material); if (p_billboard) { float md = 0; @@ -288,7 +315,7 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi ins.billboard = p_billboard; ins.extra_margin = true; if (valid) { - ins.create_instance(spatial_node); + ins.create_instance(spatial_node, hidden); VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform()); } instances.push_back(ins); @@ -330,17 +357,13 @@ void EditorSpatialGizmo::add_solid_box(Ref<Material> &p_material, Vector3 p_size add_mesh(m); } -void EditorSpatialGizmo::set_spatial_node(Spatial *p_node) { - - ERR_FAIL_NULL(p_node); - spatial_node = p_node; -} - bool EditorSpatialGizmo::intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum) { ERR_FAIL_COND_V(!spatial_node, false); ERR_FAIL_COND_V(!valid, false); + if (hidden && !gizmo_plugin->is_selectable_when_hidden()) return false; + if (selectable_icon_size > 0.0f) { Vector3 origin = spatial_node->get_global_transform().get_origin(); @@ -413,7 +436,9 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, ERR_FAIL_COND_V(!spatial_node, false); ERR_FAIL_COND_V(!valid, false); - if (r_gizmo_handle) { + if (hidden && !gizmo_plugin->is_selectable_when_hidden()) return false; + + if (r_gizmo_handle && !hidden) { Transform t = spatial_node->get_global_transform(); t.orthonormalize(); @@ -428,7 +453,8 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 hpos = t.xform(secondary_handles[i]); Vector2 p = p_camera->unproject_position(hpos); - if (p.distance_to(p_point) < SpatialEditorGizmos::singleton->handle_t->get_width() * 0.6) { + + if (p.distance_to(p_point) < HANDLE_HALF_SIZE) { real_t dp = p_camera->get_transform().origin.distance_to(hpos); if (dp < min_d) { @@ -453,7 +479,8 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 hpos = t.xform(handles[i]); Vector2 p = p_camera->unproject_position(hpos); - if (p.distance_to(p_point) < SpatialEditorGizmos::singleton->handle_t->get_width() * 0.6) { + + if (p.distance_to(p_point) < HANDLE_HALF_SIZE) { real_t dp = p_camera->get_transform().origin.distance_to(hpos); if (dp < min_d) { @@ -504,6 +531,8 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, rect.set_position(center - rect.get_size() / 2.0); if (rect.has_point(p_point)) { + r_pos = t.origin; + r_normal = -p_camera->project_ray_normal(p_point); return true; } @@ -597,7 +626,7 @@ void EditorSpatialGizmo::create() { for (int i = 0; i < instances.size(); i++) { - instances.write[i].create_instance(spatial_node); + instances.write[i].create_instance(spatial_node, hidden); } transform(); @@ -624,96 +653,21 @@ void EditorSpatialGizmo::free() { instances.write[i].instance = RID(); } + clear(); + valid = false; } -Ref<SpatialMaterial> EditorSpatialGizmo::create_material(const String &p_name, const Color &p_color, bool p_billboard, bool p_on_top, bool p_use_vertex_color) { - - String name = p_name; - - if (!is_editable()) { - name += "@readonly"; - } else if (is_selected()) { - name += "@selected"; - } - - if (SpatialEditorGizmos::singleton->material_cache.has(name)) { - return SpatialEditorGizmos::singleton->material_cache[name]; - } - - Color color = p_color; - - if (!is_editable()) { - color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/instanced"); - } - if (!is_selected()) { - color.a *= 0.3; - } - - Ref<SpatialMaterial> line_material; - line_material.instance(); - line_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - line_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - if (p_use_vertex_color) { - line_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - line_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - } - - if (p_billboard) { - line_material->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); +void EditorSpatialGizmo::set_hidden(bool p_hidden) { + hidden = p_hidden; + int layer = hidden ? 0 : 1 << SpatialEditorViewport::GIZMO_EDIT_LAYER; + for (int i = 0; i < instances.size(); ++i) { + VS::get_singleton()->instance_set_layer_mask(instances[i].instance, layer); } - - if (p_on_top && is_selected()) { - line_material->set_on_top_of_alpha(); - } - - line_material->set_albedo(color); - - SpatialEditorGizmos::singleton->material_cache[name] = line_material; - - return line_material; } -Ref<SpatialMaterial> EditorSpatialGizmo::create_icon_material(const String &p_name, const Ref<Texture> &p_texture, bool p_on_top, const Color &p_albedo) { - - String name = p_name; - - if (!is_editable()) { - name += "@readonly"; - } else if (is_selected()) { - name += "@selected"; - } - - if (SpatialEditorGizmos::singleton->material_cache.has(name)) { - return SpatialEditorGizmos::singleton->material_cache[name]; - } - - Color color = p_albedo; - - if (!is_editable()) { - color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/instanced"); - } else if (!is_selected()) { - color.a *= 0.3; - } - - Ref<SpatialMaterial> icon; - icon.instance(); - icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - icon->set_cull_mode(SpatialMaterial::CULL_DISABLED); - icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); - icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - icon->set_albedo(color); - icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, p_texture); - icon->set_flag(SpatialMaterial::FLAG_FIXED_SIZE, true); - icon->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); - - if (p_on_top && is_selected()) { - icon->set_on_top_of_alpha(); - } - - SpatialEditorGizmos::singleton->material_cache[name] = icon; - - return icon; +void EditorSpatialGizmo::set_plugin(EditorSpatialGizmoPlugin *p_plugin) { + gizmo_plugin = p_plugin; } void EditorSpatialGizmo::_bind_methods() { @@ -726,6 +680,7 @@ void EditorSpatialGizmo::_bind_methods() { ClassDB::bind_method(D_METHOD("add_handles", "handles", "billboard", "secondary"), &EditorSpatialGizmo::add_handles, DEFVAL(false), DEFVAL(false)); ClassDB::bind_method(D_METHOD("set_spatial_node", "node"), &EditorSpatialGizmo::_set_spatial_node); ClassDB::bind_method(D_METHOD("clear"), &EditorSpatialGizmo::clear); + ClassDB::bind_method(D_METHOD("set_hidden", "hidden"), &EditorSpatialGizmo::set_hidden); BIND_VMETHOD(MethodInfo("redraw")); BIND_VMETHOD(MethodInfo(Variant::STRING, "get_handle_name", PropertyInfo(Variant::INT, "index"))); @@ -743,12 +698,17 @@ void EditorSpatialGizmo::_bind_methods() { EditorSpatialGizmo::EditorSpatialGizmo() { valid = false; billboard_handle = false; + hidden = false; base = NULL; + selected = false; + instanced = false; spatial_node = NULL; + gizmo_plugin = NULL; } EditorSpatialGizmo::~EditorSpatialGizmo() { + if (gizmo_plugin != NULL) gizmo_plugin->unregister_gizmo(this); clear(); } @@ -761,7 +721,30 @@ Vector3 EditorSpatialGizmo::get_handle_pos(int p_idx) const { //// light gizmo -String LightSpatialGizmo::get_handle_name(int p_idx) const { +LightSpatialGizmoPlugin::LightSpatialGizmoPlugin() { + + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/light", Color(1, 1, 0.2)); + + create_material("lines", gizmo_color); + create_material("lines_billboard", gizmo_color, true); + + create_icon_material("light_directional_icon", SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight", "EditorIcons")); + create_icon_material("light_omni_icon", SpatialEditor::get_singleton()->get_icon("GizmoLight", "EditorIcons")); + create_icon_material("light_spot_icon", SpatialEditor::get_singleton()->get_icon("GizmoSpotLight", "EditorIcons")); + + create_handle_material("handles"); + create_handle_material("handles_billboard", true); +} + +bool LightSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<Light>(p_spatial) != NULL; +} + +String LightSpatialGizmoPlugin::get_name() const { + return "Lights"; +} + +String LightSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { if (p_idx == 0) return "Radius"; @@ -769,8 +752,9 @@ String LightSpatialGizmo::get_handle_name(int p_idx) const { return "Aperture"; } -Variant LightSpatialGizmo::get_handle_value(int p_idx) const { +Variant LightSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node()); if (p_idx == 0) return light->get_param(Light::PARAM_RANGE); if (p_idx == 1) @@ -808,8 +792,9 @@ static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vec return a * 180.0 / Math_PI; } -void LightSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { +void LightSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node()); Transform gt = light->get_global_transform(); gt.orthonormalize(); Transform gi = gt.affine_inverse(); @@ -848,8 +833,9 @@ void LightSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_ } } -void LightSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { +void LightSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node()); if (p_cancel) { light->set_param(p_idx == 0 ? Light::PARAM_RANGE : Light::PARAM_SPOT_ANGLE, p_restore); @@ -871,14 +857,16 @@ void LightSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool } } -void LightSpatialGizmo::redraw() { +void LightSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node()); - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/light"); + p_gizmo->clear(); if (Object::cast_to<DirectionalLight>(light)) { - Ref<Material> material = create_material("light_directional_material", gizmo_color); - Ref<Material> icon = create_icon_material("light_directional_icon", SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight", "EditorIcons")); + Ref<Material> material = get_material("lines", p_gizmo); + Ref<Material> icon = get_material("light_directional_icon", p_gizmo); const int arrow_points = 7; const float arrow_length = 1.5; @@ -909,16 +897,15 @@ void LightSpatialGizmo::redraw() { } } - add_lines(lines, material); - add_collision_segments(lines); - add_unscaled_billboard(icon, 0.05); + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + p_gizmo->add_unscaled_billboard(icon, 0.05); } if (Object::cast_to<OmniLight>(light)) { - Ref<Material> material = create_material("light_omni_material", gizmo_color, true); - Ref<Material> icon = create_icon_material("light_omni_icon", SpatialEditor::get_singleton()->get_icon("GizmoLight", "EditorIcons")); - clear(); + Ref<Material> material = get_material("lines_billboard", p_gizmo); + Ref<Material> icon = get_material("light_omni_icon", p_gizmo); OmniLight *on = Object::cast_to<OmniLight>(light); @@ -941,29 +928,27 @@ void LightSpatialGizmo::redraw() { points.push_back(Vector3(b.x, b.y, 0)); } - add_lines(points, material, true); - add_collision_segments(points); + p_gizmo->add_lines(points, material, true); + p_gizmo->add_collision_segments(points); - add_unscaled_billboard(icon, 0.05); + p_gizmo->add_unscaled_billboard(icon, 0.05); Vector<Vector3> handles; handles.push_back(Vector3(r, 0, 0)); - add_handles(handles, true); + p_gizmo->add_handles(handles, get_material("handles_billboard"), true); } if (Object::cast_to<SpotLight>(light)) { - Ref<Material> material = create_material("light_spot_material", gizmo_color); - Ref<Material> icon = create_icon_material("light_spot_icon", SpatialEditor::get_singleton()->get_icon("GizmoSpotLight", "EditorIcons")); - - clear(); + Ref<Material> material = get_material("lines", p_gizmo); + Ref<Material> icon = get_material("light_spot_icon", p_gizmo); Vector<Vector3> points; - SpotLight *on = Object::cast_to<SpotLight>(light); + SpotLight *sl = Object::cast_to<SpotLight>(light); - float r = on->get_param(Light::PARAM_RANGE); - float w = r * Math::sin(Math::deg2rad(on->get_param(Light::PARAM_SPOT_ANGLE))); - float d = r * Math::cos(Math::deg2rad(on->get_param(Light::PARAM_SPOT_ANGLE))); + float r = sl->get_param(Light::PARAM_RANGE); + float w = r * Math::sin(Math::deg2rad(sl->get_param(Light::PARAM_SPOT_ANGLE))); + float d = r * Math::cos(Math::deg2rad(sl->get_param(Light::PARAM_SPOT_ANGLE))); for (int i = 0; i < 360; i++) { @@ -985,7 +970,7 @@ void LightSpatialGizmo::redraw() { points.push_back(Vector3(0, 0, -r)); points.push_back(Vector3()); - add_lines(points, material); + p_gizmo->add_lines(points, material); Vector<Vector3> handles; handles.push_back(Vector3(0, 0, -r)); @@ -1017,33 +1002,45 @@ void LightSpatialGizmo::redraw() { collision_segments.push_back(Vector3(0, 0, -r)); collision_segments.push_back(Vector3()); - add_handles(handles); - add_collision_segments(collision_segments); - add_unscaled_billboard(icon, 0.05); + p_gizmo->add_handles(handles, get_material("handles")); + p_gizmo->add_collision_segments(collision_segments); + p_gizmo->add_unscaled_billboard(icon, 0.05); } } -LightSpatialGizmo::LightSpatialGizmo(Light *p_light) { +////// + +//// player gizmo +AudioStreamPlayer3DSpatialGizmoPlugin::AudioStreamPlayer3DSpatialGizmoPlugin() { + + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1)); - light = p_light; - set_spatial_node(p_light); + create_icon_material("stream_player_3d_icon", SpatialEditor::get_singleton()->get_icon("GizmoSpatialSamplePlayer", "EditorIcons")); + create_material("stream_player_3d_material", gizmo_color); + create_handle_material("handles"); } -////// +bool AudioStreamPlayer3DSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<AudioStreamPlayer3D>(p_spatial) != NULL; +} -//// player gizmo +String AudioStreamPlayer3DSpatialGizmoPlugin::get_name() const { + return "AudioStreamPlayer3D"; +} -String AudioStreamPlayer3DSpatialGizmo::get_handle_name(int p_idx) const { +String AudioStreamPlayer3DSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { return "Emission Radius"; } -Variant AudioStreamPlayer3DSpatialGizmo::get_handle_value(int p_idx) const { - +Variant AudioStreamPlayer3DSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node()); return player->get_emission_angle(); } -void AudioStreamPlayer3DSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { +void AudioStreamPlayer3DSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node()); Transform gt = player->get_global_transform(); gt.orthonormalize(); @@ -1081,7 +1078,9 @@ void AudioStreamPlayer3DSpatialGizmo::set_handle(int p_idx, Camera *p_camera, co } } -void AudioStreamPlayer3DSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { +void AudioStreamPlayer3DSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node()); if (p_cancel) { @@ -1097,16 +1096,17 @@ void AudioStreamPlayer3DSpatialGizmo::commit_handle(int p_idx, const Variant &p_ } } -void AudioStreamPlayer3DSpatialGizmo::redraw() { +void AudioStreamPlayer3DSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { - clear(); + AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); - Ref<Material> icon = create_icon_material("stream_player_3d_material", SpatialEditor::get_singleton()->get_icon("GizmoSpatialSamplePlayer", "EditorIcons")); + Ref<Material> icon = get_material("stream_player_3d_icon", p_gizmo); if (player->is_emission_angle_enabled()) { - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/stream_player_3d"); - Ref<Material> material = create_material("stream_player_3d_material", gizmo_color); + Ref<Material> material = get_material("stream_player_3d_material", p_gizmo); float pc = player->get_emission_angle(); @@ -1138,27 +1138,40 @@ void AudioStreamPlayer3DSpatialGizmo::redraw() { points.write[200 + i * 2 + 1] = Vector3(); } - add_lines(points, material); - add_collision_segments(points); + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(points); Vector<Vector3> handles; float ha = Math::deg2rad(player->get_emission_angle()); handles.push_back(Vector3(Math::sin(ha), 0, -Math::cos(ha))); - add_handles(handles); + p_gizmo->add_handles(handles, get_material("handles")); } - add_unscaled_billboard(icon, 0.05); + p_gizmo->add_unscaled_billboard(icon, 0.05); } -AudioStreamPlayer3DSpatialGizmo::AudioStreamPlayer3DSpatialGizmo(AudioStreamPlayer3D *p_player) { +////// + +CameraSpatialGizmoPlugin::CameraSpatialGizmoPlugin() { + + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8)); - player = p_player; - set_spatial_node(p_player); + create_material("camera_material", gizmo_color); + create_icon_material("camera_icon", SpatialEditor::get_singleton()->get_icon("GizmoCamera", "EditorIcons")); + create_handle_material("handles"); } -////// +bool CameraSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<Camera>(p_spatial) != NULL; +} + +String CameraSpatialGizmoPlugin::get_name() const { + return "Camera"; +} -String CameraSpatialGizmo::get_handle_name(int p_idx) const { +String CameraSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + + Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node()); if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) { return "FOV"; @@ -1166,7 +1179,10 @@ String CameraSpatialGizmo::get_handle_name(int p_idx) const { return "Size"; } } -Variant CameraSpatialGizmo::get_handle_value(int p_idx) const { + +Variant CameraSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + + Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node()); if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) { return camera->get_fov(); @@ -1175,7 +1191,10 @@ Variant CameraSpatialGizmo::get_handle_value(int p_idx) const { return camera->get_size(); } } -void CameraSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { + +void CameraSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node()); Transform gt = camera->get_global_transform(); gt.orthonormalize(); @@ -1201,7 +1220,10 @@ void CameraSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p camera->set("size", d); } } -void CameraSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { + +void CameraSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node()); if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) { @@ -1231,16 +1253,17 @@ void CameraSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool } } -void CameraSpatialGizmo::redraw() { +void CameraSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { - clear(); + Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); Vector<Vector3> lines; Vector<Vector3> handles; - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/camera"); - Ref<Material> material = create_material("camera_material", gizmo_color); - Ref<Material> icon = create_icon_material("camera_icon", SpatialEditor::get_singleton()->get_icon("GizmoCamera", "EditorIcons")); + Ref<Material> material = get_material("camera_material", p_gizmo); + Ref<Material> icon = get_material("camera_icon", p_gizmo); switch (camera->get_projection()) { @@ -1310,71 +1333,81 @@ void CameraSpatialGizmo::redraw() { } break; } - add_lines(lines, material); - add_collision_segments(lines); - add_unscaled_billboard(icon, 0.05); - add_handles(handles); + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + p_gizmo->add_unscaled_billboard(icon, 0.05); + p_gizmo->add_handles(handles, get_material("handles")); } -CameraSpatialGizmo::CameraSpatialGizmo(Camera *p_camera) { +////// - camera = p_camera; - set_spatial_node(camera); +MeshInstanceSpatialGizmoPlugin::MeshInstanceSpatialGizmoPlugin() { } -////// +bool MeshInstanceSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<MeshInstance>(p_spatial) != NULL && Object::cast_to<SoftBody>(p_spatial) == NULL; +} -bool MeshInstanceSpatialGizmo::can_draw() const { - return true; //mesh can always draw (even though nothing is displayed) +String MeshInstanceSpatialGizmoPlugin::get_name() const { + return "MeshInstance"; } -void MeshInstanceSpatialGizmo::redraw() { - clear(); +bool MeshInstanceSpatialGizmoPlugin::can_be_hidden() const { + return false; +} + +void MeshInstanceSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + MeshInstance *mesh = Object::cast_to<MeshInstance>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); Ref<Mesh> m = mesh->get_mesh(); + if (!m.is_valid()) return; //none Ref<TriangleMesh> tm = m->generate_triangle_mesh(); if (tm.is_valid()) { - add_collision_triangles(tm); + p_gizmo->add_collision_triangles(tm); } } -MeshInstanceSpatialGizmo::MeshInstanceSpatialGizmo(MeshInstance *p_mesh) { +///// +Sprite3DSpatialGizmoPlugin::Sprite3DSpatialGizmoPlugin() { +} - mesh = p_mesh; - set_spatial_node(p_mesh); +bool Sprite3DSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<Sprite3D>(p_spatial) != NULL; } -///// +String Sprite3DSpatialGizmoPlugin::get_name() const { + return "Sprite3D"; +} -bool Sprite3DSpatialGizmo::can_draw() const { - return true; +bool Sprite3DSpatialGizmoPlugin::can_be_hidden() const { + return false; } -void Sprite3DSpatialGizmo::redraw() { - clear(); +void Sprite3DSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + Sprite3D *sprite = Object::cast_to<Sprite3D>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); Ref<TriangleMesh> tm = sprite->generate_triangle_mesh(); if (tm.is_valid()) { - add_collision_triangles(tm); + p_gizmo->add_collision_triangles(tm); } } -Sprite3DSpatialGizmo::Sprite3DSpatialGizmo(SpriteBase3D *p_sprite) { - - sprite = p_sprite; - set_spatial_node(p_sprite); -} - /// -void Position3DSpatialGizmo::redraw() { +Position3DSpatialGizmoPlugin::Position3DSpatialGizmoPlugin() { + pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); + cursor_points = Vector<Vector3>(); - clear(); - add_mesh(SpatialEditorGizmos::singleton->pos3d_mesh); - Vector<Vector3> cursor_points; + PoolVector<Color> cursor_colors; float cs = 0.25; cursor_points.push_back(Vector3(+cs, 0, 0)); cursor_points.push_back(Vector3(-cs, 0, 0)); @@ -1382,51 +1415,65 @@ void Position3DSpatialGizmo::redraw() { cursor_points.push_back(Vector3(0, -cs, 0)); cursor_points.push_back(Vector3(0, 0, +cs)); cursor_points.push_back(Vector3(0, 0, -cs)); - add_collision_segments(cursor_points); + cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7)); + cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7)); + cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7)); + cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7)); + cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7)); + cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7)); + + Ref<SpatialMaterial> mat = memnew(SpatialMaterial); + mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + mat->set_line_width(3); + Array d; + d.resize(VS::ARRAY_MAX); + d[Mesh::ARRAY_VERTEX] = cursor_points; + d[Mesh::ARRAY_COLOR] = cursor_colors; + pos3d_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d); + pos3d_mesh->surface_set_material(0, mat); } -Position3DSpatialGizmo::Position3DSpatialGizmo(Position3D *p_p3d) { +bool Position3DSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<Position3D>(p_spatial) != NULL; +} + +String Position3DSpatialGizmoPlugin::get_name() const { + return "Position3D"; +} + +void Position3DSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { - p3d = p_p3d; - set_spatial_node(p3d); + p_gizmo->clear(); + p_gizmo->add_mesh(pos3d_mesh); + p_gizmo->add_collision_segments(cursor_points); } ///// -void SkeletonSpatialGizmo::redraw() { +SkeletonSpatialGizmoPlugin::SkeletonSpatialGizmoPlugin() { - clear(); + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4)); + create_material("skeleton_material", gizmo_color); +} - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/skeleton"); - Ref<Material> material = create_material("skeleton_material", gizmo_color); - SpatialMaterial *sm = Object::cast_to<SpatialMaterial>(material.ptr()); - - { // Reset - Color c(sm->get_albedo()); - c.a = 1; - sm->set_albedo(c); - } - if (sm) { - switch (SpatialEditor::get_singleton()->get_skeleton_visibility_state()) { - case 0: { - // Hidden - Color c(sm->get_albedo()); - c.a = 0; - sm->set_albedo(c); - sm->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - } break; - case 1: - // Visible - sm->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, false); - sm->set_render_priority(SpatialMaterial::RENDER_PRIORITY_MIN); - sm->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, false); - break; - case 2: - // x-ray - sm->set_on_top_of_alpha(); - break; - } - } +bool SkeletonSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<Skeleton>(p_spatial) != NULL; +} + +String SkeletonSpatialGizmoPlugin::get_name() const { + return "Skeleton"; +} + +void SkeletonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + Skeleton *skel = Object::cast_to<Skeleton>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); + + Ref<Material> material = get_material("skeleton_material", p_gizmo); Ref<SurfaceTool> surface_tool(memnew(SurfaceTool)); @@ -1452,7 +1499,9 @@ void SkeletonSpatialGizmo::redraw() { Color bonecolor = Color(1.0, 0.4, 0.4, 0.3); Color rootcolor = Color(0.4, 1.0, 0.4, 0.1); - for (int i = 0; i < skel->get_bone_count(); i++) { + for (int i_bone = 0; i_bone < skel->get_bone_count(); i_bone++) { + + int i = skel->get_process_order(i_bone); int parent = skel->get_bone_parent(i); @@ -1604,24 +1653,28 @@ void SkeletonSpatialGizmo::redraw() { } Ref<ArrayMesh> m = surface_tool->commit(); - add_mesh(m, false, skel->get_skeleton()); + p_gizmo->add_mesh(m, false, skel->get_skeleton()); } -SkeletonSpatialGizmo::SkeletonSpatialGizmo(Skeleton *p_skel) { +//// + +PhysicalBoneSpatialGizmoPlugin::PhysicalBoneSpatialGizmoPlugin() { + create_material("joint_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1))); +} - skel = p_skel; - set_spatial_node(p_skel); +bool PhysicalBoneSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<PhysicalBone>(p_spatial) != NULL; } -PhysicalBoneSpatialGizmo::PhysicalBoneSpatialGizmo(PhysicalBone *p_pb) : - EditorSpatialGizmo(), - physical_bone(p_pb) { - set_spatial_node(p_pb); +String PhysicalBoneSpatialGizmoPlugin::get_name() const { + return "PhysicalBones"; } -void PhysicalBoneSpatialGizmo::redraw() { +void PhysicalBoneSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { - clear(); + p_gizmo->clear(); + + PhysicalBone *physical_bone = Object::cast_to<PhysicalBone>(p_gizmo->get_spatial_node()); if (!physical_bone) return; @@ -1635,26 +1688,25 @@ void PhysicalBoneSpatialGizmo::redraw() { switch (physical_bone->get_joint_type()) { case PhysicalBone::JOINT_TYPE_PIN: { - PinJointSpatialGizmo::CreateGizmo(physical_bone->get_joint_offset(), points); + JointSpatialGizmoPlugin::CreatePinJointGizmo(physical_bone->get_joint_offset(), points); } break; case PhysicalBone::JOINT_TYPE_CONE: { const PhysicalBone::ConeJointData *cjd(static_cast<const PhysicalBone::ConeJointData *>(physical_bone->get_joint_data())); - ConeTwistJointSpatialGizmo::CreateGizmo( + JointSpatialGizmoPlugin::CreateConeTwistJointGizmo( physical_bone->get_joint_offset(), physical_bone->get_global_transform() * physical_bone->get_joint_offset(), pb ? pb->get_global_transform() : Transform(), pbp ? pbp->get_global_transform() : Transform(), cjd->swing_span, cjd->twist_span, - points, pb ? &points : NULL, pbp ? &points : NULL); } break; case PhysicalBone::JOINT_TYPE_HINGE: { const PhysicalBone::HingeJointData *hjd(static_cast<const PhysicalBone::HingeJointData *>(physical_bone->get_joint_data())); - HingeJointSpatialGizmo::CreateGizmo( + JointSpatialGizmoPlugin::CreateHingeJointGizmo( physical_bone->get_joint_offset(), physical_bone->get_global_transform() * physical_bone->get_joint_offset(), pb ? pb->get_global_transform() : Transform(), @@ -1669,7 +1721,7 @@ void PhysicalBoneSpatialGizmo::redraw() { case PhysicalBone::JOINT_TYPE_SLIDER: { const PhysicalBone::SliderJointData *sjd(static_cast<const PhysicalBone::SliderJointData *>(physical_bone->get_joint_data())); - SliderJointSpatialGizmo::CreateGizmo( + JointSpatialGizmoPlugin::CreateSliderJointGizmo( physical_bone->get_joint_offset(), physical_bone->get_global_transform() * physical_bone->get_joint_offset(), pb ? pb->get_global_transform() : Transform(), @@ -1685,7 +1737,7 @@ void PhysicalBoneSpatialGizmo::redraw() { case PhysicalBone::JOINT_TYPE_6DOF: { const PhysicalBone::SixDOFJointData *sdofjd(static_cast<const PhysicalBone::SixDOFJointData *>(physical_bone->get_joint_data())); - Generic6DOFJointSpatialGizmo::CreateGizmo( + JointSpatialGizmoPlugin::CreateGeneric6DOFJointGizmo( physical_bone->get_joint_offset(), physical_bone->get_global_transform() * physical_bone->get_joint_offset(), @@ -1721,14 +1773,15 @@ void PhysicalBoneSpatialGizmo::redraw() { return; } - Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); + Ref<Material> material = get_material("joint_material", p_gizmo); - add_collision_segments(points); - add_lines(points, material); + p_gizmo->add_collision_segments(points); + p_gizmo->add_lines(points, material); } // FIXME: Kept as reference for reimplementation in 3.1+ #if 0 + void RoomSpatialGizmo::redraw() { clear(); @@ -1745,41 +1798,41 @@ void RoomSpatialGizmo::redraw() { for (int i = 0; i < fc; i++) { - Vector3 fn = r[i].get_plane().normal; + Vector3 fn = r[i].get_plane().normal; - for (int j = 0; j < 3; j++) { + for (int j = 0; j < 3; j++) { - _EdgeKey ek; - ek.from = r[i].vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); - ek.to = r[i].vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); - if (ek.from < ek.to) - SWAP(ek.from, ek.to); + _EdgeKey ek; + ek.from = r[i].vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); + ek.to = r[i].vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); + if (ek.from < ek.to) + SWAP(ek.from, ek.to); - Map<_EdgeKey, Vector3>::Element *E = edge_map.find(ek); + Map<_EdgeKey, Vector3>::Element *E = edge_map.find(ek); - if (E) { + if (E) { - if (E->get().dot(fn) > 0.9) { + if (E->get().dot(fn) > 0.9) { - E->get() = Vector3(); - } + E->get() = Vector3(); + } - } else { + } else { - edge_map[ek] = fn; - } + edge_map[ek] = fn; + } + } } - } for (Map<_EdgeKey, Vector3>::Element *E = edge_map.front(); E; E = E->next()) { - if (E->get() != Vector3()) { - lines.push_back(E->key().from); - lines.push_back(E->key().to); + if (E->get() != Vector3()) { + lines.push_back(E->key().from); + lines.push_back(E->key().to); + } } - } - add_lines(lines, SpatialEditorGizmos::singleton->room_material); + add_lines(lines, EditorSpatialGizmos::singleton->room_material); add_collision_segments(lines); } @@ -1797,31 +1850,31 @@ void PortalSpatialGizmo::redraw() { Vector<Point2> points = portal->get_shape(); if (points.size() == 0) { - return; - } + return; + } Vector<Vector3> lines; Vector3 center; for (int i = 0; i < points.size(); i++) { - Vector3 f; - f.x = points[i].x; - f.y = points[i].y; - Vector3 fn; - fn.x = points[(i + 1) % points.size()].x; - fn.y = points[(i + 1) % points.size()].y; - center += f; + Vector3 f; + f.x = points[i].x; + f.y = points[i].y; + Vector3 fn; + fn.x = points[(i + 1) % points.size()].x; + fn.y = points[(i + 1) % points.size()].y; + center += f; - lines.push_back(f); - lines.push_back(fn); - } + lines.push_back(f); + lines.push_back(fn); + } center /= points.size(); lines.push_back(center); lines.push_back(center + Vector3(0, 0, 1)); - add_lines(lines, SpatialEditorGizmos::singleton->portal_material); + add_lines(lines, EditorSpatialGizmos::singleton->portal_material); add_collision_segments(lines); } @@ -1834,33 +1887,58 @@ PortalSpatialGizmo::PortalSpatialGizmo(Portal *p_portal) { #endif ///// -void RayCastSpatialGizmo::redraw() { +RayCastSpatialGizmoPlugin::RayCastSpatialGizmoPlugin() { - clear(); + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); + create_material("shape_material", gizmo_color); +} + +bool RayCastSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<RayCast>(p_spatial) != NULL; +} + +String RayCastSpatialGizmoPlugin::get_name() const { + return "RayCast"; +} + +void RayCastSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + RayCast *raycast = Object::cast_to<RayCast>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); Vector<Vector3> lines; lines.push_back(Vector3()); lines.push_back(raycast->get_cast_to()); - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - Ref<Material> material = create_material("shape_material", gizmo_color); + Ref<SpatialMaterial> material = get_material("shape_material", p_gizmo); - add_lines(lines, material); - add_collision_segments(lines); + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); } -RayCastSpatialGizmo::RayCastSpatialGizmo(RayCast *p_raycast) { +///// + +VehicleWheelSpatialGizmoPlugin::VehicleWheelSpatialGizmoPlugin() { - set_spatial_node(p_raycast); - raycast = p_raycast; + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); + create_material("shape_material", gizmo_color); } -///// +bool VehicleWheelSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<VehicleWheel>(p_spatial) != NULL; +} -void VehicleWheelSpatialGizmo::redraw() { +String VehicleWheelSpatialGizmoPlugin::get_name() const { + return "VehicleWheel"; +} - clear(); +void VehicleWheelSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + VehicleWheel *car_wheel = Object::cast_to<VehicleWheel>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); Vector<Vector3> points; @@ -1904,23 +1982,36 @@ void VehicleWheelSpatialGizmo::redraw() { points.push_back(Vector3(0, -r, r * 2)); points.push_back(Vector3(-r * 2 * 0.2, -r, r * 2 * 0.8)); - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - Ref<Material> material = create_material("shape_material", gizmo_color); + Ref<Material> material = get_material("shape_material", p_gizmo); - add_lines(points, material); - add_collision_segments(points); + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(points); } -VehicleWheelSpatialGizmo::VehicleWheelSpatialGizmo(VehicleWheel *p_car_wheel) { +/////////// - set_spatial_node(p_car_wheel); - car_wheel = p_car_wheel; +SoftBodySpatialGizmoPlugin::SoftBodySpatialGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); + create_material("shape_material", gizmo_color); + create_handle_material("handles"); } -/////////// +bool SoftBodySpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<SoftBody>(p_spatial) != NULL; +} -void SoftBodySpatialGizmo::redraw() { - clear(); +String SoftBodySpatialGizmoPlugin::get_name() const { + return "SoftBody"; +} + +bool SoftBodySpatialGizmoPlugin::is_selectable_when_hidden() const { + return true; +} + +void SoftBodySpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + SoftBody *soft_body = Object::cast_to<SoftBody>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); if (!soft_body || soft_body->get_mesh().is_null()) { return; @@ -1936,84 +2027,840 @@ void SoftBodySpatialGizmo::redraw() { return; } + Ref<TriangleMesh> tm = soft_body->get_mesh()->generate_triangle_mesh(); + Vector<Vector3> points; soft_body->get_mesh()->generate_debug_mesh_indices(points); - soft_body->get_mesh()->clear_cache(); - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - Ref<Material> material = create_material("shape_material", gizmo_color); + Ref<Material> material = get_material("shape_material", p_gizmo); - add_lines(lines, material); - add_collision_segments(lines); - add_handles(points); -} - -bool SoftBodySpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle, bool p_sec_first) { - return EditorSpatialGizmo::intersect_ray(p_camera, p_point, r_pos, r_normal, r_gizmo_handle, p_sec_first); - - /* Perform a shape cast but doesn't work with softbody - PhysicsDirectSpaceState *space_state = PhysicsServer::get_singleton()->space_get_direct_state(SceneTree::get_singleton()->get_root()->get_world()->get_space()); - if (!physics_sphere_shape.is_valid()) { - physics_sphere_shape = PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_SPHERE); - real_t radius = 0.02; - PhysicsServer::get_singleton()->shape_set_data(physics_sphere_shape, radius); - } - - Vector3 sphere_motion(p_camera->project_ray_normal(p_point)); - real_t closest_safe; - real_t closest_unsafe; - PhysicsDirectSpaceState::ShapeRestInfo result; - bool collided = space_state->cast_motion( - physics_sphere_shape, - p_camera->get_transform(), - sphere_motion * Vector3(1000, 1000, 1000), - 0.f, - closest_safe, - closest_unsafe, - Set<RID>(), - 0xFFFFFFFF, - 0xFFFFFFFF, - &result); - - if (collided) { - - if (result.collider_id == soft_body->get_instance_id()) { - print_line("Collided"); - } else { - print_line("Collided but with wrong object: " + itos(result.collider_id)); - } - } else { - print_line("Not collided, motion: x: " + rtos(sphere_motion[0]) + " y: " + rtos(sphere_motion[1]) + " z: " + rtos(sphere_motion[2])); - } - return false; - */ + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + p_gizmo->add_handles(points, get_material("handles")); + p_gizmo->add_collision_triangles(tm); +} + +String SoftBodySpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + return "SoftBody pin point"; +} + +Variant SoftBodySpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + SoftBody *soft_body = Object::cast_to<SoftBody>(p_gizmo->get_spatial_node()); + return Variant(soft_body->is_point_pinned(p_idx)); } -void SoftBodySpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { +void SoftBodySpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + SoftBody *soft_body = Object::cast_to<SoftBody>(p_gizmo->get_spatial_node()); soft_body->pin_point_toggle(p_idx); - redraw(); } -bool SoftBodySpatialGizmo::is_gizmo_handle_highlighted(int idx) const { +bool SoftBodySpatialGizmoPlugin::is_gizmo_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int idx) const { + SoftBody *soft_body = Object::cast_to<SoftBody>(p_gizmo->get_spatial_node()); return soft_body->is_point_pinned(idx); } -SoftBodySpatialGizmo::SoftBodySpatialGizmo(SoftBody *p_soft_physics_body) : - EditorSpatialGizmo(), - soft_body(p_soft_physics_body) { - set_spatial_node(p_soft_physics_body); +/////////// + +VisibilityNotifierGizmoPlugin::VisibilityNotifierGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7)); + create_material("visibility_notifier_material", gizmo_color); + gizmo_color.a = 0.1; + create_material("visibility_notifier_solid_material", gizmo_color); + create_handle_material("handles"); } -SoftBodySpatialGizmo::~SoftBodySpatialGizmo() { - //if (!physics_sphere_shape.is_valid()) { - // PhysicsServer::get_singleton()->free(physics_sphere_shape); - //} +bool VisibilityNotifierGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<VisibilityNotifier>(p_spatial) != NULL; } -/////////// +String VisibilityNotifierGizmoPlugin::get_name() const { + return "VisibilityNotifier"; +} + +String VisibilityNotifierGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + + switch (p_idx) { + case 0: return "Size X"; + case 1: return "Size Y"; + case 2: return "Size Z"; + case 3: return "Pos X"; + case 4: return "Pos Y"; + case 5: return "Pos Z"; + } + + return ""; +} + +Variant VisibilityNotifierGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + + VisibilityNotifier *notifier = Object::cast_to<VisibilityNotifier>(p_gizmo->get_spatial_node()); + return notifier->get_aabb(); +} +void VisibilityNotifierGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + VisibilityNotifier *notifier = Object::cast_to<VisibilityNotifier>(p_gizmo->get_spatial_node()); + + Transform gt = notifier->get_global_transform(); + + Transform gi = gt.affine_inverse(); + + bool move = p_idx >= 3; + p_idx = p_idx % 3; + + AABB aabb = notifier->get_aabb(); + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; + + Vector3 ofs = aabb.position + aabb.size * 0.5; + + Vector3 axis; + axis[p_idx] = 1.0; + + if (move) { + + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb); + + float d = ra[p_idx]; + + aabb.position[p_idx] = d - 1.0 - aabb.size[p_idx] * 0.5; + notifier->set_aabb(aabb); + + } else { + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb); + + float d = ra[p_idx] - ofs[p_idx]; + if (d < 0.001) + d = 0.001; + //resize + aabb.position[p_idx] = (aabb.position[p_idx] + aabb.size[p_idx] * 0.5) - d; + aabb.size[p_idx] = d * 2; + notifier->set_aabb(aabb); + } +} + +void VisibilityNotifierGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + VisibilityNotifier *notifier = Object::cast_to<VisibilityNotifier>(p_gizmo->get_spatial_node()); + + if (p_cancel) { + notifier->set_aabb(p_restore); + return; + } + + UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Change Notifier AABB")); + ur->add_do_method(notifier, "set_aabb", notifier->get_aabb()); + ur->add_undo_method(notifier, "set_aabb", p_restore); + ur->commit_action(); +} + +void VisibilityNotifierGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + VisibilityNotifier *notifier = Object::cast_to<VisibilityNotifier>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); + + Vector<Vector3> lines; + AABB aabb = notifier->get_aabb(); + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + Vector<Vector3> handles; + + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = aabb.position[i] + aabb.size[i]; + ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5; + ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5; + handles.push_back(ax); + } + + Vector3 center = aabb.position + aabb.size * 0.5; + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = 1.0; + handles.push_back(center + ax); + lines.push_back(center); + lines.push_back(center + ax); + } + + Ref<Material> material = get_material("visibility_notifier_material", p_gizmo); + + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + + if (p_gizmo->is_selected()) { + Ref<Material> solid_material = get_material("visibility_notifier_solid_material", p_gizmo); + p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0); + } + + p_gizmo->add_handles(handles, get_material("handles")); +} + +//// + +ParticlesGizmoPlugin::ParticlesGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4)); + create_material("particles_material", gizmo_color); + gizmo_color.a = 0.1; + create_material("particles_solid_material", gizmo_color); + create_icon_material("particles_icon", SpatialEditor::get_singleton()->get_icon("GizmoParticles", "EditorIcons")); + create_handle_material("handles"); +} + +bool ParticlesGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<Particles>(p_spatial) != NULL; +} + +String ParticlesGizmoPlugin::get_name() const { + return "Particles"; +} + +bool ParticlesGizmoPlugin::is_selectable_when_hidden() const { + return true; +} + +String ParticlesGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + + switch (p_idx) { + case 0: return "Size X"; + case 1: return "Size Y"; + case 2: return "Size Z"; + case 3: return "Pos X"; + case 4: return "Pos Y"; + case 5: return "Pos Z"; + } + + return ""; +} +Variant ParticlesGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + + Particles *particles = Object::cast_to<Particles>(p_gizmo->get_spatial_node()); + return particles->get_visibility_aabb(); +} +void ParticlesGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + Particles *particles = Object::cast_to<Particles>(p_gizmo->get_spatial_node()); + + Transform gt = particles->get_global_transform(); + //gt.orthonormalize(); + Transform gi = gt.affine_inverse(); + + bool move = p_idx >= 3; + p_idx = p_idx % 3; + + AABB aabb = particles->get_visibility_aabb(); + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; + + Vector3 ofs = aabb.position + aabb.size * 0.5; + + Vector3 axis; + axis[p_idx] = 1.0; + + if (move) { + + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb); + + float d = ra[p_idx]; + + aabb.position[p_idx] = d - 1.0 - aabb.size[p_idx] * 0.5; + particles->set_visibility_aabb(aabb); + + } else { + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb); + + float d = ra[p_idx] - ofs[p_idx]; + if (d < 0.001) + d = 0.001; + //resize + aabb.position[p_idx] = (aabb.position[p_idx] + aabb.size[p_idx] * 0.5) - d; + aabb.size[p_idx] = d * 2; + particles->set_visibility_aabb(aabb); + } +} + +void ParticlesGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + Particles *particles = Object::cast_to<Particles>(p_gizmo->get_spatial_node()); + + if (p_cancel) { + particles->set_visibility_aabb(p_restore); + return; + } + + UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Change Particles AABB")); + ur->add_do_method(particles, "set_custom_aabb", particles->get_visibility_aabb()); + ur->add_undo_method(particles, "set_custom_aabb", p_restore); + ur->commit_action(); +} + +void ParticlesGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + Particles *particles = Object::cast_to<Particles>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); + + Vector<Vector3> lines; + AABB aabb = particles->get_visibility_aabb(); + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + Vector<Vector3> handles; + + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = aabb.position[i] + aabb.size[i]; + ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5; + ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5; + handles.push_back(ax); + } + + Vector3 center = aabb.position + aabb.size * 0.5; + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = 1.0; + handles.push_back(center + ax); + lines.push_back(center); + lines.push_back(center + ax); + } + + Ref<Material> material = get_material("particles_material", p_gizmo); + Ref<Material> icon = get_material("particles_icon", p_gizmo); + + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + + if (p_gizmo->is_selected()) { + Ref<Material> solid_material = get_material("particles_solid_material", p_gizmo); + p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0); + } + + p_gizmo->add_handles(handles, get_material("handles")); + p_gizmo->add_unscaled_billboard(icon, 0.05); +} +//// + +ReflectionProbeGizmoPlugin::ReflectionProbeGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5)); + + create_material("reflection_probe_material", gizmo_color); + + gizmo_color.a = 0.5; + create_material("reflection_internal_material", gizmo_color); + + gizmo_color.a = 0.1; + create_material("reflection_probe_solid_material", gizmo_color); + + create_icon_material("reflection_probe_icon", SpatialEditor::get_singleton()->get_icon("GizmoReflectionProbe", "EditorIcons")); + create_handle_material("handles"); +} + +bool ReflectionProbeGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<ReflectionProbe>(p_spatial) != NULL; +} + +String ReflectionProbeGizmoPlugin::get_name() const { + return "ReflectionProbe"; +} + +String ReflectionProbeGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + + switch (p_idx) { + case 0: return "Extents X"; + case 1: return "Extents Y"; + case 2: return "Extents Z"; + case 3: return "Origin X"; + case 4: return "Origin Y"; + case 5: return "Origin Z"; + } + + return ""; +} +Variant ReflectionProbeGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + + ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node()); + return AABB(probe->get_extents(), probe->get_origin_offset()); +} +void ReflectionProbeGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node()); + Transform gt = probe->get_global_transform(); + + Transform gi = gt.affine_inverse(); + + if (p_idx < 3) { + Vector3 extents = probe->get_extents(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; + + Vector3 axis; + axis[p_idx] = 1.0; + + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); + float d = ra[p_idx]; + if (d < 0.001) + d = 0.001; + + extents[p_idx] = d; + probe->set_extents(extents); + } else { + + p_idx -= 3; + + Vector3 origin = probe->get_origin_offset(); + origin[p_idx] = 0; + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; + + Vector3 axis; + axis[p_idx] = 1.0; + + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(origin - axis * 16384, origin + axis * 16384, sg[0], sg[1], ra, rb); + float d = ra[p_idx]; + d += 0.25; + + origin[p_idx] = d; + probe->set_origin_offset(origin); + } +} + +void ReflectionProbeGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node()); + + AABB restore = p_restore; + + if (p_cancel) { + probe->set_extents(restore.position); + probe->set_origin_offset(restore.size); + return; + } + + UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Change Probe Extents")); + ur->add_do_method(probe, "set_extents", probe->get_extents()); + ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset()); + ur->add_undo_method(probe, "set_extents", restore.position); + ur->add_undo_method(probe, "set_origin_offset", restore.size); + ur->commit_action(); +} + +void ReflectionProbeGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); + + Vector<Vector3> lines; + Vector<Vector3> internal_lines; + Vector3 extents = probe->get_extents(); + + AABB aabb; + aabb.position = -extents; + aabb.size = extents * 2; + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + for (int i = 0; i < 8; i++) { + Vector3 ep = aabb.get_endpoint(i); + internal_lines.push_back(probe->get_origin_offset()); + internal_lines.push_back(ep); + } + + Vector<Vector3> handles; + + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = aabb.position[i] + aabb.size[i]; + handles.push_back(ax); + } + + for (int i = 0; i < 3; i++) { + + Vector3 orig_handle = probe->get_origin_offset(); + orig_handle[i] -= 0.25; + lines.push_back(orig_handle); + handles.push_back(orig_handle); + + orig_handle[i] += 0.5; + lines.push_back(orig_handle); + } + + Ref<Material> material = get_material("reflection_probe_material", p_gizmo); + Ref<Material> material_internal = get_material("reflection_internal_material", p_gizmo); + Ref<Material> icon = get_material("reflection_probe_icon", p_gizmo); + + p_gizmo->add_lines(lines, material); + p_gizmo->add_lines(internal_lines, material_internal); + + if (p_gizmo->is_selected()) { + Ref<Material> solid_material = get_material("reflection_probe_solid_material", p_gizmo); + p_gizmo->add_solid_box(solid_material, probe->get_extents() * 2.0); + } + + p_gizmo->add_unscaled_billboard(icon, 0.05); + p_gizmo->add_collision_segments(lines); + p_gizmo->add_handles(handles, get_material("handles")); +} + +GIProbeGizmoPlugin::GIProbeGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/gi_probe", Color(0.5, 1, 0.6)); + + create_material("gi_probe_material", gizmo_color); + + gizmo_color.a = 0.5; + create_material("gi_probe_internal_material", gizmo_color); + + gizmo_color.a = 0.1; + create_material("gi_probe_solid_material", gizmo_color); + + create_icon_material("gi_probe_icon", SpatialEditor::get_singleton()->get_icon("GizmoGIProbe", "EditorIcons")); + create_handle_material("handles"); +} + +bool GIProbeGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<GIProbe>(p_spatial) != NULL; +} + +String GIProbeGizmoPlugin::get_name() const { + return "GIProbe"; +} + +String GIProbeGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + + switch (p_idx) { + case 0: return "Extents X"; + case 1: return "Extents Y"; + case 2: return "Extents Z"; + } + + return ""; +} +Variant GIProbeGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + + GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node()); + return probe->get_extents(); +} +void GIProbeGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node()); + + Transform gt = probe->get_global_transform(); + //gt.orthonormalize(); + Transform gi = gt.affine_inverse(); + + Vector3 extents = probe->get_extents(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; + + Vector3 axis; + axis[p_idx] = 1.0; + + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); + float d = ra[p_idx]; + if (d < 0.001) + d = 0.001; + + extents[p_idx] = d; + probe->set_extents(extents); +} + +void GIProbeGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node()); + + Vector3 restore = p_restore; + + if (p_cancel) { + probe->set_extents(restore); + return; + } + + UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Change Probe Extents")); + ur->add_do_method(probe, "set_extents", probe->get_extents()); + ur->add_undo_method(probe, "set_extents", restore); + ur->commit_action(); +} + +void GIProbeGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node()); + + Ref<Material> material = get_material("gi_probe_material", p_gizmo); + Ref<Material> icon = get_material("gi_probe_icon", p_gizmo); + Ref<Material> material_internal = get_material("gi_probe_internal_material", p_gizmo); + + p_gizmo->clear(); + + Vector<Vector3> lines; + Vector3 extents = probe->get_extents(); + + static const int subdivs[GIProbe::SUBDIV_MAX] = { 64, 128, 256, 512 }; + + AABB aabb = AABB(-extents, extents * 2); + int subdiv = subdivs[probe->get_subdiv()]; + float cell_size = aabb.get_longest_axis_size() / subdiv; + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + + lines.clear(); + + for (int i = 1; i < subdiv; i++) { + + for (int j = 0; j < 3; j++) { + + if (cell_size * i > aabb.size[j]) { + continue; + } + + Vector2 dir; + dir[j] = 1.0; + Vector2 ta, tb; + int j_n1 = (j + 1) % 3; + int j_n2 = (j + 2) % 3; + ta[j_n1] = 1.0; + tb[j_n2] = 1.0; + + for (int k = 0; k < 4; k++) { + + Vector3 from = aabb.position, to = aabb.position; + from[j] += cell_size * i; + to[j] += cell_size * i; + + if (k & 1) { + to[j_n1] += aabb.size[j_n1]; + } else { + + to[j_n2] += aabb.size[j_n2]; + } + + if (k & 2) { + from[j_n1] += aabb.size[j_n1]; + from[j_n2] += aabb.size[j_n2]; + } + + lines.push_back(from); + lines.push_back(to); + } + } + } + + p_gizmo->add_lines(lines, material_internal); + + Vector<Vector3> handles; + + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = aabb.position[i] + aabb.size[i]; + handles.push_back(ax); + } + + if (p_gizmo->is_selected()) { + Ref<Material> solid_material = get_material("gi_probe_solid_material", p_gizmo); + p_gizmo->add_solid_box(solid_material, aabb.get_size()); + } + + p_gizmo->add_unscaled_billboard(icon, 0.05); + p_gizmo->add_handles(handles, get_material("handles")); +} + +//// + +BakedIndirectLightGizmoPlugin::BakedIndirectLightGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/baked_indirect_light", Color(0.5, 0.6, 1)); + + create_material("baked_indirect_light_material", gizmo_color); + + gizmo_color.a = 0.1; + create_material("baked_indirect_light_internal_material", gizmo_color); + + create_icon_material("baked_indirect_light_icon", SpatialEditor::get_singleton()->get_icon("GizmoBakedLightmap", "EditorIcons")); + create_handle_material("handles"); +} + +String BakedIndirectLightGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + + switch (p_idx) { + case 0: return "Extents X"; + case 1: return "Extents Y"; + case 2: return "Extents Z"; + } + + return ""; +} +Variant BakedIndirectLightGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + + BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node()); + return baker->get_extents(); +} +void BakedIndirectLightGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node()); + + Transform gt = baker->get_global_transform(); + //gt.orthonormalize(); + Transform gi = gt.affine_inverse(); + + Vector3 extents = baker->get_extents(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; + + Vector3 axis; + axis[p_idx] = 1.0; + + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); + float d = ra[p_idx]; + if (d < 0.001) + d = 0.001; + + extents[p_idx] = d; + baker->set_extents(extents); +} + +void BakedIndirectLightGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node()); + + Vector3 restore = p_restore; + + if (p_cancel) { + baker->set_extents(restore); + return; + } + + UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Change Probe Extents")); + ur->add_do_method(baker, "set_extents", baker->get_extents()); + ur->add_undo_method(baker, "set_extents", restore); + ur->commit_action(); +} + +bool BakedIndirectLightGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<BakedLightmap>(p_spatial) != NULL; +} + +String BakedIndirectLightGizmoPlugin::get_name() const { + return "BakedLightmap"; +} + +void BakedIndirectLightGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node()); + + Ref<Material> material = get_material("baked_indirect_light_material", p_gizmo); + Ref<Material> icon = get_material("baked_indirect_light_icon", p_gizmo); + Ref<Material> material_internal = get_material("baked_indirect_light_internal_material", p_gizmo); + + p_gizmo->clear(); + + Vector<Vector3> lines; + Vector3 extents = baker->get_extents(); + + AABB aabb = AABB(-extents, extents * 2); + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + + Vector<Vector3> handles; + + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = aabb.position[i] + aabb.size[i]; + handles.push_back(ax); + } + + if (p_gizmo->is_selected()) { + p_gizmo->add_solid_box(material_internal, aabb.get_size()); + } + + p_gizmo->add_unscaled_billboard(icon, 0.05); + p_gizmo->add_handles(handles, get_material("handles")); +} + +//// + +CollisionShapeSpatialGizmoPlugin::CollisionShapeSpatialGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); + create_material("shape_material", gizmo_color); + create_handle_material("handles"); +} + +bool CollisionShapeSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<CollisionShape>(p_spatial) != NULL; +} + +String CollisionShapeSpatialGizmoPlugin::get_name() const { + return "CollisionShape"; +} -String CollisionShapeSpatialGizmo::get_handle_name(int p_idx) const { +String CollisionShapeSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + + const CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node()); Ref<Shape> s = cs->get_shape(); if (s.is_null()) @@ -2046,7 +2893,10 @@ String CollisionShapeSpatialGizmo::get_handle_name(int p_idx) const { return ""; } -Variant CollisionShapeSpatialGizmo::get_handle_value(int p_idx) const { + +Variant CollisionShapeSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + + CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node()); Ref<Shape> s = cs->get_shape(); if (s.is_null()) @@ -2084,7 +2934,10 @@ Variant CollisionShapeSpatialGizmo::get_handle_value(int p_idx) const { return Variant(); } -void CollisionShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { +void CollisionShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node()); + Ref<Shape> s = cs->get_shape(); if (s.is_null()) return; @@ -2175,7 +3028,10 @@ void CollisionShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const P cs->set_height(d * 2.0); } } -void CollisionShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { +void CollisionShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node()); + Ref<Shape> s = cs->get_shape(); if (s.is_null()) return; @@ -2252,7 +3108,11 @@ void CollisionShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_resto ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); ur->add_undo_method(ss.ptr(), "set_radius", p_restore); } else { - ur->create_action(TTR("Change Cylinder Shape Height")); + ur->create_action( + /// + + //////// + TTR("Change Cylinder Shape Height")); ur->add_do_method(ss.ptr(), "set_height", ss->get_height()); ur->add_undo_method(ss.ptr(), "set_height", p_restore); } @@ -2275,16 +3135,18 @@ void CollisionShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_resto ur->commit_action(); } } -void CollisionShapeSpatialGizmo::redraw() { +void CollisionShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { - clear(); + CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); Ref<Shape> s = cs->get_shape(); if (s.is_null()) return; - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - Ref<Material> material = create_material("shape_material", gizmo_color); + Ref<Material> material = get_material("shape_material", p_gizmo); + Ref<Material> handles_material = get_material("handles"); if (Object::cast_to<SphereShape>(*s)) { @@ -2325,11 +3187,11 @@ void CollisionShapeSpatialGizmo::redraw() { collision_segments.push_back(Vector3(b.x, b.y, 0)); } - add_lines(points, material); - add_collision_segments(collision_segments); + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(collision_segments); Vector<Vector3> handles; handles.push_back(Vector3(r, 0, 0)); - add_handles(handles); + p_gizmo->add_handles(handles, handles_material); } if (Object::cast_to<BoxShape>(*s)) { @@ -2356,9 +3218,9 @@ void CollisionShapeSpatialGizmo::redraw() { handles.push_back(ax); } - add_lines(lines, material); - add_collision_segments(lines); - add_handles(handles); + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + p_gizmo->add_handles(handles, handles_material); } if (Object::cast_to<CapsuleShape>(*s)) { @@ -2397,7 +3259,7 @@ void CollisionShapeSpatialGizmo::redraw() { points.push_back(Vector3(b.y, 0, b.x) + dud); } - add_lines(points, material); + p_gizmo->add_lines(points, material); Vector<Vector3> collision_segments; @@ -2428,12 +3290,12 @@ void CollisionShapeSpatialGizmo::redraw() { collision_segments.push_back(Vector3(b.y, 0, b.x) + dud); } - add_collision_segments(collision_segments); + p_gizmo->add_collision_segments(collision_segments); Vector<Vector3> handles; handles.push_back(Vector3(cs->get_radius(), 0, 0)); handles.push_back(Vector3(0, 0, cs->get_height() * 0.5 + cs->get_radius())); - add_handles(handles); + p_gizmo->add_handles(handles, handles_material); } if (Object::cast_to<CylinderShape>(*s)) { @@ -2465,7 +3327,7 @@ void CollisionShapeSpatialGizmo::redraw() { } } - add_lines(points, material); + p_gizmo->add_lines(points, material); Vector<Vector3> collision_segments; @@ -2489,12 +3351,12 @@ void CollisionShapeSpatialGizmo::redraw() { } } - add_collision_segments(collision_segments); + p_gizmo->add_collision_segments(collision_segments); Vector<Vector3> handles; handles.push_back(Vector3(cs->get_radius(), 0, 0)); handles.push_back(Vector3(0, cs->get_height() * 0.5, 0)); - add_handles(handles); + p_gizmo->add_handles(handles, handles_material); } if (Object::cast_to<PlaneShape>(*s)) { @@ -2524,8 +3386,8 @@ void CollisionShapeSpatialGizmo::redraw() { points.push_back(p.normal * p.d); points.push_back(p.normal * p.d + p.normal * 3); - add_lines(points, material); - add_collision_segments(points); + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(points); } if (Object::cast_to<ConvexPolygonShape>(*s)) { @@ -2546,8 +3408,8 @@ void CollisionShapeSpatialGizmo::redraw() { points.write[i * 2 + 1] = md.vertices[md.edges[i].b]; } - add_lines(points, material); - add_collision_segments(points); + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(points); } } } @@ -2559,24 +3421,34 @@ void CollisionShapeSpatialGizmo::redraw() { Vector<Vector3> points; points.push_back(Vector3()); points.push_back(Vector3(0, 0, rs->get_length())); - add_lines(points, material); - add_collision_segments(points); + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(points); Vector<Vector3> handles; handles.push_back(Vector3(0, 0, rs->get_length())); - add_handles(handles); + p_gizmo->add_handles(handles, handles_material); } } -CollisionShapeSpatialGizmo::CollisionShapeSpatialGizmo(CollisionShape *p_cs) { - cs = p_cs; - set_spatial_node(p_cs); +///// + +CollisionPolygonSpatialGizmoPlugin::CollisionPolygonSpatialGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); + create_material("shape_material", gizmo_color); } -///// +bool CollisionPolygonSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<CollisionPolygon>(p_spatial) != NULL; +} -void CollisionPolygonSpatialGizmo::redraw() { +String CollisionPolygonSpatialGizmoPlugin::get_name() const { + return "CollisionPolygon"; +} - clear(); +void CollisionPolygonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + CollisionPolygon *polygon = Object::cast_to<CollisionPolygon>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); Vector<Vector2> points = polygon->get_polygon(); float depth = polygon->get_depth() * 0.5; @@ -2593,695 +3465,39 @@ void CollisionPolygonSpatialGizmo::redraw() { lines.push_back(Vector3(points[i].x, points[i].y, -depth)); } - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - Ref<Material> material = create_material("shape_material", gizmo_color); - - add_lines(lines, material); - add_collision_segments(lines); -} - -CollisionPolygonSpatialGizmo::CollisionPolygonSpatialGizmo(CollisionPolygon *p_polygon) { - - set_spatial_node(p_polygon); - polygon = p_polygon; -} -/// - -String VisibilityNotifierGizmo::get_handle_name(int p_idx) const { - - switch (p_idx) { - case 0: return "X"; - case 1: return "Y"; - case 2: return "Z"; - } - - return ""; -} -Variant VisibilityNotifierGizmo::get_handle_value(int p_idx) const { - - return notifier->get_aabb(); -} -void VisibilityNotifierGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { - - Transform gt = notifier->get_global_transform(); - //gt.orthonormalize(); - Transform gi = gt.affine_inverse(); - - AABB aabb = notifier->get_aabb(); - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; - Vector3 ofs = aabb.position + aabb.size * 0.5; - - Vector3 axis; - axis[p_idx] = 1.0; - - Vector3 ra, rb; - Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb); - float d = ra[p_idx]; - if (d < 0.001) - d = 0.001; - - aabb.position[p_idx] = (aabb.position[p_idx] + aabb.size[p_idx] * 0.5) - d; - aabb.size[p_idx] = d * 2; - notifier->set_aabb(aabb); -} - -void VisibilityNotifierGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { - - if (p_cancel) { - notifier->set_aabb(p_restore); - return; - } - - UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Change Notifier Extents")); - ur->add_do_method(notifier, "set_aabb", notifier->get_aabb()); - ur->add_undo_method(notifier, "set_aabb", p_restore); - ur->commit_action(); -} - -void VisibilityNotifierGizmo::redraw() { - - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/visibility_notifier"); - Ref<Material> material = create_material("visibility_notifier_material", gizmo_color); - - clear(); - - Vector<Vector3> lines; - AABB aabb = notifier->get_aabb(); - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - Vector<Vector3> handles; - - for (int i = 0; i < 3; i++) { - - Vector3 ax; - ax[i] = aabb.position[i] + aabb.size[i]; - handles.push_back(ax); - } - - add_lines(lines, material); - //add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05); - add_collision_segments(lines); - add_handles(handles); -} -VisibilityNotifierGizmo::VisibilityNotifierGizmo(VisibilityNotifier *p_notifier) { - - notifier = p_notifier; - set_spatial_node(p_notifier); -} - -//////// - -/// - -String ParticlesGizmo::get_handle_name(int p_idx) const { - - switch (p_idx) { - case 0: return "Size X"; - case 1: return "Size Y"; - case 2: return "Size Z"; - case 3: return "Pos X"; - case 4: return "Pos Y"; - case 5: return "Pos Z"; - } - - return ""; -} -Variant ParticlesGizmo::get_handle_value(int p_idx) const { - - return particles->get_visibility_aabb(); -} -void ParticlesGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { - - Transform gt = particles->get_global_transform(); - //gt.orthonormalize(); - Transform gi = gt.affine_inverse(); - - bool move = p_idx >= 3; - p_idx = p_idx % 3; - - AABB aabb = particles->get_visibility_aabb(); - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; - - Vector3 ofs = aabb.position + aabb.size * 0.5; - - Vector3 axis; - axis[p_idx] = 1.0; - - if (move) { - - Vector3 ra, rb; - Geometry::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb); - - float d = ra[p_idx]; - - aabb.position[p_idx] = d - 1.0 - aabb.size[p_idx] * 0.5; - particles->set_visibility_aabb(aabb); - - } else { - Vector3 ra, rb; - Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb); - - float d = ra[p_idx] - ofs[p_idx]; - if (d < 0.001) - d = 0.001; - //resize - aabb.position[p_idx] = (aabb.position[p_idx] + aabb.size[p_idx] * 0.5) - d; - aabb.size[p_idx] = d * 2; - particles->set_visibility_aabb(aabb); - } -} - -void ParticlesGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { - - if (p_cancel) { - particles->set_visibility_aabb(p_restore); - return; - } - - UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Change Particles AABB")); - ur->add_do_method(particles, "set_custom_aabb", particles->get_visibility_aabb()); - ur->add_undo_method(particles, "set_custom_aabb", p_restore); - ur->commit_action(); -} - -void ParticlesGizmo::redraw() { - - clear(); - - Vector<Vector3> lines; - AABB aabb = particles->get_visibility_aabb(); - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - Vector<Vector3> handles; - - for (int i = 0; i < 3; i++) { - - Vector3 ax; - ax[i] = aabb.position[i] + aabb.size[i]; - ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5; - ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5; - handles.push_back(ax); - } - - Vector3 center = aabb.position + aabb.size * 0.5; - for (int i = 0; i < 3; i++) { - - Vector3 ax; - ax[i] = 1.0; - handles.push_back(center + ax); - lines.push_back(center); - lines.push_back(center + ax); - } - - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/particles"); - Ref<Material> material = create_material("particles_material", gizmo_color); - Ref<Material> icon = create_icon_material("particles_icon", SpatialEditor::get_singleton()->get_icon("GizmoParticles", "EditorIcons")); - - add_lines(lines, material); - add_collision_segments(lines); - - if (is_selected()) { - - gizmo_color.a = 0.1; - Ref<Material> solid_material = create_material("particles_solid_material", gizmo_color); - add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0); - } - - //add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05); + Ref<Material> material = get_material("shape_material", p_gizmo); - add_handles(handles); - add_unscaled_billboard(icon, 0.05); + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); } -ParticlesGizmo::ParticlesGizmo(Particles *p_particles) { - particles = p_particles; - set_spatial_node(p_particles); -} - -//////// - -/// - -String ReflectionProbeGizmo::get_handle_name(int p_idx) const { - - switch (p_idx) { - case 0: return "Extents X"; - case 1: return "Extents Y"; - case 2: return "Extents Z"; - case 3: return "Origin X"; - case 4: return "Origin Y"; - case 5: return "Origin Z"; - } - - return ""; -} -Variant ReflectionProbeGizmo::get_handle_value(int p_idx) const { - - return AABB(probe->get_extents(), probe->get_origin_offset()); -} -void ReflectionProbeGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { - - Transform gt = probe->get_global_transform(); - //gt.orthonormalize(); - Transform gi = gt.affine_inverse(); - - if (p_idx < 3) { - Vector3 extents = probe->get_extents(); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; - - Vector3 axis; - axis[p_idx] = 1.0; - - Vector3 ra, rb; - Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); - float d = ra[p_idx]; - if (d < 0.001) - d = 0.001; - - extents[p_idx] = d; - probe->set_extents(extents); - } else { - - p_idx -= 3; - - Vector3 origin = probe->get_origin_offset(); - origin[p_idx] = 0; - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; - - Vector3 axis; - axis[p_idx] = 1.0; - - Vector3 ra, rb; - Geometry::get_closest_points_between_segments(origin - axis * 16384, origin + axis * 16384, sg[0], sg[1], ra, rb); - float d = ra[p_idx]; - d += 0.25; - - origin[p_idx] = d; - probe->set_origin_offset(origin); - } -} - -void ReflectionProbeGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { - - AABB restore = p_restore; - - if (p_cancel) { - probe->set_extents(restore.position); - probe->set_origin_offset(restore.size); - return; - } - - UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Change Probe Extents")); - ur->add_do_method(probe, "set_extents", probe->get_extents()); - ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset()); - ur->add_undo_method(probe, "set_extents", restore.position); - ur->add_undo_method(probe, "set_origin_offset", restore.size); - ur->commit_action(); -} - -void ReflectionProbeGizmo::redraw() { - - clear(); - - Vector<Vector3> lines; - Vector<Vector3> internal_lines; - Vector3 extents = probe->get_extents(); - - AABB aabb; - aabb.position = -extents; - aabb.size = extents * 2; - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - for (int i = 0; i < 8; i++) { - Vector3 ep = aabb.get_endpoint(i); - internal_lines.push_back(probe->get_origin_offset()); - internal_lines.push_back(ep); - } - - Vector<Vector3> handles; - - for (int i = 0; i < 3; i++) { - - Vector3 ax; - ax[i] = aabb.position[i] + aabb.size[i]; - handles.push_back(ax); - } - - for (int i = 0; i < 3; i++) { - - Vector3 orig_handle = probe->get_origin_offset(); - orig_handle[i] -= 0.25; - lines.push_back(orig_handle); - handles.push_back(orig_handle); - - orig_handle[i] += 0.5; - lines.push_back(orig_handle); - } - - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/reflection_probe"); - Ref<Material> material = create_material("reflection_probe_material", gizmo_color); - Ref<Material> icon = create_icon_material("reflection_probe_icon", SpatialEditor::get_singleton()->get_icon("GizmoReflectionProbe", "EditorIcons")); - - Color gizmo_color_internal = gizmo_color; - gizmo_color_internal.a = 0.5; - Ref<Material> material_internal = create_material("reflection_internal_material", gizmo_color_internal); - - add_lines(lines, material); - add_lines(internal_lines, material_internal); - - if (is_selected()) { - - gizmo_color.a = 0.1; - Ref<Material> solid_material = create_material("reflection_probe_solid_material", gizmo_color); - add_solid_box(solid_material, probe->get_extents() * 2.0); - } - - //add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05); - add_unscaled_billboard(icon, 0.05); - add_collision_segments(lines); - add_handles(handles); -} -ReflectionProbeGizmo::ReflectionProbeGizmo(ReflectionProbe *p_probe) { - - probe = p_probe; - set_spatial_node(p_probe); -} - -//////// - -/// - -String GIProbeGizmo::get_handle_name(int p_idx) const { - - switch (p_idx) { - case 0: return "Extents X"; - case 1: return "Extents Y"; - case 2: return "Extents Z"; - } - - return ""; -} -Variant GIProbeGizmo::get_handle_value(int p_idx) const { - - return probe->get_extents(); -} -void GIProbeGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { - - Transform gt = probe->get_global_transform(); - //gt.orthonormalize(); - Transform gi = gt.affine_inverse(); - - Vector3 extents = probe->get_extents(); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; - - Vector3 axis; - axis[p_idx] = 1.0; - - Vector3 ra, rb; - Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); - float d = ra[p_idx]; - if (d < 0.001) - d = 0.001; - - extents[p_idx] = d; - probe->set_extents(extents); -} - -void GIProbeGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { - - Vector3 restore = p_restore; - - if (p_cancel) { - probe->set_extents(restore); - return; - } - - UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Change Probe Extents")); - ur->add_do_method(probe, "set_extents", probe->get_extents()); - ur->add_undo_method(probe, "set_extents", restore); - ur->commit_action(); -} - -void GIProbeGizmo::redraw() { - - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/gi_probe"); - Ref<Material> material = create_material("gi_probe_material", gizmo_color); - Ref<Material> icon = create_icon_material("gi_probe_icon", SpatialEditor::get_singleton()->get_icon("GizmoGIProbe", "EditorIcons")); - Color gizmo_color_internal = gizmo_color; - gizmo_color_internal.a = 0.1; - Ref<Material> material_internal = create_material("gi_probe_internal_material", gizmo_color_internal); - - clear(); - - Vector<Vector3> lines; - Vector3 extents = probe->get_extents(); - - static const int subdivs[GIProbe::SUBDIV_MAX] = { 64, 128, 256, 512 }; - - AABB aabb = AABB(-extents, extents * 2); - int subdiv = subdivs[probe->get_subdiv()]; - float cell_size = aabb.get_longest_axis_size() / subdiv; - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - add_lines(lines, material); - add_collision_segments(lines); - - lines.clear(); - - for (int i = 1; i < subdiv; i++) { - - for (int j = 0; j < 3; j++) { - - if (cell_size * i > aabb.size[j]) { - continue; - } - - Vector2 dir; - dir[j] = 1.0; - Vector2 ta, tb; - int j_n1 = (j + 1) % 3; - int j_n2 = (j + 2) % 3; - ta[j_n1] = 1.0; - tb[j_n2] = 1.0; - - for (int k = 0; k < 4; k++) { - - Vector3 from = aabb.position, to = aabb.position; - from[j] += cell_size * i; - to[j] += cell_size * i; - - if (k & 1) { - to[j_n1] += aabb.size[j_n1]; - } else { - - to[j_n2] += aabb.size[j_n2]; - } - - if (k & 2) { - from[j_n1] += aabb.size[j_n1]; - from[j_n2] += aabb.size[j_n2]; - } - - lines.push_back(from); - lines.push_back(to); - } - } - } - - add_lines(lines, material_internal); - - Vector<Vector3> handles; - - for (int i = 0; i < 3; i++) { - - Vector3 ax; - ax[i] = aabb.position[i] + aabb.size[i]; - handles.push_back(ax); - } - - if (is_selected()) { - - gizmo_color.a = 0.1; - Ref<Material> solid_material = create_material("gi_probe_solid_material", gizmo_color); - add_solid_box(solid_material, aabb.get_size()); - } - - add_unscaled_billboard(icon, 0.05); - add_handles(handles); -} -GIProbeGizmo::GIProbeGizmo(GIProbe *p_probe) { - - probe = p_probe; - set_spatial_node(p_probe); -} - -//////// -//////// - -/// - -String BakedIndirectLightGizmo::get_handle_name(int p_idx) const { - - switch (p_idx) { - case 0: return "Extents X"; - case 1: return "Extents Y"; - case 2: return "Extents Z"; - } - - return ""; -} -Variant BakedIndirectLightGizmo::get_handle_value(int p_idx) const { - - return baker->get_extents(); -} -void BakedIndirectLightGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { - - Transform gt = baker->get_global_transform(); - //gt.orthonormalize(); - Transform gi = gt.affine_inverse(); - - Vector3 extents = baker->get_extents(); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; - - Vector3 axis; - axis[p_idx] = 1.0; - - Vector3 ra, rb; - Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); - float d = ra[p_idx]; - if (d < 0.001) - d = 0.001; +//// - extents[p_idx] = d; - baker->set_extents(extents); +NavigationMeshSpatialGizmoPlugin::NavigationMeshSpatialGizmoPlugin() { + create_material("navigation_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge", Color(0.5, 1, 1))); + create_material("navigation_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge_disabled", Color(0.7, 0.7, 0.7))); + create_material("navigation_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid", Color(0.5, 1, 1, 0.4))); + create_material("navigation_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid_disabled", Color(0.7, 0.7, 0.7, 0.4))); } -void BakedIndirectLightGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { - - Vector3 restore = p_restore; - - if (p_cancel) { - baker->set_extents(restore); - return; - } - - UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Change Probe Extents")); - ur->add_do_method(baker, "set_extents", baker->get_extents()); - ur->add_undo_method(baker, "set_extents", restore); - ur->commit_action(); +bool NavigationMeshSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<NavigationMeshInstance>(p_spatial) != NULL; } -void BakedIndirectLightGizmo::redraw() { - - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/baked_indirect_light"); - Ref<Material> material = create_material("baked_indirect_light_material", gizmo_color); - Ref<Material> icon = create_icon_material("baked_indirect_light_icon", SpatialEditor::get_singleton()->get_icon("GizmoBakedLightmap", "EditorIcons")); - Color gizmo_color_internal = gizmo_color; - gizmo_color_internal.a = 0.1; - Ref<Material> material_internal = create_material("baked_indirect_light_internal_material", gizmo_color_internal); - - clear(); - - Vector<Vector3> lines; - Vector3 extents = baker->get_extents(); - - AABB aabb = AABB(-extents, extents * 2); - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - add_lines(lines, material); - add_collision_segments(lines); - - Vector<Vector3> handles; - - for (int i = 0; i < 3; i++) { - - Vector3 ax; - ax[i] = aabb.position[i] + aabb.size[i]; - handles.push_back(ax); - } - - if (is_selected()) { - - gizmo_color.a = 0.1; - Ref<Material> solid_material = create_material("baked_indirect_light_solid_material", gizmo_color); - add_solid_box(solid_material, aabb.get_size()); - } - - add_unscaled_billboard(icon, 0.05); - add_handles(handles); +String NavigationMeshSpatialGizmoPlugin::get_name() const { + return "NavigationMeshInstance"; } -BakedIndirectLightGizmo::BakedIndirectLightGizmo(BakedLightmap *p_baker) { - baker = p_baker; - set_spatial_node(p_baker); -} +void NavigationMeshSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { -//////// -void NavigationMeshSpatialGizmo::redraw() { + NavigationMeshInstance *navmesh = Object::cast_to<NavigationMeshInstance>(p_gizmo->get_spatial_node()); - Ref<Material> edge_material = create_material("navigation_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/navigation_edge")); - Ref<Material> edge_material_disabled = create_material("navigation_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/navigation_edge_disabled")); - Ref<Material> solid_material = create_material("navigation_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/navigation_solid")); - Ref<Material> solid_material_disabled = create_material("navigation_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/navigation_solid_disabled")); + Ref<Material> edge_material = get_material("navigation_material", p_gizmo); + Ref<Material> edge_material_disabled = get_material("navigation_material", p_gizmo); + Ref<Material> solid_material = get_material("navigation_material", p_gizmo); + Ref<Material> solid_material_disabled = get_material("navigation_material", p_gizmo); - clear(); + p_gizmo->clear(); Ref<NavigationMesh> navmeshie = navmesh->get_navigation_mesh(); if (navmeshie.is_null()) return; @@ -3353,28 +3569,19 @@ void NavigationMeshSpatialGizmo::redraw() { tmesh->create(tmeshfaces); if (lines.size()) - add_lines(lines, navmesh->is_enabled() ? edge_material : edge_material_disabled); - add_collision_triangles(tmesh); + p_gizmo->add_lines(lines, navmesh->is_enabled() ? edge_material : edge_material_disabled); + p_gizmo->add_collision_triangles(tmesh); Ref<ArrayMesh> m = memnew(ArrayMesh); Array a; a.resize(Mesh::ARRAY_MAX); a[0] = tmeshfaces; m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a); m->surface_set_material(0, navmesh->is_enabled() ? solid_material : solid_material_disabled); - add_mesh(m); - add_collision_segments(lines); -} - -NavigationMeshSpatialGizmo::NavigationMeshSpatialGizmo(NavigationMeshInstance *p_navmesh) { - - set_spatial_node(p_navmesh); - navmesh = p_navmesh; + p_gizmo->add_mesh(m); + p_gizmo->add_collision_segments(lines); } ////// -/// -/// -/// #define BODY_A_RADIUS 0.25 #define BODY_B_RADIUS 0.27 @@ -3625,38 +3832,169 @@ void JointGizmosDrawer::draw_cone(const Transform &p_offset, const Basis &p_base } } -void PinJointSpatialGizmo::CreateGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points) { - float cs = 0.25; +//// - r_cursor_points.push_back(p_offset.translated(Vector3(+cs, 0, 0)).origin); - r_cursor_points.push_back(p_offset.translated(Vector3(-cs, 0, 0)).origin); - r_cursor_points.push_back(p_offset.translated(Vector3(0, +cs, 0)).origin); - r_cursor_points.push_back(p_offset.translated(Vector3(0, -cs, 0)).origin); - r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, +cs)).origin); - r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, -cs)).origin); +JointSpatialGizmoPlugin::JointSpatialGizmoPlugin() { + create_material("joint_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1))); + create_material("joint_body_a_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1))); + create_material("joint_body_b_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1))); } -void PinJointSpatialGizmo::redraw() { +bool JointSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<Joint>(p_spatial) != NULL; +} - clear(); - Vector<Vector3> cursor_points; - CreateGizmo(Transform(), cursor_points); - add_collision_segments(cursor_points); +String JointSpatialGizmoPlugin::get_name() const { + return "Joints"; +} - Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); +void JointSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + Joint *joint = Object::cast_to<Joint>(p_gizmo->get_spatial_node()); - add_lines(cursor_points, material); -} + p_gizmo->clear(); -PinJointSpatialGizmo::PinJointSpatialGizmo(PinJoint *p_p3d) { + const Spatial *node_body_a = Object::cast_to<Spatial>(joint->get_node(joint->get_node_a())); + const Spatial *node_body_b = Object::cast_to<Spatial>(joint->get_node(joint->get_node_b())); - p3d = p_p3d; - set_spatial_node(p3d); -} + Ref<Material> common_material = get_material("joint_material", p_gizmo); + Ref<Material> body_a_material = get_material("joint_body_a_material", p_gizmo); + Ref<Material> body_b_material = get_material("joint_body_b_material", p_gizmo); -//// + Vector<Vector3> points; + Vector<Vector3> body_a_points; + Vector<Vector3> body_b_points; -void HingeJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { + if (Object::cast_to<PinJoint>(joint)) { + CreatePinJointGizmo(Transform(), points); + p_gizmo->add_collision_segments(points); + p_gizmo->add_lines(points, common_material); + } + + HingeJoint *hinge = Object::cast_to<HingeJoint>(joint); + if (hinge) { + + CreateHingeJointGizmo( + Transform(), + hinge->get_global_transform(), + node_body_a ? node_body_a->get_global_transform() : Transform(), + node_body_b ? node_body_b->get_global_transform() : Transform(), + hinge->get_param(HingeJoint::PARAM_LIMIT_LOWER), + hinge->get_param(HingeJoint::PARAM_LIMIT_UPPER), + hinge->get_flag(HingeJoint::FLAG_USE_LIMIT), + points, + node_body_a ? &body_a_points : NULL, + node_body_b ? &body_b_points : NULL); + + p_gizmo->add_collision_segments(points); + p_gizmo->add_collision_segments(body_a_points); + p_gizmo->add_collision_segments(body_b_points); + + p_gizmo->add_lines(points, common_material); + p_gizmo->add_lines(body_a_points, body_a_material); + p_gizmo->add_lines(body_b_points, body_b_material); + } + + SliderJoint *slider = Object::cast_to<SliderJoint>(joint); + if (slider) { + + CreateSliderJointGizmo( + Transform(), + slider->get_global_transform(), + node_body_a ? node_body_a->get_global_transform() : Transform(), + node_body_b ? node_body_b->get_global_transform() : Transform(), + slider->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_LOWER), + slider->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_UPPER), + slider->get_param(SliderJoint::PARAM_LINEAR_LIMIT_LOWER), + slider->get_param(SliderJoint::PARAM_LINEAR_LIMIT_UPPER), + points, + node_body_a ? &body_a_points : NULL, + node_body_b ? &body_b_points : NULL); + + p_gizmo->add_collision_segments(points); + p_gizmo->add_collision_segments(body_a_points); + p_gizmo->add_collision_segments(body_b_points); + + p_gizmo->add_lines(points, common_material); + p_gizmo->add_lines(body_a_points, body_a_material); + p_gizmo->add_lines(body_b_points, body_b_material); + } + + ConeTwistJoint *cone = Object::cast_to<ConeTwistJoint>(joint); + if (cone) { + + CreateConeTwistJointGizmo( + Transform(), + cone->get_global_transform(), + node_body_a ? node_body_a->get_global_transform() : Transform(), + node_body_b ? node_body_b->get_global_transform() : Transform(), + cone->get_param(ConeTwistJoint::PARAM_SWING_SPAN), + cone->get_param(ConeTwistJoint::PARAM_TWIST_SPAN), + node_body_a ? &body_a_points : NULL, + node_body_b ? &body_b_points : NULL); + + p_gizmo->add_collision_segments(body_a_points); + p_gizmo->add_collision_segments(body_b_points); + + p_gizmo->add_lines(body_a_points, body_a_material); + p_gizmo->add_lines(body_b_points, body_b_material); + } + + Generic6DOFJoint *gen = Object::cast_to<Generic6DOFJoint>(joint); + if (gen) { + + CreateGeneric6DOFJointGizmo( + Transform(), + gen->get_global_transform(), + node_body_a ? node_body_a->get_global_transform() : Transform(), + node_body_b ? node_body_b->get_global_transform() : Transform(), + + gen->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT), + gen->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT), + gen->get_param_x(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT), + gen->get_param_x(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT), + gen->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT), + gen->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT), + + gen->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT), + gen->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT), + gen->get_param_y(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT), + gen->get_param_y(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT), + gen->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT), + gen->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT), + + gen->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT), + gen->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT), + gen->get_param_z(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT), + gen->get_param_z(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT), + gen->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT), + gen->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT), + + points, + node_body_a ? &body_a_points : NULL, + node_body_a ? &body_b_points : NULL); + + p_gizmo->add_collision_segments(points); + p_gizmo->add_collision_segments(body_a_points); + p_gizmo->add_collision_segments(body_b_points); + + p_gizmo->add_lines(points, common_material); + p_gizmo->add_lines(body_a_points, body_a_material); + p_gizmo->add_lines(body_b_points, body_b_material); + } +} + +void JointSpatialGizmoPlugin::CreatePinJointGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points) { + float cs = 0.25; + + r_cursor_points.push_back(p_offset.translated(Vector3(+cs, 0, 0)).origin); + r_cursor_points.push_back(p_offset.translated(Vector3(-cs, 0, 0)).origin); + r_cursor_points.push_back(p_offset.translated(Vector3(0, +cs, 0)).origin); + r_cursor_points.push_back(p_offset.translated(Vector3(0, -cs, 0)).origin); + r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, +cs)).origin); + r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, -cs)).origin); +} + +void JointSpatialGizmoPlugin::CreateHingeJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { r_common_points.push_back(p_offset.translated(Vector3(0, 0, 0.5)).origin); r_common_points.push_back(p_offset.translated(Vector3(0, 0, -0.5)).origin); @@ -3688,52 +4026,7 @@ void HingeJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transf } } -void HingeJointSpatialGizmo::redraw() { - - const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a())); - const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b())); - - Vector<Vector3> points; - Vector<Vector3> body_a_points; - Vector<Vector3> body_b_points; - CreateGizmo( - Transform(), - p3d->get_global_transform(), - node_body_a ? node_body_a->get_global_transform() : Transform(), - node_body_b ? node_body_b->get_global_transform() : Transform(), - p3d->get_param(HingeJoint::PARAM_LIMIT_LOWER), - p3d->get_param(HingeJoint::PARAM_LIMIT_UPPER), - p3d->get_flag(HingeJoint::FLAG_USE_LIMIT), - points, - node_body_a ? &body_a_points : NULL, - node_body_b ? &body_b_points : NULL); - - clear(); - - Ref<Material> common_material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); - Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a")); - Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b")); - - add_collision_segments(points); - add_collision_segments(body_a_points); - add_collision_segments(body_b_points); - - add_lines(points, common_material); - add_lines(body_a_points, body_a_material); - add_lines(body_b_points, body_b_material); -} - -HingeJointSpatialGizmo::HingeJointSpatialGizmo(HingeJoint *p_p3d) { - - p3d = p_p3d; - set_spatial_node(p3d); -} - -/////// -/// -//// - -void SliderJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { +void JointSpatialGizmoPlugin::CreateSliderJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { p_linear_limit_lower = -p_linear_limit_lower; p_linear_limit_upper = -p_linear_limit_upper; @@ -3793,53 +4086,7 @@ void SliderJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Trans true); } -void SliderJointSpatialGizmo::redraw() { - - const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a())); - const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b())); - - clear(); - Vector<Vector3> cursor_points; - Vector<Vector3> body_a_points; - Vector<Vector3> body_b_points; - - CreateGizmo( - Transform(), - p3d->get_global_transform(), - node_body_a ? node_body_a->get_global_transform() : Transform(), - node_body_b ? node_body_b->get_global_transform() : Transform(), - p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_LOWER), - p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_UPPER), - p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_LOWER), - p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_UPPER), - cursor_points, - node_body_a ? &body_a_points : NULL, - node_body_b ? &body_b_points : NULL); - - Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); - Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a")); - Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b")); - - add_collision_segments(cursor_points); - add_collision_segments(body_a_points); - add_collision_segments(body_b_points); - - add_lines(cursor_points, material); - add_lines(body_a_points, body_a_material); - add_lines(body_b_points, body_b_material); -} - -SliderJointSpatialGizmo::SliderJointSpatialGizmo(SliderJoint *p_p3d) { - - p3d = p_p3d; - set_spatial_node(p3d); -} - -/////// -/// -//// - -void ConeTwistJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { +void JointSpatialGizmoPlugin::CreateConeTwistJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { if (r_body_a_points) JointGizmosDrawer::draw_cone( @@ -3858,51 +4105,7 @@ void ConeTwistJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Tr *r_body_b_points); } -void ConeTwistJointSpatialGizmo::redraw() { - - const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a())); - const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b())); - - clear(); - Vector<Vector3> points; - Vector<Vector3> body_a_points; - Vector<Vector3> body_b_points; - - CreateGizmo( - Transform(), - p3d->get_global_transform(), - node_body_a ? node_body_a->get_global_transform() : Transform(), - node_body_b ? node_body_b->get_global_transform() : Transform(), - p3d->get_param(ConeTwistJoint::PARAM_SWING_SPAN), - p3d->get_param(ConeTwistJoint::PARAM_TWIST_SPAN), - points, - node_body_a ? &body_a_points : NULL, - node_body_b ? &body_b_points : NULL); - - Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); - Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a")); - Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b")); - - add_collision_segments(points); - add_collision_segments(body_a_points); - add_collision_segments(body_b_points); - - add_lines(points, material); - add_lines(body_a_points, body_a_material); - add_lines(body_b_points, body_b_material); -} - -ConeTwistJointSpatialGizmo::ConeTwistJointSpatialGizmo(ConeTwistJoint *p_p3d) { - - p3d = p_p3d; - set_spatial_node(p3d); -} - -/////// -/// -//// - -void Generic6DOFJointSpatialGizmo::CreateGizmo( +void JointSpatialGizmoPlugin::CreateGeneric6DOFJointGizmo( const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, @@ -4051,510 +4254,3 @@ void Generic6DOFJointSpatialGizmo::CreateGizmo( #undef ADD_VTX } - -void Generic6DOFJointSpatialGizmo::redraw() { - - const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a())); - const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b())); - - clear(); - Vector<Vector3> cursor_points; - Vector<Vector3> body_a_points; - Vector<Vector3> body_b_points; - - CreateGizmo( - Transform(), - p3d->get_global_transform(), - node_body_a ? node_body_a->get_global_transform() : Transform(), - node_body_b ? node_body_b->get_global_transform() : Transform(), - - p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT), - p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT), - p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT), - p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT), - p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT), - p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT), - - p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT), - p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT), - p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT), - p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT), - p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT), - p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT), - - p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT), - p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT), - p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT), - p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT), - p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT), - p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT), - - cursor_points, - node_body_a ? &body_a_points : NULL, - node_body_a ? &body_b_points : NULL); - - Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); - Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a")); - Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b")); - - add_collision_segments(cursor_points); - add_collision_segments(body_a_points); - add_collision_segments(body_b_points); - - add_lines(cursor_points, material); - add_lines(body_a_points, body_a_material); - add_lines(body_b_points, body_b_material); -} - -Generic6DOFJointSpatialGizmo::Generic6DOFJointSpatialGizmo(Generic6DOFJoint *p_p3d) { - - p3d = p_p3d; - set_spatial_node(p3d); -} - -/////// -/// -//// - -SpatialEditorGizmos *SpatialEditorGizmos::singleton = NULL; - -Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) { - - if (Object::cast_to<Light>(p_spatial)) { - - Ref<LightSpatialGizmo> lsg = memnew(LightSpatialGizmo(Object::cast_to<Light>(p_spatial))); - return lsg; - } - - if (Object::cast_to<Camera>(p_spatial)) { - - Ref<CameraSpatialGizmo> lsg = memnew(CameraSpatialGizmo(Object::cast_to<Camera>(p_spatial))); - return lsg; - } - - if (Object::cast_to<Skeleton>(p_spatial)) { - - Ref<SkeletonSpatialGizmo> lsg = memnew(SkeletonSpatialGizmo(Object::cast_to<Skeleton>(p_spatial))); - return lsg; - } - - if (Object::cast_to<PhysicalBone>(p_spatial)) { - - Ref<PhysicalBoneSpatialGizmo> pbsg = memnew(PhysicalBoneSpatialGizmo(Object::cast_to<PhysicalBone>(p_spatial))); - return pbsg; - } - - if (Object::cast_to<Position3D>(p_spatial)) { - - Ref<Position3DSpatialGizmo> lsg = memnew(Position3DSpatialGizmo(Object::cast_to<Position3D>(p_spatial))); - return lsg; - } - - if (Object::cast_to<SoftBody>(p_spatial)) { - - Ref<SoftBodySpatialGizmo> misg = memnew(SoftBodySpatialGizmo(Object::cast_to<SoftBody>(p_spatial))); - return misg; - } - - if (Object::cast_to<MeshInstance>(p_spatial)) { - - Ref<MeshInstanceSpatialGizmo> misg = memnew(MeshInstanceSpatialGizmo(Object::cast_to<MeshInstance>(p_spatial))); - return misg; - } - - /*if (Object::cast_to<Room>(p_spatial)) { - - Ref<RoomSpatialGizmo> misg = memnew(RoomSpatialGizmo(Object::cast_to<Room>(p_spatial))); - return misg; - }*/ - - if (Object::cast_to<NavigationMeshInstance>(p_spatial)) { - - Ref<NavigationMeshSpatialGizmo> misg = memnew(NavigationMeshSpatialGizmo(Object::cast_to<NavigationMeshInstance>(p_spatial))); - return misg; - } - - if (Object::cast_to<RayCast>(p_spatial)) { - - Ref<RayCastSpatialGizmo> misg = memnew(RayCastSpatialGizmo(Object::cast_to<RayCast>(p_spatial))); - return misg; - } - /* - if (Object::cast_to<Portal>(p_spatial)) { - - Ref<PortalSpatialGizmo> misg = memnew(PortalSpatialGizmo(Object::cast_to<Portal>(p_spatial))); - return misg; - } -*/ - - if (Object::cast_to<CollisionShape>(p_spatial)) { - - Ref<CollisionShapeSpatialGizmo> misg = memnew(CollisionShapeSpatialGizmo(Object::cast_to<CollisionShape>(p_spatial))); - return misg; - } - - if (Object::cast_to<VisibilityNotifier>(p_spatial)) { - - Ref<VisibilityNotifierGizmo> misg = memnew(VisibilityNotifierGizmo(Object::cast_to<VisibilityNotifier>(p_spatial))); - return misg; - } - - if (Object::cast_to<Particles>(p_spatial)) { - - Ref<ParticlesGizmo> misg = memnew(ParticlesGizmo(Object::cast_to<Particles>(p_spatial))); - return misg; - } - - if (Object::cast_to<ReflectionProbe>(p_spatial)) { - - Ref<ReflectionProbeGizmo> misg = memnew(ReflectionProbeGizmo(Object::cast_to<ReflectionProbe>(p_spatial))); - return misg; - } - if (Object::cast_to<GIProbe>(p_spatial)) { - - Ref<GIProbeGizmo> misg = memnew(GIProbeGizmo(Object::cast_to<GIProbe>(p_spatial))); - return misg; - } - if (Object::cast_to<BakedLightmap>(p_spatial)) { - - Ref<BakedIndirectLightGizmo> misg = memnew(BakedIndirectLightGizmo(Object::cast_to<BakedLightmap>(p_spatial))); - return misg; - } - - if (Object::cast_to<VehicleWheel>(p_spatial)) { - - Ref<VehicleWheelSpatialGizmo> misg = memnew(VehicleWheelSpatialGizmo(Object::cast_to<VehicleWheel>(p_spatial))); - return misg; - } - if (Object::cast_to<PinJoint>(p_spatial)) { - - Ref<PinJointSpatialGizmo> misg = memnew(PinJointSpatialGizmo(Object::cast_to<PinJoint>(p_spatial))); - return misg; - } - - if (Object::cast_to<HingeJoint>(p_spatial)) { - - Ref<HingeJointSpatialGizmo> misg = memnew(HingeJointSpatialGizmo(Object::cast_to<HingeJoint>(p_spatial))); - return misg; - } - - if (Object::cast_to<SliderJoint>(p_spatial)) { - - Ref<SliderJointSpatialGizmo> misg = memnew(SliderJointSpatialGizmo(Object::cast_to<SliderJoint>(p_spatial))); - return misg; - } - - if (Object::cast_to<ConeTwistJoint>(p_spatial)) { - - Ref<ConeTwistJointSpatialGizmo> misg = memnew(ConeTwistJointSpatialGizmo(Object::cast_to<ConeTwistJoint>(p_spatial))); - return misg; - } - - if (Object::cast_to<Generic6DOFJoint>(p_spatial)) { - - Ref<Generic6DOFJointSpatialGizmo> misg = memnew(Generic6DOFJointSpatialGizmo(Object::cast_to<Generic6DOFJoint>(p_spatial))); - return misg; - } - - if (Object::cast_to<CollisionPolygon>(p_spatial)) { - - Ref<CollisionPolygonSpatialGizmo> misg = memnew(CollisionPolygonSpatialGizmo(Object::cast_to<CollisionPolygon>(p_spatial))); - return misg; - } - - if (Object::cast_to<AudioStreamPlayer3D>(p_spatial)) { - - Ref<AudioStreamPlayer3DSpatialGizmo> misg = memnew(AudioStreamPlayer3DSpatialGizmo(Object::cast_to<AudioStreamPlayer3D>(p_spatial))); - return misg; - } - - return Ref<SpatialEditorGizmo>(); -} - -SpatialEditorGizmos::SpatialEditorGizmos() { - - singleton = this; - - handle_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - handle_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - handle_material->set_on_top_of_alpha(); - handle_material->set_albedo(Color(0.8, 0.8, 0.8)); - handle_material_billboard = handle_material->duplicate(); - handle_material_billboard->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); - - handle2_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - handle2_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - handle2_material->set_flag(SpatialMaterial::FLAG_USE_POINT_SIZE, true); - handle_t = SpatialEditor::get_singleton()->get_icon("Editor3DHandle", "EditorIcons"); - handle2_material->set_point_size(handle_t->get_width()); - handle2_material->set_texture(SpatialMaterial::TEXTURE_ALBEDO, handle_t); - handle2_material->set_albedo(Color(1, 1, 1)); - handle2_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - handle2_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - handle2_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - handle2_material->set_on_top_of_alpha(); - handle2_material_billboard = handle2_material->duplicate(); - handle2_material_billboard->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); - handle2_material_billboard->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); - handle2_material_billboard->set_on_top_of_alpha(); - - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/light", Color(1, 1, 0.2)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/gi_probe", Color(0.5, 1, 0.6)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/baked_indirect_light", Color(0.5, 0.6, 1)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge", Color(0.5, 1, 1)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge_disabled", Color(0.7, 0.7, 0.7)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid", Color(0.5, 1, 1, 0.4)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid_disabled", Color(0.7, 0.7, 0.7, 0.4)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instanced", Color(0.7, 0.7, 0.7, 0.5)); - -#if 0 - light_material = create_line_material(Color(1, 1, 0.2)); - light_material_omni = create_line_material(Color(1, 1, 0.2)); - light_material_omni->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); - - light_material_omni_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - light_material_omni_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - light_material_omni_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED); - light_material_omni_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); - light_material_omni_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - light_material_omni_icon->set_albedo(Color(1, 1, 1, 0.9)); - light_material_omni_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoLight", "EditorIcons")); - light_material_omni_icon->set_flag(SpatialMaterial::FLAG_FIXED_SIZE, true); - light_material_omni_icon->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); - - light_material_directional_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - light_material_directional_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - light_material_directional_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED); - light_material_directional_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); - light_material_directional_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - light_material_directional_icon->set_albedo(Color(1, 1, 1, 0.9)); - light_material_directional_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight", "EditorIcons")); - light_material_directional_icon->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); - light_material_directional_icon->set_depth_scale(1); - - camera_material = create_line_material(Color(1.0, 0.5, 1.0)); - - navmesh_edge_material = create_line_material(Color(0.1, 0.8, 1.0)); - navmesh_solid_material = create_solid_material(Color(0.1, 0.8, 1.0, 0.4)); - navmesh_edge_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, false); - navmesh_edge_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, false); - navmesh_solid_material->set_cull_mode(SpatialMaterial::CULL_DISABLED); - - navmesh_edge_material_disabled = create_line_material(Color(1.0, 0.8, 0.1)); - navmesh_solid_material_disabled = create_solid_material(Color(1.0, 0.8, 0.1, 0.4)); - navmesh_edge_material_disabled->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, false); - navmesh_edge_material_disabled->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, false); - navmesh_solid_material_disabled->set_cull_mode(SpatialMaterial::CULL_DISABLED); - - skeleton_material = create_line_material(Color(0.6, 1.0, 0.3)); - skeleton_material->set_cull_mode(SpatialMaterial::CULL_DISABLED); - skeleton_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - skeleton_material->set_on_top_of_alpha(); - skeleton_material->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); - - //position 3D Shared mesh - - pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); - { - - PoolVector<Vector3> cursor_points; - PoolVector<Color> cursor_colors; - float cs = 0.25; - cursor_points.push_back(Vector3(+cs, 0, 0)); - cursor_points.push_back(Vector3(-cs, 0, 0)); - cursor_points.push_back(Vector3(0, +cs, 0)); - cursor_points.push_back(Vector3(0, -cs, 0)); - cursor_points.push_back(Vector3(0, 0, +cs)); - cursor_points.push_back(Vector3(0, 0, -cs)); - cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7)); - cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7)); - cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7)); - cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7)); - cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7)); - cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7)); - - Ref<SpatialMaterial> mat = memnew(SpatialMaterial); - mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - mat->set_line_width(3); - Array d; - d.resize(VS::ARRAY_MAX); - d[Mesh::ARRAY_VERTEX] = cursor_points; - d[Mesh::ARRAY_COLOR] = cursor_colors; - pos3d_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d); - pos3d_mesh->surface_set_material(0, mat); - } - - listener_line_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); - { - - PoolVector<Vector3> cursor_points; - PoolVector<Color> cursor_colors; - cursor_points.push_back(Vector3(0, 0, 0)); - cursor_points.push_back(Vector3(0, 0, -1.0)); - cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7)); - cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7)); - - Ref<SpatialMaterial> mat = memnew(SpatialMaterial); - mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - mat->set_line_width(3); - Array d; - d.resize(VS::ARRAY_MAX); - d[Mesh::ARRAY_VERTEX] = cursor_points; - d[Mesh::ARRAY_COLOR] = cursor_colors; - listener_line_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d); - listener_line_mesh->surface_set_material(0, mat); - } - - room_material = create_line_material(Color(1.0, 0.6, 0.9)); - portal_material = create_line_material(Color(1.0, 0.8, 0.6)); - raycast_material = create_line_material(Color(1.0, 0.8, 0.6)); - car_wheel_material = create_line_material(Color(0.6, 0.8, 1.0)); - visibility_notifier_material = create_line_material(Color(1.0, 0.5, 1.0)); - particles_material = create_line_material(Color(1.0, 1.0, 0.5)); - reflection_probe_material = create_line_material(Color(0.5, 1.0, 0.7)); - reflection_probe_material_internal = create_line_material(Color(0.3, 0.8, 0.5, 0.15)); - gi_probe_material = create_line_material(Color(0.7, 1.0, 0.5)); - gi_probe_material_internal = create_line_material(Color(0.5, 0.8, 0.3, 0.1)); - joint_material = create_line_material(Color(0.6, 0.8, 1.0)); - - stream_player_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - stream_player_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - stream_player_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED); - stream_player_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); - stream_player_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - stream_player_icon->set_albedo(Color(1, 1, 1, 0.9)); - stream_player_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoSpatialStreamPlayer", "EditorIcons")); - - visibility_notifier_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - visibility_notifier_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - visibility_notifier_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED); - visibility_notifier_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); - visibility_notifier_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - visibility_notifier_icon->set_albedo(Color(1, 1, 1, 0.9)); - visibility_notifier_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("Visible", "EditorIcons")); - - listener_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - listener_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - listener_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED); - listener_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); - listener_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - listener_icon->set_albedo(Color(1, 1, 1, 0.9)); - listener_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoListener", "EditorIcons")); - - { - - PoolVector<Vector3> vertices; - -#undef ADD_VTX -#define ADD_VTX(m_idx) \ - vertices.push_back(face_points[m_idx]); - - for (int i = 0; i < 6; i++) { - - Vector3 face_points[4]; - - for (int j = 0; j < 4; j++) { - - float v[3]; - v[0] = 1.0; - v[1] = 1 - 2 * ((j >> 1) & 1); - v[2] = v[1] * (1 - 2 * (j & 1)); - - for (int k = 0; k < 3; k++) { - - if (i < 3) - face_points[j][(i + k) % 3] = v[k]; - else - face_points[3 - j][(i + k) % 3] = -v[k]; - } - } - //tri 1 - ADD_VTX(0); - ADD_VTX(1); - ADD_VTX(2); - //tri 2 - ADD_VTX(2); - ADD_VTX(3); - ADD_VTX(0); - } - - test_cube_tm = Ref<TriangleMesh>(memnew(TriangleMesh)); - test_cube_tm->create(vertices); - } - - shape_material = create_line_material(Color(0.2, 1, 1.0)); -#endif - - pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); - { - - PoolVector<Vector3> cursor_points; - PoolVector<Color> cursor_colors; - float cs = 0.25; - cursor_points.push_back(Vector3(+cs, 0, 0)); - cursor_points.push_back(Vector3(-cs, 0, 0)); - cursor_points.push_back(Vector3(0, +cs, 0)); - cursor_points.push_back(Vector3(0, -cs, 0)); - cursor_points.push_back(Vector3(0, 0, +cs)); - cursor_points.push_back(Vector3(0, 0, -cs)); - cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7)); - cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7)); - cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7)); - cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7)); - cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7)); - cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7)); - - Ref<SpatialMaterial> mat = memnew(SpatialMaterial); - mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - mat->set_line_width(3); - Array d; - d.resize(VS::ARRAY_MAX); - d[Mesh::ARRAY_VERTEX] = cursor_points; - d[Mesh::ARRAY_COLOR] = cursor_colors; - pos3d_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d); - pos3d_mesh->surface_set_material(0, mat); - } - - listener_line_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); - { - - PoolVector<Vector3> cursor_points; - PoolVector<Color> cursor_colors; - cursor_points.push_back(Vector3(0, 0, 0)); - cursor_points.push_back(Vector3(0, 0, -1.0)); - cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7)); - cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7)); - - Ref<SpatialMaterial> mat = memnew(SpatialMaterial); - mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - mat->set_line_width(3); - Array d; - d.resize(VS::ARRAY_MAX); - d[Mesh::ARRAY_VERTEX] = cursor_points; - d[Mesh::ARRAY_COLOR] = cursor_colors; - listener_line_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d); - listener_line_mesh->surface_set_material(0, mat); - } -} diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h index 198d028516..877590b91d 100644 --- a/editor/spatial_editor_gizmos.h +++ b/editor/spatial_editor_gizmos.h @@ -55,187 +55,120 @@ class Camera; -class EditorSpatialGizmo : public SpatialEditorGizmo { +class LightSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - GDCLASS(EditorSpatialGizmo, SpatialGizmo); + GDCLASS(LightSpatialGizmoPlugin, EditorSpatialGizmoPlugin); - struct Instance { - - RID instance; - Ref<ArrayMesh> mesh; - RID skeleton; - bool billboard; - bool unscaled; - bool can_intersect; - bool extra_margin; - Instance() { - - billboard = false; - unscaled = false; - can_intersect = false; - extra_margin = false; - } - - void create_instance(Spatial *p_base); - }; - - Vector<Vector3> collision_segments; - Ref<TriangleMesh> collision_mesh; - - struct Handle { - Vector3 pos; - bool billboard; - }; - - Vector<Vector3> handles; - Vector<Vector3> secondary_handles; - float selectable_icon_size = -1.0f; - bool billboard_handle; +public: + bool has_gizmo(Spatial *p_spatial); + String get_name() const; - bool valid; - Spatial *base; - Vector<Instance> instances; - Spatial *spatial_node; + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); + void redraw(EditorSpatialGizmo *p_gizmo); - void _set_spatial_node(Node *p_node) { set_spatial_node(Object::cast_to<Spatial>(p_node)); } + LightSpatialGizmoPlugin(); +}; -protected: - void add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard = false); - void add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard = false, const RID &p_skeleton = RID()); - void add_collision_segments(const Vector<Vector3> &p_lines); - void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh); - void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1); - void add_handles(const Vector<Vector3> &p_handles, bool p_billboard = false, bool p_secondary = false); - void add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position = Vector3()); +class AudioStreamPlayer3DSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - void set_spatial_node(Spatial *p_node); - const Spatial *get_spatial_node() const { return spatial_node; } + GDCLASS(AudioStreamPlayer3DSpatialGizmoPlugin, EditorSpatialGizmoPlugin); - static void _bind_methods(); +public: + bool has_gizmo(Spatial *p_spatial); + String get_name() const; - Ref<SpatialMaterial> create_material(const String &p_name, const Color &p_color, bool p_billboard = false, bool p_on_top = false, bool p_use_vertex_color = false); - Ref<SpatialMaterial> create_icon_material(const String &p_name, const Ref<Texture> &p_texture, bool p_on_top = false, const Color &p_albedo = Color(1, 1, 1, 1)); + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); + void redraw(EditorSpatialGizmo *p_gizmo); -public: - virtual Vector3 get_handle_pos(int p_idx) const; - virtual bool intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum); - virtual bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false); - - void clear(); - void create(); - void transform(); - virtual void redraw(); - void free(); - virtual bool is_editable() const; - virtual bool can_draw() const; - - EditorSpatialGizmo(); - ~EditorSpatialGizmo(); + AudioStreamPlayer3DSpatialGizmoPlugin(); }; -class LightSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(LightSpatialGizmo, EditorSpatialGizmo); +class CameraSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - Light *light; + GDCLASS(CameraSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; - void redraw(); - LightSpatialGizmo(Light *p_light = NULL); -}; + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); + void redraw(EditorSpatialGizmo *p_gizmo); -class AudioStreamPlayer3DSpatialGizmo : public EditorSpatialGizmo { + CameraSpatialGizmoPlugin(); +}; - GDCLASS(AudioStreamPlayer3DSpatialGizmo, EditorSpatialGizmo); +class MeshInstanceSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - AudioStreamPlayer3D *player; + GDCLASS(MeshInstanceSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + bool can_be_hidden() const; + void redraw(EditorSpatialGizmo *p_gizmo); - void redraw(); - AudioStreamPlayer3DSpatialGizmo(AudioStreamPlayer3D *p_player = NULL); + MeshInstanceSpatialGizmoPlugin(); }; -class CameraSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(CameraSpatialGizmo, EditorSpatialGizmo); +class Sprite3DSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - Camera *camera; + GDCLASS(Sprite3DSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + bool can_be_hidden() const; + void redraw(EditorSpatialGizmo *p_gizmo); - void redraw(); - CameraSpatialGizmo(Camera *p_camera = NULL); + Sprite3DSpatialGizmoPlugin(); }; -class MeshInstanceSpatialGizmo : public EditorSpatialGizmo { +class Position3DSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - GDCLASS(MeshInstanceSpatialGizmo, EditorSpatialGizmo); + GDCLASS(Position3DSpatialGizmoPlugin, EditorSpatialGizmoPlugin); - MeshInstance *mesh; + Ref<ArrayMesh> pos3d_mesh; + Vector<Vector3> cursor_points; public: - virtual bool can_draw() const; - void redraw(); - MeshInstanceSpatialGizmo(MeshInstance *p_mesh = NULL); -}; - -class Sprite3DSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(Sprite3DSpatialGizmo, EditorSpatialGizmo); - - SpriteBase3D *sprite; + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); -public: - virtual bool can_draw() const; - void redraw(); - Sprite3DSpatialGizmo(SpriteBase3D *p_sprite = NULL); + Position3DSpatialGizmoPlugin(); }; -class Position3DSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(Position3DSpatialGizmo, EditorSpatialGizmo); +class SkeletonSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - Position3D *p3d; + GDCLASS(SkeletonSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - void redraw(); - Position3DSpatialGizmo(Position3D *p_p3d = NULL); -}; - -class SkeletonSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(SkeletonSpatialGizmo, EditorSpatialGizmo); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); - Skeleton *skel; - -public: - void redraw(); - SkeletonSpatialGizmo(Skeleton *p_skel = NULL); + SkeletonSpatialGizmoPlugin(); }; -class PhysicalBoneSpatialGizmo : public EditorSpatialGizmo { - GDCLASS(PhysicalBoneSpatialGizmo, EditorSpatialGizmo); +class PhysicalBoneSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - PhysicalBone *physical_bone; + GDCLASS(PhysicalBoneSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - //virtual Transform get_global_gizmo_transform(); - virtual void redraw(); - PhysicalBoneSpatialGizmo(PhysicalBone *p_pb = NULL); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); + + PhysicalBoneSpatialGizmoPlugin(); }; #if 0 @@ -251,154 +184,166 @@ public: }; #endif -class VisibilityNotifierGizmo : public EditorSpatialGizmo { - - GDCLASS(VisibilityNotifierGizmo, EditorSpatialGizmo); +class RayCastSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - VisibilityNotifier *notifier; + GDCLASS(RayCastSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); - void redraw(); - VisibilityNotifierGizmo(VisibilityNotifier *p_notifier = NULL); + RayCastSpatialGizmoPlugin(); }; -class ParticlesGizmo : public EditorSpatialGizmo { - - GDCLASS(ParticlesGizmo, EditorSpatialGizmo); +class VehicleWheelSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - Particles *particles; + GDCLASS(VehicleWheelSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); - void redraw(); - ParticlesGizmo(Particles *p_particles = NULL); + VehicleWheelSpatialGizmoPlugin(); }; -class ReflectionProbeGizmo : public EditorSpatialGizmo { - - GDCLASS(ReflectionProbeGizmo, EditorSpatialGizmo); +class SoftBodySpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - ReflectionProbe *probe; + GDCLASS(SoftBodySpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + bool is_selectable_when_hidden() const; + void redraw(EditorSpatialGizmo *p_gizmo); - void redraw(); - ReflectionProbeGizmo(ReflectionProbe *p_probe = NULL); -}; + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel); + bool is_gizmo_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int idx) const; -class GIProbeGizmo : public EditorSpatialGizmo { + SoftBodySpatialGizmoPlugin(); +}; - GDCLASS(GIProbeGizmo, EditorSpatialGizmo); +class VisibilityNotifierGizmoPlugin : public EditorSpatialGizmoPlugin { - GIProbe *probe; + GDCLASS(VisibilityNotifierGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); - void redraw(); - GIProbeGizmo(GIProbe *p_probe = NULL); -}; + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); -class BakedIndirectLightGizmo : public EditorSpatialGizmo { + VisibilityNotifierGizmoPlugin(); +}; - GDCLASS(BakedIndirectLightGizmo, EditorSpatialGizmo); +class ParticlesGizmoPlugin : public EditorSpatialGizmoPlugin { - BakedLightmap *baker; + GDCLASS(ParticlesGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + bool is_selectable_when_hidden() const; + void redraw(EditorSpatialGizmo *p_gizmo); - void redraw(); - BakedIndirectLightGizmo(BakedLightmap *p_baker = NULL); + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); + + ParticlesGizmoPlugin(); }; -class SoftBodySpatialGizmo : public EditorSpatialGizmo { - GDCLASS(SoftBodySpatialGizmo, EditorSpatialGizmo); +class ReflectionProbeGizmoPlugin : public EditorSpatialGizmoPlugin { - class SoftBody *soft_body; - //RID physics_sphere_shape; // Used for raycast that doesn't work, in this moment, with softbody + GDCLASS(ReflectionProbeGizmoPlugin, EditorSpatialGizmoPlugin); public: - void redraw(); - virtual bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); - virtual bool is_gizmo_handle_highlighted(int idx) const; + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); - SoftBodySpatialGizmo(SoftBody *p_soft_physics_body = NULL); - ~SoftBodySpatialGizmo(); + ReflectionProbeGizmoPlugin(); }; -class CollisionShapeSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(CollisionShapeSpatialGizmo, EditorSpatialGizmo); +class GIProbeGizmoPlugin : public EditorSpatialGizmoPlugin { - CollisionShape *cs; + GDCLASS(GIProbeGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); - void redraw(); - CollisionShapeSpatialGizmo(CollisionShape *p_cs = NULL); -}; + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); + + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); -class CollisionPolygonSpatialGizmo : public EditorSpatialGizmo { + GIProbeGizmoPlugin(); +}; - GDCLASS(CollisionPolygonSpatialGizmo, EditorSpatialGizmo); +class BakedIndirectLightGizmoPlugin : public EditorSpatialGizmoPlugin { - CollisionPolygon *polygon; + GDCLASS(BakedIndirectLightGizmoPlugin, EditorSpatialGizmoPlugin); public: - void redraw(); - CollisionPolygonSpatialGizmo(CollisionPolygon *p_polygon = NULL); -}; + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); -class RayCastSpatialGizmo : public EditorSpatialGizmo { + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); + + BakedIndirectLightGizmoPlugin(); +}; - GDCLASS(RayCastSpatialGizmo, EditorSpatialGizmo); +class CollisionShapeSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - RayCast *raycast; + GDCLASS(CollisionShapeSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - void redraw(); - RayCastSpatialGizmo(RayCast *p_raycast = NULL); -}; + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); + + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); -class VehicleWheelSpatialGizmo : public EditorSpatialGizmo { + CollisionShapeSpatialGizmoPlugin(); +}; - GDCLASS(VehicleWheelSpatialGizmo, EditorSpatialGizmo); +class CollisionPolygonSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - VehicleWheel *car_wheel; + GDCLASS(CollisionPolygonSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - void redraw(); - VehicleWheelSpatialGizmo(VehicleWheel *p_car_wheel = NULL); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); + + CollisionPolygonSpatialGizmoPlugin(); }; -class NavigationMeshSpatialGizmo : public EditorSpatialGizmo { +class NavigationMeshSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - GDCLASS(NavigationMeshSpatialGizmo, EditorSpatialGizmo); + GDCLASS(NavigationMeshSpatialGizmoPlugin, EditorSpatialGizmoPlugin); struct _EdgeKey { @@ -408,11 +353,12 @@ class NavigationMeshSpatialGizmo : public EditorSpatialGizmo { bool operator<(const _EdgeKey &p_with) const { return from == p_with.from ? to < p_with.to : from < p_with.from; } }; - NavigationMeshInstance *navmesh; - public: - void redraw(); - NavigationMeshSpatialGizmo(NavigationMeshInstance *p_navmesh = NULL); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); + + NavigationMeshSpatialGizmoPlugin(); }; class JointGizmosDrawer { @@ -421,7 +367,7 @@ public: static Basis look_body_toward(Vector3::Axis p_axis, const Transform &joint_transform, const Transform &body_transform); static Basis look_body_toward_x(const Transform &p_joint_transform, const Transform &p_body_transform); static Basis look_body_toward_y(const Transform &p_joint_transform, const Transform &p_body_transform); - /// Special function just used for physics joints, it that returns a basis constrained toward Joint Z axis + /// Special function just used for physics joints, it returns a basis constrained toward Joint Z axis /// with axis X and Y that are looking toward the body and oriented toward up static Basis look_body_toward_z(const Transform &p_joint_transform, const Transform &p_body_transform); @@ -430,66 +376,20 @@ public: static void draw_cone(const Transform &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points); }; -class PinJointSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(PinJointSpatialGizmo, EditorSpatialGizmo); - - PinJoint *p3d; - -public: - static void CreateGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points); - - void redraw(); - PinJointSpatialGizmo(PinJoint *p_p3d = NULL); -}; - -class HingeJointSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(HingeJointSpatialGizmo, EditorSpatialGizmo); - - HingeJoint *p3d; - -public: - static void CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); - - void redraw(); - HingeJointSpatialGizmo(HingeJoint *p_p3d = NULL); -}; - -class SliderJointSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(SliderJointSpatialGizmo, EditorSpatialGizmo); - - SliderJoint *p3d; - -public: - static void CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); - - void redraw(); - SliderJointSpatialGizmo(SliderJoint *p_p3d = NULL); -}; - -class ConeTwistJointSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(ConeTwistJointSpatialGizmo, EditorSpatialGizmo); +class JointSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - ConeTwistJoint *p3d; + GDCLASS(JointSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - static void CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); - - void redraw(); - ConeTwistJointSpatialGizmo(ConeTwistJoint *p_p3d = NULL); -}; - -class Generic6DOFJointSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(Generic6DOFJointSpatialGizmo, EditorSpatialGizmo); - - Generic6DOFJoint *p3d; - -public: - static void CreateGizmo( + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); + + static void CreatePinJointGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points); + static void CreateHingeJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); + static void CreateSliderJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); + static void CreateConeTwistJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); + static void CreateGeneric6DOFJointGizmo( const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, @@ -516,26 +416,7 @@ public: Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); - void redraw(); - Generic6DOFJointSpatialGizmo(Generic6DOFJoint *p_p3d = NULL); + JointSpatialGizmoPlugin(); }; -class SpatialEditorGizmos { - -public: - HashMap<String, Ref<SpatialMaterial> > material_cache; - - Ref<SpatialMaterial> handle2_material; - Ref<SpatialMaterial> handle2_material_billboard; - Ref<SpatialMaterial> handle_material; - Ref<SpatialMaterial> handle_material_billboard; - Ref<Texture> handle_t; - Ref<ArrayMesh> pos3d_mesh; - Ref<ArrayMesh> listener_line_mesh; - static SpatialEditorGizmos *singleton; - - Ref<SpatialEditorGizmo> get_gizmo(Spatial *p_spatial); - - SpatialEditorGizmos(); -}; #endif // SPATIAL_EDITOR_GIZMOS_H |