Эх сурвалжийг харах

Merge branch '4.2-beta' of https://github.com/esotericsoftware/spine-runtimes into 4.2-beta

badlogic 3 жил өмнө
parent
commit
898743739d
25 өөрчлөгдсөн 255 нэмэгдсэн , 92 устгасан
  1. 4 4
      spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp
  2. 1 1
      spine-godot/example/assets/mix-and-match/mix-and-match.atlas.import
  3. 1 1
      spine-godot/example/assets/raptor/raptor.atlas.import
  4. 13 1
      spine-godot/example/assets/spineboy/spinebody-data-res.tres
  5. 1 1
      spine-godot/example/assets/spineboy/spineboy.atlas.import
  6. 2 24
      spine-godot/example/examples/helloworld/helloworld.tscn
  7. 1 1
      spine-godot/example/examples/helloworld/spineboy-helloworld.gd
  8. 12 0
      spine-godot/example/examples/simple-input/simple-input.tscn
  9. 19 0
      spine-godot/example/examples/simple-input/spineboy-simple-input.gd
  10. 1 1
      spine-godot/example/project.godot
  11. 1 2
      spine-godot/setup.sh
  12. 1 1
      spine-godot/spine_godot/SpineAnimation.h
  13. 3 3
      spine-godot/spine_godot/SpineAtlasResource.cpp
  14. 1 4
      spine-godot/spine_godot/SpineAtlasResource.h
  15. 28 1
      spine-godot/spine_godot/SpineEditorPlugin.cpp
  16. 57 20
      spine-godot/spine_godot/SpineEditorPlugin.h
  17. 2 0
      spine-godot/spine_godot/SpineEvent.h
  18. 1 0
      spine-godot/spine_godot/SpineIkConstraint.h
  19. 65 20
      spine-godot/spine_godot/SpineSkeletonDataResource.cpp
  20. 36 2
      spine-godot/spine_godot/SpineSkeletonDataResource.h
  21. 1 0
      spine-godot/spine_godot/icons/icon_spine_atlas_resource.svg
  22. 1 0
      spine-godot/spine_godot/icons/icon_spine_skeleton_data_resource.svg
  23. 1 0
      spine-godot/spine_godot/icons/icon_spine_skeleton_file_resource.svg
  24. 1 0
      spine-godot/spine_godot/icons/icon_spine_sprite.svg
  25. 1 5
      spine-godot/spine_godot/register_types.cpp

+ 4 - 4
spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp

@@ -455,25 +455,25 @@ Skin *SkeletonBinary::readSkin(DataInput *input, bool defaultSkin, SkeletonData
 		skin = new (__FILE__, __LINE__) Skin(readStringRef(input, skeletonData));
 		for (int i = 0, n = readVarint(input, true); i < n; i++) {
 			int boneIndex = readVarint(input, true);
-			if (boneIndex >= skeletonData->_bones.size()) return NULL;
+			if (boneIndex >= (int)skeletonData->_bones.size()) return NULL;
 			skin->getBones().add(skeletonData->_bones[boneIndex]);
 		}
 
 		for (int i = 0, n = readVarint(input, true); i < n; i++) {
 			int ikIndex = readVarint(input, true);
-			if (ikIndex >= skeletonData->_ikConstraints.size()) return NULL;
+			if (ikIndex >= (int)skeletonData->_ikConstraints.size()) return NULL;
 			skin->getConstraints().add(skeletonData->_ikConstraints[ikIndex]);
 		}
 
 		for (int i = 0, n = readVarint(input, true); i < n; i++) {
 			int transformIndex = readVarint(input, true);
-			if (transformIndex >= skeletonData->_transformConstraints.size()) return NULL;
+			if (transformIndex >= (int)skeletonData->_transformConstraints.size()) return NULL;
 			skin->getConstraints().add(skeletonData->_transformConstraints[transformIndex]);
 		}
 
 		for (int i = 0, n = readVarint(input, true); i < n; i++) {
 			int pathIndex = readVarint(input, true);
-			if (pathIndex >= skeletonData->_pathConstraints.size()) return NULL;
+			if (pathIndex >= (int)skeletonData->_pathConstraints.size()) return NULL;
 			skin->getConstraints().add(skeletonData->_pathConstraints[pathIndex]);
 		}
 		slotCount = readVarint(input, true);

+ 1 - 1
spine-godot/example/assets/mix-and-match/mix-and-match.atlas.import

@@ -11,4 +11,4 @@ dest_files=[ "res://.import/mix-and-match.atlas-3d349b543ecdcc01fb29033adaef0841
 
 [params]
 
-normal_texture_prefix="n"
+normal_map_prefix="n"

+ 1 - 1
spine-godot/example/assets/raptor/raptor.atlas.import

@@ -11,4 +11,4 @@ dest_files=[ "res://.import/raptor.atlas-66da4b831eebf404341993162ba3ddb8.spatla
 
 [params]
 
-normal_texture_prefix="n"
+normal_map_prefix="n"

+ 13 - 1
spine-godot/example/assets/spineboy/spinebody-data-res.tres

@@ -1,10 +1,22 @@
-[gd_resource type="SpineSkeletonDataResource" load_steps=3 format=2]
+[gd_resource type="SpineSkeletonDataResource" load_steps=5 format=2]
 
 [ext_resource path="res://assets/spineboy/spineboy.atlas" type="SpineAtlasResource" id=1]
 [ext_resource path="res://assets/spineboy/spineboy-pro.json" type="SpineSkeletonFileResource" id=2]
 
+[sub_resource type="SpineAnimationMix" id=1]
+from = "run"
+to = "idle"
+mix = 1.0
+
+[sub_resource type="SpineAnimationMix" id=2]
+from = "idle"
+to = "run"
+mix = 1.0
+
 [resource]
 atlas_res = ExtResource( 1 )
 skeleton_file_res = ExtResource( 2 )
+default_mix = 0.2
+animation_mixes = [ SubResource( 1 ), SubResource( 2 ), null, null ]
 animations = null
 skins = null

+ 1 - 1
spine-godot/example/assets/spineboy/spineboy.atlas.import

@@ -11,4 +11,4 @@ dest_files=[ "res://.import/spineboy.atlas-54c12b5ff1cdaaa1b4e452a7d0d868c9.spat
 
 [params]
 
-normal_texture_prefix="n"
+normal_map_prefix="n"

+ 2 - 24
spine-godot/example/examples/helloworld/helloworld.tscn

@@ -1,34 +1,12 @@
-[gd_scene load_steps=7 format=2]
+[gd_scene load_steps=3 format=2]
 
 [ext_resource path="res://examples/helloworld/spineboy-helloworld.gd" type="Script" id=1]
-[ext_resource path="res://examples/mix-and-match/mix-and-match.gd" type="Script" id=2]
 [ext_resource path="res://assets/spineboy/spinebody-data-res.tres" type="SpineSkeletonDataResource" id=3]
-[ext_resource path="res://assets/mix-and-match/mix-and-match-data.tres" type="SpineSkeletonDataResource" id=4]
-[ext_resource path="res://assets/raptor/raprot-data.tres" type="SpineSkeletonDataResource" id=5]
-
-[sub_resource type="GDScript" id=1]
-script/source = "extends SpineSprite
-
-func _ready():
-	get_animation_state().set_animation(\"walk\", true)
-"
 
 [node name="Node2D" type="Node2D"]
 
 [node name="Spineboy" type="SpineSprite" parent="."]
-position = Vector2( 137.107, 540.132 )
+position = Vector2( 496.207, 477.185 )
 scale = Vector2( 0.466832, 0.466832 )
 skeleton_data_res = ExtResource( 3 )
 script = ExtResource( 1 )
-
-[node name="MixAndMatch" type="SpineSprite" parent="."]
-position = Vector2( 402.469, 534.677 )
-scale = Vector2( 0.366163, 0.366163 )
-skeleton_data_res = ExtResource( 4 )
-script = ExtResource( 2 )
-
-[node name="Raptor" type="SpineSprite" parent="."]
-position = Vector2( 793.667, 527.026 )
-scale = Vector2( 0.343143, 0.343143 )
-skeleton_data_res = ExtResource( 5 )
-script = SubResource( 1 )

+ 1 - 1
spine-godot/example/examples/helloworld/spineboy-helloworld.gd

@@ -1,4 +1,4 @@
 extends SpineSprite
 
-func _ready():	
+func _ready():
 	get_animation_state().set_animation("walk", true, 0)

+ 12 - 0
spine-godot/example/examples/simple-input/simple-input.tscn

@@ -0,0 +1,12 @@
+[gd_scene load_steps=3 format=2]
+
+[ext_resource path="res://assets/spineboy/spinebody-data-res.tres" type="SpineSkeletonDataResource" id=1]
+[ext_resource path="res://examples/simple-input/spineboy-simple-input.gd" type="Script" id=2]
+
+[node name="Node2D" type="Node2D"]
+
+[node name="Spineboy" type="SpineSprite" parent="."]
+position = Vector2( 501.503, 472.035 )
+scale = Vector2( 0.518624, 0.518624 )
+skeleton_data_res = ExtResource( 1 )
+script = ExtResource( 2 )

+ 19 - 0
spine-godot/example/examples/simple-input/spineboy-simple-input.gd

@@ -0,0 +1,19 @@
+extends SpineSprite
+
+func _ready():	
+	get_animation_state().set_animation("idle", true, 0)
+
+func _process(delta):
+	if Input.is_action_just_pressed("ui_left"):
+		get_animation_state().set_animation("run", true, 0)
+		get_skeleton().set_scale_x(-1)
+		
+	if Input.is_action_just_released("ui_left"):
+		get_animation_state().set_animation("idle", true, 0)
+		
+	if (Input.is_action_just_pressed("ui_right")):
+		get_animation_state().set_animation("run", true, 0)
+		get_skeleton().set_scale_x(1)
+		
+	if Input.is_action_just_released("ui_right"):
+		get_animation_state().set_animation("idle", true, 0)

+ 1 - 1
spine-godot/example/project.godot

@@ -11,7 +11,7 @@ config_version=4
 [application]
 
 config/name="spine-godot-examples"
-run/main_scene="res://tests/batch-test.tscn"
+run/main_scene="res://examples/simple-input/simple-input.tscn"
 run/low_processor_mode=true
 config/icon="res://icon.png"
 

+ 1 - 2
spine-godot/setup.sh

@@ -6,6 +6,5 @@ cp -r .idea godot
 cp custom.py godot
 cp -r ../spine-cpp/spine-cpp spine_godot
 pushd godot
-scons -Q compiledb custom_modules="../spine_godot"
-scons target=debug custom_modules="../spine_godot" --jobs=8
+scons compiledb=yes custom_modules="../spine_godot" -j16
 popd

+ 1 - 1
spine-godot/spine_godot/SpineAnimation.h

@@ -32,7 +32,7 @@
 
 #include "SpineConstant.h"
 #include "core/reference.h"
-#include <spine/spine.h>
+#include <spine/Animation.h>
 
 class SpineEvent;
 class SpineSkeleton;

+ 3 - 3
spine-godot/spine_godot/SpineAtlasResource.cpp

@@ -70,8 +70,8 @@ public:
 		if (error != OK) {
 			ERR_PRINT(vformat("Can't load texture: \"%s\"", String(path.buffer())));
 			auto renderer_object = memnew(SpineRendererObject);
-			renderer_object->texture = nullptr;
-			renderer_object->normal_map = nullptr;
+			renderer_object->texture = Ref<Texture>(nullptr);
+			renderer_object->normal_map = Ref<Texture>(nullptr);
 			page.setRendererObject((void *) renderer_object);
 			return;
 		}
@@ -79,7 +79,7 @@ public:
 		textures->append(texture);
 		auto renderer_object = memnew(SpineRendererObject);
 		renderer_object->texture = texture;
-		renderer_object->normal_map = nullptr;
+		renderer_object->normal_map = Ref<Texture>(nullptr);
 
 		String temp_path = fixed_path;
 		String new_path = vformat("%s/%s_%s", temp_path.get_base_dir(), normal_map_prefix, temp_path.get_file());

+ 1 - 4
spine-godot/spine_godot/SpineAtlasResource.h

@@ -30,14 +30,11 @@
 #ifndef GODOT_SPINEATLASRESOURCE_H
 #define GODOT_SPINEATLASRESOURCE_H
 
-
-#include <spine/Atlas.h>
-
 #include "core/io/resource_loader.h"
 #include "core/io/resource_saver.h"
 #include "core/io/image_loader.h"
+#include <spine/Atlas.h>
 
-class spine::Atlas;
 class GodotSpineTextureLoader;
 
 class SpineAtlasResource : public Resource {

+ 28 - 1
spine-godot/spine_godot/SpineEditorPlugin.cpp

@@ -76,13 +76,40 @@ SpineEditorPlugin::SpineEditorPlugin(EditorNode *node) {
 	add_import_plugin(memnew(SpineAtlasResourceImportPlugin));
 	add_import_plugin(memnew(SpineJsonResourceImportPlugin));
 	add_import_plugin(memnew(SpineBinaryResourceImportPlugin));
+	add_inspector_plugin(memnew(SpineAnimationMixesInspectorPlugin));
 }
 
 SpineEditorPlugin::~SpineEditorPlugin() {
 }
 
 bool SpineEditorPlugin::handles(Object *object) const {
-	return object->is_class("SpineSprite");
+	return object->is_class("SpineSprite") || object->is_class("SpineSkeletonDataResource");
+}
+
+SpineAnimationMixesInspectorPlugin::SpineAnimationMixesInspectorPlugin(): add_mix_button(nullptr) {
+	add_mix_button = memnew(Button);
+	add_mix_button->set_text("Add mix");
+}
+
+SpineAnimationMixesInspectorPlugin::~SpineAnimationMixesInspectorPlugin() {
+
+}
+
+bool SpineAnimationMixesInspectorPlugin::can_handle(Object *object) {
+	return object->is_class("SpineSkeletonDataResource");
+}
+
+void SpineAnimationMixesInspectorPlugin::parse_begin(Object *object) {
+	sprite = object->cast_to<SpineSprite>(object);
+}
+
+bool SpineAnimationMixesInspectorPlugin::parse_property(Object *object, Variant::Type type, const String &path,
+														PropertyHint hint, const String &hint_text, int usage) {
+	if (path == "animation_mixes") {
+		add_custom_control(add_mix_button);
+		return true;
+	}
+	return false;
 }
 
 #endif

+ 57 - 20
spine-godot/spine_godot/SpineEditorPlugin.h

@@ -32,29 +32,31 @@
 
 #ifdef TOOLS_ENABLED
 #include "editor/editor_node.h"
+#include "SpineSprite.h"
+#include "editor/editor_properties.h"
 
 class SpineAtlasResourceImportPlugin : public EditorImportPlugin {
 	GDCLASS(SpineAtlasResourceImportPlugin, EditorImportPlugin)
 
 public:
 	String get_importer_name() const override { return "spine.atlas"; }
-	
+
 	String get_visible_name() const override { return "Spine Runtime Atlas"; }
-	
+
 	void get_recognized_extensions(List<String> *extensions) const override { extensions->push_back("atlas"); }
-	
+
 	String get_preset_name(int idx) const override { return idx == 0 ? "Default" : "Unknown"; }
-	
+
 	int get_preset_count() const override { return 1; }
-	
+
 	String get_save_extension() const override { return "spatlas"; }
-	
+
 	String get_resource_type() const override { return "SpineAtlasResource"; }
-	
+
 	void get_import_options(List<ImportOption> *options, int preset) const override;
-	
+
 	bool get_option_visibility(const String &option, const Map<StringName, Variant> &options) const override { return true; }
-	
+
 	Error import(const String &source_file, const String &save_path, const Map<StringName, Variant> &options, List<String> *platform_variants, List<String> *gen_files, Variant *metadata) override;
 };
 
@@ -63,23 +65,23 @@ class SpineJsonResourceImportPlugin : public EditorImportPlugin {
 
 public:
 	String get_importer_name() const override { return "spine.json"; }
-	
+
 	String get_visible_name() const override { return "Spine Skeleton Json"; }
-	
+
 	void get_recognized_extensions(List<String> *extensions) const override { extensions->push_back("json"); }
-	
+
 	String get_preset_name(int idx) const override { return idx == 0 ? "Default" : "Unknown"; }
-	
+
 	int get_preset_count() const override { return 1; }
-	
+
 	String get_save_extension() const override { return "spjson"; }
-	
+
 	String get_resource_type() const override { return "SpineSkeletonFileResource"; }
-	
+
 	void get_import_options(List<ImportOption> *options, int preset) const override {}
-	
+
 	bool get_option_visibility(const String &option, const Map<StringName, Variant> &options) const override { return true; }
-	
+
 	Error import(const String &source_file, const String &save_path, const Map<StringName, Variant> &options, List<String> *platform_variants, List<String> *gen_files, Variant *metadata) override;
 };
 
@@ -116,11 +118,46 @@ public:
 	~SpineEditorPlugin();
 
 	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)
+
+	SpineSprite *sprite;
+
+	Button *add_mix_button;
+	Vector<Button *> delete_mix;
+
+public:
+	SpineAnimationMixesInspectorPlugin();
+	~SpineAnimationMixesInspectorPlugin() override;
+
+	bool can_handle(Object *object) override;
+	void parse_begin(Object *object) override;
+	bool parse_property(Object *object, Variant::Type type, const String &path, PropertyHint hint, const String &hint_text, int usage) override;
+};
+
+class SpineAnimationMixesProperty: public EditorProperty {
+	GDCLASS(SpineAnimationMixesProperty, EditorProperty)
+
+public:
+	SpineAnimationMixesProperty();
+	~SpineAnimationMixesProperty();
+};
+
+class SpineEditorPropertyMix: public EditorProperty {
+	GDCLASS(SpineEditorPropertyMix, EditorProperty)
+
+	EditorPropertyText *from_property;
+	EditorPropertyText *to_property;
+	EditorPropertyFloat *mix_property;
+public:
+
+};
 #endif
 
 #endif//GODOT_SPINEEDITORPLUGIN_H

+ 2 - 0
spine-godot/spine_godot/SpineEvent.h

@@ -31,6 +31,8 @@
 #define GODOT_SPINEEVENT_H
 
 #include "SpineEventData.h"
+#include "core/reference.h"
+#include <spine/Event.h>
 
 class SpineEvent : public Reference {
 	GDCLASS(SpineEvent, Reference)

+ 1 - 0
spine-godot/spine_godot/SpineIkConstraint.h

@@ -31,6 +31,7 @@
 #define GODOT_SPINEIKCONSTRAINT_H
 
 #include "SpineIkConstraintData.h"
+#include <spine/IkConstraint.h>
 
 class SpineBone;
 

+ 65 - 20
spine-godot/spine_godot/SpineSkeletonDataResource.cpp

@@ -29,10 +29,48 @@
 
 #include "SpineSkeletonDataResource.h"
 
-#ifdef TOOLS_ENABLED
-#include "editor/editor_node.h"
-#include "editor/editor_inspector.h"
-#endif
+void SpineAnimationMix::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("set_from", "from"), &SpineAnimationMix::set_from);
+	ClassDB::bind_method(D_METHOD("get_from"), &SpineAnimationMix::get_from);
+	ClassDB::bind_method(D_METHOD("set_to", "to"), &SpineAnimationMix::set_to);
+	ClassDB::bind_method(D_METHOD("get_to"), &SpineAnimationMix::get_to);
+	ClassDB::bind_method(D_METHOD("set_mix", "mix"), &SpineAnimationMix::set_mix);
+	ClassDB::bind_method(D_METHOD("get_mix"), &SpineAnimationMix::get_mix);
+
+	ADD_PROPERTY(PropertyInfo(Variant::STRING, "from"), "set_from", "get_from");
+	ADD_PROPERTY(PropertyInfo(Variant::STRING, "to"), "set_to", "get_to");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "mix"), "set_mix", "get_mix");
+}
+
+SpineAnimationMix::SpineAnimationMix() {
+}
+
+SpineAnimationMix::~SpineAnimationMix() {
+}
+
+void SpineAnimationMix::set_from(const StringName &from) {
+	this->from = from;
+}
+
+String SpineAnimationMix::get_from() {
+	return from;
+}
+
+void SpineAnimationMix::set_to(const StringName &to) {
+	this->to = to;
+}
+
+String SpineAnimationMix::get_to() {
+	return to;
+}
+
+void SpineAnimationMix::set_mix(float mix) {
+	this->mix = mix;
+}
+
+float SpineAnimationMix::get_mix() {
+	return mix;
+}
 
 void SpineSkeletonDataResource::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("is_skeleton_data_loaded"), &SpineSkeletonDataResource::is_skeleton_data_loaded);
@@ -40,6 +78,10 @@ void SpineSkeletonDataResource::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_atlas_res"), &SpineSkeletonDataResource::get_atlas_res);
 	ClassDB::bind_method(D_METHOD("set_skeleton_file_res", "skeleton_file_res"), &SpineSkeletonDataResource::set_skeleton_file_res);
 	ClassDB::bind_method(D_METHOD("get_skeleton_file_res"), &SpineSkeletonDataResource::get_skeleton_file_res);
+	ClassDB::bind_method(D_METHOD("set_default_mix", "default_mix"), &SpineSkeletonDataResource::set_default_mix);
+	ClassDB::bind_method(D_METHOD("get_default_mix"), &SpineSkeletonDataResource::get_default_mix);
+	ClassDB::bind_method(D_METHOD("set_animation_mixes", "mixes"), &SpineSkeletonDataResource::set_animation_mixes);
+	ClassDB::bind_method(D_METHOD("get_animation_mixes"), &SpineSkeletonDataResource::get_animation_mixes);
 
 	// Spine API
 	ClassDB::bind_method(D_METHOD("find_bone", "bone_name"), &SpineSkeletonDataResource::find_bone);
@@ -75,9 +117,12 @@ void SpineSkeletonDataResource::_bind_methods() {
 
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "atlas_res", PropertyHint::PROPERTY_HINT_RESOURCE_TYPE, "SpineAtlasResource"), "set_atlas_res", "get_atlas_res");
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skeleton_file_res", PropertyHint::PROPERTY_HINT_RESOURCE_TYPE, "SpineSkeletonFileResource"), "set_skeleton_file_res", "get_skeleton_file_res");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "default_mix"), "set_default_mix", "get_default_mix");
+	ADD_GROUP("Animation mixes", "");
+	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animation_mixes"), "set_animation_mixes", "get_animation_mixes");
 }
 
-SpineSkeletonDataResource::SpineSkeletonDataResource() : skeleton_data(nullptr), animation_state_data(nullptr) {
+SpineSkeletonDataResource::SpineSkeletonDataResource() : skeleton_data(nullptr), animation_state_data(nullptr), default_mix(0) {
 }
 
 SpineSkeletonDataResource::~SpineSkeletonDataResource() {
@@ -137,6 +182,7 @@ void SpineSkeletonDataResource::set_atlas_res(const Ref<SpineAtlasResource> &atl
 	atlas_res = atlas;
 	update_skeleton_data();
 }
+
 Ref<SpineAtlasResource> SpineSkeletonDataResource::get_atlas_res() {
 	return atlas_res;
 }
@@ -145,6 +191,7 @@ void SpineSkeletonDataResource::set_skeleton_file_res(const Ref<SpineSkeletonFil
 	skeleton_file_res = skeleton_file;
 	update_skeleton_data();
 }
+
 Ref<SpineSkeletonFileResource> SpineSkeletonDataResource::get_skeleton_file_res() {
 	return skeleton_file_res;
 }
@@ -169,23 +216,21 @@ void SpineSkeletonDataResource::get_skin_names(Vector<String> &skin_names) const
 	}
 }
 
-void SpineSkeletonDataResource::_get_property_list(List<PropertyInfo> *p_list) const {
-	PropertyInfo property;
-	Vector<String> animation_names;
+void SpineSkeletonDataResource::set_default_mix(float default_mix) {
+	this->default_mix = default_mix;
+	if (animation_state_data) animation_state_data->setDefaultMix(default_mix);
+}
+
+float SpineSkeletonDataResource::get_default_mix() {
+	return default_mix;
+}
 
-	property.name = "animations";
-	property.type = Variant::STRING;
-	get_animation_names(animation_names);
-	property.hint_string = String(",").join(animation_names);
-	property.hint = PROPERTY_HINT_ENUM;
-	p_list->push_back(property);
+void SpineSkeletonDataResource::set_animation_mixes(Array animation_mixes) {
+	this->animation_mixes = animation_mixes;
+}
 
-	property.name = "skins";
-	property.type = Variant::STRING;
-	get_skin_names(animation_names);
-	property.hint_string = String(",").join(animation_names);
-	property.hint = PROPERTY_HINT_ENUM;
-	p_list->push_back(property);
+Array SpineSkeletonDataResource::get_animation_mixes() {
+	return animation_mixes;
 }
 
 #define CHECK(x)                                      \

+ 36 - 2
spine-godot/spine_godot/SpineSkeletonDataResource.h

@@ -12,8 +12,34 @@
 #include "SpinePathConstraintData.h"
 #include "SpineEventData.h"
 
+class SpineAnimationMix : public Resource {
+	GDCLASS(SpineAnimationMix, Resource)
+
+protected:
+	static void _bind_methods();
+
+	String from;
+	String to;
+	float mix;
+public:
+	SpineAnimationMix();
+	~SpineAnimationMix();
+
+	void set_from(const StringName &from);
+
+	String get_from();
+
+	void set_to(const StringName &to);
+
+	String get_to();
+
+	void set_mix(float mix);
+
+	float get_mix();
+};
+
 class SpineSkeletonDataResource : public Resource {
-	GDCLASS(SpineSkeletonDataResource, Resource);
+	GDCLASS(SpineSkeletonDataResource, Resource)
 
 protected:
 	static void _bind_methods();
@@ -21,6 +47,8 @@ protected:
 private:
 	Ref<SpineAtlasResource> atlas_res;
 	Ref<SpineSkeletonFileResource> skeleton_file_res;
+	float default_mix;
+	Array animation_mixes;
 
 	spine::SkeletonData *skeleton_data;
 	spine::AnimationStateData *animation_state_data;
@@ -49,7 +77,13 @@ public:
 
 	void get_skin_names(Vector<String> &l) const;
 
-	void _get_property_list(List<PropertyInfo> *p_list) const;
+	void set_default_mix(float default_mix);
+
+	float get_default_mix();
+
+	void set_animation_mixes(Array animation_mixes);
+
+	Array get_animation_mixes();
 
 	// Spine API
 	Ref<SpineBoneData> find_bone(const String &bone_name) const;

+ 1 - 0
spine-godot/spine_godot/icons/icon_spine_atlas_resource.svg

@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#ff4000"><path d="m5.21 2.36c0 1.15.84 1.79 2.43 2 1.35.21 2.57.11 3-1.05.75-2.22-1.09-1.66-2.64-1.91s-2.85-.9-2.79.96z"/><path d="m5.69 7.1c.15.86.95 1.36 2.18 1.32s2.13-.51 2.28-1.42c.23-1.74-1.15-1.08-2.36-1s-2.39-.59-2.1 1.1z"/><path d="m7.29 11.05c.24.64.91.91 1.82.72s1.53-.49 1.48-1.23c-.09-1.35-1-.93-1.89-.73s-1.89-.03-1.41 1.24z"/><path d="m8.07 14.06c.07.54.54.86 1.27.86s1.3-.3 1.39-.88c.18-1.08-.64-.68-1.38-.67s-1.42-.37-1.28.69z"/></g></svg>

+ 1 - 0
spine-godot/spine_godot/icons/icon_spine_skeleton_data_resource.svg

@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#ff4000"><path d="m5.21 2.36c0 1.15.84 1.79 2.43 2 1.35.21 2.57.11 3-1.05.75-2.22-1.09-1.66-2.64-1.91s-2.85-.9-2.79.96z"/><path d="m5.69 7.1c.15.86.95 1.36 2.18 1.32s2.13-.51 2.28-1.42c.23-1.74-1.15-1.08-2.36-1s-2.39-.59-2.1 1.1z"/><path d="m7.29 11.05c.24.64.91.91 1.82.72s1.53-.49 1.48-1.23c-.09-1.35-1-.93-1.89-.73s-1.89-.03-1.41 1.24z"/><path d="m8.07 14.06c.07.54.54.86 1.27.86s1.3-.3 1.39-.88c.18-1.08-.64-.68-1.38-.67s-1.42-.37-1.28.69z"/></g></svg>

+ 1 - 0
spine-godot/spine_godot/icons/icon_spine_skeleton_file_resource.svg

@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#ff4000"><path d="m5.21 2.36c0 1.15.84 1.79 2.43 2 1.35.21 2.57.11 3-1.05.75-2.22-1.09-1.66-2.64-1.91s-2.85-.9-2.79.96z"/><path d="m5.69 7.1c.15.86.95 1.36 2.18 1.32s2.13-.51 2.28-1.42c.23-1.74-1.15-1.08-2.36-1s-2.39-.59-2.1 1.1z"/><path d="m7.29 11.05c.24.64.91.91 1.82.72s1.53-.49 1.48-1.23c-.09-1.35-1-.93-1.89-.73s-1.89-.03-1.41 1.24z"/><path d="m8.07 14.06c.07.54.54.86 1.27.86s1.3-.3 1.39-.88c.18-1.08-.64-.68-1.38-.67s-1.42-.37-1.28.69z"/></g></svg>

+ 1 - 0
spine-godot/spine_godot/icons/icon_spine_sprite.svg

@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#ff4000"><path d="m5.21 2.36c0 1.15.84 1.79 2.43 2 1.35.21 2.57.11 3-1.05.75-2.22-1.09-1.66-2.64-1.91s-2.85-.9-2.79.96z"/><path d="m5.69 7.1c.15.86.95 1.36 2.18 1.32s2.13-.51 2.28-1.42c.23-1.74-1.15-1.08-2.36-1s-2.39-.59-2.1 1.1z"/><path d="m7.29 11.05c.24.64.91.91 1.82.72s1.53-.49 1.48-1.23c-.09-1.35-1-.93-1.89-.73s-1.89-.03-1.41 1.24z"/><path d="m8.07 14.06c.07.54.54.86 1.27.86s1.3-.3 1.39-.88c.18-1.08-.64-.68-1.38-.67s-1.42-.37-1.28.69z"/></g></svg>

+ 1 - 5
spine-godot/spine_godot/register_types.cpp

@@ -73,15 +73,12 @@ void register_spine_godot_types() {
 #ifdef TOOLS_ENABLED
 	EditorNode::add_init_callback(editor_init_callback);
 #endif
-
 	ClassDB::register_class<SpineAtlasResource>();
 	ClassDB::register_class<SpineSkeletonFileResource>();
 	ClassDB::register_class<SpineSkeletonDataResource>();
-	ClassDB::register_class<SpineSkeletonDataResource>();
-	ClassDB::register_class<SpineSprite>();
+	ClassDB::register_class<SpineAnimationMix>();
 	ClassDB::register_class<SpineSprite>();
 	ClassDB::register_class<SpineSkeleton>();
-	ClassDB::register_class<SpineSkeleton>();
 	ClassDB::register_class<SpineAnimationState>();
 	ClassDB::register_class<SpineAnimation>();
 	ClassDB::register_class<SpineEventData>();
@@ -98,7 +95,6 @@ void register_spine_godot_types() {
 	ClassDB::register_class<SpineTransformConstraintData>();
 	ClassDB::register_class<SpinePathConstraintData>();
 	ClassDB::register_class<SpineBone>();
-	ClassDB::register_class<SpineBone>();
 	ClassDB::register_class<SpineSlot>();
 	ClassDB::register_class<SpineIkConstraint>();
 	ClassDB::register_class<SpinePathConstraint>();