[godot] New SpineSprite implementation with more coherent resource management.

This commit is contained in:
Mario Zechner 2022-04-08 23:04:23 +02:00
parent 702c685b32
commit 88038fa906
12 changed files with 364 additions and 87 deletions

View File

@ -0,0 +1,10 @@
[gd_resource type="SpineNewSkeletonDataResource" load_steps=3 format=2]
[ext_resource path="res://assets/spineboy/spineboy.atlas" type="SpineAtlasResource" id=1]
[ext_resource path="res://assets/spineboy/spineboy-pro.skel" type="SpineSkeletonFileResource" id=2]
[resource]
atlas_res = ExtResource( 1 )
skeleton_file_res = ExtResource( 2 )
animations = null
skins = null

View File

@ -1,8 +1,9 @@
[gd_scene load_steps=9 format=2]
[gd_scene load_steps=10 format=2]
[ext_resource path="res://Spineboy.gd" type="Script" id=1]
[ext_resource path="res://assets/spineboy/spineboy-data.tres" type="SpineSkeletonDataResource" id=2]
[ext_resource path="res://assets/mix-and-match/mix-and-match-data.tres" type="SpineSkeletonDataResource" id=3]
[ext_resource path="res://assets/spineboy/spinebody-data-new-res.tres" type="SpineNewSkeletonDataResource" id=4]
[ext_resource path="res://mix-and-match.gd" type="Script" id=5]
[ext_resource path="res://assets/raptor/raprot-data.tres" type="SpineSkeletonDataResource" id=6]
@ -33,3 +34,7 @@ script = ExtResource( 5 )
position = Vector2( 261.223, 541.504 )
scale = Vector2( 0.5, 0.5 )
animation_state_data_res = SubResource( 5 )
[node name="SpineNewSprite" type="SpineNewSprite" parent="."]
position = Vector2( 631.194, 1005.65 )
skeleton_data_res = ExtResource( 4 )

View File

@ -0,0 +1,171 @@
/******************************************************************************
* 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 "SpineNewAnimationState.h"
void SpineNewAnimationState::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_animation", "anim_name", "loop", "track_id"), &SpineNewAnimationState::set_animation, DEFVAL(true), DEFVAL(0));
ClassDB::bind_method(D_METHOD("update", "delta"), &SpineNewAnimationState::update, DEFVAL(0));
ClassDB::bind_method(D_METHOD("apply", "skeleton"), &SpineNewAnimationState::apply);
ClassDB::bind_method(D_METHOD("clear_tracks"), &SpineNewAnimationState::clear_tracks);
ClassDB::bind_method(D_METHOD("clear_track"), &SpineNewAnimationState::clear_track);
ClassDB::bind_method(D_METHOD("add_animation", "anim_name", "delay", "loop", "track_id"), &SpineNewAnimationState::add_animation, DEFVAL(0), DEFVAL(true), DEFVAL(0));
ClassDB::bind_method(D_METHOD("set_empty_animation", "track_id", "mix_duration"), &SpineNewAnimationState::set_empty_animation);
ClassDB::bind_method(D_METHOD("add_empty_animation", "track_id", "mix_duration", "delay"), &SpineNewAnimationState::add_empty_animation);
ClassDB::bind_method(D_METHOD("set_empty_animations", "mix_duration"), &SpineNewAnimationState::set_empty_animations);
ClassDB::bind_method(D_METHOD("get_time_scale"), &SpineNewAnimationState::get_time_scale);
ClassDB::bind_method(D_METHOD("set_time_scale", "time_scale"), &SpineNewAnimationState::set_time_scale);
ClassDB::bind_method(D_METHOD("disable_queue"), &SpineNewAnimationState::disable_queue);
ClassDB::bind_method(D_METHOD("enable_queue"), &SpineNewAnimationState::enable_queue);
ClassDB::bind_method(D_METHOD("get_current", "track_id"), &SpineNewAnimationState::get_current);
}
SpineNewAnimationState::SpineNewAnimationState() : animation_state(nullptr), skeleton_data_res(nullptr) {
}
SpineNewAnimationState::~SpineNewAnimationState() {
delete animation_state;
}
void SpineNewAnimationState::set_skeleton_data_res(Ref<SpineNewSkeletonDataResource> data_res) {
delete animation_state;
animation_state = nullptr;
skeleton_data_res = data_res;
if (!skeleton_data_res.is_valid() || !skeleton_data_res->is_skeleton_data_loaded()) return;
animation_state = new spine::AnimationState(skeleton_data_res->get_animation_state_data());
}
Ref<SpineNewSkeletonDataResource> SpineNewAnimationState::get_skeleton_data_res() const {
return skeleton_data_res;
}
#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> SpineNewAnimationState::set_animation(const String &anim_name, bool loop, uint64_t track) {
CHECK_X(nullptr);
auto skeleton_data = animation_state->getData()->getSkeletonData();
auto anim = skeleton_data->findAnimation(anim_name.utf8().ptr());
if (!anim) {
ERR_PRINT(String("Can not find animation: ") + anim_name);
return nullptr;
}
auto entry = animation_state->setAnimation(track, anim, loop);
Ref<SpineTrackEntry> gd_entry(memnew(SpineTrackEntry));
gd_entry->set_spine_object(entry);
return gd_entry;
}
Ref<SpineTrackEntry> SpineNewAnimationState::add_animation(const String &anim_name, float delay, bool loop, uint64_t track) {
CHECK_X(nullptr);
auto skeleton_data = animation_state->getData()->getSkeletonData();
auto anim = skeleton_data->findAnimation(anim_name.utf8().ptr());
if (!anim) {
ERR_PRINT(String("Can not find animation: ") + anim_name);
return nullptr;
}
auto entry = animation_state->addAnimation(track, anim, loop, delay);
Ref<SpineTrackEntry> gd_entry(memnew(SpineTrackEntry));
gd_entry->set_spine_object(entry);
return gd_entry;
}
Ref<SpineTrackEntry> SpineNewAnimationState::set_empty_animation(uint64_t track_id, float mix_duration) {
CHECK_X(nullptr);
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> SpineNewAnimationState::add_empty_animation(uint64_t track_id, float mix_duration, float delay) {
CHECK_X(nullptr);
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 SpineNewAnimationState::set_empty_animations(float mix_duration) {
CHECK_V;
animation_state->setEmptyAnimations(mix_duration);
}
void SpineNewAnimationState::update(float delta) {
CHECK_V;
animation_state->update(delta);
}
bool SpineNewAnimationState::apply(Ref<SpineNewSkeleton> skeleton) {
CHECK_X(false);
return animation_state->apply(*(skeleton->get_spine_object()));
}
void SpineNewAnimationState::clear_tracks() {
CHECK_V;
animation_state->clearTracks();
}
void SpineNewAnimationState::clear_track(uint64_t track_id) {
CHECK_V;
animation_state->clearTrack(track_id);
}
float SpineNewAnimationState::get_time_scale() {
CHECK_X(0);
return animation_state->getTimeScale();
}
void SpineNewAnimationState::set_time_scale(float time_scale) {
CHECK_V;
animation_state->setTimeScale(time_scale);
}
void SpineNewAnimationState::disable_queue() {
CHECK_V;
animation_state->disableQueue();
}
void SpineNewAnimationState::enable_queue() {
CHECK_V;
animation_state->enableQueue();
}
Ref<SpineTrackEntry> SpineNewAnimationState::get_current(uint64_t track_index) {
CHECK_X(nullptr);
Ref<SpineTrackEntry> gd_entry(memnew(SpineTrackEntry));
auto entry = animation_state->getCurrent(track_index);
if (entry == nullptr) return nullptr;
gd_entry->set_spine_object(entry);
return gd_entry;
}
#undef CHECK_V
#undef CHECK_X

View File

@ -0,0 +1,82 @@
/******************************************************************************
* 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_SPINENEWANIMATIONSTATE_H
#define GODOT_SPINENEWANIMATIONSTATE_H
#include "SpineNewSkeleton.h"
#include "SpineTrackEntry.h"
class SpineNewAnimationState : public Reference {
GDCLASS(SpineNewAnimationState, Reference);
protected:
static void _bind_methods();
private:
spine::AnimationState *animation_state;
Ref<SpineNewSkeletonDataResource> skeleton_data_res;
public:
SpineNewAnimationState();
~SpineNewAnimationState();
void set_skeleton_data_res(Ref<SpineNewSkeletonDataResource> skeleton_data_res);
Ref<SpineNewSkeletonDataResource> get_skeleton_data_res() const;
inline void set_spine_object(spine::AnimationState *animation_state) { this->animation_state = animation_state; }
inline spine::AnimationState *get_spine_object() { return animation_state; }
Ref<SpineTrackEntry> set_animation(const String &anim_name, bool loop, uint64_t track_id);
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);
float get_time_scale();
void set_time_scale(float time_scale);
void disable_queue();
void enable_queue();
void update(float delta);
bool apply(Ref<SpineNewSkeleton> skeleton);
void clear_tracks();
void clear_track(uint64_t track_id);
Ref<SpineTrackEntry> get_current(uint64_t track_index);
};
#endif//GODOT_SPINENEWANIMATIONSTATE_H

View File

@ -98,9 +98,14 @@ void SpineNewBone::_bind_methods() {
ClassDB::bind_method(D_METHOD("apply_world_transform_2d", "node2d"), &SpineNewBone::apply_world_transform_2d);
}
SpineNewBone::SpineNewBone() : bone(NULL), the_sprite(nullptr) {}
SpineNewBone::SpineNewBone() : bone(nullptr), sprite(nullptr) {}
SpineNewBone::~SpineNewBone() {}
void SpineNewBone::set_spine_sprite(SpineNewSprite* sprite) {
this->sprite = sprite;
}
void SpineNewBone::update_world_transform() {
bone->updateWorldTransform();
}
@ -151,7 +156,7 @@ Ref<SpineNewSkeleton> SpineNewBone::get_skeleton() {
auto &s = bone->getSkeleton();
Ref<SpineNewSkeleton> gd_s(memnew(SpineNewSkeleton));
gd_s->set_spine_object(&s);
gd_s->set_spine_sprite(the_sprite);
gd_s->set_spine_sprite(sprite);
return gd_s;
}
@ -160,7 +165,7 @@ Ref<SpineNewBone> SpineNewBone::get_parent() {
if (b == NULL) return NULL;
Ref<SpineNewBone> gd_b(memnew(SpineNewBone));
gd_b->set_spine_object(b);
gd_b->set_spine_sprite(the_sprite);
gd_b->set_spine_sprite(sprite);
return gd_b;
}
@ -173,7 +178,7 @@ Array SpineNewBone::get_children() {
if (b == NULL) gd_bs[i] = Ref<SpineNewBone>(NULL);
Ref<SpineNewBone> gd_b(memnew(SpineNewBone));
gd_b->set_spine_object(b);
gd_b->set_spine_sprite(the_sprite);
gd_b->set_spine_sprite(sprite);
gd_bs[i] = gd_b;
}
return gd_bs;
@ -390,13 +395,13 @@ void SpineNewBone::set_godot_transform(Transform2D trans) {
Transform2D SpineNewBone::get_godot_global_transform() {
if (get_spine_object() == nullptr)
return Transform2D();
if (the_sprite == nullptr)
if (sprite == nullptr)
return get_godot_transform();
Transform2D res = the_sprite->get_transform();
Transform2D res = 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;
auto p = sprite->get_parent() ? Object::cast_to<CanvasItem>(sprite->get_parent()) : nullptr;
if (p) {
return p->get_global_transform() * res;
}
@ -406,9 +411,9 @@ Transform2D SpineNewBone::get_godot_global_transform() {
void SpineNewBone::set_godot_global_transform(Transform2D transform) {
if (get_spine_object() == nullptr)
return;
if (the_sprite == nullptr)
if (sprite == nullptr)
set_godot_transform(transform);
transform = the_sprite->get_global_transform().affine_inverse() * transform;
transform = sprite->get_global_transform().affine_inverse() * transform;
Vector2 position = transform.get_origin();
real_t rotation = transform.get_rotation();
Vector2 scale = transform.get_scale();
@ -433,7 +438,3 @@ void SpineNewBone::set_godot_global_transform(Transform2D transform) {
set_scale_x(scale.x);
set_scale_y(scale.y);
}
void SpineNewBone::set_spine_sprite(SpineNewSprite *s) {
the_sprite = s;
}

View File

@ -46,8 +46,7 @@ protected:
private:
spine::Bone *bone;
SpineNewSprite *the_sprite;
SpineNewSprite* sprite;
public:
SpineNewBone();
@ -56,11 +55,12 @@ public:
inline void set_spine_object(spine::Bone *b) {
bone = b;
}
inline spine::Bone *get_spine_object() {
return bone;
}
void set_spine_sprite(SpineNewSprite *s);
void set_spine_sprite(SpineNewSprite* sprite);
void update_world_transform();

View File

@ -46,7 +46,7 @@ void SpineNewSkeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("find_path_constraint", "constraint_name"), &SpineNewSkeleton::find_path_constraint);
ClassDB::bind_method(D_METHOD("get_bounds"), &SpineNewSkeleton::get_bounds);
ClassDB::bind_method(D_METHOD("get_root_bone"), &SpineNewSkeleton::get_root_bone);
ClassDB::bind_method(D_METHOD("get_data"), &SpineNewSkeleton::get_data);
ClassDB::bind_method(D_METHOD("get_data"), &SpineNewSkeleton::get_skeleton_data_res);
ClassDB::bind_method(D_METHOD("get_bones"), &SpineNewSkeleton::get_bones);
ClassDB::bind_method(D_METHOD("get_slots"), &SpineNewSkeleton::get_slots);
ClassDB::bind_method(D_METHOD("get_draw_orders"), &SpineNewSkeleton::get_draw_orders);
@ -77,9 +77,17 @@ SpineNewSkeleton::~SpineNewSkeleton() {
void SpineNewSkeleton::set_skeleton_data_res(Ref<SpineNewSkeletonDataResource> data_res) {
delete skeleton;
skeleton = nullptr;
if (!data_res.is_valid()) return;
skeleton = new spine::Skeleton(data_res->get_skeleton_data());
skeleton_data_res = data_res;
if (!data_res.is_valid() || !data_res->is_skeleton_data_loaded()) return;
skeleton = new spine::Skeleton(data_res->get_skeleton_data());
}
Ref<SpineNewSkeletonDataResource> SpineNewSkeleton::get_skeleton_data_res() const {
return skeleton_data_res;
}
void SpineNewSkeleton::set_spine_sprite(SpineNewSprite* sprite) {
this->sprite = sprite;
}
#define S_T(x) (spine::String((x).utf8()))
@ -205,10 +213,6 @@ Ref<SpineNewBone> SpineNewSkeleton::get_root_bone() {
return gd_b;
}
Ref<SpineNewSkeletonDataResource> SpineNewSkeleton::get_data() const {
return skeleton_data_res;
}
Array SpineNewSkeleton::get_bones() {
auto &as = skeleton->getBones();
Array gd_as;
@ -337,7 +341,3 @@ float SpineNewSkeleton::get_scale_y() {
void SpineNewSkeleton::set_scale_y(float v) {
skeleton->setScaleY(v);
}
void SpineNewSkeleton::set_spine_sprite(SpineNewSprite *s) {
sprite = s;
}

View File

@ -56,6 +56,7 @@ public:
~SpineNewSkeleton();
void set_skeleton_data_res(Ref<SpineNewSkeletonDataResource> data_res);
Ref<SpineNewSkeletonDataResource> get_skeleton_data_res() const;
inline void set_spine_object(spine::Skeleton *s) {
skeleton = s;
@ -64,8 +65,7 @@ public:
return skeleton;
}
void set_spine_sprite(SpineNewSprite *s);
void set_spine_sprite(SpineNewSprite *sprite);
void update_world_transform();
@ -95,8 +95,6 @@ public:
Ref<SpineNewBone> get_root_bone();
Ref<SpineNewSkeletonDataResource> get_data() const;
Array get_bones();
Array get_slots();
Array get_draw_orders();

View File

@ -29,6 +29,11 @@
#include "SpineNewSkeletonDataResource.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_node.h"
#include "editor/editor_inspector.h"
#endif
void SpineNewSkeletonDataResource::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_skeleton_data_loaded"), &SpineNewSkeletonDataResource::is_skeleton_data_loaded);
ClassDB::bind_method(D_METHOD("set_atlas_res", "atlas_res"), &SpineNewSkeletonDataResource::set_atlas_res);
@ -81,13 +86,6 @@ SpineNewSkeletonDataResource::~SpineNewSkeletonDataResource() {
}
void SpineNewSkeletonDataResource::update_skeleton_data() {
if (atlas_res.is_valid() && skeleton_file_res.is_valid()) {
load_res(atlas_res->get_spine_atlas(), skeleton_file_res->get_json(), skeleton_file_res->get_binary());
emit_signal("skeleton_data_changed");
}
}
void SpineNewSkeletonDataResource::load_res(spine::Atlas *atlas, const String &json, const Vector<uint8_t> &binary) {
if (skeleton_data) {
delete skeleton_data;
skeleton_data = nullptr;
@ -97,6 +95,16 @@ void SpineNewSkeletonDataResource::load_res(spine::Atlas *atlas, const String &j
animation_state_data = nullptr;
}
if (atlas_res.is_valid() && skeleton_file_res.is_valid()) {
load_res(atlas_res->get_spine_atlas(), skeleton_file_res->get_json(), skeleton_file_res->get_binary());
}
emit_signal("skeleton_data_changed");
#ifdef TOOLS_ENABLED
property_list_changed_notify();
#endif
}
void SpineNewSkeletonDataResource::load_res(spine::Atlas *atlas, const String &json, const Vector<uint8_t> &binary) {
if ((json.empty() && binary.empty()) || atlas == nullptr) return;
spine::SkeletonData *data;

View File

@ -36,10 +36,9 @@
void SpineNewSprite::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_skeleton_data_res", "skeleton_data_res"), &SpineNewSprite::set_skeleton_data_res);
ClassDB::bind_method(D_METHOD("get_skeleton_data_res"), &SpineNewSprite::get_skeleton_data_res);
ClassDB::bind_method(D_METHOD("_on_animation_data_created"), &SpineNewSprite::_on_animation_data_created);
ClassDB::bind_method(D_METHOD("get_skeleton"), &SpineNewSprite::get_skeleton);
ClassDB::bind_method(D_METHOD("get_animation_state"), &SpineNewSprite::get_animation_state);
ClassDB::bind_method(D_METHOD("_on_animation_data_changed"), &SpineNewSprite::_on_animation_data_changed);
ClassDB::bind_method(D_METHOD("_on_skeleton_data_changed"), &SpineNewSprite::_on_skeleton_data_changed);
ClassDB::bind_method(D_METHOD("get_bind_slot_nodes"), &SpineNewSprite::get_bind_slot_nodes);
ClassDB::bind_method(D_METHOD("set_bind_slot_nodes", "v"), &SpineNewSprite::set_bind_slot_nodes);
@ -73,11 +72,10 @@ void SpineNewSprite::_bind_methods() {
BIND_ENUM_CONSTANT(ProcessMode::ProcessMode_Manual);
}
SpineNewSprite::SpineNewSprite() : overlap(false),
skeleton_clipper(nullptr),
process_mode(ProcessMode_Process) {
SpineNewSprite::SpineNewSprite() : overlap(false), process_mode(ProcessMode_Process), skeleton_clipper(nullptr) {
skeleton_clipper = new spine::SkeletonClipping();
}
SpineNewSprite::~SpineNewSprite() {
delete skeleton_clipper;
}
@ -161,9 +159,11 @@ void SpineNewSprite::update_bind_slot_nodes() {
}
}
}
void SpineNewSprite::update_bind_slot_node_transform(Ref<SpineBone> bone, Node2D *node2d) {
bone->apply_world_transform_2d(node2d);
}
void SpineNewSprite::update_bind_slot_node_draw_order(const String &slot_name, Node2D *node2d) {
auto mesh_ins = find_node(slot_name);
if (mesh_ins) {
@ -184,55 +184,53 @@ Node *SpineNewSprite::find_child_node_by_node(Node *node) {
void SpineNewSprite::set_skeleton_data_res(const Ref<SpineNewSkeletonDataResource> &s) {
skeleton_data_res = s;
_on_animation_data_changed();
_on_skeleton_data_changed();
}
Ref<SpineNewSkeletonDataResource> SpineNewSprite::get_skeleton_data_res() {
return skeleton_data_res;
}
void SpineNewSprite::_on_animation_data_created() {
skeleton = Ref<SpineNewSkeleton>(memnew(SpineNewSkeleton));
skeleton->set_skeleton_data_res(skeleton_data_res);
skeleton->set_spine_sprite(this);
animation_state = Ref<SpineAnimationState>(memnew(SpineAnimationState));
animation_state->create_animation_state(skeleton_data_res->get_animation_state_data());
animation_state->get_spine_object()->setListener(this);
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);
}
}
void SpineNewSprite::_on_animation_data_changed() {
void SpineNewSprite::_on_skeleton_data_changed() {
remove_mesh_instances();
skeleton.unref();
animation_state.unref();
if (skeleton_data_res.is_valid()) {
if (!skeleton_data_res->is_connected("skeleton_data_changed", this, "_on_animation_data_created"))
skeleton_data_res->connect("skeleton_data_changed", this, "_on_animation_data_created");
if (skeleton_data_res->is_skeleton_data_loaded()) {
_on_animation_data_created();
if (skeleton_data_res.is_valid()) {
if (!skeleton_data_res->is_connected("skeleton_data_changed", this, "_on_skeleton_data_changed"))
skeleton_data_res->connect("skeleton_data_changed", this, "_on_skeleton_data_changed");
}
if (skeleton_data_res.is_valid() && skeleton_data_res->is_skeleton_data_loaded()) {
skeleton = Ref<SpineNewSkeleton>(memnew(SpineNewSkeleton));
skeleton->set_skeleton_data_res(skeleton_data_res);
skeleton->set_spine_sprite(this);
animation_state = Ref<SpineNewAnimationState>(memnew(SpineNewAnimationState));
animation_state->set_skeleton_data_res(skeleton_data_res);
if (animation_state->get_spine_object()) animation_state->get_spine_object()->setListener(this);
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);
}
}
}
Ref<SpineSkeleton> SpineNewSprite::get_skeleton() {
Ref<SpineNewSkeleton> SpineNewSprite::get_skeleton() {
return skeleton;
}
Ref<SpineAnimationState> SpineNewSprite::get_animation_state() {
Ref<SpineNewAnimationState> SpineNewSprite::get_animation_state() {
return animation_state;
}
void SpineNewSprite::gen_mesh_from_skeleton(Ref<SpineSkeleton> s) {
void SpineNewSprite::gen_mesh_from_skeleton(Ref<SpineNewSkeleton> s) {
auto sk = s->get_spine_object();
for (size_t i = 0, n = sk->getSlots().size(); i < n; ++i) {
auto mesh_ins = memnew(SpineSpriteMeshInstance2D);
@ -305,7 +303,7 @@ void SpineNewSprite::remove_redundant_mesh_instances() {
} \
} while (false);
void SpineNewSprite::update_mesh_from_skeleton(Ref<SpineSkeleton> s) {
void SpineNewSprite::update_mesh_from_skeleton(Ref<SpineNewSkeleton> s) {
static const unsigned short VERTEX_STRIDE = 2;
static unsigned short quad_indices[] = {0, 1, 2, 2, 3, 0};
@ -606,7 +604,7 @@ bool SpineNewSprite::_set(const StringName &p_property, const Variant &p_value)
if (animation_state.is_valid() && skeleton.is_valid()) {
auto animName = p_value.operator String();
skeleton->set_to_setup_pose();
if (skeleton->get_data()->find_animation(animName).is_valid()) {
if (skeleton->get_skeleton_data_res()->find_animation(animName).is_valid()) {
animation_state->set_animation(animName, true, 0);
} else {
animation_state->clear_tracks();
@ -617,7 +615,7 @@ bool SpineNewSprite::_set(const StringName &p_property, const Variant &p_value)
if (p_property == "Preview skin") {
if (animation_state.is_valid() && skeleton.is_valid()) {
auto skinName = p_value.operator String();
if (skeleton->get_data()->find_skin(skinName).is_valid()) {
if (skeleton->get_skeleton_data_res()->find_skin(skinName).is_valid()) {
skeleton->set_skin_by_name(skinName);
} else {
skeleton->set_skin(nullptr);

View File

@ -32,9 +32,8 @@
#include <scene/resources/texture.h>
#include "SpineAnimationState.h"
#include "SpineAnimationStateDataResource.h"
#include "SpineNewSkeleton.h"
#include "SpineNewAnimationState.h"
#include "SpineSpriteMeshInstance2D.h"
class SpineNewSprite : public Node2D, public spine::AnimationStateListenerObject {
@ -62,7 +61,7 @@ private:
Ref<SpineNewSkeletonDataResource> skeleton_data_res;
Ref<SpineNewSkeleton> skeleton;
Ref<SpineAnimationState> animation_state;
Ref<SpineNewAnimationState> animation_state;
String preview_animation;
Array bind_slot_nodes;
@ -80,14 +79,14 @@ public:
void set_skeleton_data_res(const Ref<SpineNewSkeletonDataResource> &a);
Ref<SpineNewSkeletonDataResource> get_skeleton_data_res();
Ref<SpineSkeleton> get_skeleton();
Ref<SpineAnimationState> get_animation_state();
Ref<SpineNewSkeleton> get_skeleton();
Ref<SpineNewAnimationState> get_animation_state();
void gen_mesh_from_skeleton(Ref<SpineSkeleton> s);
void gen_mesh_from_skeleton(Ref<SpineNewSkeleton> s);
void remove_mesh_instances();
void remove_redundant_mesh_instances();
void update_mesh_from_skeleton(Ref<SpineSkeleton> s);
void update_mesh_from_skeleton(Ref<SpineNewSkeleton> s);
void update_bind_slot_nodes();
void update_bind_slot_node_transform(Ref<SpineBone> bone, Node2D *node2d);
@ -96,8 +95,7 @@ public:
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 _on_skeleton_data_changed();
void _update_all(float delta);

View File

@ -62,6 +62,8 @@ static Ref<SpineSkeletonFileResourceFormatSaver> skeleton_file_saver;
#include "editor/editor_export.h"
#include "editor/editor_node.h"
#include "SpineRuntimeEditorPlugin.h"
#include "SpineNewSkeletonDataResource.h"
#include "SpineNewSprite.h"
static void editor_init_callback() {
EditorNode::get_singleton()->add_editor_plugin(memnew(SpineRuntimeEditorPlugin(EditorNode::get_singleton())));
@ -77,9 +79,12 @@ void register_spine_godot_types() {
ClassDB::register_class<SpineAtlasResource>();
ClassDB::register_class<SpineSkeletonFileResource>();
ClassDB::register_class<SpineSkeletonDataResource>();
ClassDB::register_class<SpineNewSkeletonDataResource>();
ClassDB::register_class<SpineAnimationStateDataResource>();
ClassDB::register_class<SpineSprite>();
ClassDB::register_class<SpineNewSprite>();
ClassDB::register_class<SpineSkeleton>();
ClassDB::register_class<SpineNewSkeleton>();
ClassDB::register_class<SpineAnimationState>();
ClassDB::register_class<SpineAnimation>();
ClassDB::register_class<SpineEventData>();
@ -96,6 +101,7 @@ void register_spine_godot_types() {
ClassDB::register_class<SpineTransformConstraintData>();
ClassDB::register_class<SpinePathConstraintData>();
ClassDB::register_class<SpineBone>();
ClassDB::register_class<SpineNewBone>();
ClassDB::register_class<SpineSlot>();
ClassDB::register_class<SpineIkConstraint>();
ClassDB::register_class<SpinePathConstraint>();