Browse Source

Merge branch 'master' into arrayBuilder

Julien Barrois 6 years ago
parent
commit
c34ca2d97f

File diff suppressed because it is too large
+ 12215 - 12185
Playground/babylon.d.txt


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


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


+ 137 - 49
dist/preview release/babylon.max.js

@@ -296,6 +296,9 @@ var BABYLON;
          * @returns if the effect is compiled and prepared.
          */
         Effect.prototype.isReady = function () {
+            if (!this._isReady && this._program && this._program.isParallelCompiled) {
+                return this._engine._isProgramCompiled(this._program);
+            }
             return this._isReady;
         };
         /**
@@ -647,50 +650,53 @@ var BABYLON;
          * @hidden
          */
         Effect.prototype._prepareEffect = function () {
+            var _this = this;
             var attributesNames = this._attributesNames;
             var defines = this.defines;
             var fallbacks = this._fallbacks;
             this._valueCache = {};
             var previousProgram = this._program;
             try {
-                var engine = this._engine;
+                var engine_1 = this._engine;
                 if (this._vertexSourceCodeOverride && this._fragmentSourceCodeOverride) {
-                    this._program = engine.createRawShaderProgram(this._vertexSourceCodeOverride, this._fragmentSourceCodeOverride, undefined, this._transformFeedbackVaryings);
+                    this._program = engine_1.createRawShaderProgram(this._vertexSourceCodeOverride, this._fragmentSourceCodeOverride, undefined, this._transformFeedbackVaryings);
                 }
                 else {
-                    this._program = engine.createShaderProgram(this._vertexSourceCode, this._fragmentSourceCode, defines, undefined, this._transformFeedbackVaryings);
+                    this._program = engine_1.createShaderProgram(this._vertexSourceCode, this._fragmentSourceCode, defines, undefined, this._transformFeedbackVaryings);
                 }
                 this._program.__SPECTOR_rebuildProgram = this._rebuildProgram.bind(this);
-                if (engine.supportsUniformBuffers) {
-                    for (var name in this._uniformBuffersNames) {
-                        this.bindUniformBlock(name, this._uniformBuffersNames[name]);
+                engine_1._executeWhenProgramIsCompiled(this._program, function () {
+                    if (engine_1.supportsUniformBuffers) {
+                        for (var name in _this._uniformBuffersNames) {
+                            _this.bindUniformBlock(name, _this._uniformBuffersNames[name]);
+                        }
                     }
-                }
-                this._uniforms = engine.getUniforms(this._program, this._uniformsNames);
-                this._attributes = engine.getAttributes(this._program, attributesNames);
-                var index;
-                for (index = 0; index < this._samplers.length; index++) {
-                    var sampler = this.getUniform(this._samplers[index]);
-                    if (sampler == null) {
-                        this._samplers.splice(index, 1);
-                        index--;
+                    _this._uniforms = engine_1.getUniforms(_this._program, _this._uniformsNames);
+                    _this._attributes = engine_1.getAttributes(_this._program, attributesNames);
+                    var index;
+                    for (index = 0; index < _this._samplers.length; index++) {
+                        var sampler = _this.getUniform(_this._samplers[index]);
+                        if (sampler == null) {
+                            _this._samplers.splice(index, 1);
+                            index--;
+                        }
                     }
-                }
-                engine.bindSamplers(this);
-                this._compilationError = "";
-                this._isReady = true;
-                if (this.onCompiled) {
-                    this.onCompiled(this);
-                }
-                this.onCompileObservable.notifyObservers(this);
-                this.onCompileObservable.clear();
-                // Unbind mesh reference in fallbacks
-                if (this._fallbacks) {
-                    this._fallbacks.unBindMesh();
-                }
-                if (previousProgram) {
-                    this.getEngine()._deleteProgram(previousProgram);
-                }
+                    engine_1.bindSamplers(_this);
+                    _this._compilationError = "";
+                    _this._isReady = true;
+                    if (_this.onCompiled) {
+                        _this.onCompiled(_this);
+                    }
+                    _this.onCompileObservable.notifyObservers(_this);
+                    _this.onCompileObservable.clear();
+                    // Unbind mesh reference in fallbacks
+                    if (_this._fallbacks) {
+                        _this._fallbacks.unBindMesh();
+                    }
+                    if (previousProgram) {
+                        _this.getEngine()._deleteProgram(previousProgram);
+                    }
+                });
             }
             catch (e) {
                 this._compilationError = e.message;
@@ -2976,7 +2982,7 @@ var BABYLON;
          * @returns a new Quaternion object, computed from the Vector3 coordinates
          */
         Vector3.prototype.toQuaternion = function () {
-            return BABYLON.Quaternion.RotationYawPitchRoll(this.x, this.y, this.z);
+            return BABYLON.Quaternion.RotationYawPitchRoll(this.y, this.x, this.z);
         };
         /**
          * Adds the given vector to the current Vector3
@@ -12684,7 +12690,7 @@ var BABYLON;
              * Returns the current version of the framework
              */
             get: function () {
-                return "3.3.0";
+                return "4.0.0-alpha.0";
             },
             enumerable: true,
             configurable: true
@@ -12933,6 +12939,12 @@ var BABYLON;
                     this._caps.drawBuffersExtension = false;
                 }
             }
+            // Shader compiler threads
+            this._caps.parallelShaderCompile = this._gl.getExtension('KHR_parallel_shader_compile');
+            if (this._caps.parallelShaderCompile) {
+                var threads = this._gl.getParameter(this._caps.parallelShaderCompile.MAX_SHADER_COMPILER_THREADS_KHR);
+                this._caps.parallelShaderCompile.maxShaderCompilerThreadsKHR(threads);
+            }
             // Depth Texture
             if (this._webGLVersion > 1) {
                 this._caps.depthTextureExtension = true;
@@ -14667,6 +14679,21 @@ var BABYLON;
             if (this.webGLVersion > 1 && transformFeedbackVaryings) {
                 this.bindTransformFeedback(null);
             }
+            shaderProgram.context = context;
+            shaderProgram.vertexShader = vertexShader;
+            shaderProgram.fragmentShader = fragmentShader;
+            if (!this._caps.parallelShaderCompile) {
+                this._finalizeProgram(shaderProgram);
+            }
+            else {
+                shaderProgram.isParallelCompiled = true;
+            }
+            return shaderProgram;
+        };
+        Engine.prototype._finalizeProgram = function (shaderProgram) {
+            var context = shaderProgram.context;
+            var vertexShader = shaderProgram.vertexShader;
+            var fragmentShader = shaderProgram.fragmentShader;
             var linked = context.getProgramParameter(shaderProgram, context.LINK_STATUS);
             if (!linked) {
                 var error = context.getProgramInfoLog(shaderProgram);
@@ -14686,7 +14713,32 @@ var BABYLON;
             }
             context.deleteShader(vertexShader);
             context.deleteShader(fragmentShader);
-            return shaderProgram;
+            shaderProgram.context = undefined;
+            shaderProgram.vertexShader = undefined;
+            shaderProgram.fragmentShader = undefined;
+            if (shaderProgram.onCompiled) {
+                shaderProgram.onCompiled();
+                shaderProgram.onCompiled = undefined;
+            }
+        };
+        /** @hidden */
+        Engine.prototype._isProgramCompiled = function (shaderProgram) {
+            if (!shaderProgram.isParallelCompiled) {
+                return true;
+            }
+            if (this._gl.getProgramParameter(shaderProgram, this._caps.parallelShaderCompile.COMPLETION_STATUS_KHR)) {
+                this._finalizeProgram(shaderProgram);
+                return true;
+            }
+            return false;
+        };
+        /** @hidden */
+        Engine.prototype._executeWhenProgramIsCompiled = function (shaderProgram, action) {
+            if (!shaderProgram.isParallelCompiled) {
+                action();
+                return;
+            }
+            shaderProgram.onCompiled = action;
         };
         /**
          * Gets the list of webGL uniform locations associated with a specific program based on a list of uniform names
@@ -25283,7 +25335,7 @@ var BABYLON;
          * Creates a new Scene
          * @param engine defines the engine to use to render this scene
          */
-        function Scene(engine) {
+        function Scene(engine, options) {
             var _this = _super.call(this) || this;
             // Members
             /**
@@ -25797,6 +25849,10 @@ var BABYLON;
              * Defines the actions happening when a pointer up event happens.
              */
             _this._pointerUpStage = BABYLON.Stage.Create();
+            /**
+             * an optional map from Geometry Id to Geometry index in the 'geometries' array
+             */
+            _this.geometriesById = null;
             _this._defaultMeshCandidates = {
                 data: [],
                 length: 0
@@ -25835,6 +25891,9 @@ var BABYLON;
                 _this._imageProcessingConfiguration = new BABYLON.ImageProcessingConfiguration();
             }
             _this.setDefaultCandidateProviders();
+            if (options && options.useGeometryIdsMap === true) {
+                _this.geometriesById = {};
+            }
             return _this;
         }
         Object.defineProperty(Scene.prototype, "environmentTexture", {
@@ -28090,6 +28149,9 @@ var BABYLON;
          * @param newGeometry The geometry to add
          */
         Scene.prototype.addGeometry = function (newGeometry) {
+            if (this.geometriesById) {
+                this.geometriesById[newGeometry.id] = this.geometries.length;
+            }
             this.geometries.push(newGeometry);
         };
         /**
@@ -28320,9 +28382,17 @@ var BABYLON;
          * @return the geometry or null if none found.
          */
         Scene.prototype.getGeometryByID = function (id) {
-            for (var index = 0; index < this.geometries.length; index++) {
-                if (this.geometries[index].id === id) {
-                    return this.geometries[index];
+            if (this.geometriesById) {
+                var index_1 = this.geometriesById[id];
+                if (index_1 !== undefined) {
+                    return this.geometries[index_1];
+                }
+            }
+            else {
+                for (var index = 0; index < this.geometries.length; index++) {
+                    if (this.geometries[index].id === id) {
+                        return this.geometries[index];
+                    }
                 }
             }
             return null;
@@ -28337,7 +28407,7 @@ var BABYLON;
             if (!force && this.getGeometryByID(geometry.id)) {
                 return false;
             }
-            this.geometries.push(geometry);
+            this.addGeometry(geometry);
             //notify the collision coordinator
             if (this.collisionCoordinator) {
                 this.collisionCoordinator.onGeometryAdded(geometry);
@@ -28351,17 +28421,34 @@ var BABYLON;
          * @return a boolean defining if the geometry was removed or not
          */
         Scene.prototype.removeGeometry = function (geometry) {
-            var index = this.geometries.indexOf(geometry);
-            if (index > -1) {
-                this.geometries.splice(index, 1);
-                //notify the collision coordinator
-                if (this.collisionCoordinator) {
-                    this.collisionCoordinator.onGeometryDeleted(geometry);
+            var index;
+            if (this.geometriesById) {
+                index = this.geometriesById[geometry.id];
+                if (index === undefined) {
+                    return false;
                 }
-                this.onGeometryRemovedObservable.notifyObservers(geometry);
-                return true;
             }
-            return false;
+            else {
+                index = this.geometries.indexOf(geometry);
+                if (index < 0) {
+                    return false;
+                }
+            }
+            if (index !== this.geometries.length - 1) {
+                var lastGeometry = this.geometries[this.geometries.length - 1];
+                this.geometries[index] = lastGeometry;
+                if (this.geometriesById) {
+                    this.geometriesById[lastGeometry.id] = index;
+                    this.geometriesById[geometry.id] = undefined;
+                }
+            }
+            this.geometries.pop();
+            //notify the collision coordinator
+            if (this.collisionCoordinator) {
+                this.collisionCoordinator.onGeometryDeleted(geometry);
+            }
+            this.onGeometryRemovedObservable.notifyObservers(geometry);
+            return true;
         };
         /**
          * Gets the list of geometries attached to the scene
@@ -114330,7 +114417,8 @@ var BABYLON;
         NullEngine.prototype.createShaderProgram = function (vertexCode, fragmentCode, defines, context) {
             return {
                 transformFeedback: null,
-                __SPECTOR_rebuildProgram: null
+                __SPECTOR_rebuildProgram: null,
+                isParallelCompiled: false
             };
         };
         NullEngine.prototype.getUniforms = function (shaderProgram, uniformsNames) {

+ 137 - 49
dist/preview release/babylon.no-module.max.js

@@ -263,6 +263,9 @@ var BABYLON;
          * @returns if the effect is compiled and prepared.
          */
         Effect.prototype.isReady = function () {
+            if (!this._isReady && this._program && this._program.isParallelCompiled) {
+                return this._engine._isProgramCompiled(this._program);
+            }
             return this._isReady;
         };
         /**
@@ -614,50 +617,53 @@ var BABYLON;
          * @hidden
          */
         Effect.prototype._prepareEffect = function () {
+            var _this = this;
             var attributesNames = this._attributesNames;
             var defines = this.defines;
             var fallbacks = this._fallbacks;
             this._valueCache = {};
             var previousProgram = this._program;
             try {
-                var engine = this._engine;
+                var engine_1 = this._engine;
                 if (this._vertexSourceCodeOverride && this._fragmentSourceCodeOverride) {
-                    this._program = engine.createRawShaderProgram(this._vertexSourceCodeOverride, this._fragmentSourceCodeOverride, undefined, this._transformFeedbackVaryings);
+                    this._program = engine_1.createRawShaderProgram(this._vertexSourceCodeOverride, this._fragmentSourceCodeOverride, undefined, this._transformFeedbackVaryings);
                 }
                 else {
-                    this._program = engine.createShaderProgram(this._vertexSourceCode, this._fragmentSourceCode, defines, undefined, this._transformFeedbackVaryings);
+                    this._program = engine_1.createShaderProgram(this._vertexSourceCode, this._fragmentSourceCode, defines, undefined, this._transformFeedbackVaryings);
                 }
                 this._program.__SPECTOR_rebuildProgram = this._rebuildProgram.bind(this);
-                if (engine.supportsUniformBuffers) {
-                    for (var name in this._uniformBuffersNames) {
-                        this.bindUniformBlock(name, this._uniformBuffersNames[name]);
+                engine_1._executeWhenProgramIsCompiled(this._program, function () {
+                    if (engine_1.supportsUniformBuffers) {
+                        for (var name in _this._uniformBuffersNames) {
+                            _this.bindUniformBlock(name, _this._uniformBuffersNames[name]);
+                        }
                     }
-                }
-                this._uniforms = engine.getUniforms(this._program, this._uniformsNames);
-                this._attributes = engine.getAttributes(this._program, attributesNames);
-                var index;
-                for (index = 0; index < this._samplers.length; index++) {
-                    var sampler = this.getUniform(this._samplers[index]);
-                    if (sampler == null) {
-                        this._samplers.splice(index, 1);
-                        index--;
+                    _this._uniforms = engine_1.getUniforms(_this._program, _this._uniformsNames);
+                    _this._attributes = engine_1.getAttributes(_this._program, attributesNames);
+                    var index;
+                    for (index = 0; index < _this._samplers.length; index++) {
+                        var sampler = _this.getUniform(_this._samplers[index]);
+                        if (sampler == null) {
+                            _this._samplers.splice(index, 1);
+                            index--;
+                        }
                     }
-                }
-                engine.bindSamplers(this);
-                this._compilationError = "";
-                this._isReady = true;
-                if (this.onCompiled) {
-                    this.onCompiled(this);
-                }
-                this.onCompileObservable.notifyObservers(this);
-                this.onCompileObservable.clear();
-                // Unbind mesh reference in fallbacks
-                if (this._fallbacks) {
-                    this._fallbacks.unBindMesh();
-                }
-                if (previousProgram) {
-                    this.getEngine()._deleteProgram(previousProgram);
-                }
+                    engine_1.bindSamplers(_this);
+                    _this._compilationError = "";
+                    _this._isReady = true;
+                    if (_this.onCompiled) {
+                        _this.onCompiled(_this);
+                    }
+                    _this.onCompileObservable.notifyObservers(_this);
+                    _this.onCompileObservable.clear();
+                    // Unbind mesh reference in fallbacks
+                    if (_this._fallbacks) {
+                        _this._fallbacks.unBindMesh();
+                    }
+                    if (previousProgram) {
+                        _this.getEngine()._deleteProgram(previousProgram);
+                    }
+                });
             }
             catch (e) {
                 this._compilationError = e.message;
@@ -2943,7 +2949,7 @@ var BABYLON;
          * @returns a new Quaternion object, computed from the Vector3 coordinates
          */
         Vector3.prototype.toQuaternion = function () {
-            return BABYLON.Quaternion.RotationYawPitchRoll(this.x, this.y, this.z);
+            return BABYLON.Quaternion.RotationYawPitchRoll(this.y, this.x, this.z);
         };
         /**
          * Adds the given vector to the current Vector3
@@ -12651,7 +12657,7 @@ var BABYLON;
              * Returns the current version of the framework
              */
             get: function () {
-                return "3.3.0";
+                return "4.0.0-alpha.0";
             },
             enumerable: true,
             configurable: true
@@ -12900,6 +12906,12 @@ var BABYLON;
                     this._caps.drawBuffersExtension = false;
                 }
             }
+            // Shader compiler threads
+            this._caps.parallelShaderCompile = this._gl.getExtension('KHR_parallel_shader_compile');
+            if (this._caps.parallelShaderCompile) {
+                var threads = this._gl.getParameter(this._caps.parallelShaderCompile.MAX_SHADER_COMPILER_THREADS_KHR);
+                this._caps.parallelShaderCompile.maxShaderCompilerThreadsKHR(threads);
+            }
             // Depth Texture
             if (this._webGLVersion > 1) {
                 this._caps.depthTextureExtension = true;
@@ -14634,6 +14646,21 @@ var BABYLON;
             if (this.webGLVersion > 1 && transformFeedbackVaryings) {
                 this.bindTransformFeedback(null);
             }
+            shaderProgram.context = context;
+            shaderProgram.vertexShader = vertexShader;
+            shaderProgram.fragmentShader = fragmentShader;
+            if (!this._caps.parallelShaderCompile) {
+                this._finalizeProgram(shaderProgram);
+            }
+            else {
+                shaderProgram.isParallelCompiled = true;
+            }
+            return shaderProgram;
+        };
+        Engine.prototype._finalizeProgram = function (shaderProgram) {
+            var context = shaderProgram.context;
+            var vertexShader = shaderProgram.vertexShader;
+            var fragmentShader = shaderProgram.fragmentShader;
             var linked = context.getProgramParameter(shaderProgram, context.LINK_STATUS);
             if (!linked) {
                 var error = context.getProgramInfoLog(shaderProgram);
@@ -14653,7 +14680,32 @@ var BABYLON;
             }
             context.deleteShader(vertexShader);
             context.deleteShader(fragmentShader);
-            return shaderProgram;
+            shaderProgram.context = undefined;
+            shaderProgram.vertexShader = undefined;
+            shaderProgram.fragmentShader = undefined;
+            if (shaderProgram.onCompiled) {
+                shaderProgram.onCompiled();
+                shaderProgram.onCompiled = undefined;
+            }
+        };
+        /** @hidden */
+        Engine.prototype._isProgramCompiled = function (shaderProgram) {
+            if (!shaderProgram.isParallelCompiled) {
+                return true;
+            }
+            if (this._gl.getProgramParameter(shaderProgram, this._caps.parallelShaderCompile.COMPLETION_STATUS_KHR)) {
+                this._finalizeProgram(shaderProgram);
+                return true;
+            }
+            return false;
+        };
+        /** @hidden */
+        Engine.prototype._executeWhenProgramIsCompiled = function (shaderProgram, action) {
+            if (!shaderProgram.isParallelCompiled) {
+                action();
+                return;
+            }
+            shaderProgram.onCompiled = action;
         };
         /**
          * Gets the list of webGL uniform locations associated with a specific program based on a list of uniform names
@@ -25250,7 +25302,7 @@ var BABYLON;
          * Creates a new Scene
          * @param engine defines the engine to use to render this scene
          */
-        function Scene(engine) {
+        function Scene(engine, options) {
             var _this = _super.call(this) || this;
             // Members
             /**
@@ -25764,6 +25816,10 @@ var BABYLON;
              * Defines the actions happening when a pointer up event happens.
              */
             _this._pointerUpStage = BABYLON.Stage.Create();
+            /**
+             * an optional map from Geometry Id to Geometry index in the 'geometries' array
+             */
+            _this.geometriesById = null;
             _this._defaultMeshCandidates = {
                 data: [],
                 length: 0
@@ -25802,6 +25858,9 @@ var BABYLON;
                 _this._imageProcessingConfiguration = new BABYLON.ImageProcessingConfiguration();
             }
             _this.setDefaultCandidateProviders();
+            if (options && options.useGeometryIdsMap === true) {
+                _this.geometriesById = {};
+            }
             return _this;
         }
         Object.defineProperty(Scene.prototype, "environmentTexture", {
@@ -28057,6 +28116,9 @@ var BABYLON;
          * @param newGeometry The geometry to add
          */
         Scene.prototype.addGeometry = function (newGeometry) {
+            if (this.geometriesById) {
+                this.geometriesById[newGeometry.id] = this.geometries.length;
+            }
             this.geometries.push(newGeometry);
         };
         /**
@@ -28287,9 +28349,17 @@ var BABYLON;
          * @return the geometry or null if none found.
          */
         Scene.prototype.getGeometryByID = function (id) {
-            for (var index = 0; index < this.geometries.length; index++) {
-                if (this.geometries[index].id === id) {
-                    return this.geometries[index];
+            if (this.geometriesById) {
+                var index_1 = this.geometriesById[id];
+                if (index_1 !== undefined) {
+                    return this.geometries[index_1];
+                }
+            }
+            else {
+                for (var index = 0; index < this.geometries.length; index++) {
+                    if (this.geometries[index].id === id) {
+                        return this.geometries[index];
+                    }
                 }
             }
             return null;
@@ -28304,7 +28374,7 @@ var BABYLON;
             if (!force && this.getGeometryByID(geometry.id)) {
                 return false;
             }
-            this.geometries.push(geometry);
+            this.addGeometry(geometry);
             //notify the collision coordinator
             if (this.collisionCoordinator) {
                 this.collisionCoordinator.onGeometryAdded(geometry);
@@ -28318,17 +28388,34 @@ var BABYLON;
          * @return a boolean defining if the geometry was removed or not
          */
         Scene.prototype.removeGeometry = function (geometry) {
-            var index = this.geometries.indexOf(geometry);
-            if (index > -1) {
-                this.geometries.splice(index, 1);
-                //notify the collision coordinator
-                if (this.collisionCoordinator) {
-                    this.collisionCoordinator.onGeometryDeleted(geometry);
+            var index;
+            if (this.geometriesById) {
+                index = this.geometriesById[geometry.id];
+                if (index === undefined) {
+                    return false;
                 }
-                this.onGeometryRemovedObservable.notifyObservers(geometry);
-                return true;
             }
-            return false;
+            else {
+                index = this.geometries.indexOf(geometry);
+                if (index < 0) {
+                    return false;
+                }
+            }
+            if (index !== this.geometries.length - 1) {
+                var lastGeometry = this.geometries[this.geometries.length - 1];
+                this.geometries[index] = lastGeometry;
+                if (this.geometriesById) {
+                    this.geometriesById[lastGeometry.id] = index;
+                    this.geometriesById[geometry.id] = undefined;
+                }
+            }
+            this.geometries.pop();
+            //notify the collision coordinator
+            if (this.collisionCoordinator) {
+                this.collisionCoordinator.onGeometryDeleted(geometry);
+            }
+            this.onGeometryRemovedObservable.notifyObservers(geometry);
+            return true;
         };
         /**
          * Gets the list of geometries attached to the scene
@@ -114297,7 +114384,8 @@ var BABYLON;
         NullEngine.prototype.createShaderProgram = function (vertexCode, fragmentCode, defines, context) {
             return {
                 transformFeedback: null,
-                __SPECTOR_rebuildProgram: null
+                __SPECTOR_rebuildProgram: null,
+                isParallelCompiled: false
             };
         };
         NullEngine.prototype.getUniforms = function (shaderProgram, uniformsNames) {

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


+ 137 - 49
dist/preview release/es6.js

@@ -263,6 +263,9 @@ var BABYLON;
          * @returns if the effect is compiled and prepared.
          */
         Effect.prototype.isReady = function () {
+            if (!this._isReady && this._program && this._program.isParallelCompiled) {
+                return this._engine._isProgramCompiled(this._program);
+            }
             return this._isReady;
         };
         /**
@@ -614,50 +617,53 @@ var BABYLON;
          * @hidden
          */
         Effect.prototype._prepareEffect = function () {
+            var _this = this;
             var attributesNames = this._attributesNames;
             var defines = this.defines;
             var fallbacks = this._fallbacks;
             this._valueCache = {};
             var previousProgram = this._program;
             try {
-                var engine = this._engine;
+                var engine_1 = this._engine;
                 if (this._vertexSourceCodeOverride && this._fragmentSourceCodeOverride) {
-                    this._program = engine.createRawShaderProgram(this._vertexSourceCodeOverride, this._fragmentSourceCodeOverride, undefined, this._transformFeedbackVaryings);
+                    this._program = engine_1.createRawShaderProgram(this._vertexSourceCodeOverride, this._fragmentSourceCodeOverride, undefined, this._transformFeedbackVaryings);
                 }
                 else {
-                    this._program = engine.createShaderProgram(this._vertexSourceCode, this._fragmentSourceCode, defines, undefined, this._transformFeedbackVaryings);
+                    this._program = engine_1.createShaderProgram(this._vertexSourceCode, this._fragmentSourceCode, defines, undefined, this._transformFeedbackVaryings);
                 }
                 this._program.__SPECTOR_rebuildProgram = this._rebuildProgram.bind(this);
-                if (engine.supportsUniformBuffers) {
-                    for (var name in this._uniformBuffersNames) {
-                        this.bindUniformBlock(name, this._uniformBuffersNames[name]);
+                engine_1._executeWhenProgramIsCompiled(this._program, function () {
+                    if (engine_1.supportsUniformBuffers) {
+                        for (var name in _this._uniformBuffersNames) {
+                            _this.bindUniformBlock(name, _this._uniformBuffersNames[name]);
+                        }
                     }
-                }
-                this._uniforms = engine.getUniforms(this._program, this._uniformsNames);
-                this._attributes = engine.getAttributes(this._program, attributesNames);
-                var index;
-                for (index = 0; index < this._samplers.length; index++) {
-                    var sampler = this.getUniform(this._samplers[index]);
-                    if (sampler == null) {
-                        this._samplers.splice(index, 1);
-                        index--;
+                    _this._uniforms = engine_1.getUniforms(_this._program, _this._uniformsNames);
+                    _this._attributes = engine_1.getAttributes(_this._program, attributesNames);
+                    var index;
+                    for (index = 0; index < _this._samplers.length; index++) {
+                        var sampler = _this.getUniform(_this._samplers[index]);
+                        if (sampler == null) {
+                            _this._samplers.splice(index, 1);
+                            index--;
+                        }
                     }
-                }
-                engine.bindSamplers(this);
-                this._compilationError = "";
-                this._isReady = true;
-                if (this.onCompiled) {
-                    this.onCompiled(this);
-                }
-                this.onCompileObservable.notifyObservers(this);
-                this.onCompileObservable.clear();
-                // Unbind mesh reference in fallbacks
-                if (this._fallbacks) {
-                    this._fallbacks.unBindMesh();
-                }
-                if (previousProgram) {
-                    this.getEngine()._deleteProgram(previousProgram);
-                }
+                    engine_1.bindSamplers(_this);
+                    _this._compilationError = "";
+                    _this._isReady = true;
+                    if (_this.onCompiled) {
+                        _this.onCompiled(_this);
+                    }
+                    _this.onCompileObservable.notifyObservers(_this);
+                    _this.onCompileObservable.clear();
+                    // Unbind mesh reference in fallbacks
+                    if (_this._fallbacks) {
+                        _this._fallbacks.unBindMesh();
+                    }
+                    if (previousProgram) {
+                        _this.getEngine()._deleteProgram(previousProgram);
+                    }
+                });
             }
             catch (e) {
                 this._compilationError = e.message;
@@ -2943,7 +2949,7 @@ var BABYLON;
          * @returns a new Quaternion object, computed from the Vector3 coordinates
          */
         Vector3.prototype.toQuaternion = function () {
-            return BABYLON.Quaternion.RotationYawPitchRoll(this.x, this.y, this.z);
+            return BABYLON.Quaternion.RotationYawPitchRoll(this.y, this.x, this.z);
         };
         /**
          * Adds the given vector to the current Vector3
@@ -12651,7 +12657,7 @@ var BABYLON;
              * Returns the current version of the framework
              */
             get: function () {
-                return "3.3.0";
+                return "4.0.0-alpha.0";
             },
             enumerable: true,
             configurable: true
@@ -12900,6 +12906,12 @@ var BABYLON;
                     this._caps.drawBuffersExtension = false;
                 }
             }
+            // Shader compiler threads
+            this._caps.parallelShaderCompile = this._gl.getExtension('KHR_parallel_shader_compile');
+            if (this._caps.parallelShaderCompile) {
+                var threads = this._gl.getParameter(this._caps.parallelShaderCompile.MAX_SHADER_COMPILER_THREADS_KHR);
+                this._caps.parallelShaderCompile.maxShaderCompilerThreadsKHR(threads);
+            }
             // Depth Texture
             if (this._webGLVersion > 1) {
                 this._caps.depthTextureExtension = true;
@@ -14634,6 +14646,21 @@ var BABYLON;
             if (this.webGLVersion > 1 && transformFeedbackVaryings) {
                 this.bindTransformFeedback(null);
             }
+            shaderProgram.context = context;
+            shaderProgram.vertexShader = vertexShader;
+            shaderProgram.fragmentShader = fragmentShader;
+            if (!this._caps.parallelShaderCompile) {
+                this._finalizeProgram(shaderProgram);
+            }
+            else {
+                shaderProgram.isParallelCompiled = true;
+            }
+            return shaderProgram;
+        };
+        Engine.prototype._finalizeProgram = function (shaderProgram) {
+            var context = shaderProgram.context;
+            var vertexShader = shaderProgram.vertexShader;
+            var fragmentShader = shaderProgram.fragmentShader;
             var linked = context.getProgramParameter(shaderProgram, context.LINK_STATUS);
             if (!linked) {
                 var error = context.getProgramInfoLog(shaderProgram);
@@ -14653,7 +14680,32 @@ var BABYLON;
             }
             context.deleteShader(vertexShader);
             context.deleteShader(fragmentShader);
-            return shaderProgram;
+            shaderProgram.context = undefined;
+            shaderProgram.vertexShader = undefined;
+            shaderProgram.fragmentShader = undefined;
+            if (shaderProgram.onCompiled) {
+                shaderProgram.onCompiled();
+                shaderProgram.onCompiled = undefined;
+            }
+        };
+        /** @hidden */
+        Engine.prototype._isProgramCompiled = function (shaderProgram) {
+            if (!shaderProgram.isParallelCompiled) {
+                return true;
+            }
+            if (this._gl.getProgramParameter(shaderProgram, this._caps.parallelShaderCompile.COMPLETION_STATUS_KHR)) {
+                this._finalizeProgram(shaderProgram);
+                return true;
+            }
+            return false;
+        };
+        /** @hidden */
+        Engine.prototype._executeWhenProgramIsCompiled = function (shaderProgram, action) {
+            if (!shaderProgram.isParallelCompiled) {
+                action();
+                return;
+            }
+            shaderProgram.onCompiled = action;
         };
         /**
          * Gets the list of webGL uniform locations associated with a specific program based on a list of uniform names
@@ -25250,7 +25302,7 @@ var BABYLON;
          * Creates a new Scene
          * @param engine defines the engine to use to render this scene
          */
-        function Scene(engine) {
+        function Scene(engine, options) {
             var _this = _super.call(this) || this;
             // Members
             /**
@@ -25764,6 +25816,10 @@ var BABYLON;
              * Defines the actions happening when a pointer up event happens.
              */
             _this._pointerUpStage = BABYLON.Stage.Create();
+            /**
+             * an optional map from Geometry Id to Geometry index in the 'geometries' array
+             */
+            _this.geometriesById = null;
             _this._defaultMeshCandidates = {
                 data: [],
                 length: 0
@@ -25802,6 +25858,9 @@ var BABYLON;
                 _this._imageProcessingConfiguration = new BABYLON.ImageProcessingConfiguration();
             }
             _this.setDefaultCandidateProviders();
+            if (options && options.useGeometryIdsMap === true) {
+                _this.geometriesById = {};
+            }
             return _this;
         }
         Object.defineProperty(Scene.prototype, "environmentTexture", {
@@ -28057,6 +28116,9 @@ var BABYLON;
          * @param newGeometry The geometry to add
          */
         Scene.prototype.addGeometry = function (newGeometry) {
+            if (this.geometriesById) {
+                this.geometriesById[newGeometry.id] = this.geometries.length;
+            }
             this.geometries.push(newGeometry);
         };
         /**
@@ -28287,9 +28349,17 @@ var BABYLON;
          * @return the geometry or null if none found.
          */
         Scene.prototype.getGeometryByID = function (id) {
-            for (var index = 0; index < this.geometries.length; index++) {
-                if (this.geometries[index].id === id) {
-                    return this.geometries[index];
+            if (this.geometriesById) {
+                var index_1 = this.geometriesById[id];
+                if (index_1 !== undefined) {
+                    return this.geometries[index_1];
+                }
+            }
+            else {
+                for (var index = 0; index < this.geometries.length; index++) {
+                    if (this.geometries[index].id === id) {
+                        return this.geometries[index];
+                    }
                 }
             }
             return null;
@@ -28304,7 +28374,7 @@ var BABYLON;
             if (!force && this.getGeometryByID(geometry.id)) {
                 return false;
             }
-            this.geometries.push(geometry);
+            this.addGeometry(geometry);
             //notify the collision coordinator
             if (this.collisionCoordinator) {
                 this.collisionCoordinator.onGeometryAdded(geometry);
@@ -28318,17 +28388,34 @@ var BABYLON;
          * @return a boolean defining if the geometry was removed or not
          */
         Scene.prototype.removeGeometry = function (geometry) {
-            var index = this.geometries.indexOf(geometry);
-            if (index > -1) {
-                this.geometries.splice(index, 1);
-                //notify the collision coordinator
-                if (this.collisionCoordinator) {
-                    this.collisionCoordinator.onGeometryDeleted(geometry);
+            var index;
+            if (this.geometriesById) {
+                index = this.geometriesById[geometry.id];
+                if (index === undefined) {
+                    return false;
                 }
-                this.onGeometryRemovedObservable.notifyObservers(geometry);
-                return true;
             }
-            return false;
+            else {
+                index = this.geometries.indexOf(geometry);
+                if (index < 0) {
+                    return false;
+                }
+            }
+            if (index !== this.geometries.length - 1) {
+                var lastGeometry = this.geometries[this.geometries.length - 1];
+                this.geometries[index] = lastGeometry;
+                if (this.geometriesById) {
+                    this.geometriesById[lastGeometry.id] = index;
+                    this.geometriesById[geometry.id] = undefined;
+                }
+            }
+            this.geometries.pop();
+            //notify the collision coordinator
+            if (this.collisionCoordinator) {
+                this.collisionCoordinator.onGeometryDeleted(geometry);
+            }
+            this.onGeometryRemovedObservable.notifyObservers(geometry);
+            return true;
         };
         /**
          * Gets the list of geometries attached to the scene
@@ -114297,7 +114384,8 @@ var BABYLON;
         NullEngine.prototype.createShaderProgram = function (vertexCode, fragmentCode, defines, context) {
             return {
                 transformFeedback: null,
-                __SPECTOR_rebuildProgram: null
+                __SPECTOR_rebuildProgram: null,
+                isParallelCompiled: false
             };
         };
         NullEngine.prototype.getUniforms = function (shaderProgram, uniformsNames) {

+ 5 - 19
dist/preview release/viewer/babylon.viewer.d.ts

@@ -168,11 +168,11 @@ declare module BabylonViewer {
                 * Mainly used for help and errors
                 * @param subScreen the name of the subScreen. Those can be defined in the configuration object
                 */
-            showOverlayScreen(subScreen: string): Promise<Template> | Promise<string>;
+            showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
             /**
                 * Hide the overlay screen.
                 */
-            hideOverlayScreen(): Promise<Template> | Promise<string>;
+            hideOverlayScreen(): Promise<string> | Promise<Template>;
             /**
                 * show the viewer (in case it was hidden)
                 *
@@ -189,11 +189,11 @@ declare module BabylonViewer {
                 * Show the loading screen.
                 * The loading screen can be configured using the configuration object
                 */
-            showLoadingScreen(): Promise<Template> | Promise<string>;
+            showLoadingScreen(): Promise<string> | Promise<Template>;
             /**
                 * Hide the loading screen
                 */
-            hideLoadingScreen(): Promise<Template> | Promise<string>;
+            hideLoadingScreen(): Promise<string> | Promise<Template>;
             dispose(): void;
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }
@@ -924,7 +924,7 @@ declare module BabylonViewer {
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 declare module BabylonViewer {
@@ -1558,20 +1558,6 @@ declare module BabylonViewer {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 declare module BabylonViewer {
-    /**
-        * A custom upgrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedUpgrade(sceneManager: SceneManager): boolean;
-    /**
-        * A custom degrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedDegrade(sceneManager: SceneManager): boolean;
-}
-declare module BabylonViewer {
 }
 declare module BabylonViewer {
     export interface IEnvironmentMapConfiguration {

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


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/viewer/babylon.viewer.max.js


+ 5 - 22
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -200,11 +200,11 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * Mainly used for help and errors
                 * @param subScreen the name of the subScreen. Those can be defined in the configuration object
                 */
-            showOverlayScreen(subScreen: string): Promise<Template> | Promise<string>;
+            showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
             /**
                 * Hide the overlay screen.
                 */
-            hideOverlayScreen(): Promise<Template> | Promise<string>;
+            hideOverlayScreen(): Promise<string> | Promise<Template>;
             /**
                 * show the viewer (in case it was hidden)
                 *
@@ -221,11 +221,11 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * Show the loading screen.
                 * The loading screen can be configured using the configuration object
                 */
-            showLoadingScreen(): Promise<Template> | Promise<string>;
+            showLoadingScreen(): Promise<string> | Promise<Template>;
             /**
                 * Hide the loading screen
                 */
-            hideLoadingScreen(): Promise<Template> | Promise<string>;
+            hideLoadingScreen(): Promise<string> | Promise<Template>;
             dispose(): void;
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }
@@ -985,14 +985,13 @@ declare module 'babylonjs-viewer/templating/viewerTemplatePlugin' {
 }
 
 declare module 'babylonjs-viewer/optimizer/custom' {
-    import { extendedUpgrade } from "babylonjs-viewer/optimizer/custom/extended";
     import { SceneManager } from "babylonjs-viewer/managers/sceneManager";
     /**
       *
       * @param name the name of the custom optimizer configuration
       * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
       */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
+    export function getCustomOptimizerByName(name: string, upgrade?: boolean): (sceneManager: SceneManager) => boolean;
     export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 
@@ -1663,22 +1662,6 @@ declare module 'babylonjs-viewer/loader/plugins' {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 
-declare module 'babylonjs-viewer/optimizer/custom/extended' {
-    import { SceneManager } from 'babylonjs-viewer/managers/sceneManager';
-    /**
-        * A custom upgrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedUpgrade(sceneManager: SceneManager): boolean;
-    /**
-        * A custom degrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedDegrade(sceneManager: SceneManager): boolean;
-}
-
 declare module 'babylonjs-viewer/configuration/interfaces' {
     export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';

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

@@ -2,6 +2,8 @@
 
 ## Major updates
 
+- Added support for [parallel shader compilation](https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/) ([Deltakosh](https://github.com/deltakosh))
+
 ## Updates
 
 ### GUI

+ 64 - 1
src/Engine/babylon.engine.ts

@@ -157,6 +157,12 @@ module BABYLON {
         public timerQuery: EXT_disjoint_timer_query;
         /** Defines if timestamp can be used with timer query */
         public canUseTimestampForTimerQuery: boolean;
+        /** Function used to let the system compiles shaders in background */
+        public parallelShaderCompile: {
+            MAX_SHADER_COMPILER_THREADS_KHR: number;
+            maxShaderCompilerThreadsKHR: (thread: number) => void;
+            COMPLETION_STATUS_KHR: number;
+        };
     }
 
     /** Interface defining initialization parameters for Engine class */
@@ -1352,6 +1358,13 @@ module BABYLON {
                 }
             }
 
+            // Shader compiler threads
+            this._caps.parallelShaderCompile = this._gl.getExtension('KHR_parallel_shader_compile');
+            if (this._caps.parallelShaderCompile) {
+                const threads = this._gl.getParameter(this._caps.parallelShaderCompile.MAX_SHADER_COMPILER_THREADS_KHR);
+                this._caps.parallelShaderCompile.maxShaderCompilerThreadsKHR(threads);
+            }
+
             // Depth Texture
             if (this._webGLVersion > 1) {
                 this._caps.depthTextureExtension = true;
@@ -1379,6 +1392,7 @@ module BABYLON {
                     this._caps.vertexArrayObject = false;
                 }
             }
+
             // Instances count
             if (this._webGLVersion > 1) {
                 this._caps.instancedArrays = true;
@@ -3305,6 +3319,24 @@ module BABYLON {
                 this.bindTransformFeedback(null);
             }
 
+            shaderProgram.context = context;
+            shaderProgram.vertexShader = vertexShader;
+            shaderProgram.fragmentShader = fragmentShader;
+
+            if (!this._caps.parallelShaderCompile) {
+                this._finalizeProgram(shaderProgram);
+            } else {
+                shaderProgram.isParallelCompiled = true;
+            }
+
+            return shaderProgram;
+        }
+
+        private _finalizeProgram(shaderProgram: WebGLProgram) {
+            const context = shaderProgram.context!;
+            const vertexShader = shaderProgram.vertexShader!;
+            const fragmentShader = shaderProgram.fragmentShader!;
+
             var linked = context.getProgramParameter(shaderProgram, context.LINK_STATUS);
 
             if (!linked) {
@@ -3329,7 +3361,38 @@ module BABYLON {
             context.deleteShader(vertexShader);
             context.deleteShader(fragmentShader);
 
-            return shaderProgram;
+            shaderProgram.context = undefined;
+            shaderProgram.vertexShader = undefined;
+            shaderProgram.fragmentShader = undefined;
+
+            if (shaderProgram.onCompiled) {
+                shaderProgram.onCompiled();
+                shaderProgram.onCompiled = undefined;
+            }
+        }
+
+        /** @hidden */
+        public _isProgramCompiled(shaderProgram: WebGLProgram): boolean {
+           if (!shaderProgram.isParallelCompiled) {
+               return true;
+           }
+
+           if (this._gl.getProgramParameter(shaderProgram, this._caps.parallelShaderCompile.COMPLETION_STATUS_KHR)) {
+               this._finalizeProgram(shaderProgram);
+               return true;
+           }
+
+           return false;
+        }
+
+        /** @hidden */
+        public _executeWhenProgramIsCompiled(shaderProgram: WebGLProgram, action: () => void) {
+            if (!shaderProgram.isParallelCompiled) {
+                action();
+                return;
+            }
+
+            shaderProgram.onCompiled = action;
         }
 
         /**

+ 2 - 1
src/Engine/babylon.nullEngine.ts

@@ -173,7 +173,8 @@ module BABYLON {
         public createShaderProgram(vertexCode: string, fragmentCode: string, defines: string, context?: WebGLRenderingContext): WebGLProgram {
             return {
                 transformFeedback: null,
-                __SPECTOR_rebuildProgram: null
+                __SPECTOR_rebuildProgram: null,
+                isParallelCompiled: false
             };
         }
 

+ 34 - 28
src/Materials/babylon.effect.ts

@@ -363,6 +363,9 @@ module BABYLON {
          * @returns if the effect is compiled and prepared.
          */
         public isReady(): boolean {
+            if (!this._isReady && this._program && this._program.isParallelCompiled) {
+                return this._engine._isProgramCompiled(this._program);
+            }
             return this._isReady;
         }
 
@@ -784,43 +787,46 @@ module BABYLON {
                 }
                 this._program.__SPECTOR_rebuildProgram = this._rebuildProgram.bind(this);
 
-                if (engine.supportsUniformBuffers) {
-                    for (var name in this._uniformBuffersNames) {
-                        this.bindUniformBlock(name, this._uniformBuffersNames[name]);
+                engine._executeWhenProgramIsCompiled(this._program, () => {
+                    if (engine.supportsUniformBuffers) {
+                        for (var name in this._uniformBuffersNames) {
+                            this.bindUniformBlock(name, this._uniformBuffersNames[name]);
+                        }
                     }
-                }
 
-                this._uniforms = engine.getUniforms(this._program, this._uniformsNames);
-                this._attributes = engine.getAttributes(this._program, attributesNames);
+                    this._uniforms = engine.getUniforms(this._program, this._uniformsNames);
+                    this._attributes = engine.getAttributes(this._program, attributesNames);
 
-                var index: number;
-                for (index = 0; index < this._samplers.length; index++) {
-                    var sampler = this.getUniform(this._samplers[index]);
+                    var index: number;
+                    for (index = 0; index < this._samplers.length; index++) {
+                        var sampler = this.getUniform(this._samplers[index]);
 
-                    if (sampler == null) {
-                        this._samplers.splice(index, 1);
-                        index--;
+                        if (sampler == null) {
+                            this._samplers.splice(index, 1);
+                            index--;
+                        }
                     }
-                }
 
-                engine.bindSamplers(this);
+                    engine.bindSamplers(this);
 
-                this._compilationError = "";
-                this._isReady = true;
-                if (this.onCompiled) {
-                    this.onCompiled(this);
-                }
-                this.onCompileObservable.notifyObservers(this);
-                this.onCompileObservable.clear();
+                    this._compilationError = "";
+                    this._isReady = true;
+                    if (this.onCompiled) {
+                        this.onCompiled(this);
+                    }
+                    this.onCompileObservable.notifyObservers(this);
+                    this.onCompileObservable.clear();
 
-                // Unbind mesh reference in fallbacks
-                if (this._fallbacks) {
-                    this._fallbacks.unBindMesh();
-                }
+                    // Unbind mesh reference in fallbacks
+                    if (this._fallbacks) {
+                        this._fallbacks.unBindMesh();
+                    }
+
+                    if (previousProgram) {
+                        this.getEngine()._deleteProgram(previousProgram);
+                    }
+                });
 
-                if (previousProgram) {
-                    this.getEngine()._deleteProgram(previousProgram);
-                }
             } catch (e) {
                 this._compilationError = e.message;
 

+ 1 - 1
src/Math/babylon.math.ts

@@ -1616,7 +1616,7 @@ module BABYLON {
          * @returns a new Quaternion object, computed from the Vector3 coordinates
          */
         public toQuaternion(): Quaternion {
-            return BABYLON.Quaternion.RotationYawPitchRoll(this.x, this.y, this.z);
+            return BABYLON.Quaternion.RotationYawPitchRoll(this.y, this.x, this.z);
         }
 
         /**

+ 8 - 0
src/babylon.mixins.ts

@@ -22,6 +22,14 @@ interface Window {
     setImmediate(handler: (...args: any[]) => void): number;
 }
 
+interface WebGLProgram {
+    context?: WebGLRenderingContext;
+    vertexShader?: WebGLShader;
+    fragmentShader?: WebGLShader;
+    isParallelCompiled: boolean;
+    onCompiled?: () => void;
+}
+
 interface WebGLRenderingContext {
     drawArraysInstanced(mode: number, first: number, count: number, primcount: number): void;
     drawElementsInstanced(mode: number, count: number, type: number, offset: number, primcount: number): void;

+ 87 - 37
src/babylon.scene.ts

@@ -63,6 +63,15 @@ module BABYLON {
         renderingGroupId: number;
     }
 
+    /** Interface defining initialization parameters for Scene class */
+    export interface SceneOptions {
+        /**
+         * Defines that scene should keep up-to-date a map of geometry to enable fast look-up by Id
+         * It will improve performance when the number of geometries becomes important.
+         */
+        useGeometryIdsMap?: boolean;
+    }
+
     /**
      * Represents a scene to be rendered by the engine.
      * @see http://doc.babylonjs.com/features/scene
@@ -1165,10 +1174,15 @@ module BABYLON {
         public _pointerUpStage = Stage.Create<PointerUpDownStageAction>();
 
         /**
+         * an optional map from Geometry Id to Geometry index in the 'geometries' array
+         */
+        private geometriesById: Nullable<{ [id: string]: number | undefined }> = null;
+
+        /**
          * Creates a new Scene
          * @param engine defines the engine to use to render this scene
          */
-        constructor(engine: Engine) {
+        constructor(engine: Engine, options?: SceneOptions) {
             super();
             this._engine = engine || Engine.LastCreatedEngine;
 
@@ -1197,6 +1211,10 @@ module BABYLON {
             }
 
             this.setDefaultCandidateProviders();
+
+            if (options && options.useGeometryIdsMap === true) {
+                this.geometriesById = {};
+            }
         }
 
         private _defaultMeshCandidates: ISmartArrayLike<AbstractMesh> = {
@@ -1802,7 +1820,7 @@ module BABYLON {
         /** @hidden */
         public _isPointerSwiping(): boolean {
             return Math.abs(this._startingPointerPosition.x - this._pointerX) > Scene.DragMovementThreshold ||
-                   Math.abs(this._startingPointerPosition.y - this._pointerY) > Scene.DragMovementThreshold;
+                Math.abs(this._startingPointerPosition.y - this._pointerY) > Scene.DragMovementThreshold;
         }
 
         /**
@@ -1846,7 +1864,7 @@ module BABYLON {
                 if (!checkPicking && ActionManager && ActionManager.HasPickTriggers) {
                     act = this._initActionManager(act, clickInfo);
                     if (act) {
-                        checkPicking = act.hasPickTriggers;
+                        checkPicking = act.hasPickTriggers;
                     }
                 }
                 if (checkPicking) {
@@ -1863,7 +1881,7 @@ module BABYLON {
                             if (checkSingleClickImmediately && !ActionManager.HasSpecificTrigger(ActionManager.OnDoublePickTrigger)) {
                                 act = this._initActionManager(act, clickInfo);
                                 if (act) {
-                                    checkSingleClickImmediately = !act.hasSpecificTrigger(ActionManager.OnDoublePickTrigger);
+                                    checkSingleClickImmediately = !act.hasSpecificTrigger(ActionManager.OnDoublePickTrigger);
                                 }
                             }
                         }
@@ -1889,7 +1907,7 @@ module BABYLON {
                         if (!checkDoubleClick && ActionManager.HasSpecificTrigger(ActionManager.OnDoublePickTrigger)) {
                             act = this._initActionManager(act, clickInfo);
                             if (act) {
-                                checkDoubleClick = act.hasSpecificTrigger(ActionManager.OnDoublePickTrigger);
+                                checkDoubleClick = act.hasSpecificTrigger(ActionManager.OnDoublePickTrigger);
                             }
                         }
                         if (checkDoubleClick) {
@@ -2197,21 +2215,9 @@ module BABYLON {
                 return false;
             }
 
-            if (this._pendingData.length > 0) {
-                return false;
-            }
             let index: number;
             let engine = this.getEngine();
 
-            // Geometries
-            for (index = 0; index < this.geometries.length; index++) {
-                var geometry = this.geometries[index];
-
-                if (geometry.delayLoadState === Engine.DELAYLOADSTATE_LOADING) {
-                    return false;
-                }
-            }
-
             // Meshes
             for (index = 0; index < this.meshes.length; index++) {
                 var mesh = this.meshes[index];
@@ -2237,6 +2243,20 @@ module BABYLON {
                 }
             }
 
+            // Pending data
+            if (this._pendingData.length > 0) {
+                return false;
+            }
+
+            // Geometries
+            for (index = 0; index < this.geometries.length; index++) {
+                var geometry = this.geometries[index];
+
+                if (geometry.delayLoadState === Engine.DELAYLOADSTATE_LOADING) {
+                    return false;
+                }
+            }
+
             // Post-processes
             if (this.activeCameras && this.activeCameras.length > 0) {
                 for (var camera of this.activeCameras) {
@@ -3270,6 +3290,10 @@ module BABYLON {
          * @param newGeometry The geometry to add
          */
         public addGeometry(newGeometry: Geometry): void {
+            if (this.geometriesById) {
+                this.geometriesById[newGeometry.id] = this.geometries.length;
+            }
+
             this.geometries.push(newGeometry);
         }
 
@@ -3535,11 +3559,19 @@ module BABYLON {
          * @return the geometry or null if none found.
          */
         public getGeometryByID(id: string): Nullable<Geometry> {
-            for (var index = 0; index < this.geometries.length; index++) {
-                if (this.geometries[index].id === id) {
+            if (this.geometriesById) {
+                const index = this.geometriesById[id];
+                if (index !== undefined) {
                     return this.geometries[index];
                 }
             }
+            else {
+                for (var index = 0; index < this.geometries.length; index++) {
+                    if (this.geometries[index].id === id) {
+                        return this.geometries[index];
+                    }
+                }
+            }
 
             return null;
         }
@@ -3555,7 +3587,7 @@ module BABYLON {
                 return false;
             }
 
-            this.geometries.push(geometry);
+            this.addGeometry(geometry);
 
             //notify the collision coordinator
             if (this.collisionCoordinator) {
@@ -3573,20 +3605,38 @@ module BABYLON {
          * @return a boolean defining if the geometry was removed or not
          */
         public removeGeometry(geometry: Geometry): boolean {
-            var index = this.geometries.indexOf(geometry);
-
-            if (index > -1) {
-                this.geometries.splice(index, 1);
+            let index;
+            if (this.geometriesById) {
+                index = this.geometriesById[geometry.id];
+                if (index === undefined) {
+                    return false;
+                }
+            }
+            else {
+                index = this.geometries.indexOf(geometry);
+                if (index < 0) {
+                    return false;
+                }
+            }
 
-                //notify the collision coordinator
-                if (this.collisionCoordinator) {
-                    this.collisionCoordinator.onGeometryDeleted(geometry);
+            if (index !== this.geometries.length - 1) {
+                const lastGeometry = this.geometries[this.geometries.length - 1];
+                this.geometries[index] = lastGeometry;
+                if (this.geometriesById) {
+                    this.geometriesById[lastGeometry.id] = index;
+                    this.geometriesById[geometry.id] = undefined;
                 }
+            }
 
-                this.onGeometryRemovedObservable.notifyObservers(geometry);
-                return true;
+            this.geometries.pop();
+
+            //notify the collision coordinator
+            if (this.collisionCoordinator) {
+                this.collisionCoordinator.onGeometryDeleted(geometry);
             }
-            return false;
+
+            this.onGeometryRemovedObservable.notifyObservers(geometry);
+            return true;
         }
 
         /**
@@ -4197,7 +4247,7 @@ module BABYLON {
             this.activeCamera = camera;
 
             if (!this.activeCamera) {
-                throw new Error("Active camera not set");
+                throw new Error("Active camera not set");
             }
 
             // Viewport
@@ -4498,7 +4548,7 @@ module BABYLON {
                         this.activeCamera = renderTarget.activeCamera || this.activeCamera;
 
                         if (!this.activeCamera) {
-                            throw new Error("Active camera not set");
+                            throw new Error("Active camera not set");
                         }
 
                         // Viewport
@@ -4906,7 +4956,7 @@ module BABYLON {
 
             if (!camera) {
                 if (!this.activeCamera) {
-                    throw new Error("Active camera not set");
+                    throw new Error("Active camera not set");
                 }
 
                 camera = this.activeCamera;
@@ -4955,7 +5005,7 @@ module BABYLON {
 
             if (!camera) {
                 if (!this.activeCamera) {
-                    throw new Error("Active camera not set");
+                    throw new Error("Active camera not set");
                 }
 
                 camera = this.activeCamera;
@@ -4995,11 +5045,11 @@ module BABYLON {
 
                 var result = mesh.intersects(ray, fastCheck);
                 if (!result || !result.hit) {
-                    continue;
+                    continue;
                 }
 
                 if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance) {
-                    continue;
+                    continue;
                 }
 
                 pickingInfo = result;
@@ -5034,7 +5084,7 @@ module BABYLON {
 
                 var result = mesh.intersects(ray, false);
                 if (!result || !result.hit) {
-                    continue;
+                    continue;
                 }
 
                 pickingInfos.push(result);