diff options
Diffstat (limited to 'editor/plugins')
20 files changed, 787 insertions, 168 deletions
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index bbaf41e3cc..41f35c3bed 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -670,6 +670,7 @@ Dictionary AnimationPlayerEditor::get_state() const { if (EditorNode::get_singleton()->get_edited_scene() && is_visible_in_tree() && player) { d["player"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(player); d["animation"] = player->get_assigned_animation(); + d["track_editor_state"] = track_editor->get_state(); } return d; @@ -696,6 +697,10 @@ void AnimationPlayerEditor::set_state(const Dictionary &p_state) { _animation_edit(); } } + + if (p_state.has("track_editor_state")) { + track_editor->set_state(p_state["track_editor_state"]); + } } } diff --git a/editor/plugins/animation_tree_player_editor_plugin.cpp b/editor/plugins/animation_tree_player_editor_plugin.cpp index e2a44069d9..e21ae4834d 100644 --- a/editor/plugins/animation_tree_player_editor_plugin.cpp +++ b/editor/plugins/animation_tree_player_editor_plugin.cpp @@ -200,7 +200,8 @@ void AnimationTreePlayerEditor::_edit_dialog_changed() { if (anim_tree->transition_node_get_current(edited_node) != edit_option->get_selected()) anim_tree->transition_node_set_current(edited_node, edit_option->get_selected()); } break; - default: {} + default: { + } } } @@ -457,7 +458,8 @@ void AnimationTreePlayerEditor::_popup_edit_dialog() { edit_dialog->set_size(Size2(150, 100)); } break; - default: {} + default: { + } } } @@ -555,7 +557,8 @@ void AnimationTreePlayerEditor::_draw_node(const StringName &p_node) { text += "->"; break; - default: {} + default: { + } } font->draw(ci, ofs + ascofs + Point2(3, 0), text, font_color); @@ -740,7 +743,8 @@ void AnimationTreePlayerEditor::_gui_input(Ref<InputEvent> p_event) { //open editor //_node_edit_property(click_node); } break; - default: {} + default: { + } } } if (mb->get_button_index() == 2) { @@ -817,7 +821,8 @@ void AnimationTreePlayerEditor::_gui_input(Ref<InputEvent> p_event) { anim_tree->node_set_position(click_node, new_pos); } break; - default: {} + default: { + } } click_type = CLICK_NONE; diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 6d2cdfc583..386bc1738e 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -454,7 +454,8 @@ void EditorAssetLibraryItemDownload::_notification(int p_what) { progress->set_max(1); progress->set_value(0); } break; - default: {} + default: { + } } prev_status = cstatus; } @@ -612,7 +613,8 @@ void EditorAssetLibrary::_notification(int p_what) { case HTTPClient::STATUS_BODY: { load_status->set_value(0.4); } break; - default: {} + default: { + } } } diff --git a/editor/plugins/baked_lightmap_editor_plugin.cpp b/editor/plugins/baked_lightmap_editor_plugin.cpp index d90ff95c1f..d75f06de12 100644 --- a/editor/plugins/baked_lightmap_editor_plugin.cpp +++ b/editor/plugins/baked_lightmap_editor_plugin.cpp @@ -50,7 +50,8 @@ void BakedLightmapEditorPlugin::_bake() { case BakedLightmap::BAKE_ERROR_CANT_CREATE_IMAGE: EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images, make sure path is writable.")); break; - default: {} + default: { + } } } } diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index c3cac582ad..b2923a1ff2 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -1340,6 +1340,10 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) { // Confirms the node rotation if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) { _commit_canvas_item_state(drag_selection, TTR("Rotate CanvasItem")); + if (key_auto_insert_button->is_pressed()) { + _insert_animation_keys(false, true, false, true); + } + drag_type = DRAG_NONE; return true; } @@ -1641,6 +1645,9 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) { // Confirm resize if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) { _commit_canvas_item_state(drag_selection, TTR("Resize CanvasItem")); + if (key_auto_insert_button->is_pressed()) { + _insert_animation_keys(false, false, true, true); + } drag_type = DRAG_NONE; viewport->update(); return true; @@ -1747,6 +1754,10 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) { // Confirm resize if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) { _commit_canvas_item_state(drag_selection, TTR("Scale CanvasItem")); + if (key_auto_insert_button->is_pressed()) { + _insert_animation_keys(false, false, true, true); + } + drag_type = DRAG_NONE; viewport->update(); return true; @@ -1852,6 +1863,9 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { _commit_canvas_item_state(drag_selection, TTR("Move CanvasItem"), true); } + if (key_auto_insert_button->is_pressed()) { + _insert_animation_keys(true, false, false, true); + } drag_type = DRAG_NONE; viewport->update(); return true; @@ -3384,6 +3398,7 @@ void CanvasItemEditor::_notification(int p_what) { key_rot_button->set_icon(get_icon("KeyRotation", "EditorIcons")); key_scale_button->set_icon(get_icon("KeyScale", "EditorIcons")); key_insert_button->set_icon(get_icon("Key", "EditorIcons")); + key_auto_insert_button->set_icon(get_icon("AutoKey", "EditorIcons")); zoom_minus->set_icon(get_icon("ZoomLess", "EditorIcons")); zoom_reset->set_icon(get_icon("ZoomReset", "EditorIcons")); @@ -3716,6 +3731,77 @@ void CanvasItemEditor::_button_tool_select(int p_index) { tool = (Tool)p_index; } +void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation, bool p_scale, bool p_on_existing) { + + Map<Node *, Object *> &selection = editor_selection->get_selection(); + + for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { + + CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->key()); + if (!canvas_item || !canvas_item->is_visible_in_tree()) + continue; + + if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) + continue; + + if (Object::cast_to<Node2D>(canvas_item)) { + Node2D *n2d = Object::cast_to<Node2D>(canvas_item); + + if (key_pos && p_location) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "position", n2d->get_position(), p_on_existing); + if (key_rot && p_rotation) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "rotation_degrees", Math::rad2deg(n2d->get_rotation()), p_on_existing); + if (key_scale && p_scale) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "scale", n2d->get_scale(), p_on_existing); + + if (n2d->has_meta("_edit_bone_") && n2d->get_parent_item()) { + //look for an IK chain + List<Node2D *> ik_chain; + + Node2D *n = Object::cast_to<Node2D>(n2d->get_parent_item()); + bool has_chain = false; + + while (n) { + + ik_chain.push_back(n); + if (n->has_meta("_edit_ik_")) { + has_chain = true; + break; + } + + if (!n->get_parent_item()) + break; + n = Object::cast_to<Node2D>(n->get_parent_item()); + } + + if (has_chain && ik_chain.size()) { + + for (List<Node2D *>::Element *F = ik_chain.front(); F; F = F->next()) { + + if (key_pos) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "position", F->get()->get_position(), p_on_existing); + if (key_rot) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "rotation_degrees", Math::rad2deg(F->get()->get_rotation()), p_on_existing); + if (key_scale) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "scale", F->get()->get_scale(), p_on_existing); + } + } + } + + } else if (Object::cast_to<Control>(canvas_item)) { + + Control *ctrl = Object::cast_to<Control>(canvas_item); + + if (key_pos) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_position", ctrl->get_position(), p_on_existing); + if (key_rot) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_rotation", ctrl->get_rotation_degrees(), p_on_existing); + if (key_scale) + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_size", ctrl->get_size(), p_on_existing); + } + } +} + void CanvasItemEditor::_popup_callback(int p_op) { last_option = MenuOption(p_op); @@ -3983,73 +4069,7 @@ void CanvasItemEditor::_popup_callback(int p_op) { bool existing = p_op == ANIM_INSERT_KEY_EXISTING; - Map<Node *, Object *> &selection = editor_selection->get_selection(); - - for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { - - CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->key()); - if (!canvas_item || !canvas_item->is_visible_in_tree()) - continue; - - if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) - continue; - - if (Object::cast_to<Node2D>(canvas_item)) { - Node2D *n2d = Object::cast_to<Node2D>(canvas_item); - - if (key_pos) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "position", n2d->get_position(), existing); - if (key_rot) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "rotation_degrees", Math::rad2deg(n2d->get_rotation()), existing); - if (key_scale) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "scale", n2d->get_scale(), existing); - - if (n2d->has_meta("_edit_bone_") && n2d->get_parent_item()) { - //look for an IK chain - List<Node2D *> ik_chain; - - Node2D *n = Object::cast_to<Node2D>(n2d->get_parent_item()); - bool has_chain = false; - - while (n) { - - ik_chain.push_back(n); - if (n->has_meta("_edit_ik_")) { - has_chain = true; - break; - } - - if (!n->get_parent_item()) - break; - n = Object::cast_to<Node2D>(n->get_parent_item()); - } - - if (has_chain && ik_chain.size()) { - - for (List<Node2D *>::Element *F = ik_chain.front(); F; F = F->next()) { - - if (key_pos) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "position", F->get()->get_position(), existing); - if (key_rot) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "rotation_degrees", Math::rad2deg(F->get()->get_rotation()), existing); - if (key_scale) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "scale", F->get()->get_scale(), existing); - } - } - } - - } else if (Object::cast_to<Control>(canvas_item)) { - - Control *ctrl = Object::cast_to<Control>(canvas_item); - - if (key_pos) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_position", ctrl->get_position(), existing); - if (key_rot) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_rotation", ctrl->get_rotation_degrees(), existing); - if (key_scale) - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_size", ctrl->get_size(), existing); - } - } + _insert_animation_keys(true, true, true, existing); } break; case ANIM_INSERT_POS: { @@ -4866,6 +4886,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { key_loc_button->set_pressed(true); key_loc_button->set_focus_mode(FOCUS_NONE); key_loc_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_POS)); + key_loc_button->set_tooltip(TTR("Translation mask for inserting keys.")); animation_hb->add_child(key_loc_button); key_rot_button = memnew(Button); key_rot_button->set_toggle_mode(true); @@ -4873,21 +4894,30 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { key_rot_button->set_pressed(true); key_rot_button->set_focus_mode(FOCUS_NONE); key_rot_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_ROT)); + key_rot_button->set_tooltip(TTR("Rotation mask for inserting keys.")); animation_hb->add_child(key_rot_button); key_scale_button = memnew(Button); key_scale_button->set_toggle_mode(true); key_scale_button->set_flat(true); key_scale_button->set_focus_mode(FOCUS_NONE); key_scale_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_SCALE)); + key_scale_button->set_tooltip(TTR("Scale mask for inserting keys.")); animation_hb->add_child(key_scale_button); key_insert_button = memnew(Button); key_insert_button->set_flat(true); key_insert_button->set_focus_mode(FOCUS_NONE); key_insert_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_KEY)); - key_insert_button->set_tooltip(TTR("Insert keys.")); + key_insert_button->set_tooltip(TTR("Insert keys (based on mask).")); key_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_insert_key", TTR("Insert Key"), KEY_INSERT)); - animation_hb->add_child(key_insert_button); + key_auto_insert_button = memnew(Button); + key_auto_insert_button->set_flat(true); + key_auto_insert_button->set_toggle_mode(true); + key_auto_insert_button->set_focus_mode(FOCUS_NONE); + //key_auto_insert_button->connect("pressed", this, "_popup_callback", varray(ANIM_INSERT_KEY)); + key_auto_insert_button->set_tooltip(TTR("Auto insert keys when objects are translated, rotated on scaled (based on mask).\nKeys are only added to existing tracks, no new tracks will be created.\nKeys must be inserted manually for the first time.")); + key_auto_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_auto_insert_key", TTR("Auto Insert Key"))); + animation_hb->add_child(key_auto_insert_button); animation_menu = memnew(MenuButton); animation_menu->set_text(TTR("Animation")); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 9173c55ae0..14ea81f302 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -351,6 +351,7 @@ private: Button *key_rot_button; Button *key_scale_button; Button *key_insert_button; + Button *key_auto_insert_button; PopupMenu *selection_menu; @@ -422,6 +423,8 @@ private: Object *_get_editor_data(Object *p_what); + void _insert_animation_keys(bool p_location, bool p_rotation, bool p_scale, bool p_on_existing); + void _keying_changed(); void _unhandled_key_input(const Ref<InputEvent> &p_ev); diff --git a/editor/plugins/item_list_editor_plugin.h b/editor/plugins/item_list_editor_plugin.h index 679235e316..701632e576 100644 --- a/editor/plugins/item_list_editor_plugin.h +++ b/editor/plugins/item_list_editor_plugin.h @@ -157,7 +157,7 @@ public: virtual void set_item_enabled(int p_idx, int p_enabled) { pp->set_item_disabled(p_idx, !p_enabled); } virtual bool is_item_enabled(int p_idx) const { return !pp->is_item_disabled(p_idx); } - virtual void set_item_id(int p_idx, int p_id) { pp->set_item_id(p_idx, p_idx); } + virtual void set_item_id(int p_idx, int p_id) { pp->set_item_id(p_idx, p_id); } virtual int get_item_id(int p_idx) const { return pp->get_item_id(p_idx); } virtual void set_item_separator(int p_idx, bool p_separator) { pp->set_item_as_separator(p_idx, p_separator); } diff --git a/editor/plugins/mesh_instance_editor_plugin.cpp b/editor/plugins/mesh_instance_editor_plugin.cpp index 3e10cdbbfa..cf111dc4ce 100644 --- a/editor/plugins/mesh_instance_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_editor_plugin.cpp @@ -95,10 +95,7 @@ void MeshInstanceEditor::_menu_option(int p_option) { return; } - if (trimesh_shape) - ur->create_action(TTR("Create Static Trimesh Body")); - else - ur->create_action(TTR("Create Static Convex Body")); + ur->create_action(TTR("Create Static Trimesh Body")); for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { @@ -132,8 +129,7 @@ void MeshInstanceEditor::_menu_option(int p_option) { } break; - case MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE: - case MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE: { + case MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE: { if (node == get_tree()->get_edited_scene_root()) { err_dialog->set_text(TTR("This doesn't work on scene root!")); @@ -141,9 +137,7 @@ void MeshInstanceEditor::_menu_option(int p_option) { return; } - bool trimesh_shape = (p_option == MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE); - - Ref<Shape> shape = trimesh_shape ? mesh->create_trimesh_shape() : mesh->create_convex_shape(); + Ref<Shape> shape = mesh->create_trimesh_shape(); if (shape.is_null()) return; @@ -154,10 +148,7 @@ void MeshInstanceEditor::_menu_option(int p_option) { UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - if (trimesh_shape) - ur->create_action(TTR("Create Trimesh Shape")); - else - ur->create_action(TTR("Create Convex Shape")); + ur->create_action(TTR("Create Trimesh Static Shape")); ur->add_do_method(node->get_parent(), "add_child", cshape); ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1); @@ -165,6 +156,40 @@ void MeshInstanceEditor::_menu_option(int p_option) { ur->add_do_reference(cshape); ur->add_undo_method(node->get_parent(), "remove_child", cshape); ur->commit_action(); + } break; + case MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE: { + + if (node == get_tree()->get_edited_scene_root()) { + err_dialog->set_text(TTR("This doesn't work on scene root!")); + err_dialog->popup_centered_minsize(); + return; + } + + Vector<Ref<Shape> > shapes = mesh->convex_decompose(); + + if (!shapes.size()) { + err_dialog->set_text(TTR("Failed creating shapes!")); + err_dialog->popup_centered_minsize(); + return; + } + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + + ur->create_action(TTR("Create Convex Shape(s)")); + + for (int i = 0; i < shapes.size(); i++) { + + CollisionShape *cshape = memnew(CollisionShape); + cshape->set_shape(shapes[i]); + + Node *owner = node->get_owner(); + + ur->add_do_method(node->get_parent(), "add_child", cshape); + ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1); + ur->add_do_method(cshape, "set_owner", owner); + ur->add_do_reference(cshape); + ur->add_undo_method(node->get_parent(), "remove_child", cshape); + } + ur->commit_action(); } break; @@ -393,10 +418,9 @@ MeshInstanceEditor::MeshInstanceEditor() { options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MeshInstance", "EditorIcons")); options->get_popup()->add_item(TTR("Create Trimesh Static Body"), MENU_OPTION_CREATE_STATIC_TRIMESH_BODY); - options->get_popup()->add_item(TTR("Create Convex Static Body"), MENU_OPTION_CREATE_STATIC_CONVEX_BODY); options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Create Trimesh Collision Sibling"), MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE); - options->get_popup()->add_item(TTR("Create Convex Collision Sibling"), MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE); + options->get_popup()->add_item(TTR("Create Convex Collision Sibling(s)"), MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE); options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Create Navigation Mesh"), MENU_OPTION_CREATE_NAVMESH); options->get_popup()->add_separator(); diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp index 89eb253afe..18586b2fe5 100644 --- a/editor/plugins/mesh_library_editor_plugin.cpp +++ b/editor/plugins/mesh_library_editor_plugin.cpp @@ -61,7 +61,8 @@ void MeshLibraryEditor::_menu_confirm() { _import_scene_cbk(existing); } break; - default: {}; + default: { + }; } } diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 0dbbaf4177..af43f679fd 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -905,7 +905,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) { bone_paint_pos = Vector2(mm->get_position().x, mm->get_position().y); } break; - default: {} + default: { + } } if (bone_painting) { diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 42aba78e96..d7d4cec07d 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -1735,7 +1735,7 @@ void ScriptEditor::_update_script_names() { String name = eh->get_class(); Ref<Texture> icon = get_icon("Help", "EditorIcons"); - String tooltip = name + TTR(" Class Reference"); + String tooltip = vformat(TTR("%s Class Reference"), name); _ScriptEditorItemData sd; sd.icon = icon; diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 9fc42e3862..c586985957 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -81,6 +81,8 @@ void ScriptTextEditor::set_edited_resource(const RES &p_res) { emit_signal("name_changed"); code_editor->update_line_and_column(); + + _validate_script(); } void ScriptTextEditor::_update_member_keywords() { @@ -286,7 +288,7 @@ void ScriptTextEditor::_warning_clicked(Variant p_line) { 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); + code_editor->get_text_edit()->insert_at("# warning-ignore:" + meta["code"].operator String(), meta["line"].operator int64_t() - 1); _validate_script(); } } diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index f48887d342..ba297539d3 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -1637,7 +1637,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { surface->update(); } break; - default: {} + default: { + } } } @@ -1704,7 +1705,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } break; - default: {} + default: { + } } } @@ -1760,7 +1762,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } break; - default: {} + default: { + } } } diff --git a/editor/plugins/sprite_editor_plugin.cpp b/editor/plugins/sprite_editor_plugin.cpp index 3854d27567..fbc72b1396 100644 --- a/editor/plugins/sprite_editor_plugin.cpp +++ b/editor/plugins/sprite_editor_plugin.cpp @@ -31,7 +31,10 @@ #include "sprite_editor_plugin.h" #include "canvas_item_editor_plugin.h" +#include "scene/2d/collision_polygon_2d.h" +#include "scene/2d/light_occluder_2d.h" #include "scene/2d/mesh_instance_2d.h" +#include "scene/2d/polygon_2d.h" #include "scene/gui/box_container.h" #include "thirdparty/misc/clipper.hpp" @@ -116,8 +119,42 @@ void SpriteEditor::_menu_option(int p_option) { return; } + selected_menu_item = (Menu)p_option; + switch (p_option) { - case MENU_OPTION_CREATE_MESH_2D: { + case MENU_OPTION_CONVERT_TO_MESH_2D: { + + debug_uv_dialog->get_ok()->set_text(TTR("Create Mesh2D")); + debug_uv_dialog->set_title("Mesh2D Preview"); + + _update_mesh_data(); + debug_uv_dialog->popup_centered(); + debug_uv->update(); + + } break; + case MENU_OPTION_CONVERT_TO_POLYGON_2D: { + + debug_uv_dialog->get_ok()->set_text(TTR("Create Polygon2D")); + debug_uv_dialog->set_title("Polygon2D Preview"); + + _update_mesh_data(); + debug_uv_dialog->popup_centered(); + debug_uv->update(); + } break; + case MENU_OPTION_CREATE_COLLISION_POLY_2D: { + + debug_uv_dialog->get_ok()->set_text(TTR("Create CollisionPolygon2D")); + debug_uv_dialog->set_title("CollisionPolygon2D Preview"); + + _update_mesh_data(); + debug_uv_dialog->popup_centered(); + debug_uv->update(); + + } break; + case MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D: { + + debug_uv_dialog->get_ok()->set_text(TTR("Create LightOccluder2D")); + debug_uv_dialog->set_title("LightOccluder2D Preview"); _update_mesh_data(); debug_uv_dialog->popup_centered(); @@ -169,47 +206,107 @@ void SpriteEditor::_update_mesh_data() { computed_indices.clear(); Size2 img_size = Vector2(image->get_width(), image->get_height()); - for (int j = 0; j < lines.size(); j++) { - lines.write[j] = expand(lines[j], rect, epsilon); + for (int i = 0; i < lines.size(); i++) { + lines.write[i] = expand(lines[i], rect, epsilon); + } + + if (selected_menu_item == MENU_OPTION_CONVERT_TO_MESH_2D) { + + for (int j = 0; j < lines.size(); j++) { + int index_ofs = computed_vertices.size(); + + for (int i = 0; i < lines[j].size(); i++) { + Vector2 vtx = lines[j][i]; + computed_uv.push_back(vtx / img_size); - int index_ofs = computed_vertices.size(); + vtx -= rect.position; //offset by rect position - for (int i = 0; i < lines[j].size(); i++) { - Vector2 vtx = lines[j][i]; - computed_uv.push_back(vtx / img_size); + //flip if flipped + if (node->is_flipped_h()) + vtx.x = rect.size.x - vtx.x - 1.0; + if (node->is_flipped_v()) + vtx.y = rect.size.y - vtx.y - 1.0; - vtx -= rect.position; //offset by rect position + if (node->is_centered()) + vtx -= rect.size / 2.0; - //flip if flipped - if (node->is_flipped_h()) - vtx.x = rect.size.x - vtx.x - 1.0; - if (node->is_flipped_v()) - vtx.y = rect.size.y - vtx.y - 1.0; + computed_vertices.push_back(vtx); + } + + Vector<int> poly = Geometry::triangulate_polygon(lines[j]); - if (node->is_centered()) - vtx -= rect.size / 2.0; + for (int i = 0; i < poly.size(); i += 3) { + for (int k = 0; k < 3; k++) { + int idx = i + k; + int idxn = i + (k + 1) % 3; + uv_lines.push_back(lines[j][poly[idx]]); + uv_lines.push_back(lines[j][poly[idxn]]); - computed_vertices.push_back(vtx); + computed_indices.push_back(poly[idx] + index_ofs); + } + } } + } - Vector<int> poly = Geometry::triangulate_polygon(lines[j]); + outline_lines.clear(); + computed_outline_lines.clear(); - for (int i = 0; i < poly.size(); i += 3) { - for (int k = 0; k < 3; k++) { - int idx = i + k; - int idxn = i + (k + 1) % 3; - uv_lines.push_back(lines[j][poly[idx]]); - uv_lines.push_back(lines[j][poly[idxn]]); + if (selected_menu_item == MENU_OPTION_CONVERT_TO_POLYGON_2D || selected_menu_item == MENU_OPTION_CREATE_COLLISION_POLY_2D || selected_menu_item == MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D) { + outline_lines.resize(lines.size()); + computed_outline_lines.resize(lines.size()); + for (int pi = 0; pi < lines.size(); pi++) { + + Vector<Vector2> ol; + Vector<Vector2> col; + + ol.resize(lines[pi].size()); + col.resize(lines[pi].size()); + + for (int i = 0; i < lines[pi].size(); i++) { + Vector2 vtx = lines[pi][i]; + + ol.write[i] = vtx; + + vtx -= rect.position; //offset by rect position + + //flip if flipped + if (node->is_flipped_h()) + vtx.x = rect.size.x - vtx.x - 1.0; + if (node->is_flipped_v()) + vtx.y = rect.size.y - vtx.y - 1.0; + + if (node->is_centered()) + vtx -= rect.size / 2.0; - computed_indices.push_back(poly[idx] + index_ofs); + col.write[i] = vtx; } + + outline_lines.write[pi] = ol; + computed_outline_lines.write[pi] = col; } } debug_uv->update(); } -void SpriteEditor::_create_mesh_node() { +void SpriteEditor::_create_node() { + switch (selected_menu_item) { + case MENU_OPTION_CONVERT_TO_MESH_2D: { + _convert_to_mesh_2d_node(); + } break; + case MENU_OPTION_CONVERT_TO_POLYGON_2D: { + _convert_to_polygon_2d_node(); + } break; + case MENU_OPTION_CREATE_COLLISION_POLY_2D: { + _create_collision_polygon_2d_node(); + } break; + case MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D: { + _create_light_occluder_2d_node(); + } break; + } +} + +void SpriteEditor::_convert_to_mesh_2d_node() { if (computed_vertices.size() < 3) { err_dialog->set_text(TTR("Invalid geometry, can't replace by mesh.")); @@ -233,6 +330,117 @@ void SpriteEditor::_create_mesh_node() { EditorNode::get_singleton()->get_scene_tree_dock()->replace_node(node, mesh_instance); } +void SpriteEditor::_convert_to_polygon_2d_node() { + Polygon2D *polygon_2d_instance = memnew(Polygon2D); + + int total_point_count = 0; + for (int i = 0; i < computed_outline_lines.size(); i++) + total_point_count += computed_outline_lines[i].size(); + + PoolVector2Array polygon; + polygon.resize(total_point_count); + PoolVector2Array::Write polygon_write = polygon.write(); + + PoolVector2Array uvs; + uvs.resize(total_point_count); + PoolVector2Array::Write uvs_write = uvs.write(); + + int current_point_index = 0; + + Array polys; + polys.resize(computed_outline_lines.size()); + + for (int i = 0; i < computed_outline_lines.size(); i++) { + + Vector<Vector2> outline = computed_outline_lines[i]; + Vector<Vector2> uv_outline = outline_lines[i]; + + if (outline.size() < 3) { + err_dialog->set_text(TTR("Invalid geometry, can't create polygon.")); + err_dialog->popup_centered_minsize(); + return; + } + + PoolIntArray pia; + pia.resize(outline.size()); + PoolIntArray::Write pia_write = pia.write(); + + for (int pi = 0; pi < outline.size(); pi++) { + polygon_write[current_point_index] = outline[pi]; + uvs_write[current_point_index] = uv_outline[pi]; + pia_write[pi] = current_point_index; + current_point_index++; + } + + polys[i] = pia; + } + + polygon_2d_instance->set_uv(uvs); + polygon_2d_instance->set_polygon(polygon); + polygon_2d_instance->set_polygons(polys); + + EditorNode::get_singleton()->get_scene_tree_dock()->replace_node(node, polygon_2d_instance); +} + +void SpriteEditor::_create_collision_polygon_2d_node() { + for (int i = 0; i < computed_outline_lines.size(); i++) { + + Vector<Vector2> outline = computed_outline_lines[i]; + + if (outline.size() < 3) { + err_dialog->set_text(TTR("Invalid geometry, can't create collision polygon.")); + err_dialog->popup_centered_minsize(); + continue; + } + + CollisionPolygon2D *collision_polygon_2d_instance = memnew(CollisionPolygon2D); + collision_polygon_2d_instance->set_polygon(outline); + + _add_as_sibling_or_child(node, collision_polygon_2d_instance); + } +} + +void SpriteEditor::_create_light_occluder_2d_node() { + for (int i = 0; i < computed_outline_lines.size(); i++) { + + Vector<Vector2> outline = computed_outline_lines[i]; + + if (outline.size() < 3) { + err_dialog->set_text(TTR("Invalid geometry, can't create light occluder.")); + err_dialog->popup_centered_minsize(); + continue; + } + + Ref<OccluderPolygon2D> polygon; + polygon.instance(); + + PoolVector2Array a; + a.resize(outline.size()); + PoolVector2Array::Write aw = a.write(); + for (int io = 0; io < outline.size(); io++) { + aw[io] = outline[io]; + } + polygon->set_polygon(a); + + LightOccluder2D *light_occluder_2d_instance = memnew(LightOccluder2D); + light_occluder_2d_instance->set_occluder_polygon(polygon); + + _add_as_sibling_or_child(node, light_occluder_2d_instance); + } +} + +void SpriteEditor::_add_as_sibling_or_child(Node2D *p_own_node, Node2D *p_new_node) { + // Can't make sibling if own node is scene root + if (p_own_node != this->get_tree()->get_edited_scene_root()) { + p_own_node->get_parent()->add_child(p_new_node, true); + p_new_node->set_transform(p_own_node->get_transform()); + } else { + p_own_node->add_child(p_new_node, true); + } + + p_new_node->set_owner(this->get_tree()->get_edited_scene_root()); +} + #if 0 void SpriteEditor::_create_uv_lines() { @@ -298,16 +506,26 @@ void SpriteEditor::_create_uv_lines() { #endif void SpriteEditor::_debug_uv_draw() { - if (uv_lines.size() == 0) - return; - Ref<Texture> tex = node->get_texture(); ERR_FAIL_COND(!tex.is_valid()); debug_uv->set_clip_contents(true); debug_uv->draw_texture(tex, Point2()); debug_uv->set_custom_minimum_size(tex->get_size()); //debug_uv->draw_set_transform(Vector2(), 0, debug_uv->get_size()); - debug_uv->draw_multiline(uv_lines, Color(1.0, 0.8, 0.7)); + + Color color = Color(1.0, 0.8, 0.7); + + if (selected_menu_item == MENU_OPTION_CONVERT_TO_MESH_2D && uv_lines.size() > 0) { + debug_uv->draw_multiline(uv_lines, color); + + } else if ((selected_menu_item == MENU_OPTION_CONVERT_TO_POLYGON_2D || selected_menu_item == MENU_OPTION_CREATE_COLLISION_POLY_2D || selected_menu_item == MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D) && outline_lines.size() > 0) { + for (int i = 0; i < outline_lines.size(); i++) { + Vector<Vector2> outline = outline_lines[i]; + + debug_uv->draw_polyline(outline, color); + debug_uv->draw_line(outline[0], outline[outline.size() - 1], color); + } + } } void SpriteEditor::_bind_methods() { @@ -315,7 +533,7 @@ void SpriteEditor::_bind_methods() { ClassDB::bind_method("_menu_option", &SpriteEditor::_menu_option); ClassDB::bind_method("_debug_uv_draw", &SpriteEditor::_debug_uv_draw); ClassDB::bind_method("_update_mesh_data", &SpriteEditor::_update_mesh_data); - ClassDB::bind_method("_create_mesh_node", &SpriteEditor::_create_mesh_node); + ClassDB::bind_method("_create_node", &SpriteEditor::_create_node); } SpriteEditor::SpriteEditor() { @@ -327,7 +545,10 @@ SpriteEditor::SpriteEditor() { options->set_text(TTR("Sprite")); options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Sprite", "EditorIcons")); - options->get_popup()->add_item(TTR("Convert to 2D Mesh"), MENU_OPTION_CREATE_MESH_2D); + options->get_popup()->add_item(TTR("Convert to Mesh2D"), MENU_OPTION_CONVERT_TO_MESH_2D); + options->get_popup()->add_item(TTR("Convert to Polygon2D"), MENU_OPTION_CONVERT_TO_POLYGON_2D); + options->get_popup()->add_item(TTR("Create CollisionPolygon2D Sibling"), MENU_OPTION_CREATE_COLLISION_POLY_2D); + options->get_popup()->add_item(TTR("Create LightOccluder2D Sibling"), MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D); options->get_popup()->connect("id_pressed", this, "_menu_option"); @@ -335,7 +556,7 @@ SpriteEditor::SpriteEditor() { add_child(err_dialog); debug_uv_dialog = memnew(ConfirmationDialog); - debug_uv_dialog->get_ok()->set_text(TTR("Create 2D Mesh")); + debug_uv_dialog->get_ok()->set_text(TTR("Create Mesh2D")); debug_uv_dialog->set_title("Mesh 2D Preview"); VBoxContainer *vb = memnew(VBoxContainer); debug_uv_dialog->add_child(vb); @@ -347,7 +568,7 @@ SpriteEditor::SpriteEditor() { debug_uv = memnew(Control); debug_uv->connect("draw", this, "_debug_uv_draw"); scroll->add_child(debug_uv); - debug_uv_dialog->connect("confirmed", this, "_create_mesh_node"); + debug_uv_dialog->connect("confirmed", this, "_create_node"); HBoxContainer *hb = memnew(HBoxContainer); hb->add_child(memnew(Label(TTR("Simplification: ")))); diff --git a/editor/plugins/sprite_editor_plugin.h b/editor/plugins/sprite_editor_plugin.h index 7250e3df59..460f5a5707 100644 --- a/editor/plugins/sprite_editor_plugin.h +++ b/editor/plugins/sprite_editor_plugin.h @@ -41,9 +41,14 @@ class SpriteEditor : public Control { GDCLASS(SpriteEditor, Control); enum Menu { - MENU_OPTION_CREATE_MESH_2D, + MENU_OPTION_CONVERT_TO_MESH_2D, + MENU_OPTION_CONVERT_TO_POLYGON_2D, + MENU_OPTION_CREATE_COLLISION_POLY_2D, + MENU_OPTION_CREATE_LIGHT_OCCLUDER_2D }; + Menu selected_menu_item; + Sprite *node; MenuButton *options; @@ -55,7 +60,8 @@ class SpriteEditor : public Control { ConfirmationDialog *debug_uv_dialog; Control *debug_uv; Vector<Vector2> uv_lines; - + Vector<Vector<Vector2> > outline_lines; + Vector<Vector<Vector2> > computed_outline_lines; Vector<Vector2> computed_vertices; Vector<Vector2> computed_uv; Vector<int> computed_indices; @@ -71,7 +77,14 @@ class SpriteEditor : public Control { void _debug_uv_draw(); void _update_mesh_data(); - void _create_mesh_node(); + + void _create_node(); + void _convert_to_mesh_2d_node(); + void _convert_to_polygon_2d_node(); + void _create_collision_polygon_2d_node(); + void _create_light_occluder_2d_node(); + + void _add_as_sibling_or_child(Node2D *p_own_node, Node2D *p_new_node); protected: void _node_removed(Node *p_node); diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index 5ba2fde763..33b8347f94 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -38,11 +38,167 @@ void SpriteFramesEditor::_gui_input(Ref<InputEvent> p_event) { } +void SpriteFramesEditor::_open_sprite_sheet() { + + file_split_sheet->clear_filters(); + List<String> extensions; + ResourceLoader::get_recognized_extensions_for_type("Texture", &extensions); + for (int i = 0; i < extensions.size(); i++) { + file_split_sheet->add_filter("*." + extensions[i]); + } + + file_split_sheet->popup_centered_ratio(); +} + +void SpriteFramesEditor::_sheet_preview_draw() { + Size2i size = split_sheet_preview->get_size(); + int h = split_sheet_h->get_value(); + int v = split_sheet_v->get_value(); + const float a = 0.3; + for (int i = 1; i < h; i++) { + for (int j = 1; j < v; j++) { + + int x = i * size.width / h; + int y = i * size.height / v; + + split_sheet_preview->draw_line(Point2(x, 0), Point2(x, size.height), Color(1, 1, 1, a)); + split_sheet_preview->draw_line(Point2(x + 1, 0), Point2(x + 1, size.height), Color(0, 0, 0, a)); + + split_sheet_preview->draw_line(Point2(0, y), Point2(size.width, y), Color(1, 1, 1, a)); + split_sheet_preview->draw_line(Point2(0, y + 1), Point2(size.width, y + 1), Color(0, 0, 0, a)); + } + } + + Color accent = get_color("accent_color", "Editor"); + + for (Set<int>::Element *E = frames_selected.front(); E; E = E->next()) { + int idx = E->get(); + int x = (idx % h) * size.width / h; + int y = (idx / v) * size.height / v; + int width = size.width / h; + int height = size.height / v; + + split_sheet_preview->draw_rect(Rect2(x + 5, y + 5, width - 10, height - 10), Color(0, 0, 0, 0.35), true); + split_sheet_preview->draw_rect(Rect2(x + 0, y + 0, width - 0, height - 0), Color(0, 0, 0, 1), false); + split_sheet_preview->draw_rect(Rect2(x + 1, y + 1, width - 2, height - 2), Color(0, 0, 0, 1), false); + split_sheet_preview->draw_rect(Rect2(x + 2, y + 2, width - 4, height - 4), accent, false); + split_sheet_preview->draw_rect(Rect2(x + 3, y + 3, width - 6, height - 6), accent, false); + split_sheet_preview->draw_rect(Rect2(x + 4, y + 4, width - 8, height - 8), Color(0, 0, 0, 1), false); + split_sheet_preview->draw_rect(Rect2(x + 5, y + 5, width - 10, height - 10), Color(0, 0, 0, 1), false); + } + + if (frames_selected.size() == 0) { + split_sheet_dialog->get_ok()->set_disabled(true); + split_sheet_dialog->get_ok()->set_text(TTR("No frames selected")); + } else { + split_sheet_dialog->get_ok()->set_disabled(false); + split_sheet_dialog->get_ok()->set_text(vformat(TTR("Add %d frame(s)"), frames_selected.size())); + } +} +void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) { + + Ref<InputEventMouseButton> mb = p_event; + + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + Size2i size = split_sheet_preview->get_size(); + int h = split_sheet_h->get_value(); + int v = split_sheet_v->get_value(); + + int x = CLAMP(int(mb->get_position().x) * h / size.width, 0, h - 1); + int y = CLAMP(int(mb->get_position().y) * v / size.height, 0, v - 1); + + int idx = h * y + x; + + if (mb->get_shift() && last_frame_selected >= 0) { + //select multiple + int from = idx; + int to = last_frame_selected; + if (from > to) { + SWAP(from, to); + } + + for (int i = from; i <= to; i++) { + if (mb->get_control()) { + frames_selected.erase(i); + } else { + frames_selected.insert(i); + } + } + } else { + if (frames_selected.has(idx)) { + frames_selected.erase(idx); + } else { + frames_selected.insert(idx); + } + } + + last_frame_selected = idx; + split_sheet_preview->update(); + } +} + +void SpriteFramesEditor::_sheet_add_frames() { + + Size2i size = split_sheet_preview->get_size(); + int h = split_sheet_h->get_value(); + int v = split_sheet_v->get_value(); + + undo_redo->create_action(TTR("Add Frame")); + + int fc = frames->get_frame_count(edited_anim); + + for (Set<int>::Element *E = frames_selected.front(); E; E = E->next()) { + int idx = E->get(); + int x = (idx % h) * size.width / h; + int y = (idx / v) * size.height / v; + int width = size.width / h; + int height = size.height / v; + + Ref<AtlasTexture> at; + at.instance(); + at->set_atlas(split_sheet_preview->get_texture()); + at->set_region(Rect2(x, y, width, height)); + + undo_redo->add_do_method(frames, "add_frame", edited_anim, at, -1); + undo_redo->add_undo_method(frames, "remove_frame", edited_anim, fc); + } + + undo_redo->add_do_method(this, "_update_library"); + undo_redo->add_undo_method(this, "_update_library"); + undo_redo->commit_action(); +} + +void SpriteFramesEditor::_sheet_spin_changed(double) { + frames_selected.clear(); + last_frame_selected = -1; + split_sheet_preview->update(); +} + +void SpriteFramesEditor::_prepare_sprite_sheet(const String &p_file) { + + Ref<Resource> texture = ResourceLoader::load(p_file); + if (!texture.is_valid()) { + EditorNode::get_singleton()->show_warning("Unable to load images"); + ERR_FAIL_COND(!texture.is_valid()); + } + if (texture != split_sheet_preview->get_texture()) { + //different texture, reset to 4x4 + split_sheet_h->set_value(4); + split_sheet_v->set_value(4); + } + frames_selected.clear(); + last_frame_selected = -1; + + split_sheet_preview->set_texture(texture); + split_sheet_dialog->popup_centered_ratio(0.65); +} + void SpriteFramesEditor::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { load->set_icon(get_icon("Load", "EditorIcons")); + load_sheet->set_icon(get_icon("SpriteSheet", "EditorIcons")); copy->set_icon(get_icon("ActionCopy", "EditorIcons")); paste->set_icon(get_icon("ActionPaste", "EditorIcons")); empty->set_icon(get_icon("InsertBefore", "EditorIcons")); @@ -72,6 +228,7 @@ void SpriteFramesEditor::_file_load_request(const PoolVector<String> &p_path, in if (resource.is_null()) { dialog->set_text(TTR("ERROR: Couldn't load frame resource!")); dialog->set_title(TTR("Error!")); + //dialog->get_cancel()->set_text("Close"); dialog->get_ok()->set_text(TTR("Close")); dialog->popup_centered_minsize(); @@ -655,6 +812,12 @@ void SpriteFramesEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &SpriteFramesEditor::get_drag_data_fw); ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &SpriteFramesEditor::can_drop_data_fw); ClassDB::bind_method(D_METHOD("drop_data_fw"), &SpriteFramesEditor::drop_data_fw); + ClassDB::bind_method(D_METHOD("_prepare_sprite_sheet"), &SpriteFramesEditor::_prepare_sprite_sheet); + ClassDB::bind_method(D_METHOD("_open_sprite_sheet"), &SpriteFramesEditor::_open_sprite_sheet); + ClassDB::bind_method(D_METHOD("_sheet_preview_draw"), &SpriteFramesEditor::_sheet_preview_draw); + ClassDB::bind_method(D_METHOD("_sheet_preview_input"), &SpriteFramesEditor::_sheet_preview_input); + ClassDB::bind_method(D_METHOD("_sheet_spin_changed"), &SpriteFramesEditor::_sheet_spin_changed); + ClassDB::bind_method(D_METHOD("_sheet_add_frames"), &SpriteFramesEditor::_sheet_add_frames); } SpriteFramesEditor::SpriteFramesEditor() { @@ -712,9 +875,15 @@ SpriteFramesEditor::SpriteFramesEditor() { sub_vb->add_child(hbc); load = memnew(ToolButton); - load->set_tooltip(TTR("Load Resource")); + load->set_tooltip(TTR("Add a Texture from File")); hbc->add_child(load); + load_sheet = memnew(ToolButton); + load_sheet->set_tooltip(TTR("Add frames from a Sprite Sheet")); + hbc->add_child(load_sheet); + + hbc->add_child(memnew(VSeparator)); + copy = memnew(ToolButton); copy->set_tooltip(TTR("Copy")); hbc->add_child(copy); @@ -723,6 +892,8 @@ SpriteFramesEditor::SpriteFramesEditor() { paste->set_tooltip(TTR("Paste")); hbc->add_child(paste); + hbc->add_spacer(false); + empty = memnew(ToolButton); empty->set_tooltip(TTR("Insert Empty (Before)")); hbc->add_child(empty); @@ -731,7 +902,7 @@ SpriteFramesEditor::SpriteFramesEditor() { empty2->set_tooltip(TTR("Insert Empty (After)")); hbc->add_child(empty2); - hbc->add_spacer(false); + hbc->add_child(memnew(VSeparator)); move_up = memnew(ToolButton); move_up->set_tooltip(TTR("Move (Before)")); @@ -766,6 +937,7 @@ SpriteFramesEditor::SpriteFramesEditor() { add_child(dialog); load->connect("pressed", this, "_load_pressed"); + load_sheet->connect("pressed", this, "_open_sprite_sheet"); _delete->connect("pressed", this, "_delete_pressed"); copy->connect("pressed", this, "_copy_pressed"); paste->connect("pressed", this, "_paste_pressed"); @@ -780,6 +952,60 @@ SpriteFramesEditor::SpriteFramesEditor() { updating = false; edited_anim = "default"; + + split_sheet_dialog = memnew(ConfirmationDialog); + add_child(split_sheet_dialog); + VBoxContainer *split_sheet_vb = memnew(VBoxContainer); + split_sheet_dialog->add_child(split_sheet_vb); + split_sheet_dialog->set_title(TTR("Select Frames")); + split_sheet_dialog->connect("confirmed", this, "_sheet_add_frames"); + + ScrollContainer *scroll = memnew(ScrollContainer); + split_sheet_preview = memnew(TextureRect); + split_sheet_preview->set_expand(false); + split_sheet_preview->set_mouse_filter(MOUSE_FILTER_PASS); + split_sheet_preview->connect("draw", this, "_sheet_preview_draw"); + split_sheet_preview->connect("gui_input", this, "_sheet_preview_input"); + + scroll->set_enable_h_scroll(true); + scroll->set_enable_v_scroll(true); + CenterContainer *cc = memnew(CenterContainer); + cc->add_child(split_sheet_preview); + cc->set_h_size_flags(SIZE_EXPAND_FILL); + cc->set_v_size_flags(SIZE_EXPAND_FILL); + scroll->add_child(cc); + + split_sheet_vb->add_margin_child(TTR("Base Image:"), scroll, true); + + HBoxContainer *split_sheet_hb = memnew(HBoxContainer); + split_sheet_hb->add_spacer(); + Label *ss_label = memnew(Label(TTR("Horizontal:"))); + split_sheet_hb->add_child(ss_label); + split_sheet_h = memnew(SpinBox); + split_sheet_h->set_min(1); + split_sheet_h->set_max(128); + split_sheet_h->set_step(1); + split_sheet_hb->add_child(split_sheet_h); + split_sheet_hb->add_spacer(); + split_sheet_h->connect("value_changed", this, "_sheet_spin_changed"); + + ss_label = memnew(Label(TTR("Vertical:"))); + split_sheet_hb->add_child(ss_label); + split_sheet_v = memnew(SpinBox); + split_sheet_v->set_min(1); + split_sheet_v->set_max(128); + split_sheet_v->set_step(1); + split_sheet_hb->add_child(split_sheet_v); + split_sheet_hb->add_spacer(); + split_sheet_v->connect("value_changed", this, "_sheet_spin_changed"); + + split_sheet_vb->add_margin_child(TTR("Split Settings:"), split_sheet_hb); + + file_split_sheet = memnew(EditorFileDialog); + file_split_sheet->set_title(TTR("Create frames from Sprite Sheet")); + file_split_sheet->set_mode(EditorFileDialog::MODE_OPEN_FILE); + add_child(file_split_sheet); + file_split_sheet->connect("file_selected", this, "_prepare_sprite_sheet"); } void SpriteFramesEditorPlugin::edit(Object *p_object) { diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h index 55dd10074e..383e99f87e 100644 --- a/editor/plugins/sprite_frames_editor_plugin.h +++ b/editor/plugins/sprite_frames_editor_plugin.h @@ -37,6 +37,7 @@ #include "scene/gui/dialogs.h" #include "scene/gui/file_dialog.h" #include "scene/gui/split_container.h" +#include "scene/gui/texture_rect.h" #include "scene/gui/tree.h" class SpriteFramesEditor : public HSplitContainer { @@ -44,6 +45,7 @@ class SpriteFramesEditor : public HSplitContainer { GDCLASS(SpriteFramesEditor, HSplitContainer); ToolButton *load; + ToolButton *load_sheet; ToolButton *_delete; ToolButton *copy; ToolButton *paste; @@ -71,6 +73,14 @@ class SpriteFramesEditor : public HSplitContainer { StringName edited_anim; + ConfirmationDialog *split_sheet_dialog; + TextureRect *split_sheet_preview; + SpinBox *split_sheet_h; + SpinBox *split_sheet_v; + EditorFileDialog *file_split_sheet; + Set<int> frames_selected; + int last_frame_selected; + void _load_pressed(); void _load_scene_pressed(); void _file_load_request(const PoolVector<String> &p_path, int p_at_pos = -1); @@ -99,6 +109,13 @@ class SpriteFramesEditor : public HSplitContainer { bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); + void _open_sprite_sheet(); + void _prepare_sprite_sheet(const String &p_file); + void _sheet_preview_draw(); + void _sheet_spin_changed(double); + void _sheet_preview_input(const Ref<InputEvent> &p_event); + void _sheet_add_frames(); + protected: void _notification(int p_what); void _gui_input(Ref<InputEvent> p_event); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 5bc1067718..8cf00cf67d 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -770,7 +770,8 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { spin_z_index->show(); } } break; - default: {} + default: { + } } _update_toggle_shape_button(); workspace->update(); @@ -940,7 +941,8 @@ void TileSetEditor::_on_workspace_draw() { spin_z_index->set_value(tileset->autotile_get_z_index(get_current_tile(), edited_shape_coord)); draw_highlight_subtile(edited_shape_coord); } break; - default: {} + default: { + } } } @@ -1036,25 +1038,26 @@ void TileSetEditor::_on_workspace_overlay_draw() { 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; - String tile_id_name = String::num(t_id, 0) + ": " + tileset->tile_get_name(t_id); - Ref<Font> font = get_font("font", "Label"); - region.set_size(font->get_string_size(tile_id_name)); - workspace_overlay->draw_rect(region, c); - region.position.y += region.size.y - 2; - c = Color(0.1, 0.1, 0.1); - workspace_overlay->draw_string(font, region.position, tile_id_name, c); - } + if (tileset->tile_get_texture(t_id)->get_rid() != current_texture_rid) + continue; + + Rect2 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; + String tile_id_name = String::num(t_id, 0) + ": " + tileset->tile_get_name(t_id); + Ref<Font> font = get_font("font", "Label"); + region.set_size(font->get_string_size(tile_id_name)); + workspace_overlay->draw_rect(region, c); + region.position.y += region.size.y - 2; + c = Color(0.1, 0.1, 0.1); + workspace_overlay->draw_string(font, region.position, tile_id_name, c); } } @@ -1570,7 +1573,8 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { } } } break; - default: {} + default: { + } } } } @@ -1724,7 +1728,8 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { undo_redo->commit_action(); } } break; - default: {} + default: { + } } } } else if (p_tool == TOOL_SELECT) { @@ -1894,7 +1899,8 @@ void TileSetEditor::_select_next_tile() { edited_shape_coord = Vector2(); _select_edited_shape_coord(); } break; - default: {} + default: { + } } } } @@ -1931,7 +1937,8 @@ void TileSetEditor::_select_previous_tile() { edited_shape_coord = cell_count; _select_edited_shape_coord(); } break; - default: {} + default: { + } } } } @@ -2668,7 +2675,8 @@ void TileSetEditor::draw_polygon_shapes() { } } } break; - default: {} + default: { + } } if (creating_shape) { diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index f71ff84bbe..0aba7f3d15 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -453,7 +453,8 @@ void VisualShaderEditor::_update_graph() { Vector3 v = default_value; button->set_text(String::num(v.x, 3) + "," + String::num(v.y, 3) + "," + String::num(v.z, 3)); } break; - default: {} + default: { + } } } @@ -1003,6 +1004,58 @@ void VisualShaderEditor::_duplicate_nodes() { } } +void VisualShaderEditor::_on_nodes_delete() { + + VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); + List<int> to_erase; + + for (int i = 0; i < graph->get_child_count(); i++) { + GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i)); + if (gn) { + if (gn->is_selected() && gn->is_close_button_visible()) { + to_erase.push_back(gn->get_name().operator String().to_int()); + } + } + } + + if (to_erase.empty()) + return; + + undo_redo->create_action(TTR("Delete Nodes")); + + for (List<int>::Element *F = to_erase.front(); F; F = F->next()) { + undo_redo->add_do_method(visual_shader.ptr(), "remove_node", type, F->get()); + undo_redo->add_undo_method(visual_shader.ptr(), "add_node", type, visual_shader->get_node(type, F->get()), visual_shader->get_node_position(type, F->get()), F->get()); + } + + List<VisualShader::Connection> conns; + visual_shader->get_node_connections(type, &conns); + + List<VisualShader::Connection> used_conns; + for (List<int>::Element *F = to_erase.front(); F; F = F->next()) { + for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) { + if (E->get().from_node == F->get() || E->get().to_node == F->get()) { + + bool cancel = false; + for (List<VisualShader::Connection>::Element *R = used_conns.front(); R; R = R->next()) { + if (R->get().from_node == E->get().from_node && R->get().from_port == E->get().from_port && R->get().to_node == E->get().to_node && R->get().to_port == E->get().to_port) { + cancel = true; // to avoid ERR_ALREADY_EXISTS warning + break; + } + } + if (!cancel) { + undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port); + used_conns.push_back(E->get()); + } + } + } + } + + undo_redo->add_do_method(this, "_update_graph"); + undo_redo->add_undo_method(this, "_update_graph"); + undo_redo->commit_action(); +} + void VisualShaderEditor::_mode_selected(int p_id) { _update_options_menu(); _update_graph(); @@ -1174,6 +1227,7 @@ void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_node_selected", &VisualShaderEditor::_node_selected); ClassDB::bind_method("_scroll_changed", &VisualShaderEditor::_scroll_changed); ClassDB::bind_method("_delete_request", &VisualShaderEditor::_delete_request); + ClassDB::bind_method("_on_nodes_delete", &VisualShaderEditor::_on_nodes_delete); ClassDB::bind_method("_node_changed", &VisualShaderEditor::_node_changed); ClassDB::bind_method("_edit_port_default_input", &VisualShaderEditor::_edit_port_default_input); ClassDB::bind_method("_port_edited", &VisualShaderEditor::_port_edited); @@ -1223,6 +1277,7 @@ VisualShaderEditor::VisualShaderEditor() { graph->connect("node_selected", this, "_node_selected"); graph->connect("scroll_offset_changed", this, "_scroll_changed"); graph->connect("duplicate_nodes_request", this, "_duplicate_nodes"); + graph->connect("delete_nodes_request", this, "_on_nodes_delete"); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_VECTOR); graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_BOOLEAN); @@ -1345,9 +1400,10 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("ColorUniform", "Color", "Variables", "VisualShaderNodeColorUniform", TTR("Color uniform."), -1, VisualShaderNode::PORT_TYPE_COLOR)); // BOOLEAN - - add_options.push_back(AddOption("BooleanConstant", "Boolean", "Variables", "VisualShaderNodeBooleanConstant", TTR("Boolean constant."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN)); - add_options.push_back(AddOption("BooleanUniform", "Boolean", "Variables", "VisualShaderNodeBooleanUniform", TTR("Boolean uniform."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN)); + add_options.push_back(AddOption("If", "Conditional", "Functions", "VisualShaderNodeIf", TTR("Returns an associated vector if the provided scalars are equal, greater or less."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("Switch", "Conditional", "Functions", "VisualShaderNodeSwitch", TTR("Returns an associated vector if the provided boolean value is true or false."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("BooleanConstant", "Conditional", "Variables", "VisualShaderNodeBooleanConstant", TTR("Boolean constant."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN)); + add_options.push_back(AddOption("BooleanUniform", "Conditional", "Variables", "VisualShaderNodeBooleanUniform", TTR("Boolean uniform."), -1, VisualShaderNode::PORT_TYPE_BOOLEAN)); // INPUT diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index 2709d72931..4b0b48ad92 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -143,6 +143,7 @@ class VisualShaderEditor : public VBoxContainer { void _node_selected(Object *p_node); void _delete_request(int); + void _on_nodes_delete(); void _removed_from_graph(); |