Przeglądaj źródła

Fix node dispose bug

Gary Hsu 7 lat temu
rodzic
commit
f5a7b7d265

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

@@ -589,7 +589,12 @@
             return new Ray(origin, direction, length);
         }
 
-        public dispose(): void {
+        /**
+         * Releases resources associated with this node.
+         * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
+         * @param disposeMaterialAndTextures Set to true to also dispose referenced materials and textures (false by default)
+         */
+        public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures = false): void {
             // Observables
             this.onViewMatrixChangedObservable.clear();
             this.onProjectionMatrixChangedObservable.clear();
@@ -639,7 +644,7 @@
             // Active Meshes
             this._activeMeshes.dispose();
 
-            super.dispose();
+            super.dispose(doNotRecurse, disposeMaterialAndTextures);
         }
 
         // ---- Camera rigs section ----

+ 5 - 4
src/Helpers/babylon.videoDome.ts

@@ -92,15 +92,16 @@ module BABYLON {
         }
 
         /**
-         * Releases all associated resources
+         * Releases resources associated with this node.
+         * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
+         * @param disposeMaterialAndTextures Set to true to also dispose referenced materials and textures (false by default)
          */
-        public dispose(): void {
-            super.dispose();
-
+        public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures = false): void {
             this._videoTexture.dispose();
             this._mesh.dispose();
             this._material.dispose();
 
+            super.dispose(doNotRecurse, disposeMaterialAndTextures);
         }
     }
 }

+ 5 - 3
src/Lights/babylon.light.ts

@@ -467,9 +467,11 @@ module BABYLON {
         }
 
         /**
-         * Disposes the light.  
+         * Releases resources associated with this node.
+         * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
+         * @param disposeMaterialAndTextures Set to true to also dispose referenced materials and textures (false by default)
          */
-        public dispose(): void {
+        public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures = false): void {
             if (this._shadowGenerator) {
                 this._shadowGenerator.dispose();
                 this._shadowGenerator = null;
@@ -487,7 +489,7 @@ module BABYLON {
 
             // Remove from scene
             this.getScene().removeLight(this);
-            super.dispose();
+            super.dispose(doNotRecurse, disposeMaterialAndTextures);
         }
 
         /**

+ 5 - 5
src/Mesh/babylon.abstractMesh.ts

@@ -1326,11 +1326,11 @@
         }
 
         /**
-         * Disposes the AbstractMesh.  
-         * By default, all the mesh children are also disposed unless the parameter `doNotRecurse` is set to `true`.  
-         * Returns nothing.  
+         * Releases resources associated with this abstract mesh.
+         * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
+         * @param disposeMaterialAndTextures Set to true to also dispose referenced materials and textures (false by default)
          */
-        public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures: boolean = false): void {
+        public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures = false): void {
             var index: number;
 
             // Action manager
@@ -1448,7 +1448,7 @@
             this.onCollideObservable.clear();
             this.onCollisionPositionChangeObservable.clear();
 
-            super.dispose(doNotRecurse);
+            super.dispose(doNotRecurse, disposeMaterialAndTextures);
         }
 
         /**

+ 2 - 2
src/Mesh/babylon.instancedMesh.ts

@@ -282,13 +282,13 @@
          * Disposes the InstancedMesh.  
          * Returns nothing.  
          */
-        public dispose(doNotRecurse?: boolean): void {
+        public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures = false): void {
 
             // Remove from mesh
             var index = this._sourceMesh.instances.indexOf(this);
             this._sourceMesh.instances.splice(index, 1);
 
-            super.dispose(doNotRecurse);
+            super.dispose(doNotRecurse, disposeMaterialAndTextures);
         }
     }
 } 

+ 4 - 4
src/Mesh/babylon.mesh.ts

@@ -1714,11 +1714,11 @@
         }
 
         /**
-         * Disposes the Mesh.  
-         * By default, all the mesh children are also disposed unless the parameter `doNotRecurse` is set to `true`.  
-         * Returns nothing.  
+         * Releases resources associated with this mesh.
+         * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
+         * @param disposeMaterialAndTextures Set to true to also dispose referenced materials and textures (false by default)
          */
-        public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures: boolean = false): void {
+        public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures = false): void {
             this.morphTargetManager = null;
 
             if (this._geometry) {

+ 13 - 20
src/Mesh/babylon.transformNode.ts

@@ -58,6 +58,14 @@ module BABYLON {
         }
 
         /**
+         * Gets a string idenfifying the name of the class
+         * @returns "TransformNode" string
+         */
+        public getClassName(): string {
+            return "TransformNode";
+        }
+
+        /**
           * Rotation property : a Vector3 depicting the rotation value in radians around each local axis X, Y, Z. 
           * If rotation quaternion is set, this Vector3 will (almost always) be the Zero vector!
           * Default : (0.0, 0.0, 0.0)
@@ -965,35 +973,20 @@ module BABYLON {
         }
 
         /**
-         * Disposes the TransformNode.  
-         * By default, all the children are also disposed unless the parameter `doNotRecurse` is set to `true`.  
-         * Returns nothing.  
+         * Releases resources associated with this transform node.
+         * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
+         * @param disposeMaterialAndTextures Set to true to also dispose referenced materials and textures (false by default)
          */
-        public dispose(doNotRecurse?: boolean): void {
+        public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures = false): void {
             // Animations
             this.getScene().stopAnimation(this);
 
             // Remove from scene
             this.getScene().removeTransformNode(this);
 
-            if (!doNotRecurse) {
-                // Children
-                var objects = this.getDescendants(true);
-                for (var index = 0; index < objects.length; index++) {
-                    objects[index].dispose();
-                }
-            } else {
-                var childMeshes = this.getChildMeshes(true);
-                for (index = 0; index < childMeshes.length; index++) {
-                    var child = childMeshes[index];
-                    child.parent = null;
-                    child.computeWorldMatrix(true);
-                }
-            }
-
             this.onAfterWorldMatrixUpdateObservable.clear();
 
-            super.dispose();
+            super.dispose(doNotRecurse, disposeMaterialAndTextures);
         }
 
     }

+ 19 - 4
src/babylon.node.ts

@@ -589,9 +589,24 @@
         }
 
         /**
-         * Releases all associated resources
-         */
-        public dispose(): void {
+         * Releases resources associated with this node.
+         * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
+         * @param disposeMaterialAndTextures Set to true to also dispose referenced materials and textures (false by default)
+         */
+        public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures = false): void {
+            if (!doNotRecurse) {
+                const nodes = this.getDescendants(true);
+                for (const node of nodes) {
+                    node.dispose(doNotRecurse, disposeMaterialAndTextures);
+                }
+            } else {
+                const transformNodes = this.getChildTransformNodes(true);
+                for (const transformNode of transformNodes) {
+                    transformNode.parent = null;
+                    transformNode.computeWorldMatrix(true);
+                }
+            }
+
             this.parent = null;
 
             // Callback
@@ -604,7 +619,7 @@
             }
 
             this._behaviors = [];
-            this._isDisposed = true;            
+            this._isDisposed = true;
         }
 
         /**

+ 0 - 15
tests/unit/babylon/src/Tools/babylon.promise.tests.ts

@@ -2,8 +2,6 @@
  * Describes the test suite.
  */
 describe('Babylon.Promise', function () {
-    var subject: BABYLON.Engine;
-
     this.timeout(10000);
 
     /**
@@ -19,19 +17,6 @@ describe('Babylon.Promise', function () {
             });
     });
 
-    /**
-     * Create a new engine subject before each test.
-     */
-    beforeEach(function () {
-        subject = new BABYLON.NullEngine({
-            renderHeight: 256,
-            renderWidth: 256,
-            textureSize: 256,
-            deterministicLockstep: false,
-            lockstepMaxSteps: 1
-        });
-    });
-
     describe('#Composition', () => {
         it('should chain promises correctly #1', (done) => {
             var tempString = "";

+ 87 - 0
tests/unit/babylon/src/babylon.node.tests.ts

@@ -0,0 +1,87 @@
+/**
+ * Describes the test suite.
+ */
+describe('Babylon Node', () => {
+    let subject: BABYLON.Engine;
+
+    /**
+     * Loads the dependencies.
+     */
+    before(function (done) {
+        this.timeout(180000);
+        (BABYLONDEVTOOLS).Loader
+            .useDist()
+            .load(function () {
+                // Force apply promise polyfill for consistent behavior between PhantomJS, IE11, and other browsers.
+                BABYLON.PromisePolyfill.Apply(true);
+                done();
+            });
+    });
+
+    /**
+     * Create a new engine subject before each test.
+     */
+    beforeEach(function () {
+        subject = new BABYLON.NullEngine({
+            renderHeight: 256,
+            renderWidth: 256,
+            textureSize: 256,
+            deterministicLockstep: false,
+            lockstepMaxSteps: 1
+        });
+    });
+
+    describe('#Node', () => {
+        it('dispose', () => {
+            const scene = new BABYLON.Scene(subject);
+            const node = new BABYLON.Node("node", scene);
+            const transformNode = new BABYLON.TransformNode("transformNode", scene);
+            transformNode.parent = node;
+            const mesh = new BABYLON.Mesh("node2", scene);
+            mesh.parent = node;
+            mesh.material = new BABYLON.PBRMaterial("material", scene)
+
+            node.dispose();
+
+            expect(node.isDisposed(), "node.isDisposed").to.be.true;
+            expect(transformNode.isDisposed(), "transformNode.isDisposed").to.be.true;
+            expect(mesh.isDisposed(), "mesh.isDisposed").to.be.true;
+
+            expect(scene.materials, "scene.materials").to.have.lengthOf(1);
+        });
+
+        it('dispose with doNotRecurse', () => {
+            const scene = new BABYLON.Scene(subject);
+            const node = new BABYLON.Node("node", scene);
+            const transformNode = new BABYLON.TransformNode("transformNode", scene);
+            transformNode.parent = node;
+            const mesh = new BABYLON.Mesh("node2", scene);
+            mesh.parent = node;
+            mesh.material = new BABYLON.PBRMaterial("material", scene)
+
+            node.dispose(true);
+
+            expect(node.isDisposed(), "node.isDisposed").to.be.true;
+            expect(transformNode.isDisposed(), "transformNode.isDisposed").to.be.false;
+            expect(mesh.isDisposed(), "mesh.isDisposed").to.be.false;
+
+            expect(scene.materials, "scene.materials").to.have.lengthOf(1);
+        });
+
+        it('dispose with disposeMaterialAndTextures', () => {
+            const scene = new BABYLON.Scene(subject);
+            const transformNode = new BABYLON.TransformNode("transformNode", scene);
+            const mesh = new BABYLON.Mesh("mesh", scene);
+            mesh.parent = transformNode;
+            mesh.material = new BABYLON.PBRMaterial("material", scene)
+
+            transformNode.dispose(false, true);
+
+            expect(transformNode.isDisposed(), "node.isDisposed").to.be.true;
+            expect(mesh.isDisposed(), "mesh.isDisposed").to.be.true;
+
+            expect(scene.meshes, "scene.meshes").to.be.empty;
+            expect(scene.materials, "scene.materials").to.be.empty;
+        });
+    });
+});

+ 1 - 0
tests/unit/karma.conf.js

@@ -15,6 +15,7 @@ module.exports = function (config) {
             './Tools/DevLoader/BabylonLoader.js',
             './tests/unit/babylon/babylon.example.tests.js',
             './tests/unit/babylon/serializers/babylon.glTFSerializer.tests.js',
+            './tests/unit/babylon/src/babylon.node.tests.js',
             './tests/unit/babylon/src/Loading/babylon.sceneLoader.tests.js',
             './tests/unit/babylon/src/Material/babylon.material.tests.js',
             './tests/unit/babylon/src/Mesh/babylon.mesh.vertexData.tests.js',