Implemented SkeletonEditorGizmo

Co-authored-by: Lyuma <xn.lyuma@gmail.com>
This commit is contained in:
Silc Renew 2021-02-04 17:20:26 +09:00
parent ce0268a0c1
commit f2e9867e9f
36 changed files with 1334 additions and 418 deletions

View File

@ -96,7 +96,7 @@
</description>
</method>
<method name="_forward_3d_gui_input" qualifiers="virtual">
<return type="bool" />
<return type="int" />
<argument index="0" name="viewport_camera" type="Camera3D" />
<argument index="1" name="event" type="InputEvent" />
<description>
@ -105,13 +105,13 @@
[gdscript]
# Prevents the InputEvent to reach other Editor classes.
func _forward_3d_gui_input(camera, event):
return true
return EditorPlugin.AFTER_GUI_INPUT_STOP
[/gdscript]
[csharp]
// Prevents the InputEvent to reach other Editor classes.
public override bool _Forward3dGuiInput(Camera3D camera, InputEvent @event)
{
return true;
return EditorPlugin.AFTER_GUI_INPUT_STOP;
}
[/csharp]
[/codeblocks]
@ -185,12 +185,12 @@
Called when there is a root node in the current edited scene, [method _handles] is implemented and an [InputEvent] happens in the 2D 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:
[codeblocks]
[gdscript]
# Prevents the InputEvent to reach other Editor classes
# Prevents the InputEvent to reach other Editor classes.
func _forward_canvas_gui_input(event):
return true
[/gdscript]
[csharp]
// Prevents the InputEvent to reach other Editor classes
// Prevents the InputEvent to reach other Editor classes.
public override bool ForwardCanvasGuiInput(InputEvent @event)
{
return true;
@ -202,13 +202,18 @@
[gdscript]
# Consumes InputEventMouseMotion and forwards other InputEvent types.
func _forward_canvas_gui_input(event):
return event is InputEventMouseMotion
if (event is InputEventMouseMotion):
return true
return false
[/gdscript]
[csharp]
// Consumes InputEventMouseMotion and forwards other InputEvent types.
public override bool ForwardCanvasGuiInput(InputEvent @event)
{
return @event is InputEventMouseMotion;
if (@event is InputEventMouseMotion) {
return true;
}
return false
}
[/csharp]
[/codeblocks]

View File

@ -212,6 +212,15 @@
Sets whether the node notifies about its global and local transformation changes. [Node3D] will not propagate this by default, unless it is in the editor context and it has a valid gizmo.
</description>
</method>
<method name="set_subgizmo_selection">
<return type="void" />
<argument index="0" name="gizmo" type="Node3DGizmo" />
<argument index="1" name="id" type="int" />
<argument index="2" name="transform" type="Transform3D" />
<description>
Set subgizmo selection for this node in the editor.
</description>
</method>
<method name="show">
<return type="void" />
<description>

View File

@ -189,6 +189,13 @@
This is helper function to make using [method Transform3D.looking_at] easier with bone poses.
</description>
</method>
<method name="is_bone_enabled" qualifiers="const">
<return type="bool" />
<argument index="0" name="bone_idx" type="int" />
<description>
Returns whether the bone pose for the bone at [code]bone_idx[/code] is enabled.
</description>
</method>
<method name="is_bone_rest_disabled" qualifiers="const">
<return type="bool" />
<argument index="0" name="bone_idx" type="int" />
@ -282,6 +289,14 @@
Disables the rest pose for the bone at [code]bone_idx[/code] if [code]true[/code], enables the bone rest if [code]false[/code].
</description>
</method>
<method name="set_bone_enabled">
<return type="void" />
<argument index="0" name="bone_idx" type="int" />
<argument index="1" name="enabled" type="bool" default="true" />
<description>
Disables the pose for the bone at [code]bone_idx[/code] if [code]false[/code], enables the bone pose if [code]true[/code].
</description>
</method>
<method name="set_bone_global_pose_override">
<return type="void" />
<argument index="0" name="bone_idx" type="int" />
@ -365,8 +380,15 @@
<members>
<member name="animate_physical_bones" type="bool" setter="set_animate_physical_bones" getter="get_animate_physical_bones" default="true">
</member>
<member name="show_rest_only" type="bool" setter="set_show_rest_only" getter="is_show_rest_only" default="false">
</member>
</members>
<signals>
<signal name="bone_enabled_changed">
<argument index="0" name="bone_idx" type="int" />
<description>
</description>
</signal>
<signal name="bone_pose_changed">
<argument index="0" name="bone_idx" type="int" />
<description>
@ -377,6 +399,10 @@
<description>
</description>
</signal>
<signal name="show_rest_only_changed">
<description>
</description>
</signal>
</signals>
<constants>
<constant name="NOTIFICATION_UPDATE_SKELETON" value="50">

View File

@ -3359,7 +3359,7 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
insert_data.push_back(p_id);
bool reset_allowed = true;
AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player();
AnimationPlayer *player = AnimationPlayerEditor::get_singleton()->get_player();
if (player->has_animation("RESET") && player->get_animation("RESET") == animation) {
// Avoid messing with the reset animation itself
reset_allowed = false;
@ -3528,6 +3528,31 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_
_query_insert(id);
}
bool AnimationTrackEditor::has_transform_track(Node3D *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;
}
int track_id = animation->find_track(path);
if (track_id >= 0) {
if (animation->track_get_type(track_id) == Animation::TYPE_TRANSFORM3D) {
return true;
}
}
return false;
}
void AnimationTrackEditor::_insert_animation_key(NodePath p_path, const Variant &p_value) {
String path = p_path;
@ -3571,7 +3596,7 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p
String path = root->get_path_to(node);
if (Object::cast_to<AnimationPlayer>(node) && p_property == "current_animation") {
if (node == AnimationPlayerEditor::singleton->get_player()) {
if (node == AnimationPlayerEditor::get_singleton()->get_player()) {
EditorNode::get_singleton()->show_warning(TTR("AnimationPlayer can't animate itself, only other players."));
return;
}
@ -3672,7 +3697,7 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari
String path = root->get_path_to(node);
if (Object::cast_to<AnimationPlayer>(node) && p_property == "current_animation") {
if (node == AnimationPlayerEditor::singleton->get_player()) {
if (node == AnimationPlayerEditor::get_singleton()->get_player()) {
EditorNode::get_singleton()->show_warning(TTR("AnimationPlayer can't animate itself, only other players."));
return;
}
@ -3752,7 +3777,7 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari
}
Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() {
AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player();
AnimationPlayer *player = AnimationPlayerEditor::get_singleton()->get_player();
if (player->has_animation("RESET")) {
return player->get_animation("RESET");
} else {
@ -3760,9 +3785,9 @@ Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() {
reset_anim.instantiate();
reset_anim->set_length(ANIM_MIN_LENGTH);
undo_redo->add_do_method(player, "add_animation", "RESET", reset_anim);
undo_redo->add_do_method(AnimationPlayerEditor::singleton, "_animation_player_changed", player);
undo_redo->add_do_method(AnimationPlayerEditor::get_singleton(), "_animation_player_changed", player);
undo_redo->add_undo_method(player, "remove_animation", "RESET");
undo_redo->add_undo_method(AnimationPlayerEditor::singleton, "_animation_player_changed", player);
undo_redo->add_undo_method(AnimationPlayerEditor::get_singleton(), "_animation_player_changed", player);
return reset_anim;
}
}
@ -4446,7 +4471,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
return;
}
if (node == AnimationPlayerEditor::singleton->get_player()) {
if (node == AnimationPlayerEditor::get_singleton()->get_player()) {
EditorNode::get_singleton()->show_warning(TTR("AnimationPlayer can't animate itself, only other players."));
return;
}
@ -5173,7 +5198,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
}
void AnimationTrackEditor::_edit_menu_about_to_popup() {
AnimationPlayer *player = AnimationPlayerEditor::singleton->get_player();
AnimationPlayer *player = AnimationPlayerEditor::get_singleton()->get_player();
edit->get_popup()->set_item_disabled(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), !player->can_apply_reset());
}
@ -5517,7 +5542,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
goto_prev_step(false);
} break;
case EDIT_APPLY_RESET: {
AnimationPlayerEditor::singleton->get_player()->apply_reset(true);
AnimationPlayerEditor::get_singleton()->get_player()->apply_reset(true);
} break;
case EDIT_OPTIMIZE_ANIMATION: {
@ -5537,9 +5562,9 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
case EDIT_CLEAN_UP_ANIMATION_CONFIRM: {
if (cleanup_all->is_pressed()) {
List<StringName> names;
AnimationPlayerEditor::singleton->get_player()->get_animation_list(&names);
AnimationPlayerEditor::get_singleton()->get_player()->get_animation_list(&names);
for (const StringName &E : names) {
_cleanup_animation(AnimationPlayerEditor::singleton->get_player()->get_animation(E));
_cleanup_animation(AnimationPlayerEditor::get_singleton()->get_player()->get_animation(E));
}
} else {
_cleanup_animation(animation);

View File

@ -531,6 +531,7 @@ public:
void insert_node_value_key(Node *p_node, const String &p_property, const Variant &p_value, bool p_only_if_exists = false);
void insert_value_key(const String &p_property, const Variant &p_value, bool p_advance);
void insert_transform_key(Node3D *p_node, const String &p_sub, const Transform3D &p_xform);
bool has_transform_track(Node3D *p_node, const String &p_sub);
void show_select_node_warning(bool p_show);

View File

@ -6930,7 +6930,7 @@ EditorNode::EditorNode() {
add_child(editor_interface);
//more visually meaningful to have this later
raise_bottom_panel_item(AnimationPlayerEditor::singleton);
raise_bottom_panel_item(AnimationPlayerEditor::get_singleton());
add_editor_plugin(VersionControlEditorPlugin::get_singleton());
add_editor_plugin(memnew(ShaderEditorPlugin(this)));
@ -7204,20 +7204,24 @@ bool EditorPluginList::forward_gui_input(const Ref<InputEvent> &p_event) {
return discard;
}
bool EditorPluginList::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled) {
bool discard = false;
EditorPlugin::AfterGUIInput EditorPluginList::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled) {
EditorPlugin::AfterGUIInput after = EditorPlugin::AFTER_GUI_INPUT_PASS;
for (int i = 0; i < plugins_list.size(); i++) {
if ((!serve_when_force_input_enabled) && plugins_list[i]->is_input_event_forwarding_always_enabled()) {
continue;
}
if (plugins_list[i]->forward_spatial_gui_input(p_camera, p_event)) {
discard = true;
EditorPlugin::AfterGUIInput current_after = plugins_list[i]->forward_spatial_gui_input(p_camera, p_event);
if (current_after == EditorPlugin::AFTER_GUI_INPUT_STOP) {
after = EditorPlugin::AFTER_GUI_INPUT_STOP;
}
if (after != EditorPlugin::AFTER_GUI_INPUT_STOP && current_after == EditorPlugin::AFTER_GUI_INPUT_DESELECT) {
after = EditorPlugin::AFTER_GUI_INPUT_DESELECT;
}
}
return discard;
return after;
}
void EditorPluginList::forward_canvas_draw_over_viewport(Control *p_overlay) {

View File

@ -942,7 +942,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(Camera3D *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled);
EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *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);

View File

@ -593,14 +593,14 @@ int EditorPlugin::update_overlays() const {
}
}
bool EditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
bool success;
EditorPlugin::AfterGUIInput EditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
int success;
if (GDVIRTUAL_CALL(_forward_3d_gui_input, p_camera, p_event, success)) {
return success;
return static_cast<EditorPlugin::AfterGUIInput>(success);
}
return false;
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
void EditorPlugin::forward_spatial_draw_over_viewport(Control *p_overlay) {

View File

@ -151,7 +151,7 @@ protected:
GDVIRTUAL1R(bool, _forward_canvas_gui_input, Ref<InputEvent>)
GDVIRTUAL1(_forward_canvas_draw_over_viewport, Control *)
GDVIRTUAL1(_forward_canvas_force_draw_over_viewport, Control *)
GDVIRTUAL2R(bool, _forward_3d_gui_input, Camera3D *, Ref<InputEvent>)
GDVIRTUAL2R(int, _forward_3d_gui_input, Camera3D *, Ref<InputEvent>)
GDVIRTUAL1(_forward_3d_draw_over_viewport, Control *)
GDVIRTUAL1(_forward_3d_force_draw_over_viewport, Control *)
GDVIRTUAL0RC(String, _get_plugin_name)
@ -200,6 +200,12 @@ public:
DOCK_SLOT_MAX
};
enum AfterGUIInput {
AFTER_GUI_INPUT_PASS,
AFTER_GUI_INPUT_STOP,
AFTER_GUI_INPUT_DESELECT
};
//TODO: send a resource for editing to the editor node?
void add_control_to_container(CustomControlContainer p_location, Control *p_control);
@ -228,7 +234,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(Camera3D *p_camera, const Ref<InputEvent> &p_event);
virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *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);

View File

@ -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("Sky");
exceptions.insert("EditorControlAnchor");

View File

@ -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>

After

Width:  |  Height:  |  Size: 170 B

View File

@ -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>

After

Width:  |  Height:  |  Size: 797 B

View File

@ -383,7 +383,7 @@ void InspectorDock::_menu_expandall() {
}
void InspectorDock::_property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance) {
AnimationPlayerEditor::singleton->get_track_editor()->insert_value_key(p_keyed, p_value, p_advance);
AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_value_key(p_keyed, p_value, p_advance);
}
void InspectorDock::_transform_keyed(Object *sp, const String &p_sub, const Transform3D &p_key) {
@ -391,7 +391,7 @@ void InspectorDock::_transform_keyed(Object *sp, const String &p_sub, const Tran
if (!s) {
return;
}
AnimationPlayerEditor::singleton->get_track_editor()->insert_transform_key(s, p_sub, p_key);
AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_transform_key(s, p_sub, p_key);
}
void InspectorDock::_warning_pressed() {
@ -545,7 +545,7 @@ void InspectorDock::go_back() {
void InspectorDock::update_keying() {
bool valid = false;
if (AnimationPlayerEditor::singleton->get_track_editor()->has_keying()) {
if (AnimationPlayerEditor::get_singleton()->get_track_editor()->has_keying()) {
EditorHistory *editor_history = EditorNode::get_singleton()->get_editor_history();
if (editor_history->get_path_size() >= 1) {
Object *obj = ObjectDB::get_instance(editor_history->get_path_object(0));

View File

@ -298,7 +298,7 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
autoplay->set_pressed(current == player->get_autoplay());
AnimationPlayerEditor::singleton->get_track_editor()->update_keying();
AnimationPlayerEditor::get_singleton()->get_track_editor()->update_keying();
EditorNode::get_singleton()->update_keying();
_animation_key_editor_seek(timeline_position, false);
}
@ -826,7 +826,7 @@ void AnimationPlayerEditor::_update_player() {
pin->set_disabled(player == nullptr);
if (!player) {
AnimationPlayerEditor::singleton->get_track_editor()->update_keying();
AnimationPlayerEditor::get_singleton()->get_track_editor()->update_keying();
EditorNode::get_singleton()->update_keying();
return;
}

View File

@ -128,6 +128,7 @@ class AnimationPlayerEditor : public VBoxContainer {
bool updating_blends;
AnimationTrackEditor *track_editor;
static AnimationPlayerEditor *singleton;
// Onion skinning.
struct {
@ -226,7 +227,8 @@ protected:
public:
AnimationPlayer *get_player() const;
static AnimationPlayerEditor *singleton;
static AnimationPlayerEditor *get_singleton() { return singleton; }
bool is_pinned() const { return pin->is_pressed(); }
void unpin() { pin->set_pressed(false); }

View File

@ -513,7 +513,7 @@ Object *CanvasItemEditor::_get_editor_data(Object *p_what) {
}
void CanvasItemEditor::_keying_changed() {
if (AnimationPlayerEditor::singleton->get_track_editor()->is_visible_in_tree()) {
if (AnimationPlayerEditor::get_singleton()->get_track_editor()->is_visible_in_tree()) {
animation_hb->show();
} else {
animation_hb->hide();
@ -3816,7 +3816,7 @@ void CanvasItemEditor::_notification(int p_what) {
select_sb->set_default_margin(Side(i), 4);
}
AnimationPlayerEditor::singleton->get_track_editor()->connect("visibility_changed", callable_mp(this, &CanvasItemEditor::_keying_changed));
AnimationPlayerEditor::get_singleton()->get_track_editor()->connect("visibility_changed", callable_mp(this, &CanvasItemEditor::_keying_changed));
_keying_changed();
} else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
@ -4277,13 +4277,13 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation,
Node2D *n2d = Object::cast_to<Node2D>(canvas_item);
if (key_pos && p_location) {
AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "position", n2d->get_position(), p_on_existing);
AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(n2d, "position", n2d->get_position(), p_on_existing);
}
if (key_rot && p_rotation) {
AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "rotation", n2d->get_rotation(), p_on_existing);
AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(n2d, "rotation", n2d->get_rotation(), p_on_existing);
}
if (key_scale && p_scale) {
AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "scale", n2d->get_scale(), p_on_existing);
AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(n2d, "scale", n2d->get_scale(), p_on_existing);
}
if (n2d->has_meta("_edit_bone_") && n2d->get_parent_item()) {
@ -4309,13 +4309,13 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation,
if (has_chain && ik_chain.size()) {
for (Node2D *&F : ik_chain) {
if (key_pos) {
AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F, "position", F->get_position(), p_on_existing);
AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(F, "position", F->get_position(), p_on_existing);
}
if (key_rot) {
AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F, "rotation", F->get_rotation(), p_on_existing);
AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(F, "rotation", F->get_rotation(), p_on_existing);
}
if (key_scale) {
AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F, "scale", F->get_scale(), p_on_existing);
AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(F, "scale", F->get_scale(), p_on_existing);
}
}
}
@ -4325,13 +4325,13 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation,
Control *ctrl = Object::cast_to<Control>(canvas_item);
if (key_pos) {
AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_position", ctrl->get_position(), p_on_existing);
AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(ctrl, "rect_position", ctrl->get_position(), p_on_existing);
}
if (key_rot) {
AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_rotation", ctrl->get_rotation(), p_on_existing);
AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(ctrl, "rect_rotation", ctrl->get_rotation(), p_on_existing);
}
if (key_scale) {
AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_size", ctrl->get_size(), p_on_existing);
AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(ctrl, "rect_size", ctrl->get_size(), p_on_existing);
}
}
}
@ -4771,7 +4771,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
}
/*
if (key_scale)
AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl,"rect/size",ctrl->get_size());
AnimationPlayerEditor::get_singleton()->get_track_editor()->insert_node_value_key(ctrl,"rect/size",ctrl->get_size());
*/
}
}

View File

@ -103,9 +103,9 @@ void CollisionPolygon3DEditor::_wip_close() {
undo_redo->commit_action();
}
bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
EditorPlugin::AfterGUIInput CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
if (!node) {
return false;
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
Transform3D gt = node->get_global_transform();
@ -124,7 +124,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
Vector3 spoint;
if (!p.intersects_ray(ray_from, ray_dir, &spoint)) {
return false;
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
spoint = gi.xform(spoint);
@ -151,19 +151,19 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
snap_ignore = false;
_polygon_draw();
edited_point = 1;
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else {
if (wip.size() > 1 && p_camera->unproject_position(gt.xform(Vector3(wip[0].x, wip[0].y, depth))).distance_to(gpoint) < grab_threshold) {
//wip closed
_wip_close();
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else {
wip.push_back(cpoint);
edited_point = wip.size();
snap_ignore = false;
_polygon_draw();
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
} else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed() && wip_active) {
@ -184,7 +184,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
undo_redo->add_do_method(this, "_polygon_draw");
undo_redo->add_undo_method(this, "_polygon_draw");
undo_redo->commit_action();
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
//search edges
@ -219,7 +219,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
_polygon_draw();
snap_ignore = true;
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
} else {
//look for points to move
@ -244,7 +244,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
edited_point_pos = poly[closest_idx];
_polygon_draw();
snap_ignore = false;
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
} else {
@ -253,7 +253,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
if (edited_point != -1) {
//apply
ERR_FAIL_INDEX_V(edited_point, poly.size(), false);
ERR_FAIL_INDEX_V(edited_point, poly.size(), EditorPlugin::AFTER_GUI_INPUT_PASS);
poly.write[edited_point] = edited_point_pos;
undo_redo->create_action(TTR("Edit Poly"));
undo_redo->add_do_method(node, "set_polygon", poly);
@ -263,7 +263,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
undo_redo->commit_action();
edited_point = -1;
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
}
@ -290,7 +290,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
undo_redo->add_do_method(this, "_polygon_draw");
undo_redo->add_undo_method(this, "_polygon_draw");
undo_redo->commit_action();
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
@ -310,7 +310,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
Vector3 spoint;
if (!p.intersects_ray(ray_from, ray_dir, &spoint)) {
return false;
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
spoint = gi.xform(spoint);
@ -332,7 +332,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
}
}
return false;
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
float CollisionPolygon3DEditor::_get_depth() {

View File

@ -88,7 +88,7 @@ protected:
static void _bind_methods();
public:
virtual bool forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event);
virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event);
void edit(Node *p_collision_polygon);
CollisionPolygon3DEditor(EditorNode *p_editor);
~CollisionPolygon3DEditor();
@ -101,7 +101,7 @@ class Polygon3DEditorPlugin : public EditorPlugin {
EditorNode *editor;
public:
virtual bool forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return collision_polygon_editor->forward_spatial_gui_input(p_camera, p_event); }
virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return collision_polygon_editor->forward_spatial_gui_input(p_camera, p_event); }
virtual String get_name() const override { return "Polygon3DEditor"; }
bool has_main_screen() const override { return false; }

View File

@ -2070,169 +2070,6 @@ void Position3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_collision_segments(cursor_points);
}
/////
Skeleton3DGizmoPlugin::Skeleton3DGizmoPlugin() {
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4));
create_material("skeleton_material", gizmo_color);
}
bool Skeleton3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<Skeleton3D>(p_spatial) != nullptr;
}
String Skeleton3DGizmoPlugin::get_gizmo_name() const {
return "Skeleton3D";
}
int Skeleton3DGizmoPlugin::get_priority() const {
return -1;
}
void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Skeleton3D *skel = Object::cast_to<Skeleton3D>(p_gizmo->get_spatial_node());
p_gizmo->clear();
Ref<Material> material = get_material("skeleton_material", p_gizmo);
Ref<SurfaceTool> surface_tool(memnew(SurfaceTool));
surface_tool->begin(Mesh::PRIMITIVE_LINES);
surface_tool->set_material(material);
LocalVector<Transform3D> grests;
grests.resize(skel->get_bone_count());
LocalVector<int> bones;
LocalVector<float> weights;
bones.resize(4);
weights.resize(4);
for (int i = 0; i < 4; i++) {
bones[i] = 0;
weights[i] = 0;
}
weights[0] = 1;
AABB aabb;
Color bonecolor = Color(1.0, 0.4, 0.4, 0.3);
Color rootcolor = Color(0.4, 1.0, 0.4, 0.1);
LocalVector<int> bones_to_process;
bones_to_process = skel->get_parentless_bones();
while (bones_to_process.size() > 0) {
int current_bone_idx = bones_to_process[0];
bones_to_process.erase(current_bone_idx);
LocalVector<int> child_bones_vector;
child_bones_vector = skel->get_bone_children(current_bone_idx);
int child_bones_size = child_bones_vector.size();
if (skel->get_bone_parent(current_bone_idx) < 0) {
grests[current_bone_idx] = skel->get_bone_rest(current_bone_idx);
}
for (int i = 0; i < child_bones_size; i++) {
int child_bone_idx = child_bones_vector[i];
grests[child_bone_idx] = grests[current_bone_idx] * skel->get_bone_rest(child_bone_idx);
Vector3 v0 = grests[current_bone_idx].origin;
Vector3 v1 = grests[child_bone_idx].origin;
Vector3 d = (v1 - v0).normalized();
real_t dist = v0.distance_to(v1);
// Find closest axis.
int closest = -1;
real_t closest_d = 0.0;
for (int j = 0; j < 3; j++) {
real_t dp = Math::abs(grests[current_bone_idx].basis[j].normalized().dot(d));
if (j == 0 || dp > closest_d) {
closest = j;
}
}
// Find closest other.
Vector3 first;
Vector3 points[4];
int point_idx = 0;
for (int j = 0; j < 3; j++) {
bones[0] = current_bone_idx;
surface_tool->set_bones(bones);
surface_tool->set_weights(weights);
surface_tool->set_color(rootcolor);
surface_tool->add_vertex(v0 - grests[current_bone_idx].basis[j].normalized() * dist * 0.05);
surface_tool->set_bones(bones);
surface_tool->set_weights(weights);
surface_tool->set_color(rootcolor);
surface_tool->add_vertex(v0 + grests[current_bone_idx].basis[j].normalized() * dist * 0.05);
if (j == closest) {
continue;
}
Vector3 axis;
if (first == Vector3()) {
axis = d.cross(d.cross(grests[current_bone_idx].basis[j])).normalized();
first = axis;
} else {
axis = d.cross(first).normalized();
}
for (int k = 0; k < 2; k++) {
if (k == 1) {
axis = -axis;
}
Vector3 point = v0 + d * dist * 0.2;
point += axis * dist * 0.1;
bones[0] = current_bone_idx;
surface_tool->set_bones(bones);
surface_tool->set_weights(weights);
surface_tool->set_color(bonecolor);
surface_tool->add_vertex(v0);
surface_tool->set_bones(bones);
surface_tool->set_weights(weights);
surface_tool->set_color(bonecolor);
surface_tool->add_vertex(point);
bones[0] = current_bone_idx;
surface_tool->set_bones(bones);
surface_tool->set_weights(weights);
surface_tool->set_color(bonecolor);
surface_tool->add_vertex(point);
bones[0] = child_bone_idx;
surface_tool->set_bones(bones);
surface_tool->set_weights(weights);
surface_tool->set_color(bonecolor);
surface_tool->add_vertex(v1);
points[point_idx++] = point;
}
}
SWAP(points[1], points[2]);
for (int j = 0; j < 4; j++) {
bones[0] = current_bone_idx;
surface_tool->set_bones(bones);
surface_tool->set_weights(weights);
surface_tool->set_color(bonecolor);
surface_tool->add_vertex(points[j]);
surface_tool->set_bones(bones);
surface_tool->set_weights(weights);
surface_tool->set_color(bonecolor);
surface_tool->add_vertex(points[(j + 1) % 4]);
}
// Add the bone's children to the list of bones to be processed.
bones_to_process.push_back(child_bones_vector[i]);
}
}
Ref<ArrayMesh> m = surface_tool->commit();
p_gizmo->add_mesh(m, Ref<Material>(), Transform3D(), skel->register_skin(Ref<Skin>()));
}
////
PhysicalBone3DGizmoPlugin::PhysicalBone3DGizmoPlugin() {

View File

@ -332,18 +332,6 @@ public:
Position3DGizmoPlugin();
};
class Skeleton3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(Skeleton3DGizmoPlugin, EditorNode3DGizmoPlugin);
public:
bool has_gizmo(Node3D *p_spatial) override;
String get_gizmo_name() const override;
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
Skeleton3DGizmoPlugin();
};
class PhysicalBone3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(PhysicalBone3DGizmoPlugin, EditorNode3DGizmoPlugin);

View File

@ -1291,24 +1291,31 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
return; //do NONE
}
EditorPlugin::AfterGUIInput after = EditorPlugin::AFTER_GUI_INPUT_PASS;
{
EditorNode *en = editor;
EditorPluginList *force_input_forwarding_list = en->get_editor_plugins_force_input_forwarding();
if (!force_input_forwarding_list->is_empty()) {
bool discard = force_input_forwarding_list->forward_spatial_gui_input(camera, p_event, true);
if (discard) {
EditorPlugin::AfterGUIInput discard = force_input_forwarding_list->forward_spatial_gui_input(camera, p_event, true);
if (discard == EditorPlugin::AFTER_GUI_INPUT_STOP) {
return;
}
if (discard == EditorPlugin::AFTER_GUI_INPUT_DESELECT) {
after = EditorPlugin::AFTER_GUI_INPUT_DESELECT;
}
}
}
{
EditorNode *en = editor;
EditorPluginList *over_plugin_list = en->get_editor_plugins_over();
if (!over_plugin_list->is_empty()) {
bool discard = over_plugin_list->forward_spatial_gui_input(camera, p_event, false);
if (discard) {
EditorPlugin::AfterGUIInput discard = over_plugin_list->forward_spatial_gui_input(camera, p_event, false);
if (discard == EditorPlugin::AFTER_GUI_INPUT_STOP) {
return;
}
if (discard == EditorPlugin::AFTER_GUI_INPUT_DESELECT) {
after = EditorPlugin::AFTER_GUI_INPUT_DESELECT;
}
}
}
@ -1573,6 +1580,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
break;
}
if (after != EditorPlugin::AFTER_GUI_INPUT_DESELECT) {
clicked = _select_ray(b->get_position());
//clicking is always deferred to either move or release
@ -1585,6 +1593,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
cursor.region_begin = b->get_position();
cursor.region_end = b->get_position();
}
}
surface->update();
} else {
@ -1594,6 +1603,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
break;
}
if (after != EditorPlugin::AFTER_GUI_INPUT_DESELECT) {
if (clicked.is_valid()) {
_select_clicked(false);
}
@ -1603,6 +1613,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
cursor.region_select = false;
surface->update();
}
}
if (_edit.mode != TRANSFORM_NONE) {
Node3D *selected = spatial_editor->get_single_selected_node();
@ -2237,7 +2248,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
return;
}
if (!AnimationPlayerEditor::singleton->get_track_editor()->has_keying()) {
if (!AnimationPlayerEditor::get_singleton()->get_track_editor()->has_keying()) {
set_message(TTR("Keying is disabled (no key inserted)."));
return;
}
@ -6736,6 +6747,33 @@ void Node3DEditor::_request_gizmo(Object *p_obj) {
}
}
void Node3DEditor::_set_subgizmo_selection(Object *p_obj, Ref<Node3DGizmo> p_gizmo, int p_id, Transform3D p_transform) {
if (p_id == -1) {
_clear_subgizmo_selection(p_obj);
return;
}
Node3D *sp = nullptr;
if (p_obj) {
sp = Object::cast_to<Node3D>(p_obj);
} else {
sp = selected;
}
if (!sp) {
return;
}
Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
if (se) {
se->subgizmos.clear();
se->subgizmos.insert(p_id, p_transform);
se->gizmo = p_gizmo;
sp->update_gizmos();
update_transform_gizmo();
}
}
void Node3DEditor::_clear_subgizmo_selection(Object *p_obj) {
Node3D *sp = nullptr;
if (p_obj) {
@ -6861,7 +6899,6 @@ void Node3DEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<OccluderInstance3DGizmoPlugin>(memnew(OccluderInstance3DGizmoPlugin)));
add_gizmo_plugin(Ref<SoftDynamicBody3DGizmoPlugin>(memnew(SoftDynamicBody3DGizmoPlugin)));
add_gizmo_plugin(Ref<Sprite3DGizmoPlugin>(memnew(Sprite3DGizmoPlugin)));
add_gizmo_plugin(Ref<Skeleton3DGizmoPlugin>(memnew(Skeleton3DGizmoPlugin)));
add_gizmo_plugin(Ref<Position3DGizmoPlugin>(memnew(Position3DGizmoPlugin)));
add_gizmo_plugin(Ref<RayCast3DGizmoPlugin>(memnew(RayCast3DGizmoPlugin)));
add_gizmo_plugin(Ref<SpringArm3DGizmoPlugin>(memnew(SpringArm3DGizmoPlugin)));
@ -6886,6 +6923,7 @@ void Node3DEditor::_register_all_gizmos() {
void Node3DEditor::_bind_methods() {
ClassDB::bind_method("_get_editor_data", &Node3DEditor::_get_editor_data);
ClassDB::bind_method("_request_gizmo", &Node3DEditor::_request_gizmo);
ClassDB::bind_method("_set_subgizmo_selection", &Node3DEditor::_set_subgizmo_selection);
ClassDB::bind_method("_clear_subgizmo_selection", &Node3DEditor::_clear_subgizmo_selection);
ClassDB::bind_method("_refresh_menu_icons", &Node3DEditor::_refresh_menu_icons);
@ -7712,6 +7750,13 @@ Vector3 Node3DEditor::snap_point(Vector3 p_target, Vector3 p_start) const {
return p_target;
}
bool Node3DEditor::is_gizmo_visible() const {
if (selected) {
return gizmo.visible && selected->is_transform_gizmo_visible();
}
return gizmo.visible;
}
double Node3DEditor::get_translate_snap() const {
double snap_value;
if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {

View File

@ -663,6 +663,7 @@ private:
Node3D *selected;
void _request_gizmo(Object *p_obj);
void _set_subgizmo_selection(Object *p_obj, Ref<Node3DGizmo> p_gizmo, int p_id, Transform3D p_transform = Transform3D());
void _clear_subgizmo_selection(Object *p_obj = nullptr);
static Node3DEditor *singleton;
@ -756,7 +757,7 @@ public:
float get_fov() const { return settings_fov->get_value(); }
Transform3D get_gizmo_transform() const { return gizmo.transform; }
bool is_gizmo_visible() const { return gizmo.visible; }
bool is_gizmo_visible() const;
ToolMode get_tool_mode() const { return tool_mode; }
bool are_local_coords_enabled() const { return tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->is_pressed(); }

View File

@ -294,13 +294,13 @@ Path3DGizmo::Path3DGizmo(Path3D *p_path) {
orig_out_length = 0;
}
bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
if (!path) {
return false;
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
Ref<Curve3D> c = path->get_curve();
if (c.is_null()) {
return false;
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
Transform3D gt = path->get_global_transform();
Transform3D it = gt.affine_inverse();
@ -329,14 +329,14 @@ bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref
const Vector3 *r = v3a.ptr();
if (p_camera->unproject_position(gt.xform(c->get_point_position(0))).distance_to(mbpos) < click_dist) {
return false; //nope, existing
return EditorPlugin::AFTER_GUI_INPUT_PASS; //nope, existing
}
for (int i = 0; i < c->get_point_count() - 1; i++) {
//find the offset and point index of the place to break up
int j = idx;
if (p_camera->unproject_position(gt.xform(c->get_point_position(i + 1))).distance_to(mbpos) < click_dist) {
return false; //nope, existing
return EditorPlugin::AFTER_GUI_INPUT_PASS; //nope, existing
}
while (j < rc && c->get_point_position(i + 1) != r[j]) {
@ -386,7 +386,7 @@ bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref
ur->add_do_method(c.ptr(), "add_point", closest_seg_point, Vector3(), Vector3(), closest_seg + 1);
ur->add_undo_method(c.ptr(), "remove_point", closest_seg + 1);
ur->commit_action();
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else {
Vector3 org;
@ -405,7 +405,7 @@ bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref
ur->add_do_method(c.ptr(), "add_point", it.xform(inters), Vector3(), Vector3(), -1);
ur->add_undo_method(c.ptr(), "remove_point", c->get_point_count());
ur->commit_action();
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
//add new at pos
@ -425,27 +425,27 @@ bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref
ur->add_do_method(c.ptr(), "remove_point", i);
ur->add_undo_method(c.ptr(), "add_point", c->get_point_position(i), c->get_point_in(i), c->get_point_out(i), i);
ur->commit_action();
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else if (dist_to_p_out < click_dist) {
UndoRedo *ur = editor->get_undo_redo();
ur->create_action(TTR("Remove Out-Control Point"));
ur->add_do_method(c.ptr(), "set_point_out", i, Vector3());
ur->add_undo_method(c.ptr(), "set_point_out", i, c->get_point_out(i));
ur->commit_action();
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else if (dist_to_p_in < click_dist) {
UndoRedo *ur = editor->get_undo_redo();
ur->create_action(TTR("Remove In-Control Point"));
ur->add_do_method(c.ptr(), "set_point_in", i, Vector3());
ur->add_undo_method(c.ptr(), "set_point_in", i, c->get_point_in(i));
ur->commit_action();
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
}
}
return false;
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
void Path3DEditorPlugin::edit(Object *p_object) {

View File

@ -100,7 +100,7 @@ public:
Path3D *get_edited_path() { return path; }
static Path3DEditorPlugin *singleton;
virtual bool forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override;
virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override;
virtual String get_name() const override { return "Path3D"; }
bool has_main_screen() const override { return false; }

File diff suppressed because it is too large Load Diff

View File

@ -33,7 +33,12 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/editor_properties.h"
#include "node_3d_editor_plugin.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/immediate_mesh.h"
class EditorInspectorPluginSkeleton;
class Joint;
@ -41,8 +46,6 @@ class PhysicalBone3D;
class Skeleton3DEditorPlugin;
class Button;
class CheckBox;
class EditorPropertyTransform3D;
class EditorPropertyVector3;
class BoneTransformEditor : public VBoxContainer {
GDCLASS(BoneTransformEditor, VBoxContainer);
@ -81,6 +84,8 @@ class BoneTransformEditor : public VBoxContainer {
void _value_changed_transform(const String p_property_name, const Transform3D p_transform, const StringName p_edited_property_name, const bool p_boolean);
// Changes the transform to the given transform and updates the UI accordingly.
void _change_transform(Transform3D p_new_transform);
// Update it is truely keyable then.
void _update_key_button(const bool p_keyable);
// Creates a Transform using the EditorPropertyVector3 properties.
Transform3D compute_transform_from_vector3s() const;
@ -92,7 +97,7 @@ protected:
public:
BoneTransformEditor(Skeleton3D *p_skeleton);
// Which transform target to modify
// Which transform target to modify.
void set_target(const String &p_prop);
void set_label(const String &p_label) { label = p_label; }
@ -100,20 +105,21 @@ public:
void _update_custom_pose_properties();
void _update_transform_properties(Transform3D 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
// 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
// When rest mode, pose and custom_pose editor are diasbled.
void set_properties_read_only(const bool p_readonly);
void set_transform_read_only(const bool p_readonly);
// 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
// Key Transform Button pressed.
void _key_button_pressed();
// Bone Enabled Checkbox toggled
void _checkbox_toggled(const bool p_toggled);
// Bone Enabled Checkbox toggled.
void _checkbox_pressed();
};
class Skeleton3DEditor : public VBoxContainer {
@ -121,13 +127,20 @@ class Skeleton3DEditor : public VBoxContainer {
friend class Skeleton3DEditorPlugin;
enum Menu {
MENU_OPTION_CREATE_PHYSICAL_SKELETON
enum SkeletonOption {
SKELETON_OPTION_INIT_POSE,
SKELETON_OPTION_INSERT_KEYS,
SKELETON_OPTION_INSERT_KEYS_EXISTED,
SKELETON_OPTION_CREATE_PHYSICAL_SKELETON
};
enum RestOption {
REST_OPTION_POSE_TO_REST
};
struct BoneInfo {
PhysicalBone3D *physical_bone = nullptr;
Transform3D relative_rest; // Relative to skeleton node
Transform3D relative_rest; // Relative to skeleton node.
};
EditorNode *editor;
@ -140,13 +153,24 @@ class Skeleton3DEditor : public VBoxContainer {
BoneTransformEditor *pose_editor = nullptr;
BoneTransformEditor *custom_pose_editor = nullptr;
MenuButton *options = nullptr;
VSeparator *separator;
MenuButton *skeleton_options = nullptr;
MenuButton *rest_options = nullptr;
Button *edit_mode_button;
bool edit_mode = false;
EditorFileDialog *file_dialog = nullptr;
UndoRedo *undo_redo = nullptr;
bool keyable;
void _on_click_option(int p_option);
static Skeleton3DEditor *singleton;
void _on_click_skeleton_option(int p_skeleton_option);
void _on_click_rest_option(int p_rest_option);
void _file_selected(const String &p_file);
TreeItem *_find(TreeItem *p_node, const NodePath &p_path);
void edit_mode_toggled(const bool pressed);
EditorFileDialog *file_export_lib = nullptr;
@ -155,6 +179,10 @@ class Skeleton3DEditor : public VBoxContainer {
void create_editors();
void init_pose();
void insert_keys(bool p_all_bones);
void pose_to_rest();
void create_physical_skeleton();
PhysicalBone3D *create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos);
@ -162,20 +190,56 @@ class Skeleton3DEditor : public VBoxContainer {
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
void set_keyable(const bool p_keyable);
void set_rest_options_enabled(const bool p_rest_options_enabled);
// Handle.
MeshInstance3D *handles_mesh_instance;
Ref<ImmediateMesh> handles_mesh;
Ref<ShaderMaterial> handle_material;
Ref<Shader> handle_shader;
Transform3D bone_original;
void _update_pose_enabled(int p_bone = -1);
void _update_show_rest_only();
void _update_gizmo_transform();
void _update_gizmo_visible();
void _hide_handles();
void _draw_gizmo();
void _draw_handles();
void _joint_tree_selection_changed();
void _joint_tree_rmb_select(const Vector2 &p_pos);
void _update_properties();
void _subgizmo_selection_change();
int selected_bone = -1;
protected:
void _notification(int p_what);
void _node_removed(Node *p_node);
static void _bind_methods();
public:
static Skeleton3DEditor *get_singleton() { return singleton; }
void select_bone(int p_idx);
int get_selected_bone() const;
void move_skeleton_bone(NodePath p_skeleton_path, int32_t p_selected_boneidx, int32_t p_target_boneidx);
Skeleton3D *get_skeleton() const { return skeleton; };
void _joint_tree_selection_changed();
void _joint_tree_rmb_select(const Vector2 &p_pos);
bool is_edit_mode() const { return edit_mode; }
void _update_properties();
void update_bone_original();
Transform3D get_bone_original() { return bone_original; };
Skeleton3DEditor(EditorInspectorPluginSkeleton *e_plugin, EditorNode *p_editor, Skeleton3D *skeleton);
~Skeleton3DEditor();
@ -186,6 +250,7 @@ class EditorInspectorPluginSkeleton : public EditorInspectorPlugin {
friend class Skeleton3DEditorPlugin;
Skeleton3DEditor *skel_editor;
EditorNode *editor;
public:
@ -196,12 +261,40 @@ public:
class Skeleton3DEditorPlugin : public EditorPlugin {
GDCLASS(Skeleton3DEditorPlugin, EditorPlugin);
EditorInspectorPluginSkeleton *skeleton_plugin;
EditorNode *editor;
public:
Skeleton3DEditorPlugin(EditorNode *p_node);
virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override;
bool has_main_screen() const override { return false; }
virtual bool handles(Object *p_object) const override;
virtual String get_name() const override { return "Skeleton3D"; }
Skeleton3DEditorPlugin(EditorNode *p_node);
};
class Skeleton3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(Skeleton3DGizmoPlugin, EditorNode3DGizmoPlugin);
Ref<StandardMaterial3D> unselected_mat;
Ref<ShaderMaterial> selected_mat;
Ref<Shader> selected_sh;
public:
bool has_gizmo(Node3D *p_spatial) override;
String get_gizmo_name() const override;
int get_priority() const override;
int subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const override;
Transform3D get_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
void set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) override;
void commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel) override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
Skeleton3DGizmoPlugin();
};
#endif // SKELETON_3D_EDITOR_PLUGIN_H

View File

@ -1833,8 +1833,8 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
editor_data->get_undo_redo().add_do_method(this, "_set_owners", edited_scene, owners);
if (AnimationPlayerEditor::singleton->get_track_editor()->get_root() == node) {
editor_data->get_undo_redo().add_do_method(AnimationPlayerEditor::singleton->get_track_editor(), "set_root", node);
if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == node) {
editor_data->get_undo_redo().add_do_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node);
}
editor_data->get_undo_redo().add_undo_method(new_parent, "remove_child", node);
@ -1859,8 +1859,8 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
editor_data->get_undo_redo().add_undo_method(node->get_parent(), "add_child", node);
editor_data->get_undo_redo().add_undo_method(node->get_parent(), "move_child", node, child_pos);
editor_data->get_undo_redo().add_undo_method(this, "_set_owners", edited_scene, owners);
if (AnimationPlayerEditor::singleton->get_track_editor()->get_root() == node) {
editor_data->get_undo_redo().add_undo_method(AnimationPlayerEditor::singleton->get_track_editor(), "set_root", node);
if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == node) {
editor_data->get_undo_redo().add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node);
}
if (p_keep_global_xform) {
@ -2071,8 +2071,8 @@ void SceneTreeDock::_delete_confirm(bool p_cut) {
editor_data->get_undo_redo().add_do_method(n->get_parent(), "remove_child", n);
editor_data->get_undo_redo().add_undo_method(n->get_parent(), "add_child", n);
editor_data->get_undo_redo().add_undo_method(n->get_parent(), "move_child", n, n->get_index());
if (AnimationPlayerEditor::singleton->get_track_editor()->get_root() == n) {
editor_data->get_undo_redo().add_undo_method(AnimationPlayerEditor::singleton->get_track_editor(), "set_root", n);
if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == n) {
editor_data->get_undo_redo().add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", n);
}
editor_data->get_undo_redo().add_undo_method(this, "_set_owners", edited_scene, owners);
editor_data->get_undo_redo().add_undo_reference(n);

View File

@ -102,7 +102,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
undo_redo->commit_action();
} else if (p_id == BUTTON_PIN) {
if (n->is_class("AnimationPlayer")) {
AnimationPlayerEditor::singleton->unpin();
AnimationPlayerEditor::get_singleton()->unpin();
_update_tree();
}
@ -386,7 +386,7 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent, bool p_scroll
_update_visibility_color(p_node, item);
} else if (p_node->is_class("AnimationPlayer")) {
bool is_pinned = AnimationPlayerEditor::singleton->get_player() == p_node && AnimationPlayerEditor::singleton->is_pinned();
bool is_pinned = AnimationPlayerEditor::get_singleton()->get_player() == p_node && AnimationPlayerEditor::get_singleton()->is_pinned();
if (is_pinned) {
item->add_button(0, get_theme_icon(SNAME("Pin"), SNAME("EditorIcons")), BUTTON_PIN, false, TTR("AnimationPlayer is pinned.\nClick to unpin."));

View File

@ -603,9 +603,9 @@ void GridMapEditor::_do_paste() {
_clear_clipboard_data();
}
bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
if (!node) {
return false;
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
Ref<InputEventMouseButton> mb = p_event;
@ -616,12 +616,12 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
floor->set_value(floor->get_value() + mb->get_factor());
}
return true; // Eaten.
return EditorPlugin::AFTER_GUI_INPUT_STOP; // Eaten.
} else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && (mb->is_command_pressed() || mb->is_shift_pressed())) {
if (mb->is_pressed()) {
floor->set_value(floor->get_value() - mb->get_factor());
}
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
if (mb->is_pressed()) {
@ -648,19 +648,22 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
_clear_clipboard_data();
input_action = INPUT_NONE;
_update_paste_indicator();
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else if (selection.active) {
_set_selection(false);
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else {
input_action = INPUT_ERASE;
set_items.clear();
}
} else {
return false;
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
return do_input_action(p_camera, Point2(mb->get_position().x, mb->get_position().y), true);
if (do_input_action(p_camera, Point2(mb->get_position().x, mb->get_position().y), true)) {
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
return EditorPlugin::AFTER_GUI_INPUT_PASS;
} else {
if ((mb->get_button_index() == MOUSE_BUTTON_RIGHT && input_action == INPUT_ERASE) || (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action == INPUT_PAINT)) {
if (set_items.size()) {
@ -677,7 +680,11 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
}
set_items.clear();
input_action = INPUT_NONE;
return set_items.size() > 0;
if (set_items.size() > 0) {
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
if (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action == INPUT_SELECT) {
@ -690,11 +697,11 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
if (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action != INPUT_NONE) {
set_items.clear();
input_action = INPUT_NONE;
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && (input_action == INPUT_ERASE || input_action == INPUT_PASTE)) {
input_action = INPUT_NONE;
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
}
@ -702,7 +709,10 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
return do_input_action(p_camera, mm->get_position(), false);
if (do_input_action(p_camera, mm->get_position(), false)) {
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
Ref<InputEventKey> k = p_event;
@ -714,16 +724,16 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
_clear_clipboard_data();
input_action = INPUT_NONE;
_update_paste_indicator();
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else if (selection.active) {
_set_selection(false);
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else {
selected_palette = -1;
mesh_library_palette->deselect_all();
update_palette();
_update_cursor_instance();
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
@ -731,12 +741,12 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
if (k->get_keycode() == options->get_popup()->get_item_accelerator(options->get_popup()->get_item_index(MENU_OPTION_PREV_LEVEL))) {
selection.click[edit_axis]--;
_validate_selection();
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
if (k->get_keycode() == options->get_popup()->get_item_accelerator(options->get_popup()->get_item_index(MENU_OPTION_NEXT_LEVEL))) {
selection.click[edit_axis]++;
_validate_selection();
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
}
@ -755,12 +765,12 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
if (step) {
floor->set_value(floor->get_value() + step);
}
return true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
accumulated_floor_delta = 0.0;
return false;
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
struct _CGMEItemSort {

View File

@ -232,7 +232,7 @@ protected:
static void _bind_methods();
public:
bool forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event);
EditorPlugin::AfterGUIInput forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event);
void edit(GridMap *p_gridmap);
GridMapEditor() {}
@ -250,7 +250,7 @@ protected:
void _notification(int p_what);
public:
virtual bool forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return grid_map_editor->forward_spatial_input_event(p_camera, p_event); }
virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return grid_map_editor->forward_spatial_input_event(p_camera, p_event); }
virtual String get_name() const override { return "GridMap"; }
bool has_main_screen() const override { return false; }
virtual void edit(Object *p_object) override;

View File

@ -376,6 +376,18 @@ void Node3D::update_gizmos() {
#endif
}
void Node3D::set_subgizmo_selection(Ref<Node3DGizmo> p_gizmo, int p_id, Transform3D p_transform) {
#ifdef TOOLS_ENABLED
if (!is_inside_world()) {
return;
}
if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) {
get_tree()->call_group_flags(0, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_set_subgizmo_selection, this, p_gizmo, p_id, p_transform);
}
#endif
}
void Node3D::clear_subgizmo_selection() {
#ifdef TOOLS_ENABLED
if (!is_inside_world()) {
@ -792,6 +804,7 @@ void Node3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_gizmo", "gizmo"), &Node3D::add_gizmo);
ClassDB::bind_method(D_METHOD("get_gizmos"), &Node3D::get_gizmos_bind);
ClassDB::bind_method(D_METHOD("clear_gizmos"), &Node3D::clear_gizmos);
ClassDB::bind_method(D_METHOD("set_subgizmo_selection", "gizmo", "id", "transform"), &Node3D::set_subgizmo_selection);
ClassDB::bind_method(D_METHOD("clear_subgizmo_selection"), &Node3D::clear_subgizmo_selection);
ClassDB::bind_method(D_METHOD("set_visible", "visible"), &Node3D::set_visible);

View File

@ -92,6 +92,7 @@ class Node3D : public Node {
Vector<Ref<Node3DGizmo>> gizmos;
bool gizmos_disabled = false;
bool gizmos_dirty = false;
bool transform_gizmo_visible = true;
#endif
} data;
@ -145,6 +146,8 @@ public:
#ifdef TOOLS_ENABLED
virtual Transform3D get_global_gizmo_transform() const;
virtual Transform3D get_local_gizmo_transform() const;
virtual void set_transform_gizmo_visible(bool p_enabled) { data.transform_gizmo_visible = p_enabled; };
virtual bool is_transform_gizmo_visible() const { return data.transform_gizmo_visible; };
#endif
void set_as_top_level(bool p_enabled);
@ -155,6 +158,7 @@ public:
void set_disable_gizmos(bool p_enabled);
void update_gizmos();
void set_subgizmo_selection(Ref<Node3DGizmo> p_gizmo, int p_id, Transform3D p_transform = Transform3D());
void clear_subgizmo_selection();
Vector<Ref<Node3DGizmo>> get_gizmos() const;
Array get_gizmos_bind() const;

View File

@ -32,6 +32,7 @@
#include "core/object/message_queue.h"
#include "core/variant/type_info.h"
#include "editor/plugins/skeleton_3d_editor_plugin.h"
#include "scene/3d/physics_body_3d.h"
#include "scene/resources/skeleton_modification_3d.h"
#include "scene/resources/surface_tool.h"
@ -178,7 +179,7 @@ void Skeleton3D::_update_process_order() {
for (int i = 0; i < len; i++) {
if (bonesptr[i].parent >= len) {
//validate this just in case
// Validate this just in case.
ERR_PRINT("Bone " + itos(i) + " has invalid parent: " + itos(bonesptr[i].parent));
bonesptr[i].parent = -1;
}
@ -186,9 +187,9 @@ void Skeleton3D::_update_process_order() {
if (bonesptr[i].parent != -1) {
int parent_bone_idx = bonesptr[i].parent;
// Check to see if this node is already added to the parent:
// Check to see if this node is already added to the parent.
if (bonesptr[parent_bone_idx].child_bones.find(i) < 0) {
// Add the child node
// Add the child node.
bonesptr[parent_bone_idx].child_bones.push_back(i);
} else {
ERR_PRINT("Skeleton3D parenthood graph is cyclic");
@ -210,10 +211,10 @@ void Skeleton3D::_notification(int p_what) {
int len = bones.size();
dirty = false;
// Update bone transforms
// Update bone transforms.
force_update_all_bone_transforms();
//update skins
// Update skins.
for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
const Skin *skin = E->get()->skin.operator->();
RID skeleton = E->get()->skeleton;
@ -231,7 +232,7 @@ void Skeleton3D::_notification(int p_what) {
StringName bind_name = skin->get_bind_name(i);
if (bind_name != StringName()) {
//bind name used, use this
// Bind name used, use this.
bool found = false;
for (int j = 0; j < len; j++) {
if (bonesptr[j].name == bind_name) {
@ -453,7 +454,8 @@ int Skeleton3D::get_bone_axis_forward_enum(int p_bone) {
return bones[p_bone].rest_bone_forward_axis;
}
// skeleton creation api
// Skeleton creation api
void Skeleton3D::add_bone(const String &p_name) {
ERR_FAIL_COND(p_name == "" || p_name.find(":") != -1 || p_name.find("/") != -1);
@ -626,6 +628,7 @@ void Skeleton3D::set_bone_enabled(int p_bone, bool p_enabled) {
ERR_FAIL_INDEX(p_bone, bone_size);
bones.write[p_bone].enabled = p_enabled;
emit_signal(SceneStringNames::get_singleton()->bone_enabled_changed, p_bone);
_make_dirty();
}
@ -635,6 +638,16 @@ bool Skeleton3D::is_bone_enabled(int p_bone) const {
return bones[p_bone].enabled;
}
void Skeleton3D::set_show_rest_only(bool p_enabled) {
show_rest_only = p_enabled;
emit_signal(SceneStringNames::get_singleton()->show_rest_only_changed);
_make_dirty();
}
bool Skeleton3D::is_show_rest_only() const {
return show_rest_only;
}
void Skeleton3D::clear_bones() {
bones.clear();
process_order_dirty = true;
@ -642,7 +655,7 @@ void Skeleton3D::clear_bones() {
_make_dirty();
}
// posing api
// Posing api
void Skeleton3D::set_bone_pose(int p_bone, const Transform3D &p_pose) {
const int bone_size = bones.size();
@ -697,7 +710,7 @@ void Skeleton3D::localize_rests() {
set_bone_rest(current_bone_idx, bones[bones[current_bone_idx].parent].rest.affine_inverse() * bones[current_bone_idx].rest);
}
// Add the bone's children to the list of bones to be processed
// Add the bone's children to the list of bones to be processed.
int child_bone_size = bones[current_bone_idx].child_bones.size();
for (int i = 0; i < child_bone_size; i++) {
bones_to_process.push_back(bones[current_bone_idx].child_bones[i]);
@ -831,7 +844,7 @@ void Skeleton3D::physical_bones_start_simulation_on(const TypedArray<StringName>
Vector<int> sim_bones;
if (p_bones.size() <= 0) {
sim_bones.push_back(0); // if no bones is specified, activate ragdoll on full body
sim_bones.push_back(0); // If no bones is specified, activate ragdoll on full body.
} else {
sim_bones.resize(p_bones.size());
int c = 0;
@ -884,19 +897,19 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
Ref<Skin> skin = p_skin;
if (skin.is_null()) {
//need to create one from existing code, this is for compatibility only
//when skeletons did not support skins. It is also used by gizmo
//to display the skeleton.
// Need to create one from existing code, this is for compatibility only
// when skeletons did not support skins. It is also used by gizmo
// to display the skeleton.
skin.instantiate();
skin->set_bind_count(bones.size());
_update_process_order(); //just in case
_update_process_order(); // Just in case.
// pose changed, rebuild cache of inverses
// Pose changed, rebuild cache of inverses.
const Bone *bonesptr = bones.ptr();
int len = bones.size();
// calculate global rests and invert them
// Calculate global rests and invert them.
LocalVector<int> bones_to_process;
bones_to_process = get_parentless_bones();
while (bones_to_process.size() > 0) {
@ -919,7 +932,7 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
}
for (int i = 0; i < len; i++) {
//the inverse is what is actually required
// The inverse is what is actually required.
skin->set_bind_bone(i, i);
skin->set_bind_pose(i, skin->get_bind_pose(i).affine_inverse());
}
@ -940,11 +953,17 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
skin->connect("changed", Callable(skin_ref.operator->(), "_skin_changed"));
_make_dirty(); //skin needs to be updated, so update skeleton
_make_dirty(); // Skin needs to be updated, so update skeleton.
return skin_ref;
}
void Skeleton3D::force_update_all_dirty_bones() {
if (dirty) {
const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON);
}
}
void Skeleton3D::force_update_all_bone_transforms() {
_update_process_order();
@ -966,9 +985,10 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
bones_to_process.erase(current_bone_idx);
Bone &b = bonesptr[current_bone_idx];
bool bone_enabled = b.enabled && !show_rest_only;
if (b.disable_rest) {
if (b.enabled) {
if (bone_enabled) {
Transform3D pose = b.pose;
if (b.custom_pose_enable) {
pose = b.custom_pose * pose;
@ -991,7 +1011,7 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
}
} else {
if (b.enabled) {
if (bone_enabled) {
Transform3D pose = b.pose;
if (b.custom_pose_enable) {
pose = b.custom_pose * pose;
@ -1035,7 +1055,7 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
b.global_pose_override_amount = 0.0;
}
// Add the bone's children to the list of bones to be processed
// Add the bone's children to the list of bones to be processed.
int child_bone_size = b.child_bones.size();
for (int i = 0; i < child_bone_size; i++) {
bones_to_process.push_back(b.child_bones[i]);
@ -1045,7 +1065,7 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
}
}
// helper functions
// Helper functions
Transform3D Skeleton3D::global_pose_to_world_transform(Transform3D p_global_pose) {
return get_global_transform() * p_global_pose;
@ -1175,6 +1195,9 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton3D::get_bone_pose);
ClassDB::bind_method(D_METHOD("set_bone_pose", "bone_idx", "pose"), &Skeleton3D::set_bone_pose);
ClassDB::bind_method(D_METHOD("is_bone_enabled", "bone_idx"), &Skeleton3D::is_bone_enabled);
ClassDB::bind_method(D_METHOD("set_bone_enabled", "bone_idx", "enabled"), &Skeleton3D::set_bone_enabled, DEFVAL(true));
ClassDB::bind_method(D_METHOD("clear_bones_global_pose_override"), &Skeleton3D::clear_bones_global_pose_override);
ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton3D::set_bone_global_pose_override, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_bone_global_pose_override", "bone_idx"), &Skeleton3D::get_bone_global_pose_override);
@ -1198,6 +1221,9 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("local_pose_to_global_pose", "bone_idx", "local_pose"), &Skeleton3D::local_pose_to_global_pose);
ClassDB::bind_method(D_METHOD("global_pose_z_forward_to_bone_forward", "bone_idx", "basis"), &Skeleton3D::global_pose_z_forward_to_bone_forward);
ClassDB::bind_method(D_METHOD("set_show_rest_only"), &Skeleton3D::set_show_rest_only);
ClassDB::bind_method(D_METHOD("is_show_rest_only"), &Skeleton3D::is_show_rest_only);
ClassDB::bind_method(D_METHOD("set_animate_physical_bones"), &Skeleton3D::set_animate_physical_bones);
ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton3D::get_animate_physical_bones);
@ -1212,6 +1238,7 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("execute_modifications", "delta", "execution_mode"), &Skeleton3D::execute_modifications);
#ifndef _3D_DISABLED
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_rest_only"), "set_show_rest_only", "is_show_rest_only");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "animate_physical_bones"), "set_animate_physical_bones", "get_animate_physical_bones");
#endif // _3D_DISABLED
@ -1220,6 +1247,8 @@ void Skeleton3D::_bind_methods() {
#endif // TOOLS_ENABLED
ADD_SIGNAL(MethodInfo("bone_pose_changed", PropertyInfo(Variant::INT, "bone_idx")));
ADD_SIGNAL(MethodInfo("bone_enabled_changed", PropertyInfo(Variant::INT, "bone_idx")));
ADD_SIGNAL(MethodInfo("show_rest_only_changed"));
BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
}
@ -1228,7 +1257,7 @@ Skeleton3D::Skeleton3D() {
}
Skeleton3D::~Skeleton3D() {
//some skins may remain bound
// Some skins may remain bound.
for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) {
E->get()->skeleton_node = nullptr;
}

View File

@ -137,6 +137,8 @@ private:
void _make_dirty();
bool dirty = false;
bool show_rest_only = false;
uint64_t version = 1;
void _update_process_order();
@ -197,6 +199,9 @@ public:
void set_bone_enabled(int p_bone, bool p_enabled);
bool is_bone_enabled(int p_bone) const;
void set_show_rest_only(bool p_enabled);
bool is_show_rest_only() const;
void clear_bones();
// posing api
@ -219,6 +224,7 @@ public:
Ref<SkinReference> register_skin(const Ref<Skin> &p_skin);
void force_update_all_dirty_bones();
void force_update_all_bone_transforms();
void force_update_bone_children_transforms(int bone_idx);

View File

@ -64,6 +64,8 @@ SceneStringNames::SceneStringNames() {
pose_updated = StaticCString::create("pose_updated");
bone_pose_changed = StaticCString::create("bone_pose_changed");
bone_enabled_changed = StaticCString::create("bone_enabled_changed");
show_rest_only_changed = StaticCString::create("show_rest_only_changed");
mouse_entered = StaticCString::create("mouse_entered");
mouse_exited = StaticCString::create("mouse_exited");
@ -134,6 +136,7 @@ SceneStringNames::SceneStringNames() {
_spatial_editor_group = StaticCString::create("_spatial_editor_group");
_request_gizmo = StaticCString::create("_request_gizmo");
_set_subgizmo_selection = StaticCString::create("_set_subgizmo_selection");
_clear_subgizmo_selection = StaticCString::create("_clear_subgizmo_selection");
offset = StaticCString::create("offset");

View File

@ -99,6 +99,8 @@ public:
StringName pose_updated;
StringName bone_pose_changed;
StringName bone_enabled_changed;
StringName show_rest_only_changed;
StringName body_shape_entered;
StringName body_entered;
@ -154,6 +156,7 @@ public:
StringName _spatial_editor_group;
StringName _request_gizmo;
StringName _set_subgizmo_selection;
StringName _clear_subgizmo_selection;
StringName offset;