Browse Source

Added node._children to track children hierarchy

David Catuhe 9 years ago
parent
commit
a42d7f62df

File diff suppressed because it is too large
+ 21 - 21
dist/preview release/babylon.core.js


File diff suppressed because it is too large
+ 2208 - 2206
dist/preview release/babylon.d.ts


File diff suppressed because it is too large
+ 26 - 25
dist/preview release/babylon.js


+ 53 - 17
dist/preview release/babylon.max.js

@@ -7129,6 +7129,31 @@ var BABYLON;
             this._scene = scene;
             this._scene = scene;
             this._initCache();
             this._initCache();
         }
         }
+        Object.defineProperty(Node.prototype, "parent", {
+            get: function () {
+                return this._parentNode;
+            },
+            set: function (parent) {
+                if (this._parentNode === parent) {
+                    return;
+                }
+                if (this._parentNode) {
+                    var index = this._parentNode._children.indexOf(this);
+                    if (index !== -1) {
+                        this._parentNode._children.splice(index, 1);
+                    }
+                }
+                this._parentNode = parent;
+                if (this._parentNode) {
+                    if (!this._parentNode._children) {
+                        this._parentNode._children = new Array();
+                    }
+                    this._parentNode._children.push(this);
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
         Node.prototype.getScene = function () {
         Node.prototype.getScene = function () {
             return this._scene;
             return this._scene;
         };
         };
@@ -7232,32 +7257,35 @@ var BABYLON;
             return false;
             return false;
         };
         };
         /**
         /**
-         * Evaluate a list of nodes and determine if they should be considered as descendants considering the given criterias
-         * @param {BABYLON.Node[]} list the input array of nodes to evaluate
+         * Evaluate the list of children and determine if they should be considered as descendants considering the given criterias
          * @param {BABYLON.Node[]} results the result array containing the nodes matching the given criterias
          * @param {BABYLON.Node[]} results the result array containing the nodes matching the given criterias
-         * @param {boolean} directDecendantsOnly 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.
+         * @param {boolean} directDescendantsOnly 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.
          * @param predicate: an optional predicate that will be called on every evaluated children, the predicate must return true for a given child to be part of the result, otherwise it will be ignored.
          * @param predicate: an optional predicate that will be called on every evaluated children, the predicate must return true for a given child to be part of the result, otherwise it will be ignored.
          */
          */
-        Node.prototype._getDescendants = function (list, results, directDecendantsOnly, predicate) {
-            if (directDecendantsOnly === void 0) { directDecendantsOnly = false; }
-            for (var index = 0; index < list.length; index++) {
-                var item = list[index];
-                if (((directDecendantsOnly && item.parent === this) || (!directDecendantsOnly && item.isDescendantOf(this))) && (!predicate || predicate(item))) {
+        Node.prototype._getDescendants = function (results, directDescendantsOnly, predicate) {
+            if (directDescendantsOnly === void 0) { directDescendantsOnly = false; }
+            if (!this._children) {
+                return;
+            }
+            for (var index = 0; index < this._children.length; index++) {
+                var item = this._children[index];
+                if (!predicate || predicate(item)) {
                     results.push(item);
                     results.push(item);
                 }
                 }
+                if (!directDescendantsOnly) {
+                    item._getDescendants(results, false, predicate);
+                }
             }
             }
         };
         };
         /**
         /**
-         * Will return all nodes that have this node as parent.
-         * @param {boolean} directDecendantsOnly 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.
+         * Will return all nodes that have this node as ascendant.
+         * @param {boolean} directDescendantsOnly 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.
          * @param predicate: an optional predicate that will be called on every evaluated children, the predicate must return true for a given child to be part of the result, otherwise it will be ignored.
          * @param predicate: an optional predicate that will be called on every evaluated children, the predicate must return true for a given child to be part of the result, otherwise it will be ignored.
          * @return {BABYLON.Node[]} all children nodes of all types.
          * @return {BABYLON.Node[]} all children nodes of all types.
          */
          */
-        Node.prototype.getDescendants = function (directDecendantsOnly, predicate) {
+        Node.prototype.getDescendants = function (directDescendantsOnly, predicate) {
             var results = [];
             var results = [];
-            this._getDescendants(this._scene.meshes, results, directDecendantsOnly, predicate);
-            this._getDescendants(this._scene.lights, results, directDecendantsOnly, predicate);
-            this._getDescendants(this._scene.cameras, results, directDecendantsOnly, predicate);
+            this._getDescendants(results, directDescendantsOnly, predicate);
             return results;
             return results;
         };
         };
         /**
         /**
@@ -7273,7 +7301,9 @@ var BABYLON;
          */
          */
         Node.prototype.getChildMeshes = function (directDecendantsOnly, predicate) {
         Node.prototype.getChildMeshes = function (directDecendantsOnly, predicate) {
             var results = [];
             var results = [];
-            this._getDescendants(this._scene.meshes, results, directDecendantsOnly, predicate);
+            this._getDescendants(results, directDecendantsOnly, function (node) {
+                return ((!predicate || predicate(node)) && (node instanceof BABYLON.AbstractMesh));
+            });
             return results;
             return results;
         };
         };
         Node.prototype._setReady = function (state) {
         Node.prototype._setReady = function (state) {
@@ -7339,6 +7369,9 @@ var BABYLON;
             }
             }
             return serializationRanges;
             return serializationRanges;
         };
         };
+        Node.prototype.dispose = function () {
+            this.parent = null;
+        };
         Node.ParseAnimationRanges = function (node, parsedNode, scene) {
         Node.ParseAnimationRanges = function (node, parsedNode, scene) {
             if (parsedNode.ranges) {
             if (parsedNode.ranges) {
                 for (var index = 0; index < parsedNode.ranges.length; index++) {
                 for (var index = 0; index < parsedNode.ranges.length; index++) {
@@ -9023,6 +9056,7 @@ var BABYLON;
                     }
                     }
                 }
                 }
             }
             }
+            _super.prototype.dispose.call(this);
             this._onAfterWorldMatrixUpdate = [];
             this._onAfterWorldMatrixUpdate = [];
             this._isDisposed = true;
             this._isDisposed = true;
             // Callback
             // Callback
@@ -9133,6 +9167,7 @@ var BABYLON;
             this.getScene().stopAnimation(this);
             this.getScene().stopAnimation(this);
             // Remove from scene
             // Remove from scene
             this.getScene().removeLight(this);
             this.getScene().removeLight(this);
+            _super.prototype.dispose.call(this);
         };
         };
         Light.prototype.getTypeID = function () {
         Light.prototype.getTypeID = function () {
             return 0;
             return 0;
@@ -10881,6 +10916,7 @@ var BABYLON;
             for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
             for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
                 this._postProcesses[this._postProcessesTakenIndices[i]].dispose(this);
                 this._postProcesses[this._postProcessesTakenIndices[i]].dispose(this);
             }
             }
+            _super.prototype.dispose.call(this);
         };
         };
         // ---- Camera rigs section ----
         // ---- Camera rigs section ----
         Camera.prototype.setCameraRigMode = function (mode, rigParams) {
         Camera.prototype.setCameraRigMode = function (mode, rigParams) {
@@ -11176,7 +11212,7 @@ var BABYLON;
         CameraInputsManager.prototype.remove = function (inputToRemove) {
         CameraInputsManager.prototype.remove = function (inputToRemove) {
             for (var cam in this.attached) {
             for (var cam in this.attached) {
                 var input = this.attached[cam];
                 var input = this.attached[cam];
-                if (input == inputToRemove) {
+                if (input === inputToRemove) {
                     input.detachControl(this.attachedElement);
                     input.detachControl(this.attachedElement);
                     delete this.attached[cam];
                     delete this.attached[cam];
                 }
                 }
@@ -11185,7 +11221,7 @@ var BABYLON;
         CameraInputsManager.prototype.removeByType = function (inputType) {
         CameraInputsManager.prototype.removeByType = function (inputType) {
             for (var cam in this.attached) {
             for (var cam in this.attached) {
                 var input = this.attached[cam];
                 var input = this.attached[cam];
-                if (input.getTypeName() == inputType) {
+                if (input.getTypeName() === inputType) {
                     input.detachControl(this.attachedElement);
                     input.detachControl(this.attachedElement);
                     delete this.attached[cam];
                     delete this.attached[cam];
                 }
                 }

File diff suppressed because it is too large
+ 26 - 25
dist/preview release/babylon.noworker.js


+ 1 - 0
dist/preview release/what's new.md

@@ -10,6 +10,7 @@
     - New debuger tool: SkeletonViewer. See [demo here](Demo available here: http://www.babylonjs-playground.com/#1BZJVJ#8) (Adam & [deltakosh](https://github.com/deltakosh))
     - New debuger tool: SkeletonViewer. See [demo here](Demo available here: http://www.babylonjs-playground.com/#1BZJVJ#8) (Adam & [deltakosh](https://github.com/deltakosh))
     - Added Camera Inputs Manager to manage camera inputs (mouse, touch, keyboard, gamepad, ...) in a composable way, without relying on class inheritance [gleborgne](https://github.com/gleborgne)
     - Added Camera Inputs Manager to manage camera inputs (mouse, touch, keyboard, gamepad, ...) in a composable way, without relying on class inheritance [gleborgne](https://github.com/gleborgne)
   - **Updates**
   - **Updates**
+    - Added node._children to track children hierarchy ([deltakosh](https://github.com/deltakosh))
     - Added Camera.ForceAttachControlToAlwaysPreventDefault to help embedding Babylon.js in iFrames ([deltakosh](https://github.com/deltakosh))
     - Added Camera.ForceAttachControlToAlwaysPreventDefault to help embedding Babylon.js in iFrames ([deltakosh](https://github.com/deltakosh))
     - Support for Layer.alphaTest ([deltakosh](https://github.com/deltakosh))
     - Support for Layer.alphaTest ([deltakosh](https://github.com/deltakosh))
     - New scene.pointerDownPredicate, scene.pointerMovePredicate, scene.pointerUpPredicate to define your own predicates for meshes picking selection ([deltakosh](https://github.com/deltakosh))
     - New scene.pointerDownPredicate, scene.pointerMovePredicate, scene.pointerUpPredicate to define your own predicates for meshes picking selection ([deltakosh](https://github.com/deltakosh))

+ 1 - 0
src/Cameras/babylon.camera.js

@@ -368,6 +368,7 @@ var BABYLON;
             for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
             for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
                 this._postProcesses[this._postProcessesTakenIndices[i]].dispose(this);
                 this._postProcesses[this._postProcessesTakenIndices[i]].dispose(this);
             }
             }
+            _super.prototype.dispose.call(this);
         };
         };
         // ---- Camera rigs section ----
         // ---- Camera rigs section ----
         Camera.prototype.setCameraRigMode = function (mode, rigParams) {
         Camera.prototype.setCameraRigMode = function (mode, rigParams) {

+ 2 - 0
src/Cameras/babylon.camera.ts

@@ -455,6 +455,8 @@
             for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
             for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
                 this._postProcesses[this._postProcessesTakenIndices[i]].dispose(this);
                 this._postProcesses[this._postProcessesTakenIndices[i]].dispose(this);
             }
             }
+
+            super.dispose();
         }
         }
         
         
         // ---- Camera rigs section ----
         // ---- Camera rigs section ----

+ 2 - 2
src/Cameras/babylon.cameraInputsManager.js

@@ -27,7 +27,7 @@ var BABYLON;
         CameraInputsManager.prototype.remove = function (inputToRemove) {
         CameraInputsManager.prototype.remove = function (inputToRemove) {
             for (var cam in this.attached) {
             for (var cam in this.attached) {
                 var input = this.attached[cam];
                 var input = this.attached[cam];
-                if (input == inputToRemove) {
+                if (input === inputToRemove) {
                     input.detachControl(this.attachedElement);
                     input.detachControl(this.attachedElement);
                     delete this.attached[cam];
                     delete this.attached[cam];
                 }
                 }
@@ -36,7 +36,7 @@ var BABYLON;
         CameraInputsManager.prototype.removeByType = function (inputType) {
         CameraInputsManager.prototype.removeByType = function (inputType) {
             for (var cam in this.attached) {
             for (var cam in this.attached) {
                 var input = this.attached[cam];
                 var input = this.attached[cam];
-                if (input.getTypeName() == inputType) {
+                if (input.getTypeName() === inputType) {
                     input.detachControl(this.attachedElement);
                     input.detachControl(this.attachedElement);
                     delete this.attached[cam];
                     delete this.attached[cam];
                 }
                 }

+ 2 - 2
src/Cameras/babylon.cameraInputsManager.ts

@@ -52,7 +52,7 @@ module BABYLON {
         public remove(inputToRemove: ICameraInput<TCamera>) {
         public remove(inputToRemove: ICameraInput<TCamera>) {
             for (var cam in this.attached) {
             for (var cam in this.attached) {
                 var input = this.attached[cam];
                 var input = this.attached[cam];
-                if (input == inputToRemove) {
+                if (input === inputToRemove) {
                     input.detachControl(this.attachedElement);
                     input.detachControl(this.attachedElement);
                     delete this.attached[cam];
                     delete this.attached[cam];
                 }
                 }
@@ -62,7 +62,7 @@ module BABYLON {
         public removeByType(inputType: string) {
         public removeByType(inputType: string) {
             for (var cam in this.attached) {
             for (var cam in this.attached) {
                 var input = this.attached[cam];
                 var input = this.attached[cam];
-                if (input.getTypeName() == inputType) {
+                if (input.getTypeName() === inputType) {
                     input.detachControl(this.attachedElement);
                     input.detachControl(this.attachedElement);
                     delete this.attached[cam];
                     delete this.attached[cam];
                 }
                 }

+ 1 - 0
src/Lights/babylon.light.js

@@ -95,6 +95,7 @@ var BABYLON;
             this.getScene().stopAnimation(this);
             this.getScene().stopAnimation(this);
             // Remove from scene
             // Remove from scene
             this.getScene().removeLight(this);
             this.getScene().removeLight(this);
+            _super.prototype.dispose.call(this);
         };
         };
         Light.prototype.getTypeID = function () {
         Light.prototype.getTypeID = function () {
             return 0;
             return 0;

+ 2 - 0
src/Lights/babylon.light.ts

@@ -141,6 +141,8 @@
 
 
             // Remove from scene
             // Remove from scene
             this.getScene().removeLight(this);
             this.getScene().removeLight(this);
+
+            super.dispose();
         }
         }
 
 
         public getTypeID(): number {
         public getTypeID(): number {

+ 1 - 0
src/Mesh/babylon.abstractMesh.js

@@ -962,6 +962,7 @@ var BABYLON;
                     }
                     }
                 }
                 }
             }
             }
+            _super.prototype.dispose.call(this);
             this._onAfterWorldMatrixUpdate = [];
             this._onAfterWorldMatrixUpdate = [];
             this._isDisposed = true;
             this._isDisposed = true;
             // Callback
             // Callback

+ 2 - 0
src/Mesh/babylon.abstractMesh.ts

@@ -1128,6 +1128,8 @@
                 }
                 }
             }
             }
 
 
+            super.dispose();
+
             this._onAfterWorldMatrixUpdate = [];
             this._onAfterWorldMatrixUpdate = [];
 
 
             this._isDisposed = true;
             this._isDisposed = true;

+ 48 - 15
src/babylon.node.js

@@ -29,6 +29,31 @@ var BABYLON;
             this._scene = scene;
             this._scene = scene;
             this._initCache();
             this._initCache();
         }
         }
+        Object.defineProperty(Node.prototype, "parent", {
+            get: function () {
+                return this._parentNode;
+            },
+            set: function (parent) {
+                if (this._parentNode === parent) {
+                    return;
+                }
+                if (this._parentNode) {
+                    var index = this._parentNode._children.indexOf(this);
+                    if (index !== -1) {
+                        this._parentNode._children.splice(index, 1);
+                    }
+                }
+                this._parentNode = parent;
+                if (this._parentNode) {
+                    if (!this._parentNode._children) {
+                        this._parentNode._children = new Array();
+                    }
+                    this._parentNode._children.push(this);
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
         Node.prototype.getScene = function () {
         Node.prototype.getScene = function () {
             return this._scene;
             return this._scene;
         };
         };
@@ -132,32 +157,35 @@ var BABYLON;
             return false;
             return false;
         };
         };
         /**
         /**
-         * Evaluate a list of nodes and determine if they should be considered as descendants considering the given criterias
-         * @param {BABYLON.Node[]} list the input array of nodes to evaluate
+         * Evaluate the list of children and determine if they should be considered as descendants considering the given criterias
          * @param {BABYLON.Node[]} results the result array containing the nodes matching the given criterias
          * @param {BABYLON.Node[]} results the result array containing the nodes matching the given criterias
-         * @param {boolean} directDecendantsOnly 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.
+         * @param {boolean} directDescendantsOnly 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.
          * @param predicate: an optional predicate that will be called on every evaluated children, the predicate must return true for a given child to be part of the result, otherwise it will be ignored.
          * @param predicate: an optional predicate that will be called on every evaluated children, the predicate must return true for a given child to be part of the result, otherwise it will be ignored.
          */
          */
-        Node.prototype._getDescendants = function (list, results, directDecendantsOnly, predicate) {
-            if (directDecendantsOnly === void 0) { directDecendantsOnly = false; }
-            for (var index = 0; index < list.length; index++) {
-                var item = list[index];
-                if (((directDecendantsOnly && item.parent === this) || (!directDecendantsOnly && item.isDescendantOf(this))) && (!predicate || predicate(item))) {
+        Node.prototype._getDescendants = function (results, directDescendantsOnly, predicate) {
+            if (directDescendantsOnly === void 0) { directDescendantsOnly = false; }
+            if (!this._children) {
+                return;
+            }
+            for (var index = 0; index < this._children.length; index++) {
+                var item = this._children[index];
+                if (!predicate || predicate(item)) {
                     results.push(item);
                     results.push(item);
                 }
                 }
+                if (!directDescendantsOnly) {
+                    item._getDescendants(results, false, predicate);
+                }
             }
             }
         };
         };
         /**
         /**
-         * Will return all nodes that have this node as parent.
-         * @param {boolean} directDecendantsOnly 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.
+         * Will return all nodes that have this node as ascendant.
+         * @param {boolean} directDescendantsOnly 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.
          * @param predicate: an optional predicate that will be called on every evaluated children, the predicate must return true for a given child to be part of the result, otherwise it will be ignored.
          * @param predicate: an optional predicate that will be called on every evaluated children, the predicate must return true for a given child to be part of the result, otherwise it will be ignored.
          * @return {BABYLON.Node[]} all children nodes of all types.
          * @return {BABYLON.Node[]} all children nodes of all types.
          */
          */
-        Node.prototype.getDescendants = function (directDecendantsOnly, predicate) {
+        Node.prototype.getDescendants = function (directDescendantsOnly, predicate) {
             var results = [];
             var results = [];
-            this._getDescendants(this._scene.meshes, results, directDecendantsOnly, predicate);
-            this._getDescendants(this._scene.lights, results, directDecendantsOnly, predicate);
-            this._getDescendants(this._scene.cameras, results, directDecendantsOnly, predicate);
+            this._getDescendants(results, directDescendantsOnly, predicate);
             return results;
             return results;
         };
         };
         /**
         /**
@@ -173,7 +201,9 @@ var BABYLON;
          */
          */
         Node.prototype.getChildMeshes = function (directDecendantsOnly, predicate) {
         Node.prototype.getChildMeshes = function (directDecendantsOnly, predicate) {
             var results = [];
             var results = [];
-            this._getDescendants(this._scene.meshes, results, directDecendantsOnly, predicate);
+            this._getDescendants(results, directDecendantsOnly, function (node) {
+                return ((!predicate || predicate(node)) && (node instanceof BABYLON.AbstractMesh));
+            });
             return results;
             return results;
         };
         };
         Node.prototype._setReady = function (state) {
         Node.prototype._setReady = function (state) {
@@ -239,6 +269,9 @@ var BABYLON;
             }
             }
             return serializationRanges;
             return serializationRanges;
         };
         };
+        Node.prototype.dispose = function () {
+            this.parent = null;
+        };
         Node.ParseAnimationRanges = function (node, parsedNode, scene) {
         Node.ParseAnimationRanges = function (node, parsedNode, scene) {
             if (parsedNode.ranges) {
             if (parsedNode.ranges) {
                 for (var index = 0; index < parsedNode.ranges.length; index++) {
                 for (var index = 0; index < parsedNode.ranges.length; index++) {

+ 56 - 16
src/babylon.node.ts

@@ -4,8 +4,6 @@
      * Node is the basic class for all scene objects (Mesh, Light Camera).
      * Node is the basic class for all scene objects (Mesh, Light Camera).
      */
      */
     export class Node {
     export class Node {
-        public parent: Node;
-
         @serialize()
         @serialize()
         public name: string;
         public name: string;
 
 
@@ -34,6 +32,35 @@
         private _scene: Scene;
         private _scene: Scene;
         public _cache;
         public _cache;
 
 
+        private _parentNode: Node;
+        private _children: Node[];
+
+        public set parent(parent: Node) {
+            if (this._parentNode === parent) {
+                return;
+            }
+
+            if (this._parentNode) {
+                var index = this._parentNode._children.indexOf(this);
+                if (index !== -1) {
+                    this._parentNode._children.splice(index, 1);
+                }
+            }
+
+            this._parentNode = parent;
+
+            if (this._parentNode) {
+                if (!this._parentNode._children) {
+                    this._parentNode._children = new Array<Node>();
+                }
+                this._parentNode._children.push(this);
+            }
+        }
+
+        public get parent(): Node {
+            return this._parentNode;
+        }
+
         /**
         /**
          * @constructor
          * @constructor
          * @param {string} name - the name and id to be given to this node
          * @param {string} name - the name and id to be given to this node
@@ -177,32 +204,39 @@
         }
         }
 
 
         /**
         /**
-         * Evaluate a list of nodes and determine if they should be considered as descendants considering the given criterias
-         * @param {BABYLON.Node[]} list the input array of nodes to evaluate
+         * Evaluate the list of children and determine if they should be considered as descendants considering the given criterias
          * @param {BABYLON.Node[]} results the result array containing the nodes matching the given criterias
          * @param {BABYLON.Node[]} results the result array containing the nodes matching the given criterias
-         * @param {boolean} directDecendantsOnly 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.
+         * @param {boolean} directDescendantsOnly 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.
          * @param predicate: an optional predicate that will be called on every evaluated children, the predicate must return true for a given child to be part of the result, otherwise it will be ignored.
          * @param predicate: an optional predicate that will be called on every evaluated children, the predicate must return true for a given child to be part of the result, otherwise it will be ignored.
          */
          */
-        public _getDescendants(list: Node[], results: Node[], directDecendantsOnly: boolean = false, predicate?: (node: Node) => boolean): void {
-            for (var index = 0; index < list.length; index++) {
-                var item = list[index];
-                if (((directDecendantsOnly && item.parent === this) || (!directDecendantsOnly && item.isDescendantOf(this))) && (!predicate || predicate(item))) {
+        public _getDescendants(results: Node[], directDescendantsOnly: boolean = false, predicate?: (node: Node) => boolean): void {
+            if (!this._children) {
+                return;
+            }
+
+            for (var index = 0; index < this._children.length; index++) {
+                var item = this._children[index];
+
+                if (!predicate || predicate(item)) {
                     results.push(item);
                     results.push(item);
                 }
                 }
+
+                if (!directDescendantsOnly) {
+                    item._getDescendants(results, false, predicate);
+                }
             }
             }
         }
         }
 
 
         /**
         /**
-         * Will return all nodes that have this node as parent.
-         * @param {boolean} directDecendantsOnly 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.
+         * Will return all nodes that have this node as ascendant.
+         * @param {boolean} directDescendantsOnly 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.
          * @param predicate: an optional predicate that will be called on every evaluated children, the predicate must return true for a given child to be part of the result, otherwise it will be ignored.
          * @param predicate: an optional predicate that will be called on every evaluated children, the predicate must return true for a given child to be part of the result, otherwise it will be ignored.
          * @return {BABYLON.Node[]} all children nodes of all types.
          * @return {BABYLON.Node[]} all children nodes of all types.
          */
          */
-        public getDescendants(directDecendantsOnly?: boolean, predicate?: (node: Node) => boolean): Node[] {
+        public getDescendants(directDescendantsOnly?: boolean, predicate?: (node: Node) => boolean): Node[] {
             var results = [];
             var results = [];
-            this._getDescendants(this._scene.meshes, results, directDecendantsOnly, predicate);
-            this._getDescendants(this._scene.lights, results, directDecendantsOnly, predicate);
-            this._getDescendants(this._scene.cameras, results, directDecendantsOnly, predicate);
+
+            this._getDescendants(results, directDescendantsOnly, predicate);
 
 
             return results;
             return results;
         }
         }
@@ -221,7 +255,9 @@
          */
          */
         public getChildMeshes(directDecendantsOnly?: boolean, predicate?: (node: Node) => boolean): AbstractMesh[] {
         public getChildMeshes(directDecendantsOnly?: boolean, predicate?: (node: Node) => boolean): AbstractMesh[] {
             var results: Array<AbstractMesh> = [];
             var results: Array<AbstractMesh> = [];
-            this._getDescendants(this._scene.meshes, results, directDecendantsOnly, predicate);
+            this._getDescendants(results, directDecendantsOnly, (node: Node) => {
+                return ((!predicate || predicate(node)) && (node instanceof AbstractMesh));
+            });
             return results;
             return results;
         }
         }
 
 
@@ -300,6 +336,10 @@
             return serializationRanges;
             return serializationRanges;
         }
         }
 
 
+        public dispose(): void {
+            this.parent = null;
+        }
+
         public static ParseAnimationRanges(node: Node, parsedNode: any, scene: Scene): void {
         public static ParseAnimationRanges(node: Node, parsedNode: any, scene: Scene): void {
             if (parsedNode.ranges) {
             if (parsedNode.ranges) {
                 for (var index = 0; index < parsedNode.ranges.length; index++) {
                 for (var index = 0; index < parsedNode.ranges.length; index++) {