spatial.cpp 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  1. /**************************************************************************/
  2. /* spatial.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  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 "spatial.h"
  31. #include "core/engine.h"
  32. #include "core/math/transform_interpolator.h"
  33. #include "core/message_queue.h"
  34. #include "scene/main/scene_tree.h"
  35. #include "scene/main/viewport.h"
  36. #include "scene/scene_string_names.h"
  37. #include "servers/visual_server_callbacks.h"
  38. /*
  39. possible algorithms:
  40. Algorithm 1: (current)
  41. definition of invalidation: global is invalid
  42. 1) If a node sets a LOCAL, it produces an invalidation of everything above
  43. . a) If above is invalid, don't keep invalidating upwards
  44. 2) If a node sets a GLOBAL, it is converted to LOCAL (and forces validation of everything pending below)
  45. drawback: setting/reading globals is useful and used very very often, and using affine inverses is slow
  46. ---
  47. Algorithm 2: (no longer current)
  48. definition of invalidation: NONE dirty, LOCAL dirty, GLOBAL dirty
  49. 1) If a node sets a LOCAL, it must climb the tree and set it as GLOBAL dirty
  50. . a) marking GLOBALs as dirty up all the tree must be done always
  51. 2) If a node sets a GLOBAL, it marks local as dirty, and that's all?
  52. //is clearing the dirty state correct in this case?
  53. drawback: setting a local down the tree forces many tree walks often
  54. --
  55. future: no idea
  56. */
  57. VARIANT_ENUM_CAST(Spatial::MergingMode);
  58. SpatialGizmo::SpatialGizmo() {
  59. }
  60. void Spatial::_notify_dirty() {
  61. #ifdef TOOLS_ENABLED
  62. if ((data.gizmo.is_valid() || data.notify_transform) && !data.ignore_notification && !xform_change.in_list()) {
  63. #else
  64. if (data.notify_transform && !data.ignore_notification && !xform_change.in_list()) {
  65. #endif
  66. get_tree()->xform_change_list.add(&xform_change);
  67. }
  68. }
  69. void Spatial::_update_local_transform() const {
  70. data.local_transform.basis.set_euler_scale(data.rotation, data.scale);
  71. data.dirty &= ~DIRTY_LOCAL;
  72. }
  73. void Spatial::_propagate_transform_changed(Spatial *p_origin) {
  74. if (!is_inside_tree()) {
  75. return;
  76. }
  77. /*
  78. if (data.dirty&DIRTY_GLOBAL)
  79. return; //already dirty
  80. */
  81. data.children_lock++;
  82. for (List<Spatial *>::Element *E = data.children.front(); E; E = E->next()) {
  83. if (E->get()->data.toplevel_active) {
  84. continue; //don't propagate to a toplevel
  85. }
  86. E->get()->_propagate_transform_changed(p_origin);
  87. }
  88. #ifdef TOOLS_ENABLED
  89. if ((data.gizmo.is_valid() || data.notify_transform) && !data.ignore_notification && !xform_change.in_list()) {
  90. #else
  91. if (data.notify_transform && !data.ignore_notification && !xform_change.in_list()) {
  92. #endif
  93. get_tree()->xform_change_list.add(&xform_change);
  94. }
  95. data.dirty |= DIRTY_GLOBAL;
  96. data.children_lock--;
  97. }
  98. void Spatial::notification_callback(int p_message_type) {
  99. switch (p_message_type) {
  100. default:
  101. break;
  102. case VisualServerCallbacks::CALLBACK_NOTIFICATION_ENTER_GAMEPLAY: {
  103. notification(NOTIFICATION_ENTER_GAMEPLAY);
  104. } break;
  105. case VisualServerCallbacks::CALLBACK_NOTIFICATION_EXIT_GAMEPLAY: {
  106. notification(NOTIFICATION_EXIT_GAMEPLAY);
  107. } break;
  108. case VisualServerCallbacks::CALLBACK_SIGNAL_ENTER_GAMEPLAY: {
  109. emit_signal("gameplay_entered");
  110. } break;
  111. case VisualServerCallbacks::CALLBACK_SIGNAL_EXIT_GAMEPLAY: {
  112. emit_signal("gameplay_exited");
  113. } break;
  114. }
  115. }
  116. void Spatial::_notification(int p_what) {
  117. switch (p_what) {
  118. case NOTIFICATION_ENTER_TREE: {
  119. ERR_FAIL_COND(!get_tree());
  120. Node *p = get_parent();
  121. if (p) {
  122. data.parent = Object::cast_to<Spatial>(p);
  123. }
  124. if (data.parent) {
  125. data.C = data.parent->data.children.push_back(this);
  126. } else {
  127. data.C = nullptr;
  128. }
  129. if (data.toplevel && !Engine::get_singleton()->is_editor_hint()) {
  130. if (data.parent) {
  131. data.local_transform = data.parent->get_global_transform() * get_transform();
  132. data.dirty = DIRTY_VECTORS; //global is always dirty upon entering a scene
  133. }
  134. data.toplevel_active = true;
  135. }
  136. if (data.merging_mode == MERGING_MODE_INHERIT) {
  137. bool merging_allowed = true; // Root node default is for merging to be on
  138. if (data.parent) {
  139. merging_allowed = data.parent->is_merging_allowed();
  140. }
  141. _propagate_merging_allowed(merging_allowed);
  142. }
  143. data.dirty |= DIRTY_GLOBAL; //global is always dirty upon entering a scene
  144. _notify_dirty();
  145. notification(NOTIFICATION_ENTER_WORLD);
  146. } break;
  147. case NOTIFICATION_EXIT_TREE: {
  148. notification(NOTIFICATION_EXIT_WORLD, true);
  149. if (xform_change.in_list()) {
  150. get_tree()->xform_change_list.remove(&xform_change);
  151. }
  152. if (data.C) {
  153. data.parent->data.children.erase(data.C);
  154. }
  155. data.parent = nullptr;
  156. data.C = nullptr;
  157. data.toplevel_active = false;
  158. _disable_client_physics_interpolation();
  159. } break;
  160. case NOTIFICATION_ENTER_WORLD: {
  161. data.inside_world = true;
  162. data.viewport = nullptr;
  163. Node *parent = get_parent();
  164. while (parent && !data.viewport) {
  165. data.viewport = Object::cast_to<Viewport>(parent);
  166. parent = parent->get_parent();
  167. }
  168. ERR_FAIL_COND(!data.viewport);
  169. if (get_script_instance()) {
  170. get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_enter_world, nullptr, 0);
  171. }
  172. #ifdef TOOLS_ENABLED
  173. if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) {
  174. //get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this);
  175. get_tree()->call_group_flags(0, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this);
  176. if (!data.gizmo_disabled) {
  177. if (data.gizmo.is_valid()) {
  178. data.gizmo->create();
  179. if (is_visible_in_tree()) {
  180. data.gizmo->redraw();
  181. }
  182. data.gizmo->transform();
  183. }
  184. }
  185. }
  186. #endif
  187. } break;
  188. case NOTIFICATION_EXIT_WORLD: {
  189. #ifdef TOOLS_ENABLED
  190. if (data.gizmo.is_valid()) {
  191. data.gizmo->free();
  192. data.gizmo.unref();
  193. }
  194. #endif
  195. if (get_script_instance()) {
  196. get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_world, nullptr, 0);
  197. }
  198. data.viewport = nullptr;
  199. data.inside_world = false;
  200. } break;
  201. case NOTIFICATION_TRANSFORM_CHANGED: {
  202. #ifdef TOOLS_ENABLED
  203. if (data.gizmo.is_valid()) {
  204. data.gizmo->transform();
  205. }
  206. #endif
  207. } break;
  208. case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: {
  209. if (data.client_physics_interpolation_data) {
  210. data.client_physics_interpolation_data->global_xform_prev = data.client_physics_interpolation_data->global_xform_curr;
  211. }
  212. } break;
  213. default: {
  214. }
  215. }
  216. }
  217. Vector3 Spatial::get_global_translation() const {
  218. return get_global_transform().get_origin();
  219. }
  220. void Spatial::set_global_translation(const Vector3 &p_translation) {
  221. Transform transform = get_global_transform();
  222. transform.set_origin(p_translation);
  223. set_global_transform(transform);
  224. }
  225. Vector3 Spatial::get_global_rotation() const {
  226. return get_global_transform().get_basis().get_euler();
  227. }
  228. void Spatial::set_global_rotation(const Vector3 &p_euler_rad) {
  229. Transform transform = get_global_transform();
  230. Basis new_basis = transform.get_basis();
  231. new_basis.set_euler(p_euler_rad);
  232. transform.set_basis(new_basis);
  233. set_global_transform(transform);
  234. }
  235. void Spatial::set_transform(const Transform &p_transform) {
  236. data.local_transform = p_transform;
  237. data.dirty |= DIRTY_VECTORS;
  238. data.dirty &= ~DIRTY_LOCAL;
  239. _change_notify("translation");
  240. _change_notify("rotation");
  241. _change_notify("rotation_degrees");
  242. _change_notify("scale");
  243. _propagate_transform_changed(this);
  244. if (data.notify_local_transform) {
  245. notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
  246. }
  247. }
  248. void Spatial::set_global_transform(const Transform &p_transform) {
  249. Transform xform = (data.parent && !data.toplevel_active) ? data.parent->get_global_transform().affine_inverse() * p_transform : p_transform;
  250. set_transform(xform);
  251. }
  252. Transform Spatial::get_transform() const {
  253. if (data.dirty & DIRTY_LOCAL) {
  254. _update_local_transform();
  255. }
  256. return data.local_transform;
  257. }
  258. // Return false to timeout and remove from the client interpolation list.
  259. bool Spatial::update_client_physics_interpolation_data() {
  260. if (!is_inside_tree() || !_is_physics_interpolated_client_side()) {
  261. return false;
  262. }
  263. ERR_FAIL_NULL_V(data.client_physics_interpolation_data, false);
  264. ClientPhysicsInterpolationData &pid = *data.client_physics_interpolation_data;
  265. uint64_t tick = Engine::get_singleton()->get_physics_frames();
  266. // Has this update been done already this tick?
  267. // (for instance, get_global_transform_interpolated() could be called multiple times)
  268. if (pid.current_physics_tick != tick) {
  269. // timeout?
  270. if (tick >= pid.timeout_physics_tick) {
  271. return false;
  272. }
  273. if (pid.current_physics_tick == (tick - 1)) {
  274. // normal interpolation situation, there is a continuous flow of data
  275. // from one tick to the next...
  276. pid.global_xform_prev = pid.global_xform_curr;
  277. } else {
  278. // there has been a gap, we cannot sensibly offer interpolation over
  279. // a multitick gap, so we will teleport
  280. pid.global_xform_prev = get_global_transform();
  281. }
  282. pid.current_physics_tick = tick;
  283. }
  284. pid.global_xform_curr = get_global_transform();
  285. return true;
  286. }
  287. void Spatial::_disable_client_physics_interpolation() {
  288. // Disable any current client side interpolation
  289. // (this can always restart as normal if you later re-attach the node to the SceneTree)
  290. if (data.client_physics_interpolation_data) {
  291. memdelete(data.client_physics_interpolation_data);
  292. data.client_physics_interpolation_data = nullptr;
  293. SceneTree *tree = get_tree();
  294. if (tree && _client_physics_interpolation_spatials_list.in_list()) {
  295. tree->client_physics_interpolation_remove_spatial(&_client_physics_interpolation_spatials_list);
  296. }
  297. }
  298. _set_physics_interpolated_client_side(false);
  299. }
  300. Transform Spatial::_get_global_transform_interpolated(real_t p_interpolation_fraction) {
  301. ERR_FAIL_COND_V(!is_inside_tree(), Transform());
  302. // set in motion the mechanisms for client side interpolation if not already active
  303. if (!_is_physics_interpolated_client_side()) {
  304. _set_physics_interpolated_client_side(true);
  305. ERR_FAIL_COND_V(data.client_physics_interpolation_data, Transform());
  306. data.client_physics_interpolation_data = memnew(ClientPhysicsInterpolationData);
  307. data.client_physics_interpolation_data->global_xform_curr = get_global_transform();
  308. data.client_physics_interpolation_data->global_xform_prev = data.client_physics_interpolation_data->global_xform_curr;
  309. data.client_physics_interpolation_data->current_physics_tick = Engine::get_singleton()->get_physics_frames();
  310. }
  311. // Storing the last tick we requested client interpolation allows us to timeout
  312. // and remove client interpolated nodes from the list to save processing.
  313. // We use some arbitrary timeout here, but this could potentially be user defined.
  314. // Note: This timeout has to be larger than the number of ticks in a frame, otherwise the interpolated
  315. // data will stop flowing before the next frame is drawn. This should only be relevant at high tick rates.
  316. // We could alternatively do this by frames rather than ticks and avoid this problem, but then the behaviour
  317. // would be machine dependent.
  318. data.client_physics_interpolation_data->timeout_physics_tick = Engine::get_singleton()->get_physics_frames() + 256;
  319. // make sure data is up to date
  320. update_client_physics_interpolation_data();
  321. // interpolate the current data
  322. const Transform &xform_curr = data.client_physics_interpolation_data->global_xform_curr;
  323. const Transform &xform_prev = data.client_physics_interpolation_data->global_xform_prev;
  324. Transform res;
  325. TransformInterpolator::interpolate_transform(xform_prev, xform_curr, res, p_interpolation_fraction);
  326. SceneTree *tree = get_tree();
  327. // This should not happen, as is_inside_tree() is checked earlier
  328. ERR_FAIL_NULL_V(tree, res);
  329. if (!_client_physics_interpolation_spatials_list.in_list()) {
  330. tree->client_physics_interpolation_add_spatial(&_client_physics_interpolation_spatials_list);
  331. }
  332. return res;
  333. }
  334. Transform Spatial::get_global_transform_interpolated() {
  335. // Pass through if physics interpolation is switched off.
  336. // This is a convenience, as it allows you to easy turn off interpolation
  337. // without changing any code.
  338. if (!is_physics_interpolated_and_enabled()) {
  339. return get_global_transform();
  340. }
  341. // If we are in the physics frame, the interpolated global transform is meaningless.
  342. // However, there is an exception, we may want to use this as a means of starting off the client
  343. // interpolation pump if not already started (when _is_physics_interpolated_client_side() is false).
  344. if (Engine::get_singleton()->is_in_physics_frame() && _is_physics_interpolated_client_side()) {
  345. return get_global_transform();
  346. }
  347. return _get_global_transform_interpolated(Engine::get_singleton()->get_physics_interpolation_fraction());
  348. }
  349. Transform Spatial::get_global_transform() const {
  350. ERR_FAIL_COND_V(!is_inside_tree(), Transform());
  351. if (data.dirty & DIRTY_GLOBAL) {
  352. if (data.dirty & DIRTY_LOCAL) {
  353. _update_local_transform();
  354. }
  355. if (data.parent && !data.toplevel_active) {
  356. data.global_transform = data.parent->get_global_transform() * data.local_transform;
  357. } else {
  358. data.global_transform = data.local_transform;
  359. }
  360. if (data.disable_scale) {
  361. data.global_transform.basis.orthonormalize();
  362. }
  363. data.dirty &= ~DIRTY_GLOBAL;
  364. }
  365. return data.global_transform;
  366. }
  367. #ifdef TOOLS_ENABLED
  368. Transform Spatial::get_global_gizmo_transform() const {
  369. return get_global_transform();
  370. }
  371. Transform Spatial::get_local_gizmo_transform() const {
  372. return get_transform();
  373. }
  374. // If not a VisualInstance, use this AABB for the orange box in the editor
  375. AABB Spatial::get_fallback_gizmo_aabb() const {
  376. return AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
  377. }
  378. #endif
  379. Spatial *Spatial::get_parent_spatial() const {
  380. return data.parent;
  381. }
  382. void Spatial::_set_vi_visible(bool p_visible) {
  383. data.vi_visible = p_visible;
  384. }
  385. Transform Spatial::get_relative_transform(const Node *p_parent) const {
  386. if (p_parent == this) {
  387. return Transform();
  388. }
  389. ERR_FAIL_COND_V(!data.parent, Transform());
  390. if (p_parent == data.parent) {
  391. return get_transform();
  392. } else {
  393. return data.parent->get_relative_transform(p_parent) * get_transform();
  394. }
  395. }
  396. void Spatial::set_translation(const Vector3 &p_translation) {
  397. data.local_transform.origin = p_translation;
  398. _change_notify("transform");
  399. _propagate_transform_changed(this);
  400. if (data.notify_local_transform) {
  401. notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
  402. }
  403. }
  404. void Spatial::set_rotation(const Vector3 &p_euler_rad) {
  405. if (data.dirty & DIRTY_VECTORS) {
  406. data.scale = data.local_transform.basis.get_scale();
  407. data.dirty &= ~DIRTY_VECTORS;
  408. }
  409. data.rotation = p_euler_rad;
  410. data.dirty |= DIRTY_LOCAL;
  411. _change_notify("transform");
  412. _propagate_transform_changed(this);
  413. if (data.notify_local_transform) {
  414. notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
  415. }
  416. }
  417. void Spatial::set_rotation_degrees(const Vector3 &p_euler_deg) {
  418. set_rotation(p_euler_deg * Math_PI / 180.0);
  419. }
  420. void Spatial::set_scale(const Vector3 &p_scale) {
  421. if (data.dirty & DIRTY_VECTORS) {
  422. data.rotation = data.local_transform.basis.get_rotation();
  423. data.dirty &= ~DIRTY_VECTORS;
  424. }
  425. data.scale = p_scale;
  426. data.dirty |= DIRTY_LOCAL;
  427. _change_notify("transform");
  428. _propagate_transform_changed(this);
  429. if (data.notify_local_transform) {
  430. notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
  431. }
  432. }
  433. Vector3 Spatial::get_translation() const {
  434. return data.local_transform.origin;
  435. }
  436. Vector3 Spatial::get_rotation() const {
  437. if (data.dirty & DIRTY_VECTORS) {
  438. data.scale = data.local_transform.basis.get_scale();
  439. data.rotation = data.local_transform.basis.get_rotation();
  440. data.dirty &= ~DIRTY_VECTORS;
  441. }
  442. return data.rotation;
  443. }
  444. Vector3 Spatial::get_rotation_degrees() const {
  445. return get_rotation() * 180.0 / Math_PI;
  446. }
  447. Vector3 Spatial::get_scale() const {
  448. if (data.dirty & DIRTY_VECTORS) {
  449. data.scale = data.local_transform.basis.get_scale();
  450. data.rotation = data.local_transform.basis.get_rotation();
  451. data.dirty &= ~DIRTY_VECTORS;
  452. }
  453. return data.scale;
  454. }
  455. void Spatial::update_gizmo() {
  456. #ifdef TOOLS_ENABLED
  457. if (!is_inside_world()) {
  458. return;
  459. }
  460. if (!data.gizmo.is_valid()) {
  461. get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this);
  462. }
  463. if (!data.gizmo.is_valid()) {
  464. return;
  465. }
  466. if (data.gizmo_dirty) {
  467. return;
  468. }
  469. data.gizmo_dirty = true;
  470. MessageQueue::get_singleton()->push_call(this, "_update_gizmo");
  471. #endif
  472. }
  473. void Spatial::set_gizmo(const Ref<SpatialGizmo> &p_gizmo) {
  474. #ifdef TOOLS_ENABLED
  475. if (data.gizmo_disabled) {
  476. return;
  477. }
  478. if (data.gizmo.is_valid() && is_inside_world()) {
  479. data.gizmo->free();
  480. }
  481. data.gizmo = p_gizmo;
  482. if (data.gizmo.is_valid() && is_inside_world()) {
  483. data.gizmo->create();
  484. if (is_visible_in_tree()) {
  485. data.gizmo->redraw();
  486. }
  487. data.gizmo->transform();
  488. }
  489. #endif
  490. }
  491. Ref<SpatialGizmo> Spatial::get_gizmo() const {
  492. #ifdef TOOLS_ENABLED
  493. return data.gizmo;
  494. #else
  495. return Ref<SpatialGizmo>();
  496. #endif
  497. }
  498. void Spatial::_update_gizmo() {
  499. #ifdef TOOLS_ENABLED
  500. if (!is_inside_world()) {
  501. return;
  502. }
  503. data.gizmo_dirty = false;
  504. if (data.gizmo.is_valid()) {
  505. if (is_visible_in_tree()) {
  506. data.gizmo->redraw();
  507. } else {
  508. data.gizmo->clear();
  509. }
  510. }
  511. #endif
  512. }
  513. void Spatial::set_disable_gizmo(bool p_enabled) {
  514. #ifdef TOOLS_ENABLED
  515. data.gizmo_disabled = p_enabled;
  516. if (!p_enabled && data.gizmo.is_valid()) {
  517. data.gizmo = Ref<SpatialGizmo>();
  518. }
  519. #endif
  520. }
  521. void Spatial::set_disable_scale(bool p_enabled) {
  522. data.disable_scale = p_enabled;
  523. }
  524. bool Spatial::is_scale_disabled() const {
  525. return data.disable_scale;
  526. }
  527. void Spatial::set_as_toplevel(bool p_enabled) {
  528. if (data.toplevel == p_enabled) {
  529. return;
  530. }
  531. if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint()) {
  532. if (p_enabled) {
  533. set_transform(get_global_transform());
  534. } else if (data.parent) {
  535. set_transform(data.parent->get_global_transform().affine_inverse() * get_global_transform());
  536. }
  537. data.toplevel = p_enabled;
  538. data.toplevel_active = p_enabled;
  539. } else {
  540. data.toplevel = p_enabled;
  541. }
  542. }
  543. bool Spatial::is_set_as_toplevel() const {
  544. return data.toplevel;
  545. }
  546. Ref<World> Spatial::get_world() const {
  547. ERR_FAIL_COND_V(!is_inside_world(), Ref<World>());
  548. ERR_FAIL_COND_V(!data.viewport, Ref<World>());
  549. return data.viewport->find_world();
  550. }
  551. void Spatial::_propagate_visibility_changed() {
  552. notification(NOTIFICATION_VISIBILITY_CHANGED);
  553. emit_signal(SceneStringNames::get_singleton()->visibility_changed);
  554. _change_notify("visible");
  555. #ifdef TOOLS_ENABLED
  556. if (data.gizmo.is_valid()) {
  557. _update_gizmo();
  558. }
  559. #endif
  560. for (List<Spatial *>::Element *E = data.children.front(); E; E = E->next()) {
  561. Spatial *c = E->get();
  562. if (!c || !c->data.visible) {
  563. continue;
  564. }
  565. c->_propagate_visibility_changed();
  566. }
  567. }
  568. void Spatial::_propagate_merging_allowed(bool p_merging_allowed) {
  569. switch (data.merging_mode) {
  570. case MERGING_MODE_INHERIT:
  571. // Keep the parent p_allow_merging.
  572. break;
  573. case MERGING_MODE_OFF: {
  574. p_merging_allowed = false;
  575. } break;
  576. case MERGING_MODE_ON: {
  577. p_merging_allowed = true;
  578. } break;
  579. }
  580. // No change? No need to propagate further.
  581. if (data.merging_allowed == p_merging_allowed) {
  582. return;
  583. }
  584. data.merging_allowed = p_merging_allowed;
  585. for (List<Spatial *>::Element *E = data.children.front(); E; E = E->next()) {
  586. Spatial *c = E->get();
  587. if (!c) {
  588. continue;
  589. }
  590. c->_propagate_merging_allowed(p_merging_allowed);
  591. }
  592. }
  593. void Spatial::show() {
  594. if (data.visible) {
  595. return;
  596. }
  597. data.visible = true;
  598. if (!is_inside_tree()) {
  599. return;
  600. }
  601. _propagate_visibility_changed();
  602. }
  603. void Spatial::hide() {
  604. if (!data.visible) {
  605. return;
  606. }
  607. data.visible = false;
  608. if (!is_inside_tree()) {
  609. return;
  610. }
  611. _propagate_visibility_changed();
  612. }
  613. bool Spatial::is_visible_in_tree() const {
  614. const Spatial *s = this;
  615. while (s) {
  616. if (!s->data.visible) {
  617. return false;
  618. }
  619. s = s->data.parent;
  620. }
  621. return true;
  622. }
  623. void Spatial::set_visible(bool p_visible) {
  624. if (p_visible) {
  625. show();
  626. } else {
  627. hide();
  628. }
  629. }
  630. bool Spatial::is_visible() const {
  631. return data.visible;
  632. }
  633. void Spatial::rotate_object_local(const Vector3 &p_axis, float p_angle) {
  634. Transform t = get_transform();
  635. t.basis.rotate_local(p_axis, p_angle);
  636. set_transform(t);
  637. }
  638. void Spatial::rotate(const Vector3 &p_axis, float p_angle) {
  639. Transform t = get_transform();
  640. t.basis.rotate(p_axis, p_angle);
  641. set_transform(t);
  642. }
  643. void Spatial::rotate_x(float p_angle) {
  644. Transform t = get_transform();
  645. t.basis.rotate(Vector3(1, 0, 0), p_angle);
  646. set_transform(t);
  647. }
  648. void Spatial::rotate_y(float p_angle) {
  649. Transform t = get_transform();
  650. t.basis.rotate(Vector3(0, 1, 0), p_angle);
  651. set_transform(t);
  652. }
  653. void Spatial::rotate_z(float p_angle) {
  654. Transform t = get_transform();
  655. t.basis.rotate(Vector3(0, 0, 1), p_angle);
  656. set_transform(t);
  657. }
  658. void Spatial::translate(const Vector3 &p_offset) {
  659. Transform t = get_transform();
  660. t.translate(p_offset);
  661. set_transform(t);
  662. }
  663. void Spatial::translate_object_local(const Vector3 &p_offset) {
  664. Transform t = get_transform();
  665. Transform s;
  666. s.translate(p_offset);
  667. set_transform(t * s);
  668. }
  669. void Spatial::scale(const Vector3 &p_ratio) {
  670. Transform t = get_transform();
  671. t.basis.scale(p_ratio);
  672. set_transform(t);
  673. }
  674. void Spatial::scale_object_local(const Vector3 &p_scale) {
  675. Transform t = get_transform();
  676. t.basis.scale_local(p_scale);
  677. set_transform(t);
  678. }
  679. void Spatial::global_rotate(const Vector3 &p_axis, float p_angle) {
  680. Transform t = get_global_transform();
  681. t.basis.rotate(p_axis, p_angle);
  682. set_global_transform(t);
  683. }
  684. void Spatial::global_scale(const Vector3 &p_scale) {
  685. Transform t = get_global_transform();
  686. t.basis.scale(p_scale);
  687. set_global_transform(t);
  688. }
  689. void Spatial::global_translate(const Vector3 &p_offset) {
  690. Transform t = get_global_transform();
  691. t.origin += p_offset;
  692. set_global_transform(t);
  693. }
  694. void Spatial::orthonormalize() {
  695. Transform t = get_transform();
  696. t.orthonormalize();
  697. set_transform(t);
  698. }
  699. void Spatial::set_identity() {
  700. set_transform(Transform());
  701. }
  702. void Spatial::look_at(const Vector3 &p_target, const Vector3 &p_up) {
  703. Vector3 origin(get_global_transform().origin);
  704. look_at_from_position(origin, p_target, p_up);
  705. }
  706. void Spatial::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) {
  707. ERR_FAIL_COND_MSG(p_pos == p_target, "Node origin and target are in the same position, look_at() failed.");
  708. ERR_FAIL_COND_MSG(p_up == Vector3(), "The up vector can't be zero, look_at() failed.");
  709. ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos) == Vector3(), "Up vector and direction between node origin and target are aligned, look_at() failed.");
  710. Transform lookat;
  711. lookat.origin = p_pos;
  712. Vector3 original_scale(get_scale());
  713. lookat = lookat.looking_at(p_target, p_up);
  714. set_global_transform(lookat);
  715. set_scale(original_scale);
  716. }
  717. Vector3 Spatial::to_local(Vector3 p_global) const {
  718. return get_global_transform().affine_inverse().xform(p_global);
  719. }
  720. Vector3 Spatial::to_global(Vector3 p_local) const {
  721. return get_global_transform().xform(p_local);
  722. }
  723. void Spatial::set_notify_transform(bool p_enable) {
  724. data.notify_transform = p_enable;
  725. }
  726. bool Spatial::is_transform_notification_enabled() const {
  727. return data.notify_transform;
  728. }
  729. void Spatial::set_notify_local_transform(bool p_enable) {
  730. data.notify_local_transform = p_enable;
  731. }
  732. bool Spatial::is_local_transform_notification_enabled() const {
  733. return data.notify_local_transform;
  734. }
  735. void Spatial::set_merging_mode(MergingMode p_mode) {
  736. if (data.merging_mode == p_mode) {
  737. return;
  738. }
  739. data.merging_mode = p_mode;
  740. bool merging_allowed = true; // Default for root node.
  741. switch (p_mode) {
  742. case MERGING_MODE_INHERIT: {
  743. if (get_parent_spatial()) {
  744. merging_allowed = get_parent_spatial()->is_merging_allowed();
  745. }
  746. } break;
  747. case MERGING_MODE_OFF: {
  748. merging_allowed = false;
  749. } break;
  750. case MERGING_MODE_ON: {
  751. merging_allowed = true;
  752. } break;
  753. }
  754. _propagate_merging_allowed(merging_allowed);
  755. }
  756. void Spatial::set_lod_range(float p_range) {
  757. data.lod_range = p_range;
  758. }
  759. void Spatial::force_update_transform() {
  760. ERR_FAIL_COND(!is_inside_tree());
  761. if (!xform_change.in_list()) {
  762. return; //nothing to update
  763. }
  764. get_tree()->xform_change_list.remove(&xform_change);
  765. notification(NOTIFICATION_TRANSFORM_CHANGED);
  766. }
  767. void Spatial::_bind_methods() {
  768. ClassDB::bind_method(D_METHOD("set_transform", "local"), &Spatial::set_transform);
  769. ClassDB::bind_method(D_METHOD("get_transform"), &Spatial::get_transform);
  770. ClassDB::bind_method(D_METHOD("set_translation", "translation"), &Spatial::set_translation);
  771. ClassDB::bind_method(D_METHOD("get_translation"), &Spatial::get_translation);
  772. ClassDB::bind_method(D_METHOD("set_rotation", "euler"), &Spatial::set_rotation);
  773. ClassDB::bind_method(D_METHOD("get_rotation"), &Spatial::get_rotation);
  774. ClassDB::bind_method(D_METHOD("set_rotation_degrees", "euler_degrees"), &Spatial::set_rotation_degrees);
  775. ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &Spatial::get_rotation_degrees);
  776. ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Spatial::set_scale);
  777. ClassDB::bind_method(D_METHOD("get_scale"), &Spatial::get_scale);
  778. ClassDB::bind_method(D_METHOD("set_global_transform", "global"), &Spatial::set_global_transform);
  779. ClassDB::bind_method(D_METHOD("get_global_transform"), &Spatial::get_global_transform);
  780. ClassDB::bind_method(D_METHOD("set_global_translation", "translation"), &Spatial::set_global_translation);
  781. ClassDB::bind_method(D_METHOD("get_global_translation"), &Spatial::get_global_translation);
  782. ClassDB::bind_method(D_METHOD("set_global_rotation", "radians"), &Spatial::set_global_rotation);
  783. ClassDB::bind_method(D_METHOD("get_global_rotation"), &Spatial::get_global_rotation);
  784. ClassDB::bind_method(D_METHOD("get_global_transform_interpolated"), &Spatial::get_global_transform_interpolated);
  785. ClassDB::bind_method(D_METHOD("get_parent_spatial"), &Spatial::get_parent_spatial);
  786. ClassDB::bind_method(D_METHOD("set_ignore_transform_notification", "enabled"), &Spatial::set_ignore_transform_notification);
  787. ClassDB::bind_method(D_METHOD("set_as_toplevel", "enable"), &Spatial::set_as_toplevel);
  788. ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &Spatial::is_set_as_toplevel);
  789. ClassDB::bind_method(D_METHOD("set_disable_scale", "disable"), &Spatial::set_disable_scale);
  790. ClassDB::bind_method(D_METHOD("is_scale_disabled"), &Spatial::is_scale_disabled);
  791. ClassDB::bind_method(D_METHOD("get_world"), &Spatial::get_world);
  792. ClassDB::bind_method(D_METHOD("force_update_transform"), &Spatial::force_update_transform);
  793. ClassDB::bind_method(D_METHOD("_update_gizmo"), &Spatial::_update_gizmo);
  794. ClassDB::bind_method(D_METHOD("update_gizmo"), &Spatial::update_gizmo);
  795. ClassDB::bind_method(D_METHOD("set_gizmo", "gizmo"), &Spatial::set_gizmo);
  796. ClassDB::bind_method(D_METHOD("get_gizmo"), &Spatial::get_gizmo);
  797. ClassDB::bind_method(D_METHOD("set_visible", "visible"), &Spatial::set_visible);
  798. ClassDB::bind_method(D_METHOD("is_visible"), &Spatial::is_visible);
  799. ClassDB::bind_method(D_METHOD("is_visible_in_tree"), &Spatial::is_visible_in_tree);
  800. ClassDB::bind_method(D_METHOD("show"), &Spatial::show);
  801. ClassDB::bind_method(D_METHOD("hide"), &Spatial::hide);
  802. ClassDB::bind_method(D_METHOD("set_notify_local_transform", "enable"), &Spatial::set_notify_local_transform);
  803. ClassDB::bind_method(D_METHOD("is_local_transform_notification_enabled"), &Spatial::is_local_transform_notification_enabled);
  804. ClassDB::bind_method(D_METHOD("set_notify_transform", "enable"), &Spatial::set_notify_transform);
  805. ClassDB::bind_method(D_METHOD("is_transform_notification_enabled"), &Spatial::is_transform_notification_enabled);
  806. ClassDB::bind_method(D_METHOD("rotate", "axis", "angle"), &Spatial::rotate);
  807. ClassDB::bind_method(D_METHOD("global_rotate", "axis", "angle"), &Spatial::global_rotate);
  808. ClassDB::bind_method(D_METHOD("global_scale", "scale"), &Spatial::global_scale);
  809. ClassDB::bind_method(D_METHOD("global_translate", "offset"), &Spatial::global_translate);
  810. ClassDB::bind_method(D_METHOD("rotate_object_local", "axis", "angle"), &Spatial::rotate_object_local);
  811. ClassDB::bind_method(D_METHOD("scale_object_local", "scale"), &Spatial::scale_object_local);
  812. ClassDB::bind_method(D_METHOD("translate_object_local", "offset"), &Spatial::translate_object_local);
  813. ClassDB::bind_method(D_METHOD("rotate_x", "angle"), &Spatial::rotate_x);
  814. ClassDB::bind_method(D_METHOD("rotate_y", "angle"), &Spatial::rotate_y);
  815. ClassDB::bind_method(D_METHOD("rotate_z", "angle"), &Spatial::rotate_z);
  816. ClassDB::bind_method(D_METHOD("translate", "offset"), &Spatial::translate);
  817. ClassDB::bind_method(D_METHOD("orthonormalize"), &Spatial::orthonormalize);
  818. ClassDB::bind_method(D_METHOD("set_identity"), &Spatial::set_identity);
  819. ClassDB::bind_method(D_METHOD("look_at", "target", "up"), &Spatial::look_at);
  820. ClassDB::bind_method(D_METHOD("look_at_from_position", "position", "target", "up"), &Spatial::look_at_from_position);
  821. ClassDB::bind_method(D_METHOD("set_merging_mode", "mode"), &Spatial::set_merging_mode);
  822. ClassDB::bind_method(D_METHOD("get_merging_mode"), &Spatial::get_merging_mode);
  823. ClassDB::bind_method(D_METHOD("set_lod_range", "range"), &Spatial::set_lod_range);
  824. ClassDB::bind_method(D_METHOD("get_lod_range"), &Spatial::get_lod_range);
  825. ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Spatial::to_local);
  826. ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Spatial::to_global);
  827. BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED);
  828. BIND_CONSTANT(NOTIFICATION_ENTER_WORLD);
  829. BIND_CONSTANT(NOTIFICATION_EXIT_WORLD);
  830. BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
  831. BIND_CONSTANT(NOTIFICATION_ENTER_GAMEPLAY);
  832. BIND_CONSTANT(NOTIFICATION_EXIT_GAMEPLAY);
  833. BIND_ENUM_CONSTANT(MERGING_MODE_INHERIT);
  834. BIND_ENUM_CONSTANT(MERGING_MODE_OFF);
  835. BIND_ENUM_CONSTANT(MERGING_MODE_ON);
  836. ADD_GROUP("Transform", "");
  837. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_NONE, "", 0), "set_translation", "get_translation");
  838. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_translation", "get_translation");
  839. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
  840. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_NONE, "", 0), "set_rotation", "get_rotation");
  841. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_LINK, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
  842. ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
  843. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_position", PROPERTY_HINT_NONE, "", 0), "set_global_translation", "get_global_translation");
  844. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_translation", PROPERTY_HINT_NONE, "", 0), "set_global_translation", "get_global_translation");
  845. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_rotation", PROPERTY_HINT_NONE, "", 0), "set_global_rotation", "get_global_rotation");
  846. ADD_GROUP("Matrix", "");
  847. ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform");
  848. ADD_GROUP("Visibility", "");
  849. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
  850. ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "SpatialGizmo", 0), "set_gizmo", "get_gizmo");
  851. ADD_GROUP("Misc", "");
  852. ADD_PROPERTY(PropertyInfo(Variant::REAL, "lod_range", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_lod_range", "get_lod_range");
  853. ADD_PROPERTY(PropertyInfo(Variant::INT, "merging_mode", PROPERTY_HINT_ENUM, "Inherit,Off,On"), "set_merging_mode", "get_merging_mode");
  854. ADD_SIGNAL(MethodInfo("visibility_changed"));
  855. ADD_SIGNAL(MethodInfo("gameplay_entered"));
  856. ADD_SIGNAL(MethodInfo("gameplay_exited"));
  857. }
  858. Spatial::Spatial() :
  859. xform_change(this), _client_physics_interpolation_spatials_list(this) {
  860. data.dirty = DIRTY_NONE;
  861. data.children_lock = 0;
  862. data.ignore_notification = false;
  863. data.toplevel = false;
  864. data.toplevel_active = false;
  865. data.scale = Vector3(1, 1, 1);
  866. data.viewport = nullptr;
  867. data.inside_world = false;
  868. data.visible = true;
  869. data.disable_scale = false;
  870. data.vi_visible = true;
  871. data.merging_allowed = true;
  872. data.merging_mode = MERGING_MODE_INHERIT;
  873. data.client_physics_interpolation_data = nullptr;
  874. #ifdef TOOLS_ENABLED
  875. data.gizmo_disabled = false;
  876. data.gizmo_dirty = false;
  877. #endif
  878. data.notify_local_transform = false;
  879. data.notify_transform = false;
  880. data.parent = nullptr;
  881. data.C = nullptr;
  882. }
  883. Spatial::~Spatial() {
  884. _disable_client_physics_interpolation();
  885. }