feat: updated engine version to 4.4-rc1

This commit is contained in:
Sara 2025-02-23 14:38:14 +01:00
parent ee00efde1f
commit 21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions

View file

@ -41,17 +41,16 @@
#include "editor/plugins/node_3d_editor_plugin.h"
#include "editor/themes/editor_scale.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/physical_bone_simulator_3d.h"
#include "scene/3d/physics/collision_shape_3d.h"
#include "scene/3d/physics/joints/joint_3d.h"
#include "scene/3d/physics/physical_bone_3d.h"
#include "scene/3d/physics/physics_body_3d.h"
#include "scene/gui/separator.h"
#include "scene/gui/texture_rect.h"
#include "scene/resources/3d/capsule_shape_3d.h"
#include "scene/resources/skeleton_profile.h"
#include "scene/resources/surface_tool.h"
void BoneTransformEditor::create_editors() {
void BonePropertiesEditor::create_editors() {
section = memnew(EditorInspectorSection);
section->setup("trf_properties", label, this, Color(0.0f, 0.0f, 0.0f), true);
section->unfold();
@ -60,34 +59,34 @@ void BoneTransformEditor::create_editors() {
enabled_checkbox = memnew(EditorPropertyCheck());
enabled_checkbox->set_label("Pose Enabled");
enabled_checkbox->set_selectable(false);
enabled_checkbox->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed));
enabled_checkbox->connect("property_changed", callable_mp(this, &BonePropertiesEditor::_value_changed));
section->get_vbox()->add_child(enabled_checkbox);
// Position property.
position_property = memnew(EditorPropertyVector3());
position_property->setup(-10000, 10000, 0.001f, true);
position_property->setup(-10000, 10000, 0.001, true);
position_property->set_label("Position");
position_property->set_selectable(false);
position_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed));
position_property->connect("property_keyed", callable_mp(this, &BoneTransformEditor::_property_keyed));
position_property->connect("property_changed", callable_mp(this, &BonePropertiesEditor::_value_changed));
position_property->connect("property_keyed", callable_mp(this, &BonePropertiesEditor::_property_keyed));
section->get_vbox()->add_child(position_property);
// Rotation property.
rotation_property = memnew(EditorPropertyQuaternion());
rotation_property->setup(-10000, 10000, 0.001f, true);
rotation_property->setup(-10000, 10000, 0.001, true);
rotation_property->set_label("Rotation");
rotation_property->set_selectable(false);
rotation_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed));
rotation_property->connect("property_keyed", callable_mp(this, &BoneTransformEditor::_property_keyed));
rotation_property->connect("property_changed", callable_mp(this, &BonePropertiesEditor::_value_changed));
rotation_property->connect("property_keyed", callable_mp(this, &BonePropertiesEditor::_property_keyed));
section->get_vbox()->add_child(rotation_property);
// Scale property.
scale_property = memnew(EditorPropertyVector3());
scale_property->setup(-10000, 10000, 0.001f, true);
scale_property->setup(-10000, 10000, 0.001, true, true);
scale_property->set_label("Scale");
scale_property->set_selectable(false);
scale_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed));
scale_property->connect("property_keyed", callable_mp(this, &BoneTransformEditor::_property_keyed));
scale_property->connect("property_changed", callable_mp(this, &BonePropertiesEditor::_value_changed));
scale_property->connect("property_keyed", callable_mp(this, &BonePropertiesEditor::_property_keyed));
section->get_vbox()->add_child(scale_property);
// Transform/Matrix section.
@ -97,47 +96,140 @@ void BoneTransformEditor::create_editors() {
// Transform/Matrix property.
rest_matrix = memnew(EditorPropertyTransform3D());
rest_matrix->setup(-10000, 10000, 0.001f, true);
rest_matrix->setup(-10000, 10000, 0.001, true);
rest_matrix->set_label("Transform");
rest_matrix->set_selectable(false);
rest_section->get_vbox()->add_child(rest_matrix);
// Bone Metadata property
meta_section = memnew(EditorInspectorSection);
meta_section->setup("bone_meta", TTR("Bone Metadata"), this, Color(.0f, .0f, .0f), true);
section->get_vbox()->add_child(meta_section);
add_metadata_button = EditorInspector::create_inspector_action_button(TTR("Add Bone Metadata"));
add_metadata_button->connect(SceneStringName(pressed), callable_mp(this, &BonePropertiesEditor::_show_add_meta_dialog));
section->get_vbox()->add_child(add_metadata_button);
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->connect("version_changed", callable_mp(this, &BonePropertiesEditor::_update_properties));
undo_redo->connect("history_changed", callable_mp(this, &BonePropertiesEditor::_update_properties));
}
void BoneTransformEditor::_notification(int p_what) {
void BonePropertiesEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
const Color section_color = get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor));
section->set_bg_color(section_color);
rest_section->set_bg_color(section_color);
add_metadata_button->set_button_icon(get_editor_theme_icon(SNAME("Add")));
} break;
}
}
void BoneTransformEditor::_value_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing) {
if (updating) {
void BonePropertiesEditor::_value_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing) {
if (updating || !skeleton) {
return;
}
if (skeleton) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS);
undo_redo->add_undo_property(skeleton, p_property, skeleton->get(p_property));
undo_redo->add_do_property(skeleton, p_property, p_value);
undo_redo->commit_action();
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS);
undo_redo->add_undo_property(skeleton, p_property, skeleton->get(p_property));
undo_redo->add_do_property(skeleton, p_property, p_value);
Skeleton3DEditor *se = Skeleton3DEditor::get_singleton();
if (se) {
undo_redo->add_do_method(se, "update_joint_tree");
undo_redo->add_undo_method(se, "update_joint_tree");
}
undo_redo->commit_action();
}
BoneTransformEditor::BoneTransformEditor(Skeleton3D *p_skeleton) :
void BonePropertiesEditor::_meta_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing) {
if (!skeleton || p_property.get_slicec('/', 2) != "bone_meta") {
return;
}
int bone = p_property.get_slicec('/', 1).to_int();
if (bone >= skeleton->get_bone_count()) {
return;
}
String key = p_property.get_slicec('/', 3);
if (!skeleton->has_bone_meta(1, key)) {
return;
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Modify metadata '%s' for bone '%s'"), key, skeleton->get_bone_name(bone)));
undo_redo->add_do_property(skeleton, p_property, p_value);
undo_redo->add_do_method(meta_editors[p_property], "update_property");
undo_redo->add_undo_property(skeleton, p_property, skeleton->get_bone_meta(bone, key));
undo_redo->add_undo_method(meta_editors[p_property], "update_property");
undo_redo->commit_action();
}
void BonePropertiesEditor::_meta_deleted(const String &p_property) {
if (!skeleton || p_property.get_slicec('/', 2) != "bone_meta") {
return;
}
int bone = p_property.get_slicec('/', 1).to_int();
if (bone >= skeleton->get_bone_count()) {
return;
}
String key = p_property.get_slicec('/', 3);
if (!skeleton->has_bone_meta(1, key)) {
return;
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Remove metadata '%s' from bone '%s'"), key, skeleton->get_bone_name(bone)));
undo_redo->add_do_property(skeleton, p_property, Variant());
undo_redo->add_undo_property(skeleton, p_property, skeleton->get_bone_meta(bone, key));
undo_redo->commit_action();
emit_signal(SNAME("property_deleted"), p_property);
}
void BonePropertiesEditor::_show_add_meta_dialog() {
if (!add_meta_dialog) {
add_meta_dialog = memnew(AddMetadataDialog());
add_meta_dialog->connect(SceneStringName(confirmed), callable_mp(this, &BonePropertiesEditor::_add_meta_confirm));
add_child(add_meta_dialog);
}
int bone = Skeleton3DEditor::get_singleton()->get_selected_bone();
StringName dialog_title = skeleton->get_bone_name(bone);
List<StringName> existing_meta_keys;
skeleton->get_bone_meta_list(bone, &existing_meta_keys);
add_meta_dialog->open(dialog_title, existing_meta_keys);
}
void BonePropertiesEditor::_add_meta_confirm() {
int bone = Skeleton3DEditor::get_singleton()->get_selected_bone();
String name = add_meta_dialog->get_meta_name();
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Add metadata '%s' to bone '%s'"), name, skeleton->get_bone_name(bone)));
undo_redo->add_do_method(skeleton, "set_bone_meta", bone, name, add_meta_dialog->get_meta_defval());
undo_redo->add_undo_method(skeleton, "set_bone_meta", bone, name, Variant());
undo_redo->commit_action();
}
BonePropertiesEditor::BonePropertiesEditor(Skeleton3D *p_skeleton) :
skeleton(p_skeleton) {
create_editors();
}
void BoneTransformEditor::set_keyable(const bool p_keyable) {
void BonePropertiesEditor::set_keyable(const bool p_keyable) {
position_property->set_keying(p_keyable);
rotation_property->set_keying(p_keyable);
scale_property->set_keying(p_keyable);
}
void BoneTransformEditor::set_target(const String &p_prop) {
void BonePropertiesEditor::set_target(const String &p_prop) {
enabled_checkbox->set_object_and_property(skeleton, p_prop + "enabled");
enabled_checkbox->update_property();
@ -154,7 +246,7 @@ void BoneTransformEditor::set_target(const String &p_prop) {
rest_matrix->update_property();
}
void BoneTransformEditor::_property_keyed(const String &p_path, bool p_advance) {
void BonePropertiesEditor::_property_keyed(const String &p_path, bool p_advance) {
AnimationTrackEditor *te = AnimationPlayerEditor::get_singleton()->get_track_editor();
if (!te || !te->has_keying()) {
return;
@ -175,45 +267,77 @@ void BoneTransformEditor::_property_keyed(const String &p_path, bool p_advance)
}
}
void BoneTransformEditor::_update_properties() {
void BonePropertiesEditor::_update_properties() {
if (!skeleton) {
return;
}
int selected = Skeleton3DEditor::get_singleton()->get_selected_bone();
List<PropertyInfo> props;
HashSet<StringName> meta_seen;
skeleton->get_property_list(&props);
for (const PropertyInfo &E : props) {
PackedStringArray split = E.name.split("/");
if (split.size() == 3 && split[0] == "bones") {
if (split.size() >= 3 && split[0] == "bones") {
if (split[1].to_int() == selected) {
if (split[2] == "enabled") {
enabled_checkbox->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
enabled_checkbox->update_property();
enabled_checkbox->update_editor_property_status();
enabled_checkbox->queue_redraw();
}
if (split[2] == "position") {
position_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
position_property->update_property();
position_property->update_editor_property_status();
position_property->queue_redraw();
}
if (split[2] == "rotation") {
rotation_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
rotation_property->update_property();
rotation_property->update_editor_property_status();
rotation_property->queue_redraw();
}
if (split[2] == "scale") {
scale_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
scale_property->update_property();
scale_property->update_editor_property_status();
scale_property->queue_redraw();
}
if (split[2] == "rest") {
rest_matrix->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY);
rest_matrix->update_property();
rest_matrix->update_editor_property_status();
rest_matrix->queue_redraw();
}
if (split[2] == "bone_meta") {
meta_seen.insert(E.name);
if (!meta_editors.find(E.name)) {
EditorProperty *editor = EditorInspectorDefaultPlugin::get_editor_for_property(skeleton, E.type, E.name, PROPERTY_HINT_NONE, "", E.usage);
editor->set_label(split[3]);
editor->set_object_and_property(skeleton, E.name);
editor->set_deletable(true);
editor->set_selectable(false);
editor->connect("property_changed", callable_mp(this, &BonePropertiesEditor::_meta_changed));
editor->connect("property_deleted", callable_mp(this, &BonePropertiesEditor::_meta_deleted));
meta_section->get_vbox()->add_child(editor);
editor->update_property();
editor->update_editor_property_status();
editor->queue_redraw();
meta_editors[E.name] = editor;
}
}
}
}
}
// UI for any bone metadata prop not seen during the iteration has to be deleted
for (KeyValue<StringName, EditorProperty *> iter : meta_editors) {
if (!meta_seen.has(iter.key)) {
callable_mp((Node *)meta_section->get_vbox(), &Node::remove_child).call_deferred(iter.value);
meta_editors.remove(meta_editors.find(iter.key));
}
}
}
Skeleton3DEditor *Skeleton3DEditor::singleton = nullptr;
@ -225,12 +349,17 @@ void Skeleton3DEditor::set_keyable(const bool p_keyable) {
} else {
animation_hb->hide();
}
};
}
void Skeleton3DEditor::set_bone_options_enabled(const bool p_bone_options_enabled) {
skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_RESET_SELECTED_POSES, !p_bone_options_enabled);
skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_SELECTED_POSES_TO_RESTS, !p_bone_options_enabled);
};
}
void Skeleton3DEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("update_all"), &Skeleton3DEditor::update_all);
ClassDB::bind_method(D_METHOD("update_joint_tree"), &Skeleton3DEditor::update_joint_tree);
}
void Skeleton3DEditor::_on_click_skeleton_option(int p_skeleton_option) {
if (!skeleton) {
@ -294,6 +423,10 @@ void Skeleton3DEditor::reset_pose(const bool p_all_bones) {
ur->add_undo_method(skeleton, "set_bone_pose_scale", selected_bone, skeleton->get_bone_pose_scale(selected_bone));
ur->add_do_method(skeleton, "reset_bone_pose", selected_bone);
}
ur->add_undo_method(this, "update_joint_tree");
ur->add_do_method(this, "update_joint_tree");
ur->commit_action();
}
@ -357,6 +490,10 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) {
ur->add_do_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_pose(selected_bone));
ur->add_undo_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_rest(selected_bone));
}
ur->add_undo_method(this, "update_joint_tree");
ur->add_do_method(this, "update_joint_tree");
ur->commit_action();
}
@ -550,6 +687,7 @@ Variant Skeleton3DEditor::get_drag_data_fw(const Point2 &p_point, Control *p_fro
tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
hb->add_child(tf);
Label *label = memnew(Label(selected->get_text(0)));
label->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
hb->add_child(label);
vb->add_child(hb);
hb->set_modulate(Color(1, 1, 1, 1));
@ -620,9 +758,12 @@ void Skeleton3DEditor::move_skeleton_bone(NodePath p_skeleton_path, int32_t p_se
}
ur->add_undo_method(skeleton_node, "set_bone_parent", p_selected_boneidx, skeleton_node->get_bone_parent(p_selected_boneidx));
ur->add_do_method(skeleton_node, "set_bone_parent", p_selected_boneidx, p_target_boneidx);
ur->add_undo_method(this, "update_joint_tree");
ur->add_do_method(this, "update_joint_tree");
skeleton_node->set_bone_parent(p_selected_boneidx, p_target_boneidx);
update_joint_tree();
ur->commit_action();
}
@ -655,6 +796,107 @@ void Skeleton3DEditor::_joint_tree_selection_changed() {
void Skeleton3DEditor::_joint_tree_rmb_select(const Vector2 &p_pos, MouseButton p_button) {
}
void Skeleton3DEditor::_joint_tree_button_clicked(Object *p_item, int p_column, int p_id, MouseButton p_button) {
if (!skeleton) {
return;
}
TreeItem *tree_item = Object::cast_to<TreeItem>(p_item);
if (tree_item) {
String tree_item_metadata = tree_item->get_metadata(0);
String bone_enabled_property = tree_item_metadata + "/enabled";
String bone_parent_property = tree_item_metadata + "/parent";
String bone_name_property = tree_item_metadata + "/name";
String bone_position_property = tree_item_metadata + "/position";
String bone_rotation_property = tree_item_metadata + "/rotation";
String bone_scale_property = tree_item_metadata + "/scale";
String bone_rest_property = tree_item_metadata + "/rest";
Variant current_enabled = skeleton->get(bone_enabled_property);
Variant current_parent = skeleton->get(bone_parent_property);
Variant current_name = skeleton->get(bone_name_property);
Variant current_position = skeleton->get(bone_position_property);
Variant current_rotation = skeleton->get(bone_rotation_property);
Variant current_scale = skeleton->get(bone_scale_property);
Variant current_rest = skeleton->get(bone_rest_property);
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Revert Bone"));
bool can_revert_enabled = EditorPropertyRevert::can_property_revert(skeleton, bone_enabled_property, &current_enabled);
if (can_revert_enabled) {
bool is_valid = false;
Variant new_enabled = EditorPropertyRevert::get_property_revert_value(skeleton, bone_enabled_property, &is_valid);
if (is_valid) {
ur->add_undo_method(skeleton, "set", bone_enabled_property, current_enabled);
ur->add_do_method(skeleton, "set", bone_enabled_property, new_enabled);
}
}
bool can_revert_parent = EditorPropertyRevert::can_property_revert(skeleton, bone_parent_property, &current_parent);
if (can_revert_parent) {
bool is_valid = false;
Variant new_parent = EditorPropertyRevert::get_property_revert_value(skeleton, bone_parent_property, &is_valid);
if (is_valid) {
ur->add_undo_method(skeleton, "set", bone_parent_property, current_parent);
ur->add_do_method(skeleton, "set", bone_parent_property, new_parent);
}
}
bool can_revert_name = EditorPropertyRevert::can_property_revert(skeleton, bone_name_property, &current_name);
if (can_revert_name) {
bool is_valid = false;
Variant new_name = EditorPropertyRevert::get_property_revert_value(skeleton, bone_name_property, &is_valid);
if (is_valid) {
ur->add_undo_method(skeleton, "set", bone_name_property, current_name);
ur->add_do_method(skeleton, "set", bone_name_property, new_name);
}
}
bool can_revert_position = EditorPropertyRevert::can_property_revert(skeleton, bone_position_property, &current_position);
if (can_revert_position) {
bool is_valid = false;
Variant new_position = EditorPropertyRevert::get_property_revert_value(skeleton, bone_position_property, &is_valid);
if (is_valid) {
ur->add_undo_method(skeleton, "set", bone_position_property, current_position);
ur->add_do_method(skeleton, "set", bone_position_property, new_position);
}
}
bool can_revert_rotation = EditorPropertyRevert::can_property_revert(skeleton, bone_rotation_property, &current_rotation);
if (can_revert_rotation) {
bool is_valid = false;
Variant new_rotation = EditorPropertyRevert::get_property_revert_value(skeleton, bone_rotation_property, &is_valid);
if (is_valid) {
ur->add_undo_method(skeleton, "set", bone_rotation_property, current_rotation);
ur->add_do_method(skeleton, "set", bone_rotation_property, new_rotation);
}
}
bool can_revert_scale = EditorPropertyRevert::can_property_revert(skeleton, bone_scale_property, &current_scale);
if (can_revert_scale) {
bool is_valid = false;
Variant new_scale = EditorPropertyRevert::get_property_revert_value(skeleton, bone_scale_property, &is_valid);
if (is_valid) {
ur->add_undo_method(skeleton, "set", bone_scale_property, current_scale);
ur->add_do_method(skeleton, "set", bone_scale_property, new_scale);
}
}
bool can_revert_rest = EditorPropertyRevert::can_property_revert(skeleton, bone_rest_property, &current_rest);
if (can_revert_rest) {
bool is_valid = false;
Variant new_rest = EditorPropertyRevert::get_property_revert_value(skeleton, bone_rest_property, &is_valid);
if (is_valid) {
ur->add_undo_method(skeleton, "set", bone_rest_property, current_rest);
ur->add_do_method(skeleton, "set", bone_rest_property, new_rest);
}
}
ur->add_undo_method(this, "update_all");
ur->add_do_method(this, "update_all");
ur->commit_action();
}
return;
}
void Skeleton3DEditor::_update_properties() {
if (pose_editor) {
pose_editor->_update_properties();
@ -693,15 +935,52 @@ void Skeleton3DEditor::update_joint_tree() {
joint_item->set_selectable(0, true);
joint_item->set_metadata(0, "bones/" + itos(current_bone_idx));
String bone_enabled_property = "bones/" + itos(current_bone_idx) + "/enabled";
String bone_parent_property = "bones/" + itos(current_bone_idx) + "/parent";
String bone_name_property = "bones/" + itos(current_bone_idx) + "/name";
String bone_position_property = "bones/" + itos(current_bone_idx) + "/position";
String bone_rotation_property = "bones/" + itos(current_bone_idx) + "/rotation";
String bone_scale_property = "bones/" + itos(current_bone_idx) + "/scale";
String bone_rest_property = "bones/" + itos(current_bone_idx) + "/rest";
Variant current_enabled = skeleton->get(bone_enabled_property);
Variant current_parent = skeleton->get(bone_parent_property);
Variant current_name = skeleton->get(bone_name_property);
Variant current_position = skeleton->get(bone_position_property);
Variant current_rotation = skeleton->get(bone_rotation_property);
Variant current_scale = skeleton->get(bone_scale_property);
Variant current_rest = skeleton->get(bone_rest_property);
bool can_revert_enabled = EditorPropertyRevert::can_property_revert(skeleton, bone_enabled_property, &current_enabled);
bool can_revert_parent = EditorPropertyRevert::can_property_revert(skeleton, bone_parent_property, &current_parent);
bool can_revert_name = EditorPropertyRevert::can_property_revert(skeleton, bone_name_property, &current_name);
bool can_revert_position = EditorPropertyRevert::can_property_revert(skeleton, bone_position_property, &current_position);
bool can_revert_rotation = EditorPropertyRevert::can_property_revert(skeleton, bone_rotation_property, &current_rotation);
bool can_revert_scale = EditorPropertyRevert::can_property_revert(skeleton, bone_scale_property, &current_scale);
bool can_revert_rest = EditorPropertyRevert::can_property_revert(skeleton, bone_rest_property, &current_rest);
if (can_revert_enabled || can_revert_parent || can_revert_name || can_revert_position || can_revert_rotation || can_revert_scale || can_revert_rest) {
joint_item->add_button(0, get_editor_theme_icon(SNAME("ReloadSmall")), JOINT_BUTTON_REVERT, false, TTR("Revert"));
}
// Add the bone's children to the list of bones to be processed.
Vector<int> current_bone_child_bones = skeleton->get_bone_children(current_bone_idx);
int child_bone_size = current_bone_child_bones.size();
for (int i = 0; i < child_bone_size; i++) {
bones_to_process.push_back(current_bone_child_bones[i]);
}
if (current_bone_idx == selected_bone) {
joint_item->select(0);
}
}
}
void Skeleton3DEditor::update_all() {
_update_properties();
update_joint_tree();
}
void Skeleton3DEditor::create_editors() {
set_h_size_flags(SIZE_EXPAND_FILL);
set_focus_mode(FOCUS_ALL);
@ -728,10 +1007,10 @@ void Skeleton3DEditor::create_editors() {
// Skeleton options.
PopupMenu *p = skeleton_options->get_popup();
p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/reset_all_poses", TTR("Reset All Bone Poses")), SKELETON_OPTION_RESET_ALL_POSES);
p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/reset_selected_poses", TTR("Reset Selected Poses")), SKELETON_OPTION_RESET_SELECTED_POSES);
p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/all_poses_to_rests", TTR("Apply All Poses to Rests")), SKELETON_OPTION_ALL_POSES_TO_RESTS);
p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/selected_poses_to_rests", TTR("Apply Selected Poses to Rests")), SKELETON_OPTION_SELECTED_POSES_TO_RESTS);
p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/reset_all_poses", TTRC("Reset All Bone Poses")), SKELETON_OPTION_RESET_ALL_POSES);
p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/reset_selected_poses", TTRC("Reset Selected Poses")), SKELETON_OPTION_RESET_SELECTED_POSES);
p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/all_poses_to_rests", TTRC("Apply All Poses to Rests")), SKELETON_OPTION_ALL_POSES_TO_RESTS);
p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/selected_poses_to_rests", TTRC("Apply Selected Poses to Rests")), SKELETON_OPTION_SELECTED_POSES_TO_RESTS);
p->add_item(TTR("Create Physical Skeleton"), SKELETON_OPTION_CREATE_PHYSICAL_SKELETON);
p->add_item(TTR("Export Skeleton Profile"), SKELETON_OPTION_EXPORT_SKELETON_PROFILE);
@ -743,11 +1022,11 @@ void Skeleton3DEditor::create_editors() {
edit_mode_button = memnew(Button);
topmenu_bar->add_child(edit_mode_button);
edit_mode_button->set_theme_type_variation("FlatButton");
edit_mode_button->set_theme_type_variation(SceneStringName(FlatButton));
edit_mode_button->set_toggle_mode(true);
edit_mode_button->set_focus_mode(FOCUS_NONE);
edit_mode_button->set_tooltip_text(TTR("Edit Mode\nShow buttons on joints."));
edit_mode_button->connect("toggled", callable_mp(this, &Skeleton3DEditor::edit_mode_toggled));
edit_mode_button->connect(SceneStringName(toggled), callable_mp(this, &Skeleton3DEditor::edit_mode_toggled));
edit_mode = false;
@ -763,7 +1042,7 @@ void Skeleton3DEditor::create_editors() {
animation_hb->hide();
key_loc_button = memnew(Button);
key_loc_button->set_theme_type_variation("FlatButton");
key_loc_button->set_theme_type_variation(SceneStringName(FlatButton));
key_loc_button->set_toggle_mode(true);
key_loc_button->set_pressed(false);
key_loc_button->set_focus_mode(FOCUS_NONE);
@ -771,7 +1050,7 @@ void Skeleton3DEditor::create_editors() {
animation_hb->add_child(key_loc_button);
key_rot_button = memnew(Button);
key_rot_button->set_theme_type_variation("FlatButton");
key_rot_button->set_theme_type_variation(SceneStringName(FlatButton));
key_rot_button->set_toggle_mode(true);
key_rot_button->set_pressed(true);
key_rot_button->set_focus_mode(FOCUS_NONE);
@ -779,7 +1058,7 @@ void Skeleton3DEditor::create_editors() {
animation_hb->add_child(key_rot_button);
key_scale_button = memnew(Button);
key_scale_button->set_theme_type_variation("FlatButton");
key_scale_button->set_theme_type_variation(SceneStringName(FlatButton));
key_scale_button->set_toggle_mode(true);
key_scale_button->set_pressed(false);
key_scale_button->set_focus_mode(FOCUS_NONE);
@ -787,19 +1066,19 @@ void Skeleton3DEditor::create_editors() {
animation_hb->add_child(key_scale_button);
key_insert_button = memnew(Button);
key_insert_button->set_theme_type_variation("FlatButton");
key_insert_button->set_theme_type_variation(SceneStringName(FlatButton));
key_insert_button->set_focus_mode(FOCUS_NONE);
key_insert_button->connect(SceneStringName(pressed), callable_mp(this, &Skeleton3DEditor::insert_keys).bind(false));
key_insert_button->set_tooltip_text(TTR("Insert key (based on mask) for bones with an existing track."));
key_insert_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_to_existing_tracks", TTR("Insert Key (Existing Tracks)"), Key::INSERT));
key_insert_button->set_tooltip_text(TTRC("Insert key (based on mask) for bones with an existing track."));
key_insert_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_to_existing_tracks", TTRC("Insert Key (Existing Tracks)"), Key::INSERT));
animation_hb->add_child(key_insert_button);
key_insert_all_button = memnew(Button);
key_insert_all_button->set_theme_type_variation("FlatButton");
key_insert_all_button->set_theme_type_variation(SceneStringName(FlatButton));
key_insert_all_button->set_focus_mode(FOCUS_NONE);
key_insert_all_button->connect(SceneStringName(pressed), callable_mp(this, &Skeleton3DEditor::insert_keys).bind(true));
key_insert_all_button->set_tooltip_text(TTR("Insert key (based on mask) for all bones."));
key_insert_all_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_of_all_bones", TTR("Insert Key (All Bones)"), KeyModifierMask::CMD_OR_CTRL + Key::INSERT));
key_insert_all_button->set_tooltip_text(TTRC("Insert key (based on mask) for all bones."));
key_insert_all_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_of_all_bones", TTRC("Insert Key (All Bones)"), KeyModifierMask::CMD_OR_CTRL + Key::INSERT));
animation_hb->add_child(key_insert_all_button);
// Bone tree.
@ -822,10 +1101,11 @@ void Skeleton3DEditor::create_editors() {
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_theme_type_variation("TreeSecondary");
SET_DRAG_FORWARDING_GCD(joint_tree, Skeleton3DEditor);
s_con->add_child(joint_tree);
pose_editor = memnew(BoneTransformEditor(skeleton));
pose_editor = memnew(BonePropertiesEditor(skeleton));
pose_editor->set_label(TTR("Bone Transform"));
pose_editor->set_visible(false);
add_child(pose_editor);
@ -840,6 +1120,7 @@ void Skeleton3DEditor::_notification(int p_what) {
joint_tree->connect(SceneStringName(item_selected), callable_mp(this, &Skeleton3DEditor::_joint_tree_selection_changed));
joint_tree->connect("item_mouse_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_rmb_select));
joint_tree->connect("button_clicked", callable_mp(this, &Skeleton3DEditor::_joint_tree_button_clicked));
#ifdef TOOLS_ENABLED
skeleton->connect(SceneStringName(pose_updated), callable_mp(this, &Skeleton3DEditor::_draw_gizmo));
skeleton->connect(SceneStringName(pose_updated), callable_mp(this, &Skeleton3DEditor::_update_properties));
@ -854,13 +1135,13 @@ void Skeleton3DEditor::_notification(int p_what) {
add_theme_constant_override("separation", 0);
} break;
case NOTIFICATION_THEME_CHANGED: {
skeleton_options->set_icon(get_editor_theme_icon(SNAME("Skeleton3D")));
edit_mode_button->set_icon(get_editor_theme_icon(SNAME("ToolBoneSelect")));
key_loc_button->set_icon(get_editor_theme_icon(SNAME("KeyPosition")));
key_rot_button->set_icon(get_editor_theme_icon(SNAME("KeyRotation")));
key_scale_button->set_icon(get_editor_theme_icon(SNAME("KeyScale")));
key_insert_button->set_icon(get_editor_theme_icon(SNAME("Key")));
key_insert_all_button->set_icon(get_editor_theme_icon(SNAME("NewKey")));
skeleton_options->set_button_icon(get_editor_theme_icon(SNAME("Skeleton3D")));
edit_mode_button->set_button_icon(get_editor_theme_icon(SNAME("ToolBoneSelect")));
key_loc_button->set_button_icon(get_editor_theme_icon(SNAME("KeyPosition")));
key_rot_button->set_button_icon(get_editor_theme_icon(SNAME("KeyRotation")));
key_scale_button->set_button_icon(get_editor_theme_icon(SNAME("KeyScale")));
key_insert_button->set_button_icon(get_editor_theme_icon(SNAME("Key")));
key_insert_all_button->set_button_icon(get_editor_theme_icon(SNAME("NewKey")));
bones_section->set_bg_color(get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor)));
update_joint_tree();
@ -904,8 +1185,8 @@ Skeleton3DEditor::Skeleton3DEditor(EditorInspectorPluginSkeleton *e_plugin, Skel
singleton = this;
// Handle.
handle_material = Ref<ShaderMaterial>(memnew(ShaderMaterial));
handle_shader = Ref<Shader>(memnew(Shader));
handle_material.instantiate();
handle_shader.instantiate();
handle_shader->set_code(R"(
// Skeleton 3D gizmo handle shader.
@ -1057,11 +1338,11 @@ void Skeleton3DEditor::_subgizmo_selection_change() {
Vector<Ref<Node3DGizmo>> gizmos = skeleton->get_gizmos();
for (int i = 0; i < gizmos.size(); i++) {
Ref<EditorNode3DGizmo> gizmo = gizmos[i];
if (!gizmo.is_valid()) {
if (gizmo.is_null()) {
continue;
}
Ref<Skeleton3DGizmoPlugin> plugin = gizmo->get_plugin();
if (!plugin.is_valid()) {
if (plugin.is_null()) {
continue;
}
skeleton->set_subgizmo_selection(gizmo, selected, skeleton->get_bone_global_pose(selected));
@ -1180,16 +1461,18 @@ int Skeleton3DEditor::get_selected_bone() const {
return selected_bone;
}
Skeleton3DGizmoPlugin::Skeleton3DGizmoPlugin() {
unselected_mat = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
unselected_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
unselected_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
unselected_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
unselected_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
unselected_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
Skeleton3DGizmoPlugin::SelectionMaterials Skeleton3DGizmoPlugin::selection_materials;
selected_mat = Ref<ShaderMaterial>(memnew(ShaderMaterial));
selected_sh = Ref<Shader>(memnew(Shader));
Skeleton3DGizmoPlugin::Skeleton3DGizmoPlugin() {
selection_materials.unselected_mat.instantiate();
selection_materials.unselected_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
selection_materials.unselected_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
selection_materials.unselected_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
selection_materials.unselected_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
selection_materials.unselected_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
selection_materials.selected_mat.instantiate();
Ref<Shader> selected_sh = Ref<Shader>(memnew(Shader));
selected_sh->set_code(R"(
// Skeleton 3D gizmo bones shader.
@ -1208,14 +1491,12 @@ void fragment() {
ALPHA = COLOR.a;
}
)");
selected_mat->set_shader(selected_sh);
selection_materials.selected_mat->set_shader(selected_sh);
}
// Register properties in editor settings.
EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4));
EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/selected_bone", Color(0.8, 0.3, 0.0));
EDITOR_DEF("editors/3d_gizmos/gizmo_settings/bone_axis_length", (float)0.1);
EDITOR_DEF("editors/3d_gizmos/gizmo_settings/bone_shape", 1);
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/3d_gizmos/gizmo_settings/bone_shape", PROPERTY_HINT_ENUM, "Wire,Octahedron"));
Skeleton3DGizmoPlugin::~Skeleton3DGizmoPlugin() {
selection_materials.unselected_mat.unref();
selection_materials.selected_mat.unref();
}
bool Skeleton3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
@ -1337,6 +1618,10 @@ void Skeleton3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, c
ur->add_undo_method(skeleton, "set_bone_pose_scale", p_ids[i], se->get_bone_original_scale());
}
}
ur->add_do_method(se, "update_joint_tree");
ur->add_undo_method(se, "update_joint_tree");
ur->commit_action();
}
@ -1354,6 +1639,11 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
selected = se->get_selected_bone();
}
Ref<ArrayMesh> m = get_bones_mesh(skeleton, selected, p_gizmo->is_selected());
p_gizmo->add_mesh(m, Ref<Material>(), Transform3D(), skeleton->register_skin(skeleton->create_skin_from_rest_transforms()));
}
Ref<ArrayMesh> Skeleton3DGizmoPlugin::get_bones_mesh(Skeleton3D *p_skeleton, int p_selected, bool p_is_selected) {
Color bone_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/skeleton");
Color selected_bone_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/selected_bone");
real_t bone_axis_length = EDITOR_GET("editors/3d_gizmos/gizmo_settings/bone_axis_length");
@ -1367,11 +1657,11 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Ref<SurfaceTool> surface_tool(memnew(SurfaceTool));
surface_tool->begin(Mesh::PRIMITIVE_LINES);
if (p_gizmo->is_selected()) {
surface_tool->set_material(selected_mat);
if (p_is_selected) {
surface_tool->set_material(selection_materials.selected_mat);
} else {
unselected_mat->set_albedo(bone_color);
surface_tool->set_material(unselected_mat);
selection_materials.unselected_mat->set_albedo(bone_color);
surface_tool->set_material(selection_materials.unselected_mat);
}
LocalVector<int> bones;
@ -1385,16 +1675,16 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
weights[0] = 1;
int current_bone_index = 0;
Vector<int> bones_to_process = skeleton->get_parentless_bones();
Vector<int> bones_to_process = p_skeleton->get_parentless_bones();
while (bones_to_process.size() > current_bone_index) {
int current_bone_idx = bones_to_process[current_bone_index];
current_bone_index++;
Color current_bone_color = (current_bone_idx == selected) ? selected_bone_color : bone_color;
Color current_bone_color = (current_bone_idx == p_selected) ? selected_bone_color : bone_color;
Vector<int> child_bones_vector;
child_bones_vector = skeleton->get_bone_children(current_bone_idx);
child_bones_vector = p_skeleton->get_bone_children(current_bone_idx);
int child_bones_size = child_bones_vector.size();
for (int i = 0; i < child_bones_size; i++) {
@ -1405,8 +1695,8 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
int child_bone_idx = child_bones_vector[i];
Vector3 v0 = skeleton->get_bone_global_rest(current_bone_idx).origin;
Vector3 v1 = skeleton->get_bone_global_rest(child_bone_idx).origin;
Vector3 v0 = p_skeleton->get_bone_global_rest(current_bone_idx).origin;
Vector3 v1 = p_skeleton->get_bone_global_rest(child_bone_idx).origin;
Vector3 d = (v1 - v0).normalized();
real_t dist = v0.distance_to(v1);
@ -1414,7 +1704,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
int closest = -1;
real_t closest_d = 0.0;
for (int j = 0; j < 3; j++) {
real_t dp = Math::abs(skeleton->get_bone_global_rest(current_bone_idx).basis[j].normalized().dot(d));
real_t dp = Math::abs(p_skeleton->get_bone_global_rest(current_bone_idx).basis[j].normalized().dot(d));
if (j == 0 || dp > closest_d) {
closest = j;
}
@ -1441,7 +1731,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
for (int j = 0; j < 3; j++) {
Vector3 axis;
if (first == Vector3()) {
axis = d.cross(d.cross(skeleton->get_bone_global_rest(current_bone_idx).basis[j])).normalized();
axis = d.cross(d.cross(p_skeleton->get_bone_global_rest(current_bone_idx).basis[j])).normalized();
first = axis;
} else {
axis = d.cross(first).normalized();
@ -1496,7 +1786,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
surface_tool->add_vertex(v0);
surface_tool->set_bones(bones);
surface_tool->set_weights(weights);
surface_tool->add_vertex(v0 + (skeleton->get_bone_global_rest(current_bone_idx).basis.inverse())[j].normalized() * dist * bone_axis_length);
surface_tool->add_vertex(v0 + (p_skeleton->get_bone_global_rest(current_bone_idx).basis.inverse())[j].normalized() * dist * bone_axis_length);
if (j == closest) {
continue;
@ -1513,7 +1803,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
surface_tool->add_vertex(v1);
surface_tool->set_bones(bones);
surface_tool->set_weights(weights);
surface_tool->add_vertex(v1 + (skeleton->get_bone_global_rest(child_bone_idx).basis.inverse())[j].normalized() * dist * bone_axis_length);
surface_tool->add_vertex(v1 + (p_skeleton->get_bone_global_rest(child_bone_idx).basis.inverse())[j].normalized() * dist * bone_axis_length);
if (j == closest) {
continue;
@ -1526,6 +1816,5 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
}
Ref<ArrayMesh> m = surface_tool->commit();
p_gizmo->add_mesh(m, Ref<Material>(), Transform3D(), skeleton->register_skin(skeleton->create_skin_from_rest_transforms()));
return surface_tool->commit();
}