瀏覽代碼

Merge pull request #3396 from BabylonJS/master

Nightly
David Catuhe 7 年之前
父節點
當前提交
9447ebbb1d
共有 58 個文件被更改,包括 14689 次插入13933 次删除
  1. 12 0
      .vscode/launch.json
  2. 4386 4356
      Playground/babylon.d.txt
  3. 12 5
      Tools/Gulp/config.json
  4. 16 2
      Tools/Gulp/gulpfile.js
  5. 5 5
      Tools/Gulp/package.json
  6. 7973 7941
      dist/preview release/babylon.d.ts
  7. 47 47
      dist/preview release/babylon.js
  8. 761 567
      dist/preview release/babylon.max.js
  9. 47 47
      dist/preview release/babylon.worker.js
  10. 47 47
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  11. 779 575
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  12. 1 1
      dist/preview release/gui/package.json
  13. 1 1
      dist/preview release/inspector/package.json
  14. 4 4
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  15. 12 2
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  16. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  17. 10 10
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  18. 26 12
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  19. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  20. 10 10
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  21. 26 12
      dist/preview release/loaders/babylon.glTFFileLoader.js
  22. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  23. 26 12
      dist/preview release/loaders/babylonjs.loaders.js
  24. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  25. 10 10
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  26. 1 1
      dist/preview release/loaders/package.json
  27. 1 1
      dist/preview release/materialsLibrary/package.json
  28. 1 1
      dist/preview release/postProcessesLibrary/package.json
  29. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  30. 1 1
      dist/preview release/serializers/package.json
  31. 51 51
      dist/preview release/viewer/babylon.viewer.js
  32. 1 1
      dist/preview release/viewer/package.json
  33. 3 0
      dist/preview release/what's new.md
  34. 23 17
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  35. 16 6
      loaders/src/glTF/babylon.glTFFileLoader.ts
  36. 1 1
      package.json
  37. 176 48
      src/Engine/babylon.engine.ts
  38. 8 2
      src/Engine/babylon.nullEngine.ts
  39. 4 5
      src/Layer/babylon.highlightlayer.ts
  40. 2 2
      src/Layer/babylon.layer.ts
  41. 1 1
      src/LensFlare/babylon.lensFlareSystem.ts
  42. 57 55
      src/Loading/babylon.sceneLoader.ts
  43. 2 2
      src/Materials/Textures/Procedurals/babylon.proceduralTexture.ts
  44. 21 19
      src/Materials/Textures/babylon.internalTexture.ts
  45. 33 1
      src/Materials/babylon.material.ts
  46. 1 1
      src/Mesh/babylon.linesMesh.ts
  47. 21 19
      src/Mesh/babylon.mesh.ts
  48. 2 2
      src/Particles/babylon.gpuParticleSystem.ts
  49. 1 1
      src/Particles/babylon.particleSystem.ts
  50. 2 2
      src/PostProcess/babylon.postProcessManager.ts
  51. 3 3
      src/Rendering/babylon.boundingBoxRenderer.ts
  52. 1 1
      src/Rendering/babylon.edgesRenderer.ts
  53. 2 2
      src/Sprites/babylon.spriteManager.ts
  54. 16 1
      src/Tools/babylon.tools.ts
  55. 1 1
      src/babylon.scene.ts
  56. 7 8
      src/tsconfig.json
  57. 二進制
      tests/validation/ReferenceImages/customRTT.png
  58. 7 0
      tests/validation/config.json

+ 12 - 0
.vscode/launch.json

@@ -125,6 +125,18 @@
             ]
         },
         {
+            "name": "Launch Local Dev (Experimental Firefox)",
+            "type": "firefox",
+            "request": "launch",
+            "reAttach": true,
+            "url": "http://localhost:1338/localDev/index.html",
+            "pathMappings": [{
+                "url": "http://localhost:1338",
+                "path": "${workspaceFolder}"
+            }],
+            "preLaunchTask": "run"
+        },
+        {
             "name": "Launch Build Validation (Chrome)",
             "type": "chrome",
             "request": "launch",

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


+ 12 - 5
Tools/Gulp/config.json

@@ -202,10 +202,8 @@
                 "../../src/Mesh/babylon.mesh.js",
                 "../../src/Mesh/babylon.subMesh.js",
                 "../../src/Materials/babylon.effect.js",
-                "../../src/Materials/babylon.materialHelper.js",
                 "../../src/Materials/babylon.material.js",
                 "../../src/Materials/babylon.uniformBuffer.js",
-                "../../src/Materials/babylon.pushMaterial.js",
                 "../../src/Mesh/babylon.mesh.vertexData.js",
                 "../../src/Mesh/babylon.geometry.js",
                 "../../src/PostProcess/babylon.postProcessManager.js",
@@ -218,6 +216,15 @@
                 "depthPrePass"
             ]
         },
+        "materialCore": {
+            "files": [
+                "../../src/Materials/babylon.materialHelper.js",
+                "../../src/Materials/babylon.pushMaterial.js"
+            ],
+            "dependUpon": [
+                "core"
+            ]
+        },
         "particles": {
             "files": [
                 "../../src/Particles/babylon.particle.js",
@@ -373,7 +380,7 @@
                 "../../src/Materials/babylon.shaderMaterial.js"
             ],
             "dependUpon": [
-                "core"
+                "materialCore"
             ]
         },
         "standardMaterial": {
@@ -381,7 +388,7 @@
                 "../../src/Materials/babylon.standardMaterial.js"
             ],
             "dependUpon": [
-                "core"
+                "materialCore"
             ],
             "shaders": [
                 "default.vertex",
@@ -438,7 +445,7 @@
                 "../../src/Materials/PBR/babylon.pbrSpecularGlossinessMaterial.js"
             ],
             "dependUpon": [
-                "core"
+                "materialCore"
             ],
             "shaders": [
                 "pbr.vertex",

+ 16 - 2
Tools/Gulp/gulpfile.js

@@ -481,12 +481,26 @@ gulp.task("typescript-all", function (cb) {
 });
 
 /**
+ * Watch ts files from typescript .
+ */
+gulp.task("srcTscWatch", function() {
+    // Reuse The TSC CLI from gulp to enable -w.
+    process.argv[2] = "-w";
+    process.argv[3] = "-p";
+    process.argv[4] = "../../src/tsconfig.json";
+    require("./node_modules/typescript/lib/tsc.js");
+});
+
+/**
  * Watch ts files and fire repective tasks.
  */
-gulp.task("watch", [], function () {
+gulp.task("watch", ["srcTscWatch"], function () {
     forceCompile = true;
     var interval = 1000;
-    var tasks = [gulp.watch(config.typescript, { interval: interval }, ["typescript-compile"])];
+
+    // Keep during Prod Tests of srcTscWatch.
+    // var tasks = [gulp.watch(config.typescript, { interval: interval }, ["typescript-compile"])];
+    var tasks = [];
 
     config.modules.map(function (module) {
         config[module].libraries.map(function (library) {

+ 5 - 5
Tools/Gulp/package.json

@@ -1,6 +1,6 @@
 {
     "name": "BabylonJS",
-    "version": "3.1.0",
+    "version": "3.1.1",
     "description": "Babylon.js is a 3D engine based on webgl and javascript",
     "main": "",
     "repository": {
@@ -9,8 +9,8 @@
     "readme": "https://github.com/BabylonJS/Babylon.js/edit/master/readme.md",
     "license": "(Apache-2.0)",
     "devDependencies": {
-        "@types/node": "^8.0.53",
-        "base64-image-loader": "^1.2.0",
+        "@types/node": "^8.5.0",
+        "base64-image-loader": "^1.2.1",
         "css-loader": "^0.25.0",
         "deepmerge": "^2.0.1",
         "del": "2.2.2",
@@ -42,10 +42,10 @@
         "style-loader": "^0.13.2",
         "through2": "~0.6.5",
         "ts-loader": "^2.3.7",
-        "typescript": "~2.6.1",
+        "typescript": "^2.6.2",
         "webpack-stream": "^4.0.0"
     },
     "scripts": {
         "install": "npm --prefix ../../Playground/ install ../../Playground/ && gulp typescript-compile && gulp typescript-libraries && gulp deployLocalDev"
     }
-}
+}

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


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


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


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


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


File diff suppressed because it is too large
+ 779 - 575
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


+ 1 - 1
dist/preview release/gui/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-gui",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
-    "version": "3.1.0",
+    "version": "3.1.1",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/inspector/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
-    "version": "3.1.0",
+    "version": "3.1.1",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 4 - 4
dist/preview release/loaders/babylon.glTF1FileLoader.d.ts

@@ -29,8 +29,8 @@ declare module BABYLON {
         bin: Nullable<ArrayBufferView>;
     }
     interface IGLTFLoader extends IDisposable {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
     }
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
@@ -88,8 +88,8 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
         canDirectLoad(data: string): boolean;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;

+ 12 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -75,7 +75,12 @@ var BABYLON;
                 this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
             }
             catch (e) {
-                onError(e.message);
+                if (onError) {
+                    onError(e.message, e);
+                }
+                else {
+                    BABYLON.Tools.Error(e.message);
+                }
             }
         };
         GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
@@ -88,7 +93,12 @@ var BABYLON;
                 this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
             }
             catch (e) {
-                onError(e.message);
+                if (onError) {
+                    onError(e.message, e);
+                }
+                else {
+                    BABYLON.Tools.Error(e.message);
+                }
             }
         };
         GLTFFileLoader.prototype.canDirectLoad = function (data) {

File diff suppressed because it is too large
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 10 - 10
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -29,8 +29,8 @@ declare module BABYLON {
         bin: Nullable<ArrayBufferView>;
     }
     interface IGLTFLoader extends IDisposable {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
     }
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
@@ -88,8 +88,8 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
         canDirectLoad(data: string): boolean;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
@@ -366,9 +366,9 @@ declare module BABYLON.GLTF2 {
         private _defaultMaterial;
         private _defaultSampler;
         private _rootNode;
-        private _successCallback;
-        private _progressCallback;
-        private _errorCallback;
+        private _successCallback?;
+        private _progressCallback?;
+        private _errorCallback?;
         private _renderReady;
         private _requests;
         private _renderReadyObservable;
@@ -384,9 +384,9 @@ declare module BABYLON.GLTF2 {
         private static _createProgressEventByDocument(name, data);
         constructor(parent: GLTFFileLoader);
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError);
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess?, onProgress?, onError?);
         private _onProgress();
         _executeWhenRenderReady(func: () => void): void;
         private _onRenderReady();

+ 26 - 12
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -75,7 +75,12 @@ var BABYLON;
                 this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
             }
             catch (e) {
-                onError(e.message);
+                if (onError) {
+                    onError(e.message, e);
+                }
+                else {
+                    BABYLON.Tools.Error(e.message);
+                }
             }
         };
         GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
@@ -88,7 +93,12 @@ var BABYLON;
                 this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
             }
             catch (e) {
-                onError(e.message);
+                if (onError) {
+                    onError(e.message, e);
+                }
+                else {
+                    BABYLON.Tools.Error(e.message);
+                }
             }
         };
         GLTFFileLoader.prototype.canDirectLoad = function (data) {
@@ -428,7 +438,9 @@ var BABYLON;
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 this._loadAsync(meshesNames, scene, data, rootUrl, function () {
-                    onSuccess(_this._getMeshes(), [], _this._getSkeletons());
+                    if (onSuccess) {
+                        onSuccess(_this._getMeshes(), [], _this._getSkeletons());
+                    }
                 }, onProgress, onError);
             };
             GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
@@ -436,13 +448,13 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadAsync = function (nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
+                this._babylonScene = scene;
+                this._rootUrl = rootUrl;
+                this._successCallback = onSuccess;
+                this._progressCallback = onProgress;
+                this._errorCallback = onError;
                 this._tryCatchOnError(function () {
                     _this._loadData(data);
-                    _this._babylonScene = scene;
-                    _this._rootUrl = rootUrl;
-                    _this._successCallback = onSuccess;
-                    _this._progressCallback = onProgress;
-                    _this._errorCallback = onError;
                     _this._addPendingData(_this);
                     _this._loadDefaultScene(nodeNames);
                     _this._loadAnimations();
@@ -480,7 +492,9 @@ var BABYLON;
             GLTFLoader.prototype._onRenderReady = function () {
                 this._rootNode.babylonMesh.setEnabled(true);
                 this._startAnimations();
-                this._successCallback();
+                if (this._successCallback) {
+                    this._successCallback();
+                }
                 this._renderReadyObservable.notifyObservers(this);
             };
             GLTFLoader.prototype._onComplete = function () {
@@ -1758,9 +1772,9 @@ var BABYLON;
                             _this._onProgress();
                         }
                     });
-                }, this._babylonScene.database, true, function (request) {
+                }, this._babylonScene.database, true, function (request, exception) {
                     _this._tryCatchOnError(function () {
-                        throw new Error(context + ": Failed to load '" + uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""));
+                        throw new BABYLON.LoadFileError(context + ": Failed to load '" + uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""), request);
                     });
                 });
                 if (request) {
@@ -1779,7 +1793,7 @@ var BABYLON;
                 catch (e) {
                     BABYLON.Tools.Error("glTF Loader: " + e.message);
                     if (this._errorCallback) {
-                        this._errorCallback(e.message);
+                        this._errorCallback(e.message, e);
                     }
                     this.dispose();
                 }

File diff suppressed because it is too large
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 10 - 10
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -29,8 +29,8 @@ declare module BABYLON {
         bin: Nullable<ArrayBufferView>;
     }
     interface IGLTFLoader extends IDisposable {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
     }
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
@@ -88,8 +88,8 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
         canDirectLoad(data: string): boolean;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
@@ -913,9 +913,9 @@ declare module BABYLON.GLTF2 {
         private _defaultMaterial;
         private _defaultSampler;
         private _rootNode;
-        private _successCallback;
-        private _progressCallback;
-        private _errorCallback;
+        private _successCallback?;
+        private _progressCallback?;
+        private _errorCallback?;
         private _renderReady;
         private _requests;
         private _renderReadyObservable;
@@ -931,9 +931,9 @@ declare module BABYLON.GLTF2 {
         private static _createProgressEventByDocument(name, data);
         constructor(parent: GLTFFileLoader);
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError);
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess?, onProgress?, onError?);
         private _onProgress();
         _executeWhenRenderReady(func: () => void): void;
         private _onRenderReady();

+ 26 - 12
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -75,7 +75,12 @@ var BABYLON;
                 this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
             }
             catch (e) {
-                onError(e.message);
+                if (onError) {
+                    onError(e.message, e);
+                }
+                else {
+                    BABYLON.Tools.Error(e.message);
+                }
             }
         };
         GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
@@ -88,7 +93,12 @@ var BABYLON;
                 this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
             }
             catch (e) {
-                onError(e.message);
+                if (onError) {
+                    onError(e.message, e);
+                }
+                else {
+                    BABYLON.Tools.Error(e.message);
+                }
             }
         };
         GLTFFileLoader.prototype.canDirectLoad = function (data) {
@@ -2584,7 +2594,9 @@ var BABYLON;
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 this._loadAsync(meshesNames, scene, data, rootUrl, function () {
-                    onSuccess(_this._getMeshes(), [], _this._getSkeletons());
+                    if (onSuccess) {
+                        onSuccess(_this._getMeshes(), [], _this._getSkeletons());
+                    }
                 }, onProgress, onError);
             };
             GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
@@ -2592,13 +2604,13 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadAsync = function (nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
+                this._babylonScene = scene;
+                this._rootUrl = rootUrl;
+                this._successCallback = onSuccess;
+                this._progressCallback = onProgress;
+                this._errorCallback = onError;
                 this._tryCatchOnError(function () {
                     _this._loadData(data);
-                    _this._babylonScene = scene;
-                    _this._rootUrl = rootUrl;
-                    _this._successCallback = onSuccess;
-                    _this._progressCallback = onProgress;
-                    _this._errorCallback = onError;
                     _this._addPendingData(_this);
                     _this._loadDefaultScene(nodeNames);
                     _this._loadAnimations();
@@ -2636,7 +2648,9 @@ var BABYLON;
             GLTFLoader.prototype._onRenderReady = function () {
                 this._rootNode.babylonMesh.setEnabled(true);
                 this._startAnimations();
-                this._successCallback();
+                if (this._successCallback) {
+                    this._successCallback();
+                }
                 this._renderReadyObservable.notifyObservers(this);
             };
             GLTFLoader.prototype._onComplete = function () {
@@ -3914,9 +3928,9 @@ var BABYLON;
                             _this._onProgress();
                         }
                     });
-                }, this._babylonScene.database, true, function (request) {
+                }, this._babylonScene.database, true, function (request, exception) {
                     _this._tryCatchOnError(function () {
-                        throw new Error(context + ": Failed to load '" + uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""));
+                        throw new BABYLON.LoadFileError(context + ": Failed to load '" + uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""), request);
                     });
                 });
                 if (request) {
@@ -3935,7 +3949,7 @@ var BABYLON;
                 catch (e) {
                     BABYLON.Tools.Error("glTF Loader: " + e.message);
                     if (this._errorCallback) {
-                        this._errorCallback(e.message);
+                        this._errorCallback(e.message, e);
                     }
                     this.dispose();
                 }

File diff suppressed because it is too large
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 26 - 12
dist/preview release/loaders/babylonjs.loaders.js

@@ -1049,7 +1049,12 @@ var BABYLON;
                 this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
             }
             catch (e) {
-                onError(e.message);
+                if (onError) {
+                    onError(e.message, e);
+                }
+                else {
+                    BABYLON.Tools.Error(e.message);
+                }
             }
         };
         GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
@@ -1062,7 +1067,12 @@ var BABYLON;
                 this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
             }
             catch (e) {
-                onError(e.message);
+                if (onError) {
+                    onError(e.message, e);
+                }
+                else {
+                    BABYLON.Tools.Error(e.message);
+                }
             }
         };
         GLTFFileLoader.prototype.canDirectLoad = function (data) {
@@ -3540,7 +3550,9 @@ var BABYLON;
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 this._loadAsync(meshesNames, scene, data, rootUrl, function () {
-                    onSuccess(_this._getMeshes(), [], _this._getSkeletons());
+                    if (onSuccess) {
+                        onSuccess(_this._getMeshes(), [], _this._getSkeletons());
+                    }
                 }, onProgress, onError);
             };
             GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
@@ -3548,13 +3560,13 @@ var BABYLON;
             };
             GLTFLoader.prototype._loadAsync = function (nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
+                this._babylonScene = scene;
+                this._rootUrl = rootUrl;
+                this._successCallback = onSuccess;
+                this._progressCallback = onProgress;
+                this._errorCallback = onError;
                 this._tryCatchOnError(function () {
                     _this._loadData(data);
-                    _this._babylonScene = scene;
-                    _this._rootUrl = rootUrl;
-                    _this._successCallback = onSuccess;
-                    _this._progressCallback = onProgress;
-                    _this._errorCallback = onError;
                     _this._addPendingData(_this);
                     _this._loadDefaultScene(nodeNames);
                     _this._loadAnimations();
@@ -3592,7 +3604,9 @@ var BABYLON;
             GLTFLoader.prototype._onRenderReady = function () {
                 this._rootNode.babylonMesh.setEnabled(true);
                 this._startAnimations();
-                this._successCallback();
+                if (this._successCallback) {
+                    this._successCallback();
+                }
                 this._renderReadyObservable.notifyObservers(this);
             };
             GLTFLoader.prototype._onComplete = function () {
@@ -4870,9 +4884,9 @@ var BABYLON;
                             _this._onProgress();
                         }
                     });
-                }, this._babylonScene.database, true, function (request) {
+                }, this._babylonScene.database, true, function (request, exception) {
                     _this._tryCatchOnError(function () {
-                        throw new Error(context + ": Failed to load '" + uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""));
+                        throw new BABYLON.LoadFileError(context + ": Failed to load '" + uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""), request);
                     });
                 });
                 if (request) {
@@ -4891,7 +4905,7 @@ var BABYLON;
                 catch (e) {
                     BABYLON.Tools.Error("glTF Loader: " + e.message);
                     if (this._errorCallback) {
-                        this._errorCallback(e.message);
+                        this._errorCallback(e.message, e);
                     }
                     this.dispose();
                 }

File diff suppressed because it is too large
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


+ 10 - 10
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -127,8 +127,8 @@ declare module BABYLON {
         bin: Nullable<ArrayBufferView>;
     }
     interface IGLTFLoader extends IDisposable {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
     }
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
@@ -186,8 +186,8 @@ declare module BABYLON {
          * Disposes the loader, releases resources during load, and cancels any outstanding requests.
          */
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
         canDirectLoad(data: string): boolean;
         rewriteRootURL: (rootUrl: string, responseURL?: string) => string;
         createPlugin(): ISceneLoaderPlugin | ISceneLoaderPluginAsync;
@@ -1011,9 +1011,9 @@ declare module BABYLON.GLTF2 {
         private _defaultMaterial;
         private _defaultSampler;
         private _rootNode;
-        private _successCallback;
-        private _progressCallback;
-        private _errorCallback;
+        private _successCallback?;
+        private _progressCallback?;
+        private _errorCallback?;
         private _renderReady;
         private _requests;
         private _renderReadyObservable;
@@ -1029,9 +1029,9 @@ declare module BABYLON.GLTF2 {
         private static _createProgressEventByDocument(name, data);
         constructor(parent: GLTFFileLoader);
         dispose(): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
-        private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError);
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void;
+        private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess?, onProgress?, onError?);
         private _onProgress();
         _executeWhenRenderReady(func: () => void): void;
         private _onRenderReady();

+ 1 - 1
dist/preview release/loaders/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-loaders",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
-    "version": "3.1.0",
+    "version": "3.1.1",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/materialsLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-materials",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.1.0",
+    "version": "3.1.1",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/postProcessesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-post-process",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.1.0",
+    "version": "3.1.1",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/proceduralTexturesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-procedural-textures",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.1.0",
+    "version": "3.1.1",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/serializers/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-serializers",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
-    "version": "3.1.0",
+    "version": "3.1.1",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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


+ 1 - 1
dist/preview release/viewer/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-viewer",
     "description": "A simple-to-use viewer based on BabylonJS to display 3D elements natively",
-    "version": "3.1.0",
+    "version": "3.1.1",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -1,8 +1,11 @@
 # 3.2.0
 
 ## Major updates
+- Introduced texture binding atlas. This optimization allows the engine to reuse texture bindings instead of rebinding textures when they are not on constant sampler indexes ([deltakosh](https://github.com/deltakosh))
 
 ## Updates
+- New watcher configuration for VSCode. Now the task only compiles changed files ([sebavan](https://github.com/sebavan))
+- Added new draw modes to engine (points, lines, linesloop, linestrip, trianglestrip, trianglefan) ([benaadams](https://github.com/benaadams))
 
 ## Bug fixes
 

+ 23 - 17
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -54,9 +54,9 @@ module BABYLON.GLTF2 {
         private _defaultMaterial: PBRMaterial;
         private _defaultSampler = {} as IGLTFSampler;
         private _rootNode: IGLTFNode;
-        private _successCallback: () => void;
-        private _progressCallback: (event: ProgressEvent) => void;
-        private _errorCallback: (message: string) => void;
+        private _successCallback?: () => void;
+        private _progressCallback?: (event: ProgressEvent) => void;
+        private _errorCallback?: (message: string, exception?: any) => void;
         private _renderReady = false;
         private _requests = new Array<GLTFLoaderRequest>();
 
@@ -133,25 +133,27 @@ module BABYLON.GLTF2 {
             }
         }
 
-        public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void {
+        public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
             this._loadAsync(meshesNames, scene, data, rootUrl, () => {
-                onSuccess(this._getMeshes(), [], this._getSkeletons());
+                if (onSuccess) {
+                    onSuccess(this._getMeshes(), [], this._getSkeletons());
+                }
             }, onProgress, onError);
         }
 
-        public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void {
+        public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
             this._loadAsync(null, scene, data, rootUrl, onSuccess, onProgress, onError);
         }
 
-        private _loadAsync(nodeNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void {
+        private _loadAsync(nodeNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
+            this._babylonScene = scene;
+            this._rootUrl = rootUrl;
+            this._successCallback = onSuccess;
+            this._progressCallback = onProgress;
+            this._errorCallback = onError;
+
             this._tryCatchOnError(() => {
                 this._loadData(data);
-                this._babylonScene = scene;
-                this._rootUrl = rootUrl;
-
-                this._successCallback = onSuccess;
-                this._progressCallback = onProgress;
-                this._errorCallback = onError;
 
                 this._addPendingData(this);
                 this._loadDefaultScene(nodeNames);
@@ -196,7 +198,11 @@ module BABYLON.GLTF2 {
             this._rootNode.babylonMesh.setEnabled(true);
 
             this._startAnimations();
-            this._successCallback();
+
+            if (this._successCallback) {
+                this._successCallback();
+            }
+
             this._renderReadyObservable.notifyObservers(this);
         }
 
@@ -1634,9 +1640,9 @@ module BABYLON.GLTF2 {
                         this._onProgress();
                     }
                 });
-            }, this._babylonScene.database, true, request => {
+            }, this._babylonScene.database, true, (request, exception) => {
                 this._tryCatchOnError(() => {
-                    throw new Error(context + ": Failed to load '" + uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""));
+                    throw new LoadFileError(context + ": Failed to load '" + uri + "'" + (request ? ": " + request.status + " " + request.statusText : ""), request);
                 });
             }) as GLTFLoaderRequest;
 
@@ -1659,7 +1665,7 @@ module BABYLON.GLTF2 {
                 Tools.Error("glTF Loader: " + e.message);
 
                 if (this._errorCallback) {
-                    this._errorCallback(e.message);
+                    this._errorCallback(e.message, e);
                 }
 
                 this.dispose();

+ 16 - 6
loaders/src/glTF/babylon.glTFFileLoader.ts

@@ -36,8 +36,8 @@ module BABYLON {
     }
 
     export interface IGLTFLoader extends IDisposable {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
     }
 
     export class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
@@ -132,7 +132,7 @@ module BABYLON {
             }
         }
 
-        public importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void {
+        public importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
             try {
                 const loaderData = GLTFFileLoader._parse(data);
 
@@ -144,11 +144,16 @@ module BABYLON {
                 this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
             }
             catch (e) {
-                onError(e.message);
+                if (onError) {
+                    onError(e.message, e);
+                }
+                else {
+                    Tools.Error(e.message);
+                }
             }
         }
 
-        public loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void {
+        public loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
             try {
                 const loaderData = GLTFFileLoader._parse(data);
 
@@ -160,7 +165,12 @@ module BABYLON {
                 this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
             }
             catch (e) {
-                onError(e.message);
+                if (onError) {
+                    onError(e.message, e);
+                }
+                else {
+                    Tools.Error(e.message);
+                }
             }
         }
 

+ 1 - 1
package.json

@@ -8,7 +8,7 @@
     ],
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "3.1.0",
+    "version": "3.1.1",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 176 - 48
src/Engine/babylon.engine.ts

@@ -566,7 +566,7 @@
         }
 
         public static get Version(): string {
-            return "3.1.1";
+            return "3.2.0-alpha0";
         }
 
         // Updatable statics so stick with vars here
@@ -751,8 +751,9 @@
 
         // Cache
         private _internalTexturesCache = new Array<InternalTexture>();
-        protected _activeTextureChannel: number;
+        protected _activeChannel: number;
         protected _boundTexturesCache: { [key: string]: Nullable<InternalTexture> } = {};
+        protected _boundTexturesOrder = new Array<InternalTexture>();
         protected _currentEffect: Nullable<Effect>;
         protected _currentProgram: Nullable<WebGLProgram>;
         private _compiledEffects: { [key: string]: Effect } = {}
@@ -789,6 +790,8 @@
 
         private _frameHandler: number;
 
+        private _nextFreeTextureSlot = 0;
+
         // Hardware supported Compressed Textures
         private _texturesSupported = new Array<string>();
         private _textureFormatInUse: Nullable<string>;
@@ -1320,8 +1323,14 @@
 
         public resetTextureCache() {
             for (var key in this._boundTexturesCache) {
+                let boundTexture = this._boundTexturesCache[key];
+                if (boundTexture) {
+                    this._removeDesignatedSlot(boundTexture);
+                }
                 this._boundTexturesCache[key] = null;
             }
+            this._nextFreeTextureSlot = 0;
+            this._activeChannel = -1;
         }
 
         public isDeterministicLockStep(): boolean {
@@ -2425,45 +2434,72 @@
         }
 
         public draw(useTriangles: boolean, indexStart: number, indexCount: number, instancesCount?: number): void {
-            // Apply states
-            this.applyStates();
+            this.drawElementsType(useTriangles ? Material.TriangleFillMode : Material.WireFrameFillMode, indexStart, indexCount, instancesCount);
+        }
 
-            this._drawCalls.addCount(1, false);
-            // Render
-            var indexFormat = this._uintIndicesCurrentlySet ? this._gl.UNSIGNED_INT : this._gl.UNSIGNED_SHORT;
-            var mult = this._uintIndicesCurrentlySet ? 4 : 2;
-            if (instancesCount) {
-                this._gl.drawElementsInstanced(useTriangles ? this._gl.TRIANGLES : this._gl.LINES, indexCount, indexFormat, indexStart * mult, instancesCount);
-                return;
-            }
+        public drawPointClouds(verticesStart: number, verticesCount: number, instancesCount?: number): void {
+            this.drawArraysType(Material.PointFillMode, verticesStart, verticesCount, instancesCount);
+        }
 
-            this._gl.drawElements(useTriangles ? this._gl.TRIANGLES : this._gl.LINES, indexCount, indexFormat, indexStart * mult);
+        public drawUnIndexed(useTriangles: boolean, verticesStart: number, verticesCount: number, instancesCount?: number): void {
+            this.drawArraysType(useTriangles ? Material.TriangleFillMode : Material.WireFrameFillMode, verticesStart, verticesCount, instancesCount);
         }
 
-        public drawPointClouds(verticesStart: number, verticesCount: number, instancesCount?: number): void {
+        public drawElementsType(fillMode: number, indexStart: number, indexCount: number, instancesCount?: number): void {
             // Apply states
             this.applyStates();
+
             this._drawCalls.addCount(1, false);
+            // Render
 
+            const drawMode = this.DrawMode(fillMode);
+            var indexFormat = this._uintIndicesCurrentlySet ? this._gl.UNSIGNED_INT : this._gl.UNSIGNED_SHORT;
+            var mult = this._uintIndicesCurrentlySet ? 4 : 2;
             if (instancesCount) {
-                this._gl.drawArraysInstanced(this._gl.POINTS, verticesStart, verticesCount, instancesCount);
-                return;
+                this._gl.drawElementsInstanced(drawMode, indexCount, indexFormat, indexStart * mult, instancesCount);
+            } else {
+                this._gl.drawElements(drawMode, indexCount, indexFormat, indexStart * mult);
             }
-
-            this._gl.drawArrays(this._gl.POINTS, verticesStart, verticesCount);
         }
 
-        public drawUnIndexed(useTriangles: boolean, verticesStart: number, verticesCount: number, instancesCount?: number): void {
+        public drawArraysType(fillMode: number, verticesStart: number, verticesCount: number, instancesCount?: number): void {
             // Apply states
             this.applyStates();
             this._drawCalls.addCount(1, false);
 
+            const drawMode = this.DrawMode(fillMode);
             if (instancesCount) {
-                this._gl.drawArraysInstanced(useTriangles ? this._gl.TRIANGLES : this._gl.LINES, verticesStart, verticesCount, instancesCount);
-                return;
+                this._gl.drawArraysInstanced(drawMode, verticesStart, verticesCount, instancesCount);
+            } else {
+                this._gl.drawArrays(drawMode, verticesStart, verticesCount);
+            }
+        }
+
+        private DrawMode(fillMode: number): number {
+            switch (fillMode) {
+                // Triangle views
+                case Material.TriangleFillMode:
+                    return this._gl.TRIANGLES;
+                case Material.PointFillMode:
+                    return this._gl.POINTS;
+                case Material.WireFrameFillMode:
+                    return this._gl.LINES;
+                // Draw modes
+                case Material.PointListDrawMode:
+                    return this._gl.POINTS
+                case Material.LineListDrawMode:
+                    return this._gl.LINES;
+                case Material.LineLoopDrawMode:
+                    return this._gl.LINE_LOOP
+                case Material.LineStripDrawMode:
+                    return this._gl.LINE_STRIP
+                case Material.TriangleStripDrawMode:
+                    return this._gl.TRIANGLE_STRIP
+                case Material.TriangleFanDrawMode:
+                    return this._gl.TRIANGLE_FAN;
+                default:
+                    return this._gl.TRIANGLES;
             }
-
-            this._gl.drawArrays(useTriangles ? this._gl.TRIANGLES : this._gl.LINES, verticesStart, verticesCount);
         }
 
         // Shaders
@@ -2620,7 +2656,7 @@
                 return;
             }
             // Use program
-            this.setProgram(effect.getProgram());
+            this.bindSamplers(effect);
 
             this._currentEffect = effect;
 
@@ -2914,7 +2950,7 @@
 
         // Textures
         public wipeCaches(bruteForce?: boolean): void {
-            if (this.preventCacheWipeBetweenFrames) {
+            if (this.preventCacheWipeBetweenFrames && !bruteForce) {
                 return;
             }
             this.resetTextureCache();
@@ -4532,28 +4568,75 @@
             }
         }
 
+        private _boundUniforms: { [key: number]: WebGLUniformLocation } = {};
+
         public bindSamplers(effect: Effect): void {
             this.setProgram(effect.getProgram());
 
             var samplers = effect.getSamplers();
             for (var index = 0; index < samplers.length; index++) {
                 var uniform = effect.getUniform(samplers[index]);
-                this._gl.uniform1i(uniform, index);
+
+                if (uniform) {
+                    this._boundUniforms[index] = uniform;
+                }
             }
             this._currentEffect = null;
         }
 
-        private activateTextureChannel(textureChannel: number): void {
-            if (this._activeTextureChannel !== textureChannel) {
-                this._gl.activeTexture(textureChannel);
-                this._activeTextureChannel = textureChannel;
+        private _activateTextureChannel(channel: number): void {
+            if (this._activeChannel !== channel) {
+                this._gl.activeTexture(this._gl.TEXTURE0 + channel);
+                this._activeChannel = channel;
             }
         }
 
-        public _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>): void {
-            if (this._boundTexturesCache[this._activeTextureChannel] !== texture) {
+        private _moveBoundTextureOnTop(internalTexture: InternalTexture): void {
+            let index = this._boundTexturesOrder.indexOf(internalTexture);
+
+            if (index > -1 && index !== this._boundTexturesOrder.length - 1) {
+                this._boundTexturesOrder.splice(index, 1);
+                this._boundTexturesOrder.push(internalTexture);
+            }
+        }
+
+        private _removeDesignatedSlot(internalTexture: InternalTexture): number {
+            let currentSlot = internalTexture._designatedSlot;
+            internalTexture._designatedSlot = -1;
+            let index = this._boundTexturesOrder.indexOf(internalTexture);
+
+            if (index > -1) {
+                this._boundTexturesOrder.splice(index, 1);
+            }
+
+            return currentSlot;
+        }
+
+        public _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>, isPartOfTextureArray = false): void {
+            let currentTextureBound = this._boundTexturesCache[this._activeChannel];
+            let isTextureForRendering = texture && texture._initialSlot > -1;
+
+            if (currentTextureBound !== texture) {
+                if (currentTextureBound) {
+                    this._removeDesignatedSlot(currentTextureBound);
+                }
+
                 this._gl.bindTexture(target, texture ? texture._webGLTexture : null);
-                this._boundTexturesCache[this._activeTextureChannel] = texture;
+
+                if (this._activeChannel >= 0) {
+                    this._boundTexturesCache[this._activeChannel] = texture;
+
+                    if (isTextureForRendering) {
+                        this._boundTexturesOrder.push(texture!);
+                    }
+                }
+            }
+
+            if (isTextureForRendering) {
+                texture!._designatedSlot = this._activeChannel;
+                if (!isPartOfTextureArray) {
+                    this._bindSamplerUniformToChannel(texture!._initialSlot, this._activeChannel);
+                }
             }
         }
 
@@ -4562,7 +4645,11 @@
                 return;
             }
 
-            this.activateTextureChannel(this._gl.TEXTURE0 + channel);
+            if (texture) {
+                channel = this._getCorrectTextureChannel(channel, texture);
+            }
+
+            this._activateTextureChannel(channel);
             this._bindTextureDirectly(this._gl.TEXTURE_2D, texture);
         }
 
@@ -4572,7 +4659,7 @@
 
         public unbindAllTextures(): void {
             for (var channel = 0; channel < this._caps.maxTexturesImageUnits; channel++) {
-                this.activateTextureChannel(this._gl.TEXTURE0 + channel);
+                this._activateTextureChannel(channel);
                 this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
                 this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
                 if (this.webGLVersion > 1) {
@@ -4586,16 +4673,49 @@
                 return;
             }
 
-            if (this._setTexture(channel, texture)) {
-                this._gl.uniform1i(uniform, channel);
+            if (uniform) {
+                this._boundUniforms[channel] = uniform;
+            }
+
+            this._setTexture(channel, texture);
+        }
+
+        private _getCorrectTextureChannel(channel: number, internalTexture: Nullable<InternalTexture>) {
+            if (!internalTexture) {
+                return -1;
+            }
+
+            internalTexture._initialSlot = channel;
+
+            if (channel !== internalTexture._designatedSlot) {
+                if (internalTexture._designatedSlot > -1) { // Texture is already assigned to a slot
+                    channel = internalTexture._designatedSlot;
+                } else { // Not slot for this texture, let's pick a new one
+                    if (this._nextFreeTextureSlot > -1) { // We can use a free slot
+                        channel = this._nextFreeTextureSlot;
+                        this._nextFreeTextureSlot++;
+                        if (this._nextFreeTextureSlot >= this._caps.maxTexturesImageUnits) {
+                            this._nextFreeTextureSlot = -1; // No more free slots, we will recycle
+                        }
+                    } else { // We need to recycle the oldest bound texture, sorry.
+                        channel = this._removeDesignatedSlot(this._boundTexturesOrder[0]);
+                    }
+                }
             }
+
+            return channel;
         }
 
-        private _setTexture(channel: number, texture: Nullable<BaseTexture>): boolean {
+        private _bindSamplerUniformToChannel(sourceSlot: number, destination: number) {
+            let uniform = this._boundUniforms[sourceSlot];
+            this._gl.uniform1i(uniform, destination);
+        }
+
+        private _setTexture(channel: number, texture: Nullable<BaseTexture>, isPartOfTextureArray = false): boolean {
             // Not ready?
             if (!texture) {
                 if (this._boundTexturesCache[channel] != null) {
-                    this.activateTextureChannel(this._gl.TEXTURE0 + channel);
+                    this._activateTextureChannel(channel);
                     this._bindTextureDirectly(this._gl.TEXTURE_2D, null);
                     this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, null);
                     if (this.webGLVersion > 1) {
@@ -4608,7 +4728,7 @@
             // Video
             var alreadyActivated = false;
             if ((<VideoTexture>texture).video) {
-                this.activateTextureChannel(this._gl.TEXTURE0 + channel);
+                this._activateTextureChannel(channel);
                 alreadyActivated = true;
                 (<VideoTexture>texture).update();
             } else if (texture.delayLoadState === Engine.DELAYLOADSTATE_NOTLOADED) { // Delay loading
@@ -4630,16 +4750,24 @@
                 internalTexture = this.emptyTexture;
             }
 
-            if (!alreadyActivated) {
-                this.activateTextureChannel(this._gl.TEXTURE0 + channel);
+            if (!isPartOfTextureArray) {
+                channel = this._getCorrectTextureChannel(channel, internalTexture);
             }
 
-            if (this._boundTexturesCache[this._activeTextureChannel] === internalTexture) {
+            if (this._boundTexturesCache[channel] === internalTexture) {
+                this._moveBoundTextureOnTop(internalTexture);
+                if (!isPartOfTextureArray) {
+                    this._bindSamplerUniformToChannel(internalTexture._initialSlot, channel);
+                }
                 return false;
             }
 
+            if (!alreadyActivated) {
+                this._activateTextureChannel(channel);
+            }
+
             if (internalTexture && internalTexture.is3D) {
-                this._bindTextureDirectly(this._gl.TEXTURE_3D, internalTexture);
+                this._bindTextureDirectly(this._gl.TEXTURE_3D, internalTexture, isPartOfTextureArray);
 
                 if (internalTexture && internalTexture._cachedWrapU !== texture.wrapU) {
                     internalTexture._cachedWrapU = texture.wrapU;
@@ -4690,7 +4818,7 @@
                 this._setAnisotropicLevel(this._gl.TEXTURE_3D, texture);
             }
             else if (internalTexture && internalTexture.isCube) {
-                this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, internalTexture);
+                this._bindTextureDirectly(this._gl.TEXTURE_CUBE_MAP, internalTexture, isPartOfTextureArray);
 
                 if (internalTexture._cachedCoordinatesMode !== texture.coordinatesMode) {
                     internalTexture._cachedCoordinatesMode = texture.coordinatesMode;
@@ -4702,7 +4830,7 @@
 
                 this._setAnisotropicLevel(this._gl.TEXTURE_CUBE_MAP, texture);
             } else {
-                this._bindTextureDirectly(this._gl.TEXTURE_2D, internalTexture);
+                this._bindTextureDirectly(this._gl.TEXTURE_2D, internalTexture, isPartOfTextureArray);
 
                 if (internalTexture && internalTexture._cachedWrapU !== texture.wrapU) {
                     internalTexture._cachedWrapU = texture.wrapU;
@@ -4750,12 +4878,12 @@
                 this._textureUnits = new Int32Array(textures.length);
             }
             for (let i = 0; i < textures.length; i++) {
-                this._textureUnits[i] = channel + i;
+                this._textureUnits[i] = this._getCorrectTextureChannel(channel + i, textures[i].getInternalTexture());
             }
             this._gl.uniform1iv(uniform, this._textureUnits);
 
             for (var index = 0; index < textures.length; index++) {
-                this._setTexture(channel + index, textures[index]);
+                this._setTexture(this._textureUnits[index], textures[index], true);
             }
         }
 

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

@@ -277,6 +277,12 @@
         public draw(useTriangles: boolean, indexStart: number, indexCount: number, instancesCount?: number): void {
         }
 
+        public drawElementsType(fillMode: number, indexStart: number, indexCount: number, instancesCount?: number): void {
+        }
+
+        public drawArraysType(fillMode: number, verticesStart: number, verticesCount: number, instancesCount?: number): void {
+        }
+
         public _createTexture(): WebGLTexture {
             return {};
         }
@@ -387,8 +393,8 @@
         }
 
         public _bindTextureDirectly(target: number, texture: InternalTexture): void {
-            if (this._boundTexturesCache[this._activeTextureChannel] !== texture) {
-                this._boundTexturesCache[this._activeTextureChannel] = texture;
+            if (this._boundTexturesCache[this._activeChannel] !== texture) {
+                this._boundTexturesCache[this._activeChannel] = texture;
             }
         }
 

+ 4 - 5
src/Layer/babylon.highlightlayer.ts

@@ -691,12 +691,12 @@
             if (this.outerGlow) {
                 currentEffect.setFloat("offset", 0);
                 engine.setStencilFunction(Engine.NOTEQUAL);
-                engine.draw(true, 0, 6);
+                engine.drawElementsType(Material.TriangleFillMode, 0, 6);
             }
             if (this.innerGlow) {
                 currentEffect.setFloat("offset", 1);
                 engine.setStencilFunction(Engine.EQUAL);
-                engine.draw(true, 0, 6);
+                engine.drawElementsType(Material.TriangleFillMode, 0, 6);
             }
 
             // Restore Cache
@@ -824,10 +824,9 @@
                 if (meshHighlight.observerDefault) {
                     mesh.onAfterRenderObservable.remove(meshHighlight.observerDefault);
                 }
+                delete this._meshes[mesh.uniqueId];
             }
 
-            this._meshes[mesh.uniqueId] = null;
-
             this._shouldRender = false;
             for (var meshHighlightToCheck in this._meshes) {
                 if (this._meshes[meshHighlightToCheck]) {
@@ -951,4 +950,4 @@
             this.onSizeChangedObservable.clear();
         }
     }
-} 
+} 

+ 2 - 2
src/Layer/babylon.layer.ts

@@ -152,11 +152,11 @@
             // Draw order
             if (!this.alphaTest) {
                 engine.setAlphaMode(this.alphaBlendingMode);
-                engine.draw(true, 0, 6);
+                engine.drawElementsType(Material.TriangleFillMode, 0, 6);
                 engine.setAlphaMode(Engine.ALPHA_DISABLE);
             }
             else {
-                engine.draw(true, 0, 6);
+                engine.drawElementsType(Material.TriangleFillMode, 0, 6);
             }
 
             this.onAfterRenderObservable.notifyObservers(this);

+ 1 - 1
src/LensFlare/babylon.lensFlareSystem.ts

@@ -234,7 +234,7 @@
                 this._effect.setFloat4("color", flare.color.r * intensity, flare.color.g * intensity, flare.color.b * intensity, 1.0);
 
                 // Draw order
-                engine.draw(true, 0, 6);
+                engine.drawElementsType(Material.TriangleFillMode, 0, 6);
             }
 
             engine.setDepthBuffer(true);

+ 57 - 55
src/Loading/babylon.sceneLoader.ts

@@ -23,8 +23,8 @@
     export interface ISceneLoaderPluginAsync {
         name: string;
         extensions: string | ISceneLoaderPluginExtensions;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
-        loadAsync: (scene: Scene, data: string, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string, exception?: any) => void) => void;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        loadAsync: (scene: Scene, data: string, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
         canDirectLoad?: (data: string) => boolean;
         rewriteRootURL?: (rootUrl: string, responseURL?: string) => string;
     }
@@ -146,7 +146,7 @@
             return null;
         }
 
-        private static _loadData(rootUrl: string, sceneFilename: string, scene: Scene, onSuccess: (plugin: ISceneLoaderPlugin | ISceneLoaderPluginAsync, data: any, responseURL?: string) => void, onProgress: (event: ProgressEvent) => void, onError: (message: Nullable<string>, exception?: any) => void, pluginExtension?: string): ISceneLoaderPlugin | ISceneLoaderPluginAsync {
+        private static _loadData(rootUrl: string, sceneFilename: string, scene: Scene, onSuccess: (plugin: ISceneLoaderPlugin | ISceneLoaderPluginAsync, data: any, responseURL?: string) => void, onProgress: ((event: ProgressEvent) => void) | undefined, onError: (message: string, exception?: any) => void, pluginExtension: Nullable<string>): ISceneLoaderPlugin | ISceneLoaderPluginAsync {
             var directLoad = SceneLoader._getDirectLoad(sceneFilename);
             var registeredPlugin = pluginExtension ? SceneLoader._getPluginForExtension(pluginExtension) : (directLoad ? SceneLoader._getPluginForDirectLoad(sceneFilename) : SceneLoader._getPluginForFilename(sceneFilename));
 
@@ -171,18 +171,13 @@
 
                 scene.database = database;
 
-                try {
-                    onSuccess(plugin, data, responseURL);
-                }
-                catch (e) {
-                    onError(null, e);
-                }
+                onSuccess(plugin, data, responseURL);
             };
 
             var manifestChecked = (success: any) => {
-                Tools.LoadFile(rootUrl + sceneFilename, dataCallback, onProgress, database, useArrayBuffer, request => {
+                Tools.LoadFile(rootUrl + sceneFilename, dataCallback, onProgress, database, useArrayBuffer, (request, exception) => {
                     if (request) {
-                        onError(request.status + " " + request.statusText);
+                        onError(request.status + " " + request.statusText, exception);
                     }
                 });
             };
@@ -250,7 +245,7 @@
         * @param onProgress a callback with a progress event for each file being loaded
         * @param onError a callback with the scene, a message, and possibly an exception when import fails
         */
-        public static ImportMesh(meshNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onSuccess: Nullable<(meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void> = null, onProgress: Nullable<(event: ProgressEvent) => void> = null, onError: Nullable<(scene: Scene, message: string, exception?: any) => void> = null, pluginExtension?: string): Nullable<ISceneLoaderPlugin | ISceneLoaderPluginAsync> {
+        public static ImportMesh(meshNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onSuccess: Nullable<(meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void> = null, onProgress: Nullable<(event: ProgressEvent) => void> = null, onError: Nullable<(scene: Scene, message: string, exception?: any) => void> = null, pluginExtension: Nullable<string> = null): Nullable<ISceneLoaderPlugin | ISceneLoaderPluginAsync> {
             if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
                 Tools.Error("Wrong sceneFilename parameter");
                 return null;
@@ -259,21 +254,41 @@
             var loadingToken = {};
             scene._addPendingData(loadingToken);
 
-            var errorHandler = (message: Nullable<string>, exception?: any) => {
-                let errorMessage = "Unable to import meshes from " + rootUrl + sceneFilename + (message ? ": " + message : "");
+            var errorHandler = (message: string, exception?: any) => {
+                let errorMessage = "Unable to import meshes from " + rootUrl + sceneFilename + ": " + message;
+
                 if (onError) {
                     onError(scene, errorMessage, exception);
                 } else {
                     Tools.Error(errorMessage);
                     // should the exception be thrown?
                 }
+
                 scene._removePendingData(loadingToken);
             };
 
-            var progressHandler = (event: ProgressEvent) => {
-                if (onProgress) {
+            var progressHandler = onProgress ? (event: ProgressEvent) => {
+                try {
                     onProgress(event);
                 }
+                catch (e) {
+                    errorHandler("Error in onProgress callback", e);
+                }
+            } : undefined;
+
+            var successHandler = (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => {
+                scene.importedMeshesFiles.push(rootUrl + sceneFilename);
+
+                if (onSuccess) {
+                    try {
+                        onSuccess(meshes, particleSystems, skeletons);
+                    }
+                    catch (e) {
+                        errorHandler("Error in onSuccess callback", e);
+                    }
+                }
+
+                scene._removePendingData(loadingToken);
             };
 
             return SceneLoader._loadData(rootUrl, sceneFilename, scene, (plugin, data, responseURL) => {
@@ -291,31 +306,14 @@
                         return;
                     }
 
-                    if (onSuccess) {
-                        // wrap onSuccess with try-catch to know if something went wrong.
-                        try {
-                            scene.importedMeshesFiles.push(rootUrl + sceneFilename);
-                            onSuccess(meshes, particleSystems, skeletons);
-                            scene._removePendingData(loadingToken);
-                        } catch (e) {
-                            let message = 'Error in onSuccess callback.';
-                            errorHandler(message, e);
-                        }
-                    }
+                    scene.loadingPluginName = plugin.name;
+                    successHandler(meshes, particleSystems, skeletons);
                 }
                 else {
                     var asyncedPlugin = <ISceneLoaderPluginAsync>plugin;
                     asyncedPlugin.importMeshAsync(meshNames, scene, data, rootUrl, (meshes, particleSystems, skeletons) => {
-                        if (onSuccess) {
-                            try {
-                                scene.importedMeshesFiles.push(rootUrl + sceneFilename);
-                                onSuccess(meshes, particleSystems, skeletons);
-                                scene._removePendingData(loadingToken);
-                            } catch (e) {
-                                let message = 'Error in onSuccess callback.';
-                                errorHandler(message, e);
-                            }
-                        }
+                        scene.loadingPluginName = plugin.name;
+                        successHandler(meshes, particleSystems, skeletons);
                     }, progressHandler, errorHandler);
                 }
             }, progressHandler, errorHandler, pluginExtension);
@@ -330,7 +328,7 @@
         * @param onProgress a callback with a progress event for each file being loaded
         * @param onError a callback with the scene, a message, and possibly an exception when import fails
         */
-        public static Load(rootUrl: string, sceneFilename: any, engine: Engine, onSuccess?: (scene: Scene) => void, onProgress?: (event: ProgressEvent) => void, onError?: (scene: Scene, message: string, exception?: any) => void, pluginExtension?: string): Nullable<ISceneLoaderPlugin | ISceneLoaderPluginAsync> {
+        public static Load(rootUrl: string, sceneFilename: any, engine: Engine, onSuccess: Nullable<(scene: Scene) => void> = null, onProgress: Nullable<(event: ProgressEvent) => void> = null, onError: Nullable<(scene: Scene, message: string, exception?: any) => void> = null, pluginExtension: Nullable<string> = null): Nullable<ISceneLoaderPlugin | ISceneLoaderPluginAsync> {
             return SceneLoader.Append(rootUrl, sceneFilename, new Scene(engine), onSuccess, onProgress, onError, pluginExtension);
         }
 
@@ -343,7 +341,7 @@
         * @param onProgress a callback with a progress event for each file being loaded
         * @param onError a callback with the scene, a message, and possibly an exception when import fails
         */
-        public static Append(rootUrl: string, sceneFilename: any, scene: Scene, onSuccess?: (scene: Scene) => void, onProgress?: (event: ProgressEvent) => void, onError?: (scene: Scene, message: string, exception?: any) => void, pluginExtension?: string): Nullable<ISceneLoaderPlugin | ISceneLoaderPluginAsync> {
+        public static Append(rootUrl: string, sceneFilename: any, scene: Scene, onSuccess: Nullable<(scene: Scene) => void> = null, onProgress: Nullable<(event: ProgressEvent) => void> = null, onError: Nullable<(scene: Scene, message: string, exception?: any) => void> = null, pluginExtension: Nullable<string> = null): Nullable<ISceneLoaderPlugin | ISceneLoaderPluginAsync> {
             if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
                 Tools.Error("Wrong sceneFilename parameter");
                 return null;
@@ -368,10 +366,26 @@
                 scene.getEngine().hideLoadingUI();
             };
 
-            var progressHandler = (event: ProgressEvent) => {
-                if (onProgress) {
+            var progressHandler = onProgress ? (event: ProgressEvent) => {
+                try {
                     onProgress(event);
                 }
+                catch (e) {
+                    errorHandler("Error in onProgress callback", e);
+                }
+            } : undefined;
+
+            var successHandler = () => {
+                if (onSuccess) {
+                    try {
+                        onSuccess(scene);
+                    }
+                    catch (e) {
+                        errorHandler("Error in onSuccess callback", e);
+                    }
+                }
+
+                scene._removePendingData(loadingToken);
             };
 
             return SceneLoader._loadData(rootUrl, sceneFilename, scene, (plugin, data, responseURL) => {
@@ -381,25 +395,13 @@
                         return;
                     }
 
-                    if (onSuccess) {
-                        try {
-                            onSuccess(scene);
-                        } catch (e) {
-                            errorHandler("Error in onSuccess callback", e);
-                        }
-                    }
-
                     scene.loadingPluginName = plugin.name;
-                    scene._removePendingData(loadingToken);
+                    successHandler();
                 } else {
                     var asyncedPlugin = <ISceneLoaderPluginAsync>plugin;
                     asyncedPlugin.loadAsync(scene, data, rootUrl, () => {
-                        if (onSuccess) {
-                            onSuccess(scene);
-                        }
-
                         scene.loadingPluginName = plugin.name;
-                        scene._removePendingData(loadingToken);
+                        successHandler();
                     }, progressHandler, errorHandler);
                 }
 

+ 2 - 2
src/Materials/Textures/Procedurals/babylon.proceduralTexture.ts

@@ -335,7 +335,7 @@
                     engine.clear(scene.clearColor, true, true, true);
 
                     // Draw order
-                    engine.draw(true, 0, 6);
+                    engine.drawElementsType(Material.TriangleFillMode, 0, 6);
 
                     // Mipmaps
                     if (face === 5) {
@@ -352,7 +352,7 @@
                 engine.clear(scene.clearColor, true, true, true);
 
                 // Draw order
-                engine.draw(true, 0, 6);
+                engine.drawElementsType(Material.TriangleFillMode, 0, 6);
             }
 
             // Unbind

+ 21 - 19
src/Materials/Textures/babylon.internalTexture.ts

@@ -32,6 +32,8 @@ module BABYLON {
         public invertY: boolean;
 
         // Private
+        public _initialSlot = -1;
+        public _designatedSlot = -1;
         public _dataSource = InternalTexture.DATASOURCE_UNKNOWN;
         public _buffer: Nullable<ArrayBuffer | HTMLImageElement>;
         public _bufferView: Nullable<ArrayBufferView>;
@@ -75,7 +77,7 @@ module BABYLON {
         constructor(engine: Engine, dataSource: number) {
             this._engine = engine;
             this._dataSource = dataSource;
-            
+
             this._webGLTexture = engine._createTexture();
         }
 
@@ -110,32 +112,32 @@ module BABYLON {
                 case InternalTexture.DATASOURCE_URL:
                     proxy = this._engine.createTexture(this.url, !this.generateMipMaps, this.invertY, null, this.samplingMode, () => {
                         this.isReady = true;
-                    }, null, this._buffer, undefined, this.format); 
+                    }, null, this._buffer, undefined, this.format);
                     proxy._swapAndDie(this);
                     return;
 
                 case InternalTexture.DATASOURCE_RAW:
-                    proxy = this._engine.createRawTexture(this._bufferView, this.baseWidth, this.baseHeight, this.format, this.generateMipMaps, 
-                                                            this.invertY, this.samplingMode, this._compression, this.type); 
+                    proxy = this._engine.createRawTexture(this._bufferView, this.baseWidth, this.baseHeight, this.format, this.generateMipMaps,
+                        this.invertY, this.samplingMode, this._compression);
                     proxy._swapAndDie(this);
 
                     this.isReady = true;
-                return;
+                    return;
 
                 case InternalTexture.DATASOURCE_RAW3D:
-                    proxy = this._engine.createRawTexture3D(this._bufferView, this.baseWidth, this.baseHeight, this.baseDepth, this.format, this.generateMipMaps, 
-                        this.invertY, this.samplingMode, this._compression); 
+                    proxy = this._engine.createRawTexture3D(this._bufferView, this.baseWidth, this.baseHeight, this.baseDepth, this.format, this.generateMipMaps,
+                        this.invertY, this.samplingMode, this._compression);
                     proxy._swapAndDie(this);
 
                     this.isReady = true;
-                return;
-                
+                    return;
+
                 case InternalTexture.DATASOURCE_DYNAMIC:
-                    proxy = this._engine.createDynamicTexture(this.baseWidth, this.baseHeight, this.generateMipMaps, this.samplingMode); 
+                    proxy = this._engine.createDynamicTexture(this.baseWidth, this.baseHeight, this.generateMipMaps, this.samplingMode);
                     proxy._swapAndDie(this);
 
                     // The engine will make sure to update content so no need to flag it as isReady = true
-                return;
+                    return;
 
                 case InternalTexture.DATASOURCE_RENDERTARGET:
                     let options = new RenderTargetCreationOptions();
@@ -146,19 +148,19 @@ module BABYLON {
                     options.type = this.type;
 
                     if (this.isCube) {
-                        proxy = this._engine.createRenderTargetCubeTexture(this.width, options); 
+                        proxy = this._engine.createRenderTargetCubeTexture(this.width, options);
                     } else {
                         let size = {
                             width: this.width,
                             height: this.height
                         }
 
-                        proxy = this._engine.createRenderTargetTexture(size, options); 
+                        proxy = this._engine.createRenderTargetTexture(size, options);
                     }
                     proxy._swapAndDie(this);
 
                     this.isReady = true;
-                return;                                      
+                    return;
 
                 case InternalTexture.DATASOURCE_CUBE:
                     proxy = this._engine.createCubeTexture(this.url, null, this._files, !this.generateMipMaps, () => {
@@ -172,14 +174,14 @@ module BABYLON {
                     proxy._swapAndDie(this);
 
                     this.isReady = true;
-                    return;                    
+                    return;
 
                 case InternalTexture.DATASOURCE_CUBEPREFILTERED:
                     proxy = this._engine.createPrefilteredCubeTexture(this.url, null, this._lodGenerationScale, this._lodGenerationOffset, (proxy) => {
                         if (proxy) {
                             proxy._swapAndDie(this);
                         }
-                        
+
                         this.isReady = true;
                     }, null, this.format, this._extension);
                     return;
@@ -207,14 +209,14 @@ module BABYLON {
             if (this._lodTextureMid) {
                 if (target._lodTextureMid) {
                     target._lodTextureMid.dispose();
-                }                
+                }
                 target._lodTextureMid = this._lodTextureMid;
             }
 
             if (this._lodTextureLow) {
                 if (target._lodTextureLow) {
                     target._lodTextureLow.dispose();
-                }                     
+                }
                 target._lodTextureLow = this._lodTextureLow;
             }
 
@@ -224,7 +226,7 @@ module BABYLON {
                 cache.splice(index, 1);
             }
         }
-        
+
         public dispose(): void {
             if (!this._webGLTexture) {
                 return;

+ 33 - 1
src/Materials/babylon.material.ts

@@ -151,9 +151,17 @@
     }
 
     export class Material implements IAnimatable {
+        // Triangle views
         private static _TriangleFillMode = 0;
         private static _WireFrameFillMode = 1;
         private static _PointFillMode = 2;
+        // Draw modes
+        private static _PointListDrawMode = 3;
+        private static _LineListDrawMode = 4;
+        private static _LineLoopDrawMode = 5;
+        private static _LineStripDrawMode = 6;
+        private static _TriangleStripDrawMode = 7;
+        private static _TriangleFanDrawMode = 8;
 
         public static get TriangleFillMode(): number {
             return Material._TriangleFillMode;
@@ -167,6 +175,30 @@
             return Material._PointFillMode;
         }
 
+        public static get PointListDrawMode(): number {
+            return Material._PointListDrawMode;
+        }
+
+        public static get LineListDrawMode(): number {
+            return Material._LineListDrawMode;
+        }
+
+        public static get LineLoopDrawMode(): number {
+            return Material._LineLoopDrawMode;
+        }
+
+        public static get LineStripDrawMode(): number {
+            return Material._LineStripDrawMode;
+        }
+
+        public static get TriangleStripDrawMode(): number {
+            return Material._TriangleStripDrawMode;
+        }
+
+        public static get TriangleFanDrawMode(): number {
+            return Material._TriangleFanDrawMode;
+        }
+
         private static _ClockWiseSideOrientation = 0;
         private static _CounterClockWiseSideOrientation = 1;
 
@@ -353,7 +385,7 @@
         }
 
         public set pointsCloud(value: boolean) {
-            this._fillMode = (value ? Material.PointFillMode : Material.TriangleFillMode);            
+            this._fillMode = (value ? Material.PointFillMode : Material.TriangleFillMode);
         }
 
         @serialize()

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

@@ -112,7 +112,7 @@
             var engine = this.getScene().getEngine();
 
             // Draw order
-            engine.draw(false, subMesh.indexStart, subMesh.indexCount);
+            engine.drawElementsType(Material.LineListDrawMode, subMesh.indexStart, subMesh.indexCount);
             return this;
         }
 

+ 21 - 19
src/Mesh/babylon.mesh.ts

@@ -149,6 +149,17 @@
             return this._source;
         }
 
+        public get isUnIndexed(): boolean {
+            return this._unIndexed;
+        }
+
+        public set isUnIndexed(value: boolean) {
+            if (this._unIndexed !== value) {
+                this._unIndexed = value;
+                this._markSubMeshesAsAttributesDirty();
+            }
+        }
+
         /**
          * @constructor
          * @param {string} name The value used by scene.getMeshByName() to do a lookup.
@@ -1050,25 +1061,14 @@
             let scene = this.getScene();
             let engine = scene.getEngine();
 
-            // Draw order
-            switch (fillMode) {
-                case Material.PointFillMode:
-                    engine.drawPointClouds(subMesh.verticesStart, subMesh.verticesCount, instancesCount);
-                    break;
-                case Material.WireFrameFillMode:
-                    if (this._unIndexed) {
-                        engine.drawUnIndexed(false, subMesh.verticesStart, subMesh.verticesCount, instancesCount);
-                    } else {
-                        engine.draw(false, 0, subMesh.linesIndexCount, instancesCount);
-                    }
-                    break;
-
-                default:
-                    if (this._unIndexed) {
-                        engine.drawUnIndexed(true, subMesh.verticesStart, subMesh.verticesCount, instancesCount);
-                    } else {
-                        engine.draw(true, subMesh.indexStart, subMesh.indexCount, instancesCount);
-                    }
+            if (this._unIndexed || fillMode == Material.PointFillMode) {
+                // or triangles as points
+                engine.drawArraysType(fillMode, subMesh.verticesStart, subMesh.verticesCount, instancesCount);
+            } else if (fillMode == Material.WireFrameFillMode) {
+                // Triangles as wireframe
+                engine.drawElementsType(fillMode, 0, subMesh.linesIndexCount, instancesCount);
+            } else {
+                engine.drawElementsType(fillMode, subMesh.indexStart, subMesh.indexCount, instancesCount);
             }
 
             if (scene._isAlternateRenderingEnabled && !alternate) {
@@ -2115,6 +2115,7 @@
             }
 
             // Geometry
+            serializationObject.isUnIndexed = this.isUnIndexed;
             var geometry = this._geometry;
             if (geometry) {
                 var geometryId = geometry.id;
@@ -2375,6 +2376,7 @@
             }
 
             // Geometry
+            mesh.isUnIndexed = !!parsedMesh.isUnIndexed;
             mesh.hasVertexAlpha = parsedMesh.hasVertexAlpha;
 
             if (parsedMesh.delayLoadingFile) {

+ 2 - 2
src/Particles/babylon.gpuParticleSystem.ts

@@ -151,7 +151,7 @@
             this._engine.bindTransformFeedbackBuffer(this._targetBuffer.getBuffer());
             this._engine.setRasterizerState(false);
             this._engine.beginTransformFeedback();
-            this._engine.drawPointClouds(0, this._capacity);
+            this._engine.drawArraysType(Material.PointListDrawMode, 0, this._capacity);
             this._engine.endTransformFeedback();
             this._engine.setRasterizerState(true);
             this._engine.bindTransformFeedbackBuffer(null);
@@ -163,7 +163,7 @@
             this._engine.bindVertexArrayObject(this._targetVAO, null);
 
             // Render
-            this._engine.drawPointClouds(0, this._capacity);            
+            this._engine.drawArraysType(Material.PointListDrawMode, 0, this._capacity);            
 
             // Switch VAOs
             let tmpVAO = this._sourceVAO;

+ 1 - 1
src/Particles/babylon.particleSystem.ts

@@ -560,7 +560,7 @@
                 engine.setDepthWrite(true);
             }
 
-            engine.draw(true, 0, this.particles.length * 6);
+            engine.drawElementsType(Material.TriangleFillMode, 0, this.particles.length * 6);
             engine.setAlphaMode(Engine.ALPHA_DISABLE);
 
             return this.particles.length;

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

@@ -91,7 +91,7 @@
                     engine.bindBuffers(this._vertexBuffers, this._indexBuffer, effect);
 
                     // Draw order
-                    engine.draw(true, 0, 6);
+                    engine.drawElementsType(Material.TriangleFillMode, 0, 6);
 
                     pp.onAfterRenderObservable.notifyObservers(effect);
                 }
@@ -141,7 +141,7 @@
                     engine.bindBuffers(this._vertexBuffers, this._indexBuffer, effect);
 
                     // Draw order
-                    engine.draw(true, 0, 6);
+                    engine.drawElementsType(Material.TriangleFillMode, 0, 6);
 
                     pp.onAfterRenderObservable.notifyObservers(effect);
                 }

+ 3 - 3
src/Rendering/babylon.boundingBoxRenderer.ts

@@ -85,7 +85,7 @@
                     this._colorShader.bind(worldMatrix);
 
                     // Draw order
-                    engine.draw(false, 0, 24);
+                    engine.drawElementsType(Material.LineListDrawMode, 0, 24);
                 }
 
                 // Front
@@ -95,7 +95,7 @@
                 this._colorShader.bind(worldMatrix);
 
                 // Draw order
-                engine.draw(false, 0, 24);
+                engine.drawElementsType(Material.TriangleFillMode, 0, 24);
             }
             this._colorShader.unbind();
             engine.setDepthFunctionToLessOrEqual();
@@ -131,7 +131,7 @@
             this._scene.resetCachedMaterial();
             this._colorShader.bind(worldMatrix);
 
-            engine.draw(false, 0, 24);
+            engine.drawElementsType(Material.TriangleFillMode, 0, 24);
 
             this._colorShader.unbind();
             engine.setDepthFunctionToLessOrEqual();

+ 1 - 1
src/Rendering/babylon.edgesRenderer.ts

@@ -324,7 +324,7 @@
             this._lineShader.bind(this._source.getWorldMatrix());
 
             // Draw order
-            engine.draw(true, 0, this._indicesCount);
+            engine.drawElementsType(Material.TriangleFillMode, 0, this._indicesCount);
             this._lineShader.unbind();
             engine.setDepthWrite(true);
         }

+ 2 - 2
src/Sprites/babylon.spriteManager.ts

@@ -250,12 +250,12 @@
             engine.setDepthFunctionToLessOrEqual();
             effect.setBool("alphaTest", true);
             engine.setColorWrite(false);
-            engine.draw(true, 0, max * 6);
+            engine.drawElementsType(Material.TriangleFillMode, 0, max * 6);
             engine.setColorWrite(true);
             effect.setBool("alphaTest", false);
 
             engine.setAlphaMode(Engine.ALPHA_COMBINE);
-            engine.draw(true, 0, max * 6);
+            engine.drawElementsType(Material.TriangleFillMode, 0, max * 6);
             engine.setAlphaMode(Engine.ALPHA_DISABLE);
         }
 

+ 16 - 1
src/Tools/babylon.tools.ts

@@ -3,6 +3,21 @@
         animations: Array<Animation>;
     }
 
+    // See https://stackoverflow.com/questions/12915412/how-do-i-extend-a-host-object-e-g-error-in-typescript
+    // and https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work
+    export class LoadFileError extends Error {
+        // Polyfill for Object.setPrototypeOf if necessary.
+        private static _setPrototypeOf: (o: any, proto: object | null) => any =
+            (Object as any).setPrototypeOf || ((o, proto) => { o.__proto__ = proto; return o; });
+
+        constructor(message: string, public request?: XMLHttpRequest) {
+            super(message);
+            this.name = "LoadFileError";
+
+            LoadFileError._setPrototypeOf(this, LoadFileError.prototype);
+        }
+    }
+
     // Screenshots
     var screenshotCanvas: HTMLCanvasElement;
 
@@ -515,7 +530,7 @@
                         if (req.status >= 200 && req.status < 300 || (!Tools.IsWindowObjectExist() && (req.status === 0))) {
                             callback(!useArrayBuffer ? req.responseText : <ArrayBuffer>req.response, req.responseURL);
                         } else { // Failed
-                            let e = new Error("Error status: " + req.status + " - Unable to load " + loadUrl);
+                            let e = new LoadFileError("Error status: " + req.status + " - Unable to load " + loadUrl, req);
                             if (onError) {
                                 onError(req, e);
                             } else {

+ 1 - 1
src/babylon.scene.ts

@@ -3924,7 +3924,7 @@
                 this._engine.scenes.splice(index, 1);
             }
 
-            this._engine.wipeCaches();
+            this._engine.wipeCaches(true);
             this._isDisposed = true;
         }
 

+ 7 - 8
src/tsconfig.json

@@ -1,20 +1,19 @@
 {
   "compileOnSave": true,
   "compilerOptions": {
-    "experimentalDecorators": true,
-    "module": "commonjs",
+    "noResolve": true,
     "target": "es5",
+    "declaration": true,
+    "experimentalDecorators": true,
+    "isolatedModules": false,
     "sourceMap": true,
+    "types": [],
     "noImplicitAny": true,
-    "lib": [
-      "dom",
-      "es2015.promise",
-      "es5"
-    ],
     "noImplicitReturns": true,
     "noImplicitThis": true,
     "noUnusedLocals": true,
     "strictNullChecks": true,
-    "strictFunctionTypes": true
+    "strictFunctionTypes": true,
+    "skipLibCheck": true
   }
 }

二進制
tests/validation/ReferenceImages/customRTT.png


+ 7 - 0
tests/validation/config.json

@@ -181,6 +181,13 @@
       "referenceImage": "normals.png"
     },
     {
+      "title": "Custom render target",
+      "scriptToRun": "/Demos/CustomRenderTarget/customRenderTarget.js",
+      "renderCount": 10,
+      "functionToCall": "CreateCustomRenderTargetTestScene",
+      "referenceImage": "customRTT.png"
+    },
+    {
       "title": "GLTF Normals",
       "renderCount": 20,
       "scriptToRun": "/Demos/GLTFNormals/index.js",