David Catuhe пре 11 година
родитељ
комит
a09571b428

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

@@ -25,6 +25,8 @@
         private _worldMatrix: Matrix;
         public _postProcesses = new Array<PostProcess>();
         public _postProcessesTakenIndices = [];
+        
+        public _waitingParentId: string;
 
         constructor(name: string, public position: Vector3, scene: Scene) {
             super(name, scene);

+ 8 - 21
Babylon/Cameras/babylon.deviceOrientationCamera.js

@@ -18,45 +18,32 @@ var BABYLON;
             this._orientationBeta = 0;
             this._initialOrientationGamma = 0;
             this._initialOrientationBeta = 0;
-            this._isLandscape = true;
             this.angularSensibility = 10000.0;
             this.moveSensibility = 50.0;
 
-            http:
             window.addEventListener("resize", function () {
-                _this._isLandscape = (window.innerWidth > window.innerHeight) ? true : false;
                 _this._initialOrientationGamma = null;
             }, false);
         }
         DeviceOrientationCamera.prototype.attachControl = function (canvas, noPreventDefault) {
+            var _this = this;
             if (this._attachedCanvas) {
                 return;
             }
             this._attachedCanvas = canvas;
 
-            var that = this;
             if (!this._orientationChanged) {
                 this._orientationChanged = function (evt) {
-                    if (!that._initialOrientationGamma) {
-                        if (!this._isLandscape) {
-                            that._initialOrientationGamma = evt.gamma;
-                            that._initialOrientationBeta = evt.beta;
-                        } else {
-                            that._initialOrientationGamma = evt.beta;
-                            that._initialOrientationBeta = evt.gamma;
-                        }
+                    if (!_this._initialOrientationGamma) {
+                        _this._initialOrientationGamma = evt.gamma;
+                        _this._initialOrientationBeta = evt.beta;
                     }
 
-                    if (!this._isLandscape) {
-                        that._orientationGamma = evt.gamma;
-                        that._orientationBeta = evt.beta;
-                    } else {
-                        that._orientationGamma = evt.beta;
-                        that._orientationBeta = evt.gamma;
-                    }
+                    _this._orientationGamma = evt.gamma;
+                    _this._orientationBeta = evt.beta;
 
-                    that._offsetY = (that._initialOrientationBeta - that._orientationBeta);
-                    that._offsetX = (that._initialOrientationGamma - that._orientationGamma);
+                    _this._offsetY = (_this._initialOrientationBeta - _this._orientationBeta);
+                    _this._offsetX = (_this._initialOrientationGamma - _this._orientationGamma);
                 };
             }
 

+ 9 - 26
Babylon/Cameras/babylon.deviceOrientationCamera.ts

@@ -9,7 +9,6 @@ module BABYLON {
         private _initialOrientationBeta: number = 0;
         private _attachedCanvas: HTMLCanvasElement;
         private _orientationChanged: (e: DeviceOrientationEvent) => any;
-        private _isLandscape: boolean = true;
 
         public angularSensibility: number = 10000.0;
         public moveSensibility: number = 50.0;
@@ -17,10 +16,7 @@ module BABYLON {
         constructor(name: string, position: Vector3, scene: Scene) {
             super(name, position, scene);
 
-            http://david.blob.core.windows.net/videos/BabylonJSWinStoreLaunchSequence.mp4 = (window.innerWidth > window.innerHeight) ? true : false;
-
             window.addEventListener("resize", () => {
-                this._isLandscape = (window.innerWidth > window.innerHeight) ? true : false;
                 this._initialOrientationGamma = null;
             }, false);
         }
@@ -31,32 +27,19 @@ module BABYLON {
             }
             this._attachedCanvas = canvas;
 
-            var that = this;
             if (!this._orientationChanged) {
-                this._orientationChanged = function (evt) {
-
-                    if (!that._initialOrientationGamma) {
-                        if (!this._isLandscape) {
-                            that._initialOrientationGamma = evt.gamma;
-                            that._initialOrientationBeta = evt.beta;
-                        }
-                        else {
-                            that._initialOrientationGamma = evt.beta;
-                            that._initialOrientationBeta = evt.gamma;
-                        }
-                    }
+                this._orientationChanged = (evt) => {
 
-                    if (!this._isLandscape) {
-                        that._orientationGamma = evt.gamma;
-                        that._orientationBeta = evt.beta;
-                    }
-                    else {
-                        that._orientationGamma = evt.beta;
-                        that._orientationBeta = evt.gamma;
+                    if (!this._initialOrientationGamma) {
+                            this._initialOrientationGamma = evt.gamma;
+                            this._initialOrientationBeta = evt.beta;
                     }
 
-                    that._offsetY = (that._initialOrientationBeta - that._orientationBeta);
-                    that._offsetX = (that._initialOrientationGamma - that._orientationGamma);
+                    this._orientationGamma = evt.gamma;
+                    this._orientationBeta = evt.beta;
+ 
+                    this._offsetY = (this._initialOrientationBeta - this._orientationBeta);
+                    this._offsetX = (this._initialOrientationGamma - this._orientationGamma);
                 };
             }
 

+ 2 - 0
Babylon/Cameras/babylon.freeCamera.ts

@@ -44,6 +44,8 @@
         public _onLostFocus: (e: FocusEvent) => any;
         private _reset: () => void;
 
+        public _waitingLockedTargetId: string;
+
         constructor(name: string, position: Vector3, scene: Scene) {
             super(name, position, scene);
         }

Разлика између датотеке није приказан због своје велике величине
+ 842 - 854
Babylon/Loading/Plugins/babylon.babylonFileLoader.js


Разлика између датотеке није приказан због своје велике величине
+ 1099 - 0
Babylon/Loading/Plugins/babylon.babylonFileLoader.ts


+ 69 - 53
Babylon/Loading/babylon.sceneLoader.js

@@ -1,12 +1,21 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-(function () {
-    BABYLON.SceneLoader = {
-        _registeredPlugins: [],
-
-        _getPluginForFilename: function(sceneFilename) {
+var BABYLON;
+(function (BABYLON) {
+    var SceneLoader = (function () {
+        function SceneLoader() {
+        }
+        Object.defineProperty(SceneLoader, "ForceFullSceneLoadingForIncremental", {
+            get: function () {
+                return SceneLoader._ForceFullSceneLoadingForIncremental;
+            },
+            set: function (value) {
+                SceneLoader._ForceFullSceneLoadingForIncremental = value;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+
+        SceneLoader._getPluginForFilename = function (sceneFilename) {
             var dotPosition = sceneFilename.lastIndexOf(".");
             var extension = sceneFilename.substring(dotPosition).toLowerCase();
 
@@ -19,53 +28,54 @@ var BABYLON = BABYLON || {};
             }
 
             return this._registeredPlugins[this._registeredPlugins.length - 1];
-        },
-
-        // Flags
-        ForceFullSceneLoadingForIncremental: false,
+        };
 
         // Public functions
-        RegisterPlugin: function (plugin) {
+        SceneLoader.RegisterPlugin = function (plugin) {
             plugin.extensions = plugin.extensions.toLowerCase();
-            this._registeredPlugins.push(plugin);
-        },
+            SceneLoader._registeredPlugins.push(plugin);
+        };
 
-        ImportMesh: function (meshesNames, rootUrl, sceneFilename, scene, onsuccess, progressCallBack, onerror) {
-            // Checking if a manifest file has been set for this scene and if offline mode has been requested
-            var database = new BABYLON.Database(rootUrl + sceneFilename);
-            scene.database = database;
+        SceneLoader.ImportMesh = function (meshesNames, rootUrl, sceneFilename, scene, onsuccess, progressCallBack, onerror) {
+            var _this = this;
+            var manifestChecked = function (success) {
+                scene.database = database;
 
-            var plugin = this._getPluginForFilename(sceneFilename);
+                var plugin = _this._getPluginForFilename(sceneFilename);
 
-            var importMeshFromData = function(data) {
-                var meshes = [];
-                var particleSystems = [];
-                var skeletons = [];
+                var importMeshFromData = function (data) {
+                    var meshes = [];
+                    var particleSystems = [];
+                    var skeletons = [];
 
-                if (!plugin.importMesh(meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons)) {
-                    if (onerror) {
-                        onerror(scene);
+                    if (!plugin.importMesh(meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons)) {
+                        if (onerror) {
+                            onerror(scene);
+                        }
+
+                        return;
                     }
 
+                    if (onsuccess) {
+                        scene.importedMeshesFiles.push(rootUrl + sceneFilename);
+                        onsuccess(meshes, particleSystems, skeletons);
+                    }
+                };
+
+                if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
+                    // Direct load
+                    importMeshFromData(sceneFilename.substr(5));
                     return;
                 }
 
-                if (onsuccess) {
-                    scene.importedMeshesFiles.push(rootUrl + sceneFilename);
-                    onsuccess(meshes, particleSystems, skeletons);
-                }
+                BABYLON.Tools.LoadFile(rootUrl + sceneFilename, function (data) {
+                    importMeshFromData(data);
+                }, progressCallBack, database);
             };
 
-            if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
-                // Direct load
-                importMeshFromData(sceneFilename.substr(5));
-                return;
-            }
-
-            BABYLON.Tools.LoadFile(rootUrl + sceneFilename, function (data) {
-                importMeshFromData(data);
-            }, progressCallBack, database);
-        },
+            // Checking if a manifest file has been set for this scene and if offline mode has been requested
+            var database = new BABYLON.Database(rootUrl + sceneFilename, manifestChecked);
+        };
 
         /**
         * Load a scene
@@ -73,8 +83,7 @@ var BABYLON = BABYLON || {};
         * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
         * @param engine is the instance of BABYLON.Engine to use to create the scene
         */
-        Load: function (rootUrl, sceneFilename, engine, onsuccess, progressCallBack, onerror) {
-
+        SceneLoader.Load = function (rootUrl, sceneFilename, engine, onsuccess, progressCallBack, onerror) {
             var plugin = this._getPluginForFilename(sceneFilename.name || sceneFilename);
             var database;
 
@@ -95,6 +104,10 @@ var BABYLON = BABYLON || {};
                 }
             };
 
+            var manifestChecked = function (success) {
+                BABYLON.Tools.LoadFile(rootUrl + sceneFilename, loadSceneFromData, progressCallBack, database);
+            };
+
             if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
                 // Direct load
                 loadSceneFromData(sceneFilename.substr(5));
@@ -103,14 +116,17 @@ var BABYLON = BABYLON || {};
 
             if (rootUrl.indexOf("file:") === -1) {
                 // Checking if a manifest file has been set for this scene and if offline mode has been requested
-                database = new BABYLON.Database(rootUrl + sceneFilename);
-
-                BABYLON.Tools.LoadFile(rootUrl + sceneFilename, loadSceneFromData, progressCallBack, database);
-            }
-                // Loading file from disk via input file or drag'n'drop
-            else {
+                database = new BABYLON.Database(rootUrl + sceneFilename, manifestChecked);
+            } else {
                 BABYLON.Tools.ReadFile(sceneFilename, loadSceneFromData, progressCallBack);
             }
-        }
-    };
-})();
+        };
+        SceneLoader._ForceFullSceneLoadingForIncremental = false;
+
+        SceneLoader._registeredPlugins = new Array();
+        return SceneLoader;
+    })();
+    BABYLON.SceneLoader = SceneLoader;
+    ;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.sceneLoader.js.map

+ 133 - 0
Babylon/Loading/babylon.sceneLoader.ts

@@ -0,0 +1,133 @@
+module BABYLON {
+    export interface ISceneLoaderPlugin {
+        extensions: string;
+        importMesh: (meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => boolean;
+        load: (scene: Scene, data: string, rootUrl: string) => boolean;
+    }
+
+    export class SceneLoader
+    {
+        // Flags
+        private static _ForceFullSceneLoadingForIncremental = false;
+
+        public static get ForceFullSceneLoadingForIncremental() {
+            return SceneLoader._ForceFullSceneLoadingForIncremental;
+        }
+
+        public static set ForceFullSceneLoadingForIncremental(value: boolean) {
+            SceneLoader._ForceFullSceneLoadingForIncremental = value;
+        }
+
+        // Members
+        private static _registeredPlugins = new Array<ISceneLoaderPlugin>();
+
+        private static _getPluginForFilename(sceneFilename): ISceneLoaderPlugin {
+            var dotPosition = sceneFilename.lastIndexOf(".");
+            var extension = sceneFilename.substring(dotPosition).toLowerCase();
+
+            for (var index = 0; index < this._registeredPlugins.length; index++) {
+                var plugin = this._registeredPlugins[index];
+
+                if (plugin.extensions.indexOf(extension) !== -1) {
+                    return plugin;
+                }
+            }
+
+            return this._registeredPlugins[this._registeredPlugins.length - 1];
+        }
+
+            // Public functions
+        public static RegisterPlugin(plugin: ISceneLoaderPlugin): void {
+            plugin.extensions = plugin.extensions.toLowerCase();
+            SceneLoader._registeredPlugins.push(plugin);
+        }
+
+        public static ImportMesh(meshesNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, progressCallBack?: () => void, onerror?: (scene: Scene) => void): void {
+            var manifestChecked = success => {
+                scene.database = database;
+
+                var plugin = this._getPluginForFilename(sceneFilename);
+
+                var importMeshFromData = data => {
+                    var meshes = [];
+                    var particleSystems = [];
+                    var skeletons = [];
+
+                    if (!plugin.importMesh(meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons)) {
+                        if (onerror) {
+                            onerror(scene);
+                        }
+
+                        return;
+                    }
+
+                    if (onsuccess) {
+                        scene.importedMeshesFiles.push(rootUrl + sceneFilename);
+                        onsuccess(meshes, particleSystems, skeletons);
+                    }
+                };
+
+                if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
+                    // Direct load
+                    importMeshFromData(sceneFilename.substr(5));
+                    return;
+                }
+
+                BABYLON.Tools.LoadFile(rootUrl + sceneFilename, data => {
+                    importMeshFromData(data);
+                }, progressCallBack, database);
+            };
+
+            // Checking if a manifest file has been set for this scene and if offline mode has been requested
+            var database = new BABYLON.Database(rootUrl + sceneFilename, manifestChecked);
+        }
+
+        /**
+        * Load a scene
+        * @param rootUrl a string that defines the root url for scene and resources
+        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
+        * @param engine is the instance of BABYLON.Engine to use to create the scene
+        */
+        public static Load(rootUrl: string, sceneFilename: any, engine: Engine, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void {
+
+            var plugin = this._getPluginForFilename(sceneFilename.name || sceneFilename);
+            var database;
+
+            var loadSceneFromData = data => {
+                var scene = new BABYLON.Scene(engine);
+                scene.database = database;
+
+                if (!plugin.load(scene, data, rootUrl)) {
+                    if (onerror) {
+                        onerror(scene);
+                    }
+
+                    return;
+                }
+
+                if (onsuccess) {
+                    onsuccess(scene);
+                }
+            };
+
+            var manifestChecked = success => {
+                BABYLON.Tools.LoadFile(rootUrl + sceneFilename, loadSceneFromData, progressCallBack, database);
+            };
+
+            if (sceneFilename.substr && sceneFilename.substr(0, 5) === "data:") {
+                // Direct load
+                loadSceneFromData(sceneFilename.substr(5));
+                return;
+            }
+
+            if (rootUrl.indexOf("file:") === -1) {
+                // Checking if a manifest file has been set for this scene and if offline mode has been requested
+                database = new BABYLON.Database(rootUrl + sceneFilename, manifestChecked);
+            }
+            // Loading file from disk via input file or drag'n'drop
+            else {
+                BABYLON.Tools.ReadFile(sceneFilename, loadSceneFromData, progressCallBack);
+            }
+        }
+    };
+}

+ 1 - 1
Babylon/Materials/textures/babylon.cubeTexture.ts

@@ -7,7 +7,7 @@
         private _extensions: string[];
         private _textureMatrix: Matrix;
 
-        constructor(rootUrl: string, scene: Scene, extensions: string[], noMipmap?: boolean) {
+        constructor(rootUrl: string, scene: Scene, extensions?: string[], noMipmap?: boolean) {
             super(scene);
 
             this.name = rootUrl;

+ 1 - 4
Babylon/Math/babylon.math.js

@@ -224,10 +224,7 @@
         };
 
         Color4.FromArray = function (array, offset) {
-            if (!offset) {
-                offset = 0;
-            }
-
+            if (typeof offset === "undefined") { offset = 0; }
             return new Color4(array[offset], array[offset + 1], array[offset + 2], array[offset + 3]);
         };
 

+ 1 - 5
Babylon/Math/babylon.math.ts

@@ -194,11 +194,7 @@
             result.a = left.a + (right.a - left.a) * amount;
         }
 
-        public static FromArray(array: number[], offset: number): Color4 {
-            if (!offset) {
-                offset = 0;
-            }
-
+        public static FromArray(array: number[], offset: number = 0): Color4 {
             return new Color4(array[offset], array[offset + 1], array[offset + 2], array[offset + 3]);
         }
 

+ 1 - 0
Babylon/Mesh/babylon.geometry.js

@@ -511,6 +511,7 @@ var BABYLON;
             var Cylinder = (function (_super) {
                 __extends(Cylinder, _super);
                 function Cylinder(id, scene, height, diameterTop, diameterBottom, tessellation, subdivisions, canBeRegenerated, mesh) {
+                    if (typeof subdivisions === "undefined") { subdivisions = 1; }
                     this.height = height;
                     this.diameterTop = diameterTop;
                     this.diameterBottom = diameterBottom;

+ 12 - 12
Babylon/Mesh/babylon.geometry.ts

@@ -12,17 +12,17 @@
         private _totalVertices = 0;
         private _indices = [];
         private _vertexBuffers;
-        private _delayInfo; //ANY
+        public _delayInfo; //ANY
         private _indexBuffer;
-        private _boundingInfo: BoundingInfo;
-        private _delayLoadingFunction: (any, Geometry) => void;
+        public _boundingInfo: BoundingInfo;
+        public _delayLoadingFunction: (any, Geometry) => void;
 
         constructor(id: string, scene: Scene, vertexData?: VertexData, updatable?: boolean, mesh?: Mesh) {
             this.id = id;
             this._engine = scene.getEngine();
             this._meshes = [];
             this._scene = scene;
-            
+
             // vertexData
             if (vertexData) {
                 this.setAllVerticesData(vertexData, updatable);
@@ -138,7 +138,7 @@
             return this._vertexBuffers[kind];
         }
 
-        public getVertexBuffers(): VertexBuffer[]{
+        public getVertexBuffers(): VertexBuffer[] {
             if (!this.isReady()) {
                 return null;
             }
@@ -411,7 +411,7 @@
 
             return geometry.copy(id);
         }
-    
+
         // from http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#answer-2117523
         // be aware Math.random() could cause collisions
         public static RandomId(): string {
@@ -529,7 +529,7 @@
             public tessellation: number;
             public subdivisions: number;
 
-            constructor(id: string, scene: Scene, height: number, diameterTop: number, diameterBottom: number, tessellation: number, subdivisions: number, canBeRegenerated?: boolean, mesh?: Mesh) {
+            constructor(id: string, scene: Scene, height: number, diameterTop: number, diameterBottom: number, tessellation: number, subdivisions: number = 1, canBeRegenerated?: boolean, mesh?: Mesh) {
                 this.height = height;
                 this.diameterTop = diameterTop;
                 this.diameterBottom = diameterBottom;
@@ -600,16 +600,16 @@
             public zmin: number;
             public xmax: number;
             public zmax: number;
-            public subdivisions: {w: number; h: number;};
-            public precision:    {w: number; h: number;};
+            public subdivisions: { w: number; h: number; };
+            public precision: { w: number; h: number; };
 
-            constructor(id: string, scene: Scene, xmin: number, zmin: number, xmax: number, zmax: number, subdivisions: {w: number; h: number;}, precision: {w: number; h: number;}, canBeRegenerated?: boolean, mesh?: Mesh) {
+            constructor(id: string, scene: Scene, xmin: number, zmin: number, xmax: number, zmax: number, subdivisions: { w: number; h: number; }, precision: { w: number; h: number; }, canBeRegenerated?: boolean, mesh?: Mesh) {
                 this.xmin = xmin;
                 this.zmin = zmin;
                 this.xmax = xmax;
                 this.zmax = zmax;
-                this.subdivisions  = subdivisions;
-                this.precision     = precision;
+                this.subdivisions = subdivisions;
+                this.precision = precision;
 
                 super(id, scene, this._regenerateVertexData(), canBeRegenerated, mesh);
             }

+ 1 - 2
Babylon/Mesh/babylon.groundMesh.js

@@ -36,8 +36,7 @@ var BABYLON;
             var pickInfo = this.intersects(ray);
 
             if (pickInfo.hit) {
-                var result = BABYLON.Vector3.TransformCoordinates(pickInfo.pickedPoint, this.getWorldMatrix());
-                return result.y;
+                return pickInfo.pickedPoint.y;
             }
 
             return 0;

+ 1 - 2
Babylon/Mesh/babylon.groundMesh.ts

@@ -28,8 +28,7 @@
             var pickInfo = this.intersects(ray);
 
             if (pickInfo.hit) {
-                var result = BABYLON.Vector3.TransformCoordinates(pickInfo.pickedPoint, this.getWorldMatrix());
-                return result.y;
+                return pickInfo.pickedPoint.y;
             }
 
             return 0;

+ 10 - 9
Babylon/Mesh/babylon.mesh.ts

@@ -2,7 +2,7 @@
     export class _InstancesBatch {
         public mustReturn = false;
         public visibleInstances = new Array<Array<InstancedMesh>>();
-        public renderSelf = new  Array<boolean>();
+        public renderSelf = new Array<boolean>();
     }
 
     export class Mesh extends AbstractMesh implements IGetSetVerticesData {
@@ -14,14 +14,15 @@
         // Private
         public _geometry: Geometry;
         private _onBeforeRenderCallbacks = [];
-        private _delayInfo; //ANY
-        private _delayLoadingFunction: (any, Mesh) => void;
+        public _delayInfo; //ANY
+        public _delayLoadingFunction: (any, Mesh) => void;
         public _visibleInstances: any = {};
         private _renderIdForInstances = new Array<number>();
         private _batchCache = new _InstancesBatch();
         private _worldMatricesInstancesBuffer: WebGLBuffer;
         private _worldMatricesInstancesArray: Float32Array;
         private _instancesBufferSize = 32 * 16 * 4; // let's start with a maximum of 32 instances
+        public _shouldGenerateFlatShading: boolean;
 
         constructor(name: string, scene: Scene) {
             super(name, scene);
@@ -268,12 +269,12 @@
         public _getInstancesRenderList(subMeshId: number): _InstancesBatch {
             var scene = this.getScene();
             this._batchCache.mustReturn = false;
-            this._batchCache.renderSelf[subMeshId]  = true;
+            this._batchCache.renderSelf[subMeshId] = true;
             this._batchCache.visibleInstances[subMeshId] = null;
 
             if (this._visibleInstances) {
                 var currentRenderId = scene.getRenderId();
-                this._batchCache.visibleInstances[subMeshId]  = this._visibleInstances[currentRenderId];
+                this._batchCache.visibleInstances[subMeshId] = this._visibleInstances[currentRenderId];
                 var selfRenderId = this._renderId;
 
                 if (!this._batchCache.visibleInstances[subMeshId] && this._visibleInstances.defaultRenderId) {
@@ -289,7 +290,7 @@
                     }
 
                     if (currentRenderId !== selfRenderId) {
-                        this._batchCache.renderSelf[subMeshId]  = false;
+                        this._batchCache.renderSelf[subMeshId] = false;
                     }
 
                 }
@@ -371,7 +372,7 @@
             }
 
             var engine = scene.getEngine();
-            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null); 
+            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null);
 
             // Material
             var effectiveMaterial = subMesh.getMaterial();
@@ -768,7 +769,7 @@
         }
 
         // Torus  (Code from SharpDX.org)
-        public static CreateTorus(name: string, diameter:number, thickness: number, tessellation: number, scene: Scene, updatable?: boolean): Mesh {
+        public static CreateTorus(name: string, diameter: number, thickness: number, tessellation: number, scene: Scene, updatable?: boolean): Mesh {
             var torus = new BABYLON.Mesh(name, scene);
             var vertexData = BABYLON.VertexData.CreateTorus(diameter, thickness, tessellation);
 
@@ -821,7 +822,7 @@
             return ground;
         }
 
-        public static CreateTiledGround(name: string, xmin: number, zmin: number, xmax: number, zmax: number, subdivisions: {w: number; h: number;}, precision: {w: number; h: number;}, scene: Scene, updatable?: boolean): Mesh {
+        public static CreateTiledGround(name: string, xmin: number, zmin: number, xmax: number, zmax: number, subdivisions: { w: number; h: number; }, precision: { w: number; h: number; }, scene: Scene, updatable?: boolean): Mesh {
             var tiledGround = new BABYLON.Mesh(name, scene);
 
             var vertexData = BABYLON.VertexData.CreateTiledGround(xmin, zmin, xmax, zmax, subdivisions, precision);

+ 9 - 14
Babylon/Mesh/babylon.mesh.vertexData.js

@@ -650,36 +650,31 @@
 
             subdivisions.h = (subdivisions.w < 1) ? 1 : subdivisions.h;
             subdivisions.w = (subdivisions.w < 1) ? 1 : subdivisions.w;
-            precision.w    = (precision.w < 1) ? 1 : precision.w;
-            precision.h    = (precision.h < 1) ? 1 : precision.h;
+            precision.w = (precision.w < 1) ? 1 : precision.w;
+            precision.h = (precision.h < 1) ? 1 : precision.h;
 
             var tileSize = {
-                'w' : (xmax - xmin) / subdivisions.w,
-                'h' : (zmax - zmin) / subdivisions.h
+                'w': (xmax - xmin) / subdivisions.w,
+                'h': (zmax - zmin) / subdivisions.h
             };
 
             for (tileRow = 0; tileRow < subdivisions.h; tileRow++) {
                 for (tileCol = 0; tileCol < subdivisions.w; tileCol++) {
-                    applyTile(
-                        xmin + tileCol * tileSize.w,
-                        zmin + tileRow * tileSize.h,
-                        xmin + (tileCol + 1) * tileSize.w,
-                        zmin + (tileRow + 1) * tileSize.h
-                    );
+                    applyTile(xmin + tileCol * tileSize.w, zmin + tileRow * tileSize.h, xmin + (tileCol + 1) * tileSize.w, zmin + (tileRow + 1) * tileSize.h);
                 }
             }
 
-            function applyTile (xTileMin, zTileMin, xTileMax, zTileMax) {
+            function applyTile(xTileMin, zTileMin, xTileMax, zTileMax) {
                 // Indices
                 var base = positions.length / 3;
                 var rowLength = precision.w + 1;
                 for (row = 0; row < precision.h; row++) {
                     for (col = 0; col < precision.w; col++) {
                         var square = [
-                            base +  col + row * rowLength,
+                            base + col + row * rowLength,
                             base + (col + 1) + row * rowLength,
                             base + (col + 1) + (row + 1) * rowLength,
-                            base +  col + (row + 1) * rowLength
+                            base + col + (row + 1) * rowLength
                         ];
 
                         indices.push(square[1]);
@@ -692,7 +687,7 @@
                 }
 
                 // Position, normals and uvs
-                var position = new BABYLON.Vector3.Zero();
+                var position = BABYLON.Vector3.Zero();
                 var normal = new BABYLON.Vector3(0, 1.0, 0);
                 for (row = 0; row <= precision.h; row++) {
                     position.z = (row * (zTileMax - zTileMin)) / precision.h + zTileMin;

+ 25 - 25
Babylon/Mesh/babylon.mesh.vertexData.ts

@@ -418,12 +418,12 @@
             var normals = [];
             var uvs = [];
 
-            height          = height || 1;
-            diameterTop     = diameterTop || 0.5;
-            diameterBottom  = diameterBottom || 1;
-            tessellation    = tessellation || 16;
-            subdivisions    = subdivisions || 1;
-            subdivisions    = (subdivisions < 1) ? 1 : subdivisions;
+            height = height || 1;
+            diameterTop = diameterTop || 0.5;
+            diameterBottom = diameterBottom || 1;
+            tessellation = tessellation || 16;
+            subdivisions = subdivisions || 1;
+            subdivisions = (subdivisions < 1) ? 1 : subdivisions;
 
             var getCircleVector = i => {
                 var angle = (i * 2.0 * Math.PI / tessellation);
@@ -456,7 +456,7 @@
                     var textureCoordinate = new BABYLON.Vector2(
                         circleVector.x * textureScale.x + 0.5,
                         circleVector.z * textureScale.y + 0.5
-                    );
+                        );
 
                     positions.push(position.x, position.y, position.z);
                     uvs.push(textureCoordinate.x, textureCoordinate.y);
@@ -476,9 +476,9 @@
                 }
             };
 
-            var base    = new BABYLON.Vector3(0, -1, 0).scale(height / 2);
-            var offset  = new BABYLON.Vector3(0, 1, 0).scale(height / subdivisions);
-            var stride  = tessellation + 1;
+            var base = new BABYLON.Vector3(0, -1, 0).scale(height / 2);
+            var offset = new BABYLON.Vector3(0, 1, 0).scale(height / subdivisions);
+            var stride = tessellation + 1;
 
             // Positions, normals & uvs
             for (var i = 0; i <= tessellation; i++) {
@@ -491,7 +491,7 @@
                     position = circleVector.scale(radius);
                     position.addInPlace(base.add(offset.scale(s)));
                     textureCoordinate.y += 1 / subdivisions;
-                    radius += (radiusTop - radiusBottom)/subdivisions;
+                    radius += (radiusTop - radiusBottom) / subdivisions;
 
                     // Push in arrays
                     positions.push(position.x, position.y, position.z);
@@ -503,11 +503,11 @@
             // Indices
             for (var s = 0; s < subdivisions - 1; s++) {
                 for (var i = 0; i <= tessellation; i++) {
-                    indices.push( i * subdivisions + s);
+                    indices.push(i * subdivisions + s);
                     indices.push((i * subdivisions + (s + subdivisions)) % (stride * subdivisions));
-                    indices.push( i * subdivisions + (s + 1));
+                    indices.push(i * subdivisions + (s + 1));
 
-                    indices.push( i * subdivisions + (s + 1));
+                    indices.push(i * subdivisions + (s + 1));
                     indices.push((i * subdivisions + (s + subdivisions)) % (stride * subdivisions));
                     indices.push((i * subdivisions + (s + subdivisions + 1)) % (stride * subdivisions));
                 }
@@ -661,7 +661,7 @@
             return vertexData;
         }
 
-        public static CreateTiledGround (xmin: number, zmin: number, xmax: number, zmax: number, subdivisions = {w: 1, h: 1}, precision = {w: 1, h: 1}): VertexData {
+        public static CreateTiledGround(xmin: number, zmin: number, xmax: number, zmax: number, subdivisions = { w: 1, h: 1 }, precision = { w: 1, h: 1 }): VertexData {
             var indices = [];
             var positions = [];
             var normals = [];
@@ -670,12 +670,12 @@
 
             subdivisions.h = (subdivisions.w < 1) ? 1 : subdivisions.h;
             subdivisions.w = (subdivisions.w < 1) ? 1 : subdivisions.w;
-            precision.w    = (precision.w < 1) ? 1 : precision.w;
-            precision.h    = (precision.h < 1) ? 1 : precision.h;
+            precision.w = (precision.w < 1) ? 1 : precision.w;
+            precision.h = (precision.h < 1) ? 1 : precision.h;
 
             var tileSize = {
-                'w' : (xmax - xmin) / subdivisions.w,
-                'h' : (zmax - zmin) / subdivisions.h
+                'w': (xmax - xmin) / subdivisions.w,
+                'h': (zmax - zmin) / subdivisions.h
             };
 
             for (tileRow = 0; tileRow < subdivisions.h; tileRow++) {
@@ -685,21 +685,21 @@
                         zmin + tileRow * tileSize.h,
                         xmin + (tileCol + 1) * tileSize.w,
                         zmin + (tileRow + 1) * tileSize.h
-                    );
+                        );
                 }
             }
 
-            function applyTile (xTileMin: number, zTileMin: number, xTileMax: number, zTileMax: number) {
+            function applyTile(xTileMin: number, zTileMin: number, xTileMax: number, zTileMax: number) {
                 // Indices
                 var base = positions.length / 3;
                 var rowLength = precision.w + 1;
                 for (row = 0; row < precision.h; row++) {
                     for (col = 0; col < precision.w; col++) {
                         var square = [
-                            base +  col + row * rowLength,
+                            base + col + row * rowLength,
                             base + (col + 1) + row * rowLength,
                             base + (col + 1) + (row + 1) * rowLength,
-                            base +  col + (row + 1) * rowLength
+                            base + col + (row + 1) * rowLength
                         ];
 
                         indices.push(square[1]);
@@ -712,7 +712,7 @@
                 }
 
                 // Position, normals and uvs
-                var position = new BABYLON.Vector3.Zero();
+                var position = BABYLON.Vector3.Zero();
                 var normal = new BABYLON.Vector3(0, 1.0, 0);
                 for (row = 0; row <= precision.h; row++) {
                     position.z = (row * (zTileMax - zTileMin)) / precision.h + zTileMin;
@@ -738,7 +738,7 @@
             return vertexData;
         }
 
-        public static CreateGroundFromHeightMap(width: number, height: number, subdivisions: number, minHeight: number, maxHeight: number, buffer: Uint8Array, bufferWidth:  number, bufferHeight: number): VertexData {
+        public static CreateGroundFromHeightMap(width: number, height: number, subdivisions: number, minHeight: number, maxHeight: number, buffer: Uint8Array, bufferWidth: number, bufferHeight: number): VertexData {
             var indices = [];
             var positions = [];
             var normals = [];

+ 423 - 452
Babylon/Tools/babylon.database.js

@@ -1,539 +1,510 @@
-"use strict";
-
-var BABYLON = BABYLON || {};
-
-(function () {
-    function parseURL(url) {
-        var a = document.createElement('a');
-        a.href = url;
-        var fileName = url.substring(url.lastIndexOf("/") + 1, url.length);
-        var absLocation = url.substring(0, url.indexOf(fileName, 0));
-        return absLocation;
-    }
-
-    // Handling various flavors of prefixed version of IndexedDB
-    var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB ||
-        window.msIndexedDB;
-    var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction ||
-        window.msIDBTransaction;
-    var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
-
-    BABYLON.Database = function (urlToScene) {
-        this.currentSceneUrl = BABYLON.Database.ReturnFullUrlLocation(urlToScene);
-        this.db = null;
-        this.enableSceneOffline = false;
-        this.enableTexturesOffline = false;
-        this.manifestVersionFound = 0;
-        this.mustUpdateRessources = false;
-        this.hasReachedQuota = false;
-        this.checkManifestFile();
-    };
-
-    BABYLON.Database.isUASupportingBlobStorage = true;
-
-    BABYLON.Database.ReturnFullUrlLocation = function (url) {
-        if (url.indexOf("http:/") === -1) {
-            return (parseURL(window.location.href) + url);
-        }
-        else {
-            return url;
-        }
-    };
-
-    BABYLON.Database.prototype.checkManifestFile = function () {
-        function noManifestFile() {
-            BABYLON.Tools.Log("Valid manifest file not found. Scene & textures will be loaded directly from the web server.");
-            that.enableSceneOffline = false;
-            that.enableTexturesOffline = false;
+var BABYLON;
+(function (BABYLON) {
+    var Database = (function () {
+        function Database(urlToScene, callbackManifestChecked) {
+            // Handling various flavors of prefixed version of IndexedDB
+            this.idbFactory = (window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB);
+            this.callbackManifestChecked = callbackManifestChecked;
+            this.currentSceneUrl = BABYLON.Database.ReturnFullUrlLocation(urlToScene);
+            this.db = null;
+            this.enableSceneOffline = false;
+            this.enableTexturesOffline = false;
+            this.manifestVersionFound = 0;
+            this.mustUpdateRessources = false;
+            this.hasReachedQuota = false;
+            this.checkManifestFile();
         }
+        Database.prototype.checkManifestFile = function () {
+            function noManifestFile() {
+                BABYLON.Tools.Log("Valid manifest file not found. Scene & textures will be loaded directly from the web server.");
+                that.enableSceneOffline = false;
+                that.enableTexturesOffline = false;
+                that.callbackManifestChecked(false);
+            }
 
-        var that = this;
-        var manifestURL = this.currentSceneUrl + ".manifest";
+            var that = this;
+            var manifestURL = this.currentSceneUrl + ".manifest";
 
-        var xhr = new XMLHttpRequest();
+            var xhr = new XMLHttpRequest();
 
-        xhr.open("GET", manifestURL, false);
+            var manifestURLTimeStamped = manifestURL + (manifestURL.match(/\?/) == null ? "?" : "&") + (new Date()).getTime();
+            xhr.open("GET", manifestURLTimeStamped, true);
 
-        xhr.addEventListener("load", function () {
-            if (xhr.status === 200 || BABYLON.Tools.ValidateXHRData(xhr, 1)) {
-                try {
-                    var manifestFile = JSON.parse(xhr.response);
-                    that.enableSceneOffline = manifestFile.enableSceneOffline;
-                    that.enableTexturesOffline = manifestFile.enableTexturesOffline;
-                    if (manifestFile.version && !isNaN(parseInt(manifestFile.version))) {
-                        that.manifestVersionFound = manifestFile.version;
+            xhr.addEventListener("load", function () {
+                if (xhr.status === 200 || BABYLON.Tools.ValidateXHRData(xhr, 1)) {
+                    try  {
+                        var manifestFile = JSON.parse(xhr.response);
+                        that.enableSceneOffline = manifestFile.enableSceneOffline;
+                        that.enableTexturesOffline = manifestFile.enableTexturesOffline;
+                        if (manifestFile.version && !isNaN(parseInt(manifestFile.version))) {
+                            that.manifestVersionFound = manifestFile.version;
+                        }
+                        if (that.callbackManifestChecked) {
+                            that.callbackManifestChecked(true);
+                        }
+                    } catch (ex) {
+                        noManifestFile();
                     }
-                }
-                catch (ex) {
+                } else {
                     noManifestFile();
                 }
-            }
-            else {
+            }, false);
+
+            xhr.addEventListener("error", function (event) {
                 noManifestFile();
+            }, false);
+
+            try  {
+                xhr.send();
+            } catch (ex) {
+                BABYLON.Tools.Error("Error on XHR send request.");
+                that.callbackManifestChecked(false);
             }
-        }, false);
+        };
 
-        xhr.addEventListener("error", function (event) {
-            noManifestFile();
-        }, false);
+        Database.prototype.openAsync = function (successCallback, errorCallback) {
+            function handleError() {
+                that.isSupported = false;
+                if (errorCallback)
+                    errorCallback();
+            }
 
-        try {
-            xhr.send();
-        }
-        catch (ex) {
-            BABYLON.Tools.Error("Error on XHR send request.");
-        }
-    };
+            var that = this;
+            if (!this.idbFactory || !(this.enableSceneOffline || this.enableTexturesOffline)) {
+                // Your browser doesn't support IndexedDB
+                this.isSupported = false;
+                if (errorCallback)
+                    errorCallback();
+            } else {
+                // If the DB hasn't been opened or created yet
+                if (!this.db) {
+                    this.hasReachedQuota = false;
+                    this.isSupported = true;
+
+                    var request = this.idbFactory.open("babylonjs", 1);
+
+                    // Could occur if user is blocking the quota for the DB and/or doesn't grant access to IndexedDB
+                    request.onerror = function (event) {
+                        handleError();
+                    };
 
-    BABYLON.Database.prototype.openAsync = function (successCallback, errorCallback) {
-        function handleError() {
-            that.isSupported = false;
-            if (errorCallback) errorCallback();
-        }
+                    // executes when a version change transaction cannot complete due to other active transactions
+                    request.onblocked = function (event) {
+                        BABYLON.Tools.Error("IDB request blocked. Please reload the page.");
+                        handleError();
+                    };
+
+                    // DB has been opened successfully
+                    request.onsuccess = function (event) {
+                        that.db = request.result;
+                        successCallback();
+                    };
+
+                    // Initialization of the DB. Creating Scenes & Textures stores
+                    request.onupgradeneeded = function (event) {
+                        that.db = (event.target).result;
+                        try  {
+                            if (event.oldVersion > 0) {
+                                that.db.deleteObjectStore("scenes");
+                                that.db.deleteObjectStore("versions");
+                                that.db.deleteObjectStore("textures");
+                            }
 
-        var that = this;
-        if (!indexedDB || !(this.enableSceneOffline || this.enableTexturesOffline)) {
-            // Your browser doesn't support IndexedDB
-            this.isSupported = false;
-            if (errorCallback) errorCallback();
-        }
-        else {
-            // If the DB hasn't been opened or created yet
-            if (!this.db) {
-                this.hasReachedQuota = false;
-                this.isSupported = true;
+                            var scenesStore = that.db.createObjectStore("scenes", { keyPath: "sceneUrl" });
+                            var versionsStore = that.db.createObjectStore("versions", { keyPath: "sceneUrl" });
+                            var texturesStore = that.db.createObjectStore("textures", { keyPath: "textureUrl" });
+                        } catch (ex) {
+                            BABYLON.Tools.Error("Error while creating object stores. Exception: " + ex.message);
+                            handleError();
+                        }
+                    };
+                } else {
+                    if (successCallback)
+                        successCallback();
+                }
+            }
+        };
 
-                var request = indexedDB.open("babylonjs", 1.0);
+        Database.prototype.loadImageFromDB = function (url, image) {
+            var that = this;
+            var completeURL = BABYLON.Database.ReturnFullUrlLocation(url);
 
-                // Could occur if user is blocking the quota for the DB and/or doesn't grant access to IndexedDB
-                request.onerror = function (event) {
-                    handleError();
-                };
+            var saveAndLoadImage = function () {
+                if (!that.hasReachedQuota && that.db !== null) {
+                    // the texture is not yet in the DB, let's try to save it
+                    that._saveImageIntoDBAsync(completeURL, image);
+                } else {
+                    image.src = url;
+                }
+            };
 
-                // executes when a version change transaction cannot complete due to other active transactions
-                request.onblocked = function (event) {
-                    BABYLON.Tools.Error("IDB request blocked. Please reload the page.");
-                    handleError();
-                };
+            if (!this.mustUpdateRessources) {
+                this._loadImageFromDBAsync(completeURL, image, saveAndLoadImage);
+            } else {
+                saveAndLoadImage();
+            }
+        };
 
-                // DB has been opened successfully
-                request.onsuccess = function (event) {
-                    that.db = request.result;
-                    successCallback();
+        Database.prototype._loadImageFromDBAsync = function (url, image, notInDBCallback) {
+            if (this.isSupported && this.db !== null) {
+                var texture;
+                var transaction = this.db.transaction(["textures"]);
+
+                transaction.onabort = function (event) {
+                    image.src = url;
                 };
 
-                // Initialization of the DB. Creating Scenes & Textures stores
-                request.onupgradeneeded = function (event) {
-                    that.db = event.target.result;
-                    try {
-                        var scenesStore = that.db.createObjectStore("scenes", { keyPath: "sceneUrl" });
-                        var versionsStore = that.db.createObjectStore("versions", { keyPath: "sceneUrl" });
-                        var texturesStore = that.db.createObjectStore("textures", { keyPath: "textureUrl" });
-                    }
-                    catch (ex) {
-                        BABYLON.Tools.Error("Error while creating object stores. Exception: " + ex.message);
-                        handleError();
+                transaction.oncomplete = function (event) {
+                    var blobTextureURL;
+                    if (texture) {
+                        var URL = window.URL || window.webkitURL;
+                        blobTextureURL = URL.createObjectURL(texture.data, { oneTimeOnly: true });
+
+                        image.onerror = function () {
+                            BABYLON.Tools.Error("Error loading image from blob URL: " + blobTextureURL + " switching back to web url: " + url);
+                            image.src = url;
+                        };
+                        image.src = blobTextureURL;
+                    } else {
+                        notInDBCallback();
                     }
                 };
-            }
-            // DB has already been created and opened
-            else {
-                if (successCallback) successCallback();
-            }
-        }
-    };
 
-    BABYLON.Database.prototype.loadImageFromDB = function (url, image) {
-        var that = this;
-        var completeURL = BABYLON.Database.ReturnFullUrlLocation(url);
+                var getRequest = transaction.objectStore("textures").get(url);
 
-        var saveAndLoadImage = function (event) {
-            if (!that.hasReachedQuota && that.db !== null) {
-                // the texture is not yet in the DB, let's try to save it
-                that._saveImageIntoDBAsync(completeURL, image);
-            }
-            // If the texture is not in the DB and we've reached the DB quota limit
-            // let's load it directly from the web
-            else {
+                getRequest.onsuccess = function (event) {
+                    texture = (event.target).result;
+                };
+                getRequest.onerror = function (event) {
+                    BABYLON.Tools.Error("Error loading texture " + url + " from DB.");
+                    image.src = url;
+                };
+            } else {
+                BABYLON.Tools.Error("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
                 image.src = url;
             }
         };
 
-        if (!this.mustUpdateRessources) {
-            this._loadImageFromDBAsync(completeURL, image, saveAndLoadImage);
-        }
-        // First time we're download the images or update requested in the manifest file by a version change
-        else {
-            saveAndLoadImage();
-        }
-    };
-
-    BABYLON.Database.prototype._loadImageFromDBAsync = function (url, image, notInDBCallback) {
-        if (this.isSupported && this.db !== null) {
-            var texture;
-            var transaction = this.db.transaction(["textures"]);
-
-            transaction.onabort = function (event) {
-                image.src = url;
-            };
+        Database.prototype._saveImageIntoDBAsync = function (url, image) {
+            if (this.isSupported) {
+                // In case of error (type not supported or quota exceeded), we're at least sending back XHR data to allow texture loading later on
+                var generateBlobUrl = function () {
+                    var blobTextureURL;
+
+                    if (blob) {
+                        var URL = window.URL || window.webkitURL;
+                        try  {
+                            blobTextureURL = URL.createObjectURL(blob, { oneTimeOnly: true });
+                        } catch (ex) {
+                            blobTextureURL = URL.createObjectURL(blob);
+                        }
+                    }
 
-            transaction.oncomplete = function (event) {
-                var blobTextureURL;
-                if (texture) {
-                    var URL = window.URL || window.webkitURL;
-                    blobTextureURL = URL.createObjectURL(texture.data, { oneTimeOnly: true });
                     image.src = blobTextureURL;
-                }
-                else {
-                    notInDBCallback();
-                }
-            };
+                };
 
-            var getRequest = transaction.objectStore("textures").get(url);
+                if (BABYLON.Database.isUASupportingBlobStorage) {
+                    var that = this;
 
-            getRequest.onsuccess = function (event) {
-                texture = event.target.result;
-            };
-            getRequest.onerror = function (event) {
-                BABYLON.Tools.Error("Error loading texture " + url + " from DB.");
-                image.src = url;
-            };
-        }
-        else {
-            BABYLON.Tools.Error("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
-            image.src = url;
-        }
-    };
-
-    BABYLON.Database.prototype._saveImageIntoDBAsync = function (url, image) {
-        if (this.isSupported) {
-            // In case of error (type not supported or quota exceeded), we're at least sending back XHR data to allow texture loading later on
-            var generateBlobUrl = function () {
-                var blobTextureURL;
-
-                if (blob) {
-                    var URL = window.URL || window.webkitURL;
-                    try {
-                        blobTextureURL = URL.createObjectURL(blob, { oneTimeOnly: true });
-                    }
-                    // Chrome is raising a type error if we're setting the oneTimeOnly parameter
-                    catch (ex) {
-                        blobTextureURL = URL.createObjectURL(blob);
-                    }
-                }
+                    // Create XHR
+                    var xhr = new XMLHttpRequest(), blob;
 
-                image.src = blobTextureURL;
-            };
+                    xhr.open("GET", url, true);
+                    xhr.responseType = "blob";
 
-            if (BABYLON.Database.isUASupportingBlobStorage) {
-                var that = this;
-                // Create XHR
-                var xhr = new XMLHttpRequest(),
-                    blob;
+                    xhr.addEventListener("load", function () {
+                        if (xhr.status === 200) {
+                            // Blob as response (XHR2)
+                            blob = xhr.response;
 
-                xhr.open("GET", url, true);
-                xhr.responseType = "blob";
+                            var transaction = that.db.transaction(["textures"], "readwrite");
 
-                xhr.addEventListener("load", function () {
-                    if (xhr.status === 200) {
-                        // Blob as response (XHR2)
-                        blob = xhr.response;
-
-                        var transaction = that.db.transaction(["textures"], "readwrite");
-
-                        // the transaction could abort because of a QuotaExceededError error
-                        transaction.onabort = function (event) {
-                            try {
-                                if (event.srcElement.error.name === "QuotaExceededError") {
-                                    that.hasReachedQuota = true;
+                            // the transaction could abort because of a QuotaExceededError error
+                            transaction.onabort = function (event) {
+                                try  {
+                                    if (event.srcElement.error.name === "QuotaExceededError") {
+                                        that.hasReachedQuota = true;
+                                    }
+                                } catch (ex) {
                                 }
-                            }
-                            catch (ex) { }
-                            generateBlobUrl();
-                        };
-
-                        transaction.oncomplete = function (event) {
-                            generateBlobUrl();
-                        };
-
-                        var newTexture = {};
-                        newTexture.textureUrl = url;
-                        newTexture.data = blob;
-
-                        try {
-                            // Put the blob into the dabase
-                            var addRequest = transaction.objectStore("textures").put(newTexture);
-                            addRequest.onsuccess = function (event) {
+                                generateBlobUrl();
                             };
-                            addRequest.onerror = function (event) {
+
+                            transaction.oncomplete = function (event) {
                                 generateBlobUrl();
                             };
-                        }
-                        catch (ex) {
-                            // "DataCloneError" generated by Chrome when you try to inject blob into IndexedDB
-                            if (ex.code === 25) {
-                                BABYLON.Database.isUASupportingBlobStorage = false;
+
+                            var newTexture = { textureUrl: url, data: blob };
+
+                            try  {
+                                // Put the blob into the dabase
+                                var addRequest = transaction.objectStore("textures").put(newTexture);
+                                addRequest.onsuccess = function (event) {
+                                };
+                                addRequest.onerror = function (event) {
+                                    generateBlobUrl();
+                                };
+                            } catch (ex) {
+                                // "DataCloneError" generated by Chrome when you try to inject blob into IndexedDB
+                                if (ex.code === 25) {
+                                    BABYLON.Database.isUASupportingBlobStorage = false;
+                                }
+                                image.src = url;
                             }
+                        } else {
                             image.src = url;
                         }
-                    }
-                    else {
+                    }, false);
+
+                    xhr.addEventListener("error", function (event) {
+                        BABYLON.Tools.Error("Error in XHR request in BABYLON.Database.");
                         image.src = url;
-                    }
-                }, false);
+                    }, false);
 
-                xhr.addEventListener("error", function (event) {
-                    BABYLON.Tools.Error("Error in XHR request in BABYLON.Database.");
+                    xhr.send();
+                } else {
                     image.src = url;
-                }, false);
-
-                xhr.send();
-            }
-            else {
+                }
+            } else {
+                BABYLON.Tools.Error("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
                 image.src = url;
             }
-        }
-        else {
-            BABYLON.Tools.Error("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
-            image.src = url;
-        }
-    };
-
-    BABYLON.Database.prototype._checkVersionFromDB = function (url, versionLoaded) {
-        var that = this;
-
-        var updateVersion = function (event) {
-            // the version is not yet in the DB or we need to update it
-            that._saveVersionIntoDBAsync(url, versionLoaded);
         };
-        this._loadVersionFromDBAsync(url, versionLoaded, updateVersion);
-    };
 
-    BABYLON.Database.prototype._loadVersionFromDBAsync = function (url, callback, updateInDBCallback) {
-        if (this.isSupported) {
-            var version;
+        Database.prototype._checkVersionFromDB = function (url, versionLoaded) {
             var that = this;
-            try {
-                var transaction = this.db.transaction(["versions"]);
 
-                transaction.oncomplete = function (event) {
-                    if (version) {
-                        // If the version in the JSON file is > than the version in DB
-                        if (that.manifestVersionFound > version.data) {
+            var updateVersion = function (event) {
+                // the version is not yet in the DB or we need to update it
+                that._saveVersionIntoDBAsync(url, versionLoaded);
+            };
+            this._loadVersionFromDBAsync(url, versionLoaded, updateVersion);
+        };
+
+        Database.prototype._loadVersionFromDBAsync = function (url, callback, updateInDBCallback) {
+            if (this.isSupported) {
+                var version;
+                var that = this;
+                try  {
+                    var transaction = this.db.transaction(["versions"]);
+
+                    transaction.oncomplete = function (event) {
+                        if (version) {
+                            // If the version in the JSON file is > than the version in DB
+                            if (that.manifestVersionFound > version.data) {
+                                that.mustUpdateRessources = true;
+                                updateInDBCallback();
+                            } else {
+                                callback(version.data);
+                            }
+                        } else {
                             that.mustUpdateRessources = true;
                             updateInDBCallback();
                         }
-                        else {
-                            callback(version.data);
-                        }
-                    }
-                        // version was not found in DB
-                    else {
-                        that.mustUpdateRessources = true;
-                        updateInDBCallback();
-                    }
-                };
-
-                transaction.onabort = function (event) {
+                    };
+
+                    transaction.onabort = function (event) {
+                        callback(-1);
+                    };
+
+                    var getRequest = transaction.objectStore("versions").get(url);
+
+                    getRequest.onsuccess = function (event) {
+                        version = (event.target).result;
+                    };
+                    getRequest.onerror = function (event) {
+                        BABYLON.Tools.Error("Error loading version for scene " + url + " from DB.");
+                        callback(-1);
+                    };
+                } catch (ex) {
+                    BABYLON.Tools.Error("Error while accessing 'versions' object store (READ OP). Exception: " + ex.message);
                     callback(-1);
-                };
-
-                var getRequest = transaction.objectStore("versions").get(url);
+                }
+            } else {
+                BABYLON.Tools.Error("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
+                callback(-1);
+            }
+        };
 
-                getRequest.onsuccess = function (event) {
-                    version = event.target.result;
-                };
-                getRequest.onerror = function (event) {
-                    BABYLON.Tools.Error("Error loading version for scene " + url + " from DB.");
+        Database.prototype._saveVersionIntoDBAsync = function (url, callback) {
+            if (this.isSupported && !this.hasReachedQuota) {
+                var that = this;
+                try  {
+                    // Open a transaction to the database
+                    var transaction = this.db.transaction(["versions"], "readwrite");
+
+                    // the transaction could abort because of a QuotaExceededError error
+                    transaction.onabort = function (event) {
+                        try  {
+                            if (event.srcElement.error.name === "QuotaExceededError") {
+                                that.hasReachedQuota = true;
+                            }
+                        } catch (ex) {
+                        }
+                        callback(-1);
+                    };
+
+                    transaction.oncomplete = function (event) {
+                        callback(that.manifestVersionFound);
+                    };
+
+                    var newVersion = { sceneUrl: url, data: this.manifestVersionFound };
+
+                    // Put the scene into the database
+                    var addRequest = transaction.objectStore("versions").put(newVersion);
+                    addRequest.onsuccess = function (event) {
+                    };
+                    addRequest.onerror = function (event) {
+                        BABYLON.Tools.Error("Error in DB add version request in BABYLON.Database.");
+                    };
+                } catch (ex) {
+                    BABYLON.Tools.Error("Error while accessing 'versions' object store (WRITE OP). Exception: " + ex.message);
                     callback(-1);
-                };
-            }
-            catch (ex) {
-                BABYLON.Tools.Error("Error while accessing 'versions' object store (READ OP). Exception: " + ex.message);
+                }
+            } else {
                 callback(-1);
             }
-        }
-        else {
-            BABYLON.Tools.Error("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
-            callback(-1);
-        }
-    };
+        };
 
-    BABYLON.Database.prototype._saveVersionIntoDBAsync = function (url, callback) {
-        if (this.isSupported && !this.hasReachedQuota) {
+        Database.prototype.loadSceneFromDB = function (url, sceneLoaded, progressCallBack, errorCallback) {
             var that = this;
-            try {
-                // Open a transaction to the database
-                var transaction = this.db.transaction(["versions"], "readwrite");
+            var completeUrl = BABYLON.Database.ReturnFullUrlLocation(url);
 
-                // the transaction could abort because of a QuotaExceededError error
-                transaction.onabort = function (event) {
-                    try {
-                        if (event.srcElement.error.name === "QuotaExceededError") {
-                            that.hasReachedQuota = true;
-                        }
+            var saveAndLoadScene = function (event) {
+                // the scene is not yet in the DB, let's try to save it
+                that._saveSceneIntoDBAsync(completeUrl, sceneLoaded, progressCallBack);
+            };
+
+            this._checkVersionFromDB(completeUrl, function (version) {
+                if (version !== -1) {
+                    if (!that.mustUpdateRessources) {
+                        that._loadSceneFromDBAsync(completeUrl, sceneLoaded, saveAndLoadScene);
+                    } else {
+                        that._saveSceneIntoDBAsync(completeUrl, sceneLoaded, progressCallBack);
                     }
-                    catch (ex) { }
-                    callback(-1);
-                };
+                } else {
+                    errorCallback();
+                }
+            });
+        };
+
+        Database.prototype._loadSceneFromDBAsync = function (url, callback, notInDBCallback) {
+            if (this.isSupported) {
+                var scene;
+                var transaction = this.db.transaction(["scenes"]);
 
                 transaction.oncomplete = function (event) {
-                    callback(that.manifestVersionFound);
+                    if (scene) {
+                        callback(scene.data);
+                    } else {
+                        notInDBCallback();
+                    }
                 };
 
-                var newVersion = {};
-                newVersion.sceneUrl = url;
-                newVersion.data = this.manifestVersionFound;
+                transaction.onabort = function (event) {
+                    notInDBCallback();
+                };
 
-                // Put the scene into the database
-                var addRequest = transaction.objectStore("versions").put(newVersion);
-                addRequest.onsuccess = function (event) {
+                var getRequest = transaction.objectStore("scenes").get(url);
+
+                getRequest.onsuccess = function (event) {
+                    scene = (event.target).result;
                 };
-                addRequest.onerror = function (event) {
-                    BABYLON.Tools.Error("Error in DB add version request in BABYLON.Database.");
+                getRequest.onerror = function (event) {
+                    BABYLON.Tools.Error("Error loading scene " + url + " from DB.");
+                    notInDBCallback();
                 };
+            } else {
+                BABYLON.Tools.Error("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
+                callback();
             }
-            catch (ex) {
-                BABYLON.Tools.Error("Error while accessing 'versions' object store (WRITE OP). Exception: " + ex.message);
-                callback(-1);
-            }
-        }
-        else {
-            callback(-1);
-        }
-    };
-
-    BABYLON.Database.prototype.loadSceneFromDB = function (url, sceneLoaded, progressCallBack, errorCallback) {
-        var that = this;
-        var completeUrl = BABYLON.Database.ReturnFullUrlLocation(url);
-        
-        var saveAndLoadScene = function (event) {
-            // the scene is not yet in the DB, let's try to save it
-            that._saveSceneIntoDBAsync(completeUrl, sceneLoaded, progressCallBack);
         };
 
-        this._checkVersionFromDB(completeUrl, function (version) {
-            if (version !== -1) {
-                if (!that.mustUpdateRessources) {
-                    that._loadSceneFromDBAsync(completeUrl, sceneLoaded, saveAndLoadScene);
-                }
-                else {
-                    that._saveSceneIntoDBAsync(completeUrl, sceneLoaded, progressCallBack);
-                }
-            }
-            else {
-                errorCallback();
-            }
-        });
-    };
-
-    BABYLON.Database.prototype._loadSceneFromDBAsync = function (url, callback, notInDBCallback) {
-        if (this.isSupported) {
-            var scene;
-            var transaction = this.db.transaction(["scenes"]);
-
-            transaction.oncomplete = function (event) {
-                if (scene) {
-                    callback(scene.data);
-                }
-                // scene was not found in DB
-                else {
-                    notInDBCallback();
-                }
-            };
-
-            transaction.onabort = function (event) {
-                notInDBCallback();
-            };
-
-            var getRequest = transaction.objectStore("scenes").get(url);
-
-            getRequest.onsuccess = function (event) {
-                scene = event.target.result;
-            };
-            getRequest.onerror = function (event) {
-                BABYLON.Tools.Error("Error loading scene " + url + " from DB.");
-                notInDBCallback();
-            };
-        }
-        else {
-            BABYLON.Tools.Error("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
-            callback();
-        }
-    };
+        Database.prototype._saveSceneIntoDBAsync = function (url, callback, progressCallback) {
+            if (this.isSupported) {
+                // Create XHR
+                var xhr = new XMLHttpRequest(), sceneText;
+                var that = this;
 
-    BABYLON.Database.prototype._saveSceneIntoDBAsync = function (url, callback, progressCallback) {
-        if (this.isSupported) {
-            // Create XHR
-            var xhr = new XMLHttpRequest(), sceneText;
-            var that = this;
+                xhr.open("GET", url, true);
 
-            var urlTimeStamped = url + (url.match(/\?/) == null ? "?" : "&") + (new Date()).getTime();
-            xhr.open("GET", urlTimeStamped, true);
+                xhr.onprogress = progressCallback;
 
-            xhr.onprogress = progressCallback;
-            
-            xhr.addEventListener("load", function () {
-                if (xhr.status === 200 || BABYLON.Tools.ValidateXHRData(xhr, 1)) {
-                    // Blob as response (XHR2)
-                    sceneText = xhr.responseText;
-
-                    if (!that.hasReachedQuota) {
-                        // Open a transaction to the database
-                        var transaction = that.db.transaction(["scenes"], "readwrite");
-
-                        // the transaction could abort because of a QuotaExceededError error
-                        transaction.onabort = function (event) {
-                            try {
-                                if (event.srcElement.error.name === "QuotaExceededError") {
-                                    that.hasReachedQuota = true;
+                xhr.addEventListener("load", function () {
+                    if (xhr.status === 200 || BABYLON.Tools.ValidateXHRData(xhr, 1)) {
+                        // Blob as response (XHR2)
+                        sceneText = xhr.responseText;
+
+                        if (!that.hasReachedQuota) {
+                            // Open a transaction to the database
+                            var transaction = that.db.transaction(["scenes"], "readwrite");
+
+                            // the transaction could abort because of a QuotaExceededError error
+                            transaction.onabort = function (event) {
+                                try  {
+                                    if (event.srcElement.error.name === "QuotaExceededError") {
+                                        that.hasReachedQuota = true;
+                                    }
+                                } catch (ex) {
                                 }
-                            }
-                            catch (ex) { }
-                            callback(sceneText);
-                        };
-
-                        transaction.oncomplete = function (event) {
-                            callback(sceneText);
-                        };
-
-                        var newScene = {};
-                        newScene.sceneUrl = url;
-                        newScene.data = sceneText;
-                        newScene.version = that.manifestVersionFound;
-
-                        try {
-                            // Put the scene into the database
-                            var addRequest = transaction.objectStore("scenes").put(newScene);
-                            addRequest.onsuccess = function (event) {
+                                callback(sceneText);
                             };
-                            addRequest.onerror = function (event) {
-                                BABYLON.Tools.Error("Error in DB add scene request in BABYLON.Database.");
+
+                            transaction.oncomplete = function (event) {
+                                callback(sceneText);
                             };
-                        }
-                        catch (ex) {
+
+                            var newScene = { sceneUrl: url, data: sceneText, version: that.manifestVersionFound };
+
+                            try  {
+                                // Put the scene into the database
+                                var addRequest = transaction.objectStore("scenes").put(newScene);
+                                addRequest.onsuccess = function (event) {
+                                };
+                                addRequest.onerror = function (event) {
+                                    BABYLON.Tools.Error("Error in DB add scene request in BABYLON.Database.");
+                                };
+                            } catch (ex) {
+                                callback(sceneText);
+                            }
+                        } else {
                             callback(sceneText);
                         }
+                    } else {
+                        callback();
                     }
-                    else {
-                        callback(sceneText);
-                    }
-                }
-                else {
+                }, false);
+
+                xhr.addEventListener("error", function (event) {
+                    BABYLON.Tools.Error("error on XHR request.");
                     callback();
-                }
-            }, false);
+                }, false);
 
-            xhr.addEventListener("error", function (event) {
-                BABYLON.Tools.Error("error on XHR request.");
+                xhr.send();
+            } else {
+                BABYLON.Tools.Error("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
                 callback();
-            }, false);
+            }
+        };
+        Database.isUASupportingBlobStorage = true;
+
+        Database.parseURL = function (url) {
+            var a = document.createElement('a');
+            a.href = url;
+            var fileName = url.substring(url.lastIndexOf("/") + 1, url.length);
+            var absLocation = url.substring(0, url.indexOf(fileName, 0));
+            return absLocation;
+        };
 
-            xhr.send();
-        }
-        else {
-            BABYLON.Tools.Error("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
-            callback();
-        }
-    };
-})();
+        Database.ReturnFullUrlLocation = function (url) {
+            if (url.indexOf("http:/") === -1) {
+                return (BABYLON.Database.parseURL(window.location.href) + url);
+            } else {
+                return url;
+            }
+        };
+        return Database;
+    })();
+    BABYLON.Database = Database;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.database.js.map

+ 553 - 0
Babylon/Tools/babylon.database.ts

@@ -0,0 +1,553 @@
+module BABYLON {
+    export class Database {
+        private callbackManifestChecked: (boolean) => any;
+        private currentSceneUrl: string;
+        private db: IDBDatabase;
+        private enableSceneOffline: boolean;
+        private enableTexturesOffline: boolean;
+        private manifestVersionFound: number;
+        private mustUpdateRessources: boolean;
+        private hasReachedQuota: boolean;
+        private isSupported: boolean;
+
+        // Handling various flavors of prefixed version of IndexedDB
+        private idbFactory = <IDBFactory> (window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB);
+
+        static isUASupportingBlobStorage: boolean = true;
+
+        constructor(urlToScene: string, callbackManifestChecked: (boolean) => any) {          
+            this.callbackManifestChecked = callbackManifestChecked;
+            this.currentSceneUrl = BABYLON.Database.ReturnFullUrlLocation(urlToScene);
+            this.db = null;
+            this.enableSceneOffline = false;
+            this.enableTexturesOffline = false;
+            this.manifestVersionFound = 0;
+            this.mustUpdateRessources = false;
+            this.hasReachedQuota = false;
+            this.checkManifestFile();
+        }
+
+        static parseURL = function(url) {
+            var a = document.createElement('a');
+            a.href = url;
+            var fileName = url.substring(url.lastIndexOf("/") + 1, url.length);
+            var absLocation = url.substring(0, url.indexOf(fileName, 0));
+            return absLocation;
+        }
+
+        static ReturnFullUrlLocation = function (url): string {
+            if (url.indexOf("http:/") === -1) {
+                return (BABYLON.Database.parseURL(window.location.href) + url);
+            }
+            else {
+                return url;
+            }
+        }
+
+        public checkManifestFile() {
+            function noManifestFile() {
+                BABYLON.Tools.Log("Valid manifest file not found. Scene & textures will be loaded directly from the web server.");
+                that.enableSceneOffline = false;
+                that.enableTexturesOffline = false;
+                that.callbackManifestChecked(false);
+            }
+
+            var that = this;
+            var manifestURL = this.currentSceneUrl + ".manifest";
+
+            var xhr: XMLHttpRequest = new XMLHttpRequest();
+
+            var manifestURLTimeStamped = manifestURL + (manifestURL.match(/\?/) == null ? "?" : "&") + (new Date()).getTime();
+            xhr.open("GET", manifestURLTimeStamped, true);
+
+            xhr.addEventListener("load", function () {
+                if (xhr.status === 200 || BABYLON.Tools.ValidateXHRData(xhr, 1)) {
+                    try {
+                        var manifestFile = JSON.parse(xhr.response);
+                        that.enableSceneOffline = manifestFile.enableSceneOffline;
+                        that.enableTexturesOffline = manifestFile.enableTexturesOffline;
+                        if (manifestFile.version && !isNaN(parseInt(manifestFile.version))) {
+                            that.manifestVersionFound = manifestFile.version;
+                        }
+                        if (that.callbackManifestChecked) {
+                            that.callbackManifestChecked(true);
+                        }
+                    }
+                    catch (ex) {
+                        noManifestFile();
+                    }
+                }
+                else {
+                    noManifestFile();
+                }
+            }, false);
+
+            xhr.addEventListener("error", function (event) {
+                noManifestFile();
+            }, false);
+
+            try {
+                xhr.send();
+            }
+            catch (ex) {
+                BABYLON.Tools.Error("Error on XHR send request.");
+                that.callbackManifestChecked(false);
+            }
+        }
+
+        public openAsync(successCallback, errorCallback) {
+            function handleError() {
+                that.isSupported = false;
+                if (errorCallback) errorCallback();
+            }
+
+            var that = this;
+            if (!this.idbFactory || !(this.enableSceneOffline || this.enableTexturesOffline)) {
+                // Your browser doesn't support IndexedDB
+                this.isSupported = false;
+                if (errorCallback) errorCallback();
+            }
+            else {
+                // If the DB hasn't been opened or created yet
+                if (!this.db) {
+                    this.hasReachedQuota = false;
+                    this.isSupported = true;
+
+                    var request: IDBOpenDBRequest = this.idbFactory.open("babylonjs", 1);
+
+                    // Could occur if user is blocking the quota for the DB and/or doesn't grant access to IndexedDB
+                    request.onerror = function (event) {
+                        handleError();
+                    };
+
+                    // executes when a version change transaction cannot complete due to other active transactions
+                    request.onblocked = function (event) {
+                        BABYLON.Tools.Error("IDB request blocked. Please reload the page.");
+                        handleError();
+                    };
+                    
+                    // DB has been opened successfully
+                    request.onsuccess = function (event) {
+                        that.db = request.result;
+                        successCallback();
+                    };
+
+                    // Initialization of the DB. Creating Scenes & Textures stores
+                    request.onupgradeneeded = function (event: IDBVersionChangeEvent) {
+                        that.db = (<any>(event.target)).result;
+                        try {
+                            if (event.oldVersion > 0) {
+                                that.db.deleteObjectStore("scenes");
+                                that.db.deleteObjectStore("versions");
+                                that.db.deleteObjectStore("textures");
+                            }
+                            
+                            var scenesStore = that.db.createObjectStore("scenes", { keyPath: "sceneUrl" });
+                            var versionsStore = that.db.createObjectStore("versions", { keyPath: "sceneUrl" });
+                            var texturesStore = that.db.createObjectStore("textures", { keyPath: "textureUrl" });
+                        }
+                        catch (ex) {
+                            BABYLON.Tools.Error("Error while creating object stores. Exception: " + ex.message);
+                            handleError();
+                        }
+                    };
+                }
+                // DB has already been created and opened
+                else {
+                    if (successCallback) successCallback();
+                }
+            }
+        }
+
+        public loadImageFromDB(url: string, image: HTMLImageElement) {
+            var that = this;
+            var completeURL = BABYLON.Database.ReturnFullUrlLocation(url);
+
+            var saveAndLoadImage = function () {
+                if (!that.hasReachedQuota && that.db !== null) {
+                    // the texture is not yet in the DB, let's try to save it
+                    that._saveImageIntoDBAsync(completeURL, image);
+                }
+                // If the texture is not in the DB and we've reached the DB quota limit
+                // let's load it directly from the web
+                else {
+                    image.src = url;
+                }
+            };
+
+            if (!this.mustUpdateRessources) {
+                this._loadImageFromDBAsync(completeURL, image, saveAndLoadImage);
+            }
+            // First time we're download the images or update requested in the manifest file by a version change
+            else {
+                saveAndLoadImage();
+            }
+        }
+
+        private _loadImageFromDBAsync(url: string, image: HTMLImageElement, notInDBCallback: () => any) {
+            if (this.isSupported && this.db !== null) {
+                var texture;
+                var transaction: IDBTransaction = this.db.transaction(["textures"]);
+
+                transaction.onabort = function (event) {
+                    image.src = url;
+                };
+
+                transaction.oncomplete = function (event) {
+                    var blobTextureURL;
+                    if (texture) {
+                        var URL = window.URL || window.webkitURL;
+                        blobTextureURL = URL.createObjectURL(texture.data, { oneTimeOnly: true });
+                       
+                        image.onerror = function () {
+                            BABYLON.Tools.Error("Error loading image from blob URL: " + blobTextureURL + " switching back to web url: " + url);
+                            image.src = url;
+                        };
+                        image.src = blobTextureURL;
+                    }
+                    else {
+                        notInDBCallback();
+                    }
+                };
+
+                var getRequest: IDBRequest = transaction.objectStore("textures").get(url);
+
+                getRequest.onsuccess = function (event) {
+                    texture = (<any>(event.target)).result;
+                };
+                getRequest.onerror = function (event) {
+                    BABYLON.Tools.Error("Error loading texture " + url + " from DB.");
+                    image.src = url;
+                };
+            }
+            else {
+                BABYLON.Tools.Error("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
+                image.src = url;
+            }
+        }
+
+        private _saveImageIntoDBAsync(url: string, image: HTMLImageElement) {
+            if (this.isSupported) {
+                // In case of error (type not supported or quota exceeded), we're at least sending back XHR data to allow texture loading later on
+                var generateBlobUrl = function () {
+                    var blobTextureURL;
+
+                    if (blob) {
+                        var URL = window.URL || window.webkitURL;
+                        try {
+                            blobTextureURL = URL.createObjectURL(blob, { oneTimeOnly: true });
+                        }
+                        // Chrome is raising a type error if we're setting the oneTimeOnly parameter
+                        catch (ex) {
+                            blobTextureURL = URL.createObjectURL(blob);
+                        }
+                    }
+
+                    image.src = blobTextureURL;
+                };
+
+                if (BABYLON.Database.isUASupportingBlobStorage) {
+                    var that = this;
+                    // Create XHR
+                    var xhr = new XMLHttpRequest(),
+                        blob: Blob;
+
+                    xhr.open("GET", url, true);
+                    xhr.responseType = "blob";
+
+                    xhr.addEventListener("load", function () {
+                        if (xhr.status === 200) {
+                            // Blob as response (XHR2)
+                            blob = xhr.response;
+
+                            var transaction = that.db.transaction(["textures"], "readwrite");
+
+                            // the transaction could abort because of a QuotaExceededError error
+                            transaction.onabort = function (event) {
+                                try {
+                                    if (event.srcElement.error.name === "QuotaExceededError") {
+                                        that.hasReachedQuota = true;
+                                    }
+                                }
+                                catch (ex) { }
+                                generateBlobUrl();
+                            };
+
+                            transaction.oncomplete = function (event) {
+                                generateBlobUrl();
+                            };
+
+                            var newTexture = { textureUrl: url, data: blob };
+
+                            try {
+                                // Put the blob into the dabase
+                                var addRequest = transaction.objectStore("textures").put(newTexture);
+                                addRequest.onsuccess = function (event) {
+                                };
+                                addRequest.onerror = function (event) {
+                                    generateBlobUrl();
+                                };
+                            }
+                            catch (ex) {
+                                // "DataCloneError" generated by Chrome when you try to inject blob into IndexedDB
+                                if (ex.code === 25) {
+                                    BABYLON.Database.isUASupportingBlobStorage = false;
+                                }
+                                image.src = url;
+                            }
+                        }
+                        else {
+                            image.src = url;
+                        }
+                    }, false);
+
+                    xhr.addEventListener("error", function (event) {
+                        BABYLON.Tools.Error("Error in XHR request in BABYLON.Database.");
+                        image.src = url;
+                    }, false);
+
+                    xhr.send();
+                }
+                else {
+                    image.src = url;
+                }
+            }
+            else {
+                BABYLON.Tools.Error("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
+                image.src = url;
+            }
+        }
+
+        private _checkVersionFromDB(url: string, versionLoaded) {
+            var that = this;
+
+            var updateVersion = function (event) {
+                // the version is not yet in the DB or we need to update it
+                that._saveVersionIntoDBAsync(url, versionLoaded);
+            };
+            this._loadVersionFromDBAsync(url, versionLoaded, updateVersion);
+        }
+
+        private _loadVersionFromDBAsync(url: string, callback, updateInDBCallback) {
+            if (this.isSupported) {
+                var version;
+                var that = this;
+                try {
+                    var transaction = this.db.transaction(["versions"]);
+
+                    transaction.oncomplete = function (event) {
+                        if (version) {
+                            // If the version in the JSON file is > than the version in DB
+                            if (that.manifestVersionFound > version.data) {
+                                that.mustUpdateRessources = true;
+                                updateInDBCallback();
+                            }
+                            else {
+                                callback(version.data);
+                            }
+                        }
+                        // version was not found in DB
+                        else {
+                            that.mustUpdateRessources = true;
+                            updateInDBCallback();
+                        }
+                    };
+
+                    transaction.onabort = function (event) {
+                        callback(-1);
+                    };
+
+                    var getRequest = transaction.objectStore("versions").get(url);
+
+                    getRequest.onsuccess = function (event) {
+                        version = (<any>(event.target)).result;
+                    };
+                    getRequest.onerror = function (event) {
+                        BABYLON.Tools.Error("Error loading version for scene " + url + " from DB.");
+                        callback(-1);
+                    };
+                }
+                catch (ex) {
+                    BABYLON.Tools.Error("Error while accessing 'versions' object store (READ OP). Exception: " + ex.message);
+                    callback(-1);
+                }
+            }
+            else {
+                BABYLON.Tools.Error("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
+                callback(-1);
+            }
+        }
+
+        private _saveVersionIntoDBAsync(url: string, callback) {
+            if (this.isSupported && !this.hasReachedQuota) {
+                var that = this;
+                try {
+                    // Open a transaction to the database
+                    var transaction = this.db.transaction(["versions"], "readwrite");
+
+                    // the transaction could abort because of a QuotaExceededError error
+                    transaction.onabort = function (event) {
+                        try {
+                            if (event.srcElement.error.name === "QuotaExceededError") {
+                                that.hasReachedQuota = true;
+                            }
+                        }
+                        catch (ex) { }
+                        callback(-1);
+                    };
+
+                    transaction.oncomplete = function (event) {
+                        callback(that.manifestVersionFound);
+                    };
+
+                    var newVersion = { sceneUrl: url, data: this.manifestVersionFound };
+
+                    // Put the scene into the database
+                    var addRequest = transaction.objectStore("versions").put(newVersion);
+                    addRequest.onsuccess = function (event) {
+                    };
+                    addRequest.onerror = function (event) {
+                        BABYLON.Tools.Error("Error in DB add version request in BABYLON.Database.");
+                    };
+                }
+                catch (ex) {
+                    BABYLON.Tools.Error("Error while accessing 'versions' object store (WRITE OP). Exception: " + ex.message);
+                    callback(-1);
+                }
+            }
+            else {
+                callback(-1);
+            }
+        }
+
+        private loadSceneFromDB(url, sceneLoaded, progressCallBack, errorCallback) {
+            var that = this;
+            var completeUrl = BABYLON.Database.ReturnFullUrlLocation(url);
+
+            var saveAndLoadScene = function (event) {
+                // the scene is not yet in the DB, let's try to save it
+                that._saveSceneIntoDBAsync(completeUrl, sceneLoaded, progressCallBack);
+            };
+
+            this._checkVersionFromDB(completeUrl, function (version) {
+                if (version !== -1) {
+                    if (!that.mustUpdateRessources) {
+                        that._loadSceneFromDBAsync(completeUrl, sceneLoaded, saveAndLoadScene);
+                    }
+                    else {
+                        that._saveSceneIntoDBAsync(completeUrl, sceneLoaded, progressCallBack);
+                    }
+                }
+                else {
+                    errorCallback();
+                }
+            });
+        }
+
+        private _loadSceneFromDBAsync(url, callback, notInDBCallback) {
+            if (this.isSupported) {
+                var scene;
+                var transaction = this.db.transaction(["scenes"]);
+
+                transaction.oncomplete = function (event) {
+                    if (scene) {
+                        callback(scene.data);
+                    }
+                    // scene was not found in DB
+                    else {
+                        notInDBCallback();
+                    }
+                };
+
+                transaction.onabort = function (event) {
+                    notInDBCallback();
+                };
+
+                var getRequest = transaction.objectStore("scenes").get(url);
+
+                getRequest.onsuccess = function (event) {
+                    scene = (<any>(event.target)).result;
+                };
+                getRequest.onerror = function (event) {
+                    BABYLON.Tools.Error("Error loading scene " + url + " from DB.");
+                    notInDBCallback();
+                };
+            }
+            else {
+                BABYLON.Tools.Error("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
+                callback();
+            }
+        }
+
+        private _saveSceneIntoDBAsync(url: string, callback, progressCallback) {
+            if (this.isSupported) {
+                // Create XHR
+                var xhr = new XMLHttpRequest(), sceneText;
+                var that = this;
+
+                xhr.open("GET", url, true);
+
+                xhr.onprogress = progressCallback;
+
+                xhr.addEventListener("load", function () {
+                    if (xhr.status === 200 || BABYLON.Tools.ValidateXHRData(xhr, 1)) {
+                        // Blob as response (XHR2)
+                        sceneText = xhr.responseText;
+
+                        if (!that.hasReachedQuota) {
+                            // Open a transaction to the database
+                            var transaction = that.db.transaction(["scenes"], "readwrite");
+
+                            // the transaction could abort because of a QuotaExceededError error
+                            transaction.onabort = function (event) {
+                                try {
+                                    if (event.srcElement.error.name === "QuotaExceededError") {
+                                        that.hasReachedQuota = true;
+                                    }
+                                }
+                                catch (ex) { }
+                                callback(sceneText);
+                            };
+
+                            transaction.oncomplete = function (event) {
+                                callback(sceneText);
+                            };
+
+                            var newScene = { sceneUrl: url, data: sceneText, version: that.manifestVersionFound};
+
+                            try {
+                                // Put the scene into the database
+                                var addRequest = transaction.objectStore("scenes").put(newScene);
+                                addRequest.onsuccess = function (event) {
+                                };
+                                addRequest.onerror = function (event) {
+                                    BABYLON.Tools.Error("Error in DB add scene request in BABYLON.Database.");
+                                };
+                            }
+                            catch (ex) {
+                                callback(sceneText);
+                            }
+                        }
+                        else {
+                            callback(sceneText);
+                        }
+                    }
+                    else {
+                        callback();
+                    }
+                }, false);
+
+                xhr.addEventListener("error", function (event) {
+                    BABYLON.Tools.Error("error on XHR request.");
+                    callback();
+                }, false);
+
+                xhr.send();
+            }
+            else {
+                BABYLON.Tools.Error("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
+                callback();
+            }
+        }
+    }
+}

+ 1 - 2
Babylon/Tools/babylon.filesInput.js

@@ -1,5 +1,4 @@
-
-var BABYLON;
+var BABYLON;
 (function (BABYLON) {
     var FilesInput = (function () {
         /// Register to core BabylonJS object: engine, scene, rendering canvas, callback function when the scene will be loaded,

+ 1 - 8
Babylon/Tools/babylon.filesInput.ts

@@ -1,11 +1,4 @@
-// ANY
-declare module BABYLON {
-    export class SceneLoader {
-        static Load: (param1: any, param2: any, param3: any, param4: any, param5: any) => void;
-    }
-}
-
-module BABYLON {
+module BABYLON {
     export class FilesInput {
         private engine: BABYLON.Engine;
         private currentScene: BABYLON.Scene;

+ 1 - 2
Babylon/Tools/babylon.tools.js

@@ -1,5 +1,4 @@
-
-var BABYLON;
+var BABYLON;
 (function (BABYLON) {
     
 

+ 1 - 8
Babylon/Tools/babylon.tools.ts

@@ -1,11 +1,4 @@
-// ANY
-declare module BABYLON {
-    export class Database {
-        static isUASupportingBlobStorage: boolean;
-    }
-}
-
-module BABYLON {
+module BABYLON {
 
     //class FilesTextures { } //ANY
 

+ 14 - 0
Babylon/babylon.mixins.ts

@@ -1,5 +1,15 @@
 // Mixins
 interface Window {
+    mozIndexedDB(func: any): any;
+    webkitIndexedDB(func: any): any;
+    IDBTransaction(func: any): any;
+    webkitIDBTransaction(func: any): any;
+    msIDBTransaction(func: any): any;
+    IDBKeyRange(func: any): any;
+    webkitIDBKeyRange(func: any): any;
+    msIDBKeyRange(func: any): any;
+    URL: HTMLURL;
+    webkitURL: HTMLURL;
     webkitRequestAnimationFrame(func: any): any;
     mozRequestAnimationFrame(func: any): any;
     oRequestAnimationFrame(func: any): any;
@@ -7,6 +17,10 @@ interface Window {
     MSGesture: MSGesture;
 }
 
+interface HTMLURL {
+    createObjectURL(param1: any, param2?: any);
+}
+
 interface Document {
     exitFullscreen(): void;
     webkitCancelFullScreen(): void;

Разлика између датотеке није приказан због своје велике величине
+ 2 - 2
babylon.1.13-beta-debug.js


Разлика између датотеке није приказан због своје велике величине
+ 12 - 12
babylon.1.13-beta.js