SpineBoneNode.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /******************************************************************************
  2. * Spine Runtimes License Agreement
  3. * Last updated April 5, 2025. Replaces all prior versions.
  4. *
  5. * Copyright (c) 2013-2025, Esoteric Software LLC
  6. *
  7. * Integration of the Spine Runtimes into software or otherwise creating
  8. * derivative works of the Spine Runtimes is permitted under the terms and
  9. * conditions of Section 2 of the Spine Editor License Agreement:
  10. * http://esotericsoftware.com/spine-editor-license
  11. *
  12. * Otherwise, it is permitted to integrate the Spine Runtimes into software
  13. * or otherwise create derivative works of the Spine Runtimes (collectively,
  14. * "Products"), provided that each user of the Products must obtain their own
  15. * Spine Editor license and redistribution of the Products in any form must
  16. * include this license and copyright notice.
  17. *
  18. * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
  19. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
  24. * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *****************************************************************************/
  29. #include "SpineBoneNode.h"
  30. #ifdef SPINE_GODOT_EXTENSION
  31. #include <godot_cpp/classes/engine.hpp>
  32. #include <godot_cpp/classes/scene_tree.hpp>
  33. #else
  34. #if VERSION_MAJOR > 3
  35. #include "core/config/engine.h"
  36. #else
  37. #include "core/engine.h"
  38. #endif
  39. #endif
  40. void SpineBoneNode::_bind_methods() {
  41. ClassDB::bind_method(D_METHOD("set_bone_mode"), &SpineBoneNode::set_bone_mode);
  42. ClassDB::bind_method(D_METHOD("get_bone_mode"), &SpineBoneNode::get_bone_mode);
  43. ClassDB::bind_method(D_METHOD("set_enabled"), &SpineBoneNode::set_enabled);
  44. ClassDB::bind_method(D_METHOD("get_enabled"), &SpineBoneNode::get_enabled);
  45. ClassDB::bind_method(D_METHOD("set_debug_thickness"), &SpineBoneNode::set_debug_thickness);
  46. ClassDB::bind_method(D_METHOD("get_debug_thickness"), &SpineBoneNode::get_debug_thickness);
  47. ClassDB::bind_method(D_METHOD("set_debug_color"), &SpineBoneNode::set_debug_color);
  48. ClassDB::bind_method(D_METHOD("get_debug_color"), &SpineBoneNode::get_debug_color);
  49. ClassDB::bind_method(D_METHOD("_on_world_transforms_changed", "spine_sprite"), &SpineBoneNode::on_world_transforms_changed);
  50. ClassDB::bind_method(D_METHOD("find_bone"), &SpineBoneNode::find_bone);
  51. ClassDB::bind_method(D_METHOD("find_sprite"), &SpineBoneNode::find_parent_sprite);
  52. ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_mode", PROPERTY_HINT_ENUM, "Follow,Drive"), "set_bone_mode", "get_bone_mode");
  53. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled");
  54. ADD_GROUP("Debug", "");
  55. ADD_PROPERTY(PropertyInfo(VARIANT_FLOAT, "thickness"), "set_debug_thickness", "get_debug_thickness");
  56. ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_debug_color", "get_debug_color");
  57. }
  58. void SpineBoneNode::_notification(int what) {
  59. switch (what) {
  60. case NOTIFICATION_PARENTED: {
  61. SpineSprite *sprite = find_parent_sprite();
  62. if (sprite) {
  63. #if VERSION_MAJOR > 3
  64. sprite->connect(SNAME("world_transforms_changed"), callable_mp(this, &SpineBoneNode::on_world_transforms_changed));
  65. #else
  66. sprite->connect(SNAME("world_transforms_changed"), this, SNAME("_on_world_transforms_changed"));
  67. #endif
  68. update_transform(sprite);
  69. #if VERSION_MAJOR == 3
  70. _change_notify("transform/translation");
  71. _change_notify("transform/rotation");
  72. _change_notify("transform/scale");
  73. _change_notify("translation");
  74. _change_notify("rotation");
  75. _change_notify("rotation_deg");
  76. _change_notify("scale");
  77. #endif
  78. } else {
  79. WARN_PRINT("SpineBoneNode parent is not a SpineSprite.");
  80. }
  81. NOTIFY_PROPERTY_LIST_CHANGED();
  82. break;
  83. }
  84. case NOTIFICATION_UNPARENTED: {
  85. SpineSprite *sprite = find_parent_sprite();
  86. if (sprite) {
  87. #if VERSION_MAJOR > 3
  88. sprite->disconnect(SNAME("world_transforms_changed"), callable_mp(this, &SpineBoneNode::on_world_transforms_changed));
  89. #else
  90. sprite->disconnect(SNAME("world_transforms_changed"), this, SNAME("_on_world_transforms_changed"));
  91. #endif
  92. }
  93. break;
  94. }
  95. case NOTIFICATION_DRAW: {
  96. draw();
  97. break;
  98. }
  99. default:
  100. break;
  101. }
  102. }
  103. void SpineBoneNode::_get_property_list(List<PropertyInfo> *list) const {
  104. #ifdef SPINE_GODOT_EXTENSION
  105. PackedStringArray bone_names;
  106. #else
  107. Vector<String> bone_names;
  108. #endif
  109. SpineSprite *sprite = find_parent_sprite();
  110. if (sprite) sprite->get_skeleton_data_res()->get_bone_names(bone_names);
  111. else
  112. bone_names.push_back(bone_name);
  113. auto element = list->front();
  114. while (element) {
  115. auto property_info = element->get();
  116. if (property_info.name == StringName("SpineBoneNode")) break;
  117. element = element->next();
  118. }
  119. PropertyInfo slot_name_property;
  120. slot_name_property.name = "bone_name";
  121. slot_name_property.type = Variant::STRING;
  122. slot_name_property.hint_string = String(",").join(bone_names);
  123. slot_name_property.hint = PROPERTY_HINT_ENUM;
  124. slot_name_property.usage = PROPERTY_USAGE_DEFAULT;
  125. list->insert_after(element, slot_name_property);
  126. }
  127. bool SpineBoneNode::_get(const StringName &property, Variant &value) const {
  128. if (property == StringName("bone_name")) {
  129. value = bone_name;
  130. return true;
  131. }
  132. return false;
  133. }
  134. bool SpineBoneNode::_set(const StringName &property, const Variant &value) {
  135. if (property == StringName("bone_name")) {
  136. bone_name = value;
  137. SpineSprite *sprite = find_parent_sprite();
  138. init_transform(sprite);
  139. return true;
  140. }
  141. return false;
  142. }
  143. void SpineBoneNode::on_world_transforms_changed(const Variant &_sprite) {
  144. SpineSprite *sprite = cast_to<SpineSprite>(_sprite.operator Object *());
  145. update_transform(sprite);
  146. #if VERSION_MAJOR > 3
  147. queue_redraw();
  148. #else
  149. update();
  150. #endif
  151. }
  152. void SpineBoneNode::update_transform(SpineSprite *sprite) {
  153. if (!enabled) return;
  154. Ref<SpineBone> bone = find_bone();
  155. if (!bone.is_valid()) return;
  156. Transform2D bone_transform = bone->get_global_transform();
  157. Transform2D this_transform = get_global_transform();
  158. if (bone_mode == SpineConstant::BoneMode_Drive) {
  159. bone->set_global_transform(this_transform);
  160. } else {
  161. set_global_transform(bone_transform);
  162. }
  163. if (Engine::get_singleton()->is_editor_hint()) {
  164. #if VERSION_MAJOR == 3
  165. _change_notify("transform/translation");
  166. _change_notify("transform/rotation");
  167. _change_notify("transform/scale");
  168. _change_notify("translation");
  169. _change_notify("rotation");
  170. _change_notify("rotation_deg");
  171. _change_notify("scale");
  172. #endif
  173. }
  174. }
  175. void SpineBoneNode::init_transform(SpineSprite *sprite) {
  176. if (!sprite) return;
  177. if (bone_mode == SpineConstant::BoneMode_Drive) return;
  178. sprite->get_skeleton()->set_to_setup_pose();
  179. sprite->get_skeleton()->update_world_transform(SpineConstant::Physics_Update);
  180. Transform2D global_transform = sprite->get_global_bone_transform(bone_name);
  181. set_global_transform(global_transform);
  182. update_transform(sprite);
  183. }
  184. SpineSprite *SpineBoneNode::find_parent_sprite() const {
  185. auto parent = get_parent();
  186. SpineSprite *sprite = nullptr;
  187. while (parent) {
  188. sprite = cast_to<SpineSprite>(parent);
  189. if (sprite) break;
  190. parent = parent->get_parent();
  191. }
  192. return sprite;
  193. }
  194. Ref<SpineBone> SpineBoneNode::find_bone() const {
  195. if (!is_visible_in_tree()) return nullptr;
  196. SpineSprite *sprite = find_parent_sprite();
  197. if (!sprite) return nullptr;
  198. if (!sprite->get_skeleton().is_valid() || !sprite->get_skeleton()->get_spine_object()) return nullptr;
  199. auto bone = sprite->get_skeleton()->find_bone(bone_name);
  200. return bone;
  201. }
  202. void SpineBoneNode::draw() {
  203. if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) return;
  204. Ref<SpineBone> bone = find_bone();
  205. if (!bone.is_valid()) return;
  206. spine::Bone *spine_bone = bone->get_spine_object();
  207. if (!spine_bone) return;
  208. float bone_length = spine_bone->getData().getLength();
  209. if (bone_length == 0) {
  210. draw_circle(Vector2(0, 0), debug_thickness, debug_color);
  211. } else {
  212. #ifdef SPINE_GODOT_EXTENSION
  213. PackedVector2Array points;
  214. #else
  215. Vector<Vector2> points;
  216. #endif
  217. points.push_back(Vector2(-debug_thickness, 0));
  218. points.push_back(Vector2(0, debug_thickness));
  219. points.push_back(Vector2(bone_length, 0));
  220. points.push_back(Vector2(0, -debug_thickness));
  221. draw_colored_polygon(points, debug_color);
  222. }
  223. }
  224. SpineConstant::BoneMode SpineBoneNode::get_bone_mode() {
  225. return bone_mode;
  226. }
  227. void SpineBoneNode::set_bone_mode(SpineConstant::BoneMode _bone_mode) {
  228. if (bone_mode != _bone_mode) {
  229. bone_mode = _bone_mode;
  230. SpineSprite *sprite = find_parent_sprite();
  231. init_transform(sprite);
  232. }
  233. }
  234. void SpineBoneNode::set_debug_thickness(float _thickness) {
  235. debug_thickness = _thickness;
  236. }
  237. float SpineBoneNode::get_debug_thickness() {
  238. return debug_thickness;
  239. }
  240. void SpineBoneNode::set_debug_color(Color _color) {
  241. debug_color = _color;
  242. }
  243. Color SpineBoneNode::get_debug_color() {
  244. return debug_color;
  245. }
  246. void SpineBoneNode::set_enabled(bool _enabled) {
  247. enabled = _enabled;
  248. if (!enabled && Engine::get_singleton()->is_editor_hint()) {
  249. auto sprite = find_parent_sprite();
  250. if (!sprite) return;
  251. sprite->get_skeleton()->set_to_setup_pose();
  252. sprite->get_skeleton()->update_world_transform(SpineConstant::Physics_Update);
  253. }
  254. }
  255. bool SpineBoneNode::get_enabled() {
  256. return enabled;
  257. }