diff --git a/spine-godot/godot/modules/spine_godot/SCsub b/spine-godot/godot/modules/spine_godot/SCsub index 4282df90e..05decba4a 100644 --- a/spine-godot/godot/modules/spine_godot/SCsub +++ b/spine-godot/godot/modules/spine_godot/SCsub @@ -2,6 +2,6 @@ Import('env') env_spine_runtime = env.Clone() -env_spine_runtime.Prepend(CPPPATH=["spine-cpp/include"]) +env_spine_runtime.Prepend(CPPPATH=["spine-cpp/include", "modules/spine_godot/spine-cpp/include"]) env_spine_runtime.add_source_files(env.modules_sources, "spine-cpp/src/spine/*.cpp") env_spine_runtime.add_source_files(env.modules_sources, "*.cpp") diff --git a/spine-godot/godot/modules/spine_godot/SpineAnimationState.cpp b/spine-godot/godot/modules/spine_godot/SpineAnimationState.cpp index b8d395a21..3becc9026 100644 --- a/spine-godot/godot/modules/spine_godot/SpineAnimationState.cpp +++ b/spine-godot/godot/modules/spine_godot/SpineAnimationState.cpp @@ -39,7 +39,6 @@ void SpineAnimationState::_bind_methods() { 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); @@ -57,13 +56,12 @@ SpineAnimationState::~SpineAnimationState() { } } -void SpineAnimationState::load_animation_state(Ref animation_state_data) { +void SpineAnimationState::create_animation_state(spine::AnimationStateData *animation_state_data) { if (animation_state) { delete animation_state; animation_state = NULL; } - animation_state = new spine::AnimationState(animation_state_data->get_animation_state_data()); - anim_state_data_res = animation_state_data; + animation_state = new spine::AnimationState(animation_state_data); } #define CHECK_V \ @@ -79,26 +77,26 @@ void SpineAnimationState::load_animation_state(Ref 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) { + 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 NULL; } - auto entry = animation_state->setAnimation(track, anim->get_spine_object(), loop); + auto entry = animation_state->setAnimation(track, anim, loop); Ref gd_entry(memnew(SpineTrackEntry)); gd_entry->set_spine_object(entry); return gd_entry; } Ref 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) { + 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 NULL; } - auto entry = animation_state->addAnimation(track, anim->get_spine_object(), loop, delay); + auto entry = animation_state->addAnimation(track, anim, loop, delay); Ref gd_entry(memnew(SpineTrackEntry)); gd_entry->set_spine_object(entry); return gd_entry; @@ -142,11 +140,6 @@ void SpineAnimationState::clear_track(uint64_t track_id) { animation_state->clearTrack(track_id); } -Ref SpineAnimationState::get_data() { - CHECK_X(NULL); - return anim_state_data_res; -} - float SpineAnimationState::get_time_scale() { CHECK_X(0); return animation_state->getTimeScale(); diff --git a/spine-godot/godot/modules/spine_godot/SpineAnimationState.h b/spine-godot/godot/modules/spine_godot/SpineAnimationState.h index 14b52d414..8736b3a18 100644 --- a/spine-godot/godot/modules/spine_godot/SpineAnimationState.h +++ b/spine-godot/godot/modules/spine_godot/SpineAnimationState.h @@ -43,13 +43,11 @@ protected: private: spine::AnimationState *animation_state; - Ref anim_state_data_res; - public: SpineAnimationState(); ~SpineAnimationState(); - void load_animation_state(Ref animation_state_data); + void create_animation_state(spine::AnimationStateData *animation_state_data); inline void set_spine_object(spine::AnimationState *animation_state) { this->animation_state = animation_state; } inline spine::AnimationState *get_spine_object() { return animation_state; } diff --git a/spine-godot/godot/modules/spine_godot/SpineNewBone.cpp b/spine-godot/godot/modules/spine_godot/SpineNewBone.cpp new file mode 100644 index 000000000..591728d57 --- /dev/null +++ b/spine-godot/godot/modules/spine_godot/SpineNewBone.cpp @@ -0,0 +1,439 @@ +/****************************************************************************** + * 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 "SpineNewBone.h" +#include "SpineNewSprite.h" +#include "SpineNewSkeleton.h" + +void SpineNewBone::_bind_methods() { + ClassDB::bind_method(D_METHOD("update_world_transform"), &SpineNewBone::update_world_transform); + ClassDB::bind_method(D_METHOD("set_to_setup_pose"), &SpineNewBone::set_to_setup_pose); + ClassDB::bind_method(D_METHOD("world_to_local", "world_position"), &SpineNewBone::world_to_local); + ClassDB::bind_method(D_METHOD("local_to_world", "local_position"), &SpineNewBone::local_to_world); + ClassDB::bind_method(D_METHOD("world_to_local_rotation", "world_rotation"), &SpineNewBone::world_to_local_rotation); + ClassDB::bind_method(D_METHOD("local_to_world_rotation", "local_rotation"), &SpineNewBone::local_to_world_rotation); + ClassDB::bind_method(D_METHOD("rotate_world"), &SpineNewBone::rotate_world); + ClassDB::bind_method(D_METHOD("get_world_to_local_rotation_x"), &SpineNewBone::get_world_to_local_rotation_x); + ClassDB::bind_method(D_METHOD("get_world_to_local_rotation_y"), &SpineNewBone::get_world_to_local_rotation_y); + ClassDB::bind_method(D_METHOD("get_data"), &SpineNewBone::get_data); + ClassDB::bind_method(D_METHOD("get_skeleton"), &SpineNewBone::get_skeleton); + ClassDB::bind_method(D_METHOD("get_parent"), &SpineNewBone::get_parent); + ClassDB::bind_method(D_METHOD("get_children"), &SpineNewBone::get_children); + ClassDB::bind_method(D_METHOD("get_x"), &SpineNewBone::get_x); + ClassDB::bind_method(D_METHOD("set_x", "v"), &SpineNewBone::set_x); + ClassDB::bind_method(D_METHOD("get_y"), &SpineNewBone::get_y); + ClassDB::bind_method(D_METHOD("set_y", "v"), &SpineNewBone::set_y); + ClassDB::bind_method(D_METHOD("get_rotation"), &SpineNewBone::get_rotation); + ClassDB::bind_method(D_METHOD("set_rotation", "v"), &SpineNewBone::set_rotation); + ClassDB::bind_method(D_METHOD("get_scale_x"), &SpineNewBone::get_scale_x); + ClassDB::bind_method(D_METHOD("set_scale_x", "v"), &SpineNewBone::set_scale_x); + ClassDB::bind_method(D_METHOD("get_scale_y"), &SpineNewBone::get_scale_y); + ClassDB::bind_method(D_METHOD("set_scale_y", "v"), &SpineNewBone::set_scale_y); + ClassDB::bind_method(D_METHOD("get_shear_x"), &SpineNewBone::get_shear_x); + ClassDB::bind_method(D_METHOD("set_shear_x", "v"), &SpineNewBone::set_shear_x); + ClassDB::bind_method(D_METHOD("get_shear_y"), &SpineNewBone::get_shear_y); + ClassDB::bind_method(D_METHOD("set_shear_y", "v"), &SpineNewBone::set_shear_y); + ClassDB::bind_method(D_METHOD("get_applied_rotation"), &SpineNewBone::get_applied_rotation); + ClassDB::bind_method(D_METHOD("set_applied_rotation", "v"), &SpineNewBone::set_applied_rotation); + ClassDB::bind_method(D_METHOD("get_a_x"), &SpineNewBone::get_a_x); + ClassDB::bind_method(D_METHOD("set_a_x", "v"), &SpineNewBone::set_a_x); + ClassDB::bind_method(D_METHOD("get_a_y"), &SpineNewBone::get_a_y); + ClassDB::bind_method(D_METHOD("set_a_y", "v"), &SpineNewBone::set_a_y); + ClassDB::bind_method(D_METHOD("get_a_scale_x"), &SpineNewBone::get_a_scale_x); + ClassDB::bind_method(D_METHOD("set_a_scale_x", "v"), &SpineNewBone::set_a_scale_x); + ClassDB::bind_method(D_METHOD("get_a_scale_y"), &SpineNewBone::get_a_scale_y); + ClassDB::bind_method(D_METHOD("set_a_scale_y", "v"), &SpineNewBone::set_a_scale_y); + ClassDB::bind_method(D_METHOD("get_a_shear_x"), &SpineNewBone::get_a_shear_x); + ClassDB::bind_method(D_METHOD("set_a_shear_x", "v"), &SpineNewBone::set_a_shear_x); + ClassDB::bind_method(D_METHOD("get_a_shear_y"), &SpineNewBone::get_a_shear_y); + ClassDB::bind_method(D_METHOD("set_a_shear_y", "v"), &SpineNewBone::set_a_shear_y); + ClassDB::bind_method(D_METHOD("get_a"), &SpineNewBone::get_a); + ClassDB::bind_method(D_METHOD("set_a", "v"), &SpineNewBone::set_a); + ClassDB::bind_method(D_METHOD("get_b"), &SpineNewBone::get_b); + ClassDB::bind_method(D_METHOD("set_b", "v"), &SpineNewBone::set_b); + ClassDB::bind_method(D_METHOD("get_c"), &SpineNewBone::get_c); + ClassDB::bind_method(D_METHOD("set_c", "v"), &SpineNewBone::set_c); + ClassDB::bind_method(D_METHOD("get_d"), &SpineNewBone::get_d); + ClassDB::bind_method(D_METHOD("set_d", "v"), &SpineNewBone::set_d); + ClassDB::bind_method(D_METHOD("get_world_x"), &SpineNewBone::get_world_x); + ClassDB::bind_method(D_METHOD("set_world_x", "v"), &SpineNewBone::set_world_x); + ClassDB::bind_method(D_METHOD("get_world_y"), &SpineNewBone::get_world_y); + ClassDB::bind_method(D_METHOD("set_world_y", "v"), &SpineNewBone::set_world_y); + ClassDB::bind_method(D_METHOD("get_world_rotation_x"), &SpineNewBone::get_world_rotation_x); + ClassDB::bind_method(D_METHOD("get_world_rotation_y"), &SpineNewBone::get_world_rotation_y); + ClassDB::bind_method(D_METHOD("get_world_scale_x"), &SpineNewBone::get_world_scale_x); + ClassDB::bind_method(D_METHOD("get_world_scale_y"), &SpineNewBone::get_world_scale_y); + ClassDB::bind_method(D_METHOD("is_active"), &SpineNewBone::is_active); + ClassDB::bind_method(D_METHOD("set_active", "v"), &SpineNewBone::set_active); + ClassDB::bind_method(D_METHOD("get_godot_transform"), &SpineNewBone::get_godot_transform); + ClassDB::bind_method(D_METHOD("set_godot_transform", "local_transform"), &SpineNewBone::set_godot_transform); + ClassDB::bind_method(D_METHOD("get_godot_global_transform"), &SpineNewBone::get_godot_global_transform); + ClassDB::bind_method(D_METHOD("set_godot_global_transform", "global_transform"), &SpineNewBone::set_godot_global_transform); + ClassDB::bind_method(D_METHOD("apply_world_transform_2d", "node2d"), &SpineNewBone::apply_world_transform_2d); +} + +SpineNewBone::SpineNewBone() : bone(NULL), the_sprite(nullptr) {} +SpineNewBone::~SpineNewBone() {} + +void SpineNewBone::update_world_transform() { + bone->updateWorldTransform(); +} + +void SpineNewBone::set_to_setup_pose() { + bone->setToSetupPose(); +} + +Vector2 SpineNewBone::world_to_local(Vector2 world_position) { + float x, y; + bone->worldToLocal(world_position.x, world_position.y, x, y); + return Vector2(x, y); +} + +Vector2 SpineNewBone::local_to_world(Vector2 local_position) { + float x, y; + bone->localToWorld(local_position.x, local_position.y, x, y); + return Vector2(x, y); +} + +float SpineNewBone::world_to_local_rotation(float world_rotation) { + return bone->worldToLocalRotation(world_rotation); +} + +float SpineNewBone::local_to_world_rotation(float local_rotation) { + return bone->localToWorldRotation(local_rotation); +} + +void SpineNewBone::rotate_world(float degrees) { + bone->rotateWorld(degrees); +} + +float SpineNewBone::get_world_to_local_rotation_x() { + return bone->getWorldToLocalRotationX(); +} +float SpineNewBone::get_world_to_local_rotation_y() { + return bone->getWorldToLocalRotationY(); +} + +Ref SpineNewBone::get_data() { + auto &bd = bone->getData(); + Ref gd_bd(memnew(SpineBoneData)); + gd_bd->set_spine_object(&bd); + return gd_bd; +} + +Ref SpineNewBone::get_skeleton() { + auto &s = bone->getSkeleton(); + Ref gd_s(memnew(SpineNewSkeleton)); + gd_s->set_spine_object(&s); + gd_s->set_spine_sprite(the_sprite); + return gd_s; +} + +Ref SpineNewBone::get_parent() { + auto b = bone->getParent(); + if (b == NULL) return NULL; + Ref gd_b(memnew(SpineNewBone)); + gd_b->set_spine_object(b); + gd_b->set_spine_sprite(the_sprite); + return gd_b; +} + +Array SpineNewBone::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(NULL); + Ref gd_b(memnew(SpineNewBone)); + gd_b->set_spine_object(b); + gd_b->set_spine_sprite(the_sprite); + gd_bs[i] = gd_b; + } + return gd_bs; +} + +float SpineNewBone::get_x() { + return bone->getX(); +} +void SpineNewBone::set_x(float v) { + bone->setX(v); +} + +float SpineNewBone::get_y() { + return bone->getY(); +} +void SpineNewBone::set_y(float v) { + bone->setY(v); +} + +float SpineNewBone::get_rotation() { + return bone->getRotation(); +} +void SpineNewBone::set_rotation(float v) { + bone->setRotation(v); +} + +float SpineNewBone::get_scale_x() { + return bone->getScaleX(); +} +void SpineNewBone::set_scale_x(float v) { + bone->setScaleX(v); +} + +float SpineNewBone::get_scale_y() { + return bone->getScaleY(); +} +void SpineNewBone::set_scale_y(float v) { + bone->setScaleY(v); +} + +float SpineNewBone::get_shear_x() { + return bone->getShearX(); +} +void SpineNewBone::set_shear_x(float v) { + bone->setShearX(v); +} + +float SpineNewBone::get_shear_y() { + return bone->getShearY(); +} +void SpineNewBone::set_shear_y(float v) { + bone->setShearY(v); +} + +float SpineNewBone::get_applied_rotation() { + return bone->getAppliedRotation(); +} +void SpineNewBone::set_applied_rotation(float v) { + bone->setAppliedRotation(v); +} + +float SpineNewBone::get_a_x() { + return bone->getAX(); +} +void SpineNewBone::set_a_x(float v) { + bone->setAX(v); +} + +float SpineNewBone::get_a_y() { + return bone->getAY(); +} +void SpineNewBone::set_a_y(float v) { + bone->setAY(v); +} + +float SpineNewBone::get_a_scale_x() { + return bone->getAScaleX(); +} +void SpineNewBone::set_a_scale_x(float v) { + bone->setAScaleX(v); +} + +float SpineNewBone::get_a_scale_y() { + return bone->getAScaleY(); +} +void SpineNewBone::set_a_scale_y(float v) { + bone->setAScaleY(v); +} + +float SpineNewBone::get_a_shear_x() { + return bone->getAShearX(); +} +void SpineNewBone::set_a_shear_x(float v) { + bone->setAShearX(v); +} + +float SpineNewBone::get_a_shear_y() { + return bone->getAShearY(); +} +void SpineNewBone::set_a_shear_y(float v) { + bone->setAShearY(v); +} + +float SpineNewBone::get_a() { + return bone->getA(); +} +void SpineNewBone::set_a(float v) { + bone->setA(v); +} + +float SpineNewBone::get_b() { + return bone->getB(); +} +void SpineNewBone::set_b(float v) { + bone->setB(v); +} + +float SpineNewBone::get_c() { + return bone->getC(); +} +void SpineNewBone::set_c(float v) { + bone->setC(v); +} + +float SpineNewBone::get_d() { + return bone->getD(); +} +void SpineNewBone::set_d(float v) { + bone->setD(v); +} + +float SpineNewBone::get_world_x() { + return bone->getWorldX(); +} +void SpineNewBone::set_world_x(float v) { + bone->setWorldX(v); +} + +float SpineNewBone::get_world_y() { + return bone->getWorldY(); +} +void SpineNewBone::set_world_y(float v) { + bone->setWorldY(v); +} + +float SpineNewBone::get_world_rotation_x() { + return bone->getWorldRotationX(); +} +float SpineNewBone::get_world_rotation_y() { + return bone->getWorldRotationY(); +} + +float SpineNewBone::get_world_scale_x() { + return bone->getWorldScaleX(); +} +float SpineNewBone::get_world_scale_y() { + return bone->getWorldScaleY(); +} + +bool SpineNewBone::is_active() { + return bone->isActive(); +} +void SpineNewBone::set_active(bool v) { + bone->setActive(v); +} + +// External feature functions +void SpineNewBone::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 SpineNewBone::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 SpineNewBone::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 SpineNewBone::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(the_sprite->get_parent()) : nullptr; + if (p) { + return p->get_global_transform() * res; + } + return res; +} + +void SpineNewBone::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 SpineNewBone::set_spine_sprite(SpineNewSprite *s) { + the_sprite = s; +} diff --git a/spine-godot/godot/modules/spine_godot/SpineNewBone.h b/spine-godot/godot/modules/spine_godot/SpineNewBone.h new file mode 100644 index 000000000..b3df4c334 --- /dev/null +++ b/spine-godot/godot/modules/spine_godot/SpineNewBone.h @@ -0,0 +1,169 @@ +/****************************************************************************** + * 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_SPINENEWBONE_H +#define GODOT_SPINENEWBONE_H + +#include +#include + +#include "SpineBoneData.h" + +class SpineNewSkeleton; +class SpineNewSprite; + +class SpineNewBone : public Reference { + GDCLASS(SpineNewBone, Reference); + +protected: + static void _bind_methods(); + +private: + spine::Bone *bone; + + SpineNewSprite *the_sprite; + +public: + SpineNewBone(); + ~SpineNewBone(); + + 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 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 get_data(); + + Ref get_skeleton(); + + Ref 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 diff --git a/spine-godot/godot/modules/spine_godot/SpineNewSkeleton.cpp b/spine-godot/godot/modules/spine_godot/SpineNewSkeleton.cpp new file mode 100644 index 000000000..7048314fa --- /dev/null +++ b/spine-godot/godot/modules/spine_godot/SpineNewSkeleton.cpp @@ -0,0 +1,343 @@ +/****************************************************************************** + * 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 "SpineNewSkeleton.h" + +void SpineNewSkeleton::_bind_methods() { + ClassDB::bind_method(D_METHOD("update_world_transform"), &SpineNewSkeleton::update_world_transform); + ClassDB::bind_method(D_METHOD("set_to_setup_pose"), &SpineNewSkeleton::set_to_setup_pose); + ClassDB::bind_method(D_METHOD("set_bones_to_setup_pose"), &SpineNewSkeleton::set_bones_to_setup_pose); + ClassDB::bind_method(D_METHOD("set_slots_to_setup_pose"), &SpineNewSkeleton::set_slots_to_setup_pose); + ClassDB::bind_method(D_METHOD("find_bone", "bone_name"), &SpineNewSkeleton::find_bone); + ClassDB::bind_method(D_METHOD("find_slot", "slot_name"), &SpineNewSkeleton::find_slot); + ClassDB::bind_method(D_METHOD("set_skin_by_name", "skin_name"), &SpineNewSkeleton::set_skin_by_name); + ClassDB::bind_method(D_METHOD("set_skin", "new_skin"), &SpineNewSkeleton::set_skin); + ClassDB::bind_method(D_METHOD("get_attachment_by_slot_name", "slot_name", "attachment_name"), &SpineNewSkeleton::get_attachment_by_slot_name); + ClassDB::bind_method(D_METHOD("get_attachment_by_slot_index", "slot_index", "attachment_name"), &SpineNewSkeleton::get_attachment_by_slot_index); + ClassDB::bind_method(D_METHOD("set_attachment", "slot_name", "attachment_name"), &SpineNewSkeleton::set_attachment); + ClassDB::bind_method(D_METHOD("find_ik_constraint", "constraint_name"), &SpineNewSkeleton::find_ik_constraint); + ClassDB::bind_method(D_METHOD("find_transform_constraint", "constraint_name"), &SpineNewSkeleton::find_transform_constraint); + 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_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); + ClassDB::bind_method(D_METHOD("get_ik_constraints"), &SpineNewSkeleton::get_ik_constraints); + ClassDB::bind_method(D_METHOD("get_path_constraints"), &SpineNewSkeleton::get_path_constraints); + ClassDB::bind_method(D_METHOD("get_transform_constraints"), &SpineNewSkeleton::get_transform_constraints); + ClassDB::bind_method(D_METHOD("get_skin"), &SpineNewSkeleton::get_skin); + ClassDB::bind_method(D_METHOD("get_color"), &SpineNewSkeleton::get_color); + ClassDB::bind_method(D_METHOD("set_color", "v"), &SpineNewSkeleton::set_color); + ClassDB::bind_method(D_METHOD("set_position", "pos"), &SpineNewSkeleton::set_position); + ClassDB::bind_method(D_METHOD("get_x"), &SpineNewSkeleton::get_x); + ClassDB::bind_method(D_METHOD("set_x", "v"), &SpineNewSkeleton::set_x); + ClassDB::bind_method(D_METHOD("get_y"), &SpineNewSkeleton::get_y); + ClassDB::bind_method(D_METHOD("set_y", "v"), &SpineNewSkeleton::set_y); + ClassDB::bind_method(D_METHOD("get_scale_x"), &SpineNewSkeleton::get_scale_x); + ClassDB::bind_method(D_METHOD("set_scale_x", "v"), &SpineNewSkeleton::set_scale_x); + ClassDB::bind_method(D_METHOD("get_scale_y"), &SpineNewSkeleton::get_scale_y); + ClassDB::bind_method(D_METHOD("set_scale_y", "v"), &SpineNewSkeleton::set_scale_y); +} + +SpineNewSkeleton::SpineNewSkeleton() : skeleton(nullptr), sprite(nullptr), skeleton_data_res(nullptr) { +} + +SpineNewSkeleton::~SpineNewSkeleton() { + delete skeleton; +} + +void SpineNewSkeleton::set_skeleton_data_res(Ref 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; +} + +#define S_T(x) (spine::String((x).utf8())) +void SpineNewSkeleton::update_world_transform() { + skeleton->updateWorldTransform(); +} + +void SpineNewSkeleton::set_to_setup_pose() { + skeleton->setToSetupPose(); +} + +void SpineNewSkeleton::set_bones_to_setup_pose() { + skeleton->setBonesToSetupPose(); +} + +void SpineNewSkeleton::set_slots_to_setup_pose() { + skeleton->setSlotsToSetupPose(); +} + +Ref SpineNewSkeleton::find_bone(const String &name) { + if (name.empty()) return nullptr; + auto bone = skeleton->findBone(S_T(name)); + if (!bone) return nullptr; + Ref bone_ref(memnew(SpineNewBone)); + bone_ref->set_spine_object(bone); + bone_ref->set_spine_sprite(sprite); + return bone_ref; +} + +Ref SpineNewSkeleton::find_slot(const String &name) { + if (name.empty()) return nullptr; + auto slot = skeleton->findSlot(S_T(name)); + if (!slot) return nullptr; + Ref slot_ref(memnew(SpineSlot)); + slot_ref->set_spine_object(slot); + return slot_ref; +} + +void SpineNewSkeleton::set_skin_by_name(const String &skin_name) { + skeleton->setSkin(S_T(skin_name)); +} +void SpineNewSkeleton::set_skin(Ref new_skin) { + if (new_skin.is_valid()) + skeleton->setSkin(new_skin->get_spine_object()); + else + skeleton->setSkin(nullptr); +} + +Ref SpineNewSkeleton::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 == nullptr) return nullptr; + Ref gd_a(memnew(SpineAttachment)); + gd_a->set_spine_object(a); + return gd_a; +} + +Ref SpineNewSkeleton::get_attachment_by_slot_index(int slot_index, const String &attachment_name) { + auto a = skeleton->getAttachment(slot_index, S_T(attachment_name)); + if (a == nullptr) return nullptr; + Ref gd_a(memnew(SpineAttachment)); + gd_a->set_spine_object(a); + return gd_a; +} + +void SpineNewSkeleton::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) == nullptr); + skeleton->setAttachment(S_T(slot_name), S_T(attachment_name)); +} + +Ref SpineNewSkeleton::find_ik_constraint(const String &constraint_name) { + if (constraint_name.empty()) return nullptr; + auto c = skeleton->findIkConstraint(S_T(constraint_name)); + if (c == nullptr) return nullptr; + Ref gd_c(memnew(SpineIkConstraint)); + gd_c->set_spine_object(c); + return gd_c; +} +Ref SpineNewSkeleton::find_transform_constraint(const String &constraint_name) { + if (constraint_name.empty()) return nullptr; + auto c = skeleton->findTransformConstraint(S_T(constraint_name)); + if (c == nullptr) return nullptr; + Ref gd_c(memnew(SpineTransformConstraint)); + gd_c->set_spine_object(c); + return gd_c; +} +Ref SpineNewSkeleton::find_path_constraint(const String &constraint_name) { + if (constraint_name.empty()) return nullptr; + auto c = skeleton->findPathConstraint(S_T(constraint_name)); + if (c == nullptr) return nullptr; + Ref gd_c(memnew(SpinePathConstraint)); + gd_c->set_spine_object(c); + return gd_c; +} + +Dictionary SpineNewSkeleton::get_bounds() { + float x, y, w, h; + spine::Vector 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 SpineNewSkeleton::get_root_bone() { + auto b = skeleton->getRootBone(); + if (b == nullptr) return nullptr; + Ref gd_b(memnew(SpineNewBone)); + gd_b->set_spine_object(b); + gd_b->set_spine_sprite(sprite); + return gd_b; +} + +Ref SpineNewSkeleton::get_data() const { + return skeleton_data_res; +} + +Array SpineNewSkeleton::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 == nullptr) gd_as[i] = Ref(nullptr); + Ref gd_a(memnew(SpineNewBone)); + gd_a->set_spine_object(b); + gd_a->set_spine_sprite(sprite); + gd_as[i] = gd_a; + } + return gd_as; +} +Array SpineNewSkeleton::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 == nullptr) gd_as[i] = Ref(nullptr); + Ref gd_a(memnew(SpineSlot)); + gd_a->set_spine_object(b); + gd_as[i] = gd_a; + } + return gd_as; +} +Array SpineNewSkeleton::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 == nullptr) gd_as[i] = Ref(nullptr); + Ref gd_a(memnew(SpineSlot)); + gd_a->set_spine_object(b); + gd_as[i] = gd_a; + } + return gd_as; +} +Array SpineNewSkeleton::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 == nullptr) gd_as[i] = Ref(nullptr); + Ref gd_a(memnew(SpineIkConstraint)); + gd_a->set_spine_object(b); + gd_as[i] = gd_a; + } + return gd_as; +} +Array SpineNewSkeleton::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 == nullptr) gd_as[i] = Ref(nullptr); + Ref gd_a(memnew(SpinePathConstraint)); + gd_a->set_spine_object(b); + gd_as[i] = gd_a; + } + return gd_as; +} +Array SpineNewSkeleton::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 == nullptr) gd_as[i] = Ref(nullptr); + Ref gd_a(memnew(SpineTransformConstraint)); + gd_a->set_spine_object(b); + gd_as[i] = gd_a; + } + return gd_as; +} + +Ref SpineNewSkeleton::get_skin() { + auto s = skeleton->getSkin(); + if (s == nullptr) return nullptr; + Ref gd_s(memnew(SpineSkin)); + gd_s->set_spine_object(s); + return gd_s; +} + +Color SpineNewSkeleton::get_color() { + auto &c = skeleton->getColor(); + return Color(c.r, c.g, c.b, c.a); +} +void SpineNewSkeleton::set_color(Color v) { + auto &c = skeleton->getColor(); + c.set(v.r, v.g, v.b, v.a); +} + +void SpineNewSkeleton::set_position(Vector2 pos) { + skeleton->setPosition(pos.x, pos.y); +} + +float SpineNewSkeleton::get_x() { + return skeleton->getX(); +} +void SpineNewSkeleton::set_x(float v) { + skeleton->setX(v); +} + +float SpineNewSkeleton::get_y() { + return skeleton->getY(); +} +void SpineNewSkeleton::set_y(float v) { + skeleton->setY(v); +} + +float SpineNewSkeleton::get_scale_x() { + return skeleton->getScaleX(); +} +void SpineNewSkeleton::set_scale_x(float v) { + skeleton->setScaleX(v); +} + +float SpineNewSkeleton::get_scale_y() { + return skeleton->getScaleY(); +} +void SpineNewSkeleton::set_scale_y(float v) { + skeleton->setScaleY(v); +} + +void SpineNewSkeleton::set_spine_sprite(SpineNewSprite *s) { + sprite = s; +} diff --git a/spine-godot/godot/modules/spine_godot/SpineNewSkeleton.h b/spine-godot/godot/modules/spine_godot/SpineNewSkeleton.h new file mode 100644 index 000000000..a1d3d9cad --- /dev/null +++ b/spine-godot/godot/modules/spine_godot/SpineNewSkeleton.h @@ -0,0 +1,127 @@ +/****************************************************************************** + * 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_SPINENEWSKELETON_H +#define GODOT_SPINENEWSKELETON_H + +#include + +#include "SpineNewSkeletonDataResource.h" +#include "SpineNewBone.h" +#include "SpineSlot.h" +#include "SpineIkConstraint.h" +#include "SpineTransformConstraint.h" + +class SpineNewSprite; + +class SpineNewSkeleton : public Reference { + GDCLASS(SpineNewSkeleton, Reference); + +protected: + static void _bind_methods(); + +private: + spine::Skeleton *skeleton; + SpineNewSprite *sprite; + Ref skeleton_data_res; + +public: + SpineNewSkeleton(); + ~SpineNewSkeleton(); + + void set_skeleton_data_res(Ref data_res); + + inline void set_spine_object(spine::Skeleton *s) { + skeleton = s; + } + inline spine::Skeleton *get_spine_object() { + return skeleton; + } + + void set_spine_sprite(SpineNewSprite *s); + + + void update_world_transform(); + + void set_to_setup_pose(); + + void set_bones_to_setup_pose(); + + void set_slots_to_setup_pose(); + + Ref find_bone(const String &name); + + Ref find_slot(const String &name); + + void set_skin_by_name(const String &skin_name); + void set_skin(Ref new_skin); + + Ref get_attachment_by_slot_name(const String &slot_name, const String &attachment_name); + Ref get_attachment_by_slot_index(int slot_index, const String &attachment_name); + + void set_attachment(const String &slot_name, const String &attachment_name); + + Ref find_ik_constraint(const String &constraint_name); + Ref find_transform_constraint(const String &constraint_name); + Ref find_path_constraint(const String &constraint_name); + + Dictionary get_bounds(); + + Ref get_root_bone(); + + Ref 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 get_skin(); + + Color get_color(); + void set_color(Color 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_SPINENEWSKELETON_H diff --git a/spine-godot/godot/modules/spine_godot/SpineNewSkeletonDataResource.cpp b/spine-godot/godot/modules/spine_godot/SpineNewSkeletonDataResource.cpp index 78a5e46c2..05d9364f2 100644 --- a/spine-godot/godot/modules/spine_godot/SpineNewSkeletonDataResource.cpp +++ b/spine-godot/godot/modules/spine_godot/SpineNewSkeletonDataResource.cpp @@ -30,428 +30,409 @@ #include "SpineNewSkeletonDataResource.h" 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); ClassDB::bind_method(D_METHOD("get_atlas_res"), &SpineNewSkeletonDataResource::get_atlas_res); ClassDB::bind_method(D_METHOD("set_skeleton_file_res", "skeleton_file_res"), &SpineNewSkeletonDataResource::set_skeleton_file_res); ClassDB::bind_method(D_METHOD("get_skeleton_file_res"), &SpineNewSkeletonDataResource::get_skeleton_file_res); - ClassDB::bind_method(D_METHOD("is_skeleton_data_loaded"), &SpineNewSkeletonDataResource::is_skeleton_data_loaded); - ClassDB::bind_method(D_METHOD("find_animation", "animation_name"), &SpineNewSkeletonDataResource::find_animation); - ClassDB::bind_method(D_METHOD("get_skeleton_name"), &SpineNewSkeletonDataResource::get_skeleton_name); - ClassDB::bind_method(D_METHOD("set_skeleton_name", "skeleton_name"), &SpineNewSkeletonDataResource::set_skeleton_name); - ClassDB::bind_method(D_METHOD("get_x"), &SpineNewSkeletonDataResource::get_x); - ClassDB::bind_method(D_METHOD("set_x", "v"), &SpineNewSkeletonDataResource::set_x); - ClassDB::bind_method(D_METHOD("get_y"), &SpineNewSkeletonDataResource::get_y); - ClassDB::bind_method(D_METHOD("set_y", "v"), &SpineNewSkeletonDataResource::set_y); - ClassDB::bind_method(D_METHOD("get_width"), &SpineNewSkeletonDataResource::get_width); - ClassDB::bind_method(D_METHOD("get_height"), &SpineNewSkeletonDataResource::get_height); - ClassDB::bind_method(D_METHOD("get_version"), &SpineNewSkeletonDataResource::get_version); - ClassDB::bind_method(D_METHOD("get_fps"), &SpineNewSkeletonDataResource::get_fps); - ClassDB::bind_method(D_METHOD("set_fps", "v"), &SpineNewSkeletonDataResource::set_fps); + // Spine API ClassDB::bind_method(D_METHOD("find_bone", "bone_name"), &SpineNewSkeletonDataResource::find_bone); ClassDB::bind_method(D_METHOD("find_slot", "slot_name"), &SpineNewSkeletonDataResource::find_slot); ClassDB::bind_method(D_METHOD("find_skin", "skin_name"), &SpineNewSkeletonDataResource::find_skin); ClassDB::bind_method(D_METHOD("find_event", "event_data_name"), &SpineNewSkeletonDataResource::find_event); + ClassDB::bind_method(D_METHOD("find_animation", "animation_name"), &SpineNewSkeletonDataResource::find_animation); ClassDB::bind_method(D_METHOD("find_ik_constraint_data", "constraint_name"), &SpineNewSkeletonDataResource::find_ik_constraint); ClassDB::bind_method(D_METHOD("find_transform_constraint_data", "constraint_name"), &SpineNewSkeletonDataResource::find_transform_constraint); ClassDB::bind_method(D_METHOD("find_path_constraint_data", "constraint_name"), &SpineNewSkeletonDataResource::find_path_constraint); - ClassDB::bind_method(D_METHOD("get_all_bone_data"), &SpineNewSkeletonDataResource::get_bones); - ClassDB::bind_method(D_METHOD("get_all_slot_data"), &SpineNewSkeletonDataResource::get_slots); + ClassDB::bind_method(D_METHOD("get_skeleton_name"), &SpineNewSkeletonDataResource::get_skeleton_name); + ClassDB::bind_method(D_METHOD("get_bones"), &SpineNewSkeletonDataResource::get_bones); + ClassDB::bind_method(D_METHOD("get_slots"), &SpineNewSkeletonDataResource::get_slots); ClassDB::bind_method(D_METHOD("get_skins"), &SpineNewSkeletonDataResource::get_skins); ClassDB::bind_method(D_METHOD("get_default_skin"), &SpineNewSkeletonDataResource::get_default_skin); - ClassDB::bind_method(D_METHOD("set_default_skin", "v"), &SpineNewSkeletonDataResource::set_default_skin); - ClassDB::bind_method(D_METHOD("get_all_event_data"), &SpineNewSkeletonDataResource::get_events); + ClassDB::bind_method(D_METHOD("set_default_skin", "skin"), &SpineNewSkeletonDataResource::set_default_skin); + ClassDB::bind_method(D_METHOD("get_events"), &SpineNewSkeletonDataResource::get_events); ClassDB::bind_method(D_METHOD("get_animations"), &SpineNewSkeletonDataResource::get_animations); - ClassDB::bind_method(D_METHOD("get_all_ik_constraint_data"), &SpineNewSkeletonDataResource::get_ik_constraints); - ClassDB::bind_method(D_METHOD("get_all_transform_constraint_data"), &SpineNewSkeletonDataResource::get_transform_constraints); - ClassDB::bind_method(D_METHOD("get_all_path_constraint_data"), &SpineNewSkeletonDataResource::get_path_constraints); + ClassDB::bind_method(D_METHOD("get_ik_constraints"), &SpineNewSkeletonDataResource::get_ik_constraints); + ClassDB::bind_method(D_METHOD("get_transform_constraints"), &SpineNewSkeletonDataResource::get_transform_constraints); + ClassDB::bind_method(D_METHOD("get_path_constraints"), &SpineNewSkeletonDataResource::get_path_constraints); + ClassDB::bind_method(D_METHOD("get_x"), &SpineNewSkeletonDataResource::get_x); + ClassDB::bind_method(D_METHOD("get_y"), &SpineNewSkeletonDataResource::get_y); + ClassDB::bind_method(D_METHOD("get_width"), &SpineNewSkeletonDataResource::get_width); + ClassDB::bind_method(D_METHOD("get_height"), &SpineNewSkeletonDataResource::get_height); + ClassDB::bind_method(D_METHOD("get_version"), &SpineNewSkeletonDataResource::get_version); + ClassDB::bind_method(D_METHOD("get_hash"), &SpineNewSkeletonDataResource::get_hash); + ClassDB::bind_method(D_METHOD("get_images_path"), &SpineNewSkeletonDataResource::get_images_path); + ClassDB::bind_method(D_METHOD("get_audio_path"), &SpineNewSkeletonDataResource::get_audio_path); + ClassDB::bind_method(D_METHOD("get_fps"), &SpineNewSkeletonDataResource::get_fps); - ADD_SIGNAL(MethodInfo("skeleton_data_loaded")); - ADD_SIGNAL(MethodInfo("atlas_res_changed")); - ADD_SIGNAL(MethodInfo("skeleton_file_res_changed")); + ADD_SIGNAL(MethodInfo("skeleton_data_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_file_res", PropertyHint::PROPERTY_HINT_RESOURCE_TYPE, "SpineSkeletonFileResource"), "set_skeleton_file_res", "get_skeleton_file_res"); } -SpineNewSkeletonDataResource::SpineNewSkeletonDataResource() : valid(false), spine_object(false), skeleton_data(NULL) { +SpineNewSkeletonDataResource::SpineNewSkeletonDataResource() : skeleton_data(nullptr), animation_state_data(nullptr) { } SpineNewSkeletonDataResource::~SpineNewSkeletonDataResource() { - if (skeleton_data && !spine_object) { - delete skeleton_data; - skeleton_data = NULL; - } + delete skeleton_data; + delete animation_state_data; } -bool SpineNewSkeletonDataResource::is_skeleton_data_loaded() const { - return valid || spine_object; +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 &binary) { - valid = false; if (skeleton_data) { delete skeleton_data; - skeleton_data = NULL; + skeleton_data = nullptr; + } + if (animation_state_data) { + delete animation_state_data; + animation_state_data = nullptr; } - if ((json.empty() && binary.empty()) || atlas == NULL) return; + if ((json.empty() && binary.empty()) || atlas == nullptr) return; - spine::SkeletonData *skeletonData = NULL; + spine::SkeletonData *data; if (!json.empty()) { spine::SkeletonJson skeletonJson(atlas); - skeletonData = skeletonJson.readSkeletonData(json.utf8()); - if (!skeletonData) { + data = skeletonJson.readSkeletonData(json.utf8()); + if (!data) { print_error(String("Error while loading skeleton data: ") + get_path()); print_error(String("Error message: ") + skeletonJson.getError().buffer()); return; } } else { spine::SkeletonBinary skeletonBinary(atlas); - skeletonData = skeletonBinary.readSkeletonData(binary.ptr(), binary.size()); - if (!skeletonData) { + data = skeletonBinary.readSkeletonData(binary.ptr(), binary.size()); + if (!data) { print_error(String("Error while loading skeleton data: ") + get_path()); print_error(String("Error message: ") + skeletonBinary.getError().buffer()); return; } } - skeleton_data = skeletonData; - valid = true; + skeleton_data = data; + animation_state_data = new spine::AnimationStateData(data); } -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()); - if (valid) { - emit_signal("skeleton_data_loaded"); - } - } +bool SpineNewSkeletonDataResource::is_skeleton_data_loaded() const { + return skeleton_data != nullptr; } -void SpineNewSkeletonDataResource::set_atlas_res(const Ref &a) { - atlas_res = a; - valid = false; - emit_signal("atlas_res_changed"); +void SpineNewSkeletonDataResource::set_atlas_res(const Ref &atlas) { + atlas_res = atlas; update_skeleton_data(); } Ref SpineNewSkeletonDataResource::get_atlas_res() { return atlas_res; } -void SpineNewSkeletonDataResource::set_skeleton_file_res(const Ref &s) { - skeleton_file_res = s; - valid = false; - emit_signal("skeleton_file_res_changed"); +void SpineNewSkeletonDataResource::set_skeleton_file_res(const Ref &skeleton_file) { + skeleton_file_res = skeleton_file; update_skeleton_data(); } Ref SpineNewSkeletonDataResource::get_skeleton_file_res() { return skeleton_file_res; } +void SpineNewSkeletonDataResource::get_animation_names(Vector &animation_names) const { + animation_names.clear(); + if (!is_skeleton_data_loaded()) return; + auto animations = skeleton_data->getAnimations(); + for (size_t i = 0; i < animations.size(); ++i) { + auto animation = animations[i]; + animation_names.push_back(animation->getName().buffer()); + } +} + +void SpineNewSkeletonDataResource::get_skin_names(Vector &skin_names) const { + skin_names.clear(); + if (!is_skeleton_data_loaded()) return; + auto skins = skeleton_data->getSkins(); + for (size_t i = 0; i < skins.size(); ++i) { + auto skin = skins[i]; + skin_names.push_back(skin->getName().buffer()); + } +} + +void SpineNewSkeletonDataResource::_get_property_list(List *p_list) const { + PropertyInfo property; + Vector animation_names; + + property.name = "animations"; + property.type = Variant::STRING; + get_animation_names(animation_names); + property.hint_string = String(",").join(animation_names); + property.hint = PROPERTY_HINT_ENUM; + p_list->push_back(property); + + property.name = "skins"; + property.type = Variant::STRING; + get_skin_names(animation_names); + property.hint_string = String(",").join(animation_names); + property.hint = PROPERTY_HINT_ENUM; + p_list->push_back(property); +} + #define CHECK(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 SpineNewSkeletonDataResource::find_animation(const String &animation_name) { - CHECK(NULL); - if (animation_name.empty()) { - return NULL; - } - auto a = skeleton_data->findAnimation(S_T(animation_name)); - if (!a) return NULL; - Ref sa(memnew(SpineAnimation)); - sa->set_spine_object(a); - return sa; +#define S_T(x) (spine::String((x).utf8())) +Ref SpineNewSkeletonDataResource::find_animation(const String &animation_name) const { + CHECK(nullptr) + if (animation_name.empty()) return nullptr; + auto animation = skeleton_data->findAnimation(S_T(animation_name)); + if (!animation) return nullptr; + Ref animation_ref(memnew(SpineAnimation)); + animation_ref->set_spine_object(animation); + return animation_ref; } -String SpineNewSkeletonDataResource::get_skeleton_name() { - CHECK(""); + +Ref SpineNewSkeletonDataResource::find_bone(const String &bone_name) const { + CHECK(nullptr) + if (bone_name.empty()) return nullptr; + auto bone = skeleton_data->findBone(S_T(bone_name)); + if (bone == nullptr) return nullptr; + Ref bone_ref(memnew(SpineBoneData)); + bone_ref->set_spine_object(bone); + return bone_ref; +} + +Ref SpineNewSkeletonDataResource::find_slot(const String &slot_name) const { + CHECK(nullptr) + if (slot_name.empty()) return nullptr; + auto slot = skeleton_data->findSlot(S_T(slot_name)); + if (slot == nullptr) return nullptr; + Ref slot_ref(memnew(SpineSlotData)); + slot_ref->set_spine_object(slot); + return slot_ref; +} + +Ref SpineNewSkeletonDataResource::find_skin(const String &skin_name) const { + CHECK(nullptr) + if (skin_name.empty()) return nullptr; + auto skin = skeleton_data->findSkin(S_T(skin_name)); + if (skin == nullptr) return nullptr; + Ref skin_ref(memnew(SpineSkin)); + skin_ref->set_spine_object(skin); + return skin_ref; +} + +Ref SpineNewSkeletonDataResource::find_event(const String &event_data_name) const { + CHECK(nullptr) + if (event_data_name.empty()) return nullptr; + auto event = skeleton_data->findEvent(S_T(event_data_name)); + if (event == nullptr) return nullptr; + Ref event_ref(memnew(SpineEventData)); + event_ref->set_spine_object(event); + return event_ref; +} + +Ref SpineNewSkeletonDataResource::find_ik_constraint(const String &constraint_name) const { + CHECK(nullptr) + if (constraint_name.empty()) return nullptr; + auto constraint = skeleton_data->findIkConstraint(S_T(constraint_name)); + if (constraint == nullptr) return nullptr; + Ref constraint_ref(memnew(SpineIkConstraintData)); + constraint_ref->set_spine_object(constraint); + return constraint_ref; +} +Ref SpineNewSkeletonDataResource::find_transform_constraint(const String &constraint_name) const { + CHECK(nullptr) + if (constraint_name.empty()) return nullptr; + auto constraint = skeleton_data->findTransformConstraint(S_T(constraint_name)); + if (constraint == nullptr) return nullptr; + Ref constraint_ref(memnew(SpineTransformConstraintData)); + constraint_ref->set_spine_object(constraint); + return constraint_ref; +} +Ref SpineNewSkeletonDataResource::find_path_constraint(const String &constraint_name) const { + CHECK(nullptr) + if (constraint_name.empty()) return nullptr; + auto constraint = skeleton_data->findPathConstraint(S_T(constraint_name)); + if (constraint == nullptr) return nullptr; + Ref constraint_ref(memnew(SpinePathConstraintData)); + constraint_ref->set_spine_object(constraint); + return constraint_ref; +} + +String SpineNewSkeletonDataResource::get_skeleton_name() const{ + CHECK("") return skeleton_data->getName().buffer(); } -void SpineNewSkeletonDataResource::set_skeleton_name(const String &v) { - CHECK(); - skeleton_data->setName(S_T(v)); +Array SpineNewSkeletonDataResource::get_bones() const { + Array bone_refs; + CHECK(bone_refs) + auto bones = skeleton_data->getBones(); + bone_refs.resize((int)bones.size()); + for (int i = 0; i < bones.size(); ++i) { + Ref bone_ref(memnew(SpineBoneData)); + bone_ref->set_spine_object(bones[i]); + bone_refs[i] = bone_ref; + } + return bone_refs; } -float SpineNewSkeletonDataResource::get_x() { - CHECK(0); +Array SpineNewSkeletonDataResource::get_slots() const { + Array slot_refs; + CHECK(slot_refs) + auto slots = skeleton_data->getSlots(); + slot_refs.resize((int)slots.size()); + for (int i = 0; i < slots.size(); ++i) { + Ref slot_ref(memnew(SpineSlotData)); + slot_ref->set_spine_object(slots[i]); + slot_refs[i] = slot_ref; + } + return slot_refs; +} + +Array SpineNewSkeletonDataResource::get_skins() const { + Array skin_refs; + CHECK(skin_refs) + auto skins = skeleton_data->getSkins(); + skin_refs.resize((int)skins.size()); + for (int i = 0; i < skins.size(); ++i) { + Ref skin_ref(memnew(SpineSkin)); + skin_ref->set_spine_object(skins[i]); + skin_refs[i] = skin_ref; + } + return skin_refs; +} + +Ref SpineNewSkeletonDataResource::get_default_skin() const { + CHECK(nullptr) + auto skin = skeleton_data->getDefaultSkin(); + if (skin == nullptr) return nullptr; + Ref skin_ref(memnew(SpineSkin)); + skin_ref->set_spine_object(skin); + return skin_ref; +} + +void SpineNewSkeletonDataResource::set_default_skin(Ref skin) { + CHECK() + if (skin.is_valid()) + skeleton_data->setDefaultSkin(skin->get_spine_object()); + else + skeleton_data->setDefaultSkin(nullptr); +} + +Array SpineNewSkeletonDataResource::get_events() const { + Array event_refs; + CHECK(event_refs) + auto events = skeleton_data->getEvents(); + event_refs.resize((int)events.size()); + for (int i = 0; i < events.size(); ++i) { + Ref event_ref(memnew(SpineEventData)); + event_ref->set_spine_object(events[i]); + event_refs[i] = event_ref; + } + return event_refs; +} + +Array SpineNewSkeletonDataResource::get_animations() const { + Array animation_refs; + CHECK(animation_refs) + auto animations = skeleton_data->getAnimations(); + animation_refs.resize((int)animations.size()); + for (int i = 0; i < animations.size(); ++i) { + Ref animation_ref(memnew(SpineAnimation)); + animation_ref->set_spine_object(animations[i]); + animation_refs[i] = animation_ref; + } + return animation_refs; +} + +Array SpineNewSkeletonDataResource::get_ik_constraints() const { + Array constraint_refs; + CHECK(constraint_refs) + auto constraints = skeleton_data->getIkConstraints(); + constraint_refs.resize((int)constraints.size()); + for (int i = 0; i < constraints.size(); ++i) { + Ref constraint_ref(memnew(SpineIkConstraintData)); + constraint_ref->set_spine_object(constraints[i]); + constraint_refs[i] = constraint_ref; + } + return constraint_refs; +} + +Array SpineNewSkeletonDataResource::get_transform_constraints() const { + Array constraint_refs; + CHECK(constraint_refs) + auto constraints = skeleton_data->getTransformConstraints(); + constraint_refs.resize((int)constraints.size()); + for (int i = 0; i < constraints.size(); ++i) { + Ref constraint_ref(memnew(SpineTransformConstraintData)); + constraint_ref->set_spine_object(constraints[i]); + constraint_refs[i] = constraint_ref; + } + return constraint_refs; +} + +Array SpineNewSkeletonDataResource::get_path_constraints() const { + Array constraint_refs; + CHECK(constraint_refs) + auto constraints = skeleton_data->getPathConstraints(); + constraint_refs.resize((int)constraints.size()); + for (int i = 0; i < constraints.size(); ++i) { + Ref constraint_ref(memnew(SpinePathConstraintData)); + constraint_ref->set_spine_object(constraints[i]); + constraint_refs[i] = constraint_ref; + } + return constraint_refs; +} + +float SpineNewSkeletonDataResource::get_x() const{ + CHECK(0) return skeleton_data->getX(); } -void SpineNewSkeletonDataResource::set_x(float v) { - CHECK(); - skeleton_data->setX(v); -} -float SpineNewSkeletonDataResource::get_y() { - CHECK(0); +float SpineNewSkeletonDataResource::get_y() const { + CHECK(0) return skeleton_data->getY(); } -void SpineNewSkeletonDataResource::set_y(float v) { - CHECK(); - skeleton_data->setY(v); -} -float SpineNewSkeletonDataResource::get_width() { - CHECK(0); + +float SpineNewSkeletonDataResource::get_width() const{ + CHECK(0) return skeleton_data->getWidth(); } -float SpineNewSkeletonDataResource::get_height() { - CHECK(0); + +float SpineNewSkeletonDataResource::get_height() const { + CHECK(0) return skeleton_data->getHeight(); } -String SpineNewSkeletonDataResource::get_version() { - CHECK("error"); + +String SpineNewSkeletonDataResource::get_version() const { + CHECK("") return skeleton_data->getVersion().buffer(); } -float SpineNewSkeletonDataResource::get_fps() { - CHECK(0); + +String SpineNewSkeletonDataResource::get_hash() const { + CHECK("") + return skeleton_data->getHash().buffer(); +} + + +String SpineNewSkeletonDataResource::get_images_path() const { + CHECK("") + return skeleton_data->getImagesPath().buffer(); +} + +String SpineNewSkeletonDataResource::get_audio_path() const { + CHECK("") + return skeleton_data->getAudioPath().buffer(); +} + +float SpineNewSkeletonDataResource::get_fps() const { + CHECK(0) return skeleton_data->getFps(); } -void SpineNewSkeletonDataResource::set_fps(float v) { - CHECK(); - skeleton_data->setFps(v); -} - -Ref SpineNewSkeletonDataResource::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 gd_b(memnew(SpineBoneData)); - gd_b->set_spine_object(b); - return gd_b; -} - -Ref SpineNewSkeletonDataResource::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 gd_b(memnew(SpineSlotData)); - gd_b->set_spine_object(b); - return gd_b; -} - -Ref SpineNewSkeletonDataResource::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 gd_b(memnew(SpineSkin)); - gd_b->set_spine_object(b); - return gd_b; -} - -Ref SpineNewSkeletonDataResource::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 gd_b(memnew(SpineEventData)); - gd_b->set_spine_object(b); - return gd_b; -} - -Ref SpineNewSkeletonDataResource::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 gd_b(memnew(SpineIkConstraintData)); - gd_b->set_spine_object(b); - return gd_b; -} -Ref SpineNewSkeletonDataResource::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 gd_b(memnew(SpineTransformConstraintData)); - gd_b->set_spine_object(b); - return gd_b; -} -Ref SpineNewSkeletonDataResource::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 gd_b(memnew(SpinePathConstraintData)); - gd_b->set_spine_object(b); - return gd_b; -} - -Array SpineNewSkeletonDataResource::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(NULL); - else { - Ref gd_b(memnew(SpineBoneData)); - gd_b->set_spine_object(bs[i]); - gd_bs[i] = gd_b; - } - } - return gd_bs; -} -Array SpineNewSkeletonDataResource::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(NULL); - else { - Ref gd_b(memnew(SpineSlotData)); - gd_b->set_spine_object(bs[i]); - gd_bs[i] = gd_b; - } - } - return gd_bs; -} -Array SpineNewSkeletonDataResource::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(NULL); - else { - Ref gd_b(memnew(SpineSkin)); - gd_b->set_spine_object(bs[i]); - gd_bs[i] = gd_b; - } - } - return gd_bs; -} - -Ref SpineNewSkeletonDataResource::get_default_skin() { - auto b = skeleton_data->getDefaultSkin(); - if (b == NULL) return NULL; - Ref gd_b(memnew(SpineSkin)); - gd_b->set_spine_object(b); - return gd_b; -} -void SpineNewSkeletonDataResource::set_default_skin(Ref v) { - if (v.is_valid()) { - skeleton_data->setDefaultSkin(v->get_spine_object()); - } else - skeleton_data->setDefaultSkin(NULL); -} - -Array SpineNewSkeletonDataResource::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(NULL); - else { - Ref gd_b(memnew(SpineEventData)); - gd_b->set_spine_object(bs[i]); - gd_bs[i] = gd_b; - } - } - return gd_bs; -} -Array SpineNewSkeletonDataResource::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(NULL); - else { - Ref gd_b(memnew(SpineAnimation)); - gd_b->set_spine_object(bs[i]); - gd_bs[i] = gd_b; - } - } - return gd_bs; -} -Array SpineNewSkeletonDataResource::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(NULL); - else { - Ref gd_b(memnew(SpineIkConstraintData)); - gd_b->set_spine_object(bs[i]); - gd_bs[i] = gd_b; - } - } - return gd_bs; -} -Array SpineNewSkeletonDataResource::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(NULL); - else { - Ref gd_b(memnew(SpineTransformConstraintData)); - gd_b->set_spine_object(bs[i]); - gd_bs[i] = gd_b; - } - } - return gd_bs; -} -Array SpineNewSkeletonDataResource::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(NULL); - else { - Ref 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 - -//External feature functions -void SpineNewSkeletonDataResource::get_animation_names(Vector &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 SpineNewSkeletonDataResource::get_skin_names(Vector &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(as[i]); - if (a.is_valid()) { - res.set(i, a->get_skin_name()); - } else { - res.set(i, ""); - } - } -} - -void SpineNewSkeletonDataResource::_get_property_list(List *p_list) const { - PropertyInfo p; - Vector 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); -} diff --git a/spine-godot/godot/modules/spine_godot/SpineNewSkeletonDataResource.h b/spine-godot/godot/modules/spine_godot/SpineNewSkeletonDataResource.h index 5cc939022..bffba7ec5 100644 --- a/spine-godot/godot/modules/spine_godot/SpineNewSkeletonDataResource.h +++ b/spine-godot/godot/modules/spine_godot/SpineNewSkeletonDataResource.h @@ -21,86 +21,92 @@ protected: private: Ref atlas_res; Ref skeleton_file_res; - bool valid; - bool spine_object; spine::SkeletonData *skeleton_data; + spine::AnimationStateData *animation_state_data; void update_skeleton_data(); + void load_res(spine::Atlas *atlas, const String &json, const Vector &binary); + public: SpineNewSkeletonDataResource(); virtual ~SpineNewSkeletonDataResource(); - 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; - } + bool is_skeleton_data_loaded() const; - void load_res(spine::Atlas *atlas, const String &json, const Vector &binary); - - void _get_property_list(List *p_list) const; - - void set_atlas_res(const Ref &a); + void set_atlas_res(const Ref &atlas); Ref get_atlas_res(); - void set_skeleton_file_res(const Ref &s); + void set_skeleton_file_res(const Ref &skeleton_file); Ref get_skeleton_file_res(); inline spine::SkeletonData *get_skeleton_data() { return skeleton_data; } - bool is_skeleton_data_loaded() const; + inline spine::AnimationStateData *get_animation_state_data() { return animation_state_data; } + + void get_animation_names(Vector &animation_names) const; - void get_animation_names(Vector &l) const; void get_skin_names(Vector &l) const; - Ref find_bone(const String &bone_name); + void _get_property_list(List *p_list) const; - Ref find_slot(const String &slot_name); + // Spine API + Ref find_bone(const String &bone_name) const; - Ref find_skin(const String &skin_name); + Ref find_slot(const String &slot_name) const; - Ref find_event(const String &event_data_name); + Ref find_skin(const String &skin_name) const; - Ref find_animation(const String &animation_name); + Ref find_event(const String &event_data_name) const; - Ref find_ik_constraint(const String &constraint_name); - Ref find_transform_constraint(const String &constraint_name); - Ref find_path_constraint(const String &constraint_name); + Ref find_animation(const String &animation_name) const; + + Ref find_ik_constraint(const String &constraint_name) const; + + Ref find_transform_constraint(const String &constraint_name) const; + + Ref find_path_constraint(const String &constraint_name) const; + + String get_skeleton_name() const; + + Array get_bones() const; + + Array get_slots() const; - Array get_bones(); - Array get_slots(); Array get_skins() const; - Ref get_default_skin(); - void set_default_skin(Ref v); + Ref get_default_skin() const; - Array get_events(); - Array get_animations(); - Array get_ik_constraints(); - Array get_transform_constraints(); - Array get_path_constraints(); + void set_default_skin(Ref skin); - String get_skeleton_name(); - void set_skeleton_name(const String &v); + Array get_events() const; - float get_x(); - void set_x(float v); + Array get_animations() const; - float get_y(); - void set_y(float v); + Array get_ik_constraints() const; - float get_width(); - float get_height(); + Array get_transform_constraints() const; - String get_version(); + Array get_path_constraints() const; - float get_fps(); - void set_fps(float v); + float get_x() const; + + float get_y() const; + + float get_width() const; + + float get_height() const; + + String get_version() const; + + String get_hash() const; + + String get_images_path() const; + + String get_audio_path() const; + + float get_fps() const; }; diff --git a/spine-godot/godot/modules/spine_godot/SpineNewSprite.cpp b/spine-godot/godot/modules/spine_godot/SpineNewSprite.cpp new file mode 100644 index 000000000..20b11be3c --- /dev/null +++ b/spine-godot/godot/modules/spine_godot/SpineNewSprite.cpp @@ -0,0 +1,629 @@ +/****************************************************************************** + * 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 "SpineNewSprite.h" + +#include "SpineEvent.h" +#include "SpineTrackEntry.h" +#include "SpineNewSkeleton.h" + +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("get_bind_slot_nodes"), &SpineNewSprite::get_bind_slot_nodes); + ClassDB::bind_method(D_METHOD("set_bind_slot_nodes", "v"), &SpineNewSprite::set_bind_slot_nodes); + + ClassDB::bind_method(D_METHOD("get_overlap"), &SpineNewSprite::get_overlap); + ClassDB::bind_method(D_METHOD("set_overlap", "v"), &SpineNewSprite::set_overlap); + + ClassDB::bind_method(D_METHOD("bone_get_global_transform", "bone_name"), &SpineNewSprite::bone_get_global_transform); + ClassDB::bind_method(D_METHOD("bone_set_global_transform", "bone_name", "global_transform"), &SpineNewSprite::bone_set_global_transform); + + ClassDB::bind_method(D_METHOD("set_process_mode", "v"), &SpineNewSprite::set_process_mode); + ClassDB::bind_method(D_METHOD("get_process_mode"), &SpineNewSprite::get_process_mode); + + ClassDB::bind_method(D_METHOD("update_all", "delta"), &SpineNewSprite::_update_all); + + 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, "skeleton_data_res", PropertyHint::PROPERTY_HINT_RESOURCE_TYPE, "SpineNewSkeletonDataResource"), "set_skeleton_data_res", "get_skeleton_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::INT, "process_mode", PROPERTY_HINT_ENUM, "Process,Physics,Manual"), "set_process_mode", "get_process_mode"); + + BIND_ENUM_CONSTANT(ProcessMode::ProcessMode_Process); + BIND_ENUM_CONSTANT(ProcessMode::ProcessMode_Physics); + BIND_ENUM_CONSTANT(ProcessMode::ProcessMode_Manual); +} + +SpineNewSprite::SpineNewSprite() : overlap(false), + skeleton_clipper(nullptr), + process_mode(ProcessMode_Process) { + skeleton_clipper = new spine::SkeletonClipping(); +} +SpineNewSprite::~SpineNewSprite() { + delete skeleton_clipper; +} + +void SpineNewSprite::_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 SpineNewSprite::_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 SpineNewSprite::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 SpineNewSprite::update_bind_slot_node_transform(Ref 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) { + 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 *SpineNewSprite::find_child_node_by_node(Node *node) { + if (node == nullptr) return nullptr; + while (node && node->get_parent() != this) node = node->get_parent(); + return node; +} + +void SpineNewSprite::set_skeleton_data_res(const Ref &s) { + skeleton_data_res = s; + _on_animation_data_changed(); +} +Ref SpineNewSprite::get_skeleton_data_res() { + return skeleton_data_res; +} + +void SpineNewSprite::_on_animation_data_created() { + skeleton = Ref(memnew(SpineNewSkeleton)); + skeleton->set_skeleton_data_res(skeleton_data_res); + skeleton->set_spine_sprite(this); + + animation_state = Ref(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() { + 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(); + } + } +} + +Ref SpineNewSprite::get_skeleton() { + return skeleton; +} +Ref SpineNewSprite::get_animation_state() { + return animation_state; +} + +void SpineNewSprite::gen_mesh_from_skeleton(Ref s) { + auto sk = s->get_spine_object(); + for (size_t i = 0, n = sk->getSlots().size(); i < n; ++i) { + 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 gd_slot(memnew(SpineSlot)); + gd_slot->set_spine_object(slot); + mesh_ins->set_slot(gd_slot); + + Ref 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 SpineNewSprite::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 SpineNewSprite::remove_redundant_mesh_instances() { + Vector ms; + // remove the redundant mesh instances that added by duplicating + for (size_t i = 0, n = get_child_count(); i < n; ++i) { + auto node = get_child(i); + if (node && node->is_class("SpineNewSpriteMeshInstance2D")) { + if (mesh_instances.find((SpineSpriteMeshInstance2D *) node) == -1) { + ms.push_back(node); + } + } + } + for (size_t i = 0, n = ms.size(); i < n; ++i) { + remove_child(ms[i]); + memdelete(ms[i]); + } + ms.clear(); +} + +#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 SpineNewSprite::update_mesh_from_skeleton(Ref s) { + static const unsigned short VERTEX_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 vertices; + spine::Vector uvs; + spine::Vector indices; + + spine::Slot *slot = sk->getDrawOrder()[i]; + + spine::Attachment *attachment = slot->getAttachment(); + if (!attachment) { + 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 tex; + Ref 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->texture; + normal_tex = p_spine_renderer_object->normal_map; + + v_num = 4; + vertices.setSize(v_num * VERTEX_STRIDE, 0); + + region_attachment->computeWorldVertices(*slot, 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->texture; + normal_tex = p_spine_renderer_object->normal_map; + + v_num = mesh->getWorldVerticesLength() / VERTEX_STRIDE; + vertices.setSize(mesh->getWorldVerticesLength(), 0); + + mesh->computeWorldVertices(*slot, vertices); + 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 p_points, p_uvs; + Vector p_colors; + Vector 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(), + Vector(), + tex.is_null() ? RID() : tex->get_rid(), + -1, + normal_tex.is_null() ? RID() : normal_tex->get_rid()); + } + } else { + if (indices.size() > 0) { + Vector p_points, p_uvs; + Vector p_colors; + Vector 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(), + Vector(), + 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 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 SpineNewSprite::callback(spine::AnimationState *state, spine::EventType type, spine::TrackEntry *entry, spine::Event *event) { + Ref gd_entry(nullptr); + Ref gd_event(nullptr); + + if (entry) { + gd_entry = Ref(memnew(SpineTrackEntry)); + gd_entry->set_spine_object(entry); + } + if (event) { + gd_event = Ref(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; + } +} + +Array SpineNewSprite::get_bind_slot_nodes() { + return bind_slot_nodes; +} + +void SpineNewSprite::set_bind_slot_nodes(Array v) { + bind_slot_nodes = v; +} + +bool SpineNewSprite::get_overlap() { + return overlap; +} + +void SpineNewSprite::set_overlap(bool v) { + overlap = v; +} + +Transform2D SpineNewSprite::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 SpineNewSprite::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); +} + +SpineNewSprite::ProcessMode SpineNewSprite::get_process_mode() { + return process_mode; +} + +void SpineNewSprite::set_process_mode(SpineNewSprite::ProcessMode v) { + process_mode = v; + set_process_internal(process_mode == ProcessMode_Process); + set_physics_process_internal(process_mode == ProcessMode_Physics); +} + +void SpineNewSprite::_get_property_list(List *p_list) const { + Vector animations; + Vector skins; + if (skeleton_data_res.is_valid()) { + skeleton_data_res->get_animation_names(animations); + skeleton_data_res->get_skin_names(skins); + } + animations.insert(0, "- None -"); + + PropertyInfo animationListProperty; + animationListProperty.name = "Preview animation"; + animationListProperty.type = Variant::STRING; + animationListProperty.hint_string = String(",").join(animations); + animationListProperty.hint = PROPERTY_HINT_ENUM; + animationListProperty.usage = PROPERTY_USAGE_EDITOR; + p_list->push_back(animationListProperty); + + PropertyInfo skinListProperty; + skinListProperty.name = "Preview skin"; + skinListProperty.type = Variant::STRING; + skinListProperty.hint_string = String(",").join(skins); + skinListProperty.hint = PROPERTY_HINT_ENUM; + skinListProperty.usage = PROPERTY_USAGE_EDITOR; + p_list->push_back(skinListProperty); +} + +bool SpineNewSprite::_get(const StringName &p_property, Variant &r_value) const { + return false; +} + +bool SpineNewSprite::_set(const StringName &p_property, const Variant &p_value) { + if (p_property == "Preview animation") { + 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()) { + animation_state->set_animation(animName, true, 0); + } else { + animation_state->clear_tracks(); + } + } + } + + 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()) { + skeleton->set_skin_by_name(skinName); + } else { + skeleton->set_skin(nullptr); + } + skeleton->set_to_setup_pose(); + } + } + return false; +} diff --git a/spine-godot/godot/modules/spine_godot/SpineNewSprite.h b/spine-godot/godot/modules/spine_godot/SpineNewSprite.h new file mode 100644 index 000000000..3dfd45830 --- /dev/null +++ b/spine-godot/godot/modules/spine_godot/SpineNewSprite.h @@ -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. + *****************************************************************************/ + +#ifndef GODOT_SPINENEWSPRITE_H +#define GODOT_SPINENEWSPRITE_H + +#include + +#include "SpineAnimationState.h" +#include "SpineAnimationStateDataResource.h" +#include "SpineNewSkeleton.h" +#include "SpineSpriteMeshInstance2D.h" + +class SpineNewSprite : public Node2D, public spine::AnimationStateListenerObject { + GDCLASS(SpineNewSprite, Node2D); + +protected: + static void _bind_methods(); + + void _notification(int p_what); + + void _get_property_list(List *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 skeleton_data_res; + + Ref skeleton; + Ref animation_state; + + String preview_animation; + Array bind_slot_nodes; + bool overlap; + + ProcessMode process_mode; + + Vector mesh_instances; + spine::SkeletonClipping *skeleton_clipper; + +public: + SpineNewSprite(); + ~SpineNewSprite(); + + void set_skeleton_data_res(const Ref &a); + Ref get_skeleton_data_res(); + + Ref get_skeleton(); + Ref get_animation_state(); + + void gen_mesh_from_skeleton(Ref s); + void remove_mesh_instances(); + void remove_redundant_mesh_instances(); + + void update_mesh_from_skeleton(Ref s); + + void update_bind_slot_nodes(); + void update_bind_slot_node_transform(Ref 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); + + Array get_bind_slot_nodes(); + void set_bind_slot_nodes(Array v); + + Transform2D bone_get_global_transform(const String &bone_name); + void bone_set_global_transform(const String &bone_name, Transform2D transform); + + bool get_overlap(); + void set_overlap(bool v); + + ProcessMode get_process_mode(); + void set_process_mode(ProcessMode v); +}; + +VARIANT_ENUM_CAST(SpineNewSprite::ProcessMode); +#endif//GODOT_SPINENEWSPRITE_H diff --git a/spine-godot/godot/modules/spine_godot/SpineSprite.cpp b/spine-godot/godot/modules/spine_godot/SpineSprite.cpp index 53ac79165..171317cf7 100644 --- a/spine-godot/godot/modules/spine_godot/SpineSprite.cpp +++ b/spine-godot/godot/modules/spine_godot/SpineSprite.cpp @@ -196,7 +196,7 @@ void SpineSprite::_on_animation_data_created() { skeleton->set_spine_sprite(this); animation_state = Ref(memnew(SpineAnimationState)); - animation_state->load_animation_state(animation_state_data_res); + animation_state->create_animation_state(animation_state_data_res->get_animation_state_data()); animation_state->get_spine_object()->setListener(this); animation_state->update(0);