Skip to content

Commit

Permalink
SkeletonDefinition Implementation
Browse files Browse the repository at this point in the history
Allows Skeletons to share a common definition, as well as export
skeletons for future use
  • Loading branch information
marstaik committed Nov 17, 2019
1 parent bb41f0b commit 6079927
Show file tree
Hide file tree
Showing 7 changed files with 419 additions and 12 deletions.
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

0 comments on commit 6079927

Please sign in to comment.