Explorar el Código

[godot] Initial commit

Mario Zechner hace 3 años
padre
commit
cc57c3dbc9
Se han modificado 87 ficheros con 10058 adiciones y 1 borrados
  1. 4 1
      .gitignore
  2. 38 0
      spine-godot/README.md
  3. 7 0
      spine-godot/example/default_env.tres
  4. BIN
      spine-godot/example/icon.png
  5. 34 0
      spine-godot/example/icon.png.import
  6. 25 0
      spine-godot/example/project.godot
  7. 9 0
      spine-godot/setup.sh
  8. 76 0
      spine-godot/spine_godot/GodotSpineExtension.cpp
  9. 57 0
      spine-godot/spine_godot/GodotSpineExtension.h
  10. 61 0
      spine-godot/spine_godot/PackedSpineSkinResource.cpp
  11. 59 0
      spine-godot/spine_godot/PackedSpineSkinResource.h
  12. 80 0
      spine-godot/spine_godot/RaiixSpineExtension.cpp
  13. 56 0
      spine-godot/spine_godot/ResourceFormatLoaderSpineAtlas.cpp
  14. 45 0
      spine-godot/spine_godot/ResourceFormatLoaderSpineAtlas.h
  15. 56 0
      spine-godot/spine_godot/ResourceFormatLoaderSpineSkeletonJsonData.cpp
  16. 44 0
      spine-godot/spine_godot/ResourceFormatLoaderSpineSkeletonJsonData.h
  17. 48 0
      spine-godot/spine_godot/ResourceFormatSaverSpineAtlas.cpp
  18. 44 0
      spine-godot/spine_godot/ResourceFormatSaverSpineAtlas.h
  19. 48 0
      spine-godot/spine_godot/ResourceFormatSaverSpineSkeletonJsonData.cpp
  20. 44 0
      spine-godot/spine_godot/ResourceFormatSaverSpineSkeletonJsonData.h
  21. 9 0
      spine-godot/spine_godot/SCsub
  22. 96 0
      spine-godot/spine_godot/SpineAnimation.cpp
  23. 74 0
      spine-godot/spine_godot/SpineAnimation.h
  24. 190 0
      spine-godot/spine_godot/SpineAnimationState.cpp
  25. 93 0
      spine-godot/spine_godot/SpineAnimationState.h
  26. 178 0
      spine-godot/spine_godot/SpineAnimationStateDataResource.cpp
  27. 76 0
      spine-godot/spine_godot/SpineAnimationStateDataResource.h
  28. 229 0
      spine-godot/spine_godot/SpineAtlasResource.cpp
  29. 79 0
      spine-godot/spine_godot/SpineAtlasResource.h
  30. 55 0
      spine-godot/spine_godot/SpineAttachment.cpp
  31. 64 0
      spine-godot/spine_godot/SpineAttachment.h
  32. 537 0
      spine-godot/spine_godot/SpineBone.cpp
  33. 174 0
      spine-godot/spine_godot/SpineBone.h
  34. 163 0
      spine-godot/spine_godot/SpineBoneData.cpp
  35. 104 0
      spine-godot/spine_godot/SpineBoneData.h
  36. 204 0
      spine-godot/spine_godot/SpineCollisionShapeProxy.cpp
  37. 78 0
      spine-godot/spine_godot/SpineCollisionShapeProxy.h
  38. 62 0
      spine-godot/spine_godot/SpineConstant.cpp
  39. 80 0
      spine-godot/spine_godot/SpineConstant.h
  40. 59 0
      spine-godot/spine_godot/SpineConstraintData.cpp
  41. 66 0
      spine-godot/spine_godot/SpineConstraintData.h
  42. 110 0
      spine-godot/spine_godot/SpineEvent.cpp
  43. 89 0
      spine-godot/spine_godot/SpineEvent.h
  44. 37 0
      spine-godot/spine_godot/SpineEventData.cpp
  45. 56 0
      spine-godot/spine_godot/SpineEventData.h
  46. 146 0
      spine-godot/spine_godot/SpineIkConstraint.cpp
  47. 95 0
      spine-godot/spine_godot/SpineIkConstraint.h
  48. 123 0
      spine-godot/spine_godot/SpineIkConstraintData.cpp
  49. 79 0
      spine-godot/spine_godot/SpineIkConstraintData.h
  50. 145 0
      spine-godot/spine_godot/SpinePathConstraint.cpp
  51. 94 0
      spine-godot/spine_godot/SpinePathConstraint.h
  52. 168 0
      spine-godot/spine_godot/SpinePathConstraintData.cpp
  53. 108 0
      spine-godot/spine_godot/SpinePathConstraintData.h
  54. 42 0
      spine-godot/spine_godot/SpineRendererObject.h
  55. 100 0
      spine-godot/spine_godot/SpineRuntimeEditorPlugin.cpp
  56. 89 0
      spine-godot/spine_godot/SpineRuntimeEditorPlugin.h
  57. 430 0
      spine-godot/spine_godot/SpineSkeleton.cpp
  58. 135 0
      spine-godot/spine_godot/SpineSkeleton.h
  59. 454 0
      spine-godot/spine_godot/SpineSkeletonDataResource.cpp
  60. 140 0
      spine-godot/spine_godot/SpineSkeletonDataResource.h
  61. 55 0
      spine-godot/spine_godot/SpineSkeletonJsonDataResource.cpp
  62. 49 0
      spine-godot/spine_godot/SpineSkeletonJsonDataResource.h
  63. 162 0
      spine-godot/spine_godot/SpineSkin.cpp
  64. 85 0
      spine-godot/spine_godot/SpineSkin.h
  65. 93 0
      spine-godot/spine_godot/SpineSkinAttachmentMapEntries.cpp
  66. 93 0
      spine-godot/spine_godot/SpineSkinAttachmentMapEntries.h
  67. 148 0
      spine-godot/spine_godot/SpineSlot.cpp
  68. 93 0
      spine-godot/spine_godot/SpineSlot.h
  69. 114 0
      spine-godot/spine_godot/SpineSlotData.cpp
  70. 88 0
      spine-godot/spine_godot/SpineSlotData.h
  71. 1039 0
      spine-godot/spine_godot/SpineSprite.cpp
  72. 162 0
      spine-godot/spine_godot/SpineSprite.h
  73. 350 0
      spine-godot/spine_godot/SpineSpriteAnimateDialog.cpp
  74. 86 0
      spine-godot/spine_godot/SpineSpriteAnimateDialog.h
  75. 48 0
      spine-godot/spine_godot/SpineSpriteMeshInstance2D.cpp
  76. 56 0
      spine-godot/spine_godot/SpineSpriteMeshInstance2D.h
  77. 103 0
      spine-godot/spine_godot/SpineTimeline.cpp
  78. 72 0
      spine-godot/spine_godot/SpineTimeline.h
  79. 265 0
      spine-godot/spine_godot/SpineTrackEntry.cpp
  80. 131 0
      spine-godot/spine_godot/SpineTrackEntry.h
  81. 148 0
      spine-godot/spine_godot/SpineTransformConstraint.cpp
  82. 93 0
      spine-godot/spine_godot/SpineTransformConstraint.h
  83. 118 0
      spine-godot/spine_godot/SpineTransformConstraintData.cpp
  84. 74 0
      spine-godot/spine_godot/SpineTransformConstraintData.h
  85. 5 0
      spine-godot/spine_godot/config.py
  86. 151 0
      spine-godot/spine_godot/register_types.cpp
  87. 32 0
      spine-godot/spine_godot/register_types.h

+ 4 - 1
.gitignore

@@ -151,4 +151,7 @@ spine-ts/spine-core/dist
 spine-ts/spine-canvas/dist
 spine-ts/spine-webgl/dist
 spine-ts/spine-player/dist
-spine-ts/spine-threejs/dist
+spine-ts/spine-threejs/dist
+spine-godot/godot
+spine-godot/spine_godot/spine-cpp
+spine-godot/spine_godot/__pycache__

+ 38 - 0
spine-godot/README.md

@@ -0,0 +1,38 @@
+# spine-godot
+
+The spine-godot runtime provides functionality to load, manipulate and render [Spine](http://esotericsoftware.com) skeletal animation data using [Godot](https://godotengine.org/). spine-godot is based on [spine-cpp](../spine-cpp).
+
+## Licensing
+
+You are welcome to evaluate the Spine Runtimes and the examples we provide in this repository free of charge.
+
+You can integrate the Spine Runtimes into your software free of charge, but users of your software must have their own [Spine license](https://esotericsoftware.com/spine-purchase). Please make your users aware of this requirement! This option is often chosen by those making development tools, such as an SDK, game toolkit, or software library.
+
+In order to distribute your software containing the Spine Runtimes to others that don't have a Spine license, you need a [Spine license](https://esotericsoftware.com/spine-purchase) at the time of integration. Then you can distribute your software containing the Spine Runtimes however you like, provided others don't modify it or use it to create new software. If others want to do that, they'll need their own Spine license.
+
+For the official legal terms governing the Spine Runtimes, please read the [Spine Runtimes License Agreement](http://esotericsoftware.com/spine-runtimes-license) and Section 2 of the [Spine Editor License Agreement](http://esotericsoftware.com/spine-editor-license#s2).
+
+## Spine version
+
+spine-godot works with data exported from Spine 4.0.xx.
+
+spine-godot supports all Spine features.
+
+## Setup
+
+spine-godot works with the latest stable Godot 3.3 release. It requires compilation of Godot, as spine-godot is implemented as a module.
+
+To integrate spine-godot into your project:
+
+1. Follow the [instructions on how to compilation of Godot](https://docs.godotengine.org/en/stable/development/compiling/index.html)
+2. Copy the `spine-runtimes/spine-godot` folder into the folder `modules/spine-godot` in your Godot source tree.
+3. Copy the `spine-cpp/spine-cpp`folder into the folder `modules/spine-godot/spine-cpp` in your Godot source tree.
+4. Compile Godot via scons for your platform as per the Godot documentation.
+
+The resulting Godot engine binary will include the spine-godot runtime.
+
+## Example
+The Spine Godot example work on all platforms supported by Godot.
+
+
+

+ 7 - 0
spine-godot/example/default_env.tres

@@ -0,0 +1,7 @@
+[gd_resource type="Environment" load_steps=2 format=2]
+
+[sub_resource type="ProceduralSky" id=1]
+
+[resource]
+background_mode = 2
+background_sky = SubResource( 1 )

BIN
spine-godot/example/icon.png


+ 34 - 0
spine-godot/example/icon.png.import

@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="StreamTexture"
+path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://icon.png"
+dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_mode=0
+compress/bptc_ldr=0
+compress/normal_map=0
+flags/repeat=0
+flags/filter=true
+flags/mipmaps=false
+flags/anisotropic=false
+flags/srgb=2
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/HDR_as_SRGB=false
+process/invert_color=false
+stream=false
+size_limit=0
+detect_3d=true
+svg/scale=1.0

+ 25 - 0
spine-godot/example/project.godot

@@ -0,0 +1,25 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+;   [section] ; section goes between []
+;   param=value ; assign values to parameters
+
+config_version=4
+
+[application]
+
+config/name="spine-godot-examples"
+config/icon="res://icon.png"
+
+[physics]
+
+common/enable_pause_aware_picking=true
+
+[rendering]
+
+quality/driver/driver_name="GLES2"
+vram_compression/import_etc=true
+vram_compression/import_etc2=false
+environment/default_environment="res://default_env.tres"

+ 9 - 0
spine-godot/setup.sh

@@ -0,0 +1,9 @@
+#!/bin/bash
+set -e
+rm -rf godot
+cp -r ../spine-cpp/spine-cpp spine-godot
+git clone --depth 1 https://github.com/godotengine/godot.git -b 3.3.3-stable
+ln -s $(pwd)/spine_godot godot/modules/spine_godot
+pushd godot
+scons --jobs=$(sysctl -n hw.logicalcpu)
+popd

+ 76 - 0
spine-godot/spine_godot/GodotSpineExtension.cpp

@@ -0,0 +1,76 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "GodotSpineExtension.h"
+
+#include "core/variant_parser.h"
+#include <spine/SpineString.h>
+
+#include <iostream>
+
+spine::SpineExtension *spine::getDefaultExtension() {
+    return new GodotSpineExtension();
+}
+
+GodotSpineExtension::GodotSpineExtension(){}
+GodotSpineExtension::~GodotSpineExtension(){}
+
+void *GodotSpineExtension::_alloc(size_t size, const char *file, int line){
+    return memalloc(size);
+}
+
+void *GodotSpineExtension::_calloc(size_t size, const char *file, int line){
+    auto p = memalloc(size);
+    memset(p, 0, size);
+    return p;
+}
+
+void *GodotSpineExtension::_realloc(void *ptr, size_t size, const char *file, int line){
+    return memrealloc(ptr, size);
+}
+
+void GodotSpineExtension::_free(void *mem, const char *file, int line){
+    memfree(mem);
+}
+
+char *GodotSpineExtension::_readFile(const spine::String &path, int *length){
+    Error error;
+    auto res = FileAccess::get_file_as_array(String(path.buffer()), &error);
+
+    if (error != OK){
+        if(length) *length = 0;
+        return NULL;
+    }
+
+    if(length) *length = res.size();
+    auto r = alloc<char>(res.size(), __FILE__, __LINE__);
+    for(size_t i=0;i<res.size();++i)
+        r[i] = res[i];
+    return r;
+}

+ 57 - 0
spine-godot/spine_godot/GodotSpineExtension.h

@@ -0,0 +1,57 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINEEXTENSION_H
+#define GODOT_SPINEEXTENSION_H
+
+
+#include <spine/Extension.h>
+class GodotSpineExtension : public spine::SpineExtension {
+public:
+	GodotSpineExtension();
+
+	virtual ~GodotSpineExtension();
+
+protected:
+	virtual void *_alloc(size_t size, const char *file, int line);
+
+	virtual void *_calloc(size_t size, const char *file, int line);
+
+	virtual void *_realloc(void *ptr, size_t size, const char *file, int line);
+
+	virtual void _free(void *mem, const char *file, int line);
+
+	virtual char *_readFile(const spine::String &path, int *length);
+};
+
+
+
+
+
+#endif //GODOT_SPINEEXTENSION_H

+ 61 - 0
spine-godot/spine_godot/PackedSpineSkinResource.cpp

@@ -0,0 +1,61 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "PackedSpineSkinResource.h"
+
+void PackedSpineSkinResource::_bind_methods(){
+	ClassDB::bind_method(D_METHOD("set_skin_name", "v"), &PackedSpineSkinResource::set_skin_name);
+	ClassDB::bind_method(D_METHOD("get_skin_name"), &PackedSpineSkinResource::get_skin_name);
+	ClassDB::bind_method(D_METHOD("set_sub_skin_names", "v"), &PackedSpineSkinResource::set_sub_skin_names);
+	ClassDB::bind_method(D_METHOD("get_sub_skin_names"), &PackedSpineSkinResource::get_sub_skin_names);
+
+	ADD_SIGNAL(MethodInfo("property_changed"));
+
+	ADD_PROPERTY(PropertyInfo(Variant::STRING, "skin_name"), "set_skin_name", "get_skin_name");
+	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "sub_skin_names"), "set_sub_skin_names", "get_sub_skin_names");
+}
+
+PackedSpineSkinResource::PackedSpineSkinResource():skin_name("custom_skin_name"){}
+PackedSpineSkinResource::~PackedSpineSkinResource(){}
+
+void PackedSpineSkinResource::set_skin_name(const String &v){
+	skin_name = v;
+	emit_signal("property_changed");
+}
+String PackedSpineSkinResource::get_skin_name(){
+	return skin_name;
+}
+
+void PackedSpineSkinResource::set_sub_skin_names(Array v){
+	sub_skin_names = v;
+	emit_signal("property_changed");
+}
+Array PackedSpineSkinResource::get_sub_skin_names(){
+	return sub_skin_names;
+}

+ 59 - 0
spine-godot/spine_godot/PackedSpineSkinResource.h

@@ -0,0 +1,59 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_PACKEDSPINESKINRESOURCE_H
+#define GODOT_PACKEDSPINESKINRESOURCE_H
+
+#include "core/variant_parser.h"
+
+#include "SpineSkin.h"
+
+class PackedSpineSkinResource : public Resource{
+	GDCLASS(PackedSpineSkinResource, Resource);
+
+protected:
+	static void _bind_methods();
+
+private:
+	String skin_name;
+	Array sub_skin_names;
+
+public:
+	PackedSpineSkinResource();
+	virtual ~PackedSpineSkinResource();
+
+	void set_skin_name(const String &v);
+	String get_skin_name();
+
+	void set_sub_skin_names(Array v);
+	Array get_sub_skin_names();
+
+};
+
+#endif //GODOT_PACKEDSPINESKINRESOURCE_H

+ 80 - 0
spine-godot/spine_godot/RaiixSpineExtension.cpp

@@ -0,0 +1,80 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "GodotSpineExtension.h"
+
+#include "core/variant_parser.h"
+#include <spine/SpineString.h>
+
+#include <iostream>
+
+spine::SpineExtension *spine::getDefaultExtension() {
+    return new GodotSpineExtension();
+}
+
+GodotSpineExtension::GodotSpineExtension(){}
+GodotSpineExtension::~GodotSpineExtension(){}
+
+void *GodotSpineExtension::_alloc(size_t size, const char *file, int line){
+//	std::cout<<"_alloc "<<file<<" "<<line<<std::endl;
+    return memalloc(size);
+}
+
+void *GodotSpineExtension::_calloc(size_t size, const char *file, int line){
+//	std::cout<<"_calloc "<<file<<" "<<line<<std::endl;
+    auto p = memalloc(size);
+    memset(p, 0, size);
+    return p;
+}
+
+void *GodotSpineExtension::_realloc(void *ptr, size_t size, const char *file, int line){
+//	std::cout<<"_realloc "<<file<<" "<<line<<std::endl;
+    return memrealloc(ptr, size);
+}
+
+void GodotSpineExtension::_free(void *mem, const char *file, int line){
+//	std::cout<<"_free "<<file<<" "<<line<<std::endl;
+    memfree(mem);
+}
+
+char *GodotSpineExtension::_readFile(const spine::String &path, int *length){
+    Error error;
+    auto res = FileAccess::get_file_as_array(String(path.buffer()), &error);
+//    std::cout<<"Spine is loading something: "<<path.buffer()<<std::endl;
+    if (error != OK){
+        if(length) *length = 0;
+        return NULL;
+    }
+
+    if(length) *length = res.size();
+    auto r = alloc<char>(res.size(), __FILE__, __LINE__);
+    for(size_t i=0;i<res.size();++i)
+        r[i] = res[i];
+    return r;
+}

+ 56 - 0
spine-godot/spine_godot/ResourceFormatLoaderSpineAtlas.cpp

@@ -0,0 +1,56 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "ResourceFormatLoaderSpineAtlas.h"
+#include "SpineAtlasResource.h"
+
+RES ResourceFormatLoaderSpineAtlas::load(const String &p_path, const String &p_original_path, Error *r_error) {
+    Ref<SpineAtlasResource> atlas = memnew(SpineAtlasResource);
+    atlas->load_from_file(p_path);
+
+    if(r_error){
+        *r_error = OK;
+    }
+    return atlas;
+}
+
+void ResourceFormatLoaderSpineAtlas::get_recognized_extensions(List<String> *r_extensions) const {
+    const char atlas_ext[] = "spatlas";
+    if(!r_extensions->find(atlas_ext)) {
+        r_extensions->push_back(atlas_ext);
+    }
+}
+
+String ResourceFormatLoaderSpineAtlas::get_resource_type(const String &p_path) const {
+    return "SpineAtlasResource";
+}
+
+bool ResourceFormatLoaderSpineAtlas::handles_type(const String &p_type) const {
+    return p_type == "SpineAtlasResource" || ClassDB::is_parent_class(p_type, "SpineAtlasResource");
+}

+ 45 - 0
spine-godot/spine_godot/ResourceFormatLoaderSpineAtlas.h

@@ -0,0 +1,45 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_RESOURCEFORMATLOADERSPINEATLAS_H
+#define GODOT_RESOURCEFORMATLOADERSPINEATLAS_H
+
+#include "core/io/resource_loader.h"
+
+class ResourceFormatLoaderSpineAtlas : public ResourceFormatLoader{
+    GDCLASS(ResourceFormatLoaderSpineAtlas, ResourceFormatLoader);
+public:
+    virtual RES load(const String &p_path, const String &p_original_path, Error *r_error = NULL);
+    virtual void get_recognized_extensions(List<String> *r_extensions) const;
+    virtual bool handles_type(const String &p_type) const;
+    virtual String get_resource_type(const String &p_path) const;
+};
+
+
+#endif //GODOT_RESOURCEFORMATLOADERSPINEATLAS_H

+ 56 - 0
spine-godot/spine_godot/ResourceFormatLoaderSpineSkeletonJsonData.cpp

@@ -0,0 +1,56 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "ResourceFormatLoaderSpineSkeletonJsonData.h"
+#include "SpineSkeletonJsonDataResource.h"
+
+RES ResourceFormatLoaderSpineSkeletonJsonData::load(const String &p_path, const String &p_original_path, Error *r_error) {
+    Ref<SpineSkeletonJsonDataResource> skeleton = memnew(SpineSkeletonJsonDataResource);
+    skeleton->load_from_file(p_path);
+
+    if(r_error){
+        *r_error = OK;
+    }
+    return skeleton;
+}
+
+void ResourceFormatLoaderSpineSkeletonJsonData::get_recognized_extensions(List<String> *r_extensions) const {
+    const char json_ext[] = "spjson";
+    if(!r_extensions->find(json_ext)) {
+        r_extensions->push_back(json_ext);
+    }
+}
+
+String ResourceFormatLoaderSpineSkeletonJsonData::get_resource_type(const String &p_path) const {
+    return "SpineSkeletonJsonDataResource";
+}
+
+bool ResourceFormatLoaderSpineSkeletonJsonData::handles_type(const String &p_type) const {
+    return p_type == "SpineSkeletonJsonDataResource" || ClassDB::is_parent_class(p_type, "SpineSkeletonJsonDataResource");
+}

+ 44 - 0
spine-godot/spine_godot/ResourceFormatLoaderSpineSkeletonJsonData.h

@@ -0,0 +1,44 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_RESOURCEFORMATLOADERSPINESKELETONJSONDATA_H
+#define GODOT_RESOURCEFORMATLOADERSPINESKELETONJSONDATA_H
+
+#include "core/io/resource_loader.h"
+
+class ResourceFormatLoaderSpineSkeletonJsonData : public ResourceFormatLoader {
+	GDCLASS(ResourceFormatLoaderSpineSkeletonJsonData, ResourceFormatLoader);
+public:
+    virtual RES load(const String &p_path, const String &p_original_path, Error *r_error = NULL);
+    virtual void get_recognized_extensions(List<String> *r_extensions) const;
+    virtual bool handles_type(const String &p_type) const;
+    virtual String get_resource_type(const String &p_path) const;
+};
+
+#endif //GODOT_RESOURCEFORMATLOADERSPINESKELETONJSONDATA_H

+ 48 - 0
spine-godot/spine_godot/ResourceFormatSaverSpineAtlas.cpp

@@ -0,0 +1,48 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "ResourceFormatSaverSpineAtlas.h"
+
+#include "SpineAtlasResource.h"
+
+Error ResourceFormatSaverSpineAtlas::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+    Ref<SpineAtlasResource> res = p_resource.get_ref_ptr();
+    Error error = res->save_to_file(p_path);
+    return error;
+}
+
+void ResourceFormatSaverSpineAtlas::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+    if (Object::cast_to<SpineAtlasResource>(*p_resource)) {
+        p_extensions->push_back("spatlas");
+    }
+}
+
+bool ResourceFormatSaverSpineAtlas::recognize(const RES &p_resource) const {
+    return Object::cast_to<SpineAtlasResource>(*p_resource) != nullptr;
+}

+ 44 - 0
spine-godot/spine_godot/ResourceFormatSaverSpineAtlas.h

@@ -0,0 +1,44 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_RESOURCEFORMATSAVERSPINEATLAS_H
+#define GODOT_RESOURCEFORMATSAVERSPINEATLAS_H
+
+#include "core/io/resource_saver.h"
+
+class ResourceFormatSaverSpineAtlas : public ResourceFormatSaver{
+    GDCLASS(ResourceFormatSaverSpineAtlas, ResourceFormatSaver);
+public:
+    Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0) override;
+    void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const override;
+    bool recognize(const RES &p_resource) const override;
+};
+
+
+#endif //GODOT_RESOURCEFORMATSAVERSPINEATLAS_H

+ 48 - 0
spine-godot/spine_godot/ResourceFormatSaverSpineSkeletonJsonData.cpp

@@ -0,0 +1,48 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "ResourceFormatSaverSpineSkeletonJsonData.h"
+
+#include "SpineSkeletonJsonDataResource.h"
+
+Error ResourceFormatSaverSpineSkeletonJsonData::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+    Ref<SpineSkeletonJsonDataResource> res = p_resource.get_ref_ptr();
+    Error error = res->save_to_file(p_path);
+    return error;
+}
+
+void ResourceFormatSaverSpineSkeletonJsonData::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+    if (Object::cast_to<SpineSkeletonJsonDataResource>(*p_resource)) {
+        p_extensions->push_back("spjson");
+    }
+}
+
+bool ResourceFormatSaverSpineSkeletonJsonData::recognize(const RES &p_resource) const {
+    return Object::cast_to<SpineSkeletonJsonDataResource>(*p_resource) != nullptr;
+}

+ 44 - 0
spine-godot/spine_godot/ResourceFormatSaverSpineSkeletonJsonData.h

@@ -0,0 +1,44 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_RESOURCEFORMATSAVERSPINESKELETONJSONDATA_H
+#define GODOT_RESOURCEFORMATSAVERSPINESKELETONJSONDATA_H
+
+#include "core/io/resource_saver.h"
+
+class ResourceFormatSaverSpineSkeletonJsonData : public ResourceFormatSaver{
+    GDCLASS(ResourceFormatSaverSpineSkeletonJsonData, ResourceFormatSaver);
+public:
+    Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0) override;
+    void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const override;
+    bool recognize(const RES &p_resource) const override;
+};
+
+
+#endif //GODOT_RESOURCEFORMATSAVERSPINESKELETONJSONDATA_H

+ 9 - 0
spine-godot/spine_godot/SCsub

@@ -0,0 +1,9 @@
+Import('env')
+
+env_spine_runtime = env.Clone()
+
+env_spine_runtime.Append(CPPPATH=["spine-cpp/include"])
+env_spine_runtime.Append(CCFLAGS=['-O2'])
+
+env_spine_runtime.add_source_files(env.modules_sources, "spine-cpp/src/spine/*.cpp")
+env_spine_runtime.add_source_files(env.modules_sources, "*.cpp")

+ 96 - 0
spine-godot/spine_godot/SpineAnimation.cpp

@@ -0,0 +1,96 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineAnimation.h"
+
+#include "SpineSkeleton.h"
+#include "SpineEvent.h"
+#include "SpineTimeline.h"
+
+// enable more than 5 arguments of a method bind function
+#include "core/method_bind_ext.gen.inc"
+
+void SpineAnimation::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_anim_name"), &SpineAnimation::get_anim_name);
+	ClassDB::bind_method(D_METHOD("get_duration"), &SpineAnimation::get_duration);
+	ClassDB::bind_method(D_METHOD("set_duration", "v"), &SpineAnimation::set_duration);
+
+	ClassDB::bind_method(D_METHOD("apply", "skeleton", "last_time", "time", "loop", "events", "alpha", "blend", "direction"), &SpineAnimation::apply);
+	ClassDB::bind_method(D_METHOD("get_timelines"), &SpineAnimation::get_timelines);
+	ClassDB::bind_method(D_METHOD("has_timeline", "ids"), &SpineAnimation::has_timeline);
+}
+
+SpineAnimation::SpineAnimation():animation(NULL) {}
+SpineAnimation::~SpineAnimation(){}
+
+String SpineAnimation::get_anim_name() {
+	return animation->getName().buffer();
+}
+
+float SpineAnimation::get_duration() {
+	return animation->getDuration();
+}
+void SpineAnimation::set_duration(float v) {
+	animation->setDuration(v);
+}
+
+void SpineAnimation::apply(Ref<SpineSkeleton> skeleton, float lastTime, float time, bool loop,
+                           Array pEvents, float alpha, SpineConstant::MixBlend blend,
+                           SpineConstant::MixDirection direction) {
+    spine::Vector<spine::Event*> events;
+    events.setSize(pEvents.size(), nullptr);
+    for (size_t i=0; i<events.size(); ++i) {
+        events[i] = ((Ref<SpineEvent>)(pEvents[i]))->get_spine_object();
+    }
+    animation->apply(*(skeleton->get_spine_object()), lastTime, time, loop, &events, alpha, (spine::MixBlend) blend, (spine::MixDirection) direction);
+}
+
+Array SpineAnimation::get_timelines() {
+    auto &timelines = animation->getTimelines();
+    Array res;
+    res.resize(timelines.size());
+
+    for (size_t i=0; i<res.size(); ++i) {
+        auto a = Ref<SpineTimeline>(memnew(SpineTimeline));
+        a->set_spine_object(timelines[i]);
+        res.set(i, a);
+    }
+
+    return res;
+}
+
+bool SpineAnimation::has_timeline(Array ids) {
+    spine::Vector<spine::PropertyId> list;
+    list.setSize(ids.size(), 0);
+
+    for (size_t i=0; i<list.size(); ++i) {
+        list[i] = ids[i];
+    }
+    return animation->hasTimeline(list);
+}

+ 74 - 0
spine-godot/spine_godot/SpineAnimation.h

@@ -0,0 +1,74 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINEANIMATION_H
+#define GODOT_SPINEANIMATION_H
+
+#include "core/variant_parser.h"
+
+#include "SpineConstant.h"
+
+#include <spine/spine.h>
+
+class SpineEvent;
+class SpineSkeleton;
+class SpineTimeline;
+
+class SpineAnimation : public Reference{
+	GDCLASS(SpineAnimation, Reference);
+
+private:
+	spine::Animation *animation;
+
+protected:
+	static void _bind_methods();
+
+public:
+	SpineAnimation();
+	~SpineAnimation();
+
+	inline void set_spine_object(spine::Animation *a){
+		animation = a;
+	}
+	inline spine::Animation *get_spine_object(){
+		return animation;
+	}
+
+	// Vector<Ref<SpineEvent>> pEvents
+    void apply(Ref<SpineSkeleton> skeleton, float lastTime, float time, bool loop, Array pEvents, float alpha, SpineConstant::MixBlend blend, SpineConstant::MixDirection direction);
+
+    Array get_timelines(); // Vector<Ref<SpineTimeline>>
+    bool has_timeline(Array ids); // Vector<SpineConstant::PropertyId>
+
+	String get_anim_name();
+	float get_duration();
+	void set_duration(float v);
+};
+
+#endif //GODOT_SPINEANIMATION_H

+ 190 - 0
spine-godot/spine_godot/SpineAnimationState.cpp

@@ -0,0 +1,190 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineAnimationState.h"
+
+void SpineAnimationState::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("set_animation", "anim_name", "loop", "track_id"), &SpineAnimationState::set_animation, DEFVAL(true), DEFVAL(0));
+	ClassDB::bind_method(D_METHOD("update", "delta"), &SpineAnimationState::update, DEFVAL(0));
+	ClassDB::bind_method(D_METHOD("apply", "skeleton"), &SpineAnimationState::apply);
+	ClassDB::bind_method(D_METHOD("clear_tracks"), &SpineAnimationState::clear_tracks);
+	ClassDB::bind_method(D_METHOD("clear_track"), &SpineAnimationState::clear_track);
+	ClassDB::bind_method(D_METHOD("add_animation", "anim_name", "delay", "loop", "track_id"), &SpineAnimationState::add_animation, DEFVAL(0), DEFVAL(true), DEFVAL(0));
+	ClassDB::bind_method(D_METHOD("set_empty_animation", "track_id", "mix_duration"), &SpineAnimationState::set_empty_animation);
+	ClassDB::bind_method(D_METHOD("add_empty_animation", "track_id", "mix_duration", "delay"), &SpineAnimationState::add_empty_animation);
+	ClassDB::bind_method(D_METHOD("set_empty_animations", "mix_duration"), &SpineAnimationState::set_empty_animations);
+	ClassDB::bind_method(D_METHOD("get_data"), &SpineAnimationState::get_data);
+	ClassDB::bind_method(D_METHOD("get_time_scale"), &SpineAnimationState::get_time_scale);
+	ClassDB::bind_method(D_METHOD("set_time_scale", "time_scale"), &SpineAnimationState::set_time_scale);
+	ClassDB::bind_method(D_METHOD("disable_queue"), &SpineAnimationState::disable_queue);
+	ClassDB::bind_method(D_METHOD("enable_queue"), &SpineAnimationState::enable_queue);
+//	ClassDB::bind_method(D_METHOD("reload"), &SpineAnimationState::reload_animation_state);
+	ClassDB::bind_method(D_METHOD("get_current", "track_id"), &SpineAnimationState::get_current);
+}
+
+SpineAnimationState::SpineAnimationState():animation_state(NULL) {
+
+}
+
+SpineAnimationState::~SpineAnimationState() {
+	if(animation_state)
+	{
+		delete animation_state;
+		animation_state = NULL;
+	}
+}
+
+void SpineAnimationState::load_animation_state(Ref<SpineAnimationStateDataResource> ad) {
+	if(animation_state)
+	{
+		delete animation_state;
+		animation_state = NULL;
+	}
+	animation_state = new spine::AnimationState(ad->get_animation_state_data());
+	anim_state_data_res = ad;
+}
+
+void SpineAnimationState::reload_animation_state() {
+	if(!anim_state_data_res.is_valid())
+	{
+		ERR_PRINT(" Reload animation state fail, because anim_state_data_res not set!");
+		return;
+	}
+	if(animation_state)
+	{
+		delete animation_state;
+		animation_state = NULL;
+	}
+	animation_state = new spine::AnimationState(anim_state_data_res->get_animation_state_data());
+}
+
+#define CHECK_V if(!animation_state){ERR_PRINT("The animation state is not loaded yet!");return;}
+#define CHECK_X(x) if(!animation_state){ERR_PRINT("The animation state is not loaded yet!");return x;}
+#define S_T(x) (spine::String(x.utf8()))
+Ref<SpineTrackEntry> SpineAnimationState::set_animation(const String &anim_name, bool loop, uint64_t track) {
+	CHECK_X(NULL);
+	auto skeleton_data = anim_state_data_res->get_skeleton();
+	auto anim = skeleton_data->find_animation(anim_name);
+	if(!anim.is_valid() || anim->get_spine_object() == NULL)
+	{
+		ERR_PRINT(String("Can not find animation: ") + anim_name)
+		return NULL;
+	}
+	auto entry = animation_state->setAnimation(track, anim->get_spine_object(), loop);
+	Ref<SpineTrackEntry> gd_entry(memnew(SpineTrackEntry));
+	gd_entry->set_spine_object(entry);
+	return gd_entry;
+}
+Ref<SpineTrackEntry> SpineAnimationState::add_animation(const String &anim_name, float delay, bool loop, uint64_t track) {
+	CHECK_X(NULL);
+	auto skeleton_data = anim_state_data_res->get_skeleton();
+	auto anim = skeleton_data->find_animation(anim_name);
+	if(!anim.is_valid() || anim->get_spine_object() == NULL)
+	{
+		ERR_PRINT(String("Can not find animation: ") + anim_name)
+		return NULL;
+	}
+	auto entry = animation_state->addAnimation(track, anim->get_spine_object(), loop, delay);
+	Ref<SpineTrackEntry> gd_entry(memnew(SpineTrackEntry));
+	gd_entry->set_spine_object(entry);
+	return gd_entry;
+}
+
+Ref<SpineTrackEntry> SpineAnimationState::set_empty_animation(uint64_t track_id, float mix_duration) {
+	CHECK_X(NULL);
+	auto entry = animation_state->setEmptyAnimation(track_id, mix_duration);
+	Ref<SpineTrackEntry> gd_entry(memnew(SpineTrackEntry));
+	gd_entry->set_spine_object(entry);
+	return gd_entry;
+}
+Ref<SpineTrackEntry> SpineAnimationState::add_empty_animation(uint64_t track_id, float mix_duration, float delay) {
+	CHECK_X(NULL);
+	auto entry = animation_state->addEmptyAnimation(track_id, mix_duration, delay);
+	Ref<SpineTrackEntry> gd_entry(memnew(SpineTrackEntry));
+	gd_entry->set_spine_object(entry);
+	return gd_entry;
+}
+void SpineAnimationState::set_empty_animations(float mix_duration) {
+	CHECK_V;
+	animation_state->setEmptyAnimations(mix_duration);
+}
+
+void SpineAnimationState::update(float delta){
+	CHECK_V;
+	animation_state->update(delta);
+}
+bool SpineAnimationState::apply(Ref<SpineSkeleton> skeleton){
+	CHECK_X(false);
+	return animation_state->apply(*(skeleton->get_spine_object()));
+}
+
+
+void SpineAnimationState::clear_tracks() {
+	CHECK_V;
+	animation_state->clearTracks();
+}
+void SpineAnimationState::clear_track(uint64_t track_id) {
+	CHECK_V;
+	animation_state->clearTrack(track_id);
+}
+
+Ref<SpineAnimationStateDataResource> SpineAnimationState::get_data() {
+	CHECK_X(NULL);
+	return anim_state_data_res;
+}
+
+float SpineAnimationState::get_time_scale() {
+	CHECK_X(0);
+	return animation_state->getTimeScale();
+}
+void SpineAnimationState::set_time_scale(float v) {
+	CHECK_V;
+	animation_state->setTimeScale(v);
+}
+
+void SpineAnimationState::disable_queue() {
+	CHECK_V;
+	animation_state->disableQueue();
+}
+void SpineAnimationState::enable_queue() {
+	CHECK_V;
+	animation_state->enableQueue();
+}
+
+Ref<SpineTrackEntry> SpineAnimationState::get_current(uint64_t track_index) {
+	CHECK_X(NULL);
+	Ref<SpineTrackEntry> gd_entry(memnew(SpineTrackEntry));
+	auto entry = animation_state->getCurrent(track_index);
+	if(entry == NULL) return NULL;
+	gd_entry->set_spine_object(entry);
+	return gd_entry;
+}
+
+#undef CHECK_V
+#undef CHECK_X

+ 93 - 0
spine-godot/spine_godot/SpineAnimationState.h

@@ -0,0 +1,93 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINEANIMATIONSTATE_H
+#define GODOT_SPINEANIMATIONSTATE_H
+
+#include "core/variant_parser.h"
+
+#include "SpineAnimationStateDataResource.h"
+#include "SpineSkeleton.h"
+#include "SpineTrackEntry.h"
+
+class SpineAnimationState : public Reference{
+	GDCLASS(SpineAnimationState, Reference);
+
+protected:
+	static void _bind_methods();
+
+private:
+	spine::AnimationState *animation_state;
+
+	Ref<SpineAnimationStateDataResource> anim_state_data_res;
+public:
+	void load_animation_state(Ref<SpineAnimationStateDataResource> ad);
+
+	inline void set_animation_state(spine::AnimationState *a){
+		animation_state = a;
+	}
+	inline spine::AnimationState *get_animation_state(){
+		return animation_state;
+	}
+
+	void reload_animation_state();
+
+	Ref<SpineTrackEntry> set_animation(const String &anim_name, bool loop, uint64_t track_id);
+	inline void set_animation_by_ref(Ref<SpineAnimation> anim, bool loop, uint64_t track_id){
+		if(anim.is_valid()){
+			animation_state->setAnimation(track_id, anim->get_spine_object(), loop);
+		}
+	}
+	Ref<SpineTrackEntry> add_animation(const String &anim_name, float delay, bool loop, uint64_t track_id);
+
+	Ref<SpineTrackEntry> set_empty_animation(uint64_t track_id, float mix_duration);
+	Ref<SpineTrackEntry> add_empty_animation(uint64_t track_id, float mix_duration, float delay);
+	void set_empty_animations(float mix_duration);
+
+	Ref<SpineAnimationStateDataResource> get_data();
+
+	float get_time_scale();
+	void set_time_scale(float v);
+
+	void disable_queue();
+	void enable_queue();
+
+	void update(float delta);
+	bool apply(Ref<SpineSkeleton> skeleton);
+
+	void clear_tracks();
+	void clear_track(uint64_t track_id);
+
+	Ref<SpineTrackEntry> get_current(uint64_t track_index);
+
+	SpineAnimationState();
+	~SpineAnimationState();
+};
+
+#endif //GODOT_SPINEANIMATIONSTATE_H

+ 178 - 0
spine-godot/spine_godot/SpineAnimationStateDataResource.cpp

@@ -0,0 +1,178 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineAnimationStateDataResource.h"
+
+SpineAnimationStateDataResource::SpineAnimationStateDataResource():animation_state_data(NULL),animation_state_data_created(false),default_mix(0.5f) {
+
+}
+SpineAnimationStateDataResource::~SpineAnimationStateDataResource() {
+	if(animation_state_data)
+	{
+		delete animation_state_data;
+		animation_state_data = NULL;
+	}
+}
+
+void SpineAnimationStateDataResource::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("set_skeleton", "skeleton"), &SpineAnimationStateDataResource::set_skeleton);
+	ClassDB::bind_method(D_METHOD("get_spine_object"), &SpineAnimationStateDataResource::get_skeleton);
+	ClassDB::bind_method(D_METHOD("_on_skeleton_data_loaded"), &SpineAnimationStateDataResource::_on_skeleton_data_loaded);
+	ClassDB::bind_method(D_METHOD("is_animation_state_data_created"), &SpineAnimationStateDataResource::is_animation_state_data_created);
+	ClassDB::bind_method(D_METHOD("_on_skeleton_data_changed"), &SpineAnimationStateDataResource::_on_skeleton_data_changed);
+	ClassDB::bind_method(D_METHOD("set_default_mix", "mix"), &SpineAnimationStateDataResource::set_default_mix);
+	ClassDB::bind_method(D_METHOD("get_default_mix"), &SpineAnimationStateDataResource::get_default_mix);
+	ClassDB::bind_method(D_METHOD("get_mix", "from", "to"), &SpineAnimationStateDataResource::get_mix);
+	ClassDB::bind_method(D_METHOD("set_mix", "from", "to", "mix"), &SpineAnimationStateDataResource::set_mix);
+
+	ADD_SIGNAL(MethodInfo("animation_state_data_created"));
+	ADD_SIGNAL(MethodInfo("skeleton_data_res_changed"));
+	ADD_SIGNAL(MethodInfo("animation_state_data_changed"));
+
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skeleton", PropertyHint::PROPERTY_HINT_RESOURCE_TYPE, "SpineSkeletonDataResource"), "set_skeleton", "get_spine_object");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "default_mix", PropertyHint::PROPERTY_HINT_EXP_RANGE, "0,1,0.01"), "set_default_mix", "get_default_mix");
+}
+
+void SpineAnimationStateDataResource::set_skeleton(const Ref<SpineSkeletonDataResource> &s) {
+	skeleton = s;
+
+	_on_skeleton_data_changed();
+	if(skeleton.is_valid())
+	{
+		skeleton->connect("skeleton_data_loaded", this, "_on_skeleton_data_loaded");
+		skeleton->connect("atlas_res_changed", this, "_on_skeleton_data_changed");
+		skeleton->connect("skeleton_json_res_changed", this, "_on_skeleton_data_changed");
+
+		if(skeleton->is_skeleton_data_loaded())
+		{
+			_on_skeleton_data_loaded();
+		}
+	}else{
+		if(animation_state_data)
+		{
+			delete animation_state_data;
+			animation_state_data = NULL;
+			animation_state_data_created = false;
+//			print_line("Animation state data deleted.");
+		}
+	}
+
+
+}
+Ref<SpineSkeletonDataResource> SpineAnimationStateDataResource::get_skeleton() {
+	return skeleton;
+}
+
+void SpineAnimationStateDataResource::set_default_mix(float m) {
+	default_mix = m;
+	if(!is_animation_state_data_created())
+	{
+//		ERR_PRINT("'set_default_mix' fail. Animation state data is not created!");
+		return;
+	}
+	animation_state_data->setDefaultMix(((m >= 0 && m <= 1) ? m : m <= 0 ? 0 : 1));
+//	emit_signal("animation_state_data_changed");
+}
+float SpineAnimationStateDataResource::get_default_mix() {
+	if(!is_animation_state_data_created())
+	{
+//		ERR_PRINT("'get_default_mix' fail. Animation state data is not created!");
+		return default_mix;
+	}
+	default_mix = animation_state_data->getDefaultMix();
+	return default_mix;
+}
+
+void SpineAnimationStateDataResource::set_mix(const String &from, const String &to, float mix_duration) {
+	if(!is_animation_state_data_created())
+	{
+		ERR_PRINT("'set_mix' fail. Animation state data is not created!");
+		return;
+	}
+	auto anim_from = get_skeleton()->find_animation(from);
+	auto anim_to = get_skeleton()->find_animation(to);
+	if(!anim_from.is_valid())
+	{
+		ERR_PRINT("'set_mix' fail. From animation animation not found!");
+		return;
+	}
+	if(!anim_to.is_valid())
+	{
+		ERR_PRINT("'set_mix' fail. To animation animation not found!");
+		return;
+	}
+	animation_state_data->setMix(anim_from->get_spine_object(), anim_to->get_spine_object(), mix_duration);
+}
+float SpineAnimationStateDataResource::get_mix(const String &from, const String &to) {
+	if(!is_animation_state_data_created())
+	{
+		ERR_PRINT("'set_mix' fail. Animation state data is not created!");
+		return 0;
+	}
+	auto anim_from = get_skeleton()->find_animation(from);
+	auto anim_to = get_skeleton()->find_animation(to);
+	if(!anim_from.is_valid())
+	{
+		ERR_PRINT("'set_mix' fail. From animation animation not found!");
+		return 0;
+	}
+	if(!anim_to.is_valid())
+	{
+		ERR_PRINT("'set_mix' fail. To animation animation not found!");
+		return 0;
+	}
+	return animation_state_data->getMix(anim_from->get_spine_object(), anim_to->get_spine_object());
+}
+
+void SpineAnimationStateDataResource::_on_skeleton_data_loaded() {
+	animation_state_data = new spine::AnimationStateData(skeleton->get_skeleton_data());
+//	print_line("Animation state data created.");
+
+
+	emit_signal("animation_state_data_created");
+	animation_state_data->setDefaultMix(default_mix);
+	animation_state_data_created = true;
+}
+
+void SpineAnimationStateDataResource::_on_skeleton_data_changed() {
+	animation_state_data_created = false;
+	if(animation_state_data)
+	{
+		delete animation_state_data;
+		animation_state_data = NULL;
+//		print_line("Animation state data deleted.");
+	}
+
+//	print_line("skeleton_data_res_changed emitted");
+	emit_signal("skeleton_data_res_changed");
+}
+
+bool SpineAnimationStateDataResource::is_animation_state_data_created(){
+	return animation_state_data_created;
+}

+ 76 - 0
spine-godot/spine_godot/SpineAnimationStateDataResource.h

@@ -0,0 +1,76 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINEANIMATIONSTATEDATARESOURCE_H
+#define GODOT_SPINEANIMATIONSTATEDATARESOURCE_H
+
+#include "core/variant_parser.h"
+
+#include "SpineSkeletonDataResource.h"
+
+class SpineAnimationStateDataResource : public Resource{
+	GDCLASS(SpineAnimationStateDataResource, Resource);
+
+protected:
+	static void _bind_methods();
+
+private:
+	Ref<SpineSkeletonDataResource> skeleton;
+
+	spine::AnimationStateData *animation_state_data;
+
+	bool animation_state_data_created;
+
+	float default_mix;
+public:
+
+	void set_skeleton(const Ref<SpineSkeletonDataResource> &s);
+	Ref<SpineSkeletonDataResource> get_skeleton();
+
+	inline spine::AnimationStateData *get_animation_state_data(){
+		return animation_state_data;
+	}
+
+	void set_default_mix(float m);
+	float get_default_mix();
+
+	void set_mix(const String &from, const String &to, float mix_duration);
+	float get_mix(const String &from, const String &to);
+
+
+	void _on_skeleton_data_loaded();
+	void _on_skeleton_data_changed();
+
+	bool is_animation_state_data_created();
+
+	SpineAnimationStateDataResource();
+	~SpineAnimationStateDataResource();
+};
+
+#endif //GODOT_SPINEANIMATIONSTATEDATARESOURCE_H

+ 229 - 0
spine-godot/spine_godot/SpineAtlasResource.cpp

@@ -0,0 +1,229 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineAtlasResource.h"
+#include "core/io/json.h"
+
+#include <spine/Atlas.h>
+
+class GodotSpineTextureLoader : public spine::TextureLoader {
+private:
+    Array *tex_list, *ntex_list;
+    String normal_tex_prefix;
+public:
+
+    GodotSpineTextureLoader(Array *t, Array *nt, const String &p):tex_list(t), ntex_list(nt), normal_tex_prefix(p){
+        if (tex_list) tex_list->clear();
+        if (ntex_list) ntex_list->clear();
+    }
+
+    String fixPathIssue(const String &path){
+        if(path.size() > 5 && path[4] == '/' && path[5] == '/') return path;
+        const String prefix = "res:/";
+        auto i = path.find(prefix);
+//        print_line(String("Found i at ") + String(Variant(i)));
+        auto sub_str_pos = i+prefix.size()-1;
+        if(sub_str_pos < 0) return path;
+        auto res = path.substr(sub_str_pos);
+//        print_line(String("rest of it: ") + res);
+        if(res.size() > 0)
+        {
+            if(res[0] != '/')
+            {
+                return prefix + "/" + res;
+            } else
+            {
+                return  prefix + res;
+            }
+        }
+        return path;
+    }
+
+    virtual void load(spine::AtlasPage &page, const spine::String &path){
+        Error err = OK;
+
+//		print_line(String("Spine is loading texture: ") + String(path.buffer()));
+        auto fixed_path = fixPathIssue(String(path.buffer()));
+//        print_line("Fixed path: " + fixed_path);
+
+		// Load texture (e.g. tex.png)
+		Ref<Texture> tex = ResourceLoader::load(fixed_path, "", false, &err);
+		if (err != OK) {
+            print_error(vformat("Can't load texture: \"%s\"", String(path.buffer())));
+            page.setRendererObject((void*)memnew(SpineRendererObject {nullptr}));
+            return;
+		}
+
+		if (tex_list) tex_list->append(tex);
+		auto p_spine_renderer_object = memnew(SpineRendererObject);
+		p_spine_renderer_object->tex = tex;
+
+		// Load normal texture (e.g. n_tex.png)
+		String temppath = fixed_path;
+		String newpath = vformat("%s/%s_%s", temppath.get_base_dir(), normal_tex_prefix, temppath.get_file());
+//        print_line(vformat("try n tex: %s", newpath));
+		if (ResourceLoader::exists(newpath)){
+			Ref<Texture> normal_tex = ResourceLoader::load(newpath);
+			if (ntex_list) ntex_list->append(normal_tex);
+			p_spine_renderer_object->normal_tex = normal_tex;
+
+			// print_line(String("From atlas resource load: ") + String(" ro ") + String(Variant((long long) p_spine_renderer_object)));
+			// print_line(String("From atlas resource load: ") + String(Variant(p_spine_renderer_object->tex)) + String(", ") + String(Variant(p_spine_renderer_object->normal_tex)));
+		}
+
+		page.setRendererObject((void*)p_spine_renderer_object);		
+
+		page.width = tex->get_width();
+		page.height = tex->get_height();
+    }
+
+    virtual void unload(void *p){
+		// print_line("I'm out.");
+		auto p_spine_renderer_object = (SpineRendererObject*) p;
+        Ref<Texture> &tex = p_spine_renderer_object->tex;
+		Ref<Texture> &normal_tex = p_spine_renderer_object->normal_tex;
+
+		if (tex.is_valid()) tex.unref();
+		if (normal_tex.is_valid()) normal_tex.unref();
+
+		memdelete(p_spine_renderer_object);
+    }
+};
+
+SpineAtlasResource::SpineAtlasResource():atlas(nullptr), normal_texture_prefix("n"){}
+SpineAtlasResource::~SpineAtlasResource(){
+    if (atlas) delete atlas;
+}
+
+void SpineAtlasResource::_bind_methods(){
+    ClassDB::bind_method(D_METHOD("load_from_atlas_file", "path"), &SpineAtlasResource::load_from_atlas_file);
+
+    ClassDB::bind_method(D_METHOD("get_source_path"), &SpineAtlasResource::get_source_path);
+
+	ClassDB::bind_method(D_METHOD("get_textures"), &SpineAtlasResource::get_textures);
+	ClassDB::bind_method(D_METHOD("get_normal_textures"), &SpineAtlasResource::get_normal_textures);
+
+	ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_path"), "", "get_source_path");
+	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "textures"), "", "get_textures");
+	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "normal_textures"), "", "get_normal_textures");
+}
+
+
+Array SpineAtlasResource::get_textures() {
+	return tex_list;
+}
+
+Array SpineAtlasResource::get_normal_textures() {
+    return ntex_list;
+}
+
+String SpineAtlasResource::get_source_path() {
+    return source_path;
+}
+
+Error SpineAtlasResource::load_from_atlas_file(const String &p_path) {
+//    print_line(vformat("Importing atlas file: %s", p_path));
+    source_path = p_path;
+
+    Error err;
+
+    atlas_data = FileAccess::get_file_as_string(p_path, &err);
+    if (err != OK) return err;
+
+    if (atlas) delete atlas;
+    tex_list.clear();
+    ntex_list.clear();
+    atlas = new spine::Atlas(atlas_data.utf8(), atlas_data.size(), source_path.get_base_dir().utf8(), new GodotSpineTextureLoader(&tex_list, &ntex_list, normal_texture_prefix));
+
+//    print_line(vformat("atlas loaded!"));
+
+    if (atlas)
+        return OK;
+
+    tex_list.clear();
+    ntex_list.clear();
+
+    return ERR_FILE_UNRECOGNIZED;
+}
+
+Error SpineAtlasResource::load_from_file(const String &p_path) {
+    Error err;
+
+    String json_string = FileAccess::get_file_as_string(p_path, &err);
+    if (err != OK) return err;
+
+    String error_string;
+    int error_line;
+    JSON json;
+    Variant result;
+    err = json.parse(json_string, result, error_string, error_line);
+    if (err != OK) {
+        return err;
+    }
+
+    Dictionary content = Dictionary(result);
+
+    source_path = content["source_path"];
+    atlas_data = content["atlas_data"];
+    normal_texture_prefix = content["normal_texture_prefix"];
+
+    if (atlas) delete atlas;
+    tex_list.clear();
+    ntex_list.clear();
+    atlas = new spine::Atlas(atlas_data.utf8(), atlas_data.size(), source_path.get_base_dir().utf8(), new GodotSpineTextureLoader(&tex_list, &ntex_list, normal_texture_prefix));
+
+    if (atlas)
+        return OK;
+
+    tex_list.clear();
+    ntex_list.clear();
+    return ERR_FILE_UNRECOGNIZED;
+}
+
+Error SpineAtlasResource::save_to_file(const String &p_path) {
+    Error err;
+    FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+    if (err != OK) {
+//        print_line(vformat("save file err: %d", err));
+        if (file) file->close();
+        return err;
+    }
+
+    Dictionary content;
+    content["source_path"] = source_path;
+    content["atlas_data"] = atlas_data;
+    content["normal_texture_prefix"] = normal_texture_prefix;
+
+//    print_line(vformat("storing source_path: %s", source_path));
+
+    file->store_string(JSON::print(content));
+    file->close();
+
+    return OK;
+}

+ 79 - 0
spine-godot/spine_godot/SpineAtlasResource.h

@@ -0,0 +1,79 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINEATLASRESOURCE_H
+#define GODOT_SPINEATLASRESOURCE_H
+
+
+
+#include "core/variant_parser.h"
+
+#include <spine/SpineString.h>
+#include <spine/TextureLoader.h>
+#include <spine/Atlas.h>
+#include <scene/resources/texture.h>
+#include <core/io/image_loader.h>
+#include "SpineRendererObject.h"
+
+class SpineAtlasResource : public Resource{
+    GDCLASS(SpineAtlasResource, Resource);
+
+protected:
+    static void _bind_methods();
+
+    spine::Atlas *atlas;
+
+    String source_path;
+    String atlas_data;
+    String normal_texture_prefix;
+
+    Array tex_list;
+    Array ntex_list;
+public:
+    inline String &get_atlas_data() {return atlas_data;}
+
+    inline spine::Atlas *get_spine_atlas() {return atlas;}
+
+    inline void set_normal_texture_prefix(const String &p) {normal_texture_prefix = p;}
+
+    Error load_from_atlas_file(const String &p_path); // .atlas
+
+    Error load_from_file(const String &p_path); // .spatlas
+    Error save_to_file(const String &p_path); // .spatlas
+
+    String get_source_path();
+	Array get_textures();
+	Array get_normal_textures();
+
+	SpineAtlasResource();
+    virtual ~SpineAtlasResource();
+};
+
+
+#endif //GODOT_SPINEATLASRESOURCE_H

+ 55 - 0
spine-godot/spine_godot/SpineAttachment.cpp

@@ -0,0 +1,55 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineAttachment.h"
+
+void SpineAttachment::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_attachment_name"), &SpineAttachment::get_attachment_name);
+	ClassDB::bind_method(D_METHOD("copy"), &SpineAttachment::copy);
+}
+
+SpineAttachment::SpineAttachment():attachment(NULL) {}
+SpineAttachment::~SpineAttachment() {
+	if(attachment){
+		attachment->dereference();
+		attachment = NULL;
+	}
+}
+
+String SpineAttachment::get_attachment_name(){
+	return attachment->getName().buffer();
+}
+
+Ref<SpineAttachment> SpineAttachment::copy(){
+	auto a = attachment->copy();
+	if(a == NULL) return NULL;
+	Ref<SpineAttachment> gd_attachment(memnew(SpineAttachment));
+	gd_attachment->set_spine_object(a);
+	return gd_attachment;
+}

+ 64 - 0
spine-godot/spine_godot/SpineAttachment.h

@@ -0,0 +1,64 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINEATTACHMENT_H
+#define GODOT_SPINEATTACHMENT_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+class SpineAttachment : public Reference {
+	GDCLASS(SpineAttachment, Reference);
+
+protected:
+	static void _bind_methods();
+
+private:
+	spine::Attachment *attachment;
+
+public:
+	SpineAttachment();
+	~SpineAttachment();
+
+	inline void set_spine_object(spine::Attachment *a){
+		attachment = a;
+		if(attachment)
+			attachment->reference();
+	}
+	inline spine::Attachment *get_spine_object(){
+		return attachment;
+	}
+
+	String get_attachment_name();
+
+	Ref<SpineAttachment> copy();
+};
+
+#endif //GODOT_SPINEATTACHMENT_H

+ 537 - 0
spine-godot/spine_godot/SpineBone.cpp

@@ -0,0 +1,537 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineBone.h"
+
+#include "SpineSprite.h"
+#include "SpineSkeleton.h"
+
+void SpineBone::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("update_world_transform"), &SpineBone::update_world_transform);
+//	void set_to_setup_pose();
+//
+//	Vector2 world_to_local(Vector2 world_position);
+//
+//	Vector2 local_to_world(Vector2 local_position);
+//
+//	float world_to_local_rotation(float world_rotation);
+//
+//	float local_to_world_rotation(float local_rotation);
+//
+//	void rotate_world(float degrees);
+	ClassDB::bind_method(D_METHOD("set_to_setup_pose"), &SpineBone::set_to_setup_pose);
+	ClassDB::bind_method(D_METHOD("world_to_local", "world_position"), &SpineBone::world_to_local);
+	ClassDB::bind_method(D_METHOD("local_to_world", "local_position"), &SpineBone::local_to_world);
+	ClassDB::bind_method(D_METHOD("world_to_local_rotation", "world_rotation"), &SpineBone::world_to_local_rotation);
+	ClassDB::bind_method(D_METHOD("local_to_world_rotation", "local_rotation"), &SpineBone::local_to_world_rotation);
+	ClassDB::bind_method(D_METHOD("rotate_world"), &SpineBone::rotate_world);
+//
+//	float get_world_to_local_rotation_x();
+//	float get_world_to_local_rotation_y();
+//
+//	Ref<SpineBoneData> get_data();
+//
+//	Ref<SpineSkeleton> get_skeleton();
+//
+//	Ref<SpineBone> get_parent();
+//
+//	Array get_children();
+	ClassDB::bind_method(D_METHOD("get_world_to_local_rotation_x"), &SpineBone::get_world_to_local_rotation_x);
+	ClassDB::bind_method(D_METHOD("get_world_to_local_rotation_y"), &SpineBone::get_world_to_local_rotation_y);
+	ClassDB::bind_method(D_METHOD("get_data"), &SpineBone::get_data);
+	ClassDB::bind_method(D_METHOD("get_skeleton"), &SpineBone::get_skeleton);
+	ClassDB::bind_method(D_METHOD("get_parent"), &SpineBone::get_parent);
+	ClassDB::bind_method(D_METHOD("get_children"), &SpineBone::get_children);
+//
+//	float get_x();
+//	void set_x(float v);
+//
+//	float get_y();
+//	void set_y(float v);
+//
+//	float get_rotation();
+//	void set_rotation(float v);
+//
+//	float get_scale_x();
+//	void set_scale_x(float v);
+	ClassDB::bind_method(D_METHOD("get_x"), &SpineBone::get_x);
+	ClassDB::bind_method(D_METHOD("set_x", "v"), &SpineBone::set_x);
+	ClassDB::bind_method(D_METHOD("get_y"), &SpineBone::get_y);
+	ClassDB::bind_method(D_METHOD("set_y", "v"), &SpineBone::set_y);
+	ClassDB::bind_method(D_METHOD("get_rotation"), &SpineBone::get_rotation);
+	ClassDB::bind_method(D_METHOD("set_rotation", "v"), &SpineBone::set_rotation);
+	ClassDB::bind_method(D_METHOD("get_scale_x"), &SpineBone::get_scale_x);
+	ClassDB::bind_method(D_METHOD("set_scale_x", "v"), &SpineBone::set_scale_x);
+//
+//	float get_scale_y();
+//	void set_scale_y(float v);
+//
+//	float get_shear_x();
+//	void set_shear_x(float v);
+//
+//	float get_shear_y();
+//	void set_shear_y(float v);
+//
+//	float get_applied_rotation();
+//	void set_applied_rotation(float v);
+	ClassDB::bind_method(D_METHOD("get_scale_y"), &SpineBone::get_scale_y);
+	ClassDB::bind_method(D_METHOD("set_scale_y", "v"), &SpineBone::set_scale_y);
+	ClassDB::bind_method(D_METHOD("get_shear_x"), &SpineBone::get_shear_x);
+	ClassDB::bind_method(D_METHOD("set_shear_x", "v"), &SpineBone::set_shear_x);
+	ClassDB::bind_method(D_METHOD("get_shear_y"), &SpineBone::get_shear_y);
+	ClassDB::bind_method(D_METHOD("set_shear_y", "v"), &SpineBone::set_shear_y);
+	ClassDB::bind_method(D_METHOD("get_applied_rotation"), &SpineBone::get_applied_rotation);
+	ClassDB::bind_method(D_METHOD("set_applied_rotation", "v"), &SpineBone::set_applied_rotation);
+//
+//	float get_a_x();
+//	void set_a_x(float v);
+//
+//	float get_a_y();
+//	void set_a_y(float v);
+//
+//	float get_a_scale_x();
+//	void set_a_scale_x(float v);
+//
+//	float get_a_scale_y();
+//	void set_a_scale_y(float v);
+	ClassDB::bind_method(D_METHOD("get_a_x"), &SpineBone::get_a_x);
+	ClassDB::bind_method(D_METHOD("set_a_x", "v"), &SpineBone::set_a_x);
+	ClassDB::bind_method(D_METHOD("get_a_y"), &SpineBone::get_a_y);
+	ClassDB::bind_method(D_METHOD("set_a_y", "v"), &SpineBone::set_a_y);
+	ClassDB::bind_method(D_METHOD("get_a_scale_x"), &SpineBone::get_a_scale_x);
+	ClassDB::bind_method(D_METHOD("set_a_scale_x", "v"), &SpineBone::set_a_scale_x);
+	ClassDB::bind_method(D_METHOD("get_a_scale_y"), &SpineBone::get_a_scale_y);
+	ClassDB::bind_method(D_METHOD("set_a_scale_y", "v"), &SpineBone::set_a_scale_y);
+//
+//	float get_a_shear_x();
+//	void set_a_shear_x(float v);
+//
+//	float get_a_shear_y();
+//	void set_a_shear_y(float v);
+//
+//	float get_a();
+//	void set_a(float v);
+//
+//	float get_b();
+//	void set_b(float v);
+	ClassDB::bind_method(D_METHOD("get_a_shear_x"), &SpineBone::get_a_shear_x);
+	ClassDB::bind_method(D_METHOD("set_a_shear_x", "v"), &SpineBone::set_a_shear_x);
+	ClassDB::bind_method(D_METHOD("get_a_shear_y"), &SpineBone::get_a_shear_y);
+	ClassDB::bind_method(D_METHOD("set_a_shear_y", "v"), &SpineBone::set_a_shear_y);
+	ClassDB::bind_method(D_METHOD("get_a"), &SpineBone::get_a);
+	ClassDB::bind_method(D_METHOD("set_a", "v"), &SpineBone::set_a);
+	ClassDB::bind_method(D_METHOD("get_b"), &SpineBone::get_b);
+	ClassDB::bind_method(D_METHOD("set_b", "v"), &SpineBone::set_b);
+//
+//	float get_c();
+//	void set_c(float v);
+//
+//	float get_d();
+//	void set_d(float v);
+//
+//	float get_world_x();
+//	void set_world_x(float v);
+//
+//	float get_world_y();
+//	void set_world_y(float v);
+	ClassDB::bind_method(D_METHOD("get_c"), &SpineBone::get_c);
+	ClassDB::bind_method(D_METHOD("set_c", "v"), &SpineBone::set_c);
+	ClassDB::bind_method(D_METHOD("get_d"), &SpineBone::get_d);
+	ClassDB::bind_method(D_METHOD("set_d", "v"), &SpineBone::set_d);
+	ClassDB::bind_method(D_METHOD("get_world_x"), &SpineBone::get_world_x);
+	ClassDB::bind_method(D_METHOD("set_world_x", "v"), &SpineBone::set_world_x);
+	ClassDB::bind_method(D_METHOD("get_world_y"), &SpineBone::get_world_y);
+	ClassDB::bind_method(D_METHOD("set_world_y", "v"), &SpineBone::set_world_y);
+//
+//	float get_world_rotation_x();
+//	float get_world_rotation_y();
+//
+//	float get_world_scale_x();
+//	float get_world_scale_y();
+//
+//	bool is_applied_valid();
+//	void set_applied_valid(bool v);
+//
+//	bool is_active();
+//	void set_active(bool v);
+	ClassDB::bind_method(D_METHOD("get_world_rotation_x"), &SpineBone::get_world_rotation_x);
+	ClassDB::bind_method(D_METHOD("get_world_rotation_y"), &SpineBone::get_world_rotation_y);
+	ClassDB::bind_method(D_METHOD("get_world_scale_x"), &SpineBone::get_world_scale_x);
+	ClassDB::bind_method(D_METHOD("get_world_scale_y"), &SpineBone::get_world_scale_y);
+	ClassDB::bind_method(D_METHOD("is_active"), &SpineBone::is_active);
+	ClassDB::bind_method(D_METHOD("set_active", "v"), &SpineBone::set_active);
+
+	ClassDB::bind_method(D_METHOD("get_godot_transform"), &SpineBone::get_godot_transform);
+	ClassDB::bind_method(D_METHOD("set_godot_transform", "local_transform"), &SpineBone::set_godot_transform);
+    ClassDB::bind_method(D_METHOD("get_godot_global_transform"), &SpineBone::get_godot_global_transform);
+    ClassDB::bind_method(D_METHOD("set_godot_global_transform", "global_transform"), &SpineBone::set_godot_global_transform);
+
+	ClassDB::bind_method(D_METHOD("apply_world_transform_2d", "node2d"), &SpineBone::apply_world_transform_2d);
+}
+
+SpineBone::SpineBone():bone(NULL), the_sprite(nullptr) {}
+SpineBone::~SpineBone() {}
+
+void SpineBone::update_world_transform(){
+	bone->updateWorldTransform();
+}
+
+void SpineBone::set_to_setup_pose(){
+	bone->setToSetupPose();
+}
+
+Vector2 SpineBone::world_to_local(Vector2 world_position){
+	float x, y;
+	bone->worldToLocal(world_position.x, world_position.y, x, y);
+	return Vector2(x, y);
+}
+
+Vector2 SpineBone::local_to_world(Vector2 local_position){
+	float x, y;
+	bone->localToWorld(local_position.x, local_position.y, x, y);
+	return Vector2(x, y);
+}
+
+float SpineBone::world_to_local_rotation(float world_rotation){
+	return bone->worldToLocalRotation(world_rotation);
+}
+
+float SpineBone::local_to_world_rotation(float local_rotation){
+	return bone->localToWorldRotation(local_rotation);
+}
+
+void SpineBone::rotate_world(float degrees){
+	bone->rotateWorld(degrees);
+}
+
+float SpineBone::get_world_to_local_rotation_x(){
+	return bone->getWorldToLocalRotationX();
+}
+float SpineBone::get_world_to_local_rotation_y(){
+	return bone->getWorldToLocalRotationY();
+}
+
+Ref<SpineBoneData> SpineBone::get_data(){
+	auto &bd = bone->getData();
+	Ref<SpineBoneData> gd_bd(memnew(SpineBoneData));
+	gd_bd->set_spine_object(&bd);
+	return gd_bd;
+}
+
+Ref<SpineSkeleton> SpineBone::get_skeleton(){
+	auto &s = bone->getSkeleton();
+	Ref<SpineSkeleton> gd_s(memnew(SpineSkeleton));
+	gd_s->set_spine_object(&s);
+	gd_s->set_spine_sprite(the_sprite);
+	return gd_s;
+}
+
+Ref<SpineBone> SpineBone::get_parent(){
+	auto b = bone->getParent();
+	if(b == NULL) return NULL;
+	Ref<SpineBone> gd_b(memnew(SpineBone));
+	gd_b->set_spine_object(b);
+	gd_b->set_spine_sprite(the_sprite);
+	return gd_b;
+}
+
+Array SpineBone::get_children(){
+	auto bs = bone->getChildren();
+	Array gd_bs;
+	gd_bs.resize(bs.size());
+	for(size_t i=0; i < bs.size(); ++i){
+		auto b = bs[i];
+		if(b == NULL) gd_bs[i] = Ref<SpineBone>(NULL);
+		Ref<SpineBone> gd_b(memnew(SpineBone));
+		gd_b->set_spine_object(b);
+		gd_b->set_spine_sprite(the_sprite);
+		gd_bs[i] = gd_b;
+	}
+	return gd_bs;
+}
+
+float SpineBone::get_x(){
+	return bone->getX();
+}
+void SpineBone::set_x(float v){
+	bone->setX(v);
+}
+
+float SpineBone::get_y(){
+	return bone->getY();
+}
+void SpineBone::set_y(float v){
+	bone->setY(v);
+}
+
+float SpineBone::get_rotation(){
+	return bone->getRotation();
+}
+void SpineBone::set_rotation(float v){
+	bone->setRotation(v);
+}
+
+float SpineBone::get_scale_x(){
+	return bone->getScaleX();
+}
+void SpineBone::set_scale_x(float v){
+	bone->setScaleX(v);
+}
+
+float SpineBone::get_scale_y(){
+	return bone->getScaleY();
+}
+void SpineBone::set_scale_y(float v){
+	bone->setScaleY(v);
+}
+
+float SpineBone::get_shear_x(){
+	return bone->getShearX();
+}
+void SpineBone::set_shear_x(float v){
+	bone->setShearX(v);
+}
+
+float SpineBone::get_shear_y(){
+	return bone->getShearY();
+}
+void SpineBone::set_shear_y(float v){
+	bone->setShearY(v);
+}
+
+float SpineBone::get_applied_rotation(){
+	return bone->getAppliedRotation();
+}
+void SpineBone::set_applied_rotation(float v){
+	bone->setAppliedRotation(v);
+}
+
+float SpineBone::get_a_x(){
+	return bone->getAX();
+}
+void SpineBone::set_a_x(float v){
+	bone->setAX(v);
+}
+
+float SpineBone::get_a_y(){
+	return bone->getAY();
+}
+void SpineBone::set_a_y(float v){
+	bone->setAY(v);
+}
+
+float SpineBone::get_a_scale_x(){
+	return bone->getAScaleX();
+}
+void SpineBone::set_a_scale_x(float v){
+	bone->setAScaleX(v);
+}
+
+float SpineBone::get_a_scale_y(){
+	return bone->getAScaleY();
+}
+void SpineBone::set_a_scale_y(float v){
+	bone->setAScaleY(v);
+}
+
+float SpineBone::get_a_shear_x(){
+	return bone->getAShearX();
+}
+void SpineBone::set_a_shear_x(float v){
+	bone->setAShearX(v);
+}
+
+float SpineBone::get_a_shear_y(){
+	return bone->getAShearY();
+}
+void SpineBone::set_a_shear_y(float v){
+	bone->setAShearY(v);
+}
+
+float SpineBone::get_a(){
+	return bone->getA();
+}
+void SpineBone::set_a(float v){
+	bone->setA(v);
+}
+
+float SpineBone::get_b(){
+	return bone->getB();
+}
+void SpineBone::set_b(float v){
+	bone->setB(v);
+}
+
+float SpineBone::get_c(){
+	return bone->getC();
+}
+void SpineBone::set_c(float v){
+	bone->setC(v);
+}
+
+float SpineBone::get_d(){
+	return bone->getD();
+}
+void SpineBone::set_d(float v){
+	bone->setD(v);
+}
+
+float SpineBone::get_world_x(){
+	return bone->getWorldX();
+}
+void SpineBone::set_world_x(float v){
+	bone->setWorldX(v);
+}
+
+float SpineBone::get_world_y(){
+	return bone->getWorldY();
+}
+void SpineBone::set_world_y(float v){
+	bone->setWorldY(v);
+}
+
+float SpineBone::get_world_rotation_x(){
+	return bone->getWorldRotationX();
+}
+float SpineBone::get_world_rotation_y(){
+	return bone->getWorldRotationY();
+}
+
+float SpineBone::get_world_scale_x(){
+	return bone->getWorldScaleX();
+}
+float SpineBone::get_world_scale_y(){
+	return bone->getWorldScaleY();
+}
+
+bool SpineBone::is_active(){
+	return bone->isActive();
+}
+void SpineBone::set_active(bool v){
+	bone->setActive(v);
+}
+
+// External feature functions
+void SpineBone::apply_world_transform_2d(Variant o){
+	if(o.get_type() == Variant::OBJECT){
+		auto node = (Node*) o;
+		if(node->is_class("Node2D")){
+			auto node2d = (Node2D*) node;
+			// In godot the y-axis is nag to spine
+			node2d->set_transform(Transform2D(
+					get_a(), get_c(),
+					get_b(), get_d(),
+					get_world_x(), -get_world_y())
+			);
+			// Fix the rotation
+			auto pos = node2d->get_position();
+			node2d->translate(-pos);
+			node2d->set_rotation(-node2d->get_rotation());
+			node2d->translate(pos);
+		}
+	}
+}
+
+Transform2D SpineBone::get_godot_transform() {
+    if (get_spine_object() == nullptr)
+        return Transform2D();
+    Transform2D trans;
+    trans.translate(get_x(), -get_y());
+    // It seems that spine uses degree for rotation
+    trans.rotate(Math::deg2rad(-get_rotation()));
+    trans.scale(Size2(get_scale_x(), get_scale_y()));
+    return trans;
+}
+
+void SpineBone::set_godot_transform(Transform2D trans) {
+    if (get_spine_object() == nullptr)
+        return;
+    Vector2 position = trans.get_origin();
+    position.y *= -1;
+    real_t rotation = trans.get_rotation();
+    rotation = Math::rad2deg(-rotation);
+    Vector2 scale = trans.get_scale();
+
+    set_x(position.x);
+    set_y(position.y);
+    set_rotation(rotation);
+    set_scale_x(scale.x);
+    set_scale_y(scale.y);
+}
+
+Transform2D SpineBone::get_godot_global_transform() {
+    if (get_spine_object() == nullptr)
+        return Transform2D();
+    if (the_sprite == nullptr)
+        return get_godot_transform();
+    Transform2D res = the_sprite->get_transform();
+    res.translate(get_world_x(), -get_world_y());
+    res.rotate(Math::deg2rad(-get_world_rotation_x()));
+    res.scale(Vector2(get_world_scale_x(), get_world_scale_y()));
+    auto p = the_sprite->get_parent() ? Object::cast_to<CanvasItem>(the_sprite->get_parent()) : nullptr;
+    if (p) {
+        return p->get_global_transform() * res;
+    }
+    return res;
+}
+
+void SpineBone::set_godot_global_transform(Transform2D transform) {
+    if (get_spine_object() == nullptr)
+        return;
+    if (the_sprite == nullptr)
+        set_godot_transform(transform);
+    transform = the_sprite->get_global_transform().affine_inverse() * transform;
+    Vector2 position = transform.get_origin();
+    real_t rotation = transform.get_rotation();
+    Vector2 scale = transform.get_scale();
+    position.y *= -1;
+    auto parent = get_parent();
+    if (parent.is_valid()) {
+        position = parent->world_to_local(position);
+        if (parent->get_world_scale_x() != 0)
+            scale.x /= parent->get_world_scale_x();
+        else
+            print_error("The parent scale.x is zero.");
+        if (parent->get_world_scale_y() != 0)
+            scale.y /= parent->get_world_scale_y();
+        else
+            print_error("The parent scale.y is zero.");
+    }
+    rotation = world_to_local_rotation(Math::rad2deg(-rotation));
+
+    set_x(position.x);
+    set_y(position.y);
+    set_rotation(rotation);
+    set_scale_x(scale.x);
+    set_scale_y(scale.y);
+}
+
+void SpineBone::set_spine_sprite(SpineSprite *s) {
+    the_sprite = s;
+}

+ 174 - 0
spine-godot/spine_godot/SpineBone.h

@@ -0,0 +1,174 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINEBONE_H
+#define GODOT_SPINEBONE_H
+
+#include "core/variant_parser.h"
+#include <scene/2d/node_2d.h>
+
+#include <scene/2d/node_2d.h>
+#include <spine/spine.h>
+
+#include "SpineBoneData.h"
+#include "SpineIkConstraint.h"
+#include "SpinePathConstraint.h"
+#include "SpineTransformConstraint.h"
+
+class SpineSkeleton;
+class SpineSprite;
+
+class SpineBone : public Reference {
+	GDCLASS(SpineBone, Reference);
+
+protected:
+	static void _bind_methods();
+
+private:
+	spine::Bone *bone;
+
+	SpineSprite *the_sprite;
+public:
+	SpineBone();
+	~SpineBone();
+
+	inline void set_spine_object(spine::Bone *b){
+		bone = b;
+	}
+	inline spine::Bone *get_spine_object(){
+		return bone;
+	}
+
+	void set_spine_sprite(SpineSprite *s);
+
+	void update_world_transform();
+
+	void set_to_setup_pose();
+
+	Vector2 world_to_local(Vector2 world_position);
+
+	Vector2 local_to_world(Vector2 local_position);
+
+	float world_to_local_rotation(float world_rotation);
+
+	float local_to_world_rotation(float local_rotation);
+
+	void rotate_world(float degrees);
+
+	float get_world_to_local_rotation_x();
+	float get_world_to_local_rotation_y();
+
+	Ref<SpineBoneData> get_data();
+
+	Ref<SpineSkeleton> get_skeleton();
+
+	Ref<SpineBone> get_parent();
+
+	Array get_children();
+
+	float get_x();
+	void set_x(float v);
+
+	float get_y();
+	void set_y(float v);
+
+	float get_rotation();
+	void set_rotation(float v);
+
+	float get_scale_x();
+	void set_scale_x(float v);
+
+	float get_scale_y();
+	void set_scale_y(float v);
+
+	float get_shear_x();
+	void set_shear_x(float v);
+
+	float get_shear_y();
+	void set_shear_y(float v);
+
+	float get_applied_rotation();
+	void set_applied_rotation(float v);
+
+	float get_a_x();
+	void set_a_x(float v);
+
+	float get_a_y();
+	void set_a_y(float v);
+
+	float get_a_scale_x();
+	void set_a_scale_x(float v);
+
+	float get_a_scale_y();
+	void set_a_scale_y(float v);
+
+	float get_a_shear_x();
+	void set_a_shear_x(float v);
+
+	float get_a_shear_y();
+	void set_a_shear_y(float v);
+
+	float get_a();
+	void set_a(float v);
+
+	float get_b();
+	void set_b(float v);
+
+	float get_c();
+	void set_c(float v);
+
+	float get_d();
+	void set_d(float v);
+
+	float get_world_x();
+	void set_world_x(float v);
+
+	float get_world_y();
+	void set_world_y(float v);
+
+	float get_world_rotation_x();
+	float get_world_rotation_y();
+
+	float get_world_scale_x();
+	float get_world_scale_y();
+
+	bool is_active();
+	void set_active(bool v);
+
+	// External feature functions
+	void apply_world_transform_2d(Variant o);
+
+	Transform2D get_godot_transform();
+	void set_godot_transform(Transform2D trans);
+
+	Transform2D get_godot_global_transform();
+	void set_godot_global_transform(Transform2D trans);
+};
+
+#endif //GODOT_SPINEBONE_H

+ 163 - 0
spine-godot/spine_godot/SpineBoneData.cpp

@@ -0,0 +1,163 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineBoneData.h"
+
+void SpineBoneData::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_index"), &SpineBoneData::get_index);
+	ClassDB::bind_method(D_METHOD("get_bone_name"), &SpineBoneData::get_bone_name);
+	ClassDB::bind_method(D_METHOD("get_parent"), &SpineBoneData::get_parent);
+
+	ClassDB::bind_method(D_METHOD("get_length"), &SpineBoneData::get_length);
+	ClassDB::bind_method(D_METHOD("set_length", "v"), &SpineBoneData::set_length);
+
+	ClassDB::bind_method(D_METHOD("get_x"), &SpineBoneData::get_x);
+	ClassDB::bind_method(D_METHOD("set_x", "v"), &SpineBoneData::set_x);
+
+	ClassDB::bind_method(D_METHOD("get_y"), &SpineBoneData::get_y);
+	ClassDB::bind_method(D_METHOD("set_y", "v"), &SpineBoneData::set_y);
+
+	ClassDB::bind_method(D_METHOD("get_rotation"), &SpineBoneData::get_rotation);
+	ClassDB::bind_method(D_METHOD("set_rotation", "v"), &SpineBoneData::set_rotation);
+
+	ClassDB::bind_method(D_METHOD("get_scale_x"), &SpineBoneData::get_scale_x);
+	ClassDB::bind_method(D_METHOD("set_scale_x", "v"), &SpineBoneData::set_scale_x);
+
+	ClassDB::bind_method(D_METHOD("get_scale_y"), &SpineBoneData::get_scale_y);
+	ClassDB::bind_method(D_METHOD("set_scale_y", "v"), &SpineBoneData::set_scale_y);
+
+	ClassDB::bind_method(D_METHOD("get_shear_x"), &SpineBoneData::get_shear_x);
+	ClassDB::bind_method(D_METHOD("set_shear_x", "v"), &SpineBoneData::set_shear_x);
+
+	ClassDB::bind_method(D_METHOD("get_shear_y"), &SpineBoneData::get_shear_y);
+	ClassDB::bind_method(D_METHOD("set_shear_y", "v"), &SpineBoneData::set_shear_y);
+
+	ClassDB::bind_method(D_METHOD("get_transform_mode"), &SpineBoneData::get_transform_mode);
+	ClassDB::bind_method(D_METHOD("set_transform_mode", "v"), &SpineBoneData::set_transform_mode);
+
+	ClassDB::bind_method(D_METHOD("is_skin_required"), &SpineBoneData::is_skin_required);
+	ClassDB::bind_method(D_METHOD("set_skin_required", "v"), &SpineBoneData::set_skin_required);
+
+	BIND_ENUM_CONSTANT(TRANSFORMMODE_NORMAL);
+	BIND_ENUM_CONSTANT(TRANSFORMMODE_ONLYTRANSLATION);
+	BIND_ENUM_CONSTANT(TRANSFORMMODE_NOROTATIONORREFLECTION);
+	BIND_ENUM_CONSTANT(TRANSFORMMODE_NOSCALE);
+	BIND_ENUM_CONSTANT(TRANSFORMMODE_NOSCALEORREFLECTION);
+}
+
+SpineBoneData::SpineBoneData():bone_data(NULL) {}
+SpineBoneData::~SpineBoneData() {}
+
+int SpineBoneData::get_index(){
+	return bone_data->getIndex();
+}
+
+String SpineBoneData::get_bone_name(){
+	return bone_data->getName().buffer();
+}
+
+Ref<SpineBoneData> SpineBoneData::get_parent(){
+	auto p = bone_data->getParent();
+	if(p == NULL) return NULL;
+	Ref<SpineBoneData> gd_bone_data(memnew(SpineBoneData));
+	gd_bone_data->set_spine_object(p);
+	return gd_bone_data;
+}
+
+float SpineBoneData::get_length(){
+	return bone_data->getLength();
+}
+void SpineBoneData::set_length(float v){
+	bone_data->setLength(v);
+}
+
+float SpineBoneData::get_x(){
+	return bone_data->getX();
+}
+void SpineBoneData::set_x(float v){
+	bone_data->setX(v);
+}
+
+float SpineBoneData::get_y(){
+	return bone_data->getY();
+}
+void SpineBoneData::set_y(float v){
+	bone_data->setY(v);
+}
+
+float SpineBoneData::get_rotation(){
+	return bone_data->getRotation();
+}
+void SpineBoneData::set_rotation(float v){
+	bone_data->setRotation(v);
+}
+
+float SpineBoneData::get_scale_x(){
+	return bone_data->getScaleX();
+}
+void SpineBoneData::set_scale_x(float v){
+	bone_data->setScaleX(v);
+}
+
+float SpineBoneData::get_scale_y(){
+	return bone_data->getScaleY();
+}
+void SpineBoneData::set_scale_y(float v){
+	bone_data->setScaleY(v);
+}
+
+float SpineBoneData::get_shear_x(){
+	return bone_data->getShearX();
+}
+void SpineBoneData::set_shear_x(float v){
+	bone_data->setShearX(v);
+}
+
+float SpineBoneData::get_shear_y(){
+	return bone_data->getShearY();
+}
+void SpineBoneData::set_shear_y(float v){
+	bone_data->setShearY(v);
+}
+
+SpineBoneData::TransformMode SpineBoneData::get_transform_mode(){
+	auto tm = (int)bone_data->getTransformMode();
+	return (TransformMode) tm;
+}
+void SpineBoneData::set_transform_mode(TransformMode v){
+	auto tm = (int) v;
+	bone_data->setTransformMode((spine::TransformMode)tm);
+}
+
+bool SpineBoneData::is_skin_required(){
+	return bone_data->isSkinRequired();
+}
+void SpineBoneData::set_skin_required(bool v){
+	bone_data->setSkinRequired(v);
+}

+ 104 - 0
spine-godot/spine_godot/SpineBoneData.h

@@ -0,0 +1,104 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINEBONEDATA_H
+#define GODOT_SPINEBONEDATA_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+class SpineBoneData : public Reference {
+	GDCLASS(SpineBoneData, Reference);
+
+protected:
+	static void _bind_methods();
+
+private:
+	spine::BoneData *bone_data;
+
+public:
+	SpineBoneData();
+	~SpineBoneData();
+
+	inline void set_spine_object(spine::BoneData *b){
+		bone_data = b;
+	}
+	inline spine::BoneData *get_spine_object(){
+		return bone_data;
+	}
+
+	enum TransformMode {
+		TRANSFORMMODE_NORMAL = 0,
+		TRANSFORMMODE_ONLYTRANSLATION,
+		TRANSFORMMODE_NOROTATIONORREFLECTION,
+		TRANSFORMMODE_NOSCALE,
+		TRANSFORMMODE_NOSCALEORREFLECTION
+	};
+
+	int get_index();
+
+	String get_bone_name();
+
+	Ref<SpineBoneData> get_parent();
+
+	float get_length();
+	void set_length(float v);
+
+	float get_x();
+	void set_x(float v);
+
+	float get_y();
+	void set_y(float v);
+
+	float get_rotation();
+	void set_rotation(float v);
+
+	float get_scale_x();
+	void set_scale_x(float v);
+
+	float get_scale_y();
+	void set_scale_y(float v);
+
+	float get_shear_x();
+	void set_shear_x(float v);
+
+	float get_shear_y();
+	void set_shear_y(float v);
+
+	TransformMode get_transform_mode();
+	void set_transform_mode(TransformMode v);
+
+	bool is_skin_required();
+	void set_skin_required(bool v);
+
+};
+
+VARIANT_ENUM_CAST(SpineBoneData::TransformMode);
+#endif //GODOT_SPINEBONEDATA_H

+ 204 - 0
spine-godot/spine_godot/SpineCollisionShapeProxy.cpp

@@ -0,0 +1,204 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineCollisionShapeProxy.h"
+
+#include "SpineSprite.h"
+
+void SpineCollisionShapeProxy::_bind_methods() {
+    ClassDB::bind_method(D_METHOD("get_spine_sprite_path"), &SpineCollisionShapeProxy::get_spine_sprite_path);
+    ClassDB::bind_method(D_METHOD("set_spine_sprite_path", "v"), &SpineCollisionShapeProxy::set_spine_sprite_path);
+
+    ClassDB::bind_method(D_METHOD("get_slot"), &SpineCollisionShapeProxy::get_slot);
+    ClassDB::bind_method(D_METHOD("set_slot", "v"), &SpineCollisionShapeProxy::set_slot);
+
+    ClassDB::bind_method(D_METHOD("get_sync_transform"), &SpineCollisionShapeProxy::get_sync_transform);
+    ClassDB::bind_method(D_METHOD("set_sync_transform", "v"), &SpineCollisionShapeProxy::set_sync_transform);
+
+    ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "spine_sprite_path"), "set_spine_sprite_path", "get_spine_sprite_path");
+    ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync_transform"), "set_sync_transform", "get_sync_transform");
+}
+
+SpineCollisionShapeProxy::SpineCollisionShapeProxy():sync_transform(true) {
+
+}
+
+SpineCollisionShapeProxy::~SpineCollisionShapeProxy() {
+
+}
+
+void SpineCollisionShapeProxy::_notification(int p_what) {
+    switch (p_what) {
+        case NOTIFICATION_READY: {
+            set_process_internal(true);
+        } break;
+        case NOTIFICATION_INTERNAL_PROCESS: {
+            if (!disabled) {
+                if (sync_transform) _sync_transform(get_spine_sprite());
+                _update_polygon_from_spine_sprite(get_spine_sprite());
+                if (is_visible()) update();
+            }
+        } break;
+    }
+}
+
+SpineSprite *SpineCollisionShapeProxy::get_spine_sprite() const {
+    return (SpineSprite*) get_node_or_null(spine_sprite_path);
+}
+
+NodePath SpineCollisionShapeProxy::get_spine_sprite_path() {
+    return spine_sprite_path;
+}
+
+void SpineCollisionShapeProxy::set_spine_sprite_path(NodePath v) {
+    spine_sprite_path = v;
+
+    _update_polygon_from_spine_sprite(get_spine_sprite());
+}
+
+String SpineCollisionShapeProxy::get_slot() const {
+    return slot;
+}
+
+void SpineCollisionShapeProxy::set_slot(const String &v) {
+    slot = v;
+    _update_polygon_from_spine_sprite(get_spine_sprite());
+}
+
+void SpineCollisionShapeProxy::_update_polygon_from_spine_sprite(SpineSprite *sprite) {
+    _clear_polygon();
+    if (sprite == nullptr || slot.empty()) {
+        return;
+    }
+
+    if (!sprite->get_skeleton().is_valid()) {
+        return;
+    }
+
+    auto sk = sprite->get_skeleton()->get_spine_object();
+
+    spine::Vector<float> vertices;
+
+    spine::Slot *s = sk->findSlot(spine::String(slot.utf8()));
+    if (!s) {
+        return;
+    }
+    spine::Attachment *attachment = s->getAttachment();
+    if(!attachment){
+        return;
+    }
+
+    if (attachment->getRTTI().isExactly(spine::BoundingBoxAttachment::rtti)) {
+        auto *box = (spine::BoundingBoxAttachment*) attachment;
+
+        vertices.setSize(box->getWorldVerticesLength(), 0);
+        box->computeWorldVertices(*s, vertices);
+    } else {
+        return;
+    }
+
+    polygon.resize(vertices.size()/2);
+    for (size_t j=0; j < vertices.size(); j+=2) {
+        polygon.set(j/2, Vector2(vertices[j], -vertices[j + 1]));
+    }
+
+    set_polygon(polygon);
+}
+
+void SpineCollisionShapeProxy::_clear_polygon() {
+    polygon.clear();
+    set_polygon(polygon);
+}
+
+void SpineCollisionShapeProxy::_sync_transform(SpineSprite *sprite) {
+    if (sprite == nullptr) return;
+    set_global_transform(sprite->get_global_transform());
+}
+
+bool SpineCollisionShapeProxy::get_sync_transform() {
+    return sync_transform;
+}
+
+void SpineCollisionShapeProxy::set_sync_transform(bool v) {
+    sync_transform = v;
+}
+
+void SpineCollisionShapeProxy::_get_property_list(List<PropertyInfo> *p_list) const {
+    PropertyInfo p;
+    Vector<String> res;
+
+    p.name = "slot";
+    p.type = Variant::STRING;
+    _get_slot_list(res);
+    if (res.empty()) res.push_back("No Slot");
+    p.hint_string = String(",").join(res);
+    p.hint = PROPERTY_HINT_ENUM;
+    p_list->push_back(p);
+}
+
+bool SpineCollisionShapeProxy::_get(const StringName &p_property, Variant &r_value) const {
+    if (p_property == "slot") {
+        r_value = get_slot();
+        return true;
+    }
+    return false;
+}
+
+bool SpineCollisionShapeProxy::_set(const StringName &p_property, const Variant &p_value) {
+    if (p_property == "slot") {
+        set_slot(p_value);
+        return true;
+    }
+    return false;
+}
+
+void SpineCollisionShapeProxy::_get_slot_list(Vector<String> &res) const {
+    if (get_spine_sprite() == nullptr) {
+        return;
+    }
+
+    auto sprite = get_spine_sprite();
+    if (!sprite->get_skeleton().is_valid()) {
+        return;
+    }
+
+    auto slots = sprite->get_skeleton()->get_slots();
+    res.resize(slots.size());
+    for (size_t i=0; i < res.size(); ++i) {
+        auto slot = (Ref<SpineSlot>)slots[i];
+        if (slot.is_valid())
+            res.set(i, slot->get_data()->get_slot_name());
+    }
+}
+
+
+
+
+
+

+ 78 - 0
spine-godot/spine_godot/SpineCollisionShapeProxy.h

@@ -0,0 +1,78 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINECOLLISIONSHAPEPROXY_H
+#define GODOT_SPINECOLLISIONSHAPEPROXY_H
+
+#include "scene/2d/collision_polygon_2d.h"
+
+class SpineSprite;
+class SpineAnimationState;
+class SpineSkeleton;
+
+class SpineCollisionShapeProxy : public CollisionPolygon2D{
+    GDCLASS(SpineCollisionShapeProxy, CollisionPolygon2D)
+protected:
+    static void _bind_methods();
+
+    NodePath spine_sprite_path;
+
+    String slot;
+
+    bool sync_transform;
+protected:
+    void _notification(int p_what);
+    void _get_property_list(List<PropertyInfo> *p_list) const;
+    bool _get(const StringName &p_property, Variant &r_value) const;
+    bool _set(const StringName &p_property, const Variant &p_value);
+
+
+    SpineSprite *get_spine_sprite() const;
+
+    void _update_polygon_from_spine_sprite(SpineSprite *sprite);
+    void _clear_polygon();
+    void _sync_transform(SpineSprite *sprite);
+
+    void _get_slot_list(Vector<String> &res) const;
+public:
+    SpineCollisionShapeProxy();
+    ~SpineCollisionShapeProxy();
+
+    NodePath get_spine_sprite_path();
+    void set_spine_sprite_path(NodePath v);
+
+    String get_slot() const;
+    void set_slot(const String &v);
+
+    bool get_sync_transform();
+    void set_sync_transform(bool v);
+};
+
+
+#endif //GODOT_SPINECOLLISIONSHAPEPROXY_H

+ 62 - 0
spine-godot/spine_godot/SpineConstant.cpp

@@ -0,0 +1,62 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineConstant.h"
+
+void SpineConstant::_bind_methods() {
+    BIND_ENUM_CONSTANT(MixBlend_Setup);
+    BIND_ENUM_CONSTANT(MixBlend_First);
+    BIND_ENUM_CONSTANT(MixBlend_Replace);
+    BIND_ENUM_CONSTANT(MixBlend_Add);
+
+    BIND_ENUM_CONSTANT(MixDirection_In);
+    BIND_ENUM_CONSTANT(MixDirection_Out);
+
+    BIND_ENUM_CONSTANT(Property_Rotate);
+    BIND_ENUM_CONSTANT(Property_X);
+    BIND_ENUM_CONSTANT(Property_Y);
+    BIND_ENUM_CONSTANT(Property_ScaleX);
+    BIND_ENUM_CONSTANT( Property_ScaleY);
+    BIND_ENUM_CONSTANT(Property_ShearX);
+    BIND_ENUM_CONSTANT(Property_ShearY);
+    BIND_ENUM_CONSTANT(Property_Rgb);
+    BIND_ENUM_CONSTANT(Property_Alpha);
+    BIND_ENUM_CONSTANT(Property_Rgb2);
+    BIND_ENUM_CONSTANT(Property_Attachment);
+    BIND_ENUM_CONSTANT(Property_Deform);
+    BIND_ENUM_CONSTANT(Property_Event);
+    BIND_ENUM_CONSTANT(Property_DrawOrder);
+    BIND_ENUM_CONSTANT(Property_IkConstraint);
+    BIND_ENUM_CONSTANT(Property_TransformConstraint);
+    BIND_ENUM_CONSTANT(Property_PathConstraintPosition);
+    BIND_ENUM_CONSTANT(Property_PathConstraintSpacing);
+    BIND_ENUM_CONSTANT(Property_PathConstraintMix);
+
+
+}

+ 80 - 0
spine-godot/spine_godot/SpineConstant.h

@@ -0,0 +1,80 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINECONSTANT_H
+#define GODOT_SPINECONSTANT_H
+
+#include "core/variant_parser.h"
+
+class SpineConstant : public Object{
+    GDCLASS(SpineConstant, Object);
+
+protected:
+    static void _bind_methods();
+public:
+    enum MixBlend {
+        MixBlend_Setup = 0,
+        MixBlend_First,
+        MixBlend_Replace,
+        MixBlend_Add
+    };
+
+    enum MixDirection {
+        MixDirection_In = 0,
+        MixDirection_Out
+    };
+
+    enum PropertyId {
+        Property_Rotate = 1 << 0,
+        Property_X = 1 << 1,
+        Property_Y = 1 << 2,
+        Property_ScaleX = 1 << 3,
+        Property_ScaleY = 1 << 4,
+        Property_ShearX = 1 << 5,
+        Property_ShearY = 1 << 6,
+        Property_Rgb = 1 << 7,
+        Property_Alpha = 1 << 8,
+        Property_Rgb2 = 1 << 9,
+        Property_Attachment = 1 << 10,
+        Property_Deform = 1 << 11,
+        Property_Event = 1 << 12,
+        Property_DrawOrder = 1 << 13,
+        Property_IkConstraint = 1 << 14,
+        Property_TransformConstraint = 1 << 15,
+        Property_PathConstraintPosition = 1 << 16,
+        Property_PathConstraintSpacing = 1 << 17,
+        Property_PathConstraintMix = 1 << 18
+    };
+};
+
+VARIANT_ENUM_CAST(SpineConstant::MixBlend);
+VARIANT_ENUM_CAST(SpineConstant::MixDirection);
+VARIANT_ENUM_CAST(SpineConstant::PropertyId);
+
+#endif //GODOT_SPINECONSTANT_H

+ 59 - 0
spine-godot/spine_godot/SpineConstraintData.cpp

@@ -0,0 +1,59 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineConstraintData.h"
+
+void SpineConstraintData::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_constraint_data_name"), &SpineConstraintData::get_constraint_data_name);
+	ClassDB::bind_method(D_METHOD("get_order"), &SpineConstraintData::get_order);
+	ClassDB::bind_method(D_METHOD("set_order", "v"), &SpineConstraintData::set_order);
+	ClassDB::bind_method(D_METHOD("is_skin_required"), &SpineConstraintData::is_skin_required);
+	ClassDB::bind_method(D_METHOD("set_skin_required", "v"), &SpineConstraintData::set_skin_required);
+}
+
+SpineConstraintData::SpineConstraintData():constraint_data(NULL) {}
+SpineConstraintData::~SpineConstraintData() {}
+
+String SpineConstraintData::get_constraint_data_name(){
+	return constraint_data->getName().buffer();
+}
+
+uint64_t SpineConstraintData::get_order(){
+	return constraint_data->getOrder();
+}
+void SpineConstraintData::set_order(uint64_t v){
+	constraint_data->setOrder(v);
+}
+
+bool SpineConstraintData::is_skin_required(){
+	return constraint_data->isSkinRequired();
+}
+void SpineConstraintData::set_skin_required(bool v){
+	constraint_data->setSkinRequired(v);
+}

+ 66 - 0
spine-godot/spine_godot/SpineConstraintData.h

@@ -0,0 +1,66 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINECONSTRAINTDATA_H
+#define GODOT_SPINECONSTRAINTDATA_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+class SpineConstraintData : public Reference {
+	GDCLASS(SpineConstraintData, Reference);
+
+protected:
+	static void _bind_methods();
+
+private:
+	spine::ConstraintData *constraint_data;
+
+public:
+	SpineConstraintData();
+	~SpineConstraintData();
+
+	inline void set_spine_object(spine::ConstraintData *c){
+		constraint_data = c;
+	}
+	virtual inline spine::ConstraintData *get_spine_object(){
+		return constraint_data;
+	}
+
+	String get_constraint_data_name();
+
+	uint64_t get_order();
+	void set_order(uint64_t v);
+
+	bool is_skin_required();
+	void set_skin_required(bool v);
+};
+
+#endif //GODOT_SPINECONSTRAINTDATA_H

+ 110 - 0
spine-godot/spine_godot/SpineEvent.cpp

@@ -0,0 +1,110 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineEvent.h"
+
+void SpineEvent::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_data"), &SpineEvent::get_data);
+	ClassDB::bind_method(D_METHOD("get_event_name"), &SpineEvent::get_event_name);
+	ClassDB::bind_method(D_METHOD("get_time"), &SpineEvent::get_time);
+	ClassDB::bind_method(D_METHOD("get_int_value"), &SpineEvent::get_int_value);
+	ClassDB::bind_method(D_METHOD("set_int_value", "v"), &SpineEvent::set_int_value);
+	ClassDB::bind_method(D_METHOD("get_float_value"), &SpineEvent::get_float_value);
+	ClassDB::bind_method(D_METHOD("set_float_value", "v"), &SpineEvent::set_float_value);
+	ClassDB::bind_method(D_METHOD("get_string_value"), &SpineEvent::get_string_value);
+	ClassDB::bind_method(D_METHOD("set_string_value", "v"), &SpineEvent::set_string_value);
+	ClassDB::bind_method(D_METHOD("get_volume"), &SpineEvent::get_volume);
+	ClassDB::bind_method(D_METHOD("set_volume", "v"), &SpineEvent::set_volume);
+	ClassDB::bind_method(D_METHOD("get_balance"), &SpineEvent::get_balance);
+	ClassDB::bind_method(D_METHOD("set_balance", "v"), &SpineEvent::set_balance);
+//
+//	BIND_ENUM_CONSTANT(EVENTTYPE_START);
+//	BIND_ENUM_CONSTANT(EVENTTYPE_INTERRUPT);
+//	BIND_ENUM_CONSTANT(EVENTTYPE_END);
+//	BIND_ENUM_CONSTANT(EVENTTYPE_COMPLETE);
+//	BIND_ENUM_CONSTANT(EVENTTYPE_DISPOSE);
+//	BIND_ENUM_CONSTANT(EVENTTYPE_EVENT);
+}
+
+SpineEvent::SpineEvent():event(NULL) {}
+SpineEvent::~SpineEvent(){}
+
+Ref<SpineEventData> SpineEvent::get_data(){
+	Ref<SpineEventData> event_data(memnew(SpineEventData));
+	event_data->set_spine_object(&(event->getData()));
+	return event_data;
+}
+
+String SpineEvent::get_event_name() {
+	return event->getData().getName().buffer();
+}
+
+float SpineEvent::get_time(){
+	return event->getTime();
+}
+
+int SpineEvent::get_int_value(){
+	return event->getIntValue();
+}
+
+void SpineEvent::set_int_value(int v){
+	event->setIntValue(v);
+}
+
+float SpineEvent::get_float_value(){
+	return event->getFloatValue();
+}
+
+void SpineEvent::set_float_value(float v){
+	event->setFloatValue(v);
+}
+
+String SpineEvent::get_string_value(){
+	return event->getStringValue().buffer();
+}
+
+void SpineEvent::set_string_value(const String &v){
+	event->setStringValue(spine::String(v.utf8()));
+}
+
+float SpineEvent::get_volume(){
+	return event->getVolume();
+}
+
+void SpineEvent::set_volume(float v){
+	event->setVolume(v);
+}
+
+float SpineEvent::get_balance(){
+	return event->getBalance();
+}
+
+void SpineEvent::set_balance(float v){
+	event->setBalance(v);
+}

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

@@ -0,0 +1,89 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINEEVENT_H
+#define GODOT_SPINEEVENT_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+#include "SpineEventData.h"
+
+class SpineEvent : public Reference{
+	GDCLASS(SpineEvent, Reference);
+
+protected:
+	static void _bind_methods();
+private:
+	spine::Event *event;
+public:
+	SpineEvent();
+	~SpineEvent();
+
+	inline void set_spine_object(spine::Event *e){
+		event = e;
+	}
+	inline spine::Event *get_spine_object() const{
+		return event;
+	}
+
+	enum EventType{
+		EVENTTYPE_START = spine::EventType_Start,
+		EVENTTYPE_INTERRUPT = spine::EventType_Interrupt,
+		EVENTTYPE_END = spine::EventType_End,
+		EVENTTYPE_COMPLETE = spine::EventType_Complete,
+		EVENTTYPE_DISPOSE = spine::EventType_Dispose,
+		EVENTTYPE_EVENT = spine::EventType_Event
+	};
+
+
+	Ref<SpineEventData> get_data();
+
+	String get_event_name();
+
+	float get_time();
+
+	int get_int_value();
+	void set_int_value(int inValue);
+
+	float get_float_value();
+	void set_float_value(float inValue);
+
+	String get_string_value();
+	void set_string_value(const String &inValue);
+
+	float get_volume();
+	void set_volume(float inValue);
+
+	float get_balance();
+	void set_balance(float inValue);
+};
+
+#endif //GODOT_SPINEEVENT_H

+ 37 - 0
spine-godot/spine_godot/SpineEventData.cpp

@@ -0,0 +1,37 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineEventData.h"
+
+void SpineEventData::_bind_methods() {
+
+}
+
+SpineEventData::SpineEventData():event_data(NULL) {}
+SpineEventData::~SpineEventData(){}

+ 56 - 0
spine-godot/spine_godot/SpineEventData.h

@@ -0,0 +1,56 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINEEVENTDATA_H
+#define GODOT_SPINEEVENTDATA_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+class SpineEventData : public Reference{
+	GDCLASS(SpineEventData, Reference);
+
+protected:
+	static void _bind_methods();
+private:
+	const spine::EventData *event_data;
+public:
+	SpineEventData();
+	~SpineEventData();
+
+	inline void set_spine_object(const spine::EventData *e){
+		event_data = e;
+	}
+	inline const spine::EventData *get_spine_object(){
+		return event_data;
+	}
+};
+
+#endif //GODOT_SPINEEVENTDATA_H

+ 146 - 0
spine-godot/spine_godot/SpineIkConstraint.cpp

@@ -0,0 +1,146 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineIkConstraint.h"
+#include "SpineBone.h"
+
+void SpineIkConstraint::_bind_methods() {
+	// ClassDB::bind_method(D_METHOD("apply"), &SpineIkConstraint::apply);
+	ClassDB::bind_method(D_METHOD("update"), &SpineIkConstraint::update);
+	ClassDB::bind_method(D_METHOD("get_order"), &SpineIkConstraint::get_order);
+	ClassDB::bind_method(D_METHOD("get_data"), &SpineIkConstraint::get_data);
+	ClassDB::bind_method(D_METHOD("get_bones"), &SpineIkConstraint::get_bones);
+	ClassDB::bind_method(D_METHOD("get_target"), &SpineIkConstraint::get_target);
+	ClassDB::bind_method(D_METHOD("set_target", "v"), &SpineIkConstraint::set_target);
+	ClassDB::bind_method(D_METHOD("get_bend_direction"), &SpineIkConstraint::get_bend_direction);
+	ClassDB::bind_method(D_METHOD("set_bend_direction", "v"), &SpineIkConstraint::set_bend_direction);
+	ClassDB::bind_method(D_METHOD("get_compress"), &SpineIkConstraint::get_compress);
+	ClassDB::bind_method(D_METHOD("set_compress", "v"), &SpineIkConstraint::set_compress);
+	ClassDB::bind_method(D_METHOD("get_stretch"), &SpineIkConstraint::get_stretch);
+	ClassDB::bind_method(D_METHOD("set_stretch", "v"), &SpineIkConstraint::set_stretch);
+	ClassDB::bind_method(D_METHOD("get_mix"), &SpineIkConstraint::get_mix);
+	ClassDB::bind_method(D_METHOD("set_mix", "v"), &SpineIkConstraint::set_mix);
+	ClassDB::bind_method(D_METHOD("get_softness"), &SpineIkConstraint::get_softness);
+	ClassDB::bind_method(D_METHOD("set_softness", "v"), &SpineIkConstraint::set_softness);
+	ClassDB::bind_method(D_METHOD("is_active"), &SpineIkConstraint::is_active);
+	ClassDB::bind_method(D_METHOD("set_active", "v"), &SpineIkConstraint::set_active);
+}
+
+SpineIkConstraint::SpineIkConstraint():ik_constraint(NULL) {}
+SpineIkConstraint::~SpineIkConstraint() {}
+
+// void SpineIkConstraint::apply(){
+// 	ik_constraint->apply();
+// }
+
+void SpineIkConstraint::update(){
+	ik_constraint->update();
+}
+
+int SpineIkConstraint::get_order(){
+	return ik_constraint->getOrder();
+}
+
+Ref<SpineIkConstraintData> SpineIkConstraint::get_data(){
+	auto &ikc = ik_constraint->getData();
+	Ref<SpineIkConstraintData> gd_ikc(memnew(SpineIkConstraintData));
+	gd_ikc->set_spine_object(&ikc);
+	return gd_ikc;
+}
+
+Array SpineIkConstraint::get_bones(){
+	auto &bs = ik_constraint->getBones();
+	Array gd_bs;
+	gd_bs.resize(bs.size());
+	for(size_t i=0; i<bs.size(); ++i){
+		auto b = bs[i];
+		if(b == NULL) gd_bs[i] = Ref<SpineBone>(NULL);
+		Ref<SpineBone> gd_b(memnew(SpineBone));
+		gd_b->set_spine_object(b);
+		gd_bs[i] = gd_b;
+	}
+	return gd_bs;
+}
+
+Ref<SpineBone> SpineIkConstraint::get_target(){
+	auto b = ik_constraint->getTarget();
+	if(b == NULL) return NULL;
+	Ref<SpineBone> gd_b(memnew(SpineBone));
+	gd_b->set_spine_object(b);
+	return gd_b;
+}
+void SpineIkConstraint::set_target(Ref<SpineBone> v){
+	if(v.is_valid()){
+		ik_constraint->setTarget(v->get_spine_object());
+	} else{
+		ik_constraint->setTarget(NULL);
+	}
+}
+
+int SpineIkConstraint::get_bend_direction(){
+	return ik_constraint->getBendDirection();
+}
+void SpineIkConstraint::set_bend_direction(int v){
+	ik_constraint->setBendDirection(v);
+}
+
+bool SpineIkConstraint::get_compress(){
+	return ik_constraint->getCompress();
+}
+void SpineIkConstraint::set_compress(bool v){
+	ik_constraint->setCompress(v);
+}
+
+bool SpineIkConstraint::get_stretch(){
+	return ik_constraint->getStretch();
+}
+void SpineIkConstraint::set_stretch(bool v){
+	ik_constraint->setStretch(v);
+}
+
+float SpineIkConstraint::get_mix(){
+	return ik_constraint->getMix();
+}
+void SpineIkConstraint::set_mix(float v){
+	ik_constraint->setMix(v);
+}
+
+float SpineIkConstraint::get_softness(){
+	return ik_constraint->getSoftness();
+}
+void SpineIkConstraint::set_softness(float v){
+	ik_constraint->setSoftness(v);
+}
+
+bool SpineIkConstraint::is_active(){
+	return ik_constraint->isActive();
+}
+void SpineIkConstraint::set_active(bool v){
+	ik_constraint->setActive(v);
+}

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

@@ -0,0 +1,95 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINEIKCONSTRAINT_H
+#define GODOT_SPINEIKCONSTRAINT_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+#include "SpineIkConstraintData.h"
+
+class SpineBone;
+
+class SpineIkConstraint : public Reference {
+	GDCLASS(SpineIkConstraint, Reference);
+
+protected:
+	static void _bind_methods();
+
+private:
+	spine::IkConstraint *ik_constraint;
+
+public:
+	SpineIkConstraint();
+	~SpineIkConstraint();
+
+	inline void set_spine_object(spine::IkConstraint * ic){
+		ik_constraint = ic;
+	}
+	inline spine::IkConstraint *get_spine_object(){
+		return ik_constraint;
+	}
+
+	// The spine-runtime-cpp 4.0 seems to not have a apply function implementation.
+	// void apply(); 
+
+	void update();
+
+	int get_order();
+
+	Ref<SpineIkConstraintData> get_data();
+
+	Array get_bones();
+
+	Ref<SpineBone> get_target();
+	void set_target(Ref<SpineBone> v);
+
+	int get_bend_direction();
+	void set_bend_direction(int v);
+
+	bool get_compress();
+	void set_compress(bool v);
+
+	bool get_stretch();
+	void set_stretch(bool v);
+
+	float get_mix();
+	void set_mix(float v);
+
+	float get_softness();
+	void set_softness(float v);
+
+	bool is_active();
+	void set_active(bool v);
+
+};
+
+#endif //GODOT_SPINEIKCONSTRAINT_H

+ 123 - 0
spine-godot/spine_godot/SpineIkConstraintData.cpp

@@ -0,0 +1,123 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineIkConstraintData.h"
+
+void SpineIkConstraintData::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_all_bone_data"), &SpineIkConstraintData::get_bones);
+	ClassDB::bind_method(D_METHOD("get_target"), &SpineIkConstraintData::get_target);
+	ClassDB::bind_method(D_METHOD("set_target", "v"), &SpineIkConstraintData::set_target);
+	ClassDB::bind_method(D_METHOD("get_bend_direction"), &SpineIkConstraintData::get_bend_direction);
+	ClassDB::bind_method(D_METHOD("set_bend_direction", "v"), &SpineIkConstraintData::set_bend_direction);
+	ClassDB::bind_method(D_METHOD("get_compress"), &SpineIkConstraintData::get_compress);
+	ClassDB::bind_method(D_METHOD("set_compress", "v"), &SpineIkConstraintData::set_compress);
+	ClassDB::bind_method(D_METHOD("get_stretch"), &SpineIkConstraintData::get_stretch);
+	ClassDB::bind_method(D_METHOD("set_stretch", "v"), &SpineIkConstraintData::set_stretch);
+	ClassDB::bind_method(D_METHOD("get_uniform"), &SpineIkConstraintData::get_uniform);
+	ClassDB::bind_method(D_METHOD("set_uniform", "v"), &SpineIkConstraintData::set_uniform);
+	ClassDB::bind_method(D_METHOD("get_mix"), &SpineIkConstraintData::get_mix);
+	ClassDB::bind_method(D_METHOD("set_mix", "v"), &SpineIkConstraintData::set_mix);
+	ClassDB::bind_method(D_METHOD("get_softness"), &SpineIkConstraintData::get_softness);
+	ClassDB::bind_method(D_METHOD("set_softness", "v"), &SpineIkConstraintData::set_softness);
+}
+
+SpineIkConstraintData::SpineIkConstraintData() {}
+SpineIkConstraintData::~SpineIkConstraintData() {}
+
+Array SpineIkConstraintData::get_bones(){
+	auto bs = get_spine_data()->getBones();
+	Array gd_bs;
+	gd_bs.resize(bs.size());
+	for(size_t i=0; i < bs.size(); ++i){
+		if(bs[i] == NULL) gd_bs[i] = Ref<SpineBoneData>(NULL);
+		else {
+			Ref<SpineBoneData> gd_b(memnew(SpineBoneData));
+			gd_b->set_spine_object(bs[i]);
+			gd_bs[i] = gd_b;
+		}
+	}
+	return gd_bs;
+}
+
+Ref<SpineBoneData> SpineIkConstraintData::get_target(){
+	auto b = get_spine_data()->getTarget();
+	if(b == NULL) return NULL;
+	Ref<SpineBoneData> gd_b(memnew(SpineBoneData));
+	gd_b->set_spine_object(b);
+	return gd_b;
+}
+void SpineIkConstraintData::set_target(Ref<SpineBoneData> v){
+	if(v.is_valid()){
+		get_spine_data()->setTarget(v->get_spine_object());
+	}else{
+		get_spine_data()->setTarget(NULL);
+	}
+}
+
+int SpineIkConstraintData::get_bend_direction(){
+	return get_spine_data()->getBendDirection();
+}
+void SpineIkConstraintData::set_bend_direction(int v){
+	get_spine_data()->setBendDirection(v);
+}
+
+bool SpineIkConstraintData::get_compress(){
+	return get_spine_data()->getCompress();
+}
+void SpineIkConstraintData::set_compress(bool v){
+	get_spine_data()->setCompress(v);
+}
+
+bool SpineIkConstraintData::get_stretch(){
+	return get_spine_data()->getStretch();
+}
+void SpineIkConstraintData::set_stretch(bool v){
+	get_spine_data()->setStretch(v);
+}
+
+bool SpineIkConstraintData::get_uniform(){
+	return get_spine_data()->getUniform();
+}
+void SpineIkConstraintData::set_uniform(bool v){
+	get_spine_data()->setUniform(v);
+}
+
+float SpineIkConstraintData::get_mix(){
+	return get_spine_data()->getMix();
+}
+void SpineIkConstraintData::set_mix(float v){
+	get_spine_data()->setMix(v);
+}
+
+float SpineIkConstraintData::get_softness(){
+	return get_spine_data()->getSoftness();
+}
+void SpineIkConstraintData::set_softness(float v){
+	get_spine_data()->setSoftness(v);
+}

+ 79 - 0
spine-godot/spine_godot/SpineIkConstraintData.h

@@ -0,0 +1,79 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINEIKCONSTRAINTDATA_H
+#define GODOT_SPINEIKCONSTRAINTDATA_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+#include "SpineConstraintData.h"
+#include "SpineBoneData.h"
+
+class SpineIkConstraintData : public SpineConstraintData {
+	GDCLASS(SpineIkConstraintData, SpineConstraintData);
+
+protected:
+	static void _bind_methods();
+
+public:
+	SpineIkConstraintData();
+	~SpineIkConstraintData();
+
+	virtual inline spine::IkConstraintData *get_spine_data(){
+		return (spine::IkConstraintData*) SpineConstraintData::get_spine_object();
+	}
+
+	Array get_bones();
+
+	Ref<SpineBoneData> get_target();
+	void set_target(Ref<SpineBoneData> v);
+
+	int get_bend_direction();
+	void set_bend_direction(int v);
+
+	bool get_compress();
+	void set_compress(bool v);
+
+	bool get_stretch();
+	void set_stretch(bool v);
+
+	bool get_uniform();
+	void set_uniform(bool v);
+
+	float get_mix();
+	void set_mix(float v);
+
+	float get_softness();
+	void set_softness(float v);
+
+};
+
+#endif //GODOT_SPINEIKCONSTRAINTDATA_H

+ 145 - 0
spine-godot/spine_godot/SpinePathConstraint.cpp

@@ -0,0 +1,145 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpinePathConstraint.h"
+
+void SpinePathConstraint::_bind_methods(){
+	// ClassDB::bind_method(D_METHOD("apply"), &SpinePathConstraint::apply);
+	ClassDB::bind_method(D_METHOD("update"), &SpinePathConstraint::update);
+	ClassDB::bind_method(D_METHOD("get_order"), &SpinePathConstraint::get_order);
+	ClassDB::bind_method(D_METHOD("get_position"), &SpinePathConstraint::get_position);
+	ClassDB::bind_method(D_METHOD("set_position", "v"), &SpinePathConstraint::set_position);
+	ClassDB::bind_method(D_METHOD("get_spacing"), &SpinePathConstraint::get_spacing);
+	ClassDB::bind_method(D_METHOD("set_spacing", "v"), &SpinePathConstraint::set_spacing);
+	ClassDB::bind_method(D_METHOD("get_mix_rotate"), &SpinePathConstraint::get_mix_rotate);
+	ClassDB::bind_method(D_METHOD("set_mix_rotate", "v"), &SpinePathConstraint::set_mix_rotate);
+	ClassDB::bind_method(D_METHOD("get_mix_x"), &SpinePathConstraint::get_mix_x);
+	ClassDB::bind_method(D_METHOD("set_mix_x", "v"), &SpinePathConstraint::set_mix_x);
+	ClassDB::bind_method(D_METHOD("get_mix_y"), &SpinePathConstraint::get_mix_y);
+	ClassDB::bind_method(D_METHOD("set_mix_y", "v"), &SpinePathConstraint::set_mix_y);
+	ClassDB::bind_method(D_METHOD("get_bones"), &SpinePathConstraint::get_bones);
+	ClassDB::bind_method(D_METHOD("get_target"), &SpinePathConstraint::get_target);
+	ClassDB::bind_method(D_METHOD("set_target", "v"), &SpinePathConstraint::set_target);
+	ClassDB::bind_method(D_METHOD("get_data"), &SpinePathConstraint::get_data);
+	ClassDB::bind_method(D_METHOD("is_active"), &SpinePathConstraint::is_active);
+	ClassDB::bind_method(D_METHOD("set_active", "v"), &SpinePathConstraint::set_active);
+}
+
+SpinePathConstraint::SpinePathConstraint():path_constraint(NULL) {}
+SpinePathConstraint::~SpinePathConstraint() {}
+
+// void SpinePathConstraint::apply(){
+// 	path_constraint->apply();
+// }
+
+void SpinePathConstraint::update(){
+	path_constraint->update();
+}
+
+int SpinePathConstraint::get_order(){
+	return path_constraint->getOrder();
+}
+
+float SpinePathConstraint::get_position(){
+	return path_constraint->getPosition();
+}
+void SpinePathConstraint::set_position(float v){
+	path_constraint->setPosition(v);
+}
+
+float SpinePathConstraint::get_spacing(){
+	return path_constraint->getSpacing();
+}
+void SpinePathConstraint::set_spacing(float v){
+	path_constraint->setSpacing(v);
+}
+
+float SpinePathConstraint::get_mix_rotate(){
+	return path_constraint->getMixRotate();
+}
+void SpinePathConstraint::set_mix_rotate(float v){
+	path_constraint->setMixRotate(v);
+}
+
+float SpinePathConstraint::get_mix_x(){
+	return path_constraint->getMixX();
+}
+void SpinePathConstraint::set_mix_x(float v){
+	path_constraint->setMixX(v);
+}
+
+float SpinePathConstraint::get_mix_y(){
+	return path_constraint->getMixY();
+}
+void SpinePathConstraint::set_mix_y(float v){
+	path_constraint->setMixY(v);
+}
+
+Array SpinePathConstraint::get_bones(){
+	auto &bs = path_constraint->getBones();
+	Array gd_bs;
+	gd_bs.resize(bs.size());
+	for(size_t i=0; i<bs.size(); ++i){
+		auto b = bs[i];
+		if(b == NULL) gd_bs[i] = Ref<SpineBone>(NULL);
+		Ref<SpineBone> gd_b(memnew(SpineBone));
+		gd_b->set_spine_object(b);
+		gd_bs[i] = gd_b;
+	}
+	return gd_bs;
+}
+
+Ref<SpineSlot> SpinePathConstraint::get_target(){
+	auto s = path_constraint->getTarget();
+	if(s == NULL) return NULL;
+	Ref<SpineSlot> gd_s(memnew(SpineSlot));
+	gd_s->set_spine_object(s);
+	return gd_s;
+}
+void SpinePathConstraint::set_target(Ref<SpineSlot> v){
+	if(v.is_valid()){
+		path_constraint->setTarget(v->get_spine_object());
+	}else{
+		path_constraint->setTarget(NULL);
+	}
+}
+
+Ref<SpinePathConstraintData> SpinePathConstraint::get_data(){
+	auto &sd = path_constraint->getData();
+	Ref<SpinePathConstraintData> gd_sd(memnew(SpinePathConstraintData));
+	gd_sd->set_spine_object(&sd);
+	return gd_sd;
+}
+
+bool SpinePathConstraint::is_active(){
+	return path_constraint->isActive();
+}
+void SpinePathConstraint::set_active(bool v){
+	path_constraint->setActive(v);
+}

+ 94 - 0
spine-godot/spine_godot/SpinePathConstraint.h

@@ -0,0 +1,94 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINEPATHCONSTRAINT_H
+#define GODOT_SPINEPATHCONSTRAINT_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+#include "SpineBone.h"
+#include "SpineSlot.h"
+#include "SpinePathConstraintData.h"
+
+class SpinePathConstraint : public Reference{
+	GDCLASS(SpinePathConstraint, Reference);
+
+protected:
+	static void _bind_methods();
+
+private:
+	spine::PathConstraint *path_constraint;
+
+public:
+	SpinePathConstraint();
+	~SpinePathConstraint();
+
+	inline void set_spine_object(spine::PathConstraint *pc){
+		path_constraint = pc;
+	}
+	inline spine::PathConstraint *get_spine_object(){
+		return path_constraint;
+	}
+
+	// The spine-runtime-cpp 4.0 seems to not have a apply function implementation.
+	// void apply(); 
+
+	void update();
+
+	int get_order();
+
+	float get_position();
+	void set_position(float v);
+
+	float get_spacing();
+	void set_spacing(float v);
+
+	float get_mix_rotate();
+	void set_mix_rotate(float v);
+
+	float get_mix_x();
+	void set_mix_x(float v);
+
+	float get_mix_y();
+	void set_mix_y(float v);
+
+	Array get_bones();
+
+	Ref<SpineSlot> get_target();
+	void set_target(Ref<SpineSlot> v);
+
+	Ref<SpinePathConstraintData> get_data();
+
+	bool is_active();
+	void set_active(bool v);
+};
+
+#endif //GODOT_SPINEPATHCONSTRAINT_H

+ 168 - 0
spine-godot/spine_godot/SpinePathConstraintData.cpp

@@ -0,0 +1,168 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpinePathConstraintData.h"
+
+
+void SpinePathConstraintData::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_all_bone_data"), &SpinePathConstraintData::get_bones);
+	ClassDB::bind_method(D_METHOD("get_target"), &SpinePathConstraintData::get_target);
+	ClassDB::bind_method(D_METHOD("set_target", "V"), &SpinePathConstraintData::set_target);
+	ClassDB::bind_method(D_METHOD("get_position_mode"), &SpinePathConstraintData::get_position_mode);
+	ClassDB::bind_method(D_METHOD("set_position_mode", "V"), &SpinePathConstraintData::set_position_mode);
+	ClassDB::bind_method(D_METHOD("get_spacing_mode"), &SpinePathConstraintData::get_spacing_mode);
+	ClassDB::bind_method(D_METHOD("set_spacing_mode", "V"), &SpinePathConstraintData::set_spacing_mode);
+	ClassDB::bind_method(D_METHOD("get_rotate_mode"), &SpinePathConstraintData::get_rotate_mode);
+	ClassDB::bind_method(D_METHOD("set_rotate_mode", "V"), &SpinePathConstraintData::set_rotate_mode);
+	ClassDB::bind_method(D_METHOD("get_offset_rotation"), &SpinePathConstraintData::get_offset_rotation);
+	ClassDB::bind_method(D_METHOD("set_offset_rotation", "V"), &SpinePathConstraintData::set_offset_rotation);
+	ClassDB::bind_method(D_METHOD("get_position"), &SpinePathConstraintData::get_position);
+	ClassDB::bind_method(D_METHOD("set_position", "V"), &SpinePathConstraintData::set_position);
+	ClassDB::bind_method(D_METHOD("get_spacing"), &SpinePathConstraintData::get_spacing);
+	ClassDB::bind_method(D_METHOD("set_spacing", "V"), &SpinePathConstraintData::set_spacing);
+	ClassDB::bind_method(D_METHOD("get_mix_rotate"), &SpinePathConstraintData::get_mix_rotate);
+	ClassDB::bind_method(D_METHOD("set_mix_rotate", "V"), &SpinePathConstraintData::set_mix_rotate);
+	ClassDB::bind_method(D_METHOD("get_mix_x"), &SpinePathConstraintData::get_mix_x);
+	ClassDB::bind_method(D_METHOD("set_mix_x", "V"), &SpinePathConstraintData::set_mix_x);
+	ClassDB::bind_method(D_METHOD("get_mix_y"), &SpinePathConstraintData::get_mix_y);
+	ClassDB::bind_method(D_METHOD("set_mix_y", "V"), &SpinePathConstraintData::set_mix_y);
+
+	BIND_ENUM_CONSTANT(POSITIONMODE_FIXED);
+	BIND_ENUM_CONSTANT(POSITIONMODE_PERCENT);
+
+	BIND_ENUM_CONSTANT(SPACINGMODE_LENGTH);
+	BIND_ENUM_CONSTANT(SPACINGMODE_FIXED);
+	BIND_ENUM_CONSTANT(SPACINGMODE_PERCENT);
+
+	BIND_ENUM_CONSTANT(ROTATEMODE_TANGENT);
+	BIND_ENUM_CONSTANT(ROTATEMODE_CHAIN);
+	BIND_ENUM_CONSTANT(ROTATEMODE_CHAINSCALE);
+}
+
+SpinePathConstraintData::SpinePathConstraintData() {}
+SpinePathConstraintData::~SpinePathConstraintData() {}
+
+Array SpinePathConstraintData::get_bones(){
+	auto bs = get_spine_data()->getBones();
+	Array gd_bs;
+	gd_bs.resize(bs.size());
+	for(size_t i=0; i < bs.size(); ++i){
+		if(bs[i] == NULL) gd_bs[i] = Ref<SpineBoneData>(NULL);
+		else {
+			Ref<SpineBoneData> gd_b(memnew(SpineBoneData));
+			gd_b->set_spine_object(bs[i]);
+			gd_bs[i] = gd_b;
+		}
+	}
+	return gd_bs;
+}
+
+Ref<SpineSlotData> SpinePathConstraintData::get_target(){
+	auto s = get_spine_data()->getTarget();
+	if(s == NULL) return NULL;
+	Ref<SpineSlotData> gd_s(memnew(SpineSlotData));
+	gd_s->set_spine_object(s);
+	return gd_s;
+}
+void SpinePathConstraintData::set_target(Ref<SpineSlotData> v){
+	if(v.is_valid()){
+		get_spine_data()->setTarget(v->get_spine_object());
+	}else{
+		get_spine_data()->setTarget(NULL);
+	}
+}
+
+SpinePathConstraintData::PositionMode SpinePathConstraintData::get_position_mode(){
+	auto m = (int) get_spine_data()->getPositionMode();
+	return (PositionMode) m;
+}
+void SpinePathConstraintData::set_position_mode(PositionMode v){
+	auto m = (int) v;
+	get_spine_data()->setPositionMode((spine::PositionMode)m);
+}
+
+SpinePathConstraintData::SpacingMode SpinePathConstraintData::get_spacing_mode(){
+	auto m = (int) get_spine_data()->getSpacingMode();
+	return (SpacingMode) m;
+}
+void SpinePathConstraintData::set_spacing_mode(SpacingMode v){
+	auto m = (int) v;
+	get_spine_data()->setSpacingMode((spine::SpacingMode)m);
+}
+
+SpinePathConstraintData::RotateMode SpinePathConstraintData::get_rotate_mode(){
+	auto m = (int) get_spine_data()->getRotateMode();
+	return (RotateMode) m;
+}
+void SpinePathConstraintData::set_rotate_mode(RotateMode v){
+	auto m = (int) v;
+	get_spine_data()->setRotateMode((spine::RotateMode)m);
+}
+
+float SpinePathConstraintData::get_offset_rotation(){
+	return get_spine_data()->getOffsetRotation();
+}
+void SpinePathConstraintData::set_offset_rotation(float v){
+	get_spine_data()->setOffsetRotation(v);
+}
+
+float SpinePathConstraintData::get_position(){
+	return get_spine_data()->getPosition();
+}
+void SpinePathConstraintData::set_position(float v){
+	get_spine_data()->setPosition(v);
+}
+
+float SpinePathConstraintData::get_spacing(){
+	return get_spine_data()->getSpacing();
+}
+void SpinePathConstraintData::set_spacing(float v){
+	get_spine_data()->setSpacing(v);
+}
+
+float SpinePathConstraintData::get_mix_rotate(){
+	return get_spine_data()->getMixRotate();
+}
+void SpinePathConstraintData::set_mix_rotate(float v){
+	get_spine_data()->setMixRotate(v);
+}
+
+float SpinePathConstraintData::get_mix_x(){
+	return get_spine_data()->getMixX();
+}
+void SpinePathConstraintData::set_mix_x(float v){
+	get_spine_data()->setMixX(v);
+}
+
+float SpinePathConstraintData::get_mix_y(){
+	return get_spine_data()->getMixY();
+}
+void SpinePathConstraintData::set_mix_y(float v){
+	get_spine_data()->setMixY(v);
+}

+ 108 - 0
spine-godot/spine_godot/SpinePathConstraintData.h

@@ -0,0 +1,108 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINEPATHCONSTRAINTDATA_H
+#define GODOT_SPINEPATHCONSTRAINTDATA_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+#include "SpineConstraintData.h"
+#include "SpineBoneData.h"
+#include "SpineSlotData.h"
+
+class SpinePathConstraintData : public SpineConstraintData {
+	GDCLASS(SpinePathConstraintData, SpineConstraintData);
+
+protected:
+	static void _bind_methods();
+
+public:
+	SpinePathConstraintData();
+	~SpinePathConstraintData();
+
+	virtual inline spine::PathConstraintData *get_spine_data(){
+		return (spine::PathConstraintData*) SpineConstraintData::get_spine_object();
+	}
+
+	enum PositionMode {
+		POSITIONMODE_FIXED = 0,
+		POSITIONMODE_PERCENT
+	};
+
+	enum SpacingMode {
+		SPACINGMODE_LENGTH = 0,
+		SPACINGMODE_FIXED,
+		SPACINGMODE_PERCENT
+	};
+
+	enum RotateMode {
+		ROTATEMODE_TANGENT = 0,
+		ROTATEMODE_CHAIN,
+		ROTATEMODE_CHAINSCALE
+	};
+
+	Array get_bones();
+
+	Ref<SpineSlotData> get_target();
+	void set_target(Ref<SpineSlotData> v);
+
+	PositionMode get_position_mode();
+	void set_position_mode(PositionMode v);
+
+	SpacingMode get_spacing_mode();
+	void set_spacing_mode(SpacingMode v);
+
+	RotateMode get_rotate_mode();
+	void set_rotate_mode(RotateMode v);
+
+	float get_offset_rotation();
+	void set_offset_rotation(float v);
+
+	float get_position();
+	void set_position(float v);
+
+	float get_spacing();
+	void set_spacing(float v);
+
+	float get_mix_rotate();
+	void set_mix_rotate(float v);
+
+	float get_mix_x();
+	void set_mix_x(float v);
+
+	float get_mix_y();
+	void set_mix_y(float v);
+};
+
+VARIANT_ENUM_CAST(SpinePathConstraintData::PositionMode);
+VARIANT_ENUM_CAST(SpinePathConstraintData::SpacingMode);
+VARIANT_ENUM_CAST(SpinePathConstraintData::RotateMode);
+#endif //GODOT_SPINEPATHCONSTRAINTDATA_H

+ 42 - 0
spine-godot/spine_godot/SpineRendererObject.h

@@ -0,0 +1,42 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINERENDEREROBJECT_H
+#define GODOT_SPINERENDEREROBJECT_H
+
+#include <scene/resources/texture.h>
+
+
+struct SpineRendererObject {
+    Ref<Texture> tex;
+    Ref<Texture> normal_tex;    
+};
+
+
+#endif 

+ 100 - 0
spine-godot/spine_godot/SpineRuntimeEditorPlugin.cpp

@@ -0,0 +1,100 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifdef TOOLS_ENABLED
+#include "SpineRuntimeEditorPlugin.h"
+
+#include "SpineAtlasResource.h"
+#include "SpineSkeletonJsonDataResource.h"
+#include "SpineSpriteAnimateDialog.h"
+
+#include "SpineSprite.h"
+
+Error SpineAtlasResourceImportPlugin::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata){
+    Ref<SpineAtlasResource> res(memnew(SpineAtlasResource));
+    res->set_normal_texture_prefix(p_options["normal_texture_prefix"]);
+    res->load_from_atlas_file(p_source_file);
+
+    String file_name = vformat("%s.%s", p_save_path, get_save_extension());
+    auto err = ResourceSaver::save(file_name, res);
+    return err;
+}
+
+void SpineAtlasResourceImportPlugin::get_import_options(List<ImportOption> *r_options, int p_preset) const {
+    if (p_preset == 0) {
+        ImportOption op;
+        op.option.name = "normal_texture_prefix";
+        op.option.type = Variant::STRING;
+        op.option.hint_string = "String";
+        op.default_value = String("n");
+        r_options->push_back(op);
+    }
+}
+
+Error SpineJsonResourceImportPlugin::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata){
+    Ref<SpineSkeletonJsonDataResource> res(memnew(SpineSkeletonJsonDataResource));
+    res->load_from_file(p_source_file);
+
+    String file_name = vformat("%s.%s", p_save_path, get_save_extension());
+    auto err = ResourceSaver::save(file_name, res);
+    return err;
+}
+
+//=======================| SpineRuntimeEditorPlugin |============================
+SpineRuntimeEditorPlugin::SpineRuntimeEditorPlugin(EditorNode *p_node) {
+    add_import_plugin(memnew(SpineAtlasResourceImportPlugin));
+    add_import_plugin(memnew(SpineJsonResourceImportPlugin));
+
+    auto animate_button = memnew(ToolButton);
+    animate_button->set_text("Animate");
+    add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, animate_button);
+
+    animate_dialog = memnew(SpineSpriteAnimateDialog);
+    get_editor_interface()->get_base_control()->add_child(animate_dialog);
+    animate_dialog->set_animate_button(animate_button);
+    animate_dialog->set_plugin(this);
+}
+
+SpineRuntimeEditorPlugin::~SpineRuntimeEditorPlugin() {
+
+}
+
+bool SpineRuntimeEditorPlugin::handles(Object *p_object) const {
+    return p_object->is_class("SpineSprite");
+}
+
+void SpineRuntimeEditorPlugin::make_visible(bool p_visible) {
+    if (get_editor_interface()->get_selection()->get_selected_node_list().size() != 1) {
+        p_visible = false;
+    }
+    animate_dialog->get_animate_button()->set_visible(p_visible);
+}
+
+
+#endif

+ 89 - 0
spine-godot/spine_godot/SpineRuntimeEditorPlugin.h

@@ -0,0 +1,89 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINERUNTIMEEDITORPLUGIN_H
+#define GODOT_SPINERUNTIMEEDITORPLUGIN_H
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_node.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> *p_extensions) const override {p_extensions->push_back("atlas");}
+    String get_preset_name(int p_idx) const override {if (p_idx == 0) return "Default"; else return "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> *r_options, int p_preset) const override;
+    bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const override {return true;}
+    Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) override;
+};
+
+class SpineJsonResourceImportPlugin : public EditorImportPlugin {
+GDCLASS(SpineJsonResourceImportPlugin, EditorImportPlugin);
+
+public:
+    String get_importer_name() const override {return "spine.json";}
+    String get_visible_name() const override {return "Spine Runtime Json";}
+    void get_recognized_extensions(List<String> *p_extensions) const override {p_extensions->push_back("json");}
+    String get_preset_name(int p_idx) const override {if (p_idx == 0) return "Default"; else return "Unknown";}
+    int get_preset_count() const override {return 1;}
+    String get_save_extension() const override {return "spjson";}
+    String get_resource_type() const override {return "SpineSkeletonJsonDataResource";}
+    void get_import_options(List<ImportOption> *r_options, int p_preset) const override {}
+    bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const override {return true;}
+    Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) override;
+};
+
+class SpineSpriteAnimateDialog;
+
+class SpineRuntimeEditorPlugin : public EditorPlugin {
+	GDCLASS(SpineRuntimeEditorPlugin, EditorPlugin);
+
+protected:
+    SpineSpriteAnimateDialog *animate_dialog;
+public:
+    SpineRuntimeEditorPlugin(EditorNode *p_node);
+    ~SpineRuntimeEditorPlugin();
+
+	String get_name() const override { return "SpineRuntimeEditorPlugin"; }
+	bool has_main_screen() const { return false; }
+
+	bool handles(Object *p_object) const override;
+	void make_visible(bool p_visible) override;
+
+	void _on_animate_button_pressed();
+};
+#endif
+
+#endif //GODOT_SPINERUNTIMEEDITORPLUGIN_H

+ 430 - 0
spine-godot/spine_godot/SpineSkeleton.cpp

@@ -0,0 +1,430 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineSkeleton.h"
+
+void SpineSkeleton::_bind_methods() {
+//void update_world_transform();
+//
+//	void set_to_setup_pose();
+//
+//	void set_bones_to_setup_pose();
+//
+//	void set_slots_to_setup_pose();
+	ClassDB::bind_method(D_METHOD("update_world_transform"), &SpineSkeleton::update_world_transform);
+	ClassDB::bind_method(D_METHOD("set_to_setup_pose"), &SpineSkeleton::set_to_setup_pose);
+	ClassDB::bind_method(D_METHOD("set_bones_to_setup_pose"), &SpineSkeleton::set_bones_to_setup_pose);
+	ClassDB::bind_method(D_METHOD("set_slots_to_setup_pose"), &SpineSkeleton::set_slots_to_setup_pose);
+//
+//	Ref<SpineBone> find_bone(const String &name);
+//	int find_bone_index(const String &name);
+//
+//	Ref<SpineSlot> find_slot(const String &name);
+//	int find_slot_index(const String &name);
+//
+//	void set_skin_by_name(const String &skin_name);
+//	void set_skin(Ref<SpineSkin> new_skin);
+//
+//	Ref<SpineAttachment> get_attachment_by_slot_name(const String &slot_name, const String &attachment_name);
+//	Ref<SpineAttachment> get_attachment_by_slot_index(int slot_index, const String &attachment_name);
+	ClassDB::bind_method(D_METHOD("find_bone", "bone_name"), &SpineSkeleton::find_bone);	
+	ClassDB::bind_method(D_METHOD("find_slot", "slot_name"), &SpineSkeleton::find_slot);	
+	ClassDB::bind_method(D_METHOD("set_skin_by_name", "skin_name"), &SpineSkeleton::set_skin_by_name);
+	ClassDB::bind_method(D_METHOD("set_skin", "new_skin"), &SpineSkeleton::set_skin);
+	ClassDB::bind_method(D_METHOD("get_attachment_by_slot_name", "slot_name", "attachment_name"), &SpineSkeleton::get_attachment_by_slot_name);
+	ClassDB::bind_method(D_METHOD("get_attachment_by_slot_index", "slot_index", "attachment_name"), &SpineSkeleton::get_attachment_by_slot_index);
+//
+//	void set_attachment(const String &slot_name, const String &attachment_name);
+//
+//	Ref<SpineIkConstraint> find_ik_constraint(const String &constraint_name);
+//	Ref<SpineTransformConstraint> find_transform_constraint(const String &constraint_name);
+//	Ref<SpinePathConstraint> find_path_constraint(const String &constraint_name);
+//
+//	void update(float delta);
+//
+//	Dictionary get_bounds();
+//
+//	Ref<SpineBone> get_root_bone();
+//
+//	Ref<SpineSkeletonDataResource> get_data();
+	ClassDB::bind_method(D_METHOD("set_attachment", "slot_name", "attachment_name"), &SpineSkeleton::set_attachment);
+	ClassDB::bind_method(D_METHOD("find_ik_constraint", "constraint_name"), &SpineSkeleton::find_ik_constraint);
+	ClassDB::bind_method(D_METHOD("find_transform_constraint", "constraint_name"), &SpineSkeleton::find_transform_constraint);
+	ClassDB::bind_method(D_METHOD("find_path_constraint", "constraint_name"), &SpineSkeleton::find_path_constraint);
+	ClassDB::bind_method(D_METHOD("update", "delta"), &SpineSkeleton::update);
+	ClassDB::bind_method(D_METHOD("get_bounds"), &SpineSkeleton::get_bounds);
+	ClassDB::bind_method(D_METHOD("get_root_bone"), &SpineSkeleton::get_root_bone);
+	ClassDB::bind_method(D_METHOD("get_data"), &SpineSkeleton::get_data);
+//
+//	Array get_bones();
+//	Array get_slots();
+//	Array get_draw_orders();
+//	Array get_ik_constraints();
+//	Array get_path_constraints();
+//	Array get_transform_constraints();
+//
+//	Ref<SpineSkin> get_skin();
+	ClassDB::bind_method(D_METHOD("get_bones"), &SpineSkeleton::get_bones);
+	ClassDB::bind_method(D_METHOD("get_slots"), &SpineSkeleton::get_slots);
+	ClassDB::bind_method(D_METHOD("get_draw_orders"), &SpineSkeleton::get_draw_orders);
+	ClassDB::bind_method(D_METHOD("get_ik_constraints"), &SpineSkeleton::get_ik_constraints);
+	ClassDB::bind_method(D_METHOD("get_path_constraints"), &SpineSkeleton::get_path_constraints);
+	ClassDB::bind_method(D_METHOD("get_transform_constraints"), &SpineSkeleton::get_transform_constraints);
+	ClassDB::bind_method(D_METHOD("get_skin"), &SpineSkeleton::get_skin);
+//
+//	Color get_color();
+//	void set_color(Color v);
+//
+//	float get_time();
+//	void set_time(float v);
+//
+//	void set_position(Vector2 pos);
+	ClassDB::bind_method(D_METHOD("get_color"), &SpineSkeleton::get_color);
+	ClassDB::bind_method(D_METHOD("set_color", "v"), &SpineSkeleton::set_color);
+	ClassDB::bind_method(D_METHOD("get_time"), &SpineSkeleton::get_time);
+	ClassDB::bind_method(D_METHOD("set_time", "v"), &SpineSkeleton::set_time);
+	ClassDB::bind_method(D_METHOD("set_position", "pos"), &SpineSkeleton::set_position);
+//
+//	float get_x();
+//	void set_x(float v);
+//
+//	float get_y();
+//	void set_y(float v);
+//
+//	float get_scale_x();
+//	void set_scale_x(float v);
+//
+//	float get_scale_y();
+//	void set_scale_y(float v);
+	ClassDB::bind_method(D_METHOD("get_x"), &SpineSkeleton::get_x);
+	ClassDB::bind_method(D_METHOD("set_x", "v"), &SpineSkeleton::set_x);
+	ClassDB::bind_method(D_METHOD("get_y"), &SpineSkeleton::get_y);
+	ClassDB::bind_method(D_METHOD("set_y", "v"), &SpineSkeleton::set_y);
+	ClassDB::bind_method(D_METHOD("get_scale_x"), &SpineSkeleton::get_scale_x);
+	ClassDB::bind_method(D_METHOD("set_scale_x", "v"), &SpineSkeleton::set_scale_x);
+	ClassDB::bind_method(D_METHOD("get_scale_y"), &SpineSkeleton::get_scale_y);
+	ClassDB::bind_method(D_METHOD("set_scale_y", "v"), &SpineSkeleton::set_scale_y);
+}
+
+SpineSkeleton::SpineSkeleton():skeleton(NULL),spine_object(false),the_sprite(nullptr) {
+
+}
+
+SpineSkeleton::~SpineSkeleton() {
+	if(skeleton && !spine_object)
+	{
+		delete skeleton;
+		skeleton = NULL;
+	}
+}
+
+void SpineSkeleton::load_skeleton(Ref<SpineSkeletonDataResource> sd) {
+	if(skeleton && !spine_object)
+	{
+		delete skeleton;
+		skeleton = NULL;
+	}
+	skeleton = new spine::Skeleton(sd->get_skeleton_data());
+	spine_object = false;
+}
+
+#define S_T(x) (spine::String(x.utf8()))
+void SpineSkeleton::update_world_transform(){
+	skeleton->updateWorldTransform();
+}
+
+void SpineSkeleton::set_to_setup_pose(){
+	skeleton->setToSetupPose();
+}
+
+void SpineSkeleton::set_bones_to_setup_pose(){
+	skeleton->setBonesToSetupPose();
+}
+
+void SpineSkeleton::set_slots_to_setup_pose(){
+	skeleton->setSlotsToSetupPose();
+}
+
+Ref<SpineBone> SpineSkeleton::find_bone(const String &name){
+	if(name.empty()) return NULL;
+	auto b = skeleton->findBone(S_T(name));
+	if(b == NULL) return NULL;
+	Ref<SpineBone> gd_b(memnew(SpineBone));
+	gd_b->set_spine_object(b);
+	gd_b->set_spine_sprite(the_sprite);
+	return gd_b;
+}
+
+Ref<SpineSlot> SpineSkeleton::find_slot(const String &name){
+	if(name.empty()) return NULL;
+	auto s = skeleton->findSlot(S_T(name));
+	if(s == NULL) return NULL;
+	Ref<SpineSlot> gd_s(memnew(SpineSlot));
+	gd_s->set_spine_object(s);
+	return gd_s;
+}
+
+void SpineSkeleton::set_skin_by_name(const String &skin_name){
+	skeleton->setSkin(S_T(skin_name));
+}
+void SpineSkeleton::set_skin(Ref<SpineSkin> new_skin){
+	if(new_skin.is_valid()){
+		skeleton->setSkin(new_skin->get_spine_object());
+	}else{
+		skeleton->setSkin(NULL);
+	}
+}
+
+Ref<SpineAttachment> SpineSkeleton::get_attachment_by_slot_name(const String &slot_name, const String &attachment_name){
+	auto a = skeleton->getAttachment(S_T(slot_name), S_T(attachment_name));
+	if(a == NULL) return NULL;
+	Ref<SpineAttachment> gd_a(memnew(SpineAttachment));
+	gd_a->set_spine_object(a);
+	return gd_a;
+}
+Ref<SpineAttachment> SpineSkeleton::get_attachment_by_slot_index(int slot_index, const String &attachment_name){
+	auto a = skeleton->getAttachment(slot_index, S_T(attachment_name));
+	if(a == NULL) return NULL;
+	Ref<SpineAttachment> gd_a(memnew(SpineAttachment));
+	gd_a->set_spine_object(a);
+	return gd_a;
+}
+
+void SpineSkeleton::set_attachment(const String &slot_name, const String &attachment_name){
+	ERR_FAIL_COND(slot_name.empty());
+	ERR_FAIL_COND(get_attachment_by_slot_name(slot_name, attachment_name) == NULL);
+	skeleton->setAttachment(S_T(slot_name), S_T(attachment_name));
+}
+
+Ref<SpineIkConstraint> SpineSkeleton::find_ik_constraint(const String &constraint_name){
+	if(constraint_name.empty()) return NULL;
+	auto c = skeleton->findIkConstraint(S_T(constraint_name));
+	if(c == NULL) return NULL;
+	Ref<SpineIkConstraint> gd_c(memnew(SpineIkConstraint));
+	gd_c->set_spine_object(c);
+	return gd_c;
+}
+Ref<SpineTransformConstraint> SpineSkeleton::find_transform_constraint(const String &constraint_name){
+	if(constraint_name.empty()) return NULL;
+	auto c = skeleton->findTransformConstraint(S_T(constraint_name));
+	if(c == NULL) return NULL;
+	Ref<SpineTransformConstraint> gd_c(memnew(SpineTransformConstraint));
+	gd_c->set_spine_object(c);
+	return gd_c;
+}
+Ref<SpinePathConstraint> SpineSkeleton::find_path_constraint(const String &constraint_name){
+	if(constraint_name.empty()) return NULL;
+	auto c = skeleton->findPathConstraint(S_T(constraint_name));
+	if(c == NULL) return NULL;
+	Ref<SpinePathConstraint> gd_c(memnew(SpinePathConstraint));
+	gd_c->set_spine_object(c);
+	return gd_c;
+}
+
+void SpineSkeleton::update(float delta){
+	skeleton->update(delta);
+}
+
+Dictionary SpineSkeleton::get_bounds(){
+	float x, y, w, h;
+	spine::Vector<float> vertex_buffer;
+	skeleton->getBounds(x, y, w, h, vertex_buffer);
+
+	Dictionary res;
+	res["x"] = x;
+	res["y"] = y;
+	res["w"] = w;
+	res["h"] = h;
+
+	Array gd_a;
+	gd_a.resize(vertex_buffer.size());
+	for(size_t i=0; i<gd_a.size(); ++i){
+		gd_a[i] = vertex_buffer[i];
+	}
+	res["vertex_buffer"] = gd_a;
+
+	return res;
+}
+
+Ref<SpineBone> SpineSkeleton::get_root_bone(){
+	auto b = skeleton->getRootBone();
+	if(b == NULL) return NULL;
+	Ref<SpineBone> gd_b(memnew(SpineBone));
+	gd_b->set_spine_object(b);
+	gd_b->set_spine_sprite(the_sprite);
+	return gd_b;
+}
+
+Ref<SpineSkeletonDataResource> SpineSkeleton::get_data() const {
+	auto sd = skeleton->getData();
+	if(sd == NULL) return NULL;
+	Ref<SpineSkeletonDataResource> gd_sd(memnew(SpineSkeletonDataResource));
+	gd_sd->set_spine_object(sd);
+	return gd_sd;
+}
+
+Array SpineSkeleton::get_bones(){
+	auto &as = skeleton->getBones();
+	Array gd_as;
+	gd_as.resize(as.size());
+	for(size_t i=0; i<gd_as.size(); ++i){
+		auto b = as[i];
+		if(b == NULL) gd_as[i] = Ref<SpineBone>(NULL);
+		Ref<SpineBone> gd_a(memnew(SpineBone));
+		gd_a->set_spine_object(b);
+		gd_a->set_spine_sprite(the_sprite);
+		gd_as[i] = gd_a;
+	}
+	return gd_as;
+}
+Array SpineSkeleton::get_slots(){
+	auto &as = skeleton->getSlots();
+	Array gd_as;
+	gd_as.resize(as.size());
+	for(size_t i=0; i<gd_as.size(); ++i){
+		auto b = as[i];
+		if(b == NULL) gd_as[i] = Ref<SpineSlot>(NULL);
+		Ref<SpineSlot> gd_a(memnew(SpineSlot));
+		gd_a->set_spine_object(b);
+		gd_as[i] = gd_a;
+	}
+	return gd_as;
+}
+Array SpineSkeleton::get_draw_orders(){
+	auto &as = skeleton->getDrawOrder();
+	Array gd_as;
+	gd_as.resize(as.size());
+	for(size_t i=0; i<gd_as.size(); ++i){
+		auto b = as[i];
+		if(b == NULL) gd_as[i] = Ref<SpineSlot>(NULL);
+		Ref<SpineSlot> gd_a(memnew(SpineSlot));
+		gd_a->set_spine_object(b);
+		gd_as[i] = gd_a;
+	}
+	return gd_as;
+}
+Array SpineSkeleton::get_ik_constraints(){
+	auto &as = skeleton->getIkConstraints();
+	Array gd_as;
+	gd_as.resize(as.size());
+	for(size_t i=0; i<gd_as.size(); ++i){
+		auto b = as[i];
+		if(b == NULL) gd_as[i] = Ref<SpineIkConstraint>(NULL);
+		Ref<SpineIkConstraint> gd_a(memnew(SpineIkConstraint));
+		gd_a->set_spine_object(b);
+		gd_as[i] = gd_a;
+	}
+	return gd_as;
+}
+Array SpineSkeleton::get_path_constraints(){
+	auto &as = skeleton->getPathConstraints();
+	Array gd_as;
+	gd_as.resize(as.size());
+	for(size_t i=0; i<gd_as.size(); ++i){
+		auto b = as[i];
+		if(b == NULL) gd_as[i] = Ref<SpinePathConstraint>(NULL);
+		Ref<SpinePathConstraint> gd_a(memnew(SpinePathConstraint));
+		gd_a->set_spine_object(b);
+		gd_as[i] = gd_a;
+	}
+	return gd_as;
+}
+Array SpineSkeleton::get_transform_constraints(){
+	auto &as = skeleton->getTransformConstraints();
+	Array gd_as;
+	gd_as.resize(as.size());
+	for(size_t i=0; i<gd_as.size(); ++i){
+		auto b = as[i];
+		if(b == NULL) gd_as[i] = Ref<SpineTransformConstraint>(NULL);
+		Ref<SpineTransformConstraint> gd_a(memnew(SpineTransformConstraint));
+		gd_a->set_spine_object(b);
+		gd_as[i] = gd_a;
+	}
+	return gd_as;
+}
+
+Ref<SpineSkin> SpineSkeleton::get_skin(){
+	auto s = skeleton->getSkin();
+	if(s == NULL) return NULL;
+	Ref<SpineSkin> gd_s(memnew(SpineSkin));
+	gd_s->set_spine_object(s);
+	return gd_s;
+}
+
+Color SpineSkeleton::get_color(){
+	auto &c = skeleton->getColor();
+	return Color(c.r, c.g, c.b, c.a);
+}
+void SpineSkeleton::set_color(Color v){
+	auto &c = skeleton->getColor();
+	c.set(v.r, v.g, v.b, v.a);
+}
+
+float SpineSkeleton::get_time(){
+	return skeleton->getTime();
+}
+void SpineSkeleton::set_time(float v){
+	skeleton->setTime(v);
+}
+
+void SpineSkeleton::set_position(Vector2 pos){
+	skeleton->setPosition(pos.x, pos.y);
+}
+
+float SpineSkeleton::get_x(){
+	return skeleton->getX();
+}
+void SpineSkeleton::set_x(float v){
+	skeleton->setX(v);
+}
+
+float SpineSkeleton::get_y(){
+	return skeleton->getY();
+}
+void SpineSkeleton::set_y(float v){
+	skeleton->setY(v);
+}
+
+float SpineSkeleton::get_scale_x(){
+	return skeleton->getScaleX();
+}
+void SpineSkeleton::set_scale_x(float v){
+	skeleton->setScaleX(v);
+}
+
+float SpineSkeleton::get_scale_y(){
+	return skeleton->getScaleY();
+}
+void SpineSkeleton::set_scale_y(float v){
+	skeleton->setScaleY(v);
+}
+
+void SpineSkeleton::set_spine_sprite(SpineSprite *s) {
+    the_sprite = s;
+}

+ 135 - 0
spine-godot/spine_godot/SpineSkeleton.h

@@ -0,0 +1,135 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINESKELETON_H
+#define GODOT_SPINESKELETON_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+#include "SpineSkeletonDataResource.h"
+#include "SpineBone.h"
+#include "SpineSlot.h"
+
+class SpineSprite;
+
+class SpineSkeleton : public Reference{
+	GDCLASS(SpineSkeleton, Reference);
+
+protected:
+	static void _bind_methods();
+
+private:
+	spine::Skeleton *skeleton;
+	bool spine_object;
+
+	SpineSprite *the_sprite;
+public:
+
+	SpineSkeleton();
+	~SpineSkeleton();
+
+	void load_skeleton(Ref<SpineSkeletonDataResource> sd);
+
+	inline void set_spine_object(spine::Skeleton *s){
+		skeleton = s;
+		spine_object = true;
+	}
+	inline spine::Skeleton *get_spine_object(){
+		return skeleton;
+	}
+
+	void set_spine_sprite(SpineSprite *s);
+
+
+	void update_world_transform();
+
+	void set_to_setup_pose();
+
+	void set_bones_to_setup_pose();
+
+	void set_slots_to_setup_pose();
+
+	Ref<SpineBone> find_bone(const String &name);
+
+	Ref<SpineSlot> find_slot(const String &name);	
+
+	void set_skin_by_name(const String &skin_name);
+	void set_skin(Ref<SpineSkin> new_skin);
+
+	Ref<SpineAttachment> get_attachment_by_slot_name(const String &slot_name, const String &attachment_name);
+	Ref<SpineAttachment> get_attachment_by_slot_index(int slot_index, const String &attachment_name);
+
+	void set_attachment(const String &slot_name, const String &attachment_name);
+
+	Ref<SpineIkConstraint> find_ik_constraint(const String &constraint_name);
+	Ref<SpineTransformConstraint> find_transform_constraint(const String &constraint_name);
+	Ref<SpinePathConstraint> find_path_constraint(const String &constraint_name);
+
+	void update(float delta);
+
+	Dictionary get_bounds();
+
+	Ref<SpineBone> get_root_bone();
+
+	Ref<SpineSkeletonDataResource> get_data() const;
+
+	Array get_bones();
+	Array get_slots();
+	Array get_draw_orders();
+	Array get_ik_constraints();
+	Array get_path_constraints();
+	Array get_transform_constraints();
+
+	Ref<SpineSkin> get_skin();
+
+	Color get_color();
+	void set_color(Color v);
+
+	float get_time();
+	void set_time(float v);
+
+	void set_position(Vector2 pos);
+
+	float get_x();
+	void set_x(float v);
+
+	float get_y();
+	void set_y(float v);
+
+	float get_scale_x();
+	void set_scale_x(float v);
+
+	float get_scale_y();
+	void set_scale_y(float v);
+
+};
+
+#endif //GODOT_SPINESKELETON_H

+ 454 - 0
spine-godot/spine_godot/SpineSkeletonDataResource.cpp

@@ -0,0 +1,454 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineSkeletonDataResource.h"
+
+void SpineSkeletonDataResource::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("set_atlas_res", "atlas_res"), &SpineSkeletonDataResource::set_atlas_res);
+	ClassDB::bind_method(D_METHOD("get_atlas_res"), &SpineSkeletonDataResource::get_atlas_res);
+	ClassDB::bind_method(D_METHOD("set_skeleton_json_res", "skeleton_json_res"), &SpineSkeletonDataResource::set_skeleton_json_res);
+	ClassDB::bind_method(D_METHOD("get_skeleton_json_res"), &SpineSkeletonDataResource::get_skeleton_json_res);
+	ClassDB::bind_method(D_METHOD("is_skeleton_data_loaded"), &SpineSkeletonDataResource::is_skeleton_data_loaded);	
+	ClassDB::bind_method(D_METHOD("find_animation", "animation_name"), &SpineSkeletonDataResource::find_animation);
+	ClassDB::bind_method(D_METHOD("get_sk_name"), &SpineSkeletonDataResource::get_sk_name);
+	ClassDB::bind_method(D_METHOD("set_sk_name", "sk_name"), &SpineSkeletonDataResource::set_sk_name);
+	ClassDB::bind_method(D_METHOD("get_x"), &SpineSkeletonDataResource::get_x);
+	ClassDB::bind_method(D_METHOD("set_x", "v"), &SpineSkeletonDataResource::set_x);
+	ClassDB::bind_method(D_METHOD("get_y"), &SpineSkeletonDataResource::get_y);
+	ClassDB::bind_method(D_METHOD("set_y", "v"), &SpineSkeletonDataResource::set_y);
+	ClassDB::bind_method(D_METHOD("get_width"), &SpineSkeletonDataResource::get_width);
+	ClassDB::bind_method(D_METHOD("get_height"), &SpineSkeletonDataResource::get_height);
+	ClassDB::bind_method(D_METHOD("get_version"), &SpineSkeletonDataResource::get_version);
+	ClassDB::bind_method(D_METHOD("get_fps"), &SpineSkeletonDataResource::get_fps);
+	ClassDB::bind_method(D_METHOD("set_fps", "v"), &SpineSkeletonDataResource::set_fps);
+
+	ClassDB::bind_method(D_METHOD("find_bone", "bone_name"), &SpineSkeletonDataResource::find_bone);
+	ClassDB::bind_method(D_METHOD("find_slot", "slot_name"), &SpineSkeletonDataResource::find_slot);
+	ClassDB::bind_method(D_METHOD("find_skin", "skin_name"), &SpineSkeletonDataResource::find_skin);
+	ClassDB::bind_method(D_METHOD("find_event", "event_data_name"), &SpineSkeletonDataResource::find_event);
+	ClassDB::bind_method(D_METHOD("find_ik_constraint_data", "constraint_name"), &SpineSkeletonDataResource::find_ik_constraint);
+	ClassDB::bind_method(D_METHOD("find_transform_constraint_data", "constraint_name"), &SpineSkeletonDataResource::find_transform_constraint);
+	ClassDB::bind_method(D_METHOD("find_path_constraint_data", "constraint_name"), &SpineSkeletonDataResource::find_path_constraint);
+	ClassDB::bind_method(D_METHOD("get_all_bone_data"), &SpineSkeletonDataResource::get_bones);
+	ClassDB::bind_method(D_METHOD("get_all_slot_data"), &SpineSkeletonDataResource::get_slots);
+	ClassDB::bind_method(D_METHOD("get_skins"), &SpineSkeletonDataResource::get_skins);
+	ClassDB::bind_method(D_METHOD("get_default_skin"), &SpineSkeletonDataResource::get_default_skin);
+	ClassDB::bind_method(D_METHOD("set_default_skin", "v"), &SpineSkeletonDataResource::set_default_skin);
+	ClassDB::bind_method(D_METHOD("get_all_event_data"), &SpineSkeletonDataResource::get_events);
+	ClassDB::bind_method(D_METHOD("get_animations"), &SpineSkeletonDataResource::get_animations);
+	ClassDB::bind_method(D_METHOD("get_all_ik_constraint_data"), &SpineSkeletonDataResource::get_ik_constraints);
+	ClassDB::bind_method(D_METHOD("get_all_transform_constraint_data"), &SpineSkeletonDataResource::get_transform_constraints);
+	ClassDB::bind_method(D_METHOD("get_all_path_constraint_data"), &SpineSkeletonDataResource::get_path_constraints);
+
+	ADD_SIGNAL(MethodInfo("skeleton_data_loaded"));
+	ADD_SIGNAL(MethodInfo("atlas_res_changed"));
+	ADD_SIGNAL(MethodInfo("skeleton_json_res_changed"));
+
+	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_json_res", PropertyHint::PROPERTY_HINT_RESOURCE_TYPE, "SpineSkeletonJsonDataResource"), "set_skeleton_json_res", "get_skeleton_json_res");
+}
+
+SpineSkeletonDataResource::SpineSkeletonDataResource():valid(false),spine_object(false),skeleton_data(NULL) {
+
+}
+SpineSkeletonDataResource::~SpineSkeletonDataResource() {
+	if(skeleton_data && !spine_object)
+	{
+		delete skeleton_data;
+		skeleton_data = NULL;
+	}
+}
+
+bool SpineSkeletonDataResource::is_skeleton_data_loaded() const{
+	return valid || spine_object;
+}
+
+void SpineSkeletonDataResource::load_res(spine::Atlas *a, const String &json_string) {
+	if (json_string.empty()) return;
+	auto path = get_path();
+	spine::SkeletonJson json(a);
+	auto temp_skeleton_data = json.readSkeletonData(json_string.utf8());
+	if(!temp_skeleton_data)
+	{
+		print_error(String("Error happened while loading skeleton json data: ") + path);
+		print_error(String("Error msg: ") + json.getError().buffer());
+		return;
+	}
+	if(skeleton_data)
+	{
+		delete skeleton_data;
+		skeleton_data = NULL;
+	}
+	skeleton_data = temp_skeleton_data;
+
+	valid = true;
+//	print_line("Skeleton json data loaded!");
+}
+
+void SpineSkeletonDataResource::update_skeleton_data() {
+	if(atlas_res.is_valid() && skeleton_json_res.is_valid())
+	{
+		load_res(atlas_res->get_spine_atlas(), skeleton_json_res->get_json_string());
+		if(valid)
+		{
+			emit_signal("skeleton_data_loaded");
+		}
+	}
+}
+
+void SpineSkeletonDataResource::set_atlas_res(const Ref<SpineAtlasResource> &a) {
+	atlas_res = a;
+	valid = false;
+//	print_line("atlas_res_changed emitted");
+	emit_signal("atlas_res_changed");
+	update_skeleton_data();
+}
+Ref<SpineAtlasResource> SpineSkeletonDataResource::get_atlas_res() {
+	if(spine_object){
+		print_line("Getting atlas res from a spine_object skeleton! The result may be NULL!");
+	}
+	return atlas_res;
+}
+
+void SpineSkeletonDataResource::set_skeleton_json_res(const Ref<SpineSkeletonJsonDataResource> &s) {
+	skeleton_json_res = s;
+	valid = false;
+//	print_line("skeleton_json_res_changed emitted");
+	emit_signal("skeleton_json_res_changed");
+	update_skeleton_data();
+}
+Ref<SpineSkeletonJsonDataResource> SpineSkeletonDataResource::get_skeleton_json_res() {
+	if(spine_object){
+		print_line("Getting atlas res from a spine_object skeleton! The result may be NULL!");
+	}
+	return skeleton_json_res;
+}
+
+#define CHECK_V if(!is_skeleton_data_loaded()){ERR_PRINT("skeleton data has not loaded yet!");return;}
+#define CHECK_X(x) if(!is_skeleton_data_loaded()){ERR_PRINT("skeleton data has not loaded yet!");return x;}
+#define S_T(x) (spine::String(x.utf8()))
+Ref<SpineAnimation> SpineSkeletonDataResource::find_animation(const String &animation_name) {
+	CHECK_X(NULL);
+	if(animation_name.empty()){
+		return NULL;
+	}
+	auto a = skeleton_data->findAnimation(S_T(animation_name));
+	if(!a) return NULL;
+	Ref<SpineAnimation> sa(memnew(SpineAnimation));
+	sa->set_spine_object(a);
+	return sa;
+}
+String SpineSkeletonDataResource::get_sk_name() {
+	CHECK_X("error");
+	return skeleton_data->getName().buffer();
+}
+void SpineSkeletonDataResource::set_sk_name(const String &v) {
+	CHECK_V;
+	skeleton_data->setName(S_T(v));
+}
+float SpineSkeletonDataResource::get_x() {
+	CHECK_X(0);
+	return skeleton_data->getX();
+}
+void SpineSkeletonDataResource::set_x(float v) {
+	CHECK_V;
+	skeleton_data->setX(v);
+}
+float SpineSkeletonDataResource::get_y() {
+	CHECK_X(0);
+	return skeleton_data->getY();
+}
+void SpineSkeletonDataResource::set_y(float v) {
+	CHECK_V;
+	skeleton_data->setY(v);
+}
+float SpineSkeletonDataResource::get_width() {
+	CHECK_X(0);
+	return skeleton_data->getWidth();
+}
+float SpineSkeletonDataResource::get_height() {
+	CHECK_X(0);
+	return skeleton_data->getHeight();
+}
+String SpineSkeletonDataResource::get_version() {
+	CHECK_X("error");
+	return skeleton_data->getVersion().buffer();
+}
+float SpineSkeletonDataResource::get_fps() {
+	CHECK_X(0);
+	return skeleton_data->getFps();
+}
+void SpineSkeletonDataResource::set_fps(float v) {
+	CHECK_V;
+	skeleton_data->setFps(v);
+}
+
+Ref<SpineBoneData> SpineSkeletonDataResource::find_bone(const String &bone_name){
+	if(bone_name.empty()) return NULL;
+	auto b = skeleton_data->findBone(S_T(bone_name));
+	if(b == NULL) return NULL;
+	Ref<SpineBoneData> gd_b(memnew(SpineBoneData));
+	gd_b->set_spine_object(b);
+	return gd_b;
+}
+
+Ref<SpineSlotData> SpineSkeletonDataResource::find_slot(const String &slot_name){
+	if(slot_name.empty()) return NULL;
+	auto b = skeleton_data->findSlot(S_T(slot_name));
+	if(b == NULL) return NULL;
+	Ref<SpineSlotData> gd_b(memnew(SpineSlotData));
+	gd_b->set_spine_object(b);
+	return gd_b;
+}
+
+Ref<SpineSkin> SpineSkeletonDataResource::find_skin(const String &skin_name){
+	if(skin_name.empty()) return NULL;
+	auto b = skeleton_data->findSkin(S_T(skin_name));
+	if(b == NULL) return NULL;
+	Ref<SpineSkin> gd_b(memnew(SpineSkin));
+	gd_b->set_spine_object(b);
+	return gd_b;
+}
+
+Ref<SpineEventData> SpineSkeletonDataResource::find_event(const String &event_data_name){
+	if(event_data_name.empty()) return NULL;
+	auto b = skeleton_data->findEvent(S_T(event_data_name));
+	if(b == NULL) return NULL;
+	Ref<SpineEventData> gd_b(memnew(SpineEventData));
+	gd_b->set_spine_object(b);
+	return gd_b;
+}
+
+Ref<SpineIkConstraintData> SpineSkeletonDataResource::find_ik_constraint(const String &constraint_name){
+	if(constraint_name.empty()) return NULL;
+	auto b = skeleton_data->findIkConstraint(S_T(constraint_name));
+	if(b == NULL) return NULL;
+	Ref<SpineIkConstraintData> gd_b(memnew(SpineIkConstraintData));
+	gd_b->set_spine_object(b);
+	return gd_b;
+}
+Ref<SpineTransformConstraintData> SpineSkeletonDataResource::find_transform_constraint(const String &constraint_name){
+	if(constraint_name.empty()) return NULL;
+	auto b = skeleton_data->findTransformConstraint(S_T(constraint_name));
+	if(b == NULL) return NULL;
+	Ref<SpineTransformConstraintData> gd_b(memnew(SpineTransformConstraintData));
+	gd_b->set_spine_object(b);
+	return gd_b;
+}
+Ref<SpinePathConstraintData> SpineSkeletonDataResource::find_path_constraint(const String &constraint_name){
+	if(constraint_name.empty()) return NULL;
+	auto b = skeleton_data->findPathConstraint(S_T(constraint_name));
+	if(b == NULL) return NULL;
+	Ref<SpinePathConstraintData> gd_b(memnew(SpinePathConstraintData));
+	gd_b->set_spine_object(b);
+	return gd_b;
+}
+
+Array SpineSkeletonDataResource::get_bones(){
+	auto bs = skeleton_data->getBones();
+	Array gd_bs;
+	gd_bs.resize(bs.size());
+	for(size_t i=0; i < bs.size(); ++i){
+		if(bs[i] == NULL) gd_bs[i] = Ref<SpineBoneData>(NULL);
+		else {
+			Ref<SpineBoneData> gd_b(memnew(SpineBoneData));
+			gd_b->set_spine_object(bs[i]);
+			gd_bs[i] = gd_b;
+		}
+	}
+	return gd_bs;
+}
+Array SpineSkeletonDataResource::get_slots(){
+	auto bs = skeleton_data->getSlots();
+	Array gd_bs;
+	gd_bs.resize(bs.size());
+	for(size_t i=0; i < bs.size(); ++i){
+		if(bs[i] == NULL) gd_bs[i] = Ref<SpineSlotData>(NULL);
+		else {
+			Ref<SpineSlotData> gd_b(memnew(SpineSlotData));
+			gd_b->set_spine_object(bs[i]);
+			gd_bs[i] = gd_b;
+		}
+	}
+	return gd_bs;
+}
+Array SpineSkeletonDataResource::get_skins() const{
+	auto bs = skeleton_data->getSkins();
+	Array gd_bs;
+	gd_bs.resize(bs.size());
+	for(size_t i=0; i < bs.size(); ++i){
+		if(bs[i] == NULL) gd_bs[i] = Ref<SpineSkin>(NULL);
+		else {
+			Ref<SpineSkin> gd_b(memnew(SpineSkin));
+			gd_b->set_spine_object(bs[i]);
+			gd_bs[i] = gd_b;
+		}
+	}
+	return gd_bs;
+}
+
+Ref<SpineSkin> SpineSkeletonDataResource::get_default_skin(){
+	auto b = skeleton_data->getDefaultSkin();
+	if(b == NULL) return NULL;
+	Ref<SpineSkin> gd_b(memnew(SpineSkin));
+	gd_b->set_spine_object(b);
+	return gd_b;
+}
+void SpineSkeletonDataResource::set_default_skin(Ref<SpineSkin> v){
+	if(v.is_valid()){
+		skeleton_data->setDefaultSkin(v->get_spine_object());
+	} else
+		skeleton_data->setDefaultSkin(NULL);
+}
+
+Array SpineSkeletonDataResource::get_events(){
+	auto bs = skeleton_data->getEvents();
+	Array gd_bs;
+	gd_bs.resize(bs.size());
+	for(size_t i=0; i < bs.size(); ++i){
+		if(bs[i] == NULL) gd_bs[i] = Ref<SpineEventData>(NULL);
+		else {
+			Ref<SpineEventData> gd_b(memnew(SpineEventData));
+			gd_b->set_spine_object(bs[i]);
+			gd_bs[i] = gd_b;
+		}
+	}
+	return gd_bs;
+}
+Array SpineSkeletonDataResource::get_animations(){
+	auto bs = skeleton_data->getAnimations();
+	Array gd_bs;
+	gd_bs.resize(bs.size());
+	for(size_t i=0; i < bs.size(); ++i){
+		if(bs[i] == NULL) gd_bs[i] = Ref<SpineAnimation>(NULL);
+		else {
+			Ref<SpineAnimation> gd_b(memnew(SpineAnimation));
+			gd_b->set_spine_object(bs[i]);
+			gd_bs[i] = gd_b;
+		}
+	}
+	return gd_bs;
+}
+Array SpineSkeletonDataResource::get_ik_constraints(){
+	auto bs = skeleton_data->getIkConstraints();
+	Array gd_bs;
+	gd_bs.resize(bs.size());
+	for(size_t i=0; i < bs.size(); ++i){
+		if(bs[i] == NULL) gd_bs[i] = Ref<SpineIkConstraintData>(NULL);
+		else {
+			Ref<SpineIkConstraintData> gd_b(memnew(SpineIkConstraintData));
+			gd_b->set_spine_object(bs[i]);
+			gd_bs[i] = gd_b;
+		}
+	}
+	return gd_bs;
+}
+Array SpineSkeletonDataResource::get_transform_constraints(){
+	auto bs = skeleton_data->getTransformConstraints();
+	Array gd_bs;
+	gd_bs.resize(bs.size());
+	for(size_t i=0; i < bs.size(); ++i){
+		if(bs[i] == NULL) gd_bs[i] = Ref<SpineTransformConstraintData>(NULL);
+		else {
+			Ref<SpineTransformConstraintData> gd_b(memnew(SpineTransformConstraintData));
+			gd_b->set_spine_object(bs[i]);
+			gd_bs[i] = gd_b;
+		}
+	}
+	return gd_bs;
+}
+Array SpineSkeletonDataResource::get_path_constraints(){
+	auto bs = skeleton_data->getPathConstraints();
+	Array gd_bs;
+	gd_bs.resize(bs.size());
+	for(size_t i=0; i < bs.size(); ++i){
+		if(bs[i] == NULL) gd_bs[i] = Ref<SpinePathConstraintData>(NULL);
+		else {
+			Ref<SpinePathConstraintData> gd_b(memnew(SpinePathConstraintData));
+			gd_b->set_spine_object(bs[i]);
+			gd_bs[i] = gd_b;
+		}
+	}
+	return gd_bs;
+}
+#undef S_T
+#undef CHECK_V
+#undef CHECK_X
+
+//External feature functions
+void SpineSkeletonDataResource::get_animation_names(Vector<String> &res) const{
+    res.clear();
+	if(!is_skeleton_data_loaded()){
+		return;
+	}
+	auto as = skeleton_data->getAnimations();
+	for(size_t i=0; i<as.size(); ++i){
+		auto a = as[i];
+		if(a){
+		    res.push_back(a->getName().buffer());
+		}else{
+		    res.push_back("");
+		}
+	}
+}
+void SpineSkeletonDataResource::get_skin_names(Vector<String> &res) const{
+    res.clear();
+	if(!is_skeleton_data_loaded()){
+		return;
+	}
+	auto as = get_skins();
+	res.resize(as.size());
+	for(size_t i=0; i<as.size(); ++i){
+		auto a = Ref<SpineSkin>(as[i]);
+		if(a.is_valid()){
+			res.push_back(a->get_skin_name());
+		}else{
+		    res.push_back("");
+		}
+	}
+}
+
+void SpineSkeletonDataResource::_get_property_list(List<PropertyInfo> *p_list) const{
+    PropertyInfo p;
+    Vector<String> res;
+
+    p.name = "animations";
+    p.type = Variant::STRING;
+    get_animation_names(res);
+    p.hint_string = String(",").join(res);
+    p.hint = PROPERTY_HINT_ENUM;
+    p_list->push_back(p);
+
+    p.name = "skins";
+    p.type = Variant::STRING;
+    get_skin_names(res);
+    p.hint_string = String(",").join(res);
+    p.hint = PROPERTY_HINT_ENUM;
+    p_list->push_back(p);
+}

+ 140 - 0
spine-godot/spine_godot/SpineSkeletonDataResource.h

@@ -0,0 +1,140 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINESKELETONDATARESOURCE_H
+#define GODOT_SPINESKELETONDATARESOURCE_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+#include "SpineAtlasResource.h"
+#include "SpineSkeletonJsonDataResource.h"
+#include "SpineAnimation.h"
+#include "SpineBoneData.h"
+#include "SpineSlotData.h"
+#include "SpineSkin.h"
+#include "SpineIkConstraintData.h"
+#include "SpineTransformConstraintData.h"
+#include "SpinePathConstraintData.h"
+#include "SpineEventData.h"
+
+class SpineSkeletonDataResource : public Resource{
+	GDCLASS(SpineSkeletonDataResource, Resource);
+
+protected:
+	static void _bind_methods();
+
+private:
+	Ref<SpineAtlasResource> atlas_res;
+	Ref<SpineSkeletonJsonDataResource> skeleton_json_res;
+	bool valid;
+	bool spine_object;
+
+	spine::SkeletonData *skeleton_data;
+
+	void update_skeleton_data();
+public:
+
+	inline void set_spine_object(spine::SkeletonData *s){
+		skeleton_data = s;
+		if(s)
+			spine_object = true;
+	}
+	inline spine::SkeletonData *get_spine_object(){
+		return skeleton_data;
+	}
+
+	void load_res(spine::Atlas *a, const String &json_path);
+
+	SpineSkeletonDataResource();
+	virtual ~SpineSkeletonDataResource();
+
+    void _get_property_list(List<PropertyInfo> *p_list) const;
+
+	void set_atlas_res(const Ref<SpineAtlasResource> &a);
+	Ref<SpineAtlasResource> get_atlas_res();
+
+	void set_skeleton_json_res(const Ref<SpineSkeletonJsonDataResource> &s);
+	Ref<SpineSkeletonJsonDataResource> get_skeleton_json_res();
+
+	inline spine::SkeletonData *get_skeleton_data(){return skeleton_data;}
+
+	bool is_skeleton_data_loaded() const;
+
+	void get_animation_names(Vector<String> &l) const;
+    void get_skin_names(Vector<String> &l) const;
+
+	// spine api
+	Ref<SpineBoneData> find_bone(const String &bone_name);	
+
+	Ref<SpineSlotData> find_slot(const String &slot_name);	
+
+	Ref<SpineSkin> find_skin(const String &skin_name);
+
+	Ref<SpineEventData> find_event(const String &event_data_name);
+
+	Ref<SpineAnimation> find_animation(const String &animation_name);
+
+	Ref<SpineIkConstraintData> find_ik_constraint(const String &constraint_name);
+	Ref<SpineTransformConstraintData> find_transform_constraint(const String &constraint_name);
+	Ref<SpinePathConstraintData> find_path_constraint(const String &constraint_name);	
+
+	Array get_bones();
+	Array get_slots();
+	Array get_skins() const;
+
+	Ref<SpineSkin> get_default_skin();
+	void set_default_skin(Ref<SpineSkin> v);
+
+	Array get_events();
+	Array get_animations();
+	Array get_ik_constraints();
+	Array get_transform_constraints();
+	Array get_path_constraints();
+
+	String get_sk_name();
+	void set_sk_name(const String &v);
+
+	float get_x();
+	void set_x(float v);
+
+	float get_y();
+	void set_y(float v);
+
+	float get_width();
+	float get_height();
+
+	String get_version();
+
+	float get_fps();
+	void set_fps(float v);
+};
+
+#endif //GODOT_SPINESKELETONDATARESOURCE_H

+ 55 - 0
spine-godot/spine_godot/SpineSkeletonJsonDataResource.cpp

@@ -0,0 +1,55 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineSkeletonJsonDataResource.h"
+
+
+void SpineSkeletonJsonDataResource::_bind_methods() {
+}
+
+Error SpineSkeletonJsonDataResource::load_from_file(const String &p_path) {
+    Error err;
+
+    json_string = FileAccess::get_file_as_string(p_path, &err);
+    return err;
+}
+
+Error SpineSkeletonJsonDataResource::save_to_file(const String &p_path) {
+    Error err;
+    FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+    if (err != OK) {
+        if (file) file->close();
+        return err;
+    }
+
+    file->store_string(json_string);
+    file->close();
+
+    return OK;
+}

+ 49 - 0
spine-godot/spine_godot/SpineSkeletonJsonDataResource.h

@@ -0,0 +1,49 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINESKELETONJSONDATARESOURCE_H
+#define GODOT_SPINESKELETONJSONDATARESOURCE_H
+
+#include "core/variant_parser.h"
+
+class SpineSkeletonJsonDataResource : public Resource{
+	GDCLASS(SpineSkeletonJsonDataResource, Resource);
+
+protected:
+	static void _bind_methods();
+
+    String json_string;
+public:
+    inline const String &get_json_string() {return json_string;}
+
+    Error load_from_file(const String &p_path);
+    Error save_to_file(const String &p_path);
+};
+
+#endif //GODOT_SPINESKELETONJSONDATARESOURCE_H

+ 162 - 0
spine-godot/spine_godot/SpineSkin.cpp

@@ -0,0 +1,162 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineSkin.h"
+
+#include "SpineBoneData.h"
+#include "SpineConstraintData.h"
+
+void SpineSkin::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("init", "name"), &SpineSkin::init);
+	ClassDB::bind_method(D_METHOD("set_attachment", "slot_index", "name", "attachment"), &SpineSkin::set_attachment);
+	ClassDB::bind_method(D_METHOD("get_attachment", "slot_index", "name"), &SpineSkin::get_attachment);
+	ClassDB::bind_method(D_METHOD("remove_attachment", "slot_index", "name"), &SpineSkin::remove_attachment);
+	ClassDB::bind_method(D_METHOD("find_names_for_slot", "slot_index"), &SpineSkin::find_names_for_slot);
+	ClassDB::bind_method(D_METHOD("find_attachments_for_slot", "slot_index"), &SpineSkin::find_attachments_for_slot);
+	ClassDB::bind_method(D_METHOD("get_skin_name"), &SpineSkin::get_skin_name);
+	ClassDB::bind_method(D_METHOD("add_skin", "other"), &SpineSkin::add_skin);
+	ClassDB::bind_method(D_METHOD("copy_skin", "other"), &SpineSkin::copy_skin);
+	ClassDB::bind_method(D_METHOD("get_attachments"), &SpineSkin::get_attachments);
+	ClassDB::bind_method(D_METHOD("get_all_bone_data"), &SpineSkin::get_bones);
+	ClassDB::bind_method(D_METHOD("get_all_constraint_data"), &SpineSkin::get_constraint);
+}
+
+SpineSkin::SpineSkin():skin(NULL) {}
+SpineSkin::~SpineSkin() {}
+
+#define S_T(x) (spine::String(x.utf8()))
+Ref<SpineSkin> SpineSkin::init(const String &name){
+	skin = new spine::Skin(S_T(name));
+	return this;
+}
+
+void SpineSkin::set_attachment(uint64_t slot_index, const String &name, Ref<SpineAttachment> attachment){
+	if(!attachment.is_valid()){
+		ERR_PRINT("attachment is invalid!");
+		return;
+	}
+	skin->setAttachment(slot_index, S_T(name), attachment->get_spine_object());
+}
+
+Ref<SpineAttachment> SpineSkin::get_attachment(uint64_t slot_index, const String &name){
+	auto a = skin->getAttachment(slot_index, S_T(name));
+	if(a == NULL) return NULL;
+	Ref<SpineAttachment> gd_attachment(memnew(SpineAttachment));
+	gd_attachment->set_spine_object(a);
+	return gd_attachment;
+}
+
+void SpineSkin::remove_attachment(uint64_t slot_index, const String &name){
+	skin->removeAttachment(slot_index, S_T(name));
+}
+
+Array SpineSkin::find_names_for_slot(uint64_t slot_index){
+	spine::Vector<spine::String> names;
+	skin->findNamesForSlot(slot_index, names);
+	Array gd_names;
+	gd_names.resize(names.size());
+	for(size_t i=0; i < names.size(); ++i){
+		gd_names[i] = names[i].buffer();
+	}
+	return gd_names;
+}
+
+Array SpineSkin::find_attachments_for_slot(uint64_t slot_index){
+	spine::Vector<spine::Attachment*> as;
+	skin->findAttachmentsForSlot(slot_index, as);
+	Array gd_as;
+	gd_as.resize(as.size());
+	for(size_t i=0; i < as.size(); ++i){
+		if(as[i] == NULL) gd_as[i] = Ref<SpineAttachment>(NULL);
+		else {
+			Ref<SpineAttachment> gd_a(memnew(SpineAttachment));
+			gd_a->set_spine_object(as[i]);
+			gd_as[i] = gd_a;
+		}
+	}
+	return gd_as;
+}
+
+String SpineSkin::get_skin_name(){
+	return skin->getName().buffer();
+}
+
+void SpineSkin::add_skin(Ref<SpineSkin> other){
+	if(other.is_valid() && other->get_spine_object()){
+		skin->addSkin(other->get_spine_object());
+	} else{
+		ERR_PRINT("other is NULL!");
+	}
+}
+
+void SpineSkin::copy_skin(Ref<SpineSkin> other){
+	if(other.is_valid() && other->get_spine_object()){
+		skin->copySkin(other->get_spine_object());
+	} else{
+		ERR_PRINT("other is NULL!");
+	}
+}
+
+Ref<SpineSkinAttachmentMapEntries> SpineSkin::get_attachments(){
+	auto *es = new spine::Skin::AttachmentMap::Entries(skin->getAttachments());
+	Ref<SpineSkinAttachmentMapEntries> gd_es(memnew(SpineSkinAttachmentMapEntries));
+	gd_es->set_spine_object(es);
+	return gd_es;
+
+}
+
+Array SpineSkin::get_bones(){
+	auto bs = skin->getBones();
+	Array gd_bs;
+	gd_bs.resize(bs.size());
+	for(size_t i=0; i < bs.size(); ++i){
+		if(bs[i] == NULL) gd_bs[i] = Ref<SpineBoneData>(NULL);
+		else{
+			Ref<SpineBoneData> gd_b(memnew(SpineBoneData));
+			gd_b->set_spine_object(bs[i]);
+			gd_bs[i] = gd_b;
+		}
+	}
+	return gd_bs;
+}
+
+Array SpineSkin::get_constraint(){
+	auto cs = skin->getConstraints();
+	Array gd_cs;
+	gd_cs.resize(cs.size());
+	for(size_t i=0; i < cs.size(); ++i){
+		if(cs[i] == NULL) gd_cs[i] = Ref<SpineConstraintData>(NULL);
+		else{
+			Ref<SpineConstraintData> gd_c(memnew(SpineConstraintData));
+			gd_c->set_spine_object(cs[i]);
+			gd_cs[i] = gd_c;
+		}
+	}
+	return gd_cs;
+}

+ 85 - 0
spine-godot/spine_godot/SpineSkin.h

@@ -0,0 +1,85 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINESKIN_H
+#define GODOT_SPINESKIN_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+#include "SpineAttachment.h"
+#include "SpineSkinAttachmentMapEntries.h"
+
+class SpineSkin : public Reference {
+	GDCLASS(SpineSkin, Reference);
+
+protected:
+	static void _bind_methods();
+
+private:
+	spine::Skin *skin;
+
+public:
+	SpineSkin();
+	~SpineSkin();
+
+	inline void set_spine_object(spine::Skin *s){
+		skin = s;
+	}
+	spine::Skin *get_spine_object(){
+		return skin;
+	}
+
+	Ref<SpineSkin> init(const String &name);
+
+	void set_attachment(uint64_t slot_index, const String &name, Ref<SpineAttachment> attachment);
+
+	Ref<SpineAttachment> get_attachment(uint64_t slot_index, const String &name);
+
+	void remove_attachment(uint64_t slot_index, const String &name);
+
+	Array find_names_for_slot(uint64_t slot_index);
+
+	Array find_attachments_for_slot(uint64_t slot_index);
+
+	String get_skin_name();
+
+	void add_skin(Ref<SpineSkin> other);
+
+	void copy_skin(Ref<SpineSkin> other);
+
+	Ref<SpineSkinAttachmentMapEntries> get_attachments();
+
+	Array get_bones();
+
+	Array get_constraint();
+};
+
+#endif //GODOT_SPINESKIN_H

+ 93 - 0
spine-godot/spine_godot/SpineSkinAttachmentMapEntries.cpp

@@ -0,0 +1,93 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineSkinAttachmentMapEntries.h"
+
+void SpineSkinAttachmentMapEntry::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_slot_index"), &SpineSkinAttachmentMapEntry::get_slot_index);
+	ClassDB::bind_method(D_METHOD("set_slot_index", "v"), &SpineSkinAttachmentMapEntry::set_slot_index);
+	ClassDB::bind_method(D_METHOD("get_entry_name"), &SpineSkinAttachmentMapEntry::get_entry_name);
+	ClassDB::bind_method(D_METHOD("set_entry_name", "v"), &SpineSkinAttachmentMapEntry::set_entry_name);
+	ClassDB::bind_method(D_METHOD("get_attachment"), &SpineSkinAttachmentMapEntry::get_attachment);
+	ClassDB::bind_method(D_METHOD("set_attachment", "v"), &SpineSkinAttachmentMapEntry::set_attachment);
+}
+
+SpineSkinAttachmentMapEntry::SpineSkinAttachmentMapEntry():entry(NULL) {}
+SpineSkinAttachmentMapEntry::~SpineSkinAttachmentMapEntry() {}
+
+uint64_t SpineSkinAttachmentMapEntry::get_slot_index(){
+	return entry->_slotIndex;
+}
+void SpineSkinAttachmentMapEntry::set_slot_index(uint64_t v){
+	entry->_slotIndex = v;
+}
+
+String SpineSkinAttachmentMapEntry::get_entry_name(){
+	return entry->_name.buffer();
+}
+void SpineSkinAttachmentMapEntry::set_entry_name(const String &v){
+	entry->_name = spine::String(v.utf8());
+}
+
+Ref<SpineAttachment> SpineSkinAttachmentMapEntry::get_attachment(){
+	if(entry->_attachment == NULL) return NULL;
+	Ref<SpineAttachment> gd_attachment(memnew(SpineAttachment));
+	gd_attachment->set_spine_object(entry->_attachment);
+	return gd_attachment;
+}
+void SpineSkinAttachmentMapEntry::set_attachment(Ref<SpineAttachment> v){
+	if(v.is_valid()){
+		entry->_attachment = v->get_spine_object();
+	}else{
+		entry->_attachment = NULL;
+	}
+}
+
+void SpineSkinAttachmentMapEntries::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("has_next"), &SpineSkinAttachmentMapEntries::has_next);
+	ClassDB::bind_method(D_METHOD("next"), &SpineSkinAttachmentMapEntries::next);
+}
+
+SpineSkinAttachmentMapEntries::SpineSkinAttachmentMapEntries():entries(NULL) {}
+SpineSkinAttachmentMapEntries::~SpineSkinAttachmentMapEntries() {
+	if(entries){
+		delete entries;
+		return;
+	}
+}
+
+bool SpineSkinAttachmentMapEntries::has_next(){
+	return entries->hasNext();
+}
+Ref<SpineSkinAttachmentMapEntry> SpineSkinAttachmentMapEntries::next(){
+	auto &e = entries->next();
+	Ref<SpineSkinAttachmentMapEntry> gd_entry(memnew(SpineSkinAttachmentMapEntry));
+	gd_entry->set_spine_object(&e);
+	return gd_entry;
+}

+ 93 - 0
spine-godot/spine_godot/SpineSkinAttachmentMapEntries.h

@@ -0,0 +1,93 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINESKINATTACHMENTMAPENTRIES_H
+#define GODOT_SPINESKINATTACHMENTMAPENTRIES_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+#include "SpineAttachment.h"
+
+class SpineSkinAttachmentMapEntry : public Reference {
+	GDCLASS(SpineSkinAttachmentMapEntry, Reference);
+
+protected:
+	static void _bind_methods();
+
+private:
+	spine::Skin::AttachmentMap::Entry *entry;
+
+public:
+	SpineSkinAttachmentMapEntry();
+	~SpineSkinAttachmentMapEntry();
+
+	inline void set_spine_object(spine::Skin::AttachmentMap::Entry *e){
+		entry = e;
+	}
+	inline spine::Skin::AttachmentMap::Entry *get_spine_object(){
+		return entry;
+	}
+
+	uint64_t get_slot_index();
+	void set_slot_index(uint64_t v);
+
+	String get_entry_name();
+	void set_entry_name(const String &v);
+
+	Ref<SpineAttachment> get_attachment();
+	void set_attachment(Ref<SpineAttachment> v);
+};
+
+class SpineSkinAttachmentMapEntries : public Reference {
+	GDCLASS(SpineSkinAttachmentMapEntries, Reference);
+
+protected:
+	static void _bind_methods();
+
+private:
+	spine::Skin::AttachmentMap::Entries *entries;
+
+public:
+	SpineSkinAttachmentMapEntries();
+	~SpineSkinAttachmentMapEntries();
+
+	inline void set_spine_object(spine::Skin::AttachmentMap::Entries *e){
+		entries = e;
+	}
+	inline spine::Skin::AttachmentMap::Entries *get_spine_object(){
+		return entries;
+	}
+
+	bool has_next();
+	Ref<SpineSkinAttachmentMapEntry> next();
+};
+
+#endif //GODOT_SPINESKINATTACHMENTMAPENTRIES_H

+ 148 - 0
spine-godot/spine_godot/SpineSlot.cpp

@@ -0,0 +1,148 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineSlot.h"
+
+#include "SpineBone.h"
+#include "SpineSkeleton.h"
+
+
+void SpineSlot::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("set_to_setup_pos"), &SpineSlot::set_to_setup_pos);
+	ClassDB::bind_method(D_METHOD("get_data"), &SpineSlot::get_data);
+	ClassDB::bind_method(D_METHOD("get_bone"), &SpineSlot::get_bone);
+	ClassDB::bind_method(D_METHOD("get_skeleton"), &SpineSlot::get_skeleton);
+	ClassDB::bind_method(D_METHOD("get_color"), &SpineSlot::get_color);
+	ClassDB::bind_method(D_METHOD("set_color"), &SpineSlot::set_color);
+	ClassDB::bind_method(D_METHOD("get_dark_color"), &SpineSlot::get_dark_color);
+	ClassDB::bind_method(D_METHOD("set_dark_color", "v"), &SpineSlot::set_dark_color);
+	ClassDB::bind_method(D_METHOD("has_dark_color"), &SpineSlot::has_dark_color);
+	ClassDB::bind_method(D_METHOD("get_attachment"), &SpineSlot::get_attachment);
+	ClassDB::bind_method(D_METHOD("set_attachment", "v"), &SpineSlot::set_attachment);
+	ClassDB::bind_method(D_METHOD("get_attachment_state"), &SpineSlot::get_attachment_state);
+	ClassDB::bind_method(D_METHOD("set_attachment_state", "v"), &SpineSlot::set_attachment_state);
+	ClassDB::bind_method(D_METHOD("get_deform"), &SpineSlot::get_deform);
+	ClassDB::bind_method(D_METHOD("set_deform", "v"), &SpineSlot::set_deform);
+}
+
+SpineSlot::SpineSlot():slot(NULL) {}
+SpineSlot::~SpineSlot() {}
+
+void SpineSlot::set_to_setup_pos(){
+	slot->setToSetupPose();
+}
+
+Ref<SpineSlotData> SpineSlot::get_data(){
+	auto &sd = slot->getData();
+	Ref<SpineSlotData> gd_sd(memnew(SpineSlotData));
+	gd_sd->set_spine_object(&sd);
+	return gd_sd;
+}
+
+Ref<SpineBone> SpineSlot::get_bone(){
+	auto &b = slot->getBone();
+	Ref<SpineBone> gd_b(memnew(SpineBone));
+	gd_b->set_spine_object(&b);
+	return gd_b;
+}
+
+Ref<SpineSkeleton> SpineSlot::get_skeleton(){
+	auto &s = slot->getSkeleton();
+	Ref<SpineSkeleton> gd_s(memnew(SpineSkeleton));
+	gd_s->set_spine_object(&s);
+	return gd_s;
+}
+
+Color SpineSlot::get_color(){
+	auto &c = slot->getColor();
+	return Color(c.r, c.g, c.b, c.a);
+}
+void SpineSlot::set_color(Color v){
+	auto &c = slot->getColor();
+	c.set(v.r, v.g, v.b, v.a);
+}
+
+Color SpineSlot::get_dark_color(){
+	auto &c = slot->getDarkColor();
+	return Color(c.r, c.g, c.b, c.a);
+}
+void SpineSlot::set_dark_color(Color v){
+	auto &c = slot->getDarkColor();
+	c.set(v.r, v.g, v.b, v.a);
+}
+
+bool SpineSlot::has_dark_color(){
+	return slot->hasDarkColor();
+}
+
+Ref<SpineAttachment> SpineSlot::get_attachment(){
+	auto a = slot->getAttachment();
+	if(a == NULL) return NULL;
+	Ref<SpineAttachment> gd_a(memnew(SpineAttachment));
+	gd_a->set_spine_object(a);
+	return gd_a;
+}
+void SpineSlot::set_attachment(Ref<SpineAttachment> v){
+	if(v.is_valid()){
+		slot->setAttachment(v->get_spine_object());
+	}else{
+		slot->setAttachment(NULL);
+	}
+}
+
+int SpineSlot::get_attachment_state(){
+	return slot->getAttachmentState();
+}
+void SpineSlot::set_attachment_state(int v){
+	slot->setAttachmentState(v);
+}
+
+float SpineSlot::get_attachment_time(){
+	return slot->getAttachmentTime();
+}
+void SpineSlot::set_attachment_time(float v){
+	slot->setAttachmentTime(v);
+}
+
+Array SpineSlot::get_deform(){
+	auto &ds = slot->getDeform();
+	Array gd_ds;
+	gd_ds.resize(ds.size());
+	for(size_t i=0; i < ds.size(); ++i){
+		gd_ds[i] = ds[i];
+	}
+	return gd_ds;
+}
+void SpineSlot::set_deform(Array gd_ds){
+	auto &ds = slot->getDeform();
+	ds.setSize(gd_ds.size(), 0);
+	for(size_t i=0; i < gd_ds.size(); ++i){
+		ds[i] = gd_ds[i];
+	}
+}

+ 93 - 0
spine-godot/spine_godot/SpineSlot.h

@@ -0,0 +1,93 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINESLOT_H
+#define GODOT_SPINESLOT_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+#include "SpineSlotData.h"
+#include "SpineAttachment.h"
+
+class SpineSkeleton;
+
+class SpineBone;
+
+class SpineSlot : public Reference{
+	GDCLASS(SpineSlot, Reference);
+
+protected:
+	static void _bind_methods();
+
+private:
+	spine::Slot *slot;
+
+public:
+	SpineSlot();
+	~SpineSlot();
+
+	inline void set_spine_object(spine::Slot *s){
+		slot = s;
+	}
+	inline spine::Slot *get_spine_object(){
+		return slot;
+	}
+
+	void set_to_setup_pos();
+
+	Ref<SpineSlotData> get_data();
+
+	Ref<SpineBone> get_bone();
+
+	Ref<SpineSkeleton> get_skeleton();
+
+	Color get_color();
+	void set_color(Color v);
+
+	Color get_dark_color();
+	void set_dark_color(Color v);
+
+	bool has_dark_color();
+
+	Ref<SpineAttachment> get_attachment();
+	void set_attachment(Ref<SpineAttachment> v);
+
+	int get_attachment_state();
+	void set_attachment_state(int v);
+
+	float get_attachment_time();
+	void set_attachment_time(float v);
+
+	Array get_deform();
+	void set_deform(Array v);
+};
+
+#endif //GODOT_SPINESLOT_H

+ 114 - 0
spine-godot/spine_godot/SpineSlotData.cpp

@@ -0,0 +1,114 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineSlotData.h"
+
+void SpineSlotData::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_index"), &SpineSlotData::get_index);
+	ClassDB::bind_method(D_METHOD("get_slot_name"), &SpineSlotData::get_slot_name);
+	ClassDB::bind_method(D_METHOD("get_bone_data"), &SpineSlotData::get_bone_data);
+	ClassDB::bind_method(D_METHOD("get_color"), &SpineSlotData::get_color);
+	ClassDB::bind_method(D_METHOD("get_dark_color"), &SpineSlotData::get_dark_color);
+	ClassDB::bind_method(D_METHOD("has_dark_color"), &SpineSlotData::has_dark_color);
+	ClassDB::bind_method(D_METHOD("set_has_dark_color", "v"), &SpineSlotData::set_has_dark_color);
+	ClassDB::bind_method(D_METHOD("get_attachment_name"), &SpineSlotData::get_attachment_name);
+	ClassDB::bind_method(D_METHOD("set_attachment_name", "v"), &SpineSlotData::set_attachment_name);
+	ClassDB::bind_method(D_METHOD("get_blend_mode"), &SpineSlotData::get_blend_mode);
+	ClassDB::bind_method(D_METHOD("set_blend_mode", "v"), &SpineSlotData::set_blend_mode);
+
+	ClassDB::bind_method(D_METHOD("set_color", "v"), &SpineSlotData::set_color);
+	ClassDB::bind_method(D_METHOD("set_dark_color", "v"), &SpineSlotData::set_dark_color);
+
+	BIND_ENUM_CONSTANT(BLENDMODE_NORMAL);
+	BIND_ENUM_CONSTANT(BLENDMODE_ADDITIVE);
+	BIND_ENUM_CONSTANT(BLENDMODE_MULTIPLY);
+	BIND_ENUM_CONSTANT(BLENDMODE_SCREEN);
+}
+
+SpineSlotData::SpineSlotData():slot_data(NULL) {}
+SpineSlotData::~SpineSlotData() {}
+
+#define S_T(x) (spine::String(x.utf8()))
+int SpineSlotData::get_index(){
+	return slot_data->getIndex();
+}
+
+String SpineSlotData::get_slot_name(){
+	return slot_data->getName().buffer();
+}
+
+Ref<SpineBoneData> SpineSlotData::get_bone_data(){
+	auto &bd = slot_data->getBoneData();
+	Ref<SpineBoneData> gd_bone_data(memnew(SpineBoneData));
+	gd_bone_data->set_spine_object(&bd);
+	return gd_bone_data;
+}
+
+Color SpineSlotData::get_color(){
+	auto &c = slot_data->getColor();
+	return Color(c.r, c.g, c.b, c.a);
+}
+void SpineSlotData::set_color(Color v){
+	auto &c = slot_data->getColor();
+	c.set(v.r, v.g, v.b, v.a);
+}
+
+Color SpineSlotData::get_dark_color(){
+	auto &c = slot_data->getDarkColor();
+	return Color(c.r, c.g, c.b, c.a);
+}
+void SpineSlotData::set_dark_color(Color v){
+	auto &c = slot_data->getDarkColor();
+	c.set(v.r, v.g, v.b, v.a);
+}
+
+bool SpineSlotData::has_dark_color(){
+	return slot_data->hasDarkColor();
+}
+void SpineSlotData::set_has_dark_color(bool v){
+	slot_data->setHasDarkColor(v);
+}
+
+String SpineSlotData::get_attachment_name(){
+	return slot_data->getAttachmentName().buffer();
+}
+void SpineSlotData::set_attachment_name(const String &v){
+	slot_data->setAttachmentName(S_T(v));
+}
+
+SpineSlotData::BlendMode SpineSlotData::get_blend_mode(){
+	auto bm = (int) slot_data->getBlendMode();
+	return (BlendMode) bm;
+}
+void SpineSlotData::set_blend_mode(BlendMode v){
+	auto bm = (int) v;
+	slot_data->setBlendMode((spine::BlendMode) bm);
+}
+
+#undef S_T

+ 88 - 0
spine-godot/spine_godot/SpineSlotData.h

@@ -0,0 +1,88 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINESLOTDATA_H
+#define GODOT_SPINESLOTDATA_H
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+#include "SpineBoneData.h"
+
+class SpineSlotData : public Reference {
+	GDCLASS(SpineSlotData, Reference);
+
+protected:
+	static void _bind_methods();
+
+private:
+	spine::SlotData *slot_data;
+
+public:
+	SpineSlotData();
+	~SpineSlotData();
+
+	inline void set_spine_object(spine::SlotData *s){
+		slot_data = s;
+	}
+	inline spine::SlotData *get_spine_object(){
+		return slot_data;
+	}
+
+	enum BlendMode {
+		BLENDMODE_NORMAL = 0,
+		BLENDMODE_ADDITIVE,
+		BLENDMODE_MULTIPLY,
+		BLENDMODE_SCREEN
+	};
+
+	int get_index();
+
+	String get_slot_name();
+
+	Ref<SpineBoneData> get_bone_data();
+
+	Color get_color();
+	void set_color(Color c);
+
+	Color get_dark_color();
+	void set_dark_color(Color c);
+
+	bool has_dark_color();
+	void set_has_dark_color(bool v);
+
+	String get_attachment_name();
+	void set_attachment_name(const String &v);
+
+	BlendMode get_blend_mode();
+	void set_blend_mode(BlendMode v);
+};
+
+VARIANT_ENUM_CAST(SpineSlotData::BlendMode);
+#endif //GODOT_SPINESLOTDATA_H

+ 1039 - 0
spine-godot/spine_godot/SpineSprite.cpp

@@ -0,0 +1,1039 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineSprite.h"
+
+#include "SpineTrackEntry.h"
+#include "SpineEvent.h"
+
+void SpineSprite::_bind_methods() {
+    ClassDB::bind_method(D_METHOD("set_animation_state_data_res", "animation_state_data_res"), &SpineSprite::set_animation_state_data_res);
+    ClassDB::bind_method(D_METHOD("get_animation_state_data_res"), &SpineSprite::get_animation_state_data_res);
+	ClassDB::bind_method(D_METHOD("_on_animation_data_created"), &SpineSprite::_on_animation_data_created);
+	ClassDB::bind_method(D_METHOD("get_skeleton"), &SpineSprite::get_skeleton);
+	ClassDB::bind_method(D_METHOD("get_animation_state"), &SpineSprite::get_animation_state);
+	ClassDB::bind_method(D_METHOD("_on_animation_data_changed"), &SpineSprite::_on_animation_data_changed);
+
+	ClassDB::bind_method(D_METHOD("get_current_animations"), &SpineSprite::get_current_animations);
+	ClassDB::bind_method(D_METHOD("set_current_animations", "current_animations"), &SpineSprite::set_current_animations);
+
+	ClassDB::bind_method(D_METHOD("get_select_track_id"), &SpineSprite::get_select_track_id);
+	ClassDB::bind_method(D_METHOD("set_select_track_id", "track_id"), &SpineSprite::set_select_track_id);
+	ClassDB::bind_method(D_METHOD("get_clear_track"), &SpineSprite::get_clear_track);
+	ClassDB::bind_method(D_METHOD("set_clear_track", "v"), &SpineSprite::set_clear_track);
+	ClassDB::bind_method(D_METHOD("get_clear_tracks"), &SpineSprite::get_clear_tracks);
+	ClassDB::bind_method(D_METHOD("set_clear_tracks", "v"), &SpineSprite::set_clear_tracks);
+
+	ClassDB::bind_method(D_METHOD("get_empty_animation_duration"), &SpineSprite::get_empty_animation_duration);
+	ClassDB::bind_method(D_METHOD("set_empty_animation_duration", "track_id"), &SpineSprite::set_empty_animation_duration);
+	ClassDB::bind_method(D_METHOD("get_set_empty_animation"), &SpineSprite::get_set_empty_animation);
+	ClassDB::bind_method(D_METHOD("set_set_empty_animation", "v"), &SpineSprite::set_set_empty_animation);
+	ClassDB::bind_method(D_METHOD("get_set_empty_animations"), &SpineSprite::get_set_empty_animations);
+	ClassDB::bind_method(D_METHOD("set_set_empty_animations", "v"), &SpineSprite::set_set_empty_animations);
+
+	ClassDB::bind_method(D_METHOD("get_bind_slot_nodes"), &SpineSprite::get_bind_slot_nodes);
+	ClassDB::bind_method(D_METHOD("set_bind_slot_nodes", "v"), &SpineSprite::set_bind_slot_nodes);
+	ClassDB::bind_method(D_METHOD("get_overlap"), &SpineSprite::get_overlap);
+	ClassDB::bind_method(D_METHOD("set_overlap", "v"), &SpineSprite::set_overlap);	
+	ClassDB::bind_method(D_METHOD("set_skin", "v"), &SpineSprite::set_skin);
+	ClassDB::bind_method(D_METHOD("get_skin"), &SpineSprite::get_skin);
+	ClassDB::bind_method(D_METHOD("_on_skin_property_changed"), &SpineSprite::_on_skin_property_changed);
+	ClassDB::bind_method(D_METHOD("gen_spine_skin_from_packed_resource", "res"), &SpineSprite::gen_spine_skin_from_packed_resource);
+
+	ClassDB::bind_method(D_METHOD("bone_get_global_transform", "bone_name"), &SpineSprite::bone_get_global_transform);
+	ClassDB::bind_method(D_METHOD("bone_set_global_transform", "bone_name", "global_transform"), &SpineSprite::bone_set_global_transform);
+
+    ClassDB::bind_method(D_METHOD("set_process_mode", "v"), &SpineSprite::set_process_mode);
+    ClassDB::bind_method(D_METHOD("get_process_mode"), &SpineSprite::get_process_mode);
+
+    ClassDB::bind_method(D_METHOD("manual_update", "delta"), &SpineSprite::_update_all);
+
+	ADD_SIGNAL(MethodInfo("animation_state_ready", PropertyInfo(Variant::OBJECT, "animation_state", PROPERTY_HINT_TYPE_STRING, "SpineAnimationState"), PropertyInfo(Variant::OBJECT, "skeleton", PROPERTY_HINT_TYPE_STRING, "SpineSkeleton")));
+	ADD_SIGNAL(MethodInfo("animation_start", PropertyInfo(Variant::OBJECT, "animation_state", PROPERTY_HINT_TYPE_STRING, "SpineAnimationState"), PropertyInfo(Variant::OBJECT, "track_entry", PROPERTY_HINT_TYPE_STRING, "SpineTrackEntry"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_TYPE_STRING, "SpineEvent")));
+	ADD_SIGNAL(MethodInfo("animation_interrupt", PropertyInfo(Variant::OBJECT, "animation_state", PROPERTY_HINT_TYPE_STRING, "SpineAnimationState"), PropertyInfo(Variant::OBJECT, "track_entry", PROPERTY_HINT_TYPE_STRING, "SpineTrackEntry"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_TYPE_STRING, "SpineEvent")));
+	ADD_SIGNAL(MethodInfo("animation_end", PropertyInfo(Variant::OBJECT, "animation_state", PROPERTY_HINT_TYPE_STRING, "SpineAnimationState"), PropertyInfo(Variant::OBJECT, "track_entry", PROPERTY_HINT_TYPE_STRING, "SpineTrackEntry"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_TYPE_STRING, "SpineEvent")));
+	ADD_SIGNAL(MethodInfo("animation_complete", PropertyInfo(Variant::OBJECT, "animation_state", PROPERTY_HINT_TYPE_STRING, "SpineAnimationState"), PropertyInfo(Variant::OBJECT, "track_entry", PROPERTY_HINT_TYPE_STRING, "SpineTrackEntry"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_TYPE_STRING, "SpineEvent")));
+	ADD_SIGNAL(MethodInfo("animation_dispose", PropertyInfo(Variant::OBJECT, "animation_state", PROPERTY_HINT_TYPE_STRING, "SpineAnimationState"), PropertyInfo(Variant::OBJECT, "track_entry", PROPERTY_HINT_TYPE_STRING, "SpineTrackEntry"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_TYPE_STRING, "SpineEvent")));
+	ADD_SIGNAL(MethodInfo("animation_event", PropertyInfo(Variant::OBJECT, "animation_state", PROPERTY_HINT_TYPE_STRING, "SpineAnimationState"), PropertyInfo(Variant::OBJECT, "track_entry", PROPERTY_HINT_TYPE_STRING, "SpineTrackEntry"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_TYPE_STRING, "SpineEvent")));
+
+    ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "animation_state_data_res", PropertyHint::PROPERTY_HINT_RESOURCE_TYPE, "SpineAnimationStateDataResource"), "set_animation_state_data_res", "get_animation_state_data_res");
+
+    ADD_PROPERTY(PropertyInfo(Variant::BOOL, "overlap"), "set_overlap", "get_overlap");
+	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bind_slot_nodes"), "set_bind_slot_nodes", "get_bind_slot_nodes");
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "packed_skin_resource", PropertyHint::PROPERTY_HINT_RESOURCE_TYPE, "PackedSpineSkinResource"), "set_skin", "get_skin");
+
+    ADD_GROUP("animation", "");
+    ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Process,Physics,Manually"), "set_process_mode", "get_process_mode");
+
+	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "current_animations"), "set_current_animations", "get_current_animations");
+
+    BIND_ENUM_CONSTANT(ProcessMode::ProcessMode_Process);
+    BIND_ENUM_CONSTANT(ProcessMode::ProcessMode_Physics);
+    BIND_ENUM_CONSTANT(ProcessMode::ProcessMode_Manual);
+}
+
+SpineSprite::SpineSprite() :
+		select_track_id(0), empty_animation_duration(0.2f), skeleton_clipper(NULL),
+		overlap(false),
+		process_mode(ProcessMode_Process)
+		{
+	skeleton_clipper = new spine::SkeletonClipping();
+}
+SpineSprite::~SpineSprite() {
+	delete skeleton_clipper;
+}
+
+void SpineSprite::_notification(int p_what) {
+	switch (p_what) {
+		case NOTIFICATION_READY:{
+            set_process_internal(process_mode == ProcessMode_Process);
+            set_physics_process_internal(process_mode == ProcessMode_Physics);
+			remove_redundant_mesh_instances();
+		} break;
+		case NOTIFICATION_INTERNAL_PROCESS: {
+		    if (process_mode == ProcessMode_Process)
+			    _update_all(get_process_delta_time());
+		} break;
+		case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
+            if (process_mode == ProcessMode_Physics)
+                _update_all(get_physics_process_delta_time());
+        } break;
+	}
+}
+
+void SpineSprite::_update_all(float delta) {
+    if (!(skeleton.is_valid() && animation_state.is_valid()) || mesh_instances.empty())
+        return;
+
+    animation_state->update(delta);
+    if (!is_visible_in_tree())
+        return;
+
+    animation_state->apply(skeleton);
+
+    skeleton->update_world_transform();
+
+    update_mesh_from_skeleton(skeleton);
+
+    update();
+
+    update_bind_slot_nodes();
+}
+
+void SpineSprite::update_bind_slot_nodes(){
+	if(animation_state.is_valid() && skeleton.is_valid()){
+		for(size_t i=0, n=bind_slot_nodes.size(); i<n; ++i){
+			auto a = bind_slot_nodes[i];
+			if(a.get_type() == Variant::DICTIONARY){
+				auto d = (Dictionary) a;
+				if(d.has("slot_name") && d.has("node_path")){
+					NodePath node_path = d["node_path"];
+					Node *node = get_node_or_null(node_path);
+					if(node && node->is_class("Node2D")){
+						Node2D *node2d = (Node2D*) node;
+
+						String slot_name = d["slot_name"];
+						auto slot = skeleton->find_slot(slot_name);
+						if(slot.is_valid()){
+							auto bone = slot->get_bone();
+							if(bone.is_valid())
+							{
+								update_bind_slot_node_transform(bone, node2d);
+								update_bind_slot_node_draw_order(slot_name, node2d);
+							}
+						}
+
+					}
+				}
+			}else if(a.get_type() == Variant::ARRAY){
+				auto as = (Array) a;// 0: slot_name, 1: node_path
+				if(as.size() >= 2 && as[0].get_type() == Variant::STRING && as[1].get_type() == Variant::NODE_PATH){
+					NodePath node_path = as[1];
+					Node *node = get_node_or_null(node_path);
+					if(node && node->is_class("Node2D")){
+						Node2D *node2d = (Node2D*) node;
+
+						String slot_name = as[0];
+						auto slot = skeleton->find_slot(slot_name);
+						if(slot.is_valid()){
+							auto bone = slot->get_bone();
+							if(bone.is_valid())
+							{
+								update_bind_slot_node_transform(bone, node2d);
+								update_bind_slot_node_draw_order(slot_name, node2d);
+							}
+						}
+
+					}
+				}
+			}
+		}
+	}
+}
+void SpineSprite::update_bind_slot_node_transform(Ref<SpineBone> bone, Node2D *node2d){
+	bone->apply_world_transform_2d(node2d);
+}
+void SpineSprite::update_bind_slot_node_draw_order(const String &slot_name, Node2D *node2d){
+	auto mesh_ins = find_node(slot_name);
+	if(mesh_ins){
+		auto pos = mesh_ins->get_index();
+
+		// get child
+		auto node = find_child_node_by_node(node2d);
+		if(node && node->get_index() != pos+1){
+			move_child(node, pos+1);
+		}
+	}
+}
+Node *SpineSprite::find_child_node_by_node(Node *node){
+	if(node == NULL) return NULL;
+	while(node && node->get_parent() != this) node = node->get_parent();
+	return node;
+}
+
+void SpineSprite::set_animation_state_data_res(const Ref<SpineAnimationStateDataResource> &s) {
+    animation_state_data_res = s;
+
+	// update run time skeleton and meshes
+	_on_animation_data_changed();
+}
+Ref<SpineAnimationStateDataResource> SpineSprite::get_animation_state_data_res() {
+    return animation_state_data_res;
+}
+
+void SpineSprite::_on_animation_data_created(){
+//	print_line("_on_animation_data_created");
+	skeleton = Ref<SpineSkeleton>(memnew(SpineSkeleton));
+	skeleton->load_skeleton(animation_state_data_res->get_skeleton());
+	skeleton->set_spine_sprite(this);
+//	print_line("Run time skeleton created.");
+
+	animation_state = Ref<SpineAnimationState>(memnew(SpineAnimationState));
+	animation_state->load_animation_state(animation_state_data_res);
+	animation_state->get_animation_state()->setListener(this);
+//	print_line("Run time animation state created.");
+
+	// add mesh instances related by current skeleton
+	animation_state->update(0);
+	animation_state->apply(skeleton);
+	skeleton->update_world_transform();
+	gen_mesh_from_skeleton(skeleton);
+
+	if (process_mode == ProcessMode_Process) {
+        _notification(NOTIFICATION_INTERNAL_PROCESS);
+    } else if (process_mode == ProcessMode_Physics) {
+        _notification(NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
+	}
+
+	emit_signal("animation_state_ready", animation_state, skeleton);
+}
+void SpineSprite::_on_animation_data_changed() {
+//	print_line("_on_animation_data_changed");
+	remove_mesh_instances();
+	skeleton.unref();
+	animation_state.unref();
+	if(!animation_state_data_res.is_null())
+	{
+		if(!animation_state_data_res->is_connected("animation_state_data_created", this, "_on_animation_data_created"))
+			animation_state_data_res->connect("animation_state_data_created", this, "_on_animation_data_created");
+		if(!animation_state_data_res->is_connected("skeleton_data_res_changed", this, "_on_animation_data_changed"))
+			animation_state_data_res->connect("skeleton_data_res_changed", this, "_on_animation_data_changed");
+		if(!animation_state_data_res->is_connected("animation_state_data_changed", this, "_on_animation_data_changed"))
+			animation_state_data_res->connect("animation_state_data_changed", this, "_on_animation_data_changed");
+
+		if(animation_state_data_res->is_animation_state_data_created())
+		{
+			_on_animation_data_created();
+		}
+	}
+}
+
+Ref<SpineSkeleton> SpineSprite::get_skeleton() {
+	return skeleton;
+}
+Ref<SpineAnimationState> SpineSprite::get_animation_state() {
+	return animation_state;
+}
+
+void SpineSprite::gen_mesh_from_skeleton(Ref<SpineSkeleton> s) {
+	auto sk = s->get_spine_object();
+	for(size_t i=0, n = sk->getSlots().size(); i < n; ++i)
+	{
+		// creat a mesh instance 2d for every slot
+		auto mesh_ins = memnew(SpineSpriteMeshInstance2D);
+		add_child(mesh_ins);
+		mesh_ins->set_position(Vector2(0, 0));
+		mesh_ins->set_owner(this);
+		mesh_instances.push_back(mesh_ins);
+
+		spine::Slot *slot = sk->getDrawOrder()[i];
+		mesh_ins->set_name(slot->getData().getName().buffer());
+		Ref<SpineSlot> gd_slot(memnew(SpineSlot));
+		gd_slot->set_spine_object(slot);
+		mesh_ins->set_slot(gd_slot);
+
+		// creat a material
+		Ref<CanvasItemMaterial> mat(memnew(CanvasItemMaterial));
+		CanvasItemMaterial::BlendMode blend_mode;
+		switch (slot->getData().getBlendMode()) {
+			case spine::BlendMode_Normal:
+				blend_mode = CanvasItemMaterial::BLEND_MODE_MIX;
+				break;
+			case spine::BlendMode_Additive:
+				blend_mode = CanvasItemMaterial::BLEND_MODE_ADD;
+				break;
+			case spine::BlendMode_Multiply:
+				blend_mode = CanvasItemMaterial::BLEND_MODE_MUL;
+				break;
+			case spine::BlendMode_Screen:
+				blend_mode = CanvasItemMaterial::BLEND_MODE_MIX;
+				break;
+			default:
+				blend_mode = CanvasItemMaterial::BLEND_MODE_MIX;
+		}		
+		mat->set_blend_mode(blend_mode);		
+		mesh_ins->set_material(mat);
+	}
+}
+
+void SpineSprite::remove_mesh_instances() {
+	for(size_t i=0;i < mesh_instances.size();++i)
+	{
+		remove_child(mesh_instances[i]);
+		memdelete(mesh_instances[i]);
+	}
+	mesh_instances.clear();
+}
+
+void SpineSprite::remove_redundant_mesh_instances() {
+	Vector<Node*> ms;
+	// remove the redundant mesh instances that added by duplicating
+//	print_line("start clearing");
+	for(size_t i=0, n=get_child_count(); i<n; ++i){
+		auto node = get_child(i);
+//		print_line(String("get a node: ") + node->get_name());
+		if(node && node->is_class("SpineSpriteMeshInstance2D")){
+			if(mesh_instances.find((SpineSpriteMeshInstance2D*)node) == -1)
+			{
+//				print_line("marked clear");
+				ms.push_back(node);
+			}
+
+		}
+	}
+	for(size_t i=0, n=ms.size(); i<n; ++i){
+		remove_child(ms[i]);
+		memdelete(ms[i]);
+	}
+	ms.clear();
+//	print_line("end clearing");
+}
+
+#define TEMP_COPY(t, get_res) do{auto &temp_uvs = get_res;        \
+								t.setSize(temp_uvs.size(), 0);    \
+								for(size_t j=0;j<t.size();++j)    \
+								{                                 \
+								t[j] = temp_uvs[j];               \
+								}}while(false);
+void SpineSprite::update_mesh_from_skeleton(Ref<SpineSkeleton> s) {
+	static const unsigned short VERTEX_STRIDE = 2;
+	static const unsigned short UV_STRIDE = 2;
+	static unsigned short quad_indices[] = { 0, 1, 2, 2, 3, 0 };
+
+	auto sk = s->get_spine_object();
+	for(size_t i=0, n = sk->getSlots().size(); i < n; ++i)
+	{
+		spine::Vector<float> vertices;
+		spine::Vector<float> uvs;
+		spine::Vector<unsigned short> indices;
+
+		spine::Slot *slot = sk->getDrawOrder()[i];
+
+		spine::Attachment *attachment = slot->getAttachment();
+		if(!attachment){
+			// set invisible to mesh instance
+			mesh_instances[i]->set_visible(false);
+
+			skeleton_clipper->clipEnd(*slot);
+			continue;
+		}
+		mesh_instances[i]->set_visible(true);
+
+		spine::Color skeleton_color = sk->getColor();
+		spine::Color slot_color = slot->getColor();
+		spine::Color tint(skeleton_color.r * slot_color.r, skeleton_color.g * slot_color.g, skeleton_color.b * slot_color.b, skeleton_color.a * slot_color.a);
+
+		Ref<Texture> tex;
+		Ref<Texture> normal_tex;
+		size_t v_num = 0;
+
+		if(attachment->getRTTI().isExactly(spine::RegionAttachment::rtti))
+		{
+			spine::RegionAttachment *region_attachment = (spine::RegionAttachment*)attachment;
+
+			auto p_spine_renderer_object = (SpineRendererObject*) ((spine::AtlasRegion*)region_attachment->getRendererObject())->page->getRendererObject();
+			tex = p_spine_renderer_object->tex;
+			normal_tex = p_spine_renderer_object->normal_tex;
+
+			v_num = 4;
+			vertices.setSize(v_num * VERTEX_STRIDE, 0);
+
+			region_attachment->computeWorldVertices(slot->getBone(), vertices, 0);
+
+			TEMP_COPY(uvs, region_attachment->getUVs());
+
+			indices.setSize(sizeof(quad_indices) / sizeof(unsigned short), 0);
+			for (size_t j = 0, qn = indices.size();j<qn;++j) {
+				indices[j] = quad_indices[j];
+			}
+
+			auto attachment_color = region_attachment->getColor();
+			tint.r *= attachment_color.r;
+			tint.g *= attachment_color.g;
+			tint.b *= attachment_color.b;
+			tint.a *= attachment_color.a;
+		}else if(attachment->getRTTI().isExactly(spine::MeshAttachment::rtti)) {
+			spine::MeshAttachment *mesh = (spine::MeshAttachment*) attachment;
+
+			auto p_spine_renderer_object = (SpineRendererObject*) ((spine::AtlasRegion*)mesh->getRendererObject())->page->getRendererObject();
+			tex = p_spine_renderer_object->tex;
+			normal_tex = p_spine_renderer_object->normal_tex;
+
+			v_num = mesh->getWorldVerticesLength()/VERTEX_STRIDE;
+			vertices.setSize(mesh->getWorldVerticesLength(), 0);
+
+			mesh->computeWorldVertices(*slot, vertices);
+
+//			uvs = mesh->getUVs();
+//			indices = mesh->getTriangles();
+			TEMP_COPY(uvs, mesh->getUVs());
+			TEMP_COPY(indices, mesh->getTriangles());
+
+			auto attachment_color = mesh->getColor();
+			tint.r *= attachment_color.r;
+			tint.g *= attachment_color.g;
+			tint.b *= attachment_color.b;
+			tint.a *= attachment_color.a;
+		} else if (attachment->getRTTI().isExactly(spine::ClippingAttachment::rtti)) {
+			auto clip = (spine::ClippingAttachment *) attachment;
+			skeleton_clipper->clipStart(*slot, clip);
+			continue;
+		} else {
+			skeleton_clipper->clipEnd(*slot);
+			continue;
+		}
+
+		auto mesh_ins = mesh_instances[i];
+		VisualServer::get_singleton()->canvas_item_clear(mesh_ins->get_canvas_item());	
+
+		if (skeleton_clipper->isClipping()) {
+			skeleton_clipper->clipTriangles(vertices, indices, uvs, VERTEX_STRIDE);
+
+			if (skeleton_clipper->getClippedTriangles().size() == 0) {
+				skeleton_clipper->clipEnd(*slot);
+				continue;
+			}
+
+			auto &clipped_vertices = skeleton_clipper->getClippedVertices();
+			v_num = clipped_vertices.size()/VERTEX_STRIDE;
+			auto &clipped_uvs = skeleton_clipper->getClippedUVs();
+			auto &clipped_indices = skeleton_clipper->getClippedTriangles();
+
+			if (indices.size() > 0) {
+				Vector<Vector2> p_points, p_uvs;
+				Vector<Color> p_colors;
+				Vector<int> p_indices;
+				p_points.resize(v_num);
+				p_uvs.resize(v_num);
+				p_colors.resize(v_num);
+				for (size_t j = 0; j < v_num; j++) {
+					p_points.set(j, Vector2(clipped_vertices[j*VERTEX_STRIDE], -clipped_vertices[j*VERTEX_STRIDE+1]));
+					p_uvs.set(j, Vector2(clipped_uvs[j*VERTEX_STRIDE], clipped_uvs[j*VERTEX_STRIDE+1]));
+					p_colors.set(j, Color(tint.r, tint.g, tint.b, tint.a));
+				}
+				p_indices.resize(clipped_indices.size());
+				for (size_t j = 0; j < clipped_indices.size(); ++j) {
+					p_indices.set(j, clipped_indices[j]);
+				}
+
+				VisualServer::get_singleton()->canvas_item_add_triangle_array(mesh_ins->get_canvas_item(),
+																			  p_indices,
+																			  p_points,
+																			  p_colors,
+																			  p_uvs,
+																			  Vector<int>(),
+																			  Vector<float>(),
+																			  tex.is_null() ? RID() : tex->get_rid(),
+																			  -1,
+																			  normal_tex.is_null() ? RID() : normal_tex->get_rid());
+			}
+		}else {
+			if (indices.size() > 0) {
+				Vector<Vector2> p_points, p_uvs;
+				Vector<Color> p_colors;
+				Vector<int> p_indices;
+				p_points.resize(v_num);
+				p_uvs.resize(v_num);
+				p_colors.resize(v_num);
+				for (size_t j = 0; j < v_num; j++) {
+					p_points.set(j, Vector2(vertices[j*VERTEX_STRIDE], -vertices[j*VERTEX_STRIDE+1]));
+					p_uvs.set(j, Vector2(uvs[j*VERTEX_STRIDE], uvs[j*VERTEX_STRIDE+1]));
+					p_colors.set(j, Color(tint.r, tint.g, tint.b, tint.a));
+				}
+				p_indices.resize(indices.size());
+				for (size_t j = 0; j < indices.size(); ++j) {
+					p_indices.set(j, indices[j]);
+				}
+
+				VisualServer::get_singleton()->canvas_item_add_triangle_array(mesh_ins->get_canvas_item(),
+																			  p_indices,
+																			  p_points,
+																			  p_colors,
+																			  p_uvs,
+																			  Vector<int>(),
+																			  Vector<float>(),
+																			  tex.is_null() ? RID() : tex->get_rid(),
+																			  -1,
+																			  normal_tex.is_null() ? RID() : normal_tex->get_rid());
+			}
+		}
+		skeleton_clipper->clipEnd(*slot);
+
+		if (mesh_ins->get_material()->is_class("CanvasItemMaterial")){
+			Ref<CanvasItemMaterial> mat = mesh_ins->get_material();
+			CanvasItemMaterial::BlendMode blend_mode;
+			switch (slot->getData().getBlendMode()) {
+				case spine::BlendMode_Normal:
+					blend_mode = CanvasItemMaterial::BLEND_MODE_MIX;
+					break;
+				case spine::BlendMode_Additive:
+					blend_mode = CanvasItemMaterial::BLEND_MODE_ADD;
+					break;
+				case spine::BlendMode_Multiply:
+					blend_mode = CanvasItemMaterial::BLEND_MODE_MUL;
+					break;
+				case spine::BlendMode_Screen:
+					blend_mode = CanvasItemMaterial::BLEND_MODE_MIX;
+					break;
+				default:
+					blend_mode = CanvasItemMaterial::BLEND_MODE_MIX;
+			}		
+			mat->set_blend_mode(blend_mode);
+		}
+	}
+	skeleton_clipper->clipEnd();
+}
+
+void SpineSprite::callback(spine::AnimationState *state, spine::EventType type, spine::TrackEntry *entry, spine::Event *event) {
+	Ref<SpineTrackEntry> gd_entry(NULL);
+	Ref<SpineEvent> gd_event(NULL);
+
+	if(entry){
+		gd_entry = Ref<SpineTrackEntry>(memnew(SpineTrackEntry));
+		gd_entry->set_spine_object(entry);
+	}
+	if(event){
+		gd_event = Ref<SpineEvent>(memnew(SpineEvent));
+		gd_event->set_spine_object(event);
+	}
+
+	switch (type) {
+		case spine::EventType_Start:
+		{
+			emit_signal("animation_start", animation_state, gd_entry, gd_event);
+		}break;
+		case spine::EventType_Interrupt:
+		{
+			emit_signal("animation_interrupt", animation_state, gd_entry, gd_event);
+		}break;
+		case spine::EventType_End:
+		{
+			emit_signal("animation_end", animation_state, gd_entry, gd_event);
+		}break;
+		case spine::EventType_Complete:
+		{
+			emit_signal("animation_complete", animation_state, gd_entry, gd_event);
+		}break;
+		case spine::EventType_Dispose:
+		{
+			emit_signal("animation_dispose", animation_state, gd_entry, gd_event);
+		}break;
+		case spine::EventType_Event:
+		{
+			emit_signal("animation_event", animation_state, gd_entry, gd_event);
+		}break;
+	}
+}
+
+// External feature functions
+Array SpineSprite::get_current_animations() {
+	return current_animations.duplicate(true);
+}
+void SpineSprite::set_current_animations(Array as) {
+	current_animations = as.duplicate(true);
+
+	// validate it then play the animations
+	_validate_and_play_current_animations();
+}
+
+int SpineSprite::get_select_track_id(){
+	return select_track_id;
+}
+void SpineSprite::set_select_track_id(int v){
+	select_track_id = v;
+
+	if(select_track_id < 0) select_track_id = 0;
+}
+
+bool SpineSprite::get_clear_track(){
+	return false;
+}
+void SpineSprite::set_clear_track(bool v){
+	if(v && animation_state.is_valid() && skeleton.is_valid())
+		animation_state->clear_track(select_track_id);
+}
+
+bool SpineSprite::get_clear_tracks(){
+	return false;
+}
+void SpineSprite::set_clear_tracks(bool v){
+	if(v && animation_state.is_valid() && skeleton.is_valid())
+		animation_state->clear_tracks();
+}
+
+float SpineSprite::get_empty_animation_duration(){
+	return empty_animation_duration;
+}
+void SpineSprite::set_empty_animation_duration(float v){
+	empty_animation_duration = v;
+}
+
+bool SpineSprite::get_set_empty_animation(){
+	return false;
+}
+void SpineSprite::set_set_empty_animation(bool v){
+	if(v && animation_state.is_valid() && skeleton.is_valid())
+		animation_state->set_empty_animation(select_track_id, empty_animation_duration);
+}
+
+bool SpineSprite::get_set_empty_animations(){
+	return false;
+}
+void SpineSprite::set_set_empty_animations(bool v){
+	if(v && animation_state.is_valid() && skeleton.is_valid())
+		animation_state->set_empty_animations(empty_animation_duration);
+}
+
+Array SpineSprite::get_bind_slot_nodes(){
+	return bind_slot_nodes;
+}
+void SpineSprite::set_bind_slot_nodes(Array v) {
+	bind_slot_nodes = v;
+}
+
+bool SpineSprite::get_overlap(){
+	return overlap;
+}
+void SpineSprite::set_overlap(bool v){
+	overlap = v;
+}
+
+void SpineSprite::set_skin(Ref<PackedSpineSkinResource> v)
+{
+	if(v != skin && skin.is_valid()){
+		if(skin->is_connected("property_changed", this, "_on_skin_property_changed"))
+			skin->disconnect("property_changed", this, "_on_skin_property_changed");
+	}
+
+	skin = v;
+
+	if(skin.is_valid()){
+		if(!skin->is_connected("property_changed", this, "_on_skin_property_changed"))
+			skin->connect("property_changed", this, "_on_skin_property_changed");
+		update_runtime_skin();
+	}
+}
+Ref<PackedSpineSkinResource> SpineSprite::get_skin(){
+	return skin;
+}
+void SpineSprite::update_runtime_skin(){
+	auto new_skin = gen_spine_skin_from_packed_resource(skin);
+
+	if(new_skin.is_valid())
+	{
+		skeleton->set_skin(new_skin);
+		skeleton->set_to_setup_pose();
+	}
+}
+void SpineSprite::_on_skin_property_changed(){
+	update_runtime_skin();
+}
+
+Ref<SpineSkin> SpineSprite::gen_spine_skin_from_packed_resource(Ref<PackedSpineSkinResource> res){
+	if(!(animation_state.is_valid() && skeleton.is_valid()))
+		return NULL;
+	if(!res.is_valid())
+		return NULL;
+	if(res->get_skin_name().empty())
+		return NULL;
+	auto exist_skin = animation_state_data_res->get_skeleton()->find_skin(res->get_skin_name());
+	if(exist_skin.is_valid())
+	{
+		return exist_skin;
+	}
+
+	auto new_skin = Ref<SpineSkin>(memnew(SpineSkin))->init(res->get_skin_name());
+	auto sub_skin_names = res->get_sub_skin_names();
+	for(size_t i=0;i<sub_skin_names.size();++i)
+	{
+		auto skin_name = (String)sub_skin_names[i];
+		auto sub_skin = animation_state_data_res->get_skeleton()->find_skin(skin_name);
+		if(sub_skin.is_valid())
+			new_skin->add_skin(sub_skin);
+	}
+	return new_skin;
+}
+
+void SpineSprite::bind_slot_with_node_2d(const String &slot_name, Node2D *n){
+	auto node_path = n->get_path_to(this);
+
+	// check if has the same binding
+	for(size_t i=0, size=bind_slot_nodes.size(); i<size; ++i){
+		auto a = bind_slot_nodes[i];
+		if(a.get_type() == Variant::DICTIONARY){
+			auto d = (Dictionary) a;
+			if(d.has("slot_name") && d.has("node_path")){
+				if(slot_name == d["slot_name"] && node_path == d["node_path"]){
+					return;
+				}
+			}
+		}else if(a.get_type() == Variant::ARRAY){
+			auto as = (Array) a;
+			if(as.size() >= 2 && as[0].get_type() == Variant::STRING && as[1].get_type() == Variant::NODE_PATH){
+				if(slot_name == as[0] && node_path == as[1]){
+					return;
+				}
+			}
+		}
+	}
+
+	Array bound;
+	bound.resize(2);
+	bound[0] = slot_name;
+	bound[1] = node_path;
+
+	bind_slot_nodes.append(bound);
+}
+void SpineSprite::unbind_slot_with_node_2d(const String &slot_name, Node2D *n){
+	auto node_path = n->get_path_to(this);
+
+	for(size_t i=0, size=bind_slot_nodes.size(); i<size; ++i){
+		auto a = bind_slot_nodes[i];
+		if(a.get_type() == Variant::DICTIONARY){
+			auto d = (Dictionary) a;
+			if(d.has("slot_name") && d.has("node_path")){
+				if(slot_name == d["slot_name"] && node_path == d["node_path"]){
+					bind_slot_nodes.remove(i);
+					return;
+				}
+			}
+		}else if(a.get_type() == Variant::ARRAY){
+			auto as = (Array) a;
+			if(as.size() >= 2 && as[0].get_type() == Variant::STRING && as[1].get_type() == Variant::NODE_PATH){
+				if(slot_name == as[0] && node_path == as[1]){
+					bind_slot_nodes.remove(i);
+					return;
+				}
+			}
+		}
+	}
+}
+
+Transform2D SpineSprite::bone_get_global_transform(const String &bone_name) {
+    if (!animation_state.is_valid() && !skeleton.is_valid()) {
+        return get_global_transform();
+    }
+    auto bone = skeleton->find_bone(bone_name);
+    if (!bone.is_valid()) {
+        print_error(vformat("Bone: '%s' not found.", bone_name));
+        return get_global_transform();
+    }
+    return bone->get_godot_global_transform();
+}
+
+void SpineSprite::bone_set_global_transform(const String &bone_name, Transform2D transform) {
+    if (!animation_state.is_valid() && !skeleton.is_valid()) {
+        return;
+    }
+    auto bone = skeleton->find_bone(bone_name);
+    if (!bone.is_valid()) {
+        return;
+    }
+    bone->set_godot_global_transform(transform);
+}
+
+SpineSprite::ProcessMode SpineSprite::get_process_mode() {
+    return process_mode;
+}
+
+void SpineSprite::set_process_mode(SpineSprite::ProcessMode v) {
+    process_mode = v;
+    set_process_internal(process_mode == ProcessMode_Process);
+    set_physics_process_internal(process_mode == ProcessMode_Physics);
+}
+
+void SpineSprite::_get_property_list(List<PropertyInfo> *p_list) const {
+    p_list->push_back(PropertyInfo(Variant::NIL, "Current Animation Editor", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CATEGORY));
+    p_list->push_back(PropertyInfo(Variant::BOOL, "setup_pose_trigger", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+    p_list->push_back(PropertyInfo(Variant::BOOL, "clear_tracks_trigger", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+    p_list->push_back(PropertyInfo(Variant::BOOL, "set_empty_animations_trigger", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+    p_list->push_back(PropertyInfo(Variant::REAL, "empty_animation_duration"));
+    p_list->push_back(PropertyInfo(Variant::INT, "track_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+
+    for (size_t i=0; i<current_animations.size(); ++i) {
+        String prefix = vformat("ca/%d/", (unsigned int)i);
+        p_list->push_back(PropertyInfo(Variant::NIL, vformat("ID %d", (unsigned int)i), PROPERTY_HINT_NONE, prefix, PROPERTY_USAGE_GROUP));
+        p_list->push_back(PropertyInfo(Variant::INT, vformat("%strack_id", prefix), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+
+        Vector<String> anim_list;
+        if (skeleton.is_valid() && skeleton->get_data().is_valid()) {
+            skeleton->get_data()->get_animation_names(anim_list);
+        }
+        if (anim_list.empty()) anim_list.push_back("No Animation");
+        p_list->push_back(PropertyInfo(Variant::STRING, vformat("%sanimation", prefix), PROPERTY_HINT_ENUM, String(",").join(anim_list), PROPERTY_USAGE_EDITOR));
+
+        p_list->push_back(PropertyInfo(Variant::REAL, vformat("%sdelay", prefix), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+
+        p_list->push_back(PropertyInfo(Variant::BOOL, vformat("%sloop", prefix), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+
+        p_list->push_back(PropertyInfo(Variant::BOOL, vformat("%sempty", prefix), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+        p_list->push_back(PropertyInfo(Variant::REAL, vformat("%sempty_animation_duration", prefix), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+
+        p_list->push_back(PropertyInfo(Variant::BOOL, vformat("%sclear", prefix), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
+    }
+}
+
+bool SpineSprite::_get(const StringName &p_property, Variant &r_value) const {
+    if (p_property == "setup_pose_trigger" || p_property == "clear_tracks_trigger" || p_property == "set_empty_animations_trigger") {
+        r_value = false;
+        return true;
+    }
+    if (p_property == "empty_animation_duration") {
+        r_value = empty_animation_duration;
+        return true;
+    }
+    if (p_property == "track_count") {
+        r_value = get_current_animation_count();
+        return true;
+    }
+    String p = p_property;
+    if (p.size() > 2 && p[0] == 'c' && p[1] == 'a' && p[2] == '/') {
+        Vector<String> sp = p.split("/");
+        if (sp.size() > 2) {
+            int64_t id = sp[1].to_int64();
+            if (id >= 0 && id < current_animations.size()) {
+                auto &key = sp[2];
+                if (current_animations[id].get_type() == Variant::DICTIONARY) {
+                    Dictionary dic = current_animations.get(id);
+                    if (dic.has(key)) {
+                        r_value = dic[key];
+                    } else {
+                        if (key == "track_id") r_value = 0;
+                        else if (key == "animation") r_value = "";
+                        else if (key == "loop") r_value = true;
+                        else if (key == "empty") r_value = false;
+                        else if (key == "empty_animation_duration") r_value = 0.3;
+                        else if (key == "clear") r_value = false;
+                        else if (key == "delay") r_value = 0;
+                        else return false;
+                    }
+                    return true;
+                }
+            }
+        }
+    }
+    return false;
+}
+
+bool SpineSprite::_set(const StringName &p_property, const Variant &p_value) {
+    if (p_property == "setup_pose_trigger") {
+        if (p_value) {
+            if (skeleton.is_valid()) {
+                skeleton->set_bones_to_setup_pose();
+                skeleton->set_slots_to_setup_pose();
+            }
+        }
+        return true;
+    }
+    if (p_property == "clear_tracks_trigger") {
+        if (p_value) {
+            if (animation_state.is_valid() && skeleton.is_valid()) {
+                animation_state->clear_tracks();
+            }
+        }
+        return true;
+    }
+    if (p_property == "set_empty_animations_trigger") {
+        if (p_value) {
+            if (animation_state.is_valid() && skeleton.is_valid()) {
+                animation_state->set_empty_animations(empty_animation_duration);
+            }
+        }
+        return true;
+    }
+    if (p_property == "empty_animation_duration") {
+        empty_animation_duration = p_value;
+        return true;
+    }
+    if (p_property == "track_count") {
+        set_current_animation_count(p_value);
+        return true;
+    }
+    String p = p_property;
+    if (p.size() > 2 && p[0] == 'c' && p[1] == 'a' && p[2] == '/') {
+        Vector<String> sp = p.split("/");
+        if (sp.size() > 2) {
+            int64_t id = sp[1].to_int64();
+            if (id >= 0 && id < current_animations.size()) {
+                auto &key = sp[2];
+                if (current_animations[id].get_type() != Variant::DICTIONARY) {
+                    current_animations.set(id, Dictionary());
+                }
+
+                Dictionary dic = current_animations.get(id);
+                dic[key] = p_value;
+
+                _validate_and_play_current_animations();
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+int64_t SpineSprite::get_current_animation_count() const {
+    return current_animations.size();
+}
+
+void SpineSprite::set_current_animation_count(int64_t v) {
+    if (v < 0) v = 0;
+    while (current_animations.size() < v) {
+        Dictionary d;
+        d["track_id"] = current_animations.size();
+        d["animation"] = "";
+        d["delay"] = 0;
+        d["loop"] = true;
+        d["empty"] = false;
+        d["empty_animation_duration"] = 0.3;
+        d["clear"] = false;
+        current_animations.push_back(d);
+    }
+    while (current_animations.size() > v) {
+        if (animation_state.is_valid() && skeleton.is_valid()) {
+            if (current_animations.back().get_type() == Variant::DICTIONARY) {
+                Dictionary back = current_animations.back();
+                if (back.has("track_id")) {
+                    int64_t track_id = back["track_id"];
+                    int track_cnt = 0;
+                    for (size_t i=0; i<current_animations.size(); ++i) {
+                        if (current_animations[i].get_type() == Variant::DICTIONARY) {
+                            Dictionary d = current_animations[i];
+                            if (d.has("track_id") && track_id == (int64_t)d["track_id"]) {
+                                track_cnt += 1;
+                            }
+                        }
+                    }
+                    if (track_cnt == 0)
+                        animation_state->clear_track(track_id);
+                }
+            }
+        }
+        current_animations.pop_back();
+    }
+    property_list_changed_notify();
+}
+
+void SpineSprite::_validate_and_play_current_animations() {
+    if(animation_state.is_valid() && skeleton.is_valid()){
+        int64_t track_cnt = 0;
+        HashMap<int64_t, bool> has_track;
+        for(size_t i=0; i<current_animations.size(); ++i) {
+            auto a = current_animations[i];
+            if(a.get_type() == Variant::DICTIONARY){
+                Dictionary d = a;
+
+                int64_t track_id = 0;
+                String animation = "";
+                float delay = 0;
+                bool loop = true;
+                bool empty = false;
+                float empty_animation_duration = 0.3;
+                bool clear = false;
+
+                if (d.has("track_id")) track_id = d["track_id"];
+                if (d.has("animation")) animation = d["animation"];
+                if (d.has("delay")) delay = d["delay"];
+                if (d.has("loop")) loop = d["loop"];
+                if (d.has("empty")) empty = d["empty"];
+                if (d.has("empty_animation_duration")) empty_animation_duration = d["empty_animation_duration"];
+                if (d.has("clear")) clear = d["clear"];
+
+                if (track_id < 0) {
+                    print_line(vformat("track_id at 'ID %d'  can not be less than 0!", (unsigned int)i));
+                    continue;
+                }
+
+                track_cnt += 1;
+
+
+                if (empty) {
+                    if (has_track.has(track_id))
+                        animation_state->add_empty_animation(track_id, empty_animation_duration, delay);
+                    else
+                        animation_state->set_empty_animation(track_id, empty_animation_duration);
+                    has_track[track_id] = true;
+                } else if (clear) {
+                    animation_state->clear_track(track_id);
+                } else if (skeleton->get_data()->find_animation(animation).is_valid()) {
+                    if (has_track.has(track_id))
+                        animation_state->add_animation(animation, delay, loop, track_id);
+                    else
+                        animation_state->set_animation(animation, loop, track_id);
+                    has_track[track_id] = true;
+                }
+
+            }
+        }
+
+        if (track_cnt == 0) animation_state->clear_tracks();
+    }
+}
+
+
+

+ 162 - 0
spine-godot/spine_godot/SpineSprite.h

@@ -0,0 +1,162 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINESPRITE_H
+#define GODOT_SPINESPRITE_H
+
+#include <scene/resources/texture.h>
+
+#include <scene/2d/collision_polygon_2d.h>
+
+#include "SpineAnimationStateDataResource.h"
+#include "SpineSkeleton.h"
+#include "SpineAnimationState.h"
+#include "SpineSpriteMeshInstance2D.h"
+#include "PackedSpineSkinResource.h"
+
+class SpineSprite : public Node2D, public spine::AnimationStateListenerObject {
+    GDCLASS(SpineSprite, Node2D);
+protected:
+    static void _bind_methods();
+
+	void _notification(int p_what);
+
+    void _get_property_list(List<PropertyInfo> *p_list) const;
+    bool _get(const StringName &p_property, Variant &r_value) const;
+    bool _set(const StringName &p_property, const Variant &p_value);
+
+    void _validate_and_play_current_animations();
+public:
+    enum ProcessMode {
+        ProcessMode_Process,
+        ProcessMode_Physics,
+        ProcessMode_Manual
+    };
+private:
+
+    Ref<SpineAnimationStateDataResource> animation_state_data_res;
+
+	Ref<SpineSkeleton> skeleton;
+	Ref<SpineAnimationState> animation_state;
+
+	Vector<SpineSpriteMeshInstance2D*> mesh_instances;
+
+	Array current_animations;
+	int select_track_id;
+	float empty_animation_duration;
+
+	Array bind_slot_nodes;
+	bool overlap;
+	Ref<PackedSpineSkinResource> skin;
+
+    ProcessMode process_mode;
+
+	spine::SkeletonClipping *skeleton_clipper;
+
+public:
+	SpineSprite();
+	~SpineSprite();
+
+    void set_animation_state_data_res(const Ref<SpineAnimationStateDataResource> &a);
+    Ref<SpineAnimationStateDataResource> get_animation_state_data_res();
+
+	Ref<SpineSkeleton> get_skeleton();
+	Ref<SpineAnimationState> get_animation_state();
+
+	void gen_mesh_from_skeleton(Ref<SpineSkeleton> s);
+	void remove_mesh_instances();
+	void remove_redundant_mesh_instances();
+
+	void update_mesh_from_skeleton(Ref<SpineSkeleton> s);
+
+	void update_bind_slot_nodes();
+	void update_bind_slot_node_transform(Ref<SpineBone> bone, Node2D *node2d);
+	void update_bind_slot_node_draw_order(const String &slot_name, Node2D *node2d);
+	Node *find_child_node_by_node(Node *node);
+
+	virtual void callback(spine::AnimationState* state, spine::EventType type, spine::TrackEntry* entry, spine::Event* event);
+
+	void _on_animation_data_created();
+	void _on_animation_data_changed();
+
+	void _update_all(float delta);
+
+	// External feature functions
+	Array get_current_animations();
+	void set_current_animations(Array as);
+
+	int get_select_track_id();
+	void set_select_track_id(int v);
+
+	bool get_clear_track();
+	void set_clear_track(bool v);
+
+	bool get_clear_tracks();
+	void set_clear_tracks(bool v);
+
+	float get_empty_animation_duration();
+	void set_empty_animation_duration(float v);
+
+	bool get_set_empty_animation();
+	void set_set_empty_animation(bool v);
+
+	bool get_set_empty_animations();
+	void set_set_empty_animations(bool v);
+
+	Array get_bind_slot_nodes();
+	void set_bind_slot_nodes(Array v);
+
+	void bind_slot_with_node_2d(const String &slot_name, Node2D *n);
+	void unbind_slot_with_node_2d(const String &slot_name, Node2D *n);
+
+	// bone manipulations
+	Transform2D bone_get_global_transform(const String &bone_name);
+	void bone_set_global_transform(const String &bone_name, Transform2D transform);
+
+	//allow z-manipulation
+	bool get_overlap();
+	void set_overlap(bool v);
+
+	void set_skin(Ref<PackedSpineSkinResource> v);
+	Ref<PackedSpineSkinResource> get_skin();
+	void _on_skin_property_changed();
+	void update_runtime_skin();
+
+	Ref<SpineSkin> gen_spine_skin_from_packed_resource(Ref<PackedSpineSkinResource> res);
+
+    // current animation count
+    int64_t get_current_animation_count() const;
+    void set_current_animation_count(int64_t v);
+
+	ProcessMode get_process_mode();
+	void set_process_mode(ProcessMode v);
+};
+
+VARIANT_ENUM_CAST(SpineSprite::ProcessMode);
+#endif //GODOT_SPINESPRITE_H

+ 350 - 0
spine-godot/spine_godot/SpineSpriteAnimateDialog.cpp

@@ -0,0 +1,350 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineSpriteAnimateDialog.h"
+
+#ifdef TOOLS_ENABLED
+
+#include "SpineSprite.h"
+
+void SpineSpriteAnimateDialog::_bind_methods() {
+    ClassDB::bind_method(D_METHOD("_on_animate_button_pressed"), &SpineSpriteAnimateDialog::_on_animate_button_pressed);
+    ClassDB::bind_method(D_METHOD("_on_scene_tree_selected"), &SpineSpriteAnimateDialog::_on_scene_tree_selected);
+    ClassDB::bind_method(D_METHOD("_on_scene_tree_hide"), &SpineSpriteAnimateDialog::_on_scene_tree_hide);
+    ClassDB::bind_method(D_METHOD("_on_animate_dialog_action"), &SpineSpriteAnimateDialog::_on_animate_dialog_action);
+}
+
+SpineSpriteAnimateDialog::SpineSpriteAnimateDialog() {
+    animate_dialog = memnew(ConfirmationDialog);
+    add_child(animate_dialog);
+    animate_dialog->get_ok()->set_text("Generate");
+    animate_dialog_override_button = animate_dialog->add_button("Override", false, "override");
+    animate_dialog_override_button->set_visible(false);
+    animate_dialog->set_title("Animations Generator");
+    animate_dialog->set_resizable(true);
+    animate_dialog->set_custom_minimum_size(Vector2(550, 400));
+    animate_dialog->set_hide_on_ok(false);
+    animate_dialog->connect("custom_action", this, "_on_animate_dialog_action");
+    Vector<Variant> al;
+    al.push_back("confirmed");
+    animate_dialog->connect("confirmed", this, "_on_animate_dialog_action", al);
+
+    auto vb = memnew(VBoxContainer);
+    animate_dialog->add_child(vb);
+
+    auto scroll = memnew(ScrollContainer);
+    scroll->set_h_size_flags(SIZE_EXPAND_FILL);
+    scroll->set_v_size_flags(SIZE_EXPAND_FILL);
+//    vb->add_margin_child("Animations", scroll);
+    vb->add_child(scroll);
+
+    animate_dialog_tree = memnew(Tree);
+    animate_dialog_tree->set_h_size_flags(SIZE_EXPAND_FILL);
+    animate_dialog_tree->set_v_size_flags(SIZE_EXPAND_FILL);
+    scroll->add_child(animate_dialog_tree);
+
+    animate_dialog_tree->set_columns(3);
+    animate_dialog_tree->set_column_titles_visible(true);
+    animate_dialog_tree->set_hide_folding(true);
+    animate_dialog_tree->set_hide_root(true);
+
+    animate_dialog_tree->set_column_title(0, TTR("Animation"));
+    animate_dialog_tree->set_column_title(1, TTR("Loop"));
+    animate_dialog_tree->set_column_title(2, TTR("Track ID"));
+
+    animate_dialog_tree->create_item();
+    add_row("test1");
+    add_row("test12");
+    add_row("test13");
+
+    auto l = memnew(Label);
+    l->set_text("W.I.P");
+    vb->add_child(l);
+
+    scene_tree_dialog = memnew(SceneTreeDialog);
+    scene_tree_dialog->set_title("Choose a AnimationPlayer to override, or choose none to create a new one.");
+    Vector<StringName> valid_types;
+    valid_types.push_back("AnimationPlayer");
+    scene_tree_dialog->get_scene_tree()->set_valid_types(valid_types);
+    scene_tree_dialog->get_scene_tree()->set_show_enabled_subscene(true);
+    scene_tree_dialog->get_ok()->hide();
+    add_child(scene_tree_dialog);
+    scene_tree_dialog->connect("selected", this, "_on_scene_tree_selected");
+    scene_tree_dialog->connect("popup_hide", this, "_on_scene_tree_hide");
+
+    error_dialog = memnew(AcceptDialog);
+    add_child(error_dialog);
+}
+
+SpineSpriteAnimateDialog::~SpineSpriteAnimateDialog() {
+
+}
+
+void SpineSpriteAnimateDialog::set_animate_button(ToolButton *b) {
+    animate_button = b;
+    animate_button->connect("pressed", this, "_on_animate_button_pressed");
+}
+
+void SpineSpriteAnimateDialog::add_row(const String &animation, bool loop, int64_t track_id) {
+    auto item = animate_dialog_tree->create_item();
+    item->set_text(0, animation);
+
+    item->set_cell_mode(1, TreeItem::CELL_MODE_CHECK);
+    item->set_checked(1, loop);
+    item->set_editable(1, true);
+
+    item->set_cell_mode(2, TreeItem::CELL_MODE_RANGE);
+    item->set_range(2, track_id);
+    item->set_editable(2, true);
+}
+
+void SpineSpriteAnimateDialog::clear_tree() {
+    animate_dialog_tree->clear();
+    animate_dialog_tree->create_item();
+}
+
+void SpineSpriteAnimateDialog::error(const String &text, const String &title) {
+    error_dialog->set_text(text);
+    error_dialog->set_title(title);
+    error_dialog->popup_centered();
+}
+
+#define ERROR_MSG(x) do{error(x);err=true;return;}while(false)
+void SpineSpriteAnimateDialog::load_data_from_sprite(SpineSprite *sprite, bool &err) {
+    if (sprite == nullptr) {
+        ERROR_MSG("The sprite is null.");
+    }
+    if (!sprite->get_animation_state().is_valid() || !sprite->get_skeleton().is_valid()) {
+        ERROR_MSG("The sprite is not loaded.");
+    }
+    clear_tree();
+
+    Vector<String> animations;
+    sprite->get_skeleton()->get_data()->get_animation_names(animations);
+
+    for (size_t i=0; i<animations.size(); ++i) {
+        add_row(animations[i]);
+    }
+
+    err = false;
+}
+
+#define MIN_TRACK_LENGTH 0.15
+
+void SpineSpriteAnimateDialog::gen_new_animation_player(SpineSprite *sprite, bool &err) {
+    if (sprite == nullptr) {
+        ERROR_MSG("The sprite player is null.");
+    }
+    if (!sprite->get_animation_state().is_valid() || !sprite->get_skeleton().is_valid()) {
+        ERROR_MSG("The sprite is not loaded.");
+    }
+    auto p = sprite->get_parent();
+    if (p == nullptr) {
+        p = sprite;
+    }
+
+    auto anim_player = memnew(AnimationPlayer);
+    anim_player->set_name("AnimationPlayer");
+    p->add_child(anim_player);
+    anim_player->set_owner(sprite->get_owner());
+    anim_player->set_root(anim_player->get_path_to(p));
+
+    gen_animations(sprite, anim_player, get_data_from_tree(), MIN_TRACK_LENGTH, err);
+}
+
+Dictionary SpineSpriteAnimateDialog::get_data_from_tree() {
+    Dictionary res;
+    if (animate_dialog_tree->get_root() == nullptr) return res;
+
+    auto item = animate_dialog_tree->get_root()->get_children();
+    while (item) {
+        Dictionary row;
+        row["loop"] = item->is_checked(1);
+        row["track_id"] = item->get_range(2);
+
+        res[item->get_text(0)] = row;
+        item = item->get_next();
+    }
+    return res;
+}
+
+void SpineSpriteAnimateDialog::gen_animations(SpineSprite *sprite, AnimationPlayer *anim_player, const Dictionary &config, float min_duration, bool &err) {
+    if (sprite == nullptr || anim_player == nullptr) {
+        ERROR_MSG("The sprite or animation player is null.");
+    }
+    if (!sprite->get_animation_state().is_valid() || !sprite->get_skeleton().is_valid()) {
+        ERROR_MSG("The sprite is not loaded.");
+    }
+    if (anim_player->get_node_or_null(anim_player->get_root()) == nullptr) {
+        ERROR_MSG("The root node of animation player is null.");
+    }
+
+    auto path_to_sprite = anim_player->get_node(anim_player->get_root())->get_path_to(sprite);
+
+    Array animations = sprite->get_skeleton()->get_data()->get_animations();
+    for (size_t i=0; i<animations.size(); ++i) {
+        auto spine_anim = (Ref<SpineAnimation>) animations[i];
+
+        Dictionary ca;
+        if (config.has(spine_anim->get_anim_name())) {
+            ca = config[spine_anim->get_anim_name()];
+        }
+
+        if (!ca.has("loop")) ca["loop"] = true;
+        if (!ca.has("track_id")) ca["track_id"] = 0;
+
+        Array key_frame_value;
+        key_frame_value.push_back(gen_current_animation_data(spine_anim->get_anim_name(), ca["track_id"], ca["loop"], false, false, 0.3, 0));
+
+        auto anim = Ref<Animation>(memnew(Animation));
+        auto track_index = anim->add_track(Animation::TYPE_VALUE);
+        anim->set_length(min_duration > spine_anim->get_duration() ? min_duration : spine_anim->get_duration());
+        anim->track_set_path(track_index, NodePath(vformat("%s:current_animations", path_to_sprite)));
+        anim->track_insert_key(track_index, 0.0, key_frame_value);
+        anim->value_track_set_update_mode(track_index, Animation::UPDATE_DISCRETE);
+
+        if (anim_player->has_animation(spine_anim->get_anim_name()))
+            anim_player->remove_animation(spine_anim->get_anim_name());
+        anim_player->add_animation(spine_anim->get_anim_name(), anim);
+    }
+
+    err = false;
+}
+
+Dictionary SpineSpriteAnimateDialog::gen_current_animation_data(const String &animation, int64_t track_id, bool loop, bool clear, bool empty, bool empty_duration, float delay) {
+    Dictionary res;
+    res["animation"] = animation;
+    res["track_id"] = track_id;
+    res["loop"] = loop;
+    res["clear"] = clear;
+    res["empty"] = empty;
+    res["empty_animation_duration"] = empty_duration;
+    res["delay"] = delay;
+    return res;
+}
+
+
+void SpineSpriteAnimateDialog::load_data_from_anim_player(AnimationPlayer *anim_player, bool &err) {
+    if (anim_player == nullptr) {
+        ERROR_MSG("The animation player is null.");
+    }
+    auto root = anim_player->get_node_or_null(anim_player->get_root());
+    if (root == nullptr) return;
+
+    auto sprite = get_node_or_null(spine_sprite_path);
+    if (sprite == nullptr) return;
+
+    auto item = animate_dialog_tree->get_root()->get_children();
+    while (item) {
+        String animation = item->get_text(0);
+
+        auto anim = anim_player->get_animation(animation);
+        if (anim.is_valid() && anim->get_track_count() > 0) {
+            if (anim->track_get_type(0) == Animation::TYPE_VALUE) {
+                auto track_path = anim->track_get_path(0);
+                if (root->get_node_or_null(track_path) == sprite) {
+                    if (anim->track_get_key_count(0) > 0) {
+                        Array key_frame_value = anim->track_get_key_value(0, 0);
+                        if (!key_frame_value.empty()) {
+                            Dictionary _ca = key_frame_value.front();
+                            if (_ca.has("loop")) item->set_checked(1, _ca["loop"]);
+                            if (_ca.has("track_id")) item->set_range(2, _ca["track_id"]);
+                        }
+                    }
+                }
+            }
+
+        }
+
+        item = item->get_next();
+    }
+
+    err = false;
+}
+
+//----- Signals -----
+void SpineSpriteAnimateDialog::_on_scene_tree_selected(NodePath path) {
+//    print_line(vformat("anime: %s", path));
+    auto node = get_node_or_null(path);
+    if (node == nullptr) {
+        error("The node you chose is null.");
+        return;
+    }
+    if (!node->is_class("AnimationPlayer")) {
+        error("The node you chose is not AnimationPlayer.");
+        return;
+    }
+    anim_player_path = path;
+}
+
+void SpineSpriteAnimateDialog::_on_animate_button_pressed() {
+    anim_player_path = String("");
+    auto node = (Node*)the_plugin->get_editor_interface()->get_selection()->get_selected_nodes().back();
+    spine_sprite_path = node->get_path();
+
+//    print_line(vformat("sp: %s", spine_sprite_path));
+
+    animate_dialog_override_button->set_visible(false);
+    scene_tree_dialog->popup_centered_ratio();
+}
+
+void SpineSpriteAnimateDialog::_on_scene_tree_hide() {
+    animate_dialog->popup_centered();
+
+    bool err = false;
+    load_data_from_sprite((SpineSprite*)get_node_or_null(spine_sprite_path), err);
+
+    if (err) animate_dialog->hide();
+
+    err = false;
+    auto node = get_node_or_null(anim_player_path);
+    if (node != nullptr) {
+        load_data_from_anim_player((AnimationPlayer*)node, err);
+        animate_dialog_override_button->set_visible(!err);
+    } else {
+        animate_dialog_override_button->set_visible(false);
+    }
+
+
+}
+
+void SpineSpriteAnimateDialog::_on_animate_dialog_action(const String &act) {
+    bool err = false;
+    if (act == "confirmed") {
+        gen_new_animation_player((SpineSprite*)get_node_or_null(spine_sprite_path), err);
+    } else if (act == "override") {
+        gen_animations((SpineSprite*)get_node_or_null(spine_sprite_path), (AnimationPlayer*)get_node_or_null(anim_player_path), get_data_from_tree(), MIN_TRACK_LENGTH, err);
+    }
+    if (!err) {
+        animate_dialog->hide();
+    }
+}
+
+
+#endif

+ 86 - 0
spine-godot/spine_godot/SpineSpriteAnimateDialog.h

@@ -0,0 +1,86 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINESPRITEANIMATEDIALOG_H
+#define GODOT_SPINESPRITEANIMATEDIALOG_H
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_node.h"
+
+class SpineSprite;
+
+class SpineSpriteAnimateDialog : public Control {
+    GDCLASS(SpineSpriteAnimateDialog, Control);
+
+protected:
+    static void _bind_methods();
+
+    AcceptDialog *error_dialog;
+
+    ToolButton *animate_button;
+    EditorPlugin *the_plugin;
+
+    ConfirmationDialog *animate_dialog;
+    Button *animate_dialog_override_button;
+    Tree *animate_dialog_tree;
+    SceneTreeDialog *scene_tree_dialog;
+
+    NodePath spine_sprite_path;
+    NodePath anim_player_path;
+
+    void add_row(const String &animation, bool loop=true, int64_t track_id=0);
+    void clear_tree();
+
+    void error(const String &text, const String &title="Error");
+
+    void load_data_from_sprite(SpineSprite *sprite, bool &err);
+    void load_data_from_anim_player(AnimationPlayer *anim_player, bool &err);
+
+    Dictionary get_data_from_tree();
+
+    void gen_new_animation_player(SpineSprite *sprite, bool &err);
+    void gen_animations(SpineSprite *sprite, AnimationPlayer *anim_player, const Dictionary &config, float min_duration, bool &err);
+    Dictionary gen_current_animation_data(const String &animation, int64_t track_id, bool loop, bool clear, bool empty, bool empty_duration, float delay);
+public:
+    SpineSpriteAnimateDialog();
+    ~SpineSpriteAnimateDialog();
+
+    void set_animate_button(ToolButton *b);
+    inline ToolButton *get_animate_button() {return animate_button;}
+
+    inline void set_plugin(EditorPlugin *p) {the_plugin = p;}
+
+    void _on_animate_button_pressed();
+    void _on_scene_tree_selected(NodePath path);
+    void _on_scene_tree_hide();
+    void _on_animate_dialog_action(const String &act);
+};
+#endif
+
+#endif //GODOT_SPINESPRITEANIMATEDIALOG_H

+ 48 - 0
spine-godot/spine_godot/SpineSpriteMeshInstance2D.cpp

@@ -0,0 +1,48 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineSpriteMeshInstance2D.h"
+
+#include "SpineBone.h"
+
+void SpineSpriteMeshInstance2D::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_slot"), &SpineSpriteMeshInstance2D::get_slot);
+	ClassDB::bind_method(D_METHOD("apply_transform_2d", "node2d"), &SpineSpriteMeshInstance2D::apply_transform_2d);
+}
+
+SpineSpriteMeshInstance2D::SpineSpriteMeshInstance2D() {}
+SpineSpriteMeshInstance2D::~SpineSpriteMeshInstance2D() {}
+
+Ref<SpineSlot> SpineSpriteMeshInstance2D::get_slot() {
+	return slot;
+}
+
+void SpineSpriteMeshInstance2D::apply_transform_2d(Variant o){
+	slot->get_bone()->apply_world_transform_2d(o);
+}

+ 56 - 0
spine-godot/spine_godot/SpineSpriteMeshInstance2D.h

@@ -0,0 +1,56 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINESPRITEMESHINSTANCE2D_H
+#define GODOT_SPINESPRITEMESHINSTANCE2D_H
+
+#include <scene/2d/mesh_instance_2d.h>
+
+#include "SpineSlot.h"
+
+class SpineSpriteMeshInstance2D : public MeshInstance2D {
+	GDCLASS(SpineSpriteMeshInstance2D, MeshInstance2D);
+
+protected:
+	static void _bind_methods();
+
+	Ref<SpineSlot> slot;
+public:
+	SpineSpriteMeshInstance2D();
+	~SpineSpriteMeshInstance2D();
+
+	inline void set_slot(Ref<SpineSlot> s){
+		slot = s;
+	}
+	Ref<SpineSlot> get_slot();
+
+	void apply_transform_2d(Variant o);
+};
+
+#endif //GODOT_SPINESPRITEMESHINSTANCE2D_H

+ 103 - 0
spine-godot/spine_godot/SpineTimeline.cpp

@@ -0,0 +1,103 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineTimeline.h"
+
+#include "SpineSkeleton.h"
+#include "SpineEvent.h"
+
+// enable more than 5 arguments of a method bind function
+#include "core/method_bind_ext.gen.inc"
+
+void SpineTimeline::_bind_methods() {
+    ClassDB::bind_method(D_METHOD("apply", "skeleton", "lastTime", "time", "pEvents", "alpha", "blend", "direction"), &SpineTimeline::apply);
+    ClassDB::bind_method(D_METHOD("get_frame_entries"), &SpineTimeline::get_frame_entries);
+    ClassDB::bind_method(D_METHOD("get_frame_count"), &SpineTimeline::get_frame_count);
+    ClassDB::bind_method(D_METHOD("get_frames"), &SpineTimeline::get_frames);
+    ClassDB::bind_method(D_METHOD("get_duration"), &SpineTimeline::get_duration);
+    ClassDB::bind_method(D_METHOD("getPropertyIds"), &SpineTimeline::getPropertyIds);
+}
+
+
+SpineTimeline::SpineTimeline():timeline(nullptr) {
+
+}
+
+SpineTimeline::~SpineTimeline() {
+
+}
+
+void SpineTimeline::apply(Ref<SpineSkeleton> skeleton, float lastTime, float time, Array pEvents, float alpha,
+                          SpineConstant::MixBlend blend, SpineConstant::MixDirection direction) {
+    spine::Vector<spine::Event*> events;
+    events.setSize(pEvents.size(), nullptr);
+    for (size_t i=0; i<events.size(); ++i) {
+        events[i] = ((Ref<SpineEvent>)pEvents[i])->get_spine_object();
+    }
+
+    timeline->apply(*(skeleton->get_spine_object()), lastTime, time, &events, alpha, (spine::MixBlend) blend, (spine::MixDirection) direction);
+}
+
+int64_t SpineTimeline::get_frame_entries() {
+    return timeline->getFrameEntries();
+}
+
+int64_t SpineTimeline::get_frame_count() {
+    return timeline->getFrameCount();
+}
+
+Array SpineTimeline::get_frames() {
+    auto &frames = timeline->getFrames();
+    Array res;
+    res.resize(frames.size());
+
+    for (size_t i=0; i<res.size(); ++i) {
+        res[i] = frames[i];
+    }
+
+    return res;
+}
+
+float SpineTimeline::get_duration() {
+    return timeline->getDuration();
+}
+
+Array SpineTimeline::getPropertyIds() {
+    auto &ids = timeline->getPropertyIds();
+    Array res;
+    res.resize(ids.size());
+
+    for (size_t i=0; i<res.size(); ++i) {
+        res[i] = ids[i];
+    }
+
+    return res;
+}
+
+

+ 72 - 0
spine-godot/spine_godot/SpineTimeline.h

@@ -0,0 +1,72 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINETIMELINE_H
+#define GODOT_SPINETIMELINE_H
+
+#include "core/variant_parser.h"
+
+#include "spine/Timeline.h"
+
+#include "SpineConstant.h"
+
+class SpineSkeleton;
+class SpineEvent;
+
+class SpineTimeline : public Reference{
+    GDCLASS(SpineTimeline, Reference);
+protected:
+    static void _bind_methods();
+private:
+    spine::Timeline *timeline;
+public:
+    SpineTimeline();
+    ~SpineTimeline();
+
+    inline void set_spine_object(spine::Timeline *v) {timeline = v;}
+    inline spine::Timeline *get_spine_object() {return timeline;}
+
+    // Vector<Event *>
+    void apply(Ref<SpineSkeleton> skeleton, float lastTime, float time, Array pEvents, float alpha, SpineConstant::MixBlend blend, SpineConstant::MixDirection direction);
+
+    int64_t get_frame_entries();
+
+    int64_t get_frame_count();
+
+    // Vector<float>
+    Array get_frames();
+
+    float get_duration();
+
+    // Vector <PropertyId>
+    Array getPropertyIds();
+};
+
+
+#endif //GODOT_SPINETIMELINE_H

+ 265 - 0
spine-godot/spine_godot/SpineTrackEntry.cpp

@@ -0,0 +1,265 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineTrackEntry.h"
+
+void SpineTrackEntry::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_track_index"), &SpineTrackEntry::get_track_index);
+
+	ClassDB::bind_method(D_METHOD("get_animation"), &SpineTrackEntry::get_animation);
+
+	ClassDB::bind_method(D_METHOD("get_loop"), &SpineTrackEntry::get_loop);
+	ClassDB::bind_method(D_METHOD("set_loop", "v"), &SpineTrackEntry::set_loop);
+
+	ClassDB::bind_method(D_METHOD("get_hold_previous"), &SpineTrackEntry::get_hold_previous);
+	ClassDB::bind_method(D_METHOD("set_hold_previous", "v"), &SpineTrackEntry::set_hold_previous);
+
+    ClassDB::bind_method(D_METHOD("get_reverse"), &SpineTrackEntry::get_reverse);
+    ClassDB::bind_method(D_METHOD("set_reverse", "v"), &SpineTrackEntry::set_reverse);
+
+	ClassDB::bind_method(D_METHOD("get_delay"), &SpineTrackEntry::get_delay);
+	ClassDB::bind_method(D_METHOD("set_delay", "v"), &SpineTrackEntry::set_delay);
+
+	ClassDB::bind_method(D_METHOD("get_track_time"), &SpineTrackEntry::get_track_time);
+	ClassDB::bind_method(D_METHOD("set_track_time", "v"), &SpineTrackEntry::set_track_time);
+
+	ClassDB::bind_method(D_METHOD("get_track_end"), &SpineTrackEntry::get_track_end);
+	ClassDB::bind_method(D_METHOD("set_track_end", "v"), &SpineTrackEntry::set_track_end);
+
+	ClassDB::bind_method(D_METHOD("get_animation_start"), &SpineTrackEntry::get_animation_start);
+	ClassDB::bind_method(D_METHOD("set_animation_start", "v"), &SpineTrackEntry::set_animation_start);
+
+	ClassDB::bind_method(D_METHOD("get_animation_last"), &SpineTrackEntry::get_animation_last);
+	ClassDB::bind_method(D_METHOD("set_animation_last", "v"), &SpineTrackEntry::set_animation_last);
+
+	ClassDB::bind_method(D_METHOD("get_animation_time"), &SpineTrackEntry::get_animation_time);
+
+	ClassDB::bind_method(D_METHOD("get_time_scale"), &SpineTrackEntry::get_time_scale);
+	ClassDB::bind_method(D_METHOD("set_time_scale", "v"), &SpineTrackEntry::set_time_scale);
+
+	ClassDB::bind_method(D_METHOD("get_alpha"), &SpineTrackEntry::get_alpha);
+	ClassDB::bind_method(D_METHOD("set_alpha", "v"), &SpineTrackEntry::set_alpha);
+
+	ClassDB::bind_method(D_METHOD("get_event_threshold"), &SpineTrackEntry::get_event_threshold);
+	ClassDB::bind_method(D_METHOD("set_event_threshold", "v"), &SpineTrackEntry::set_event_threshold);
+
+	ClassDB::bind_method(D_METHOD("get_attachment_threshold"), &SpineTrackEntry::get_attachment_threshold);
+	ClassDB::bind_method(D_METHOD("set_attachment_threshold", "v"), &SpineTrackEntry::set_attachment_threshold);
+
+	ClassDB::bind_method(D_METHOD("get_draw_order_threshold"), &SpineTrackEntry::get_draw_order_threshold);
+	ClassDB::bind_method(D_METHOD("set_draw_order_threshold", "v"), &SpineTrackEntry::set_draw_order_threshold);
+
+	ClassDB::bind_method(D_METHOD("get_next"), &SpineTrackEntry::get_next);
+
+	ClassDB::bind_method(D_METHOD("is_complete"), &SpineTrackEntry::is_complete);
+
+	ClassDB::bind_method(D_METHOD("get_mix_time"), &SpineTrackEntry::get_mix_time);
+	ClassDB::bind_method(D_METHOD("set_mix_time", "v"), &SpineTrackEntry::set_mix_time);
+
+	ClassDB::bind_method(D_METHOD("get_mix_duration"), &SpineTrackEntry::get_mix_duration);
+	ClassDB::bind_method(D_METHOD("set_mix_duration", "v"), &SpineTrackEntry::set_mix_duration);
+
+	ClassDB::bind_method(D_METHOD("get_mix_blend"), &SpineTrackEntry::get_mix_blend);
+	ClassDB::bind_method(D_METHOD("set_mix_blend", "v"), &SpineTrackEntry::set_mix_blend);
+
+	ClassDB::bind_method(D_METHOD("get_mixing_from"), &SpineTrackEntry::get_mixing_from);
+	ClassDB::bind_method(D_METHOD("get_mixing_to"), &SpineTrackEntry::get_mixing_to);
+
+	ClassDB::bind_method(D_METHOD("reset_rotation_directions"), &SpineTrackEntry::reset_rotation_directions);
+
+	BIND_ENUM_CONSTANT(MIXBLEND_SETUP);
+	BIND_ENUM_CONSTANT(MIXBLEND_FIRST);
+	BIND_ENUM_CONSTANT(MIXBLEND_REPLACE);
+	BIND_ENUM_CONSTANT(MIXBLEND_ADD);
+}
+
+SpineTrackEntry::SpineTrackEntry():track_entry(NULL) {}
+SpineTrackEntry::~SpineTrackEntry() {}
+
+int SpineTrackEntry::get_track_index(){
+	return track_entry->getTrackIndex();
+}
+
+Ref<SpineAnimation> SpineTrackEntry::get_animation(){
+	Ref<SpineAnimation> gd_anim(memnew(SpineAnimation));
+	auto anim = track_entry->getAnimation();
+	if(anim == NULL) return NULL;
+	gd_anim->set_spine_object(anim);
+	return gd_anim;
+}
+
+bool SpineTrackEntry::get_loop(){
+	return track_entry->getLoop();
+}
+void SpineTrackEntry::set_loop(bool v){
+	track_entry->setLoop(v);
+}
+
+bool SpineTrackEntry::get_hold_previous(){
+	return track_entry->getHoldPrevious();
+}
+void SpineTrackEntry::set_hold_previous(bool v){
+	track_entry->setHoldPrevious(v);
+}
+
+float SpineTrackEntry::get_delay(){
+	return track_entry->getDelay();
+}
+void SpineTrackEntry::set_delay(float v){
+	track_entry->setDelay(v);
+}
+
+float SpineTrackEntry::get_track_time(){
+	return track_entry->getTrackTime();
+}
+void SpineTrackEntry::set_track_time(float v){
+	track_entry->setTrackTime(v);
+}
+
+float SpineTrackEntry::get_track_end(){
+	return track_entry->getTrackEnd();
+}
+void SpineTrackEntry::set_track_end(float v){
+	track_entry->setTrackEnd(v);
+}
+
+float SpineTrackEntry::get_animation_start(){
+	return track_entry->getAnimationStart();
+}
+void SpineTrackEntry::set_animation_start(float v){
+	track_entry->setAnimationStart(v);
+}
+
+float SpineTrackEntry::get_animation_last(){
+	return track_entry->getAnimationLast();
+}
+void SpineTrackEntry::set_animation_last(float v){
+	track_entry->setAnimationLast(v);
+}
+
+float SpineTrackEntry::get_animation_time(){
+	return track_entry->getAnimationTime();
+}
+
+float SpineTrackEntry::get_time_scale(){
+	return track_entry->getTimeScale();
+}
+void SpineTrackEntry::set_time_scale(float v){
+	track_entry->setTimeScale(v);
+}
+
+float SpineTrackEntry::get_alpha(){
+	return track_entry->getAlpha();
+}
+void SpineTrackEntry::set_alpha(float v){
+	track_entry->setAlpha(v);
+}
+
+float SpineTrackEntry::get_event_threshold(){
+	return track_entry->getEventThreshold();
+}
+void SpineTrackEntry::set_event_threshold(float v){
+	track_entry->setEventThreshold(v);
+}
+
+float SpineTrackEntry::get_attachment_threshold(){
+	return track_entry->getAttachmentThreshold();
+}
+void SpineTrackEntry::set_attachment_threshold(float v){
+	track_entry->setAttachmentThreshold(v);
+}
+
+float SpineTrackEntry::get_draw_order_threshold(){
+	return track_entry->getDrawOrderThreshold();
+}
+void SpineTrackEntry::set_draw_order_threshold(float v){
+	track_entry->setDrawOrderThreshold(v);
+}
+
+Ref<SpineTrackEntry> SpineTrackEntry::get_next(){
+	Ref<SpineTrackEntry> gd_entry(memnew(SpineTrackEntry));
+	auto entry = track_entry->getNext();
+	if(entry == NULL) return NULL;
+	gd_entry->set_spine_object(entry);
+	return gd_entry;
+}
+
+bool SpineTrackEntry::is_complete(){
+	return track_entry->isComplete();
+}
+
+float SpineTrackEntry::get_mix_time(){
+	return track_entry->getMixTime();
+}
+void SpineTrackEntry::set_mix_time(float v){
+	track_entry->setMixTime(v);
+}
+
+float SpineTrackEntry::get_mix_duration(){
+	return track_entry->getMixDuration();
+}
+void SpineTrackEntry::set_mix_duration(float v){
+	track_entry->setMixDuration(v);
+}
+
+SpineTrackEntry::MixBlend SpineTrackEntry::get_mix_blend(){
+	int mb = track_entry->getMixBlend();
+	return (MixBlend) mb;
+}
+void SpineTrackEntry::set_mix_blend(SpineTrackEntry::MixBlend v){
+	int mb = (int) v;
+	track_entry->setMixBlend((spine::MixBlend)mb);
+}
+
+Ref<SpineTrackEntry> SpineTrackEntry::get_mixing_from(){
+	Ref<SpineTrackEntry> gd_entry(memnew(SpineTrackEntry));
+	auto entry = track_entry->getMixingFrom();
+	if(entry == NULL) return NULL;
+	gd_entry->set_spine_object(entry);
+	return gd_entry;
+}
+Ref<SpineTrackEntry> SpineTrackEntry::get_mixing_to(){
+	Ref<SpineTrackEntry> gd_entry(memnew(SpineTrackEntry));
+	auto entry = track_entry->getMixingTo();
+	if(entry == NULL) return NULL;
+	gd_entry->set_spine_object(entry);
+	return gd_entry;
+}
+
+void SpineTrackEntry::reset_rotation_directions(){
+	track_entry->resetRotationDirections();
+}
+
+bool SpineTrackEntry::get_reverse() {
+    return track_entry->getReverse();
+}
+
+void SpineTrackEntry::set_reverse(bool v) {
+    track_entry->setReverse(v);
+}

+ 131 - 0
spine-godot/spine_godot/SpineTrackEntry.h

@@ -0,0 +1,131 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINETRACKENTRY_H
+#define GODOT_SPINETRACKENTRY_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+#include "SpineAnimation.h"
+
+class SpineTrackEntry : public Reference{
+	GDCLASS(SpineTrackEntry, Reference);
+
+protected:
+	static void _bind_methods();
+
+private:
+	spine::TrackEntry *track_entry;
+
+public:
+	SpineTrackEntry();
+	~SpineTrackEntry();
+
+	inline void set_spine_object(spine::TrackEntry *t){
+		track_entry = t;
+	}
+	inline spine::TrackEntry *get_spine_object(){
+		return track_entry;
+	}
+
+	enum MixBlend {
+		MIXBLEND_SETUP = 0,
+		MIXBLEND_FIRST,
+		MIXBLEND_REPLACE,
+		MIXBLEND_ADD
+	};
+
+	int get_track_index();
+
+	Ref<SpineAnimation> get_animation();
+
+	bool get_loop();
+	void set_loop(bool v);
+
+	bool get_hold_previous();
+	void set_hold_previous(bool v);
+
+    bool get_reverse();
+    void set_reverse(bool v);
+
+	float get_delay();
+	void set_delay(float v);
+
+	float get_track_time();
+	void set_track_time(float v);
+
+	float get_track_end();
+	void set_track_end(float v);
+
+	float get_animation_start();
+	void set_animation_start(float v);
+
+	float get_animation_last();
+	void set_animation_last(float v);
+
+	float get_animation_time();
+
+	float get_time_scale();
+	void set_time_scale(float v);
+
+	float get_alpha();
+	void set_alpha(float v);
+
+	float get_event_threshold();
+	void set_event_threshold(float v);
+
+	float get_attachment_threshold();
+	void set_attachment_threshold(float v);
+
+	float get_draw_order_threshold();
+	void set_draw_order_threshold(float v);
+
+	Ref<SpineTrackEntry> get_next();
+
+	bool is_complete();
+
+	float get_mix_time();
+	void set_mix_time(float v);
+
+	float get_mix_duration();
+	void set_mix_duration(float v);
+
+	MixBlend get_mix_blend();
+	void set_mix_blend(MixBlend v);
+
+	Ref<SpineTrackEntry> get_mixing_from();
+	Ref<SpineTrackEntry> get_mixing_to();
+
+	void reset_rotation_directions();
+};
+
+VARIANT_ENUM_CAST(SpineTrackEntry::MixBlend);
+#endif //GODOT_SPINETRACKENTRY_H

+ 148 - 0
spine-godot/spine_godot/SpineTransformConstraint.cpp

@@ -0,0 +1,148 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineTransformConstraint.h"
+
+void SpineTransformConstraint::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("update"), &SpineTransformConstraint::update);
+	ClassDB::bind_method(D_METHOD("get_data"), &SpineTransformConstraint::get_data);
+	ClassDB::bind_method(D_METHOD("get_bones"), &SpineTransformConstraint::get_bones);
+	ClassDB::bind_method(D_METHOD("get_target"), &SpineTransformConstraint::get_target);
+	ClassDB::bind_method(D_METHOD("set_target", "v"), &SpineTransformConstraint::set_target);
+	ClassDB::bind_method(D_METHOD("get_mix_rotate"), &SpineTransformConstraint::get_mix_rotate);
+	ClassDB::bind_method(D_METHOD("set_mix_rotate", "v"), &SpineTransformConstraint::set_mix_rotate);
+	ClassDB::bind_method(D_METHOD("get_mix_x"), &SpineTransformConstraint::get_mix_x);
+	ClassDB::bind_method(D_METHOD("set_mix_x", "v"), &SpineTransformConstraint::set_mix_x);
+	ClassDB::bind_method(D_METHOD("get_mix_y"), &SpineTransformConstraint::get_mix_y);
+	ClassDB::bind_method(D_METHOD("set_mix_y", "v"), &SpineTransformConstraint::set_mix_y);
+	ClassDB::bind_method(D_METHOD("get_mix_scale_x"), &SpineTransformConstraint::get_mix_scale_x);
+	ClassDB::bind_method(D_METHOD("set_mix_scale_x", "v"), &SpineTransformConstraint::set_mix_scale_x);
+	ClassDB::bind_method(D_METHOD("get_mix_scale_y"), &SpineTransformConstraint::get_mix_scale_y);
+	ClassDB::bind_method(D_METHOD("set_mix_scale_y", "v"), &SpineTransformConstraint::set_mix_scale_y);
+	ClassDB::bind_method(D_METHOD("get_mix_shear_y"), &SpineTransformConstraint::get_mix_shear_y);
+	ClassDB::bind_method(D_METHOD("set_mix_shear_y", "v"), &SpineTransformConstraint::set_mix_shear_y);
+	ClassDB::bind_method(D_METHOD("is_active"), &SpineTransformConstraint::is_active);
+	ClassDB::bind_method(D_METHOD("set_active", "v"), &SpineTransformConstraint::set_active);
+}
+
+SpineTransformConstraint::SpineTransformConstraint():transform_constraint(NULL) {}
+SpineTransformConstraint::~SpineTransformConstraint() {}
+
+void SpineTransformConstraint::update(){
+	transform_constraint->update();
+}
+
+int SpineTransformConstraint::get_order(){
+	return transform_constraint->getOrder();
+}
+
+Ref<SpineTransformConstraintData> SpineTransformConstraint::get_data(){
+	auto &d = transform_constraint->getData();
+	Ref<SpineTransformConstraintData> gd_d(memnew(SpineTransformConstraintData));
+	gd_d->set_spine_object(&d);
+	return gd_d;
+}
+
+Array SpineTransformConstraint::get_bones(){
+	auto &bs = transform_constraint->getBones();
+	Array gd_bs;
+	gd_bs.resize(bs.size());
+	for(size_t i=0; i<bs.size(); ++i){
+		auto b = bs[i];
+		if(b == NULL) gd_bs[i] = Ref<SpineBone>(NULL);
+		Ref<SpineBone> gd_b(memnew(SpineBone));
+		gd_b->set_spine_object(b);
+		gd_bs[i] = gd_b;
+	}
+	return gd_bs;
+}
+
+Ref<SpineBone> SpineTransformConstraint::get_target(){
+	auto b = transform_constraint->getTarget();
+	if(b == NULL) return NULL;
+	Ref<SpineBone> gd_b(memnew(SpineBone));
+	gd_b->set_spine_object(b);
+	return gd_b;
+}
+void SpineTransformConstraint::set_target(Ref<SpineBone> v){
+	if(v.is_valid()){
+		transform_constraint->setTarget(v->get_spine_object());
+	} else{
+		transform_constraint->setTarget(NULL);
+	}
+}
+
+float SpineTransformConstraint::get_mix_rotate(){
+	return transform_constraint->getMixRotate();
+}
+void SpineTransformConstraint::set_mix_rotate(float v){
+	transform_constraint->setMixRotate(v);
+}
+
+float SpineTransformConstraint::get_mix_x(){
+	return transform_constraint->getMixX();
+}
+void SpineTransformConstraint::set_mix_x(float v){
+	transform_constraint->setMixX(v);
+}
+
+float SpineTransformConstraint::get_mix_y(){
+	return transform_constraint->getMixY();
+}
+void SpineTransformConstraint::set_mix_y(float v){
+	transform_constraint->setMixY(v);
+}
+
+float SpineTransformConstraint::get_mix_scale_x(){
+	return transform_constraint->getMixScaleX();
+}
+void SpineTransformConstraint::set_mix_scale_x(float v){
+	transform_constraint->setMixScaleX(v);
+}
+
+float SpineTransformConstraint::get_mix_scale_y(){
+	return transform_constraint->getMixScaleY();
+}
+void SpineTransformConstraint::set_mix_scale_y(float v){
+	transform_constraint->setMixScaleY(v);
+}
+
+float SpineTransformConstraint::get_mix_shear_y(){
+	return transform_constraint->getMixShearY();
+}
+void SpineTransformConstraint::set_mix_shear_y(float v){
+	transform_constraint->setMixShearY(v);
+}
+
+bool SpineTransformConstraint::is_active(){
+	return transform_constraint->isActive();
+}
+void SpineTransformConstraint::set_active(bool v){
+	transform_constraint->setActive(v);
+}

+ 93 - 0
spine-godot/spine_godot/SpineTransformConstraint.h

@@ -0,0 +1,93 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINETRANSFORMCONSTRAINT_H
+#define GODOT_SPINETRANSFORMCONSTRAINT_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+#include "SpineTransformConstraintData.h"
+#include "SpineBone.h"
+
+class SpineTransformConstraint : public Reference{
+	GDCLASS(SpineTransformConstraint, Reference);
+
+protected:
+	static void _bind_methods();
+
+private:
+	spine::TransformConstraint *transform_constraint;
+
+public:
+	SpineTransformConstraint();
+	~SpineTransformConstraint();
+
+	inline void set_spine_object(spine::TransformConstraint *tc){
+		transform_constraint = tc;
+	}
+	inline spine::TransformConstraint *get_spine_object(){
+		return transform_constraint;
+	}
+
+	void update();
+
+	int get_order();
+
+	Ref<SpineTransformConstraintData> get_data();
+
+	Array get_bones();
+
+	Ref<SpineBone> get_target();
+	void set_target(Ref<SpineBone> v);
+
+	float get_mix_rotate();
+	void set_mix_rotate(float v);
+
+	float get_mix_x();
+	void set_mix_x(float v);
+
+	float get_mix_y();
+	void set_mix_y(float v);
+
+	float get_mix_scale_x();
+	void set_mix_scale_x(float v);
+
+	float get_mix_scale_y();
+	void set_mix_scale_y(float v);
+
+	float get_mix_shear_y();
+	void set_mix_shear_y(float v);
+
+	bool is_active();
+	void set_active(bool v);
+};
+
+#endif //GODOT_SPINETRANSFORMCONSTRAINT_H

+ 118 - 0
spine-godot/spine_godot/SpineTransformConstraintData.cpp

@@ -0,0 +1,118 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "SpineTransformConstraintData.h"
+
+void SpineTransformConstraintData::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("get_all_bone_data"), &SpineTransformConstraintData::get_bones);
+	ClassDB::bind_method(D_METHOD("get_target"), &SpineTransformConstraintData::get_target);
+	ClassDB::bind_method(D_METHOD("get_mix_rotate"), &SpineTransformConstraintData::get_mix_rotate);
+	ClassDB::bind_method(D_METHOD("get_mix_x"), &SpineTransformConstraintData::get_mix_x);
+	ClassDB::bind_method(D_METHOD("get_mix_y"), &SpineTransformConstraintData::get_mix_y);
+	ClassDB::bind_method(D_METHOD("get_mix_scale_x"), &SpineTransformConstraintData::get_mix_scale_x);
+	ClassDB::bind_method(D_METHOD("get_mix_scale_y"), &SpineTransformConstraintData::get_mix_scale_y);
+	ClassDB::bind_method(D_METHOD("get_mix_shear_y"), &SpineTransformConstraintData::get_mix_shear_y);
+	ClassDB::bind_method(D_METHOD("get_offset_rotation"), &SpineTransformConstraintData::get_offset_rotation);
+	ClassDB::bind_method(D_METHOD("get_offset_x"), &SpineTransformConstraintData::get_offset_x);
+	ClassDB::bind_method(D_METHOD("get_offset_y"), &SpineTransformConstraintData::get_offset_y);
+	ClassDB::bind_method(D_METHOD("get_offset_scale_x"), &SpineTransformConstraintData::get_offset_scale_x);
+	ClassDB::bind_method(D_METHOD("get_offset_scale_y"), &SpineTransformConstraintData::get_offset_scale_y);
+	ClassDB::bind_method(D_METHOD("get_offset_shear_y"), &SpineTransformConstraintData::get_offset_shear_y);
+	ClassDB::bind_method(D_METHOD("is_relative"), &SpineTransformConstraintData::is_relative);
+	ClassDB::bind_method(D_METHOD("is_local"), &SpineTransformConstraintData::is_local);
+}
+
+SpineTransformConstraintData::SpineTransformConstraintData() {}
+SpineTransformConstraintData::~SpineTransformConstraintData() {}
+
+Array SpineTransformConstraintData::get_bones(){
+	auto bs = get_spine_data()->getBones();
+	Array gd_bs;
+	gd_bs.resize(bs.size());
+	for(size_t i=0; i < bs.size(); ++i){
+		if(bs[i] == NULL) gd_bs[i] = Ref<SpineBoneData>(NULL);
+		else {
+			Ref<SpineBoneData> gd_b(memnew(SpineBoneData));
+			gd_b->set_spine_object(bs[i]);
+			gd_bs[i] = gd_b;
+		}
+	}
+	return gd_bs;
+}
+Ref<SpineBoneData> SpineTransformConstraintData::get_target(){
+	auto b = get_spine_data()->getTarget();
+	if(b == NULL) return NULL;
+	Ref<SpineBoneData> gd_b(memnew(SpineBoneData));
+	gd_b->set_spine_object(b);
+	return gd_b;
+}
+float SpineTransformConstraintData::get_mix_rotate(){
+	return get_spine_data()->getMixRotate();
+}
+float SpineTransformConstraintData::get_mix_x(){
+	return get_spine_data()->getMixX();
+}
+float SpineTransformConstraintData::get_mix_y(){
+	return get_spine_data()->getMixY();
+}
+float SpineTransformConstraintData::get_mix_scale_x(){
+	return get_spine_data()->getMixScaleX();
+}
+float SpineTransformConstraintData::get_mix_scale_y(){
+	return get_spine_data()->getMixScaleY();
+}
+float SpineTransformConstraintData::get_mix_shear_y(){
+	return get_spine_data()->getMixShearY();
+}
+
+float SpineTransformConstraintData::get_offset_rotation(){
+	return get_spine_data()->getOffsetRotation();
+}
+float SpineTransformConstraintData::get_offset_x(){
+	return get_spine_data()->getOffsetX();
+}
+float SpineTransformConstraintData::get_offset_y(){
+	return get_spine_data()->getOffsetY();
+}
+float SpineTransformConstraintData::get_offset_scale_x(){
+	return get_spine_data()->getOffsetScaleX();
+}
+float SpineTransformConstraintData::get_offset_scale_y(){
+	return get_spine_data()->getOffsetScaleY();
+}
+float SpineTransformConstraintData::get_offset_shear_y(){
+	return get_spine_data()->getOffsetShearY();
+}
+
+bool SpineTransformConstraintData::is_relative(){
+	return get_spine_data()->isRelative();
+}
+bool SpineTransformConstraintData::is_local(){
+	return get_spine_data()->isLocal();
+}

+ 74 - 0
spine-godot/spine_godot/SpineTransformConstraintData.h

@@ -0,0 +1,74 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef GODOT_SPINETRANSFORMCONSTRAINTDATA_H
+#define GODOT_SPINETRANSFORMCONSTRAINTDATA_H
+
+#include "core/variant_parser.h"
+
+#include <spine/spine.h>
+
+#include "SpineConstraintData.h"
+#include "SpineBoneData.h"
+
+class SpineTransformConstraintData : public SpineConstraintData {
+	GDCLASS(SpineTransformConstraintData, SpineConstraintData);
+
+protected:
+	static void _bind_methods();
+
+public:
+	SpineTransformConstraintData();
+	~SpineTransformConstraintData();
+
+	virtual inline spine::TransformConstraintData *get_spine_data(){
+		return (spine::TransformConstraintData*) SpineConstraintData::get_spine_object();
+	}
+
+	Array get_bones();
+	Ref<SpineBoneData> get_target();
+	float get_mix_rotate();
+	float get_mix_x();
+	float get_mix_y();
+	float get_mix_scale_x();
+	float get_mix_scale_y();
+	float get_mix_shear_y();
+
+	float get_offset_rotation();
+	float get_offset_x();
+	float get_offset_y();
+	float get_offset_scale_x();
+	float get_offset_scale_y();
+	float get_offset_shear_y();
+
+	bool is_relative();
+	bool is_local();
+};
+
+#endif //GODOT_SPINETRANSFORMCONSTRAINTDATA_H

+ 5 - 0
spine-godot/spine_godot/config.py

@@ -0,0 +1,5 @@
+def can_build(env, platform):
+    return True
+
+def configure(env):
+    pass

+ 151 - 0
spine-godot/spine_godot/register_types.cpp

@@ -0,0 +1,151 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include "register_types.h"
+
+#include "core/class_db.h"
+
+#include "spine_runtime.h"
+#include "SpineAtlasResource.h"
+#include "ResourceFormatLoaderSpineAtlas.h"
+#include "ResourceFormatSaverSpineAtlas.h"
+#include "SpineSkeletonDataResource.h"
+#include "ResourceFormatLoaderSpineSkeletonJsonData.h"
+#include "ResourceFormatSaverSpineSkeletonJsonData.h"
+#include "SpineSprite.h"
+#include "SpineAnimationStateDataResource.h"
+#include "SpineSkeleton.h"
+#include "SpineAnimationState.h"
+#include "SpineEventData.h"
+#include "SpineEvent.h"
+#include "SpineTrackEntry.h"
+#include "SpineBoneData.h"
+#include "SpineSlotData.h"
+#include "SpineAttachment.h"
+#include "SpineSkinAttachmentMapEntries.h"
+#include "SpineConstraintData.h"
+#include "SpineSkin.h"
+#include "SpineIkConstraintData.h"
+#include "SpineTransformConstraintData.h"
+#include "SpinePathConstraintData.h"
+#include "SpineSpriteMeshInstance2D.h"
+#include "PackedSpineSkinResource.h"
+#include "SpineTimeline.h"
+#include "SpineConstant.h"
+#include "SpineCollisionShapeProxy.h"
+#include "SpineSpriteAnimateDialog.h"
+
+
+static Ref<ResourceFormatLoaderSpineAtlas> atlas_loader;
+static Ref<ResourceFormatSaverSpineAtlas> atlas_saver;
+static Ref<ResourceFormatLoaderSpineSkeletonJsonData> json_skeleton_loader;
+static Ref<ResourceFormatSaverSpineSkeletonJsonData> json_skeleton_saver;
+
+// editor plugin
+#ifdef TOOLS_ENABLED
+#include "editor/editor_export.h"
+#include "editor/editor_node.h"
+
+#include "SpineRuntimeEditorPlugin.h"
+
+static void editor_init_callback() {
+    EditorNode::get_singleton()->add_editor_plugin(memnew(SpineRuntimeEditorPlugin(EditorNode::get_singleton())));
+}
+
+
+#endif
+
+void register_spine_godot_types(){
+#ifdef TOOLS_ENABLED
+    ClassDB::register_class<SpineSpriteAnimateDialog>();
+
+	EditorNode::add_init_callback(editor_init_callback);
+
+#endif
+
+    ClassDB::register_class<SpineRuntime>();
+    ClassDB::register_class<SpineAtlasResource>();
+    ClassDB::register_class<SpineSprite>();
+	ClassDB::register_class<SpineSkeletonDataResource>();
+	ClassDB::register_class<SpineAnimationStateDataResource>();
+	ClassDB::register_class<SpineSkeletonJsonDataResource>();
+	ClassDB::register_class<SpineSkeleton>();
+	ClassDB::register_class<SpineAnimationState>();
+	ClassDB::register_class<SpineAnimation>();
+	ClassDB::register_class<SpineEventData>();
+	ClassDB::register_class<SpineTrackEntry>();
+	ClassDB::register_class<SpineEvent>();
+	ClassDB::register_class<SpineBoneData>();
+	ClassDB::register_class<SpineSlotData>();
+	ClassDB::register_class<SpineAttachment>();
+	ClassDB::register_class<SpineSkinAttachmentMapEntry>();
+	ClassDB::register_class<SpineSkinAttachmentMapEntries>();
+	ClassDB::register_class<SpineConstraintData>();
+	ClassDB::register_class<SpineSkin>();
+	ClassDB::register_class<SpineIkConstraintData>();
+	ClassDB::register_class<SpineTransformConstraintData>();
+	ClassDB::register_class<SpinePathConstraintData>();
+	ClassDB::register_class<SpineBone>();
+	ClassDB::register_class<SpineSlot>();
+	ClassDB::register_class<SpineIkConstraint>();
+	ClassDB::register_class<SpinePathConstraint>();
+	ClassDB::register_class<SpineTransformConstraint>();
+	ClassDB::register_class<SpineSpriteMeshInstance2D>();
+	ClassDB::register_class<PackedSpineSkinResource>();
+	ClassDB::register_class<SpineTimeline>();
+	ClassDB::register_class<SpineConstant>();
+	ClassDB::register_class<SpineCollisionShapeProxy>();
+
+    atlas_loader.instance();
+    ResourceLoader::add_resource_format_loader(atlas_loader);
+
+    atlas_saver.instance();
+    ResourceSaver::add_resource_format_saver(atlas_saver);
+
+	json_skeleton_loader.instance();
+	ResourceLoader::add_resource_format_loader(json_skeleton_loader);
+
+	json_skeleton_saver.instance();
+	ResourceSaver::add_resource_format_saver(json_skeleton_saver);
+
+}
+
+void unregister_spine_godot_types(){
+    ResourceLoader::remove_resource_format_loader(atlas_loader);
+    atlas_loader.unref();
+
+    ResourceSaver::remove_resource_format_saver(atlas_saver);
+    atlas_saver.unref();
+
+	ResourceLoader::remove_resource_format_loader(json_skeleton_loader);
+	json_skeleton_loader.unref();
+
+	ResourceSaver::remove_resource_format_saver(json_skeleton_saver);
+	json_skeleton_saver.unref();
+}

+ 32 - 0
spine-godot/spine_godot/register_types.h

@@ -0,0 +1,32 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+void register_spine_godot_types();
+void unregister_spine_godot_types();
+