Explorar o código

nullCheck : first step1

David Catuhe %!s(int64=7) %!d(string=hai) anos
pai
achega
6864419271
Modificáronse 35 ficheiros con 14868 adicións e 14354 borrados
  1. 1 0
      Tools/Gulp/config.json
  2. 0 9
      Tools/Gulp/gulpfile.js
  3. 0 1
      Tools/Gulp/package.json
  4. 2651 2647
      dist/preview release/babylon.d.ts
  5. 29 29
      dist/preview release/babylon.js
  6. 307 159
      dist/preview release/babylon.max.js
  7. 2651 2647
      dist/preview release/babylon.module.d.ts
  8. 29 29
      dist/preview release/babylon.worker.js
  9. 4111 4107
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  10. 47 47
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  11. 307 159
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  12. 4111 4107
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts
  13. 3 3
      src/Actions/babylon.action.ts
  14. 16 14
      src/Actions/babylon.actionManager.ts
  15. 31 20
      src/Cameras/babylon.camera.ts
  16. 9 4
      src/Cameras/babylon.followCamera.ts
  17. 120 53
      src/Engine/babylon.engine.ts
  18. 15 15
      src/Materials/Textures/babylon.baseTexture.ts
  19. 17 15
      src/Materials/Textures/babylon.internalTexture.ts
  20. 44 21
      src/Materials/Textures/babylon.renderTargetTexture.ts
  21. 26 15
      src/Materials/Textures/babylon.texture.ts
  22. 5 5
      src/Materials/babylon.uniformBuffer.ts
  23. 1 1
      src/Mesh/babylon.abstractMesh.ts
  24. 2 2
      src/PostProcess/babylon.passPostProcess.ts
  25. 15 13
      src/PostProcess/babylon.postProcess.ts
  26. 1 1
      src/PostProcess/babylon.postProcessManager.ts
  27. 21 17
      src/Rendering/babylon.renderingGroup.ts
  28. 13 13
      src/Rendering/babylon.renderingManager.ts
  29. 27 19
      src/Tools/babylon.database.ts
  30. 42 26
      src/Tools/babylon.tools.ts
  31. 2 2
      src/babylon.mixins.ts
  32. 18 12
      src/babylon.node.ts
  33. 191 141
      src/babylon.scene.ts
  34. 3 0
      src/babylon.types.ts
  35. 2 1
      src/tsconfig.json

+ 1 - 0
Tools/Gulp/config.json

@@ -160,6 +160,7 @@
     "workloads": {
         "core": {
             "files": [
+                "../../src/babylon.types.js",
                 "../../src/Events/babylon.keyboardEvents.js",
                 "../../src/Events/babylon.pointerEvents.js",
                 "../../src/Math/babylon.math.js",

+ 0 - 9
Tools/Gulp/gulpfile.js

@@ -21,8 +21,6 @@ var path = require('path');
 var sass = require('gulp-sass');
 var webpack = require('webpack-stream');
 
-var zip = require('gulp-zip');
-
 var config = require("./config.json");
 
 var del = require('del');
@@ -518,13 +516,6 @@ gulp.task('webserver', function () {
 gulp.task('run', ['watch', 'webserver'], function () {
 });
 
-
-gulp.task("zip-blender", function () {
-    return gulp.src('../../Exporters/Blender/src/**')
-        .pipe(zip('Blender2Babylon-5.4.zip'))
-        .pipe(gulp.dest('../../Exporters/Blender'));
-});
-
 gulp.task('clean-JS-MAP', function () {
     return del([
         '../../src/**/*.js.map', '../../src/**/*.js'

+ 0 - 1
Tools/Gulp/package.json

@@ -32,7 +32,6 @@
     "style-loader": "^0.13.1",
     "exports-loader": "^0.6.3",
     "imports-loader": "^0.7.0",
-    "gulp-zip": "~3.2.0",
     "del": "2.2.2"
   },
   "scripts": {

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 2651 - 2647
dist/preview release/babylon.d.ts


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 29 - 29
dist/preview release/babylon.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 307 - 159
dist/preview release/babylon.max.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 2651 - 2647
dist/preview release/babylon.module.d.ts


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 29 - 29
dist/preview release/babylon.worker.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 4111 - 4107
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 47 - 47
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 307 - 159
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 4111 - 4107
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts


+ 3 - 3
src/Actions/babylon.action.ts

@@ -5,7 +5,7 @@
 
         private _nextActiveAction: Action;
         private _child: Action;
-        private _condition: Condition;
+        private _condition?: Condition;
         private _triggerParameter: any;
 
         public onBeforeExecuteObservable = new Observable<Action>();
@@ -31,7 +31,7 @@
             return this._triggerParameter;
         }
 
-        public _executeCurrent(evt: ActionEvent): void {
+        public _executeCurrent(evt?: ActionEvent): void {
             if (this._nextActiveAction._condition) {
                 var condition = this._nextActiveAction._condition;
                 var currentRenderId = this._actionManager.getScene().getRenderId();
@@ -59,7 +59,7 @@
             this.skipToNextActiveAction();
         }
 
-        public execute(evt: ActionEvent): void {
+        public execute(evt?: ActionEvent): void {
 
         }
 

+ 16 - 14
src/Actions/babylon.actionManager.ts

@@ -323,27 +323,29 @@
          * @param {number} trigger - the trigger to process
          * @param evt {BABYLON.ActionEvent} the event details to be processed
          */
-        public processTrigger(trigger: number, evt: ActionEvent): void {
+        public processTrigger(trigger: number, evt?: ActionEvent): void {
             for (var index = 0; index < this.actions.length; index++) {
                 var action = this.actions[index];
 
                 if (action.trigger === trigger) {
-                    if (trigger === ActionManager.OnKeyUpTrigger
-                        || trigger === ActionManager.OnKeyDownTrigger) {
-                        var parameter = action.getTriggerParameter();
+                    if (evt) {
+                        if (trigger === ActionManager.OnKeyUpTrigger
+                            || trigger === ActionManager.OnKeyDownTrigger) {
+                            var parameter = action.getTriggerParameter();
 
-                        if (parameter && parameter !== evt.sourceEvent.keyCode) {
-                            if (!parameter.toLowerCase) {
-                                continue;
-                            }
-                            var lowerCase = parameter.toLowerCase();
-
-                            if (lowerCase !== evt.sourceEvent.key) {
-                                var unicode = evt.sourceEvent.charCode ? evt.sourceEvent.charCode : evt.sourceEvent.keyCode;
-                                var actualkey = String.fromCharCode(unicode).toLowerCase();
-                                if (actualkey !== lowerCase) {
+                            if (parameter && parameter !== evt.sourceEvent.keyCode) {
+                                if (!parameter.toLowerCase) {
                                     continue;
                                 }
+                                var lowerCase = parameter.toLowerCase();
+
+                                if (lowerCase !== evt.sourceEvent.key) {
+                                    var unicode = evt.sourceEvent.charCode ? evt.sourceEvent.charCode : evt.sourceEvent.keyCode;
+                                    var actualkey = String.fromCharCode(unicode).toLowerCase();
+                                    if (actualkey !== lowerCase) {
+                                        continue;
+                                    }
+                                }
                             }
                         }
                     }

+ 31 - 20
src/Cameras/babylon.camera.ts

@@ -73,16 +73,16 @@
         public upVector = Vector3.Up();
 
         @serialize()
-        public orthoLeft: number = null;
+        public orthoLeft: Nullable<number> = null;
 
         @serialize()
-        public orthoRight: number = null;
+        public orthoRight: Nullable<number> = null;
 
         @serialize()
-        public orthoBottom: number = null;
+        public orthoBottom: Nullable<number> = null;
 
         @serialize()
-        public orthoTop: number = null;
+        public orthoTop: Nullable<number> = null;
 
         @serialize()
         public fov = 0.8;
@@ -120,7 +120,7 @@
 
         public _cameraRigParams: any;
         public _rigCameras = new Array<Camera>();
-        public _rigPostProcess: PostProcess;
+        public _rigPostProcess: Nullable<PostProcess>;
         protected _webvrViewMatrix = Matrix.Identity();
         public _skipRendering = false;
         public _alternateCamera: Camera;
@@ -325,7 +325,7 @@
             return this._rigCameras;
         }
 
-        public get rigPostProcess(): PostProcess {
+        public get rigPostProcess(): Nullable<PostProcess> {
             return this._rigPostProcess;
         }
 
@@ -356,7 +356,7 @@
             }
         }
 
-        public attachPostProcess(postProcess: PostProcess, insertAt: number = null): number {
+        public attachPostProcess(postProcess: PostProcess, insertAt: Nullable<number> = null): number {
             if (!postProcess.isReusable() && this._postProcesses.indexOf(postProcess) > -1) {
                 Tools.Error("You're trying to reuse a post process not defined as reusable.");
                 return 0;
@@ -603,7 +603,10 @@
             // Remove from scene
             this.getScene().removeCamera(this);
             while (this._rigCameras.length > 0) {
-                this._rigCameras.pop().dispose();
+                let camera = this._rigCameras.pop();
+                if (camera) {
+                    camera.dispose();
+                }                
             }
 
             // Postprocesses
@@ -636,30 +639,30 @@
         }
 
         // ---- Camera rigs section ----
-        public get leftCamera(): FreeCamera {
+        public get leftCamera(): Nullable<FreeCamera> {
             if (this._rigCameras.length < 1) {
-                return undefined;
+                return null;
             }
             return (<FreeCamera>this._rigCameras[0]);
         }
 
-        public get rightCamera(): FreeCamera {
+        public get rightCamera(): Nullable<FreeCamera> {
             if (this._rigCameras.length < 2) {
-                return undefined;
+                return null;
             }
             return (<FreeCamera>this._rigCameras[1]);
         }
 
-        public getLeftTarget(): Vector3 {
+        public getLeftTarget(): Nullable<Vector3> {
             if (this._rigCameras.length < 1) {
-                return undefined;
+                return null;
             }
             return (<TargetCamera>this._rigCameras[0]).getTarget();
         }
 
-        public getRightTarget(): Vector3 {
+        public getRightTarget(): Nullable<Vector3> {
             if (this._rigCameras.length < 2) {
-                return undefined;
+                return null;
             }
             return (<TargetCamera>this._rigCameras[1]).getTarget();
         }
@@ -670,7 +673,11 @@
             }
 
             while (this._rigCameras.length > 0) {
-                this._rigCameras.pop().dispose();
+                let camera = this._rigCameras.pop();
+
+                if (camera) {
+                    camera.dispose();
+                }
             }
             this.cameraRigMode = mode;
             this._cameraRigParams = {};
@@ -681,8 +688,12 @@
 
             // create the rig cameras, unless none
             if (this.cameraRigMode !== Camera.RIG_MODE_NONE) {
-                this._rigCameras.push(this.createRigCamera(this.name + "_L", 0));
-                this._rigCameras.push(this.createRigCamera(this.name + "_R", 1));
+                let leftCamera = this.createRigCamera(this.name + "_L", 0);
+                let rightCamera = this.createRigCamera(this.name + "_R", 1);
+                if (leftCamera && rightCamera) {
+                    this._rigCameras.push(leftCamera);
+                    this._rigCameras.push(rightCamera);
+                }
             }
 
             switch (this.cameraRigMode) {
@@ -808,7 +819,7 @@
         /**
          * needs to be overridden by children so sub has required properties to be copied
          */
-        public createRigCamera(name: string, cameraIndex: number): Camera {
+        public createRigCamera(name: string, cameraIndex: number): Nullable<Camera> {
             return null;
         }
 

+ 9 - 4
src/Cameras/babylon.followCamera.ts

@@ -18,9 +18,9 @@ module BABYLON {
         public maxCameraSpeed: number = 20;
 
         @serializeAsMeshReference("lockedTargetId")
-        public lockedTarget: AbstractMesh;
+        public lockedTarget: Nullable<AbstractMesh>;
 
-        constructor(name: string, position: Vector3, scene: Scene, lockedTarget?: AbstractMesh) {
+        constructor(name: string, position: Vector3, scene: Scene, lockedTarget: Nullable<AbstractMesh> = null) {
             super(name, position, scene);
 
             this.lockedTarget = lockedTarget;
@@ -72,7 +72,9 @@ module BABYLON {
 
         public _checkInputs(): void {
             super._checkInputs();
-            this.follow(this.lockedTarget);
+            if (this.lockedTarget) {
+                this.follow(this.lockedTarget);
+            }
         }
 
         public getClassName(): string {
@@ -84,12 +86,15 @@ module BABYLON {
 
         private _cartesianCoordinates: Vector3 = Vector3.Zero();
 
-        constructor(name: string, public alpha: number, public beta: number, public radius: number, public target: AbstractMesh, scene: Scene) {
+        constructor(name: string, public alpha: number, public beta: number, public radius: number, public target: Nullable<AbstractMesh>, scene: Scene) {
             super(name, Vector3.Zero(), scene);
             this.follow();
         }
 
         private follow(): void {
+            if (!this.target) {
+                return;
+            }
             this._cartesianCoordinates.x = this.radius * Math.cos(this.alpha) * Math.cos(this.beta);
             this._cartesianCoordinates.y = this.radius * Math.sin(this.beta);
             this._cartesianCoordinates.z = this.radius * Math.sin(this.alpha) * Math.cos(this.beta);

+ 120 - 53
src/Engine/babylon.engine.ts

@@ -10,8 +10,16 @@
         gl.compileShader(shader);
 
         if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
-            throw new Error(gl.getShaderInfoLog(shader));
+            let log = gl.getShaderInfoLog(shader);
+            if (log) {
+                throw new Error(log);
+            }
+        }
+
+        if (!shader) {
+            throw new Error("Something went wrong while compile the shader.");
         }
+
         return shader;
     };
 
@@ -109,7 +117,7 @@
     }
 
     var partialLoad = (url: string, index: number, loadedImages: any, scene: Scene,
-        onfinish: (images: HTMLImageElement[]) => void, onErrorCallBack: (message?: string, exception?: any) => void = null) => {
+        onfinish: (images: HTMLImageElement[]) => void, onErrorCallBack: Nullable<(message?: string, exception?: any) => void> = null) => {
 
         var img: HTMLImageElement;
 
@@ -143,7 +151,7 @@
     }
 
     var cascadeLoad = (rootUrl: string, scene: Scene,
-        onfinish: (images: HTMLImageElement[]) => void, files: string[], onError: (message?: string, exception?: any) => void = null) => {
+        onfinish: (images: HTMLImageElement[]) => void, files: string[], onError: Nullable<(message?: string, exception?: any) => void> = null) => {
 
         var loadedImages: any = [];
         loadedImages._internalCount = 0;
@@ -269,7 +277,7 @@
     export class Engine {
         public static Instances = new Array<Engine>();
 
-        public static get LastCreatedEngine(): Engine {
+        public static get LastCreatedEngine(): Nullable<Engine> {
             if (Engine.Instances.length === 0) {
                 return null;
             }
@@ -277,7 +285,7 @@
             return Engine.Instances[Engine.Instances.length - 1];
         }
 
-        public static get LastCreatedScene(): Scene {
+        public static get LastCreatedScene(): Nullable<Scene> {
             var lastCreatedEngine = Engine.LastCreatedEngine;
             if (!lastCreatedEngine) {
                 return null;
@@ -685,20 +693,20 @@
         // Cache
         private _internalTexturesCache = new Array<InternalTexture>();
         protected _activeTexture: number;
-        protected _activeTexturesCache: { [key: string]: WebGLTexture } = {};
-        protected _currentEffect: Effect;
-        protected _currentProgram: WebGLProgram;
+        protected _activeTexturesCache: { [key: string]: Nullable<WebGLTexture> } = {};
+        protected _currentEffect: Nullable<Effect>;
+        protected _currentProgram: Nullable<WebGLProgram>;
         private _compiledEffects: { [key: string]: Effect } = {}
         private _vertexAttribArraysEnabled: boolean[] = [];
-        protected _cachedViewport: Viewport;
-        private _cachedVertexArrayObject: WebGLVertexArrayObject;
+        protected _cachedViewport: Nullable<Viewport>;
+        private _cachedVertexArrayObject: Nullable<WebGLVertexArrayObject>;
         protected _cachedVertexBuffers: any;
-        protected _cachedIndexBuffer: WebGLBuffer;
-        protected _cachedEffectForVertexBuffers: Effect;
-        protected _currentRenderTarget: InternalTexture;
+        protected _cachedIndexBuffer: Nullable<WebGLBuffer>;
+        protected _cachedEffectForVertexBuffers: Nullable<Effect>;
+        protected _currentRenderTarget: Nullable<InternalTexture>;
         private _uintIndicesCurrentlySet = false;
-        private _currentBoundBuffer = new Array<WebGLBuffer>();
-        protected _currentFramebuffer: WebGLFramebuffer;
+        private _currentBoundBuffer = new Array<Nullable<WebGLBuffer>>();
+        protected _currentFramebuffer: Nullable<WebGLFramebuffer>;
         private _currentBufferPointers = new Array<BufferPointer>();
         private _currentInstanceLocations = new Array<number>();
         private _currentInstanceBuffers = new Array<WebGLBuffer>();
@@ -723,17 +731,17 @@
 
         // Hardware supported Compressed Textures
         private _texturesSupported = new Array<string>();
-        private _textureFormatInUse: string;
+        private _textureFormatInUse: Nullable<string>;
 
         public get texturesSupported(): Array<string> {
             return this._texturesSupported;
         }
 
-        public get textureFormatInUse(): string {
+        public get textureFormatInUse(): Nullable<string> {
             return this._textureFormatInUse;
         }
 
-        public get currentViewport(): Viewport {
+        public get currentViewport(): Nullable<Viewport> {
             return this._cachedViewport;
         }
 
@@ -762,7 +770,7 @@
          * @param options - further options to be sent to the getContext function
          */
         constructor(canvasOrContext: HTMLCanvasElement | WebGLRenderingContext, antialias?: boolean, options?: EngineOptions, adaptToDeviceRatio = false) {
-            var canvas: HTMLCanvasElement;
+            let canvas: Nullable<HTMLCanvasElement> = null;
             Engine.Instances.push(this);
 
             if (!canvasOrContext) {
@@ -801,7 +809,7 @@
 
                 this._deterministicLockstep = options.deterministicLockstep;
                 this._lockstepMaxSteps = options.lockstepMaxSteps;
-                this._doNotHandleContextLost = options.doNotHandleContextLost;
+                this._doNotHandleContextLost = options.doNotHandleContextLost ? true : false;
 
                 // GL
                 if (!options.disableWebGL2Support) {
@@ -919,7 +927,7 @@
             this._hardwareScalingLevel = adaptToDeviceRatio ? 1.0 / Math.min(limitDeviceRatio, window.devicePixelRatio || 1.0) : 1.0;
             this.resize();
 
-            this._isStencilEnable = options.stencil;
+            this._isStencilEnable = options.stencil ? true : false;
             this._initGLContext();
 
             if (canvas) {
@@ -936,7 +944,7 @@
                     }
 
                     // Pointer lock
-                    if (this.isFullscreen && this._pointerLockRequested) {
+                    if (this.isFullscreen && this._pointerLockRequested && canvas) {
                         canvas.requestPointerLock = canvas.requestPointerLock ||
                             canvas.msRequestPointerLock ||
                             canvas.mozRequestPointerLock ||
@@ -968,7 +976,9 @@
                 document.addEventListener("webkitpointerlockchange", this._onPointerLockChange, false);
 
                 this._onVRDisplayPointerRestricted = () => {
-                    canvas.requestPointerLock();
+                    if (canvas) {
+                        canvas.requestPointerLock();
+                    }
                 }
 
                 this._onVRDisplayPointerUnrestricted = () => {
@@ -1178,7 +1188,10 @@
 
             if (this._gl.getShaderPrecisionFormat) {
                 var highp = this._gl.getShaderPrecisionFormat(this._gl.FRAGMENT_SHADER, this._gl.HIGH_FLOAT);
-                this._caps.highPrecisionShaderSupported = highp.precision !== 0;
+
+                if (highp) {
+                    this._caps.highPrecisionShaderSupported = highp.precision !== 0;
+                }
             }
 
             // Depth buffer
@@ -1204,7 +1217,11 @@
             }
 
             this._workingCanvas = document.createElement("canvas");
-            this._workingContext = this._workingCanvas.getContext("2d");
+            let context = this._workingCanvas.getContext("2d");
+
+            if (context) {
+                this._workingContext = context;
+            }
         }
 
         public resetTextureCache() {
@@ -1466,7 +1483,7 @@
             }
         }
 
-        public clear(color: Color4, backBuffer: boolean, depth: boolean, stencil: boolean = false): void {
+        public clear(color: Nullable<Color4>, backBuffer: boolean, depth: boolean, stencil: boolean = false): void {
             this.applyStates();
 
             var mode = 0;
@@ -1531,7 +1548,7 @@
          * The x, y, width & height are directly passed to the WebGL call
          * @return the current viewport Object (if any) that is being replaced by this call. You can restore this viewport later on to go back to the original state.
          */
-        public setDirectViewport(x: number, y: number, width: number, height: number): Viewport {
+        public setDirectViewport(x: number, y: number, width: number, height: number): Nullable<Viewport> {
             let currentViewport = this._cachedViewport;
             this._cachedViewport = null;
 
@@ -1712,6 +1729,9 @@
             this.bindUnboundFramebuffer(texture._MSAAFramebuffer ? texture._MSAAFramebuffer : texture._framebuffer);
             var gl = this._gl;
             if (texture.isCube) {
+                if (faceIndex === undefined) {
+                    faceIndex = 0;
+                }
                 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture._webGLTexture, 0);
             }
 
@@ -1724,7 +1744,7 @@
             this.wipeCaches();
         }
 
-        private bindUnboundFramebuffer(framebuffer: WebGLFramebuffer) {
+        private bindUnboundFramebuffer(framebuffer: Nullable<WebGLFramebuffer>) {
             if (this._currentFramebuffer !== framebuffer) {
                 this._gl.bindFramebuffer(this._gl.FRAMEBUFFER, framebuffer);
                 this._currentFramebuffer = framebuffer;
@@ -1791,6 +1811,11 @@
         // UBOs
         public createUniformBuffer(elements: number[] | Float32Array): WebGLBuffer {
             var ubo = this._gl.createBuffer();
+
+            if (!ubo) {
+                throw new Error("Unable to create uniform buffer");
+            }
+
             this.bindUniformBuffer(ubo);
 
             if (elements instanceof Float32Array) {
@@ -1807,6 +1832,11 @@
 
         public createDynamicUniformBuffer(elements: number[] | Float32Array): WebGLBuffer {
             var ubo = this._gl.createBuffer();
+
+            if (!ubo) {
+                throw new Error("Unable to create dynamic uniform buffer");
+            }
+
             this.bindUniformBuffer(ubo);
 
             if (elements instanceof Float32Array) {
@@ -1854,6 +1884,11 @@
 
         public createVertexBuffer(vertices: number[] | Float32Array): WebGLBuffer {
             var vbo = this._gl.createBuffer();
+
+            if (!vbo) {
+                throw new Error("Unable to create vertex buffer");
+            }
+
             this.bindArrayBuffer(vbo);
 
             if (vertices instanceof Float32Array) {
@@ -1869,6 +1904,11 @@
 
         public createDynamicVertexBuffer(vertices: number[] | Float32Array): WebGLBuffer {
             var vbo = this._gl.createBuffer();
+
+            if (!vbo) {
+                throw new Error("Unable to create dynamic vertex buffer");
+            }
+
             this.bindArrayBuffer(vbo);
 
             if (vertices instanceof Float32Array) {
@@ -1927,6 +1967,11 @@
 
         public createIndexBuffer(indices: IndicesArray, updatable?: boolean): WebGLBuffer {
             var vbo = this._gl.createBuffer();
+
+            if (!vbo) {
+                throw new Error("Unable to create index buffer");
+            }
+
             this.bindIndexBuffer(vbo);
 
             // Check for 32 bits indices
@@ -1965,14 +2010,14 @@
             return vbo;
         }
 
-        public bindArrayBuffer(buffer: WebGLBuffer): void {
+        public bindArrayBuffer(buffer: Nullable<WebGLBuffer>): void {
             if (!this._vaoRecordInProgress) {
                 this._unbindVertexArrayObject();
             }
             this.bindBuffer(buffer, this._gl.ARRAY_BUFFER);
         }
 
-        public bindUniformBuffer(buffer?: WebGLBuffer): void {
+        public bindUniformBuffer(buffer: Nullable<WebGLBuffer>): void {
             this._gl.bindBuffer(this._gl.UNIFORM_BUFFER, buffer);
         }
 
@@ -1986,14 +2031,14 @@
             this._gl.uniformBlockBinding(shaderProgram, uniformLocation, index);
         };
 
-        private bindIndexBuffer(buffer: WebGLBuffer): void {
+        private bindIndexBuffer(buffer: Nullable<WebGLBuffer>): void {
             if (!this._vaoRecordInProgress) {
                 this._unbindVertexArrayObject();
             }
             this.bindBuffer(buffer, this._gl.ELEMENT_ARRAY_BUFFER);
         }
 
-        private bindBuffer(buffer: WebGLBuffer, target: number): void {
+        private bindBuffer(buffer: Nullable<WebGLBuffer>, target: number): void {
             if (this._vaoRecordInProgress || this._currentBoundBuffer[target] !== buffer) {
                 this._gl.bindBuffer(target, buffer);
                 this._currentBoundBuffer[target] = buffer;
@@ -2197,6 +2242,10 @@
         public createInstancesBuffer(capacity: number): WebGLBuffer {
             var buffer = this._gl.createBuffer();
 
+            if (!buffer) {
+                throw new Error("Unable to create instance buffer");
+            }
+
             buffer.capacity = capacity;
 
             this.bindArrayBuffer(buffer);
@@ -2372,8 +2421,13 @@
             return this._createShaderProgram(vertexShader, fragmentShader, context);
         }
 
-        private _createShaderProgram(vertexShader: WebGLShader, fragmentShader: WebGLShader, context?: WebGLRenderingContext): WebGLProgram {
+        private _createShaderProgram(vertexShader: WebGLShader, fragmentShader: WebGLShader, context: WebGLRenderingContext): WebGLProgram {
             var shaderProgram = context.createProgram();
+
+            if (!shaderProgram) {
+                throw new Error("Unable to create program");
+            }
+
             context.attachShader(shaderProgram, vertexShader);
             context.attachShader(shaderProgram, fragmentShader);
 
@@ -2395,7 +2449,7 @@
             return shaderProgram;
         }
 
-        public getUniforms(shaderProgram: WebGLProgram, uniformsNames: string[]): WebGLUniformLocation[] {
+        public getUniforms(shaderProgram: WebGLProgram, uniformsNames: string[]): Nullable<WebGLUniformLocation>[] {
             var results = [];
 
             for (var index = 0; index < uniformsNames.length; index++) {
@@ -2760,7 +2814,7 @@
          * Current families are astc, dxt, pvrtc, etc2, & etc1.
          * @returns The extension selected.
          */
-        public setTextureFormatToUse(formatsAvailable: Array<string>): string {
+        public setTextureFormatToUse(formatsAvailable: Array<string>): Nullable<string> {
             for (var i = 0, len1 = this.texturesSupported.length; i < len1; i++) {
                 for (var j = 0, len2 = formatsAvailable.length; j < len2; j++) {
                     if (this._texturesSupported[i] === formatsAvailable[j].toLowerCase()) {
@@ -2770,11 +2824,18 @@
             }
             // actively set format to nothing, to allow this to be called more than once
             // and possibly fail the 2nd time
-            return this._textureFormatInUse = null;
+            this._textureFormatInUse = null;
+            return null;
         }
 
         public _createTexture(): WebGLTexture {
-            return this._gl.createTexture();
+            let texture = this._gl.createTexture();
+
+            if (!texture) {
+                throw new Error("Unable to create texture");
+            }
+
+            return texture;
         }
 
         /**
@@ -2796,7 +2857,9 @@
          *
          * @returns {WebGLTexture} for assignment back into BABYLON.Texture
          */
-        public createTexture(urlArg: string, noMipmap: boolean, invertY: boolean, scene: Scene, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, onLoad: () => void = null, onError: () => void = null, buffer: ArrayBuffer | HTMLImageElement = null, fallBack?: InternalTexture, format?: number): InternalTexture {
+        public createTexture(urlArg: Nullable<string>, noMipmap: boolean, invertY: boolean, scene: Nullable<Scene>, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, 
+                            onLoad: Nullable<() => void> = null, onError: Nullable<() => void> = null, 
+                            buffer: Nullable<ArrayBuffer | HTMLImageElement> = null, fallBack: Nullable<InternalTexture> = null, format: Nullable<number> = null): InternalTexture {
             var url = String(urlArg); // assign a new string, so that the original is still available in case of fallback
             var fromData = url.substr(0, 5) === "data:";
             var fromBlob = url.substr(0, 5) === "blob:";
@@ -2848,7 +2911,7 @@
                 }
             };
 
-            var callback: (arrayBuffer: any) => void;
+            var callback: Nullable<(arrayBuffer: any) => void> = null;
 
             // processing for non-image formats
             if (isKTX || isTGA || isDDS) {
@@ -2887,10 +2950,14 @@
 
                 if (!buffer) {
                     Tools.LoadFile(url, data => {
-                        callback(data);
-                    }, null, scene ? scene.database : null, true, onerror);
+                        if (callback) {
+                            callback(data);
+                        }
+                    }, undefined, scene ? scene.database : undefined, true, onerror);
                 } else {
-                    callback(buffer);
+                    if (callback) {
+                        callback(buffer);
+                    }
                 }
                 // image format processing
             } else {
@@ -2947,7 +3014,7 @@
             return texture;
         }
 
-        private _rescaleTexture(source: InternalTexture, destination: InternalTexture, scene: Scene, internalFormat: number, onComplete: () => void): void {
+        private _rescaleTexture(source: InternalTexture, destination: InternalTexture, scene: Nullable<Scene>, internalFormat: number, onComplete: () => void): void {
             let rtt = this.createRenderTargetTexture({
                 width: destination.width,
                 height: destination.height,
@@ -3011,7 +3078,7 @@
             return internalFormat;
         }
 
-        public updateRawTexture(texture: InternalTexture, data: ArrayBufferView, format: number, invertY: boolean, compression: string = null): void {
+        public updateRawTexture(texture: InternalTexture, data: ArrayBufferView, format: number, invertY: boolean, compression: Nullable<string> = null): void {
             var internalFormat = this._getInternalFormat(format);
             this._bindTextureDirectly(this._gl.TEXTURE_2D, texture);
             this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, invertY === undefined ? 1 : (invertY ? 1 : 0));
@@ -3041,7 +3108,7 @@
             texture.isReady = true;
         }
 
-        public createRawTexture(data: ArrayBufferView, width: number, height: number, format: number, generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression: string = null): InternalTexture {
+        public createRawTexture(data: ArrayBufferView, width: number, height: number, format: number, generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression: Nullable<string> = null): InternalTexture {
             var texture = new InternalTexture(this, InternalTexture.DATASOURCE_RAW);
             texture.baseWidth = width;
             texture.baseHeight = height;
@@ -3464,8 +3531,8 @@
             return depthStencilBuffer;
         }
 
-        public updateRenderTargetTextureSampleCount(texture: InternalTexture, samples: number): number {
-            if (this.webGLVersion < 2) {
+        public updateRenderTargetTextureSampleCount(texture: Nullable<InternalTexture>, samples: number): number {
+            if (this.webGLVersion < 2 || !texture) {
                 return 1;
             }
 
@@ -3589,7 +3656,7 @@
             return texture;
         }
 
-        public createPrefilteredCubeTexture(rootUrl: string, scene: Scene, scale: number, offset: number, onLoad: (internalTexture: InternalTexture) => void, onError: (message?: string, exception?: any) => void = null, format?: number, forcedExtension: any = null): InternalTexture {
+        public createPrefilteredCubeTexture(rootUrl: string, scene: Nullable<Scene>, scale: number, offset: number, onLoad: (internalTexture: Nullable<InternalTexture>) => void, onError: Nullable<(message?: string, exception?: any) => void> = null, format?: number, forcedExtension: any = null): InternalTexture {
             var callback = (loadData: any) => {
                 if (!loadData) {
                     if (onLoad) {
@@ -3674,7 +3741,7 @@
             return this.createCubeTexture(rootUrl, scene, null, false, callback, onError, format, forcedExtension);
         }
 
-        public createCubeTexture(rootUrl: string, scene: Scene, files: string[], noMipmap?: boolean, onLoad: (data?: any) => void = null, onError: (message?: string, exception?: any) => void = null, format?: number, forcedExtension: any = null): InternalTexture {
+        public createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad: Nullable<(data?: any) => void> = null, onError: Nullable<(message?: string, exception?: any) => void> = null, format?: number, forcedExtension: any = null): InternalTexture {
             var gl = this._gl;
 
             var texture = new InternalTexture(this, InternalTexture.DATASOURCE_CUBE);
@@ -3866,7 +3933,7 @@
             texture.isReady = true;
         }
 
-        public createRawCubeTexture(data: ArrayBufferView[], size: number, format: number, type: number, generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression: string = null): InternalTexture {
+        public createRawCubeTexture(data: ArrayBufferView[], size: number, format: number, type: number, generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression: Nullable<string> = null): InternalTexture {
             var gl = this._gl;
             var texture = new InternalTexture(this, InternalTexture.DATASOURCE_CUBERAW);
             texture.isCube = true;
@@ -4006,7 +4073,7 @@
             return texture;
         };
 
-        private _prepareWebGLTextureContinuation(texture: InternalTexture, scene: Scene, noMipmap: boolean, isCompressed: boolean, samplingMode: number): void {
+        private _prepareWebGLTextureContinuation(texture: InternalTexture, scene: Nullable<Scene>, noMipmap: boolean, isCompressed: boolean, samplingMode: number): void {
             var gl = this._gl;
             if (!gl) {
                 return;
@@ -4032,7 +4099,7 @@
             texture.onLoadedObservable.clear();
         }
 
-        private _prepareWebGLTexture(texture: InternalTexture, scene: Scene, width: number, height: number, invertY: boolean, noMipmap: boolean, isCompressed: boolean,
+        private _prepareWebGLTexture(texture: InternalTexture, scene: Nullable<Scene>, width: number, height: number, invertY: boolean, noMipmap: boolean, isCompressed: boolean,
             processFunction: (width: number, height: number, continuationCallback: () => void) => boolean, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE): void {
             var potWidth = this.needPOTTextures ? Tools.GetExponentOfTwo(width, this.getCaps().maxTextureSize) : width;
             var potHeight = this.needPOTTextures ? Tools.GetExponentOfTwo(height, this.getCaps().maxTextureSize) : height;
@@ -4166,7 +4233,7 @@
             }
         }
 
-        public _bindTextureDirectly(target: number, texture: InternalTexture): void {
+        public _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>): void {
             if (this._activeTexturesCache[this._activeTexture] !== texture) {
                 this._gl.bindTexture(target, texture ? texture._webGLTexture : null);
                 this._activeTexturesCache[this._activeTexture] = texture;

+ 15 - 15
src/Materials/Textures/babylon.baseTexture.ts

@@ -104,8 +104,8 @@
         public delayLoadState = Engine.DELAYLOADSTATE_NONE;
 
         private _scene: Scene;
-        public _texture: InternalTexture;
-        private _uid: string;
+        public _texture: Nullable<InternalTexture>;
+        private _uid: Nullable<string>;
 
         public get isBlocking(): boolean {
             return true;
@@ -121,15 +121,15 @@
             return this._scene;
         }
 
-        public getTextureMatrix(): Matrix {
+        public getTextureMatrix(): Nullable<Matrix> {
             return null;
         }
 
-        public getReflectionTextureMatrix(): Matrix {
+        public getReflectionTextureMatrix(): Nullable<Matrix> {
             return null;
         }
 
-        public getInternalTexture(): InternalTexture {
+        public getInternalTexture(): Nullable<InternalTexture> {
             return this._texture;
         }
 
@@ -151,11 +151,11 @@
         }
 
         public getSize(): ISize {
-            if (this._texture.width) {
+            if (this._texture && this._texture.width) {
                 return new Size(this._texture.width, this._texture.height);
             }
 
-            if (this._texture._size) {
+            if (this._texture && this._texture._size) {
                 return new Size(this._texture._size, this._texture._size);
             }
 
@@ -180,7 +180,7 @@
             return false;
         }
 
-        public _getFromCache(url: string, noMipmap: boolean, sampling?: number): InternalTexture {
+        public _getFromCache(url: Nullable<string>, noMipmap: boolean, sampling?: number): Nullable<InternalTexture> {
             var texturesCache = this._scene.getEngine().getLoadedTexturesCache();
             for (var index = 0; index < texturesCache.length; index++) {
                 var texturesCacheEntry = texturesCache[index];
@@ -203,7 +203,7 @@
         public delayLoad(): void {
         }
 
-        public clone(): BaseTexture {
+        public clone(): Nullable<BaseTexture> {
             return null;
         }
 
@@ -223,7 +223,7 @@
             return (this._texture.format !== undefined) ? this._texture.format : Engine.TEXTUREFORMAT_RGBA;
         }
 
-        public readPixels(faceIndex = 0): ArrayBufferView {
+        public readPixels(faceIndex = 0): Nullable<ArrayBufferView> {
             if (!this._texture) {
                 return null;
             }
@@ -245,7 +245,7 @@
             }
         }
 
-        public get sphericalPolynomial(): SphericalPolynomial {
+        public get sphericalPolynomial(): Nullable<SphericalPolynomial> {
             if (!this._texture || !Internals.CubeMapToSphericalPolynomialTools || !this.isReady()) {
                 return null;
             }
@@ -258,27 +258,27 @@
             return this._texture._sphericalPolynomial;
         }
 
-        public set sphericalPolynomial(value: SphericalPolynomial) {
+        public set sphericalPolynomial(value: Nullable<SphericalPolynomial>) {
             if (this._texture) {
                 this._texture._sphericalPolynomial = value;
             }
         }
 
-        public get _lodTextureHigh(): BaseTexture {
+        public get _lodTextureHigh(): Nullable<BaseTexture> {
             if (this._texture) {
                 return this._texture._lodTextureHigh;
             }
             return null;
         }
 
-        public get _lodTextureMid(): BaseTexture {
+        public get _lodTextureMid(): Nullable<BaseTexture> {
             if (this._texture) {
                 return this._texture._lodTextureMid;
             }
             return null;
         }
 
-        public get _lodTextureLow(): BaseTexture {
+        public get _lodTextureLow(): Nullable<BaseTexture> {
             if (this._texture) {
                 return this._texture._lodTextureLow;
             }

+ 17 - 15
src/Materials/Textures/babylon.internalTexture.ts

@@ -29,37 +29,37 @@ module BABYLON {
 
         // Private
         public _dataSource = InternalTexture.DATASOURCE_UNKNOWN;
-        public _buffer: ArrayBuffer | HTMLImageElement;
+        public _buffer: Nullable<ArrayBuffer | HTMLImageElement>;
         public _bufferView: ArrayBufferView;
         public _bufferViewArray: ArrayBufferView[];
         public _size: number;
         public _extension: string;
-        public _files: string[];
+        public _files: Nullable<string[]>;
         public _workingCanvas: HTMLCanvasElement;
         public _workingContext: CanvasRenderingContext2D;
-        public _framebuffer: WebGLFramebuffer;
+        public _framebuffer: Nullable<WebGLFramebuffer>;
         public _depthStencilBuffer: WebGLRenderbuffer;
         public _MSAAFramebuffer: WebGLFramebuffer;
         public _MSAARenderBuffer: WebGLRenderbuffer;
-        public _cachedCoordinatesMode: number;
-        public _cachedWrapU: number;
-        public _cachedWrapV: number;
-        public _cachedAnisotropicFilteringLevel: number;
+        public _cachedCoordinatesMode: Nullable<number>;
+        public _cachedWrapU: Nullable<number>;
+        public _cachedWrapV: Nullable<number>;
+        public _cachedAnisotropicFilteringLevel: Nullable<number>;
         public _isDisabled: boolean;
-        public _compression: string;
+        public _compression: Nullable<string>;
         public _generateStencilBuffer: boolean;
         public _generateDepthBuffer: boolean;
-        public _sphericalPolynomial: BABYLON.SphericalPolynomial;
+        public _sphericalPolynomial: Nullable<SphericalPolynomial>;
         public _lodGenerationScale: number;
         public _lodGenerationOffset: number;
         // The following three fields helps sharing generated fixed LODs for texture filtering
         // In environment not supporting the textureLOD extension like EDGE. They are for internal use only.
         // They are at the level of the gl texture to benefit from the cache.
-        public _lodTextureHigh: BABYLON.BaseTexture;
-        public _lodTextureMid: BABYLON.BaseTexture;
-        public _lodTextureLow: BABYLON.BaseTexture;
+        public _lodTextureHigh: BaseTexture;
+        public _lodTextureMid: BaseTexture;
+        public _lodTextureLow: BaseTexture;
 
-        public _webGLTexture: WebGLTexture;
+        public _webGLTexture: Nullable<WebGLTexture>;
         public _references: number = 1;
         private _engine: Engine;
 
@@ -101,7 +101,7 @@ module BABYLON {
                 case InternalTexture.DATASOURCE_URL:
                     proxy = this._engine.createTexture(this.url, !this.generateMipMaps, this.invertY, null, this.samplingMode, () => {
                         this.isReady = true;
-                    }, null, this._buffer, null, this.format); 
+                    }, null, this._buffer, undefined, this.format); 
                     proxy._swapAndDie(this);
                     return;
 
@@ -159,7 +159,9 @@ module BABYLON {
 
                 case InternalTexture.DATASOURCE_CUBEPREFILTERED:
                     proxy = this._engine.createPrefilteredCubeTexture(this.url, null, this._lodGenerationScale, this._lodGenerationOffset, (proxy) => {
-                        proxy._swapAndDie(this);
+                        if (proxy) {
+                            proxy._swapAndDie(this);
+                        }
                         
                         this.isReady = true;
                     }, null, this.format, this._extension);

+ 44 - 21
src/Materials/Textures/babylon.renderTargetTexture.ts

@@ -25,7 +25,7 @@
         /**
         * Use this list to define the list of mesh you want to render.
         */
-        public renderList = new Array<AbstractMesh>();
+        public renderList: Nullable<Array<AbstractMesh>> = new Array<AbstractMesh>();
         public renderParticles = true;
         public renderSprites = false;
         public coordinatesMode = Texture.PROJECTION_MODE;
@@ -34,7 +34,7 @@
         public useCameraPostProcesses: boolean;
         public ignoreCameraViewport: boolean = false;
 
-        private _postProcessManager: PostProcessManager;
+        private _postProcessManager: Nullable<PostProcessManager>;
         private _postProcesses: PostProcess[];
 
         // Events
@@ -123,7 +123,7 @@
             this.name = name;
             this.isRenderTarget = true;
             this._size = size;
-            this._generateMipMaps = generateMipMaps;
+            this._generateMipMaps = generateMipMaps ? true : false;
             this._doNotChangeAspectRatio = doNotChangeAspectRatio;
 
             // Rendering groups
@@ -200,7 +200,6 @@
             if (dispose) {
                 for (var postProcess of this._postProcesses) {
                     postProcess.dispose();
-                    postProcess = null;
                 }
             }
 
@@ -273,7 +272,7 @@
             this._size = size;
         }
 
-        public render(useCameraPostProcess?: boolean, dumpForDebug?: boolean) {
+        public render(useCameraPostProcess: boolean = false, dumpForDebug: boolean = false) {
             var scene = this.getScene();
             var engine = scene.getEngine();
 
@@ -285,7 +284,10 @@
                 this.renderList = [];
                 for (var index = 0; index < this._waitingRenderList.length; index++) {
                     var id = this._waitingRenderList[index];
-                    this.renderList.push(scene.getMeshByID(id));
+                    let mesh = scene.getMeshByID(id);
+                    if (mesh) {
+                        this.renderList.push(mesh);
+                    }
                 }
 
                 delete this._waitingRenderList;
@@ -293,7 +295,11 @@
 
             // Is predicate defined?
             if (this.renderListPredicate) {
-                this.renderList.splice(0); // Clear previous renderList
+                if (this.renderList) {
+                    this.renderList.splice(0); // Clear previous renderList
+                } else {
+                    this.renderList = [];
+                }
 
                 var sceneMeshes = this.getScene().meshes;
 
@@ -309,7 +315,7 @@
 
             // Set custom projection.
             // Needs to be before binding to prevent changing the aspect ratio.
-            let camera: Camera;
+            let camera: Nullable<Camera>;
             if (this.activeCamera) {
                 camera = this.activeCamera;
                 engine.setViewport(this.activeCamera.viewport, this._size, this._size);
@@ -320,7 +326,9 @@
             }
             else {
                 camera = scene.activeCamera;
-                engine.setViewport(scene.activeCamera.viewport, this._size, this._size);
+                if (camera) {
+                    engine.setViewport(camera.viewport, this._size, this._size);
+                }
             }
 
             // Prepare renderingManager
@@ -342,7 +350,7 @@
                     mesh._preActivateForIntermediateRendering(sceneRenderId);
 
                     let isMasked;
-                    if (!this.renderList) {
+                    if (!this.renderList && camera) {
                         isMasked = ((mesh.layerMask & camera.layerMask) === 0);
                     } else {
                         isMasked = false;
@@ -385,10 +393,12 @@
 
             this.onAfterUnbindObservable.notifyObservers(this);
 
-            if (this.activeCamera && this.activeCamera !== scene.activeCamera) {
-                scene.setTransformMatrix(scene.activeCamera.getViewMatrix(), scene.activeCamera.getProjectionMatrix(true));
+            if (scene.activeCamera) {
+                if (this.activeCamera && this.activeCamera !== scene.activeCamera) {
+                    scene.setTransformMatrix(scene.activeCamera.getViewMatrix(), scene.activeCamera.getProjectionMatrix(true));
+                }
+                engine.setViewport(scene.activeCamera.viewport);
             }
-            engine.setViewport(scene.activeCamera.viewport);
 
             scene.resetCachedMaterial();
         }
@@ -397,12 +407,18 @@
             var scene = this.getScene();
             var engine = scene.getEngine();
 
+            if (!this._texture) {
+                return;
+            }
+
             // Bind
             if (this._postProcessManager) {
                 this._postProcessManager._prepareFrame(this._texture, this._postProcesses);
             }
             else if (!useCameraPostProcess || !scene.postProcessManager._prepareFrame(this._texture)) {
-                engine.bindFramebuffer(this._texture, this.isCube ? faceIndex : undefined, undefined, undefined, this.ignoreCameraViewport);
+                if (this._texture) {
+                    engine.bindFramebuffer(this._texture, this.isCube ? faceIndex : undefined, undefined, undefined, this.ignoreCameraViewport);
+                }
             }
 
             this.onBeforeRenderObservable.notifyObservers(faceIndex);
@@ -464,9 +480,9 @@
          * @param transparentSortCompareFn The transparent queue comparison function use to sort.
          */
         public setRenderingOrder(renderingGroupId: number,
-            opaqueSortCompareFn: (a: SubMesh, b: SubMesh) => number = null,
-            alphaTestSortCompareFn: (a: SubMesh, b: SubMesh) => number = null,
-            transparentSortCompareFn: (a: SubMesh, b: SubMesh) => number = null): void {
+            opaqueSortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number> = null,
+            alphaTestSortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number> = null,
+            transparentSortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number> = null): void {
 
             this._renderingManager.setRenderingOrder(renderingGroupId,
                 opaqueSortCompareFn,
@@ -505,7 +521,9 @@
 
             // RenderTarget Texture
             newTexture.coordinatesMode = this.coordinatesMode;
-            newTexture.renderList = this.renderList.slice(0);
+            if (this.renderList) {
+                newTexture.renderList = this.renderList.slice(0);
+            }
 
             return newTexture;
         }
@@ -520,8 +538,10 @@
             serializationObject.renderTargetSize = this.getRenderSize();
             serializationObject.renderList = [];
 
-            for (var index = 0; index < this.renderList.length; index++) {
-                serializationObject.renderList.push(this.renderList[index].id);
+            if (this.renderList) {
+                for (var index = 0; index < this.renderList.length; index++) {
+                    serializationObject.renderList.push(this.renderList[index].id);
+                }
             }
 
             return serializationObject;
@@ -529,7 +549,10 @@
 
         // This will remove the attached framebuffer objects. The texture will not be able to be used as render target anymore
         public disposeFramebufferObjects(): void {
-            this.getScene().getEngine()._releaseFramebufferObjects(this.getInternalTexture());
+            let objBuffer = this.getInternalTexture();
+            if (objBuffer) {
+                this.getScene().getEngine()._releaseFramebufferObjects(objBuffer);
+            }
         }
 
         public dispose(): void {

+ 26 - 15
src/Materials/Textures/babylon.texture.ts

@@ -37,7 +37,7 @@
 
         // Members
         @serialize()
-        public url: string;
+        public url: Nullable<string>;
 
         @serialize()
         public uOffset = 0;
@@ -85,10 +85,10 @@
         public _samplingMode: number;
         private _buffer: any;
         private _deleteBuffer: boolean;
-        protected _format: number;
-        private _delayedOnLoad: () => void;
-        private _delayedOnError: () => void;
-        private _onLoadObservable: Observable<Texture>;
+        protected _format: Nullable<number>;
+        private _delayedOnLoad: Nullable<() => void>;
+        private _delayedOnError: Nullable<() => void>;
+        private _onLoadObservable: Nullable<Observable<Texture>>;
 
         protected _isBlocking: boolean = true;
         public set isBlocking(value: boolean) {
@@ -103,17 +103,19 @@
             return this._samplingMode;
         }
 
-        constructor(url: string, scene: Scene, noMipmap: boolean = false, invertY: boolean = true, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, onLoad: () => void = null, onError: (message?: string, esception?: any) => void = null, buffer: any = null, deleteBuffer: boolean = false, format?: number) {
+        constructor(url: Nullable<string>, scene: Scene, noMipmap: boolean = false, invertY: boolean = true, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, onLoad: Nullable<() => void> = null, onError: Nullable<(message?: string, esception?: any) => void> = null, buffer: any = null, deleteBuffer: boolean = false, format?: number) {
             super(scene);
 
-            this.name = url;
+            this.name = url || "";
             this.url = url;
             this._noMipmap = noMipmap;
             this._invertY = invertY;
             this._samplingMode = samplingMode;
             this._buffer = buffer;
             this._deleteBuffer = deleteBuffer;
-            this._format = format;
+            if (format) {
+                this._format = format;
+            }
 
             scene = this.getScene();
 
@@ -142,7 +144,7 @@
 
             if (!this._texture) {
                 if (!scene.useDelayedTextureLoading) {
-                    this._texture = scene.getEngine().createTexture(this.url, noMipmap, invertY, scene, this._samplingMode, load, onError, this._buffer, null, this._format);
+                    this._texture = scene.getEngine().createTexture(this.url, noMipmap, invertY, scene, this._samplingMode, load, onError, this._buffer, undefined, this._format);
                     if (deleteBuffer) {
                         delete this._buffer;
                     }
@@ -182,9 +184,16 @@
                 }
             } else {
                 if (this._texture.isReady) {
-                    Tools.SetImmediate(() => this._delayedOnLoad());
+                    Tools.SetImmediate(() => {
+                        if (!this._delayedOnLoad) {
+                            return;
+                        }
+                        this._delayedOnLoad();
+                    });
                 } else {
-                    this._texture.onLoadedObservable.add(this._delayedOnLoad);
+                    if (this._delayedOnLoad) {
+                        this._texture.onLoadedObservable.add(this._delayedOnLoad);
+                    }
                 }
             }
         }
@@ -327,7 +336,7 @@
 
         public clone(): Texture {
             return SerializationHelper.Clone(() => {
-                return new Texture(this._texture.url, this.getScene(), this._noMipmap, this._invertY, this._samplingMode);
+                return new Texture(this._texture ? this._texture.url : null, this.getScene(), this._noMipmap, this._invertY, this._samplingMode);
             }, this);
         }
 
@@ -366,11 +375,12 @@
         }
 
         // Statics
-        public static CreateFromBase64String(data: string, name: string, scene: Scene, noMipmap?: boolean, invertY?: boolean, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, onLoad: () => void = null, onError: () => void = null, format: number = Engine.TEXTUREFORMAT_RGBA): Texture {
+        public static CreateFromBase64String(data: string, name: string, scene: Scene, noMipmap?: boolean, invertY?: boolean, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, 
+                                            onLoad: Nullable<() => void> = null, onError: Nullable<() => void> = null, format: number = Engine.TEXTUREFORMAT_RGBA): Texture {
             return new Texture("data:" + name, scene, noMipmap, invertY, samplingMode, onLoad, onError, data, false, format);
         }
 
-        public static Parse(parsedTexture: any, scene: Scene, rootUrl: string): BaseTexture {
+        public static Parse(parsedTexture: any, scene: Scene, rootUrl: string): Nullable<BaseTexture> {
             if (parsedTexture.customType) {
                 var customTexture = Tools.Instantiate(parsedTexture.customType);
                 // Update Sampling Mode
@@ -435,7 +445,8 @@
             return texture;
         }
 
-        public static LoadFromDataString(name: string, buffer: any, scene: Scene, deleteBuffer: boolean = false, noMipmap: boolean = false, invertY: boolean = true, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, onLoad: () => void = null, onError: (message?: string, exception?: any) => void = null, format: number = Engine.TEXTUREFORMAT_RGBA): Texture {
+        public static LoadFromDataString(name: string, buffer: any, scene: Scene, deleteBuffer: boolean = false, noMipmap: boolean = false, invertY: boolean = true, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, 
+                                    onLoad: Nullable<() => void> = null, onError: Nullable<(message?: string, exception?: any) => void> = null, format: number = Engine.TEXTUREFORMAT_RGBA): Texture {
             if (name.substr(0, 5) !== "data:") {
                 name = "data:" + name;
             }

+ 5 - 5
src/Materials/babylon.uniformBuffer.ts

@@ -2,10 +2,10 @@ module BABYLON {
 
     export class UniformBuffer {
         private _engine: Engine;
-        private _buffer: WebGLBuffer;
+        private _buffer: Nullable<WebGLBuffer>;
         private _data: number[];
         private _bufferData: Float32Array;
-        private _dynamic: boolean;
+        private _dynamic?: boolean;
         private _uniformLocations: { [key:string]:number; };
         private _uniformSizes: { [key:string]:number; };
         private _uniformLocationPointer: number;
@@ -182,7 +182,7 @@ module BABYLON {
          * update the underlying WebGL uniform buffer to the GPU.
          */
         public isDynamic(): boolean {
-            return this._dynamic;
+            return this._dynamic !== undefined;
         }
 
         /**
@@ -195,7 +195,7 @@ module BABYLON {
         /**
          * The underlying WebGL Uniform buffer.
          */
-        public getBuffer(): WebGLBuffer {
+        public getBuffer(): Nullable<WebGLBuffer> {
             return this._buffer;
         }
 
@@ -600,7 +600,7 @@ module BABYLON {
         public bindToEffect(effect: Effect, name: string): void {
             this._currentEffect = effect;
 
-            if (this._noUBO) {
+            if (this._noUBO || !this._buffer) {
                 return;
             }
             

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

@@ -335,7 +335,7 @@
         public actionManager: ActionManager;
 
         // Physics
-        public physicsImpostor: BABYLON.PhysicsImpostor;
+        public physicsImpostor: Nullable<PhysicsImpostor>;
 
         // Collisions
         private _checkCollisions = false;

+ 2 - 2
src/PostProcess/babylon.passPostProcess.ts

@@ -1,7 +1,7 @@
 module BABYLON {
     export class PassPostProcess extends PostProcess {    
-        constructor(name: string, options: number | PostProcessOptions, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT) {
-            super(name, "pass", null, null, options, camera, samplingMode, engine, reusable, null, textureType);
+        constructor(name: string, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT) {
+            super(name, "pass", null, null, options, camera, samplingMode, engine, reusable, undefined, textureType);
         }
     }
 } 

+ 15 - 13
src/PostProcess/babylon.postProcess.ts

@@ -137,7 +137,8 @@
             return this._texelSize;
         }
 
-        constructor(public name: string, fragmentUrl: string, parameters: string[], samplers: string[], options: number | PostProcessOptions, camera: Camera, samplingMode: number = Texture.NEAREST_SAMPLINGMODE, engine?: Engine, reusable?: boolean, defines?: string, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT, vertexUrl: string = "postprocess", indexParameters?: any, blockCompilation = false) {
+        constructor(public name: string, fragmentUrl: string, parameters: Nullable<string[]>, samplers: Nullable<string[]>, options: number | PostProcessOptions, camera: Nullable<Camera>, 
+                    samplingMode: number = Texture.NEAREST_SAMPLINGMODE, engine?: Engine, reusable?: boolean, defines?: string, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT, vertexUrl: string = "postprocess", indexParameters?: any, blockCompilation = false) {
             if (camera != null) {
                 this._camera = camera;
                 this._scene = camera.getScene();
@@ -146,7 +147,7 @@
 
                 this._scene.postProcesses.push(this);
             }
-            else {
+            else if (engine) {
                 this._engine = engine;
                 this._engine.postProcesses.push(this);
             }
@@ -195,7 +196,7 @@
                 uniforms || this._parameters,
                 samplers || this._samplers, 
                 defines !== undefined ? defines : "",
-                null,
+                undefined,
                 onCompiled,
                 onError,
                 indexParameters || this._indexParameters
@@ -212,18 +213,19 @@
         }
 
         public activate(camera: Camera, sourceTexture?: InternalTexture, forceDepthStencil?: boolean): void {            
-            if (!this._shareOutputWithPostProcess && !this._forcedOutputTexture) {
-                camera = camera || this._camera;
+            camera = camera || this._camera;
+            
+            var scene = camera.getScene();
+            var engine = scene.getEngine();
+            var maxSize = engine.getCaps().maxTextureSize;
 
-                var scene = camera.getScene();
-                var engine = scene.getEngine();
-                var maxSize = engine.getCaps().maxTextureSize;
+            var requiredWidth = ((sourceTexture ? sourceTexture.width : this._engine.getRenderWidth(true)) * <number>this._options) | 0;
+            var requiredHeight = ((sourceTexture ? sourceTexture.height : this._engine.getRenderHeight(true)) * <number>this._options) | 0;
 
-                var requiredWidth = ((sourceTexture ? sourceTexture.width : this._engine.getRenderWidth(true)) * <number>this._options) | 0;
-                var requiredHeight = ((sourceTexture ? sourceTexture.height : this._engine.getRenderHeight(true)) * <number>this._options) | 0;
+            var desiredWidth = ((<PostProcessOptions>this._options).width || requiredWidth);
+            var desiredHeight = (<PostProcessOptions>this._options).height || requiredHeight;
 
-                var desiredWidth = ((<PostProcessOptions>this._options).width || requiredWidth);
-                var desiredHeight = (<PostProcessOptions>this._options).height || requiredHeight;
+            if (!this._shareOutputWithPostProcess && !this._forcedOutputTexture) {
 
                 if (this.adaptScaleToCurrentViewport) {
                     let currentViewport = engine.currentViewport;
@@ -330,7 +332,7 @@
             return this.width / this.height;
         }
         
-        public apply(): Effect {
+        public apply(): Nullable<Effect> {
             // Check
             if (!this._effect || !this._effect.isReady())
                 return null;

+ 1 - 1
src/PostProcess/babylon.postProcessManager.ts

@@ -48,7 +48,7 @@
         }
         
         // Methods
-        public _prepareFrame(sourceTexture?: InternalTexture, postProcesses?: PostProcess[]): boolean {
+        public _prepareFrame(sourceTexture: Nullable<InternalTexture> = null, postProcesses: Nullable<PostProcess[]> = null): boolean {
             var postProcesses = postProcesses || this._scene.activeCamera._postProcesses;
 
             if (postProcesses.length === 0 || !this._scene.postProcessesEnabled) {

+ 21 - 17
src/Rendering/babylon.renderingGroup.ts

@@ -8,8 +8,8 @@
         private _particleSystems = new SmartArray<IParticleSystem>(256);
         private _spriteManagers = new SmartArray<SpriteManager>(256);        
 
-        private _opaqueSortCompareFn: (a: SubMesh, b: SubMesh) => number;
-        private _alphaTestSortCompareFn: (a: SubMesh, b: SubMesh) => number;
+        private _opaqueSortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number>;
+        private _alphaTestSortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number>;
         private _transparentSortCompareFn: (a: SubMesh, b: SubMesh) => number;
         
         private _renderOpaque: (subMeshes: SmartArray<SubMesh>) => void;
@@ -24,7 +24,7 @@
          * Set the opaque sort comparison function.
          * If null the sub meshes will be render in the order they were created 
          */
-        public set opaqueSortCompareFn(value: (a: SubMesh, b: SubMesh) => number) {
+        public set opaqueSortCompareFn(value: Nullable<(a: SubMesh, b: SubMesh) => number>) {
             this._opaqueSortCompareFn = value;
             if (value) {
                 this._renderOpaque = this.renderOpaqueSorted;
@@ -38,7 +38,7 @@
          * Set the alpha test sort comparison function.
          * If null the sub meshes will be render in the order they were created 
          */
-        public set alphaTestSortCompareFn(value: (a: SubMesh, b: SubMesh) => number) {
+        public set alphaTestSortCompareFn(value: Nullable<(a: SubMesh, b: SubMesh) => number>) {
             this._alphaTestSortCompareFn = value;
             if (value) {
                 this._renderAlphaTest = this.renderAlphaTestSorted;
@@ -52,7 +52,7 @@
          * Set the transparent sort comparison function.
          * If null the sub meshes will be render in the order they were created 
          */
-        public set transparentSortCompareFn(value: (a: SubMesh, b: SubMesh) => number) {
+        public set transparentSortCompareFn(value: Nullable<(a: SubMesh, b: SubMesh) => number>) {
             if (value) {
                 this._transparentSortCompareFn = value;
             }
@@ -70,9 +70,9 @@
          * @param transparentSortCompareFn The transparent sort comparison function. If null back to front + alpha index sort is applied
          */
         constructor(public index: number, scene: Scene,
-            opaqueSortCompareFn: (a: SubMesh, b: SubMesh) => number = null,
-            alphaTestSortCompareFn: (a: SubMesh, b: SubMesh) => number = null,
-            transparentSortCompareFn: (a: SubMesh, b: SubMesh) => number = null) {
+            opaqueSortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number> = null,
+            alphaTestSortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number> = null,
+            transparentSortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number> = null) {
             this._scene = scene;
 
             this.opaqueSortCompareFn = opaqueSortCompareFn;
@@ -85,7 +85,7 @@
          * @param customRenderFunction Used to override the default render behaviour of the group.
          * @returns true if rendered some submeshes.
          */
-        public render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>) => void, renderSprites: boolean, renderParticles: boolean, activeMeshes: AbstractMesh[]): void {
+        public render(customRenderFunction: Nullable<(opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>) => void>, renderSprites: boolean, renderParticles: boolean, activeMeshes: Nullable<AbstractMesh[]>): void {
             if (customRenderFunction) {
                 customRenderFunction(this._opaqueSubMeshes, this._alphaTestSubMeshes, this._transparentSubMeshes, this._depthOnlySubMeshes);
                 return;
@@ -154,7 +154,7 @@
          * @param subMeshes The submeshes to render
          */
         private renderOpaqueSorted(subMeshes: SmartArray<SubMesh>): void {
-            return RenderingGroup.renderSorted(subMeshes, this._opaqueSortCompareFn, this._scene.activeCamera.globalPosition, false);
+            return RenderingGroup.renderSorted(subMeshes, this._opaqueSortCompareFn, this._scene.activeCamera, false);
         }
 
         /**
@@ -162,7 +162,7 @@
          * @param subMeshes The submeshes to render
          */
         private renderAlphaTestSorted(subMeshes: SmartArray<SubMesh>): void {
-            return RenderingGroup.renderSorted(subMeshes, this._alphaTestSortCompareFn, this._scene.activeCamera.globalPosition, false);
+            return RenderingGroup.renderSorted(subMeshes, this._alphaTestSortCompareFn, this._scene.activeCamera, false);
         }
 
         /**
@@ -170,7 +170,7 @@
          * @param subMeshes The submeshes to render
          */
         private renderTransparentSorted(subMeshes: SmartArray<SubMesh>): void {
-            return RenderingGroup.renderSorted(subMeshes, this._transparentSortCompareFn, this._scene.activeCamera.globalPosition, true);
+            return RenderingGroup.renderSorted(subMeshes, this._transparentSortCompareFn, this._scene.activeCamera, true);
         }
 
         /**
@@ -180,9 +180,10 @@
          * @param cameraPosition The camera position use to preprocess the submeshes to help sorting
          * @param transparent Specifies to activate blending if true
          */
-        private static renderSorted(subMeshes: SmartArray<SubMesh>, sortCompareFn: (a: SubMesh, b: SubMesh) => number, cameraPosition: Vector3, transparent: boolean): void {
+        private static renderSorted(subMeshes: SmartArray<SubMesh>, sortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number>, camera: Nullable<Camera>, transparent: boolean): void {
             let subIndex = 0;
             let subMesh: SubMesh;
+            let cameraPosition = camera ? camera.globalPosition : Vector3.Zero();
             for (; subIndex < subMeshes.length; subIndex++) {
                 subMesh = subMeshes.data[subIndex];
                 subMesh._alphaIndex = subMesh.getMesh().alphaIndex;
@@ -190,7 +191,10 @@
             }
 
             let sortedArray = subMeshes.data.slice(0, subMeshes.length);
-            sortedArray.sort(sortCompareFn);
+
+            if (sortCompareFn) {
+                sortedArray.sort(sortCompareFn);
+            }
 
             for (subIndex = 0; subIndex < sortedArray.length; subIndex++) {
                 subMesh = sortedArray[subIndex];
@@ -345,7 +349,7 @@
             this._particleSystems.push(particleSystem);
         }
 
-        private _renderParticles(activeMeshes: AbstractMesh[]): void {
+        private _renderParticles(activeMeshes: Nullable<AbstractMesh[]>): void {
             if (this._particleSystems.length === 0) {
                 return;
             }
@@ -356,7 +360,7 @@
             for (var particleIndex = 0; particleIndex < this._scene._activeParticleSystems.length; particleIndex++) {
                 var particleSystem = this._scene._activeParticleSystems.data[particleIndex];
 
-                if ((activeCamera.layerMask & particleSystem.layerMask) === 0) {
+                if ((activeCamera && activeCamera.layerMask & particleSystem.layerMask) === 0) {
                     continue;
                 }
 
@@ -379,7 +383,7 @@
             for (var id = 0; id < this._spriteManagers.length; id++) {
                 var spriteManager = this._spriteManagers.data[id];
 
-                if (((activeCamera.layerMask & spriteManager.layerMask) !== 0)) {
+                if (((activeCamera && activeCamera.layerMask & spriteManager.layerMask) !== 0)) {
                     spriteManager.render();
                 }
             }

+ 13 - 13
src/Rendering/babylon.renderingManager.ts

@@ -33,10 +33,10 @@
         private _currentIndex: number;
 
         private _autoClearDepthStencil: { [id:number]: RenderingManageAutoClearOptions } = {};
-        private _customOpaqueSortCompareFn: { [id:number]: (a: SubMesh, b: SubMesh) => number } = {};
-        private _customAlphaTestSortCompareFn: { [id:number]: (a: SubMesh, b: SubMesh) => number } = {};
-        private _customTransparentSortCompareFn: { [id:number]: (a: SubMesh, b: SubMesh) => number } = {};
-        private _renderinGroupInfo: RenderingGroupInfo = null;
+        private _customOpaqueSortCompareFn: { [id:number]: Nullable<(a: SubMesh, b: SubMesh) => number> } = {};
+        private _customAlphaTestSortCompareFn: { [id:number]: Nullable<(a: SubMesh, b: SubMesh) => number> } = {};
+        private _customTransparentSortCompareFn: { [id:number]: Nullable<(a: SubMesh, b: SubMesh) => number> } = {};
+        private _renderinGroupInfo: Nullable<RenderingGroupInfo> = null;
 
         constructor(scene: Scene) {
             this._scene = scene;
@@ -55,12 +55,12 @@
             this._depthStencilBufferAlreadyCleaned = true;
         }
 
-        public render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>) => void,
-            activeMeshes: AbstractMesh[], renderParticles: boolean, renderSprites: boolean): void {          
+        public render(customRenderFunction: Nullable<(opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>) => void>,
+            activeMeshes: Nullable<AbstractMesh[]>, renderParticles: boolean, renderSprites: boolean): void {          
                   
             // Check if there's at least on observer on the onRenderingGroupObservable and initialize things to fire it
             let observable = this._scene.onRenderingGroupObservable.hasObservers() ? this._scene.onRenderingGroupObservable : null;
-            let info: RenderingGroupInfo = null;
+            let info: Nullable<RenderingGroupInfo> = null;
             if (observable) {
                 if (!this._renderinGroupInfo) {
                     this._renderinGroupInfo = new RenderingGroupInfo();
@@ -90,7 +90,7 @@
                 let renderingGroupMask = 0;
 
                 // Fire PRECLEAR stage
-                if (observable) {
+                if (observable && info) {
                     renderingGroupMask = Math.pow(2, index);
                     info.renderStage = RenderingGroupInfo.STAGE_PRECLEAR;
                     info.renderingGroupId = index;
@@ -105,7 +105,7 @@
                     }
                 }
 
-                if (observable) {
+                if (observable && info) {
                     // Fire PREOPAQUE stage
                     info.renderStage = RenderingGroupInfo.STAGE_PREOPAQUE;
                     observable.notifyObservers(info, renderingGroupMask);
@@ -118,7 +118,7 @@
                     renderingGroup.render(customRenderFunction, renderSprites, renderParticles, activeMeshes);
 
                 // Fire POSTTRANSPARENT stage
-                if (observable) {
+                if (observable && info) {
                     info.renderStage = RenderingGroupInfo.STAGE_POSTTRANSPARENT;
                     observable.notifyObservers(info, renderingGroupMask);
                 }
@@ -190,9 +190,9 @@
          * @param transparentSortCompareFn The transparent queue comparison function use to sort.
          */
         public setRenderingOrder(renderingGroupId: number,
-            opaqueSortCompareFn: (a: SubMesh, b: SubMesh) => number = null,
-            alphaTestSortCompareFn: (a: SubMesh, b: SubMesh) => number = null,
-            transparentSortCompareFn: (a: SubMesh, b: SubMesh) => number = null) {
+            opaqueSortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number> = null,
+            alphaTestSortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number> = null,
+            transparentSortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number> = null) {
 
             this._customOpaqueSortCompareFn[renderingGroupId] = opaqueSortCompareFn;
             this._customAlphaTestSortCompareFn[renderingGroupId] = alphaTestSortCompareFn;

+ 27 - 19
src/Tools/babylon.database.ts

@@ -2,7 +2,7 @@ module BABYLON {
     export class Database {
         private callbackManifestChecked: (check: boolean) => any;
         private currentSceneUrl: string;
-        private db: IDBDatabase;
+        private db: Nullable<IDBDatabase>;
         private _enableSceneOffline: boolean;
         private _enableTexturesOffline: boolean;
         private manifestVersionFound: number;
@@ -163,14 +163,16 @@ module BABYLON {
                     // Initialization of the DB. Creating Scenes & Textures stores
                     request.onupgradeneeded = (event: IDBVersionChangeEvent) => {
                         this.db = (<any>(event.target)).result;
-                        try {
-                            this.db.createObjectStore("scenes", { keyPath: "sceneUrl" });
-                            this.db.createObjectStore("versions", { keyPath: "sceneUrl" });
-                            this.db.createObjectStore("textures", { keyPath: "textureUrl" });
-                        }
-                        catch (ex) {
-                            Tools.Error("Error while creating object stores. Exception: " + ex.message);
-                            handleError();
+                        if (this.db) {
+                            try {
+                                this.db.createObjectStore("scenes", { keyPath: "sceneUrl" });
+                                this.db.createObjectStore("versions", { keyPath: "sceneUrl" });
+                                this.db.createObjectStore("textures", { keyPath: "textureUrl" });
+                            }
+                            catch (ex) {
+                                Tools.Error("Error while creating object stores. Exception: " + ex.message);
+                                handleError();
+                            }
                         }
                     };
                 }
@@ -264,7 +266,9 @@ module BABYLON {
                         }
                     }
 
-                    image.src = blobTextureURL;
+                    if (blobTextureURL) {
+                        image.src = blobTextureURL;
+                    }
                 };
 
                 if (Database.IsUASupportingBlobStorage) { // Create XHR
@@ -275,7 +279,7 @@ module BABYLON {
                     xhr.responseType = "blob";
 
                     xhr.addEventListener("load",() => {
-                        if (xhr.status === 200) {
+                        if (xhr.status === 200 && this.db) {
                             // Blob as response (XHR2)
                             blob = xhr.response;
 
@@ -348,7 +352,7 @@ module BABYLON {
         }
 
         private _loadVersionFromDBAsync(url: string, callback: (version: number) => void, updateInDBCallback: () => void) {
-            if (this.isSupported) {
+            if (this.isSupported && this.db) {
                 var version: any;
                 try {
                     var transaction = this.db.transaction(["versions"]);
@@ -397,7 +401,7 @@ module BABYLON {
         }
 
         private _saveVersionIntoDBAsync(url: string, callback: (version: number) => void) {
-            if (this.isSupported && !this.hasReachedQuota) {
+            if (this.isSupported && !this.hasReachedQuota && this.db) {
                 try {
                     // Open a transaction to the database
                     var transaction = this.db.transaction(["versions"], "readwrite");
@@ -438,7 +442,7 @@ module BABYLON {
             }
         }
 
-        public loadFileFromDB(url: string, sceneLoaded: (data: any) => void, progressCallBack: (data: any) => void, errorCallback: () => void, useArrayBuffer?: boolean) {
+        public loadFileFromDB(url: string, sceneLoaded: (data: any) => void, progressCallBack?: (data: any) => void, errorCallback?: () => void, useArrayBuffer?: boolean) {
             var completeUrl = Database.ReturnFullUrlLocation(url);
 
             var saveAndLoadFile = () => {
@@ -456,13 +460,15 @@ module BABYLON {
                     }
                 }
                 else {
-                    errorCallback();
+                    if (errorCallback) {
+                        errorCallback();
+                    }
                 }
             });
         }
 
         private _loadFileFromDBAsync(url: string, callback: (data?: any) => void, notInDBCallback: () => void, useArrayBuffer?: boolean) {
-            if (this.isSupported) {
+            if (this.isSupported && this.db) {
                 var targetStore: string;
                 if (url.indexOf(".babylon") !== -1) {
                     targetStore = "scenes";
@@ -504,7 +510,7 @@ module BABYLON {
             }
         }
 
-        private _saveFileIntoDBAsync(url: string, callback: (data?: any) => void, progressCallback: (this: XMLHttpRequestEventTarget, ev: ProgressEvent) => any, useArrayBuffer?: boolean) {
+        private _saveFileIntoDBAsync(url: string, callback: (data?: any) => void, progressCallback?: (this: XMLHttpRequestEventTarget, ev: ProgressEvent) => any, useArrayBuffer?: boolean) {
             if (this.isSupported) {
                 var targetStore: string;
                 if (url.indexOf(".babylon") !== -1) {
@@ -523,7 +529,9 @@ module BABYLON {
                     xhr.responseType = "arraybuffer";
                 }
 
-                xhr.onprogress = progressCallback;
+                if (progressCallback) {
+                    xhr.onprogress = progressCallback;
+                }
 
                 xhr.addEventListener("load",() => {
                     if (xhr.status === 200 || Tools.ValidateXHRData(xhr, !useArrayBuffer ? 1 : 6)) {
@@ -531,7 +539,7 @@ module BABYLON {
                         //fileData = xhr.responseText;
                         fileData = !useArrayBuffer ? xhr.responseText : xhr.response;
 
-                        if (!this.hasReachedQuota) {
+                        if (!this.hasReachedQuota && this.db) {
                             // Open a transaction to the database
                             var transaction = this.db.transaction([targetStore], "readwrite");
 

+ 42 - 26
src/Tools/babylon.tools.ts

@@ -136,6 +136,7 @@
                     pot = Tools.NearestPOT(value);
                     break;
                 case Engine.SCALEMODE_CEILING:
+                default:
                     pot = Tools.CeilingPOT(value);
                     break;
             }
@@ -202,7 +203,7 @@
             return "data:image/png;base64," + output;
         }
 
-        public static ExtractMinAndMaxIndexed(positions: number[] | Float32Array, indices: IndicesArray, indexStart: number, indexCount: number, bias: Vector2 = null): { minimum: Vector3; maximum: Vector3 } {
+        public static ExtractMinAndMaxIndexed(positions: number[] | Float32Array, indices: IndicesArray, indexStart: number, indexCount: number, bias: Nullable<Vector2> = null): { minimum: Vector3; maximum: Vector3 } {
             var minimum = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
             var maximum = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
 
@@ -228,7 +229,7 @@
             };
         }
 
-        public static ExtractMinAndMax(positions: number[] | Float32Array, start: number, count: number, bias: Vector2 = null, stride?: number): { minimum: Vector3; maximum: Vector3 } {
+        public static ExtractMinAndMax(positions: number[] | Float32Array, start: number, count: number, bias: Nullable<Vector2> = null, stride?: number): { minimum: Vector3; maximum: Vector3 } {
             var minimum = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
             var maximum = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
 
@@ -258,7 +259,7 @@
             };
         }
 
-        public static Vector2ArrayFeeder(array: Array<Vector2> | Float32Array): (i: number) => Vector2 {
+        public static Vector2ArrayFeeder(array: Array<Vector2> | Float32Array): (i: number) => Nullable<Vector2> {
             return (index: number) => {
                 let isFloatArray = ((<Float32Array>array).BYTES_PER_ELEMENT !== undefined);
                 let length = isFloatArray ? array.length / 2 : array.length;
@@ -276,7 +277,7 @@
             };
         }
 
-        public static ExtractMinAndMaxVector2(feeder: (index: number) => Vector2, bias: Vector2 = null): { minimum: Vector2; maximum: Vector2 } {
+        public static ExtractMinAndMaxVector2(feeder: (index: number) => Vector2, bias: Nullable<Vector2> = null): { minimum: Vector2; maximum: Vector2 } {
             var minimum = new Vector2(Number.MAX_VALUE, Number.MAX_VALUE);
             var maximum = new Vector2(-Number.MAX_VALUE, -Number.MAX_VALUE);
 
@@ -302,9 +303,9 @@
             };
         }
 
-        public static MakeArray(obj: any, allowsNullUndefined?: boolean): Array<any> {
+        public static MakeArray(obj: any, allowsNullUndefined?: boolean): Nullable<Array<any>> {
             if (allowsNullUndefined !== true && (obj === undefined || obj == null))
-                return undefined;
+                return null;
 
             return Array.isArray(obj) ? obj : [obj];
         }
@@ -402,7 +403,7 @@
             return url;
         }
 
-        public static LoadImage(url: any, onLoad: (img: HTMLImageElement) => void, onError: (message?: string, exception?: any) => void, database: Database): HTMLImageElement {
+        public static LoadImage(url: any, onLoad: (img: HTMLImageElement) => void, onError: (message?: string, exception?: any) => void, database: Nullable<Database>): HTMLImageElement {
             if (url instanceof ArrayBuffer) {
                 url = Tools.EncodeArrayBufferTobase64(url);
             }
@@ -437,7 +438,9 @@
             };
 
             var loadFromIndexedDB = () => {
-                database.loadImageFromDB(url, img);
+                if (database) {
+                    database.loadImageFromDB(url, img);
+                }
             };
 
 
@@ -464,7 +467,7 @@
                             img.src = blobURL;
                         }
                         catch (e) {
-                            img.src = null;
+                            img.src = "";
                         }
                     }
                     else {
@@ -478,7 +481,7 @@
         }
 
         //ANY
-        public static LoadFile(url: string, callback: (data: any) => void, progressCallBack?: (data: any) => void, database?: Database, useArrayBuffer?: boolean, onError?: (request: XMLHttpRequest, exception?: any) => void): void {
+        public static LoadFile(url: string, callback: (data: any) => void, progressCallBack?: (data: any) => void, database?: Database, useArrayBuffer?: boolean, onError?: (request?: XMLHttpRequest, exception?: any) => void): void {
             url = Tools.CleanUrl(url);
 
             url = Tools.PreprocessUrl(url);
@@ -492,12 +495,14 @@
                     request.responseType = "arraybuffer";
                 }
 
-                request.onprogress = progressCallBack;
+                if (progressCallBack) {
+                    request.onprogress = progressCallBack;
+                }
 
                 request.onreadystatechange = () => {
                     // In case of undefined state in some browsers.
                     if (request.readyState === (XMLHttpRequest.DONE || 4)) {
-                        request.onreadystatechange = null;//some browsers have issues where onreadystatechange can be called multiple times with the same value
+                        request.onreadystatechange = () => {};//some browsers have issues where onreadystatechange can be called multiple times with the same value
 
                         if (request.status >= 200 && request.status < 300 || (!Tools.IsWindowObjectExist() && (request.status === 0))) {
                             callback(!useArrayBuffer ? request.responseText : request.response);
@@ -516,7 +521,9 @@
             };
 
             var loadFromIndexedDB = () => {
-                database.loadFileFromDB(url, callback, progressCallBack, noIndexedDB, useArrayBuffer);
+                if (database) {
+                    database.loadFileFromDB(url, callback, progressCallBack, noIndexedDB, useArrayBuffer);
+                }
             };
 
             if (url.indexOf("file:") !== -1) {
@@ -580,7 +587,7 @@
             reader.readAsDataURL(fileToLoad);
         }
 
-        public static ReadFile(fileToLoad: File, callback: (data: any) => void, progressCallBack: (this: MSBaseReader, ev: ProgressEvent) => any, useArrayBuffer?: boolean): void {
+        public static ReadFile(fileToLoad: File, callback: (data: any) => void, progressCallBack?: (this: MSBaseReader, ev: ProgressEvent) => any, useArrayBuffer?: boolean): void {
             var reader = new FileReader();
             reader.onerror = e => {
                 Tools.Log("Error while reading file: " + fileToLoad.name);
@@ -590,7 +597,10 @@
                 //target doesn't have result from ts 1.3
                 callback((<any>e.target)['result']);
             };
-            reader.onprogress = progressCallBack;
+
+            if (progressCallBack) {
+                reader.onprogress = progressCallBack;
+            }
             if (!useArrayBuffer) {
                 // Asynchronous read
                 reader.readAsText(fileToLoad);
@@ -740,13 +750,15 @@
             screenshotCanvas.height = height;
             var context = screenshotCanvas.getContext('2d');
 
-            // Copy the pixels to a 2D canvas
-            var imageData = context.createImageData(width, height);
-            var castData = <any>(imageData.data);
-            castData.set(data);
-            context.putImageData(imageData, 0, 0);
+            if (context) {
+                // Copy the pixels to a 2D canvas
+                var imageData = context.createImageData(width, height);
+                var castData = <any>(imageData.data);
+                castData.set(data);
+                context.putImageData(imageData, 0, 0);
 
-            Tools.EncodeScreenshotCanvasData(successCallback, mimeType);
+                Tools.EncodeScreenshotCanvasData(successCallback, mimeType);
+            }
         }
 
         static EncodeScreenshotCanvasData(successCallback?: (data: string) => void, mimeType: string = "image/png") {
@@ -766,7 +778,9 @@
                     window.document.body.appendChild(a);
 
                     a.addEventListener("click", () => {
-                        a.parentElement.removeChild(a);
+                        if (a.parentElement) {
+                            a.parentElement.removeChild(a);
+                        }
                     });
                     a.click();
 
@@ -833,7 +847,9 @@
             var offsetX = Math.max(0, width - newWidth) / 2;
             var offsetY = Math.max(0, height - newHeight) / 2;
 
-            renderContext.drawImage(engine.getRenderingCanvas(), offsetX, offsetY, newWidth, newHeight);
+            if (renderContext) {
+                renderContext.drawImage(engine.getRenderingCanvas(), offsetX, offsetY, newWidth, newHeight);
+            }
 
             Tools.EncodeScreenshotCanvasData(successCallback, mimeType);
         }
@@ -875,7 +891,7 @@
             }
 
             var scene = camera.getScene();
-            var previousCamera: Camera = null;
+            var previousCamera: Nullable<Camera> = null;
 
             if (scene.activeCamera !== camera) {
                 previousCamera = scene.activeCamera;
@@ -1200,7 +1216,7 @@
             return name;
         }
 
-        public static First<T>(array: Array<T>, predicate: (item: T) => boolean): T {
+        public static First<T>(array: Array<T>, predicate: (item: T) => boolean): Nullable<T> {
             for (let el of array) {
                 if (predicate(el)) {
                     return el;
@@ -1216,7 +1232,7 @@
          * @param object the object to get the class name from
          * @return a string that can have two forms: "moduleName.className" if module was specified when the class' Name was registered or "className" if there was not module specified.
          */
-        public static getFullClassName(object: any, isType: boolean = false): string {
+        public static getFullClassName(object: any, isType: boolean = false): Nullable<string> {
             let className = null;
             let moduleName = null;
 

+ 2 - 2
src/babylon.mixins.ts

@@ -34,7 +34,7 @@ interface WebGLRenderingContext {
     vertexAttribDivisor(index: number, divisor: number): void;
 
     createVertexArray(): any;
-    bindVertexArray(vao: WebGLVertexArrayObject): void;
+    bindVertexArray(vao: Nullable<WebGLVertexArrayObject>): void;
     deleteVertexArray(vao: WebGLVertexArrayObject): void;
 
     blitFramebuffer(srcX0: number, srcY0: number, srcX1: number, srcY1: number, dstX0: number, dstY0: number, dstX1: number, dstY1: number, mask: number, filter: number): void;
@@ -119,7 +119,7 @@ interface WebGLBuffer {
 }
 
 interface WebGLProgram {
-    __SPECTOR_rebuildProgram(vertexSourceCode: string, fragmentSourceCode: string, onCompiled: (program: WebGLProgram) => void, onError: (message: string) => void): void;
+    __SPECTOR_rebuildProgram: Nullable<(vertexSourceCode: string, fragmentSourceCode: string, onCompiled: (program: WebGLProgram) => void, onError: (message: string) => void) => void>;
 }
 
 interface MouseEvent {

+ 18 - 12
src/babylon.node.ts

@@ -24,7 +24,7 @@ module BABYLON {
         public doNotSerialize = false;
 
         public animations = new Array<Animation>();
-        private _ranges: { [name: string]: AnimationRange; } = {};
+        private _ranges: { [name: string]: Nullable<AnimationRange> } = {};
 
         public onReady: (node: Node) => void;
 
@@ -38,10 +38,10 @@ module BABYLON {
         private _scene: Scene;
         public _cache: any;
 
-        private _parentNode: Node;
+        private _parentNode: Nullable<Node>;
         private _children: Node[];
 
-        public set parent(parent: Node) {
+        public set parent(parent: Nullable<Node>) {
             if (this._parentNode === parent) {
                 return;
             }
@@ -63,7 +63,7 @@ module BABYLON {
             }
         }
 
-        public get parent(): Node {
+        public get parent(): Nullable<Node> {
             return this._parentNode;
         }
 
@@ -139,7 +139,7 @@ module BABYLON {
             return this._behaviors;
         }
 
-        public getBehaviorByName(name: string): Behavior<Node> {
+        public getBehaviorByName(name: string): Nullable<Behavior<Node>> {
             for (var behavior of this._behaviors) {
                 if (behavior.name === name) {
                     return behavior;
@@ -181,7 +181,9 @@ module BABYLON {
         }
 
         public _markSyncedWithParent() {
-            this._parentRenderId = this.parent._currentRenderId;
+            if (this.parent) {
+                this._parentRenderId = this.parent._currentRenderId;
+            }
         }
 
         public isSynchronizedWithParent(): boolean {
@@ -343,7 +345,7 @@ module BABYLON {
             }
         }
 
-        public getAnimationByName(name: string): Animation {
+        public getAnimationByName(name: string): Nullable<Animation> {
             for (var i = 0; i < this.animations.length; i++) {
                 var animation = this.animations[i];
 
@@ -373,10 +375,10 @@ module BABYLON {
                     this.animations[i].deleteRange(name, deleteFrames);
                 }
             }
-            this._ranges[name] = undefined; // said much faster than 'delete this._range[name]' 
+            this._ranges[name] = null; // said much faster than 'delete this._range[name]' 
         }
 
-        public getAnimationRange(name: string): AnimationRange {
+        public getAnimationRange(name: string): Nullable<AnimationRange> {
             return this._ranges[name];
         }
 
@@ -384,7 +386,7 @@ module BABYLON {
             var range = this.getAnimationRange(name);
 
             if (!range) {
-                return null;
+                return;
             }
 
             this._scene.beginAnimation(this, range.from, range.to, loop, speedRatio, onAnimationEnd);
@@ -393,10 +395,14 @@ module BABYLON {
         public serializeAnimationRanges(): any {
             var serializationRanges = [];
             for (var name in this._ranges) {
+                var localRange = this._ranges[name];
+                if (!localRange) {
+                    continue;
+                }
                 var range: any = {};
                 range.name = name;
-                range.from = this._ranges[name].from;
-                range.to = this._ranges[name].to;
+                range.from = localRange.from;
+                range.to = localRange.to;
                 serializationRanges.push(range);
             }
             return serializationRanges;

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 191 - 141
src/babylon.scene.ts


+ 3 - 0
src/babylon.types.ts

@@ -0,0 +1,3 @@
+type Nullable<T> = T | null;
+type float = number;
+type int = number;

+ 2 - 1
src/tsconfig.json

@@ -9,6 +9,7 @@
     "lib": ["dom", "es2015.promise", "es5"],
     "noImplicitReturns": true,
     "noImplicitThis": true,
-    "noUnusedLocals": true
+    "noUnusedLocals": true,
+    "strictNullChecks": true
   }
 }