From 60a1ca98d96777f96e4565413e7c326cf64f0829 Mon Sep 17 00:00:00 2001 From: badlogic Date: Fri, 15 Apr 2022 00:05:47 +0200 Subject: [PATCH] [godot] More work on animation mixes inspector. --- .../assets/spineboy/spinebody-data-res.tres | 12 +- spine-godot/spine_godot/SpineEditorPlugin.cpp | 139 +++++++++++------- spine-godot/spine_godot/SpineEditorPlugin.h | 25 +++- .../spine_godot/SpineSkeletonDataResource.h | 5 +- 4 files changed, 117 insertions(+), 64 deletions(-) diff --git a/spine-godot/example/assets/spineboy/spinebody-data-res.tres b/spine-godot/example/assets/spineboy/spinebody-data-res.tres index 9bc3ba1a1..8ac4ee3db 100644 --- a/spine-godot/example/assets/spineboy/spinebody-data-res.tres +++ b/spine-godot/example/assets/spineboy/spinebody-data-res.tres @@ -4,16 +4,16 @@ [ext_resource path="res://assets/spineboy/spineboy-pro.json" type="SpineSkeletonFileResource" id=2] [sub_resource type="SpineAnimationMix" id=1] -from = "death" -to = "aim" -mix = 1.2 +from = "idle" +to = "death" +mix = 1.0 [sub_resource type="SpineAnimationMix" id=2] -from = "idle-turn" -to = "aim" +from = "run" +to = "idle" +mix = 0.2 [resource] atlas_res = ExtResource( 1 ) skeleton_file_res = ExtResource( 2 ) -default_mix = 0.2 animation_mixes = [ SubResource( 1 ), SubResource( 2 ) ] diff --git a/spine-godot/spine_godot/SpineEditorPlugin.cpp b/spine-godot/spine_godot/SpineEditorPlugin.cpp index 4195e7e47..507ef89ca 100644 --- a/spine-godot/spine_godot/SpineEditorPlugin.cpp +++ b/spine-godot/spine_godot/SpineEditorPlugin.cpp @@ -76,27 +76,24 @@ SpineEditorPlugin::SpineEditorPlugin(EditorNode *node) { add_import_plugin(memnew(SpineAtlasResourceImportPlugin)); add_import_plugin(memnew(SpineJsonResourceImportPlugin)); add_import_plugin(memnew(SpineBinaryResourceImportPlugin)); - add_inspector_plugin(memnew(SpineAnimationMixesInspectorPlugin)); + add_inspector_plugin(memnew(SpineSkeletonDataResourceInspectorPlugin)); } SpineEditorPlugin::~SpineEditorPlugin() { } -bool SpineEditorPlugin::handles(Object *object) const { - return object->is_class("SpineSprite") || object->is_class("SpineSkeletonDataResource"); -} - -bool SpineAnimationMixesInspectorPlugin::can_handle(Object *object) { +bool SpineSkeletonDataResourceInspectorPlugin::can_handle(Object *object) { return object->is_class("SpineSkeletonDataResource"); } -bool SpineAnimationMixesInspectorPlugin::parse_property(Object *object, Variant::Type type, const String &path, - PropertyHint hint, const String &hint_text, int usage) { - if (path == "animation_mixes" && object) { +bool SpineSkeletonDataResourceInspectorPlugin::parse_property(Object *object, Variant::Type type, const String &path, + PropertyHint hint, const String &hint_text, int usage) { + if (path == "animation_mixes") { + Ref skeleton_data = Object::cast_to(object); + if (!skeleton_data.is_valid() || !skeleton_data->is_skeleton_data_loaded()) return true; auto mixes_property = memnew(SpineEditorPropertyAnimationMixes); - mixes_property->setup(Object::cast_to(object)); + mixes_property->setup(skeleton_data); add_property_editor(path, mixes_property); - return true; } return false; } @@ -107,10 +104,8 @@ SpineEditorPropertyAnimationMixes::SpineEditorPropertyAnimationMixes(): skeleton void SpineEditorPropertyAnimationMixes::_bind_methods() { ClassDB::bind_method(D_METHOD("add_mix"), &SpineEditorPropertyAnimationMixes::add_mix); ClassDB::bind_method(D_METHOD("delete_mix"), &SpineEditorPropertyAnimationMixes::delete_mix); - ClassDB::bind_method(D_METHOD("property_changed"), &SpineEditorPropertyAnimationMixes::property_changed); } - void SpineEditorPropertyAnimationMixes::add_mix() { if (!skeleton_data.is_valid() || !skeleton_data->is_skeleton_data_loaded() || updating) return; @@ -136,13 +131,6 @@ void SpineEditorPropertyAnimationMixes::delete_mix(int64_t idx) { emit_changed(get_edited_property(), mixes); } -void SpineEditorPropertyAnimationMixes::property_changed(const String &property, Variant value, const String &name, bool changing, Ref mix) { - if (property == "from") mix->set_from(value); - if (property == "to") mix->set_to(value); - if (property == "mix") mix->set_mix(value); - emit_changed(get_edited_property(), skeleton_data->get_animation_mixes().duplicate()); -} - void SpineEditorPropertyAnimationMixes::update_property() { if (updating) return; updating = true; @@ -169,49 +157,100 @@ void SpineEditorPropertyAnimationMixes::update_property() { Array mixes = skeleton_data->get_animation_mixes(); for (int i = 0; i < mixes.size(); i++) { Ref mix = mixes[i]; + auto hbox = memnew(HBoxContainer); - hbox->set_h_size_flags(SIZE_FILL); - - auto from_enum = memnew(EditorPropertyTextEnum); - from_enum->set_h_size_flags(SIZE_EXPAND_FILL); - from_enum->setup(animation_names); - from_enum->set_object_and_property(*mix, "from"); - from_enum->update_property(); - from_enum->connect("property_changed", this, "property_changed", varray(mix)); - hbox->add_child(from_enum); - - auto to_enum = memnew(EditorPropertyTextEnum); - to_enum->set_h_size_flags(SIZE_EXPAND_FILL); - to_enum->setup(animation_names); - to_enum->set_object_and_property(*mix, "to"); - to_enum->update_property(); - to_enum->connect("property_changed", this, "property_changed", varray(mix)); - hbox->add_child(to_enum); - - auto mix_float = memnew(EditorPropertyFloat); - mix_float->set_h_size_flags(SIZE_EXPAND_FILL); - mix_float->setup(0, 9999999, 0.001, true, false, false, false); - mix_float->set_object_and_property(*mix, "mix"); - mix_float->update_property(); - mix_float->connect("property_changed", this, "property_changed", varray(mix)); - hbox->add_child(mix_float); - + hbox->set_h_size_flags(SIZE_EXPAND_FILL); + container->add_child(hbox); + + auto mix_property = memnew(SpineEditorPropertyAnimationMix); + mix_property->set_h_size_flags(SIZE_EXPAND_FILL); + hbox->add_child(mix_property); + mix_property->setup(skeleton_data, mix); + mix_property->set_object_and_property(*mix, ""); + mix_property->update_property(); + auto delete_button = memnew(Button); + hbox->add_child(delete_button); delete_button->set_text("Delete"); delete_button->connect("pressed", this, "delete_mix", varray(i)); - hbox->add_child(delete_button); - - container->add_child(hbox); } auto add_mix_button = memnew(Button); add_mix_button->set_text("Add mix"); - add_mix_button->set_h_size_flags(SIZE_EXPAND_FILL); + // add_mix_button->set_h_size_flags(SIZE_EXPAND_FILL); add_mix_button->connect("pressed", this, "add_mix"); container->add_child(add_mix_button); updating = false; } +SpineEditorPropertyAnimationMix::SpineEditorPropertyAnimationMix(): skeleton_data(nullptr), container(nullptr), updating(false) { +} + +void SpineEditorPropertyAnimationMix::setup(Ref skeleton_data, Ref mix) { + this->skeleton_data = skeleton_data; + this->mix = mix; +} + +void SpineEditorPropertyAnimationMix::_bind_methods() { + ClassDB::bind_method(D_METHOD("data_changed"), &SpineEditorPropertyAnimationMix::data_changed); +} + +void SpineEditorPropertyAnimationMix::data_changed(const String &property, Variant value, const String &name, bool changing) { + if (property == "from") mix->set_from(value); + if (property == "to") mix->set_to(value); + if (property == "mix") mix->set_mix(value); + emit_changed(property, value); + skeleton_data->update_mixes(); +} + +void SpineEditorPropertyAnimationMix::update_property() { + if (updating) return; + updating = true; + + if (container) { + memdelete(container); + container->queue_delete(); + container = nullptr; + } + + if (!skeleton_data.is_valid() || !skeleton_data->is_skeleton_data_loaded()) { + updating = false; + return; + } + + Vector animation_names; + skeleton_data->get_animation_names(animation_names); + + container = memnew(HBoxContainer); + container->set_h_size_flags(SIZE_EXPAND_FILL); + add_child(container); + + auto from_enum = memnew(EditorPropertyTextEnum); + from_enum->set_h_size_flags(SIZE_EXPAND_FILL); + container->add_child(from_enum); + from_enum->setup(animation_names); + from_enum->set_object_and_property(get_edited_object(), "from"); + from_enum->update_property(); + from_enum->connect("property_changed", this, "data_changed"); + + auto to_enum = memnew(EditorPropertyTextEnum); + to_enum->set_h_size_flags(SIZE_EXPAND_FILL); + container->add_child(to_enum); + to_enum->setup(animation_names); + to_enum->set_object_and_property(get_edited_object(), "to"); + to_enum->update_property(); + to_enum->connect("property_changed", this, "data_changed"); + + auto mix_float = memnew(EditorPropertyFloat); + mix_float->set_h_size_flags(SIZE_EXPAND_FILL); + container->add_child(mix_float); + mix_float->setup(0, 9999999, 0.001, true, false, false, false); + mix_float->set_object_and_property(get_edited_object(), "mix"); + mix_float->update_property(); + mix_float->connect("property_changed", this, "property_changed"); + + updating = false; +} #endif diff --git a/spine-godot/spine_godot/SpineEditorPlugin.h b/spine-godot/spine_godot/SpineEditorPlugin.h index 4c503adaf..d1d853c6d 100644 --- a/spine-godot/spine_godot/SpineEditorPlugin.h +++ b/spine-godot/spine_godot/SpineEditorPlugin.h @@ -121,15 +121,13 @@ public: String get_name() const override { return "SpineEditorPlugin"; } bool has_main_screen() const { return false; } - - bool handles(Object *object) const override; }; -class SpineAnimationMixesInspectorPlugin: public EditorInspectorPlugin { - GDCLASS(SpineAnimationMixesInspectorPlugin, EditorInspectorPlugin) +class SpineSkeletonDataResourceInspectorPlugin: public EditorInspectorPlugin { + GDCLASS(SpineSkeletonDataResourceInspectorPlugin, EditorInspectorPlugin) public: - SpineAnimationMixesInspectorPlugin() = default; + SpineSkeletonDataResourceInspectorPlugin() = default; bool can_handle(Object *object) override; bool parse_property(Object *object, Variant::Type type, const String &path, PropertyHint hint, const String &hint_text, int usage) override; @@ -145,13 +143,28 @@ class SpineEditorPropertyAnimationMixes: public EditorProperty { static void _bind_methods(); void add_mix(); void delete_mix(int64_t idx); - void property_changed(const String &property, Variant value, const String &name, bool changing, Ref mix); public: SpineEditorPropertyAnimationMixes(); void setup(Ref skeleton_data) { this->skeleton_data = skeleton_data; }; virtual void update_property(); }; +class SpineEditorPropertyAnimationMix: public EditorProperty { + GDCLASS(SpineEditorPropertyAnimationMix, EditorProperty) + + Ref skeleton_data; + Ref mix; + HBoxContainer *container; + bool updating; + + static void _bind_methods(); + void data_changed(const String &property, Variant value, const String &name, bool changing); +public: + SpineEditorPropertyAnimationMix(); + void setup(Ref skeleton_data, Ref mix); + virtual void update_property(); +}; + #endif #endif//GODOT_SPINEEDITORPLUGIN_H diff --git a/spine-godot/spine_godot/SpineSkeletonDataResource.h b/spine-godot/spine_godot/SpineSkeletonDataResource.h index 27daae11d..d780ab999 100644 --- a/spine-godot/spine_godot/SpineSkeletonDataResource.h +++ b/spine-godot/spine_godot/SpineSkeletonDataResource.h @@ -57,8 +57,6 @@ private: void load_res(spine::Atlas *atlas, const String &json, const Vector &binary); - void update_mixes(); - public: SpineSkeletonDataResource(); virtual ~SpineSkeletonDataResource(); @@ -87,6 +85,9 @@ public: Array get_animation_mixes(); + // Used by SpineEditorPropertyAnimationMix(es) to update the underlying AnimationState + void update_mixes(); + // Spine API Ref find_bone(const String &bone_name) const;