node.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. import { __decorate } from "./tslib.es6.js";
  2. import { Matrix, Vector3 } from "./Maths/math.vector.js";
  3. import { serialize } from "./Misc/decorators.js";
  4. import { Observable } from "./Misc/observable.js";
  5. import { EngineStore } from "./Engines/engineStore.js";
  6. import { _WarnImport } from "./Misc/devTools.js";
  7. import { SerializationHelper } from "./Misc/decorators.serialization.js";
  8. /** @internal */
  9. class _InternalNodeDataInfo {
  10. constructor() {
  11. this._doNotSerialize = false;
  12. this._isDisposed = false;
  13. this._sceneRootNodesIndex = -1;
  14. this._isEnabled = true;
  15. this._isParentEnabled = true;
  16. this._isReady = true;
  17. this._onEnabledStateChangedObservable = new Observable();
  18. this._onClonedObservable = new Observable();
  19. }
  20. }
  21. /**
  22. * Node is the basic class for all scene objects (Mesh, Light, Camera.)
  23. */
  24. export class Node {
  25. /**
  26. * Add a new node constructor
  27. * @param type defines the type name of the node to construct
  28. * @param constructorFunc defines the constructor function
  29. */
  30. static AddNodeConstructor(type, constructorFunc) {
  31. this._NodeConstructors[type] = constructorFunc;
  32. }
  33. /**
  34. * Returns a node constructor based on type name
  35. * @param type defines the type name
  36. * @param name defines the new node name
  37. * @param scene defines the hosting scene
  38. * @param options defines optional options to transmit to constructors
  39. * @returns the new constructor or null
  40. */
  41. static Construct(type, name, scene, options) {
  42. const constructorFunc = this._NodeConstructors[type];
  43. if (!constructorFunc) {
  44. return null;
  45. }
  46. return constructorFunc(name, scene, options);
  47. }
  48. /**
  49. * Gets or sets the accessibility tag to describe the node for accessibility purpose.
  50. */
  51. set accessibilityTag(value) {
  52. this._accessibilityTag = value;
  53. this.onAccessibilityTagChangedObservable.notifyObservers(value);
  54. }
  55. get accessibilityTag() {
  56. return this._accessibilityTag;
  57. }
  58. /**
  59. * Gets or sets a boolean used to define if the node must be serialized
  60. */
  61. get doNotSerialize() {
  62. if (this._nodeDataStorage._doNotSerialize) {
  63. return true;
  64. }
  65. if (this._parentNode) {
  66. return this._parentNode.doNotSerialize;
  67. }
  68. return false;
  69. }
  70. set doNotSerialize(value) {
  71. this._nodeDataStorage._doNotSerialize = value;
  72. }
  73. /**
  74. * Gets a boolean indicating if the node has been disposed
  75. * @returns true if the node was disposed
  76. */
  77. isDisposed() {
  78. return this._nodeDataStorage._isDisposed;
  79. }
  80. /**
  81. * Gets or sets the parent of the node (without keeping the current position in the scene)
  82. * @see https://doc.babylonjs.com/features/featuresDeepDive/mesh/transforms/parent_pivot/parent
  83. */
  84. set parent(parent) {
  85. if (this._parentNode === parent) {
  86. return;
  87. }
  88. const previousParentNode = this._parentNode;
  89. // Remove self from list of children of parent
  90. if (this._parentNode && this._parentNode._children !== undefined && this._parentNode._children !== null) {
  91. const index = this._parentNode._children.indexOf(this);
  92. if (index !== -1) {
  93. this._parentNode._children.splice(index, 1);
  94. }
  95. if (!parent && !this._nodeDataStorage._isDisposed) {
  96. this._addToSceneRootNodes();
  97. }
  98. }
  99. // Store new parent
  100. this._parentNode = parent;
  101. this._isDirty = true;
  102. // Add as child to new parent
  103. if (this._parentNode) {
  104. if (this._parentNode._children === undefined || this._parentNode._children === null) {
  105. this._parentNode._children = new Array();
  106. }
  107. this._parentNode._children.push(this);
  108. if (!previousParentNode) {
  109. this._removeFromSceneRootNodes();
  110. }
  111. }
  112. // Enabled state
  113. this._syncParentEnabledState();
  114. }
  115. get parent() {
  116. return this._parentNode;
  117. }
  118. /**
  119. * @internal
  120. */
  121. _serializeAsParent(serializationObject) {
  122. serializationObject.parentId = this.uniqueId;
  123. }
  124. /** @internal */
  125. _addToSceneRootNodes() {
  126. if (this._nodeDataStorage._sceneRootNodesIndex === -1) {
  127. this._nodeDataStorage._sceneRootNodesIndex = this._scene.rootNodes.length;
  128. this._scene.rootNodes.push(this);
  129. }
  130. }
  131. /** @internal */
  132. _removeFromSceneRootNodes() {
  133. if (this._nodeDataStorage._sceneRootNodesIndex !== -1) {
  134. const rootNodes = this._scene.rootNodes;
  135. const lastIdx = rootNodes.length - 1;
  136. rootNodes[this._nodeDataStorage._sceneRootNodesIndex] = rootNodes[lastIdx];
  137. rootNodes[this._nodeDataStorage._sceneRootNodesIndex]._nodeDataStorage._sceneRootNodesIndex = this._nodeDataStorage._sceneRootNodesIndex;
  138. this._scene.rootNodes.pop();
  139. this._nodeDataStorage._sceneRootNodesIndex = -1;
  140. }
  141. }
  142. /**
  143. * Gets or sets the animation properties override
  144. */
  145. get animationPropertiesOverride() {
  146. if (!this._animationPropertiesOverride) {
  147. return this._scene.animationPropertiesOverride;
  148. }
  149. return this._animationPropertiesOverride;
  150. }
  151. set animationPropertiesOverride(value) {
  152. this._animationPropertiesOverride = value;
  153. }
  154. /**
  155. * Gets a string identifying the name of the class
  156. * @returns "Node" string
  157. */
  158. getClassName() {
  159. return "Node";
  160. }
  161. /**
  162. * Sets a callback that will be raised when the node will be disposed
  163. */
  164. set onDispose(callback) {
  165. if (this._onDisposeObserver) {
  166. this.onDisposeObservable.remove(this._onDisposeObserver);
  167. }
  168. this._onDisposeObserver = this.onDisposeObservable.add(callback);
  169. }
  170. /**
  171. * An event triggered when the enabled state of the node changes
  172. */
  173. get onEnabledStateChangedObservable() {
  174. return this._nodeDataStorage._onEnabledStateChangedObservable;
  175. }
  176. /**
  177. * An event triggered when the node is cloned
  178. */
  179. get onClonedObservable() {
  180. return this._nodeDataStorage._onClonedObservable;
  181. }
  182. /**
  183. * Creates a new Node
  184. * @param name the name and id to be given to this node
  185. * @param scene the scene this node will be added to
  186. */
  187. constructor(name, scene = null) {
  188. this._isDirty = false;
  189. this._nodeDataStorage = new _InternalNodeDataInfo();
  190. /**
  191. * Gets or sets a string used to store user defined state for the node
  192. */
  193. this.state = "";
  194. /**
  195. * Gets or sets an object used to store user defined information for the node
  196. */
  197. this.metadata = null;
  198. /**
  199. * For internal use only. Please do not use.
  200. */
  201. this.reservedDataStore = null;
  202. this._accessibilityTag = null;
  203. /**
  204. * Observable fired when an accessibility tag is changed
  205. */
  206. this.onAccessibilityTagChangedObservable = new Observable();
  207. /** @internal */
  208. this._parentContainer = null;
  209. /**
  210. * Gets a list of Animations associated with the node
  211. */
  212. this.animations = [];
  213. this._ranges = {};
  214. /**
  215. * Callback raised when the node is ready to be used
  216. */
  217. this.onReady = null;
  218. /** @internal */
  219. this._currentRenderId = -1;
  220. this._parentUpdateId = -1;
  221. /** @internal */
  222. this._childUpdateId = -1;
  223. /** @internal */
  224. this._waitingParentId = null;
  225. /** @internal */
  226. this._waitingParentInstanceIndex = null;
  227. /** @internal */
  228. this._waitingParsedUniqueId = null;
  229. /** @internal */
  230. this._cache = {};
  231. this._parentNode = null;
  232. /** @internal */
  233. this._children = null;
  234. /** @internal */
  235. this._worldMatrix = Matrix.Identity();
  236. /** @internal */
  237. this._worldMatrixDeterminant = 0;
  238. /** @internal */
  239. this._worldMatrixDeterminantIsDirty = true;
  240. this._animationPropertiesOverride = null;
  241. /** @internal */
  242. this._isNode = true;
  243. /**
  244. * An event triggered when the mesh is disposed
  245. */
  246. this.onDisposeObservable = new Observable();
  247. this._onDisposeObserver = null;
  248. // Behaviors
  249. this._behaviors = new Array();
  250. this.name = name;
  251. this.id = name;
  252. this._scene = (scene || EngineStore.LastCreatedScene);
  253. this.uniqueId = this._scene.getUniqueId();
  254. this._initCache();
  255. }
  256. /**
  257. * Gets the scene of the node
  258. * @returns a scene
  259. */
  260. getScene() {
  261. return this._scene;
  262. }
  263. /**
  264. * Gets the engine of the node
  265. * @returns a Engine
  266. */
  267. getEngine() {
  268. return this._scene.getEngine();
  269. }
  270. /**
  271. * Attach a behavior to the node
  272. * @see https://doc.babylonjs.com/features/featuresDeepDive/behaviors
  273. * @param behavior defines the behavior to attach
  274. * @param attachImmediately defines that the behavior must be attached even if the scene is still loading
  275. * @returns the current Node
  276. */
  277. addBehavior(behavior, attachImmediately = false) {
  278. const index = this._behaviors.indexOf(behavior);
  279. if (index !== -1) {
  280. return this;
  281. }
  282. behavior.init();
  283. if (this._scene.isLoading && !attachImmediately) {
  284. // We defer the attach when the scene will be loaded
  285. this._scene.onDataLoadedObservable.addOnce(() => {
  286. behavior.attach(this);
  287. });
  288. }
  289. else {
  290. behavior.attach(this);
  291. }
  292. this._behaviors.push(behavior);
  293. return this;
  294. }
  295. /**
  296. * Remove an attached behavior
  297. * @see https://doc.babylonjs.com/features/featuresDeepDive/behaviors
  298. * @param behavior defines the behavior to attach
  299. * @returns the current Node
  300. */
  301. removeBehavior(behavior) {
  302. const index = this._behaviors.indexOf(behavior);
  303. if (index === -1) {
  304. return this;
  305. }
  306. this._behaviors[index].detach();
  307. this._behaviors.splice(index, 1);
  308. return this;
  309. }
  310. /**
  311. * Gets the list of attached behaviors
  312. * @see https://doc.babylonjs.com/features/featuresDeepDive/behaviors
  313. */
  314. get behaviors() {
  315. return this._behaviors;
  316. }
  317. /**
  318. * Gets an attached behavior by name
  319. * @param name defines the name of the behavior to look for
  320. * @see https://doc.babylonjs.com/features/featuresDeepDive/behaviors
  321. * @returns null if behavior was not found else the requested behavior
  322. */
  323. getBehaviorByName(name) {
  324. for (const behavior of this._behaviors) {
  325. if (behavior.name === name) {
  326. return behavior;
  327. }
  328. }
  329. return null;
  330. }
  331. /**
  332. * Returns the latest update of the World matrix
  333. * @returns a Matrix
  334. */
  335. getWorldMatrix() {
  336. if (this._currentRenderId !== this._scene.getRenderId()) {
  337. this.computeWorldMatrix();
  338. }
  339. return this._worldMatrix;
  340. }
  341. /** @internal */
  342. _getWorldMatrixDeterminant() {
  343. if (this._worldMatrixDeterminantIsDirty) {
  344. this._worldMatrixDeterminantIsDirty = false;
  345. this._worldMatrixDeterminant = this._worldMatrix.determinant();
  346. }
  347. return this._worldMatrixDeterminant;
  348. }
  349. /**
  350. * Returns directly the latest state of the mesh World matrix.
  351. * A Matrix is returned.
  352. */
  353. get worldMatrixFromCache() {
  354. return this._worldMatrix;
  355. }
  356. // override it in derived class if you add new variables to the cache
  357. // and call the parent class method
  358. /** @internal */
  359. _initCache() {
  360. this._cache = {};
  361. }
  362. /**
  363. * @internal
  364. */
  365. updateCache(force) {
  366. if (!force && this.isSynchronized()) {
  367. return;
  368. }
  369. this._updateCache();
  370. }
  371. /**
  372. * @internal
  373. */
  374. _getActionManagerForTrigger(trigger, _initialCall = true) {
  375. if (!this.parent) {
  376. return null;
  377. }
  378. return this.parent._getActionManagerForTrigger(trigger, false);
  379. }
  380. // override it in derived class if you add new variables to the cache
  381. // and call the parent class method if !ignoreParentClass
  382. /**
  383. * @internal
  384. */
  385. _updateCache(_ignoreParentClass) { }
  386. // override it in derived class if you add new variables to the cache
  387. /** @internal */
  388. _isSynchronized() {
  389. return true;
  390. }
  391. /** @internal */
  392. _markSyncedWithParent() {
  393. if (this._parentNode) {
  394. this._parentUpdateId = this._parentNode._childUpdateId;
  395. }
  396. }
  397. /** @internal */
  398. isSynchronizedWithParent() {
  399. if (!this._parentNode) {
  400. return true;
  401. }
  402. if (this._parentNode._isDirty || this._parentUpdateId !== this._parentNode._childUpdateId) {
  403. return false;
  404. }
  405. return this._parentNode.isSynchronized();
  406. }
  407. /** @internal */
  408. isSynchronized() {
  409. if (this._parentNode && !this.isSynchronizedWithParent()) {
  410. return false;
  411. }
  412. return this._isSynchronized();
  413. }
  414. /**
  415. * Is this node ready to be used/rendered
  416. * @param _completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
  417. * @returns true if the node is ready
  418. */
  419. isReady(_completeCheck = false) {
  420. return this._nodeDataStorage._isReady;
  421. }
  422. /**
  423. * Flag the node as dirty (Forcing it to update everything)
  424. * @param _property helps children apply precise "dirtyfication"
  425. * @returns this node
  426. */
  427. markAsDirty(_property) {
  428. this._currentRenderId = Number.MAX_VALUE;
  429. this._isDirty = true;
  430. return this;
  431. }
  432. /**
  433. * Is this node enabled?
  434. * If the node has a parent, all ancestors will be checked and false will be returned if any are false (not enabled), otherwise will return true
  435. * @param checkAncestors indicates if this method should check the ancestors. The default is to check the ancestors. If set to false, the method will return the value of this node without checking ancestors
  436. * @returns whether this node (and its parent) is enabled
  437. */
  438. isEnabled(checkAncestors = true) {
  439. if (checkAncestors === false) {
  440. return this._nodeDataStorage._isEnabled;
  441. }
  442. if (!this._nodeDataStorage._isEnabled) {
  443. return false;
  444. }
  445. return this._nodeDataStorage._isParentEnabled;
  446. }
  447. /** @internal */
  448. _syncParentEnabledState() {
  449. this._nodeDataStorage._isParentEnabled = this._parentNode ? this._parentNode.isEnabled() : true;
  450. if (this._children) {
  451. this._children.forEach((c) => {
  452. c._syncParentEnabledState(); // Force children to update accordingly
  453. });
  454. }
  455. }
  456. /**
  457. * Set the enabled state of this node
  458. * @param value defines the new enabled state
  459. */
  460. setEnabled(value) {
  461. if (this._nodeDataStorage._isEnabled === value) {
  462. return;
  463. }
  464. this._nodeDataStorage._isEnabled = value;
  465. this._syncParentEnabledState();
  466. this._nodeDataStorage._onEnabledStateChangedObservable.notifyObservers(value);
  467. }
  468. /**
  469. * Is this node a descendant of the given node?
  470. * The function will iterate up the hierarchy until the ancestor was found or no more parents defined
  471. * @param ancestor defines the parent node to inspect
  472. * @returns a boolean indicating if this node is a descendant of the given node
  473. */
  474. isDescendantOf(ancestor) {
  475. if (this.parent) {
  476. if (this.parent === ancestor) {
  477. return true;
  478. }
  479. return this.parent.isDescendantOf(ancestor);
  480. }
  481. return false;
  482. }
  483. /**
  484. * @internal
  485. */
  486. _getDescendants(results, directDescendantsOnly = false, predicate) {
  487. if (!this._children) {
  488. return;
  489. }
  490. for (let index = 0; index < this._children.length; index++) {
  491. const item = this._children[index];
  492. if (!predicate || predicate(item)) {
  493. results.push(item);
  494. }
  495. if (!directDescendantsOnly) {
  496. item._getDescendants(results, false, predicate);
  497. }
  498. }
  499. }
  500. /**
  501. * Will return all nodes that have this node as ascendant
  502. * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
  503. * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
  504. * @returns all children nodes of all types
  505. */
  506. getDescendants(directDescendantsOnly, predicate) {
  507. const results = [];
  508. this._getDescendants(results, directDescendantsOnly, predicate);
  509. return results;
  510. }
  511. /**
  512. * Get all child-meshes of this node
  513. * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered (Default: false)
  514. * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
  515. * @returns an array of AbstractMesh
  516. */
  517. getChildMeshes(directDescendantsOnly, predicate) {
  518. const results = [];
  519. this._getDescendants(results, directDescendantsOnly, (node) => {
  520. return (!predicate || predicate(node)) && node.cullingStrategy !== undefined;
  521. });
  522. return results;
  523. }
  524. /**
  525. * Get all direct children of this node
  526. * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
  527. * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered (Default: true)
  528. * @returns an array of Node
  529. */
  530. getChildren(predicate, directDescendantsOnly = true) {
  531. return this.getDescendants(directDescendantsOnly, predicate);
  532. }
  533. /**
  534. * @internal
  535. */
  536. _setReady(state) {
  537. if (state === this._nodeDataStorage._isReady) {
  538. return;
  539. }
  540. if (!state) {
  541. this._nodeDataStorage._isReady = false;
  542. return;
  543. }
  544. if (this.onReady) {
  545. this.onReady(this);
  546. }
  547. this._nodeDataStorage._isReady = true;
  548. }
  549. /**
  550. * Get an animation by name
  551. * @param name defines the name of the animation to look for
  552. * @returns null if not found else the requested animation
  553. */
  554. getAnimationByName(name) {
  555. for (let i = 0; i < this.animations.length; i++) {
  556. const animation = this.animations[i];
  557. if (animation.name === name) {
  558. return animation;
  559. }
  560. }
  561. return null;
  562. }
  563. /**
  564. * Creates an animation range for this node
  565. * @param name defines the name of the range
  566. * @param from defines the starting key
  567. * @param to defines the end key
  568. */
  569. createAnimationRange(name, from, to) {
  570. // check name not already in use
  571. if (!this._ranges[name]) {
  572. this._ranges[name] = Node._AnimationRangeFactory(name, from, to);
  573. for (let i = 0, nAnimations = this.animations.length; i < nAnimations; i++) {
  574. if (this.animations[i]) {
  575. this.animations[i].createRange(name, from, to);
  576. }
  577. }
  578. }
  579. }
  580. /**
  581. * Delete a specific animation range
  582. * @param name defines the name of the range to delete
  583. * @param deleteFrames defines if animation frames from the range must be deleted as well
  584. */
  585. deleteAnimationRange(name, deleteFrames = true) {
  586. for (let i = 0, nAnimations = this.animations.length; i < nAnimations; i++) {
  587. if (this.animations[i]) {
  588. this.animations[i].deleteRange(name, deleteFrames);
  589. }
  590. }
  591. this._ranges[name] = null; // said much faster than 'delete this._range[name]'
  592. }
  593. /**
  594. * Get an animation range by name
  595. * @param name defines the name of the animation range to look for
  596. * @returns null if not found else the requested animation range
  597. */
  598. getAnimationRange(name) {
  599. return this._ranges[name] || null;
  600. }
  601. /**
  602. * Clone the current node
  603. * @param name Name of the new clone
  604. * @param newParent New parent for the clone
  605. * @param doNotCloneChildren Do not clone children hierarchy
  606. * @returns the new transform node
  607. */
  608. clone(name, newParent, doNotCloneChildren) {
  609. const result = SerializationHelper.Clone(() => new Node(name, this.getScene()), this);
  610. if (newParent) {
  611. result.parent = newParent;
  612. }
  613. if (!doNotCloneChildren) {
  614. // Children
  615. const directDescendants = this.getDescendants(true);
  616. for (let index = 0; index < directDescendants.length; index++) {
  617. const child = directDescendants[index];
  618. child.clone(name + "." + child.name, result);
  619. }
  620. }
  621. return result;
  622. }
  623. /**
  624. * Gets the list of all animation ranges defined on this node
  625. * @returns an array
  626. */
  627. getAnimationRanges() {
  628. const animationRanges = [];
  629. let name;
  630. for (name in this._ranges) {
  631. animationRanges.push(this._ranges[name]);
  632. }
  633. return animationRanges;
  634. }
  635. /**
  636. * Will start the animation sequence
  637. * @param name defines the range frames for animation sequence
  638. * @param loop defines if the animation should loop (false by default)
  639. * @param speedRatio defines the speed factor in which to run the animation (1 by default)
  640. * @param onAnimationEnd defines a function to be executed when the animation ended (undefined by default)
  641. * @returns the object created for this animation. If range does not exist, it will return null
  642. */
  643. beginAnimation(name, loop, speedRatio, onAnimationEnd) {
  644. const range = this.getAnimationRange(name);
  645. if (!range) {
  646. return null;
  647. }
  648. return this._scene.beginAnimation(this, range.from, range.to, loop, speedRatio, onAnimationEnd);
  649. }
  650. /**
  651. * Serialize animation ranges into a JSON compatible object
  652. * @returns serialization object
  653. */
  654. serializeAnimationRanges() {
  655. const serializationRanges = [];
  656. for (const name in this._ranges) {
  657. const localRange = this._ranges[name];
  658. if (!localRange) {
  659. continue;
  660. }
  661. const range = {};
  662. range.name = name;
  663. range.from = localRange.from;
  664. range.to = localRange.to;
  665. serializationRanges.push(range);
  666. }
  667. return serializationRanges;
  668. }
  669. /**
  670. * Computes the world matrix of the node
  671. * @param _force defines if the cache version should be invalidated forcing the world matrix to be created from scratch
  672. * @returns the world matrix
  673. */
  674. computeWorldMatrix(_force) {
  675. if (!this._worldMatrix) {
  676. this._worldMatrix = Matrix.Identity();
  677. }
  678. return this._worldMatrix;
  679. }
  680. /**
  681. * Releases resources associated with this node.
  682. * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
  683. * @param disposeMaterialAndTextures Set to true to also dispose referenced materials and textures (false by default)
  684. */
  685. dispose(doNotRecurse, disposeMaterialAndTextures = false) {
  686. this._nodeDataStorage._isDisposed = true;
  687. if (!doNotRecurse) {
  688. const nodes = this.getDescendants(true);
  689. for (const node of nodes) {
  690. node.dispose(doNotRecurse, disposeMaterialAndTextures);
  691. }
  692. }
  693. if (!this.parent) {
  694. this._removeFromSceneRootNodes();
  695. }
  696. else {
  697. this.parent = null;
  698. }
  699. // Callback
  700. this.onDisposeObservable.notifyObservers(this);
  701. this.onDisposeObservable.clear();
  702. this.onEnabledStateChangedObservable.clear();
  703. this.onClonedObservable.clear();
  704. // Behaviors
  705. for (const behavior of this._behaviors) {
  706. behavior.detach();
  707. }
  708. this._behaviors.length = 0;
  709. this.metadata = null;
  710. }
  711. /**
  712. * Parse animation range data from a serialization object and store them into a given node
  713. * @param node defines where to store the animation ranges
  714. * @param parsedNode defines the serialization object to read data from
  715. * @param _scene defines the hosting scene
  716. */
  717. static ParseAnimationRanges(node, parsedNode, _scene) {
  718. if (parsedNode.ranges) {
  719. for (let index = 0; index < parsedNode.ranges.length; index++) {
  720. const data = parsedNode.ranges[index];
  721. node.createAnimationRange(data.name, data.from, data.to);
  722. }
  723. }
  724. }
  725. /**
  726. * Return the minimum and maximum world vectors of the entire hierarchy under current node
  727. * @param includeDescendants Include bounding info from descendants as well (true by default)
  728. * @param predicate defines a callback function that can be customize to filter what meshes should be included in the list used to compute the bounding vectors
  729. * @returns the new bounding vectors
  730. */
  731. getHierarchyBoundingVectors(includeDescendants = true, predicate = null) {
  732. // Ensures that all world matrix will be recomputed.
  733. this.getScene().incrementRenderId();
  734. this.computeWorldMatrix(true);
  735. let min;
  736. let max;
  737. const thisAbstractMesh = this;
  738. if (thisAbstractMesh.getBoundingInfo && thisAbstractMesh.subMeshes) {
  739. // If this is an abstract mesh get its bounding info
  740. const boundingInfo = thisAbstractMesh.getBoundingInfo();
  741. min = boundingInfo.boundingBox.minimumWorld.clone();
  742. max = boundingInfo.boundingBox.maximumWorld.clone();
  743. }
  744. else {
  745. min = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
  746. max = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
  747. }
  748. if (includeDescendants) {
  749. const descendants = this.getDescendants(false);
  750. for (const descendant of descendants) {
  751. const childMesh = descendant;
  752. childMesh.computeWorldMatrix(true);
  753. // Filters meshes based on custom predicate function.
  754. if (predicate && !predicate(childMesh)) {
  755. continue;
  756. }
  757. //make sure we have the needed params to get mix and max
  758. if (!childMesh.getBoundingInfo || childMesh.getTotalVertices() === 0) {
  759. continue;
  760. }
  761. const childBoundingInfo = childMesh.getBoundingInfo();
  762. const boundingBox = childBoundingInfo.boundingBox;
  763. const minBox = boundingBox.minimumWorld;
  764. const maxBox = boundingBox.maximumWorld;
  765. Vector3.CheckExtends(minBox, min, max);
  766. Vector3.CheckExtends(maxBox, min, max);
  767. }
  768. }
  769. return {
  770. min: min,
  771. max: max,
  772. };
  773. }
  774. }
  775. /**
  776. * @internal
  777. */
  778. Node._AnimationRangeFactory = (_name, _from, _to) => {
  779. throw _WarnImport("AnimationRange");
  780. };
  781. Node._NodeConstructors = {};
  782. __decorate([
  783. serialize()
  784. ], Node.prototype, "name", void 0);
  785. __decorate([
  786. serialize()
  787. ], Node.prototype, "id", void 0);
  788. __decorate([
  789. serialize()
  790. ], Node.prototype, "uniqueId", void 0);
  791. __decorate([
  792. serialize()
  793. ], Node.prototype, "state", void 0);
  794. __decorate([
  795. serialize()
  796. ], Node.prototype, "metadata", void 0);
  797. //# sourceMappingURL=node.js.map