From 3f31925b180dd0bfd2601c20d7200b9b152b12ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Sun, 29 Oct 2017 20:32:09 +0100 Subject: [PATCH 1/6] Universalize draw-over API for EditorPlugins - Now it is usable from both `CanvasItem` and `Spatial` editors. - `EditorPlugin` API changes: - `forward_draw_over_canvas()` becomes `forward_draw_over_viewport()`. - `update_canvas()` becomes `update_overlays()`, which now triggers the update of every overlay on top of any 2D or 3D viewports present. Also now it returns the number of such viewports, which is useful whenever you need to know the number of draw-over calls you'll get. - New: `[set/is]_force_draw_over_forwarding_enabled()` to force overlaying regardless it handles the current object type, in a similar fashion as `[set/is]_input_event_forwarding_always_enabled`. This kind of overlay is also on top of those for regular handled node types. - New: `forward_force_draw_over_canvas()`, which is the callback that gets called for plugins that enable forced overlaying. --- editor/editor_node.cpp | 13 +++++- editor/editor_node.h | 5 +- editor/editor_plugin.cpp | 46 ++++++++++++++++--- editor/editor_plugin.h | 9 +++- editor/plugins/abstract_polygon_2d_editor.cpp | 2 +- editor/plugins/abstract_polygon_2d_editor.h | 4 +- editor/plugins/canvas_item_editor_plugin.cpp | 7 ++- .../collision_shape_2d_editor_plugin.cpp | 22 ++++----- .../collision_shape_2d_editor_plugin.h | 4 +- .../light_occluder_2d_editor_plugin.cpp | 2 +- .../plugins/light_occluder_2d_editor_plugin.h | 4 +- editor/plugins/path_2d_editor_plugin.cpp | 2 +- editor/plugins/path_2d_editor_plugin.h | 4 +- editor/plugins/spatial_editor_plugin.cpp | 10 ++++ editor/plugins/spatial_editor_plugin.h | 5 +- editor/plugins/tile_map_editor_plugin.cpp | 2 +- editor/plugins/tile_map_editor_plugin.h | 4 +- 17 files changed, 105 insertions(+), 40 deletions(-) diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index a32ade3b71d..d7e48391bcc 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -5624,6 +5624,7 @@ EditorNode::EditorNode() { editor_plugin_screen = NULL; editor_plugins_over = memnew(EditorPluginList); + editor_plugins_force_over = memnew(EditorPluginList); editor_plugins_force_input_forwarding = memnew(EditorPluginList); _edit_current(); @@ -5748,6 +5749,7 @@ EditorNode::~EditorNode() { memdelete(EditorHelp::get_doc_data()); memdelete(editor_selection); memdelete(editor_plugins_over); + memdelete(editor_plugins_force_over); memdelete(editor_plugins_force_input_forwarding); memdelete(file_server); memdelete(progress_hb); @@ -5801,10 +5803,17 @@ bool EditorPluginList::forward_spatial_gui_input(Camera *p_camera, const Refforward_draw_over_canvas(p_canvas); + plugins_list[i]->forward_draw_over_viewport(p_overlay); + } +} + +void EditorPluginList::forward_force_draw_over_viewport(Control *p_overlay) { + + for (int i = 0; i < plugins_list.size(); i++) { + plugins_list[i]->forward_force_draw_over_viewport(p_overlay); } } diff --git a/editor/editor_node.h b/editor/editor_node.h index a2b4a0a049b..386f02a0313 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -378,6 +378,7 @@ private: Vector editor_plugins; EditorPlugin *editor_plugin_screen; EditorPluginList *editor_plugins_over; + EditorPluginList *editor_plugins_force_over; EditorPluginList *editor_plugins_force_input_forwarding; EditorHistory editor_history; @@ -636,6 +637,7 @@ public: EditorPlugin *get_editor_plugin_screen() { return editor_plugin_screen; } EditorPluginList *get_editor_plugins_over() { return editor_plugins_over; } + EditorPluginList *get_editor_plugins_force_over() { return editor_plugins_force_over; } EditorPluginList *get_editor_plugins_force_input_forwarding() { return editor_plugins_force_input_forwarding; } PropertyEditor *get_property_editor() { return property_editor; } VBoxContainer *get_property_editor_vb() { return prop_editor_vb; } @@ -820,7 +822,8 @@ public: void edit(Object *p_object); bool forward_gui_input(const Ref &p_event); bool forward_spatial_gui_input(Camera *p_camera, const Ref &p_event, bool serve_when_force_input_enabled); - void forward_draw_over_canvas(Control *p_canvas); + void forward_draw_over_viewport(Control *p_overlay); + void forward_force_draw_over_viewport(Control *p_overlay); void add_plugin(EditorPlugin *p_plugin); void clear(); bool empty(); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 38e8b301b7e..c1fbcde6ac8 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -375,6 +375,12 @@ void EditorPlugin::set_input_event_forwarding_always_enabled() { always_input_forwarding_list->add_plugin(this); } +void EditorPlugin::set_force_draw_over_forwarding_enabled() { + force_draw_over_forwarding_enabled = true; + EditorPluginList *always_draw_over_forwarding_list = EditorNode::get_singleton()->get_editor_plugins_force_over(); + always_draw_over_forwarding_list->add_plugin(this); +} + void EditorPlugin::notify_scene_changed(const Node *scn_root) { if (scn_root == NULL) return; emit_signal("scene_changed", scn_root); @@ -410,15 +416,38 @@ bool EditorPlugin::forward_canvas_gui_input(const Ref &p_event) { return false; } -void EditorPlugin::forward_draw_over_canvas(Control *p_canvas) { +void EditorPlugin::forward_draw_over_viewport(Control *p_overlay) { - if (get_script_instance() && get_script_instance()->has_method("forward_draw_over_canvas")) { - get_script_instance()->call("forward_draw_over_canvas", p_canvas); + if (get_script_instance() && get_script_instance()->has_method("forward_draw_over_viewport")) { + get_script_instance()->call("forward_draw_over_viewport", p_overlay); } } -void EditorPlugin::update_canvas() { - CanvasItemEditor::get_singleton()->get_viewport_control()->update(); +void EditorPlugin::forward_force_draw_over_viewport(Control *p_overlay) { + + if (get_script_instance() && get_script_instance()->has_method("forward_force_draw_over_viewport")) { + get_script_instance()->call("forward_force_draw_over_viewport", p_overlay); + } +} + +// Updates the overlays of the 2D viewport or, if in 3D mode, of every 3D viewport. +int EditorPlugin::update_overlays() const { + + if (SpatialEditor::get_singleton()->is_visible()) { + int count = 0; + for (int i = 0; i < SpatialEditor::VIEWPORTS_COUNT; i++) { + SpatialEditorViewport *vp = SpatialEditor::get_singleton()->get_editor_viewport(i); + if (vp->is_visible()) { + vp->update_surface(); + count++; + } + } + return count; + } else { + // This will update the normal viewport itself as well + CanvasItemEditor::get_singleton()->get_viewport_control()->update(); + return 1; + } } bool EditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref &p_event) { @@ -590,7 +619,7 @@ void EditorPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("add_custom_type", "type", "base", "script", "icon"), &EditorPlugin::add_custom_type); ClassDB::bind_method(D_METHOD("remove_custom_type", "type"), &EditorPlugin::remove_custom_type); - ClassDB::bind_method(D_METHOD("update_canvas"), &EditorPlugin::update_canvas); + ClassDB::bind_method(D_METHOD("update_overlays"), &EditorPlugin::update_overlays); ClassDB::bind_method(D_METHOD("make_bottom_panel_item_visible", "item"), &EditorPlugin::make_bottom_panel_item_visible); ClassDB::bind_method(D_METHOD("hide_bottom_panel"), &EditorPlugin::hide_bottom_panel); @@ -602,11 +631,13 @@ void EditorPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("add_export_plugin", "exporter"), &EditorPlugin::add_export_plugin); ClassDB::bind_method(D_METHOD("remove_export_plugin", "exporter"), &EditorPlugin::remove_export_plugin); ClassDB::bind_method(D_METHOD("set_input_event_forwarding_always_enabled"), &EditorPlugin::set_input_event_forwarding_always_enabled); + ClassDB::bind_method(D_METHOD("set_force_draw_over_forwarding_enabled"), &EditorPlugin::set_force_draw_over_forwarding_enabled); ClassDB::bind_method(D_METHOD("get_editor_interface"), &EditorPlugin::get_editor_interface); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_canvas_gui_input", PropertyInfo(Variant::TRANSFORM2D, "canvas_xform"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_draw_over_canvas", PropertyInfo(Variant::TRANSFORM2D, "canvas_xform"), PropertyInfo(Variant::OBJECT, "canvas", PROPERTY_HINT_RESOURCE_TYPE, "Control"))); + 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; @@ -653,6 +684,7 @@ void EditorPlugin::_bind_methods() { EditorPlugin::EditorPlugin() { undo_redo = NULL; input_event_forwarding_always_enabled = false; + force_draw_over_forwarding_enabled = false; last_main_screen_name = ""; } diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 1d68eee1170..11f43786671 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -102,6 +102,7 @@ class EditorPlugin : public Node { UndoRedo *_get_undo_redo() { return undo_redo; } bool input_event_forwarding_always_enabled; + bool force_draw_over_forwarding_enabled; String last_main_screen_name; @@ -151,13 +152,17 @@ public: void set_input_event_forwarding_always_enabled(); bool is_input_event_forwarding_always_enabled() { return input_event_forwarding_always_enabled; } + void set_force_draw_over_forwarding_enabled(); + bool is_force_draw_over_forwarding_enabled() { return force_draw_over_forwarding_enabled; } + void notify_main_screen_changed(const String &screen_name); void notify_scene_changed(const Node *scn_root); void notify_scene_closed(const String &scene_filepath); virtual Ref create_spatial_gizmo(Spatial *p_spatial); virtual bool forward_canvas_gui_input(const Ref &p_event); - virtual void forward_draw_over_canvas(Control *p_canvas); + virtual void forward_draw_over_viewport(Control *p_overlay); + virtual void forward_force_draw_over_viewport(Control *p_overlay); virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref &p_event); virtual String get_name() const; virtual bool has_main_screen() const; @@ -178,7 +183,7 @@ public: EditorInterface *get_editor_interface(); - void update_canvas(); + int update_overlays() const; void queue_save_layout() const; diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index 736e176ab8d..1c4569d1175 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -490,7 +490,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref &p_event) return false; } -void AbstractPolygon2DEditor::forward_draw_over_canvas(Control *p_canvas) { +void AbstractPolygon2DEditor::forward_draw_over_viewport(Control *p_overlay) { if (!_get_node()) return; diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h index 915fe0803e3..545eff6ef42 100644 --- a/editor/plugins/abstract_polygon_2d_editor.h +++ b/editor/plugins/abstract_polygon_2d_editor.h @@ -136,7 +136,7 @@ protected: public: bool forward_gui_input(const Ref &p_event); - void forward_draw_over_canvas(Control *p_canvas); + void forward_draw_over_viewport(Control *p_overlay); void edit(Node *p_polygon); AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wip_destructive = true); @@ -152,7 +152,7 @@ class AbstractPolygon2DEditorPlugin : public EditorPlugin { public: virtual bool forward_canvas_gui_input(const Ref &p_event) { return polygon_editor->forward_gui_input(p_event); } - virtual void forward_draw_over_canvas(Control *p_canvas) { polygon_editor->forward_draw_over_canvas(p_canvas); } + virtual void forward_draw_over_viewport(Control *p_overlay) { polygon_editor->forward_draw_over_viewport(p_overlay); } bool has_main_screen() const { return false; } virtual String get_name() const { return klass; } diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 3940dd9044c..d18e97fe83a 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -2955,8 +2955,13 @@ void CanvasItemEditor::_draw_viewport() { EditorPluginList *over_plugin_list = editor->get_editor_plugins_over(); if (!over_plugin_list->empty()) { - over_plugin_list->forward_draw_over_canvas(viewport); + over_plugin_list->forward_draw_over_viewport(viewport); } + EditorPluginList *force_over_plugin_list = editor->get_editor_plugins_force_over(); + if (!force_over_plugin_list->empty()) { + force_over_plugin_list->forward_force_draw_over_viewport(viewport); + } + _draw_bones(); } diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp index 005de096cd1..029e3a558dd 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.cpp +++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp @@ -414,7 +414,7 @@ void CollisionShape2DEditor::_get_current_shape_type() { canvas_item_editor->get_viewport_control()->update(); } -void CollisionShape2DEditor::forward_draw_over_canvas(Control *p_canvas) { +void CollisionShape2DEditor::forward_draw_over_viewport(Control *p_overlay) { if (!node) { return; @@ -448,8 +448,8 @@ void CollisionShape2DEditor::forward_draw_over_canvas(Control *p_canvas) { handles[0] = Point2(radius, -height); handles[1] = Point2(0, -(height + radius)); - p_canvas->draw_texture(h, gt.xform(handles[0]) - size); - p_canvas->draw_texture(h, gt.xform(handles[1]) - size); + p_overlay->draw_texture(h, gt.xform(handles[0]) - size); + p_overlay->draw_texture(h, gt.xform(handles[1]) - size); } break; @@ -459,7 +459,7 @@ void CollisionShape2DEditor::forward_draw_over_canvas(Control *p_canvas) { handles.resize(1); handles[0] = Point2(shape->get_radius(), 0); - p_canvas->draw_texture(h, gt.xform(handles[0]) - size); + p_overlay->draw_texture(h, gt.xform(handles[0]) - size); } break; @@ -478,8 +478,8 @@ void CollisionShape2DEditor::forward_draw_over_canvas(Control *p_canvas) { handles[0] = shape->get_normal() * shape->get_d(); handles[1] = shape->get_normal() * (shape->get_d() + 30.0); - p_canvas->draw_texture(h, gt.xform(handles[0]) - size); - p_canvas->draw_texture(h, gt.xform(handles[1]) - size); + p_overlay->draw_texture(h, gt.xform(handles[0]) - size); + p_overlay->draw_texture(h, gt.xform(handles[1]) - size); } break; @@ -489,7 +489,7 @@ void CollisionShape2DEditor::forward_draw_over_canvas(Control *p_canvas) { handles.resize(1); handles[0] = Point2(0, shape->get_length()); - p_canvas->draw_texture(h, gt.xform(handles[0]) - size); + p_overlay->draw_texture(h, gt.xform(handles[0]) - size); } break; @@ -501,8 +501,8 @@ void CollisionShape2DEditor::forward_draw_over_canvas(Control *p_canvas) { handles[0] = Point2(ext.x, 0); handles[1] = Point2(0, -ext.y); - p_canvas->draw_texture(h, gt.xform(handles[0]) - size); - p_canvas->draw_texture(h, gt.xform(handles[1]) - size); + p_overlay->draw_texture(h, gt.xform(handles[0]) - size); + p_overlay->draw_texture(h, gt.xform(handles[1]) - size); } break; @@ -513,8 +513,8 @@ void CollisionShape2DEditor::forward_draw_over_canvas(Control *p_canvas) { handles[0] = shape->get_a(); handles[1] = shape->get_b(); - p_canvas->draw_texture(h, gt.xform(handles[0]) - size); - p_canvas->draw_texture(h, gt.xform(handles[1]) - size); + p_overlay->draw_texture(h, gt.xform(handles[0]) - size); + p_overlay->draw_texture(h, gt.xform(handles[1]) - size); } break; } diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h index d4fbe87fb3d..1e930ef3711 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.h +++ b/editor/plugins/collision_shape_2d_editor_plugin.h @@ -74,7 +74,7 @@ protected: public: bool forward_canvas_gui_input(const Ref &p_event); - void forward_draw_over_canvas(Control *p_canvas); + void forward_draw_over_viewport(Control *p_overlay); void edit(Node *p_node); CollisionShape2DEditor(EditorNode *p_editor); @@ -88,7 +88,7 @@ class CollisionShape2DEditorPlugin : public EditorPlugin { public: virtual bool forward_canvas_gui_input(const Ref &p_event) { return collision_shape_2d_editor->forward_canvas_gui_input(p_event); } - virtual void forward_draw_over_canvas(Control *p_canvas) { return collision_shape_2d_editor->forward_draw_over_canvas(p_canvas); } + virtual void forward_draw_over_viewport(Control *p_overlay) { return collision_shape_2d_editor->forward_draw_over_viewport(p_overlay); } virtual String get_name() const { return "CollisionShape2D"; } bool has_main_screen() const { return false; } diff --git a/editor/plugins/light_occluder_2d_editor_plugin.cpp b/editor/plugins/light_occluder_2d_editor_plugin.cpp index 485657d2c9e..3febc99239d 100644 --- a/editor/plugins/light_occluder_2d_editor_plugin.cpp +++ b/editor/plugins/light_occluder_2d_editor_plugin.cpp @@ -318,7 +318,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref &p_event) { return false; } -void LightOccluder2DEditor::forward_draw_over_canvas(Control *p_canvas) { +void LightOccluder2DEditor::forward_draw_over_viewport(Control *p_overlay) { if (!node || !node->get_occluder_polygon().is_valid()) return; diff --git a/editor/plugins/light_occluder_2d_editor_plugin.h b/editor/plugins/light_occluder_2d_editor_plugin.h index 068832d8ed9..dc3ff74052f 100644 --- a/editor/plugins/light_occluder_2d_editor_plugin.h +++ b/editor/plugins/light_occluder_2d_editor_plugin.h @@ -82,7 +82,7 @@ protected: public: Vector2 snap_point(const Vector2 &p_point) const; - void forward_draw_over_canvas(Control *p_canvas); + void forward_draw_over_viewport(Control *p_overlay); bool forward_gui_input(const Ref &p_event); void edit(Node *p_collision_polygon); LightOccluder2DEditor(EditorNode *p_editor); @@ -97,7 +97,7 @@ class LightOccluder2DEditorPlugin : public EditorPlugin { public: virtual bool forward_canvas_gui_input(const Ref &p_event) { return light_occluder_editor->forward_gui_input(p_event); } - virtual void forward_draw_over_canvas(Control *p_canvas) { return light_occluder_editor->forward_draw_over_canvas(p_canvas); } + virtual void forward_draw_over_viewport(Control *p_overlay) { return light_occluder_editor->forward_draw_over_viewport(p_overlay); } virtual String get_name() const { return "LightOccluder2D"; } bool has_main_screen() const { return false; } diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp index 2174f08e231..5e811bfa113 100644 --- a/editor/plugins/path_2d_editor_plugin.cpp +++ b/editor/plugins/path_2d_editor_plugin.cpp @@ -269,7 +269,7 @@ bool Path2DEditor::forward_gui_input(const Ref &p_event) { return false; } -void Path2DEditor::forward_draw_over_canvas(Control *p_canvas) { +void Path2DEditor::forward_draw_over_viewport(Control *p_overlay) { if (!node) return; diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h index 516e48c4716..638d9337973 100644 --- a/editor/plugins/path_2d_editor_plugin.h +++ b/editor/plugins/path_2d_editor_plugin.h @@ -94,7 +94,7 @@ protected: public: bool forward_gui_input(const Ref &p_event); - void forward_draw_over_canvas(Control *p_canvas); + void forward_draw_over_viewport(Control *p_overlay); void edit(Node *p_path2d); Path2DEditor(EditorNode *p_editor); }; @@ -108,7 +108,7 @@ class Path2DEditorPlugin : public EditorPlugin { public: virtual bool forward_canvas_gui_input(const Ref &p_event) { return path2d_editor->forward_gui_input(p_event); } - virtual void forward_draw_over_canvas(Control *p_canvas) { return path2d_editor->forward_draw_over_canvas(p_canvas); } + virtual void forward_draw_over_viewport(Control *p_overlay) { return path2d_editor->forward_draw_over_viewport(p_overlay); } virtual String get_name() const { return "Path2D"; } bool has_main_screen() const { return false; } diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 20dda8b6951..c8a7ad45ae8 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -2332,6 +2332,16 @@ static void draw_indicator_bar(Control &surface, real_t fill, Ref icon) void SpatialEditorViewport::_draw() { + EditorPluginList *over_plugin_list = EditorNode::get_singleton()->get_editor_plugins_over(); + if (!over_plugin_list->empty()) { + over_plugin_list->forward_draw_over_viewport(surface); + } + + EditorPluginList *force_over_plugin_list = editor->get_editor_plugins_force_over(); + if (!force_over_plugin_list->empty()) { + force_over_plugin_list->forward_force_draw_over_viewport(surface); + } + if (surface->has_focus()) { Size2 size = surface->get_size(); Rect2 r = Rect2(Point2(), size); diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index 58c464c3ea4..ab26a70f7f7 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -311,6 +311,7 @@ protected: static void _bind_methods(); public: + void update_surface() { surface->update(); } void update_transform_gizmo_view(); void set_can_preview(Camera *p_preview); @@ -389,6 +390,8 @@ class SpatialEditor : public VBoxContainer { GDCLASS(SpatialEditor, VBoxContainer); public: + static const unsigned int VIEWPORTS_COUNT = 4; + enum ToolMode { TOOL_MODE_SELECT, @@ -403,8 +406,6 @@ public: }; private: - static const unsigned int VIEWPORTS_COUNT = 4; - EditorNode *editor; EditorSelection *editor_selection; diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 4092fd3994e..e552e24c178 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -1183,7 +1183,7 @@ bool TileMapEditor::forward_gui_input(const Ref &p_event) { return false; } -void TileMapEditor::forward_draw_over_canvas(Control *p_canvas) { +void TileMapEditor::forward_draw_over_viewport(Control *p_overlay) { if (!node) return; diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h index c7a5bf0cc6a..ce58cc9708b 100644 --- a/editor/plugins/tile_map_editor_plugin.h +++ b/editor/plugins/tile_map_editor_plugin.h @@ -184,7 +184,7 @@ public: HBoxContainer *get_toolbar() const { return toolbar; } bool forward_gui_input(const Ref &p_event); - void forward_draw_over_canvas(Control *p_canvas); + void forward_draw_over_viewport(Control *p_overlay); void edit(Node *p_tile_map); @@ -200,7 +200,7 @@ class TileMapEditorPlugin : public EditorPlugin { public: virtual bool forward_canvas_gui_input(const Ref &p_event) { return tile_map_editor->forward_gui_input(p_event); } - virtual void forward_draw_over_canvas(Control *p_canvas) { tile_map_editor->forward_draw_over_canvas(p_canvas); } + virtual void forward_draw_over_viewport(Control *p_overlay) { tile_map_editor->forward_draw_over_viewport(p_overlay); } virtual String get_name() const { return "TileMap"; } bool has_main_screen() const { return false; } From ff03a0bc7b6ac7c42dcb036ab40f45147b897c74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Wed, 1 Nov 2017 21:32:39 +0100 Subject: [PATCH 2/6] Implement backup/restore for animated values --- scene/animation/animation_player.cpp | 76 +++++++++++++++++++++++++--- scene/animation/animation_player.h | 23 ++++++++- 2 files changed, 92 insertions(+), 7 deletions(-) diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 010f5a586fd..ea445b15735 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -228,7 +228,11 @@ void AnimationPlayer::_notification(int p_what) { } } -void AnimationPlayer::_generate_node_caches(AnimationData *p_anim) { +void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) { + + // Already cached? + if (p_anim->node_cache.size() == p_anim->animation->get_track_count()) + return; Node *parent = get_node(root); @@ -336,11 +340,7 @@ void AnimationPlayer::_generate_node_caches(AnimationData *p_anim) { void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float p_time, float p_delta, float p_interp, bool p_allow_discrete) { - if (p_anim->node_cache.size() != p_anim->animation->get_track_count()) { - // animation hasn't been "node-cached" - _generate_node_caches(p_anim); - } - + _ensure_node_caches(p_anim); ERR_FAIL_COND(p_anim->node_cache.size() != p_anim->animation->get_track_count()); Animation *a = p_anim->animation.operator->(); @@ -1205,6 +1205,70 @@ void AnimationPlayer::get_argument_options(const StringName &p_function, int p_i Node::get_argument_options(p_function, p_idx, r_options); } +#ifdef TOOLS_ENABLED +AnimatedValuesBackup AnimationPlayer::backup_animated_values() { + + if (!playback.current.from) + return AnimatedValuesBackup(); + + _ensure_node_caches(playback.current.from); + + AnimatedValuesBackup backup; + + for (int i = 0; i < playback.current.from->node_cache.size(); i++) { + TrackNodeCache *nc = playback.current.from->node_cache[i]; + if (!nc) + continue; + + if (nc->skeleton) { + if (nc->bone_idx == -1) + continue; + + AnimatedValuesBackup::Entry entry; + entry.object = nc->skeleton; + entry.bone_idx = nc->bone_idx; + entry.value = nc->skeleton->get_bone_pose(nc->bone_idx); + backup.entries.push_back(entry); + } else { + if (nc->spatial) { + AnimatedValuesBackup::Entry entry; + entry.object = nc->spatial; + entry.subpath.push_back("transform"); + entry.value = nc->spatial->get_transform(); + entry.bone_idx = -1; + backup.entries.push_back(entry); + } else { + for (Map::Element *E = nc->property_anim.front(); E; E = E->next()) { + AnimatedValuesBackup::Entry entry; + entry.object = E->value().object; + entry.subpath = E->value().subpath; + bool valid; + entry.value = E->value().object->get_indexed(E->value().subpath, &valid); + entry.bone_idx = -1; + if (valid) + backup.entries.push_back(entry); + } + } + } + } + + return backup; +} + +void AnimationPlayer::restore_animated_values(const AnimatedValuesBackup &p_backup) { + + for (int i = 0; i < p_backup.entries.size(); i++) { + + const AnimatedValuesBackup::Entry *entry = &p_backup.entries[i]; + if (entry->bone_idx == -1) { + entry->object->set_indexed(entry->subpath, entry->value); + } else { + Object::cast_to(entry->object)->set_bone_pose(entry->bone_idx, entry->value); + } + } +} +#endif + void AnimationPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationPlayer::_node_removed); diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index e4e021c7fe1..4a347f49ea7 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -38,6 +38,21 @@ @author Juan Linietsky */ +#ifdef TOOLS_ENABLED +// To save/restore animated values +class AnimatedValuesBackup { + struct Entry { + Object *object; + Vector subpath; // Unused if bone + int bone_idx; // -1 if not a bone + Variant value; + }; + Vector entries; + + friend class AnimationPlayer; +}; +#endif + class AnimationPlayer : public Node { GDCLASS(AnimationPlayer, Node); OBJ_CATEGORY("Animation Nodes"); @@ -198,7 +213,7 @@ private: void _animation_process_animation(AnimationData *p_anim, float p_time, float p_delta, float p_interp, bool p_allow_discrete = true); - void _generate_node_caches(AnimationData *p_anim); + void _ensure_node_caches(AnimationData *p_anim); void _animation_process_data(PlaybackData &cd, float p_delta, float p_blend); void _animation_process2(float p_delta); void _animation_update_transforms(); @@ -291,6 +306,12 @@ public: void get_argument_options(const StringName &p_function, int p_idx, List *r_options) const; +#ifdef TOOLS_ENABLED + // These may be interesting for games, but are too dangerous for general use + AnimatedValuesBackup backup_animated_values(); + void restore_animated_values(const AnimatedValuesBackup &p_backup); +#endif + AnimationPlayer(); ~AnimationPlayer(); }; From 3aa79fc1a32f505f71c88e58023d728a225353e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Mon, 30 Oct 2017 21:33:36 +0100 Subject: [PATCH 3/6] Add ability to opt-out buffer swapping in `VS::draw()` --- drivers/gles3/rasterizer_gles3.cpp | 7 +++++-- drivers/gles3/rasterizer_gles3.h | 2 +- servers/visual/rasterizer.h | 2 +- servers/visual/visual_server_raster.cpp | 4 ++-- servers/visual/visual_server_raster.h | 2 +- servers/visual/visual_server_wrap_mt.cpp | 4 ++-- servers/visual/visual_server_wrap_mt.h | 2 +- servers/visual_server.cpp | 4 ++-- servers/visual_server.h | 2 +- 9 files changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index ee61481a869..b34aec089d1 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -352,7 +352,7 @@ void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target, const Re canvas->canvas_end(); } -void RasterizerGLES3::end_frame() { +void RasterizerGLES3::end_frame(bool p_swap_buffers) { #if 0 canvas->canvas_begin(); @@ -384,7 +384,10 @@ void RasterizerGLES3::end_frame() { canvas->draw_generic_textured_rect(Rect2(0,0,15,15),Rect2(0,0,1,1)); #endif - OS::get_singleton()->swap_buffers(); + if (p_swap_buffers) + OS::get_singleton()->swap_buffers(); + else + glFinish(); /* print_line("objects: "+itos(storage->info.render_object_count)); print_line("material chages: "+itos(storage->info.render_material_switch_count)); diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h index 4bfec09bf32..c27af7d0191 100644 --- a/drivers/gles3/rasterizer_gles3.h +++ b/drivers/gles3/rasterizer_gles3.h @@ -59,7 +59,7 @@ public: virtual void restore_render_target(); virtual void clear_render_target(const Color &p_color); virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0); - virtual void end_frame(); + virtual void end_frame(bool p_swap_buffers); virtual void finalize(); static void make_current(); diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 21d059c48e3..2499551607f 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -1027,7 +1027,7 @@ public: virtual void restore_render_target() = 0; virtual void clear_render_target(const Color &p_color) = 0; virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0) = 0; - virtual void end_frame() = 0; + virtual void end_frame(bool p_swap_buffers) = 0; virtual void finalize() = 0; virtual ~Rasterizer() {} diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 9432d3fdd91..6b527b5cd10 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -92,7 +92,7 @@ void VisualServerRaster::request_frame_drawn_callback(Object *p_where, const Str frame_drawn_callbacks.push_back(fdc); } -void VisualServerRaster::draw() { +void VisualServerRaster::draw(bool p_swap_buffers) { changes = 0; @@ -103,7 +103,7 @@ void VisualServerRaster::draw() { VSG::viewport->draw_viewports(); VSG::scene->render_probes(); _draw_margins(); - VSG::rasterizer->end_frame(); + VSG::rasterizer->end_frame(p_swap_buffers); while (frame_drawn_callbacks.front()) { diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 75514859194..56400d6a19f 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -625,7 +625,7 @@ public: virtual void request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata); - virtual void draw(); + virtual void draw(bool p_swap_buffers); virtual void sync(); virtual bool has_changed() const; virtual void init(); diff --git a/servers/visual/visual_server_wrap_mt.cpp b/servers/visual/visual_server_wrap_mt.cpp index a9bfef7ef31..03c68ab4543 100644 --- a/servers/visual/visual_server_wrap_mt.cpp +++ b/servers/visual/visual_server_wrap_mt.cpp @@ -89,7 +89,7 @@ void VisualServerWrapMT::sync() { } } -void VisualServerWrapMT::draw() { +void VisualServerWrapMT::draw(bool p_swap_buffers) { if (create_thread) { @@ -97,7 +97,7 @@ void VisualServerWrapMT::draw() { command_queue.push(this, &VisualServerWrapMT::thread_draw); } else { - visual_server->draw(); + visual_server->draw(p_swap_buffers); } } diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 417e8de833a..1e8071af610 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -542,7 +542,7 @@ public: virtual void init(); virtual void finish(); - virtual void draw(); + virtual void draw(bool p_swap_buffers); virtual void sync(); FUNC0RC(bool, has_changed) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 10f350d6671..f745785efd8 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1481,7 +1481,7 @@ Array VisualServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_surfa void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("force_sync"), &VisualServer::sync); - ClassDB::bind_method(D_METHOD("force_draw"), &VisualServer::draw); + ClassDB::bind_method(D_METHOD("force_draw"), &VisualServer::draw, DEFVAL(true)); ClassDB::bind_method(D_METHOD("texture_create"), &VisualServer::texture_create); ClassDB::bind_method(D_METHOD("texture_create_from_image", "image", "flags"), &VisualServer::texture_create_from_image, DEFVAL(TEXTURE_FLAGS_DEFAULT)); @@ -1658,7 +1658,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("free", "rid"), &VisualServer::free); ClassDB::bind_method(D_METHOD("request_frame_drawn_callback", "where", "method", "userdata"), &VisualServer::request_frame_drawn_callback); - ClassDB::bind_method(D_METHOD("draw"), &VisualServer::draw); + ClassDB::bind_method(D_METHOD("draw"), &VisualServer::draw, DEFVAL(true)); ClassDB::bind_method(D_METHOD("sync"), &VisualServer::sync); ClassDB::bind_method(D_METHOD("has_changed"), &VisualServer::has_changed); ClassDB::bind_method(D_METHOD("init"), &VisualServer::init); diff --git a/servers/visual_server.h b/servers/visual_server.h index c4b15830095..9df389999aa 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -909,7 +909,7 @@ public: /* EVENT QUEUING */ - virtual void draw() = 0; + virtual void draw(bool p_swap_buffers = true) = 0; virtual void sync() = 0; virtual bool has_changed() const = 0; virtual void init() = 0; From 81c49fb5368ab1194fc9cedffa8920c45f5b241b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Mon, 20 Nov 2017 19:45:41 +0100 Subject: [PATCH 4/6] Update clang-format in modified files --- servers/visual/visual_server_raster.h | 10 +++++----- servers/visual/visual_server_wrap_mt.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 56400d6a19f..f34951f4527 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -77,8 +77,8 @@ class VisualServerRaster : public VisualServer { static void _changes_changed() {} public: - //if editor is redrawing when it shouldn't, enable this and put a breakpoint in _changes_changed() - //#define DEBUG_CHANGES +//if editor is redrawing when it shouldn't, enable this and put a breakpoint in _changes_changed() +//#define DEBUG_CHANGES #ifdef DEBUG_CHANGES _FORCE_INLINE_ static void redraw_request() { @@ -96,7 +96,7 @@ public: #define DISPLAY_CHANGED \ changes++; #endif - // print_line(String("CHANGED: ") + __FUNCTION__); +// print_line(String("CHANGED: ") + __FUNCTION__); #define BIND0R(m_r, m_name) \ m_r m_name() { return BINDBASE->m_name(); } @@ -449,7 +449,7 @@ public: BIND2R(int, viewport_get_render_info, RID, ViewportRenderInfo) BIND2(viewport_set_debug_draw, RID, ViewportDebugDraw) - /* ENVIRONMENT API */ +/* ENVIRONMENT API */ #undef BINDBASE //from now on, calls forwarded to this singleton @@ -479,7 +479,7 @@ public: BIND6(environment_set_fog_depth, RID, bool, float, float, bool, float) BIND5(environment_set_fog_height, RID, bool, float, float, float) - /* SCENARIO API */ +/* SCENARIO API */ #undef BINDBASE #define BINDBASE VSG::scene diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 1e8071af610..d1069a410c7 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -62,7 +62,7 @@ class VisualServerWrapMT : public VisualServer { int pool_max_size; - //#define DEBUG_SYNC +//#define DEBUG_SYNC #ifdef DEBUG_SYNC #define SYNC_DEBUG print_line("sync on: " + String(__FUNCTION__)); From 1964d5fdddf9611e0a69f91e31c06771345754e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Mon, 20 Nov 2017 01:45:56 +0100 Subject: [PATCH 5/6] Improve/fix SpatialEditor state saving/restoring --- editor/plugins/spatial_editor_plugin.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index c8a7ad45ae8..384c20d79f9 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -2849,6 +2849,20 @@ void SpatialEditorViewport::set_state(const Dictionary &p_state) { camera->set_doppler_tracking(doppler ? Camera::DOPPLER_TRACKING_IDLE_STEP : Camera::DOPPLER_TRACKING_DISABLED); view_menu->get_popup()->set_item_checked(idx, doppler); } + if (p_state.has("gizmos")) { + bool gizmos = p_state["gizmos"]; + + int idx = view_menu->get_popup()->get_item_index(VIEW_GIZMOS); + if (view_menu->get_popup()->is_item_checked(idx) != gizmos) + _menu_option(VIEW_GIZMOS); + } + if (p_state.has("information")) { + bool information = p_state["information"]; + + int idx = view_menu->get_popup()->get_item_index(VIEW_INFORMATION); + if (view_menu->get_popup()->is_item_checked(idx) != information) + _menu_option(VIEW_INFORMATION); + } if (p_state.has("half_res")) { bool half_res = p_state["half_res"]; @@ -2880,6 +2894,9 @@ Dictionary SpatialEditorViewport::get_state() const { d["use_environment"] = camera->get_environment().is_valid(); d["use_orthogonal"] = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL; d["listener"] = viewport->is_audio_listener(); + d["doppler"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER)); + d["gizmos"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS)); + d["information"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION)); d["half_res"] = viewport_container->get_stretch_shrink() > 1; if (previewing) { d["previewing"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing); From d0e09d84f085c5bffdd5ad06d335be20c246e954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Mon, 30 Oct 2017 19:43:19 +0100 Subject: [PATCH 6/6] Implement onion skinning for the animation editor --- editor/editor_settings.cpp | 2 + .../animation_player_editor_plugin.cpp | 452 +++++++++++++++++- .../plugins/animation_player_editor_plugin.h | 66 ++- scene/animation/animation_player.cpp | 11 + scene/animation/animation_player.h | 3 + scene/main/scene_tree.cpp | 10 +- scene/main/scene_tree.h | 3 +- 7 files changed, 538 insertions(+), 9 deletions(-) diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 582bb977b85..910c06053e3 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -462,6 +462,8 @@ void EditorSettings::_load_defaults(Ref p_extra_config) { _initial_set("editors/animation/autorename_animation_tracks", true); _initial_set("editors/animation/confirm_insert_track", true); + _initial_set("editors/animation/onion_layers_past_color", Color(1, 0, 0)); + _initial_set("editors/animation/onion_layers_future_color", Color(0, 1, 0)); _initial_set("docks/property_editor/texture_preview_width", 48); _initial_set("docks/property_editor/auto_refresh_interval", 0.3); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 2b9c625aa4d..019e32f8473 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -36,6 +36,12 @@ #include "os/keyboard.h" #include "project_settings.h" +// For onion skinning +#include "editor/plugins/canvas_item_editor_plugin.h" +#include "editor/plugins/spatial_editor_plugin.h" +#include "scene/main/viewport.h" +#include "servers/visual_server.h" + void AnimationPlayerEditor::_node_removed(Node *p_node) { if (player && player == p_node) { @@ -98,6 +104,8 @@ void AnimationPlayerEditor::_notification(int p_what) { tool_anim->get_popup()->connect("id_pressed", this, "_animation_tool_menu"); + onion_skinning->get_popup()->connect("id_pressed", this, "_onion_skinning_menu"); + blend_editor.next->connect("item_selected", this, "_blend_editor_next_changed"); get_tree()->connect("node_removed", this, "_node_removed"); @@ -132,6 +140,7 @@ void AnimationPlayerEditor::_notification(int p_what) { resource_edit_anim->set_icon(get_icon("EditResource", "EditorIcons")); pin->set_icon(get_icon("Pin", "EditorIcons")); tool_anim->set_icon(get_icon("Tools", "EditorIcons")); + onion_skinning->set_icon(get_icon("Onion", "EditorIcons")); } break; } @@ -809,6 +818,7 @@ void AnimationPlayerEditor::_update_player() { resource_edit_anim->set_disabled(animlist.size() == 0); save_anim->set_disabled(animlist.size() == 0); tool_anim->set_disabled(player == NULL); + onion_skinning->set_disabled(player == NULL); int active_idx = -1; for (List::Element *E = animlist.front(); E; E = E->next()) { @@ -855,6 +865,9 @@ void AnimationPlayerEditor::_update_player() { void AnimationPlayerEditor::edit(AnimationPlayer *p_player) { + if (onion.enabled) + _start_onion_skinning(); + if (player && pin->is_pressed()) return; //ignore, pinned player = p_player; @@ -869,6 +882,55 @@ void AnimationPlayerEditor::edit(AnimationPlayer *p_player) { } } +void AnimationPlayerEditor::forward_force_draw_over_viewport(Control *p_overlay) { + + if (!onion.can_overlay) + return; + + // Can happen on viewport resize, at least + if (!_are_onion_layers_valid()) + return; + + RID ci = p_overlay->get_canvas_item(); + Rect2 src_rect = p_overlay->get_global_rect(); + // Re-flip since captures are already flipped + src_rect.position.y = onion.capture_size.y - (src_rect.position.y + src_rect.size.y); + src_rect.size.y *= -1; + + Rect2 dst_rect = Rect2(Point2(), p_overlay->get_size()); + + float alpha_step = 1.0 / (onion.steps + 1); + + int cidx = 0; + if (onion.past) { + float alpha = 0; + do { + alpha += alpha_step; + + if (onion.captures_valid[cidx]) { + VS::get_singleton()->canvas_item_add_texture_rect_region( + ci, dst_rect, VS::get_singleton()->viewport_get_texture(onion.captures[cidx]), src_rect, Color(1, 1, 1, alpha)); + } + + cidx++; + } while (cidx < onion.steps); + } + if (onion.future) { + float alpha = 1; + int base_cidx = cidx; + do { + alpha -= alpha_step; + + if (onion.captures_valid[cidx]) { + VS::get_singleton()->canvas_item_add_texture_rect_region( + ci, dst_rect, VS::get_singleton()->viewport_get_texture(onion.captures[cidx]), src_rect, Color(1, 1, 1, alpha)); + } + + cidx++; + } while (cidx < base_cidx + onion.steps); // In case there's the present capture at the end, skip it + } +} + void AnimationPlayerEditor::_animation_duplicate() { if (!animation->get_item_count()) @@ -1100,6 +1162,70 @@ void AnimationPlayerEditor::_animation_save_menu(int p_option) { } } +void AnimationPlayerEditor::_onion_skinning_menu(int p_option) { + + PopupMenu *menu = onion_skinning->get_popup(); + int idx = menu->get_item_index(p_option); + + switch (p_option) { + + case ONION_SKINNING_ENABLE: { + + onion.enabled = !onion.enabled; + menu->set_item_checked(idx, onion.enabled); + + if (onion.enabled) + _start_onion_skinning(); + else + _stop_onion_skinning(); + + } break; + + case ONION_SKINNING_PAST: { + + // Ensure at least one of past/future is checjed + onion.past = onion.future ? !onion.past : true; + menu->set_item_checked(idx, onion.past); + } break; + + case ONION_SKINNING_FUTURE: { + + // Ensure at least one of past/future is checjed + onion.future = onion.past ? !onion.future : true; + menu->set_item_checked(idx, onion.future); + } break; + + case ONION_SKINNING_1_STEP: // Fall-through + case ONION_SKINNING_2_STEPS: + case ONION_SKINNING_3_STEPS: { + + onion.steps = (p_option - ONION_SKINNING_1_STEP) + 1; + int one_frame_idx = menu->get_item_index(ONION_SKINNING_1_STEP); + for (int i = 0; i <= ONION_SKINNING_LAST_STEPS_OPTION - ONION_SKINNING_1_STEP; i++) { + menu->set_item_checked(one_frame_idx + i, onion.steps == i + 1); + } + } break; + + case ONION_SKINNING_DIFFERENCES_ONLY: { + + onion.differences_only = !onion.differences_only; + menu->set_item_checked(idx, onion.differences_only); + } break; + + case ONION_SKINNING_FORCE_WHITE_MODULATE: { + + onion.force_white_modulate = !onion.force_white_modulate; + menu->set_item_checked(idx, onion.force_white_modulate); + } break; + + case ONION_SKINNING_INCLUDE_GIZMOS: { + + onion.include_gizmos = !onion.include_gizmos; + menu->set_item_checked(idx, onion.include_gizmos); + } break; + } +} + void AnimationPlayerEditor::_unhandled_key_input(const Ref &p_ev) { Ref k = p_ev; @@ -1126,6 +1252,237 @@ void AnimationPlayerEditor::_unhandled_key_input(const Ref &p_ev) { } } +void AnimationPlayerEditor::_editor_visibility_changed() { + + if (is_visible()) { + _start_onion_skinning(); + } +} + +bool AnimationPlayerEditor::_are_onion_layers_valid() { + + ERR_FAIL_COND_V(!onion.past && !onion.future, false); + + Point2 capture_size = get_tree()->get_root()->get_size(); + return onion.captures.size() == onion.get_needed_capture_count() && onion.capture_size == capture_size; +} + +void AnimationPlayerEditor::_allocate_onion_layers() { + + _free_onion_layers(); + + int captures = onion.get_needed_capture_count(); + Point2 capture_size = get_tree()->get_root()->get_size(); + + onion.captures.resize(captures); + onion.captures_valid.resize(captures); + + for (int i = 0; i < captures; i++) { + bool is_present = onion.differences_only && i == captures - 1; + + // Each capture is a viewport with a canvas item attached that renders a full-size rect with the contents of the main viewport + onion.captures[i] = VS::get_singleton()->viewport_create(); + VS::get_singleton()->viewport_set_usage(onion.captures[i], VS::VIEWPORT_USAGE_2D); + VS::get_singleton()->viewport_set_size(onion.captures[i], capture_size.width, capture_size.height); + VS::get_singleton()->viewport_set_update_mode(onion.captures[i], VS::VIEWPORT_UPDATE_ALWAYS); + VS::get_singleton()->viewport_set_transparent_background(onion.captures[i], !is_present); + VS::get_singleton()->viewport_set_vflip(onion.captures[i], true); + VS::get_singleton()->viewport_attach_canvas(onion.captures[i], onion.capture.canvas); + } + + // Reset the capture canvas item to the current root viewport texture (defensive) + VS::get_singleton()->canvas_item_clear(onion.capture.canvas_item); + VS::get_singleton()->canvas_item_add_texture_rect(onion.capture.canvas_item, Rect2(Point2(), capture_size), get_tree()->get_root()->get_texture()->get_rid()); + + onion.capture_size = capture_size; +} + +void AnimationPlayerEditor::_free_onion_layers() { + + for (int i = 0; i < onion.captures.size(); i++) { + if (onion.captures[i].is_valid()) { + VS::get_singleton()->free(onion.captures[i]); + } + } + onion.captures.clear(); + onion.captures_valid.clear(); +} + +void AnimationPlayerEditor::_prepare_onion_layers_1() { + + // This would be called per viewport and we want to act once only + int64_t frame = get_tree()->get_frame(); + if (frame == onion.last_frame) + return; + + if (!onion.enabled || !is_processing() || !is_visible() || !get_player()) { + _stop_onion_skinning(); + return; + } + + onion.last_frame = frame; + + // Refresh viewports with no onion layers overlaid + onion.can_overlay = false; + plugin->update_overlays(); + + if (player->is_playing()) + return; + + // And go to next step afterwards + call_deferred("_prepare_onion_layers_2"); +} + +void AnimationPlayerEditor::_prepare_onion_layers_2() { + + Ref anim = player->get_animation(player->get_current_animation()); + if (!anim.is_valid()) + return; + + if (!_are_onion_layers_valid()) + _allocate_onion_layers(); + + // Hide superfluous elements that would make the overlay unnecessary cluttered + Dictionary canvas_edit_state; + Dictionary spatial_edit_state; + if (SpatialEditor::get_singleton()->is_visible()) { + // 3D + spatial_edit_state = SpatialEditor::get_singleton()->get_state(); + Dictionary new_state = spatial_edit_state.copy(); + new_state["show_grid"] = false; + new_state["show_origin"] = false; + Array orig_vp = spatial_edit_state["viewports"]; + Array vp; + vp.resize(4); + for (int i = 0; i < vp.size(); i++) { + Dictionary d = ((Dictionary)orig_vp[i]).copy(); + d["use_environment"] = false; + d["doppler"] = false; + d["gizmos"] = onion.include_gizmos ? d["gizmos"] : Variant(false); + d["information"] = false; + vp[i] = d; + } + new_state["viewports"] = vp; + // TODO: Save/restore only affected entries + SpatialEditor::get_singleton()->set_state(new_state); + } else { // CanvasItemEditor + // 2D + canvas_edit_state = CanvasItemEditor::get_singleton()->get_state(); + Dictionary new_state = canvas_edit_state.copy(); + new_state["show_grid"] = false; + new_state["show_rulers"] = false; + new_state["show_guides"] = false; + new_state["show_helpers"] = false; + // TODO: Save/restore only affected entries + CanvasItemEditor::get_singleton()->set_state(new_state); + } + + // Tweak the root viewport to ensure it's rendered before our target + RID root_vp = get_tree()->get_root()->get_viewport_rid(); + Rect2 root_vp_screen_rect = get_tree()->get_root()->get_attach_to_screen_rect(); + VS::get_singleton()->viewport_attach_to_screen(root_vp, Rect2()); + VS::get_singleton()->viewport_set_update_mode(root_vp, VS::VIEWPORT_UPDATE_ALWAYS); + + RID present_rid; + if (onion.differences_only) { + // Capture present scene as it is + VS::get_singleton()->canvas_item_set_material(onion.capture.canvas_item, RID()); + present_rid = onion.captures[onion.captures.size() - 1]; + VS::get_singleton()->viewport_set_active(present_rid, true); + VS::get_singleton()->viewport_set_parent_viewport(root_vp, present_rid); + VS::get_singleton()->draw(false); + VS::get_singleton()->viewport_set_active(present_rid, false); + } + + // Backup current animation state + AnimatedValuesBackup values_backup = player->backup_animated_values(); + float cpos = player->get_current_animation_position(); + + // Render every past/future step with the capture shader + + VS::get_singleton()->canvas_item_set_material(onion.capture.canvas_item, onion.capture.material->get_rid()); + onion.capture.material->set_shader_param("bkg_color", GLOBAL_GET("rendering/environment/default_clear_color")); + onion.capture.material->set_shader_param("differences_only", onion.differences_only); + onion.capture.material->set_shader_param("present", onion.differences_only ? VS::get_singleton()->viewport_get_texture(present_rid) : RID()); + + int step_off_a = onion.past ? -onion.steps : 0; + int step_off_b = onion.future ? onion.steps : 0; + int cidx = 0; + onion.capture.material->set_shader_param("dir_color", onion.force_white_modulate ? Color(1, 1, 1) : Color(EDITOR_GET("editors/animation/onion_layers_past_color"))); + for (int step_off = step_off_a; step_off <= step_off_b; step_off++) { + + if (step_off == 0) { + // Skip present step and switch to the color of future + if (!onion.force_white_modulate) + onion.capture.material->set_shader_param("dir_color", EDITOR_GET("editors/animation/onion_layers_future_color")); + continue; + } + + float pos = cpos + step_off * anim->get_step(); + + bool valid = anim->has_loop() || pos >= 0 && pos <= anim->get_length(); + onion.captures_valid[cidx] = valid; + if (valid) { + player->seek(pos, true); + get_tree()->flush_transform_notifications(); // Needed for transforms of Spatials + values_backup.update_skeletons(); // Needed for Skeletons + + VS::get_singleton()->viewport_set_active(onion.captures[cidx], true); + VS::get_singleton()->viewport_set_parent_viewport(root_vp, onion.captures[cidx]); + VS::get_singleton()->draw(false); + VS::get_singleton()->viewport_set_active(onion.captures[cidx], false); + } + + cidx++; + } + + // Restore root viewport + VS::get_singleton()->viewport_set_parent_viewport(root_vp, RID()); + VS::get_singleton()->viewport_attach_to_screen(root_vp, root_vp_screen_rect); + VS::get_singleton()->viewport_set_update_mode(root_vp, VS::VIEWPORT_UPDATE_WHEN_VISIBLE); + + // Restore animation state + // (Seeking with update=true wouldn't do the trick because the current value of the properties + // may not match their value for the current point in the animation) + player->seek(cpos, false); + player->restore_animated_values(values_backup); + + // Restor state of main editors + if (SpatialEditor::get_singleton()->is_visible()) { + // 3D + SpatialEditor::get_singleton()->set_state(spatial_edit_state); + } else { // CanvasItemEditor + // 2D + CanvasItemEditor::get_singleton()->set_state(canvas_edit_state); + } + + // Update viewports with skin layers overlaid for the actual engine loop render + onion.can_overlay = true; + plugin->update_overlays(); +} + +void AnimationPlayerEditor::_start_onion_skinning() { + + // FIXME: Using "idle_frame" makes onion layers update one frame behing the current + if (!get_tree()->is_connected("idle_frame", this, "call_deferred")) { + get_tree()->connect("idle_frame", this, "call_deferred", varray("_prepare_onion_layers_1")); + } +} + +void AnimationPlayerEditor::_stop_onion_skinning() { + + if (get_tree()->is_connected("idle_frame", this, "call_deferred")) { + + get_tree()->disconnect("idle_frame", this, "call_deferred"); + + _free_onion_layers(); + + // Clean up the overlay + onion.can_overlay = false; + plugin->update_overlays(); + } +} + void AnimationPlayerEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_gui_input"), &AnimationPlayerEditor::_gui_input); @@ -1165,6 +1522,10 @@ void AnimationPlayerEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_unhandled_key_input"), &AnimationPlayerEditor::_unhandled_key_input); ClassDB::bind_method(D_METHOD("_animation_tool_menu"), &AnimationPlayerEditor::_animation_tool_menu); ClassDB::bind_method(D_METHOD("_animation_save_menu"), &AnimationPlayerEditor::_animation_save_menu); + ClassDB::bind_method(D_METHOD("_onion_skinning_menu"), &AnimationPlayerEditor::_onion_skinning_menu); + ClassDB::bind_method(D_METHOD("_editor_visibility_changed"), &AnimationPlayerEditor::_editor_visibility_changed); + ClassDB::bind_method(D_METHOD("_prepare_onion_layers_1"), &AnimationPlayerEditor::_prepare_onion_layers_1); + ClassDB::bind_method(D_METHOD("_prepare_onion_layers_2"), &AnimationPlayerEditor::_prepare_onion_layers_2); } AnimationPlayerEditor *AnimationPlayerEditor::singleton = NULL; @@ -1173,8 +1534,10 @@ AnimationPlayer *AnimationPlayerEditor::get_player() const { return player; } -AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) { + +AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlayerEditorPlugin *p_plugin) { editor = p_editor; + plugin = p_plugin; singleton = this; updating = false; @@ -1301,6 +1664,29 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) { //tool_anim->get_popup()->add_item("Edit Anim Resource",TOOL_PASTE_ANIM); hb->add_child(tool_anim); + onion_skinning = memnew(MenuButton); + //onion_skinning->set_flat(false); + onion_skinning->set_tooltip(TTR("Onion Skinning")); + onion_skinning->get_popup()->add_check_shortcut(ED_SHORTCUT("animation_player_editor/onion_skinning", TTR("Enable Onion Skinning")), ONION_SKINNING_ENABLE); + onion_skinning->get_popup()->add_separator(); + onion_skinning->get_popup()->add_item(TTR("Directions"), -1); + onion_skinning->get_popup()->set_item_disabled(onion_skinning->get_popup()->get_item_count() - 1, true); + onion_skinning->get_popup()->add_check_item(TTR("Past"), ONION_SKINNING_PAST); + onion_skinning->get_popup()->set_item_checked(onion_skinning->get_popup()->get_item_count() - 1, true); + onion_skinning->get_popup()->add_check_item(TTR("Future"), ONION_SKINNING_FUTURE); + onion_skinning->get_popup()->add_separator(); + onion_skinning->get_popup()->add_item(TTR("Depth"), -1); + onion_skinning->get_popup()->set_item_disabled(onion_skinning->get_popup()->get_item_count() - 1, true); + onion_skinning->get_popup()->add_check_item(TTR("1 step"), ONION_SKINNING_1_STEP); + onion_skinning->get_popup()->set_item_checked(onion_skinning->get_popup()->get_item_count() - 1, true); + onion_skinning->get_popup()->add_check_item(TTR("2 steps"), ONION_SKINNING_2_STEPS); + onion_skinning->get_popup()->add_check_item(TTR("3 steps"), ONION_SKINNING_3_STEPS); + onion_skinning->get_popup()->add_separator(); + onion_skinning->get_popup()->add_check_item(TTR("Differences Only"), ONION_SKINNING_DIFFERENCES_ONLY); + onion_skinning->get_popup()->add_check_item(TTR("Force White Modulate"), ONION_SKINNING_FORCE_WHITE_MODULATE); + onion_skinning->get_popup()->add_check_item(TTR("Include Gizmos (3D)"), ONION_SKINNING_INCLUDE_GIZMOS); + hb->add_child(onion_skinning); + pin = memnew(ToolButton); pin->set_toggle_mode(true); hb->add_child(pin); @@ -1387,6 +1773,68 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) { key_editor->connect("animation_step_changed", this, "_animation_key_editor_anim_step_changed"); _update_player(); + + // Onion skinning + + key_editor->connect("visibility_changed", this, "_editor_visibility_changed"); + + onion.enabled = false; + onion.past = true; + onion.future = false; + onion.steps = 1; + onion.differences_only = false; + onion.force_white_modulate = false; + onion.include_gizmos = false; + + onion.last_frame = 0; + onion.can_overlay = false; + onion.capture_size = Size2(); + onion.capture.canvas = VS::get_singleton()->canvas_create(); + onion.capture.canvas_item = VS::get_singleton()->canvas_item_create(); + VS::get_singleton()->canvas_item_set_parent(onion.capture.canvas_item, onion.capture.canvas); + + onion.capture.material = Ref(memnew(ShaderMaterial)); + + onion.capture.shader = Ref(memnew(Shader)); + onion.capture.shader->set_code(" \ + shader_type canvas_item; \ + \ + uniform vec4 bkg_color; \ + uniform vec4 dir_color; \ + uniform bool differences_only; \ + uniform sampler2D present; \ + \ + float zero_if_equal(vec4 a, vec4 b) { \ + return smoothstep(0.0, 0.005, length(a.rgb - b.rgb) / sqrt(3.0)); \ + } \ + \ + void fragment() { \ + vec4 capture_samp = texture(TEXTURE, UV); \ + vec4 present_samp = texture(present, UV); \ + float bkg_mask = zero_if_equal(capture_samp, bkg_color); \ + float diff_mask = 1.0 - zero_if_equal(present_samp, bkg_color); \ + diff_mask = min(1.0, diff_mask + float(!differences_only)); \ + COLOR = vec4(capture_samp.rgb * dir_color.rgb, bkg_mask * diff_mask); \ + } \ + "); + VS::get_singleton()->material_set_shader(onion.capture.material->get_rid(), onion.capture.shader->get_rid()); +} + +AnimationPlayerEditor::~AnimationPlayerEditor() { + + _free_onion_layers(); + VS::get_singleton()->free(onion.capture.canvas); + VS::get_singleton()->free(onion.capture.canvas_item); +} + +void AnimationPlayerEditorPlugin::_notification(int p_what) { + + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + + set_force_draw_over_forwarding_enabled(); + } break; + } } void AnimationPlayerEditorPlugin::edit(Object *p_object) { @@ -1420,7 +1868,7 @@ void AnimationPlayerEditorPlugin::make_visible(bool p_visible) { AnimationPlayerEditorPlugin::AnimationPlayerEditorPlugin(EditorNode *p_node) { editor = p_node; - anim_editor = memnew(AnimationPlayerEditor(editor)); + anim_editor = memnew(AnimationPlayerEditor(editor, this)); anim_editor->set_undo_redo(editor->get_undo_redo()); editor->add_bottom_panel_item(TTR("Animation"), anim_editor); diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index cea6b05ed44..1a1e92d7b72 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -42,11 +42,13 @@ @author Juan Linietsky */ class AnimationKeyEditor; +class AnimationPlayerEditorPlugin; class AnimationPlayerEditor : public VBoxContainer { GDCLASS(AnimationPlayerEditor, VBoxContainer); EditorNode *editor; + AnimationPlayerEditorPlugin *plugin; AnimationPlayer *player; enum { @@ -55,6 +57,19 @@ class AnimationPlayerEditor : public VBoxContainer { TOOL_EDIT_RESOURCE }; + enum { + ONION_SKINNING_ENABLE, + ONION_SKINNING_PAST, + ONION_SKINNING_FUTURE, + ONION_SKINNING_1_STEP, + ONION_SKINNING_2_STEPS, + ONION_SKINNING_3_STEPS, + ONION_SKINNING_LAST_STEPS_OPTION = ONION_SKINNING_3_STEPS, + ONION_SKINNING_DIFFERENCES_ONLY, + ONION_SKINNING_FORCE_WHITE_MODULATE, + ONION_SKINNING_INCLUDE_GIZMOS, + }; + enum { ANIM_SAVE, ANIM_SAVE_AS @@ -84,6 +99,7 @@ class AnimationPlayerEditor : public VBoxContainer { Button *blend_anim; Button *remove_anim; MenuButton *tool_anim; + MenuButton *onion_skinning; ToolButton *pin; SpinBox *frame; LineEdit *scale; @@ -115,6 +131,36 @@ class AnimationPlayerEditor : public VBoxContainer { AnimationKeyEditor *key_editor; + // Onion skinning + struct { + // Settings + bool enabled; + bool past; + bool future; + int steps; + bool differences_only; + bool force_white_modulate; + bool include_gizmos; + + int get_needed_capture_count() const { + // 'Differences only' needs a capture of the present + return (past && future ? 2 * steps : steps) + (differences_only ? 1 : 0); + } + + // Rendering + int64_t last_frame; + int can_overlay; + Size2 capture_size; + Vector captures; + Vector captures_valid; + struct { + RID canvas; + RID canvas_item; + Ref material; + Ref shader; + } capture; + } onion; + void _select_anim_by_name(const String &p_anim); void _play_pressed(); void _play_from_pressed(); @@ -161,8 +207,19 @@ class AnimationPlayerEditor : public VBoxContainer { void _unhandled_key_input(const Ref &p_ev); void _animation_tool_menu(int p_option); void _animation_save_menu(int p_option); + void _onion_skinning_menu(int p_option); + + void _editor_visibility_changed(); + bool _are_onion_layers_valid(); + void _allocate_onion_layers(); + void _free_onion_layers(); + void _prepare_onion_layers_1(); + void _prepare_onion_layers_2(); + void _start_onion_skinning(); + void _stop_onion_skinning(); AnimationPlayerEditor(); + ~AnimationPlayerEditor(); protected: void _notification(int p_what); @@ -182,7 +239,9 @@ public: void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; } void edit(AnimationPlayer *p_player); - AnimationPlayerEditor(EditorNode *p_editor); + void forward_force_draw_over_viewport(Control *p_overlay); + + AnimationPlayerEditor(EditorNode *p_editor, AnimationPlayerEditorPlugin *p_plugin); }; class AnimationPlayerEditorPlugin : public EditorPlugin { @@ -192,6 +251,9 @@ class AnimationPlayerEditorPlugin : public EditorPlugin { AnimationPlayerEditor *anim_editor; EditorNode *editor; +protected: + void _notification(int p_what); + public: virtual Dictionary get_state() const { return anim_editor->get_state(); } virtual void set_state(const Dictionary &p_state) { anim_editor->set_state(p_state); } @@ -202,6 +264,8 @@ public: virtual bool handles(Object *p_object) const; virtual void make_visible(bool p_visible); + virtual void forward_force_draw_over_viewport(Control *p_overlay) { anim_editor->forward_force_draw_over_viewport(p_overlay); } + AnimationPlayerEditorPlugin(EditorNode *p_node); ~AnimationPlayerEditorPlugin(); }; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index ea445b15735..206f3ccca2f 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -33,6 +33,17 @@ #include "message_queue.h" #include "scene/scene_string_names.h" +#ifdef TOOLS_ENABLED +void AnimatedValuesBackup::update_skeletons() { + + for (int i = 0; i < entries.size(); i++) { + if (entries[i].bone_idx != -1) { + Object::cast_to(entries[i].object)->notification(Skeleton::NOTIFICATION_UPDATE_SKELETON); + } + } +} +#endif + bool AnimationPlayer::_set(const StringName &p_name, const Variant &p_value) { String name = p_name; diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 4a347f49ea7..e39afcf199d 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -50,6 +50,9 @@ class AnimatedValuesBackup { Vector entries; friend class AnimationPlayer; + +public: + void update_skeletons(); }; #endif diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index d4be683a2b0..b8dba96551d 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -127,7 +127,7 @@ void SceneTree::remove_from_group(const StringName &p_group, Node *p_node) { group_map.erase(E); } -void SceneTree::_flush_transform_notifications() { +void SceneTree::flush_transform_notifications() { SelfList *n = xform_change_list.first(); while (n) { @@ -448,7 +448,7 @@ bool SceneTree::iteration(float p_time) { current_frame++; - _flush_transform_notifications(); + flush_transform_notifications(); MainLoop::iteration(p_time); physics_process_time = p_time; @@ -459,7 +459,7 @@ bool SceneTree::iteration(float p_time) { _notify_group_pause("physics_process", Node::NOTIFICATION_PHYSICS_PROCESS); _flush_ugc(); MessageQueue::get_singleton()->flush(); //small little hack - _flush_transform_notifications(); + flush_transform_notifications(); call_group_flags(GROUP_CALL_REALTIME, "_viewports", "update_worlds"); root_lock--; @@ -487,7 +487,7 @@ bool SceneTree::idle(float p_time) { MessageQueue::get_singleton()->flush(); //small little hack - _flush_transform_notifications(); + flush_transform_notifications(); _notify_group_pause("idle_process_internal", Node::NOTIFICATION_INTERNAL_PROCESS); _notify_group_pause("idle_process", Node::NOTIFICATION_PROCESS); @@ -503,7 +503,7 @@ bool SceneTree::idle(float p_time) { _flush_ugc(); MessageQueue::get_singleton()->flush(); //small little hack - _flush_transform_notifications(); //transforms after world update, to avoid unnecessary enter/exit notifications + flush_transform_notifications(); //transforms after world update, to avoid unnecessary enter/exit notifications call_group_flags(GROUP_CALL_REALTIME, "_viewports", "update_worlds"); root_lock--; diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index bc3efdc42f6..7898dc065a1 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -157,7 +157,6 @@ private: Map > unique_group_calls; bool ugc_locked; void _flush_ugc(); - void _flush_transform_notifications(); _FORCE_INLINE_ void _update_group_order(Group &g); void _update_listener(); @@ -344,6 +343,8 @@ public: void notify_group(const StringName &p_group, int p_notification); void set_group(const StringName &p_group, const String &p_name, const Variant &p_value); + void flush_transform_notifications(); + virtual void input_text(const String &p_text); virtual void input_event(const Ref &p_event); virtual void init();