mirror of
https://github.com/Relintai/broken_seals.git
synced 2024-12-21 13:16:49 +01:00
3274 lines
125 KiB
Diff
3274 lines
125 KiB
Diff
From dba67e552f3ded667d287aee3c2d24abf454db82 Mon Sep 17 00:00:00 2001
|
|
From: Saracen <SaracenOne@gmail.com>
|
|
Date: Sat, 2 May 2020 10:11:48 +0100
|
|
Subject: [PATCH] Custom Skeleton3DEditorPlugin
|
|
|
|
Add fallthrough hint
|
|
|
|
Add missing semicolon
|
|
|
|
Fix regression from Skeleton3D Inspector redesign
|
|
|
|
It can be reproduced by reimporting many FBX files with a skeleton.
|
|
|
|
A change in commit f7fdc87 [Merged on May 27] mistakenly changed the Skeleton3D "pose" property from PROPERTY_USAGE_EDITOR to PROPERTY_USAGE_NOEDITOR.
|
|
|
|
skel edit
|
|
|
|
fix selection
|
|
---
|
|
doc/classes/EditorPlugin.xml | 10 +-
|
|
editor/animation_track_editor.cpp | 20 +
|
|
editor/animation_track_editor.h | 2 +
|
|
editor/editor_node.cpp | 4 +-
|
|
editor/editor_node.h | 2 +-
|
|
editor/editor_plugin.cpp | 6 +-
|
|
editor/editor_plugin.h | 2 +-
|
|
editor/editor_themes.cpp | 1 +
|
|
editor/icons/icon_editor_bone_handle.svg | 1 +
|
|
editor/icons/icon_tool_bone_move.svg | 1 +
|
|
editor/icons/icon_tool_bone_rest.svg | 1 +
|
|
editor/icons/icon_tool_bone_rotate.svg | 1 +
|
|
editor/icons/icon_tool_bone_scale.svg | 1 +
|
|
editor/icons/icon_tool_bone_select.svg | 1 +
|
|
.../collision_polygon_editor_plugin.cpp | 2 +-
|
|
.../plugins/collision_polygon_editor_plugin.h | 4 +-
|
|
editor/plugins/path_editor_plugin.cpp | 2 +-
|
|
editor/plugins/path_editor_plugin.h | 2 +-
|
|
editor/plugins/skeleton_editor_plugin.cpp | 1705 ++++++++++++++++-
|
|
editor/plugins/skeleton_editor_plugin.h | 234 ++-
|
|
editor/plugins/spatial_editor_plugin.cpp | 173 +-
|
|
editor/plugins/spatial_editor_plugin.h | 99 +-
|
|
editor/spatial_editor_gizmos.cpp | 94 +-
|
|
editor/spatial_editor_gizmos.h | 5 +
|
|
modules/gridmap/grid_map_editor_plugin.h | 2 +-
|
|
scene/3d/skeleton.cpp | 37 +-
|
|
scene/3d/skeleton.h | 6 +
|
|
27 files changed, 2223 insertions(+), 195 deletions(-)
|
|
create mode 100644 editor/icons/icon_editor_bone_handle.svg
|
|
create mode 100644 editor/icons/icon_tool_bone_move.svg
|
|
create mode 100644 editor/icons/icon_tool_bone_rest.svg
|
|
create mode 100644 editor/icons/icon_tool_bone_rotate.svg
|
|
create mode 100644 editor/icons/icon_tool_bone_scale.svg
|
|
create mode 100644 editor/icons/icon_tool_bone_select.svg
|
|
|
|
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
|
|
index 3f741d3e76..585580261b 100644
|
|
--- a/doc/classes/EditorPlugin.xml
|
|
+++ b/doc/classes/EditorPlugin.xml
|
|
@@ -278,22 +278,24 @@
|
|
<method name="forward_spatial_gui_input" qualifiers="virtual">
|
|
<return type="bool">
|
|
</return>
|
|
- <argument index="0" name="camera" type="Camera">
|
|
+ <argument index="0" name="index" type="int">
|
|
</argument>
|
|
- <argument index="1" name="event" type="InputEvent">
|
|
+ <argument index="1" name="camera" type="Camera">
|
|
+ </argument>
|
|
+ <argument index="2" name="event" type="InputEvent">
|
|
</argument>
|
|
<description>
|
|
Called when there is a root node in the current edited scene, [method handles] is implemented and an [InputEvent] happens in the 3D viewport. Intercepts the [InputEvent], if [code]return true[/code] [EditorPlugin] consumes the [code]event[/code], otherwise forwards [code]event[/code] to other Editor classes. Example:
|
|
[codeblock]
|
|
# Prevents the InputEvent to reach other Editor classes
|
|
- func forward_spatial_gui_input(camera, event):
|
|
+ func forward_spatial_gui_input(index, camera, event):
|
|
var forward = true
|
|
return forward
|
|
[/codeblock]
|
|
Must [code]return false[/code] in order to forward the [InputEvent] to other Editor classes. Example:
|
|
[codeblock]
|
|
# Consumes InputEventMouseMotion and forwards other InputEvent types
|
|
- func forward_spatial_gui_input(camera, event):
|
|
+ func forward_spatial_gui_input(index, camera, event):
|
|
var forward = false
|
|
if event is InputEventMouseMotion:
|
|
forward = true
|
|
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
|
|
index b5792034cf..cc9725d0bc 100644
|
|
--- a/editor/animation_track_editor.cpp
|
|
+++ b/editor/animation_track_editor.cpp
|
|
@@ -3562,6 +3562,26 @@ void AnimationTrackEditor::_insert_delay() {
|
|
insert_queue = false;
|
|
}
|
|
|
|
+bool AnimationTrackEditor::has_transform_key(Spatial *p_node, const String &p_sub) {
|
|
+
|
|
+ if (!keying)
|
|
+ return false;
|
|
+ if (!animation.is_valid())
|
|
+ return false;
|
|
+ if (!root)
|
|
+ return false;
|
|
+
|
|
+ //let's build a node path
|
|
+ String path = root->get_path_to(p_node);
|
|
+ if (p_sub != "")
|
|
+ path += ":" + p_sub;
|
|
+
|
|
+ if (animation->find_track(path) >= 0) {
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
void AnimationTrackEditor::insert_transform_key(Spatial *p_node, const String &p_sub, const Transform &p_xform) {
|
|
|
|
if (!keying)
|
|
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
|
|
index e1798affa9..fa8ac3ff69 100644
|
|
--- a/editor/animation_track_editor.h
|
|
+++ b/editor/animation_track_editor.h
|
|
@@ -514,6 +514,8 @@ public:
|
|
void insert_value_key(const String &p_property, const Variant &p_value, bool p_advance);
|
|
void insert_transform_key(Spatial *p_node, const String &p_sub, const Transform &p_xform);
|
|
|
|
+ bool has_transform_key(Spatial *p_node, const String &p_sub);
|
|
+
|
|
void show_select_node_warning(bool p_show);
|
|
|
|
bool is_key_selected(int p_track, int p_key) const;
|
|
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
|
|
index 1db054c26f..d99598f817 100644
|
|
--- a/editor/editor_node.cpp
|
|
+++ b/editor/editor_node.cpp
|
|
@@ -7151,7 +7151,7 @@ bool EditorPluginList::forward_gui_input(const Ref<InputEvent> &p_event) {
|
|
return discard;
|
|
}
|
|
|
|
-bool EditorPluginList::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled) {
|
|
+bool EditorPluginList::forward_spatial_gui_input(int p_index, Camera *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled) {
|
|
bool discard = false;
|
|
|
|
for (int i = 0; i < plugins_list.size(); i++) {
|
|
@@ -7159,7 +7159,7 @@ bool EditorPluginList::forward_spatial_gui_input(Camera *p_camera, const Ref<Inp
|
|
continue;
|
|
}
|
|
|
|
- if (plugins_list[i]->forward_spatial_gui_input(p_camera, p_event)) {
|
|
+ if (plugins_list[i]->forward_spatial_gui_input(p_index, p_camera, p_event)) {
|
|
discard = true;
|
|
}
|
|
}
|
|
diff --git a/editor/editor_node.h b/editor/editor_node.h
|
|
index cddc0c84e4..b8d247abc9 100644
|
|
--- a/editor/editor_node.h
|
|
+++ b/editor/editor_node.h
|
|
@@ -907,7 +907,7 @@ public:
|
|
bool forward_gui_input(const Ref<InputEvent> &p_event);
|
|
void forward_canvas_draw_over_viewport(Control *p_overlay);
|
|
void forward_canvas_force_draw_over_viewport(Control *p_overlay);
|
|
- bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled);
|
|
+ bool forward_spatial_gui_input(int p_index, Camera *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled);
|
|
void forward_spatial_draw_over_viewport(Control *p_overlay);
|
|
void forward_spatial_force_draw_over_viewport(Control *p_overlay);
|
|
void add_plugin(EditorPlugin *p_plugin);
|
|
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
|
|
index d4c16ee042..89e3316680 100644
|
|
--- a/editor/editor_plugin.cpp
|
|
+++ b/editor/editor_plugin.cpp
|
|
@@ -617,10 +617,10 @@ int EditorPlugin::update_overlays() const {
|
|
}
|
|
}
|
|
|
|
-bool EditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) {
|
|
+bool EditorPlugin::forward_spatial_gui_input(int p_index, Camera *p_camera, const Ref<InputEvent> &p_event) {
|
|
|
|
if (get_script_instance() && get_script_instance()->has_method("forward_spatial_gui_input")) {
|
|
- return get_script_instance()->call("forward_spatial_gui_input", p_camera, p_event);
|
|
+ return get_script_instance()->call("forward_spatial_gui_input", p_index, p_camera, p_event);
|
|
}
|
|
|
|
return false;
|
|
@@ -903,7 +903,7 @@ void EditorPlugin::_bind_methods() {
|
|
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_canvas_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
|
|
ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_canvas_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
|
|
ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_canvas_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")));
|
|
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_spatial_gui_input", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
|
|
ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_spatial_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
|
|
ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_spatial_force_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
|
|
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_plugin_name"));
|
|
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
|
|
index 21293cbbfc..af6732b867 100644
|
|
--- a/editor/editor_plugin.h
|
|
+++ b/editor/editor_plugin.h
|
|
@@ -193,7 +193,7 @@ public:
|
|
virtual void forward_canvas_draw_over_viewport(Control *p_overlay);
|
|
virtual void forward_canvas_force_draw_over_viewport(Control *p_overlay);
|
|
|
|
- virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event);
|
|
+ virtual bool forward_spatial_gui_input(int p_index, Camera *p_camera, const Ref<InputEvent> &p_event);
|
|
virtual void forward_spatial_draw_over_viewport(Control *p_overlay);
|
|
virtual void forward_spatial_force_draw_over_viewport(Control *p_overlay);
|
|
|
|
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
|
|
index 2864ed652a..7b164c6223 100644
|
|
--- a/editor/editor_themes.cpp
|
|
+++ b/editor/editor_themes.cpp
|
|
@@ -213,6 +213,7 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
|
|
exceptions.insert("EditorPivot");
|
|
exceptions.insert("EditorHandle");
|
|
exceptions.insert("Editor3DHandle");
|
|
+ exceptions.insert("EditorBoneHandle");
|
|
exceptions.insert("Godot");
|
|
exceptions.insert("PanoramaSky");
|
|
exceptions.insert("ProceduralSky");
|
|
diff --git a/editor/icons/icon_editor_bone_handle.svg b/editor/icons/icon_editor_bone_handle.svg
|
|
new file mode 100644
|
|
index 0000000000..7658b90f7e
|
|
--- /dev/null
|
|
+++ b/editor/icons/icon_editor_bone_handle.svg
|
|
@@ -0,0 +1 @@
|
|
+<svg height="8" viewBox="0 0 8 8" width="8" xmlns="http://www.w3.org/2000/svg"><circle cx="4" cy="4" fill="#fff" r="4"/><circle cx="4" cy="4" fill="#000" r="2.5"/></svg>
|
|
\ No newline at end of file
|
|
diff --git a/editor/icons/icon_tool_bone_move.svg b/editor/icons/icon_tool_bone_move.svg
|
|
new file mode 100644
|
|
index 0000000000..b9b15eee3f
|
|
--- /dev/null
|
|
+++ b/editor/icons/icon_tool_bone_move.svg
|
|
@@ -0,0 +1 @@
|
|
+<svg enable-background="new 0 0 16 16" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-opacity=".9961"><path d="m11.5 14.448-.831-.831-.909.909 1.286 1.285c.251.251.657.251.908 0l1.286-1.285-.909-.909z"/><circle cx="11.5" cy="11.5" r="1.286"/><path d="m8.753 10.038-.278-.278-1.286 1.286c-.251.251-.251.657 0 .908l.824.824.462.462.909-.909-.832-.831.832-.831z"/><path d="m15.812 11.046-1.286-1.286-.909.909.831.831-.831.831.909.909 1.285-1.286c.252-.251.252-.657.001-.908z"/><path d="m11.954 7.188c-.061-.061-.133-.107-.21-.139-.028-.012-.059-.01-.088-.018-.051-.013-.1-.03-.151-.03-.005 0-.01 0-.015 0-.167.002-.327.069-.444.187l-1.286 1.287.278.278.631.63.831-.831.831.831.909-.908-.465-.465z"/><path d="m6.128 9.985 1.286-1.286c.241-.242.545-.384.859-.426.044-.323.193-.626.426-.859l1.286-1.286c.396-.397.925-.619 1.47-.625h.05c.562 0 1.112.228 1.51.626l1.215 1.215c.016-.015.033-.025.048-.04.964-.963.964-2.524 0-3.488-.378-.378-.868-.623-1.397-.698-.074-.529-.318-1.019-.695-1.397-.455-.453-1.067-.711-1.707-.721-.667-.01-1.309.25-1.782.72-.828.829-.96 2.126-.314 3.105l-3.558 3.561c-.978-.646-2.274-.515-3.103.312-.963.962-.963 2.524 0 3.487.378.377.868.621 1.396.695.075.529.319 1.02.696 1.396.963.964 2.525.964 3.488 0 .015-.015.025-.032.04-.048l-1.215-1.215c-.835-.833-.835-2.193.001-3.028z"/></g></svg>
|
|
\ No newline at end of file
|
|
diff --git a/editor/icons/icon_tool_bone_rest.svg b/editor/icons/icon_tool_bone_rest.svg
|
|
new file mode 100644
|
|
index 0000000000..ab4f915e3d
|
|
--- /dev/null
|
|
+++ b/editor/icons/icon_tool_bone_rest.svg
|
|
@@ -0,0 +1 @@
|
|
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m16 8c0 1.409-.72 2.641-1.824 3.345l1.824 1.823v2.832h-2.832l-4-4h-5.168v4h-4v-16h12c2.208 0 4 1.792 4 4zm-12 0h8v-4h-8z" fill="#e0e0e0"/></svg>
|
|
\ No newline at end of file
|
|
diff --git a/editor/icons/icon_tool_bone_rotate.svg b/editor/icons/icon_tool_bone_rotate.svg
|
|
new file mode 100644
|
|
index 0000000000..1c81687245
|
|
--- /dev/null
|
|
+++ b/editor/icons/icon_tool_bone_rotate.svg
|
|
@@ -0,0 +1 @@
|
|
+<svg enable-background="new 0 0 16 16" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-opacity=".9961"><circle cx="11.501" cy="11.5" r="1.286"/><path d="m15.536 9.51c-.568-1.152-1.591-1.985-2.79-2.331-.027-.008-.056-.011-.084-.019-.163-.043-.327-.084-.496-.109-.199-.03-.402-.048-.608-.05-.027 0-.054 0-.081 0-.039 0-.077 0-.115.001-.149.004-.299.017-.448.037-1.911.251-3.45 1.693-3.826 3.584-.049.248-.069.497-.076.745-.002.062-.002.123-.001.185.004.496.092.983.256 1.447.019.054.04.106.061.16.091.228.194.45.321.661.001.001.001.003.002.004.194.321.429.62.704.889h-.71v1.286h2.571c.355 0 .643-.287.643-.643 0-.053-.006-.105-.019-.156l-.643-2.571-1.248.313.181.721c-.54-.591-.841-1.362-.843-2.163 0-.442.09-.863.251-1.246.08-.189.178-.369.291-.537.001-.005.003-.009.005-.013.348-.516.841-.924 1.42-1.168.384-.162.805-.251 1.247-.251 1.775 0 3.214 1.439 3.214 3.214-.001.853-.34 1.669-.942 2.271l.91.91c1.363-1.363 1.706-3.442.853-5.171z"/><path d="m5.616 10.33c.502-2.522 2.553-4.443 5.103-4.778.199-.026.399-.043.598-.049l.16-.002h.1c1.182.015 2.294.375 3.236 1 .369-.894.191-1.959-.535-2.686-.378-.377-.868-.622-1.397-.697-.074-.529-.318-1.019-.695-1.397-.455-.453-1.067-.711-1.707-.721-.667-.01-1.309.25-1.782.72-.828.829-.96 2.126-.314 3.105l-3.558 3.561c-.978-.646-2.274-.515-3.103.312-.963.962-.963 2.524 0 3.487.378.377.868.621 1.396.695.075.529.319 1.02.696 1.396.632.633 1.52.842 2.329.645v-.208c0-.14.019-.275.055-.403-.639-1.202-.856-2.601-.582-3.98z"/></g></svg>
|
|
\ No newline at end of file
|
|
diff --git a/editor/icons/icon_tool_bone_scale.svg b/editor/icons/icon_tool_bone_scale.svg
|
|
new file mode 100644
|
|
index 0000000000..b1facc4049
|
|
--- /dev/null
|
|
+++ b/editor/icons/icon_tool_bone_scale.svg
|
|
@@ -0,0 +1 @@
|
|
+<svg enable-background="new 0 0 16 16" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-opacity=".9961"><path d="m10.857 14.714h-1.662l.83-.831-.908-.909-.832.832v-1.663c0-.355-.288-.643-.643-.643s-.642.287-.642.643v2.383.832c0 .355.288.642.643.642h3.214c.355 0 .643-.287.643-.643s-.287-.643-.643-.643z"/><path d="m15.357 7h-.832-2.383c-.355 0-.642.288-.642.643s.287.643.643.643h1.663l-.832.832.909.908.831-.83v1.662c0 .355.288.643.644.643s.642-.288.642-.644v-3.214c0-.355-.287-.643-.643-.643z"/><circle cx="11.5" cy="11.5" r="1.286"/><path d="m8.573 10.218 1.645-1.645c-.137-.282-.218-.596-.218-.93 0-1.182.961-2.143 2.143-2.143h2.852c-.014-.611-.25-1.218-.717-1.685-.378-.377-.868-.622-1.397-.697-.074-.529-.318-1.019-.695-1.397-.455-.453-1.067-.711-1.707-.721-.667-.01-1.309.25-1.782.72-.828.829-.96 2.126-.314 3.105l-3.558 3.561c-.978-.646-2.274-.515-3.103.312-.963.962-.963 2.524 0 3.487.378.377.868.621 1.396.695.075.529.319 1.02.696 1.396.467.467 1.074.703 1.685.717v-2.852c.001-1.18.962-2.141 2.144-2.141.334 0 .648.081.93.218z"/></g></svg>
|
|
\ No newline at end of file
|
|
diff --git a/editor/icons/icon_tool_bone_select.svg b/editor/icons/icon_tool_bone_select.svg
|
|
new file mode 100644
|
|
index 0000000000..73e79a191d
|
|
--- /dev/null
|
|
+++ b/editor/icons/icon_tool_bone_select.svg
|
|
@@ -0,0 +1 @@
|
|
+<svg enable-background="new 0 0 16 16" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-opacity=".9961"><path d="m16 11.46-6.142-2.527-1.572-.647.647 1.572 2.527 6.142.913-2.72 1.815 1.817.91-.909-1.818-1.815z"/><path d="m7.784 11.008-.886-2.152c-.23-.56-.102-1.203.327-1.631.287-.287.67-.439 1.061-.439.192 0 .386.037.57.113l2.151.885.17-.17c.977.645 2.271.516 3.1-.311.964-.963.964-2.524 0-3.488-.377-.377-.867-.622-1.396-.697-.074-.529-.318-1.019-.695-1.397-.455-.453-1.067-.711-1.707-.721-.667-.01-1.309.25-1.782.72-.828.829-.96 2.126-.314 3.105l-3.558 3.561c-.978-.646-2.274-.515-3.103.312-.963.962-.963 2.524 0 3.487.378.377.868.621 1.396.695.075.529.319 1.02.696 1.396.963.964 2.525.964 3.488 0 .828-.828.96-2.125.314-3.104z"/></g></svg>
|
|
\ No newline at end of file
|
|
diff --git a/editor/plugins/collision_polygon_editor_plugin.cpp b/editor/plugins/collision_polygon_editor_plugin.cpp
|
|
index 9cd7a60946..b207590996 100644
|
|
--- a/editor/plugins/collision_polygon_editor_plugin.cpp
|
|
+++ b/editor/plugins/collision_polygon_editor_plugin.cpp
|
|
@@ -109,7 +109,7 @@ void Polygon3DEditor::_wip_close() {
|
|
undo_redo->commit_action();
|
|
}
|
|
|
|
-bool Polygon3DEditor::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) {
|
|
+bool Polygon3DEditor::forward_spatial_gui_input(int p_index, Camera *p_camera, const Ref<InputEvent> &p_event) {
|
|
|
|
if (!node)
|
|
return false;
|
|
diff --git a/editor/plugins/collision_polygon_editor_plugin.h b/editor/plugins/collision_polygon_editor_plugin.h
|
|
index 26e0a22713..ed2bf8cee6 100644
|
|
--- a/editor/plugins/collision_polygon_editor_plugin.h
|
|
+++ b/editor/plugins/collision_polygon_editor_plugin.h
|
|
@@ -90,7 +90,7 @@ protected:
|
|
static void _bind_methods();
|
|
|
|
public:
|
|
- virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event);
|
|
+ virtual bool forward_spatial_gui_input(int p_index, Camera *p_camera, const Ref<InputEvent> &p_event);
|
|
void edit(Node *p_collision_polygon);
|
|
Polygon3DEditor(EditorNode *p_editor);
|
|
~Polygon3DEditor();
|
|
@@ -104,7 +104,7 @@ class Polygon3DEditorPlugin : public EditorPlugin {
|
|
EditorNode *editor;
|
|
|
|
public:
|
|
- virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { return collision_polygon_editor->forward_spatial_gui_input(p_camera, p_event); }
|
|
+ virtual bool forward_spatial_gui_input(int p_index, Camera *p_camera, const Ref<InputEvent> &p_event) { return collision_polygon_editor->forward_spatial_gui_input(p_index, p_camera, p_event); }
|
|
|
|
virtual String get_name() const { return "Polygon3DEditor"; }
|
|
bool has_main_screen() const { return false; }
|
|
diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp
|
|
index 35eef6102e..e5221fc17e 100644
|
|
--- a/editor/plugins/path_editor_plugin.cpp
|
|
+++ b/editor/plugins/path_editor_plugin.cpp
|
|
@@ -292,7 +292,7 @@ PathSpatialGizmo::PathSpatialGizmo(Path *p_path) {
|
|
set_spatial_node(p_path);
|
|
}
|
|
|
|
-bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) {
|
|
+bool PathEditorPlugin::forward_spatial_gui_input(int p_index, Camera *p_camera, const Ref<InputEvent> &p_event) {
|
|
|
|
if (!path)
|
|
return false;
|
|
diff --git a/editor/plugins/path_editor_plugin.h b/editor/plugins/path_editor_plugin.h
|
|
index ea908b654a..f9e736ea56 100644
|
|
--- a/editor/plugins/path_editor_plugin.h
|
|
+++ b/editor/plugins/path_editor_plugin.h
|
|
@@ -101,7 +101,7 @@ public:
|
|
Path *get_edited_path() { return path; }
|
|
|
|
static PathEditorPlugin *singleton;
|
|
- virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event);
|
|
+ virtual bool forward_spatial_gui_input(int p_index, Camera *p_camera, const Ref<InputEvent> &p_event);
|
|
|
|
//virtual bool forward_gui_input(const InputEvent& p_event) { return collision_polygon_editor->forward_gui_input(p_event); }
|
|
//virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial);
|
|
diff --git a/editor/plugins/skeleton_editor_plugin.cpp b/editor/plugins/skeleton_editor_plugin.cpp
|
|
index 92d396b903..5cd989efce 100644
|
|
--- a/editor/plugins/skeleton_editor_plugin.cpp
|
|
+++ b/editor/plugins/skeleton_editor_plugin.cpp
|
|
@@ -30,27 +30,523 @@
|
|
|
|
#include "skeleton_editor_plugin.h"
|
|
|
|
+#include "core/io/resource_saver.h"
|
|
+#include "editor/editor_file_dialog.h"
|
|
+#include "editor/editor_properties.h"
|
|
+#include "editor/editor_scale.h"
|
|
+#include "editor/plugins/animation_player_editor_plugin.h"
|
|
#include "scene/3d/collision_shape.h"
|
|
+#include "scene/3d/mesh_instance.h"
|
|
#include "scene/3d/physics_body.h"
|
|
#include "scene/3d/physics_joint.h"
|
|
#include "scene/resources/capsule_shape.h"
|
|
#include "scene/resources/sphere_shape.h"
|
|
#include "spatial_editor_plugin.h"
|
|
|
|
+#define DISTANCE_DEFAULT 4
|
|
+
|
|
+#define GIZMO_ARROW_SIZE 0.35
|
|
+#define GIZMO_RING_HALF_WIDTH 0.1
|
|
+#define GIZMO_SCALE_DEFAULT 0.15
|
|
+#define GIZMO_PLANE_SIZE 0.2
|
|
+#define GIZMO_PLANE_DST 0.3
|
|
+#define GIZMO_CIRCLE_SIZE 1.1
|
|
+#define GIZMO_SCALE_OFFSET (GIZMO_CIRCLE_SIZE + 0.3)
|
|
+#define GIZMO_ARROW_OFFSET (GIZMO_CIRCLE_SIZE + 0.3)
|
|
+
|
|
+#define ZOOM_MIN_DISTANCE 0.001
|
|
+#define ZOOM_MULTIPLIER 1.08
|
|
+#define ZOOM_INDICATOR_DELAY_S 1.5
|
|
+
|
|
+#define FREELOOK_MIN_SPEED 0.01
|
|
+#define FREELOOK_SPEED_MULTIPLIER 1.08
|
|
+
|
|
+#define MIN_Z 0.01
|
|
+#define MAX_Z 1000000.0
|
|
+
|
|
+#define MIN_FOV 0.01
|
|
+#define MAX_FOV 179
|
|
+
|
|
+void BoneTransformEditor::create_editors() {
|
|
+ const Color section_color = get_color("prop_subsection", "Editor");
|
|
+
|
|
+ section = memnew(EditorInspectorSection);
|
|
+ section->setup("trf_properties", label, this, section_color, true);
|
|
+ add_child(section);
|
|
+
|
|
+ key_button = memnew(Button);
|
|
+ key_button->set_text(TTR("Key Transform"));
|
|
+ key_button->set_visible(keyable);
|
|
+ key_button->set_icon(get_icon("Key", "EditorIcons"));
|
|
+ key_button->set_flat(true);
|
|
+ section->get_vbox()->add_child(key_button);
|
|
+
|
|
+ enabled_checkbox = memnew(CheckBox(TTR("Pose Enabled")));
|
|
+ enabled_checkbox->set_flat(true);
|
|
+ enabled_checkbox->set_visible(toggle_enabled);
|
|
+ section->get_vbox()->add_child(enabled_checkbox);
|
|
+
|
|
+ Label *l1 = memnew(Label(TTR("Translation")));
|
|
+ section->get_vbox()->add_child(l1);
|
|
+
|
|
+ translation_grid = memnew(GridContainer());
|
|
+ translation_grid->set_columns(TRANSLATION_COMPONENTS);
|
|
+ section->get_vbox()->add_child(translation_grid);
|
|
+
|
|
+ Label *l2 = memnew(Label(TTR("Rotation Degrees")));
|
|
+ section->get_vbox()->add_child(l2);
|
|
+
|
|
+ rotation_grid = memnew(GridContainer());
|
|
+ rotation_grid->set_columns(ROTATION_DEGREES_COMPONENTS);
|
|
+ section->get_vbox()->add_child(rotation_grid);
|
|
+
|
|
+ Label *l3 = memnew(Label(TTR("Scale")));
|
|
+ section->get_vbox()->add_child(l3);
|
|
+
|
|
+ scale_grid = memnew(GridContainer());
|
|
+ scale_grid->set_columns(SCALE_COMPONENTS);
|
|
+ section->get_vbox()->add_child(scale_grid);
|
|
+
|
|
+ Label *l4 = memnew(Label(TTR("Transform")));
|
|
+ section->get_vbox()->add_child(l4);
|
|
+
|
|
+ transform_grid = memnew(GridContainer());
|
|
+ transform_grid->set_columns(TRANSFORM_CONTROL_COMPONENTS);
|
|
+ section->get_vbox()->add_child(transform_grid);
|
|
+
|
|
+ static const char *desc[TRANSFORM_COMPONENTS] = { "x", "y", "z", "x", "y", "z", "x", "y", "z", "x", "y", "z" };
|
|
+ float snap = EDITOR_GET("interface/inspector/default_float_step");
|
|
+
|
|
+ for (int i = 0; i < TRANSFORM_CONTROL_COMPONENTS; ++i) {
|
|
+ translation_slider[i] = memnew(EditorSpinSlider());
|
|
+ translation_slider[i]->set_label(desc[i]);
|
|
+ translation_slider[i]->set_step(snap);
|
|
+ setup_spinner(translation_slider[i], false);
|
|
+ translation_grid->add_child(translation_slider[i]);
|
|
+
|
|
+ rotation_slider[i] = memnew(EditorSpinSlider());
|
|
+ rotation_slider[i]->set_label(desc[i]);
|
|
+ rotation_slider[i]->set_step(snap);
|
|
+ setup_spinner(rotation_slider[i], false);
|
|
+ rotation_grid->add_child(rotation_slider[i]);
|
|
+
|
|
+ scale_slider[i] = memnew(EditorSpinSlider());
|
|
+ scale_slider[i]->set_label(desc[i]);
|
|
+ scale_slider[i]->set_step(snap);
|
|
+ setup_spinner(scale_slider[i], false);
|
|
+ scale_grid->add_child(scale_slider[i]);
|
|
+ }
|
|
+
|
|
+ for (int i = 0; i < TRANSFORM_COMPONENTS; ++i) {
|
|
+ transform_slider[i] = memnew(EditorSpinSlider());
|
|
+ transform_slider[i]->set_label(desc[i]);
|
|
+ transform_slider[i]->set_step(snap);
|
|
+ setup_spinner(transform_slider[i], true);
|
|
+ transform_grid->add_child(transform_slider[i]);
|
|
+ }
|
|
+}
|
|
+
|
|
+void BoneTransformEditor::setup_spinner(EditorSpinSlider *spinner, const bool is_transform_spinner) {
|
|
+ spinner->set_flat(true);
|
|
+ spinner->set_min(-10000);
|
|
+ spinner->set_max(10000);
|
|
+ spinner->set_hide_slider(true);
|
|
+ spinner->set_allow_greater(true);
|
|
+ spinner->set_allow_lesser(true);
|
|
+ spinner->set_h_size_flags(SIZE_EXPAND_FILL);
|
|
+
|
|
+ spinner->connect("value_changed", this, "_value_changed", varray(is_transform_spinner));
|
|
+}
|
|
+
|
|
+void BoneTransformEditor::_notification(int p_what) {
|
|
+ switch (p_what) {
|
|
+ case NOTIFICATION_ENTER_TREE: {
|
|
+ create_editors();
|
|
+ key_button->connect("pressed", this, "_key_button_pressed");
|
|
+ enabled_checkbox->connect("toggled", this, "_checkbox_toggled");
|
|
+ FALLTHROUGH;
|
|
+ }
|
|
+ case NOTIFICATION_THEME_CHANGED: {
|
|
+ const Color base = get_color("accent_color", "Editor");
|
|
+ const Color bg_color = get_color("property_color", "Editor");
|
|
+ const Color bg_lbl_color(bg_color.r, bg_color.g, bg_color.b, 0.5);
|
|
+
|
|
+ for (int i = 0; i < TRANSLATION_COMPONENTS; i++) {
|
|
+ Color c = base;
|
|
+ c.set_hsv(float(i % TRANSLATION_COMPONENTS) / TRANSLATION_COMPONENTS + 0.05, c.get_s() * 0.75, c.get_v());
|
|
+ if (!translation_slider[i]) {
|
|
+ continue;
|
|
+ }
|
|
+ translation_slider[i]->set_custom_label_color(true, c);
|
|
+ }
|
|
+
|
|
+ for (int i = 0; i < ROTATION_DEGREES_COMPONENTS; i++) {
|
|
+ Color c = base;
|
|
+ c.set_hsv(float(i % ROTATION_DEGREES_COMPONENTS) / ROTATION_DEGREES_COMPONENTS + 0.05, c.get_s() * 0.75, c.get_v());
|
|
+ if (!rotation_slider[i]) {
|
|
+ continue;
|
|
+ }
|
|
+ rotation_slider[i]->set_custom_label_color(true, c);
|
|
+ }
|
|
+
|
|
+ for (int i = 0; i < SCALE_COMPONENTS; i++) {
|
|
+ Color c = base;
|
|
+ c.set_hsv(float(i % SCALE_COMPONENTS) / SCALE_COMPONENTS + 0.05, c.get_s() * 0.75, c.get_v());
|
|
+ if (!scale_slider[i]) {
|
|
+ continue;
|
|
+ }
|
|
+ scale_slider[i]->set_custom_label_color(true, c);
|
|
+ }
|
|
+
|
|
+ for (int i = 0; i < TRANSFORM_COMPONENTS; i++) {
|
|
+ Color c = base;
|
|
+ c.set_hsv(float(i % TRANSFORM_COMPONENTS) / TRANSFORM_COMPONENTS + 0.05, c.get_s() * 0.75, c.get_v());
|
|
+ if (!transform_slider[i]) {
|
|
+ continue;
|
|
+ }
|
|
+ transform_slider[i]->set_custom_label_color(true, c);
|
|
+ }
|
|
+
|
|
+ break;
|
|
+ }
|
|
+ case NOTIFICATION_SORT_CHILDREN: {
|
|
+ const Ref<Font> font = get_font("font", "Tree");
|
|
+
|
|
+ Point2 buffer;
|
|
+ buffer.x += get_constant("inspector_margin", "Editor");
|
|
+ buffer.y += font->get_height();
|
|
+ buffer.y += get_constant("vseparation", "Tree");
|
|
+
|
|
+ const float vector_height = translation_grid->get_size().y;
|
|
+ const float transform_height = transform_grid->get_size().y;
|
|
+ const float button_height = key_button->get_size().y;
|
|
+
|
|
+ const float width = get_size().x - get_constant("inspector_margin", "Editor");
|
|
+ Vector<Rect2> input_rects;
|
|
+ if (keyable && section->get_vbox()->is_visible()) {
|
|
+ input_rects.push_back(Rect2(key_button->get_position() + buffer, Size2(width, button_height)));
|
|
+ } else {
|
|
+ input_rects.push_back(Rect2(0, 0, 0, 0));
|
|
+ }
|
|
+
|
|
+ if (section->get_vbox()->is_visible()) {
|
|
+ input_rects.push_back(Rect2(translation_grid->get_position() + buffer, Size2(width, vector_height)));
|
|
+ input_rects.push_back(Rect2(rotation_grid->get_position() + buffer, Size2(width, vector_height)));
|
|
+ input_rects.push_back(Rect2(scale_grid->get_position() + buffer, Size2(width, vector_height)));
|
|
+ input_rects.push_back(Rect2(transform_grid->get_position() + buffer, Size2(width, transform_height)));
|
|
+ } else {
|
|
+ const int32_t start = input_rects.size();
|
|
+ const int32_t empty_input_rect_elements = 4;
|
|
+ const int32_t end = start + empty_input_rect_elements;
|
|
+ for (int i = start; i < end; ++i) {
|
|
+ input_rects.push_back(Rect2(0, 0, 0, 0));
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (int32_t i = 0; i < input_rects.size(); i++) {
|
|
+ background_rects[i] = input_rects[i];
|
|
+ }
|
|
+
|
|
+ update();
|
|
+ break;
|
|
+ }
|
|
+ case NOTIFICATION_DRAW: {
|
|
+ const Color dark_color = get_color("dark_color_2", "Editor");
|
|
+
|
|
+ for (int i = 0; i < 5; ++i) {
|
|
+ draw_rect(background_rects[i], dark_color);
|
|
+ }
|
|
+
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+void BoneTransformEditor::_value_changed(const double p_value, const bool p_from_transform) {
|
|
+ if (updating)
|
|
+ return;
|
|
+
|
|
+ if (property.get_slicec('/', 0) == "bones" && property.get_slicec('/', 2) == "custom_pose") {
|
|
+ const Transform tform = compute_transform(p_from_transform);
|
|
+
|
|
+ undo_redo->create_action(TTR("Set Custom Bone Pose Transform"), UndoRedo::MERGE_ENDS);
|
|
+ undo_redo->add_undo_method(skeleton, "set_bone_custom_pose", property.get_slicec('/', 1).to_int(), skeleton->get_bone_custom_pose(property.get_slicec('/', 1).to_int()));
|
|
+ undo_redo->add_do_method(skeleton, "set_bone_custom_pose", property.get_slicec('/', 1).to_int(), tform);
|
|
+ undo_redo->commit_action();
|
|
+ } else if (property.get_slicec('/', 0) == "bones") {
|
|
+ const Transform tform = compute_transform(p_from_transform);
|
|
+
|
|
+ undo_redo->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS);
|
|
+ undo_redo->add_undo_property(skeleton, property, skeleton->get(property));
|
|
+ undo_redo->add_do_property(skeleton, property, tform);
|
|
+ undo_redo->commit_action();
|
|
+ }
|
|
+}
|
|
+
|
|
+Transform BoneTransformEditor::compute_transform(const bool p_from_transform) const {
|
|
+
|
|
+ // Last modified was a raw transform column...
|
|
+ if (p_from_transform) {
|
|
+ Transform tform;
|
|
+
|
|
+ for (int i = 0; i < BASIS_COMPONENTS; ++i) {
|
|
+ tform.basis[i / BASIS_SPLIT_COMPONENTS][i % BASIS_SPLIT_COMPONENTS] = transform_slider[i]->get_value();
|
|
+ }
|
|
+
|
|
+ for (int i = 0; i < TRANSLATION_COMPONENTS; ++i) {
|
|
+ tform.origin[i] = transform_slider[i + BASIS_COMPONENTS]->get_value();
|
|
+ }
|
|
+
|
|
+ return tform;
|
|
+ }
|
|
+
|
|
+ return Transform(
|
|
+ Basis(Vector3(Math::deg2rad(rotation_slider[0]->get_value()), Math::deg2rad(rotation_slider[1]->get_value()), Math::deg2rad(rotation_slider[2]->get_value())),
|
|
+ Vector3(scale_slider[0]->get_value(), scale_slider[1]->get_value(), scale_slider[2]->get_value())),
|
|
+ Vector3(translation_slider[0]->get_value(), translation_slider[1]->get_value(), translation_slider[2]->get_value()));
|
|
+}
|
|
+
|
|
+void BoneTransformEditor::update_enabled_checkbox() {
|
|
+ if (enabled_checkbox) {
|
|
+ const String path = "bones/" + property.get_slicec('/', 1) + "/enabled";
|
|
+ const bool is_enabled = skeleton->get(path);
|
|
+ enabled_checkbox->set_pressed(is_enabled);
|
|
+ }
|
|
+}
|
|
+
|
|
+void BoneTransformEditor::_bind_methods() {
|
|
+ ClassDB::bind_method(D_METHOD("_value_changed", "value"), &BoneTransformEditor::_value_changed);
|
|
+ ClassDB::bind_method(D_METHOD("_key_button_pressed"), &BoneTransformEditor::_key_button_pressed);
|
|
+ ClassDB::bind_method(D_METHOD("_checkbox_toggled", "toggled"), &BoneTransformEditor::_checkbox_toggled);
|
|
+}
|
|
+
|
|
+void BoneTransformEditor::_update_properties() {
|
|
+ if (updating)
|
|
+ return;
|
|
+
|
|
+ if (skeleton == nullptr)
|
|
+ return;
|
|
+
|
|
+ updating = true;
|
|
+
|
|
+ Transform tform = skeleton->get(property);
|
|
+ _update_transform_properties(tform);
|
|
+}
|
|
+
|
|
+void BoneTransformEditor::_update_custom_pose_properties() {
|
|
+ if (updating)
|
|
+ return;
|
|
+
|
|
+ if (skeleton == nullptr)
|
|
+ return;
|
|
+
|
|
+ updating = true;
|
|
+
|
|
+ Transform tform = skeleton->get_bone_custom_pose(property.to_int());
|
|
+ _update_transform_properties(tform);
|
|
+}
|
|
+
|
|
+void BoneTransformEditor::_update_transform_properties(Transform tform) {
|
|
+
|
|
+ Quat rot = tform.get_basis().orthonormalized();
|
|
+ Vector3 rot_rad = rot.get_euler();
|
|
+ Vector3 rot_degrees = Vector3(Math::rad2deg(rot_rad.x), Math::rad2deg(rot_rad.y), Math::rad2deg(rot_rad.z));
|
|
+ Vector3 tr = tform.get_origin();
|
|
+ Vector3 scale = tform.basis.get_scale();
|
|
+
|
|
+ for (int i = 0; i < TRANSLATION_COMPONENTS; i++) {
|
|
+ translation_slider[i]->set_value(tr[i]);
|
|
+ }
|
|
+
|
|
+ for (int i = 0; i < ROTATION_DEGREES_COMPONENTS; i++) {
|
|
+ rotation_slider[i]->set_value(rot_degrees[i]);
|
|
+ }
|
|
+
|
|
+ for (int i = 0; i < SCALE_COMPONENTS; i++) {
|
|
+ scale_slider[i]->set_value(scale[i]);
|
|
+ }
|
|
+
|
|
+ transform_slider[0]->set_value(tform.get_basis()[Vector3::AXIS_X].x);
|
|
+ transform_slider[1]->set_value(tform.get_basis()[Vector3::AXIS_X].y);
|
|
+ transform_slider[2]->set_value(tform.get_basis()[Vector3::AXIS_X].z);
|
|
+ transform_slider[3]->set_value(tform.get_basis()[Vector3::AXIS_Y].x);
|
|
+ transform_slider[4]->set_value(tform.get_basis()[Vector3::AXIS_Y].y);
|
|
+ transform_slider[5]->set_value(tform.get_basis()[Vector3::AXIS_Y].z);
|
|
+ transform_slider[6]->set_value(tform.get_basis()[Vector3::AXIS_Z].x);
|
|
+ transform_slider[7]->set_value(tform.get_basis()[Vector3::AXIS_Z].y);
|
|
+ transform_slider[8]->set_value(tform.get_basis()[Vector3::AXIS_Z].z);
|
|
+
|
|
+ for (int i = 0; i < TRANSLATION_COMPONENTS; i++) {
|
|
+ transform_slider[BASIS_COMPONENTS + i]->set_value(tform.get_origin()[i]);
|
|
+ }
|
|
+
|
|
+ update_enabled_checkbox();
|
|
+ updating = false;
|
|
+}
|
|
+
|
|
+BoneTransformEditor::BoneTransformEditor(Skeleton *p_skeleton) :
|
|
+ translation_slider(),
|
|
+ rotation_slider(),
|
|
+ scale_slider(),
|
|
+ transform_slider(),
|
|
+ skeleton(p_skeleton),
|
|
+ key_button(nullptr),
|
|
+ enabled_checkbox(nullptr),
|
|
+ keyable(false),
|
|
+ toggle_enabled(false),
|
|
+ updating(false) {
|
|
+
|
|
+ undo_redo = EditorNode::get_undo_redo();
|
|
+}
|
|
+
|
|
+void BoneTransformEditor::set_target(const String &p_prop) {
|
|
+ property = p_prop;
|
|
+}
|
|
+
|
|
+void BoneTransformEditor::set_keyable(const bool p_keyable) {
|
|
+ keyable = p_keyable;
|
|
+ if (key_button) {
|
|
+ key_button->set_visible(p_keyable);
|
|
+ }
|
|
+}
|
|
+
|
|
+void BoneTransformEditor::set_toggle_enabled(const bool p_enabled) {
|
|
+ toggle_enabled = p_enabled;
|
|
+ if (enabled_checkbox) {
|
|
+ enabled_checkbox->set_visible(p_enabled);
|
|
+ }
|
|
+}
|
|
+
|
|
+void BoneTransformEditor::_key_button_pressed() {
|
|
+ if (skeleton == nullptr)
|
|
+ return;
|
|
+
|
|
+ const BoneId bone_id = property.get_slicec('/', 1).to_int();
|
|
+ const String name = skeleton->get_bone_name(bone_id);
|
|
+
|
|
+ if (name.empty())
|
|
+ return;
|
|
+
|
|
+ // Need to normalize the basis before you key it
|
|
+ Transform tform = compute_transform(true);
|
|
+ tform.orthonormalize();
|
|
+ AnimationPlayerEditor::singleton->get_track_editor()->insert_transform_key(skeleton, name, tform);
|
|
+}
|
|
+
|
|
+void BoneTransformEditor::_checkbox_toggled(const bool p_toggled) {
|
|
+ if (enabled_checkbox) {
|
|
+ const String path = "bones/" + property.get_slicec('/', 1) + "/enabled";
|
|
+ skeleton->set(path, p_toggled);
|
|
+ }
|
|
+}
|
|
+
|
|
+void BoneTransformEditor::set_read_only(const bool p_read_only) {
|
|
+ for (int i = 0; i < TRANSLATION_COMPONENTS; i++) {
|
|
+ translation_slider[i]->set_read_only(p_read_only);
|
|
+ }
|
|
+ for (int i = 0; i < ROTATION_DEGREES_COMPONENTS; i++) {
|
|
+ rotation_slider[i]->set_read_only(p_read_only);
|
|
+ }
|
|
+ for (int i = 0; i < SCALE_COMPONENTS; i++) {
|
|
+ scale_slider[i]->set_read_only(p_read_only);
|
|
+ }
|
|
+ for (int i = 0; i < TRANSFORM_COMPONENTS; i++) {
|
|
+ transform_slider[i]->set_read_only(p_read_only);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+void SkeletonEditor::set_keyable(const bool p_keyable) {
|
|
+ keyable = p_keyable;
|
|
+ options->get_popup()->set_item_disabled(MENU_OPTION_INSERT_KEYS, !p_keyable);
|
|
+ options->get_popup()->set_item_disabled(MENU_OPTION_INSERT_KEYS_EXISTED, !p_keyable);
|
|
+};
|
|
+
|
|
void SkeletonEditor::_on_click_option(int p_option) {
|
|
if (!skeleton) {
|
|
return;
|
|
}
|
|
|
|
switch (p_option) {
|
|
+ case MENU_OPTION_INIT_POSE: {
|
|
+ init_pose();
|
|
+ } break;
|
|
+ case MENU_OPTION_INSERT_KEYS: {
|
|
+ insert_keys(true);
|
|
+ } break;
|
|
+ case MENU_OPTION_INSERT_KEYS_EXISTED: {
|
|
+ insert_keys(false);
|
|
+ } break;
|
|
+ case MENU_OPTION_POSE_TO_REST: {
|
|
+ pose_to_rest();
|
|
+ } break;
|
|
case MENU_OPTION_CREATE_PHYSICAL_SKELETON: {
|
|
create_physical_skeleton();
|
|
} break;
|
|
}
|
|
}
|
|
|
|
+void SkeletonEditor::init_pose() {
|
|
+ const int bone_len = skeleton->get_bone_count();
|
|
+ if (!bone_len) {
|
|
+ return;
|
|
+ }
|
|
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
|
|
+ ur->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS);
|
|
+ for (int i = 0; i < bone_len; i++) {
|
|
+ ur->add_do_method(skeleton, "set_bone_pose", i, Transform());
|
|
+ ur->add_undo_method(skeleton, "set_bone_pose", i, skeleton->get_bone_pose(i));
|
|
+ }
|
|
+ ur->commit_action();
|
|
+}
|
|
+
|
|
+void SkeletonEditor::insert_keys(bool p_all_bones) {
|
|
+ if (skeleton == nullptr)
|
|
+ return;
|
|
+
|
|
+ int bone_len = skeleton->get_bone_count();
|
|
+ Node *root = EditorNode::get_singleton()->get_tree()->get_root();
|
|
+ String path = root->get_path_to(skeleton);
|
|
+
|
|
+ for (int i = 0; i < bone_len; i++) {
|
|
+ const String name = skeleton->get_bone_name(i);
|
|
+
|
|
+ if (name.empty())
|
|
+ continue;
|
|
+
|
|
+ if (!p_all_bones && !AnimationPlayerEditor::singleton->get_track_editor()->has_transform_key(skeleton, name)) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ // Need to normalize the basis before you key it
|
|
+ Transform tform = skeleton->get_bone_pose(i);
|
|
+ tform.orthonormalize();
|
|
+ AnimationPlayerEditor::singleton->get_track_editor()->insert_transform_key(skeleton, name, tform);
|
|
+ }
|
|
+
|
|
+}
|
|
+
|
|
+void SkeletonEditor::pose_to_rest() {
|
|
+ const int bone_len = skeleton->get_bone_count();
|
|
+ if (!bone_len) {
|
|
+ return;
|
|
+ }
|
|
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
|
|
+ ur->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS);
|
|
+ for (int i = 0; i < bone_len; i++) {
|
|
+ ur->add_do_method(skeleton, "set_bone_pose", i, Transform());
|
|
+ ur->add_undo_method(skeleton, "set_bone_pose", i, skeleton->get_bone_pose(i));
|
|
+ ur->add_do_method(skeleton, "set_bone_custom_pose", i, Transform());
|
|
+ ur->add_undo_method(skeleton, "set_bone_custom_pose", i, skeleton->get_bone_custom_pose(i));
|
|
+ ur->add_do_method(skeleton, "set_bone_rest", i, skeleton->get_bone_rest(i) * skeleton->get_bone_custom_pose(i) * skeleton->get_bone_pose(i));
|
|
+ ur->add_undo_method(skeleton, "set_bone_rest", i, skeleton->get_bone_rest(i));
|
|
+ }
|
|
+ ur->commit_action();
|
|
+}
|
|
+
|
|
void SkeletonEditor::create_physical_skeleton() {
|
|
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
|
|
+ ERR_FAIL_COND(!get_tree());
|
|
Node *owner = skeleton == get_tree()->get_edited_scene_root() ? skeleton : skeleton->get_owner();
|
|
|
|
const int bc = skeleton->get_bone_count();
|
|
@@ -131,68 +627,1213 @@ PhysicalBone *SkeletonEditor::create_physical_bone(int bone_id, int bone_child_i
|
|
return physical_bone;
|
|
}
|
|
|
|
-void SkeletonEditor::edit(Skeleton *p_node) {
|
|
+Variant SkeletonEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
|
|
+ TreeItem *selected = joint_tree->get_selected();
|
|
+
|
|
+ if (!selected)
|
|
+ return Variant();
|
|
+
|
|
+ Ref<Texture> icon = selected->get_icon(0);
|
|
+
|
|
+ VBoxContainer *vb = memnew(VBoxContainer);
|
|
+ HBoxContainer *hb = memnew(HBoxContainer);
|
|
+ TextureRect *tf = memnew(TextureRect);
|
|
+ tf->set_texture(icon);
|
|
+ tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
|
|
+ hb->add_child(tf);
|
|
+ Label *label = memnew(Label(selected->get_text(0)));
|
|
+ hb->add_child(label);
|
|
+ vb->add_child(hb);
|
|
+ hb->set_modulate(Color(1, 1, 1, 1));
|
|
+
|
|
+ set_drag_preview(vb);
|
|
+ Dictionary drag_data;
|
|
+ drag_data["type"] = "nodes";
|
|
+ drag_data["node"] = selected;
|
|
+
|
|
+ return drag_data;
|
|
+}
|
|
+
|
|
+bool SkeletonEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
|
|
+
|
|
+ TreeItem *target = joint_tree->get_item_at_position(p_point);
|
|
+ if (!target)
|
|
+ return false;
|
|
+
|
|
+ const String path = target->get_metadata(0);
|
|
+ if (!path.begins_with("bones/"))
|
|
+ return false;
|
|
|
|
- skeleton = p_node;
|
|
+ TreeItem *selected = Object::cast_to<TreeItem>(Dictionary(p_data)["node"]);
|
|
+ if (target == selected)
|
|
+ return false;
|
|
+
|
|
+ const String path2 = target->get_metadata(0);
|
|
+ if (!path2.begins_with("bones/"))
|
|
+ return false;
|
|
+
|
|
+ return true;
|
|
}
|
|
|
|
-void SkeletonEditor::_notification(int p_what) {
|
|
- if (p_what == NOTIFICATION_ENTER_TREE) {
|
|
- get_tree()->connect("node_removed", this, "_node_removed");
|
|
+void SkeletonEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
|
|
+ if (!can_drop_data_fw(p_point, p_data, p_from))
|
|
+ return;
|
|
+
|
|
+ TreeItem *target = joint_tree->get_item_at_position(p_point);
|
|
+ TreeItem *selected = Object::cast_to<TreeItem>(Dictionary(p_data)["node"]);
|
|
+
|
|
+ const BoneId target_boneidx = String(target->get_metadata(0)).get_slicec('/', 1).to_int();
|
|
+ const BoneId selected_boneidx = String(selected->get_metadata(0)).get_slicec('/', 1).to_int();
|
|
+
|
|
+ move_skeleton_bone(skeleton->get_path(), selected_boneidx, target_boneidx);
|
|
+}
|
|
+
|
|
+void SkeletonEditor::move_skeleton_bone(NodePath p_skeleton_path, int32_t p_selected_boneidx, int32_t p_target_boneidx) {
|
|
+ Node *node = get_node_or_null(p_skeleton_path);
|
|
+ Skeleton *skeleton = Object::cast_to<Skeleton>(node);
|
|
+ ERR_FAIL_NULL(skeleton);
|
|
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
|
|
+ ur->create_action(TTR("Set Bone Parentage"));
|
|
+ // If the target is a child of ourselves, we move only *us* and not our children
|
|
+ if (skeleton->is_bone_parent_of(p_target_boneidx, p_selected_boneidx)) {
|
|
+ const BoneId parent_idx = skeleton->get_bone_parent(p_selected_boneidx);
|
|
+ const int bone_count = skeleton->get_bone_count();
|
|
+ for (BoneId i = 0; i < bone_count; ++i) {
|
|
+ if (skeleton->get_bone_parent(i) == p_selected_boneidx) {
|
|
+ ur->add_undo_method(skeleton, "set_bone_parent", i, skeleton->get_bone_parent(i));
|
|
+ ur->add_do_method(skeleton, "set_bone_parent", i, parent_idx);
|
|
+ skeleton->set_bone_parent(i, parent_idx);
|
|
+ }
|
|
+ }
|
|
}
|
|
+ ur->add_undo_method(skeleton, "set_bone_parent", p_selected_boneidx, skeleton->get_bone_parent(p_selected_boneidx));
|
|
+ ur->add_do_method(skeleton, "set_bone_parent", p_selected_boneidx, p_target_boneidx);
|
|
+ skeleton->set_bone_parent(p_selected_boneidx, p_target_boneidx);
|
|
+
|
|
+ update_joint_tree();
|
|
+ ur->commit_action();
|
|
}
|
|
|
|
-void SkeletonEditor::_node_removed(Node *p_node) {
|
|
+void SkeletonEditor::_update_spatial_transform_gizmo() {
|
|
+ SpatialEditor::get_singleton()->clear_externals();
|
|
+ if (skeleton->get_selected_bone() >= 0) {
|
|
+ SpatialEditor::get_singleton()->append_to_externals(skeleton->get_global_transform() * skeleton->get_bone_global_pose(skeleton->get_selected_bone()));
|
|
+ }
|
|
+ SpatialEditor::get_singleton()->update_transform_gizmo();
|
|
+};
|
|
|
|
- if (p_node == skeleton) {
|
|
- skeleton = NULL;
|
|
- options->hide();
|
|
+void SkeletonEditor::_joint_tree_selection_changed() {
|
|
+ TreeItem *selected = joint_tree->get_selected();
|
|
+ const String path = selected->get_metadata(0);
|
|
+
|
|
+ if (path.begins_with("bones/")) {
|
|
+ const int b_idx = path.get_slicec('/', 1).to_int();
|
|
+ const String bone_path = "bones/" + itos(b_idx) + "/";
|
|
+
|
|
+ pose_editor->set_target(bone_path + "pose");
|
|
+ rest_editor->set_target(bone_path + "rest");
|
|
+ custom_pose_editor->set_target(bone_path + "custom_pose");
|
|
+
|
|
+ pose_editor->set_visible(true);
|
|
+ rest_editor->set_visible(true);
|
|
+ custom_pose_editor->set_visible(true);
|
|
+
|
|
+ skeleton->set_selected_bone(b_idx);
|
|
}
|
|
+
|
|
+ _update_properties();
|
|
}
|
|
|
|
-void SkeletonEditor::_bind_methods() {
|
|
- ClassDB::bind_method("_on_click_option", &SkeletonEditor::_on_click_option);
|
|
- ClassDB::bind_method("_node_removed", &SkeletonEditor::_node_removed);
|
|
+void SkeletonEditor::_joint_tree_rmb_select(const Vector2 &p_pos) {
|
|
+ skeleton->set_selected_bone(-1);
|
|
+ _update_spatial_transform_gizmo();
|
|
+}
|
|
+
|
|
+void SkeletonEditor::_update_properties() {
|
|
+ if (rest_editor)
|
|
+ rest_editor->_update_properties();
|
|
+ if (pose_editor)
|
|
+ pose_editor->_update_properties();
|
|
+ if (custom_pose_editor)
|
|
+ custom_pose_editor->_update_custom_pose_properties();
|
|
+ _update_spatial_transform_gizmo();
|
|
+}
|
|
+
|
|
+void SkeletonEditor::update_joint_tree() {
|
|
+ joint_tree->clear();
|
|
+
|
|
+ if (skeleton == nullptr)
|
|
+ return;
|
|
+
|
|
+ TreeItem *root = joint_tree->create_item();
|
|
+
|
|
+ Map<int, TreeItem *> items;
|
|
+
|
|
+ items.insert(-1, root);
|
|
+
|
|
+ const Vector<int> &joint_porder = skeleton->get_bone_process_order();
|
|
+
|
|
+ Ref<Texture> bone_icon = get_icon("Bone", "EditorIcons");
|
|
+
|
|
+ for (int i = 0; i < joint_porder.size(); ++i) {
|
|
+ const int b_idx = joint_porder[i];
|
|
+
|
|
+ const int p_idx = skeleton->get_bone_parent(b_idx);
|
|
+ TreeItem *p_item = items.find(p_idx)->get();
|
|
+
|
|
+ TreeItem *joint_item = joint_tree->create_item(p_item);
|
|
+ items.insert(b_idx, joint_item);
|
|
+
|
|
+ joint_item->set_text(0, skeleton->get_bone_name(b_idx));
|
|
+ joint_item->set_icon(0, bone_icon);
|
|
+ joint_item->set_selectable(0, true);
|
|
+ joint_item->set_metadata(0, "bones/" + itos(b_idx));
|
|
+ }
|
|
}
|
|
|
|
-SkeletonEditor::SkeletonEditor() {
|
|
- skeleton = NULL;
|
|
+void SkeletonEditor::update_editors() {
|
|
+}
|
|
+
|
|
+void SkeletonEditor::create_editors() {
|
|
+
|
|
+ set_h_size_flags(SIZE_EXPAND_FILL);
|
|
+ add_constant_override("separation", 0);
|
|
+
|
|
+ set_focus_mode(FOCUS_ALL);
|
|
+
|
|
+ // Create Top Menu Bar
|
|
+ separators[0] = memnew(VSeparator);
|
|
+ separators[1] = memnew(VSeparator);
|
|
+
|
|
+ SpatialEditor::get_singleton()->add_control_to_menu_panel(separators[0]);
|
|
+
|
|
options = memnew(MenuButton);
|
|
SpatialEditor::get_singleton()->add_control_to_menu_panel(options);
|
|
-
|
|
options->set_text(TTR("Skeleton"));
|
|
options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Skeleton", "EditorIcons"));
|
|
-
|
|
+ options->get_popup()->add_item(TTR("Init pose"), MENU_OPTION_INIT_POSE);
|
|
+ options->get_popup()->add_item(TTR("Insert key of all bone poses"), MENU_OPTION_INSERT_KEYS);
|
|
+ options->get_popup()->add_item(TTR("Insert key of bone poses already exist track"), MENU_OPTION_INSERT_KEYS_EXISTED);
|
|
+ options->get_popup()->add_item(TTR("Apply current pose to rest"), MENU_OPTION_POSE_TO_REST);
|
|
options->get_popup()->add_item(TTR("Create physical skeleton"), MENU_OPTION_CREATE_PHYSICAL_SKELETON);
|
|
-
|
|
options->get_popup()->connect("id_pressed", this, "_on_click_option");
|
|
- options->hide();
|
|
+
|
|
+ Vector<Variant> button_binds;
|
|
+ button_binds.resize(1);
|
|
+
|
|
+ tool_button[TOOL_MODE_BONE_SELECT] = memnew(ToolButton);
|
|
+ SpatialEditor::get_singleton()->add_control_to_menu_panel(tool_button[TOOL_MODE_BONE_SELECT]);
|
|
+ tool_button[TOOL_MODE_BONE_SELECT]->set_tooltip(TTR("Transform Bone Mode"));
|
|
+ tool_button[TOOL_MODE_BONE_SELECT]->set_toggle_mode(true);
|
|
+ tool_button[TOOL_MODE_BONE_SELECT]->set_flat(true);
|
|
+ button_binds.write[0] = MENU_TOOL_BONE_SELECT;
|
|
+ tool_button[TOOL_MODE_BONE_SELECT]->connect("pressed", this, "_menu_tool_item_pressed", button_binds);
|
|
+
|
|
+ tool_button[TOOL_MODE_BONE_MOVE] = memnew(ToolButton);
|
|
+ SpatialEditor::get_singleton()->add_control_to_menu_panel(tool_button[TOOL_MODE_BONE_MOVE]);
|
|
+ tool_button[TOOL_MODE_BONE_MOVE]->set_tooltip(TTR("Move Bone Mode"));
|
|
+ tool_button[TOOL_MODE_BONE_MOVE]->set_toggle_mode(true);
|
|
+ tool_button[TOOL_MODE_BONE_MOVE]->set_flat(true);
|
|
+ button_binds.write[0] = MENU_TOOL_BONE_MOVE;
|
|
+ tool_button[TOOL_MODE_BONE_MOVE]->connect("pressed", this, "_menu_tool_item_pressed", button_binds);
|
|
+
|
|
+ tool_button[TOOL_MODE_BONE_ROTATE] = memnew(ToolButton);
|
|
+ SpatialEditor::get_singleton()->add_control_to_menu_panel(tool_button[TOOL_MODE_BONE_ROTATE]);
|
|
+ tool_button[TOOL_MODE_BONE_ROTATE]->set_tooltip(TTR("Rotate Bone Mode"));
|
|
+ tool_button[TOOL_MODE_BONE_ROTATE]->set_toggle_mode(true);
|
|
+ tool_button[TOOL_MODE_BONE_ROTATE]->set_flat(true);
|
|
+ button_binds.write[0] = MENU_TOOL_BONE_ROTATE;
|
|
+ tool_button[TOOL_MODE_BONE_ROTATE]->connect("pressed", this, "_menu_tool_item_pressed", button_binds);
|
|
+
|
|
+ tool_button[TOOL_MODE_BONE_SCALE] = memnew(ToolButton);
|
|
+ SpatialEditor::get_singleton()->add_control_to_menu_panel(tool_button[TOOL_MODE_BONE_SCALE]);
|
|
+ tool_button[TOOL_MODE_BONE_SCALE]->set_tooltip(TTR("Scale Bone Mode"));
|
|
+ tool_button[TOOL_MODE_BONE_SCALE]->set_toggle_mode(true);
|
|
+ tool_button[TOOL_MODE_BONE_SCALE]->set_flat(true);
|
|
+ button_binds.write[0] = MENU_TOOL_BONE_SCALE;
|
|
+ tool_button[TOOL_MODE_BONE_SCALE]->connect("pressed", this, "_menu_tool_item_pressed", button_binds);
|
|
+
|
|
+ tool_button[TOOL_MODE_BONE_NONE] = memnew(ToolButton);
|
|
+ button_binds.write[0] = MENU_TOOL_BONE_NONE;
|
|
+ tool_button[TOOL_MODE_BONE_NONE]->connect("pressed", this, "_menu_tool_item_pressed", button_binds);
|
|
+ SpatialEditor::get_singleton()->connect("change_tool_mode", this, "_menu_tool_item_pressed", button_binds);
|
|
+
|
|
+ tool_mode = TOOL_MODE_BONE_NONE;
|
|
+
|
|
+ SpatialEditor::get_singleton()->add_control_to_menu_panel(separators[1]);
|
|
+
|
|
+ rest_mode_button = memnew(ToolButton);
|
|
+ SpatialEditor::get_singleton()->add_control_to_menu_panel(rest_mode_button);
|
|
+ rest_mode_button->set_tooltip(TTR("Rest Mode\nNote: Bone poses are disabled during Rest Mode."));
|
|
+ rest_mode_button->set_toggle_mode(true);
|
|
+ rest_mode_button->set_flat(true);
|
|
+ rest_mode_button->connect("toggled", this, "rest_mode_toggled");
|
|
+
|
|
+ rest_mode = false;
|
|
+
|
|
+ set_keyable(AnimationPlayerEditor::singleton->get_track_editor()->has_keying());
|
|
+
|
|
+ if (skeleton) {
|
|
+ skeleton->add_child(pointsm);
|
|
+ pointsm->set_skeleton_path(NodePath(""));
|
|
+ skeleton->connect("pose_updated", this, "_draw_handles");
|
|
+ }
|
|
+
|
|
+ const Color section_color = get_color("prop_subsection", "Editor");
|
|
+
|
|
+ EditorInspectorSection *bones_section = memnew(EditorInspectorSection);
|
|
+ bones_section->setup("bones", "Bones", skeleton, section_color, true);
|
|
+ add_child(bones_section);
|
|
+ bones_section->unfold();
|
|
+
|
|
+ ScrollContainer *s_con = memnew(ScrollContainer);
|
|
+ s_con->set_h_size_flags(SIZE_EXPAND_FILL);
|
|
+ s_con->set_custom_minimum_size(Size2(1, 350) * EDSCALE);
|
|
+ bones_section->get_vbox()->add_child(s_con);
|
|
+
|
|
+ joint_tree = memnew(Tree);
|
|
+ joint_tree->set_columns(1);
|
|
+ joint_tree->set_focus_mode(Control::FocusMode::FOCUS_NONE);
|
|
+ joint_tree->set_select_mode(Tree::SELECT_SINGLE);
|
|
+ joint_tree->set_hide_root(true);
|
|
+ joint_tree->set_v_size_flags(SIZE_EXPAND_FILL);
|
|
+ joint_tree->set_h_size_flags(SIZE_EXPAND_FILL);
|
|
+ joint_tree->set_allow_rmb_select(true);
|
|
+ joint_tree->set_drag_forwarding(this);
|
|
+ s_con->add_child(joint_tree);
|
|
+
|
|
+ pose_editor = memnew(BoneTransformEditor(skeleton));
|
|
+ pose_editor->set_label(TTR("Bone Pose"));
|
|
+ pose_editor->set_keyable(AnimationPlayerEditor::singleton->get_track_editor()->has_keying());
|
|
+ // pose_editor->set_toggle_enabled(true);
|
|
+ pose_editor->set_visible(false);
|
|
+ add_child(pose_editor);
|
|
+
|
|
+ rest_editor = memnew(BoneTransformEditor(skeleton));
|
|
+ rest_editor->set_label(TTR("Bone Rest"));
|
|
+ rest_editor->set_visible(false);
|
|
+ add_child(rest_editor);
|
|
+
|
|
+ custom_pose_editor = memnew(BoneTransformEditor(skeleton));
|
|
+ custom_pose_editor->set_label(TTR("Bone Custom Pose"));
|
|
+ custom_pose_editor->set_visible(false);
|
|
+ add_child(custom_pose_editor);
|
|
+
|
|
+ skeleton->set_selected_bone(-1);
|
|
}
|
|
|
|
-SkeletonEditor::~SkeletonEditor() {}
|
|
+void SkeletonEditor::_notification(int p_what) {
|
|
+
|
|
+ switch (p_what) {
|
|
+ case NOTIFICATION_READY: {
|
|
+ tool_button[TOOL_MODE_BONE_SELECT]->set_icon(get_icon("ToolBoneSelect", "EditorIcons"));
|
|
+ tool_button[TOOL_MODE_BONE_MOVE]->set_icon(get_icon("ToolBoneMove", "EditorIcons"));
|
|
+ tool_button[TOOL_MODE_BONE_ROTATE]->set_icon(get_icon("ToolBoneRotate", "EditorIcons"));
|
|
+ tool_button[TOOL_MODE_BONE_SCALE]->set_icon(get_icon("ToolBoneScale", "EditorIcons"));
|
|
+ rest_mode_button->set_icon(get_icon("ToolBoneRest", "EditorIcons"));
|
|
+ } break;
|
|
+ case NOTIFICATION_ENTER_TREE: {
|
|
+ create_editors();
|
|
+ update_joint_tree();
|
|
+ update_editors();
|
|
+
|
|
+ get_tree()->connect("node_removed", this, "_node_removed", Vector<Variant>(), Object::CONNECT_ONESHOT);
|
|
+ joint_tree->connect("item_selected", this, "_joint_tree_selection_changed");
|
|
+ joint_tree->connect("item_rmb_selected", this, "_joint_tree_rmb_select");
|
|
+
|
|
+#ifdef TOOLS_ENABLED
|
|
+ skeleton->connect("pose_updated", this, "_update_properties");
|
|
+#endif // TOOLS_ENABLED
|
|
|
|
-void SkeletonEditorPlugin::edit(Object *p_object) {
|
|
- skeleton_editor->edit(Object::cast_to<Skeleton>(p_object));
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
-bool SkeletonEditorPlugin::handles(Object *p_object) const {
|
|
- return p_object->is_class("Skeleton");
|
|
+void SkeletonEditor::_node_removed(Node *p_node) {
|
|
+ if (skeleton && p_node == skeleton) {
|
|
+ skeleton = nullptr;
|
|
+ }
|
|
+}
|
|
+
|
|
+void SkeletonEditor::_bind_methods() {
|
|
+ ClassDB::bind_method(D_METHOD("_node_removed"), &SkeletonEditor::_node_removed);
|
|
+ ClassDB::bind_method(D_METHOD("_joint_tree_selection_changed"), &SkeletonEditor::_joint_tree_selection_changed);
|
|
+ ClassDB::bind_method(D_METHOD("_joint_tree_rmb_select"), &SkeletonEditor::_joint_tree_rmb_select);
|
|
+ ClassDB::bind_method(D_METHOD("_update_properties"), &SkeletonEditor::_update_properties);
|
|
+ ClassDB::bind_method(D_METHOD("_on_click_option"), &SkeletonEditor::_on_click_option);
|
|
+ ClassDB::bind_method(D_METHOD("_menu_tool_item_pressed"), &SkeletonEditor::_menu_tool_item_pressed);
|
|
+ ClassDB::bind_method(D_METHOD("rest_mode_toggled"), &SkeletonEditor::rest_mode_toggled);
|
|
+ ClassDB::bind_method(D_METHOD("set_rest_mode_toggled"), &SkeletonEditor::set_rest_mode_toggled);
|
|
+
|
|
+ ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &SkeletonEditor::get_drag_data_fw);
|
|
+ ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &SkeletonEditor::can_drop_data_fw);
|
|
+ ClassDB::bind_method(D_METHOD("drop_data_fw"), &SkeletonEditor::drop_data_fw);
|
|
+ ClassDB::bind_method(D_METHOD("move_skeleton_bone"), &SkeletonEditor::move_skeleton_bone);
|
|
+
|
|
+ ClassDB::bind_method(D_METHOD("_draw_handles"), &SkeletonEditor::_draw_handles);
|
|
+}
|
|
+
|
|
+void SkeletonEditor::_menu_tool_item_pressed(int p_option) {
|
|
+
|
|
+ if (p_option != TOOL_MODE_BONE_NONE && !SpatialEditor::get_singleton()->is_tool_external()) {
|
|
+ SpatialEditor::get_singleton()->set_tool_mode(SpatialEditor::TOOL_MODE_EXTERNAL);
|
|
+ }
|
|
+ for (int i = 0; i < TOOL_MODE_BONE_MAX; i++)
|
|
+ tool_button[i]->set_pressed(i == p_option);
|
|
+ tool_mode = (ToolMode)p_option;
|
|
+ if (skeleton) {
|
|
+ if (p_option == TOOL_MODE_BONE_NONE) {
|
|
+ _hide_handles();
|
|
+ } else {
|
|
+ _draw_handles();
|
|
+ if (skeleton->get_selected_bone() >= 0) {
|
|
+ SpatialEditor::get_singleton()->clear_externals();
|
|
+ SpatialEditor::get_singleton()->append_to_externals(skeleton->get_global_transform() * skeleton->get_bone_global_pose(skeleton->get_selected_bone()));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ switch (p_option) {
|
|
+ case TOOL_MODE_BONE_SELECT: {
|
|
+ SpatialEditor::get_singleton()->set_external_tool_mode(SpatialEditor::EX_TOOL_MODE_SELECT);
|
|
+ } break;
|
|
+ case TOOL_MODE_BONE_MOVE: {
|
|
+ SpatialEditor::get_singleton()->set_external_tool_mode(SpatialEditor::EX_TOOL_MODE_MOVE);
|
|
+ } break;
|
|
+ case TOOL_MODE_BONE_ROTATE: {
|
|
+ SpatialEditor::get_singleton()->set_external_tool_mode(SpatialEditor::EX_TOOL_MODE_ROTATE);
|
|
+ } break;
|
|
+ case TOOL_MODE_BONE_SCALE: {
|
|
+ SpatialEditor::get_singleton()->set_external_tool_mode(SpatialEditor::EX_TOOL_MODE_SCALE);
|
|
+ } break;
|
|
+ case TOOL_MODE_BONE_NONE:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ _update_spatial_transform_gizmo();
|
|
+}
|
|
+
|
|
+void SkeletonEditor::rest_mode_toggled(const bool pressed) {
|
|
+ bool before_val = rest_mode;
|
|
+
|
|
+ // Prevent that bone pose will be undo during rest mode.
|
|
+ // However SkeletonEditor will be memdeleted,
|
|
+ // so it need to record in SpatialEditor with calling method in
|
|
+ // EditorInspectorPluginSkeleton and it will not be memdeleted.
|
|
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
|
|
+ ur->create_action(TTR("Toggled Rest Mode"));
|
|
+ set_rest_mode_toggled(pressed);
|
|
+ ur->add_undo_method(editor_plugin, "set_rest_mode_toggled", before_val);
|
|
+ ur->add_do_method(editor_plugin, "set_rest_mode_toggled", pressed);
|
|
+ ur->commit_action();
|
|
+}
|
|
+
|
|
+void SkeletonEditor::set_rest_mode_toggled(const bool pressed) {
|
|
+ rest_mode_button->disconnect("toggled", this, "rest_mode_toggled");
|
|
+ rest_mode_button->set_pressed(pressed);
|
|
+ rest_mode_button->connect("toggled", this, "rest_mode_toggled");
|
|
+
|
|
+ rest_mode = pressed;
|
|
+ const int bone_len = skeleton->get_bone_count();
|
|
+ for (int i = 0; i < bone_len; i++) {
|
|
+ skeleton->set_bone_enabled(i, !rest_mode);
|
|
+ }
|
|
+ if (pose_editor) {
|
|
+ pose_editor->set_read_only(rest_mode);
|
|
+ }
|
|
+ if (custom_pose_editor) {
|
|
+ custom_pose_editor->set_read_only(rest_mode);
|
|
+ }
|
|
+ set_keyable(AnimationPlayerEditor::singleton->get_track_editor()->has_keying() && !rest_mode);
|
|
+}
|
|
+
|
|
+SkeletonEditor::SkeletonEditor(EditorInspectorPluginSkeleton *e_plugin, EditorNode *p_editor, Skeleton *p_skeleton) :
|
|
+ editor(p_editor),
|
|
+ editor_plugin(e_plugin),
|
|
+ skeleton(p_skeleton) {
|
|
+ handle_material = Ref<ShaderMaterial>(memnew(ShaderMaterial));
|
|
+ handle_shader = Ref<Shader>(memnew(Shader));
|
|
+ handle_shader->set_code(" \
|
|
+ shader_type spatial; \
|
|
+ render_mode unshaded; \
|
|
+ uniform vec4 albedo : hint_color = vec4(1,1,1,1); \
|
|
+ uniform sampler2D texture_albedo : hint_albedo; \
|
|
+ uniform float point_size : hint_range(0,128) = 32; \
|
|
+ void vertex() { \
|
|
+ if (!OUTPUT_IS_SRGB) { \
|
|
+ COLOR.rgb = mix( pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb* (1.0 / 12.92), lessThan(COLOR.rgb,vec3(0.04045)) ); \
|
|
+ } \
|
|
+ POINT_SIZE=point_size; \
|
|
+ VERTEX = VERTEX; \
|
|
+ POSITION=PROJECTION_MATRIX*INV_CAMERA_MATRIX*WORLD_MATRIX*vec4(VERTEX.xyz,1.0); \
|
|
+ POSITION.z = mix(POSITION.z, -POSITION.w, 0.999); \
|
|
+ } \
|
|
+ void fragment() { \
|
|
+ vec4 albedo_tex = texture(texture_albedo,POINT_COORD); \
|
|
+ if (albedo.a * albedo_tex.a < 0.5) { discard; } \
|
|
+ vec3 col = albedo_tex.rgb + COLOR.rgb; \
|
|
+ col = vec3(min(col.r,1.0),min(col.g,1.0),min(col.b,1.0)); \
|
|
+ ALBEDO = albedo.rgb * col; \
|
|
+ } \
|
|
+ ");
|
|
+ handle_material->set_shader(handle_shader);
|
|
+ // handle_material->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, true);
|
|
+ handle_material->set_render_priority(SpatialMaterial::RENDER_PRIORITY_MIN);
|
|
+ // handle_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true);
|
|
+ // handle_material->set_flag(SpatialMaterial::FLAG_USE_POINT_SIZE, true);
|
|
+ // handle_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
|
|
+ Ref<Texture> handle = editor->get_gui_base()->get_icon("EditorBoneHandle", "EditorIcons");
|
|
+ handle_material->set_shader_param("point_size", handle->get_width());
|
|
+ handle_material->set_shader_param("texture_albedo", handle);
|
|
+ //handle_material->set_texture(SpatialMaterial::TEXTURE_ALBEDO, handle);
|
|
+
|
|
+ pointsm = memnew(MeshInstance);
|
|
+ am.instance();
|
|
+ pointsm->set_mesh(am);
|
|
+ pointsm->set_transform(Transform(Basis(), Vector3(0, 0, 0.00001)));
|
|
+}
|
|
+
|
|
+SkeletonEditor::~SkeletonEditor() {
|
|
+ set_rest_mode_toggled(false);
|
|
+ SpatialEditor::get_singleton()->disconnect("change_tool_mode", this, "_menu_tool_item_pressed");
|
|
+ if (skeleton) {
|
|
+ pointsm->get_parent()->remove_child(pointsm);
|
|
+ skeleton->set_selected_bone(-1);
|
|
+ skeleton->disconnect("pose_updated", this, "_draw_handles");
|
|
+ memdelete(pointsm);
|
|
+ }
|
|
+ for (int i = 0; i < 2; i++) {
|
|
+ if (separators[i]) {
|
|
+ SpatialEditor::get_singleton()->remove_control_from_menu_panel(separators[i]);
|
|
+ memdelete(separators[i]);
|
|
+ }
|
|
+ }
|
|
+ if (options) {
|
|
+ SpatialEditor::get_singleton()->remove_control_from_menu_panel(options);
|
|
+ memdelete(options);
|
|
+ }
|
|
+ SpatialEditor::get_singleton()->remove_control_from_menu_panel(tool_button[TOOL_MODE_BONE_SELECT]);
|
|
+ SpatialEditor::get_singleton()->remove_control_from_menu_panel(tool_button[TOOL_MODE_BONE_MOVE]);
|
|
+ SpatialEditor::get_singleton()->remove_control_from_menu_panel(tool_button[TOOL_MODE_BONE_ROTATE]);
|
|
+ SpatialEditor::get_singleton()->remove_control_from_menu_panel(tool_button[TOOL_MODE_BONE_SCALE]);
|
|
+ for (int i = 0; i < TOOL_MODE_BONE_MAX; i++) {
|
|
+ if (tool_button[i]) {
|
|
+ memdelete(tool_button[i]);
|
|
+ }
|
|
+ }
|
|
+ SpatialEditor::get_singleton()->remove_control_from_menu_panel(rest_mode_button);
|
|
+ if (rest_mode_button) {
|
|
+ memdelete(rest_mode_button);
|
|
+ }
|
|
+ if (SpatialEditor::get_singleton()->is_tool_external()) {
|
|
+ SpatialEditor::get_singleton()->set_tool_mode(SpatialEditor::TOOL_MODE_SELECT);
|
|
+ SpatialEditor::get_singleton()->set_external_tool_mode(SpatialEditor::EX_TOOL_MODE_SELECT);
|
|
+ }
|
|
+
|
|
+}
|
|
+
|
|
+void SkeletonEditor::_hide_handles() {
|
|
+ if (!skeleton)
|
|
+ return;
|
|
+
|
|
+ pointsm->hide();
|
|
+}
|
|
+
|
|
+void SkeletonEditor::_draw_handles() {
|
|
+
|
|
+ if (!skeleton || tool_mode == TOOL_MODE_BONE_NONE)
|
|
+ return;
|
|
+
|
|
+ while (am->get_surface_count()) {
|
|
+ am->surface_remove(0);
|
|
+ }
|
|
+
|
|
+ pointsm->show();
|
|
+
|
|
+ Array a;
|
|
+ a.resize(Mesh::ARRAY_MAX);
|
|
+ PoolVector<Vector3> va;
|
|
+ PoolVector<Color> ca;
|
|
+ {
|
|
+ const int bone_len = skeleton->get_bone_count();
|
|
+ va.resize(bone_len);
|
|
+ ca.resize(bone_len);
|
|
+ PoolVector<Vector3>::Write vaw = va.write();
|
|
+ PoolVector<Color>::Write caw = ca.write();
|
|
+
|
|
+ for (int i = 0; i < bone_len; i++) {
|
|
+ Vector3 point = skeleton->get_bone_global_pose(i).origin;
|
|
+ vaw[i] = point;
|
|
+ Color c;
|
|
+ if (i == skeleton->get_selected_bone()) {
|
|
+ c = Color(1,1,0);
|
|
+ } else {
|
|
+ c = Color(0,0,1);
|
|
+ }
|
|
+ caw[i] = c;
|
|
+ }
|
|
+
|
|
+ }
|
|
+ a[Mesh::ARRAY_VERTEX] = va;
|
|
+ a[Mesh::ARRAY_COLOR] = ca;
|
|
+ am->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS, a);
|
|
+ am->surface_set_material(0, handle_material);
|
|
+}
|
|
+
|
|
+bool SkeletonEditor::forward_spatial_gui_input(int p_index, Camera *p_camera, const Ref<InputEvent> &p_event) {
|
|
+
|
|
+ if (!skeleton || tool_mode == TOOL_MODE_BONE_NONE)
|
|
+ return false;
|
|
+
|
|
+ SpatialEditor *se = SpatialEditor::get_singleton();
|
|
+ SpatialEditorViewport *sev = se->get_editor_viewport(p_index);
|
|
+
|
|
+ Ref<InputEventMouseButton> mb = p_event;
|
|
+ if (mb.is_valid()) {
|
|
+
|
|
+ Transform gt = skeleton->get_global_transform();
|
|
+ Vector3 ray_from = p_camera->get_global_transform().origin;
|
|
+ Vector2 gpoint = mb->get_position();
|
|
+ real_t grab_threshold = 4 * EDSCALE;
|
|
+
|
|
+ switch (mb->get_button_index()) {
|
|
+ case BUTTON_LEFT: {
|
|
+ if (mb->is_pressed()) {
|
|
+
|
|
+ _edit.mouse_pos = mb->get_position();
|
|
+ _edit.snap = se->is_snap_enabled();
|
|
+ _edit.mode = SpatialEditorViewport::TRANSFORM_NONE;
|
|
+
|
|
+ // check gizmo
|
|
+ if (_gizmo_select(p_index, _edit.mouse_pos)) {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ // select bone
|
|
+ int closest_idx = -1;
|
|
+ real_t closest_dist = 1e10;
|
|
+ const int bone_len = skeleton->get_bone_count();
|
|
+ for (int i = 0; i < bone_len; i++) {
|
|
+
|
|
+ Vector3 joint_pos_3d = gt.xform(skeleton->get_bone_global_pose(i).origin);
|
|
+ Vector2 joint_pos_2d = p_camera->unproject_position(joint_pos_3d);
|
|
+ real_t dist_3d = ray_from.distance_to(joint_pos_3d);
|
|
+ real_t dist_2d = gpoint.distance_to(joint_pos_2d);
|
|
+ if (dist_2d < grab_threshold && dist_3d < closest_dist) {
|
|
+ closest_dist = dist_3d;
|
|
+ closest_idx = i;
|
|
+ }
|
|
+ }
|
|
+ if (closest_idx >= 0) {
|
|
+ TreeItem *ti = _find(joint_tree->get_root(), "bones/" + itos(closest_idx));
|
|
+ if (ti) {
|
|
+ // make visible when it's collapsed
|
|
+ TreeItem *node = ti->get_parent();
|
|
+ while (node && node != joint_tree->get_root()) {
|
|
+ node->set_collapsed(false);
|
|
+ node = node->get_parent();
|
|
+ }
|
|
+ ti->select(0);
|
|
+ joint_tree->scroll_to_item(ti);
|
|
+ }
|
|
+ } else {
|
|
+ skeleton->set_selected_bone(-1);
|
|
+ joint_tree->deselect_all();
|
|
+ }
|
|
+
|
|
+ } else {
|
|
+ if (_edit.mode != SpatialEditorViewport::TRANSFORM_NONE) {
|
|
+ if (skeleton && (skeleton->get_selected_bone() >= 0)) {
|
|
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
|
|
+ ur->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS);
|
|
+ if (rest_mode) {
|
|
+ ur->add_do_method(skeleton, "set_bone_rest", skeleton->get_selected_bone(), skeleton->get_bone_rest(skeleton->get_selected_bone()));
|
|
+ ur->add_undo_method(skeleton, "set_bone_rest", skeleton->get_selected_bone(), original_local);
|
|
+ } else {
|
|
+ ur->add_do_method(skeleton, "set_bone_pose", skeleton->get_selected_bone(), skeleton->get_bone_pose(skeleton->get_selected_bone()));
|
|
+ ur->add_undo_method(skeleton, "set_bone_pose", skeleton->get_selected_bone(), original_local);
|
|
+ }
|
|
+ ur->commit_action();
|
|
+ _edit.mode = SpatialEditorViewport::TRANSFORM_NONE;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return true;
|
|
+ } break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ }
|
|
+
|
|
+ Ref<InputEventMouseMotion> mm = p_event;
|
|
+ if (mm.is_valid()) {
|
|
+ _edit.mouse_pos = mm->get_position();
|
|
+ if (!(mm->get_button_mask() & 1)) {
|
|
+ _gizmo_select(p_index, _edit.mouse_pos, true);
|
|
+ }
|
|
+ if (mm->get_button_mask() & BUTTON_MASK_LEFT) {
|
|
+ if (_edit.mode == SpatialEditorViewport::TRANSFORM_NONE)
|
|
+ return true;
|
|
+
|
|
+ Vector3 ray_pos = sev->get_ray_pos(mm->get_position());
|
|
+ Vector3 ray = sev->get_ray(mm->get_position());
|
|
+ float snap = EDITOR_GET("interface/inspector/default_float_step");
|
|
+
|
|
+ switch (_edit.mode) {
|
|
+
|
|
+ case SpatialEditorViewport::TRANSFORM_SCALE: {
|
|
+
|
|
+ Vector3 motion_mask;
|
|
+ Plane plane;
|
|
+ bool plane_mv = false;
|
|
+
|
|
+ switch (_edit.plane) {
|
|
+ case SpatialEditorViewport::TRANSFORM_VIEW:
|
|
+ motion_mask = Vector3(0, 0, 0);
|
|
+ plane = Plane(_edit.center, sev->get_camera_normal());
|
|
+ break;
|
|
+ case SpatialEditorViewport::TRANSFORM_X_AXIS:
|
|
+ motion_mask = se->get_gizmo_transform().basis.get_axis(0);
|
|
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(sev->get_camera_normal())).normalized());
|
|
+ break;
|
|
+ case SpatialEditorViewport::TRANSFORM_Y_AXIS:
|
|
+ motion_mask = se->get_gizmo_transform().basis.get_axis(1);
|
|
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(sev->get_camera_normal())).normalized());
|
|
+ break;
|
|
+ case SpatialEditorViewport::TRANSFORM_Z_AXIS:
|
|
+ motion_mask = se->get_gizmo_transform().basis.get_axis(2);
|
|
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(sev->get_camera_normal())).normalized());
|
|
+ break;
|
|
+ case SpatialEditorViewport::TRANSFORM_YZ:
|
|
+ motion_mask = se->get_gizmo_transform().basis.get_axis(2) + se->get_gizmo_transform().basis.get_axis(1);
|
|
+ plane = Plane(_edit.center, se->get_gizmo_transform().basis.get_axis(0));
|
|
+ plane_mv = true;
|
|
+ break;
|
|
+ case SpatialEditorViewport::TRANSFORM_XZ:
|
|
+ motion_mask = se->get_gizmo_transform().basis.get_axis(2) + se->get_gizmo_transform().basis.get_axis(0);
|
|
+ plane = Plane(_edit.center, se->get_gizmo_transform().basis.get_axis(1));
|
|
+ plane_mv = true;
|
|
+ break;
|
|
+ case SpatialEditorViewport::TRANSFORM_XY:
|
|
+ motion_mask = se->get_gizmo_transform().basis.get_axis(0) + se->get_gizmo_transform().basis.get_axis(1);
|
|
+ plane = Plane(_edit.center, se->get_gizmo_transform().basis.get_axis(2));
|
|
+ plane_mv = true;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ Vector3 intersection;
|
|
+ if (!plane.intersects_ray(ray_pos, ray, &intersection))
|
|
+ break;
|
|
+
|
|
+ Vector3 click;
|
|
+ if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click))
|
|
+ break;
|
|
+
|
|
+ Vector3 motion = intersection - click;
|
|
+ if (_edit.plane != SpatialEditorViewport::TRANSFORM_VIEW) {
|
|
+ motion = motion_mask.dot(motion) * motion_mask;
|
|
+ } else {
|
|
+ float center_click_dist = click.distance_to(_edit.center);
|
|
+ float center_inters_dist = intersection.distance_to(_edit.center);
|
|
+ if (center_click_dist == 0)
|
|
+ break;
|
|
+
|
|
+ float scale = center_inters_dist - center_click_dist;
|
|
+ motion = Vector3(scale, scale, scale);
|
|
+ }
|
|
+
|
|
+ bool local_coords = (se->are_local_coords_enabled() && _edit.plane != SpatialEditorViewport::TRANSFORM_VIEW);
|
|
+
|
|
+ if (_edit.snap || se->is_snap_enabled()) {
|
|
+ snap = se->get_scale_snap() / 100;
|
|
+ }
|
|
+
|
|
+ Transform t;
|
|
+
|
|
+ if (local_coords) {
|
|
+ Basis g = original_global.basis;
|
|
+ motion = g.inverse().xform(motion);
|
|
+ if (_edit.snap || se->is_snap_enabled()) {
|
|
+ motion.snap(Vector3(snap, snap, snap));
|
|
+ }
|
|
+ Vector3 local_scale = original_local.basis.get_scale() * (motion + Vector3(1, 1, 1));
|
|
+ // Prevent scaling to 0 it would break the gizmo
|
|
+ Basis check = original_local.basis;
|
|
+ check.scale(local_scale);
|
|
+ if (check.determinant() != 0) {
|
|
+ t = original_local;
|
|
+ t.basis = t.basis.scaled_local(motion + Vector3(1, 1, 1));
|
|
+ }
|
|
+ } else {
|
|
+ if (_edit.snap || se->is_snap_enabled()) {
|
|
+ motion.snap(Vector3(snap, snap, snap));
|
|
+ }
|
|
+ t = original_local;
|
|
+ Transform r;
|
|
+ r.basis.scale(motion + Vector3(1, 1, 1));
|
|
+ Basis base = original_to_local.get_basis().orthonormalized().inverse();
|
|
+ t.basis = base * (r.get_basis() * (base.inverse() * original_local.get_basis()));
|
|
+ }
|
|
+
|
|
+ // Apply scale
|
|
+ if (rest_mode) {
|
|
+ skeleton->set_bone_rest(skeleton->get_selected_bone(), t);
|
|
+ } else {
|
|
+ skeleton->set_bone_pose(skeleton->get_selected_bone(), t);
|
|
+ }
|
|
+
|
|
+ sev->update_surface();
|
|
+
|
|
+ } break;
|
|
+
|
|
+ case SpatialEditorViewport::TRANSFORM_TRANSLATE: {
|
|
+
|
|
+ Vector3 motion_mask;
|
|
+ Plane plane;
|
|
+ bool plane_mv = false;
|
|
+
|
|
+ switch (_edit.plane) {
|
|
+ case SpatialEditorViewport::TRANSFORM_VIEW:
|
|
+ plane = Plane(_edit.center, sev->get_camera_normal());
|
|
+ break;
|
|
+ case SpatialEditorViewport::TRANSFORM_X_AXIS:
|
|
+ motion_mask = se->get_gizmo_transform().basis.get_axis(0);
|
|
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(sev->get_camera_normal())).normalized());
|
|
+ break;
|
|
+ case SpatialEditorViewport::TRANSFORM_Y_AXIS:
|
|
+ motion_mask = se->get_gizmo_transform().basis.get_axis(1);
|
|
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(sev->get_camera_normal())).normalized());
|
|
+ break;
|
|
+ case SpatialEditorViewport::TRANSFORM_Z_AXIS:
|
|
+ motion_mask = se->get_gizmo_transform().basis.get_axis(2);
|
|
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(sev->get_camera_normal())).normalized());
|
|
+ break;
|
|
+ case SpatialEditorViewport::TRANSFORM_YZ:
|
|
+ plane = Plane(_edit.center, se->get_gizmo_transform().basis.get_axis(0));
|
|
+ plane_mv = true;
|
|
+ break;
|
|
+ case SpatialEditorViewport::TRANSFORM_XZ:
|
|
+ plane = Plane(_edit.center, se->get_gizmo_transform().basis.get_axis(1));
|
|
+ plane_mv = true;
|
|
+ break;
|
|
+ case SpatialEditorViewport::TRANSFORM_XY:
|
|
+ plane = Plane(_edit.center, se->get_gizmo_transform().basis.get_axis(2));
|
|
+ plane_mv = true;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ Vector3 intersection;
|
|
+ if (!plane.intersects_ray(ray_pos, ray, &intersection))
|
|
+ break;
|
|
+
|
|
+ Vector3 click;
|
|
+ if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click))
|
|
+ break;
|
|
+
|
|
+ Vector3 motion = intersection - click;
|
|
+ if (_edit.plane != SpatialEditorViewport::TRANSFORM_VIEW) {
|
|
+ if (!plane_mv) {
|
|
+ motion = motion_mask.dot(motion) * motion_mask;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (_edit.snap || se->is_snap_enabled()) {
|
|
+ snap = se->get_translate_snap();
|
|
+ }
|
|
+
|
|
+ motion = original_to_local.basis.inverse().xform(motion);
|
|
+ if (_edit.snap || se->is_snap_enabled()) {
|
|
+ motion.snap(Vector3(snap, snap, snap));
|
|
+ }
|
|
+
|
|
+ Transform t;
|
|
+ // Apply translation
|
|
+ t = original_local;
|
|
+ t.origin += motion;
|
|
+
|
|
+ if (rest_mode) {
|
|
+ skeleton->set_bone_rest(skeleton->get_selected_bone(), t);
|
|
+ } else {
|
|
+ skeleton->set_bone_pose(skeleton->get_selected_bone(), t);
|
|
+ }
|
|
+
|
|
+ sev->update_surface();
|
|
+
|
|
+ } break;
|
|
+
|
|
+ case SpatialEditorViewport::TRANSFORM_ROTATE: {
|
|
+
|
|
+ Plane plane;
|
|
+ Vector3 axis;
|
|
+
|
|
+ switch (_edit.plane) {
|
|
+ case SpatialEditorViewport::TRANSFORM_VIEW:
|
|
+ plane = Plane(_edit.center, sev->get_camera_normal());
|
|
+ break;
|
|
+ case SpatialEditorViewport::TRANSFORM_X_AXIS:
|
|
+ plane = Plane(_edit.center, se->get_gizmo_transform().basis.get_axis(0));
|
|
+ axis = Vector3(1, 0, 0);
|
|
+ break;
|
|
+ case SpatialEditorViewport::TRANSFORM_Y_AXIS:
|
|
+ plane = Plane(_edit.center, se->get_gizmo_transform().basis.get_axis(1));
|
|
+ axis = Vector3(0, 1, 0);
|
|
+ break;
|
|
+ case SpatialEditorViewport::TRANSFORM_Z_AXIS:
|
|
+ plane = Plane(_edit.center, se->get_gizmo_transform().basis.get_axis(2));
|
|
+ axis = Vector3(0, 0, 1);
|
|
+ break;
|
|
+ case SpatialEditorViewport::TRANSFORM_YZ:
|
|
+ case SpatialEditorViewport::TRANSFORM_XZ:
|
|
+ case SpatialEditorViewport::TRANSFORM_XY:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ Vector3 intersection;
|
|
+ if (!plane.intersects_ray(ray_pos, ray, &intersection))
|
|
+ break;
|
|
+
|
|
+ Vector3 click;
|
|
+ if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click))
|
|
+ break;
|
|
+
|
|
+ Vector3 y_axis = (click - _edit.center).normalized();
|
|
+ Vector3 x_axis = plane.normal.cross(y_axis).normalized();
|
|
+
|
|
+ float angle = Math::atan2(x_axis.dot(intersection - _edit.center), y_axis.dot(intersection - _edit.center));
|
|
+
|
|
+ if (_edit.snap || se->is_snap_enabled()) {
|
|
+ snap = se->get_rotate_snap();
|
|
+ }
|
|
+ angle = Math::rad2deg(angle) + snap * 0.5; //else it won't reach +180
|
|
+ angle -= Math::fmod(angle, snap);
|
|
+ // set_message(vformat(TTR("Rotating %s degrees."), String::num(angle, snap_step_decimals)));
|
|
+ angle = Math::deg2rad(angle);
|
|
+
|
|
+ bool local_coords = (se->are_local_coords_enabled() && _edit.plane != SpatialEditorViewport::TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
|
|
+
|
|
+ Transform t;
|
|
+
|
|
+ if (local_coords) {
|
|
+ Basis rot = Basis(axis, angle);
|
|
+ t.basis = original_local.get_basis().orthonormalized() * rot;
|
|
+ t.basis = t.basis.scaled_local(original_local.basis.get_scale());
|
|
+ t.origin = original_local.origin;
|
|
+ } else {
|
|
+ Transform r;
|
|
+ Basis base = original_to_local.get_basis().orthonormalized().inverse();
|
|
+ r.basis.rotate(plane.normal, angle);
|
|
+ t.basis = base * r.get_basis() * base.inverse() * original_local.get_basis();
|
|
+ // t.basis = t.basis.scaled(original_local.basis.get_scale());
|
|
+ t.origin = original_local.origin;
|
|
+ }
|
|
+
|
|
+ // Apply rotation
|
|
+ if (rest_mode) {
|
|
+ skeleton->set_bone_rest(skeleton->get_selected_bone(), t);
|
|
+ } else {
|
|
+ skeleton->set_bone_pose(skeleton->get_selected_bone(), t);
|
|
+ }
|
|
+
|
|
+ sev->update_surface();
|
|
+
|
|
+ } break;
|
|
+ default: {
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
+void EditorInspectorPluginSkeleton::_bind_methods() {
|
|
+ ClassDB::bind_method(D_METHOD("set_rest_mode_toggled"), &EditorInspectorPluginSkeleton::set_rest_mode_toggled);
|
|
+}
|
|
+
|
|
+bool EditorInspectorPluginSkeleton::can_handle(Object *p_object) {
|
|
+ return Object::cast_to<Skeleton>(p_object) != nullptr;
|
|
}
|
|
|
|
-void SkeletonEditorPlugin::make_visible(bool p_visible) {
|
|
- if (p_visible) {
|
|
- skeleton_editor->options->show();
|
|
- } else {
|
|
+void EditorInspectorPluginSkeleton::parse_begin(Object *p_object) {
|
|
+ Skeleton *skeleton = Object::cast_to<Skeleton>(p_object);
|
|
+ ERR_FAIL_COND(!skeleton);
|
|
|
|
- skeleton_editor->options->hide();
|
|
- skeleton_editor->edit(NULL);
|
|
+ skel_editor = memnew(SkeletonEditor(this, editor, skeleton));
|
|
+ add_custom_control(skel_editor);
|
|
+}
|
|
+
|
|
+void EditorInspectorPluginSkeleton::set_rest_mode_toggled(const bool p_pressed) {
|
|
+ if (SpatialEditor::get_singleton()->get_selected()->get_class() == "Skeleton" && skel_editor) {
|
|
+ skel_editor->set_rest_mode_toggled(p_pressed);
|
|
}
|
|
}
|
|
|
|
SkeletonEditorPlugin::SkeletonEditorPlugin(EditorNode *p_node) {
|
|
editor = p_node;
|
|
- skeleton_editor = memnew(SkeletonEditor);
|
|
- editor->get_viewport()->add_child(skeleton_editor);
|
|
+
|
|
+ skeleton_plugin = memnew(EditorInspectorPluginSkeleton);
|
|
+ skeleton_plugin->editor = editor;
|
|
+
|
|
+ EditorInspector::add_inspector_plugin(skeleton_plugin);
|
|
+}
|
|
+
|
|
+bool SkeletonEditorPlugin::handles(Object *p_object) const {
|
|
+ return p_object->is_class("Skeleton");
|
|
}
|
|
|
|
-SkeletonEditorPlugin::~SkeletonEditorPlugin() {}
|
|
+void SkeletonEditor::_compute_edit(int p_index, const Point2 &p_point) {
|
|
+
|
|
+ SpatialEditor *se = SpatialEditor::get_singleton();
|
|
+ SpatialEditorViewport *sev = se->get_editor_viewport(p_index);
|
|
+
|
|
+ _edit.click_ray = sev->get_ray(Vector2(p_point.x, p_point.y));
|
|
+ _edit.click_ray_pos = sev->get_ray_pos(Vector2(p_point.x, p_point.y));
|
|
+ _edit.plane = SpatialEditorViewport::TRANSFORM_VIEW;
|
|
+ _update_spatial_transform_gizmo();
|
|
+ _edit.center = se->get_gizmo_transform().origin;
|
|
+
|
|
+ if (skeleton->get_selected_bone() != -1) {
|
|
+ original_global = skeleton->get_global_transform() * skeleton->get_bone_global_pose(skeleton->get_selected_bone());
|
|
+ if (rest_mode) {
|
|
+ original_local = skeleton->get_bone_rest(skeleton->get_selected_bone());
|
|
+ } else {
|
|
+ original_local = skeleton->get_bone_pose(skeleton->get_selected_bone());
|
|
+ }
|
|
+ original_to_local = skeleton->get_global_transform();
|
|
+ int parent_idx = skeleton->get_bone_parent(skeleton->get_selected_bone());
|
|
+ if (parent_idx >= 0) {
|
|
+ original_to_local = original_to_local * skeleton->get_bone_global_pose(parent_idx);
|
|
+ }
|
|
+ if (!rest_mode) {
|
|
+ original_to_local = original_to_local * skeleton->get_bone_rest(skeleton->get_selected_bone()) * skeleton->get_bone_custom_pose(skeleton->get_selected_bone());
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+bool SkeletonEditor::_gizmo_select(int p_index, const Vector2 &p_screenpos, bool p_highlight_only) {
|
|
+
|
|
+ SpatialEditor *se = SpatialEditor::get_singleton();
|
|
+ SpatialEditorViewport *sev = se->get_editor_viewport(p_index);
|
|
+
|
|
+ if (!se->is_gizmo_visible())
|
|
+ return false;
|
|
+ if (skeleton->get_selected_bone() == -1) {
|
|
+ if (p_highlight_only)
|
|
+ se->select_gizmo_highlight_axis(-1);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ Vector3 ray_pos = sev->get_ray_pos(Vector2(p_screenpos.x, p_screenpos.y));
|
|
+ Vector3 ray = sev->get_ray(Vector2(p_screenpos.x, p_screenpos.y));
|
|
+
|
|
+ Transform gt = se->get_gizmo_transform();
|
|
+ float gs = sev->get_gizmo_scale();
|
|
+
|
|
+ if (se->get_external_tool_mode() == SpatialEditor::EX_TOOL_MODE_SELECT || se->get_external_tool_mode() == SpatialEditor::EX_TOOL_MODE_MOVE) {
|
|
+
|
|
+ int col_axis = -1;
|
|
+ float col_d = 1e20;
|
|
+
|
|
+ for (int i = 0; i < 3; i++) {
|
|
+
|
|
+ Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs * (GIZMO_ARROW_OFFSET + (GIZMO_ARROW_SIZE * 0.5));
|
|
+ float grabber_radius = gs * GIZMO_ARROW_SIZE;
|
|
+
|
|
+ Vector3 r;
|
|
+
|
|
+ if (Geometry::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) {
|
|
+ float d = r.distance_to(ray_pos);
|
|
+ if (d < col_d) {
|
|
+ col_d = d;
|
|
+ col_axis = i;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ bool is_plane_translate = false;
|
|
+ // plane select
|
|
+ if (col_axis == -1) {
|
|
+ col_d = 1e20;
|
|
+
|
|
+ for (int i = 0; i < 3; i++) {
|
|
+
|
|
+ Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized();
|
|
+ Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized();
|
|
+
|
|
+ Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gs * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST);
|
|
+
|
|
+ Vector3 r;
|
|
+ Plane plane(gt.origin, gt.basis.get_axis(i).normalized());
|
|
+
|
|
+ if (plane.intersects_ray(ray_pos, ray, &r)) {
|
|
+
|
|
+ float dist = r.distance_to(grabber_pos);
|
|
+ if (dist < (gs * GIZMO_PLANE_SIZE)) {
|
|
+
|
|
+ float d = ray_pos.distance_to(r);
|
|
+ if (d < col_d) {
|
|
+ col_d = d;
|
|
+ col_axis = i;
|
|
+
|
|
+ is_plane_translate = true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (col_axis != -1) {
|
|
+
|
|
+ if (p_highlight_only) {
|
|
+
|
|
+ se->select_gizmo_highlight_axis(col_axis + (is_plane_translate ? 6 : 0));
|
|
+
|
|
+ } else {
|
|
+ //handle plane translate
|
|
+ _edit.mode = SpatialEditorViewport::TRANSFORM_TRANSLATE;
|
|
+ _compute_edit(p_index, Point2(p_screenpos.x, p_screenpos.y));
|
|
+ _edit.plane = SpatialEditorViewport::TransformPlane(SpatialEditorViewport::TRANSFORM_X_AXIS + col_axis + (is_plane_translate ? 3 : 0));
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (se->get_external_tool_mode() == SpatialEditor::EX_TOOL_MODE_SELECT || se->get_external_tool_mode() == SpatialEditor::EX_TOOL_MODE_ROTATE) {
|
|
+
|
|
+ int col_axis = -1;
|
|
+ float col_d = 1e20;
|
|
+
|
|
+ for (int i = 0; i < 3; i++) {
|
|
+
|
|
+ Plane plane(gt.origin, gt.basis.get_axis(i).normalized());
|
|
+ Vector3 r;
|
|
+ if (!plane.intersects_ray(ray_pos, ray, &r))
|
|
+ continue;
|
|
+
|
|
+ float dist = r.distance_to(gt.origin);
|
|
+
|
|
+ if (dist > gs * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gs * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) {
|
|
+
|
|
+ float d = ray_pos.distance_to(r);
|
|
+ if (d < col_d) {
|
|
+ col_d = d;
|
|
+ col_axis = i;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (col_axis != -1) {
|
|
+
|
|
+ if (p_highlight_only) {
|
|
+
|
|
+ se->select_gizmo_highlight_axis(col_axis + 3);
|
|
+ } else {
|
|
+ //handle rotate
|
|
+ _edit.mode = SpatialEditorViewport::TRANSFORM_ROTATE;
|
|
+ _compute_edit(p_index, Point2(p_screenpos.x, p_screenpos.y));
|
|
+ _edit.plane = SpatialEditorViewport::TransformPlane(SpatialEditorViewport::TRANSFORM_X_AXIS + col_axis);
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (se->get_external_tool_mode() == SpatialEditor::EX_TOOL_MODE_SCALE) {
|
|
+
|
|
+ int col_axis = -1;
|
|
+ float col_d = 1e20;
|
|
+
|
|
+ for (int i = 0; i < 3; i++) {
|
|
+
|
|
+ Vector3 grabber_pos = gt.origin + gt.basis.get_axis(i) * gs * GIZMO_SCALE_OFFSET;
|
|
+ float grabber_radius = gs * GIZMO_ARROW_SIZE;
|
|
+
|
|
+ Vector3 r;
|
|
+
|
|
+ if (Geometry::segment_intersects_sphere(ray_pos, ray_pos + ray * MAX_Z, grabber_pos, grabber_radius, &r)) {
|
|
+ float d = r.distance_to(ray_pos);
|
|
+ if (d < col_d) {
|
|
+ col_d = d;
|
|
+ col_axis = i;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ bool is_plane_scale = false;
|
|
+ // plane select
|
|
+ if (col_axis == -1) {
|
|
+ col_d = 1e20;
|
|
+
|
|
+ for (int i = 0; i < 3; i++) {
|
|
+
|
|
+ Vector3 ivec2 = gt.basis.get_axis((i + 1) % 3).normalized();
|
|
+ Vector3 ivec3 = gt.basis.get_axis((i + 2) % 3).normalized();
|
|
+
|
|
+ Vector3 grabber_pos = gt.origin + (ivec2 + ivec3) * gs * (GIZMO_PLANE_SIZE + GIZMO_PLANE_DST);
|
|
+
|
|
+ Vector3 r;
|
|
+ Plane plane(gt.origin, gt.basis.get_axis(i).normalized());
|
|
+
|
|
+ if (plane.intersects_ray(ray_pos, ray, &r)) {
|
|
+
|
|
+ float dist = r.distance_to(grabber_pos);
|
|
+ if (dist < (gs * GIZMO_PLANE_SIZE)) {
|
|
+
|
|
+ float d = ray_pos.distance_to(r);
|
|
+ if (d < col_d) {
|
|
+ col_d = d;
|
|
+ col_axis = i;
|
|
+
|
|
+ is_plane_scale = true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (col_axis != -1) {
|
|
+
|
|
+ if (p_highlight_only) {
|
|
+
|
|
+ se->select_gizmo_highlight_axis(col_axis + (is_plane_scale ? 12 : 9));
|
|
+
|
|
+ } else {
|
|
+ //handle scale
|
|
+ _edit.mode = SpatialEditorViewport::TRANSFORM_SCALE;
|
|
+ _compute_edit(p_index, Point2(p_screenpos.x, p_screenpos.y));
|
|
+ _edit.plane = SpatialEditorViewport::TransformPlane(SpatialEditorViewport::TRANSFORM_X_AXIS + col_axis + (is_plane_scale ? 3 : 0));
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (p_highlight_only)
|
|
+ se->select_gizmo_highlight_axis(-1);
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
+TreeItem *SkeletonEditor::_find(TreeItem *p_node, const NodePath &p_path) {
|
|
+ if (!p_node) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ NodePath np = p_node->get_metadata(0);
|
|
+ if (np == p_path) {
|
|
+ return p_node;
|
|
+ }
|
|
+
|
|
+ TreeItem *children = p_node->get_children();
|
|
+ while (children) {
|
|
+ TreeItem *n = _find(children, p_path);
|
|
+ if (n) {
|
|
+ return n;
|
|
+ }
|
|
+ children = children->get_next();
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/editor/plugins/skeleton_editor_plugin.h b/editor/plugins/skeleton_editor_plugin.h
|
|
index de3f752af6..b701d1af1e 100644
|
|
--- a/editor/plugins/skeleton_editor_plugin.h
|
|
+++ b/editor/plugins/skeleton_editor_plugin.h
|
|
@@ -31,20 +31,133 @@
|
|
#ifndef SKELETON_EDITOR_PLUGIN_H
|
|
#define SKELETON_EDITOR_PLUGIN_H
|
|
|
|
+#include "core/os/input_event.h"
|
|
#include "editor/editor_node.h"
|
|
#include "editor/editor_plugin.h"
|
|
+#include "spatial_editor_plugin.h"
|
|
+#include "scene/3d/camera.h"
|
|
+#include "scene/3d/mesh_instance.h"
|
|
#include "scene/3d/skeleton.h"
|
|
|
|
-class PhysicalBone;
|
|
+class EditorInspectorPluginSkeleton;
|
|
class Joint;
|
|
+class PhysicalBone;
|
|
+class SkeletonEditorPlugin;
|
|
+class Button;
|
|
+class CheckBox;
|
|
+
|
|
+class BoneTransformEditor : public VBoxContainer {
|
|
+ GDCLASS(BoneTransformEditor, VBoxContainer);
|
|
+
|
|
+ static const int32_t TRANSLATION_COMPONENTS = 3;
|
|
+ static const int32_t ROTATION_DEGREES_COMPONENTS = 3;
|
|
+ static const int32_t SCALE_COMPONENTS = 3;
|
|
+ static const int32_t BASIS_COMPONENTS = 9;
|
|
+ static const int32_t BASIS_SPLIT_COMPONENTS = 3;
|
|
+ static const int32_t TRANSFORM_COMPONENTS = 12;
|
|
+ static const int32_t TRANSFORM_SPLIT_COMPONENTS = 3;
|
|
+ static const int32_t TRANSFORM_CONTROL_COMPONENTS = 3;
|
|
+
|
|
+ EditorInspectorSection *section;
|
|
+
|
|
+ GridContainer *translation_grid;
|
|
+ GridContainer *rotation_grid;
|
|
+ GridContainer *scale_grid;
|
|
+ GridContainer *transform_grid;
|
|
+
|
|
+ EditorSpinSlider *translation_slider[TRANSLATION_COMPONENTS];
|
|
+ EditorSpinSlider *rotation_slider[ROTATION_DEGREES_COMPONENTS];
|
|
+ EditorSpinSlider *scale_slider[SCALE_COMPONENTS];
|
|
+ EditorSpinSlider *transform_slider[TRANSFORM_COMPONENTS];
|
|
+
|
|
+ Rect2 background_rects[5];
|
|
+
|
|
+ Skeleton *skeleton;
|
|
+ String property;
|
|
+
|
|
+ UndoRedo *undo_redo;
|
|
+
|
|
+ Button *key_button;
|
|
+ CheckBox *enabled_checkbox;
|
|
+
|
|
+ bool keyable;
|
|
+ bool toggle_enabled;
|
|
+ bool updating;
|
|
+
|
|
+ String label;
|
|
+
|
|
+ void create_editors();
|
|
+ void setup_spinner(EditorSpinSlider *spinner, const bool is_transform_spinner);
|
|
+
|
|
+ void _value_changed(const double p_value, const bool p_from_transform);
|
|
+
|
|
+ Transform compute_transform(const bool p_from_transform) const;
|
|
+
|
|
+ void update_enabled_checkbox();
|
|
+
|
|
+protected:
|
|
+ void _notification(int p_what);
|
|
+ static void _bind_methods();
|
|
+
|
|
+public:
|
|
+ BoneTransformEditor(Skeleton *p_skeleton);
|
|
+
|
|
+ // Which transform target to modify
|
|
+ void set_target(const String &p_prop);
|
|
+ void set_label(const String &p_label) { label = p_label; }
|
|
+
|
|
+ void _update_properties();
|
|
+ void _update_custom_pose_properties();
|
|
+ void _update_transform_properties(Transform p_transform);
|
|
+
|
|
+ // Can/cannot modify the spinner values for the Transform
|
|
+ void set_read_only(const bool p_read_only);
|
|
+
|
|
+ // Transform can be keyed, whether or not to show the button
|
|
+ void set_keyable(const bool p_keyable);
|
|
+
|
|
+ // Bone can be toggled enabled or disabled, whether or not to show the checkbox
|
|
+ void set_toggle_enabled(const bool p_enabled);
|
|
+
|
|
+ // Key Transform Button pressed
|
|
+ void _key_button_pressed();
|
|
|
|
-class SkeletonEditor : public Node {
|
|
- GDCLASS(SkeletonEditor, Node);
|
|
+ // Bone Enabled Checkbox toggled
|
|
+ void _checkbox_toggled(const bool p_toggled);
|
|
+};
|
|
+
|
|
+class SkeletonEditor : public VBoxContainer {
|
|
+
|
|
+ GDCLASS(SkeletonEditor, VBoxContainer);
|
|
+
|
|
+ friend class SkeletonEditorPlugin;
|
|
|
|
enum Menu {
|
|
+ MENU_OPTION_INIT_POSE,
|
|
+ MENU_OPTION_INSERT_KEYS,
|
|
+ MENU_OPTION_INSERT_KEYS_EXISTED,
|
|
+ MENU_OPTION_POSE_TO_REST,
|
|
MENU_OPTION_CREATE_PHYSICAL_SKELETON
|
|
};
|
|
|
|
+ enum ToolMode {
|
|
+ TOOL_MODE_BONE_SELECT,
|
|
+ TOOL_MODE_BONE_MOVE,
|
|
+ TOOL_MODE_BONE_ROTATE,
|
|
+ TOOL_MODE_BONE_SCALE,
|
|
+ TOOL_MODE_BONE_NONE,
|
|
+ TOOL_MODE_BONE_MAX
|
|
+ };
|
|
+
|
|
+ enum MenuToolOption {
|
|
+ MENU_TOOL_BONE_SELECT,
|
|
+ MENU_TOOL_BONE_MOVE,
|
|
+ MENU_TOOL_BONE_ROTATE,
|
|
+ MENU_TOOL_BONE_SCALE,
|
|
+ MENU_TOOL_BONE_NONE,
|
|
+ MENU_TOOL_BONE_MAX
|
|
+ };
|
|
+
|
|
struct BoneInfo {
|
|
PhysicalBone *physical_bone;
|
|
Transform relative_rest; // Relative to skeleton node
|
|
@@ -52,45 +165,134 @@ class SkeletonEditor : public Node {
|
|
physical_bone(NULL) {}
|
|
};
|
|
|
|
+ EditorNode *editor;
|
|
+ EditorInspectorPluginSkeleton *editor_plugin;
|
|
+
|
|
Skeleton *skeleton;
|
|
|
|
+ Tree *joint_tree;
|
|
+ BoneTransformEditor *rest_editor;
|
|
+ BoneTransformEditor *pose_editor;
|
|
+ BoneTransformEditor *custom_pose_editor;
|
|
+
|
|
+ VSeparator *separators[2];
|
|
MenuButton *options;
|
|
+ ToolButton *tool_button[TOOL_MODE_BONE_MAX];
|
|
+ ToolButton *rest_mode_button;
|
|
+
|
|
+ ToolMode tool_mode = TOOL_MODE_BONE_NONE;
|
|
+ bool rest_mode = false;
|
|
+
|
|
+ EditorFileDialog *file_dialog;
|
|
+
|
|
+ UndoRedo *undo_redo;
|
|
+
|
|
+ bool keyable;
|
|
|
|
void _on_click_option(int p_option);
|
|
+ void _file_selected(const String &p_file);
|
|
+ void _menu_tool_item_pressed(int p_option);
|
|
+ TreeItem *_find(TreeItem *p_node, const NodePath &p_path);
|
|
+ void rest_mode_toggled(const bool pressed);
|
|
|
|
- friend class SkeletonEditorPlugin;
|
|
+ EditorFileDialog *file_export_lib;
|
|
+
|
|
+ void update_joint_tree();
|
|
+ void update_editors();
|
|
+
|
|
+ void create_editors();
|
|
+
|
|
+ void init_pose();
|
|
+ void insert_keys(bool p_all_bones);
|
|
+ void pose_to_rest();
|
|
+ void create_physical_skeleton();
|
|
+ PhysicalBone *create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos);
|
|
+
|
|
+ Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
|
|
+ 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);
|
|
+
|
|
+ Ref<ShaderMaterial> handle_material;
|
|
+ Ref<Shader> handle_shader;
|
|
+ MeshInstance *pointsm;
|
|
+ Ref<ArrayMesh> am;
|
|
+ void _hide_handles();
|
|
+ void _draw_handles();
|
|
+
|
|
+ SpatialEditorViewport::EditData _edit;
|
|
+ void _compute_edit(int p_index, const Point2 &p_point);
|
|
+ bool _gizmo_select(int p_index, const Vector2 &p_screenpos, bool p_highlight_only = false);
|
|
+
|
|
+ Transform original_local;
|
|
+ Transform original_global;
|
|
+ Transform original_to_local;
|
|
+
|
|
+ void _update_spatial_transform_gizmo();
|
|
|
|
protected:
|
|
void _notification(int p_what);
|
|
void _node_removed(Node *p_node);
|
|
static void _bind_methods();
|
|
|
|
- void create_physical_skeleton();
|
|
- PhysicalBone *create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos);
|
|
-
|
|
public:
|
|
- void edit(Skeleton *p_node);
|
|
+ virtual bool forward_spatial_gui_input(int p_index, Camera *p_camera, const Ref<InputEvent> &p_event);
|
|
+ void move_skeleton_bone(NodePath p_skeleton_path, int32_t p_selected_boneidx, int32_t p_target_boneidx);
|
|
|
|
- SkeletonEditor();
|
|
+ // Transform can be keyed, whether or not to show the button
|
|
+ void set_keyable(const bool p_keyable);
|
|
+
|
|
+ Skeleton *get_skeleton() const { return skeleton; };
|
|
+
|
|
+ void set_rest_mode_toggled(const bool pressed);
|
|
+
|
|
+ void _joint_tree_selection_changed();
|
|
+ void _joint_tree_rmb_select(const Vector2 &p_pos);
|
|
+
|
|
+ void _update_properties();
|
|
+
|
|
+ SkeletonEditor(EditorInspectorPluginSkeleton *e_plugin, EditorNode *p_editor, Skeleton *skeleton);
|
|
~SkeletonEditor();
|
|
};
|
|
|
|
-class SkeletonEditorPlugin : public EditorPlugin {
|
|
+class EditorInspectorPluginSkeleton : public EditorInspectorPlugin {
|
|
+ GDCLASS(EditorInspectorPluginSkeleton, EditorInspectorPlugin);
|
|
+
|
|
+ friend class SkeletonEditorPlugin;
|
|
+
|
|
+ SkeletonEditor *skel_editor;
|
|
+ EditorNode *editor;
|
|
+ UndoRedo *undo_redo;
|
|
|
|
+ void set_rest_mode_toggled (const bool p_pressed);
|
|
+
|
|
+protected:
|
|
+ static void _bind_methods();
|
|
+public:
|
|
+ virtual bool forward_spatial_gui_input(int p_index, Camera *p_camera, const Ref<InputEvent> &p_event) { return skel_editor->forward_spatial_gui_input(p_index, p_camera, p_event); }
|
|
+ virtual bool can_handle(Object *p_object);
|
|
+ virtual void parse_begin(Object *p_object);
|
|
+ UndoRedo *get_undo_redo() { return undo_redo; }
|
|
+};
|
|
+
|
|
+class SkeletonEditorPlugin : public EditorPlugin {
|
|
GDCLASS(SkeletonEditorPlugin, EditorPlugin);
|
|
|
|
+ EditorInspectorPluginSkeleton *skeleton_plugin;
|
|
EditorNode *editor;
|
|
- SkeletonEditor *skeleton_editor;
|
|
|
|
public:
|
|
- virtual String get_name() const { return "Skeleton"; }
|
|
- virtual bool has_main_screen() const { return false; }
|
|
- virtual void edit(Object *p_object);
|
|
+ virtual bool forward_spatial_gui_input(int p_index, Camera *p_camera, const Ref<InputEvent> &p_event) {
|
|
+ if (SpatialEditor::get_singleton()->get_tool_mode() != SpatialEditor::TOOL_MODE_EXTERNAL) {
|
|
+ return false;
|
|
+ }
|
|
+ return skeleton_plugin->forward_spatial_gui_input(p_index, p_camera, p_event);
|
|
+ }
|
|
+ bool has_main_screen() const { return false; }
|
|
virtual bool handles(Object *p_object) const;
|
|
- virtual void make_visible(bool p_visible);
|
|
+
|
|
+ virtual String get_name() const { return "Skeleton"; }
|
|
|
|
SkeletonEditorPlugin(EditorNode *p_node);
|
|
- ~SkeletonEditorPlugin();
|
|
};
|
|
|
|
#endif // SKELETON_EDITOR_PLUGIN_H
|
|
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
|
|
index 483dff7616..4ff84c658c 100644
|
|
--- a/editor/plugins/spatial_editor_plugin.cpp
|
|
+++ b/editor/plugins/spatial_editor_plugin.cpp
|
|
@@ -422,18 +422,15 @@ Point2 SpatialEditorViewport::_point_to_screen(const Vector3 &p_point) {
|
|
return camera->unproject_position(p_point) * viewport_container->get_stretch_shrink();
|
|
}
|
|
|
|
-Vector3 SpatialEditorViewport::_get_ray_pos(const Vector2 &p_pos) const {
|
|
-
|
|
+Vector3 SpatialEditorViewport::get_ray_pos(const Vector2 &p_pos) const {
|
|
return camera->project_ray_origin(p_pos / viewport_container->get_stretch_shrink());
|
|
}
|
|
|
|
-Vector3 SpatialEditorViewport::_get_camera_normal() const {
|
|
-
|
|
+Vector3 SpatialEditorViewport::get_camera_normal() const {
|
|
return -_get_camera_transform().basis.get_axis(2);
|
|
}
|
|
|
|
-Vector3 SpatialEditorViewport::_get_ray(const Vector2 &p_pos) const {
|
|
-
|
|
+Vector3 SpatialEditorViewport::get_ray(const Vector2 &p_pos) const {
|
|
return camera->project_ray_normal(p_pos / viewport_container->get_stretch_shrink());
|
|
}
|
|
|
|
@@ -490,8 +487,8 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append,
|
|
if (r_gizmo_handle)
|
|
*r_gizmo_handle = -1;
|
|
|
|
- Vector3 ray = _get_ray(p_pos);
|
|
- Vector3 pos = _get_ray_pos(p_pos);
|
|
+ Vector3 ray = get_ray(p_pos);
|
|
+ Vector3 pos = get_ray_pos(p_pos);
|
|
Vector2 shrinked_pos = p_pos / viewport_container->get_stretch_shrink();
|
|
|
|
Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario());
|
|
@@ -554,8 +551,8 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append,
|
|
|
|
void SpatialEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_includes_current, Vector<_RayResult> &results, bool p_alt_select) {
|
|
|
|
- Vector3 ray = _get_ray(p_pos);
|
|
- Vector3 pos = _get_ray_pos(p_pos);
|
|
+ Vector3 ray = get_ray(p_pos);
|
|
+ Vector3 pos = get_ray_pos(p_pos);
|
|
|
|
Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario());
|
|
Set<Ref<EditorSpatialGizmo> > found_gizmos;
|
|
@@ -668,7 +665,7 @@ void SpatialEditorViewport::_select_region() {
|
|
}
|
|
}
|
|
|
|
- Plane near(cam_pos, -_get_camera_normal());
|
|
+ Plane near(cam_pos, -get_camera_normal());
|
|
near.d -= get_znear();
|
|
frustum.push_back(near);
|
|
|
|
@@ -740,8 +737,8 @@ void SpatialEditorViewport::_update_name() {
|
|
|
|
void SpatialEditorViewport::_compute_edit(const Point2 &p_point) {
|
|
|
|
- _edit.click_ray = _get_ray(Vector2(p_point.x, p_point.y));
|
|
- _edit.click_ray_pos = _get_ray_pos(Vector2(p_point.x, p_point.y));
|
|
+ _edit.click_ray = get_ray(Vector2(p_point.x, p_point.y));
|
|
+ _edit.click_ray_pos = get_ray_pos(Vector2(p_point.x, p_point.y));
|
|
_edit.plane = TRANSFORM_VIEW;
|
|
spatial_editor->update_transform_gizmo();
|
|
_edit.center = spatial_editor->get_gizmo_transform().origin;
|
|
@@ -798,8 +795,8 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig
|
|
return false;
|
|
}
|
|
|
|
- Vector3 ray_pos = _get_ray_pos(Vector2(p_screenpos.x, p_screenpos.y));
|
|
- Vector3 ray = _get_ray(Vector2(p_screenpos.x, p_screenpos.y));
|
|
+ Vector3 ray_pos = get_ray_pos(Vector2(p_screenpos.x, p_screenpos.y));
|
|
+ Vector3 ray = get_ray(Vector2(p_screenpos.x, p_screenpos.y));
|
|
|
|
Transform gt = spatial_editor->get_gizmo_transform();
|
|
float gs = gizmo_scale;
|
|
@@ -887,7 +884,7 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig
|
|
float dist = r.distance_to(gt.origin);
|
|
Vector3 r_dir = (r - gt.origin).normalized();
|
|
|
|
- if (_get_camera_normal().dot(r_dir) <= 0.005) {
|
|
+ if (get_camera_normal().dot(r_dir) <= 0.005) {
|
|
if (dist > gs * (GIZMO_CIRCLE_SIZE - GIZMO_RING_HALF_WIDTH) && dist < gs * (GIZMO_CIRCLE_SIZE + GIZMO_RING_HALF_WIDTH)) {
|
|
float d = ray_pos.distance_to(r);
|
|
if (d < col_d) {
|
|
@@ -982,7 +979,7 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_hig
|
|
}
|
|
}
|
|
|
|
- if (p_highlight_only)
|
|
+ if (p_highlight_only && spatial_editor->get_tool_mode() != SpatialEditor::TOOL_MODE_EXTERNAL)
|
|
spatial_editor->select_gizmo_highlight_axis(-1);
|
|
|
|
return false;
|
|
@@ -1071,7 +1068,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
|
|
EditorNode *en = editor;
|
|
EditorPluginList *force_input_forwarding_list = en->get_editor_plugins_force_input_forwarding();
|
|
if (!force_input_forwarding_list->empty()) {
|
|
- bool discard = force_input_forwarding_list->forward_spatial_gui_input(camera, p_event, true);
|
|
+ bool discard = force_input_forwarding_list->forward_spatial_gui_input(index, camera, p_event, true);
|
|
if (discard)
|
|
return;
|
|
}
|
|
@@ -1080,7 +1077,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
|
|
EditorNode *en = editor;
|
|
EditorPluginList *over_plugin_list = en->get_editor_plugins_over();
|
|
if (!over_plugin_list->empty()) {
|
|
- bool discard = over_plugin_list->forward_spatial_gui_input(camera, p_event, false);
|
|
+ bool discard = over_plugin_list->forward_spatial_gui_input(index, camera, p_event, false);
|
|
if (discard)
|
|
return;
|
|
}
|
|
@@ -1462,8 +1459,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
|
|
if (_edit.mode == TRANSFORM_NONE)
|
|
return;
|
|
|
|
- Vector3 ray_pos = _get_ray_pos(m->get_position());
|
|
- Vector3 ray = _get_ray(m->get_position());
|
|
+ Vector3 ray_pos = get_ray_pos(m->get_position());
|
|
+ Vector3 ray = get_ray(m->get_position());
|
|
float snap = EDITOR_GET("interface/inspector/default_float_step");
|
|
int snap_step_decimals = Math::range_step_decimals(snap);
|
|
|
|
@@ -1478,19 +1475,19 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
|
|
switch (_edit.plane) {
|
|
case TRANSFORM_VIEW:
|
|
motion_mask = Vector3(0, 0, 0);
|
|
- plane = Plane(_edit.center, _get_camera_normal());
|
|
+ plane = Plane(_edit.center, get_camera_normal());
|
|
break;
|
|
case TRANSFORM_X_AXIS:
|
|
motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0);
|
|
- plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
|
|
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(get_camera_normal())).normalized());
|
|
break;
|
|
case TRANSFORM_Y_AXIS:
|
|
motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1);
|
|
- plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
|
|
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(get_camera_normal())).normalized());
|
|
break;
|
|
case TRANSFORM_Z_AXIS:
|
|
motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2);
|
|
- plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
|
|
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(get_camera_normal())).normalized());
|
|
break;
|
|
case TRANSFORM_YZ:
|
|
motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2) + spatial_editor->get_gizmo_transform().basis.get_axis(1);
|
|
@@ -1625,19 +1622,19 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
|
|
|
|
switch (_edit.plane) {
|
|
case TRANSFORM_VIEW:
|
|
- plane = Plane(_edit.center, _get_camera_normal());
|
|
+ plane = Plane(_edit.center, get_camera_normal());
|
|
break;
|
|
case TRANSFORM_X_AXIS:
|
|
motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(0);
|
|
- plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
|
|
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(get_camera_normal())).normalized());
|
|
break;
|
|
case TRANSFORM_Y_AXIS:
|
|
motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(1);
|
|
- plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
|
|
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(get_camera_normal())).normalized());
|
|
break;
|
|
case TRANSFORM_Z_AXIS:
|
|
motion_mask = spatial_editor->get_gizmo_transform().basis.get_axis(2);
|
|
- plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized());
|
|
+ plane = Plane(_edit.center, motion_mask.cross(motion_mask.cross(get_camera_normal())).normalized());
|
|
break;
|
|
case TRANSFORM_YZ:
|
|
plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(0));
|
|
@@ -1734,7 +1731,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
|
|
|
|
switch (_edit.plane) {
|
|
case TRANSFORM_VIEW:
|
|
- plane = Plane(_edit.center, _get_camera_normal());
|
|
+ plane = Plane(_edit.center, get_camera_normal());
|
|
break;
|
|
case TRANSFORM_X_AXIS:
|
|
plane = Plane(_edit.center, spatial_editor->get_gizmo_transform().basis.get_axis(0));
|
|
@@ -3215,7 +3212,6 @@ void SpatialEditorViewport::update_transform_gizmo_view() {
|
|
return;
|
|
|
|
Transform xform = spatial_editor->get_gizmo_transform();
|
|
-
|
|
Transform camera_xform = camera->get_transform();
|
|
|
|
if (xform.origin.distance_squared_to(camera_xform.origin) < 0.01) {
|
|
@@ -3254,17 +3250,32 @@ void SpatialEditorViewport::update_transform_gizmo_view() {
|
|
|
|
xform.basis.scale(scale);
|
|
|
|
- for (int i = 0; i < 3; i++) {
|
|
- VisualServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], xform);
|
|
- VisualServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE));
|
|
- VisualServer::get_singleton()->instance_set_transform(move_plane_gizmo_instance[i], xform);
|
|
- VisualServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE));
|
|
- VisualServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], xform);
|
|
- VisualServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE));
|
|
- VisualServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], xform);
|
|
- VisualServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE));
|
|
- VisualServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], xform);
|
|
- VisualServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE));
|
|
+ if (spatial_editor->is_tool_external()) {
|
|
+ for (int i = 0; i < 3; i++) {
|
|
+ VisualServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], xform);
|
|
+ VisualServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_external_tool_mode() == SpatialEditor::EX_TOOL_MODE_SELECT || spatial_editor->get_external_tool_mode() == SpatialEditor::EX_TOOL_MODE_MOVE));
|
|
+ VisualServer::get_singleton()->instance_set_transform(move_plane_gizmo_instance[i], xform);
|
|
+ VisualServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_external_tool_mode() == SpatialEditor::EX_TOOL_MODE_SELECT || spatial_editor->get_external_tool_mode() == SpatialEditor::EX_TOOL_MODE_MOVE));
|
|
+ VisualServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], xform);
|
|
+ VisualServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_external_tool_mode() == SpatialEditor::EX_TOOL_MODE_SELECT || spatial_editor->get_external_tool_mode() == SpatialEditor::EX_TOOL_MODE_ROTATE));
|
|
+ VisualServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], xform);
|
|
+ VisualServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_external_tool_mode() == SpatialEditor::EX_TOOL_MODE_SCALE));
|
|
+ VisualServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], xform);
|
|
+ VisualServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_external_tool_mode() == SpatialEditor::EX_TOOL_MODE_SCALE));
|
|
+ }
|
|
+ } else {
|
|
+ for (int i = 0; i < 3; i++) {
|
|
+ VisualServer::get_singleton()->instance_set_transform(move_gizmo_instance[i], xform);
|
|
+ VisualServer::get_singleton()->instance_set_visible(move_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE));
|
|
+ VisualServer::get_singleton()->instance_set_transform(move_plane_gizmo_instance[i], xform);
|
|
+ VisualServer::get_singleton()->instance_set_visible(move_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_MOVE));
|
|
+ VisualServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[i], xform);
|
|
+ VisualServer::get_singleton()->instance_set_visible(rotate_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_ROTATE));
|
|
+ VisualServer::get_singleton()->instance_set_transform(scale_gizmo_instance[i], xform);
|
|
+ VisualServer::get_singleton()->instance_set_visible(scale_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE));
|
|
+ VisualServer::get_singleton()->instance_set_transform(scale_plane_gizmo_instance[i], xform);
|
|
+ VisualServer::get_singleton()->instance_set_visible(scale_plane_gizmo_instance[i], spatial_editor->is_gizmo_visible() && (spatial_editor->get_tool_mode() == SpatialEditor::TOOL_MODE_SCALE));
|
|
+ }
|
|
}
|
|
// Rotation white outline
|
|
VisualServer::get_singleton()->instance_set_transform(rotate_gizmo_instance[3], xform);
|
|
@@ -3498,8 +3509,8 @@ void SpatialEditorViewport::assign_pending_data_pointers(Spatial *p_preview_node
|
|
Vector3 SpatialEditorViewport::_get_instance_position(const Point2 &p_pos) const {
|
|
const float MAX_DISTANCE = 10;
|
|
|
|
- Vector3 world_ray = _get_ray(p_pos);
|
|
- Vector3 world_pos = _get_ray_pos(p_pos);
|
|
+ Vector3 world_ray = get_ray(p_pos);
|
|
+ Vector3 world_pos = get_ray_pos(p_pos);
|
|
|
|
Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(world_pos, world_ray, get_tree()->get_root()->get_world()->get_scenario());
|
|
Set<Ref<EditorSpatialGizmo> > found_gizmos;
|
|
@@ -4410,42 +4421,60 @@ void SpatialEditor::select_gizmo_highlight_axis(int p_axis) {
|
|
|
|
void SpatialEditor::update_transform_gizmo() {
|
|
|
|
- List<Node *> &selection = editor_selection->get_selected_node_list();
|
|
AABB center;
|
|
bool first = true;
|
|
|
|
Basis gizmo_basis;
|
|
bool local_gizmo_coords = are_local_coords_enabled();
|
|
|
|
- for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
|
|
+ if (is_tool_external()) {
|
|
+ Vector<Transform> transforms = get_externals();
|
|
+ for (int i=0; i < transforms.size(); i++) {
|
|
+ Transform xf = transforms[i];
|
|
+ if (first) {
|
|
+ center.position = xf.origin;
|
|
+ first = false;
|
|
+ if (local_gizmo_coords) {
|
|
+ gizmo_basis = xf.basis;
|
|
+ gizmo_basis.orthonormalize();
|
|
+ }
|
|
+ } else {
|
|
+ center.expand_to(xf.origin);
|
|
+ gizmo_basis = Basis();
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ List<Node *> &selection = editor_selection->get_selected_node_list();
|
|
+ for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
|
|
|
|
- Spatial *sp = Object::cast_to<Spatial>(E->get());
|
|
- if (!sp)
|
|
- continue;
|
|
+ Spatial *sp = Object::cast_to<Spatial>(E->get());
|
|
+ if (!sp)
|
|
+ continue;
|
|
|
|
- SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
|
|
- if (!se)
|
|
- continue;
|
|
+ SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
|
|
+ if (!se)
|
|
+ continue;
|
|
|
|
- Transform xf = se->sp->get_global_gizmo_transform();
|
|
+ Transform xf = se->sp->get_global_gizmo_transform();
|
|
|
|
- if (first) {
|
|
- center.position = xf.origin;
|
|
- first = false;
|
|
- if (local_gizmo_coords) {
|
|
- gizmo_basis = xf.basis;
|
|
- gizmo_basis.orthonormalize();
|
|
+ if (first) {
|
|
+ center.position = xf.origin;
|
|
+ first = false;
|
|
+ if (local_gizmo_coords) {
|
|
+ gizmo_basis = xf.basis;
|
|
+ gizmo_basis.orthonormalize();
|
|
+ }
|
|
+ } else {
|
|
+ center.expand_to(xf.origin);
|
|
+ gizmo_basis = Basis();
|
|
}
|
|
- } else {
|
|
- center.expand_to(xf.origin);
|
|
- gizmo_basis = Basis();
|
|
}
|
|
}
|
|
|
|
Vector3 pcenter = center.position + center.size * 0.5;
|
|
- gizmo.visible = !first;
|
|
gizmo.transform.origin = pcenter;
|
|
gizmo.transform.basis = gizmo_basis;
|
|
+ gizmo.visible = !first;
|
|
|
|
for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
|
|
viewports[i]->update_transform_gizmo_view();
|
|
@@ -4880,12 +4909,15 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
|
|
case MENU_TOOL_MOVE:
|
|
case MENU_TOOL_ROTATE:
|
|
case MENU_TOOL_SCALE:
|
|
- case MENU_TOOL_LIST_SELECT: {
|
|
-
|
|
- for (int i = 0; i < TOOL_MAX; i++)
|
|
+ case MENU_TOOL_LIST_SELECT:
|
|
+ case MENU_TOOL_EXTERNAL: {
|
|
+ for (int i = 0; i < TOOL_MAX; i++) {
|
|
tool_button[i]->set_pressed(i == p_option);
|
|
+ }
|
|
tool_mode = (ToolMode)p_option;
|
|
+ clear_externals();
|
|
update_transform_gizmo();
|
|
+ emit_signal("change_tool_mode");
|
|
|
|
} break;
|
|
case MENU_TRANSFORM_CONFIGURE_SNAP: {
|
|
@@ -6233,6 +6265,7 @@ void SpatialEditor::_bind_methods() {
|
|
ADD_SIGNAL(MethodInfo("transform_key_request"));
|
|
ADD_SIGNAL(MethodInfo("item_lock_status_changed"));
|
|
ADD_SIGNAL(MethodInfo("item_group_status_changed"));
|
|
+ ADD_SIGNAL(MethodInfo("change_tool_mode"));
|
|
}
|
|
|
|
void SpatialEditor::clear() {
|
|
@@ -6326,6 +6359,10 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
|
|
tool_button[TOOL_MODE_SCALE]->connect("pressed", this, "_menu_item_pressed", button_binds);
|
|
tool_button[TOOL_MODE_SCALE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_scale", TTR("Scale Mode"), KEY_R));
|
|
|
|
+ tool_button[TOOL_MODE_EXTERNAL] = memnew(ToolButton);
|
|
+ button_binds.write[0] = MENU_TOOL_EXTERNAL;
|
|
+ tool_button[TOOL_MODE_EXTERNAL]->connect("pressed", this, "_menu_item_pressed", button_binds);
|
|
+
|
|
hbc_menu->add_child(memnew(VSeparator));
|
|
|
|
tool_button[TOOL_MODE_LIST_SELECT] = memnew(ToolButton);
|
|
@@ -6625,6 +6662,10 @@ SpatialEditor::~SpatialEditor() {
|
|
memdelete(preview_node);
|
|
}
|
|
|
|
+void SpatialEditor::set_tool_mode(ToolMode p_tool_mode) {
|
|
+ _menu_item_pressed(p_tool_mode);
|
|
+}
|
|
+
|
|
void SpatialEditorPlugin::make_visible(bool p_visible) {
|
|
|
|
if (p_visible) {
|
|
diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h
|
|
index 4644144a58..351063ed47 100644
|
|
--- a/editor/plugins/spatial_editor_plugin.h
|
|
+++ b/editor/plugins/spatial_editor_plugin.h
|
|
@@ -233,6 +233,40 @@ public:
|
|
FREELOOK_FULLY_AXIS_LOCKED,
|
|
};
|
|
|
|
+ enum TransformMode {
|
|
+ TRANSFORM_NONE,
|
|
+ TRANSFORM_ROTATE,
|
|
+ TRANSFORM_TRANSLATE,
|
|
+ TRANSFORM_SCALE
|
|
+ };
|
|
+
|
|
+ enum TransformPlane {
|
|
+ TRANSFORM_VIEW,
|
|
+ TRANSFORM_X_AXIS,
|
|
+ TRANSFORM_Y_AXIS,
|
|
+ TRANSFORM_Z_AXIS,
|
|
+ TRANSFORM_YZ,
|
|
+ TRANSFORM_XZ,
|
|
+ TRANSFORM_XY,
|
|
+ };
|
|
+
|
|
+ struct EditData {
|
|
+ TransformMode mode;
|
|
+ TransformPlane plane;
|
|
+ Transform original;
|
|
+ Vector3 click_ray;
|
|
+ Vector3 click_ray_pos;
|
|
+ Vector3 center;
|
|
+ Vector3 orig_gizmo_pos;
|
|
+ int edited_gizmo;
|
|
+ Point2 mouse_pos;
|
|
+ bool snap;
|
|
+ Ref<EditorSpatialGizmo> gizmo;
|
|
+ int gizmo_handle;
|
|
+ Variant gizmo_initial_value;
|
|
+ Vector3 gizmo_initial_pos;
|
|
+ };
|
|
+
|
|
private:
|
|
int index;
|
|
String name;
|
|
@@ -292,14 +326,11 @@ private:
|
|
void _select(Node *p_node, bool p_append, bool p_single);
|
|
ObjectID _select_ray(const Point2 &p_pos, bool p_append, bool &r_includes_current, int *r_gizmo_handle = NULL, bool p_alt_select = false);
|
|
void _find_items_at_pos(const Point2 &p_pos, bool &r_includes_current, Vector<_RayResult> &results, bool p_alt_select = false);
|
|
- Vector3 _get_ray_pos(const Vector2 &p_pos) const;
|
|
- Vector3 _get_ray(const Vector2 &p_pos) const;
|
|
Point2 _point_to_screen(const Vector3 &p_point);
|
|
Transform _get_camera_transform() const;
|
|
int get_selected_count() const;
|
|
|
|
Vector3 _get_camera_position() const;
|
|
- Vector3 _get_camera_normal() const;
|
|
Vector3 _get_screen_to_space(const Vector3 &p_vector3);
|
|
|
|
void _select_region();
|
|
@@ -333,39 +364,8 @@ private:
|
|
NAVIGATION_ORBIT,
|
|
NAVIGATION_LOOK
|
|
};
|
|
- enum TransformMode {
|
|
- TRANSFORM_NONE,
|
|
- TRANSFORM_ROTATE,
|
|
- TRANSFORM_TRANSLATE,
|
|
- TRANSFORM_SCALE
|
|
|
|
- };
|
|
- enum TransformPlane {
|
|
- TRANSFORM_VIEW,
|
|
- TRANSFORM_X_AXIS,
|
|
- TRANSFORM_Y_AXIS,
|
|
- TRANSFORM_Z_AXIS,
|
|
- TRANSFORM_YZ,
|
|
- TRANSFORM_XZ,
|
|
- TRANSFORM_XY,
|
|
- };
|
|
-
|
|
- struct EditData {
|
|
- TransformMode mode;
|
|
- TransformPlane plane;
|
|
- Transform original;
|
|
- Vector3 click_ray;
|
|
- Vector3 click_ray_pos;
|
|
- Vector3 center;
|
|
- Vector3 orig_gizmo_pos;
|
|
- int edited_gizmo;
|
|
- Point2 mouse_pos;
|
|
- bool snap;
|
|
- Ref<EditorSpatialGizmo> gizmo;
|
|
- int gizmo_handle;
|
|
- Variant gizmo_initial_value;
|
|
- Vector3 gizmo_initial_pos;
|
|
- } _edit;
|
|
+ EditData _edit;
|
|
|
|
struct Cursor {
|
|
|
|
@@ -451,6 +451,8 @@ public:
|
|
void update_surface() { surface->update(); }
|
|
void update_transform_gizmo_view();
|
|
|
|
+ ViewportContainer *get_viewport_container() const { return viewport_container; }
|
|
+
|
|
void set_can_preview(Camera *p_preview);
|
|
void set_state(const Dictionary &p_state);
|
|
Dictionary get_state() const;
|
|
@@ -466,6 +468,11 @@ public:
|
|
|
|
Viewport *get_viewport_node() { return viewport; }
|
|
Camera *get_camera() { return camera; } // return the default camera object.
|
|
+ float get_gizmo_scale() { return gizmo_scale; };
|
|
+
|
|
+ Vector3 get_camera_normal() const;
|
|
+ Vector3 get_ray_pos(const Vector2 &p_pos) const;
|
|
+ Vector3 get_ray(const Vector2 &p_pos) const;
|
|
|
|
SpatialEditorViewport(SpatialEditor *p_spatial_editor, EditorNode *p_editor, int p_index);
|
|
};
|
|
@@ -545,6 +552,7 @@ public:
|
|
TOOL_MODE_MOVE,
|
|
TOOL_MODE_ROTATE,
|
|
TOOL_MODE_SCALE,
|
|
+ TOOL_MODE_EXTERNAL,
|
|
TOOL_MODE_LIST_SELECT,
|
|
TOOL_LOCK_SELECTED,
|
|
TOOL_UNLOCK_SELECTED,
|
|
@@ -559,7 +567,15 @@ public:
|
|
TOOL_OPT_USE_SNAP,
|
|
TOOL_OPT_OVERRIDE_CAMERA,
|
|
TOOL_OPT_MAX
|
|
+ };
|
|
+
|
|
+ enum ExternalToolMode {
|
|
|
|
+ EX_TOOL_MODE_SELECT,
|
|
+ EX_TOOL_MODE_MOVE,
|
|
+ EX_TOOL_MODE_ROTATE,
|
|
+ EX_TOOL_MODE_SCALE,
|
|
+ EX_TOOL_MAX
|
|
};
|
|
|
|
private:
|
|
@@ -574,6 +590,7 @@ private:
|
|
/////
|
|
|
|
ToolMode tool_mode;
|
|
+ ExternalToolMode external_tool_mode = EX_TOOL_MODE_SELECT;
|
|
|
|
VisualServer::ScenarioDebugMode scenario_debug;
|
|
|
|
@@ -626,6 +643,7 @@ private:
|
|
MENU_TOOL_MOVE,
|
|
MENU_TOOL_ROTATE,
|
|
MENU_TOOL_SCALE,
|
|
+ MENU_TOOL_EXTERNAL,
|
|
MENU_TOOL_LIST_SELECT,
|
|
MENU_TOOL_LOCAL_COORDS,
|
|
MENU_TOOL_USE_SNAP,
|
|
@@ -728,6 +746,8 @@ private:
|
|
|
|
void _refresh_menu_icons();
|
|
|
|
+ Vector<Transform> externals;
|
|
+
|
|
protected:
|
|
void _notification(int p_what);
|
|
//void _gui_input(InputEvent p_event);
|
|
@@ -748,7 +768,11 @@ public:
|
|
Transform get_gizmo_transform() const { return gizmo.transform; }
|
|
bool is_gizmo_visible() const { return gizmo.visible; }
|
|
|
|
+ void set_tool_mode(ToolMode p_tool_mode);
|
|
ToolMode get_tool_mode() const { return tool_mode; }
|
|
+ bool is_tool_external() const { return tool_mode == TOOL_MODE_EXTERNAL; }
|
|
+ ExternalToolMode get_external_tool_mode() const { return external_tool_mode; }
|
|
+ void set_external_tool_mode(ExternalToolMode p_external_tool_mode) { external_tool_mode = p_external_tool_mode; }
|
|
bool are_local_coords_enabled() const { return tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->is_pressed(); }
|
|
bool is_snap_enabled() const { return snap_enabled ^ snap_key_enabled; }
|
|
float get_translate_snap() const;
|
|
@@ -800,6 +824,11 @@ public:
|
|
void edit(Spatial *p_spatial);
|
|
void clear();
|
|
|
|
+ void append_to_externals(Transform p_transform) { externals.push_back(p_transform); }
|
|
+ void append_array_to_externals(Vector<Transform> p_transforms) { externals.append_array(p_transforms); }
|
|
+ void clear_externals() { externals.clear(); }
|
|
+ Vector<Transform> get_externals() const { return externals; }
|
|
+
|
|
SpatialEditor(EditorNode *p_editor);
|
|
~SpatialEditor();
|
|
};
|
|
diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp
|
|
index c60952e5a6..ddecd103f4 100644
|
|
--- a/editor/spatial_editor_gizmos.cpp
|
|
+++ b/editor/spatial_editor_gizmos.cpp
|
|
@@ -32,6 +32,7 @@
|
|
|
|
#include "core/math/geometry.h"
|
|
#include "core/math/quick_hull.h"
|
|
+#include "editor/plugins/skeleton_editor_plugin.h"
|
|
#include "scene/3d/audio_stream_player_3d.h"
|
|
#include "scene/3d/baked_lightmap.h"
|
|
#include "scene/3d/collision_polygon.h"
|
|
@@ -1611,8 +1612,35 @@ void Position3DSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
|
|
|
|
SkeletonSpatialGizmoPlugin::SkeletonSpatialGizmoPlugin() {
|
|
|
|
- Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4));
|
|
- create_material("skeleton_material", gizmo_color);
|
|
+ skeleton_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4));
|
|
+ selected_bone_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/selected_bone", Color(1, 0, 0));
|
|
+ bone_axis_length = EDITOR_DEF("editors/3d_gizmos/gizmo_settings/bone_axis_length", (float)0.015);
|
|
+ create_material("skeleton_material", skeleton_color);
|
|
+ selected_mat = Ref<ShaderMaterial>(memnew(ShaderMaterial));
|
|
+ selected_sh = Ref<Shader>(memnew(Shader));
|
|
+ selected_sh->set_code(" \
|
|
+ shader_type spatial; \
|
|
+ render_mode unshaded; \
|
|
+ uniform vec4 albedo : hint_color = vec4(1,1,1,1); \
|
|
+ uniform sampler2D texture_albedo : hint_albedo; \
|
|
+ uniform float point_size : hint_range(0,128) = 32; \
|
|
+ void vertex() { \
|
|
+ if (!OUTPUT_IS_SRGB) { \
|
|
+ COLOR.rgb = mix( pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb* (1.0 / 12.92), lessThan(COLOR.rgb,vec3(0.04045)) ); \
|
|
+ } \
|
|
+ VERTEX = VERTEX; \
|
|
+ POSITION=PROJECTION_MATRIX*INV_CAMERA_MATRIX*WORLD_MATRIX*vec4(VERTEX.xyz,1.0); \
|
|
+ POSITION.z = mix(POSITION.z, -POSITION.w, 0.998); \
|
|
+ } \
|
|
+ void fragment() { \
|
|
+ vec2 base_uv = UV; \
|
|
+ vec4 albedo_tex = texture(texture_albedo,base_uv); \
|
|
+ albedo_tex *= COLOR; \
|
|
+ if (albedo.a * albedo_tex.a < 0.5) { discard; } \
|
|
+ ALBEDO = albedo.rgb * albedo_tex.rgb; \
|
|
+ } \
|
|
+ ");
|
|
+ selected_mat->set_shader(selected_sh);
|
|
}
|
|
|
|
bool SkeletonSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) {
|
|
@@ -1633,7 +1661,12 @@ void SkeletonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
|
|
|
|
p_gizmo->clear();
|
|
|
|
- Ref<Material> material = get_material("skeleton_material", p_gizmo);
|
|
+ Ref<Material> material;
|
|
+ if (p_gizmo->is_selected()) {
|
|
+ material = selected_mat;
|
|
+ } else {
|
|
+ material = get_material("skeleton_material", p_gizmo);
|
|
+ }
|
|
|
|
Ref<SurfaceTool> surface_tool(memnew(SurfaceTool));
|
|
|
|
@@ -1654,12 +1687,15 @@ void SkeletonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
|
|
|
|
weights.write[0] = 1;
|
|
|
|
+ Color bone_color;
|
|
AABB aabb;
|
|
|
|
- Color bonecolor = Color(1.0, 0.4, 0.4, 0.3);
|
|
- Color rootcolor = Color(0.4, 1.0, 0.4, 0.1);
|
|
-
|
|
for (int i_bone = 0; i_bone < skel->get_bone_count(); i_bone++) {
|
|
+ if (skel->get_bone_parent(i_bone) == skel->get_selected_bone()) {
|
|
+ bone_color = selected_bone_color;
|
|
+ } else {
|
|
+ bone_color = skeleton_color;
|
|
+ }
|
|
|
|
int i = skel->get_process_order(i_bone);
|
|
|
|
@@ -1687,17 +1723,33 @@ void SkeletonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
|
|
Vector3 first;
|
|
Vector3 points[4];
|
|
int pointidx = 0;
|
|
+ Color axis_color[3];
|
|
+ axis_color[0] = Color(1,0,0);
|
|
+ axis_color[1] = Color(0,1,0);
|
|
+ axis_color[2] = Color(0,0,1);
|
|
for (int j = 0; j < 3; j++) {
|
|
|
|
- bones.write[0] = parent;
|
|
- surface_tool->add_bones(bones);
|
|
- surface_tool->add_weights(weights);
|
|
- surface_tool->add_color(rootcolor);
|
|
- surface_tool->add_vertex(v0 - grests[parent].basis[j].normalized() * dist * 0.05);
|
|
- surface_tool->add_bones(bones);
|
|
- surface_tool->add_weights(weights);
|
|
- surface_tool->add_color(rootcolor);
|
|
- surface_tool->add_vertex(v0 + grests[parent].basis[j].normalized() * dist * 0.05);
|
|
+ if (p_gizmo->is_selected()) {
|
|
+ bones.write[0] = i;
|
|
+ surface_tool->add_bones(bones);
|
|
+ surface_tool->add_weights(weights);
|
|
+ surface_tool->add_color(axis_color[j]);
|
|
+ surface_tool->add_vertex(v1);
|
|
+ surface_tool->add_bones(bones);
|
|
+ surface_tool->add_weights(weights);
|
|
+ surface_tool->add_color(axis_color[j]);
|
|
+ surface_tool->add_vertex(v1 + grests[i].basis[j].normalized() * bone_axis_length);
|
|
+ } else {
|
|
+ bones.write[0] = i;
|
|
+ surface_tool->add_bones(bones);
|
|
+ surface_tool->add_weights(weights);
|
|
+ surface_tool->add_color(axis_color[j]);
|
|
+ surface_tool->add_vertex(v1 - grests[i].basis[j].normalized() * dist * 0.05);
|
|
+ surface_tool->add_bones(bones);
|
|
+ surface_tool->add_weights(weights);
|
|
+ surface_tool->add_color(axis_color[j]);
|
|
+ surface_tool->add_vertex(v1 + grests[i].basis[j].normalized() * dist * 0.05);
|
|
+ }
|
|
|
|
if (j == closest)
|
|
continue;
|
|
@@ -1720,22 +1772,22 @@ void SkeletonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
|
|
bones.write[0] = parent;
|
|
surface_tool->add_bones(bones);
|
|
surface_tool->add_weights(weights);
|
|
- surface_tool->add_color(bonecolor);
|
|
+ surface_tool->add_color(bone_color);
|
|
surface_tool->add_vertex(v0);
|
|
surface_tool->add_bones(bones);
|
|
surface_tool->add_weights(weights);
|
|
- surface_tool->add_color(bonecolor);
|
|
+ surface_tool->add_color(bone_color);
|
|
surface_tool->add_vertex(point);
|
|
|
|
bones.write[0] = parent;
|
|
surface_tool->add_bones(bones);
|
|
surface_tool->add_weights(weights);
|
|
- surface_tool->add_color(bonecolor);
|
|
+ surface_tool->add_color(bone_color);
|
|
surface_tool->add_vertex(point);
|
|
bones.write[0] = i;
|
|
surface_tool->add_bones(bones);
|
|
surface_tool->add_weights(weights);
|
|
- surface_tool->add_color(bonecolor);
|
|
+ surface_tool->add_color(bone_color);
|
|
surface_tool->add_vertex(v1);
|
|
points[pointidx++] = point;
|
|
}
|
|
@@ -1747,11 +1799,11 @@ void SkeletonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
|
|
bones.write[0] = parent;
|
|
surface_tool->add_bones(bones);
|
|
surface_tool->add_weights(weights);
|
|
- surface_tool->add_color(bonecolor);
|
|
+ surface_tool->add_color(bone_color);
|
|
surface_tool->add_vertex(points[j]);
|
|
surface_tool->add_bones(bones);
|
|
surface_tool->add_weights(weights);
|
|
- surface_tool->add_color(bonecolor);
|
|
+ surface_tool->add_color(bone_color);
|
|
surface_tool->add_vertex(points[(j + 1) % 4]);
|
|
}
|
|
|
|
diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h
|
|
index 58598d1ff3..36070116d9 100644
|
|
--- a/editor/spatial_editor_gizmos.h
|
|
+++ b/editor/spatial_editor_gizmos.h
|
|
@@ -137,6 +137,11 @@ public:
|
|
class SkeletonSpatialGizmoPlugin : public EditorSpatialGizmoPlugin {
|
|
|
|
GDCLASS(SkeletonSpatialGizmoPlugin, EditorSpatialGizmoPlugin);
|
|
+ Color skeleton_color = Color(1, 0.8, 0.4);
|
|
+ Color selected_bone_color = Color(1, 0, 0);
|
|
+ float bone_axis_length = 0.015;
|
|
+ Ref<ShaderMaterial> selected_mat;
|
|
+ Ref<Shader> selected_sh;
|
|
|
|
public:
|
|
bool has_gizmo(Spatial *p_spatial);
|
|
diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h
|
|
index 941f3c52f4..6de4061ca9 100644
|
|
--- a/modules/gridmap/grid_map_editor_plugin.h
|
|
+++ b/modules/gridmap/grid_map_editor_plugin.h
|
|
@@ -261,7 +261,7 @@ protected:
|
|
void _notification(int p_what);
|
|
|
|
public:
|
|
- virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { return grid_map_editor->forward_spatial_input_event(p_camera, p_event); }
|
|
+ virtual bool forward_spatial_gui_input(int p_index, Camera *p_camera, const Ref<InputEvent> &p_event) { return grid_map_editor->forward_spatial_input_event(p_camera, p_event); }
|
|
virtual String get_name() const { return "GridMap"; }
|
|
bool has_main_screen() const { return false; }
|
|
virtual void edit(Object *p_object);
|
|
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
|
|
index ec6d4dceef..2c77bec64a 100644
|
|
--- a/scene/3d/skeleton.cpp
|
|
+++ b/scene/3d/skeleton.cpp
|
|
@@ -158,17 +158,17 @@ bool Skeleton::_get(const StringName &p_path, Variant &r_ret) const {
|
|
|
|
return true;
|
|
}
|
|
-void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const {
|
|
|
|
+void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const {
|
|
for (int i = 0; i < bones.size(); i++) {
|
|
|
|
String prep = "bones/" + itos(i) + "/";
|
|
- p_list->push_back(PropertyInfo(Variant::STRING, prep + "name"));
|
|
- p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1"));
|
|
- p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest"));
|
|
- p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled"));
|
|
+ p_list->push_back(PropertyInfo(Variant::STRING, prep + "name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
|
|
+ p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1", PROPERTY_USAGE_NOEDITOR));
|
|
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
|
|
+ p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
|
|
p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
|
|
- p_list->push_back(PropertyInfo(Variant::ARRAY, prep + "bound_children"));
|
|
+ p_list->push_back(PropertyInfo(Variant::ARRAY, prep + "bound_children", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
|
|
}
|
|
}
|
|
|
|
@@ -375,7 +375,11 @@ void Skeleton::_notification(int p_what) {
|
|
}
|
|
|
|
dirty = false;
|
|
- emit_signal("skeleton_updated");
|
|
+
|
|
+#ifdef TOOLS_ENABLED
|
|
+ emit_signal("pose_updated");
|
|
+#endif // TOOLS_ENABLED
|
|
+
|
|
} break;
|
|
}
|
|
}
|
|
@@ -624,7 +628,6 @@ int Skeleton::get_process_order(int p_idx) {
|
|
}
|
|
|
|
void Skeleton::localize_rests() {
|
|
-
|
|
_update_process_order();
|
|
|
|
for (int i = bones.size() - 1; i >= 0; i--) {
|
|
@@ -849,6 +852,16 @@ Ref<SkinReference> Skeleton::register_skin(const Ref<Skin> &p_skin) {
|
|
return skin_ref;
|
|
}
|
|
|
|
+void Skeleton::set_selected_bone(int p_bone) {
|
|
+ selected_bone = p_bone;
|
|
+ update_gizmo();
|
|
+ return;
|
|
+}
|
|
+
|
|
+int Skeleton::get_selected_bone() const {
|
|
+ return selected_bone;
|
|
+}
|
|
+
|
|
void Skeleton::_bind_methods() {
|
|
|
|
ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton::add_bone);
|
|
@@ -897,7 +910,10 @@ void Skeleton::_bind_methods() {
|
|
|
|
#endif // _3D_DISABLED
|
|
|
|
+#ifdef TOOLS_ENABLED
|
|
+ ADD_SIGNAL(MethodInfo("pose_updated"));
|
|
ADD_SIGNAL(MethodInfo("skeleton_updated"));
|
|
+#endif // TOOLS_ENABLED
|
|
|
|
BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
|
|
}
|
|
@@ -916,3 +932,8 @@ Skeleton::~Skeleton() {
|
|
E->get()->skeleton_node = nullptr;
|
|
}
|
|
}
|
|
+
|
|
+Vector<int> Skeleton::get_bone_process_order() {
|
|
+ _update_process_order();
|
|
+ return process_order;
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
|
|
index fb5d1367d4..73df15ec98 100644
|
|
--- a/scene/3d/skeleton.h
|
|
+++ b/scene/3d/skeleton.h
|
|
@@ -144,6 +144,8 @@ private:
|
|
|
|
void _update_process_order();
|
|
|
|
+ int selected_bone = -1;
|
|
+
|
|
protected:
|
|
bool _get(const StringName &p_path, Variant &r_ret) const;
|
|
bool _set(const StringName &p_path, const Variant &p_value);
|
|
@@ -200,9 +202,13 @@ public:
|
|
|
|
void localize_rests(); // used for loaders and tools
|
|
int get_process_order(int p_idx);
|
|
+ Vector<int> get_bone_process_order();
|
|
|
|
Ref<SkinReference> register_skin(const Ref<Skin> &p_skin);
|
|
|
|
+ void set_selected_bone(int p_bone);
|
|
+ int get_selected_bone() const;
|
|
+
|
|
#ifndef _3D_DISABLED
|
|
// Physical bone API
|
|
|
|
--
|
|
2.30.1
|
|
|