فهرست منبع

Merge branch 'master' into dualVRControllers

Trevor Baron 7 سال پیش
والد
کامیت
3e0b161519
78فایلهای تغییر یافته به همراه71517 افزوده شده و 36701 حذف شده
  1. 2 0
      .gitignore
  2. 10273 10066
      Playground/babylon.d.txt
  3. BIN
      Playground/scenes/Buggy/glTF-Draco/0.bin
  4. 16995 0
      Playground/scenes/Buggy/glTF-Draco/Buggy.gltf
  5. 15818 0
      Playground/scenes/Buggy/glTF/Buggy.gltf
  6. BIN
      Playground/scenes/Buggy/glTF/Buggy0.bin
  7. 10 9
      Tools/Gulp/config.json
  8. 5 1
      Tools/Gulp/gulp-addModuleExports.js
  9. 8 1
      Tools/Gulp/gulpfile.js
  10. 1 0
      Viewer/dist/_redirects
  11. 15 18
      Viewer/src/configuration/loader.ts
  12. 0 26
      Viewer/src/helper.ts
  13. 47 24
      Viewer/src/templateManager.ts
  14. 2 2
      Viewer/src/viewer/defaultViewer.ts
  15. 41 7
      Viewer/src/viewer/viewer.ts
  16. 4998 4826
      dist/preview release/babylon.d.ts
  17. 14 14
      dist/preview release/babylon.js
  18. 367 43
      dist/preview release/babylon.max.js
  19. 14 14
      dist/preview release/babylon.worker.js
  20. 15439 15232
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  21. 27 27
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  22. 2898 2738
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  23. 2898 2738
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  24. 367 43
      dist/preview release/es6.js
  25. 1 1
      dist/preview release/gui/package.json
  26. 1 1
      dist/preview release/inspector/package.json
  27. 1 0
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  28. 14 2
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  29. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  30. 1 0
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  31. 14 2
      dist/preview release/loaders/babylon.glTFFileLoader.js
  32. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  33. 14 2
      dist/preview release/loaders/babylonjs.loaders.js
  34. 2 2
      dist/preview release/loaders/babylonjs.loaders.min.js
  35. 1 0
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  36. 1 1
      dist/preview release/loaders/package.json
  37. 1 1
      dist/preview release/materialsLibrary/package.json
  38. 1 1
      dist/preview release/postProcessesLibrary/package.json
  39. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  40. 1 1
      dist/preview release/serializers/package.json
  41. 8 24
      dist/preview release/viewer/babylon.viewer.d.ts
  42. 67 66
      dist/preview release/viewer/babylon.viewer.js
  43. 430 112
      dist/preview release/viewer/babylon.viewer.max.js
  44. 4 484
      dist/preview release/viewer/babylon.viewer.module.d.ts
  45. 3 1
      dist/preview release/viewer/package.json
  46. 25 12
      dist/preview release/viewer/readme.md
  47. 4 2
      dist/preview release/what's new.md
  48. 12 0
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  49. 2 2
      package.json
  50. 2 3
      sandbox/index.html
  51. 2 2
      src/Engine/babylon.engine.ts
  52. 4 0
      src/Engine/babylon.nullEngine.ts
  53. 3 1
      src/Helpers/babylon.environmentHelper.ts
  54. 8 2
      src/Loading/Plugins/babylon.babylonFileLoader.ts
  55. 5 1
      src/Materials/Textures/babylon.cubeTexture.ts
  56. 0 6
      src/Math/babylon.math.ts
  57. 1 1
      src/Mesh/Compression/babylon.dracoCompression.ts
  58. 6 0
      src/Particles/EmitterTypes/babylon.IParticleEmitterType.ts
  59. 17 0
      src/Particles/EmitterTypes/babylon.boxParticleEmitter.ts
  60. 19 4
      src/Particles/EmitterTypes/babylon.coneParticleEmitter.ts
  61. 40 14
      src/Particles/EmitterTypes/babylon.sphereParticleEmitter.ts
  62. 168 0
      src/Particles/babylon.IParticleSystem.ts
  63. 211 23
      src/Particles/babylon.gpuParticleSystem.ts
  64. 5 62
      src/Particles/babylon.particleSystem.ts
  65. 23 1
      src/Shaders/default.fragment.fx
  66. 14 1
      src/Shaders/default.vertex.fx
  67. 8 0
      src/Shaders/gpuRenderParticles.fragment.fx
  68. 13 0
      src/Shaders/gpuRenderParticles.vertex.fx
  69. 7 7
      src/Shaders/gpuUpdateParticles.vertex.fx
  70. 1 1
      src/babylon.assetContainer.ts
  71. 13 8
      src/babylon.scene.ts
  72. 25 12
      tests/nullEngine/app.js
  73. BIN
      tests/validation/ReferenceImages/gltfBuggyDraco.png
  74. 6 1
      tests/validation/config.json
  75. 1 0
      tests/validation/index.html
  76. 1 0
      tests/validation/karma.conf.browserstack.js
  77. 1 0
      tests/validation/karma.conf.js
  78. 61 0
      tests/validation/validate.html

+ 2 - 0
.gitignore

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

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 10273 - 10066
Playground/babylon.d.txt


BIN
Playground/scenes/Buggy/glTF-Draco/0.bin


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 16995 - 0
Playground/scenes/Buggy/glTF-Draco/Buggy.gltf


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 15818 - 0
Playground/scenes/Buggy/glTF/Buggy.gltf


BIN
Playground/scenes/Buggy/glTF/Buggy0.bin


+ 10 - 9
Tools/Gulp/config.json

@@ -274,10 +274,10 @@
             "files": [
                 "../../src/Particles/babylon.particle.js",
                 "../../src/Particles/babylon.particleSystem.js",
+                "../../src/Particles/EmitterTypes/babylon.IParticleEmitterType.js",
                 "../../src/Particles/EmitterTypes/babylon.boxParticleEmitter.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": [
                 "core"
@@ -289,7 +289,7 @@
         },
         "gpuParticles": {
             "files": [
-                "../../src/Particles/babylon.gpuParticleSystem.js"          
+                "../../src/Particles/babylon.gpuParticleSystem.js"
             ],
             "dependUpon": [
                 "core",
@@ -430,8 +430,7 @@
                 "additionalMeshes"
             ]
         },
-        "meshCompression" :
-        {
+        "meshCompression": {
             "files": [
                 "../../src/Mesh/Compression/babylon.dracoCompression.js"
             ]
@@ -1676,7 +1675,8 @@
                 "output": "babylon.viewer.js",
                 "webpack": "../../Viewer/webpack.gulp.config.js",
                 "bundle": "true",
-                "moduleDeclaration": "BabylonViewer"
+                "moduleDeclaration": "BabylonViewer",
+                "babylonIncluded": true
             }
         ],
         "build": {
@@ -1685,12 +1685,13 @@
                 {
                     "destination": [
                         {
-                            "filename": "viewer.min.js",
+                            "filename": "viewer.js",
                             "outputDirectory": "/../../Viewer/dist/"
                         },
                         {
                             "filename": "babylon.viewer.js",
-                            "outputDirectory": "/viewer/"
+                            "outputDirectory": "/viewer/",
+                            "addBabylonDeclaration": true
                         }
                     ],
                     "minified": true
@@ -1698,7 +1699,7 @@
                 {
                     "destination": [
                         {
-                            "filename": "viewer.js",
+                            "filename": "viewer.max.js",
                             "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.
  * 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) {
 
         var optionalRequire = `var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
@@ -75,6 +75,10 @@ globalObject["${base}"] = f;` : '';
             return;
         }
 
+        if (noBabylonInit) {
+            optionalRequire = '';
+        }
+
         try {
             if (externalUsingBabylon) {
                 //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));
             if (settings.build.outputs) {
                 let build = wpBuild
-                    .pipe(addModuleExports(library.moduleDeclaration, false, false, true));
+                    .pipe(addModuleExports(library.moduleDeclaration, false, false, true, library.babylonIncluded));
 
                 let unminifiedOutpus = [];
                 let minifiedOutputs = [];
@@ -455,6 +455,12 @@ var buildExternalLibrary = function (library, settings, watch) {
                     build = build
                         .pipe(rename(dest.filename.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
                         .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 => {
@@ -472,6 +478,7 @@ var buildExternalLibrary = function (library, settings, watch) {
                 });
 
                 sequence.push(build);
+
             } else {
                 sequence.push(
                     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 * as deepmerge from '../../assets/deepmerge.min.js';
+import { Tools, IFileRequest } from 'babylonjs';
 
 export class ConfigurationLoader {
 
     private configurationCache: { [url: string]: any };
 
+    private loadRequests: Array<IFileRequest>;
+
     constructor() {
         this.configurationCache = {};
+        this.loadRequests = [];
     }
 
     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> {
         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.
-                    }
-                }
-            }
+        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();

+ 0 - 26
Viewer/src/helper.ts

@@ -5,32 +5,6 @@ export function isUrl(urlToCheck: string): boolean {
     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) {
     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 {
     location?: string; // #template-id OR http://example.com/loading.html
@@ -212,6 +212,8 @@ export class Template {
     private fragment: DocumentFragment;
     private htmlTemplate: string;
 
+    private loadRequests: Array<IFileRequest>;
+
     constructor(public name: string, private _configuration: ITemplateConfiguration) {
         this.onInit = new Observable<Template>();
         this.onLoaded = new Observable<Template>();
@@ -219,6 +221,8 @@ export class Template {
         this.onStateChange = new Observable<Template>();
         this.onEventTriggered = new Observable<EventCallback>();
 
+        this.loadRequests = [];
+
         this.isLoaded = false;
         this.isShown = false;
         /*
@@ -228,7 +232,7 @@ export class Template {
         */
         this.onInit.notifyObservers(this);
 
-        let htmlContentPromise = getTemplateAsHtml(_configuration);
+        let htmlContentPromise = this.getTemplateAsHtml(_configuration);
 
         this.initPromise = htmlContentPromise.then(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> {
+        if (this.isHiding) return Promise.resolve(this);
         return Promise.resolve().then(() => {
+            this.isShowing = true;
             if (visibilityFunction) {
                 return visibilityFunction(this);
             } else {
@@ -310,13 +318,16 @@ export class Template {
             }
         }).then(() => {
             this.isShown = true;
+            this.isShowing = false;
             this.onStateChange.notifyObservers(this);
             return this;
         });
     }
 
     public hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
+        if (this.isShowing) return Promise.resolve(this);
         return Promise.resolve().then(() => {
+            this.isHiding = true;
             if (visibilityFunction) {
                 return visibilityFunction(this);
             } else {
@@ -326,6 +337,7 @@ export class Template {
             }
         }).then(() => {
             this.isShown = false;
+            this.isHiding = false;
             this.onStateChange.notifyObservers(this);
             return this;
         });
@@ -340,6 +352,38 @@ export class Template {
         this.isLoaded = false;
         // remove from parent
         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 }>;
@@ -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 {
     if (!templateConfig || typeof templateConfig === 'string') {
         return templateConfig;

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

@@ -103,8 +103,8 @@ export class DefaultViewer extends AbstractViewer {
         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');
         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 sceneDiagonalLenght = sceneDiagonal.length();
         if (isFinite(sceneDiagonalLenght))
@@ -744,13 +746,36 @@ export abstract class AbstractViewer {
         return Promise.resolve(this.scene);
     }
 
+    private isLoading: boolean;
+    private nextLoading: Function;
+
     public loadModel(model: any = this.configuration.model, clearScene: boolean = true): Promise<Scene> {
         // no model was provided? Do nothing!
-        if (!model.url) {
+        let modelUrl = (typeof model === 'string') ? model : model.url;
+        if (!modelUrl) {
             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 filename = parts.pop();
         let base = parts.join('/') + '/';
@@ -761,13 +786,18 @@ export abstract class AbstractViewer {
 
             if (clearScene) {
                 scene.meshes.forEach(mesh => {
-                    mesh.dispose();
+                    if (Tags.MatchesQuery(mesh, "viewerMesh")) {
+                        mesh.dispose();
+                    }
                 });
             }
             return scene!;
         }).then(() => {
             return new Promise<Array<AbstractMesh>>((resolve, reject) => {
                 this.lastUsedLoader = SceneLoader.ImportMesh(undefined, base, filename, this.scene, (meshes) => {
+                    meshes.forEach(mesh => {
+                        Tags.AddTagsTo(mesh, "viewerMesh");
+                    });
                     resolve(meshes);
                 }, (progressEvent) => {
                     this.onModelLoadProgressObservable.notifyObserversWithPromise(progressEvent);
@@ -783,7 +813,7 @@ export abstract class AbstractViewer {
             return this.onModelLoadedObservable.notifyObserversWithPromise(meshes)
                 .then(() => {
                     // update the models' configuration
-                    this.configureModel(model, meshes);
+                    this.configureModel(this.configuration.model || model, meshes);
                     this.configureLights(this.configuration.lights);
 
                     if (this.configuration.camera) {
@@ -791,12 +821,16 @@ export abstract class AbstractViewer {
                     }
                     return this.initEnvironment(meshes);
                 }).then(() => {
+                    this.isLoading = false;
+                    if (this.nextLoading) {
+                        return this.nextLoading();
+                    }
                     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);
 
         return Promise.resolve(this.scene);

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 4998 - 4826
dist/preview release/babylon.d.ts


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 14 - 14
dist/preview release/babylon.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 367 - 43
dist/preview release/babylon.max.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 14 - 14
dist/preview release/babylon.worker.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 15439 - 15232
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 27 - 27
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2898 - 2738
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2898 - 2738
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 367 - 43
dist/preview release/es6.js


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

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

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

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

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

@@ -304,6 +304,7 @@ declare module BABYLON.GLTF2 {
         private _loadExtensions();
         private _loadData(data);
         private _setupData();
+        private _checkExtensions();
         private _createRootNode();
         private _loadNodesAsync(nodes);
         _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;

+ 14 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -571,6 +571,7 @@ var BABYLON;
                     _this._progressCallback = onProgress;
                     _this._state = BABYLON.GLTFLoaderState.Loading;
                     _this._loadData(data);
+                    _this._checkExtensions();
                     var promises = new Array();
                     if (nodes) {
                         promises.push(_this._loadNodesAsync(nodes));
@@ -667,6 +668,17 @@ var BABYLON;
                     }
                 }
             };
+            GLTFLoader.prototype._checkExtensions = function () {
+                if (this._gltf.extensionsRequired) {
+                    for (var _i = 0, _a = this._gltf.extensionsRequired; _i < _a.length; _i++) {
+                        var name_2 = _a[_i];
+                        var extension = this._extensions[name_2];
+                        if (!extension || !extension.enabled) {
+                            throw new Error("Require extension " + name_2 + " is not available");
+                        }
+                    }
+                }
+            };
             GLTFLoader.prototype._createRootNode = function () {
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
@@ -1809,8 +1821,8 @@ var BABYLON;
             };
             GLTFLoader.prototype._applyExtensions = function (actionAsync) {
                 for (var _i = 0, _a = GLTFLoader._Names; _i < _a.length; _i++) {
-                    var name_2 = _a[_i];
-                    var extension = this._extensions[name_2];
+                    var name_3 = _a[_i];
+                    var extension = this._extensions[name_3];
                     if (extension.enabled) {
                         var promise = actionAsync(extension);
                         if (promise) {

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


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

@@ -859,6 +859,7 @@ declare module BABYLON.GLTF2 {
         private _loadExtensions();
         private _loadData(data);
         private _setupData();
+        private _checkExtensions();
         private _createRootNode();
         private _loadNodesAsync(nodes);
         _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;

+ 14 - 2
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -2747,6 +2747,7 @@ var BABYLON;
                     _this._progressCallback = onProgress;
                     _this._state = BABYLON.GLTFLoaderState.Loading;
                     _this._loadData(data);
+                    _this._checkExtensions();
                     var promises = new Array();
                     if (nodes) {
                         promises.push(_this._loadNodesAsync(nodes));
@@ -2843,6 +2844,17 @@ var BABYLON;
                     }
                 }
             };
+            GLTFLoader.prototype._checkExtensions = function () {
+                if (this._gltf.extensionsRequired) {
+                    for (var _i = 0, _a = this._gltf.extensionsRequired; _i < _a.length; _i++) {
+                        var name_2 = _a[_i];
+                        var extension = this._extensions[name_2];
+                        if (!extension || !extension.enabled) {
+                            throw new Error("Require extension " + name_2 + " is not available");
+                        }
+                    }
+                }
+            };
             GLTFLoader.prototype._createRootNode = function () {
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
@@ -3985,8 +3997,8 @@ var BABYLON;
             };
             GLTFLoader.prototype._applyExtensions = function (actionAsync) {
                 for (var _i = 0, _a = GLTFLoader._Names; _i < _a.length; _i++) {
-                    var name_2 = _a[_i];
-                    var extension = this._extensions[name_2];
+                    var name_3 = _a[_i];
+                    var extension = this._extensions[name_3];
                     if (extension.enabled) {
                         var promise = actionAsync(extension);
                         if (promise) {

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2 - 2
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 14 - 2
dist/preview release/loaders/babylonjs.loaders.js

@@ -3715,6 +3715,7 @@ var BABYLON;
                     _this._progressCallback = onProgress;
                     _this._state = BABYLON.GLTFLoaderState.Loading;
                     _this._loadData(data);
+                    _this._checkExtensions();
                     var promises = new Array();
                     if (nodes) {
                         promises.push(_this._loadNodesAsync(nodes));
@@ -3811,6 +3812,17 @@ var BABYLON;
                     }
                 }
             };
+            GLTFLoader.prototype._checkExtensions = function () {
+                if (this._gltf.extensionsRequired) {
+                    for (var _i = 0, _a = this._gltf.extensionsRequired; _i < _a.length; _i++) {
+                        var name_2 = _a[_i];
+                        var extension = this._extensions[name_2];
+                        if (!extension || !extension.enabled) {
+                            throw new Error("Require extension " + name_2 + " is not available");
+                        }
+                    }
+                }
+            };
             GLTFLoader.prototype._createRootNode = function () {
                 this._rootBabylonMesh = new BABYLON.Mesh("__root__", this._babylonScene);
                 var rootNode = { _babylonMesh: this._rootBabylonMesh };
@@ -4953,8 +4965,8 @@ var BABYLON;
             };
             GLTFLoader.prototype._applyExtensions = function (actionAsync) {
                 for (var _i = 0, _a = GLTFLoader._Names; _i < _a.length; _i++) {
-                    var name_2 = _a[_i];
-                    var extension = this._extensions[name_2];
+                    var name_3 = _a[_i];
+                    var extension = this._extensions[name_3];
                     if (extension.enabled) {
                         var promise = actionAsync(extension);
                         if (promise) {

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2 - 2
dist/preview release/loaders/babylonjs.loaders.min.js


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

@@ -960,6 +960,7 @@ declare module BABYLON.GLTF2 {
         private _loadExtensions();
         private _loadData(data);
         private _setupData();
+        private _checkExtensions();
         private _createRootNode();
         private _loadNodesAsync(nodes);
         _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;

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

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

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

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

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

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

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

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

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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-serializers",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
-    "version": "3.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
         "type": "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 {
 
     export let disableInit: boolean;
@@ -56,7 +54,7 @@ declare module BabylonViewer {
         selector: string;
         payload?: any;
     }
-    class TemplateManager {
+    interface TemplateManager {
         containerElement: HTMLElement;
         onInit: BABYLON.Observable<Template>;
         onLoaded: BABYLON.Observable<Template>;
@@ -64,20 +62,16 @@ declare module BabylonViewer {
         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 {
+    interface Template {
         name: string;
-        private _configuration;
         onInit: BABYLON.Observable<Template>;
         onLoaded: BABYLON.Observable<Template>;
         onAppended: BABYLON.Observable<Template>;
@@ -87,7 +81,6 @@ declare module BabylonViewer {
         isShown: boolean;
         parent: HTMLElement;
         initPromise: Promise<Template>;
-        private fragment;
         constructor(name: string, _configuration: ITemplateConfiguration);
         readonly configuration: ITemplateConfiguration;
         getChildElements(): Array<string>;
@@ -95,11 +88,9 @@ declare module BabylonViewer {
         show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
         hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
         dispose(): void;
-        private registerEvents();
     }
 
-    class ViewerManager {
-        private viewers;
+    interface ViewerManager {
         onViewerAdded: (viewer: AbstractViewer) => void;
         onViewerAddedObservable: BABYLON.Observable<AbstractViewer>;
         constructor();
@@ -107,7 +98,6 @@ declare module BabylonViewer {
         getViewerById(id: string): AbstractViewer;
         getViewerByHTMLElement(element: HTMLElement): AbstractViewer | undefined;
         getViewerPromiseById(id: string): Promise<AbstractViewer>;
-        private _onViewerAdded(viewer);
     }
     export let viewerManager: ViewerManager;
 
@@ -119,37 +109,31 @@ declare module BabylonViewer {
 
     export function InitTags(selector?: string): void;
 
-    class EventManager {
-        private templateManager;
-        private callbacksContainer;
+    interface EventManager {
         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> {
+    interface 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;
+    interface MapperManager {
+        DefaultMapper: string;
         constructor();
         getMapper(type: string): IMapper;
         registerMapper(type: string, mapper: IMapper): void;
     }
     export let mapperManager: MapperManager;
 
-    class ConfigurationLoader {
-        private configurationCache;
+    interface ConfigurationLoader {
         constructor();
         loadConfiguration(initConfig?: ViewerConfiguration): Promise<ViewerConfiguration>;
         getConfigurationType(type: string): void;
-        private loadFile(url);
     }
     export let configurationLoader: ConfigurationLoader;
 

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 67 - 66
dist/preview release/viewer/babylon.viewer.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 430 - 112
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",
     "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": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -12,7 +12,9 @@
     "main": "babylon.viewer.js",
     "files": [
         "babylon.viewer.js",
+        "babylon.viewer.d.ts",
         "babylon.viewer.module.d.ts",
+        "babylon.d.ts",
         "readme.md",
         "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.
 
@@ -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
 
-# 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
 <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:
@@ -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 :
 
-```
+```javascript
 npm install --save babylonjs-viewer
 ```
 
 Afterwards it can be imported to the project using:
 
-```
+```javascript
 import from 'babylonjs-viewer';
 ```
 
 This will enable the BabylonViewer namespace.
 
 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)
+```

+ 4 - 2
dist/preview release/what's new.md

@@ -2,7 +2,7 @@
 
 ## Major updates
 
--Support for [GPU particles](DOC HERE) ([deltakosh](https://github.com/deltakosh))
+- 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))
@@ -71,9 +71,10 @@
 - 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))
+- (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))
 - Support multiple simultaneous webVR controller gui interactions in WebVRExperienceHelper ([trevordev](https://github.com/trevordev))
+- (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))
 
 ## Bug fixes
 
@@ -83,6 +84,7 @@
 - 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
 

+ 12 - 0
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -123,6 +123,7 @@ module BABYLON.GLTF2 {
                 this._state = GLTFLoaderState.Loading;
 
                 this._loadData(data);
+                this._checkExtensions();
 
                 const promises = new Array<Promise<void>>();
 
@@ -231,6 +232,17 @@ module BABYLON.GLTF2 {
             }
         }
 
+        private _checkExtensions(): void {
+            if (this._gltf.extensionsRequired) {
+                for (const name of this._gltf.extensionsRequired) {
+                    const extension = this._extensions[name];
+                    if (!extension || !extension.enabled) {
+                        throw new Error(`Require extension ${name} is not available`);
+                    }
+                }
+            }
+        }
+
         private _createRootNode(): ILoaderNode {
             this._rootBabylonMesh = new Mesh("__root__", this._babylonScene);
             const rootNode = { _babylonMesh: this._rootBabylonMesh } as ILoaderNode;

+ 2 - 2
package.json

@@ -9,7 +9,7 @@
     ],
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "3.2.0-alpha7",
+    "version": "3.2.0-alpha8",
     "repository": {
         "type": "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",
     "readmeFilename": "README.md"
-}
+}

+ 2 - 3
sandbox/index.html

@@ -32,9 +32,8 @@
     <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/babylon.glTFFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.stlFileLoader.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>
 </head>
 
 <body>

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

@@ -4268,7 +4268,7 @@
                 }, undefined, undefined, true, onerror);
             } else if (isDDS) {
                 if (files && files.length === 6) {
-                    this._cascadeLoadFiles(rootUrl,
+                    this._cascadeLoadFiles(
                         scene,
                         imgs => {
                             var info: DDSInfo | undefined;
@@ -5883,7 +5883,7 @@
             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)[] = [];
             (<any>loadedFiles)._internalCount = 0;
 

+ 4 - 0
src/Engine/babylon.nullEngine.ts

@@ -25,6 +25,10 @@
             return this._options.lockstepMaxSteps;
         }
 
+        public getHardwareScalingLevel(): number {
+            return 1.0;
+        }
+
         public constructor(options: NullEngineOptions = new NullEngineOptions()) {
             super(null);
 

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

@@ -476,7 +476,9 @@ module BABYLON {
                 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);
 
             if (this._options.sizeAuto) {

+ 8 - 2
src/Loading/Plugins/babylon.babylonFileLoader.ts

@@ -298,8 +298,14 @@
             if (parsedData.particleSystems !== undefined && parsedData.particleSystems !== null) {
                 for (index = 0, cache = parsedData.particleSystems.length; index < cache; index++) {
                     var parsedParticleSystem = parsedData.particleSystems[index];
-                    var ps = ParticleSystem.Parse(parsedParticleSystem, scene, rootUrl);
-                    container.particleSystems.push(ps);
+
+                    if (parsedParticleSystem.activeParticleCount) {
+                        let ps = GPUParticleSystem.Parse(parsedParticleSystem, scene, rootUrl);
+                        container.particleSystems.push(ps);
+                    } else {
+                        let ps = ParticleSystem.Parse(parsedParticleSystem, scene, rootUrl);
+                        container.particleSystems.push(ps);
+                    }
                 }
             }
 

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

@@ -39,7 +39,11 @@
         private _prefiltered: 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) {

+ 0 - 6
src/Math/babylon.math.ts

@@ -334,7 +334,6 @@
          */
         public static FromHexString(hex: string): Color3 {
             if (hex.substring(0, 1) !== "#" || hex.length !== 7) {
-                //Tools.Warn("Color3.FromHexString must be called with a string like #FFFFFF");
                 return new Color3(0, 0, 0);
             }
 
@@ -746,7 +745,6 @@
          */
         public static FromHexString(hex: string): Color4 {
             if (hex.substring(0, 1) !== "#" || hex.length !== 9) {
-                //Tools.Warn("Color4.FromHexString must be called with a string like #FFFFFFFF");
                 return new Color4(0.0, 0.0, 0.0, 0.0);
             }
 
@@ -5290,7 +5288,6 @@
          */
         public addLineTo(x: number, y: number): Path2 {
             if (this.closed) {
-                //Tools.Error("cannot add lines to closed paths");
                 return this;
             }
             var newPoint = new Vector2(x, y);
@@ -5306,7 +5303,6 @@
          */
         public addArcTo(midX: number, midY: number, endX: number, endY: number, numberOfSegments = 36): Path2 {
             if (this.closed) {
-                //Tools.Error("cannot add arcs to closed paths");
                 return this;
             }
             var startPoint = this._points[this._points.length - 1];
@@ -5361,7 +5357,6 @@
          */
         public getPointAtLengthPosition(normalizedLengthPosition: number): Vector2 {
             if (normalizedLengthPosition < 0 || normalizedLengthPosition > 1) {
-                //Tools.Error("normalized length position should be between 0 and 1.");
                 return Vector2.Zero();
             }
 
@@ -5388,7 +5383,6 @@
                 previousOffset = nextOffset;
             }
 
-            //Tools.Error("internal error");
             return Vector2.Zero();
         }
 

+ 1 - 1
src/Mesh/Compression/babylon.dracoCompression.ts

@@ -11,7 +11,7 @@ module BABYLON {
          * Returns whether Draco compression is supported.
          */
         public static get IsSupported(): boolean {
-            return !!window.DracoDecoderModule;
+            return Tools.IsWindowObjectExist() && !!window.DracoDecoderModule;
         }
 
         /**

+ 6 - 0
src/Particles/EmitterTypes/babylon.IParticleEmitterType.ts

@@ -50,5 +50,11 @@ module BABYLON {
          * @returns the JSON object
          */        
         serialize(): any;
+
+ /**
+         * Parse properties from a JSON object
+         * @param serializationObject defines the JSON object
+         */
+        parse(serializationObject: any): void;
     }
 }

+ 17 - 0
src/Particles/EmitterTypes/babylon.boxParticleEmitter.ts

@@ -106,7 +106,24 @@ module BABYLON {
         public serialize(): any {
             var serializationObject: any = {};
 
+            serializationObject.type = this.getClassName();
+            serializationObject.direction1  = this.direction1.asArray();;
+            serializationObject.direction2  = this.direction2.asArray();;
+            serializationObject.minEmitBox  = this.minEmitBox.asArray();;
+            serializationObject.maxEmitBox  = this.maxEmitBox.asArray();;
+
             return serializationObject;
         }
+
+        /**
+         * Parse properties from a JSON object
+         * @param serializationObject defines the JSON object
+         */
+        public parse(serializationObject: any): void {
+            this.direction1.copyFrom(serializationObject.direction1);
+            this.direction2.copyFrom(serializationObject.direction2);
+            this.minEmitBox.copyFrom(serializationObject.minEmitBox);
+            this.maxEmitBox.copyFrom(serializationObject.maxEmitBox);
+        }
     }
 }

+ 19 - 4
src/Particles/EmitterTypes/babylon.coneParticleEmitter.ts

@@ -30,15 +30,15 @@ module BABYLON {
 
         /**
          * Creates a new instance of @see ConeParticleEmitter
-         * @param radius the radius of the emission cone
-         * @param angles the cone base angle
+         * @param radius the radius of the emission cone (1 by default)
+         * @param angles the cone base angle (PI by default)
          * @param directionRandomizer defines how much to randomize the particle direction [0-1]
          */
-        constructor(radius: number, 
+        constructor(radius = 1, 
             /**
              * The radius of the emission cone.
              */
-            public angle: number, 
+            public angle = Math.PI, 
             /**
              * The cone base angle.
              */
@@ -139,7 +139,22 @@ module BABYLON {
         public serialize(): any {
             var serializationObject: any = {};
 
+            serializationObject.type = this.getClassName();
+            serializationObject.radius  = this.radius;
+            serializationObject.angle  = this.angle;
+            serializationObject.directionRandomizer  = this.directionRandomizer;
+
             return serializationObject;
+        }   
+
+        /**
+         * Parse properties from a JSON object
+         * @param serializationObject defines the JSON object
+         */
+        public parse(serializationObject: any): void {
+            this.radius = serializationObject.radius;
+            this.angle = serializationObject.angle;
+            this.directionRandomizer = serializationObject.directionRandomizer;
         }        
     }
 }

+ 40 - 14
src/Particles/EmitterTypes/babylon.sphereParticleEmitter.ts

@@ -7,14 +7,14 @@ module BABYLON {
 
         /**
          * Creates a new instance of @see SphereParticleEmitter
-         * @param radius the radius of the emission sphere
+         * @param radius the radius of the emission sphere (1 by default)
          * @param directionRandomizer defines how much to randomize the particle direction [0-1]
          */
         constructor(
             /**
              * The radius of the emission sphere.
              */
-            public radius: number, 
+            public radius = 1, 
             /**
              * How much to randomize the particle direction [0-1].
              */
@@ -51,9 +51,10 @@ module BABYLON {
         public startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void {
             var phi = Scalar.RandomRange(0, 2 * Math.PI);
             var theta = Scalar.RandomRange(0, Math.PI);
-            var randX = this.radius * Math.cos(phi) * Math.sin(theta);
-            var randY = this.radius * Math.cos(theta);
-            var randZ = this.radius * Math.sin(phi) * Math.sin(theta);
+            var randRadius = Scalar.RandomRange(0, this.radius);
+            var randX = randRadius * Math.cos(phi) * Math.sin(theta);
+            var randY = randRadius * Math.cos(theta);
+            var randZ = randRadius * Math.sin(phi) * Math.sin(theta);
             Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
         }
 
@@ -100,9 +101,21 @@ module BABYLON {
          */        
         public serialize(): any {
             var serializationObject: any = {};
+            serializationObject.type = this.getClassName();
+            serializationObject.radius = this.radius;
+            serializationObject.directionRandomizer = this.directionRandomizer;
 
             return serializationObject;
-        }        
+        }    
+        
+        /**
+         * Parse properties from a JSON object
+         * @param serializationObject defines the JSON object
+         */
+        public parse(serializationObject: any): void {
+            this.radius = serializationObject.radius;
+            this.directionRandomizer = serializationObject.directionRandomizer;
+        }          
     }
 
     /**
@@ -113,19 +126,19 @@ module BABYLON {
 
         /**
          * Creates a new instance of @see SphereDirectedParticleEmitter
-         * @param radius the radius of the emission sphere
-         * @param direction1 the min limit of the emission direction
-         * @param direction2 the max limit of the emission direction
+         * @param radius the radius of the emission sphere (1 by default)
+         * @param direction1 the min limit of the emission direction (up vector by default)
+         * @param direction2 the max limit of the emission direction (up vector by default)
          */
-        constructor(radius: number, 
+        constructor(radius = 1, 
             /**
              * The min limit of the emission direction.
              */
-            public direction1: Vector3, 
+            public direction1 = new Vector3(0, 1, 0), 
             /**
              * The max limit of the emission direction.
              */
-            public direction2: Vector3) {
+            public direction2 = new Vector3(0, 1, 0)) {
             super(radius);
         }
 
@@ -186,9 +199,22 @@ module BABYLON {
          * @returns the JSON object
          */        
         public serialize(): any {
-            var serializationObject: any = {};
+            var serializationObject = super.serialize();;
+
+            serializationObject.direction1 = this.direction1.asArray();;
+            serializationObject.direction2 = this.direction2.asArray();;
 
             return serializationObject;
-        }        
+        }    
+        
+        /**
+         * Parse properties from a JSON object
+         * @param serializationObject defines the JSON object
+         */
+        public parse(serializationObject: any): void {
+            super.parse(serializationObject);
+            this.direction1.copyFrom(serializationObject.direction1);
+            this.direction2.copyFrom(serializationObject.direction2);
+        }           
     }
 }

+ 168 - 0
src/Particles/babylon.IParticleSystem.ts

@@ -0,0 +1,168 @@
+module BABYLON {
+    /**
+     * Interface representing a particle system in Babylon.
+     * This groups the common functionalities that needs to be implemented in order to create a particle system.
+     * A particle system represents a way to manage particles (@see Particle) from their emission to their animation and rendering.
+     */
+    export interface IParticleSystem {
+        /**
+         * The id of the Particle system.
+         */
+        id: string;
+        /**
+         * The name of the Particle system.
+         */
+        name: string;
+        /**
+         * The emitter represents the Mesh or position we are attaching the particle system to.
+         */
+        emitter: Nullable<AbstractMesh | Vector3>;
+        /**
+         * The rendering group used by the Particle system to chose when to render.
+         */
+        renderingGroupId: number;
+        /**
+         * The layer mask we are rendering the particles through.
+         */
+        layerMask: number;
+
+         /**
+         * The overall motion speed (0.01 is default update speed, faster updates = faster animation)
+         */
+        updateSpeed: number;        
+
+        /**
+         * The amount of time the particle system is running (depends of the overall update speed).
+         */
+        targetStopDuration: number;        
+
+        /**
+         * The texture used to render each particle. (this can be a spritesheet)
+         */
+        particleTexture: Nullable<Texture>;   
+        
+        /**
+         * Blend mode use to render the particle, it can be either ParticleSystem.BLENDMODE_ONEONE or ParticleSystem.BLENDMODE_STANDARD.
+         */
+        blendMode: number;   
+        
+        /**
+         * Minimum life time of emitting particles.
+         */
+        minLifeTime: number;
+        /**
+         * Maximum life time of emitting particles.
+         */
+        maxLifeTime: number;    
+
+        /**
+         * Minimum Size of emitting particles.
+         */
+        minSize: number;
+        /**
+         * Maximum Size of emitting particles.
+         */
+        maxSize: number;        
+        
+        /**
+         * Random color of each particle after it has been emitted, between color1 and color2 vectors.
+         */
+        color1: Color4;
+        /**
+         * Random color of each particle after it has been emitted, between color1 and color2 vectors.
+         */
+        color2: Color4;  
+        
+        /**
+         * Color the particle will have at the end of its lifetime.
+         */
+        colorDead: Color4;
+        
+        /**
+         * The maximum number of particles to emit per frame until we reach the activeParticleCount value
+         */
+        emitRate: number; 
+        
+        /**
+         * You can use gravity if you want to give an orientation to your particles.
+         */
+        gravity: Vector3;    
+
+        /**
+         * Minimum power of emitting particles.
+         */
+        minEmitPower: number;
+        /**
+         * Maximum power of emitting particles.
+         */
+        maxEmitPower: number;        
+
+        /**
+         * The particle emitter type defines the emitter used by the particle system.
+         * It can be for example box, sphere, or cone...
+         */
+        particleEmitterType: Nullable<IParticleEmitterType>;        
+
+        /**
+         * Gets the maximum number of particles active at the same time.
+         * @returns The max number of active particles.
+         */
+        getCapacity(): number;
+
+        /**
+         * Gets Wether the system has been started.
+         * @returns True if it has been started, otherwise false.
+         */
+        isStarted(): boolean;
+
+        /**
+         * Gets if the particle system has been started.
+         * @return true if the system has been started, otherwise false.
+         */
+        isStarted(): boolean;
+        /**
+         * Animates the particle system for this frame.
+         */
+        animate(): void;
+        /**
+         * Renders the particle system in its current state.
+         * @returns the current number of particles
+         */
+        render(): number;
+        /**
+         * Dispose the particle system and frees its associated resources.
+         */
+        dispose(): void;
+        /**
+         * Clones the particle system.
+         * @param name The name of the cloned object
+         * @param newEmitter The new emitter to use
+         * @returns the cloned particle system
+         */
+        clone(name: string, newEmitter: any): Nullable<IParticleSystem>;
+        /**
+         * Serializes the particle system to a JSON object.
+         * @returns the JSON object
+         */
+        serialize(): any;
+        /**
+         * Rebuild the particle system
+         */
+        rebuild(): void;
+
+        /**
+         * Starts the particle system and begins to emit.
+         */
+        start(): void;
+
+        /**
+         * Stops the particle system.
+         */
+        stop(): void;
+
+        /**
+         * Remove all active particles
+         */
+        reset(): void;
+    }
+}

+ 211 - 23
src/Particles/babylon.gpuParticleSystem.ts

@@ -1,7 +1,8 @@
 module BABYLON {
     /**
-     * This represents a GPU particle system in Babylon.
-     * This os the fastest particle system in Babylon as it uses the GPU to update the individual particle data.
+     * This represents a GPU particle system in Babylon
+     * This is the fastest particle system in Babylon as it uses the GPU to update the individual particle data
+     * @see https://www.babylonjs-playground.com/#PU4WYI#4
      */
     export class GPUParticleSystem implements IDisposable, IParticleSystem, IAnimatable {
         /**
@@ -27,7 +28,7 @@
         /**
          * The layer mask we are rendering the particles through.
          */
-        public layerMask: number = 0x0FFFFFFF; // TODO
+        public layerMask: number = 0x0FFFFFFF;
 
         private _capacity: number;
         private _activeCount: number;
@@ -38,8 +39,8 @@
         private _buffer0: Buffer;
         private _buffer1: Buffer;
         private _spriteBuffer: Buffer;
-        private _updateVAO = new Array<WebGLVertexArrayObject>();
-        private _renderVAO = new Array<WebGLVertexArrayObject>()
+        private _updateVAO: Array<WebGLVertexArrayObject>;
+        private _renderVAO: Array<WebGLVertexArrayObject>;
 
         private _targetIndex = 0;
         private _sourceBuffer: Buffer;
@@ -157,7 +158,79 @@
          * The particle emitter type defines the emitter used by the particle system.
          * It can be for example box, sphere, or cone...
          */
-        public particleEmitterType: Nullable<IParticleEmitterType>;        
+        public particleEmitterType: Nullable<IParticleEmitterType>;    
+
+        /**
+         * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+         * This only works when particleEmitterTyps is a BoxParticleEmitter
+         */
+        public get direction1(): Vector3 {
+            if ((<BoxParticleEmitter>this.particleEmitterType).direction1) {
+                return (<BoxParticleEmitter>this.particleEmitterType).direction1;
+            }
+
+            return Vector3.Zero();
+        }
+
+        public set direction1(value: Vector3) {
+            if ((<BoxParticleEmitter>this.particleEmitterType).direction1) {
+                (<BoxParticleEmitter>this.particleEmitterType).direction1 = value;
+            }
+        }        
+        
+        /**
+         * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+         * This only works when particleEmitterTyps is a BoxParticleEmitter
+         */
+        public get direction2(): Vector3 {
+            if ((<BoxParticleEmitter>this.particleEmitterType).direction2) {
+                return (<BoxParticleEmitter>this.particleEmitterType).direction2;
+            }
+
+            return Vector3.Zero();
+        }
+
+        public set direction2(value: Vector3) {
+            if ((<BoxParticleEmitter>this.particleEmitterType).direction2) {
+                (<BoxParticleEmitter>this.particleEmitterType).direction2 = value;
+            }
+        }
+
+        /**
+         * Minimum box point around our emitter. Our emitter is the center of particles source, but if you want your particles to emit from more than one point, then you can tell it to do so.
+         * This only works when particleEmitterTyps is a BoxParticleEmitter
+         */
+        public get minEmitBox(): Vector3 {
+            if ((<BoxParticleEmitter>this.particleEmitterType).minEmitBox) {
+                return (<BoxParticleEmitter>this.particleEmitterType).minEmitBox;
+            }
+
+            return Vector3.Zero();
+        }
+
+        public set minEmitBox(value: Vector3) {
+            if ((<BoxParticleEmitter>this.particleEmitterType).minEmitBox) {
+                (<BoxParticleEmitter>this.particleEmitterType).minEmitBox = value;
+            }
+        }      
+        
+        /**
+         * Maximum box point around our emitter. Our emitter is the center of particles source, but if you want your particles to emit from more than one point, then you can tell it to do so.
+         * This only works when particleEmitterTyps is a BoxParticleEmitter
+         */
+        public get maxEmitBox(): Vector3 {
+            if ((<BoxParticleEmitter>this.particleEmitterType).maxEmitBox) {
+                return (<BoxParticleEmitter>this.particleEmitterType).maxEmitBox;
+            }
+
+            return Vector3.Zero();
+        }
+
+        public set maxEmitBox(value: Vector3) {
+            if ((<BoxParticleEmitter>this.particleEmitterType).maxEmitBox) {
+                (<BoxParticleEmitter>this.particleEmitterType).maxEmitBox = value;
+            }
+        }        
 
         /**
          * Gets the maximum number of particles active at the same time.
@@ -262,10 +335,6 @@
                 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
             var maxTextureSize = Math.min(this._engine.getCaps().maxTextureSize, fullOptions.randomTextureSize);
             var d = [];
@@ -280,6 +349,7 @@
             this._randomTexture.wrapV = Texture.WRAP_ADDRESSMODE;
 
             this._randomTextureSize = maxTextureSize;
+            this.particleEmitterType = new BoxParticleEmitter();
         }
 
         private _createUpdateVAO(source: Buffer): WebGLVertexArrayObject {            
@@ -362,10 +432,12 @@
             this._spriteBuffer = new Buffer(engine, spriteData, false, 4);                                      
 
             // Update VAO
+            this._updateVAO = [];
             this._updateVAO.push(this._createUpdateVAO(this._buffer0));
             this._updateVAO.push(this._createUpdateVAO(this._buffer1));
 
             // Render VAO
+            this._renderVAO = [];
             this._renderVAO.push(this._createRenderVAO(this._buffer1, this._spriteBuffer));
             this._renderVAO.push(this._createRenderVAO(this._buffer0, this._spriteBuffer));
 
@@ -376,14 +448,32 @@
         }
 
         /** @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;
             }
             this._updateEffectOptions.defines = defines;
             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.
          */
@@ -408,9 +498,8 @@
                 return 0;
             }
 
-            if (this.particleEmitterType) {
-                this._recreateUpdateEffect(this.particleEmitterType.getEffectDefines());
-            }
+            this._recreateUpdateEffect();
+            this._recreateRenderEffect();
 
             if (!this.emitter || !this._updateEffect.isReady() || !this._renderEffect.isReady() ) {
                 return 0;
@@ -425,7 +514,7 @@
             // Get everything ready to render
             this. _initialize();
 
-            this._currentActiveCount = Math.min(this._activeCount, this._currentActiveCount + this.emitRate);
+            this._currentActiveCount = Math.min(this._activeCount, this._currentActiveCount + (this.emitRate * this._timeDelta) | 0);
             
             // Enable update effect
 
@@ -471,11 +560,21 @@
 
             // Enable render effect
             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.setTexture("textureSampler", this.particleTexture);
             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
             if (this.blendMode === ParticleSystem.BLENDMODE_ONEONE) {
                 this._engine.setAlphaMode(Engine.ALPHA_ONEONE);
@@ -560,9 +659,6 @@
             this.onDisposeObservable.notifyObservers(this);
             this.onDisposeObservable.clear();
         }
-
-        //TODO: Clone / Parse / serialize
-
         /**
          * Clones the particle system.
          * @param name The name of the cloned object
@@ -570,7 +666,20 @@
          * @returns the cloned particle system
          */
         public clone(name: string, newEmitter: any): Nullable<GPUParticleSystem> {
-            return null;
+            var result = new GPUParticleSystem(name, {capacity: this._capacity, randomTextureSize: this._randomTextureSize}, this._scene);
+
+            Tools.DeepCopy(this, result);
+
+            if (newEmitter === undefined) {
+                newEmitter = this.emitter;
+            }
+
+            result.emitter = newEmitter;
+            if (this.particleTexture) {
+                result.particleTexture = new Texture(this.particleTexture.url, this._scene);
+            }
+
+            return result;
         }
 
         /**
@@ -619,12 +728,91 @@
             serializationObject.targetStopDuration = this.targetStopDuration;
             serializationObject.blendMode = this.blendMode;
 
-            // Emitters
+            // Emitter
             if (this.particleEmitterType) {
-                
+                serializationObject.particleEmitterType = this.particleEmitterType.serialize();
             }
 
             return serializationObject;            
         }
+
+        /**
+         * Parses a JSON object to create a GPU particle system.
+         * @param parsedParticleSystem The JSON object to parse
+         * @param scene The scene to create the particle system in
+         * @param rootUrl The root url to use to load external dependencies like texture
+         * @returns the parsed GPU particle system
+         */
+        public static Parse(parsedParticleSystem: any, scene: Scene, rootUrl: string): GPUParticleSystem {
+            var name = parsedParticleSystem.name;
+            var particleSystem = new GPUParticleSystem(name, {capacity: parsedParticleSystem.capacity, randomTextureSize: parsedParticleSystem.randomTextureSize}, scene);
+
+            if (parsedParticleSystem.id) {
+                particleSystem.id = parsedParticleSystem.id;
+            }
+
+            // Texture
+            if (parsedParticleSystem.textureName) {
+                particleSystem.particleTexture = new Texture(rootUrl + parsedParticleSystem.textureName, scene);
+                particleSystem.particleTexture.name = parsedParticleSystem.textureName;
+            }
+
+            // Emitter
+            if (parsedParticleSystem.emitterId) {
+                particleSystem.emitter = scene.getLastMeshByID(parsedParticleSystem.emitterId);
+            } else {
+                particleSystem.emitter = Vector3.FromArray(parsedParticleSystem.emitter);
+            }
+
+            // Animations
+            if (parsedParticleSystem.animations) {
+                for (var animationIndex = 0; animationIndex < parsedParticleSystem.animations.length; animationIndex++) {
+                    var parsedAnimation = parsedParticleSystem.animations[animationIndex];
+                    particleSystem.animations.push(Animation.Parse(parsedAnimation));
+                }
+            }
+
+            // Particle system
+            particleSystem.activeParticleCount = parsedParticleSystem.activeParticleCount;
+            particleSystem.minSize = parsedParticleSystem.minSize;
+            particleSystem.maxSize = parsedParticleSystem.maxSize;
+            particleSystem.minLifeTime = parsedParticleSystem.minLifeTime;
+            particleSystem.maxLifeTime = parsedParticleSystem.maxLifeTime;
+            particleSystem.minEmitPower = parsedParticleSystem.minEmitPower;
+            particleSystem.maxEmitPower = parsedParticleSystem.maxEmitPower;
+            particleSystem.emitRate = parsedParticleSystem.emitRate;
+            particleSystem.gravity = Vector3.FromArray(parsedParticleSystem.gravity);
+            particleSystem.color1 = Color4.FromArray(parsedParticleSystem.color1);
+            particleSystem.color2 = Color4.FromArray(parsedParticleSystem.color2);
+            particleSystem.colorDead = Color4.FromArray(parsedParticleSystem.colorDead);
+            particleSystem.updateSpeed = parsedParticleSystem.updateSpeed;
+            particleSystem.targetStopDuration = parsedParticleSystem.targetStopDuration;
+            particleSystem.blendMode = parsedParticleSystem.blendMode;
+
+            // Emitter
+            if (parsedParticleSystem.particleEmitterType) {
+                let emitterType: IParticleEmitterType;
+                switch (parsedParticleSystem.particleEmitterType.type) {
+                    case "SphereEmitter":
+                        emitterType = new SphereParticleEmitter();
+                        break;
+                    case "SphereDirectedParticleEmitter":
+                        emitterType = new SphereDirectedParticleEmitter();
+                        break;
+                    case "ConeEmitter":
+                        emitterType = new ConeParticleEmitter();
+                        break;
+                    case "BoxEmitter":
+                    default:
+                        emitterType = new BoxParticleEmitter();
+                        break;                                                
+                }
+
+                emitterType.parse(parsedParticleSystem.particleEmitterType);
+                particleSystem.particleEmitterType = emitterType;
+            }
+
+            return particleSystem;
+        }        
     }
 }

+ 5 - 62
src/Particles/babylon.particleSystem.ts

@@ -1,67 +1,5 @@
 module BABYLON {
     /**
-     * Interface representing a particle system in Babylon.
-     * This groups the common functionalities that needs to be implemented in order to create a particle system.
-     * A particle system represents a way to manage particles (@see Particle) from their emission to their animation and rendering.
-     */
-    export interface IParticleSystem {
-        /**
-         * The id of the Particle system.
-         */
-        id: string;
-        /**
-         * The name of the Particle system.
-         */
-        name: string;
-        /**
-         * The emitter represents the Mesh or position we are attaching the particle system to.
-         */
-        emitter: Nullable<AbstractMesh | Vector3>;
-        /**
-         * The rendering group used by the Particle system to chose when to render.
-         */
-        renderingGroupId: number;
-        /**
-         * The layer mask we are rendering the particles through.
-         */
-        layerMask: number;
-        /**
-         * Gets if the particle system has been started.
-         * @return true if the system has been started, otherwise false.
-         */
-        isStarted(): boolean;
-        /**
-         * Animates the particle system for this frame.
-         */
-        animate(): void;
-        /**
-         * Renders the particle system in its current state.
-         * @returns the current number of particles
-         */
-        render(): number;
-        /**
-         * Dispose the particle system and frees its associated resources.
-         */
-        dispose(): void;
-        /**
-         * Clones the particle system.
-         * @param name The name of the cloned object
-         * @param newEmitter The new emitter to use
-         * @returns the cloned particle system
-         */
-        clone(name: string, newEmitter: any): Nullable<IParticleSystem>;
-        /**
-         * Serializes the particle system to a JSON object.
-         * @returns the JSON object
-         */
-        serialize(): any;
-        /**
-         * Rebuild the particle system
-         */
-        rebuild(): void
-    }
-
-    /**
      * This represents a particle system in Babylon.
      * Particles are often small sprites used to simulate hard-to-reproduce phenomena like fire, smoke, water, or abstract visual effects like magic glitter and faery dust.
      * Particles can take different shapes while emitted like box, sphere, cone or you can write your custom function.
@@ -1067,6 +1005,11 @@
 
             serializationObject.isAnimationSheetEnabled = this._isAnimationSheetEnabled;
 
+            // Emitter
+            if (this.particleEmitterType) {
+                serializationObject.particleEmitterType = this.particleEmitterType.serialize();
+            }            
+
             return serializationObject;
         }
 

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

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

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

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

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

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

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

@@ -16,6 +16,13 @@ in vec2 uv;
 out vec2 vUV;
 out vec4 vColor;
 
+#ifdef CLIPPLANE
+uniform vec4 vClipPlane;
+uniform mat4 invView;
+out float fClipDistance;
+#endif
+
+
 void main() {
   vUV = uv;
   float ratio = age / life;
@@ -24,4 +31,10 @@ void main() {
   // Expand position
   vec4 viewPosition = view * vec4(position, 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  
 }

+ 7 - 7
src/Shaders/gpuUpdateParticles.vertex.fx

@@ -105,13 +105,13 @@ void main() {
     float randY = cos(theta);
     float randZ = sin(phi) * sin(theta);
 
-    position = radius * vec3(randX, randY, randZ);
+    position = (radius * randoms2.z) * vec3(randX, randY, randZ);
 
     #ifdef DIRECTEDSPHEREEMITTER
       direction = direction1 + (direction2 - direction1) * randoms3;
     #else
-        // Direction
-        direction = position + directionRandomizer * randoms3;
+      // Direction
+      direction = position + directionRandomizer * randoms3;
     #endif
 #elif defined(CONEEMITTER)
     vec3 randoms2 = getRandomVec3(generalRandoms.y);
@@ -132,10 +132,10 @@ void main() {
 
     // Direction
     if (angle == 0.) {
-      direction = vec3(0., 1.0, 0.);
+        direction = vec3(0., 1.0, 0.);
     } else {
-      vec3 randoms3 = getRandomVec3(generalRandoms.z);
-      direction = position + directionRandomizer * randoms3;
+        vec3 randoms3 = getRandomVec3(generalRandoms.z);
+        direction = position + directionRandomizer * randoms3;
     }
 #else    
     // Create the particle at origin
@@ -148,7 +148,7 @@ void main() {
     float power = emitPower.x + (emitPower.y - emitPower.x) * randoms.a;
 
     outPosition = (emitterWM * vec4(position, 1.)).xyz;
-    outDirection = (emitterWM * vec4(normalize(direction) * power, 0.)).xyz;
+    outDirection = (emitterWM * vec4(direction * power, 0.)).xyz;
 
   } else {   
     outPosition = position + (direction + gravity) * timeDelta;

+ 1 - 1
src/babylon.assetContainer.ts

@@ -94,7 +94,7 @@ module BABYLON {
         /**
          * ParticleSystems populated in the container.
          */
-        public particleSystems = new Array<ParticleSystem>();
+        public particleSystems = new Array<IParticleSystem>();
         /**
          * Animations populated in the container.
          */

+ 13 - 8
src/babylon.scene.ts

@@ -2394,7 +2394,7 @@
         }
 
 
-        public removeParticleSystem(toRemove: ParticleSystem): number {
+        public removeParticleSystem(toRemove: IParticleSystem): number {
             var index = this.particleSystems.indexOf(toRemove);
             if (index !== -1) {
                 this.particleSystems.splice(index, 1);
@@ -2467,7 +2467,7 @@
             this.skeletons.push(newSkeleton)
         }
 
-        public addParticleSystem(newParticleSystem: ParticleSystem) {
+        public addParticleSystem(newParticleSystem: IParticleSystem) {
             this.particleSystems.push(newParticleSystem)
         }
 
@@ -4235,16 +4235,21 @@
         }
 
         // Octrees
-        public getWorldExtends(): { min: Vector3; max: Vector3 } {
+        /**
+         * Get the world extend vectors with an optional filter
+         * 
+         * @param {(mesh: AbstractMesh) => boolean} [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 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);
 
                 if (!mesh.subMeshes || mesh.subMeshes.length === 0 || mesh.infiniteDistance) {
-                    continue;
+                    return;
                 }
 
                 let boundingInfo = mesh.getBoundingInfo();
@@ -4254,7 +4259,7 @@
 
                 Tools.CheckExtends(minBox, min, max);
                 Tools.CheckExtends(maxBox, min, max);
-            }
+            })
 
             return {
                 min: min,

+ 25 - 12
tests/nullEngine/app.js

@@ -129,16 +129,29 @@ var engine = new BABYLON.NullEngine();
 //     scene.render();
 // })
 
-new BABYLON.Scene(engine).dispose()
-
-BABYLON.SceneLoader.Load("https://playground.babylonjs.com/scenes/", "skull.babylon", engine, (scene) => {
-    console.log('scene loaded!');
-    for (var index = 0; index < scene.meshes.length; index++) {
-        console.log(scene.meshes[index].name);
-    } 
-    engine.dispose();   
-   // engine.runRenderLoop(function() {
-     //   scene.render();
-    //});
+// new BABYLON.Scene(engine).dispose()
+
+// BABYLON.SceneLoader.Load("https://playground.babylonjs.com/scenes/", "skull.babylon", engine, (scene) => {
+//     console.log('scene loaded!');
+//     for (var index = 0; index < scene.meshes.length; index++) {
+//         console.log(scene.meshes[index].name);
+//     } 
+//     engine.dispose();   
+//    // engine.runRenderLoop(function() {
+//      //   scene.render();
+//     //});
   
-  }, progress => {}, (scene, err) => console.error('error:', err));
+//   }, progress => {}, (scene, err) => console.error('error:', err));
+var scene = new BABYLON.Scene(engine);
+var camera = new BABYLON.ArcRotateCamera("camera", 0, 0, 0, BABYLON.Vector3.Zero(), scene);
+scene.render();
+var pos = BABYLON.Vector3.Project(
+              new BABYLON.Vector3(0.5, 0.5, 0.5),
+              BABYLON.Matrix.Identity(),
+              scene.getTransformMatrix(),
+              scene.activeCamera.viewport.toGlobal(
+              engine.getRenderWidth(),
+              engine.getRenderHeight()
+            ));;
+
+            console.log(pos);

BIN
tests/validation/ReferenceImages/gltfBuggyDraco.png


+ 6 - 1
tests/validation/config.json

@@ -18,7 +18,7 @@
       "sceneFolder": "/Scenes/Espilit/",
       "sceneFilename": "espilit.babylon",
       "referenceImage": "Espilit.png"
-    },
+    },    
     {
       "title": "The car",
       "sceneFolder": "/Scenes/TheCar/",
@@ -250,6 +250,11 @@
       "excludeFromAutomaticTesting": true
     },
     {
+      "title": "GLTF Buggy with Draco Mesh Compression",
+      "playgroundId": "#JNW207#1",
+      "referenceImage": "gltfBuggyDraco.png"
+    },
+    {
       "title": "Asset Containers",
       "playgroundId": "#P3U079#19",
       "referenceImage": "assetContainer.png"

+ 1 - 0
tests/validation/index.html

@@ -3,6 +3,7 @@
 <head>
 	<title>BabylonJS - Build validation page</title>
 	<link href="index.css" rel="stylesheet" />
+    <script src="../../dist/preview%20release/draco_decoder.js"></script>
 	<script src="../../Tools/DevLoader/BabylonLoader.js"></script>
 </head>
 <body>

+ 1 - 0
tests/validation/karma.conf.browserstack.js

@@ -14,6 +14,7 @@ module.exports = function (config) {
         frameworks: ['mocha', 'chai', 'sinon'],
 
         files: [
+            './dist/preview release/draco_decoder.js',
             './Tools/DevLoader/BabylonLoader.js',
             './tests/validation/index.css',
             './tests/validation/integration.js',

+ 1 - 0
tests/validation/karma.conf.js

@@ -14,6 +14,7 @@ module.exports = function (config) {
         frameworks: ['mocha', 'chai', 'sinon'],
 
         files: [
+            './dist/preview release/draco_decoder.js',
             './Tools/DevLoader/BabylonLoader.js',
             './tests/validation/index.css',
             './tests/validation/integration.js',

+ 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>