瀏覽代碼

Merge branch 'master' into draco-web-workers

Gary Hsu 7 年之前
父節點
當前提交
f2a7eaf614
共有 46 個文件被更改,包括 18050 次插入18260 次删除
  1. 2 0
      .gitignore
  2. 7813 7810
      Playground/babylon.d.txt
  3. 10 9
      Tools/Gulp/config.json
  4. 5 1
      Tools/Gulp/gulp-addModuleExports.js
  5. 8 1
      Tools/Gulp/gulpfile.js
  6. 1 0
      Viewer/dist/_redirects
  7. 15 18
      Viewer/src/configuration/loader.ts
  8. 0 26
      Viewer/src/helper.ts
  9. 47 24
      Viewer/src/templateManager.ts
  10. 2 2
      Viewer/src/viewer/defaultViewer.ts
  11. 41 7
      Viewer/src/viewer/viewer.ts
  12. 7999 7991
      dist/preview release/babylon.d.ts
  13. 13 13
      dist/preview release/babylon.js
  14. 50 22
      dist/preview release/babylon.max.js
  15. 13 13
      dist/preview release/babylon.worker.js
  16. 1506 1504
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  17. 6 6
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  18. 10 8
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  19. 10 8
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  20. 50 22
      dist/preview release/es6.js
  21. 1 1
      dist/preview release/gui/package.json
  22. 1 1
      dist/preview release/inspector/package.json
  23. 1 1
      dist/preview release/loaders/package.json
  24. 1 1
      dist/preview release/materialsLibrary/package.json
  25. 1 1
      dist/preview release/postProcessesLibrary/package.json
  26. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  27. 1 1
      dist/preview release/serializers/package.json
  28. 8 24
      dist/preview release/viewer/babylon.viewer.d.ts
  29. 48 48
      dist/preview release/viewer/babylon.viewer.js
  30. 84 83
      dist/preview release/viewer/babylon.viewer.max.js
  31. 4 484
      dist/preview release/viewer/babylon.viewer.module.d.ts
  32. 3 1
      dist/preview release/viewer/package.json
  33. 25 12
      dist/preview release/viewer/readme.md
  34. 93 91
      dist/preview release/what's new.md
  35. 2 2
      package.json
  36. 2 2
      src/Engine/babylon.engine.ts
  37. 3 1
      src/Helpers/babylon.environmentHelper.ts
  38. 5 1
      src/Materials/Textures/babylon.cubeTexture.ts
  39. 33 10
      src/Particles/babylon.gpuParticleSystem.ts
  40. 23 1
      src/Shaders/default.fragment.fx
  41. 14 1
      src/Shaders/default.vertex.fx
  42. 8 0
      src/Shaders/gpuRenderParticles.fragment.fx
  43. 13 0
      src/Shaders/gpuRenderParticles.vertex.fx
  44. 12 6
      src/babylon.scene.ts
  45. 1 1
      tests/validation/config.json
  46. 61 0
      tests/validation/validate.html

+ 2 - 0
.gitignore

@@ -174,3 +174,5 @@ dist/preview release/package/
 # viewer dist files
 # viewer dist files
 /Viewer/dist/viewer.js
 /Viewer/dist/viewer.js
 /Viewer/dist/viewer.min.js
 /Viewer/dist/viewer.min.js
+dist/preview release/viewer/babylon.d.ts
+Viewer/dist/viewer.max.js

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


+ 10 - 9
Tools/Gulp/config.json

@@ -275,10 +275,10 @@
             "files": [
             "files": [
                 "../../src/Particles/babylon.particle.js",
                 "../../src/Particles/babylon.particle.js",
                 "../../src/Particles/babylon.particleSystem.js",
                 "../../src/Particles/babylon.particleSystem.js",
+                "../../src/Particles/EmitterTypes/babylon.IParticleEmitterType.js",
                 "../../src/Particles/EmitterTypes/babylon.boxParticleEmitter.js",
                 "../../src/Particles/EmitterTypes/babylon.boxParticleEmitter.js",
                 "../../src/Particles/EmitterTypes/babylon.coneParticleEmitter.js",
                 "../../src/Particles/EmitterTypes/babylon.coneParticleEmitter.js",
-                "../../src/Particles/EmitterTypes/babylon.sphereParticleEmitter.js",
-                "../../src/Particles/EmitterTypes/babylon.IParticleEmitterType.js"
+                "../../src/Particles/EmitterTypes/babylon.sphereParticleEmitter.js"
             ],
             ],
             "dependUpon": [
             "dependUpon": [
                 "core"
                 "core"
@@ -290,7 +290,7 @@
         },
         },
         "gpuParticles": {
         "gpuParticles": {
             "files": [
             "files": [
-                "../../src/Particles/babylon.gpuParticleSystem.js"          
+                "../../src/Particles/babylon.gpuParticleSystem.js"
             ],
             ],
             "dependUpon": [
             "dependUpon": [
                 "core",
                 "core",
@@ -431,8 +431,7 @@
                 "additionalMeshes"
                 "additionalMeshes"
             ]
             ]
         },
         },
-        "meshCompression" :
-        {
+        "meshCompression": {
             "files": [
             "files": [
                 "../../src/Mesh/Compression/babylon.dracoCompression.js"
                 "../../src/Mesh/Compression/babylon.dracoCompression.js"
             ]
             ]
@@ -1677,7 +1676,8 @@
                 "output": "babylon.viewer.js",
                 "output": "babylon.viewer.js",
                 "webpack": "../../Viewer/webpack.gulp.config.js",
                 "webpack": "../../Viewer/webpack.gulp.config.js",
                 "bundle": "true",
                 "bundle": "true",
-                "moduleDeclaration": "BabylonViewer"
+                "moduleDeclaration": "BabylonViewer",
+                "babylonIncluded": true
             }
             }
         ],
         ],
         "build": {
         "build": {
@@ -1686,12 +1686,13 @@
                 {
                 {
                     "destination": [
                     "destination": [
                         {
                         {
-                            "filename": "viewer.min.js",
+                            "filename": "viewer.js",
                             "outputDirectory": "/../../Viewer/dist/"
                             "outputDirectory": "/../../Viewer/dist/"
                         },
                         },
                         {
                         {
                             "filename": "babylon.viewer.js",
                             "filename": "babylon.viewer.js",
-                            "outputDirectory": "/viewer/"
+                            "outputDirectory": "/viewer/",
+                            "addBabylonDeclaration": true
                         }
                         }
                     ],
                     ],
                     "minified": true
                     "minified": true
@@ -1699,7 +1700,7 @@
                 {
                 {
                     "destination": [
                     "destination": [
                         {
                         {
-                            "filename": "viewer.js",
+                            "filename": "viewer.max.js",
                             "outputDirectory": "/../../Viewer/dist/"
                             "outputDirectory": "/../../Viewer/dist/"
                         },
                         },
                         {
                         {

+ 5 - 1
Tools/Gulp/gulp-addModuleExports.js

@@ -5,7 +5,7 @@ var through = require('through2');
  * The parameters for this function has grown during development.
  * The parameters for this function has grown during development.
  * Eventually, this function will need to be reorganized. 
  * Eventually, this function will need to be reorganized. 
  */
  */
-module.exports = function (varName, subModule, extendsRoot, externalUsingBabylon) {
+module.exports = function (varName, subModule, extendsRoot, externalUsingBabylon, noBabylonInit) {
     return through.obj(function (file, enc, cb) {
     return through.obj(function (file, enc, cb) {
 
 
         var optionalRequire = `var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
         var optionalRequire = `var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
@@ -75,6 +75,10 @@ globalObject["${base}"] = f;` : '';
             return;
             return;
         }
         }
 
 
+        if (noBabylonInit) {
+            optionalRequire = '';
+        }
+
         try {
         try {
             if (externalUsingBabylon) {
             if (externalUsingBabylon) {
                 //file.contents = new Buffer(optionalRequire.concat(String(file.contents)));
                 //file.contents = new Buffer(optionalRequire.concat(String(file.contents)));

+ 8 - 1
Tools/Gulp/gulpfile.js

@@ -434,7 +434,7 @@ var buildExternalLibrary = function (library, settings, watch) {
             let wpBuild = webpack(require(library.webpack));
             let wpBuild = webpack(require(library.webpack));
             if (settings.build.outputs) {
             if (settings.build.outputs) {
                 let build = wpBuild
                 let build = wpBuild
-                    .pipe(addModuleExports(library.moduleDeclaration, false, false, true));
+                    .pipe(addModuleExports(library.moduleDeclaration, false, false, true, library.babylonIncluded));
 
 
                 let unminifiedOutpus = [];
                 let unminifiedOutpus = [];
                 let minifiedOutputs = [];
                 let minifiedOutputs = [];
@@ -455,6 +455,12 @@ var buildExternalLibrary = function (library, settings, watch) {
                     build = build
                     build = build
                         .pipe(rename(dest.filename.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
                         .pipe(rename(dest.filename.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
                         .pipe(gulp.dest(outputDirectory));
                         .pipe(gulp.dest(outputDirectory));
+
+                    if (library.babylonIncluded && dest.addBabylonDeclaration) {
+                        // include the babylon declaration
+                        sequence.unshift(gulp.src(config.build.outputDirectory + '/' + config.build.declarationFilename)
+                            .pipe(gulp.dest(outputDirectory)))
+                    }
                 }
                 }
 
 
                 unminifiedOutpus.forEach(dest => {
                 unminifiedOutpus.forEach(dest => {
@@ -472,6 +478,7 @@ var buildExternalLibrary = function (library, settings, watch) {
                 });
                 });
 
 
                 sequence.push(build);
                 sequence.push(build);
+
             } else {
             } else {
                 sequence.push(
                 sequence.push(
                     wpBuild
                     wpBuild

+ 1 - 0
Viewer/dist/_redirects

@@ -0,0 +1 @@
+/viewer.min.js /viewer.js

+ 15 - 18
Viewer/src/configuration/loader.ts

@@ -3,13 +3,17 @@ import { ViewerConfiguration } from './configuration';
 import { getConfigurationType } from './types';
 import { getConfigurationType } from './types';
 
 
 import * as deepmerge from '../../assets/deepmerge.min.js';
 import * as deepmerge from '../../assets/deepmerge.min.js';
+import { Tools, IFileRequest } from 'babylonjs';
 
 
 export class ConfigurationLoader {
 export class ConfigurationLoader {
 
 
     private configurationCache: { [url: string]: any };
     private configurationCache: { [url: string]: any };
 
 
+    private loadRequests: Array<IFileRequest>;
+
     constructor() {
     constructor() {
         this.configurationCache = {};
         this.configurationCache = {};
+        this.loadRequests = [];
     }
     }
 
 
     public loadConfiguration(initConfig: ViewerConfiguration = {}, callback?: (config: ViewerConfiguration) => void): Promise<ViewerConfiguration> {
     public loadConfiguration(initConfig: ViewerConfiguration = {}, callback?: (config: ViewerConfiguration) => void): Promise<ViewerConfiguration> {
@@ -65,33 +69,26 @@ export class ConfigurationLoader {
         }
         }
     }
     }
 
 
+    public dispose() {
+        this.loadRequests.forEach(request => {
+            request.abort();
+        });
+    }
+
     private loadFile(url: string): Promise<any> {
     private loadFile(url: string): Promise<any> {
         let cacheReference = this.configurationCache;
         let cacheReference = this.configurationCache;
         if (cacheReference[url]) {
         if (cacheReference[url]) {
             return Promise.resolve(cacheReference[url]);
             return Promise.resolve(cacheReference[url]);
         }
         }
 
 
-        return new Promise(function (resolve, reject) {
-            var xhr = new XMLHttpRequest();
-            xhr.open('GET', url);
-            xhr.send();
-            xhr.onreadystatechange = function () {
-                var DONE = 4;
-                var OK = 200;
-                if (xhr.readyState === DONE) {
-                    if (xhr.status === OK) {
-                        cacheReference[url] = xhr.responseText;
-                        resolve(xhr.responseText); // 'This is the returned text.'
-                    } else {
-                        console.log('Error: ' + xhr.status, url);
-                        reject('Error: ' + xhr.status); // An error occurred during the request.
-                    }
-                }
-            }
+        return new Promise((resolve, reject) => {
+            let fileRequest = Tools.LoadFile(url, resolve, undefined, undefined, false, (request, error: any) => {
+                reject(error);
+            });
+            this.loadRequests.push(fileRequest);
         });
         });
     }
     }
 
 
-
 }
 }
 
 
 export let configurationLoader = new ConfigurationLoader();
 export let configurationLoader = new ConfigurationLoader();

+ 0 - 26
Viewer/src/helper.ts

@@ -5,32 +5,6 @@ export function isUrl(urlToCheck: string): boolean {
     return false;
     return false;
 }
 }
 
 
-export function loadFile(url: string): Promise<any> {
-    /*let cacheReference = this.configurationCache;
-    if (cacheReference[url]) {
-        return Promise.resolve(cacheReference[url]);
-    }*/
-
-    return new Promise(function (resolve, reject) {
-        var xhr = new XMLHttpRequest();
-        xhr.open('GET', url);
-        xhr.send();
-        xhr.onreadystatechange = function () {
-            var DONE = 4;
-            var OK = 200;
-            if (xhr.readyState === DONE) {
-                if (xhr.status === OK) {
-                    //cacheReference[url] = xhr.responseText;
-                    resolve(xhr.responseText); // 'This is the returned text.'
-                }
-            } else {
-                console.log('Error: ' + xhr.status, url);
-                reject('Error: ' + xhr.status); // An error occurred during the request.
-            }
-        }
-    });
-}
-
 export function kebabToCamel(s) {
 export function kebabToCamel(s) {
     return s.replace(/(\-\w)/g, function (m) { return m[1].toUpperCase(); });
     return s.replace(/(\-\w)/g, function (m) { return m[1].toUpperCase(); });
 }
 }

+ 47 - 24
Viewer/src/templateManager.ts

@@ -1,6 +1,6 @@
 
 
-import { Observable } from 'babylonjs';
-import { isUrl, loadFile, camelToKebab, kebabToCamel } from './helper';
+import { Observable, IFileRequest, Tools } from 'babylonjs';
+import { isUrl, camelToKebab, kebabToCamel } from './helper';
 
 
 export interface ITemplateConfiguration {
 export interface ITemplateConfiguration {
     location?: string; // #template-id OR http://example.com/loading.html
     location?: string; // #template-id OR http://example.com/loading.html
@@ -212,6 +212,8 @@ export class Template {
     private fragment: DocumentFragment;
     private fragment: DocumentFragment;
     private htmlTemplate: string;
     private htmlTemplate: string;
 
 
+    private loadRequests: Array<IFileRequest>;
+
     constructor(public name: string, private _configuration: ITemplateConfiguration) {
     constructor(public name: string, private _configuration: ITemplateConfiguration) {
         this.onInit = new Observable<Template>();
         this.onInit = new Observable<Template>();
         this.onLoaded = new Observable<Template>();
         this.onLoaded = new Observable<Template>();
@@ -219,6 +221,8 @@ export class Template {
         this.onStateChange = new Observable<Template>();
         this.onStateChange = new Observable<Template>();
         this.onEventTriggered = new Observable<EventCallback>();
         this.onEventTriggered = new Observable<EventCallback>();
 
 
+        this.loadRequests = [];
+
         this.isLoaded = false;
         this.isLoaded = false;
         this.isShown = false;
         this.isShown = false;
         /*
         /*
@@ -228,7 +232,7 @@ export class Template {
         */
         */
         this.onInit.notifyObservers(this);
         this.onInit.notifyObservers(this);
 
 
-        let htmlContentPromise = getTemplateAsHtml(_configuration);
+        let htmlContentPromise = this.getTemplateAsHtml(_configuration);
 
 
         this.initPromise = htmlContentPromise.then(htmlTemplate => {
         this.initPromise = htmlContentPromise.then(htmlTemplate => {
             if (htmlTemplate) {
             if (htmlTemplate) {
@@ -299,8 +303,12 @@ export class Template {
         });
         });
     }
     }
 
 
+    private isShowing: boolean;
+    private isHiding: boolean;
     public show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
     public show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
+        if (this.isHiding) return Promise.resolve(this);
         return Promise.resolve().then(() => {
         return Promise.resolve().then(() => {
+            this.isShowing = true;
             if (visibilityFunction) {
             if (visibilityFunction) {
                 return visibilityFunction(this);
                 return visibilityFunction(this);
             } else {
             } else {
@@ -310,13 +318,16 @@ export class Template {
             }
             }
         }).then(() => {
         }).then(() => {
             this.isShown = true;
             this.isShown = true;
+            this.isShowing = false;
             this.onStateChange.notifyObservers(this);
             this.onStateChange.notifyObservers(this);
             return this;
             return this;
         });
         });
     }
     }
 
 
     public hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
     public hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
+        if (this.isShowing) return Promise.resolve(this);
         return Promise.resolve().then(() => {
         return Promise.resolve().then(() => {
+            this.isHiding = true;
             if (visibilityFunction) {
             if (visibilityFunction) {
                 return visibilityFunction(this);
                 return visibilityFunction(this);
             } else {
             } else {
@@ -326,6 +337,7 @@ export class Template {
             }
             }
         }).then(() => {
         }).then(() => {
             this.isShown = false;
             this.isShown = false;
+            this.isHiding = false;
             this.onStateChange.notifyObservers(this);
             this.onStateChange.notifyObservers(this);
             return this;
             return this;
         });
         });
@@ -340,6 +352,38 @@ export class Template {
         this.isLoaded = false;
         this.isLoaded = false;
         // remove from parent
         // remove from parent
         this.parent.removeChild(this.fragment);
         this.parent.removeChild(this.fragment);
+
+        this.loadRequests.forEach(request => {
+            request.abort();
+        });
+    }
+
+    private getTemplateAsHtml(templateConfig: ITemplateConfiguration): Promise<string> {
+        if (!templateConfig) {
+            return Promise.reject('No templateConfig provided');
+        } else if (templateConfig.html) {
+            return Promise.resolve(templateConfig.html);
+        } else {
+            let location = getTemplateLocation(templateConfig);
+            if (isUrl(location)) {
+                return new Promise((resolve, reject) => {
+                    let fileRequest = Tools.LoadFile(location, (data: string) => {
+                        resolve(data);
+                    }, undefined, undefined, false, (request, error: any) => {
+                        reject(error);
+                    });
+                    this.loadRequests.push(fileRequest);
+                });
+            } else {
+                location = location.replace('#', '');
+                let element = document.getElementById(location);
+                if (element) {
+                    return Promise.resolve(element.innerHTML);
+                } else {
+                    return Promise.reject('Template ID not found');
+                }
+            }
+        }
     }
     }
 
 
     private registeredEvents: Array<{ htmlElement: HTMLElement, eventName: string, function: EventListenerOrEventListenerObject }>;
     private registeredEvents: Array<{ htmlElement: HTMLElement, eventName: string, function: EventListenerOrEventListenerObject }>;
@@ -389,27 +433,6 @@ export class Template {
     }
     }
 }
 }
 
 
-export function getTemplateAsHtml(templateConfig: ITemplateConfiguration): Promise<string> {
-    if (!templateConfig) {
-        return Promise.reject('No templateConfig provided');
-    } else if (templateConfig.html) {
-        return Promise.resolve(templateConfig.html);
-    } else {
-        let location = getTemplateLocation(templateConfig);
-        if (isUrl(location)) {
-            return loadFile(location);
-        } else {
-            location = location.replace('#', '');
-            let element = document.getElementById(location);
-            if (element) {
-                return Promise.resolve(element.innerHTML);
-            } else {
-                return Promise.reject('Template ID not found');
-            }
-        }
-    }
-}
-
 export function getTemplateLocation(templateConfig): string {
 export function getTemplateLocation(templateConfig): string {
     if (!templateConfig || typeof templateConfig === 'string') {
     if (!templateConfig || typeof templateConfig === 'string') {
         return templateConfig;
         return templateConfig;

+ 2 - 2
Viewer/src/viewer/defaultViewer.ts

@@ -103,8 +103,8 @@ export class DefaultViewer extends AbstractViewer {
         this.containerElement.style.display = 'flex';
         this.containerElement.style.display = 'flex';
     }
     }
 
 
-    protected configureModel(modelConfiguration: Partial<IModelConfiguration>) {
-        super.configureModel(modelConfiguration);
+    protected configureModel(modelConfiguration: Partial<IModelConfiguration>, focusMeshes: Array<AbstractMesh> = this.scene.meshes) {
+        super.configureModel(modelConfiguration, focusMeshes);
 
 
         let navbar = this.templateManager.getTemplate('navBar');
         let navbar = this.templateManager.getTemplate('navBar');
         if (!navbar) return;
         if (!navbar) return;

+ 41 - 7
Viewer/src/viewer/viewer.ts

@@ -421,7 +421,9 @@ export abstract class AbstractViewer {
             }
             }
         };
         };
 
 
-        const sceneExtends = this.scene.getWorldExtends();
+        const sceneExtends = this.scene.getWorldExtends((mesh) => {
+            return !this.environmentHelper || (mesh !== this.environmentHelper.ground && mesh !== this.environmentHelper.rootMesh && mesh !== this.environmentHelper.skybox);
+        });
         const sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
         const sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
         const sceneDiagonalLenght = sceneDiagonal.length();
         const sceneDiagonalLenght = sceneDiagonal.length();
         if (isFinite(sceneDiagonalLenght))
         if (isFinite(sceneDiagonalLenght))
@@ -744,13 +746,36 @@ export abstract class AbstractViewer {
         return Promise.resolve(this.scene);
         return Promise.resolve(this.scene);
     }
     }
 
 
+    private isLoading: boolean;
+    private nextLoading: Function;
+
     public loadModel(model: any = this.configuration.model, clearScene: boolean = true): Promise<Scene> {
     public loadModel(model: any = this.configuration.model, clearScene: boolean = true): Promise<Scene> {
         // no model was provided? Do nothing!
         // no model was provided? Do nothing!
-        if (!model.url) {
+        let modelUrl = (typeof model === 'string') ? model : model.url;
+        if (!modelUrl) {
             return Promise.resolve(this.scene);
             return Promise.resolve(this.scene);
         }
         }
-        this.configuration.model = model;
-        let modelUrl = (typeof model === 'string') ? model : model.url;
+        if (this.isLoading) {
+            //another model is being model. Wait for it to finish, trigger the load afterwards
+            this.nextLoading = () => {
+                delete this.nextLoading;
+                this.loadModel(model, clearScene);
+            }
+            return Promise.resolve(this.scene);
+        }
+        this.isLoading = true;
+        if ((typeof model === 'string')) {
+            if (this.configuration.model && typeof this.configuration.model === 'object') {
+                this.configuration.model.url = model;
+            }
+        } else {
+            if (this.configuration.model) {
+                deepmerge(this.configuration.model, model)
+            } else {
+                this.configuration.model = model;
+            }
+        }
+
         let parts = modelUrl.split('/');
         let parts = modelUrl.split('/');
         let filename = parts.pop();
         let filename = parts.pop();
         let base = parts.join('/') + '/';
         let base = parts.join('/') + '/';
@@ -761,13 +786,18 @@ export abstract class AbstractViewer {
 
 
             if (clearScene) {
             if (clearScene) {
                 scene.meshes.forEach(mesh => {
                 scene.meshes.forEach(mesh => {
-                    mesh.dispose();
+                    if (Tags.MatchesQuery(mesh, "viewerMesh")) {
+                        mesh.dispose();
+                    }
                 });
                 });
             }
             }
             return scene!;
             return scene!;
         }).then(() => {
         }).then(() => {
             return new Promise<Array<AbstractMesh>>((resolve, reject) => {
             return new Promise<Array<AbstractMesh>>((resolve, reject) => {
                 this.lastUsedLoader = SceneLoader.ImportMesh(undefined, base, filename, this.scene, (meshes) => {
                 this.lastUsedLoader = SceneLoader.ImportMesh(undefined, base, filename, this.scene, (meshes) => {
+                    meshes.forEach(mesh => {
+                        Tags.AddTagsTo(mesh, "viewerMesh");
+                    });
                     resolve(meshes);
                     resolve(meshes);
                 }, (progressEvent) => {
                 }, (progressEvent) => {
                     this.onModelLoadProgressObservable.notifyObserversWithPromise(progressEvent);
                     this.onModelLoadProgressObservable.notifyObserversWithPromise(progressEvent);
@@ -783,7 +813,7 @@ export abstract class AbstractViewer {
             return this.onModelLoadedObservable.notifyObserversWithPromise(meshes)
             return this.onModelLoadedObservable.notifyObserversWithPromise(meshes)
                 .then(() => {
                 .then(() => {
                     // update the models' configuration
                     // update the models' configuration
-                    this.configureModel(model, meshes);
+                    this.configureModel(this.configuration.model || model, meshes);
                     this.configureLights(this.configuration.lights);
                     this.configureLights(this.configuration.lights);
 
 
                     if (this.configuration.camera) {
                     if (this.configuration.camera) {
@@ -791,12 +821,16 @@ export abstract class AbstractViewer {
                     }
                     }
                     return this.initEnvironment(meshes);
                     return this.initEnvironment(meshes);
                 }).then(() => {
                 }).then(() => {
+                    this.isLoading = false;
+                    if (this.nextLoading) {
+                        return this.nextLoading();
+                    }
                     return this.scene;
                     return this.scene;
                 });
                 });
         });
         });
     }
     }
 
 
-    protected initEnvironment(focusMeshes: Array<AbstractMesh> = []): Promise<Scene> {
+    protected initEnvironment(focusMeshes: Array<AbstractMesh> = this.scene.meshes): Promise<Scene> {
         this.configureEnvironment(this.configuration.skybox, this.configuration.ground);
         this.configureEnvironment(this.configuration.skybox, this.configuration.ground);
 
 
         return Promise.resolve(this.scene);
         return Promise.resolve(this.scene);

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


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


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


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


File diff suppressed because it is too large
+ 1506 - 1504
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


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


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


File diff suppressed because it is too large
+ 10 - 8
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js


File diff suppressed because it is too large
+ 50 - 22
dist/preview release/es6.js


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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-gui",
     "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.",
     "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.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

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

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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-loaders",
     "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.",
     "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.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-materials",
     "name": "babylonjs-materials",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.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",
     "name": "babylonjs-post-process",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.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",
     "name": "babylonjs-procedural-textures",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

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

+ 8 - 24
dist/preview release/viewer/babylon.viewer.d.ts

@@ -1,5 +1,3 @@
-/// <reference path="../babylon.d.ts"/>
-
 declare module BabylonViewer {
 declare module BabylonViewer {
 
 
     export let disableInit: boolean;
     export let disableInit: boolean;
@@ -56,7 +54,7 @@ declare module BabylonViewer {
         selector: string;
         selector: string;
         payload?: any;
         payload?: any;
     }
     }
-    class TemplateManager {
+    interface TemplateManager {
         containerElement: HTMLElement;
         containerElement: HTMLElement;
         onInit: BABYLON.Observable<Template>;
         onInit: BABYLON.Observable<Template>;
         onLoaded: BABYLON.Observable<Template>;
         onLoaded: BABYLON.Observable<Template>;
@@ -64,20 +62,16 @@ declare module BabylonViewer {
         onAllLoaded: BABYLON.Observable<TemplateManager>;
         onAllLoaded: BABYLON.Observable<TemplateManager>;
         onEventTriggered: BABYLON.Observable<EventCallback>;
         onEventTriggered: BABYLON.Observable<EventCallback>;
         eventManager: EventManager;
         eventManager: EventManager;
-        private templates;
         constructor(containerElement: HTMLElement);
         constructor(containerElement: HTMLElement);
         initTemplate(templates: {
         initTemplate(templates: {
             [key: string]: ITemplateConfiguration;
             [key: string]: ITemplateConfiguration;
         }): void;
         }): void;
-        private buildHTMLTree(templates);
         getCanvas(): HTMLCanvasElement | null;
         getCanvas(): HTMLCanvasElement | null;
         getTemplate(name: string): Template | undefined;
         getTemplate(name: string): Template | undefined;
-        private checkLoadedState();
     }
     }
 
 
-    class Template {
+    interface Template {
         name: string;
         name: string;
-        private _configuration;
         onInit: BABYLON.Observable<Template>;
         onInit: BABYLON.Observable<Template>;
         onLoaded: BABYLON.Observable<Template>;
         onLoaded: BABYLON.Observable<Template>;
         onAppended: BABYLON.Observable<Template>;
         onAppended: BABYLON.Observable<Template>;
@@ -87,7 +81,6 @@ declare module BabylonViewer {
         isShown: boolean;
         isShown: boolean;
         parent: HTMLElement;
         parent: HTMLElement;
         initPromise: Promise<Template>;
         initPromise: Promise<Template>;
-        private fragment;
         constructor(name: string, _configuration: ITemplateConfiguration);
         constructor(name: string, _configuration: ITemplateConfiguration);
         readonly configuration: ITemplateConfiguration;
         readonly configuration: ITemplateConfiguration;
         getChildElements(): Array<string>;
         getChildElements(): Array<string>;
@@ -95,11 +88,9 @@ declare module BabylonViewer {
         show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
         show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
         hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
         hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
         dispose(): void;
         dispose(): void;
-        private registerEvents();
     }
     }
 
 
-    class ViewerManager {
-        private viewers;
+    interface ViewerManager {
         onViewerAdded: (viewer: AbstractViewer) => void;
         onViewerAdded: (viewer: AbstractViewer) => void;
         onViewerAddedObservable: BABYLON.Observable<AbstractViewer>;
         onViewerAddedObservable: BABYLON.Observable<AbstractViewer>;
         constructor();
         constructor();
@@ -107,7 +98,6 @@ declare module BabylonViewer {
         getViewerById(id: string): AbstractViewer;
         getViewerById(id: string): AbstractViewer;
         getViewerByHTMLElement(element: HTMLElement): AbstractViewer | undefined;
         getViewerByHTMLElement(element: HTMLElement): AbstractViewer | undefined;
         getViewerPromiseById(id: string): Promise<AbstractViewer>;
         getViewerPromiseById(id: string): Promise<AbstractViewer>;
-        private _onViewerAdded(viewer);
     }
     }
     export let viewerManager: ViewerManager;
     export let viewerManager: ViewerManager;
 
 
@@ -119,37 +109,31 @@ declare module BabylonViewer {
 
 
     export function InitTags(selector?: string): void;
     export function InitTags(selector?: string): void;
 
 
-    class EventManager {
-        private templateManager;
-        private callbacksContainer;
+    interface EventManager {
         constructor(templateManager: TemplateManager);
         constructor(templateManager: TemplateManager);
         registerCallback(templateName: string, callback: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
         registerCallback(templateName: string, callback: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
         unregisterCallback(templateName: string, callback?: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
         unregisterCallback(templateName: string, callback?: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
-        private eventTriggered(data);
     }
     }
 
 
-    class PromiseObservable<T> extends BABYLON.Observable<T> {
+    interface PromiseObservable<T> extends BABYLON.Observable<T> {
         notifyWithPromise(eventData: T, mask?: number, target?: any, currentTarget?: any): Promise<any>;
         notifyWithPromise(eventData: T, mask?: number, target?: any, currentTarget?: any): Promise<any>;
     }
     }
 
 
     export interface IMapper {
     export interface IMapper {
         map(rawSource: any): ViewerConfiguration;
         map(rawSource: any): ViewerConfiguration;
     }
     }
-    class MapperManager {
-        private mappers;
-        static DefaultMapper: string;
+    interface MapperManager {
+        DefaultMapper: string;
         constructor();
         constructor();
         getMapper(type: string): IMapper;
         getMapper(type: string): IMapper;
         registerMapper(type: string, mapper: IMapper): void;
         registerMapper(type: string, mapper: IMapper): void;
     }
     }
     export let mapperManager: MapperManager;
     export let mapperManager: MapperManager;
 
 
-    class ConfigurationLoader {
-        private configurationCache;
+    interface ConfigurationLoader {
         constructor();
         constructor();
         loadConfiguration(initConfig?: ViewerConfiguration): Promise<ViewerConfiguration>;
         loadConfiguration(initConfig?: ViewerConfiguration): Promise<ViewerConfiguration>;
         getConfigurationType(type: string): void;
         getConfigurationType(type: string): void;
-        private loadFile(url);
     }
     }
     export let configurationLoader: ConfigurationLoader;
     export let configurationLoader: ConfigurationLoader;
 
 

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


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


+ 4 - 484
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -1,486 +1,6 @@
-/// <reference types="babylonjs"/>
+/// <reference path="./babylon.d.ts"/>
+/// <reference path="./babylon.viewer.d.ts"/>
 
 
-declare module BabylonViewer {
-
-    export let disableInit: boolean;
-
-    export interface ITemplateConfiguration {
-        location?: string;
-        html?: string;
-        id?: string;
-        params?: {
-            [key: string]: string | number | boolean | object;
-        };
-        events?: {
-            pointerdown?: boolean | {
-                [id: string]: boolean;
-            };
-            pointerup?: boolean | {
-                [id: string]: boolean;
-            };
-            pointermove?: boolean | {
-                [id: string]: boolean;
-            };
-            pointerover?: boolean | {
-                [id: string]: boolean;
-            };
-            pointerout?: boolean | {
-                [id: string]: boolean;
-            };
-            pointerenter?: boolean | {
-                [id: string]: boolean;
-            };
-            pointerleave?: boolean | {
-                [id: string]: boolean;
-            };
-            pointercancel?: boolean | {
-                [id: string]: boolean;
-            };
-            click?: boolean | {
-                [id: string]: boolean;
-            };
-            dragstart?: boolean | {
-                [id: string]: boolean;
-            };
-            drop?: boolean | {
-                [id: string]: boolean;
-            };
-            [key: string]: boolean | {
-                [id: string]: boolean;
-            } | undefined;
-        };
-    }
-    export interface EventCallback {
-        event: Event;
-        template: Template;
-        selector: string;
-        payload?: any;
-    }
-    class TemplateManager {
-        containerElement: HTMLElement;
-        onInit: BABYLON.Observable<Template>;
-        onLoaded: BABYLON.Observable<Template>;
-        onStateChange: BABYLON.Observable<Template>;
-        onAllLoaded: BABYLON.Observable<TemplateManager>;
-        onEventTriggered: BABYLON.Observable<EventCallback>;
-        eventManager: EventManager;
-        private templates;
-        constructor(containerElement: HTMLElement);
-        initTemplate(templates: {
-            [key: string]: ITemplateConfiguration;
-        }): void;
-        private buildHTMLTree(templates);
-        getCanvas(): HTMLCanvasElement | null;
-        getTemplate(name: string): Template | undefined;
-        private checkLoadedState();
-    }
-
-    class Template {
-        name: string;
-        private _configuration;
-        onInit: BABYLON.Observable<Template>;
-        onLoaded: BABYLON.Observable<Template>;
-        onAppended: BABYLON.Observable<Template>;
-        onStateChange: BABYLON.Observable<Template>;
-        onEventTriggered: BABYLON.Observable<EventCallback>;
-        isLoaded: boolean;
-        isShown: boolean;
-        parent: HTMLElement;
-        initPromise: Promise<Template>;
-        private fragment;
-        constructor(name: string, _configuration: ITemplateConfiguration);
-        readonly configuration: ITemplateConfiguration;
-        getChildElements(): Array<string>;
-        appendTo(parent: HTMLElement): void;
-        show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
-        hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
-        dispose(): void;
-        private registerEvents();
-    }
-
-    class ViewerManager {
-        private viewers;
-        onViewerAdded: (viewer: AbstractViewer) => void;
-        onViewerAddedObservable: BABYLON.Observable<AbstractViewer>;
-        constructor();
-        addViewer(viewer: AbstractViewer): void;
-        getViewerById(id: string): AbstractViewer;
-        getViewerByHTMLElement(element: HTMLElement): AbstractViewer | undefined;
-        getViewerPromiseById(id: string): Promise<AbstractViewer>;
-        private _onViewerAdded(viewer);
-    }
-    export let viewerManager: ViewerManager;
-
-    export const enum CameraBehavior {
-        AUTOROTATION = 0,
-        BOUNCING = 1,
-        FRAMING = 2,
-    }
-
-    export function InitTags(selector?: string): void;
-
-    class EventManager {
-        private templateManager;
-        private callbacksContainer;
-        constructor(templateManager: TemplateManager);
-        registerCallback(templateName: string, callback: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
-        unregisterCallback(templateName: string, callback?: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
-        private eventTriggered(data);
-    }
-
-    class PromiseObservable<T> extends BABYLON.Observable<T> {
-        notifyWithPromise(eventData: T, mask?: number, target?: any, currentTarget?: any): Promise<any>;
-    }
-
-    export interface IMapper {
-        map(rawSource: any): ViewerConfiguration;
-    }
-    class MapperManager {
-        private mappers;
-        static DefaultMapper: string;
-        constructor();
-        getMapper(type: string): IMapper;
-        registerMapper(type: string, mapper: IMapper): void;
-    }
-    export let mapperManager: MapperManager;
-
-    class ConfigurationLoader {
-        private configurationCache;
-        constructor();
-        loadConfiguration(initConfig?: ViewerConfiguration): Promise<ViewerConfiguration>;
-        getConfigurationType(type: string): void;
-        private loadFile(url);
-    }
-    export let configurationLoader: ConfigurationLoader;
-
-
-    /////> configuration
-    export interface ViewerConfiguration {
-
-        // configuration version
-        version?: string;
-        extends?: string; // is this configuration extending an existing configuration?
-
-        pageUrl?: string; // will be used for sharing and other fun stuff. This is the page showing the model (not the model's url!)
-
-        configuration?: string | {
-            url?: string;
-            payload?: any;
-            mapper?: string; // json (default), html, yaml, xml, etc'. if not provided, file extension will be used.
-        };
-
-        // names of functions in the window context.
-        observers?: IObserversConfiguration;
-
-        canvasElement?: string; // if there is a need to override the standard implementation - ID of HTMLCanvasElement
-
-        model?: IModelConfiguration | string;
-
-        scene?: ISceneConfiguration;
-        optimizer?: ISceneOptimizerConfiguration | boolean;
-        // at the moment, support only a single camera.
-        camera?: ICameraConfiguration,
-        skybox?: boolean | ISkyboxConfiguration;
-
-        ground?: boolean | IGroundConfiguration;
-        lights?: { [name: string]: boolean | ILightConfiguration },
-        // engine configuration. optional!
-        engine?: {
-            antialiasing?: boolean;
-            disableResize?: boolean;
-            engineOptions?: { [key: string]: any };
-            adaptiveQuality?: boolean;
-        },
-        //templateStructure?: ITemplateStructure,
-        templates?: {
-            main: ITemplateConfiguration,
-            [key: string]: ITemplateConfiguration
-        };
-
-        customShaders?: {
-            shaders?: {
-                [key: string]: string;
-            };
-            includes?: {
-                [key: string]: string;
-            }
-        }
-
-        // features that are being tested.
-        // those features' syntax will change and move out! 
-        // Don't use in production (or be ready to make the changes :) )
-        lab?: {
-            flashlight?: boolean | {
-                exponent?: number;
-                angle?: number;
-                intensity?: number;
-                diffuse?: { r: number, g: number, b: number };
-                specular?: { r: number, g: number, b: number };
-            }
-            hideLoadingDelay?: number;
-        }
-    }
-
-    export interface IModelConfiguration {
-        url?: string;
-        loader?: string; // obj, gltf?
-        position?: { x: number, y: number, z: number };
-        rotation?: { x: number, y: number, z: number, w?: number };
-        scaling?: { x: number, y: number, z: number };
-        parentObjectIndex?: number; // the index of the parent object of the model in the loaded meshes array.
-
-        castShadow?: boolean;
-        normalize?: boolean | {
-            center?: boolean;
-            unitSize?: boolean;
-            parentIndex?: number;
-        }; // shoud the model be scaled to unit-size
-
-        title?: string;
-        subtitle?: string;
-        thumbnail?: string; // URL or data-url
-
-        // [propName: string]: any; // further configuration, like title and creator
-    }
-
-    export interface ISkyboxConfiguration {
-        cubeTexture?: {
-            noMipMap?: boolean;
-            gammaSpace?: boolean;
-            url?: string | Array<string>;
-        };
-        color?: { r: number, g: number, b: number };
-        pbr?: boolean; // deprecated
-        scale?: number;
-        blur?: number; // deprecated
-        material?: {
-            imageProcessingConfiguration?: IImageProcessingConfiguration;
-            [propName: string]: any;
-        };
-        infiniteDIstance?: boolean;
-
-    }
-
-    export interface IGroundConfiguration {
-        size?: number;
-        receiveShadows?: boolean;
-        shadowLevel?: number;
-        shadowOnly?: boolean; // deprecated
-        mirror?: boolean | {
-            sizeRatio?: number;
-            blurKernel?: number;
-            amount?: number;
-            fresnelWeight?: number;
-            fallOffDistance?: number;
-            textureType?: number;
-        };
-        texture?: string;
-        color?: { r: number, g: number, b: number };
-        opacity?: number;
-        material?: { // deprecated!
-            [propName: string]: any;
-        };
-    }
-
-    export interface ISceneConfiguration {
-        debug?: boolean;
-        autoRotate?: boolean; // deprecated
-        rotationSpeed?: number; // deprecated
-        defaultCamera?: boolean; // deprecated
-        defaultLight?: boolean; // deprecated
-        clearColor?: { r: number, g: number, b: number, a: number };
-        imageProcessingConfiguration?: IImageProcessingConfiguration;
-        environmentTexture?: string;
-    }
-
-    export interface ISceneOptimizerConfiguration {
-        targetFrameRate?: number;
-        trackerDuration?: number;
-        autoGeneratePriorities?: boolean;
-        improvementMode?: boolean;
-        degradation?: string; // low, moderate, high
-        types?: {
-            texture?: ISceneOptimizerParameters;
-            hardwareScaling?: ISceneOptimizerParameters;
-            shadow?: ISceneOptimizerParameters;
-            postProcess?: ISceneOptimizerParameters;
-            lensFlare?: ISceneOptimizerParameters;
-            particles?: ISceneOptimizerParameters;
-            renderTarget?: ISceneOptimizerParameters;
-            mergeMeshes?: ISceneOptimizerParameters;
-        }
-    }
-
-    export interface IObserversConfiguration {
-        onEngineInit?: string;
-        onSceneInit?: string;
-        onModelLoaded?: string;
-    }
-
-    export interface ICameraConfiguration {
-        position?: { x: number, y: number, z: number };
-        rotation?: { x: number, y: number, z: number, w: number };
-        fov?: number;
-        fovMode?: number;
-        minZ?: number;
-        maxZ?: number;
-        inertia?: number;
-        behaviors?: {
-            [name: string]: number | {
-                type: number;
-                [propName: string]: any;
-            };
-        };
-
-        [propName: string]: any;
-    }
-
-    export interface ILightConfiguration {
-        type: number;
-        name?: string;
-        disabled?: boolean;
-        position?: { x: number, y: number, z: number };
-        target?: { x: number, y: number, z: number };
-        direction?: { x: number, y: number, z: number };
-        diffuse?: { r: number, g: number, b: number };
-        specular?: { r: number, g: number, b: number };
-        intensity?: number;
-        intensityMode?: number;
-        radius?: number;
-        shadownEnabled?: boolean; // only on specific lights!
-        shadowConfig?: {
-            useBlurExponentialShadowMap?: boolean;
-            useKernelBlur?: boolean;
-            blurKernel?: number;
-            blurScale?: number;
-            minZ?: number;
-            maxZ?: number;
-            frustumSize?: number;
-            angleScale?: number;
-            [propName: string]: any;
-        }
-        [propName: string]: any;
-
-        // no behaviors for light at the moment, but allowing configuration for future reference.
-        behaviors?: {
-            [name: string]: number | {
-                type: number;
-                [propName: string]: any;
-            };
-        };
-    }
-
-    export interface ISceneOptimizerParameters {
-        priority?: number;
-        maximumSize?: number;
-        step?: number;
-    }
-
-    export interface IImageProcessingConfiguration {
-        colorGradingEnabled?: boolean;
-        colorCurvesEnabled?: boolean;
-        colorCurves?: {
-            globalHue?: number;
-            globalDensity?: number;
-            globalSaturation?: number;
-            globalExposure?: number;
-            highlightsHue?: number;
-            highlightsDensity?: number;
-            highlightsSaturation?: number;
-            highlightsExposure?: number;
-            midtonesHue?: number;
-            midtonesDensity?: number;
-            midtonesSaturation?: number;
-            midtonesExposure?: number;
-            shadowsHue?: number;
-            shadowsDensity?: number;
-            shadowsSaturation?: number;
-            shadowsExposure?: number;
-        };
-        colorGradingWithGreenDepth?: boolean;
-        colorGradingBGR?: boolean;
-        exposure?: number;
-        toneMappingEnabled?: boolean;
-        contrast?: number;
-        vignetteEnabled?: boolean;
-        vignetteStretch?: number;
-        vignetteCentreX?: number;
-        vignetteCentreY?: number;
-        vignetteWeight?: number;
-        vignetteColor?: { r: number, g: number, b: number, a?: number };
-        vignetteCameraFov?: number;
-        vignetteBlendMode?: number;
-        vignetteM?: boolean;
-        applyByPostProcess?: boolean;
-
-    }
-    /////>configuration
-
-    /////<viewer
-    export abstract class AbstractViewer {
-        containerElement: HTMLElement;
-        templateManager: TemplateManager;
-        camera: BABYLON.ArcRotateCamera;
-        engine: BABYLON.Engine;
-        scene: BABYLON.Scene;
-        baseId: string;
-        canvas: HTMLCanvasElement;
-        protected configuration: ViewerConfiguration;
-        environmentHelper: BABYLON.EnvironmentHelper;
-        protected defaultHighpTextureType: number;
-        protected shadowGeneratorBias: number;
-        protected defaultPipelineTextureType: number;
-        protected maxShadows: number;
-        onSceneInitObservable: BABYLON.Observable<BABYLON.Scene>;
-        onEngineInitObservable: BABYLON.Observable<BABYLON.Engine>;
-        onModelLoadedObservable: BABYLON.Observable<BABYLON.AbstractMesh[]>;
-        onModelLoadProgressObservable: BABYLON.Observable<BABYLON.SceneLoaderProgressEvent>;
-        onModelLoadErrorObservable: BABYLON.Observable<{ message: string; exception: any }>;
-        onLoaderInitObservable: BABYLON.Observable<BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync>;
-        onInitDoneObservable: BABYLON.Observable<AbstractViewer>;
-        constructor(containerElement: HTMLElement, initialConfiguration?: ViewerConfiguration);
-        getBaseId(): string;
-        protected abstract prepareContainerElement(): any;
-        protected onTemplatesLoaded(): Promise<AbstractViewer>;
-        protected initEngine(): Promise<BABYLON.Engine>;
-        protected initScene(): Promise<BABYLON.Scene>;
-        dispose(): void;
-        loadModel(model?: any, clearScene?: boolean): Promise<BABYLON.Scene>;
-        lastUsedLoader: BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync;
-        sceneOptimizer: BABYLON.SceneOptimizer;
-        protected registeredOnBeforerenderFunctions: Array<() => void>;
-        isCanvasInDOM(): boolean;
-        protected resize: () => void;
-        protected render: () => void;
-        updateConfiguration(newConfiguration: Partial<ViewerConfiguration>): void;
-        protected configureEnvironment(skyboxConifguration?: ISkyboxConfiguration | boolean, groundConfiguration?: IGroundConfiguration | boolean): void;
-        protected configureScene(sceneConfig: ISceneConfiguration, optimizerConfig?: ISceneOptimizerConfiguration): void;
-        protected configureOptimizer(optimizerConfig: ISceneOptimizerConfiguration | boolean): void;
-        protected configureObservers(observersConfiguration: IObserversConfiguration): void;
-        protected configureCamera(cameraConfig: ICameraConfiguration, focusMeshes: Array<BABYLON.AbstractMesh>): void;
-        protected configureLights(lightsConfiguration: { [name: string]: ILightConfiguration | boolean }, focusMeshes: Array<BABYLON.AbstractMesh>): void;
-        protected configureModel(modelConfiguration: Partial<IModelConfiguration>, focusMeshes: Array<BABYLON.AbstractMesh>): void;
-        dispose(): void;
-        protected initEnvironment(focusMeshes: Array<BABYLON.AbstractMesh>): Promise<BABYLON.Scene>;
-        protected injectCustomShaders(): void;
-        protected extendClassWithConfig(object: any, config: any): void;
-        protected handleHardwareLimitations(): void;
-
-
-    }
-
-    export class DefaultViewer extends AbstractViewer {
-        containerElement: HTMLElement;
-        camera: BABYLON.ArcRotateCamera;
-        constructor(containerElement: HTMLElement, initialConfiguration?: ViewerConfiguration);
-        initScene(): Promise<BABYLON.Scene>;
-        protected onTemplatesLoaded(): Promise<AbstractViewer>;
-        protected prepareContainerElement(): void;
-        loadModel(model?: any): Promise<BABYLON.Scene>;
-        initEnvironment(focusMeshes?: Array<BABYLON.AbstractMesh>): Promise<BABYLON.Scene>;
-        showOverlayScreen(subScreen: string): Promise<Template>;
-        hideOverlayScreen(): Promise<Template>;
-        showLoadingScreen(): Promise<Template>;
-        hideLoadingScreen(): Promise<Template>;
-    }
+declare module "babylonjs-viewer" {
+    export = BabylonViewer;
 }
 }

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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-viewer",
     "name": "babylonjs-viewer",
     "description": "A simple-to-use viewer based on BabylonJS to display 3D elements natively",
     "description": "A simple-to-use viewer based on BabylonJS to display 3D elements natively",
-    "version": "3.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -12,7 +12,9 @@
     "main": "babylon.viewer.js",
     "main": "babylon.viewer.js",
     "files": [
     "files": [
         "babylon.viewer.js",
         "babylon.viewer.js",
+        "babylon.viewer.d.ts",
         "babylon.viewer.module.d.ts",
         "babylon.viewer.module.d.ts",
+        "babylon.d.ts",
         "readme.md",
         "readme.md",
         "package.json"
         "package.json"
     ],
     ],

+ 25 - 12
dist/preview release/viewer/readme.md

@@ -1,5 +1,4 @@
-Babylon.js Viewer
-=====================
+# Babylon.js Viewer
 
 
 Babylon's viewer is a wrapper around Babylon, that automatically initializes the needed components in order to display a loaded model. It is easy to use, and require no coding at all.
 Babylon's viewer is a wrapper around Babylon, that automatically initializes the needed components in order to display a loaded model. It is easy to use, and require no coding at all.
 
 
@@ -9,13 +8,13 @@ for basic and advanced usage instructions please read the doc at https://doc.bab
 
 
 The source code can be found at https://github.com/BabylonJS/Babylon.js/tree/master/Viewer
 The source code can be found at https://github.com/BabylonJS/Babylon.js/tree/master/Viewer
 
 
-# Basic usage
+## Basic usage
 
 
-to create a simple viewer add the following code to your HTML>
+to create a simple viewer add the following code to your HTML:
 
 
 ```HTML
 ```HTML
 <babylon model="https://playground.babylonjs.com/scenes/Rabbit.babylon"></babylon>
 <babylon model="https://playground.babylonjs.com/scenes/Rabbit.babylon"></babylon>
-<script src="https://viewer.babylonjs.com/viewer.min.js"></script>
+<script src="https://viewer.babylonjs.com/viewer.js"></script>
 ```
 ```
 
 
 Make sure to size the babylon HTML tag. For example:
 Make sure to size the babylon HTML tag. For example:
@@ -29,28 +28,42 @@ babylon {
 }
 }
 ```
 ```
 
 
-# Installation instructions
+## Installation instructions
 
 
-## CDN
+### CDN
 
 
-Compiled js files (minified) are offered on our public CDN here:
+Compiled js files are offered on our public CDN here:
 
 
-* https://viewer.babylonjs.com/serializers/viewer.min.js
+* https://viewer.babylonjs.com/viewer.js (minified)
+* https://viewer.babylonjs.com/viewer.max.js
 
 
-## NPM
+### Using NPM
 
 
 To install using npm :
 To install using npm :
 
 
-```
+```javascript
 npm install --save babylonjs-viewer
 npm install --save babylonjs-viewer
 ```
 ```
 
 
 Afterwards it can be imported to the project using:
 Afterwards it can be imported to the project using:
 
 
-```
+```javascript
 import from 'babylonjs-viewer';
 import from 'babylonjs-viewer';
 ```
 ```
 
 
 This will enable the BabylonViewer namespace.
 This will enable the BabylonViewer namespace.
 
 
 Using webpack to package your project will use the minified js file.
 Using webpack to package your project will use the minified js file.
+
+## TypeScript
+
+If you use the npm package, starting 3.2.0-alpha8 the babylon viewer has a module declaration file that also includes the BABYLON namespace.
+
+Using TypeScript and NPM you could do the following:
+
+```javascript
+import from 'babylonjs-viewer';
+
+// both namespaces are now available
+console.log(BabylonViewer, BABYLON)
+```

+ 93 - 91
dist/preview release/what's new.md

@@ -1,91 +1,93 @@
-# 3.2.0
-
-## Major updates
-
-- Support for [GPU particles](https://doc.babylonjs.com/babylon101/particles#gpu-particles) ([deltakosh](https://github.com/deltakosh))
-- Improved building process: We now run a full visual validation test for each pull request. Furthermore, code comments and what's new updates are now mandatory ([sebavan](https://github.com/sebavan))
-- 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))
-- New [AnimationGroup class](http://doc.babylonjs.com/how_to/group) to control simultaneously multiple animations with different targets ([deltakosh](https://github.com/deltakosh))
-- `WebVRCamera` now supports GearVR ([brianzinn](https://github.com/brianzinn))
-- New glTF [serializer](https://github.com/BabylonJS/Babylon.js/tree/master/serializers/src/glTF/2.0). You can now export glTF or glb files directly from a Babylon scene ([kcoley](https://github.com/kcoley))
-- Babylon.js now uses Promises in addition to callbacks. We created several `xxxAsync` functions all over the framework (`SceneLoader.AppendAsync` for instance, which returns a Promise). A polyfill is also integrated to support older browsers ([deltakosh](https://github.com/deltakosh))
-- Introduced [Projection Texture on SpotLight](http://doc.babylonjs.com/babylon101/lights#projection-texture) ([lostink](https://github.com/lostink))
-- Introduced support for [local cubemaps](http://doc.babylonjs.com/how_to/reflect#using-local-cubemap-mode) ([deltakosh](https://github.com/deltakosh))
-- Added [VideoDome](http://doc.babylonjs.com/how_to/360videodome) class to easily support 360 videos ([DavidHGillen](https://github.com/DavidHGillen))
-- Added [GlowLayer](https://doc.babylonjs.com/how_to/glow_layer) to easily support glow from emissive materials ([sebavan](https://github.com/sebavan))
-
-## Updates
-
-- Tons of functions and classes received the code comments they deserved (All the community)
-- Added `particleSystem.reset()` to clear a particle system ([deltakosh](https://github.com/deltakosh))
-- Added support for all RGBA orders (BGR, RGB, etc..) for the DDS loader ([deltakosh](https://github.com/deltakosh))
-- Improved [SceneOptimizer](http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer) to provide better adaptability ([deltakosh](https://github.com/deltakosh))
-- Improved `scene.isReady()` function which now takes in account shadows and LOD ([deltakosh](https://github.com/deltakosh))
-- 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))
-- Added GUI Textblock.lineSpacing setter and getter to configure vertical space between lines in pixels or percentage values when working with text wrapping ([carloslanderas](https://github.com/carloslanderas))
-- VRHelper now has onSelectedMeshUnselected observable that will notify observers when the current selected mesh gets unselected
-  ([carloslanderas](https://github.com/carloslanderas))
-- VRHelper now has onBeforeCameraTeleport and onAfterCameraTeleport observables that will be notified before and after camera teleportation is triggered.
-  ([carloslanderas](https://github.com/carloslanderas))
-- VRHelper now has the public property teleportationEnabled to enable / disable camera teleportation.
-   ([carloslanderas](https://github.com/carloslanderas))
-- VRHelper now exposes onNewMeshPicked observable that will notify a PickingInfo object after meshSelectionPredicate evaluation
-   ([carloslanderas](https://github.com/carloslanderas))
-- `AssetsManager` will now clear its `tasks` lsit from all successfully loaded tasks ([deltakosh](https://github.com/deltakosh))
-- Added documentation to WebVRCamera and VRExperienceHelper ([trevordev](https://github.com/trevordev))
-- Introduced `isStroke` on `HighlightLayerOptions` which makes the highlight solid ([PixelsCommander](https://github.com/pixelscommander))
-- (Viewer) There is now an option to paste payload instead of a URL for configuration ([RaananW](https://github.com/RaananW))
-- (Viewer) Models can be loaded async using JavaScript ([RaananW](https://github.com/RaananW))
-- VRHelper will notify now onSelectedMeshUnselected observable to subscribers when the applied ray selection predicate does not produce a hit and a mesh compliant with the meshSelectionPredicate was previously selected
-   ([carloslanderas](https://github.com/carloslanderas))
-- (Viewer) initScene and initEngine can now be extended. onProgress during model loading is implemented as observable. ([RaananW](https://github.com/RaananW))
-- glTF loader now supports the KHR_lights extension ([MiiBond](https://github.com/MiiBond))
-- Added depth of field effect to the default pipeline ([trevordev](https://github.com/trevordev))
-- The observable can now notify observers using promise-based callback chain. ([RaananW](https://github.com/RaananW))
-- Added base64 helper functions to `Tools` ([bghgary](https://github.com/bghgary))
-- Added `createDefaultCamera` and `createDefaultLight` functions to `Scene` ([bghgary](https://github.com/bghgary))
-- Gulp process now supports multiple outputs when using webpack. ([RaananW](https://github.com/RaananW))
-- (Viewer) Scene Optimizer intergrated in viewer. ([RaananW](https://github.com/RaananW))
-- (Viewer) The viewer supports custom shaders in the configuration. ([RaananW](https://github.com/RaananW))
-- Documented PostProcessRenderEffect, DefaultRenderingPipeline, BlurPostProcess, DepthOfFieldEffect, PostProcess, PostProcessManager, Effect classes ([trevordev](https://github.com/trevordev))
-- SPS internal storage of each solid particle rotation matrix ([jbousquie](https://github.com/jbousquie)) 
-- SPS particle parenting feature ([jbousquie](https://github.com/jbousquie))
-- (Viewer) Introducing the viewer labs - testing new features. ([RaananW](https://github.com/RaananW))
-- AssetContainer Class and loading methods ([trevordev](https://github.com/trevordev))
-- KeepAssets class and AssetContainer.moveAllFromScene ([HoloLite](http://www.html5gamedevs.com/profile/28694-hololite/) [trevordev](https://github.com/trevordev))
-- (Viewer) It is now possible to update parts of the configuration without rcreating the objects. Extra configuration can be loaded sync (if provided) ([RaananW](https://github.com/RaananW))
-- (Gulp) extra/external declarations can be prepended to final declarations during build. ([RaananW](https://github.com/RaananW))
-- (Viewer) Model can be normalized using configuration, camera is dynamically configured. ([RaananW](https://github.com/RaananW))
-- (Gulp) extra/external declarations can be prepended to final NPM declarations during build. ([RaananW](https://github.com/RaananW))
-- GUI.Line can have its world position set from one end or the other ([SvenFrankson](https://github.com/SvenFrankson))
-- Added FOV system to background material for zoom effects in skyboxes without adjusting camera FOV ([DavidHGillen](https://github.com/DavidHGillen))
-- Improved glTF loader by using promises for asynchronous operations. ([bghgary](https://github.com/bghgary)]
-- Improved glTF loader performance by compiling materials in parallel with downloading external resources. ([bghgary](https://github.com/bghgary)]
-- Added unit tests for the glTF 2.0 loader. ([bghgary](https://github.com/bghgary)]
-- Added promise-based async functions to the SceneLoader, Scene.whenReadyAsync, and material.forceCompilationAsync. ([bghgary](https://github.com/bghgary)]
-- Added checks to VertexData.merge to ensure data is valid before merging. ([bghgary](https://github.com/bghgary)]
-- Ability to set a mesh to customize the webVR gaze tracker ([trevordev](https://github.com/trevordev))
-- Added promise-based async functions for initWebVRAsync and useStandingMatrixAsync ([trevordev](https://github.com/trevordev))
-- Add stroke (outline) options on GUI text control ([SvenFrankson](https://github.com/SvenFrankson))
-- Add isThumbClamped option on GUI slider control ([JeanPhilippeKernel](https://github.com/JeanPhilippeKernel))
-- Add floating point texture support for RenderTargetCubeTexture ([PeapBoy](https://github.com/NicolasBuecher))
-- Support for mutli-touch when interacting with multiple gui elements simultaneously ([trevordev](https://github.com/trevordev))
-- (Viewer) Declaration file published. ([RaananW](https://github.com/RaananW))
-- Added Draco mesh compression support to glTF 2.0 loader. ([bghgary](https://github.com/bghgary))
-- Added `Tools.WorkerPool` class for web worker management. ([bghgary](https://github.com/bghgary))
-
-## Bug fixes
-
-- `setPivotMatrix` ws not setting pivot correctly. This is now fixed. We also introduced a new `setPreTransformMatrix` to reproduce the sometimes needed behavior of the previous `setPivotMatrix` function ([deltakosh](https://github.com/deltakosh))
-- SPS solid particle `.pivot` property now also behaves like the standard mesh pivot. Former behavior (particle translation) can be kept with the particle property `.translateFromPivot` set to true ([jbousquie](https://github.com/jbousquie))
-- Texture extension detection in `Engine.CreateTexture` ([sebavan](https://github.com/sebavan))
-- SPS internal temporary vector3 instead of Tmp.Vector3 to avoid possible concurrent uses ([jbousquie](https://github.com/jbousquie))
-- Fixed a bug when calling load on an empty assets manager - [#3739](https://github.com/BabylonJS/Babylon.js/issues/3739). ([RaananW](https://github.com/RaananW))
-- Enabling teleportation in the vr helper class caused a redundant post process to be added ([trevordev](https://github.com/trevordev))
-
-## Breaking changes
-
-- Removed the unused PostProcessRenderPass class and extended postProcessingRenderingEffect to support multiple PostProcesses ([trevordev](https://github.com/trevordev))
-- VertexData.merge no longer supports merging of data that do not have the same set of attributes. ([bghgary](https://github.com/bghgary)]
-- glTF 2.0 loader will now create a mesh for each primitive instead of merging the primitives together into one mesh. ([bghgary](https://github.com/bghgary)]
+# 3.2.0
+
+## Major updates
+
+- Support for [GPU particles](https://doc.babylonjs.com/babylon101/particles#gpu-particles) ([deltakosh](https://github.com/deltakosh))
+- Improved building process: We now run a full visual validation test for each pull request. Furthermore, code comments and what's new updates are now mandatory ([sebavan](https://github.com/sebavan))
+- 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))
+- New [AnimationGroup class](http://doc.babylonjs.com/how_to/group) to control simultaneously multiple animations with different targets ([deltakosh](https://github.com/deltakosh))
+- `WebVRCamera` now supports GearVR ([brianzinn](https://github.com/brianzinn))
+- New glTF [serializer](https://github.com/BabylonJS/Babylon.js/tree/master/serializers/src/glTF/2.0). You can now export glTF or glb files directly from a Babylon scene ([kcoley](https://github.com/kcoley))
+- Babylon.js now uses Promises in addition to callbacks. We created several `xxxAsync` functions all over the framework (`SceneLoader.AppendAsync` for instance, which returns a Promise). A polyfill is also integrated to support older browsers ([deltakosh](https://github.com/deltakosh))
+- Introduced [Projection Texture on SpotLight](http://doc.babylonjs.com/babylon101/lights#projection-texture) ([lostink](https://github.com/lostink))
+- Introduced support for [local cubemaps](http://doc.babylonjs.com/how_to/reflect#using-local-cubemap-mode) ([deltakosh](https://github.com/deltakosh))
+- Added [VideoDome](http://doc.babylonjs.com/how_to/360videodome) class to easily support 360 videos ([DavidHGillen](https://github.com/DavidHGillen))
+- Added [GlowLayer](https://doc.babylonjs.com/how_to/glow_layer) to easily support glow from emissive materials ([sebavan](https://github.com/sebavan))
+
+## Updates
+
+- Tons of functions and classes received the code comments they deserved (All the community)
+- Added `particleSystem.reset()` to clear a particle system ([deltakosh](https://github.com/deltakosh))
+- Added support for all RGBA orders (BGR, RGB, etc..) for the DDS loader ([deltakosh](https://github.com/deltakosh))
+- Improved [SceneOptimizer](http://doc.babylonjs.com/how_to/how_to_use_sceneoptimizer) to provide better adaptability ([deltakosh](https://github.com/deltakosh))
+- Improved `scene.isReady()` function which now takes in account shadows and LOD ([deltakosh](https://github.com/deltakosh))
+- 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))
+- Added GUI Textblock.lineSpacing setter and getter to configure vertical space between lines in pixels or percentage values when working with text wrapping ([carloslanderas](https://github.com/carloslanderas))
+- VRHelper now has onSelectedMeshUnselected observable that will notify observers when the current selected mesh gets unselected
+  ([carloslanderas](https://github.com/carloslanderas))
+- VRHelper now has onBeforeCameraTeleport and onAfterCameraTeleport observables that will be notified before and after camera teleportation is triggered.
+  ([carloslanderas](https://github.com/carloslanderas))
+- VRHelper now has the public property teleportationEnabled to enable / disable camera teleportation.
+   ([carloslanderas](https://github.com/carloslanderas))
+- VRHelper now exposes onNewMeshPicked observable that will notify a PickingInfo object after meshSelectionPredicate evaluation
+   ([carloslanderas](https://github.com/carloslanderas))
+- `AssetsManager` will now clear its `tasks` lsit from all successfully loaded tasks ([deltakosh](https://github.com/deltakosh))
+- Added documentation to WebVRCamera and VRExperienceHelper ([trevordev](https://github.com/trevordev))
+- Introduced `isStroke` on `HighlightLayerOptions` which makes the highlight solid ([PixelsCommander](https://github.com/pixelscommander))
+- (Viewer) There is now an option to paste payload instead of a URL for configuration ([RaananW](https://github.com/RaananW))
+- (Viewer) Models can be loaded async using JavaScript ([RaananW](https://github.com/RaananW))
+- VRHelper will notify now onSelectedMeshUnselected observable to subscribers when the applied ray selection predicate does not produce a hit and a mesh compliant with the meshSelectionPredicate was previously selected
+   ([carloslanderas](https://github.com/carloslanderas))
+- (Viewer) initScene and initEngine can now be extended. onProgress during model loading is implemented as observable. ([RaananW](https://github.com/RaananW))
+- glTF loader now supports the KHR_lights extension ([MiiBond](https://github.com/MiiBond))
+- Added depth of field effect to the default pipeline ([trevordev](https://github.com/trevordev))
+- The observable can now notify observers using promise-based callback chain. ([RaananW](https://github.com/RaananW))
+- Added base64 helper functions to `Tools` ([bghgary](https://github.com/bghgary))
+- Added `createDefaultCamera` and `createDefaultLight` functions to `Scene` ([bghgary](https://github.com/bghgary))
+- Gulp process now supports multiple outputs when using webpack. ([RaananW](https://github.com/RaananW))
+- (Viewer) Scene Optimizer intergrated in viewer. ([RaananW](https://github.com/RaananW))
+- (Viewer) The viewer supports custom shaders in the configuration. ([RaananW](https://github.com/RaananW))
+- Documented PostProcessRenderEffect, DefaultRenderingPipeline, BlurPostProcess, DepthOfFieldEffect, PostProcess, PostProcessManager, Effect classes ([trevordev](https://github.com/trevordev))
+- SPS internal storage of each solid particle rotation matrix ([jbousquie](https://github.com/jbousquie)) 
+- SPS particle parenting feature ([jbousquie](https://github.com/jbousquie))
+- (Viewer) Introducing the viewer labs - testing new features. ([RaananW](https://github.com/RaananW))
+- AssetContainer Class and loading methods ([trevordev](https://github.com/trevordev))
+- KeepAssets class and AssetContainer.moveAllFromScene ([HoloLite](http://www.html5gamedevs.com/profile/28694-hololite/) [trevordev](https://github.com/trevordev))
+- (Viewer) It is now possible to update parts of the configuration without rcreating the objects. Extra configuration can be loaded sync (if provided) ([RaananW](https://github.com/RaananW))
+- (Gulp) extra/external declarations can be prepended to final declarations during build. ([RaananW](https://github.com/RaananW))
+- (Viewer) Model can be normalized using configuration, camera is dynamically configured. ([RaananW](https://github.com/RaananW))
+- (Gulp) extra/external declarations can be prepended to final NPM declarations during build. ([RaananW](https://github.com/RaananW))
+- GUI.Line can have its world position set from one end or the other ([SvenFrankson](https://github.com/SvenFrankson))
+- Added FOV system to background material for zoom effects in skyboxes without adjusting camera FOV ([DavidHGillen](https://github.com/DavidHGillen))
+- Improved glTF loader by using promises for asynchronous operations. ([bghgary](https://github.com/bghgary)]
+- Improved glTF loader performance by compiling materials in parallel with downloading external resources. ([bghgary](https://github.com/bghgary)]
+- Added unit tests for the glTF 2.0 loader. ([bghgary](https://github.com/bghgary)]
+- Added promise-based async functions to the SceneLoader, Scene.whenReadyAsync, and material.forceCompilationAsync. ([bghgary](https://github.com/bghgary)]
+- Added checks to VertexData.merge to ensure data is valid before merging. ([bghgary](https://github.com/bghgary)]
+- Ability to set a mesh to customize the webVR gaze tracker ([trevordev](https://github.com/trevordev))
+- Added promise-based async functions for initWebVRAsync and useStandingMatrixAsync ([trevordev](https://github.com/trevordev))
+- Add stroke (outline) options on GUI text control ([SvenFrankson](https://github.com/SvenFrankson))
+- Add isThumbClamped option on GUI slider control ([JeanPhilippeKernel](https://github.com/JeanPhilippeKernel))
+- Add floating point texture support for RenderTargetCubeTexture ([PeapBoy](https://github.com/NicolasBuecher))
+- Support for mutli-touch when interacting with multiple gui elements simultaneously ([trevordev](https://github.com/trevordev))
+- (Viewer) Declaration file published, ready for npm. ([RaananW](https://github.com/RaananW))
+- Added Draco mesh compression support to glTF 2.0 loader. ([bghgary](https://github.com/bghgary))
+- (Viewer) XHR requests not use Tools.LoadFile and are disposed correctly - [#3671](https://github.com/BabylonJS/Babylon.js/issues/3671) ([RaananW](https://github.com/RaananW))
+- Added `Tools.WorkerPool` class for web worker management. ([bghgary](https://github.com/bghgary))
+
+## Bug fixes
+
+- `setPivotMatrix` ws not setting pivot correctly. This is now fixed. We also introduced a new `setPreTransformMatrix` to reproduce the sometimes needed behavior of the previous `setPivotMatrix` function ([deltakosh](https://github.com/deltakosh))
+- SPS solid particle `.pivot` property now also behaves like the standard mesh pivot. Former behavior (particle translation) can be kept with the particle property `.translateFromPivot` set to true ([jbousquie](https://github.com/jbousquie))
+- Texture extension detection in `Engine.CreateTexture` ([sebavan](https://github.com/sebavan))
+- SPS internal temporary vector3 instead of Tmp.Vector3 to avoid possible concurrent uses ([jbousquie](https://github.com/jbousquie))
+- Fixed a bug when calling load on an empty assets manager - [#3739](https://github.com/BabylonJS/Babylon.js/issues/3739). ([RaananW](https://github.com/RaananW))
+- Enabling teleportation in the vr helper class caused a redundant post process to be added ([trevordev](https://github.com/trevordev))
+- (Viewer) Fixed a bug where loading another mesh positioned it incorrectly ([RaananW](https://github.com/RaananW))
+
+## Breaking changes
+
+- Removed the unused PostProcessRenderPass class and extended postProcessingRenderingEffect to support multiple PostProcesses ([trevordev](https://github.com/trevordev))
+- VertexData.merge no longer supports merging of data that do not have the same set of attributes. ([bghgary](https://github.com/bghgary)]
+- glTF 2.0 loader will now create a mesh for each primitive instead of merging the primitives together into one mesh. ([bghgary](https://github.com/bghgary)]

+ 2 - 2
package.json

@@ -9,7 +9,7 @@
     ],
     ],
     "name": "babylonjs",
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "3.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -41,4 +41,4 @@
     },
     },
     "readme": "Babylon.js is a 3D engine based on webgl and javascript",
     "readme": "Babylon.js is a 3D engine based on webgl and javascript",
     "readmeFilename": "README.md"
     "readmeFilename": "README.md"
-}
+}

+ 2 - 2
src/Engine/babylon.engine.ts

@@ -4268,7 +4268,7 @@
                 }, undefined, undefined, true, onerror);
                 }, undefined, undefined, true, onerror);
             } else if (isDDS) {
             } else if (isDDS) {
                 if (files && files.length === 6) {
                 if (files && files.length === 6) {
-                    this._cascadeLoadFiles(rootUrl,
+                    this._cascadeLoadFiles(
                         scene,
                         scene,
                         imgs => {
                         imgs => {
                             var info: DDSInfo | undefined;
                             var info: DDSInfo | undefined;
@@ -5883,7 +5883,7 @@
             this._loadFile(url, onload, undefined, undefined, true, onerror);
             this._loadFile(url, onload, undefined, undefined, true, onerror);
         }
         }
 
 
-        private _cascadeLoadFiles(rootUrl: string, scene: Nullable<Scene>, onfinish: (images: (string | ArrayBuffer)[]) => void, files: string[], onError: Nullable<(message?: string, exception?: any) => void> = null): void {
+        private _cascadeLoadFiles(scene: Nullable<Scene>, onfinish: (images: (string | ArrayBuffer)[]) => void, files: string[], onError: Nullable<(message?: string, exception?: any) => void> = null): void {
             var loadedFiles: (string | ArrayBuffer)[] = [];
             var loadedFiles: (string | ArrayBuffer)[] = [];
             (<any>loadedFiles)._internalCount = 0;
             (<any>loadedFiles)._internalCount = 0;
 
 

+ 3 - 1
src/Helpers/babylon.environmentHelper.ts

@@ -476,7 +476,9 @@ module BABYLON {
                 return { groundSize, skyboxSize, rootPosition };
                 return { groundSize, skyboxSize, rootPosition };
             }
             }
 
 
-            const sceneExtends = this._scene.getWorldExtends();
+            const sceneExtends = this._scene.getWorldExtends((mesh) => {
+                return (mesh !== this._ground && mesh !== this._rootMesh && mesh !== this._skybox);
+            });
             const sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
             const sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
 
 
             if (this._options.sizeAuto) {
             if (this._options.sizeAuto) {

+ 5 - 1
src/Materials/Textures/babylon.cubeTexture.ts

@@ -39,7 +39,11 @@
         private _prefiltered: boolean;
         private _prefiltered: boolean;
 
 
         public static CreateFromImages(files: string[], scene: Scene, noMipmap?: boolean) {
         public static CreateFromImages(files: string[], scene: Scene, noMipmap?: boolean) {
-            return new CubeTexture("", scene, null, noMipmap, files);
+            let rootUrlKey = "";
+            
+            files.forEach(url => rootUrlKey += url);
+
+            return new CubeTexture(rootUrlKey, scene, null, noMipmap, files);
         }
         }
 
 
         public static CreateFromPrefilteredData(url: string, scene: Scene, forcedExtension: any = null) {
         public static CreateFromPrefilteredData(url: string, scene: Scene, forcedExtension: any = null) {

+ 33 - 10
src/Particles/babylon.gpuParticleSystem.ts

@@ -335,10 +335,6 @@
                 transformFeedbackVaryings: ["outPosition", "outAge", "outLife", "outSeed", "outSize", "outColor", "outDirection"]
                 transformFeedbackVaryings: ["outPosition", "outAge", "outLife", "outSeed", "outSize", "outColor", "outDirection"]
             };
             };
 
 
-            this._updateEffect = new Effect("gpuUpdateParticles", this._updateEffectOptions, this._scene.getEngine());   
-
-            this._renderEffect = new Effect("gpuRenderParticles", ["position", "age", "life", "size", "color", "offset", "uv"], ["view", "projection", "colorDead"], ["textureSampler"], this._scene.getEngine());
-
             // Random data
             // Random data
             var maxTextureSize = Math.min(this._engine.getCaps().maxTextureSize, fullOptions.randomTextureSize);
             var maxTextureSize = Math.min(this._engine.getCaps().maxTextureSize, fullOptions.randomTextureSize);
             var d = [];
             var d = [];
@@ -452,14 +448,32 @@
         }
         }
 
 
         /** @ignore */
         /** @ignore */
-        public _recreateUpdateEffect(defines: string) {
-            if (this._updateEffectOptions.defines === defines) {
+        public _recreateUpdateEffect() {
+            let defines = this.particleEmitterType ? this.particleEmitterType.getEffectDefines() : "";
+            if (this._updateEffect && this._updateEffectOptions.defines === defines) {
                 return;
                 return;
             }
             }
             this._updateEffectOptions.defines = defines;
             this._updateEffectOptions.defines = defines;
             this._updateEffect = new Effect("gpuUpdateParticles", this._updateEffectOptions, this._scene.getEngine());   
             this._updateEffect = new Effect("gpuUpdateParticles", this._updateEffectOptions, this._scene.getEngine());   
         }
         }
 
 
+        /** @ignore */
+        public _recreateRenderEffect() {
+            let defines = "";
+            if (this._scene.clipPlane) {
+                defines = "\n#define CLIPPLANE";
+            }
+
+            if (this._renderEffect && this._renderEffect.defines === defines) {
+                return;
+            }
+
+            this._renderEffect = new Effect("gpuRenderParticles", 
+                                            ["position", "age", "life", "size", "color", "offset", "uv"], 
+                                            ["view", "projection", "colorDead", "invView", "vClipPlane"], 
+                                            ["textureSampler"], this._scene.getEngine(), defines);
+        }        
+
         /**
         /**
          * Animates the particle system for the current frame by emitting new particles and or animating the living ones.
          * Animates the particle system for the current frame by emitting new particles and or animating the living ones.
          */
          */
@@ -484,9 +498,8 @@
                 return 0;
                 return 0;
             }
             }
 
 
-            if (this.particleEmitterType) {
-                this._recreateUpdateEffect(this.particleEmitterType.getEffectDefines());
-            }
+            this._recreateUpdateEffect();
+            this._recreateRenderEffect();
 
 
             if (!this.emitter || !this._updateEffect.isReady() || !this._renderEffect.isReady() ) {
             if (!this.emitter || !this._updateEffect.isReady() || !this._renderEffect.isReady() ) {
                 return 0;
                 return 0;
@@ -547,11 +560,21 @@
 
 
             // Enable render effect
             // Enable render effect
             this._engine.enableEffect(this._renderEffect);
             this._engine.enableEffect(this._renderEffect);
-            this._renderEffect.setMatrix("view", this._scene.getViewMatrix());
+            let viewMatrix = this._scene.getViewMatrix();
+            this._renderEffect.setMatrix("view", viewMatrix);
             this._renderEffect.setMatrix("projection", this._scene.getProjectionMatrix());
             this._renderEffect.setMatrix("projection", this._scene.getProjectionMatrix());
             this._renderEffect.setTexture("textureSampler", this.particleTexture);
             this._renderEffect.setTexture("textureSampler", this.particleTexture);
             this._renderEffect.setDirectColor4("colorDead", this.colorDead);
             this._renderEffect.setDirectColor4("colorDead", this.colorDead);
 
 
+
+            if (this._scene.clipPlane) {
+                var clipPlane = this._scene.clipPlane;
+                var invView = viewMatrix.clone();
+                invView.invert();
+                this._renderEffect.setMatrix("invView", invView);
+                this._renderEffect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
+            }            
+
             // Draw order
             // Draw order
             if (this.blendMode === ParticleSystem.BLENDMODE_ONEONE) {
             if (this.blendMode === ParticleSystem.BLENDMODE_ONEONE) {
                 this._engine.setAlphaMode(Engine.ALPHA_ONEONE);
                 this._engine.setAlphaMode(Engine.ALPHA_ONEONE);

+ 23 - 1
src/Shaders/default.fragment.fx

@@ -4,6 +4,8 @@
 #extension GL_OES_standard_derivatives : enable
 #extension GL_OES_standard_derivatives : enable
 #endif
 #endif
 
 
+#define CUSTOM_FRAGMENT_BEGIN
+
 #ifdef LOGARITHMICDEPTH
 #ifdef LOGARITHMICDEPTH
 #extension GL_EXT_frag_depth : enable
 #extension GL_EXT_frag_depth : enable
 #endif
 #endif
@@ -152,14 +154,23 @@ varying vec3 vDirectionW;
 #include<logDepthDeclaration>
 #include<logDepthDeclaration>
 #include<fogFragmentDeclaration>
 #include<fogFragmentDeclaration>
 
 
+#define CUSTOM_FRAGMENT_DEFINITIONS
+
 void main(void) {
 void main(void) {
+
+#define CUSTOM_FRAGMENT_MAIN_BEGIN
+
 #include<clipPlaneFragment>
 #include<clipPlaneFragment>
 
 
+
+
 	vec3 viewDirectionW = normalize(vEyePosition - vPositionW);
 	vec3 viewDirectionW = normalize(vEyePosition - vPositionW);
 
 
 	// Base color
 	// Base color
 	vec4 baseColor = vec4(1., 1., 1., 1.);
 	vec4 baseColor = vec4(1., 1., 1., 1.);
 	vec3 diffuseColor = vDiffuseColor.rgb;
 	vec3 diffuseColor = vDiffuseColor.rgb;
+	
+	
 
 
 	// Alpha
 	// Alpha
 	float alpha = vDiffuseColor.a;
 	float alpha = vDiffuseColor.a;
@@ -188,16 +199,22 @@ void main(void) {
 	#ifdef ALPHAFROMDIFFUSE
 	#ifdef ALPHAFROMDIFFUSE
 		alpha *= baseColor.a;
 		alpha *= baseColor.a;
 	#endif
 	#endif
+	
+	#define CUSTOM_FRAGMENT_UPDATE_ALPHA
 
 
 	baseColor.rgb *= vDiffuseInfos.y;
 	baseColor.rgb *= vDiffuseInfos.y;
 #endif
 #endif
 
 
+
+
 #include<depthPrePass>
 #include<depthPrePass>
 
 
 #ifdef VERTEXCOLOR
 #ifdef VERTEXCOLOR
 	baseColor.rgb *= vColor.rgb;
 	baseColor.rgb *= vColor.rgb;
 #endif
 #endif
 
 
+#define CUSTOM_FRAGMENT_UPDATE_DIFFUSE
+
 	// Ambient color
 	// Ambient color
 	vec3 baseAmbientColor = vec3(1., 1., 1.);
 	vec3 baseAmbientColor = vec3(1., 1., 1.);
 
 
@@ -205,6 +222,8 @@ void main(void) {
 	baseAmbientColor = texture2D(ambientSampler, vAmbientUV + uvOffset).rgb * vAmbientInfos.y;
 	baseAmbientColor = texture2D(ambientSampler, vAmbientUV + uvOffset).rgb * vAmbientInfos.y;
 #endif
 #endif
 
 
+#define CUSTOM_FRAGMENT_BEFORE_LIGHTS
+
 	// Specular map
 	// Specular map
 #ifdef SPECULARTERM
 #ifdef SPECULARTERM
 	float glossiness = vSpecularColor.a;
 	float glossiness = vSpecularColor.a;
@@ -398,6 +417,8 @@ void main(void) {
     #endif
     #endif
 #endif
 #endif
 
 
+#define CUSTOM_FRAGMENT_BEFORE_FOG
+
 #include<logDepthFragment>
 #include<logDepthFragment>
 #include<fogFragment>
 #include<fogFragment>
 
 
@@ -417,5 +438,6 @@ void main(void) {
 	color.rgb *= color.a;
 	color.rgb *= color.a;
 #endif
 #endif
 
 
+#define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR
 	gl_FragColor = color;
 	gl_FragColor = color;
-}
+}

+ 14 - 1
src/Shaders/default.vertex.fx

@@ -1,5 +1,8 @@
 #include<__decl__defaultVertex>
 #include<__decl__defaultVertex>
 // Attributes
 // Attributes
+
+#define CUSTOM_VERTEX_BEGIN
+
 attribute vec3 position;
 attribute vec3 position;
 #ifdef NORMAL
 #ifdef NORMAL
 attribute vec3 normal;
 attribute vec3 normal;
@@ -89,8 +92,12 @@ varying vec3 vDirectionW;
 #endif
 #endif
 
 
 #include<logDepthDeclaration>
 #include<logDepthDeclaration>
+#define CUSTOM_VERTEX_DEFINITIONS
 
 
 void main(void) {
 void main(void) {
+	
+	#define CUSTOM_VERTEX_MAIN_BEGIN
+	
 	vec3 positionUpdated = position;
 	vec3 positionUpdated = position;
 #ifdef NORMAL	
 #ifdef NORMAL	
 	vec3 normalUpdated = normal;
 	vec3 normalUpdated = normal;
@@ -105,6 +112,10 @@ void main(void) {
 	vPositionUVW = positionUpdated;
 	vPositionUVW = positionUpdated;
 #endif 
 #endif 
 
 
+#define CUSTOM_VERTEX_UPDATE_POSITION
+
+#define CUSTOM_VERTEX_UPDATE_NORMAL
+
 #include<instancesVertex>
 #include<instancesVertex>
 #include<bonesVertex>
 #include<bonesVertex>
 
 
@@ -233,4 +244,6 @@ void main(void) {
 #include<pointCloudVertex>
 #include<pointCloudVertex>
 #include<logDepthVertex>
 #include<logDepthVertex>
 
 
-}
+#define CUSTOM_VERTEX_MAIN_END
+
+}

+ 8 - 0
src/Shaders/gpuRenderParticles.fragment.fx

@@ -7,6 +7,14 @@ in vec4 vColor;
 
 
 out vec4 outFragColor;
 out vec4 outFragColor;
 
 
+#ifdef CLIPPLANE
+in float fClipDistance;
+#endif
+
 void main() {
 void main() {
+#ifdef CLIPPLANE
+	if (fClipDistance > 0.0)
+		discard;
+#endif  
   outFragColor = texture(textureSampler, vUV) * vColor;
   outFragColor = texture(textureSampler, vUV) * vColor;
 }
 }

+ 13 - 0
src/Shaders/gpuRenderParticles.vertex.fx

@@ -16,6 +16,13 @@ in vec2 uv;
 out vec2 vUV;
 out vec2 vUV;
 out vec4 vColor;
 out vec4 vColor;
 
 
+#ifdef CLIPPLANE
+uniform vec4 vClipPlane;
+uniform mat4 invView;
+out float fClipDistance;
+#endif
+
+
 void main() {
 void main() {
   vUV = uv;
   vUV = uv;
   float ratio = age / life;
   float ratio = age / life;
@@ -24,4 +31,10 @@ void main() {
   // Expand position
   // Expand position
   vec4 viewPosition = view * vec4(position, 1.0);
   vec4 viewPosition = view * vec4(position, 1.0);
   gl_Position = projection * (viewPosition + vec4(offset * size, 0, 1.0));
   gl_Position = projection * (viewPosition + vec4(offset * size, 0, 1.0));
+
+	// Clip plane
+#ifdef CLIPPLANE
+	vec4 worldPos = invView * viewPosition;
+	fClipDistance = dot(worldPos, vClipPlane);
+#endif  
 }
 }

+ 12 - 6
src/babylon.scene.ts

@@ -4230,16 +4230,22 @@
         }
         }
 
 
         // Octrees
         // Octrees
-        public getWorldExtends(): { min: Vector3; max: Vector3 } {
+
+        /**
+         * Get the world extend vectors with an optional filter
+         * 
+         * @param filterPredicate the predicate - which meshes should be included when calculating the world size
+         * @returns {{ min: Vector3; max: Vector3 }} min and max vectors
+         */
+        public getWorldExtends(filterPredicate?: (mesh: AbstractMesh) => boolean): { min: Vector3; max: Vector3 } {
             var min = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
             var min = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
             var max = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
             var max = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
-            for (var index = 0; index < this.meshes.length; index++) {
-                var mesh = this.meshes[index];
-
+            filterPredicate = filterPredicate || (() => true);
+            this.meshes.filter(filterPredicate).forEach(mesh => {
                 mesh.computeWorldMatrix(true);
                 mesh.computeWorldMatrix(true);
 
 
                 if (!mesh.subMeshes || mesh.subMeshes.length === 0 || mesh.infiniteDistance) {
                 if (!mesh.subMeshes || mesh.subMeshes.length === 0 || mesh.infiniteDistance) {
-                    continue;
+                    return;
                 }
                 }
 
 
                 let boundingInfo = mesh.getBoundingInfo();
                 let boundingInfo = mesh.getBoundingInfo();
@@ -4249,7 +4255,7 @@
 
 
                 Tools.CheckExtends(minBox, min, max);
                 Tools.CheckExtends(minBox, min, max);
                 Tools.CheckExtends(maxBox, min, max);
                 Tools.CheckExtends(maxBox, min, max);
-            }
+            })
 
 
             return {
             return {
                 min: min,
                 min: min,

+ 1 - 1
tests/validation/config.json

@@ -18,7 +18,7 @@
       "sceneFolder": "/Scenes/Espilit/",
       "sceneFolder": "/Scenes/Espilit/",
       "sceneFilename": "espilit.babylon",
       "sceneFilename": "espilit.babylon",
       "referenceImage": "Espilit.png"
       "referenceImage": "Espilit.png"
-    },
+    },    
     {
     {
       "title": "The car",
       "title": "The car",
       "sceneFolder": "/Scenes/TheCar/",
       "sceneFolder": "/Scenes/TheCar/",

+ 61 - 0
tests/validation/validate.html

@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+<head>
+	<title>BabylonJS - Build validation page</title>
+	<link href="index.css" rel="stylesheet" />
+    <script src="https://preview.babylonjs.com/draco_decoder.js"></script>
+    <script src="https://preview.babylonjs.com/cannon.js"></script>
+    <script src="https://preview.babylonjs.com/draco_decoder.js"></script>
+    <script src="https://preview.babylonjs.com/Oimo.js"></script>
+    <script src="https://preview.babylonjs.com/babylon.js"></script>
+    <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
+
+    <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
+	<script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
+    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
+	<script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
+    <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>	
+</head>
+<body>
+	<script src="validation.js"></script>
+	<script>
+		// Loading tests
+		var xhr = new XMLHttpRequest();
+
+		xhr.open("GET", "config.json", true);
+
+		xhr.addEventListener("load", function () {
+			if (xhr.status === 200) {
+
+				config = JSON.parse(xhr.responseText);
+
+				// Run tests
+				var index = 0;
+				if (window.location.search) {
+					justOnce = true;
+					var title = window.location.search.replace("?", "").replace(/%20/g, " ");
+					for (var index = 0; index < config.tests.length; index++) {
+						if (config.tests[index].title === title) {
+							break;
+						}
+					}
+				}
+
+				var recursiveRunTest = function(i) {
+					runTest(i, function() {
+						i++;
+						if (justOnce || i >= config.tests.length) {
+							return;
+						}
+						recursiveRunTest(i);
+					});
+				}
+
+				recursiveRunTest(index);
+			}
+		}, false);
+
+		xhr.send();
+    </script>	
+</body>
+</html>