skeleton_2d.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. /*************************************************************************/
  2. /* skeleton_2d.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "skeleton_2d.h"
  31. #ifdef TOOLS_ENABLED
  32. #include "editor/editor_data.h"
  33. #include "editor/editor_settings.h"
  34. #include "editor/plugins/canvas_item_editor_plugin.h"
  35. #endif //TOOLS_ENABLED
  36. bool Bone2D::_set(const StringName &p_path, const Variant &p_value) {
  37. String path = p_path;
  38. if (path.begins_with("auto_calculate_length_and_angle")) {
  39. set_autocalculate_length_and_angle(p_value);
  40. } else if (path.begins_with("length")) {
  41. set_length(p_value);
  42. } else if (path.begins_with("bone_angle")) {
  43. set_bone_angle(Math::deg_to_rad(real_t(p_value)));
  44. } else if (path.begins_with("default_length")) {
  45. set_length(p_value);
  46. }
  47. #ifdef TOOLS_ENABLED
  48. if (path.begins_with("editor_settings/show_bone_gizmo")) {
  49. _editor_set_show_bone_gizmo(p_value);
  50. }
  51. #endif // TOOLS_ENABLED
  52. return true;
  53. }
  54. bool Bone2D::_get(const StringName &p_path, Variant &r_ret) const {
  55. String path = p_path;
  56. if (path.begins_with("auto_calculate_length_and_angle")) {
  57. r_ret = get_autocalculate_length_and_angle();
  58. } else if (path.begins_with("length")) {
  59. r_ret = get_length();
  60. } else if (path.begins_with("bone_angle")) {
  61. r_ret = Math::rad_to_deg(get_bone_angle());
  62. } else if (path.begins_with("default_length")) {
  63. r_ret = get_length();
  64. }
  65. #ifdef TOOLS_ENABLED
  66. if (path.begins_with("editor_settings/show_bone_gizmo")) {
  67. r_ret = _editor_get_show_bone_gizmo();
  68. }
  69. #endif // TOOLS_ENABLED
  70. return true;
  71. }
  72. void Bone2D::_get_property_list(List<PropertyInfo> *p_list) const {
  73. p_list->push_back(PropertyInfo(Variant::BOOL, PNAME("auto_calculate_length_and_angle"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
  74. if (!autocalculate_length_and_angle) {
  75. p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("length"), PROPERTY_HINT_RANGE, "1, 1024, 1", PROPERTY_USAGE_DEFAULT));
  76. p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("bone_angle"), PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT));
  77. }
  78. #ifdef TOOLS_ENABLED
  79. p_list->push_back(PropertyInfo(Variant::BOOL, PNAME("editor_settings/show_bone_gizmo"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
  80. #endif // TOOLS_ENABLED
  81. }
  82. void Bone2D::_notification(int p_what) {
  83. switch (p_what) {
  84. case NOTIFICATION_ENTER_TREE: {
  85. Node *parent = get_parent();
  86. parent_bone = Object::cast_to<Bone2D>(parent);
  87. skeleton = nullptr;
  88. while (parent) {
  89. skeleton = Object::cast_to<Skeleton2D>(parent);
  90. if (skeleton) {
  91. break;
  92. }
  93. if (!Object::cast_to<Bone2D>(parent)) {
  94. break; //skeletons must be chained to Bone2Ds.
  95. }
  96. parent = parent->get_parent();
  97. }
  98. if (skeleton) {
  99. Skeleton2D::Bone bone;
  100. bone.bone = this;
  101. skeleton->bones.push_back(bone);
  102. skeleton->_make_bone_setup_dirty();
  103. }
  104. cache_transform = get_transform();
  105. copy_transform_to_cache = true;
  106. #ifdef TOOLS_ENABLED
  107. // Only draw the gizmo in the editor!
  108. if (Engine::get_singleton()->is_editor_hint() == false) {
  109. return;
  110. }
  111. queue_redraw();
  112. #endif // TOOLS_ENABLED
  113. } break;
  114. case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
  115. if (skeleton) {
  116. skeleton->_make_transform_dirty();
  117. }
  118. if (copy_transform_to_cache) {
  119. cache_transform = get_transform();
  120. }
  121. #ifdef TOOLS_ENABLED
  122. // Only draw the gizmo in the editor!
  123. if (Engine::get_singleton()->is_editor_hint() == false) {
  124. return;
  125. }
  126. queue_redraw();
  127. if (get_parent()) {
  128. Bone2D *parent_bone = Object::cast_to<Bone2D>(get_parent());
  129. if (parent_bone) {
  130. parent_bone->queue_redraw();
  131. }
  132. }
  133. #endif // TOOLS_ENABLED
  134. } break;
  135. case NOTIFICATION_MOVED_IN_PARENT: {
  136. if (skeleton) {
  137. skeleton->_make_bone_setup_dirty();
  138. }
  139. if (copy_transform_to_cache) {
  140. cache_transform = get_transform();
  141. }
  142. } break;
  143. case NOTIFICATION_EXIT_TREE: {
  144. if (skeleton) {
  145. for (int i = 0; i < skeleton->bones.size(); i++) {
  146. if (skeleton->bones[i].bone == this) {
  147. skeleton->bones.remove_at(i);
  148. break;
  149. }
  150. }
  151. skeleton->_make_bone_setup_dirty();
  152. skeleton = nullptr;
  153. }
  154. parent_bone = nullptr;
  155. set_transform(cache_transform);
  156. } break;
  157. case NOTIFICATION_READY: {
  158. if (autocalculate_length_and_angle) {
  159. calculate_length_and_rotation();
  160. }
  161. } break;
  162. #ifdef TOOLS_ENABLED
  163. case NOTIFICATION_EDITOR_PRE_SAVE:
  164. case NOTIFICATION_EDITOR_POST_SAVE: {
  165. Transform2D tmp_trans = get_transform();
  166. set_transform(cache_transform);
  167. cache_transform = tmp_trans;
  168. } break;
  169. // Bone2D Editor gizmo drawing:
  170. #ifndef _MSC_VER
  171. #warning TODO Bone2D gizmo drawing needs to be moved to an editor plugin
  172. #endif
  173. case NOTIFICATION_DRAW: {
  174. // Only draw the gizmo in the editor!
  175. if (Engine::get_singleton()->is_editor_hint() == false) {
  176. return;
  177. }
  178. if (editor_gizmo_rid.is_null()) {
  179. editor_gizmo_rid = RenderingServer::get_singleton()->canvas_item_create();
  180. RenderingServer::get_singleton()->canvas_item_set_parent(editor_gizmo_rid, get_canvas_item());
  181. RenderingServer::get_singleton()->canvas_item_set_z_as_relative_to_parent(editor_gizmo_rid, true);
  182. RenderingServer::get_singleton()->canvas_item_set_z_index(editor_gizmo_rid, 10);
  183. }
  184. RenderingServer::get_singleton()->canvas_item_clear(editor_gizmo_rid);
  185. if (!_editor_show_bone_gizmo) {
  186. return;
  187. }
  188. // Undo scaling
  189. Transform2D editor_gizmo_trans = Transform2D();
  190. editor_gizmo_trans.set_scale(Vector2(1, 1) / get_global_scale());
  191. RenderingServer::get_singleton()->canvas_item_set_transform(editor_gizmo_rid, editor_gizmo_trans);
  192. Color bone_color1 = EditorSettings::get_singleton()->get("editors/2d/bone_color1");
  193. Color bone_color2 = EditorSettings::get_singleton()->get("editors/2d/bone_color2");
  194. Color bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color");
  195. Color bone_outline_color = EditorSettings::get_singleton()->get("editors/2d/bone_outline_color");
  196. Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color");
  197. bool Bone2D_found = false;
  198. for (int i = 0; i < get_child_count(); i++) {
  199. Bone2D *child_node = nullptr;
  200. child_node = Object::cast_to<Bone2D>(get_child(i));
  201. if (!child_node) {
  202. continue;
  203. }
  204. Bone2D_found = true;
  205. Vector<Vector2> bone_shape;
  206. Vector<Vector2> bone_shape_outline;
  207. _editor_get_bone_shape(&bone_shape, &bone_shape_outline, child_node);
  208. Vector<Color> colors;
  209. if (has_meta("_local_pose_override_enabled_")) {
  210. colors.push_back(bone_ik_color);
  211. colors.push_back(bone_ik_color);
  212. colors.push_back(bone_ik_color);
  213. colors.push_back(bone_ik_color);
  214. } else {
  215. colors.push_back(bone_color1);
  216. colors.push_back(bone_color2);
  217. colors.push_back(bone_color1);
  218. colors.push_back(bone_color2);
  219. }
  220. Vector<Color> outline_colors;
  221. if (CanvasItemEditor::get_singleton()->editor_selection->is_selected(this)) {
  222. outline_colors.push_back(bone_selected_color);
  223. outline_colors.push_back(bone_selected_color);
  224. outline_colors.push_back(bone_selected_color);
  225. outline_colors.push_back(bone_selected_color);
  226. outline_colors.push_back(bone_selected_color);
  227. outline_colors.push_back(bone_selected_color);
  228. } else {
  229. outline_colors.push_back(bone_outline_color);
  230. outline_colors.push_back(bone_outline_color);
  231. outline_colors.push_back(bone_outline_color);
  232. outline_colors.push_back(bone_outline_color);
  233. outline_colors.push_back(bone_outline_color);
  234. outline_colors.push_back(bone_outline_color);
  235. }
  236. RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape_outline, outline_colors);
  237. RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape, colors);
  238. }
  239. if (!Bone2D_found) {
  240. Vector<Vector2> bone_shape;
  241. Vector<Vector2> bone_shape_outline;
  242. _editor_get_bone_shape(&bone_shape, &bone_shape_outline, nullptr);
  243. Vector<Color> colors;
  244. if (has_meta("_local_pose_override_enabled_")) {
  245. colors.push_back(bone_ik_color);
  246. colors.push_back(bone_ik_color);
  247. colors.push_back(bone_ik_color);
  248. colors.push_back(bone_ik_color);
  249. } else {
  250. colors.push_back(bone_color1);
  251. colors.push_back(bone_color2);
  252. colors.push_back(bone_color1);
  253. colors.push_back(bone_color2);
  254. }
  255. Vector<Color> outline_colors;
  256. if (CanvasItemEditor::get_singleton()->editor_selection->is_selected(this)) {
  257. outline_colors.push_back(bone_selected_color);
  258. outline_colors.push_back(bone_selected_color);
  259. outline_colors.push_back(bone_selected_color);
  260. outline_colors.push_back(bone_selected_color);
  261. outline_colors.push_back(bone_selected_color);
  262. outline_colors.push_back(bone_selected_color);
  263. } else {
  264. outline_colors.push_back(bone_outline_color);
  265. outline_colors.push_back(bone_outline_color);
  266. outline_colors.push_back(bone_outline_color);
  267. outline_colors.push_back(bone_outline_color);
  268. outline_colors.push_back(bone_outline_color);
  269. outline_colors.push_back(bone_outline_color);
  270. }
  271. RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape_outline, outline_colors);
  272. RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape, colors);
  273. }
  274. } break;
  275. #endif // TOOLS_ENABLED
  276. }
  277. }
  278. #ifdef TOOLS_ENABLED
  279. bool Bone2D::_editor_get_bone_shape(Vector<Vector2> *p_shape, Vector<Vector2> *p_outline_shape, Bone2D *p_other_bone) {
  280. int bone_width = EditorSettings::get_singleton()->get("editors/2d/bone_width");
  281. int bone_outline_width = EditorSettings::get_singleton()->get("editors/2d/bone_outline_size");
  282. if (!is_inside_tree()) {
  283. return false; //may have been removed
  284. }
  285. if (!p_other_bone && length <= 0) {
  286. return false;
  287. }
  288. Vector2 rel;
  289. if (p_other_bone) {
  290. rel = (p_other_bone->get_global_position() - get_global_position());
  291. rel = rel.rotated(-get_global_rotation()); // Undo Bone2D node's rotation so its drawn correctly regardless of the node's rotation
  292. } else {
  293. real_t angle_to_use = get_rotation() + bone_angle;
  294. rel = Vector2(cos(angle_to_use), sin(angle_to_use)) * (length * MIN(get_global_scale().x, get_global_scale().y));
  295. rel = rel.rotated(-get_rotation()); // Undo Bone2D node's rotation so its drawn correctly regardless of the node's rotation
  296. }
  297. Vector2 relt = rel.rotated(Math_PI * 0.5).normalized() * bone_width;
  298. Vector2 reln = rel.normalized();
  299. Vector2 reltn = relt.normalized();
  300. if (p_shape) {
  301. p_shape->clear();
  302. p_shape->push_back(Vector2(0, 0));
  303. p_shape->push_back(rel * 0.2 + relt);
  304. p_shape->push_back(rel);
  305. p_shape->push_back(rel * 0.2 - relt);
  306. }
  307. if (p_outline_shape) {
  308. p_outline_shape->clear();
  309. p_outline_shape->push_back((-reln - reltn) * bone_outline_width);
  310. p_outline_shape->push_back((-reln + reltn) * bone_outline_width);
  311. p_outline_shape->push_back(rel * 0.2 + relt + reltn * bone_outline_width);
  312. p_outline_shape->push_back(rel + (reln + reltn) * bone_outline_width);
  313. p_outline_shape->push_back(rel + (reln - reltn) * bone_outline_width);
  314. p_outline_shape->push_back(rel * 0.2 - relt - reltn * bone_outline_width);
  315. }
  316. return true;
  317. }
  318. void Bone2D::_editor_set_show_bone_gizmo(bool p_show_gizmo) {
  319. _editor_show_bone_gizmo = p_show_gizmo;
  320. queue_redraw();
  321. }
  322. bool Bone2D::_editor_get_show_bone_gizmo() const {
  323. return _editor_show_bone_gizmo;
  324. }
  325. #endif // TOOLS_ENABLED
  326. void Bone2D::_bind_methods() {
  327. ClassDB::bind_method(D_METHOD("set_rest", "rest"), &Bone2D::set_rest);
  328. ClassDB::bind_method(D_METHOD("get_rest"), &Bone2D::get_rest);
  329. ClassDB::bind_method(D_METHOD("apply_rest"), &Bone2D::apply_rest);
  330. ClassDB::bind_method(D_METHOD("get_skeleton_rest"), &Bone2D::get_skeleton_rest);
  331. ClassDB::bind_method(D_METHOD("get_index_in_skeleton"), &Bone2D::get_index_in_skeleton);
  332. ClassDB::bind_method(D_METHOD("set_default_length", "default_length"), &Bone2D::set_default_length);
  333. ClassDB::bind_method(D_METHOD("get_default_length"), &Bone2D::get_default_length);
  334. ClassDB::bind_method(D_METHOD("set_autocalculate_length_and_angle", "auto_calculate"), &Bone2D::set_autocalculate_length_and_angle);
  335. ClassDB::bind_method(D_METHOD("get_autocalculate_length_and_angle"), &Bone2D::get_autocalculate_length_and_angle);
  336. ClassDB::bind_method(D_METHOD("set_length", "length"), &Bone2D::set_length);
  337. ClassDB::bind_method(D_METHOD("get_length"), &Bone2D::get_length);
  338. ClassDB::bind_method(D_METHOD("set_bone_angle", "angle"), &Bone2D::set_bone_angle);
  339. ClassDB::bind_method(D_METHOD("get_bone_angle"), &Bone2D::get_bone_angle);
  340. ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "rest", PROPERTY_HINT_NONE, "suffix:px"), "set_rest", "get_rest");
  341. }
  342. void Bone2D::set_rest(const Transform2D &p_rest) {
  343. rest = p_rest;
  344. if (skeleton) {
  345. skeleton->_make_bone_setup_dirty();
  346. }
  347. update_configuration_warnings();
  348. }
  349. Transform2D Bone2D::get_rest() const {
  350. return rest;
  351. }
  352. Transform2D Bone2D::get_skeleton_rest() const {
  353. if (parent_bone) {
  354. return parent_bone->get_skeleton_rest() * rest;
  355. } else {
  356. return rest;
  357. }
  358. }
  359. void Bone2D::apply_rest() {
  360. set_transform(rest);
  361. }
  362. void Bone2D::set_default_length(real_t p_length) {
  363. WARN_DEPRECATED_MSG("set_default_length is deprecated. Please use set_length instead!");
  364. set_length(p_length);
  365. }
  366. real_t Bone2D::get_default_length() const {
  367. WARN_DEPRECATED_MSG("get_default_length is deprecated. Please use get_length instead!");
  368. return get_length();
  369. }
  370. int Bone2D::get_index_in_skeleton() const {
  371. ERR_FAIL_COND_V(!skeleton, -1);
  372. skeleton->_update_bone_setup();
  373. return skeleton_index;
  374. }
  375. TypedArray<String> Bone2D::get_configuration_warnings() const {
  376. TypedArray<String> warnings = Node::get_configuration_warnings();
  377. if (!skeleton) {
  378. if (parent_bone) {
  379. warnings.push_back(RTR("This Bone2D chain should end at a Skeleton2D node."));
  380. } else {
  381. warnings.push_back(RTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node."));
  382. }
  383. }
  384. if (rest == Transform2D(0, 0, 0, 0, 0, 0)) {
  385. warnings.push_back(RTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."));
  386. }
  387. return warnings;
  388. }
  389. void Bone2D::calculate_length_and_rotation() {
  390. // if there is at least a single child Bone2D node, we can calculate
  391. // the length and direction. We will always just use the first Bone2D for this.
  392. bool calculated = false;
  393. int child_count = get_child_count();
  394. if (child_count > 0) {
  395. for (int i = 0; i < child_count; i++) {
  396. Bone2D *child = Object::cast_to<Bone2D>(get_child(i));
  397. if (child) {
  398. Vector2 child_local_pos = to_local(child->get_global_position());
  399. length = child_local_pos.length();
  400. bone_angle = child_local_pos.normalized().angle();
  401. calculated = true;
  402. break;
  403. }
  404. }
  405. }
  406. if (calculated) {
  407. return; // Finished!
  408. } else {
  409. WARN_PRINT("No Bone2D children of node " + get_name() + ". Cannot calculate bone length or angle reliably.\nUsing transform rotation for bone angle");
  410. bone_angle = get_transform().get_rotation();
  411. return;
  412. }
  413. }
  414. void Bone2D::set_autocalculate_length_and_angle(bool p_autocalculate) {
  415. autocalculate_length_and_angle = p_autocalculate;
  416. if (autocalculate_length_and_angle) {
  417. calculate_length_and_rotation();
  418. }
  419. notify_property_list_changed();
  420. }
  421. bool Bone2D::get_autocalculate_length_and_angle() const {
  422. return autocalculate_length_and_angle;
  423. }
  424. void Bone2D::set_length(real_t p_length) {
  425. length = p_length;
  426. #ifdef TOOLS_ENABLED
  427. queue_redraw();
  428. #endif // TOOLS_ENABLED
  429. }
  430. real_t Bone2D::get_length() const {
  431. return length;
  432. }
  433. void Bone2D::set_bone_angle(real_t p_angle) {
  434. bone_angle = p_angle;
  435. #ifdef TOOLS_ENABLED
  436. queue_redraw();
  437. #endif // TOOLS_ENABLED
  438. }
  439. real_t Bone2D::get_bone_angle() const {
  440. return bone_angle;
  441. }
  442. Bone2D::Bone2D() {
  443. skeleton = nullptr;
  444. parent_bone = nullptr;
  445. skeleton_index = -1;
  446. length = 16;
  447. bone_angle = 0;
  448. autocalculate_length_and_angle = true;
  449. set_notify_local_transform(true);
  450. //this is a clever hack so the bone knows no rest has been set yet, allowing to show an error.
  451. for (int i = 0; i < 3; i++) {
  452. rest[i] = Vector2(0, 0);
  453. }
  454. copy_transform_to_cache = true;
  455. }
  456. Bone2D::~Bone2D() {
  457. #ifdef TOOLS_ENABLED
  458. if (!editor_gizmo_rid.is_null()) {
  459. RenderingServer::get_singleton()->free(editor_gizmo_rid);
  460. }
  461. #endif // TOOLS_ENABLED
  462. }
  463. //////////////////////////////////////
  464. bool Skeleton2D::_set(const StringName &p_path, const Variant &p_value) {
  465. String path = p_path;
  466. if (path.begins_with("modification_stack")) {
  467. set_modification_stack(p_value);
  468. return true;
  469. }
  470. return true;
  471. }
  472. bool Skeleton2D::_get(const StringName &p_path, Variant &r_ret) const {
  473. String path = p_path;
  474. if (path.begins_with("modification_stack")) {
  475. r_ret = get_modification_stack();
  476. return true;
  477. }
  478. return true;
  479. }
  480. void Skeleton2D::_get_property_list(List<PropertyInfo> *p_list) const {
  481. p_list->push_back(
  482. PropertyInfo(Variant::OBJECT, PNAME("modification_stack"),
  483. PROPERTY_HINT_RESOURCE_TYPE,
  484. "SkeletonModificationStack2D",
  485. PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
  486. }
  487. void Skeleton2D::_make_bone_setup_dirty() {
  488. if (bone_setup_dirty) {
  489. return;
  490. }
  491. bone_setup_dirty = true;
  492. if (is_inside_tree()) {
  493. call_deferred(SNAME("_update_bone_setup"));
  494. }
  495. }
  496. void Skeleton2D::_update_bone_setup() {
  497. if (!bone_setup_dirty) {
  498. return;
  499. }
  500. bone_setup_dirty = false;
  501. RS::get_singleton()->skeleton_allocate_data(skeleton, bones.size(), true);
  502. bones.sort(); //sorting so that they are always in the same order/index
  503. for (int i = 0; i < bones.size(); i++) {
  504. bones.write[i].rest_inverse = bones[i].bone->get_skeleton_rest().affine_inverse(); //bind pose
  505. bones.write[i].bone->skeleton_index = i;
  506. Bone2D *parent_bone = Object::cast_to<Bone2D>(bones[i].bone->get_parent());
  507. if (parent_bone) {
  508. bones.write[i].parent_index = parent_bone->skeleton_index;
  509. } else {
  510. bones.write[i].parent_index = -1;
  511. }
  512. bones.write[i].local_pose_override = bones[i].bone->get_skeleton_rest();
  513. }
  514. transform_dirty = true;
  515. _update_transform();
  516. emit_signal(SNAME("bone_setup_changed"));
  517. }
  518. void Skeleton2D::_make_transform_dirty() {
  519. if (transform_dirty) {
  520. return;
  521. }
  522. transform_dirty = true;
  523. if (is_inside_tree()) {
  524. call_deferred(SNAME("_update_transform"));
  525. }
  526. }
  527. void Skeleton2D::_update_transform() {
  528. if (bone_setup_dirty) {
  529. _update_bone_setup();
  530. return; //above will update transform anyway
  531. }
  532. if (!transform_dirty) {
  533. return;
  534. }
  535. transform_dirty = false;
  536. for (int i = 0; i < bones.size(); i++) {
  537. ERR_CONTINUE(bones[i].parent_index >= i);
  538. if (bones[i].parent_index >= 0) {
  539. bones.write[i].accum_transform = bones[bones[i].parent_index].accum_transform * bones[i].bone->get_transform();
  540. } else {
  541. bones.write[i].accum_transform = bones[i].bone->get_transform();
  542. }
  543. }
  544. for (int i = 0; i < bones.size(); i++) {
  545. Transform2D final_xform = bones[i].accum_transform * bones[i].rest_inverse;
  546. RS::get_singleton()->skeleton_bone_set_transform_2d(skeleton, i, final_xform);
  547. }
  548. }
  549. int Skeleton2D::get_bone_count() const {
  550. ERR_FAIL_COND_V(!is_inside_tree(), 0);
  551. if (bone_setup_dirty) {
  552. const_cast<Skeleton2D *>(this)->_update_bone_setup();
  553. }
  554. return bones.size();
  555. }
  556. Bone2D *Skeleton2D::get_bone(int p_idx) {
  557. ERR_FAIL_COND_V(!is_inside_tree(), nullptr);
  558. ERR_FAIL_INDEX_V(p_idx, bones.size(), nullptr);
  559. return bones[p_idx].bone;
  560. }
  561. void Skeleton2D::_notification(int p_what) {
  562. if (p_what == NOTIFICATION_READY) {
  563. if (bone_setup_dirty) {
  564. _update_bone_setup();
  565. }
  566. if (transform_dirty) {
  567. _update_transform();
  568. }
  569. request_ready();
  570. }
  571. if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
  572. RS::get_singleton()->skeleton_set_base_transform_2d(skeleton, get_global_transform());
  573. } else if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
  574. if (modification_stack.is_valid()) {
  575. execute_modifications(get_process_delta_time(), SkeletonModificationStack2D::EXECUTION_MODE::execution_mode_process);
  576. }
  577. } else if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
  578. if (modification_stack.is_valid()) {
  579. execute_modifications(get_physics_process_delta_time(), SkeletonModificationStack2D::EXECUTION_MODE::execution_mode_physics_process);
  580. }
  581. }
  582. #ifdef TOOLS_ENABLED
  583. else if (p_what == NOTIFICATION_DRAW) {
  584. if (Engine::get_singleton()->is_editor_hint()) {
  585. if (modification_stack.is_valid()) {
  586. modification_stack->draw_editor_gizmos();
  587. }
  588. }
  589. }
  590. #endif // TOOLS_ENABLED
  591. }
  592. RID Skeleton2D::get_skeleton() const {
  593. return skeleton;
  594. }
  595. void Skeleton2D::set_bone_local_pose_override(int p_bone_idx, Transform2D p_override, real_t p_amount, bool p_persistent) {
  596. ERR_FAIL_INDEX_MSG(p_bone_idx, bones.size(), "Bone index is out of range!");
  597. bones.write[p_bone_idx].local_pose_override = p_override;
  598. bones.write[p_bone_idx].local_pose_override_amount = p_amount;
  599. bones.write[p_bone_idx].local_pose_override_persistent = p_persistent;
  600. }
  601. Transform2D Skeleton2D::get_bone_local_pose_override(int p_bone_idx) {
  602. ERR_FAIL_INDEX_V_MSG(p_bone_idx, bones.size(), Transform2D(), "Bone index is out of range!");
  603. return bones[p_bone_idx].local_pose_override;
  604. }
  605. void Skeleton2D::set_modification_stack(Ref<SkeletonModificationStack2D> p_stack) {
  606. if (modification_stack.is_valid()) {
  607. modification_stack->is_setup = false;
  608. modification_stack->set_skeleton(nullptr);
  609. set_process_internal(false);
  610. set_physics_process_internal(false);
  611. }
  612. modification_stack = p_stack;
  613. if (modification_stack.is_valid()) {
  614. modification_stack->set_skeleton(this);
  615. modification_stack->setup();
  616. set_process_internal(true);
  617. set_physics_process_internal(true);
  618. #ifdef TOOLS_ENABLED
  619. modification_stack->set_editor_gizmos_dirty(true);
  620. #endif // TOOLS_ENABLED
  621. }
  622. }
  623. Ref<SkeletonModificationStack2D> Skeleton2D::get_modification_stack() const {
  624. return modification_stack;
  625. }
  626. void Skeleton2D::execute_modifications(real_t p_delta, int p_execution_mode) {
  627. if (!modification_stack.is_valid()) {
  628. return;
  629. }
  630. // Do not cache the transform changes caused by the modifications!
  631. for (int i = 0; i < bones.size(); i++) {
  632. bones[i].bone->copy_transform_to_cache = false;
  633. }
  634. if (modification_stack->skeleton != this) {
  635. modification_stack->set_skeleton(this);
  636. }
  637. modification_stack->execute(p_delta, p_execution_mode);
  638. // Only apply the local pose override on _process. Otherwise, just calculate the local_pose_override and reset the transform.
  639. if (p_execution_mode == SkeletonModificationStack2D::EXECUTION_MODE::execution_mode_process) {
  640. for (int i = 0; i < bones.size(); i++) {
  641. if (bones[i].local_pose_override_amount > 0) {
  642. bones[i].bone->set_meta("_local_pose_override_enabled_", true);
  643. Transform2D final_trans = bones[i].bone->cache_transform;
  644. final_trans = final_trans.interpolate_with(bones[i].local_pose_override, bones[i].local_pose_override_amount);
  645. bones[i].bone->set_transform(final_trans);
  646. bones[i].bone->propagate_call("force_update_transform");
  647. if (bones[i].local_pose_override_persistent) {
  648. bones.write[i].local_pose_override_amount = 0.0;
  649. }
  650. } else {
  651. // TODO: see if there is a way to undo the override without having to resort to setting every bone's transform.
  652. bones[i].bone->remove_meta("_local_pose_override_enabled_");
  653. bones[i].bone->set_transform(bones[i].bone->cache_transform);
  654. }
  655. }
  656. }
  657. // Cache any future transform changes
  658. for (int i = 0; i < bones.size(); i++) {
  659. bones[i].bone->copy_transform_to_cache = true;
  660. }
  661. #ifdef TOOLS_ENABLED
  662. modification_stack->set_editor_gizmos_dirty(true);
  663. #endif // TOOLS_ENABLED
  664. }
  665. void Skeleton2D::_bind_methods() {
  666. ClassDB::bind_method(D_METHOD("_update_bone_setup"), &Skeleton2D::_update_bone_setup);
  667. ClassDB::bind_method(D_METHOD("_update_transform"), &Skeleton2D::_update_transform);
  668. ClassDB::bind_method(D_METHOD("get_bone_count"), &Skeleton2D::get_bone_count);
  669. ClassDB::bind_method(D_METHOD("get_bone", "idx"), &Skeleton2D::get_bone);
  670. ClassDB::bind_method(D_METHOD("get_skeleton"), &Skeleton2D::get_skeleton);
  671. ClassDB::bind_method(D_METHOD("set_modification_stack", "modification_stack"), &Skeleton2D::set_modification_stack);
  672. ClassDB::bind_method(D_METHOD("get_modification_stack"), &Skeleton2D::get_modification_stack);
  673. ClassDB::bind_method(D_METHOD("execute_modifications", "delta", "execution_mode"), &Skeleton2D::execute_modifications);
  674. ClassDB::bind_method(D_METHOD("set_bone_local_pose_override", "bone_idx", "override_pose", "strength", "persistent"), &Skeleton2D::set_bone_local_pose_override);
  675. ClassDB::bind_method(D_METHOD("get_bone_local_pose_override", "bone_idx"), &Skeleton2D::get_bone_local_pose_override);
  676. ADD_SIGNAL(MethodInfo("bone_setup_changed"));
  677. }
  678. Skeleton2D::Skeleton2D() {
  679. skeleton = RS::get_singleton()->skeleton_create();
  680. set_notify_transform(true);
  681. }
  682. Skeleton2D::~Skeleton2D() {
  683. RS::get_singleton()->free(skeleton);
  684. }