ソースを参照

strict null check: step 2

David Catuhe 7 年 前
コミット
03dcc7230c

+ 4 - 2
Tools/Gulp/gulpfile.js

@@ -47,7 +47,8 @@ var tsConfig = {
     noImplicitAny: true,
     noImplicitReturns: true,
     noImplicitThis: true,
-    noUnusedLocals: true
+    noUnusedLocals: true,
+    strictNullChecks: true
 };
 var tsProject = typescript.createProject(tsConfig);
 
@@ -61,7 +62,8 @@ var externalTsConfig = {
     noImplicitAny: true,
     noImplicitReturns: true,
     noImplicitThis: true,
-    noUnusedLocals: true
+    noUnusedLocals: true,
+    strictNullChecks: true
 };
 
 function processDependency(kind, dependency, filesToLoad) {

ファイルの差分が大きいため隠しています
+ 5508 - 5509
dist/preview release/babylon.d.ts


ファイルの差分が大きいため隠しています
+ 5508 - 5509
dist/preview release/babylon.module.d.ts


+ 5 - 5
src/Actions/babylon.actionManager.ts

@@ -11,7 +11,7 @@
          * @param meshUnderPointer The mesh that is currently pointed at (can be null)
          * @param sourceEvent the original (browser) event that triggered the ActionEvent
          */
-        constructor(public source: any, public pointerX: number, public pointerY: number, public meshUnderPointer: AbstractMesh, public sourceEvent?: any, public additionalData?: any) {
+        constructor(public source: any, public pointerX: number, public pointerY: number, public meshUnderPointer: Nullable<AbstractMesh>, public sourceEvent?: any, public additionalData?: any) {
 
         }
 
@@ -295,7 +295,7 @@
          * @param {BABYLON.Action} action - the action to be registered
          * @return {BABYLON.Action} the action amended (prepared) after registration
          */
-        public registerAction(action: Action): Action {
+        public registerAction(action: Action): Nullable<Action> {
             if (action.trigger === ActionManager.OnEveryFrameTrigger) {
                 if (this.getScene().actionManager !== this) {
                     Tools.Warn("OnEveryFrameTrigger can only be used with scene.actionManager");
@@ -429,7 +429,7 @@
                 return newInstance;
             };
 
-            var parseParameter = (name: string, value: string, target: any, propertyPath: string): any => {
+            var parseParameter = (name: string, value: string, target: any, propertyPath: Nullable<string>): any => {
                 if (propertyPath === null) {
                     // String, boolean or float
                     var floatValue = parseFloat(value);
@@ -476,13 +476,13 @@
             };
 
             // traverse graph per trigger
-            var traverse = (parsedAction: any, trigger: any, condition: Condition, action: Action, combineArray: Array<Action> = null) => {
+            var traverse = (parsedAction: any, trigger: any, condition: Nullable<Condition>, action: Nullable<Action>, combineArray: Nullable<Array<Action>> = null) => {
                 if (parsedAction.detached)
                     return;
 
                 var parameters = new Array<any>();
                 var target: any = null;
-                var propertyPath: string = null;
+                var propertyPath: Nullable<string> = null;
                 var combine = parsedAction.combine && parsedAction.combine.length > 0;
 
                 // Parameters

+ 8 - 5
src/Animations/babylon.animatable.ts

@@ -1,7 +1,7 @@
 module BABYLON {
     export class Animatable {
-        private _localDelayOffset: number = null;
-        private _pausedDelay: number = null;
+        private _localDelayOffset: Nullable<number> = null;
+        private _pausedDelay: Nullable<number> = null;
         private _runtimeAnimations = new Array<RuntimeAnimation>();
         private _paused = false;
         private _scene: Scene;
@@ -22,7 +22,7 @@
             this._speedRatio = value;
         }
 
-        constructor(scene: Scene, public target: any, public fromFrame: number = 0, public toFrame: number = 100, public loopAnimation: boolean = false, speedRatio: number = 1.0, public onAnimationEnd?: () => void, animations?: any) {
+        constructor(scene: Scene, public target: any, public fromFrame: number = 0, public toFrame: number = 100, public loopAnimation: boolean = false, speedRatio: number = 1.0, public onAnimationEnd?: Nullable<() => void>, animations?: any) {
             if (animations) {
                 this.appendAnimations(target, animations);
             }
@@ -45,7 +45,7 @@
             }
         }
 
-        public getAnimationByTargetProperty(property: string): Animation {
+        public getAnimationByTargetProperty(property: string): Nullable<Animation> {
             var runtimeAnimations = this._runtimeAnimations;
 
             for (var index = 0; index < runtimeAnimations.length; index++) {
@@ -57,7 +57,7 @@
             return null;
         }
 
-        public getRuntimeAnimationByTargetProperty(property: string): RuntimeAnimation {
+        public getRuntimeAnimationByTargetProperty(property: string): Nullable<RuntimeAnimation> {
             var runtimeAnimations = this._runtimeAnimations;
 
             for (var index = 0; index < runtimeAnimations.length; index++) {
@@ -105,6 +105,9 @@
                 var currentFrame = runtimeAnimations[0].currentFrame;
                 var adjustTime = frame - currentFrame;
                 var delay = adjustTime * 1000 / fps;
+                if (this._localDelayOffset === null) {
+                    this._localDelayOffset = 0;
+                }
                 this._localDelayOffset -= delay;
             }
 

+ 41 - 20
src/Animations/babylon.animation.ts

@@ -96,10 +96,10 @@
 
         public blendingSpeed = 0.01;
 
-        private _ranges: { [name: string]: AnimationRange; } = {};
+        private _ranges: { [name: string]: Nullable<AnimationRange> } = {};
 
         static _PrepareAnimation(name: string, targetProperty: string, framePerSecond: number, totalFrame: number,
-            from: any, to: any, loopMode?: number, easingFunction?: EasingFunction): Animation {
+            from: any, to: any, loopMode?: number, easingFunction?: EasingFunction): Nullable<Animation> {
             var dataType = undefined;
 
             if (!isNaN(parseFloat(from)) && isFinite(from)) {
@@ -153,19 +153,27 @@
 
         public static CreateAndStartAnimation(name: string, node: Node, targetProperty: string,
             framePerSecond: number, totalFrame: number,
-            from: any, to: any, loopMode?: number, easingFunction?: EasingFunction, onAnimationEnd?: () => void) {
+            from: any, to: any, loopMode?: number, easingFunction?: EasingFunction, onAnimationEnd?: () => void): Nullable<Animatable> {
 
             var animation = Animation._PrepareAnimation(name, targetProperty, framePerSecond, totalFrame, from, to, loopMode, easingFunction);
 
+            if (!animation) {
+                return null;
+            }
+
             return node.getScene().beginDirectAnimation(node, [animation], 0, totalFrame, (animation.loopMode === 1), 1.0, onAnimationEnd);
         }
 
         public static CreateMergeAndStartAnimation(name: string, node: Node, targetProperty: string,
             framePerSecond: number, totalFrame: number,
-            from: any, to: any, loopMode?: number, easingFunction?: EasingFunction, onAnimationEnd?: () => void) {
+            from: any, to: any, loopMode?: number, easingFunction?: EasingFunction, onAnimationEnd?: () => void): Nullable<Animatable> {
 
             var animation = Animation._PrepareAnimation(name, targetProperty, framePerSecond, totalFrame, from, to, loopMode, easingFunction);
 
+            if (!animation) {
+                return null;
+            }
+
             node.animations.push(animation);
 
             return node.getScene().beginAnimation(node, 0, totalFrame, (animation.loopMode === 1), 1.0, onAnimationEnd);
@@ -182,7 +190,7 @@
 		 * @param duration The duration of the animation, in milliseconds
 		 * @param onAnimationEnd Call back trigger at the end of the animation.
 		 */
-		public static TransitionTo(property: string, targetValue: any, host: any, scene: Scene, frameRate: number, transition: Animation, duration: number,	onAnimationEnd: () => void = null): Animatable {
+		public static TransitionTo(property: string, targetValue: any, host: any, scene: Scene, frameRate: number, transition: Animation, duration: number,	onAnimationEnd: Nullable<() => void> = null): Nullable<Animatable> {
 
 			if (duration <= 0) {
 				host[property] = targetValue;
@@ -293,23 +301,27 @@
         }
 
         public deleteRange(name: string, deleteFrames = true): void {
-            if (this._ranges[name]) {
-                if (deleteFrames) {
-                    var from = this._ranges[name].from;
-                    var to = this._ranges[name].to;
- 
-                    // this loop MUST go high to low for multiple splices to work
-                    for (var key = this._keys.length - 1; key >= 0; key--) {
-                        if (this._keys[key].frame >= from && this._keys[key].frame <= to) {
-                            this._keys.splice(key, 1);
-                        }
+            let range = this._ranges[name];
+            if (!range) {
+                return;
+
+            }
+            if (deleteFrames) {
+                var from = range.from;
+                var to = range.to;
+
+                // this loop MUST go high to low for multiple splices to work
+                for (var key = this._keys.length - 1; key >= 0; key--) {
+                    if (this._keys[key].frame >= from && this._keys[key].frame <= to) {
+                        this._keys.splice(key, 1);
                     }
                 }
-                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 getRange(name: string): AnimationRange {
+        public getRange(name: string): Nullable<AnimationRange> {
             return this._ranges[name];
         }
 
@@ -394,7 +406,11 @@
             if (this._ranges) {
                 clone._ranges = {};
                 for (var name in this._ranges) {
-                    clone._ranges[name] = this._ranges[name].clone();
+                    let range = this._ranges[name];
+                    if (!range) {
+                        continue;
+                    }
+                    clone._ranges[name] = range.clone();
                 }
             }
 
@@ -442,10 +458,15 @@
 
             serializationObject.ranges = [];
             for (var name in this._ranges) {
+                let source  =this._ranges[name];
+
+                if (!source) {
+                    continue;
+                }
                 var range: any = {};
                 range.name = name;
-                range.from = this._ranges[name].from;
-                range.to = this._ranges[name].to;
+                range.from = source.from;
+                range.to = source.to;
                 serializationObject.ranges.push(range);
             }
 

+ 1 - 1
src/Animations/babylon.runtimeAnimation.ts

@@ -50,7 +50,7 @@
             return value;
         }      
         
-        private _interpolate(currentFrame: number, repeatCount: number, loopMode: number, offsetValue?: any, highLimitValue?: any) {
+        private _interpolate(currentFrame: number, repeatCount: number, loopMode?: number, offsetValue?: any, highLimitValue?: any) {
             if (loopMode === Animation.ANIMATIONLOOPMODE_CONSTANT && repeatCount > 0) {
                 return highLimitValue.clone ? highLimitValue.clone() : highLimitValue;
             }

+ 111 - 57
src/Engine/babylon.engine.ts

@@ -116,7 +116,7 @@
         }
     }
 
-    var partialLoad = (url: string, index: number, loadedImages: any, scene: Scene,
+    var partialLoad = (url: string, index: number, loadedImages: any, scene: Nullable<Scene>,
         onfinish: (images: HTMLImageElement[]) => void, onErrorCallBack: Nullable<(message?: string, exception?: any) => void> = null) => {
 
         var img: HTMLImageElement;
@@ -150,7 +150,7 @@
         }
     }
 
-    var cascadeLoad = (rootUrl: string, scene: Scene,
+    var cascadeLoad = (rootUrl: string, scene: Nullable<Scene>,
         onfinish: (images: HTMLImageElement[]) => void, files: string[], onError: Nullable<(message?: string, exception?: any) => void> = null) => {
 
         var loadedImages: any = [];
@@ -597,7 +597,7 @@
 
         // Private Members
         private _gl: WebGLRenderingContext;
-        private _renderingCanvas: HTMLCanvasElement;
+        private _renderingCanvas: Nullable<HTMLCanvasElement>;
         private _windowIsBackground = false;
         private _webGLVersion = 1.0;
 
@@ -632,9 +632,9 @@
         private _onVRDisplayPointerUnrestricted: () => void;
 
         // VRDisplay connection
-        private _onVrDisplayConnect: (display: any) => void;
-        private _onVrDisplayDisconnect: () => void;
-        private _onVrDisplayPresentChange: () => void;
+        private _onVrDisplayConnect: Nullable<(display: any) => void>;
+        private _onVrDisplayDisconnect: Nullable<() => void>;
+        private _onVrDisplayPresentChange: Nullable<() => void>;
         public onVRDisplayChangedObservable = new Observable<IDisplayChangedEventArgs>();
         public onVRRequestPresentComplete = new Observable<boolean>();
         public onVRRequestPresentStart = new Observable<Engine>();
@@ -712,8 +712,8 @@
         private _currentInstanceBuffers = new Array<WebGLBuffer>();
         private _textureUnits: Int32Array;
 
-        private _workingCanvas: HTMLCanvasElement;
-        private _workingContext: CanvasRenderingContext2D;
+        private _workingCanvas: Nullable<HTMLCanvasElement>;
+        private _workingContext: Nullable<CanvasRenderingContext2D>;
         private _rescalePostProcess: PassPostProcess;
 
         private _dummyFramebuffer: WebGLFramebuffer;
@@ -724,8 +724,8 @@
         private _vaoRecordInProgress = false;
         private _mustWipeVertexAttributes = false;
 
-        private _emptyTexture: InternalTexture;
-        private _emptyCubeTexture: InternalTexture;
+        private _emptyTexture: Nullable<InternalTexture>;
+        private _emptyCubeTexture: Nullable<InternalTexture>;
 
         private _frameHandler: number;
 
@@ -1267,11 +1267,14 @@
             return this._gl.drawingBufferHeight;
         }
 
-        public getRenderingCanvas(): HTMLCanvasElement {
+        public getRenderingCanvas(): Nullable<HTMLCanvasElement> {
             return this._renderingCanvas;
         }
 
-        public getRenderingCanvasClientRect(): ClientRect {
+        public getRenderingCanvasClientRect(): Nullable<ClientRect> {
+            if (!this._renderingCanvas) {
+                return null;
+            }
             return this._renderingCanvas.getBoundingClientRect();
         }
 
@@ -1479,7 +1482,9 @@
                 Tools.ExitFullscreen();
             } else {
                 this._pointerLockRequested = requestPointerLock;
-                Tools.RequestFullscreen(this._renderingCanvas);
+                if (this._renderingCanvas) {
+                    Tools.RequestFullscreen(this._renderingCanvas);
+                }
             }
         }
 
@@ -1584,8 +1589,8 @@
         public resize(): void {
             // We're not resizing the size of the canvas while in VR mode & presenting
             if (!(this._vrDisplay && this._vrDisplay.isPresenting)) {
-                var width = navigator.isCocoonJS ? window.innerWidth : this._renderingCanvas.clientWidth;
-                var height = navigator.isCocoonJS ? window.innerHeight : this._renderingCanvas.clientHeight;
+                var width = this._renderingCanvas ? this._renderingCanvas.clientWidth : window.innerWidth;
+                var height = this._renderingCanvas ? this._renderingCanvas.clientHeight : window.innerHeight;
 
                 this.setSize(width / this._hardwareScalingLevel, height / this._hardwareScalingLevel);
             }
@@ -1597,6 +1602,10 @@
          * @param {number} height - the new canvas' height
          */
         public setSize(width: number, height: number): void {
+            if (!this._renderingCanvas) {
+                return;
+            }
+
             if (this._renderingCanvas.width === width && this._renderingCanvas.height === height) {
                 return;
             }
@@ -3232,7 +3241,13 @@
                 if (!this._videoTextureSupported) {
                     if (!texture._workingCanvas) {
                         texture._workingCanvas = document.createElement("canvas");
-                        texture._workingContext = texture._workingCanvas.getContext("2d");
+                        let context = texture._workingCanvas.getContext("2d");
+
+                        if (!context) {
+                            throw new Error("Unable to get 2d context");
+                        }
+
+                        texture._workingContext = context;
                         texture._workingCanvas.width = texture.width;
                         texture._workingCanvas.height = texture.height;
                     }
@@ -3292,7 +3307,7 @@
             var width = size.width || size;
             var height = size.height || size;
 
-            var filters = getSamplingParameters(fullOptions.samplingMode, fullOptions.generateMipMaps, gl);
+            var filters = getSamplingParameters(fullOptions.samplingMode, fullOptions.generateMipMaps ? true : false, gl);
 
             if (fullOptions.type === Engine.TEXTURETYPE_FLOAT && !this._caps.textureFloat) {
                 fullOptions.type = Engine.TEXTURETYPE_UNSIGNED_INT;
@@ -3311,7 +3326,7 @@
             this.bindUnboundFramebuffer(framebuffer);
             gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture._webGLTexture, 0);
 
-            texture._depthStencilBuffer = this._setupFramebufferDepthAttachments(fullOptions.generateStencilBuffer, fullOptions.generateDepthBuffer, width, height);
+            texture._depthStencilBuffer = this._setupFramebufferDepthAttachments(fullOptions.generateStencilBuffer ? true : false, fullOptions.generateDepthBuffer, width, height);
 
             if (fullOptions.generateMipMaps) {
                 this._gl.generateMipmap(this._gl.TEXTURE_2D);
@@ -3329,11 +3344,11 @@
             texture.height = height;
             texture.isReady = true;
             texture.samples = 1;
-            texture.generateMipMaps = fullOptions.generateMipMaps;
+            texture.generateMipMaps = fullOptions.generateMipMaps ? true : false;
             texture.samplingMode = fullOptions.samplingMode;
             texture.type = fullOptions.type;
             texture._generateDepthBuffer = fullOptions.generateDepthBuffer;
-            texture._generateStencilBuffer = fullOptions.generateStencilBuffer;
+            texture._generateStencilBuffer = fullOptions.generateStencilBuffer ? true : false;
 
             this.resetTextureCache();
 
@@ -3498,8 +3513,8 @@
             return textures;
         }
 
-        private _setupFramebufferDepthAttachments(generateStencilBuffer: boolean, generateDepthBuffer: boolean, width: number, height: number, samples = 1): WebGLRenderbuffer {
-            var depthStencilBuffer: WebGLRenderbuffer = null;
+        private _setupFramebufferDepthAttachments(generateStencilBuffer: boolean, generateDepthBuffer: boolean, width: number, height: number, samples = 1): Nullable<WebGLRenderbuffer> {
+            var depthStencilBuffer: Nullable<WebGLRenderbuffer> = null;
             var gl = this._gl;
 
             // Create the depth/stencil buffer
@@ -3558,10 +3573,21 @@
             }
 
             if (samples > 1) {
-                texture._MSAAFramebuffer = gl.createFramebuffer();
+                let framebuffer = gl.createFramebuffer();
+
+                if (!framebuffer) {
+                    throw new Error("Unable to create multi sampled framebuffer");
+                }
+
+                texture._MSAAFramebuffer = framebuffer;
                 this.bindUnboundFramebuffer(texture._MSAAFramebuffer);
 
                 var colorRenderbuffer = gl.createRenderbuffer();
+
+                if (!colorRenderbuffer) {
+                    throw new Error("Unable to create multi sampled framebuffer");
+                }
+
                 gl.bindRenderbuffer(gl.RENDERBUFFER, colorRenderbuffer);
                 gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, gl.RGBA8, texture.width, texture.height);
 
@@ -3602,7 +3628,7 @@
             if (options !== undefined) {
                 generateMipMaps = options.generateMipMaps === undefined ? true : options.generateMipMaps;
                 generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
-                generateStencilBuffer = generateDepthBuffer && options.generateStencilBuffer;
+                generateStencilBuffer = (generateDepthBuffer && options.generateStencilBuffer) ? true : false;
 
                 if (options.samplingMode !== undefined) {
                     samplingMode = options.samplingMode;
@@ -3795,7 +3821,7 @@
                     texture.width = ktx.pixelWidth;
                     texture.height = ktx.pixelHeight;
                     texture.isReady = true;
-                }, null, null, true, onerror);
+                }, undefined, undefined, true, onerror);
             } else if (isDDS) {
                 Tools.LoadFile(rootUrl, data => {
                     var info = Internals.DDSTools.GetDDSInfo(data);
@@ -3828,13 +3854,20 @@
                     if (onLoad) {
                         onLoad({ isDDS: true, width: info.width, info, data, texture });
                     }
-                }, null, null, true, onerror);
+                }, undefined, undefined, true, onerror);
             } else {
+                if (!files) {
+                    throw new Error("Cannot load cubemap because files were not defined");
+                }
+
                 cascadeLoad(rootUrl, scene, imgs => {
                     var width = this.needPOTTextures ? Tools.GetExponentOfTwo(imgs[0].width, this._caps.maxCubemapTextureSize) : imgs[0].width;
                     var height = width;
 
                     this._prepareWorkingCanvas();
+                    if (!this._workingCanvas || !this._workingContext) {
+                        return;
+                    }
                     this._workingCanvas.width = width;
                     this._workingCanvas.height = height;
 
@@ -3868,7 +3901,9 @@
                     texture.width = width;
                     texture.height = height;
                     texture.isReady = true;
-                    texture.format = format;
+                    if (format) {
+                        texture.format = format;
+                    }
 
                     texture.onLoadedObservable.notifyObservers(texture);
                     texture.onLoadedObservable.clear();
@@ -3884,7 +3919,7 @@
             return texture;
         }
 
-        public updateRawCubeTexture(texture: InternalTexture, data: ArrayBufferView[], format: number, type: number, invertY: boolean, compression: string = null, level = 0): void {
+        public updateRawCubeTexture(texture: InternalTexture, data: ArrayBufferView[], format: number, type: number, invertY: boolean, compression: Nullable<string> = null, level = 0): void {
             texture._bufferViewArray = data;
             texture.format = format;
             texture.type = type;
@@ -3933,7 +3968,7 @@
             texture.isReady = true;
         }
 
-        public createRawCubeTexture(data: ArrayBufferView[], size: number, format: number, type: number, generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression: Nullable<string> = null): InternalTexture {
+        public createRawCubeTexture(data: Nullable<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;
@@ -4001,8 +4036,8 @@
         public createRawCubeTextureFromUrl(url: string, scene: Scene, size: number, format: number, type: number, noMipmap: boolean,
             callback: (ArrayBuffer: ArrayBuffer) => ArrayBufferView[],
             mipmmapGenerator: ((faces: ArrayBufferView[]) => ArrayBufferView[][]),
-            onLoad: () => void = null,
-            onError: (message?: string, exception?: any) => void = null,
+            onLoad: Nullable<() => void> = null,
+            onError: Nullable<(message?: string, exception?: any) => void> = null,
             samplingMode = Texture.TRILINEAR_SAMPLINGMODE,
             invertY = false): InternalTexture {
 
@@ -4303,7 +4338,7 @@
                 this.activateTexture((<any>this._gl)["TEXTURE" + channel]);
             }
 
-            if (internalTexture.isCube) {
+            if (internalTexture && internalTexture.isCube) {
                 this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, internalTexture);
 
                 if (internalTexture._cachedCoordinatesMode !== texture.coordinatesMode) {
@@ -4318,7 +4353,7 @@
             } else {
                 this._bindTextureDirectly(this._gl.TEXTURE_2D, internalTexture);
 
-                if (internalTexture._cachedWrapU !== texture.wrapU) {
+                if (internalTexture && internalTexture._cachedWrapU !== texture.wrapU) {
                     internalTexture._cachedWrapU = texture.wrapU;
 
                     switch (texture.wrapU) {
@@ -4334,7 +4369,7 @@
                     }
                 }
 
-                if (internalTexture._cachedWrapV !== texture.wrapV) {
+                if (internalTexture && internalTexture._cachedWrapV !== texture.wrapV) {
                     internalTexture._cachedWrapV = texture.wrapV;
                     switch (texture.wrapV) {
                         case Texture.WRAP_ADDRESSMODE:
@@ -4530,8 +4565,6 @@
                 this._gl.deleteFramebuffer(this._dummyFramebuffer);
             }
 
-            this._gl = null;
-
             //WebVR
             this.disableVR();
 
@@ -4540,13 +4573,15 @@
             window.removeEventListener("focus", this._onFocus);
             window.removeEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted);
             window.removeEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted);
-            this._renderingCanvas.removeEventListener("focus", this._onCanvasFocus);
-            this._renderingCanvas.removeEventListener("blur", this._onCanvasBlur);
-            this._renderingCanvas.removeEventListener("pointerout", this._onCanvasBlur);
+            if (this._renderingCanvas) {
+                this._renderingCanvas.removeEventListener("focus", this._onCanvasFocus);
+                this._renderingCanvas.removeEventListener("blur", this._onCanvasBlur);
+                this._renderingCanvas.removeEventListener("pointerout", this._onCanvasBlur);
 
-            if (!this._doNotHandleContextLost) {
-                this._renderingCanvas.removeEventListener("webglcontextlost", this._onContextLost);
-                this._renderingCanvas.removeEventListener("webglcontextrestored", this._onContextRestored);
+                if (!this._doNotHandleContextLost) {
+                    this._renderingCanvas.removeEventListener("webglcontextlost", this._onContextLost);
+                    this._renderingCanvas.removeEventListener("webglcontextrestored", this._onContextRestored);
+                }
             }
             document.removeEventListener("fullscreenchange", this._onFullscreenChange);
             document.removeEventListener("mozfullscreenchange", this._onFullscreenChange);
@@ -4559,10 +4594,15 @@
 
             if (this._onVrDisplayConnect) {
                 window.removeEventListener('vrdisplayconnect', this._onVrDisplayConnect);
-                window.removeEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
-                window.removeEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
-                this._onVrDisplayConnect = undefined;
-                this._onVrDisplayDisconnect = undefined;
+                if (this._onVrDisplayDisconnect) {
+                    window.removeEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
+                }
+
+                if (this._onVrDisplayPresentChange) {
+                    window.removeEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
+                }
+                this._onVrDisplayConnect = null;
+                this._onVrDisplayDisconnect = null;
             }
 
             // Remove from Instances
@@ -4574,7 +4614,7 @@
 
             this._workingCanvas = null;
             this._workingContext = null;
-            this._currentBufferPointers = null;
+            this._currentBufferPointers = [];
             this._renderingCanvas = null;
             this._currentProgram = null;
 
@@ -4608,7 +4648,7 @@
         }
 
         public get loadingScreen(): ILoadingScreen {
-            if (!this._loadingScreen && DefaultLoadingScreen)
+            if (!this._loadingScreen && DefaultLoadingScreen && this._renderingCanvas)
                 this._loadingScreen = new DefaultLoadingScreen(this._renderingCanvas)
             return this._loadingScreen;
         }
@@ -4626,22 +4666,34 @@
         }
 
         public attachContextLostEvent(callback: ((event: WebGLContextEvent) => void)): void {
-            this._renderingCanvas.addEventListener("webglcontextlost", callback, false);
+            if (this._renderingCanvas) {
+                this._renderingCanvas.addEventListener("webglcontextlost", callback, false);
+            }
         }
 
         public attachContextRestoredEvent(callback: ((event: WebGLContextEvent) => void)): void {
-            this._renderingCanvas.addEventListener("webglcontextrestored", callback, false);
+            if (this._renderingCanvas) {
+                this._renderingCanvas.addEventListener("webglcontextrestored", callback, false);
+            }
         }
 
-        public getVertexShaderSource(program: WebGLProgram): string {
+        public getVertexShaderSource(program: WebGLProgram): Nullable<string> {
             var shaders = this._gl.getAttachedShaders(program);
 
+            if (!shaders) {
+                return null;
+            }
+
             return this._gl.getShaderSource(shaders[0]);
         }
 
-        public getFragmentShaderSource(program: WebGLProgram): string {
+        public getFragmentShaderSource(program: WebGLProgram): Nullable<string> {
             var shaders = this._gl.getAttachedShaders(program);
 
+            if (!shaders) {
+                return null;
+            }
+
             return this._gl.getShaderSource(shaders[1]);
         }
 
@@ -4667,7 +4719,13 @@
         public _readTexturePixels(texture: InternalTexture, width: number, height: number, faceIndex = -1): ArrayBufferView {
             let gl = this._gl;
             if (!this._dummyFramebuffer) {
-                this._dummyFramebuffer = gl.createFramebuffer();
+                let dummy = gl.createFramebuffer();
+
+                if (!dummy) {
+                    throw new Error("Unable to create dummy framebuffer");
+                }
+
+                this._dummyFramebuffer = dummy;
             }
             gl.bindFramebuffer(gl.FRAMEBUFFER, this._dummyFramebuffer);
 
@@ -4826,10 +4884,6 @@
         // Statics
         public static isSupported(): boolean {
             try {
-                // Avoid creating an unsized context for CocoonJS, since size determined on first creation.  Is not resizable
-                if (navigator.isCocoonJS) {
-                    return true;
-                }
                 var tempcanvas = document.createElement("canvas");
                 var gl = tempcanvas.getContext("webgl") || tempcanvas.getContext("experimental-webgl");
 

+ 28 - 8
src/Materials/Textures/babylon.baseTexture.ts

@@ -12,7 +12,9 @@
                 return;
             }
             this._hasAlpha = value;
-            this._scene.markAllMaterialsAsDirty(Material.TextureDirtyFlag);
+            if (this._scene) {
+                this._scene.markAllMaterialsAsDirty(Material.TextureDirtyFlag);
+            }
         }
         public get hasAlpha(): boolean {
             return this._hasAlpha;
@@ -34,7 +36,9 @@
                 return;
             }
             this._coordinatesMode = value;
-            this._scene.markAllMaterialsAsDirty(Material.TextureDirtyFlag);
+            if (this._scene) {
+                this._scene.markAllMaterialsAsDirty(Material.TextureDirtyFlag);
+            }
         }
         public get coordinatesMode(): number {
             return this._coordinatesMode;
@@ -103,7 +107,7 @@
 
         public delayLoadState = Engine.DELAYLOADSTATE_NONE;
 
-        private _scene: Scene;
+        private _scene: Nullable<Scene>;
         public _texture: Nullable<InternalTexture>;
         private _uid: Nullable<string>;
 
@@ -111,13 +115,15 @@
             return true;
         }
 
-        constructor(scene: Scene) {
+        constructor(scene: Nullable<Scene>) {
             this._scene = scene || Engine.LastCreatedScene;
-            this._scene.textures.push(this);
+            if (this._scene) {
+                this._scene.textures.push(this);
+            }
             this._uid = null;
         }
 
-        public getScene(): Scene {
+        public getScene(): Nullable<Scene> {
             return this._scene;
         }
 
@@ -181,6 +187,10 @@
         }
 
         public _getFromCache(url: Nullable<string>, noMipmap: boolean, sampling?: number): Nullable<InternalTexture> {
+            if (!this._scene) {
+                return null
+            }
+
             var texturesCache = this._scene.getEngine().getLoadedTexturesCache();
             for (var index = 0; index < texturesCache.length; index++) {
                 var texturesCacheEntry = texturesCache[index];
@@ -229,7 +239,13 @@
             }
 
             var size = this.getSize();
-            var engine = this.getScene().getEngine();
+            let scene = this.getScene();
+
+            if (!scene) {
+                return null;
+            }
+
+            var engine = scene.getEngine();
 
             if (this._texture.isCube) {
                 return engine._readTexturePixels(this._texture, size.width, size.height, faceIndex);
@@ -286,8 +302,12 @@
         }
 
         public dispose(): void {
+            if (!this._scene) {
+                return;
+            }
+            
             // Animations
-            this.getScene().stopAnimation(this);
+            this._scene.stopAnimation(this);
 
             // Remove from scene
             this._scene._removePendingData(this);

+ 4 - 4
src/Materials/Textures/babylon.internalTexture.ts

@@ -31,16 +31,16 @@ module BABYLON {
         public _dataSource = InternalTexture.DATASOURCE_UNKNOWN;
         public _buffer: Nullable<ArrayBuffer | HTMLImageElement>;
         public _bufferView: ArrayBufferView;
-        public _bufferViewArray: ArrayBufferView[];
+        public _bufferViewArray: Nullable<ArrayBufferView[]>;
         public _size: number;
         public _extension: string;
         public _files: Nullable<string[]>;
         public _workingCanvas: HTMLCanvasElement;
         public _workingContext: CanvasRenderingContext2D;
         public _framebuffer: Nullable<WebGLFramebuffer>;
-        public _depthStencilBuffer: WebGLRenderbuffer;
-        public _MSAAFramebuffer: WebGLFramebuffer;
-        public _MSAARenderBuffer: WebGLRenderbuffer;
+        public _depthStencilBuffer: Nullable<WebGLRenderbuffer>;
+        public _MSAAFramebuffer: Nullable<WebGLFramebuffer>;
+        public _MSAARenderBuffer: Nullable<WebGLRenderbuffer>;
         public _cachedCoordinatesMode: Nullable<number>;
         public _cachedWrapU: Nullable<number>;
         public _cachedWrapV: Nullable<number>;

+ 51 - 8
src/Materials/Textures/babylon.renderTargetTexture.ts

@@ -116,10 +116,14 @@
             return this._renderTargetOptions;
         }
 
-        constructor(name: string, size: any, scene: Scene, generateMipMaps?: boolean, doNotChangeAspectRatio: boolean = true, type: number = Engine.TEXTURETYPE_UNSIGNED_INT, public isCube = false, samplingMode = Texture.TRILINEAR_SAMPLINGMODE, generateDepthBuffer = true, generateStencilBuffer = false, isMulti = false) {
+        constructor(name: string, size: any, scene: Nullable<Scene>, generateMipMaps?: boolean, doNotChangeAspectRatio: boolean = true, type: number = Engine.TEXTURETYPE_UNSIGNED_INT, public isCube = false, samplingMode = Texture.TRILINEAR_SAMPLINGMODE, generateDepthBuffer = true, generateStencilBuffer = false, isMulti = false) {
             super(null, scene, !generateMipMaps);
             scene = this.getScene();
 
+            if (!scene) {
+                return;
+            }
+
             this.name = name;
             this.isRenderTarget = true;
             this._size = size;
@@ -165,7 +169,13 @@
                 return;
             }
 
-            this._samples = this.getScene().getEngine().updateRenderTargetTextureSampleCount(this._texture, value);
+            let scene = this.getScene();
+
+            if (!scene) {
+                return;
+            }
+
+            this._samples = scene.getEngine().updateRenderTargetTextureSampleCount(this._texture, value);
         }
 
         public resetRefreshCounter(): void {
@@ -184,7 +194,12 @@
 
         public addPostProcess(postProcess: PostProcess): void {
             if (!this._postProcessManager) {
-                this._postProcessManager = new PostProcessManager(this.getScene());
+                let scene = this.getScene();
+                
+                if (!scene) {
+                    return;
+                }                
+                this._postProcessManager = new PostProcessManager(scene);
                 this._postProcesses = new Array<PostProcess>();
             }
 
@@ -263,10 +278,16 @@
 
         public resize(size: any) {
             this.releaseInternalTexture();
+            let scene = this.getScene();
+            
+            if (!scene) {
+                return;
+            } 
+
             if (this.isCube) {
-                this._texture = this.getScene().getEngine().createRenderTargetCubeTexture(size, this._renderTargetOptions);
+                this._texture = scene.getEngine().createRenderTargetCubeTexture(size, this._renderTargetOptions);
             } else {
-                this._texture = this.getScene().getEngine().createRenderTargetTexture(size, this._renderTargetOptions);
+                this._texture = scene.getEngine().createRenderTargetTexture(size, this._renderTargetOptions);
             }
 
             this._size = size;
@@ -274,6 +295,11 @@
 
         public render(useCameraPostProcess: boolean = false, dumpForDebug: boolean = false) {
             var scene = this.getScene();
+
+            if (!scene) {
+                return;
+            }
+
             var engine = scene.getEngine();
 
             if (this.useCameraPostProcesses !== undefined) {
@@ -301,7 +327,13 @@
                     this.renderList = [];
                 }
 
-                var sceneMeshes = this.getScene().meshes;
+                var scene = this.getScene();
+                
+                if (!scene) {
+                    return;
+                }
+
+                var sceneMeshes = scene.meshes;
 
                 for (var index = 0; index < sceneMeshes.length; index++) {
                     var mesh = sceneMeshes[index];
@@ -405,6 +437,11 @@
 
         private renderToTarget(faceIndex: number, currentRenderList: AbstractMesh[], currentRenderListLength: number, useCameraPostProcess: boolean, dumpForDebug: boolean): void {
             var scene = this.getScene();
+            
+            if (!scene) {
+                return;
+            }
+
             var engine = scene.getEngine();
 
             if (!this._texture) {
@@ -550,8 +587,9 @@
         // This will remove the attached framebuffer objects. The texture will not be able to be used as render target anymore
         public disposeFramebufferObjects(): void {
             let objBuffer = this.getInternalTexture();
-            if (objBuffer) {
-                this.getScene().getEngine()._releaseFramebufferObjects(objBuffer);
+            let scene = this.getScene();
+            if (objBuffer && scene) {
+                scene.getEngine()._releaseFramebufferObjects(objBuffer);
             }
         }
 
@@ -567,6 +605,11 @@
 
             // Remove from custom render targets
             var scene = this.getScene();
+
+            if (!scene) {
+                return;
+            }
+
             var index = scene.customRenderTargets.indexOf(this);
 
             if (index >= 0) {

+ 31 - 5
src/Materials/Textures/babylon.texture.ts

@@ -103,7 +103,7 @@
             return this._samplingMode;
         }
 
-        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) {
+        constructor(url: Nullable<string>, scene: Nullable<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 || "";
@@ -119,6 +119,9 @@
 
             scene = this.getScene();
 
+            if (!scene) {
+                return;
+            }
             scene.getEngine().onBeforeTextureInitObservable.notifyObservers(this);
 
             let load = () => {
@@ -129,7 +132,7 @@
                     onLoad();
                 }
 
-                if (!this.isBlocking) {
+                if (!this.isBlocking && scene) {
                     scene.resetCachedMaterial();
                 }
             }
@@ -174,11 +177,17 @@
                 return;
             }
 
+            let scene = this.getScene();
+
+            if (!scene) {
+                return;
+            }
+            
             this.delayLoadState = Engine.DELAYLOADSTATE_LOADED;
             this._texture = this._getFromCache(this.url, this._noMipmap, this._samplingMode);
 
             if (!this._texture) {
-                this._texture = this.getScene().getEngine().createTexture(this.url, this._noMipmap, this._invertY, this.getScene(), this._samplingMode, this._delayedOnLoad, this._delayedOnError, this._buffer, null, this._format);
+                this._texture = scene.getEngine().createTexture(this.url, this._noMipmap, this._invertY, scene, this._samplingMode, this._delayedOnLoad, this._delayedOnError, this._buffer, null, this._format);
                 if (this._deleteBuffer) {
                     delete this._buffer;
                 }
@@ -203,8 +212,14 @@
                 return;
             }
 
+            let scene = this.getScene();
+            
+            if (!scene) {
+                return;
+            }            
+
             this._samplingMode = samplingMode;
-            this.getScene().getEngine().updateTextureSamplingMode(samplingMode, this._texture);
+            scene.getEngine().updateTextureSamplingMode(samplingMode, this._texture);
         }
 
         private _prepareRowForTextureGeneration(x: number, y: number, z: number, t: Vector3): void {
@@ -264,7 +279,13 @@
             this._cachedTextureMatrix.m[4] = this._t2.x; this._cachedTextureMatrix.m[5] = this._t2.y; this._cachedTextureMatrix.m[6] = this._t2.z;
             this._cachedTextureMatrix.m[8] = this._t0.x; this._cachedTextureMatrix.m[9] = this._t0.y; this._cachedTextureMatrix.m[10] = this._t0.z;
 
-            this.getScene().markAllMaterialsAsDirty(Material.TextureDirtyFlag, (mat) => {
+            let scene = this.getScene();
+            
+            if (!scene) {
+                return this._cachedTextureMatrix;
+            }
+
+            scene.markAllMaterialsAsDirty(Material.TextureDirtyFlag, (mat) => {
                 return mat.hasTexture(this);
             });
 
@@ -273,6 +294,11 @@
 
         public getReflectionTextureMatrix(): Matrix {
             let scene = this.getScene();
+
+            if (!scene) {
+                return this._cachedTextureMatrix;
+            }
+
             if (
                 this.uOffset === this._cachedUOffset &&
                 this.vOffset === this._cachedVOffset &&

+ 0 - 1
src/babylon.mixins.ts

@@ -139,7 +139,6 @@ interface MSStyleCSSProperties {
 interface Navigator {
     getVRDisplays: () => any;
     mozGetVRDevices: (any: any) => any;
-    isCocoonJS: boolean;
     getUserMedia: any;
     webkitGetUserMedia: any;
     mozGetUserMedia: any;