spatial.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  1. /*************************************************************************/
  2. /* spatial.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2020 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 "spatial.h"
  31. #include "message_queue.h"
  32. #include "scene/main/viewport.h"
  33. #include "scene/scene_string_names.h"
  34. /*
  35. possible algorithms:
  36. Algorithm 1: (current)
  37. definition of invalidation: global is invalid
  38. 1) If a node sets a LOCAL, it produces an invalidation of everything above
  39. a) If above is invalid, don't keep invalidating upwards
  40. 2) If a node sets a GLOBAL, it is converted to LOCAL (and forces validation of everything pending below)
  41. drawback: setting/reading globals is useful and used very very often, and using affine inverses is slow
  42. ---
  43. Algorithm 2: (no longer current)
  44. definition of invalidation: NONE dirty, LOCAL dirty, GLOBAL dirty
  45. 1) If a node sets a LOCAL, it must climb the tree and set it as GLOBAL dirty
  46. a) marking GLOBALs as dirty up all the tree must be done always
  47. 2) If a node sets a GLOBAL, it marks local as dirty, and that's all?
  48. //is clearing the dirty state correct in this case?
  49. drawback: setting a local down the tree forces many tree walks often
  50. --
  51. future: no idea
  52. */
  53. SpatialGizmo::SpatialGizmo() {
  54. }
  55. void Spatial::_notify_dirty() {
  56. if (!data.ignore_notification && !xform_change.in_list()) {
  57. get_tree()->xform_change_list.add(&xform_change);
  58. }
  59. }
  60. void Spatial::_update_local_transform() const {
  61. data.local_transform.basis.set_euler(data.rotation);
  62. data.local_transform.basis.scale(data.scale);
  63. data.dirty &= ~DIRTY_LOCAL;
  64. }
  65. void Spatial::_propagate_transform_changed(Spatial *p_origin) {
  66. if (!is_inside_tree()) {
  67. return;
  68. }
  69. // if (data.dirty&DIRTY_GLOBAL)
  70. // return; //already dirty
  71. data.children_lock++;
  72. for (List<Spatial *>::Element *E = data.children.front(); E; E = E->next()) {
  73. if (E->get()->data.toplevel_active)
  74. continue; //don't propagate to a toplevel
  75. E->get()->_propagate_transform_changed(p_origin);
  76. }
  77. if (!data.ignore_notification && !xform_change.in_list()) {
  78. get_tree()->xform_change_list.add(&xform_change);
  79. }
  80. data.dirty |= DIRTY_GLOBAL;
  81. data.children_lock--;
  82. }
  83. void Spatial::_notification(int p_what) {
  84. switch (p_what) {
  85. case NOTIFICATION_ENTER_TREE: {
  86. Node *p = get_parent();
  87. if (p)
  88. data.parent = p->cast_to<Spatial>();
  89. if (data.parent)
  90. data.C = data.parent->data.children.push_back(this);
  91. else
  92. data.C = NULL;
  93. if (data.toplevel && !get_tree()->is_editor_hint()) {
  94. if (data.parent) {
  95. data.local_transform = data.parent->get_global_transform() * get_transform();
  96. data.dirty = DIRTY_VECTORS; //global is always dirty upon entering a scene
  97. }
  98. data.toplevel_active = true;
  99. }
  100. data.dirty |= DIRTY_GLOBAL; //global is always dirty upon entering a scene
  101. _notify_dirty();
  102. notification(NOTIFICATION_ENTER_WORLD);
  103. } break;
  104. case NOTIFICATION_EXIT_TREE: {
  105. notification(NOTIFICATION_EXIT_WORLD, true);
  106. if (xform_change.in_list())
  107. get_tree()->xform_change_list.remove(&xform_change);
  108. if (data.C)
  109. data.parent->data.children.erase(data.C);
  110. data.parent = NULL;
  111. data.C = NULL;
  112. data.toplevel_active = false;
  113. } break;
  114. case NOTIFICATION_ENTER_WORLD: {
  115. data.inside_world = true;
  116. data.viewport = NULL;
  117. Node *parent = get_parent();
  118. while (parent && !data.viewport) {
  119. data.viewport = parent->cast_to<Viewport>();
  120. parent = parent->get_parent();
  121. }
  122. ERR_FAIL_COND(!data.viewport);
  123. if (get_script_instance()) {
  124. Variant::CallError err;
  125. get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_enter_world, NULL, 0);
  126. }
  127. #ifdef TOOLS_ENABLED
  128. if (get_tree()->is_editor_hint()) {
  129. // get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this);
  130. get_tree()->call_group(0, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this);
  131. if (!data.gizmo_disabled) {
  132. if (data.gizmo.is_valid())
  133. data.gizmo->create();
  134. }
  135. }
  136. #endif
  137. } break;
  138. case NOTIFICATION_EXIT_WORLD: {
  139. #ifdef TOOLS_ENABLED
  140. if (data.gizmo.is_valid()) {
  141. data.gizmo->free();
  142. }
  143. #endif
  144. if (get_script_instance()) {
  145. Variant::CallError err;
  146. get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_world, NULL, 0);
  147. }
  148. data.viewport = NULL;
  149. data.inside_world = false;
  150. } break;
  151. case NOTIFICATION_TRANSFORM_CHANGED: {
  152. #ifdef TOOLS_ENABLED
  153. if (data.gizmo.is_valid()) {
  154. data.gizmo->transform();
  155. }
  156. #endif
  157. } break;
  158. default: {
  159. }
  160. }
  161. }
  162. void Spatial::set_transform(const Transform &p_transform) {
  163. data.local_transform = p_transform;
  164. data.dirty |= DIRTY_VECTORS;
  165. _change_notify("transform/translation");
  166. _change_notify("transform/rotation");
  167. _change_notify("transform/scale");
  168. _propagate_transform_changed(this);
  169. if (data.notify_local_transform) {
  170. notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
  171. }
  172. }
  173. void Spatial::set_global_transform(const Transform &p_transform) {
  174. Transform xform =
  175. (data.parent && !data.toplevel_active) ?
  176. data.parent->get_global_transform().affine_inverse() * p_transform :
  177. p_transform;
  178. set_transform(xform);
  179. }
  180. Transform Spatial::get_transform() const {
  181. if (data.dirty & DIRTY_LOCAL) {
  182. _update_local_transform();
  183. }
  184. return data.local_transform;
  185. }
  186. Transform Spatial::get_global_transform() const {
  187. ERR_FAIL_COND_V(!is_inside_tree(), Transform());
  188. if (data.dirty & DIRTY_GLOBAL) {
  189. if (data.dirty & DIRTY_LOCAL) {
  190. _update_local_transform();
  191. }
  192. if (data.parent && !data.toplevel_active) {
  193. data.global_transform = data.parent->get_global_transform() * data.local_transform;
  194. } else {
  195. data.global_transform = data.local_transform;
  196. }
  197. data.dirty &= ~DIRTY_GLOBAL;
  198. }
  199. return data.global_transform;
  200. }
  201. #if 0
  202. void Spatial::add_child_notify(Node *p_child) {
  203. /*
  204. Spatial *s=p_child->cast_to<Spatial>();
  205. if (!s)
  206. return;
  207. ERR_FAIL_COND(data.children_lock>0);
  208. s->data.dirty=DIRTY_GLOBAL; // don't allow global transform to be valid
  209. s->data.parent=this;
  210. data.children.push_back(s);
  211. s->data.C=data.children.back();
  212. */
  213. }
  214. void Spatial::remove_child_notify(Node *p_child) {
  215. /*
  216. Spatial *s=p_child->cast_to<Spatial>();
  217. if (!s)
  218. return;
  219. ERR_FAIL_COND(data.children_lock>0);
  220. if (s->data.C)
  221. data.children.erase(s->data.C);
  222. s->data.parent=NULL;
  223. s->data.C=NULL;
  224. */
  225. }
  226. #endif
  227. Spatial *Spatial::get_parent_spatial() const {
  228. return data.parent;
  229. }
  230. Transform Spatial::get_relative_transform(const Node *p_parent) const {
  231. if (p_parent == this)
  232. return Transform();
  233. ERR_FAIL_COND_V(!data.parent, Transform());
  234. if (p_parent == data.parent)
  235. return get_transform();
  236. else
  237. return data.parent->get_relative_transform(p_parent) * get_transform();
  238. }
  239. void Spatial::set_translation(const Vector3 &p_translation) {
  240. data.local_transform.origin = p_translation;
  241. _propagate_transform_changed(this);
  242. if (data.notify_local_transform) {
  243. notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
  244. }
  245. }
  246. void Spatial::set_rotation(const Vector3 &p_euler_rad) {
  247. if (data.dirty & DIRTY_VECTORS) {
  248. data.scale = data.local_transform.basis.get_scale();
  249. data.dirty &= ~DIRTY_VECTORS;
  250. }
  251. data.rotation = p_euler_rad;
  252. data.dirty |= DIRTY_LOCAL;
  253. _propagate_transform_changed(this);
  254. if (data.notify_local_transform) {
  255. notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
  256. }
  257. }
  258. void Spatial::set_rotation_deg(const Vector3 &p_euler_deg) {
  259. set_rotation(p_euler_deg * Math_PI / 180.0);
  260. }
  261. void Spatial::_set_rotation_deg(const Vector3 &p_euler_deg) {
  262. WARN_PRINT("Deprecated method Spatial._set_rotation_deg(): This method was renamed to set_rotation_deg. Please adapt your code accordingly, as the old method will be obsoleted.");
  263. set_rotation_deg(p_euler_deg);
  264. }
  265. void Spatial::set_scale(const Vector3 &p_scale) {
  266. if (data.dirty & DIRTY_VECTORS) {
  267. data.rotation = data.local_transform.basis.get_euler();
  268. data.dirty &= ~DIRTY_VECTORS;
  269. }
  270. data.scale = p_scale;
  271. data.dirty |= DIRTY_LOCAL;
  272. _propagate_transform_changed(this);
  273. if (data.notify_local_transform) {
  274. notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
  275. }
  276. }
  277. Vector3 Spatial::get_translation() const {
  278. return data.local_transform.origin;
  279. }
  280. Vector3 Spatial::get_rotation() const {
  281. if (data.dirty & DIRTY_VECTORS) {
  282. data.scale = data.local_transform.basis.get_scale();
  283. data.rotation = data.local_transform.basis.get_euler();
  284. data.dirty &= ~DIRTY_VECTORS;
  285. }
  286. return data.rotation;
  287. }
  288. Vector3 Spatial::get_rotation_deg() const {
  289. return get_rotation() * 180.0 / Math_PI;
  290. }
  291. // Kept for compatibility after rename to set_rotd.
  292. // Could be removed after a couple releases.
  293. Vector3 Spatial::_get_rotation_deg() const {
  294. WARN_PRINT("Deprecated method Spatial._get_rotation_deg(): This method was renamed to get_rotation_deg. Please adapt your code accordingly, as the old method will be obsoleted.");
  295. return get_rotation_deg();
  296. }
  297. Vector3 Spatial::get_scale() const {
  298. if (data.dirty & DIRTY_VECTORS) {
  299. data.scale = data.local_transform.basis.get_scale();
  300. data.rotation = data.local_transform.basis.get_euler();
  301. data.dirty &= ~DIRTY_VECTORS;
  302. }
  303. return data.scale;
  304. }
  305. void Spatial::update_gizmo() {
  306. #ifdef TOOLS_ENABLED
  307. if (!is_inside_world())
  308. return;
  309. if (!data.gizmo.is_valid())
  310. return;
  311. if (data.gizmo_dirty)
  312. return;
  313. data.gizmo_dirty = true;
  314. MessageQueue::get_singleton()->push_call(this, "_update_gizmo");
  315. #endif
  316. }
  317. void Spatial::set_gizmo(const Ref<SpatialGizmo> &p_gizmo) {
  318. #ifdef TOOLS_ENABLED
  319. if (data.gizmo_disabled)
  320. return;
  321. if (data.gizmo.is_valid() && is_inside_world())
  322. data.gizmo->free();
  323. data.gizmo = p_gizmo;
  324. if (data.gizmo.is_valid() && is_inside_world()) {
  325. data.gizmo->create();
  326. data.gizmo->redraw();
  327. data.gizmo->transform();
  328. }
  329. #endif
  330. }
  331. Ref<SpatialGizmo> Spatial::get_gizmo() const {
  332. #ifdef TOOLS_ENABLED
  333. return data.gizmo;
  334. #else
  335. return Ref<SpatialGizmo>();
  336. #endif
  337. }
  338. #ifdef TOOLS_ENABLED
  339. void Spatial::_update_gizmo() {
  340. data.gizmo_dirty = false;
  341. if (data.gizmo.is_valid()) {
  342. if (is_visible())
  343. data.gizmo->redraw();
  344. else
  345. data.gizmo->clear();
  346. }
  347. }
  348. void Spatial::set_disable_gizmo(bool p_enabled) {
  349. data.gizmo_disabled = p_enabled;
  350. if (!p_enabled && data.gizmo.is_valid())
  351. data.gizmo = Ref<SpatialGizmo>();
  352. }
  353. #endif
  354. void Spatial::set_as_toplevel(bool p_enabled) {
  355. if (data.toplevel == p_enabled)
  356. return;
  357. if (is_inside_tree() && !get_tree()->is_editor_hint()) {
  358. if (p_enabled)
  359. set_transform(get_global_transform());
  360. else if (data.parent)
  361. set_transform(data.parent->get_global_transform().affine_inverse() * get_global_transform());
  362. data.toplevel = p_enabled;
  363. data.toplevel_active = p_enabled;
  364. } else {
  365. data.toplevel = p_enabled;
  366. }
  367. }
  368. bool Spatial::is_set_as_toplevel() const {
  369. return data.toplevel;
  370. }
  371. Ref<World> Spatial::get_world() const {
  372. ERR_FAIL_COND_V(!is_inside_world(), Ref<World>());
  373. return data.viewport->find_world();
  374. }
  375. #ifdef TOOLS_ENABLED
  376. void Spatial::set_import_transform(const Transform &p_transform) {
  377. data.import_transform = p_transform;
  378. }
  379. Transform Spatial::get_import_transform() const {
  380. return data.import_transform;
  381. }
  382. #endif
  383. void Spatial::_propagate_visibility_changed() {
  384. notification(NOTIFICATION_VISIBILITY_CHANGED);
  385. emit_signal(SceneStringNames::get_singleton()->visibility_changed);
  386. _change_notify("visibility/visible");
  387. #ifdef TOOLS_ENABLED
  388. if (data.gizmo.is_valid())
  389. _update_gizmo();
  390. #endif
  391. for (List<Spatial *>::Element *E = data.children.front(); E; E = E->next()) {
  392. Spatial *c = E->get();
  393. if (!c || !c->data.visible)
  394. continue;
  395. c->_propagate_visibility_changed();
  396. }
  397. }
  398. void Spatial::show() {
  399. if (data.visible)
  400. return;
  401. data.visible = true;
  402. if (!is_inside_tree())
  403. return;
  404. _propagate_visibility_changed();
  405. }
  406. void Spatial::hide() {
  407. if (!data.visible)
  408. return;
  409. data.visible = false;
  410. if (!is_inside_tree())
  411. return;
  412. _propagate_visibility_changed();
  413. }
  414. bool Spatial::is_visible() const {
  415. const Spatial *s = this;
  416. while (s) {
  417. if (!s->data.visible) {
  418. return false;
  419. }
  420. s = s->data.parent;
  421. }
  422. return true;
  423. }
  424. bool Spatial::is_hidden() const {
  425. return !data.visible;
  426. }
  427. void Spatial::set_hidden(bool p_hidden) {
  428. if (data.visible != p_hidden) {
  429. return;
  430. }
  431. _set_visible_(!p_hidden);
  432. }
  433. void Spatial::_set_visible_(bool p_visible) {
  434. if (p_visible)
  435. show();
  436. else
  437. hide();
  438. }
  439. bool Spatial::_is_visible_() const {
  440. return !is_hidden();
  441. }
  442. void Spatial::rotate(const Vector3 &p_normal, float p_radians) {
  443. Transform t = get_transform();
  444. t.basis.rotate(p_normal, p_radians);
  445. set_transform(t);
  446. }
  447. void Spatial::rotate_x(float p_radians) {
  448. Transform t = get_transform();
  449. t.basis.rotate(Vector3(1, 0, 0), p_radians);
  450. set_transform(t);
  451. }
  452. void Spatial::rotate_y(float p_radians) {
  453. Transform t = get_transform();
  454. t.basis.rotate(Vector3(0, 1, 0), p_radians);
  455. set_transform(t);
  456. }
  457. void Spatial::rotate_z(float p_radians) {
  458. Transform t = get_transform();
  459. t.basis.rotate(Vector3(0, 0, 1), p_radians);
  460. set_transform(t);
  461. }
  462. void Spatial::translate(const Vector3 &p_offset) {
  463. Transform t = get_transform();
  464. t.translate(p_offset);
  465. set_transform(t);
  466. }
  467. void Spatial::scale(const Vector3 &p_ratio) {
  468. Transform t = get_transform();
  469. t.basis.scale(p_ratio);
  470. set_transform(t);
  471. }
  472. void Spatial::global_rotate(const Vector3 &p_normal, float p_radians) {
  473. Matrix3 rotation(p_normal, p_radians);
  474. Transform t = get_global_transform();
  475. t.basis = rotation * t.basis;
  476. set_global_transform(t);
  477. }
  478. void Spatial::global_translate(const Vector3 &p_offset) {
  479. Transform t = get_global_transform();
  480. t.origin += p_offset;
  481. set_global_transform(t);
  482. }
  483. void Spatial::orthonormalize() {
  484. Transform t = get_transform();
  485. t.orthonormalize();
  486. set_transform(t);
  487. }
  488. void Spatial::set_identity() {
  489. set_transform(Transform());
  490. }
  491. void Spatial::look_at(const Vector3 &p_target, const Vector3 &p_up_normal) {
  492. Transform lookat;
  493. lookat.origin = get_global_transform().origin;
  494. if (lookat.origin == p_target) {
  495. ERR_EXPLAIN("Node origin and target are in the same position, look_at() failed");
  496. ERR_FAIL();
  497. }
  498. if (p_up_normal.cross(p_target - lookat.origin) == Vector3()) {
  499. ERR_EXPLAIN("Up vector and direction between node origin and target are aligned, look_at() failed");
  500. ERR_FAIL();
  501. }
  502. lookat = lookat.looking_at(p_target, p_up_normal);
  503. set_global_transform(lookat);
  504. }
  505. void Spatial::look_at_from_pos(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up_normal) {
  506. Transform lookat;
  507. lookat.origin = p_pos;
  508. lookat = lookat.looking_at(p_target, p_up_normal);
  509. set_global_transform(lookat);
  510. }
  511. void Spatial::set_notify_local_transform(bool p_enable) {
  512. data.notify_local_transform = p_enable;
  513. }
  514. bool Spatial::is_local_transform_notification_enabled() const {
  515. return data.notify_local_transform;
  516. }
  517. void Spatial::_bind_methods() {
  518. ObjectTypeDB::bind_method(_MD("set_transform", "local"), &Spatial::set_transform);
  519. ObjectTypeDB::bind_method(_MD("get_transform"), &Spatial::get_transform);
  520. ObjectTypeDB::bind_method(_MD("set_translation", "translation"), &Spatial::set_translation);
  521. ObjectTypeDB::bind_method(_MD("get_translation"), &Spatial::get_translation);
  522. ObjectTypeDB::bind_method(_MD("set_rotation", "rotation_rad"), &Spatial::set_rotation);
  523. ObjectTypeDB::bind_method(_MD("get_rotation"), &Spatial::get_rotation);
  524. ObjectTypeDB::bind_method(_MD("set_rotation_deg", "rotation_deg"), &Spatial::set_rotation_deg);
  525. ObjectTypeDB::bind_method(_MD("get_rotation_deg"), &Spatial::get_rotation_deg);
  526. ObjectTypeDB::bind_method(_MD("set_scale", "scale"), &Spatial::set_scale);
  527. ObjectTypeDB::bind_method(_MD("get_scale"), &Spatial::get_scale);
  528. ObjectTypeDB::bind_method(_MD("set_global_transform", "global"), &Spatial::set_global_transform);
  529. ObjectTypeDB::bind_method(_MD("get_global_transform"), &Spatial::get_global_transform);
  530. ObjectTypeDB::bind_method(_MD("get_parent_spatial"), &Spatial::get_parent_spatial);
  531. ObjectTypeDB::bind_method(_MD("set_ignore_transform_notification", "enabled"), &Spatial::set_ignore_transform_notification);
  532. ObjectTypeDB::bind_method(_MD("set_as_toplevel", "enable"), &Spatial::set_as_toplevel);
  533. ObjectTypeDB::bind_method(_MD("is_set_as_toplevel"), &Spatial::is_set_as_toplevel);
  534. ObjectTypeDB::bind_method(_MD("get_world:World"), &Spatial::get_world);
  535. // TODO: Obsolete those two methods (old name) properly (GH-4397)
  536. ObjectTypeDB::bind_method(_MD("_set_rotation_deg", "rotation_deg"), &Spatial::_set_rotation_deg);
  537. ObjectTypeDB::bind_method(_MD("_get_rotation_deg"), &Spatial::_get_rotation_deg);
  538. #ifdef TOOLS_ENABLED
  539. ObjectTypeDB::bind_method(_MD("_update_gizmo"), &Spatial::_update_gizmo);
  540. ObjectTypeDB::bind_method(_MD("_set_import_transform"), &Spatial::set_import_transform);
  541. ObjectTypeDB::bind_method(_MD("_get_import_transform"), &Spatial::get_import_transform);
  542. ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "_import_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), _SCS("_set_import_transform"), _SCS("_get_import_transform"));
  543. #endif
  544. ObjectTypeDB::bind_method(_MD("update_gizmo"), &Spatial::update_gizmo);
  545. ObjectTypeDB::bind_method(_MD("set_gizmo", "gizmo:SpatialGizmo"), &Spatial::set_gizmo);
  546. ObjectTypeDB::bind_method(_MD("get_gizmo:SpatialGizmo"), &Spatial::get_gizmo);
  547. ObjectTypeDB::bind_method(_MD("show"), &Spatial::show);
  548. ObjectTypeDB::bind_method(_MD("hide"), &Spatial::hide);
  549. ObjectTypeDB::bind_method(_MD("is_visible"), &Spatial::is_visible);
  550. ObjectTypeDB::bind_method(_MD("is_hidden"), &Spatial::is_hidden);
  551. ObjectTypeDB::bind_method(_MD("set_hidden", "hidden"), &Spatial::set_hidden);
  552. ObjectTypeDB::bind_method(_MD("_set_visible_"), &Spatial::_set_visible_);
  553. ObjectTypeDB::bind_method(_MD("_is_visible_"), &Spatial::_is_visible_);
  554. ObjectTypeDB::bind_method(_MD("set_notify_local_transform", "enable"), &Spatial::set_notify_local_transform);
  555. ObjectTypeDB::bind_method(_MD("is_local_transform_notification_enabled"), &Spatial::is_local_transform_notification_enabled);
  556. void rotate(const Vector3 &p_normal, float p_radians);
  557. void rotate_x(float p_radians);
  558. void rotate_y(float p_radians);
  559. void rotate_z(float p_radians);
  560. void translate(const Vector3 &p_offset);
  561. void scale(const Vector3 &p_ratio);
  562. void global_rotate(const Vector3 &p_normal, float p_radians);
  563. void global_translate(const Vector3 &p_offset);
  564. ObjectTypeDB::bind_method(_MD("rotate", "normal", "radians"), &Spatial::rotate);
  565. ObjectTypeDB::bind_method(_MD("global_rotate", "normal", "radians"), &Spatial::global_rotate);
  566. ObjectTypeDB::bind_method(_MD("rotate_x", "radians"), &Spatial::rotate_x);
  567. ObjectTypeDB::bind_method(_MD("rotate_y", "radians"), &Spatial::rotate_y);
  568. ObjectTypeDB::bind_method(_MD("rotate_z", "radians"), &Spatial::rotate_z);
  569. ObjectTypeDB::bind_method(_MD("translate", "offset"), &Spatial::translate);
  570. ObjectTypeDB::bind_method(_MD("global_translate", "offset"), &Spatial::global_translate);
  571. ObjectTypeDB::bind_method(_MD("orthonormalize"), &Spatial::orthonormalize);
  572. ObjectTypeDB::bind_method(_MD("set_identity"), &Spatial::set_identity);
  573. ObjectTypeDB::bind_method(_MD("look_at", "target", "up"), &Spatial::look_at);
  574. ObjectTypeDB::bind_method(_MD("look_at_from_pos", "pos", "target", "up"), &Spatial::look_at_from_pos);
  575. BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED);
  576. BIND_CONSTANT(NOTIFICATION_ENTER_WORLD);
  577. BIND_CONSTANT(NOTIFICATION_EXIT_WORLD);
  578. BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
  579. //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), _SCS("set_global_transform"), _SCS("get_global_transform") );
  580. ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "transform/local", PROPERTY_HINT_NONE, ""), _SCS("set_transform"), _SCS("get_transform"));
  581. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "transform/translation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), _SCS("set_translation"), _SCS("get_translation"));
  582. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "transform/rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), _SCS("set_rotation_deg"), _SCS("get_rotation_deg"));
  583. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "transform/rotation_rad", PROPERTY_HINT_NONE, "", 0), _SCS("set_rotation"), _SCS("get_rotation"));
  584. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "transform/scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), _SCS("set_scale"), _SCS("get_scale"));
  585. ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "visibility/visible"), _SCS("_set_visible_"), _SCS("_is_visible_"));
  586. //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/local"), _SCS("set_transform"), _SCS("get_transform") );
  587. ADD_SIGNAL(MethodInfo("visibility_changed"));
  588. }
  589. Spatial::Spatial() :
  590. xform_change(this) {
  591. data.dirty = DIRTY_NONE;
  592. data.children_lock = 0;
  593. data.ignore_notification = false;
  594. data.toplevel = false;
  595. data.toplevel_active = false;
  596. data.scale = Vector3(1, 1, 1);
  597. data.viewport = NULL;
  598. data.inside_world = false;
  599. data.visible = true;
  600. #ifdef TOOLS_ENABLED
  601. data.gizmo_disabled = false;
  602. data.gizmo_dirty = false;
  603. #endif
  604. data.notify_local_transform = false;
  605. data.parent = NULL;
  606. data.C = NULL;
  607. }
  608. Spatial::~Spatial() {
  609. }