Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SkeletonDefinition Implementation #33684

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 34 additions & 3 deletions editor/plugins/skeleton_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@

#include "skeleton_editor_plugin.h"

#include "core/io/resource_saver.h"
#include "editor/editor_file_dialog.h"
#include "scene/3d/collision_shape.h"
#include "scene/3d/physics_body.h"
#include "scene/3d/physics_joint.h"
#include "scene/resources/capsule_shape.h"
#include "scene/resources/skeleton_definition.h"
#include "scene/resources/sphere_shape.h"
#include "spatial_editor_plugin.h"

Expand All @@ -45,7 +48,26 @@ void SkeletonEditor::_on_click_option(int p_option) {
switch (p_option) {
case MENU_OPTION_CREATE_PHYSICAL_SKELETON: {
create_physical_skeleton();
} break;
break;
}
case MENU_OPTION_SAVE_DEFINITION: {
save_skeleton_definition();
break;
}
}
}

void SkeletonEditor::save_skeleton_definition() {
file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
file_dialog->popup_centered_ratio();
}

void SkeletonEditor::_file_selected(const String &p_file) {
const Ref<SkeletonDefinition> def = SkeletonDefinition::create_from_skeleton(skeleton);
const Error result = ResourceSaver::save(p_file, def);

if (result != Error::OK) {
ERR_FAIL_MSG("Failed to Save the SkeletonDefinition");
}
}

Expand Down Expand Up @@ -132,8 +154,11 @@ void SkeletonEditor::edit(Skeleton *p_node) {
}

void SkeletonEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
get_tree()->connect("node_removed", this, "_node_removed");
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
get_tree()->connect("node_removed", this, "_node_removed");
file_dialog->connect("file_selected", this, "_file_selected");
}
}
}

Expand All @@ -148,6 +173,7 @@ void SkeletonEditor::_node_removed(Node *p_node) {
void SkeletonEditor::_bind_methods() {
ClassDB::bind_method("_on_click_option", &SkeletonEditor::_on_click_option);
ClassDB::bind_method("_node_removed", &SkeletonEditor::_node_removed);
ClassDB::bind_method(D_METHOD("_file_selected"), &SkeletonEditor::_file_selected);
}

SkeletonEditor::SkeletonEditor() {
Expand All @@ -159,9 +185,14 @@ SkeletonEditor::SkeletonEditor() {
options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Skeleton", "EditorIcons"));

options->get_popup()->add_item(TTR("Create physical skeleton"), MENU_OPTION_CREATE_PHYSICAL_SKELETON);
options->get_popup()->add_item(TTR("Export Skeleton Definition"), MENU_OPTION_SAVE_DEFINITION);

options->get_popup()->connect("id_pressed", this, "_on_click_option");
options->hide();

file_dialog = memnew(EditorFileDialog);
file_dialog->add_filter("*.skel");
options->add_child(file_dialog);
}

SkeletonEditor::~SkeletonEditor() {}
Expand Down
9 changes: 8 additions & 1 deletion editor/plugins/skeleton_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@

class PhysicalBone;
class Joint;
class EditorFileDialog;

class SkeletonEditor : public Node {
GDCLASS(SkeletonEditor, Node);

enum Menu {
MENU_OPTION_CREATE_PHYSICAL_SKELETON
MENU_OPTION_CREATE_PHYSICAL_SKELETON,
MENU_OPTION_SAVE_DEFINITION
};

struct BoneInfo {
Expand All @@ -56,10 +58,15 @@ class SkeletonEditor : public Node {

MenuButton *options;

EditorFileDialog *file_dialog;

void _on_click_option(int p_option);

friend class SkeletonEditorPlugin;

void save_skeleton_definition();
void _file_selected(const String &p_file);

protected:
void _notification(int p_what);
void _node_removed(Node *p_node);
Expand Down
105 changes: 98 additions & 7 deletions scene/3d/skeleton.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

#include "core/project_settings.h"
#include "scene/3d/physics_body.h"
#include "scene/resources/skeleton_definition.h"
#include "scene/resources/surface_tool.h"

void SkinReference::_skin_changed() {
Expand Down Expand Up @@ -158,9 +159,14 @@ void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const {
for (int i = 0; i < bones.size(); i++) {

String prep = "bones/" + itos(i) + "/";
p_list->push_back(PropertyInfo(Variant::STRING, prep + "name"));
p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1"));
p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest"));
// Only write out the bone properties if we dont have a skeleton defintiion, otherwise we will load them from
// there
if (skeleton_definition == nullptr) {
p_list->push_back(PropertyInfo(Variant::STRING, prep + "name"));
p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1"));
p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest"));
}

p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled"));
p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
p_list->push_back(PropertyInfo(Variant::ARRAY, prep + "bound_children"));
Expand Down Expand Up @@ -354,7 +360,7 @@ Transform Skeleton::get_bone_global_pose(int p_bone) const {

// skeleton creation api
void Skeleton::add_bone(const String &p_name) {

ERR_FAIL_COND(skeleton_definition != nullptr);
ERR_FAIL_COND(p_name == "" || p_name.find(":") != -1 || p_name.find("/") != -1);

for (int i = 0; i < bones.size(); i++) {
Expand Down Expand Up @@ -405,7 +411,7 @@ int Skeleton::get_bone_count() const {
}

void Skeleton::set_bone_parent(int p_bone, int p_parent) {

ERR_FAIL_COND(skeleton_definition != nullptr);
ERR_FAIL_INDEX(p_bone, bones.size());
ERR_FAIL_COND(p_parent != -1 && (p_parent < 0));

Expand All @@ -415,7 +421,7 @@ void Skeleton::set_bone_parent(int p_bone, int p_parent) {
}

void Skeleton::unparent_bone_and_rest(int p_bone) {

ERR_FAIL_COND(skeleton_definition != nullptr);
ERR_FAIL_INDEX(p_bone, bones.size());

_update_process_order();
Expand Down Expand Up @@ -452,7 +458,7 @@ int Skeleton::get_bone_parent(int p_bone) const {
}

void Skeleton::set_bone_rest(int p_bone, const Transform &p_rest) {

ERR_FAIL_COND(skeleton_definition != nullptr);
ERR_FAIL_INDEX(p_bone, bones.size());

bones.write[p_bone].rest = p_rest;
Expand Down Expand Up @@ -514,6 +520,7 @@ void Skeleton::get_bound_child_nodes_to_bone(int p_bone, List<Node *> *p_bound)
}

void Skeleton::clear_bones() {
ERR_FAIL_COND(skeleton_definition != nullptr);

bones.clear();
process_order_dirty = true;
Expand Down Expand Up @@ -571,6 +578,7 @@ int Skeleton::get_process_order(int p_idx) {
}

void Skeleton::localize_rests() {
ERR_FAIL_COND(skeleton_definition != nullptr);

_update_process_order();

Expand Down Expand Up @@ -796,6 +804,84 @@ Ref<SkinReference> Skeleton::register_skin(const Ref<Skin> &p_skin) {
return skin_ref;
}

void Skeleton::set_skeleton_definition(Ref<SkeletonDefinition> p_definition) {

struct BoneTemp {
String name;
#ifndef _3D_DISABLED
PhysicalBone *physical_bone;
#endif // _3D_DISABLED
List<Node *> bound_nodes;
};

Vector<BoneTemp> bone_temps;
for (BoneId i = 0; i < bones.size(); ++i) {
BoneTemp temp;
temp.name = bones[i].name;

#ifndef _3D_DISABLED
temp.physical_bone = bones[i].physical_bone;
#endif // _3D_DISABLED

for (int j = 0; j < bones[i].nodes_bound.size(); ++j) {
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(bones[i].nodes_bound[j]));
if (node)
temp.bound_nodes.push_back(node);
}

bone_temps.push_back(temp);
}

// Remove the skeleton definition first
skeleton_definition = Ref<SkeletonDefinition>();
if (p_definition == nullptr)
return;

clear_bones();

const int bone_count = p_definition->get_bone_count();
for (BoneId i = 0; i < bone_count; ++i) {
add_bone(p_definition->get_bone_name(i));
set_bone_parent(i, p_definition->get_bone_parent(i));
set_bone_rest(i, p_definition->get_bone_rest(i));
}

for (BoneId old_id = 0; old_id < bone_temps.size(); ++old_id) {
BoneTemp &bone = bone_temps.write[old_id];

BoneId new_id = find_bone(bone.name);

if (new_id == -1) {
// We don't want to re-parent physical bones (if we cant match), just kill them off
#ifndef _3D_DISABLED
if (bone.physical_bone) {
bone.physical_bone->set_owner(nullptr);
bone.physical_bone = nullptr;
}
#endif // _3D_DISABLED

// Attempt to re-parent any nodes to the root if we cant find anything
new_id = 0;
}

#ifndef _3D_DISABLED
if (bone.physical_bone) {
bind_physical_bone_to_bone(new_id, bone.physical_bone);
}
#endif // _3D_DISABLED

for (List<Node *>::Element *el = bone.bound_nodes.front(); el != nullptr; el = el->next()) {
bind_child_node_to_bone(new_id, el->get());
}
}

skeleton_definition = p_definition;
}

Ref<SkeletonDefinition> Skeleton::get_skeleton_definition() const {
return skeleton_definition;
}

void Skeleton::_bind_methods() {

ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton::add_bone);
Expand Down Expand Up @@ -843,6 +929,11 @@ void Skeleton::_bind_methods() {

#endif // _3D_DISABLED

ClassDB::bind_method(D_METHOD("get_skeleton_definition"), &Skeleton::get_skeleton_definition);
ClassDB::bind_method(D_METHOD("set_skeleton_definition", "skeleton_definition"), &Skeleton::set_skeleton_definition);

ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skeleton_definition", PROPERTY_HINT_RESOURCE_TYPE), "set_skeleton_definition", "get_skeleton_definition");

BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
}

Expand Down
12 changes: 11 additions & 1 deletion scene/3d/skeleton.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,17 @@
#include "scene/3d/spatial.h"
#include "scene/resources/skin.h"

#ifndef _3D_DISABLED
#ifndef BONE_ID_DEF
#define BONE_ID_DEF
typedef int BoneId;
#endif // BONE_ID_DEF

#ifndef _3D_DISABLED
class PhysicalBone;
#endif // _3D_DISABLED

class Skeleton;
class SkeletonDefinition;

class SkinReference : public Reference {
GDCLASS(SkinReference, Reference)
Expand All @@ -68,6 +72,7 @@ class Skeleton : public Spatial {

private:
friend class SkinReference;
friend class SkeletonDefinition;

Set<SkinReference *> skin_bindings;

Expand Down Expand Up @@ -122,6 +127,8 @@ class Skeleton : public Spatial {
void _make_dirty();
bool dirty;

Ref<SkeletonDefinition> skeleton_definition;

// bind helpers
Array _get_bound_child_nodes_to_bone(int p_bone) const {

Expand Down Expand Up @@ -196,6 +203,9 @@ class Skeleton : public Spatial {

Ref<SkinReference> register_skin(const Ref<Skin> &p_skin);

void set_skeleton_definition(Ref<SkeletonDefinition> p_definition);
Ref<SkeletonDefinition> get_skeleton_definition() const;

#ifndef _3D_DISABLED
// Physical bone API

Expand Down
2 changes: 2 additions & 0 deletions scene/register_scene_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
#include "scene/resources/rectangle_shape_2d.h"
#include "scene/resources/resource_format_text.h"
#include "scene/resources/segment_shape_2d.h"
#include "scene/resources/skeleton_definition.h"
#include "scene/resources/sky.h"
#include "scene/resources/sphere_shape.h"
#include "scene/resources/surface_tool.h"
Expand Down Expand Up @@ -368,6 +369,7 @@ void register_scene_types() {

ClassDB::register_class<Spatial>();
ClassDB::register_virtual_class<SpatialGizmo>();
ClassDB::register_class<SkeletonDefinition>();
ClassDB::register_class<Skeleton>();
ClassDB::register_class<AnimationPlayer>();
ClassDB::register_class<Tween>();
Expand Down
Loading