123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- /******************************************************************************
- * Spine Runtimes License Agreement
- * Last updated April 5, 2025. Replaces all prior versions.
- *
- * Copyright (c) 2013-2025, 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 "SpineBoneNode.h"
- #ifdef SPINE_GODOT_EXTENSION
- #include <godot_cpp/classes/engine.hpp>
- #include <godot_cpp/classes/scene_tree.hpp>
- #else
- #if VERSION_MAJOR > 3
- #include "core/config/engine.h"
- #else
- #include "core/engine.h"
- #endif
- #endif
- void SpineBoneNode::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_bone_mode"), &SpineBoneNode::set_bone_mode);
- ClassDB::bind_method(D_METHOD("get_bone_mode"), &SpineBoneNode::get_bone_mode);
- ClassDB::bind_method(D_METHOD("set_enabled"), &SpineBoneNode::set_enabled);
- ClassDB::bind_method(D_METHOD("get_enabled"), &SpineBoneNode::get_enabled);
- ClassDB::bind_method(D_METHOD("set_debug_thickness"), &SpineBoneNode::set_debug_thickness);
- ClassDB::bind_method(D_METHOD("get_debug_thickness"), &SpineBoneNode::get_debug_thickness);
- ClassDB::bind_method(D_METHOD("set_debug_color"), &SpineBoneNode::set_debug_color);
- ClassDB::bind_method(D_METHOD("get_debug_color"), &SpineBoneNode::get_debug_color);
- ClassDB::bind_method(D_METHOD("_on_world_transforms_changed", "spine_sprite"), &SpineBoneNode::on_world_transforms_changed);
- ClassDB::bind_method(D_METHOD("find_bone"), &SpineBoneNode::find_bone);
- ClassDB::bind_method(D_METHOD("find_sprite"), &SpineBoneNode::find_parent_sprite);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_mode", PROPERTY_HINT_ENUM, "Follow,Drive"), "set_bone_mode", "get_bone_mode");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled");
- ADD_GROUP("Debug", "");
- ADD_PROPERTY(PropertyInfo(VARIANT_FLOAT, "thickness"), "set_debug_thickness", "get_debug_thickness");
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_debug_color", "get_debug_color");
- }
- void SpineBoneNode::_notification(int what) {
- switch (what) {
- case NOTIFICATION_PARENTED: {
- SpineSprite *sprite = find_parent_sprite();
- if (sprite) {
- #if VERSION_MAJOR > 3
- sprite->connect(SNAME("world_transforms_changed"), callable_mp(this, &SpineBoneNode::on_world_transforms_changed));
- #else
- sprite->connect(SNAME("world_transforms_changed"), this, SNAME("_on_world_transforms_changed"));
- #endif
- update_transform(sprite);
- #if VERSION_MAJOR == 3
- _change_notify("transform/translation");
- _change_notify("transform/rotation");
- _change_notify("transform/scale");
- _change_notify("translation");
- _change_notify("rotation");
- _change_notify("rotation_deg");
- _change_notify("scale");
- #endif
- } else {
- WARN_PRINT("SpineBoneNode parent is not a SpineSprite.");
- }
- NOTIFY_PROPERTY_LIST_CHANGED();
- break;
- }
- case NOTIFICATION_UNPARENTED: {
- SpineSprite *sprite = find_parent_sprite();
- if (sprite) {
- #if VERSION_MAJOR > 3
- sprite->disconnect(SNAME("world_transforms_changed"), callable_mp(this, &SpineBoneNode::on_world_transforms_changed));
- #else
- sprite->disconnect(SNAME("world_transforms_changed"), this, SNAME("_on_world_transforms_changed"));
- #endif
- }
- break;
- }
- case NOTIFICATION_DRAW: {
- draw();
- break;
- }
- default:
- break;
- }
- }
- void SpineBoneNode::_get_property_list(List<PropertyInfo> *list) const {
- #ifdef SPINE_GODOT_EXTENSION
- PackedStringArray bone_names;
- #else
- Vector<String> bone_names;
- #endif
- SpineSprite *sprite = find_parent_sprite();
- if (sprite) sprite->get_skeleton_data_res()->get_bone_names(bone_names);
- else
- bone_names.push_back(bone_name);
- auto element = list->front();
- while (element) {
- auto property_info = element->get();
- if (property_info.name == StringName("SpineBoneNode")) break;
- element = element->next();
- }
- PropertyInfo slot_name_property;
- slot_name_property.name = "bone_name";
- slot_name_property.type = Variant::STRING;
- slot_name_property.hint_string = String(",").join(bone_names);
- slot_name_property.hint = PROPERTY_HINT_ENUM;
- slot_name_property.usage = PROPERTY_USAGE_DEFAULT;
- list->insert_after(element, slot_name_property);
- }
- bool SpineBoneNode::_get(const StringName &property, Variant &value) const {
- if (property == StringName("bone_name")) {
- value = bone_name;
- return true;
- }
- return false;
- }
- bool SpineBoneNode::_set(const StringName &property, const Variant &value) {
- if (property == StringName("bone_name")) {
- bone_name = value;
- SpineSprite *sprite = find_parent_sprite();
- init_transform(sprite);
- return true;
- }
- return false;
- }
- void SpineBoneNode::on_world_transforms_changed(const Variant &_sprite) {
- SpineSprite *sprite = cast_to<SpineSprite>(_sprite.operator Object *());
- update_transform(sprite);
- #if VERSION_MAJOR > 3
- queue_redraw();
- #else
- update();
- #endif
- }
- void SpineBoneNode::update_transform(SpineSprite *sprite) {
- if (!enabled) return;
- Ref<SpineBone> bone = find_bone();
- if (!bone.is_valid()) return;
- Transform2D bone_transform = bone->get_global_transform();
- Transform2D this_transform = get_global_transform();
- if (bone_mode == SpineConstant::BoneMode_Drive) {
- bone->set_global_transform(this_transform);
- } else {
- set_global_transform(bone_transform);
- }
- if (Engine::get_singleton()->is_editor_hint()) {
- #if VERSION_MAJOR == 3
- _change_notify("transform/translation");
- _change_notify("transform/rotation");
- _change_notify("transform/scale");
- _change_notify("translation");
- _change_notify("rotation");
- _change_notify("rotation_deg");
- _change_notify("scale");
- #endif
- }
- }
- void SpineBoneNode::init_transform(SpineSprite *sprite) {
- if (!sprite) return;
- if (bone_mode == SpineConstant::BoneMode_Drive) return;
- sprite->get_skeleton()->set_to_setup_pose();
- sprite->get_skeleton()->update_world_transform(SpineConstant::Physics_Update);
- Transform2D global_transform = sprite->get_global_bone_transform(bone_name);
- set_global_transform(global_transform);
- update_transform(sprite);
- }
- SpineSprite *SpineBoneNode::find_parent_sprite() const {
- auto parent = get_parent();
- SpineSprite *sprite = nullptr;
- while (parent) {
- sprite = cast_to<SpineSprite>(parent);
- if (sprite) break;
- parent = parent->get_parent();
- }
- return sprite;
- }
- Ref<SpineBone> SpineBoneNode::find_bone() const {
- if (!is_visible_in_tree()) return nullptr;
- SpineSprite *sprite = find_parent_sprite();
- if (!sprite) return nullptr;
- if (!sprite->get_skeleton().is_valid() || !sprite->get_skeleton()->get_spine_object()) return nullptr;
- auto bone = sprite->get_skeleton()->find_bone(bone_name);
- return bone;
- }
- void SpineBoneNode::draw() {
- if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) return;
- Ref<SpineBone> bone = find_bone();
- if (!bone.is_valid()) return;
- spine::Bone *spine_bone = bone->get_spine_object();
- if (!spine_bone) return;
- float bone_length = spine_bone->getData().getLength();
- if (bone_length == 0) {
- draw_circle(Vector2(0, 0), debug_thickness, debug_color);
- } else {
- #ifdef SPINE_GODOT_EXTENSION
- PackedVector2Array points;
- #else
- Vector<Vector2> points;
- #endif
- points.push_back(Vector2(-debug_thickness, 0));
- points.push_back(Vector2(0, debug_thickness));
- points.push_back(Vector2(bone_length, 0));
- points.push_back(Vector2(0, -debug_thickness));
- draw_colored_polygon(points, debug_color);
- }
- }
- SpineConstant::BoneMode SpineBoneNode::get_bone_mode() {
- return bone_mode;
- }
- void SpineBoneNode::set_bone_mode(SpineConstant::BoneMode _bone_mode) {
- if (bone_mode != _bone_mode) {
- bone_mode = _bone_mode;
- SpineSprite *sprite = find_parent_sprite();
- init_transform(sprite);
- }
- }
- void SpineBoneNode::set_debug_thickness(float _thickness) {
- debug_thickness = _thickness;
- }
- float SpineBoneNode::get_debug_thickness() {
- return debug_thickness;
- }
- void SpineBoneNode::set_debug_color(Color _color) {
- debug_color = _color;
- }
- Color SpineBoneNode::get_debug_color() {
- return debug_color;
- }
- void SpineBoneNode::set_enabled(bool _enabled) {
- enabled = _enabled;
- if (!enabled && Engine::get_singleton()->is_editor_hint()) {
- auto sprite = find_parent_sprite();
- if (!sprite) return;
- sprite->get_skeleton()->set_to_setup_pose();
- sprite->get_skeleton()->update_world_transform(SpineConstant::Physics_Update);
- }
- }
- bool SpineBoneNode::get_enabled() {
- return enabled;
- }
|