Переглянути джерело

Merge remote-tracking branch 'BabylonJS/master'

MackeyK24 7 роки тому
батько
коміт
2adc537ad3
100 змінених файлів з 33505 додано та 282932 видалено
  1. 12618 11106
      Playground/babylon.d.txt
  2. 2 1
      Playground/index-local.html
  3. 2 1
      Playground/index.html
  4. 56 72
      Tools/Gulp/config.json
  5. 3 3
      Tools/Gulp/gulp-addDtsExport.js
  6. 8 1
      Tools/Gulp/gulp-addModuleExports.js
  7. 8 4
      Tools/Gulp/gulp-validateTypedoc.js
  8. 7 23
      Tools/Gulp/gulpfile.js
  9. 0 0
      Viewer/src/configuration/index.ts
  10. 30 14
      Viewer/src/configuration/loader.ts
  11. 72 9
      Viewer/src/configuration/mappers.ts
  12. 39 14
      Viewer/src/eventManager.ts
  13. 13 0
      Viewer/src/helper.ts
  14. 6 5
      Viewer/src/index.ts
  15. 5 0
      Viewer/src/initializer.ts
  16. 121 3
      Viewer/src/model/modelAnimation.ts
  17. 68 1
      Viewer/src/model/modelLoader.ts
  18. 90 70
      Viewer/src/model/viewerModel.ts
  19. 175 67
      Viewer/src/templateManager.ts
  20. 81 38
      Viewer/src/viewer/defaultViewer.ts
  21. 278 118
      Viewer/src/viewer/viewer.ts
  22. 47 9
      Viewer/src/viewer/viewerManager.ts
  23. 10 3
      Viewer/tsconfig-gulp.json
  24. 11 6
      Viewer/tsconfig.json
  25. 2 1
      Viewer/webpack.config.js
  26. 2 1
      Viewer/webpack.gulp.config.js
  27. 11722 10426
      dist/preview release/babylon.d.ts
  28. 60 60
      dist/preview release/babylon.js
  29. 1867 1201
      dist/preview release/babylon.max.js
  30. 61 61
      dist/preview release/babylon.worker.js
  31. 0 29515
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  32. 0 62
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  33. 0 96733
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  34. 0 30389
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts
  35. 0 96703
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  36. 15 0
      dist/preview release/earcut.license
  37. 1 0
      dist/preview release/earcut.min.js
  38. 1852 1198
      dist/preview release/es6.js
  39. 1 1
      dist/preview release/gltf2Interface/package.json
  40. 0 10
      dist/preview release/gui/babylon.gui.d.ts
  41. 1 10
      dist/preview release/gui/babylon.gui.js
  42. 4 4
      dist/preview release/gui/babylon.gui.min.js
  43. 0 11
      dist/preview release/gui/babylon.gui.module.d.ts
  44. 1 1
      dist/preview release/gui/package.json
  45. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  46. 7 0
      dist/preview release/inspector/babylon.inspector.d.ts
  47. 54 0
      dist/preview release/inspector/babylon.inspector.js
  48. 4 4
      dist/preview release/inspector/babylon.inspector.min.js
  49. 1 1
      dist/preview release/inspector/package.json
  50. 3 8
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  51. 7 21
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  52. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  53. 11 8
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  54. 83 28
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  55. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  56. 12 9
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  57. 89 34
      dist/preview release/loaders/babylon.glTFFileLoader.js
  58. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  59. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  60. 90 34
      dist/preview release/loaders/babylonjs.loaders.js
  61. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  62. 12 11
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  63. 2 2
      dist/preview release/loaders/package.json
  64. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  65. 2 2
      dist/preview release/materialsLibrary/babylon.gradientMaterial.js
  66. 1 1
      dist/preview release/materialsLibrary/babylon.gradientMaterial.min.js
  67. 1 1
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js
  68. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  69. 3 2
      dist/preview release/materialsLibrary/babylonjs.materials.js
  70. 3 3
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  71. 0 1
      dist/preview release/materialsLibrary/babylonjs.materials.module.d.ts
  72. 1 1
      dist/preview release/materialsLibrary/package.json
  73. 1 1
      dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js
  74. 1 1
      dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js
  75. 1 0
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.js
  76. 1 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js
  77. 0 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.module.d.ts
  78. 1 1
      dist/preview release/postProcessesLibrary/package.json
  79. 1 0
      dist/preview release/proceduralTexturesLibrary/babylonjs.proceduralTextures.js
  80. 0 1
      dist/preview release/proceduralTexturesLibrary/babylonjs.proceduralTextures.module.d.ts
  81. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  82. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  83. 1 0
      dist/preview release/serializers/babylonjs.serializers.js
  84. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  85. 0 2
      dist/preview release/serializers/babylonjs.serializers.module.d.ts
  86. 2 2
      dist/preview release/serializers/package.json
  87. 468 2918
      dist/preview release/typedocValidationBaseline.json
  88. 693 57
      dist/preview release/viewer/babylon.viewer.d.ts
  89. 68 68
      dist/preview release/viewer/babylon.viewer.js
  90. 2442 1711
      dist/preview release/viewer/babylon.viewer.max.js
  91. 1 1
      dist/preview release/viewer/package.json
  92. 12 3
      dist/preview release/what's new.md
  93. 0 8
      gui/src/controls/control.ts
  94. 0 2
      gui/src/controls/textBlock.ts
  95. 18 0
      inspector/src/tabs/SceneTab.ts
  96. 23 0
      inspector/src/tools/FullscreenTool.ts
  97. 3 0
      inspector/src/tools/Toolbar.ts
  98. 15 0
      inspector/test/index.js
  99. 8 8
      loaders/src/glTF/1.0/babylon.glTFLoader.ts
  100. 0 0
      loaders/src/glTF/2.0/babylon.glTFLoader.ts

Різницю між файлами не показано, бо вона завелика
+ 12618 - 11106
Playground/babylon.d.txt


+ 2 - 1
Playground/index-local.html

@@ -13,9 +13,10 @@
         <!-- jszip -->
         <script src="js/libs/jszip.min.js"></script>
         <script src="js/libs/fileSaver.js"></script>
-        <!-- Physics -->
+        <!-- Dependencies -->
         <script src="../dist/preview%20release/cannon.js"></script>
         <script src="../dist/preview%20release/Oimo.js"></script>
+        <script src="../dist/preview%20release/earcut.min.js"></script>
         <!--Monaco-->
         <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
         <!-- Babylon.js -->

+ 2 - 1
Playground/index.html

@@ -33,9 +33,10 @@
         <!-- jszip -->
         <script src="js/libs/jszip.min.js"></script>
         <script src="js/libs/fileSaver.js"></script>
-        <!-- Physics -->
+        <!-- Dependencies -->
         <script src="https://preview.babylonjs.com/cannon.js"></script>
         <script src="https://preview.babylonjs.com/Oimo.js"></script>
+        <script src="https://preview.babylonjs.com/earcut.min.js"></script>
         <!--Monaco-->
         <script src="node_modules/monaco-editor/min/vs/loader.js"></script>
         <!-- Babylon.js -->

+ 56 - 72
Tools/Gulp/config.json

@@ -27,6 +27,11 @@
                 "name": "OIMO",
                 "module": "oimo",
                 "optional": true
+            },
+            {
+                "name": "earcut",
+                "module": "earcut",
+                "optional": true
             }
         ]
     },
@@ -74,7 +79,9 @@
             "additionalPostProcess_fxaa",
             "additionalPostProcess_circleOfConfusion",
             "additionalPostProcess_depthOfFieldMerge",
+            "additionalPostProcess_bloomMerge",
             "additionalPostProcess_depthOfFieldEffect",
+            "additionalPostProcess_bloomEffect",
             "additionalPostProcess_imageProcessing",
             "bones",
             "hdr",
@@ -110,75 +117,6 @@
             "meshBuilder",
             "freeCamera",
             "hemisphericLight"
-        ],
-        "minimalGLTFViewer": [
-            "pbrMaterial",
-            "freeCamera",
-            "arcRotateCamera",
-            "hemisphericLight",
-            "pointLight",
-            "directionalLight",
-            "spotLight",
-            "animations",
-            "actions",
-            "sprites",
-            "picking",
-            "collisions",
-            "particles",
-            "solidParticles",
-            "additionalMeshes",
-            "meshBuilder",
-            "meshCompression",
-            "audio",
-            "additionalTextures",
-            "shadows",
-            "loader",
-            "userData",
-            "offline",
-            "fresnel",
-            "multiMaterial",
-            "touchCamera",
-            "procedural",
-            "gamepad",
-            "additionalCameras",
-            "postProcesses",
-            "renderingPipeline",
-            "additionalRenderingPipeline",
-            "defaultRenderingPipeline",
-            "depthRenderer",
-            "geometryBufferRenderer",
-            "additionalPostProcesses",
-            "additionalPostProcess_blur",
-            "additionalPostProcess_fxaa",
-            "additionalPostProcess_imageProcessing",
-            "bones",
-            "hdr",
-            "polygonMesh",
-            "csg",
-            "lensFlares",
-            "physics",
-            "textureFormats",
-            "debug",
-            "morphTargets",
-            "octrees",
-            "vr",
-            "virtualJoystick",
-            "optimizations",
-            "highlights",
-            "assetsManager",
-            "serialization",
-            "probes",
-            "layer",
-            "textureTools",
-            "cameraBehaviors",
-            "instrumentation",
-            "backgroundMaterial",
-            "environmentHelper",
-            "materialsLibrary/babylon.gridMaterial.js",
-            "loaders/babylon.glTFFileLoader.js"
-        ],
-        "distributed": [
-            "minimalGLTFViewer"
         ]
     },
     "workloads": {
@@ -803,6 +741,17 @@
                 "chromaticAberration.fragment"
             ]
         },
+        "additionalPostProcess_grain": {
+            "files": [
+                "../../src/PostProcess/babylon.grainPostProcess.js"
+            ],
+            "dependUpon": [
+                "postProcesses"
+            ],
+            "shaders": [
+                "grain.fragment"
+            ]
+        },
         "additionalPostProcess_depthOfFieldMerge": {
             "files": [
                 "../../src/PostProcess/babylon.depthOfFieldMergePostProcess.js"
@@ -814,6 +763,17 @@
                 "depthOfFieldMerge.fragment"
             ]
         },
+        "additionalPostProcess_bloomMerge": {
+            "files": [
+                "../../src/PostProcess/babylon.bloomMergePostProcess.js"
+            ],
+            "dependUpon": [
+                "postProcesses"
+            ],
+            "shaders": [
+                "bloomMerge.fragment"
+            ]
+        },
         "additionalPostProcess_depthOfFieldEffect": {
             "files": [
                 "../../src/PostProcess/babylon.depthOfFieldEffect.js"
@@ -824,6 +784,16 @@
                 "additionalPostProcess_circleOfConfusion"
             ]
         },
+        "additionalPostProcess_bloomEffect": {
+            "files": [
+                "../../src/PostProcess/babylon.bloomEffect.js"
+            ],
+            "dependUpon": [
+                "additionalPostProcess_blur",
+                "additionalPostProcess_bloomMerge",
+                "additionalPostProcess_extractHighlights"
+            ]
+        },
         "additionalPostProcess_fxaa": {
             "files": [
                 "../../src/PostProcess/babylon.fxaaPostProcess.js"
@@ -847,6 +817,17 @@
                 "highlights.fragment"
             ]
         },
+        "additionalPostProcess_extractHighlights": {
+            "files": [
+                "../../src/PostProcess/babylon.extractHighlightsPostProcess.js"
+            ],
+            "dependUpon": [
+                "postProcesses"
+            ],
+            "shaders": [
+                "extractHighlights.fragment"
+            ]
+        },
         "additionalPostProcess_imageProcessing": {
             "files": [
                 "../../src/PostProcess/babylon.imageProcessingPostProcess.js"
@@ -866,6 +847,7 @@
                 "../../src/PostProcess/babylon.convolutionPostProcess.js",
                 "../../src/PostProcess/babylon.sharpenPostProcess.js",
                 "../../src/PostProcess/babylon.chromaticAberrationPostProcess.js",
+                "../../src/PostProcess/babylon.grainPostProcess.js",
                 "../../src/PostProcess/babylon.filterPostProcess.js",
                 "../../src/PostProcess/babylon.fxaaPostProcess.js",
                 "../../src/PostProcess/babylon.volumetricLightScatteringPostProcess.js",
@@ -873,6 +855,7 @@
                 "../../src/PostProcess/babylon.tonemapPostProcess.js",
                 "../../src/PostProcess/babylon.displayPassPostProcess.js",
                 "../../src/PostProcess/babylon.highlightsPostProcess.js",
+                "../../src/PostProcess/babylon.extractHighlightsPostProcess.js",
                 "../../src/PostProcess/babylon.imageProcessingPostProcess.js"
             ],
             "dependUpon": [
@@ -919,7 +902,6 @@
                 "ssao.fragment",
                 "ssao2.fragment",
                 "ssaoCombine.fragment",
-                "chromaticAberration.fragment",
                 "lensHighlights.fragment",
                 "depthOfField.fragment",
                 "standard.fragment"
@@ -933,8 +915,10 @@
                 "renderingPipeline",
                 "additionalPostProcess_fxaa",
                 "additionalPostProcess_chromaticAberration",
+                "additionalPostProcess_grain",
                 "additionalPostProcess_sharpen",
-                "additionalPostProcess_depthOfFieldEffect"
+                "additionalPostProcess_depthOfFieldEffect",
+                "additionalPostProcess_bloomEffect"
             ]
         },
         "bones": {
@@ -970,7 +954,6 @@
         },
         "polygonMesh": {
             "files": [
-                "../../src/Tools/babylon.earcut.js",
                 "../../src/Mesh/babylon.polygonMesh.js"
             ],
             "dependUpon": [
@@ -1712,6 +1695,7 @@
                     "../../inspector/src/tools/LabelTool.ts",
                     "../../inspector/src/tools/Toolbar.ts",
                     "../../inspector/src/tools/DisposeTool.ts",
+                    "../../inspector/src/tools/FullscreenTool.ts",
                     "../../inspector/src/tree/TreeItem.ts",
                     "../../inspector/src/treetools/AbstractTreeTool.ts",
                     "../../inspector/src/treetools/BoundingBox.ts",

+ 3 - 3
Tools/Gulp/gulp-addDtsExport.js

@@ -11,15 +11,15 @@ module.exports = function (varName, moduleName, subModule, extendsRoot, dependen
 
         let referenceText = '';
         if (subModule) {
-            referenceText = '/// <reference types="babylonjs"/>\n';
+            // referenceText = '/// <reference types="babylonjs"/>\n';
         }
 
         if (dependencies) {
             referenceText = '';
             dependencies.forEach(element => {
                 // was "babylonjs/${element}""
-                referenceText += `/// <reference types="${element}"/>
-`;
+                /*referenceText += `/// <reference types="${element}"/>
+`;*/
             });
         }
 

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

@@ -74,7 +74,14 @@ ${afterInitText}
 ${String(file.contents)}
     ${varName.name === 'BABYLON' || varName.name === 'INSPECTOR' ? `
 var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
-globalObject["${varName.name}"] = ${varName.name}` : ''}
+globalObject["${varName.name}"] = ${varName.name};
+//backwards compatibility
+if(typeof earcut !== 'undefined') {
+    globalObject["Earcut"] = {
+        earcut: earcut
+    };
+}` : ''}
+
     return ${base}${(config.subModule && !config.extendsRoot) ? '.' + varName.name : ''};
 });
 `;

+ 8 - 4
Tools/Gulp/gulp-validateTypedoc.js

@@ -319,7 +319,7 @@ Validate.prototype.validateTypedocNamespaces = function (namespaces) {
                 this.validateNaming(containerNode, childNode);
 
                 //if comment contains @ignore then skip validation completely
-                if (Validate.hasTag(childNode, 'ignore')) continue;                
+                if (Validate.hasTag(childNode, 'ignore')) continue;
 
                 if (isPublic) {
                     tags = this.validateTags(childNode);
@@ -413,7 +413,7 @@ Validate.prototype.validateTags = function(node) {
         if (tags) {
             for (var i = 0; i < tags.length; i++) {
                 var tag = tags[i];
-                var validTags = ["constructor", "throw", "type", "deprecated", "example", "examples", "remark", "see", "remarks"]
+                var validTags = ["constructor", "throw", "type", "deprecated", "example", "examples", "remark", "see", "remarks", "ignorenaming"]
                 if (validTags.indexOf(tag.tag) === -1) {
                     errorTags.push(tag.tag);
                 }
@@ -449,10 +449,9 @@ Validate.prototype.validateComment = function(node) {
     if (node.overwrites) {
         return true;
     }
-    
 
+    // Check comments.
     if (node.comment) {
-
         if (node.comment.text || node.comment.shortText) {
             return true;
         }
@@ -500,6 +499,11 @@ Validate.prototype.validateNaming = function(parent, node) {
         return;
     }
 
+    // Ignore Naming Tag Check
+    if (Validate.hasTag(node, 'ignoreNaming')) {
+        return;
+    }
+
     if (node.inheritedFrom) {
         return;
     }

+ 7 - 23
Tools/Gulp/gulpfile.js

@@ -532,21 +532,6 @@ gulp.task("typescript-libraries", config.modules, function () {
 });
 
 /**
- * Dynamic custom configurations.
- */
-config.buildConfigurations.distributed.map(function (customConfiguration) {
-    gulp.task(customConfiguration, function (cb) {
-        config.build.currentConfig = customConfiguration;
-        config.build.outputDirectory = config.build.outputCustomConfigurationsDirectory + "/" + customConfiguration;
-        runSequence("typescript-compile", "build", cb);
-    });
-});
-
-gulp.task("typescript-customConfigurations", function (cb) {
-    runSequence(config.buildConfigurations.distributed, cb);
-});
-
-/**
  * Custom build with full path file control; used by profile.html
  */
 gulp.task("build-custom", function (cb) {
@@ -557,7 +542,7 @@ gulp.task("build-custom", function (cb) {
  * Do it all.
  */
 gulp.task("typescript-all", function (cb) {
-    runSequence("typescript", "typescript-libraries", "typescript-customConfigurations", cb);
+    runSequence("typescript", "typescript-libraries", cb);
 });
 
 /**
@@ -604,13 +589,12 @@ gulp.task("watch", ["srcTscWatch"], function () {
 
 gulp.task("intellisense", function () {
     gulp.src(config.build.intellisenseSources)
-        .pipe(concat(config.build.intellisenseFile))
-        .pipe(replace(/^\s*_.*?$/gm, ""))
-        .pipe(replace(/^\s*private .*?$/gm, ""))
-        .pipe(replace(/^\s*public _.*?$/gm, ""))
-        .pipe(replace(/^\s*protected .*?$/gm, ""))
-        .pipe(replace(/^\s*public static _.*?$/gm, ""))
-        .pipe(replace(/^\s*static _.*?$/gm, ""))
+        .pipe(concat(config.build.intellisenseFile))    
+        .pipe(replace(/^\s+_.*?;/gm, ""))
+        .pipe(replace(/^\s+_[\S\s]*?}/gm, ""))
+        .pipe(replace(/^\s*readonly _/gm, "protected readonly _"))
+        .pipe(replace(/^\s*static _/gm, "private static _"))
+        .pipe(replace(/^\s*abstract _/gm, ""))
         .pipe(gulp.dest(config.build.playgroundDirectory));
 });
 

+ 0 - 0
Viewer/src/configuration/index.ts


+ 30 - 14
Viewer/src/configuration/loader.ts

@@ -5,17 +5,30 @@ import { getConfigurationType } from './types';
 import * as deepmerge from '../../assets/deepmerge.min.js';
 import { Tools, IFileRequest } from 'babylonjs';
 
+/**
+ * The configuration loader will load the configuration object from any source and will use the defined mapper to
+ * parse the object and return a conform ViewerConfiguration.
+ * It is a private member of the scene.
+ */
 export class ConfigurationLoader {
 
-    private configurationCache: { [url: string]: any };
+    private _configurationCache: { [url: string]: any };
 
-    private loadRequests: Array<IFileRequest>;
+    private _loadRequests: Array<IFileRequest>;
 
     constructor(private _enableCache: boolean = false) {
-        this.configurationCache = {};
-        this.loadRequests = [];
+        this._configurationCache = {};
+        this._loadRequests = [];
     }
 
+    /**
+     * load a configuration object that is defined in the initial configuration provided.
+     * The viewer configuration can extend different types of configuration objects and have an extra configuration defined.
+     * 
+     * @param initConfig the initial configuration that has the definitions of further configuration to load.
+     * @param callback an optional callback that will be called sync, if noconfiguration needs to be loaded or configuration is payload-only
+     * @returns A promise that delivers the extended viewer configuration, when done.
+     */
     public loadConfiguration(initConfig: ViewerConfiguration = {}, callback?: (config: ViewerConfiguration) => void): Promise<ViewerConfiguration> {
 
         let loadedConfig: ViewerConfiguration = deepmerge({}, initConfig);
@@ -47,7 +60,7 @@ export class ConfigurationLoader {
                         }
                         mapperType = type || mapperType;
                     }
-                    return this.loadFile(url);
+                    return this._loadFile(url);
                 } else {
                     if (typeof loadedConfig.configuration === "object") {
                         mapperType = loadedConfig.configuration.mapper || mapperType;
@@ -69,33 +82,36 @@ export class ConfigurationLoader {
         }
     }
 
+    /**
+     * Dispose the configuration loader. This will cancel file requests, if active.
+     */
     public dispose() {
-        this.loadRequests.forEach(request => {
+        this._loadRequests.forEach(request => {
             request.abort();
         });
-        this.loadRequests.length = 0;
+        this._loadRequests.length = 0;
     }
 
-    private loadFile(url: string): Promise<any> {
-        let cacheReference = this.configurationCache;
+    private _loadFile(url: string): Promise<any> {
+        let cacheReference = this._configurationCache;
         if (this._enableCache && cacheReference[url]) {
             return Promise.resolve(cacheReference[url]);
         }
 
         return new Promise((resolve, reject) => {
             let fileRequest = Tools.LoadFile(url, (result) => {
-                let idx = this.loadRequests.indexOf(fileRequest);
+                let idx = this._loadRequests.indexOf(fileRequest);
                 if (idx !== -1)
-                    this.loadRequests.splice(idx, 1);
+                    this._loadRequests.splice(idx, 1);
                 if (this._enableCache) cacheReference[url] = result;
                 resolve(result);
             }, undefined, undefined, false, (request, error: any) => {
-                let idx = this.loadRequests.indexOf(fileRequest);
+                let idx = this._loadRequests.indexOf(fileRequest);
                 if (idx !== -1)
-                    this.loadRequests.splice(idx, 1);
+                    this._loadRequests.splice(idx, 1);
                 reject(error);
             });
-            this.loadRequests.push(fileRequest);
+            this._loadRequests.push(fileRequest);
         });
     }
 

+ 72 - 9
Viewer/src/configuration/mappers.ts

@@ -3,12 +3,36 @@ import { ViewerConfiguration } from './configuration';
 
 import { kebabToCamel } from '../helper';
 
+/**
+ * This is the mapper's interface. Implement this function to create your own mapper and register it at the mapper manager
+ */
 export interface IMapper {
     map(rawSource: any): ViewerConfiguration;
 }
 
+/**
+ * This is a simple HTML mapper. 
+ * This mapper parses a single HTML element and returns the configuration from its attributes.
+ * it parses numbers and boolean values to the corresponding variable types.
+ * The following HTML element: 
+ *  <div test="1" random-flag="true" a.string.object="test"> will result in the following configuration:
+ * 
+ *  {
+ *      test: 1, //a number!
+ *      randomFlag: boolean, //camelCase and boolean
+ *      a: {
+ *          string: {
+ *              object: "test" //dot-separated object levels
+ *          }
+ *      }
+ *  }
+ */
 class HTMLMapper implements IMapper {
 
+    /**
+     * Map a specific element and get configuration from it
+     * @param element the HTML element to analyze. 
+     */
     map(element: HTMLElement): ViewerConfiguration {
 
         let config = {};
@@ -46,15 +70,27 @@ class HTMLMapper implements IMapper {
     }
 }
 
+/**
+ * A simple string-to-JSON mapper.
+ * This is the main mapper, used to analyze downloaded JSON-Configuration or JSON payload
+ */
 class JSONMapper implements IMapper {
-    map(rawSource: any) {
+    map(rawSource: string) {
         return JSON.parse(rawSource);
     }
 }
 
-// TODO - Dom configuration mapper.
+/**
+ * The DOM Mapper will traverse an entire DOM Tree and will load the configuration from the
+ * DOM elements and attributes.
+ */
 class DOMMapper implements IMapper {
 
+    /**
+     * The mapping function that will convert HTML data to a viewer configuration object
+     * @param baseElement the baseElement from which to start traversing
+     * @returns a ViewerCOnfiguration object from the provided HTML Element
+     */
     map(baseElement: HTMLElement): ViewerConfiguration {
         let htmlMapper = new HTMLMapper();
         let config = htmlMapper.map(baseElement);
@@ -64,6 +100,7 @@ class DOMMapper implements IMapper {
             if (children.length) {
                 for (let i = 0; i < children.length; ++i) {
                     let item = <HTMLElement>children.item(i);
+                    // use the HTML Mapper to read configuration from a single element
                     let configMapped = htmlMapper.map(item);
                     let key = kebabToCamel(item.nodeName.toLowerCase());
                     if (item.attributes.getNamedItem('array') && item.attributes.getNamedItem('array').nodeValue === 'true') {
@@ -72,7 +109,7 @@ class DOMMapper implements IMapper {
                         if (element.attributes.getNamedItem('array') && element.attributes.getNamedItem('array').nodeValue === 'true') {
                             partConfig.push(configMapped)
                         } else if (partConfig[key]) {
-                            //exists already! problem... probably an array
+                            //exists already! probably an array
                             element.setAttribute('array', 'true');
                             let oldItem = partConfig[key];
                             partConfig = [oldItem, configMapped]
@@ -94,34 +131,60 @@ class DOMMapper implements IMapper {
 
 }
 
+/**
+ * The MapperManager manages the different implemented mappers.
+ * It allows the user to register new mappers as well and use them to parse their own configuration data
+ */
 export class MapperManager {
 
-    private mappers: { [key: string]: IMapper };
+    private _mappers: { [key: string]: IMapper };
+    /**
+     * The default mapper is the JSON mapper.
+     */
     public static DefaultMapper = 'json';
 
     constructor() {
-        this.mappers = {
+        this._mappers = {
             "html": new HTMLMapper(),
             "json": new JSONMapper(),
             "dom": new DOMMapper()
         }
     }
 
+    /**
+     * Get a specific configuration mapper.
+     * 
+     * @param type the name of the mapper to load
+     */
     public getMapper(type: string) {
-        if (!this.mappers[type]) {
+        if (!this._mappers[type]) {
             Tools.Error("No mapper defined for " + type);
         }
-        return this.mappers[type] || this.mappers[MapperManager.DefaultMapper];
+        return this._mappers[type] || this._mappers[MapperManager.DefaultMapper];
     }
 
+    /**
+     * Use this functio to register your own configuration mapper.
+     * After a mapper is registered, it can be used to parse the specific type fo configuration to the standard ViewerConfiguration.
+     * @param type the name of the mapper. This will be used to define the configuration type and/or to get the mapper
+     * @param mapper The implemented mapper 
+     */
     public registerMapper(type: string, mapper: IMapper) {
-        this.mappers[type] = mapper;
+        this._mappers[type] = mapper;
     }
 
+    /**
+     * Dispose the mapper manager and all of its mappers.
+     */
     public dispose() {
-        this.mappers = {};
+        this._mappers = {};
     }
 
 }
 
+/**
+ * mapperManager is a singleton of the type MapperManager.
+ * The mapperManager can be disposed directly with calling mapperManager.dispose()
+ * or indirectly with using BabylonViewer.disposeAll()
+ */
 export let mapperManager = new MapperManager();

+ 39 - 14
Viewer/src/eventManager.ts

@@ -1,44 +1,69 @@
 import { EventCallback, TemplateManager } from "./templateManager";
 
 
+/**
+ * The EventManager is in charge of registering user interctions with the viewer.
+ * It is used in the TemplateManager
+ */
 export class EventManager {
 
-    private callbacksContainer: { [key: string]: Array<{ eventType?: string, selector?: string, callback: (eventData: EventCallback) => void }> }
+    private _callbacksContainer: { [key: string]: Array<{ eventType?: string, selector?: string, callback: (eventData: EventCallback) => void }> }
 
-    constructor(private templateManager: TemplateManager) {
-        this.callbacksContainer = {};
-        this.templateManager.onEventTriggered.add(eventData => {
-            this.eventTriggered(eventData);
+    constructor(private _templateManager: TemplateManager) {
+        this._callbacksContainer = {};
+        this._templateManager.onEventTriggered.add(eventData => {
+            this._eventTriggered(eventData);
         })
     }
 
+    /**
+     * Register a new callback to a specific template.
+     * The best example for the usage can be found in the DefaultViewer
+     * 
+     * @param templateName the templateName to register the event to
+     * @param callback The callback to be executed
+     * @param eventType the type of event to register
+     * @param selector an optional selector. if not defined the parent object in the template will be selected
+     */
     public registerCallback(templateName: string, callback: (eventData: EventCallback) => void, eventType?: string, selector?: string) {
-        if (!this.callbacksContainer[templateName]) {
-            this.callbacksContainer[templateName] = [];
+        if (!this._callbacksContainer[templateName]) {
+            this._callbacksContainer[templateName] = [];
         }
-        this.callbacksContainer[templateName].push({
+        this._callbacksContainer[templateName].push({
             eventType: eventType,
             callback: callback
         });
     }
 
-    public unregisterCallback(templateName: string, callback?: (eventData: EventCallback) => void, eventType?: string, selector?: string) {
-        let callbackDefs = this.callbacksContainer[templateName] || [];
-        this.callbacksContainer[templateName] = callbackDefs.filter(callbackDef => (!callbackDef.eventType || callbackDef.eventType === eventType) && (!callbackDef.selector || callbackDef.selector === selector));
+    /**
+     * This will remove a registered event from the defined template.
+     * Each one of the variables apart from the template name are optional, but one must be provided.
+     * 
+     * @param templateName the templateName
+     * @param callback the callback to remove (optional)
+     * @param eventType the event type to remove (optional)
+     * @param selector the selector from which to remove the event (optional)
+     */
+    public unregisterCallback(templateName: string, callback: (eventData: EventCallback) => void, eventType?: string, selector?: string) {
+        let callbackDefs = this._callbacksContainer[templateName] || [];
+        this._callbacksContainer[templateName] = callbackDefs.filter(callbackDef => (!callbackDef.eventType || callbackDef.eventType === eventType) && (!callbackDef.selector || callbackDef.selector === selector));
     }
 
-    private eventTriggered(data: EventCallback) {
+    private _eventTriggered(data: EventCallback) {
         let templateName = data.template.name;
         let eventType = data.event.type;
         let selector = data.selector;
 
-        let callbackDefs = this.callbacksContainer[templateName] || [];
+        let callbackDefs = this._callbacksContainer[templateName] || [];
         callbackDefs.filter(callbackDef => (!callbackDef.eventType || callbackDef.eventType === eventType) && (!callbackDef.selector || callbackDef.selector === selector)).forEach(callbackDef => {
             callbackDef.callback(data);
         });
     }
 
+    /**
+     * Dispose the event manager
+     */
     public dispose() {
-        this.callbacksContainer = {};
+        this._callbacksContainer = {};
     }
 }

+ 13 - 0
Viewer/src/helper.ts

@@ -1,3 +1,8 @@
+/**
+ * Is the provided string a URL?
+ * 
+ * @param urlToCheck the url to inspect
+ */
 export function isUrl(urlToCheck: string): boolean {
     if (urlToCheck.indexOf('http') === 0 || urlToCheck.indexOf('/') === 0 || urlToCheck.indexOf('./') === 0 || urlToCheck.indexOf('../') === 0) {
         return true;
@@ -5,11 +10,19 @@ export function isUrl(urlToCheck: string): boolean {
     return false;
 }
 
+/**
+ * Convert a string from kebab-case to camelCase
+ * @param s string to convert
+ */
 export function kebabToCamel(s) {
     return s.replace(/(\-\w)/g, function (m) { return m[1].toUpperCase(); });
 }
 
 //https://gist.github.com/youssman/745578062609e8acac9f
+/**
+ * Convert a string from camelCase to kebab-case
+ * @param str string to convert
+ */
 export function camelToKebab(str) {
     return !str ? null : str.replace(/([A-Z])/g, function (g) { return '-' + g[0].toLowerCase() });
 }

+ 6 - 5
Viewer/src/index.ts

@@ -1,13 +1,11 @@
-/// <reference path="../../dist/preview release/babylon.d.ts"/>
 /// <reference path="../../dist/babylon.glTF2Interface.d.ts"/>
-/// <reference path="../../dist/preview release/loaders/babylon.glTFFileLoader.d.ts"/>
-
 import { mapperManager } from './configuration/mappers';
 import { viewerManager } from './viewer/viewerManager';
 import { DefaultViewer } from './viewer/defaultViewer';
 import { AbstractViewer } from './viewer/viewer';
 import { ModelLoader } from './model/modelLoader';
-import { ViewerModel } from './model/viewerModel';
+import { ViewerModel, ModelState } from './model/viewerModel';
+import { AnimationPlayMode, AnimationState } from './model/modelAnimation';
 
 /**
  * BabylonJS Viewer
@@ -35,10 +33,13 @@ function init(event) {
     InitTags();
 }
 
+/**
+ * Dispose all viewers currently registered
+ */
 function disposeAll() {
     viewerManager.dispose();
     mapperManager.dispose();
 }
 
 // public API for initialization
-export { InitTags, DefaultViewer, AbstractViewer, viewerManager, mapperManager, disposeAll, ModelLoader, ViewerModel };
+export { InitTags, DefaultViewer, AbstractViewer, viewerManager, mapperManager, disposeAll, ModelLoader, ViewerModel, AnimationPlayMode, AnimationState, ModelState };

+ 5 - 0
Viewer/src/initializer.ts

@@ -1,6 +1,11 @@
 import { DefaultViewer } from './viewer/defaultViewer';
 import { mapperManager } from './configuration/mappers';
 
+/**
+ * Select all HTML tags on the page that match the selector and initialize a viewer
+ * 
+ * @param selector the selector to initialize the viewer on (default is 'babylon')
+ */
 export function InitTags(selector: string = 'babylon') {
     let elements = document.querySelectorAll(selector);
     for (let i = 0; i < elements.length; ++i) {

+ 121 - 3
Viewer/src/model/modelAnimation.ts

@@ -1,10 +1,16 @@
 import { AnimationGroup, Animatable, Skeleton } from "babylonjs";
 
+/**
+ * Animation play mode enum - is the animation looping or playing once
+ */
 export enum AnimationPlayMode {
     ONCE,
     LOOP
 }
 
+/**
+ * An enum representing the current state of an animation object
+ */
 export enum AnimationState {
     INIT,
     PLAYING,
@@ -13,28 +19,89 @@ export enum AnimationState {
     ENDED
 }
 
+/**
+ * This interface can be implemented to define new types of ModelAnimation objects.
+ */
 export interface IModelAnimation {
+    /**
+     * Current animation state (playing, stopped etc')
+     */
     readonly state: AnimationState;
+    /**
+     * the name of the animation
+     */
     readonly name: string;
+    /**
+     * Get the max numbers of frame available in the animation group
+     * 
+     * In correlation to an arry, this would be ".length"
+     */
     readonly frames: number;
+    /**
+     * Get the current frame playing right now. 
+     * This can be used to poll the frame currently playing (and, for exmaple, display a progress bar with the data)
+     * 
+     * In correlation to an array, this would be the current index
+     */
     readonly currentFrame: number;
+    /**
+     * Animation's FPS value
+     */
     readonly fps: number;
+    /**
+     * Get or set the animation's speed ration (Frame-to-fps)
+     */
     speedRatio: number;
+    /**
+     * Gets or sets the aimation's play mode.
+     */
     playMode: AnimationPlayMode;
+    /**
+     * Start the animation
+     */
     start();
+    /**
+     * Stop the animation.
+     * This will fail silently if the animation group is already stopped.
+     */
     stop();
+    /**
+     * Pause the animation
+     * This will fail silently if the animation is not currently playing
+     */
     pause();
+    /**
+     * Reset this animation
+     */
     reset();
+    /**
+     * Restart the animation
+     */
     restart();
+    /**
+     * Go to a specific 
+     * @param frameNumber the frame number to go to
+     */
     goToFrame(frameNumber: number);
+    /**
+     * Dispose this animation
+     */
     dispose();
 }
 
+/**
+ * The GroupModelAnimation is an implementation of the IModelAnimation interface using BABYLON's
+ * native GroupAnimation class.
+ */
 export class GroupModelAnimation implements IModelAnimation {
 
     private _playMode: AnimationPlayMode;
     private _state: AnimationState;
 
+    /**
+     * Create a new GroupModelAnimation object using an AnimationGroup object
+     * @param _animationGroup The aniamtion group to base the class on
+     */
     constructor(private _animationGroup: AnimationGroup) {
         this._state = AnimationState.INIT;
         this._playMode = AnimationPlayMode.LOOP;
@@ -42,31 +109,42 @@ export class GroupModelAnimation implements IModelAnimation {
         this._animationGroup.onAnimationEndObservable.add(() => {
             this.stop();
             this._state = AnimationState.ENDED;
-        })
+        });
     }
 
+    /**
+     * Get the animation's name
+     */
     public get name() {
         return this._animationGroup.name;
     }
 
+    /**
+     * Get the current animation's state
+     */
     public get state() {
         return this._state;
     }
 
     /**
-     * Gets or sets the speed ratio to use for all animations
+     * Gets the speed ratio to use for all animations
      */
     public get speedRatio(): number {
         return this._animationGroup.speedRatio;
     }
 
     /**
-     * Gets or sets the speed ratio to use for all animations
+     * Sets the speed ratio to use for all animations
      */
     public set speedRatio(value: number) {
         this._animationGroup.speedRatio = value;
     }
 
+    /**
+     * Get the max numbers of frame available in the animation group
+     * 
+     * In correlation to an arry, this would be ".length"
+     */
     public get frames(): number {
         let animationFrames = this._animationGroup.targetedAnimations.map(ta => {
             let keys = ta.animation.getKeys();
@@ -75,6 +153,12 @@ export class GroupModelAnimation implements IModelAnimation {
         return Math.max.apply(null, animationFrames);
     }
 
+    /**
+     * Get the current frame playing right now. 
+     * This can be used to poll the frame currently playing (and, for exmaple, display a progress bar with the data)
+     * 
+     * In correlation to an array, this would be the current index
+     */
     public get currentFrame(): number {
         // get the first currentFrame found
         for (let i = 0; i < this._animationGroup.animatables.length; ++i) {
@@ -92,6 +176,9 @@ export class GroupModelAnimation implements IModelAnimation {
         return 0;
     }
 
+    /**
+     * Get the FPS value of this animation
+     */
     public get fps(): number {
         // get the first currentFrame found
         for (let i = 0; i < this._animationGroup.animatables.length; ++i) {
@@ -109,10 +196,18 @@ export class GroupModelAnimation implements IModelAnimation {
         return 0;
     }
 
+    /**
+     * What is the animation'S play mode (looping or played once)
+     */
     public get playMode(): AnimationPlayMode {
         return this._playMode;
     }
 
+    /**
+     * Set the play mode.
+     * If the animation is played, it will continue playing at least once more, depending on the new play mode set.
+     * If the animation is not set, the will be initialized and will wait for the user to start playing it.
+     */
     public set playMode(value: AnimationPlayMode) {
         if (value === this._playMode) {
             return;
@@ -128,14 +223,24 @@ export class GroupModelAnimation implements IModelAnimation {
         }
     }
 
+    /**
+     * Reset the animation group
+     */
     reset() {
         this._animationGroup.reset();
     }
 
+    /**
+     * Restart the animation group
+     */
     restart() {
         this._animationGroup.restart();
     }
 
+    /**
+     * 
+     * @param frameNumber Go to a specific frame in the animation
+     */
     goToFrame(frameNumber: number) {
         // this._animationGroup.goToFrame(frameNumber);
         this._animationGroup['_animatables'].forEach(a => {
@@ -143,6 +248,9 @@ export class GroupModelAnimation implements IModelAnimation {
         })
     }
 
+    /**
+     * Start playing the animation.
+     */
     public start() {
         this._animationGroup.start(this.playMode === AnimationPlayMode.LOOP, this.speedRatio);
         if (this._animationGroup.isStarted) {
@@ -150,11 +258,18 @@ export class GroupModelAnimation implements IModelAnimation {
         }
     }
 
+    /**
+     * Pause the animation
+     */
     pause() {
         this._animationGroup.pause();
         this._state = AnimationState.PAUSED;
     }
 
+    /**
+     * Stop the animation.
+     * This will fail silently if the animation group is already stopped.
+     */
     public stop() {
         this._animationGroup.stop();
         if (!this._animationGroup.isStarted) {
@@ -162,6 +277,9 @@ export class GroupModelAnimation implements IModelAnimation {
         }
     }
 
+    /**
+     * Dispose this animation object.
+     */
     public dispose() {
         this._animationGroup.dispose();
     }

+ 68 - 1
Viewer/src/model/modelLoader.ts

@@ -3,6 +3,12 @@ import { ISceneLoaderPlugin, ISceneLoaderPluginAsync, Tools, SceneLoader, Tags,
 import { IModelConfiguration } from "../configuration/configuration";
 import { ViewerModel, ModelState } from "./viewerModel";
 
+/**
+ * An instance of the class is in charge of loading the model correctly.
+ * This class will continously be expended with tasks required from the specific loaders Babylon has.
+ * 
+ * A Model loader is unique per (Abstract)Viewer. It is being generated by the viewer
+ */
 export class ModelLoader {
 
     private _loadId: number;
@@ -10,14 +16,59 @@ export class ModelLoader {
 
     private _loaders: Array<ISceneLoaderPlugin | ISceneLoaderPluginAsync>;
 
+    /**
+     * Create a new Model loader
+     * @param _viewer the viewer using this model loader
+     */
     constructor(private _viewer: AbstractViewer) {
         this._loaders = [];
         this._loadId = 0;
     }
 
+    /**
+     * Load a model using predefined configuration
+     * @param modelConfiguration the modelConfiguration to use to load the model
+     */
     public load(modelConfiguration: IModelConfiguration): ViewerModel {
 
-        const model = new ViewerModel(this._viewer.scene, modelConfiguration);
+        const model = new ViewerModel(this._viewer, modelConfiguration);
+
+        if (!modelConfiguration.url) {
+            model.state = ModelState.ERROR;
+            Tools.Error("No URL provided");
+            return model;
+        }
+
+        let filename = Tools.GetFilename(modelConfiguration.url) || modelConfiguration.url;
+        let base = modelConfiguration.root || Tools.GetFolderPath(modelConfiguration.url);
+        let plugin = modelConfiguration.loader;
+
+        model.loader = SceneLoader.ImportMesh(undefined, base, filename, this._viewer.scene, (meshes, particleSystems, skeletons, animationGroups) => {
+            meshes.forEach(mesh => {
+                Tags.AddTagsTo(mesh, "viewerMesh");
+            });
+            model.meshes = meshes;
+            model.particleSystems = particleSystems;
+            model.skeletons = skeletons;
+
+            for (const animationGroup of animationGroups) {
+                model.addAnimationGroup(animationGroup);
+            }
+
+            model.initAnimations();
+            model.onLoadedObservable.notifyObserversWithPromise(model);
+        }, (progressEvent) => {
+            model.onLoadProgressObservable.notifyObserversWithPromise(progressEvent);
+        }, (e, m, exception) => {
+            model.state = ModelState.ERROR;
+            Tools.Error("Load Error: There was an error loading the model. " + m);
+            model.onLoadErrorObservable.notifyObserversWithPromise({ message: m, exception: exception });
+        }, plugin)!;
+
+        if (model.loader.name === "gltf") {
+            let gltfLoader = (<GLTFFileLoader>model.loader);
+            gltfLoader.animationStartMode = BABYLON.GLTFLoaderAnimationStartMode.NONE;
+        }
 
         model.loadId = this._loadId++;
         this._loaders.push(model.loader);
@@ -25,6 +76,22 @@ export class ModelLoader {
         return model;
     }
 
+    public cancelLoad(model: ViewerModel) {
+        const loader = model.loader || this._loaders[model.loadId];
+        // ATM only available in the GLTF Loader
+        if (loader && loader.name === "gltf") {
+            let gltfLoader = (<GLTFFileLoader>loader);
+            gltfLoader.dispose();
+            model.state = ModelState.CANCELED;
+        } else {
+            Tools.Warn("This type of loader cannot cancel the request");
+        }
+    }
+
+    /**
+     * dispose the model loader.
+     * If loaders are registered and are in the middle of loading, they will be disposed and the request(s) will be cancelled.
+     */
     public dispose() {
         this._loaders.forEach(loader => {
             if (loader.name === "gltf") {

+ 90 - 70
Viewer/src/model/viewerModel.ts

@@ -3,6 +3,8 @@ import { IModelConfiguration } from "../configuration/configuration";
 import { IModelAnimation, GroupModelAnimation, AnimationPlayMode } from "./modelAnimation";
 
 import * as deepmerge from '../../assets/deepmerge.min.js';
+import { AbstractViewer } from "..";
+
 
 export enum ModelState {
     INIT,
@@ -12,30 +14,72 @@ export enum ModelState {
     ERROR
 }
 
+/**
+ * The viewer model is a container for all assets representing a sngle loaded model.
+ */
 export class ViewerModel implements IDisposable {
 
+    /**
+     * The loader used to load this model.
+     */
     public loader: ISceneLoaderPlugin | ISceneLoaderPluginAsync;
 
     private _animations: Array<IModelAnimation>;
+
+    /**
+     * the list of meshes that are a part of this model
+     */
     public meshes: Array<AbstractMesh> = [];
+    /**
+     * This model's root mesh (the parent of all other meshes).
+     * This mesh also exist in the meshes array.
+     */
     public rootMesh: AbstractMesh;
+    /**
+     * ParticleSystems connected to this model
+     */
     public particleSystems: Array<ParticleSystem> = [];
+    /**
+     * Skeletons defined in this model
+     */
     public skeletons: Array<Skeleton> = [];
+    /**
+     * The current model animation.
+     * On init, this will be undefined.
+     */
     public currentAnimation: IModelAnimation;
 
+    /**
+     * Observers registered here will be executed when the model is done loading
+     */
     public onLoadedObservable: Observable<ViewerModel>;
+    /**
+     * Observers registered here will be executed when the loader notified of a progress event
+     */
     public onLoadProgressObservable: Observable<SceneLoaderProgressEvent>;
+    /**
+     * Observers registered here will be executed when the loader notified of an error.
+     */
     public onLoadErrorObservable: Observable<{ message: string; exception: any }>;
 
+    /**
+     * Observers registered here will be executed every time the model is being configured.
+     * This can be used to extend the model's configuration without extending the class itself
+     */
     public onAfterConfigure: Observable<ViewerModel>;
 
+    /**
+     * The current model state (loaded, error, etc)
+     */
     public state: ModelState;
+    /**
+     * A loadID provided by the modelLoader, unique to ths (Abstract)Viewer instance.
+     */
     public loadId: number;
-
-    private _loaderDisposed: boolean = false;
     private _loadedUrl: string;
+    private _modelConfiguration: IModelConfiguration;
 
-    constructor(private _scene: Scene, private _modelConfiguration: IModelConfiguration, disableAutoLoad = false) {
+    constructor(protected _viewer: AbstractViewer, modelConfiguration: IModelConfiguration) {
         this.onLoadedObservable = new Observable();
         this.onLoadErrorObservable = new Observable();
         this.onLoadProgressObservable = new Observable();
@@ -44,43 +88,40 @@ export class ViewerModel implements IDisposable {
         this.state = ModelState.INIT;
 
         this._animations = [];
+        //create a copy of the configuration to make sure it doesn't change even after it is changed in the viewer
+        this._modelConfiguration = deepmerge({}, modelConfiguration);
 
-        if (!disableAutoLoad) {
-            this._initLoad();
-        }
-    }
-
-    public load() {
-        if (this.loader) {
-            Tools.Error("Model was already loaded or in the process of loading.");
-        } else {
-            this._initLoad();
-        }
-    }
-
-    public cancelLoad() {
-        // ATM only available in the GLTF Loader
-        if (this.loader && this.loader.name === "gltf") {
-            let gltfLoader = (<GLTFFileLoader>this.loader);
-            gltfLoader.dispose();
-            this.state = ModelState.CANCELED;
-        }
+        this._viewer.models.push(this);
     }
 
+    /**
+     * Get the model's configuration
+     */
     public get configuration(): IModelConfiguration {
         return this._modelConfiguration;
     }
 
+    /**
+     * (Re-)set the model's entire configuration
+     * @param newConfiguration the new configuration to replace the new one
+     */
     public set configuration(newConfiguration: IModelConfiguration) {
         this._modelConfiguration = newConfiguration;
         this._configureModel();
     }
 
+    /**
+     * Update the current configuration with new values.
+     * Configuration will not be overwritten, but merged with the new configuration.
+     * Priority is to the new configuration
+     * @param newConfiguration the configuration to be merged into the current configuration;
+     */
     public updateConfiguration(newConfiguration: Partial<IModelConfiguration>) {
         this._modelConfiguration = deepmerge(this._modelConfiguration, newConfiguration);
         this._configureModel();
     }
 
+
     public initAnimations() {
         this._animations.forEach(a => {
             a.dispose();
@@ -90,7 +131,7 @@ export class ViewerModel implements IDisposable {
         // check if this is not a gltf loader and init the animations
         if (this.loader.name !== 'gltf') {
             this.skeletons.forEach((skeleton, idx) => {
-                let ag = new AnimationGroup("animation-" + idx, this._scene);
+                let ag = new AnimationGroup("animation-" + idx, this._viewer.scene);
                 skeleton.getAnimatables().forEach(a => {
                     if (a.animations[0]) {
                         ag.addTargetedAnimation(a.animations[0], a);
@@ -116,18 +157,32 @@ export class ViewerModel implements IDisposable {
         }
     }
 
+    /**
+     * Add a new animation group to this model.
+     * @param animationGroup the new animation group to be added
+     */
     public addAnimationGroup(animationGroup: AnimationGroup) {
         this._animations.push(new GroupModelAnimation(animationGroup));
     }
 
-    public getAnimations() {
+    /**
+     * Get the ModelAnimation array
+     */
+    public getAnimations(): Array<IModelAnimation> {
         return this._animations;
     }
 
-    public getAnimationNames() {
+    /**
+     * Get the animations' names. Using the names you can play a specific animation.
+     */
+    public getAnimationNames(): Array<string> {
         return this._animations.map(a => a.name);
     }
 
+    /**
+     * Get an animation by the provided name. Used mainly when playing n animation.
+     * @param name the name of the animation to find
+     */
     protected _getAnimationByName(name: string): Nullable<IModelAnimation> {
         // can't use .find, noe available on IE
         let filtered = this._animations.filter(a => a.name === name);
@@ -139,6 +194,11 @@ export class ViewerModel implements IDisposable {
         }
     }
 
+    /**
+     * Choose an initialized animation using its name and start playing it
+     * @param name the name of the animation to play
+     * @returns The model aniamtion to be played.
+     */
     public playAnimation(name: string): IModelAnimation {
         let animation = this._getAnimationByName(name);
         if (animation) {
@@ -251,50 +311,9 @@ export class ViewerModel implements IDisposable {
         this.onAfterConfigure.notifyObservers(this);
     }
 
-    private _initLoad() {
-        if (!this._modelConfiguration.url) {
-            this.state = ModelState.ERROR;
-            Tools.Error("No URL provided");
-            return;
-        }
-
-        let filename = Tools.GetFilename(this._modelConfiguration.url) || this._modelConfiguration.url;
-        let base = this._modelConfiguration.root || Tools.GetFolderPath(this._modelConfiguration.url);
-        let plugin = this._modelConfiguration.loader;
-        this._loadedUrl = this._modelConfiguration.url;
-
-
-        this.loader = SceneLoader.ImportMesh(undefined, base, filename, this._scene, (meshes, particleSystems, skeletons) => {
-            meshes.forEach(mesh => {
-                Tags.AddTagsTo(mesh, "viewerMesh");
-            });
-            this.meshes = meshes;
-            this.particleSystems = particleSystems;
-            this.skeletons = skeletons;
-
-            this.initAnimations();
-            this.onLoadedObservable.notifyObserversWithPromise(this);
-        }, (progressEvent) => {
-            this.onLoadProgressObservable.notifyObserversWithPromise(progressEvent);
-        }, (e, m, exception) => {
-            this.state = ModelState.ERROR;
-            Tools.Error("Load Error: There was an error loading the model. " + m);
-            this.onLoadErrorObservable.notifyObserversWithPromise({ message: m, exception: exception });
-        }, plugin)!;
-
-        if (this.loader.name === "gltf") {
-            let gltfLoader = (<GLTFFileLoader>this.loader);
-            gltfLoader.animationStartMode = 0;
-            gltfLoader.onDispose = () => {
-                this._loaderDisposed = true;
-            }
-            gltfLoader.onAnimationGroupLoaded = ag => {
-                this.addAnimationGroup(ag);
-            }
-        }
-
-    }
-
+    /**
+     * Dispose this model, including all of its associated assets.
+     */
     public dispose() {
         this.onAfterConfigure.clear();
         this.onLoadedObservable.clear();
@@ -311,5 +330,6 @@ export class ViewerModel implements IDisposable {
         this._animations.length = 0;
         this.meshes.forEach(m => m.dispose());
         this.meshes.length = 0;
+        this._viewer.models.splice(this._viewer.models.indexOf(this), 1);
     }
 }

+ 175 - 67
Viewer/src/templateManager.ts

@@ -2,6 +2,9 @@
 import { Observable, IFileRequest, Tools } from 'babylonjs';
 import { isUrl, camelToKebab, kebabToCamel } from './helper';
 
+/**
+ * A single template configuration object
+ */
 export interface ITemplateConfiguration {
     location?: string; // #template-id OR http://example.com/loading.html
     html?: string; // raw html string
@@ -27,6 +30,9 @@ export interface ITemplateConfiguration {
     }
 }
 
+/**
+ * The object sent when an event is triggered
+ */
 export interface EventCallback {
     event: Event;
     template: Template;
@@ -34,14 +40,36 @@ export interface EventCallback {
     payload?: any;
 }
 
+/**
+ * The template manager, a member of the viewer class, will manage the viewer's templates and generate the HTML.
+ * The template manager managers a single viewer and can be seen as the collection of all sub-templates of the viewer.
+ */
 export class TemplateManager {
 
-    public onInit: Observable<Template>;
-    public onLoaded: Observable<Template>;
-    public onStateChange: Observable<Template>;
+    /**
+     * Will be triggered when any template is initialized
+     */
+    public onTemplateInit: Observable<Template>;
+    /**
+     * Will be triggered when any template is fully loaded
+     */
+    public onTemplateLoaded: Observable<Template>;
+    /**
+     * Will be triggered when a template state changes
+     */
+    public onTemplateStateChange: Observable<Template>;
+    /**
+     * Will be triggered when all templates finished loading
+     */
     public onAllLoaded: Observable<TemplateManager>;
+    /**
+     * Will be triggered when any event on any template is triggered.
+     */
     public onEventTriggered: Observable<EventCallback>;
 
+    /**
+     * This template manager's event manager. In charge of callback registrations to native event types
+     */
     public eventManager: EventManager;
 
     private templates: { [name: string]: Template };
@@ -49,15 +77,19 @@ export class TemplateManager {
     constructor(public containerElement: HTMLElement) {
         this.templates = {};
 
-        this.onInit = new Observable<Template>();
-        this.onLoaded = new Observable<Template>();
-        this.onStateChange = new Observable<Template>();
+        this.onTemplateInit = new Observable<Template>();
+        this.onTemplateLoaded = new Observable<Template>();
+        this.onTemplateStateChange = new Observable<Template>();
         this.onAllLoaded = new Observable<TemplateManager>();
         this.onEventTriggered = new Observable<EventCallback>();
 
         this.eventManager = new EventManager(this);
     }
 
+    /**
+     * Initialize the template(s) for the viewer. Called bay the Viewer class
+     * @param templates the templates to be used to initialize the main template
+     */
     public initTemplate(templates: { [key: string]: ITemplateConfiguration }) {
 
         let internalInit = (dependencyMap, name: string, parentTemplate?: Template) => {
@@ -73,7 +105,7 @@ export class TemplateManager {
             let addToParent = () => {
                 let containingElement = parentTemplate && parentTemplate.parent.querySelector(camelToKebab(name)) || this.containerElement;
                 template.appendTo(containingElement);
-                this.checkLoadedState();
+                this._checkLoadedState();
             }
 
             if (parentTemplate && !parentTemplate.parent) {
@@ -89,11 +121,11 @@ export class TemplateManager {
         }
 
         //build the html tree
-        return this.buildHTMLTree(templates).then(htmlTree => {
+        return this._buildHTMLTree(templates).then(htmlTree => {
             if (this.templates['main']) {
                 internalInit(htmlTree, 'main');
             } else {
-                this.checkLoadedState();
+                this._checkLoadedState();
             }
             return;
         });
@@ -105,16 +137,21 @@ export class TemplateManager {
      * It will compile each template, check if its children exist in the configuration and will add them if they do.
      * It is expected that the main template will be called main!
      * 
-     * @private
-     * @param {{ [key: string]: ITemplateConfiguration }} templates 
-     * @memberof TemplateManager
+     * @param templates
      */
-    private buildHTMLTree(templates: { [key: string]: ITemplateConfiguration }): Promise<object> {
+    private _buildHTMLTree(templates: { [key: string]: ITemplateConfiguration }): Promise<object> {
         let promises: Array<Promise<Template | boolean>> = Object.keys(templates).map(name => {
             // if the template was overridden
             if (!templates[name]) return Promise.resolve(false);
             // else - we have a template, let's do our job!
             let template = new Template(name, templates[name]);
+            template.onLoaded.add(() => {
+                this.onTemplateLoaded.notifyObservers(template);
+            });
+            template.onStateChange.add(() => {
+                this.onTemplateStateChange.notifyObservers(template);
+            });
+            this.onTemplateInit.notifyObservers(template);
             // make sure the global onEventTriggered is called as well
             template.onEventTriggered.add(eventData => this.onEventTriggered.notifyObservers(eventData));
             this.templates[name] = template;
@@ -139,16 +176,23 @@ export class TemplateManager {
         });
     }
 
-    // assumiung only ONE(!) canvas
+    /**
+     * Get the canvas in the template tree.
+     * There must be one and only one canvas inthe template.
+     */
     public getCanvas(): HTMLCanvasElement | null {
         return this.containerElement.querySelector('canvas');
     }
 
+    /**
+     * Get a specific template from the template tree
+     * @param name the name of the template to load
+     */
     public getTemplate(name: string): Template | undefined {
         return this.templates[name];
     }
 
-    private checkLoadedState() {
+    private _checkLoadedState() {
         let done = Object.keys(this.templates).length === 0 || Object.keys(this.templates).every((key) => {
             return (this.templates[key].isLoaded && !!this.templates[key].parent) || !this.templates[key].isInHtmlTree;
         });
@@ -158,6 +202,9 @@ export class TemplateManager {
         }
     }
 
+    /**
+     * Dispose the template manager
+     */
     public dispose() {
         // dispose all templates
         Object.keys(this.templates).forEach(template => {
@@ -166,11 +213,11 @@ export class TemplateManager {
         this.templates = {};
         this.eventManager.dispose();
 
-        this.onInit.clear();
+        this.onTemplateInit.clear();
         this.onAllLoaded.clear();
         this.onEventTriggered.clear();
-        this.onLoaded.clear();
-        this.onStateChange.clear();
+        this.onTemplateLoaded.clear();
+        this.onTemplateStateChange.clear();
     }
 
 }
@@ -193,14 +240,37 @@ Handlebars.registerHelper('eachInMap', function (map, block) {
     return out;
 });
 
+/**
+ * This class represents a single template in the viewer's template tree.
+ * An example for a template is a single canvas, an overlay (containing sub-templates) or the navigation bar.
+ * A template is injected using the template manager in the correct position.
+ * The template is rendered using Handlebars and can use Handlebars' features (such as parameter injection)
+ * 
+ * For further information please refer to the documentation page, https://doc.babylonjs.com
+ */
 export class Template {
 
-    public onInit: Observable<Template>;
+    /**
+     * Will be triggered when the template is loaded
+     */
     public onLoaded: Observable<Template>;
+    /**
+     * will be triggered when the template is appended to the tree
+     */
     public onAppended: Observable<Template>;
+    /**
+     * Will be triggered when the template's state changed (shown, hidden)
+     */
     public onStateChange: Observable<Template>;
+    /**
+     * Will be triggered when an event is triggered on ths template.
+     * The event is a native browser event (like mouse or pointer events)
+     */
     public onEventTriggered: Observable<EventCallback>;
 
+    /**
+     * is the template loaded?
+     */
     public isLoaded: boolean;
     /**
      * This is meant to be used to track the show and hide functions.
@@ -208,19 +278,27 @@ export class Template {
      */
     public isShown: boolean;
 
+    /**
+     * Is this template a part of the HTML tree (the template manager injected it)
+     */
     public isInHtmlTree: boolean;
 
+    /**
+     * The HTML element containing this template
+     */
     public parent: HTMLElement;
 
+    /**
+     * A promise that is fulfilled when the template finished loading.
+     */
     public initPromise: Promise<Template>;
 
-    private fragment: DocumentFragment;
-    private htmlTemplate: string;
+    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>();
         this.onAppended = new Observable<Template>();
         this.onStateChange = new Observable<Template>();
@@ -231,22 +309,16 @@ export class Template {
         this.isLoaded = false;
         this.isShown = false;
         this.isInHtmlTree = false;
-        /*
-        if (configuration.id) {
-            this.parent.id = configuration.id;
-        }
-        */
-        this.onInit.notifyObservers(this);
 
-        let htmlContentPromise = this.getTemplateAsHtml(_configuration);
+        let htmlContentPromise = this._getTemplateAsHtml(_configuration);
 
         this.initPromise = htmlContentPromise.then(htmlTemplate => {
             if (htmlTemplate) {
-                this.htmlTemplate = htmlTemplate;
+                this._htmlTemplate = htmlTemplate;
                 let compiledTemplate = Handlebars.compile(htmlTemplate);
                 let config = this._configuration.params || {};
                 let rawHtml = compiledTemplate(config);
-                this.fragment = document.createRange().createContextualFragment(rawHtml);
+                this._fragment = document.createRange().createContextualFragment(rawHtml);
                 this.isLoaded = true;
                 this.isShown = true;
                 this.onLoaded.notifyObservers(this);
@@ -255,32 +327,46 @@ export class Template {
         });
     }
 
+    /**
+     * Some templates have parameters (like background color for example).
+     * The parameters are provided to Handlebars which in turn generates the template.
+     * This function will update the template with the new parameters
+     * 
+     * @param params the new template parameters
+     */
     public updateParams(params: { [key: string]: string | number | boolean | object }) {
         this._configuration.params = params;
         // update the template
         if (this.isLoaded) {
             this.dispose();
         }
-        let compiledTemplate = Handlebars.compile(this.htmlTemplate);
+        let compiledTemplate = Handlebars.compile(this._htmlTemplate);
         let config = this._configuration.params || {};
         let rawHtml = compiledTemplate(config);
-        this.fragment = document.createRange().createContextualFragment(rawHtml);
+        this._fragment = document.createRange().createContextualFragment(rawHtml);
         if (this.parent) {
             this.appendTo(this.parent, true);
         }
     }
 
+    /**
+     * Get the template'S configuration
+     */
     public get configuration(): ITemplateConfiguration {
         return this._configuration;
     }
 
+    /**
+     * A template can be a parent element for other templates or HTML elements.
+     * This function will deliver all child HTML elements of this template.
+     */
     public getChildElements(): Array<string> {
         let childrenArray: string[] = [];
         //Edge and IE don't support frage,ent.children
-        let children = this.fragment.children;
+        let children = this._fragment.children;
         if (!children) {
             // casting to HTMLCollection, as both NodeListOf and HTMLCollection have 'item()' and 'length'.
-            children = <HTMLCollection>this.fragment.querySelectorAll('*');
+            children = <HTMLCollection>this._fragment.querySelectorAll('*');
         }
         for (let i = 0; i < children.length; ++i) {
             childrenArray.push(kebabToCamel(children.item(i).nodeName.toLowerCase()));
@@ -288,10 +374,16 @@ export class Template {
         return childrenArray;
     }
 
+    /**
+     * Appending the template to a parent HTML element.
+     * If a parent is already set and you wish to replace the old HTML with new one, forceRemove should be true.
+     * @param parent the parent to which the template is added
+     * @param forceRemove if the parent already exists, shoud the template be removed from it?
+     */
     public appendTo(parent: HTMLElement, forceRemove?: boolean) {
         if (this.parent) {
             if (forceRemove) {
-                this.parent.removeChild(this.fragment);
+                this.parent.removeChild(this._fragment);
             } else {
                 return;
             }
@@ -301,20 +393,28 @@ export class Template {
         if (this._configuration.id) {
             this.parent.id = this._configuration.id;
         }
-        this.fragment = this.parent.appendChild(this.fragment);
+        this._fragment = this.parent.appendChild(this._fragment);
         // appended only one frame after.
         setTimeout(() => {
-            this.registerEvents();
+            this._registerEvents();
             this.onAppended.notifyObservers(this);
         });
     }
 
-    private isShowing: boolean;
-    private isHiding: boolean;
+    private _isShowing: boolean;
+    private _isHiding: boolean;
+
+    /**
+     * Show the template using the provided visibilityFunction, or natively using display: flex.
+     * The provided function returns a promise that should be fullfilled when the element is shown.
+     * Since it is a promise async operations are more than possible.
+     * See the default viewer for an opacity example.
+     * @param visibilityFunction The function to execute to show the template. 
+     */
     public show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
-        if (this.isHiding) return Promise.resolve(this);
+        if (this._isHiding) return Promise.resolve(this);
         return Promise.resolve().then(() => {
-            this.isShowing = true;
+            this._isShowing = true;
             if (visibilityFunction) {
                 return visibilityFunction(this);
             } else {
@@ -324,16 +424,23 @@ export class Template {
             }
         }).then(() => {
             this.isShown = true;
-            this.isShowing = false;
+            this._isShowing = false;
             this.onStateChange.notifyObservers(this);
             return this;
         });
     }
 
+    /**
+     * Hide the template using the provided visibilityFunction, or natively using display: none.
+     * The provided function returns a promise that should be fullfilled when the element is hidden.
+     * Since it is a promise async operations are more than possible.
+     * See the default viewer for an opacity example.
+     * @param visibilityFunction The function to execute to show the template. 
+     */
     public hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template> {
-        if (this.isShowing) return Promise.resolve(this);
+        if (this._isShowing) return Promise.resolve(this);
         return Promise.resolve().then(() => {
-            this.isHiding = true;
+            this._isHiding = true;
             if (visibilityFunction) {
                 return visibilityFunction(this);
             } else {
@@ -343,22 +450,24 @@ export class Template {
             }
         }).then(() => {
             this.isShown = false;
-            this.isHiding = false;
+            this._isHiding = false;
             this.onStateChange.notifyObservers(this);
             return this;
         });
     }
 
+    /**
+     * Dispose this template
+     */
     public dispose() {
         this.onAppended.clear();
         this.onEventTriggered.clear();
-        this.onInit.clear();
         this.onLoaded.clear();
         this.onStateChange.clear();
         this.isLoaded = false;
         // remove from parent
         try {
-            this.parent.removeChild(this.fragment);
+            this.parent.removeChild(this._fragment);
         } catch (e) {
             //noop
         }
@@ -367,22 +476,22 @@ export class Template {
             request.abort();
         });
 
-        if (this.registeredEvents) {
-            this.registeredEvents.forEach(evt => {
+        if (this._registeredEvents) {
+            this._registeredEvents.forEach(evt => {
                 evt.htmlElement.removeEventListener(evt.eventName, evt.function);
             });
         }
 
-        delete this.fragment;
+        delete this._fragment;
     }
 
-    private getTemplateAsHtml(templateConfig: ITemplateConfiguration): Promise<string> {
+    private _getTemplateAsHtml(templateConfig: ITemplateConfiguration): Promise<string> {
         if (!templateConfig) {
             return Promise.reject('No templateConfig provided');
         } else if (templateConfig.html !== undefined) {
             return Promise.resolve(templateConfig.html);
         } else {
-            let location = getTemplateLocation(templateConfig);
+            let location = this._getTemplateLocation(templateConfig);
             if (isUrl(location)) {
                 return new Promise((resolve, reject) => {
                     let fileRequest = Tools.LoadFile(location, (data: string) => {
@@ -404,14 +513,13 @@ export class Template {
         }
     }
 
-    private registeredEvents: Array<{ htmlElement: HTMLElement, eventName: string, function: EventListenerOrEventListenerObject }>;
+    private _registeredEvents: Array<{ htmlElement: HTMLElement, eventName: string, function: EventListenerOrEventListenerObject }>;
 
-    // TODO - Should events be removed as well? when are templates disposed?
-    private registerEvents() {
-        this.registeredEvents = this.registeredEvents || [];
-        if (this.registeredEvents.length) {
+    private _registerEvents() {
+        this._registeredEvents = this._registeredEvents || [];
+        if (this._registeredEvents.length) {
             // first remove the registered events
-            this.registeredEvents.forEach(evt => {
+            this._registeredEvents.forEach(evt => {
                 evt.htmlElement.removeEventListener(evt.eventName, evt.function);
             });
         }
@@ -426,7 +534,7 @@ export class Template {
                     if (typeof this._configuration.events[eventName] === 'boolean') {
                         let binding = functionToFire.bind(this, '#' + this.parent.id);
                         this.parent.addEventListener(eventName, functionToFire.bind(this, '#' + this.parent.id), false);
-                        this.registeredEvents.push({
+                        this._registeredEvents.push({
                             htmlElement: this.parent,
                             eventName: eventName,
                             function: binding
@@ -443,7 +551,7 @@ export class Template {
                             if (htmlElement) {
                                 let binding = functionToFire.bind(this, selector);
                                 htmlElement.addEventListener(eventName, binding, false);
-                                this.registeredEvents.push({
+                                this._registeredEvents.push({
                                     htmlElement: htmlElement,
                                     eventName: eventName,
                                     function: binding
@@ -455,12 +563,12 @@ export class Template {
             }
         }
     }
-}
 
-export function getTemplateLocation(templateConfig): string {
-    if (!templateConfig || typeof templateConfig === 'string') {
-        return templateConfig;
-    } else {
-        return templateConfig.location;
+    private _getTemplateLocation(templateConfig): string {
+        if (!templateConfig || typeof templateConfig === 'string') {
+            return templateConfig;
+        } else {
+            return templateConfig.location;
+        }
     }
 }

+ 81 - 38
Viewer/src/viewer/defaultViewer.ts

@@ -7,26 +7,40 @@ import { SpotLight, MirrorTexture, Plane, ShadowGenerator, Texture, BackgroundMa
 import { CameraBehavior } from '../interfaces';
 import { ViewerModel } from '../model/viewerModel';
 
+/**
+ * The Default viewer is the default implementation of the AbstractViewer.
+ * It uses the templating system to render a new canvas and controls.
+ */
 export class DefaultViewer extends AbstractViewer {
 
+    /**
+     * Create a new default viewer
+     * @param containerElement the element in which the templates will be rendered
+     * @param initialConfiguration the initial configuration. Defaults to extending the default configuration
+     */
     constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = { extends: 'default' }) {
         super(containerElement, initialConfiguration);
-        this.onModelLoadedObservable.add(this.onModelLoaded);
+        this.onModelLoadedObservable.add(this._onModelLoaded);
     }
 
-    public initScene(): Promise<Scene> {
-        return super.initScene().then(() => {
-            this.extendClassWithConfig(this.scene, this.configuration.scene);
+    /**
+     * Overriding the AbstractViewer's _initScene fcuntion
+     */
+    protected _initScene(): Promise<Scene> {
+        return super._initScene().then(() => {
+            this._extendClassWithConfig(this.scene, this._configuration.scene);
             return this.scene;
         })
     }
 
-    protected onTemplatesLoaded() {
-
+    /**
+     * This will be executed when the templates initialize.
+     */
+    protected _onTemplatesLoaded() {
         this.showLoadingScreen();
 
         // navbar
-        this.initNavbar();
+        this._initNavbar();
 
         // close overlay button
         let closeButton = document.getElementById('close-button');
@@ -36,10 +50,10 @@ export class DefaultViewer extends AbstractViewer {
             })
         }
 
-        return super.onTemplatesLoaded();
+        return super._onTemplatesLoaded();
     }
 
-    private initNavbar() {
+    private _initNavbar() {
         let navbar = this.templateManager.getTemplate('navBar');
         if (navbar) {
             let navbarHeight = navbar.parent.clientHeight + 'px';
@@ -99,12 +113,20 @@ export class DefaultViewer extends AbstractViewer {
         }
     }
 
-    protected prepareContainerElement() {
+    /**
+     * Preparing the container element to present the viewer
+     */
+    protected _prepareContainerElement() {
         this.containerElement.style.position = 'relative';
         this.containerElement.style.display = 'flex';
     }
 
-    protected configureTemplate(model: ViewerModel) {
+    /**
+     * This function will configure the templates and update them after a model was loaded
+     * It is mainly responsible to changing the title and subtitle etc'.
+     * @param model the model to be used to configure the templates by
+     */
+    protected _configureTemplate(model: ViewerModel) {
         let navbar = this.templateManager.getTemplate('navBar');
         if (!navbar) return;
 
@@ -132,7 +154,13 @@ export class DefaultViewer extends AbstractViewer {
         }
     }
 
-    public loadModel(model: any = this.configuration.model): Promise<ViewerModel> {
+    /**
+     * This will load a new model to the default viewer
+     * overriding the AbstractViewer's loadModel.
+     * The scene will automatically be cleared of the old models, if exist.
+     * @param model the configuration object (or URL) to load.
+     */
+    public loadModel(model: any = this._configuration.model): Promise<ViewerModel> {
         this.showLoadingScreen();
         return super.loadModel(model, true).catch((error) => {
             console.log(error);
@@ -142,12 +170,12 @@ export class DefaultViewer extends AbstractViewer {
         });
     }
 
-    private onModelLoaded = (model: ViewerModel) => {
-        this.configureTemplate(model);
+    private _onModelLoaded = (model: ViewerModel) => {
+        this._configureTemplate(model);
         // with a short timeout, making sure everything is there already.
         let hideLoadingDelay = 500;
-        if (this.configuration.lab && this.configuration.lab.hideLoadingDelay !== undefined) {
-            hideLoadingDelay = this.configuration.lab.hideLoadingDelay;
+        if (this._configuration.lab && this._configuration.lab.hideLoadingDelay !== undefined) {
+            hideLoadingDelay = this._configuration.lab.hideLoadingDelay;
         }
         setTimeout(() => {
             this.hideLoadingScreen();
@@ -156,6 +184,11 @@ export class DefaultViewer extends AbstractViewer {
         return;
     }
 
+    /**
+     * Show the overlay and the defined sub-screen.
+     * Mainly used for help and errors
+     * @param subScreen the name of the subScreen. Those can be defined in the configuration object
+     */
     public showOverlayScreen(subScreen: string) {
         let template = this.templateManager.getTemplate('overlay');
         if (!template) return Promise.resolve('Overlay template not found');
@@ -181,6 +214,9 @@ export class DefaultViewer extends AbstractViewer {
         }));
     }
 
+    /**
+     * Hide the overlay screen.
+     */
     public hideOverlayScreen() {
         let template = this.templateManager.getTemplate('overlay');
         if (!template) return Promise.resolve('Overlay template not found');
@@ -200,15 +236,14 @@ export class DefaultViewer extends AbstractViewer {
                     htmlElement.style.display = 'none';
                 }
             }
-
-            /*return this.templateManager.getTemplate(subScreen).show((template => {
-                template.parent.style.display = 'none';
-                return Promise.resolve(template);
-            }));*/
             return Promise.resolve(template);
         }));
     }
 
+    /**
+     * Show the loading screen.
+     * The loading screen can be configured using the configuration object
+     */
     public showLoadingScreen() {
         let template = this.templateManager.getTemplate('loadingScreen');
         if (!template) return Promise.resolve('Loading Screen template not found');
@@ -228,6 +263,9 @@ export class DefaultViewer extends AbstractViewer {
         }));
     }
 
+    /**
+     * Hide the loading screen
+     */
     public hideLoadingScreen() {
         let template = this.templateManager.getTemplate('loadingScreen');
         if (!template) return Promise.resolve('Loading Screen template not found');
@@ -243,31 +281,36 @@ export class DefaultViewer extends AbstractViewer {
         }));
     }
 
-    protected configureLights(lightsConfiguration: { [name: string]: ILightConfiguration | boolean } = {}, model: ViewerModel) {
-        super.configureLights(lightsConfiguration, model);
+    /**
+     * An extension of the light configuration of the abstract viewer.
+     * @param lightsConfiguration the light configuration to use
+     * @param model the model that will be used to configure the lights (if the lights are model-dependant)
+     */
+    protected _configureLights(lightsConfiguration: { [name: string]: ILightConfiguration | boolean } = {}, model: ViewerModel) {
+        super._configureLights(lightsConfiguration, model);
         // labs feature - flashlight
-        if (this.configuration.lab && this.configuration.lab.flashlight) {
+        if (this._configuration.lab && this._configuration.lab.flashlight) {
             let pointerPosition = Vector3.Zero();
             let lightTarget;
             let angle = 0.5;
             let exponent = Math.PI / 2;
-            if (typeof this.configuration.lab.flashlight === "object") {
-                exponent = this.configuration.lab.flashlight.exponent || exponent;
-                angle = this.configuration.lab.flashlight.angle || angle;
+            if (typeof this._configuration.lab.flashlight === "object") {
+                exponent = this._configuration.lab.flashlight.exponent || exponent;
+                angle = this._configuration.lab.flashlight.angle || angle;
             }
             var flashlight = new SpotLight("flashlight", Vector3.Zero(),
                 Vector3.Zero(), exponent, angle, this.scene);
-            if (typeof this.configuration.lab.flashlight === "object") {
-                flashlight.intensity = this.configuration.lab.flashlight.intensity || flashlight.intensity;
-                if (this.configuration.lab.flashlight.diffuse) {
-                    flashlight.diffuse.r = this.configuration.lab.flashlight.diffuse.r;
-                    flashlight.diffuse.g = this.configuration.lab.flashlight.diffuse.g;
-                    flashlight.diffuse.b = this.configuration.lab.flashlight.diffuse.b;
+            if (typeof this._configuration.lab.flashlight === "object") {
+                flashlight.intensity = this._configuration.lab.flashlight.intensity || flashlight.intensity;
+                if (this._configuration.lab.flashlight.diffuse) {
+                    flashlight.diffuse.r = this._configuration.lab.flashlight.diffuse.r;
+                    flashlight.diffuse.g = this._configuration.lab.flashlight.diffuse.g;
+                    flashlight.diffuse.b = this._configuration.lab.flashlight.diffuse.b;
                 }
-                if (this.configuration.lab.flashlight.specular) {
-                    flashlight.specular.r = this.configuration.lab.flashlight.specular.r;
-                    flashlight.specular.g = this.configuration.lab.flashlight.specular.g;
-                    flashlight.specular.b = this.configuration.lab.flashlight.specular.b;
+                if (this._configuration.lab.flashlight.specular) {
+                    flashlight.specular.r = this._configuration.lab.flashlight.specular.r;
+                    flashlight.specular.g = this._configuration.lab.flashlight.specular.g;
+                    flashlight.specular.b = this._configuration.lab.flashlight.specular.b;
                 }
 
             }
@@ -288,7 +331,7 @@ export class DefaultViewer extends AbstractViewer {
                 }
             }
             this.scene.registerBeforeRender(updateFlashlightFunction);
-            this.registeredOnBeforerenderFunctions.push(updateFlashlightFunction);
+            this._registeredOnBeforeRenderFunctions.push(updateFlashlightFunction);
         }
     }
 }

+ 278 - 118
Viewer/src/viewer/viewer.ts

@@ -5,56 +5,143 @@ import { Skeleton, AnimationGroup, ParticleSystem, CubeTexture, Color3, IEnviron
 import { ViewerConfiguration, ISceneConfiguration, ISceneOptimizerConfiguration, IObserversConfiguration, IModelConfiguration, ISkyboxConfiguration, IGroundConfiguration, ILightConfiguration, ICameraConfiguration } from '../configuration/configuration';
 
 import * as deepmerge from '../../assets/deepmerge.min.js';
-import { CameraBehavior } from 'src/interfaces';
 import { ViewerModel } from '../model/viewerModel';
 import { GroupModelAnimation } from '../model/modelAnimation';
 import { ModelLoader } from '../model/modelLoader';
+import { CameraBehavior } from '../interfaces';
 
+/**
+ * The AbstractViewr is the center of Babylon's viewer.
+ * It is the basic implementation of the default viewer and is responsible of loading and showing the model and the templates
+ */
 export abstract class AbstractViewer {
 
+    /**
+     * The corresponsing template manager of this viewer.
+     */
     public templateManager: TemplateManager;
 
+    /**
+     * Babylon Engine corresponding with this viewer
+     */
     public engine: Engine;
+    /**
+     * The Babylon Scene of this viewer
+     */
     public scene: Scene;
+    /**
+     * The camera used in this viewer
+     */
     public camera: ArcRotateCamera;
+    /**
+     * Babylon's scene optimizer
+     */
     public sceneOptimizer: SceneOptimizer;
-    public baseId: string;
+    /**
+     * The ID of this viewer. it will be generated randomly or use the HTML Element's ID.
+     */
+    public readonly baseId: string;
+    /**
+     * Models displayed in this viewer.
+     */
     public models: Array<ViewerModel>;
 
     /**
      * The last loader used to load a model. 
      */
     public lastUsedLoader: ISceneLoaderPlugin | ISceneLoaderPluginAsync;
+    /**
+     * The ModelLoader instance connected with this viewer.
+     */
     public modelLoader: ModelLoader;
 
-    protected configuration: ViewerConfiguration;
+    /**
+     * the viewer configuration object
+     */
+    protected _configuration: ViewerConfiguration;
+    /**
+     * Babylon's environment helper of this viewer
+     */
     public environmentHelper: EnvironmentHelper;
 
-    protected defaultHighpTextureType: number;
-    protected shadowGeneratorBias: number;
-    protected defaultPipelineTextureType: number;
-    protected maxShadows: number;
+    //The following are configuration objects, default values.
+    protected _defaultHighpTextureType: number;
+    protected _shadowGeneratorBias: number;
+    protected _defaultPipelineTextureType: number;
+
+    /**
+     * The maximum number of shadows supported by the curent viewer
+     */
+    protected _maxShadows: number;
+    /**
+     * is HDR supported?
+     */
     private _hdrSupport: boolean;
 
+    /**
+     * is this viewer disposed?
+     */
     protected _isDisposed: boolean = false;
 
+    /**
+     * Returns a boolean representing HDR support
+     */
     public get isHdrSupported() {
         return this._hdrSupport;
     }
 
 
     // observables
+    /**
+     * Will notify when the scene was initialized
+     */
     public onSceneInitObservable: Observable<Scene>;
+    /**
+     * will notify when the engine was initialized
+     */
     public onEngineInitObservable: Observable<Engine>;
+    /**
+     * will notify after every model load
+     */
     public onModelLoadedObservable: Observable<ViewerModel>;
+    /**
+     * will notify when any model notify of progress
+     */
     public onModelLoadProgressObservable: Observable<SceneLoaderProgressEvent>;
+    /**
+     * will notify when any model load failed.
+     */
     public onModelLoadErrorObservable: Observable<{ message: string; exception: any }>;
+    /**
+     * will notify when a new loader was initialized.
+     * Used mainly to know when a model starts loading.
+     */
     public onLoaderInitObservable: Observable<ISceneLoaderPlugin | ISceneLoaderPluginAsync>;
+    /**
+     * Observers registered here will be executed when the entire load process has finished.
+     */
     public onInitDoneObservable: Observable<AbstractViewer>;
 
-    public canvas: HTMLCanvasElement;
+    /**
+     * The canvas associated with this viewer
+     */
+    protected _canvas: HTMLCanvasElement;
+
+    /**
+     * The (single) canvas of this viewer
+     */
+    public get canvas(): HTMLCanvasElement {
+        return this._canvas;
+    }
 
-    protected registeredOnBeforerenderFunctions: Array<() => void>;
+    /**
+     * registered onBeforeRender functions.
+     * This functions are also registered at the native scene. The reference can be used to unregister them.
+     */
+    protected _registeredOnBeforeRenderFunctions: Array<() => void>;
+    /**
+     * The configuration loader of this viewer
+     */
     protected _configurationLoader: ConfigurationLoader;
 
     constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = {}) {
@@ -73,7 +160,7 @@ export abstract class AbstractViewer {
         this.onInitDoneObservable = new Observable();
         this.onLoaderInitObservable = new Observable();
 
-        this.registeredOnBeforerenderFunctions = [];
+        this._registeredOnBeforeRenderFunctions = [];
         this.models = [];
         this.modelLoader = new ModelLoader(this);
 
@@ -83,43 +170,49 @@ export abstract class AbstractViewer {
         // create a new template manager. TODO - singleton?
         this.templateManager = new TemplateManager(containerElement);
 
-        this.prepareContainerElement();
+        this._prepareContainerElement();
 
         // extend the configuration
         this._configurationLoader = new ConfigurationLoader();
         this._configurationLoader.loadConfiguration(initialConfiguration, (configuration) => {
-            this.configuration = deepmerge(this.configuration || {}, configuration);
-            if (this.configuration.observers) {
-                this.configureObservers(this.configuration.observers);
+            this._configuration = deepmerge(this._configuration || {}, configuration);
+            if (this._configuration.observers) {
+                this._configureObservers(this._configuration.observers);
             }
             //this.updateConfiguration(configuration);
 
             // initialize the templates
-            let templateConfiguration = this.configuration.templates || {};
+            let templateConfiguration = this._configuration.templates || {};
             this.templateManager.initTemplate(templateConfiguration);
             // when done, execute onTemplatesLoaded()
             this.templateManager.onAllLoaded.add(() => {
                 let canvas = this.templateManager.getCanvas();
                 if (canvas) {
-                    this.canvas = canvas;
+                    this._canvas = canvas;
                 }
                 this._onTemplateLoaded();
             });
         });
-
-        //this.onModelLoadedObservable.add(this.initEnvironment.bind(this));
-
     }
 
+    /**
+     * get the baseId of this viewer
+     */
     public getBaseId(): string {
         return this.baseId;
     }
 
+    /**
+     * Do we have a canvas to render on, and is it a part of the scene
+     */
     public isCanvasInDOM(): boolean {
-        return !!this.canvas && !!this.canvas.parentElement;
+        return !!this._canvas && !!this._canvas.parentElement;
     }
 
-    protected resize = (): void => {
+    /**
+     * The resize function that will be registered with the window object
+     */
+    protected _resize = (): void => {
         // Only resize if Canvas is in the DOM
         if (!this.isCanvasInDOM()) {
             return;
@@ -132,7 +225,10 @@ export abstract class AbstractViewer {
         this.engine.resize();
     }
 
-    protected render = (): void => {
+    /**
+     * render loop that will be executed by the engine
+     */
+    protected _render = (): void => {
         this.scene && this.scene.activeCamera && this.scene.render();
     }
 
@@ -143,46 +239,46 @@ export abstract class AbstractViewer {
      * and the entire configuration will be updated. 
      * @param newConfiguration 
      */
-    public updateConfiguration(newConfiguration: Partial<ViewerConfiguration> = this.configuration) {
+    public updateConfiguration(newConfiguration: Partial<ViewerConfiguration> = this._configuration) {
         // update this.configuration with the new data
-        this.configuration = deepmerge(this.configuration || {}, newConfiguration);
+        this._configuration = deepmerge(this._configuration || {}, newConfiguration);
 
         // update scene configuration
         if (newConfiguration.scene) {
-            this.configureScene(newConfiguration.scene);
+            this._configureScene(newConfiguration.scene);
         }
         // optimizer
         if (newConfiguration.optimizer) {
-            this.configureOptimizer(newConfiguration.optimizer);
+            this._configureOptimizer(newConfiguration.optimizer);
         }
 
         // observers in configuration
         if (newConfiguration.observers) {
-            this.configureObservers(newConfiguration.observers);
+            this._configureObservers(newConfiguration.observers);
         }
 
         // configure model
         if (newConfiguration.model && typeof newConfiguration.model === 'object') {
-            this.configureModel(newConfiguration.model);
+            this._configureModel(newConfiguration.model);
         }
 
         // lights
         if (newConfiguration.lights) {
-            this.configureLights(newConfiguration.lights);
+            this._configureLights(newConfiguration.lights);
         }
 
         // environment
         if (newConfiguration.skybox !== undefined || newConfiguration.ground !== undefined) {
-            this.configureEnvironment(newConfiguration.skybox, newConfiguration.ground);
+            this._configureEnvironment(newConfiguration.skybox, newConfiguration.ground);
         }
 
         // camera
         if (newConfiguration.camera) {
-            this.configureCamera(newConfiguration.camera);
+            this._configureCamera(newConfiguration.camera);
         }
     }
 
-    protected configureEnvironment(skyboxConifguration?: ISkyboxConfiguration | boolean, groundConfiguration?: IGroundConfiguration | boolean) {
+    protected _configureEnvironment(skyboxConifguration?: ISkyboxConfiguration | boolean, groundConfiguration?: IGroundConfiguration | boolean) {
         if (!skyboxConifguration && !groundConfiguration) {
             if (this.environmentHelper) {
                 this.environmentHelper.dispose();
@@ -235,8 +331,8 @@ export abstract class AbstractViewer {
                         options.groundMirrorFresnelWeight = groundConfig.mirror.fresnelWeight;
                     if (groundConfig.mirror.fallOffDistance !== undefined)
                         options.groundMirrorFallOffDistance = groundConfig.mirror.fallOffDistance;
-                    if (this.defaultPipelineTextureType !== undefined)
-                        options.groundMirrorTextureType = this.defaultPipelineTextureType;
+                    if (this._defaultPipelineTextureType !== undefined)
+                        options.groundMirrorTextureType = this._defaultPipelineTextureType;
                 }
             }
 
@@ -292,13 +388,18 @@ export abstract class AbstractViewer {
             let skyboxMaterial = this.environmentHelper.skyboxMaterial;
             if (skyboxMaterial) {
                 if (typeof skyboxConifguration === 'object' && skyboxConifguration.material && skyboxConifguration.material.imageProcessingConfiguration) {
-                    this.extendClassWithConfig(skyboxMaterial.imageProcessingConfiguration, skyboxConifguration.material.imageProcessingConfiguration);
+                    this._extendClassWithConfig(skyboxMaterial.imageProcessingConfiguration, skyboxConifguration.material.imageProcessingConfiguration);
                 }
             }
         }
     }
 
-    protected configureScene(sceneConfig: ISceneConfiguration, optimizerConfig?: ISceneOptimizerConfiguration) {
+    /**
+     * internally configure the scene using the provided configuration.
+     * The scene will not be recreated, but just updated.
+     * @param sceneConfig the (new) scene configuration
+     */
+    protected _configureScene(sceneConfig: ISceneConfiguration) {
         // sanity check!
         if (!this.scene) {
             return;
@@ -330,7 +431,7 @@ export abstract class AbstractViewer {
 
         // image processing configuration - optional.
         if (sceneConfig.imageProcessingConfiguration) {
-            this.extendClassWithConfig(this.scene.imageProcessingConfiguration, sceneConfig.imageProcessingConfiguration);
+            this._extendClassWithConfig(this.scene.imageProcessingConfiguration, sceneConfig.imageProcessingConfiguration);
         }
         if (sceneConfig.environmentTexture) {
             if (this.scene.environmentTexture) {
@@ -345,7 +446,13 @@ export abstract class AbstractViewer {
         }
     }
 
-    protected configureOptimizer(optimizerConfig: ISceneOptimizerConfiguration | boolean) {
+
+    /**
+     * Configure the scene optimizer.
+     * The existing scene optimizer will be disposed and a new one will be created.
+     * @param optimizerConfig the (new) optimizer configuration
+     */
+    protected _configureOptimizer(optimizerConfig: ISceneOptimizerConfiguration | boolean) {
         if (typeof optimizerConfig === 'boolean') {
             if (this.sceneOptimizer) {
                 this.sceneOptimizer.stop();
@@ -381,31 +488,41 @@ export abstract class AbstractViewer {
         }
     }
 
-    protected configureObservers(observersConfiguration: IObserversConfiguration) {
+    /**
+     * this is used to register native functions using the configuration object.
+     * This will configure the observers.
+     * @param observersConfiguration observers configuration
+     */
+    protected _configureObservers(observersConfiguration: IObserversConfiguration) {
         if (observersConfiguration.onEngineInit) {
             this.onEngineInitObservable.add(window[observersConfiguration.onEngineInit]);
         } else {
-            if (observersConfiguration.onEngineInit === '' && this.configuration.observers && this.configuration.observers!.onEngineInit) {
-                this.onEngineInitObservable.removeCallback(window[this.configuration.observers!.onEngineInit!]);
+            if (observersConfiguration.onEngineInit === '' && this._configuration.observers && this._configuration.observers!.onEngineInit) {
+                this.onEngineInitObservable.removeCallback(window[this._configuration.observers!.onEngineInit!]);
             }
         }
         if (observersConfiguration.onSceneInit) {
             this.onSceneInitObservable.add(window[observersConfiguration.onSceneInit]);
         } else {
-            if (observersConfiguration.onSceneInit === '' && this.configuration.observers && this.configuration.observers!.onSceneInit) {
-                this.onSceneInitObservable.removeCallback(window[this.configuration.observers!.onSceneInit!]);
+            if (observersConfiguration.onSceneInit === '' && this._configuration.observers && this._configuration.observers!.onSceneInit) {
+                this.onSceneInitObservable.removeCallback(window[this._configuration.observers!.onSceneInit!]);
             }
         }
         if (observersConfiguration.onModelLoaded) {
             this.onModelLoadedObservable.add(window[observersConfiguration.onModelLoaded]);
         } else {
-            if (observersConfiguration.onModelLoaded === '' && this.configuration.observers && this.configuration.observers!.onModelLoaded) {
-                this.onModelLoadedObservable.removeCallback(window[this.configuration.observers!.onModelLoaded!]);
+            if (observersConfiguration.onModelLoaded === '' && this._configuration.observers && this._configuration.observers!.onModelLoaded) {
+                this.onModelLoadedObservable.removeCallback(window[this._configuration.observers!.onModelLoaded!]);
             }
         }
     }
 
-    protected configureCamera(cameraConfig: ICameraConfiguration, model?: ViewerModel) {
+    /**
+     * (Re) configure the camera. The camera will only be created once and from this point will only be reconfigured.
+     * @param cameraConfig the new camera configuration
+     * @param model optionally use the model to configure the camera.
+     */
+    protected _configureCamera(cameraConfig: ICameraConfiguration, model?: ViewerModel) {
         let focusMeshes = model ? model.meshes : this.scene.meshes;
 
         if (!this.scene.activeCamera) {
@@ -420,14 +537,14 @@ export abstract class AbstractViewer {
             this.camera.rotationQuaternion = new Quaternion(cameraConfig.rotation.x || 0, cameraConfig.rotation.y || 0, cameraConfig.rotation.z || 0, cameraConfig.rotation.w || 0)
         }
 
-        this.extendClassWithConfig(this.camera, cameraConfig);
+        this._extendClassWithConfig(this.camera, cameraConfig);
 
         this.camera.minZ = cameraConfig.minZ || this.camera.minZ;
         this.camera.maxZ = cameraConfig.maxZ || this.camera.maxZ;
 
         if (cameraConfig.behaviors) {
             for (let name in cameraConfig.behaviors) {
-                this.setCameraBehavior(cameraConfig.behaviors[name], focusMeshes);
+                this._setCameraBehavior(cameraConfig.behaviors[name], focusMeshes);
             }
         };
 
@@ -440,14 +557,20 @@ export abstract class AbstractViewer {
             this.camera.upperRadiusLimit = sceneDiagonalLenght * 3;
     }
 
-    protected configureLights(lightsConfiguration: { [name: string]: ILightConfiguration | boolean } = {}, model?: ViewerModel) {
+    /**
+     * configure the lights.
+     * 
+     * @param lightsConfiguration the (new) light(s) configuration
+     * @param model optionally use the model to configure the camera.
+     */
+    protected _configureLights(lightsConfiguration: { [name: string]: ILightConfiguration | boolean } = {}, model?: ViewerModel) {
         let focusMeshes = model ? model.meshes : this.scene.meshes;
         // sanity check!
         if (!Object.keys(lightsConfiguration).length) return;
 
         let lightsAvailable: Array<string> = this.scene.lights.map(light => light.name);
         // compare to the global (!) configuration object and dispose unneeded:
-        let lightsToConfigure = Object.keys(this.configuration.lights || []);
+        let lightsToConfigure = Object.keys(this._configuration.lights || []);
         if (Object.keys(lightsToConfigure).length !== lightsAvailable.length) {
             lightsAvailable.forEach(lName => {
                 if (lightsToConfigure.indexOf(lName) === -1) {
@@ -493,7 +616,7 @@ export abstract class AbstractViewer {
             light.setEnabled(enabled);
 
 
-            this.extendClassWithConfig(light, lightConfig);
+            this._extendClassWithConfig(light, lightConfig);
 
             //position. Some lights don't support shadows
             if (light instanceof ShadowLight) {
@@ -507,12 +630,12 @@ export abstract class AbstractViewer {
                     light.direction = direction;
                 }
                 let shadowGenerator = light.getShadowGenerator();
-                if (lightConfig.shadowEnabled && this.maxShadows) {
+                if (lightConfig.shadowEnabled && this._maxShadows) {
                     if (!shadowGenerator) {
                         shadowGenerator = new ShadowGenerator(512, light);
                         // TODO blur kernel definition
                     }
-                    this.extendClassWithConfig(shadowGenerator, lightConfig.shadowConfig || {});
+                    this._extendClassWithConfig(shadowGenerator, lightConfig.shadowConfig || {});
                     // add the focues meshes to the shadow list
                     let shadownMap = shadowGenerator.getShadowMap();
                     if (!shadownMap) return;
@@ -529,17 +652,24 @@ export abstract class AbstractViewer {
         });
     }
 
-    protected configureModel(modelConfiguration: Partial<IModelConfiguration>, model?: ViewerModel) {
+    /**
+     * configure all models using the configuration.
+     * @param modelConfiguration the configuration to use to reconfigure the models
+     */
+    protected _configureModel(modelConfiguration: Partial<IModelConfiguration>) {
         this.models.forEach(model => {
-            model.configuration = modelConfiguration;
+            model.updateConfiguration(modelConfiguration);
         })
     }
 
+    /**
+     * Dispoe the entire viewer including the scene and the engine
+     */
     public dispose() {
         if (this._isDisposed) {
             return;
         }
-        window.removeEventListener('resize', this.resize);
+        window.removeEventListener('resize', this._resize);
         if (this.sceneOptimizer) {
             this.sceneOptimizer.stop();
             this.sceneOptimizer.dispose();
@@ -589,17 +719,18 @@ export abstract class AbstractViewer {
         this._isDisposed = true;
     }
 
-    protected abstract prepareContainerElement();
+    /**
+     * This will prepare the container element for the viewer
+     */
+    protected abstract _prepareContainerElement();
 
     /**
      * This function will execute when the HTML templates finished initializing.
      * It should initialize the engine and continue execution.
      * 
-     * @protected
      * @returns {Promise<AbstractViewer>} The viewer object will be returned after the object was loaded.
-     * @memberof AbstractViewer
      */
-    protected onTemplatesLoaded(): Promise<AbstractViewer> {
+    protected _onTemplatesLoaded(): Promise<AbstractViewer> {
         return Promise.resolve(this);
     }
 
@@ -609,15 +740,15 @@ export abstract class AbstractViewer {
      * But first - it will load the extendible onTemplateLoaded()!
      */
     private _onTemplateLoaded(): Promise<AbstractViewer> {
-        return this.onTemplatesLoaded().then(() => {
-            let autoLoadModel = this.configuration.model;
-            return this.initEngine().then((engine) => {
+        return this._onTemplatesLoaded().then(() => {
+            let autoLoadModel = this._configuration.model;
+            return this._initEngine().then((engine) => {
                 return this.onEngineInitObservable.notifyObserversWithPromise(engine);
             }).then(() => {
                 if (autoLoadModel) {
                     return this.loadModel().catch(e => { }).then(() => { return this.scene });
                 } else {
-                    return this.scene || this.initScene();
+                    return this.scene || this._initScene();
                 }
             }).then((scene) => {
                 return this.onSceneInitObservable.notifyObserversWithPromise(scene);
@@ -637,16 +768,16 @@ export abstract class AbstractViewer {
      * @returns {Promise<Engine>} 
      * @memberof Viewer
      */
-    protected initEngine(): Promise<Engine> {
+    protected _initEngine(): Promise<Engine> {
 
         // init custom shaders
-        this.injectCustomShaders();
+        this._injectCustomShaders();
 
         let canvasElement = this.templateManager.getCanvas();
         if (!canvasElement) {
             return Promise.reject('Canvas element not found!');
         }
-        let config = this.configuration.engine || {};
+        let config = this._configuration.engine || {};
         // TDO enable further configuration
         this.engine = new Engine(canvasElement, !!config.antialiasing, config.engineOptions);
 
@@ -654,24 +785,27 @@ export abstract class AbstractViewer {
         Database.IDBStorageEnabled = false;
 
         if (!config.disableResize) {
-            window.addEventListener('resize', this.resize);
+            window.addEventListener('resize', this._resize);
         }
 
 
-        this.engine.runRenderLoop(this.render);
+        this.engine.runRenderLoop(this._render);
 
-        if (this.configuration.engine && this.configuration.engine.adaptiveQuality) {
+        if (this._configuration.engine && this._configuration.engine.adaptiveQuality) {
             var scale = Math.max(0.5, 1 / (window.devicePixelRatio || 2));
             this.engine.setHardwareScalingLevel(scale);
         }
 
         // set hardware limitations for scene initialization
-        this.handleHardwareLimitations();
+        this._handleHardwareLimitations();
 
         return Promise.resolve(this.engine);
     }
 
-    protected initScene(): Promise<Scene> {
+    /**
+     * initialize the scene. Calling thsi function again will dispose the old scene, if exists.
+     */
+    protected _initScene(): Promise<Scene> {
 
         // if the scen exists, dispose it.
         if (this.scene) {
@@ -683,30 +817,36 @@ export abstract class AbstractViewer {
         // make sure there is a default camera and light.
         this.scene.createDefaultLight(true);
 
-        if (this.configuration.scene) {
-            this.configureScene(this.configuration.scene);
+        if (this._configuration.scene) {
+            this._configureScene(this._configuration.scene);
 
             // Scene optimizer
-            if (this.configuration.optimizer) {
-                this.configureOptimizer(this.configuration.optimizer);
+            if (this._configuration.optimizer) {
+                this._configureOptimizer(this._configuration.optimizer);
             }
         }
 
         return Promise.resolve(this.scene);
     }
 
-    private isLoading: boolean;
-    private nextLoading: Function;
-
-    public initModel(modelConfig: any = this.configuration.model, clearScene: boolean = true): ViewerModel {
-        let model = this.modelLoader.load(modelConfig);
+    private _isLoading: boolean;
+    private _nextLoading: Function;
 
+    /**
+     * Initialize a model loading. The returns object (a ViewerModel object) will be loaded in the background.
+     * The difference between this and loadModel is that loadModel will fulfill the promise when the model finished loading.
+     * 
+     * @param modelConfig model configuration to use when loading the model.
+     * @param clearScene should the scene be cleared before loading this model
+     * @returns a ViewerModel object that is not yet fully loaded.
+     */
+    public initModel(modelConfig: IModelConfiguration, clearScene: boolean = true): ViewerModel {
         if (clearScene) {
             this.models.forEach(m => m.dispose());
             this.models.length = 0;
         }
+        let model = this.modelLoader.load(modelConfig);
 
-        this.models.push(model);
         this.lastUsedLoader = model.loader;
         model.onLoadErrorObservable.add((errorObject) => {
             this.onModelLoadErrorObservable.notifyObserversWithPromise(errorObject);
@@ -719,14 +859,14 @@ export abstract class AbstractViewer {
         model.onLoadedObservable.add(() => {
             this.onModelLoadedObservable.notifyObserversWithPromise(model)
                 .then(() => {
-                    this.configureLights(this.configuration.lights);
+                    this._configureLights(this._configuration.lights);
 
-                    if (this.configuration.camera) {
-                        this.configureCamera(this.configuration.camera, model);
+                    if (this._configuration.camera || !this.scene.activeCamera) {
+                        this._configureCamera(this._configuration.camera || {}, model);
                     }
-                    return this.initEnvironment(model);
+                    return this._initEnvironment(model);
                 }).then(() => {
-                    this.isLoading = false;
+                    this._isLoading = false;
                     return model;
                 });
         });
@@ -735,31 +875,38 @@ export abstract class AbstractViewer {
         return model;
     }
 
-    public loadModel(modelConfig: any = this.configuration.model, clearScene: boolean = true): Promise<ViewerModel> {
+    /**
+     * load a model using the provided configuration
+     * 
+     * @param modelConfig the model configuration or URL to load.
+     * @param clearScene Should the scene be cleared before loading the model
+     * @returns a Promise the fulfills when the model finished loading successfully. 
+     */
+    public loadModel(modelConfig: any = this._configuration.model, clearScene: boolean = true): Promise<ViewerModel> {
         // no model was provided? Do nothing!
         let modelUrl = (typeof modelConfig === 'string') ? modelConfig : modelConfig.url;
         if (!modelUrl) {
             return Promise.reject("no model configuration found");
         }
-        if (this.isLoading) {
+        if (this._isLoading) {
             // We can decide here whether or not to cancel the lst load, but the developer can do that.
             return Promise.reject("another model is curently being loaded.");
         }
-        this.isLoading = true;
+        this._isLoading = true;
         if ((typeof modelConfig === 'string')) {
-            if (this.configuration.model && typeof this.configuration.model === 'object') {
-                this.configuration.model.url = modelConfig;
+            if (this._configuration.model && typeof this._configuration.model === 'object') {
+                this._configuration.model.url = modelConfig;
             }
         } else {
-            if (this.configuration.model) {
-                deepmerge(this.configuration.model, modelConfig)
+            if (this._configuration.model) {
+                deepmerge(this._configuration.model, modelConfig)
             } else {
-                this.configuration.model = modelConfig;
+                this._configuration.model = modelConfig;
             }
         }
 
         return Promise.resolve(this.scene).then((scene) => {
-            if (!scene) return this.initScene();
+            if (!scene) return this._initScene();
             return scene;
         }).then(() => {
             return new Promise<ViewerModel>((resolve, reject) => {
@@ -769,26 +916,32 @@ export abstract class AbstractViewer {
         })
     }
 
-    protected initEnvironment(model?: ViewerModel): Promise<Scene> {
-        this.configureEnvironment(this.configuration.skybox, this.configuration.ground);
+    /**
+     * initialize the environment for a specific model.
+     * Per default it will use the viewer'S configuration.
+     * @param model the model to use to configure the environment.
+     * @returns a Promise that will resolve when the configuration is done.
+     */
+    protected _initEnvironment(model?: ViewerModel): Promise<Scene> {
+        this._configureEnvironment(this._configuration.skybox, this._configuration.ground);
 
         return Promise.resolve(this.scene);
     }
 
     /**
-		 * Alters render settings to reduce features based on hardware feature limitations
-		 * @param options Viewer options to modify
-		 */
-    protected handleHardwareLimitations() {
+     * Alters render settings to reduce features based on hardware feature limitations
+     * @param enableHDR Allows the viewer to run in HDR mode.
+     */
+    protected _handleHardwareLimitations(enableHDR = true) {
         //flip rendering settings switches based on hardware support
         let maxVaryingRows = this.engine.getCaps().maxVaryingVectors;
         let maxFragmentSamplers = this.engine.getCaps().maxTexturesImageUnits;
 
         //shadows are disabled if there's not enough varyings for a single shadow
         if ((maxVaryingRows < 8) || (maxFragmentSamplers < 8)) {
-            this.maxShadows = 0;
+            this._maxShadows = 0;
         } else {
-            this.maxShadows = 3;
+            this._maxShadows = 3;
         }
 
         //can we render to any >= 16-bit targets (required for HDR)
@@ -796,27 +949,27 @@ export abstract class AbstractViewer {
         let linearHalfFloatTargets = caps.textureHalfFloatRender && caps.textureHalfFloatLinearFiltering;
         let linearFloatTargets = caps.textureFloatRender && caps.textureFloatLinearFiltering;
 
-        this._hdrSupport = !!(linearFloatTargets || linearHalfFloatTargets);
+        this._hdrSupport = enableHDR && !!(linearFloatTargets || linearHalfFloatTargets);
 
         if (linearHalfFloatTargets) {
-            this.defaultHighpTextureType = Engine.TEXTURETYPE_HALF_FLOAT;
-            this.shadowGeneratorBias = 0.002;
+            this._defaultHighpTextureType = Engine.TEXTURETYPE_HALF_FLOAT;
+            this._shadowGeneratorBias = 0.002;
         } else if (linearFloatTargets) {
-            this.defaultHighpTextureType = Engine.TEXTURETYPE_FLOAT;
-            this.shadowGeneratorBias = 0.001;
+            this._defaultHighpTextureType = Engine.TEXTURETYPE_FLOAT;
+            this._shadowGeneratorBias = 0.001;
         } else {
-            this.defaultHighpTextureType = Engine.TEXTURETYPE_UNSIGNED_INT;
-            this.shadowGeneratorBias = 0.001;
+            this._defaultHighpTextureType = Engine.TEXTURETYPE_UNSIGNED_INT;
+            this._shadowGeneratorBias = 0.001;
         }
 
-        this.defaultPipelineTextureType = this._hdrSupport ? this.defaultHighpTextureType : Engine.TEXTURETYPE_UNSIGNED_INT;
+        this._defaultPipelineTextureType = this._hdrSupport ? this._defaultHighpTextureType : Engine.TEXTURETYPE_UNSIGNED_INT;
     }
 
     /**
      * Injects all the spectre shader in the babylon shader store
      */
-    protected injectCustomShaders(): void {
-        let customShaders = this.configuration.customShaders;
+    protected _injectCustomShaders(): void {
+        let customShaders = this._configuration.customShaders;
         // Inject all the spectre shader in the babylon shader store.
         if (!customShaders) {
             return;
@@ -835,14 +988,21 @@ export abstract class AbstractViewer {
         }
     }
 
-    protected extendClassWithConfig(object: any, config: any) {
+    /**
+     * This will extend an object with configuration values.
+     * What it practically does it take the keys from the configuration and set them on the object.
+     * I the configuration is a tree, it will traverse into the tree.
+     * @param object the object to extend
+     * @param config the configuration object that will extend the object
+     */
+    protected _extendClassWithConfig(object: any, config: any) {
         if (!config) return;
         Object.keys(config).forEach(key => {
             if (key in object && typeof object[key] !== 'function') {
                 // if (typeof object[key] === 'function') return;
                 // if it is an object, iterate internally until reaching basic types
                 if (typeof object[key] === 'object') {
-                    this.extendClassWithConfig(object[key], config[key]);
+                    this._extendClassWithConfig(object[key], config[key]);
                 } else {
                     if (config[key] !== undefined) {
                         object[key] = config[key];
@@ -852,7 +1012,7 @@ export abstract class AbstractViewer {
         });
     }
 
-    private setCameraBehavior(behaviorConfig: number | {
+    private _setCameraBehavior(behaviorConfig: number | {
         type: number;
         [propName: string]: any;
     }, payload: any) {
@@ -883,7 +1043,7 @@ export abstract class AbstractViewer {
 
         if (behavior) {
             if (typeof behaviorConfig === "object") {
-                this.extendClassWithConfig(behavior, behaviorConfig);
+                this._extendClassWithConfig(behavior, behaviorConfig);
             }
         }
 

+ 47 - 9
Viewer/src/viewer/viewerManager.ts

@@ -1,43 +1,78 @@
 import { Observable } from 'babylonjs';
 import { AbstractViewer } from './viewer';
 
+/**
+ * The viewer manager is the container for all viewers currently registered on this page.
+ * It is possible to have more than one viewer on a single page.
+ */
 export class ViewerManager {
 
-    private viewers: { [key: string]: AbstractViewer };
+    private _viewers: { [key: string]: AbstractViewer };
 
+    /**
+     * A callback that will be triggered when a new viewer was added
+     */
     public onViewerAdded: (viewer: AbstractViewer) => void;
+    /**
+     * Will notify when a new viewer was added
+     */
     public onViewerAddedObservable: Observable<AbstractViewer>;
+    /**
+     * Will notify when a viewer was removed (disposed)
+     */
     public onViewerRemovedObservable: Observable<string>;
 
     constructor() {
-        this.viewers = {};
+        this._viewers = {};
         this.onViewerAddedObservable = new Observable();
         this.onViewerRemovedObservable = new Observable();
     }
 
+    /**
+     * Adding a new viewer to the viewer manager and start tracking it.
+     * @param viewer the viewer to add
+     */
     public addViewer(viewer: AbstractViewer) {
-        this.viewers[viewer.getBaseId()] = viewer;
+        this._viewers[viewer.getBaseId()] = viewer;
         this._onViewerAdded(viewer);
     }
 
+    /**
+     * remove a viewer from the viewer manager
+     * @param viewer the viewer to remove
+     */
     public removeViewer(viewer: AbstractViewer) {
         let id = viewer.getBaseId();
-        delete this.viewers[id];
+        delete this._viewers[id];
         this.onViewerRemovedObservable.notifyObservers(id);
     }
 
+    /**
+     * Get a viewer by its baseId (if the container element has an ID, it is the this is. if not, a random id was assigned)
+     * @param id the id of the HTMl element (or the viewer's, if none provided)
+     */
     public getViewerById(id: string): AbstractViewer {
-        return this.viewers[id];
+        return this._viewers[id];
     }
 
+    /**
+     * Get a viewer using a container element
+     * @param element the HTML element to search viewers associated with
+     */
     public getViewerByHTMLElement(element: HTMLElement) {
-        for (let id in this.viewers) {
-            if (this.viewers[id].containerElement === element) {
+        for (let id in this._viewers) {
+            if (this._viewers[id].containerElement === element) {
                 return this.getViewerById(id);
             }
         }
     }
 
+    /**
+     * Get a promise that will fullfil when this viewer was initialized.
+     * Since viewer initialization and template injection is asynchronous, using the promise will guaranty that
+     * you will get the viewer after everything was already configured.
+     * @param id the viewer id to find
+     */
     public getViewerPromiseById(id: string): Promise<AbstractViewer> {
         return new Promise((resolve, reject) => {
             let localViewer = this.getViewerById(id)
@@ -59,9 +94,12 @@ export class ViewerManager {
         this.onViewerAddedObservable.notifyObservers(viewer);
     }
 
+    /**
+     * dispose the manager and all of its associated viewers
+     */
     public dispose() {
-        for (let id in this.viewers) {
-            this.viewers[id].dispose();
+        for (let id in this._viewers) {
+            this._viewers[id].dispose();
         }
     }
 }

+ 10 - 3
Viewer/tsconfig-gulp.json

@@ -22,11 +22,18 @@
         "baseUrl": ".",
         "paths": {
             "babylonjs": [
-                "../dist/preview release/babylon.max.js"
+                "../dist/preview release/babylon.d.ts"
             ],
             "babylonjs-loaders": [
-                "../dist/preview release/loaders/babylonjs.loaders.js"
+                "../dist/preview release/loaders/babylonjs.loaders.module.d.ts"
+            ],
+            "babylonjs-gltf2interface": [
+                "../dist/babylon.glTF2Interface.d.ts"
             ]
         }
-    }
+    },
+    "exclude": [
+        "node_modules",
+        "dist"
+    ]
 }

+ 11 - 6
Viewer/tsconfig.json

@@ -19,18 +19,23 @@
         "types": [
             "node"
         ],
-        "baseUrl": ".",
+        "baseUrl": "./src/",
         "paths": {
             "babylonjs": [
-                "../dist/preview release/babylon.max.js",
-                "../dist/preview release/babylon.d.ts"
+                "../../dist/preview release/babylon.d.ts"
             ],
             "babylonjs-loaders": [
-                "../dist/preview release/loaders/babylonjs.loaders.js",
-                "../dist/preview release/loaders/babylonjs.loaders.module.d.ts"
+                "../../dist/preview release/loaders/babylonjs.loaders.module.d.ts"
+            ],
+            "babylonjs-gltf2interface": [
+                "../../dist/babylon.glTF2Interface.d.ts"
             ]
-        }
+        },
+        //"outDir": "./dist/build"
     },
+    "files": [
+        "./src/index.ts"
+    ],
     "exclude": [
         "node_modules",
         "dist"

+ 2 - 1
Viewer/webpack.config.js

@@ -26,7 +26,8 @@ module.exports = {
         // until physics will be integrated in the viewer, ignore cannon
         cannon: 'CANNON',
         oimo: 'OIMO',
-        './Oimo': 'OIMO'
+        './Oimo': 'OIMO',
+        "earcut": true
     },
     devtool: 'source-map',
     plugins: [

+ 2 - 1
Viewer/webpack.gulp.config.js

@@ -13,7 +13,8 @@ module.exports = {
         cannon: 'CANNON',
         oimo: 'OIMO',
         vertx: true,
-        "./Oimo": "OIMO"
+        "./Oimo": "OIMO",
+        "earcut": true
     },
     resolve: {
         extensions: ['.ts', '.js'],

Різницю між файлами не показано, бо вона завелика
+ 11722 - 10426
dist/preview release/babylon.d.ts


Різницю між файлами не показано, бо вона завелика
+ 60 - 60
dist/preview release/babylon.js


Різницю між файлами не показано, бо вона завелика
+ 1867 - 1201
dist/preview release/babylon.max.js


Різницю між файлами не показано, бо вона завелика
+ 61 - 61
dist/preview release/babylon.worker.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 29515
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


Різницю між файлами не показано, бо вона завелика
+ 0 - 62
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 96733
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 30389
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts


Різницю між файлами не показано, бо вона завелика
+ 0 - 96703
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js


+ 15 - 0
dist/preview release/earcut.license

@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) 2016, Mapbox
+
+Permission to use, copy, modify, and/or distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright notice
+and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.

Різницю між файлами не показано, бо вона завелика
+ 1 - 0
dist/preview release/earcut.min.js


Різницю між файлами не показано, бо вона завелика
+ 1852 - 1198
dist/preview release/es6.js


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

@@ -1,7 +1,7 @@
 {
     "name": "babylonjs-gltf2interface",
     "description": "A typescript declaration of babylon's gltf2 inteface.",
-    "version": "3.2.0-beta.1",
+    "version": "3.2.0-beta.3",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 0 - 10
dist/preview release/gui/babylon.gui.d.ts

@@ -211,42 +211,34 @@ declare module BABYLON.GUI {
         readonly typeName: string;
         /**
         * An event triggered when the pointer move over the control.
-        * @type {BABYLON.Observable}
         */
         onPointerMoveObservable: Observable<Vector2>;
         /**
         * An event triggered when the pointer move out of the control.
-        * @type {BABYLON.Observable}
         */
         onPointerOutObservable: Observable<Control>;
         /**
         * An event triggered when the pointer taps the control
-        * @type {BABYLON.Observable}
         */
         onPointerDownObservable: Observable<Vector2WithInfo>;
         /**
         * An event triggered when pointer up
-        * @type {BABYLON.Observable}
         */
         onPointerUpObservable: Observable<Vector2WithInfo>;
         /**
         * An event triggered when a control is clicked on
-        * @type {BABYLON.Observable}
         */
         onPointerClickObservable: Observable<Vector2WithInfo>;
         /**
         * An event triggered when pointer enters the control
-        * @type {BABYLON.Observable}
         */
         onPointerEnterObservable: Observable<Control>;
         /**
         * An event triggered when the control is marked as dirty
-        * @type {BABYLON.Observable}
         */
         onDirtyObservable: Observable<Control>;
         /**
        * An event triggered after the control is drawn
-       * @type {BABYLON.Observable}
        */
         onAfterDrawObservable: Observable<Control>;
         alpha: number;
@@ -571,12 +563,10 @@ declare module BABYLON.GUI {
         private _outlineColor;
         /**
         * An event triggered after the text is changed
-        * @type {BABYLON.Observable}
         */
         onTextChangedObservable: Observable<TextBlock>;
         /**
         * An event triggered after the text was broken up into lines
-        * @type {BABYLON.Observable}
         */
         onLinesReadyObservable: Observable<TextBlock>;
         /**

+ 1 - 10
dist/preview release/gui/babylon.gui.js

@@ -909,42 +909,34 @@ var BABYLON;
                 this._linkOffsetY = new GUI.ValueAndUnit(0);
                 /**
                 * An event triggered when the pointer move over the control.
-                * @type {BABYLON.Observable}
                 */
                 this.onPointerMoveObservable = new BABYLON.Observable();
                 /**
                 * An event triggered when the pointer move out of the control.
-                * @type {BABYLON.Observable}
                 */
                 this.onPointerOutObservable = new BABYLON.Observable();
                 /**
                 * An event triggered when the pointer taps the control
-                * @type {BABYLON.Observable}
                 */
                 this.onPointerDownObservable = new BABYLON.Observable();
                 /**
                 * An event triggered when pointer up
-                * @type {BABYLON.Observable}
                 */
                 this.onPointerUpObservable = new BABYLON.Observable();
                 /**
                 * An event triggered when a control is clicked on
-                * @type {BABYLON.Observable}
                 */
                 this.onPointerClickObservable = new BABYLON.Observable();
                 /**
                 * An event triggered when pointer enters the control
-                * @type {BABYLON.Observable}
                 */
                 this.onPointerEnterObservable = new BABYLON.Observable();
                 /**
                 * An event triggered when the control is marked as dirty
-                * @type {BABYLON.Observable}
                 */
                 this.onDirtyObservable = new BABYLON.Observable();
                 /**
                * An event triggered after the control is drawn
-               * @type {BABYLON.Observable}
                */
                 this.onAfterDrawObservable = new BABYLON.Observable();
             }
@@ -3413,12 +3405,10 @@ var BABYLON;
                 _this._outlineColor = "white";
                 /**
                 * An event triggered after the text is changed
-                * @type {BABYLON.Observable}
                 */
                 _this.onTextChangedObservable = new BABYLON.Observable();
                 /**
                 * An event triggered after the text was broken up into lines
-                * @type {BABYLON.Observable}
                 */
                 _this.onLinesReadyObservable = new BABYLON.Observable();
                 _this.text = text;
@@ -5139,5 +5129,6 @@ var BABYLON;
 })(BABYLON || (BABYLON = {}));
 
     
+
     return BABYLON.GUI;
 });

Різницю між файлами не показано, бо вона завелика
+ 4 - 4
dist/preview release/gui/babylon.gui.min.js


+ 0 - 11
dist/preview release/gui/babylon.gui.module.d.ts

@@ -1,4 +1,3 @@
-/// <reference types="babylonjs"/>
 
 
 declare module 'babylonjs-gui' { 
@@ -217,42 +216,34 @@ declare module BABYLON.GUI {
         readonly typeName: string;
         /**
         * An event triggered when the pointer move over the control.
-        * @type {BABYLON.Observable}
         */
         onPointerMoveObservable: Observable<Vector2>;
         /**
         * An event triggered when the pointer move out of the control.
-        * @type {BABYLON.Observable}
         */
         onPointerOutObservable: Observable<Control>;
         /**
         * An event triggered when the pointer taps the control
-        * @type {BABYLON.Observable}
         */
         onPointerDownObservable: Observable<Vector2WithInfo>;
         /**
         * An event triggered when pointer up
-        * @type {BABYLON.Observable}
         */
         onPointerUpObservable: Observable<Vector2WithInfo>;
         /**
         * An event triggered when a control is clicked on
-        * @type {BABYLON.Observable}
         */
         onPointerClickObservable: Observable<Vector2WithInfo>;
         /**
         * An event triggered when pointer enters the control
-        * @type {BABYLON.Observable}
         */
         onPointerEnterObservable: Observable<Control>;
         /**
         * An event triggered when the control is marked as dirty
-        * @type {BABYLON.Observable}
         */
         onDirtyObservable: Observable<Control>;
         /**
        * An event triggered after the control is drawn
-       * @type {BABYLON.Observable}
        */
         onAfterDrawObservable: Observable<Control>;
         alpha: number;
@@ -577,12 +568,10 @@ declare module BABYLON.GUI {
         private _outlineColor;
         /**
         * An event triggered after the text is changed
-        * @type {BABYLON.Observable}
         */
         onTextChangedObservable: Observable<TextBlock>;
         /**
         * An event triggered after the text was broken up into lines
-        * @type {BABYLON.Observable}
         */
         onLinesReadyObservable: Observable<TextBlock>;
         /**

+ 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-beta.1",
+    "version": "3.2.0-beta.3",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

Різницю між файлами не показано, бо вона завелика
+ 4 - 4
dist/preview release/inspector/babylon.inspector.bundle.js


+ 7 - 0
dist/preview release/inspector/babylon.inspector.d.ts

@@ -1165,6 +1165,13 @@ declare module INSPECTOR {
 }
 
 declare module INSPECTOR {
+    class FullscreenTool extends AbstractTool {
+        constructor(parent: HTMLElement, inspector: Inspector);
+        action(): void;
+    }
+}
+
+declare module INSPECTOR {
     class TreeItem extends BasicElement {
         private _tab;
         private _adapter;

+ 54 - 0
dist/preview release/inspector/babylon.inspector.js

@@ -3441,6 +3441,25 @@ var INSPECTOR;
                 point.addEventListener('click', function () { _this._inspector.scene.forcePointsCloud = true; _this._inspector.scene.forceWireframe = false; });
                 wireframe.addEventListener('click', function () { _this._inspector.scene.forcePointsCloud = false; _this._inspector.scene.forceWireframe = true; });
                 solid.addEventListener('click', function () { _this._inspector.scene.forcePointsCloud = false; _this._inspector.scene.forceWireframe = false; });
+                // Cameras
+                title = INSPECTOR.Helpers.CreateDiv('actions-title', _this._actions);
+                title.textContent = 'Cameras';
+                var cameraRadioButtons = [];
+                var _loop_1 = function (camera) {
+                    var cameraRadio = INSPECTOR.Helpers.CreateDiv('action-radio', this_1._actions);
+                    cameraRadio.textContent = camera.name;
+                    if (this_1._inspector.scene.activeCamera == camera) {
+                        cameraRadio.classList.add('active');
+                    }
+                    cameraRadioButtons.push(cameraRadio);
+                    cameraRadio.addEventListener('click', function () { _this._inspector.scene.switchActiveCamera(camera); });
+                };
+                var this_1 = this;
+                for (var _a = 0, _b = _this._inspector.scene.cameras; _a < _b.length; _a++) {
+                    var camera = _b[_a];
+                    _loop_1(camera);
+                }
+                _this._generateRadioAction(cameraRadioButtons);
                 // Textures
                 title = INSPECTOR.Helpers.CreateDiv('actions-title', _this._actions);
                 title.textContent = 'Textures channels';
@@ -4629,6 +4648,8 @@ var INSPECTOR;
             if (!this._inspector.popupMode && !INSPECTOR.Helpers.IsBrowserEdge()) {
                 this._tools.push(new INSPECTOR.PopupTool(this._div, this._inspector));
             }
+            // FullScreen
+            this._tools.push(new INSPECTOR.FullscreenTool(this._div, this._inspector));
             // Pause schedule
             this._tools.push(new INSPECTOR.PauseScheduleTool(this._div, this._inspector));
             // Pause schedule
@@ -4694,6 +4715,39 @@ var __extends = (this && this.__extends) || (function () {
 })();
 var INSPECTOR;
 (function (INSPECTOR) {
+    var FullscreenTool = /** @class */ (function (_super) {
+        __extends(FullscreenTool, _super);
+        function FullscreenTool(parent, inspector) {
+            return _super.call(this, 'fa-expand', parent, inspector, 'Open the scene in fullscreen, press Esc to exit') || this;
+        }
+        // Action : refresh the whole panel
+        FullscreenTool.prototype.action = function () {
+            var elem = document.body;
+            function requestFullScreen(element) {
+                // Supports most browsers and their versions.
+                var requestMethod = element.requestFullscreen || element.webkitRequestFullScreen;
+                requestMethod.call(element);
+            }
+            requestFullScreen(elem);
+        };
+        return FullscreenTool;
+    }(INSPECTOR.AbstractTool));
+    INSPECTOR.FullscreenTool = FullscreenTool;
+})(INSPECTOR || (INSPECTOR = {}));
+
+"use strict";
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+var INSPECTOR;
+(function (INSPECTOR) {
     var TreeItem = /** @class */ (function (_super) {
         __extends(TreeItem, _super);
         function TreeItem(tab, obj) {

Різницю між файлами не показано, бо вона завелика
+ 4 - 4
dist/preview release/inspector/babylon.inspector.min.js


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

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

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

@@ -52,7 +52,6 @@ declare module BABYLON {
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
-        onAnimationGroupLoadedObservable: Observable<AnimationGroup>;
         onCompleteObservable: Observable<IGLTFLoader>;
         onDisposeObservable: Observable<IGLTFLoader>;
         onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
@@ -61,6 +60,7 @@ declare module BABYLON {
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
+            animationGroups: AnimationGroup[];
         }>;
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
@@ -116,12 +116,6 @@ declare module BABYLON {
         private _onMaterialLoadedObserver;
         onMaterialLoaded: (material: Material) => void;
         /**
-         * Raised when the loader creates an animation group after parsing the glTF properties of the animation.
-         */
-        readonly onAnimationGroupLoadedObservable: Observable<AnimationGroup>;
-        private _onAnimationGroupLoadedObserver;
-        onAnimationGroupLoaded: (animationGroup: AnimationGroup) => void;
-        /**
          * Raised when the asset is completely loaded, immediately before the loader is disposed.
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
@@ -162,6 +156,7 @@ declare module BABYLON {
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
+            animationGroups: AnimationGroup[];
         }>;
         loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
@@ -581,7 +576,6 @@ declare module BABYLON.GLTF1 {
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
-        onAnimationGroupLoadedObservable: Observable<AnimationGroup>;
         onCompleteObservable: Observable<IGLTFLoader>;
         onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
         state: Nullable<GLTFLoaderState>;
@@ -591,6 +585,7 @@ declare module BABYLON.GLTF1 {
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
+            animationGroups: AnimationGroup[];
         }>;
         private _loadAsync(scene, data, rootUrl, onSuccess, onProgress?, onError?);
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;

+ 7 - 21
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -78,10 +78,6 @@ var BABYLON;
              */
             this.onMaterialLoadedObservable = new BABYLON.Observable();
             /**
-             * Raised when the loader creates an animation group after parsing the glTF properties of the animation.
-             */
-            this.onAnimationGroupLoadedObservable = new BABYLON.Observable();
-            /**
              * Raised when the asset is completely loaded, immediately before the loader is disposed.
              * For assets with LODs, raised when all of the LODs are complete.
              * For assets without LODs, raised when the model is complete, immediately after onSuccess.
@@ -144,16 +140,6 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
-        Object.defineProperty(GLTFFileLoader.prototype, "onAnimationGroupLoaded", {
-            set: function (callback) {
-                if (this._onAnimationGroupLoadedObserver) {
-                    this.onAnimationGroupLoadedObservable.remove(this._onAnimationGroupLoadedObserver);
-                }
-                this._onAnimationGroupLoadedObserver = this.onAnimationGroupLoadedObservable.add(callback);
-            },
-            enumerable: true,
-            configurable: true
-        });
         Object.defineProperty(GLTFFileLoader.prototype, "onComplete", {
             set: function (callback) {
                 if (this._onCompleteObserver) {
@@ -246,6 +232,7 @@ var BABYLON;
                     Array.prototype.push.apply(container.meshes, result.meshes);
                     Array.prototype.push.apply(container.particleSystems, result.particleSystems);
                     Array.prototype.push.apply(container.skeletons, result.skeletons);
+                    Array.prototype.push.apply(container.animationGroups, result.animationGroups);
                     container.removeAllFromScene();
                     return container;
                 });
@@ -307,7 +294,6 @@ var BABYLON;
             loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
             loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
             loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
-            loader.onAnimationGroupLoadedObservable.add(function (animationGroup) { return _this.onAnimationGroupLoadedObservable.notifyObservers(animationGroup); });
             loader.onCompleteObservable.add(function () {
                 _this.onMeshLoadedObservable.clear();
                 _this.onTextureLoadedObservable.clear();
@@ -1872,7 +1858,6 @@ var BABYLON;
                 this.onMeshLoadedObservable = new BABYLON.Observable();
                 this.onTextureLoadedObservable = new BABYLON.Observable();
                 this.onMaterialLoadedObservable = new BABYLON.Observable();
-                this.onAnimationGroupLoadedObservable = new BABYLON.Observable();
                 this.onCompleteObservable = new BABYLON.Observable();
                 this.onExtensionLoadedObservable = new BABYLON.Observable();
                 this.state = null;
@@ -1927,12 +1912,12 @@ var BABYLON;
                             importMaterials(gltfRuntime);
                             postLoad(gltfRuntime);
                             if (!BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
-                                onSuccess(meshes, [], skeletons);
+                                onSuccess(meshes, skeletons);
                             }
                         });
                     }, onProgress);
                     if (BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
-                        onSuccess(meshes, [], skeletons);
+                        onSuccess(meshes, skeletons);
                     }
                 }, onError);
                 return true;
@@ -1940,11 +1925,12 @@ var BABYLON;
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
                 var _this = this;
                 return new Promise(function (resolve, reject) {
-                    _this._importMeshAsync(meshesNames, scene, data, rootUrl, function (meshes, particleSystems, skeletons) {
+                    _this._importMeshAsync(meshesNames, scene, data, rootUrl, function (meshes, skeletons) {
                         resolve({
                             meshes: meshes,
-                            particleSystems: particleSystems,
-                            skeletons: skeletons
+                            particleSystems: [],
+                            skeletons: skeletons,
+                            animationGroups: []
                         });
                     }, onProgress, function (message) {
                         reject(new Error(message));

Різницю між файлами не показано, бо вона завелика
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


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

@@ -52,7 +52,6 @@ declare module BABYLON {
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
-        onAnimationGroupLoadedObservable: Observable<AnimationGroup>;
         onCompleteObservable: Observable<IGLTFLoader>;
         onDisposeObservable: Observable<IGLTFLoader>;
         onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
@@ -61,6 +60,7 @@ declare module BABYLON {
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
+            animationGroups: AnimationGroup[];
         }>;
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
@@ -116,12 +116,6 @@ declare module BABYLON {
         private _onMaterialLoadedObserver;
         onMaterialLoaded: (material: Material) => void;
         /**
-         * Raised when the loader creates an animation group after parsing the glTF properties of the animation.
-         */
-        readonly onAnimationGroupLoadedObservable: Observable<AnimationGroup>;
-        private _onAnimationGroupLoadedObserver;
-        onAnimationGroupLoaded: (animationGroup: AnimationGroup) => void;
-        /**
          * Raised when the asset is completely loaded, immediately before the loader is disposed.
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
@@ -162,6 +156,7 @@ declare module BABYLON {
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
+            animationGroups: AnimationGroup[];
         }>;
         loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
@@ -190,6 +185,13 @@ declare module BABYLON.GLTF2 {
     class ArrayItem {
         static Assign(values?: IArrayItem[]): void;
     }
+    class AnimationMultiTarget {
+        subTargets: any[];
+        position: Vector3;
+        rotationQuaternion: Quaternion;
+        scaling: Vector3;
+        influence: number;
+    }
 }
 
 
@@ -310,7 +312,6 @@ declare module BABYLON.GLTF2 {
         readonly onMeshLoadedObservable: Observable<AbstractMesh>;
         readonly onTextureLoadedObservable: Observable<BaseTexture>;
         readonly onMaterialLoadedObservable: Observable<Material>;
-        readonly onAnimationGroupLoadedObservable: Observable<AnimationGroup>;
         readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
         readonly onCompleteObservable: Observable<IGLTFLoader>;
         readonly state: Nullable<GLTFLoaderState>;
@@ -319,6 +320,7 @@ declare module BABYLON.GLTF2 {
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
+            animationGroups: AnimationGroup[];
         }>;
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         private _loadAsync(nodes, scene, data, rootUrl, onProgress?);
@@ -332,6 +334,7 @@ declare module BABYLON.GLTF2 {
         private _forEachPrimitive(node, callback);
         private _getMeshes();
         private _getSkeletons();
+        private _getAnimationGroups();
         private _startAnimations();
         _loadNodeAsync(context: string, node: ILoaderNode): Promise<void>;
         private _loadMeshAsync(context, node, mesh, babylonMesh);

+ 83 - 28
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -78,10 +78,6 @@ var BABYLON;
              */
             this.onMaterialLoadedObservable = new BABYLON.Observable();
             /**
-             * Raised when the loader creates an animation group after parsing the glTF properties of the animation.
-             */
-            this.onAnimationGroupLoadedObservable = new BABYLON.Observable();
-            /**
              * Raised when the asset is completely loaded, immediately before the loader is disposed.
              * For assets with LODs, raised when all of the LODs are complete.
              * For assets without LODs, raised when the model is complete, immediately after onSuccess.
@@ -144,16 +140,6 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
-        Object.defineProperty(GLTFFileLoader.prototype, "onAnimationGroupLoaded", {
-            set: function (callback) {
-                if (this._onAnimationGroupLoadedObserver) {
-                    this.onAnimationGroupLoadedObservable.remove(this._onAnimationGroupLoadedObserver);
-                }
-                this._onAnimationGroupLoadedObserver = this.onAnimationGroupLoadedObservable.add(callback);
-            },
-            enumerable: true,
-            configurable: true
-        });
         Object.defineProperty(GLTFFileLoader.prototype, "onComplete", {
             set: function (callback) {
                 if (this._onCompleteObserver) {
@@ -246,6 +232,7 @@ var BABYLON;
                     Array.prototype.push.apply(container.meshes, result.meshes);
                     Array.prototype.push.apply(container.particleSystems, result.particleSystems);
                     Array.prototype.push.apply(container.skeletons, result.skeletons);
+                    Array.prototype.push.apply(container.animationGroups, result.animationGroups);
                     container.removeAllFromScene();
                     return container;
                 });
@@ -307,7 +294,6 @@ var BABYLON;
             loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
             loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
             loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
-            loader.onAnimationGroupLoadedObservable.add(function (animationGroup) { return _this.onAnimationGroupLoadedObservable.notifyObservers(animationGroup); });
             loader.onCompleteObservable.add(function () {
                 _this.onMeshLoadedObservable.clear();
                 _this.onTextureLoadedObservable.clear();
@@ -496,6 +482,53 @@ var BABYLON;
             return ArrayItem;
         }());
         GLTF2.ArrayItem = ArrayItem;
+        var AnimationMultiTarget = /** @class */ (function () {
+            function AnimationMultiTarget() {
+                this.subTargets = new Array();
+            }
+            Object.defineProperty(AnimationMultiTarget.prototype, "position", {
+                set: function (value) {
+                    for (var _i = 0, _a = this.subTargets; _i < _a.length; _i++) {
+                        var subTarget = _a[_i];
+                        subTarget.position = value;
+                    }
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(AnimationMultiTarget.prototype, "rotationQuaternion", {
+                set: function (value) {
+                    for (var _i = 0, _a = this.subTargets; _i < _a.length; _i++) {
+                        var subTarget = _a[_i];
+                        subTarget.rotationQuaternion = value;
+                    }
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(AnimationMultiTarget.prototype, "scaling", {
+                set: function (value) {
+                    for (var _i = 0, _a = this.subTargets; _i < _a.length; _i++) {
+                        var subTarget = _a[_i];
+                        subTarget.scaling = value;
+                    }
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(AnimationMultiTarget.prototype, "influence", {
+                set: function (value) {
+                    for (var _i = 0, _a = this.subTargets; _i < _a.length; _i++) {
+                        var subTarget = _a[_i];
+                        subTarget.influence = value;
+                    }
+                },
+                enumerable: true,
+                configurable: true
+            });
+            return AnimationMultiTarget;
+        }());
+        GLTF2.AnimationMultiTarget = AnimationMultiTarget;
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));
 
@@ -531,7 +564,6 @@ var BABYLON;
                 this.onMeshLoadedObservable = new BABYLON.Observable();
                 this.onTextureLoadedObservable = new BABYLON.Observable();
                 this.onMaterialLoadedObservable = new BABYLON.Observable();
-                this.onAnimationGroupLoadedObservable = new BABYLON.Observable();
                 this.onExtensionLoadedObservable = new BABYLON.Observable();
                 this.onCompleteObservable = new BABYLON.Observable();
             }
@@ -588,6 +620,7 @@ var BABYLON;
                             meshes: _this._getMeshes(),
                             particleSystems: [],
                             skeletons: _this._getSkeletons(),
+                            animationGroups: _this._getAnimationGroups()
                         };
                     });
                 });
@@ -808,25 +841,37 @@ var BABYLON;
                 }
                 return skeletons;
             };
-            GLTFLoader.prototype._startAnimations = function () {
+            GLTFLoader.prototype._getAnimationGroups = function () {
+                var animationGroups = new Array();
                 var animations = this._gltf.animations;
-                if (!animations) {
-                    return;
+                if (animations) {
+                    for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
+                        var animation = animations_1[_i];
+                        if (animation._babylonAnimationGroup) {
+                            animationGroups.push(animation._babylonAnimationGroup);
+                        }
+                    }
                 }
+                return animationGroups;
+            };
+            GLTFLoader.prototype._startAnimations = function () {
                 switch (this.animationStartMode) {
                     case BABYLON.GLTFLoaderAnimationStartMode.NONE: {
                         // do nothing
                         break;
                     }
                     case BABYLON.GLTFLoaderAnimationStartMode.FIRST: {
-                        var animation = animations[0];
-                        animation._babylonAnimationGroup.start(true);
+                        var babylonAnimationGroups = this._getAnimationGroups();
+                        if (babylonAnimationGroups.length !== 0) {
+                            babylonAnimationGroups[0].start(true);
+                        }
                         break;
                     }
                     case BABYLON.GLTFLoaderAnimationStartMode.ALL: {
-                        for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
-                            var animation = animations_1[_i];
-                            animation._babylonAnimationGroup.start(true);
+                        var babylonAnimationGroups = this._getAnimationGroups();
+                        for (var _i = 0, babylonAnimationGroups_1 = babylonAnimationGroups; _i < babylonAnimationGroups_1.length; _i++) {
+                            var babylonAnimationGroup = babylonAnimationGroups_1[_i];
+                            babylonAnimationGroup.start(true);
                         }
                         break;
                     }
@@ -1116,6 +1161,8 @@ var BABYLON;
                     _this._forEachPrimitive(node, function (babylonMesh) {
                         babylonMesh.skeleton = skin._babylonSkeleton;
                     });
+                    // Ignore the TRS of skinned nodes.
+                    // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
                     node._babylonMesh.parent = _this._rootBabylonMesh;
                     node._babylonMesh.position = BABYLON.Vector3.Zero();
                     node._babylonMesh.rotationQuaternion = BABYLON.Quaternion.Identity();
@@ -1205,7 +1252,6 @@ var BABYLON;
                     var channel = _a[_i];
                     promises.push(this._loadAnimationChannelAsync(context + "/channels/" + channel._index, context, animation, channel, babylonAnimationGroup));
                 }
-                this.onAnimationGroupLoadedObservable.notifyObservers(babylonAnimationGroup);
                 return Promise.all(promises).then(function () {
                     babylonAnimationGroup.normalize();
                 });
@@ -1213,7 +1259,12 @@ var BABYLON;
             GLTFLoader.prototype._loadAnimationChannelAsync = function (context, animationContext, animation, channel, babylonAnimationGroup) {
                 var _this = this;
                 var targetNode = GLTFLoader._GetProperty(context + "/target/node", this._gltf.nodes, channel.target.node);
-                if (!targetNode._babylonMesh || targetNode.skin != undefined) {
+                if (!targetNode._babylonMesh) {
+                    return Promise.resolve();
+                }
+                // Ignore animations targeting TRS of skinned nodes.
+                // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
+                if (targetNode.skin != undefined && channel.target.path !== "weights" /* WEIGHTS */) {
                     return Promise.resolve();
                 }
                 var sampler = GLTFLoader._GetProperty(context + "/sampler", animation.samplers, channel.sampler);
@@ -1324,10 +1375,12 @@ var BABYLON;
                                 value: key.value[targetIndex],
                                 outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
                             }); }));
+                            var multiTarget = new GLTF2.AnimationMultiTarget();
                             _this._forEachPrimitive(targetNode, function (babylonMesh) {
                                 var morphTarget = babylonMesh.morphTargetManager.getTarget(targetIndex);
-                                babylonAnimationGroup.addTargetedAnimation(babylonAnimation, morphTarget);
+                                multiTarget.subTargets.push(morphTarget);
                             });
+                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, multiTarget);
                         };
                         for (var targetIndex = 0; targetIndex < targetNode._numMorphTargets; targetIndex++) {
                             _loop_1(targetIndex);
@@ -1338,10 +1391,12 @@ var BABYLON;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
                         if (targetNode._babylonAnimationTargets) {
+                            var multiTarget = new GLTF2.AnimationMultiTarget();
                             for (var _i = 0, _a = targetNode._babylonAnimationTargets; _i < _a.length; _i++) {
                                 var target = _a[_i];
-                                babylonAnimationGroup.addTargetedAnimation(babylonAnimation, target);
+                                multiTarget.subTargets.push(target);
                             }
+                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, multiTarget);
                         }
                     }
                 });

Різницю між файлами не показано, бо вона завелика
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


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

@@ -52,7 +52,6 @@ declare module BABYLON {
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
-        onAnimationGroupLoadedObservable: Observable<AnimationGroup>;
         onCompleteObservable: Observable<IGLTFLoader>;
         onDisposeObservable: Observable<IGLTFLoader>;
         onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
@@ -61,6 +60,7 @@ declare module BABYLON {
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
+            animationGroups: AnimationGroup[];
         }>;
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
@@ -116,12 +116,6 @@ declare module BABYLON {
         private _onMaterialLoadedObserver;
         onMaterialLoaded: (material: Material) => void;
         /**
-         * Raised when the loader creates an animation group after parsing the glTF properties of the animation.
-         */
-        readonly onAnimationGroupLoadedObservable: Observable<AnimationGroup>;
-        private _onAnimationGroupLoadedObserver;
-        onAnimationGroupLoaded: (animationGroup: AnimationGroup) => void;
-        /**
          * Raised when the asset is completely loaded, immediately before the loader is disposed.
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
@@ -162,6 +156,7 @@ declare module BABYLON {
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
+            animationGroups: AnimationGroup[];
         }>;
         loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
@@ -581,7 +576,6 @@ declare module BABYLON.GLTF1 {
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
-        onAnimationGroupLoadedObservable: Observable<AnimationGroup>;
         onCompleteObservable: Observable<IGLTFLoader>;
         onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
         state: Nullable<GLTFLoaderState>;
@@ -591,6 +585,7 @@ declare module BABYLON.GLTF1 {
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
+            animationGroups: AnimationGroup[];
         }>;
         private _loadAsync(scene, data, rootUrl, onSuccess, onProgress?, onError?);
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
@@ -746,6 +741,13 @@ declare module BABYLON.GLTF2 {
     class ArrayItem {
         static Assign(values?: IArrayItem[]): void;
     }
+    class AnimationMultiTarget {
+        subTargets: any[];
+        position: Vector3;
+        rotationQuaternion: Quaternion;
+        scaling: Vector3;
+        influence: number;
+    }
 }
 
 
@@ -866,7 +868,6 @@ declare module BABYLON.GLTF2 {
         readonly onMeshLoadedObservable: Observable<AbstractMesh>;
         readonly onTextureLoadedObservable: Observable<BaseTexture>;
         readonly onMaterialLoadedObservable: Observable<Material>;
-        readonly onAnimationGroupLoadedObservable: Observable<AnimationGroup>;
         readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
         readonly onCompleteObservable: Observable<IGLTFLoader>;
         readonly state: Nullable<GLTFLoaderState>;
@@ -875,6 +876,7 @@ declare module BABYLON.GLTF2 {
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
+            animationGroups: AnimationGroup[];
         }>;
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         private _loadAsync(nodes, scene, data, rootUrl, onProgress?);
@@ -888,6 +890,7 @@ declare module BABYLON.GLTF2 {
         private _forEachPrimitive(node, callback);
         private _getMeshes();
         private _getSkeletons();
+        private _getAnimationGroups();
         private _startAnimations();
         _loadNodeAsync(context: string, node: ILoaderNode): Promise<void>;
         private _loadMeshAsync(context, node, mesh, babylonMesh);

+ 89 - 34
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -78,10 +78,6 @@ var BABYLON;
              */
             this.onMaterialLoadedObservable = new BABYLON.Observable();
             /**
-             * Raised when the loader creates an animation group after parsing the glTF properties of the animation.
-             */
-            this.onAnimationGroupLoadedObservable = new BABYLON.Observable();
-            /**
              * Raised when the asset is completely loaded, immediately before the loader is disposed.
              * For assets with LODs, raised when all of the LODs are complete.
              * For assets without LODs, raised when the model is complete, immediately after onSuccess.
@@ -144,16 +140,6 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
-        Object.defineProperty(GLTFFileLoader.prototype, "onAnimationGroupLoaded", {
-            set: function (callback) {
-                if (this._onAnimationGroupLoadedObserver) {
-                    this.onAnimationGroupLoadedObservable.remove(this._onAnimationGroupLoadedObserver);
-                }
-                this._onAnimationGroupLoadedObserver = this.onAnimationGroupLoadedObservable.add(callback);
-            },
-            enumerable: true,
-            configurable: true
-        });
         Object.defineProperty(GLTFFileLoader.prototype, "onComplete", {
             set: function (callback) {
                 if (this._onCompleteObserver) {
@@ -246,6 +232,7 @@ var BABYLON;
                     Array.prototype.push.apply(container.meshes, result.meshes);
                     Array.prototype.push.apply(container.particleSystems, result.particleSystems);
                     Array.prototype.push.apply(container.skeletons, result.skeletons);
+                    Array.prototype.push.apply(container.animationGroups, result.animationGroups);
                     container.removeAllFromScene();
                     return container;
                 });
@@ -307,7 +294,6 @@ var BABYLON;
             loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
             loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
             loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
-            loader.onAnimationGroupLoadedObservable.add(function (animationGroup) { return _this.onAnimationGroupLoadedObservable.notifyObservers(animationGroup); });
             loader.onCompleteObservable.add(function () {
                 _this.onMeshLoadedObservable.clear();
                 _this.onTextureLoadedObservable.clear();
@@ -1872,7 +1858,6 @@ var BABYLON;
                 this.onMeshLoadedObservable = new BABYLON.Observable();
                 this.onTextureLoadedObservable = new BABYLON.Observable();
                 this.onMaterialLoadedObservable = new BABYLON.Observable();
-                this.onAnimationGroupLoadedObservable = new BABYLON.Observable();
                 this.onCompleteObservable = new BABYLON.Observable();
                 this.onExtensionLoadedObservable = new BABYLON.Observable();
                 this.state = null;
@@ -1927,12 +1912,12 @@ var BABYLON;
                             importMaterials(gltfRuntime);
                             postLoad(gltfRuntime);
                             if (!BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
-                                onSuccess(meshes, [], skeletons);
+                                onSuccess(meshes, skeletons);
                             }
                         });
                     }, onProgress);
                     if (BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
-                        onSuccess(meshes, [], skeletons);
+                        onSuccess(meshes, skeletons);
                     }
                 }, onError);
                 return true;
@@ -1940,11 +1925,12 @@ var BABYLON;
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
                 var _this = this;
                 return new Promise(function (resolve, reject) {
-                    _this._importMeshAsync(meshesNames, scene, data, rootUrl, function (meshes, particleSystems, skeletons) {
+                    _this._importMeshAsync(meshesNames, scene, data, rootUrl, function (meshes, skeletons) {
                         resolve({
                             meshes: meshes,
-                            particleSystems: particleSystems,
-                            skeletons: skeletons
+                            particleSystems: [],
+                            skeletons: skeletons,
+                            animationGroups: []
                         });
                     }, onProgress, function (message) {
                         reject(new Error(message));
@@ -2694,6 +2680,53 @@ var BABYLON;
             return ArrayItem;
         }());
         GLTF2.ArrayItem = ArrayItem;
+        var AnimationMultiTarget = /** @class */ (function () {
+            function AnimationMultiTarget() {
+                this.subTargets = new Array();
+            }
+            Object.defineProperty(AnimationMultiTarget.prototype, "position", {
+                set: function (value) {
+                    for (var _i = 0, _a = this.subTargets; _i < _a.length; _i++) {
+                        var subTarget = _a[_i];
+                        subTarget.position = value;
+                    }
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(AnimationMultiTarget.prototype, "rotationQuaternion", {
+                set: function (value) {
+                    for (var _i = 0, _a = this.subTargets; _i < _a.length; _i++) {
+                        var subTarget = _a[_i];
+                        subTarget.rotationQuaternion = value;
+                    }
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(AnimationMultiTarget.prototype, "scaling", {
+                set: function (value) {
+                    for (var _i = 0, _a = this.subTargets; _i < _a.length; _i++) {
+                        var subTarget = _a[_i];
+                        subTarget.scaling = value;
+                    }
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(AnimationMultiTarget.prototype, "influence", {
+                set: function (value) {
+                    for (var _i = 0, _a = this.subTargets; _i < _a.length; _i++) {
+                        var subTarget = _a[_i];
+                        subTarget.influence = value;
+                    }
+                },
+                enumerable: true,
+                configurable: true
+            });
+            return AnimationMultiTarget;
+        }());
+        GLTF2.AnimationMultiTarget = AnimationMultiTarget;
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));
 
@@ -2729,7 +2762,6 @@ var BABYLON;
                 this.onMeshLoadedObservable = new BABYLON.Observable();
                 this.onTextureLoadedObservable = new BABYLON.Observable();
                 this.onMaterialLoadedObservable = new BABYLON.Observable();
-                this.onAnimationGroupLoadedObservable = new BABYLON.Observable();
                 this.onExtensionLoadedObservable = new BABYLON.Observable();
                 this.onCompleteObservable = new BABYLON.Observable();
             }
@@ -2786,6 +2818,7 @@ var BABYLON;
                             meshes: _this._getMeshes(),
                             particleSystems: [],
                             skeletons: _this._getSkeletons(),
+                            animationGroups: _this._getAnimationGroups()
                         };
                     });
                 });
@@ -3006,25 +3039,37 @@ var BABYLON;
                 }
                 return skeletons;
             };
-            GLTFLoader.prototype._startAnimations = function () {
+            GLTFLoader.prototype._getAnimationGroups = function () {
+                var animationGroups = new Array();
                 var animations = this._gltf.animations;
-                if (!animations) {
-                    return;
+                if (animations) {
+                    for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
+                        var animation = animations_1[_i];
+                        if (animation._babylonAnimationGroup) {
+                            animationGroups.push(animation._babylonAnimationGroup);
+                        }
+                    }
                 }
+                return animationGroups;
+            };
+            GLTFLoader.prototype._startAnimations = function () {
                 switch (this.animationStartMode) {
                     case BABYLON.GLTFLoaderAnimationStartMode.NONE: {
                         // do nothing
                         break;
                     }
                     case BABYLON.GLTFLoaderAnimationStartMode.FIRST: {
-                        var animation = animations[0];
-                        animation._babylonAnimationGroup.start(true);
+                        var babylonAnimationGroups = this._getAnimationGroups();
+                        if (babylonAnimationGroups.length !== 0) {
+                            babylonAnimationGroups[0].start(true);
+                        }
                         break;
                     }
                     case BABYLON.GLTFLoaderAnimationStartMode.ALL: {
-                        for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
-                            var animation = animations_1[_i];
-                            animation._babylonAnimationGroup.start(true);
+                        var babylonAnimationGroups = this._getAnimationGroups();
+                        for (var _i = 0, babylonAnimationGroups_1 = babylonAnimationGroups; _i < babylonAnimationGroups_1.length; _i++) {
+                            var babylonAnimationGroup = babylonAnimationGroups_1[_i];
+                            babylonAnimationGroup.start(true);
                         }
                         break;
                     }
@@ -3314,6 +3359,8 @@ var BABYLON;
                     _this._forEachPrimitive(node, function (babylonMesh) {
                         babylonMesh.skeleton = skin._babylonSkeleton;
                     });
+                    // Ignore the TRS of skinned nodes.
+                    // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
                     node._babylonMesh.parent = _this._rootBabylonMesh;
                     node._babylonMesh.position = BABYLON.Vector3.Zero();
                     node._babylonMesh.rotationQuaternion = BABYLON.Quaternion.Identity();
@@ -3403,7 +3450,6 @@ var BABYLON;
                     var channel = _a[_i];
                     promises.push(this._loadAnimationChannelAsync(context + "/channels/" + channel._index, context, animation, channel, babylonAnimationGroup));
                 }
-                this.onAnimationGroupLoadedObservable.notifyObservers(babylonAnimationGroup);
                 return Promise.all(promises).then(function () {
                     babylonAnimationGroup.normalize();
                 });
@@ -3411,7 +3457,12 @@ var BABYLON;
             GLTFLoader.prototype._loadAnimationChannelAsync = function (context, animationContext, animation, channel, babylonAnimationGroup) {
                 var _this = this;
                 var targetNode = GLTFLoader._GetProperty(context + "/target/node", this._gltf.nodes, channel.target.node);
-                if (!targetNode._babylonMesh || targetNode.skin != undefined) {
+                if (!targetNode._babylonMesh) {
+                    return Promise.resolve();
+                }
+                // Ignore animations targeting TRS of skinned nodes.
+                // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
+                if (targetNode.skin != undefined && channel.target.path !== "weights" /* WEIGHTS */) {
                     return Promise.resolve();
                 }
                 var sampler = GLTFLoader._GetProperty(context + "/sampler", animation.samplers, channel.sampler);
@@ -3522,10 +3573,12 @@ var BABYLON;
                                 value: key.value[targetIndex],
                                 outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
                             }); }));
+                            var multiTarget = new GLTF2.AnimationMultiTarget();
                             _this._forEachPrimitive(targetNode, function (babylonMesh) {
                                 var morphTarget = babylonMesh.morphTargetManager.getTarget(targetIndex);
-                                babylonAnimationGroup.addTargetedAnimation(babylonAnimation, morphTarget);
+                                multiTarget.subTargets.push(morphTarget);
                             });
+                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, multiTarget);
                         };
                         for (var targetIndex = 0; targetIndex < targetNode._numMorphTargets; targetIndex++) {
                             _loop_1(targetIndex);
@@ -3536,10 +3589,12 @@ var BABYLON;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
                         if (targetNode._babylonAnimationTargets) {
+                            var multiTarget = new GLTF2.AnimationMultiTarget();
                             for (var _i = 0, _a = targetNode._babylonAnimationTargets; _i < _a.length; _i++) {
                                 var target = _a[_i];
-                                babylonAnimationGroup.addTargetedAnimation(babylonAnimation, target);
+                                multiTarget.subTargets.push(target);
                             }
+                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, multiTarget);
                         }
                     }
                 });

Різницю між файлами не показано, бо вона завелика
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


+ 90 - 34
dist/preview release/loaders/babylonjs.loaders.js

@@ -1075,10 +1075,6 @@ var BABYLON;
              */
             this.onMaterialLoadedObservable = new BABYLON.Observable();
             /**
-             * Raised when the loader creates an animation group after parsing the glTF properties of the animation.
-             */
-            this.onAnimationGroupLoadedObservable = new BABYLON.Observable();
-            /**
              * Raised when the asset is completely loaded, immediately before the loader is disposed.
              * For assets with LODs, raised when all of the LODs are complete.
              * For assets without LODs, raised when the model is complete, immediately after onSuccess.
@@ -1141,16 +1137,6 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
-        Object.defineProperty(GLTFFileLoader.prototype, "onAnimationGroupLoaded", {
-            set: function (callback) {
-                if (this._onAnimationGroupLoadedObserver) {
-                    this.onAnimationGroupLoadedObservable.remove(this._onAnimationGroupLoadedObserver);
-                }
-                this._onAnimationGroupLoadedObserver = this.onAnimationGroupLoadedObservable.add(callback);
-            },
-            enumerable: true,
-            configurable: true
-        });
         Object.defineProperty(GLTFFileLoader.prototype, "onComplete", {
             set: function (callback) {
                 if (this._onCompleteObserver) {
@@ -1243,6 +1229,7 @@ var BABYLON;
                     Array.prototype.push.apply(container.meshes, result.meshes);
                     Array.prototype.push.apply(container.particleSystems, result.particleSystems);
                     Array.prototype.push.apply(container.skeletons, result.skeletons);
+                    Array.prototype.push.apply(container.animationGroups, result.animationGroups);
                     container.removeAllFromScene();
                     return container;
                 });
@@ -1304,7 +1291,6 @@ var BABYLON;
             loader.onTextureLoadedObservable.add(function (texture) { return _this.onTextureLoadedObservable.notifyObservers(texture); });
             loader.onMaterialLoadedObservable.add(function (material) { return _this.onMaterialLoadedObservable.notifyObservers(material); });
             loader.onExtensionLoadedObservable.add(function (extension) { return _this.onExtensionLoadedObservable.notifyObservers(extension); });
-            loader.onAnimationGroupLoadedObservable.add(function (animationGroup) { return _this.onAnimationGroupLoadedObservable.notifyObservers(animationGroup); });
             loader.onCompleteObservable.add(function () {
                 _this.onMeshLoadedObservable.clear();
                 _this.onTextureLoadedObservable.clear();
@@ -2869,7 +2855,6 @@ var BABYLON;
                 this.onMeshLoadedObservable = new BABYLON.Observable();
                 this.onTextureLoadedObservable = new BABYLON.Observable();
                 this.onMaterialLoadedObservable = new BABYLON.Observable();
-                this.onAnimationGroupLoadedObservable = new BABYLON.Observable();
                 this.onCompleteObservable = new BABYLON.Observable();
                 this.onExtensionLoadedObservable = new BABYLON.Observable();
                 this.state = null;
@@ -2924,12 +2909,12 @@ var BABYLON;
                             importMaterials(gltfRuntime);
                             postLoad(gltfRuntime);
                             if (!BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
-                                onSuccess(meshes, [], skeletons);
+                                onSuccess(meshes, skeletons);
                             }
                         });
                     }, onProgress);
                     if (BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
-                        onSuccess(meshes, [], skeletons);
+                        onSuccess(meshes, skeletons);
                     }
                 }, onError);
                 return true;
@@ -2937,11 +2922,12 @@ var BABYLON;
             GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
                 var _this = this;
                 return new Promise(function (resolve, reject) {
-                    _this._importMeshAsync(meshesNames, scene, data, rootUrl, function (meshes, particleSystems, skeletons) {
+                    _this._importMeshAsync(meshesNames, scene, data, rootUrl, function (meshes, skeletons) {
                         resolve({
                             meshes: meshes,
-                            particleSystems: particleSystems,
-                            skeletons: skeletons
+                            particleSystems: [],
+                            skeletons: skeletons,
+                            animationGroups: []
                         });
                     }, onProgress, function (message) {
                         reject(new Error(message));
@@ -3673,6 +3659,53 @@ var BABYLON;
             return ArrayItem;
         }());
         GLTF2.ArrayItem = ArrayItem;
+        var AnimationMultiTarget = /** @class */ (function () {
+            function AnimationMultiTarget() {
+                this.subTargets = new Array();
+            }
+            Object.defineProperty(AnimationMultiTarget.prototype, "position", {
+                set: function (value) {
+                    for (var _i = 0, _a = this.subTargets; _i < _a.length; _i++) {
+                        var subTarget = _a[_i];
+                        subTarget.position = value;
+                    }
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(AnimationMultiTarget.prototype, "rotationQuaternion", {
+                set: function (value) {
+                    for (var _i = 0, _a = this.subTargets; _i < _a.length; _i++) {
+                        var subTarget = _a[_i];
+                        subTarget.rotationQuaternion = value;
+                    }
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(AnimationMultiTarget.prototype, "scaling", {
+                set: function (value) {
+                    for (var _i = 0, _a = this.subTargets; _i < _a.length; _i++) {
+                        var subTarget = _a[_i];
+                        subTarget.scaling = value;
+                    }
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(AnimationMultiTarget.prototype, "influence", {
+                set: function (value) {
+                    for (var _i = 0, _a = this.subTargets; _i < _a.length; _i++) {
+                        var subTarget = _a[_i];
+                        subTarget.influence = value;
+                    }
+                },
+                enumerable: true,
+                configurable: true
+            });
+            return AnimationMultiTarget;
+        }());
+        GLTF2.AnimationMultiTarget = AnimationMultiTarget;
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));
 
@@ -3708,7 +3741,6 @@ var BABYLON;
                 this.onMeshLoadedObservable = new BABYLON.Observable();
                 this.onTextureLoadedObservable = new BABYLON.Observable();
                 this.onMaterialLoadedObservable = new BABYLON.Observable();
-                this.onAnimationGroupLoadedObservable = new BABYLON.Observable();
                 this.onExtensionLoadedObservable = new BABYLON.Observable();
                 this.onCompleteObservable = new BABYLON.Observable();
             }
@@ -3765,6 +3797,7 @@ var BABYLON;
                             meshes: _this._getMeshes(),
                             particleSystems: [],
                             skeletons: _this._getSkeletons(),
+                            animationGroups: _this._getAnimationGroups()
                         };
                     });
                 });
@@ -3985,25 +4018,37 @@ var BABYLON;
                 }
                 return skeletons;
             };
-            GLTFLoader.prototype._startAnimations = function () {
+            GLTFLoader.prototype._getAnimationGroups = function () {
+                var animationGroups = new Array();
                 var animations = this._gltf.animations;
-                if (!animations) {
-                    return;
+                if (animations) {
+                    for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
+                        var animation = animations_1[_i];
+                        if (animation._babylonAnimationGroup) {
+                            animationGroups.push(animation._babylonAnimationGroup);
+                        }
+                    }
                 }
+                return animationGroups;
+            };
+            GLTFLoader.prototype._startAnimations = function () {
                 switch (this.animationStartMode) {
                     case BABYLON.GLTFLoaderAnimationStartMode.NONE: {
                         // do nothing
                         break;
                     }
                     case BABYLON.GLTFLoaderAnimationStartMode.FIRST: {
-                        var animation = animations[0];
-                        animation._babylonAnimationGroup.start(true);
+                        var babylonAnimationGroups = this._getAnimationGroups();
+                        if (babylonAnimationGroups.length !== 0) {
+                            babylonAnimationGroups[0].start(true);
+                        }
                         break;
                     }
                     case BABYLON.GLTFLoaderAnimationStartMode.ALL: {
-                        for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
-                            var animation = animations_1[_i];
-                            animation._babylonAnimationGroup.start(true);
+                        var babylonAnimationGroups = this._getAnimationGroups();
+                        for (var _i = 0, babylonAnimationGroups_1 = babylonAnimationGroups; _i < babylonAnimationGroups_1.length; _i++) {
+                            var babylonAnimationGroup = babylonAnimationGroups_1[_i];
+                            babylonAnimationGroup.start(true);
                         }
                         break;
                     }
@@ -4293,6 +4338,8 @@ var BABYLON;
                     _this._forEachPrimitive(node, function (babylonMesh) {
                         babylonMesh.skeleton = skin._babylonSkeleton;
                     });
+                    // Ignore the TRS of skinned nodes.
+                    // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
                     node._babylonMesh.parent = _this._rootBabylonMesh;
                     node._babylonMesh.position = BABYLON.Vector3.Zero();
                     node._babylonMesh.rotationQuaternion = BABYLON.Quaternion.Identity();
@@ -4382,7 +4429,6 @@ var BABYLON;
                     var channel = _a[_i];
                     promises.push(this._loadAnimationChannelAsync(context + "/channels/" + channel._index, context, animation, channel, babylonAnimationGroup));
                 }
-                this.onAnimationGroupLoadedObservable.notifyObservers(babylonAnimationGroup);
                 return Promise.all(promises).then(function () {
                     babylonAnimationGroup.normalize();
                 });
@@ -4390,7 +4436,12 @@ var BABYLON;
             GLTFLoader.prototype._loadAnimationChannelAsync = function (context, animationContext, animation, channel, babylonAnimationGroup) {
                 var _this = this;
                 var targetNode = GLTFLoader._GetProperty(context + "/target/node", this._gltf.nodes, channel.target.node);
-                if (!targetNode._babylonMesh || targetNode.skin != undefined) {
+                if (!targetNode._babylonMesh) {
+                    return Promise.resolve();
+                }
+                // Ignore animations targeting TRS of skinned nodes.
+                // See https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins (second implementation note)
+                if (targetNode.skin != undefined && channel.target.path !== "weights" /* WEIGHTS */) {
                     return Promise.resolve();
                 }
                 var sampler = GLTFLoader._GetProperty(context + "/sampler", animation.samplers, channel.sampler);
@@ -4501,10 +4552,12 @@ var BABYLON;
                                 value: key.value[targetIndex],
                                 outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
                             }); }));
+                            var multiTarget = new GLTF2.AnimationMultiTarget();
                             _this._forEachPrimitive(targetNode, function (babylonMesh) {
                                 var morphTarget = babylonMesh.morphTargetManager.getTarget(targetIndex);
-                                babylonAnimationGroup.addTargetedAnimation(babylonAnimation, morphTarget);
+                                multiTarget.subTargets.push(morphTarget);
                             });
+                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, multiTarget);
                         };
                         for (var targetIndex = 0; targetIndex < targetNode._numMorphTargets; targetIndex++) {
                             _loop_1(targetIndex);
@@ -4515,10 +4568,12 @@ var BABYLON;
                         var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
                         babylonAnimation.setKeys(keys);
                         if (targetNode._babylonAnimationTargets) {
+                            var multiTarget = new GLTF2.AnimationMultiTarget();
                             for (var _i = 0, _a = targetNode._babylonAnimationTargets; _i < _a.length; _i++) {
                                 var target = _a[_i];
-                                babylonAnimationGroup.addTargetedAnimation(babylonAnimation, target);
+                                multiTarget.subTargets.push(target);
                             }
+                            babylonAnimationGroup.addTargetedAnimation(babylonAnimation, multiTarget);
                         }
                     }
                 });
@@ -5571,5 +5626,6 @@ var BABYLON;
 //# sourceMappingURL=KHR_lights.js.map
 
     
+
     return BABYLON;
 });

Різницю між файлами не показано, бо вона завелика
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


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

@@ -1,5 +1,3 @@
-/// <reference types="babylonjs"/>
-/// <reference types="babylonjs-gltf2interface"/>
 
 
 declare module 'babylonjs-loaders' { 
@@ -154,7 +152,6 @@ declare module BABYLON {
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
-        onAnimationGroupLoadedObservable: Observable<AnimationGroup>;
         onCompleteObservable: Observable<IGLTFLoader>;
         onDisposeObservable: Observable<IGLTFLoader>;
         onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
@@ -163,6 +160,7 @@ declare module BABYLON {
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
+            animationGroups: AnimationGroup[];
         }>;
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
     }
@@ -218,12 +216,6 @@ declare module BABYLON {
         private _onMaterialLoadedObserver;
         onMaterialLoaded: (material: Material) => void;
         /**
-         * Raised when the loader creates an animation group after parsing the glTF properties of the animation.
-         */
-        readonly onAnimationGroupLoadedObservable: Observable<AnimationGroup>;
-        private _onAnimationGroupLoadedObserver;
-        onAnimationGroupLoaded: (animationGroup: AnimationGroup) => void;
-        /**
          * Raised when the asset is completely loaded, immediately before the loader is disposed.
          * For assets with LODs, raised when all of the LODs are complete.
          * For assets without LODs, raised when the model is complete, immediately after onSuccess.
@@ -264,6 +256,7 @@ declare module BABYLON {
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
+            animationGroups: AnimationGroup[];
         }>;
         loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
@@ -683,7 +676,6 @@ declare module BABYLON.GLTF1 {
         onMeshLoadedObservable: Observable<AbstractMesh>;
         onTextureLoadedObservable: Observable<BaseTexture>;
         onMaterialLoadedObservable: Observable<Material>;
-        onAnimationGroupLoadedObservable: Observable<AnimationGroup>;
         onCompleteObservable: Observable<IGLTFLoader>;
         onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
         state: Nullable<GLTFLoaderState>;
@@ -693,6 +685,7 @@ declare module BABYLON.GLTF1 {
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
+            animationGroups: AnimationGroup[];
         }>;
         private _loadAsync(scene, data, rootUrl, onSuccess, onProgress?, onError?);
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
@@ -848,6 +841,13 @@ declare module BABYLON.GLTF2 {
     class ArrayItem {
         static Assign(values?: IArrayItem[]): void;
     }
+    class AnimationMultiTarget {
+        subTargets: any[];
+        position: Vector3;
+        rotationQuaternion: Quaternion;
+        scaling: Vector3;
+        influence: number;
+    }
 }
 
 
@@ -968,7 +968,6 @@ declare module BABYLON.GLTF2 {
         readonly onMeshLoadedObservable: Observable<AbstractMesh>;
         readonly onTextureLoadedObservable: Observable<BaseTexture>;
         readonly onMaterialLoadedObservable: Observable<Material>;
-        readonly onAnimationGroupLoadedObservable: Observable<AnimationGroup>;
         readonly onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
         readonly onCompleteObservable: Observable<IGLTFLoader>;
         readonly state: Nullable<GLTFLoaderState>;
@@ -977,6 +976,7 @@ declare module BABYLON.GLTF2 {
             meshes: AbstractMesh[];
             particleSystems: ParticleSystem[];
             skeletons: Skeleton[];
+            animationGroups: AnimationGroup[];
         }>;
         loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
         private _loadAsync(nodes, scene, data, rootUrl, onProgress?);
@@ -990,6 +990,7 @@ declare module BABYLON.GLTF2 {
         private _forEachPrimitive(node, callback);
         private _getMeshes();
         private _getSkeletons();
+        private _getAnimationGroups();
         private _startAnimations();
         _loadNodeAsync(context: string, node: ILoaderNode): Promise<void>;
         private _loadMeshAsync(context, node, mesh, babylonMesh);

+ 2 - 2
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-beta.1",
+    "version": "3.2.0-beta.3",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "3.2.0-beta.1"
+        "babylonjs-gltf2interface": "3.2.0-beta.3"
     },
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


Різницю між файлами не показано, бо вона завелика
+ 2 - 2
dist/preview release/materialsLibrary/babylon.gradientMaterial.js


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/materialsLibrary/babylon.gradientMaterial.min.js


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


Різницю між файлами не показано, бо вона завелика
+ 3 - 2
dist/preview release/materialsLibrary/babylonjs.materials.js


Різницю між файлами не показано, бо вона завелика
+ 3 - 3
dist/preview release/materialsLibrary/babylonjs.materials.min.js


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

@@ -1,4 +1,3 @@
-/// <reference types="babylonjs"/>
 
 
 declare module 'babylonjs-materials' { 

+ 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-beta.1",
+    "version": "3.2.0-beta.3",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js


Різницю між файлами не показано, бо вона завелика
+ 1 - 0
dist/preview release/postProcessesLibrary/babylonjs.postProcess.js


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js


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

@@ -1,4 +1,3 @@
-/// <reference types="babylonjs"/>
 
 
 declare module 'babylonjs-post-process' { 

+ 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-beta.1",
+    "version": "3.2.0-beta.3",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

Різницю між файлами не показано, бо вона завелика
+ 1 - 0
dist/preview release/proceduralTexturesLibrary/babylonjs.proceduralTextures.js


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

@@ -1,4 +1,3 @@
-/// <reference types="babylonjs"/>
 
 
 declare module 'babylonjs-procedural-textures' { 

+ 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-beta.1",
+    "version": "3.2.0-beta.3",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.min.js


+ 1 - 0
dist/preview release/serializers/babylonjs.serializers.js

@@ -1798,5 +1798,6 @@ var BABYLON;
 //# sourceMappingURL=babylon.glTFMaterial.js.map
 
     
+
     return BABYLON;
 });

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


+ 0 - 2
dist/preview release/serializers/babylonjs.serializers.module.d.ts

@@ -1,5 +1,3 @@
-/// <reference types="babylonjs"/>
-/// <reference types="babylonjs-gltf2interface"/>
 
 
 declare module 'babylonjs-serializers' { 

+ 2 - 2
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-beta.1",
+    "version": "3.2.0-beta.3",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "3.2.0-beta.1"
+        "babylonjs-gltf2interface": "3.2.0-beta.3"
     },
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"

Різницю між файлами не показано, бо вона завелика
+ 468 - 2918
dist/preview release/typedocValidationBaseline.json


+ 693 - 57
dist/preview release/viewer/babylon.viewer.d.ts

@@ -50,55 +50,231 @@ declare module BabylonViewer {
             } | undefined;
         };
     }
+    /**
+     * The object sent when an event is triggered
+     */
     export interface EventCallback {
+        /**
+         * The native javascript event triggered
+         */
         event: Event;
+        /**
+         * The template on which the event was triggered
+         */
         template: Template;
+        /**
+         * The selector provided
+         */
         selector: string;
+        /**
+         * Payload, if provided by the viewer
+         */
         payload?: any;
     }
+    /**
+     * The template manager, a member of the viewer class, will manage the viewer's templates and generate the HTML.
+     * The template manager managers a single viewer and can be seen as the collection of all sub-templates of the viewer.
+     */
     interface TemplateManager {
+        /**
+         * The element to which all the templates wil be appended
+         */
         containerElement: HTMLElement;
-        onInit: BABYLON.Observable<Template>;
-        onLoaded: BABYLON.Observable<Template>;
-        onStateChange: BABYLON.Observable<Template>;
+        /**
+         * Will be triggered when any template is initialized
+         */
+        onTemplateInit: BABYLON.Observable<Template>;
+        /**
+         * Will be triggered when any template is fully loaded
+         */
+        onTemplateLoaded: BABYLON.Observable<Template>;
+        /**
+         * Will be triggered when a template state changes
+         */
+        onTemplateStateChange: BABYLON.Observable<Template>;
+        /**
+         * Will be triggered when all templates finished loading
+         */
         onAllLoaded: BABYLON.Observable<TemplateManager>;
+        /**
+         * Will be triggered when any event on any template is triggered.
+         */
         onEventTriggered: BABYLON.Observable<EventCallback>;
+        /**
+         * This template manager's event manager. In charge of callback registrations to native event types
+         */
         eventManager: EventManager;
+        /**
+         * Initialize the template(s) for the viewer. Called bay the Viewer class
+         * @param templates the templates to be used to initialize the main template
+         */
         initTemplate(templates: {
             [key: string]: ITemplateConfiguration;
-        }): void;
+        }): Promise<void>;
+        /**
+        /**
+         * Get the canvas in the template tree.
+         * There must be one and only one canvas inthe template.
+         */
         getCanvas(): HTMLCanvasElement | null;
+        /**
+         * Get a specific template from the template tree
+         * @param name the name of the template to load
+         */
         getTemplate(name: string): Template | undefined;
+        /**
+         * Dispose the template manager
+         */
+        dispose(): void;
     }
 
+    /**
+     * This class represents a single template in the viewer's template tree.
+     * An example for a template is a single canvas, an overlay (containing sub-templates) or the navigation bar.
+     * A template is injected using the template manager in the correct position.
+     * The template is rendered using Handlebars and can use Handlebars' features (such as parameter injection)
+     *
+     * For further information please refer to the documentation page, https://doc.babylonjs.com
+    */
     interface Template {
+        /**
+         * The name of the template
+         */
         name: string;
-        onInit: BABYLON.Observable<Template>;
+        /**
+         * Will be triggered when the template is loaded
+         */
         onLoaded: BABYLON.Observable<Template>;
+        /**
+         * will be triggered when the template is appended to the tree
+         */
         onAppended: BABYLON.Observable<Template>;
+        /**
+         * Will be triggered when the template's state changed (shown, hidden)
+         */
         onStateChange: BABYLON.Observable<Template>;
+        /**
+         * Will be triggered when an event is triggered on ths template.
+         * The event is a native browser event (like mouse or pointer events)
+         */
         onEventTriggered: BABYLON.Observable<EventCallback>;
+        /**
+         * is the template loaded?
+         */
         isLoaded: boolean;
+        /**
+         * This is meant to be used to track the show and hide functions.
+         * This is NOT (!!) a flag to check if the element is actually visible to the user.
+         */
         isShown: boolean;
+        /**
+         * Is this template a part of the HTML tree (the template manager injected it)
+         */
+        isInHtmlTree: boolean;
+        /**
+         * The HTML element containing this template
+         */
         parent: HTMLElement;
+        /**
+         * A promise that is fulfilled when the template finished loading.
+         */
         initPromise: Promise<Template>;
+        /**
+         * Some templates have parameters (like background color for example).
+         * The parameters are provided to Handlebars which in turn generates the template.
+         * This function will update the template with the new parameters
+         *
+         * @param params the new template parameters
+         */
+        updateParams(params: {
+            [key: string]: string | number | boolean | object;
+        }): void;
+        /**
+         * Get the template'S configuration
+         */
         readonly configuration: ITemplateConfiguration;
+        /**
+         * A template can be a parent element for other templates or HTML elements.
+         * This function will deliver all child HTML elements of this template.
+         */
         getChildElements(): Array<string>;
-        appendTo(parent: HTMLElement): void;
+        /**
+         * Appending the template to a parent HTML element.
+         * If a parent is already set and you wish to replace the old HTML with new one, forceRemove should be true.
+         * @param parent the parent to which the template is added
+         * @param forceRemove if the parent already exists, shoud the template be removed from it?
+         */
+        appendTo(parent: HTMLElement, forceRemove?: boolean): void;
+        /**
+         * Show the template using the provided visibilityFunction, or natively using display: flex.
+         * The provided function returns a promise that should be fullfilled when the element is shown.
+         * Since it is a promise async operations are more than possible.
+         * See the default viewer for an opacity example.
+         * @param visibilityFunction The function to execute to show the template.
+         */
         show(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
+        /**
+         * Hide the template using the provided visibilityFunction, or natively using display: none.
+         * The provided function returns a promise that should be fullfilled when the element is hidden.
+         * Since it is a promise async operations are more than possible.
+         * See the default viewer for an opacity example.
+         * @param visibilityFunction The function to execute to show the template.
+         */
         hide(visibilityFunction?: (template: Template) => Promise<Template>): Promise<Template>;
+        /**
+         * Dispose this template
+         */
         dispose(): void;
     }
 
+    /**
+     * The viewer manager is the container for all viewers currently registered on this page.
+     * It is possible to have more than one viewer on a single page.
+     */
     interface ViewerManager {
+        /**
+         * A callback that will be triggered when a new viewer was added
+         */
         onViewerAdded: (viewer: AbstractViewer) => void;
+        /**
+         * Will notify when a new viewer was added
+         */
         onViewerAddedObservable: BABYLON.Observable<AbstractViewer>;
+        /**
+         * Will notify when a viewer was removed (disposed)
+         */
         onViewerRemovedObservable: BABYLON.Observable<string>;
+        /**
+         * Adding a new viewer to the viewer manager and start tracking it.
+         * @param viewer the viewer to add
+         */
         addViewer(viewer: AbstractViewer): void;
+        /**
+         * remove a viewer from the viewer manager
+         * @param viewer the viewer to remove
+         */
         removeViewer(viewer: AbstractViewer): void;
+        /**
+         * Get a viewer by its baseId (if the container element has an ID, it is the this is. if not, a random id was assigned)
+         * @param id the id of the HTMl element (or the viewer's, if none provided)
+         */
         getViewerById(id: string): AbstractViewer;
+        /**
+         * Get a viewer using a container element
+         * @param element the HTML element to search viewers associated with
+         */
         getViewerByHTMLElement(element: HTMLElement): AbstractViewer | undefined;
+        /**
+         * Get a promise that will fullfil when this viewer was initialized.
+         * Since viewer initialization and template injection is asynchronous, using the promise will guaranty that
+         * you will get the viewer after everything was already configured.
+         * @param id the viewer id to find
+         */
         getViewerPromiseById(id: string): Promise<AbstractViewer>;
+        /**
+         * dispose the manager and all of its associated viewers
+         */
+        dispose(): void;
     }
     export let viewerManager: ViewerManager;
 
@@ -108,30 +284,90 @@ declare module BabylonViewer {
         FRAMING = 2,
     }
 
+    /*
+    * Select all HTML tags on the page that match the selector and initialize a viewer
+    *
+    * @param selector the selector to initialize the viewer on (default is 'babylon')
+    */
     export function InitTags(selector?: string): void;
 
+    /**
+     * The EventManager is in charge of registering user interctions with the viewer.
+     * It is used in the TemplateManager
+     */
     interface EventManager {
+        /**
+         * Register a new callback to a specific template.
+         * The best example for the usage can be found in the DefaultViewer
+         *
+         * @param templateName the templateName to register the event to
+         * @param callback The callback to be executed
+         * @param eventType the type of event to register
+         * @param selector an optional selector. if not defined the parent object in the template will be selected
+         */
         registerCallback(templateName: string, callback: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
-        unregisterCallback(templateName: string, callback?: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
-    }
-
-    interface PromiseObservable<T> extends BABYLON.Observable<T> {
-        notifyWithPromise(eventData: T, mask?: number, target?: any, currentTarget?: any): Promise<any>;
+        /**
+         * This will remove a registered event from the defined template.
+         * Each one of the variables apart from the template name are optional, but one must be provided.
+         *
+         * @param templateName the templateName
+         * @param callback the callback to remove (optional)
+         * @param eventType the event type to remove (optional)
+         * @param selector the selector from which to remove the event (optional)
+         */
+        unregisterCallback(templateName: string, callback: (eventData: EventCallback) => void, eventType?: string, selector?: string): void;
+        /**
+         * Dispose the event manager
+         */
+        dispose(): void;
     }
 
+    /**
+     * This is the mapper's interface. Implement this function to create your own mapper and register it at the mapper manager
+     */
     export interface IMapper {
         map(rawSource: any): ViewerConfiguration;
     }
+
     interface MapperManager {
+        /**
+         * The default mapper is the JSON mapper.
+         */
         DefaultMapper: string;
+        /**
+         * Get a specific configuration mapper.
+         *
+         * @param type the name of the mapper to load
+         */
         getMapper(type: string): IMapper;
+        /**
+         * Use this functio to register your own configuration mapper.
+         * After a mapper is registered, it can be used to parse the specific type fo configuration to the standard ViewerConfiguration.
+         * @param type the name of the mapper. This will be used to define the configuration type and/or to get the mapper
+         * @param mapper The implemented mapper
+         */
         registerMapper(type: string, mapper: IMapper): void;
+        /**
+         * Dispose the mapper manager and all of its mappers.
+         */
+        dispose(): void;
     }
     export let mapperManager: MapperManager;
 
     interface ConfigurationLoader {
-        loadConfiguration(initConfig?: ViewerConfiguration): Promise<ViewerConfiguration>;
-        getConfigurationType(type: string): void;
+        /**
+         * load a configuration object that is defined in the initial configuration provided.
+         * The viewer configuration can extend different types of configuration objects and have an extra configuration defined.
+         *
+         * @param initConfig the initial configuration that has the definitions of further configuration to load.
+         * @param callback an optional callback that will be called sync, if noconfiguration needs to be loaded or configuration is payload-only
+         * @returns A promise that delivers the extended viewer configuration, when done.
+         */
+        loadConfiguration(initConfig?: ViewerConfiguration, callback?: (config: ViewerConfiguration) => void): Promise<ViewerConfiguration>;
+        /**
+         * Dispose the configuration loader. This will cancel file requests, if active.
+         */
+        dispose(): void;
     }
     export let configurationLoader: ConfigurationLoader;
 
@@ -227,8 +463,6 @@ declare module BabylonViewer {
             autoStart?: boolean | string;
             playOnce?: boolean;
         }
-
-        // [propName: string]: any; // further configuration, like title and creator
     }
 
     export interface ISkyboxConfiguration {
@@ -404,10 +638,16 @@ declare module BabylonViewer {
     }
     /////>configuration
 
+    /**
+     * Animation play mode enum - is the animation looping or playing once
+     */
     export enum AnimationPlayMode {
         ONCE = 0,
         LOOP = 1,
     }
+    /**
+     * An enum representing the current state of an animation object
+     */
     export enum AnimationState {
         INIT = 0,
         PLAYING = 1,
@@ -415,133 +655,529 @@ declare module BabylonViewer {
         STOPPED = 3,
         ENDED = 4,
     }
-    export interface IModelAnimation extends BABYLON.IDisposable {
+    /**
+     * This interface can be implemented to define new types of ModelAnimation objects.
+     */
+    export interface IModelAnimation {
+        /**
+         * Current animation state (playing, stopped etc')
+         */
         readonly state: AnimationState;
+        /**
+         * the name of the animation
+         */
         readonly name: string;
+        /**
+         * Get the max numbers of frame available in the animation group
+         *
+         * In correlation to an arry, this would be ".length"
+         */
         readonly frames: number;
+        /**
+         * Get the current frame playing right now.
+         * This can be used to poll the frame currently playing (and, for exmaple, display a progress bar with the data)
+         *
+         * In correlation to an array, this would be the current index
+         */
         readonly currentFrame: number;
+        /**
+         * Animation's FPS value
+         */
         readonly fps: number;
+        /**
+         * Get or set the animation's speed ration (Frame-to-fps)
+         */
         speedRatio: number;
+        /**
+         * Gets or sets the aimation's play mode.
+         */
         playMode: AnimationPlayMode;
+        /**
+         * Start the animation
+         */
         start(): any;
+        /**
+         * Stop the animation.
+         * This will fail silently if the animation group is already stopped.
+         */
         stop(): any;
+        /**
+         * Pause the animation
+         * This will fail silently if the animation is not currently playing
+         */
         pause(): any;
+        /**
+         * Reset this animation
+         */
         reset(): any;
+        /**
+         * Restart the animation
+         */
         restart(): any;
+        /**
+         * Go to a specific
+         * @param frameNumber the frame number to go to
+         */
         goToFrame(frameNumber: number): any;
+        /**
+         * Dispose this animation
+         */
+        dispose(): any;
     }
 
     export enum ModelState {
         INIT,
         LOADING,
         LOADED,
+        CANCELED,
         ERROR
     }
 
+    /**
+     * An instance of the class is in charge of loading the model correctly.
+     * This class will continously be expended with tasks required from the specific loaders Babylon has.
+     *
+     * A Model loader is unique per (Abstract)Viewer. It is being generated by the viewer
+     */
     export class ModelLoader {
-        constructor(viewer: AbstractViewer);
+        private _viewer;
+        private _loadId;
+        private _disposed;
+        private _loaders;
+        /**
+         * Create a new Model loader
+         * @param _viewer the viewer using this model loader
+         */
+        constructor(_viewer: AbstractViewer);
+        /**
+         * Load a model using predefined configuration
+         * @param modelConfiguration the modelConfiguration to use to load the model
+         */
         load(modelConfiguration: IModelConfiguration): ViewerModel;
+        cancelLoad(model: ViewerModel): void;
+        /**
+         * dispose the model loader.
+         * If loaders are registered and are in the middle of loading, they will be disposed and the request(s) will be cancelled.
+         */
         dispose(): void;
     }
 
     export class ViewerModel {
-        constructor(scene: BABYLON.Scene, modelConfiguration: IModelConfiguration, disableAutoLoad: boolean);
+        /**
+         * The viewer associated with this viewer model
+         */
+        protected _viewer: AbstractViewer;
+        /**
+         * The loader used to load this model.
+         */
         loader: BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync;
+        private _animations;
+        /**
+         * the list of meshes that are a part of this model
+         */
         meshes: Array<BABYLON.AbstractMesh>;
+        /**
+         * This model's root mesh (the parent of all other meshes).
+         * This mesh also exist in the meshes array.
+         */
         rootMesh: BABYLON.AbstractMesh;
+        /**
+         * ParticleSystems connected to this model
+         */
         particleSystems: Array<BABYLON.ParticleSystem>;
+        /**
+         * Skeletons defined in this model
+         */
         skeletons: Array<BABYLON.Skeleton>;
+        /**
+         * The current model animation.
+         * On init, this will be undefined.
+         */
         currentAnimation: IModelAnimation;
+        /**
+         * Observers registered here will be executed when the model is done loading
+         */
         onLoadedObservable: BABYLON.Observable<ViewerModel>;
+        /**
+         * Observers registered here will be executed when the loader notified of a progress event
+         */
         onLoadProgressObservable: BABYLON.Observable<BABYLON.SceneLoaderProgressEvent>;
+        /**
+         * Observers registered here will be executed when the loader notified of an error.
+         */
         onLoadErrorObservable: BABYLON.Observable<{
             message: string;
             exception: any;
         }>;
+        /**
+         * Observers registered here will be executed every time the model is being configured.
+         * This can be used to extend the model's configuration without extending the class itself
+         */
         onAfterConfigure: BABYLON.Observable<ViewerModel>;
+        /**
+         * The current model state (loaded, error, etc)
+         */
         state: ModelState;
+        /**
+         * A loadID provided by the modelLoader, unique to ths (Abstract)Viewer instance.
+         */
         loadId: number;
-        load(): void;
+        private _loadedUrl;
+        private _modelConfiguration;
+        constructor(_viewer: AbstractViewer, modelConfiguration: IModelConfiguration);
+        /**
+         * Get the model's configuration
+         */
+        configuration: IModelConfiguration;
+        /**
+         * Update the current configuration with new values.
+         * Configuration will not be overwritten, but merged with the new configuration.
+         * Priority is to the new configuration
+         * @param newConfiguration the configuration to be merged into the current configuration;
+         */
+        updateConfiguration(newConfiguration: Partial<IModelConfiguration>): void;
         initAnimations(): void;
+        /**
+         * Add a new animation group to this model.
+         * @param animationGroup the new animation group to be added
+         */
         addAnimationGroup(animationGroup: BABYLON.AnimationGroup): void;
+        /**
+         * Get the ModelAnimation array
+         */
         getAnimations(): Array<IModelAnimation>;
-        getAnimationNames(): string[];
+        /**
+         * Get the animations' names. Using the names you can play a specific animation.
+         */
+        getAnimationNames(): Array<string>;
+        /**
+         * Get an animation by the provided name. Used mainly when playing n animation.
+         * @param name the name of the animation to find
+         */
+        protected _getAnimationByName(name: string): BABYLON.Nullable<IModelAnimation>;
+        /**
+         * Choose an initialized animation using its name and start playing it
+         * @param name the name of the animation to play
+         * @returns The model aniamtion to be played.
+         */
         playAnimation(name: string): IModelAnimation;
+        private _configureModel();
+        /**
+         * Dispose this model, including all of its associated assets.
+         */
         dispose(): void;
     }
 
     /////<viewer
     export abstract class AbstractViewer {
         containerElement: HTMLElement;
+        /**
+         * The corresponsing template manager of this viewer.
+         */
         templateManager: TemplateManager;
+        /**
+         * Babylon Engine corresponding with this viewer
+         */
         engine: BABYLON.Engine;
+        /**
+         * The Babylon Scene of this viewer
+         */
         scene: BABYLON.Scene;
+        /**
+         * The camera used in this viewer
+         */
         camera: BABYLON.ArcRotateCamera;
+        /**
+         * Babylon's scene optimizer
+         */
         sceneOptimizer: BABYLON.SceneOptimizer;
-        baseId: string;
+        /**
+         * The ID of this viewer. it will be generated randomly or use the HTML Element's ID.
+         */
+        readonly baseId: string;
+        /**
+         * Models displayed in this viewer.
+         */
         models: Array<ViewerModel>;
-        modelLoader: ModelLoader;
+        /**
+         * The last loader used to load a model.
+         */
         lastUsedLoader: BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync;
-        protected configuration: ViewerConfiguration;
+        /**
+         * The ModelLoader instance connected with this viewer.
+         */
+        modelLoader: ModelLoader;
+        /**
+         * the viewer configuration object
+         */
+        protected _configuration: ViewerConfiguration;
+        /**
+         * Babylon's environment helper of this viewer
+         */
         environmentHelper: BABYLON.EnvironmentHelper;
-        protected defaultHighpTextureType: number;
-        protected shadowGeneratorBias: number;
-        protected defaultPipelineTextureType: number;
-        protected maxShadows: number;
-        readonly isHdrSupported: boolean;
+        protected _defaultHighpTextureType: number;
+        protected _shadowGeneratorBias: number;
+        protected _defaultPipelineTextureType: number;
+        /**
+         * The maximum number of shadows supported by the curent viewer
+         */
+        protected _maxShadows: number;
+        /**
+         * is HDR supported?
+         */
+        private _hdrSupport;
+        /**
+         * is this viewer disposed?
+         */
         protected _isDisposed: boolean;
+        /**
+         * Returns a boolean representing HDR support
+         */
+        readonly isHdrSupported: boolean;
+        /**
+         * Will notify when the scene was initialized
+         */
         onSceneInitObservable: BABYLON.Observable<BABYLON.Scene>;
+        /**
+         * will notify when the engine was initialized
+         */
         onEngineInitObservable: BABYLON.Observable<BABYLON.Engine>;
+        /**
+         * will notify after every model load
+         */
         onModelLoadedObservable: BABYLON.Observable<ViewerModel>;
+        /**
+         * will notify when any model notify of progress
+         */
         onModelLoadProgressObservable: BABYLON.Observable<BABYLON.SceneLoaderProgressEvent>;
+        /**
+         * will notify when any model load failed.
+         */
         onModelLoadErrorObservable: BABYLON.Observable<{
             message: string;
             exception: any;
         }>;
+        /**
+         * will notify when a new loader was initialized.
+         * Used mainly to know when a model starts loading.
+         */
         onLoaderInitObservable: BABYLON.Observable<BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync>;
+        /**
+         * Observers registered here will be executed when the entire load process has finished.
+         */
         onInitDoneObservable: BABYLON.Observable<AbstractViewer>;
-        canvas: HTMLCanvasElement;
-        protected registeredOnBeforerenderFunctions: Array<() => void>;
+        /**
+         * The canvas associated with this viewer
+         */
+        protected _canvas: HTMLCanvasElement;
+        /**
+         * The (single) canvas of this viewer
+         */
+        readonly canvas: HTMLCanvasElement;
+        /**
+         * registered onBeforeRender functions.
+         * This functions are also registered at the native scene. The reference can be used to unregister them.
+         */
+        protected _registeredOnBeforeRenderFunctions: Array<() => void>;
+        /**
+         * The configuration loader of this viewer
+         */
+        protected _configurationLoader: ConfigurationLoader;
         constructor(containerElement: HTMLElement, initialConfiguration?: ViewerConfiguration);
+        /**
+         * get the baseId of this viewer
+         */
         getBaseId(): string;
+        /**
+         * Do we have a canvas to render on, and is it a part of the scene
+         */
         isCanvasInDOM(): boolean;
-        protected resize: () => void;
-        protected render: () => void;
+        /**
+         * The resize function that will be registered with the window object
+         */
+        protected _resize: () => void;
+        /**
+         * render loop that will be executed by the engine
+         */
+        protected _render: () => void;
+        /**
+         * Update the current viewer configuration with new values.
+         * Only provided information will be updated, old configuration values will be kept.
+         * If this.configuration was manually changed, you can trigger this function with no parameters,
+         * and the entire configuration will be updated.
+         * @param newConfiguration
+         */
         updateConfiguration(newConfiguration?: Partial<ViewerConfiguration>): void;
-        protected configureEnvironment(skyboxConifguration?: ISkyboxConfiguration | boolean, groundConfiguration?: IGroundConfiguration | boolean): Promise<BABYLON.Scene> | undefined;
-        protected configureScene(sceneConfig: ISceneConfiguration, optimizerConfig?: ISceneOptimizerConfiguration): void;
-        protected configureOptimizer(optimizerConfig: ISceneOptimizerConfiguration | boolean): void;
-        protected configureObservers(observersConfiguration: IObserversConfiguration): void;
-        protected configureCamera(cameraConfig: ICameraConfiguration, model?: ViewerModel): void;
-        protected configureLights(lightsConfiguration?: {
+        protected _configureEnvironment(skyboxConifguration?: ISkyboxConfiguration | boolean, groundConfiguration?: IGroundConfiguration | boolean): Promise<BABYLON.Scene> | undefined;
+        /**
+         * internally configure the scene using the provided configuration.
+         * The scene will not be recreated, but just updated.
+         * @param sceneConfig the (new) scene configuration
+         */
+        protected _configureScene(sceneConfig: ISceneConfiguration): void;
+        /**
+         * Configure the scene optimizer.
+         * The existing scene optimizer will be disposed and a new one will be created.
+         * @param optimizerConfig the (new) optimizer configuration
+         */
+        protected _configureOptimizer(optimizerConfig: ISceneOptimizerConfiguration | boolean): void;
+        /**
+         * this is used to register native functions using the configuration object.
+         * This will configure the observers.
+         * @param observersConfiguration observers configuration
+         */
+        protected _configureObservers(observersConfiguration: IObserversConfiguration): void;
+        /**
+         * (Re) configure the camera. The camera will only be created once and from this point will only be reconfigured.
+         * @param cameraConfig the new camera configuration
+         * @param model optionally use the model to configure the camera.
+         */
+        protected _configureCamera(cameraConfig: ICameraConfiguration, model?: ViewerModel): void;
+        /**
+         * configure the lights.
+         *
+         * @param lightsConfiguration the (new) light(s) configuration
+         * @param model optionally use the model to configure the camera.
+         */
+        protected _configureLights(lightsConfiguration?: {
             [name: string]: ILightConfiguration | boolean;
         }, model?: ViewerModel): void;
-        protected configureModel(modelConfiguration: Partial<IModelConfiguration>, model?: ViewerModel): void;
+        /**
+         * configure all models using the configuration.
+         * @param modelConfiguration the configuration to use to reconfigure the models
+         */
+        protected _configureModel(modelConfiguration: Partial<IModelConfiguration>): void;
+        /**
+         * Dispoe the entire viewer including the scene and the engine
+         */
         dispose(): void;
-        protected abstract prepareContainerElement(): any;
-        protected onTemplatesLoaded(): Promise<AbstractViewer>;
-        protected initEngine(): Promise<BABYLON.Engine>;
-        protected initScene(): Promise<BABYLON.Scene>;
-        initModel(modelConfig?: any, clearScene?: boolean): ViewerModel
+        /**
+         * This will prepare the container element for the viewer
+         */
+        protected abstract _prepareContainerElement(): any;
+        /**
+         * This function will execute when the HTML templates finished initializing.
+         * It should initialize the engine and continue execution.
+         *
+         * @returns {Promise<AbstractViewer>} The viewer object will be returned after the object was loaded.
+         */
+        protected _onTemplatesLoaded(): Promise<AbstractViewer>;
+        /**
+         * Initialize the engine. Retruns a promise in case async calls are needed.
+         *
+         * @protected
+         * @returns {Promise<Engine>}
+         * @memberof Viewer
+         */
+        protected _initEngine(): Promise<BABYLON.Engine>;
+        /**
+         * initialize the scene. Calling thsi function again will dispose the old scene, if exists.
+         */
+        protected _initScene(): Promise<BABYLON.Scene>;
+        /**
+         * Initialize a model loading. The returns object (a ViewerModel object) will be loaded in the background.
+         * The difference between this and loadModel is that loadModel will fulfill the promise when the model finished loading.
+         *
+         * @param modelConfig model configuration to use when loading the model.
+         * @param clearScene should the scene be cleared before loading this model
+         * @returns a ViewerModel object that is not yet fully loaded.
+         */
+        initModel(modelConfig: IModelConfiguration, clearScene?: boolean): ViewerModel;
+        /**
+         * load a model using the provided configuration
+         *
+         * @param modelConfig the model configuration or URL to load.
+         * @param clearScene Should the scene be cleared before loading the model
+         * @returns a Promise the fulfills when the model finished loading successfully.
+         */
         loadModel(modelConfig?: any, clearScene?: boolean): Promise<ViewerModel>;
-        protected initEnvironment(viewerModel?: ViewerModel): Promise<BABYLON.Scene>;
-        protected handleHardwareLimitations(): void;
-        protected injectCustomShaders(): void;
-        protected extendClassWithConfig(object: any, config: any): void;
+        /**
+         * initialize the environment for a specific model.
+         * Per default it will use the viewer'S configuration.
+         * @param model the model to use to configure the environment.
+         * @returns a Promise that will resolve when the configuration is done.
+         */
+        protected _initEnvironment(model?: ViewerModel): Promise<BABYLON.Scene>;
+        /**
+		 * Alters render settings to reduce features based on hardware feature limitations
+		 * @param enableHDR Allows the viewer to run in HDR mode.
+		 */
+        protected _handleHardwareLimitations(enableHDR?: boolean): void;
+        /**
+         * Injects all the spectre shader in the babylon shader store
+         */
+        protected _injectCustomShaders(): void;
+        /**
+         * This will extend an object with configuration values.
+         * What it practically does it take the keys from the configuration and set them on the object.
+         * I the configuration is a tree, it will traverse into the tree.
+         * @param object the object to extend
+         * @param config the configuration object that will extend the object
+         */
+        protected _extendClassWithConfig(object: any, config: any): void;
     }
 
     export class DefaultViewer extends AbstractViewer {
         containerElement: HTMLElement;
-        camera: BABYLON.ArcRotateCamera;
+        /**
+         * Create a new default viewer
+         * @param containerElement the element in which the templates will be rendered
+         * @param initialConfiguration the initial configuration. Defaults to extending the default configuration
+         */
         constructor(containerElement: HTMLElement, initialConfiguration?: ViewerConfiguration);
-        initScene(): Promise<BABYLON.Scene>;
-        protected onTemplatesLoaded(): Promise<AbstractViewer>;
-        protected prepareContainerElement(): void;
+        /**
+         * Overriding the AbstractViewer's _initScene fcuntion
+         */
+        protected _initScene(): Promise<BABYLON.Scene>;
+        /**
+         * This will be executed when the templates initialize.
+         */
+        protected _onTemplatesLoaded(): Promise<AbstractViewer>;
+        private _initNavbar();
+        /**
+         * Preparing the container element to present the viewer
+         */
+        protected _prepareContainerElement(): void;
+        /**
+         * This function will configure the templates and update them after a model was loaded
+         * It is mainly responsible to changing the title and subtitle etc'.
+         * @param model the model to be used to configure the templates by
+         */
+        protected _configureTemplate(model: ViewerModel): void;
+        /**
+         * This will load a new model to the default viewer
+         * overriding the AbstractViewer's loadModel.
+         * The scene will automatically be cleared of the old models, if exist.
+         * @param model the configuration object (or URL) to load.
+         */
         loadModel(model?: any): Promise<ViewerModel>;
-        initEnvironment(viewerModel?: ViewerModel): Promise<BABYLON.Scene>;
-        showOverlayScreen(subScreen: string): Promise<Template>;
-        hideOverlayScreen(): Promise<Template>;
-        showLoadingScreen(): Promise<Template>;
-        hideLoadingScreen(): Promise<Template>;
+        private _onModelLoaded;
+        /**
+         * Show the overlay and the defined sub-screen.
+         * Mainly used for help and errors
+         * @param subScreen the name of the subScreen. Those can be defined in the configuration object
+         */
+        showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
+        /**
+         * Hide the overlay screen.
+         */
+        hideOverlayScreen(): Promise<string> | Promise<Template>;
+        /**
+         * Show the loading screen.
+         * The loading screen can be configured using the configuration object
+         */
+        showLoadingScreen(): Promise<string> | Promise<Template>;
+        /**
+         * Hide the loading screen
+         */
+        hideLoadingScreen(): Promise<string> | Promise<Template>;
+        /**
+         * An extension of the light configuration of the abstract viewer.
+         * @param lightsConfiguration the light configuration to use
+         * @param model the model that will be used to configure the lights (if the lights are model-dependant)
+         */
+        protected _configureLights(lightsConfiguration: {
+            [name: string]: boolean | ILightConfiguration;
+        } | undefined, model: ViewerModel): void;
     }
 }

Різницю між файлами не показано, бо вона завелика
+ 68 - 68
dist/preview release/viewer/babylon.viewer.js


Різницю між файлами не показано, бо вона завелика
+ 2442 - 1711
dist/preview release/viewer/babylon.viewer.max.js


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

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

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

@@ -2,7 +2,7 @@
 
 ## Major updates
 
-- Support for [GPU particles](https://doc.babylonjs.com/babylon101/particles#gpu-particles). Demo [here](https://www.babylonjs-playground.com/frame.html#PU4WYI#2) ([deltakosh](https://github.com/deltakosh))
+- Support for [GPU particles](https://doc.babylonjs.com/babylon101/particles#gpu-particles). Demo [here](https://www.babylonjs-playground.com/frame.html#PU4WYI#14) ([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))
 - Babylon.js now uses Promises in addition to callbacks. We created several `xxxAsync` functions all over the framework (`SceneLoader.AppendAsync` for instance, which returns a Promise). A polyfill is also integrated to support older browsers ([deltakosh](https://github.com/deltakosh))
 - Introduced 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))
@@ -13,17 +13,21 @@
 - Added [VideoDome](http://doc.babylonjs.com/how_to/360videodome) class to easily support 360 videos. Demo [here](https://www.babylonjs-playground.com/frame.html#1E9JQ8#7) ([DavidHGillen](https://github.com/DavidHGillen))
 - Added [GlowLayer](https://doc.babylonjs.com/how_to/glow_layer) to easily support glow from emissive materials. Demo [here](http://www.babylonjs.com/demos/GlowLayer/) ([sebavan](https://github.com/sebavan))
 - New [AssetContainer](http://doc.babylonjs.com/how_to/how_to_use_assetcontainer) class and loading methods ([trevordev](https://github.com/trevordev))
-- Added [depth of field](https://www.babylonjs-playground.com/frame.html#8F5HYV#5), sharpening, MSAA, chromatic aberration and grain effect to the default pipeline ([trevordev](https://github.com/trevordev))
+- Added [depth of field](https://www.babylonjs-playground.com/frame.html#8F5HYV#9), [sharpening, MSAA, chromatic aberration and grain effect](https://www.babylonjs-playground.com/#Y3C0HQ#146) to the default pipeline ([trevordev](https://github.com/trevordev))
 - Added support for [animation weights](http://doc.babylonjs.com/babylon101/animations#animation-weights). Demo [here](https://www.babylonjs-playground.com/#IQN716#9) ([deltakosh](https://github.com/deltakosh))
 - Added [sub emitters for particle system](http://doc.babylonjs.com/babylon101/particles#sub-emitters) which will spawn new particle systems when particles dies. Demo [here](https://www.babylonjs-playground.com/frame.html#9NHBCC#1) ([IbraheemOsama](https://github.com/IbraheemOsama))
 - New [Babylon.js](http://doc.babylonjs.com/resources/maya) and [glTF](http://doc.babylonjs.com/resources/maya_to_gltf) exporter for Autodesk Maya ([Noalak](https://github.com/Noalak))
 - New glTF [serializer](https://github.com/BabylonJS/Babylon.js/tree/master/serializers/src/glTF/2.0). You can now export glTF or glb files directly from a Babylon scene ([kcoley](https://github.com/kcoley))
 - New [glTF exporter](http://doc.babylonjs.com/resources/3dsmax_to_gltf) for Autodesk 3dsmax ([Noalak](https://github.com/Noalak))
 - Physics - Latest production version of Oimo.js is being used - 1.0.9 ([RaananW](https://github.com/RaananW))
+- Introduces [PCF](https://doc.babylonjs.com/babylon101/shadows#percentage-closer-filtering-webgl2-only) and [PCSS](https://doc.babylonjs.com/babylon101/shadows#contact-hardening-shadow-webgl2-only) shadow support in Webgl 2 ([sebavan](https://github.com/sebavan)))
+
+## Documentation
+- Tons of functions and classes received the code comments they deserved (All the community with a special thanks to [John King](https://github.com/BabylonJSGuide))
+- Moved the class API documentation to Typedoc ([deltakosh](https://github.com/deltakosh))
 
 ## Updates
 
-- Tons of functions and classes received the code comments they deserved (All the community)
 - New [particle system emitter shapes](http://doc.babylonjs.com/babylon101/particles#particles-shapes): cone and sphere ([IbraheemOsama](https://github.com/IbraheemOsama))
 - Added support for 16bits TGA ([deltakosh](https://github.com/deltakosh))
 - New `AnimationPropertiesOverride` class used to simplify setting animation properties on child animations. [Documentation](http://doc.babylonjs.com/babylon101/animations#overriding-properties) ([deltakosh](https://github.com/deltakosh))
@@ -98,7 +102,11 @@
 - Lightmap texture in PBR material follow the gammaSpace Flag of the texture ([sebavan](https://github.com/sebavan))
 - Added setTextureFromPostProcessOutput to bind the output of a postprocess into an effect ([trevordev](https://github.com/trevordev))
 - Added support for primitive modes to glTF 2.0 loader. ([bghgary](https://github.com/bghgary)]
+- Updated bloom effect to only bloom areas of the image above a luminance threshold ([trevordev](https://github.com/trevordev))
 - Cannon and Oimo are optional dependencies ([RaananW](https://github.com/RaananW))
+- Shadows - Introduces [Normal Bias](https://doc.babylonjs.com/babylon101/shadows#normal-bias-since-32) ([sebavan](https://github.com/sebavan)))
+- Earcut is an external, optional dependency. ([RaananW](https://github.com/RaananW))
+- Return animation groups when calling `SceneLoader.ImportMesh`. ([bghgary](https://github.com/bghgary)]
 
 ## Bug fixes
 
@@ -125,3 +133,4 @@
 - VertexData.merge no longer supports merging of data that do not have the same set of attributes. ([bghgary](https://github.com/bghgary)]
 - glTF 2.0 loader now creates a mesh for each primitive instead of merging the primitives together into one mesh. If a mesh only has one primitive, the behavior is the same as before. This change only affects meshes that have multiple primitives. ([bghgary](https://github.com/bghgary)]
 - Engine's onCanvasPointerOutObservable will now return a PointerEvent instead of the Engine. ([trevordev](https://github.com/trevordev))
+- Removed public references to default rendering pipeline's internal post process ([trevordev](https://github.com/trevordev))

+ 0 - 8
gui/src/controls/control.ts

@@ -69,49 +69,41 @@ module BABYLON.GUI {
 
         /**
         * An event triggered when the pointer move over the control.
-        * @type {BABYLON.Observable}
         */
         public onPointerMoveObservable = new Observable<Vector2>();
 
         /**
         * An event triggered when the pointer move out of the control.
-        * @type {BABYLON.Observable}
         */
         public onPointerOutObservable = new Observable<Control>();
 
         /**
         * An event triggered when the pointer taps the control
-        * @type {BABYLON.Observable}
         */
         public onPointerDownObservable = new Observable<Vector2WithInfo>();
 
         /**
         * An event triggered when pointer up
-        * @type {BABYLON.Observable}
         */
         public onPointerUpObservable = new Observable<Vector2WithInfo>();
 
         /**
         * An event triggered when a control is clicked on
-        * @type {BABYLON.Observable}
         */
         public onPointerClickObservable = new Observable<Vector2WithInfo>();
 
         /**
         * An event triggered when pointer enters the control
-        * @type {BABYLON.Observable}
         */
         public onPointerEnterObservable = new Observable<Control>();
 
         /**
         * An event triggered when the control is marked as dirty
-        * @type {BABYLON.Observable}
         */
         public onDirtyObservable = new Observable<Control>();
 
         /**
        * An event triggered after the control is drawn
-       * @type {BABYLON.Observable}
        */
         public onAfterDrawObservable = new Observable<Control>();
 

+ 0 - 2
gui/src/controls/textBlock.ts

@@ -14,13 +14,11 @@ module BABYLON.GUI {
         private _outlineColor: string = "white";
         /**
         * An event triggered after the text is changed
-        * @type {BABYLON.Observable}
         */
         public onTextChangedObservable = new Observable<TextBlock>();
 
         /**
         * An event triggered after the text was broken up into lines
-        * @type {BABYLON.Observable}
         */
         public onLinesReadyObservable = new Observable<TextBlock>();
 

+ 18 - 0
inspector/src/tabs/SceneTab.ts

@@ -67,6 +67,24 @@ module INSPECTOR {
                 wireframe.addEventListener('click', () => { this._inspector.scene.forcePointsCloud = false; this._inspector.scene.forceWireframe = true; });
                 solid.addEventListener('click', () => { this._inspector.scene.forcePointsCloud = false; this._inspector.scene.forceWireframe = false; });
 
+                // Cameras
+                title = Helpers.CreateDiv('actions-title', this._actions);
+                title.textContent = 'Cameras';
+                let cameraRadioButtons = [];
+                for (let camera of this._inspector.scene.cameras) {
+                    let cameraRadio = Helpers.CreateDiv('action-radio', this._actions);
+                    cameraRadio.textContent = camera.name;
+                    if(this._inspector.scene.activeCamera == camera)
+                    {
+                        cameraRadio.classList.add('active');
+                    }
+                    cameraRadioButtons.push(cameraRadio);
+                    cameraRadio.addEventListener('click', () => { this._inspector.scene.switchActiveCamera(camera);});
+                }
+
+                this._generateRadioAction(cameraRadioButtons);
+                
+
                 // Textures
                 title = Helpers.CreateDiv('actions-title', this._actions);
                 title.textContent = 'Textures channels';

+ 23 - 0
inspector/src/tools/FullscreenTool.ts

@@ -0,0 +1,23 @@
+module INSPECTOR {
+     
+    export class FullscreenTool extends AbstractTool {
+
+        constructor(parent:HTMLElement, inspector:Inspector) {
+            super('fa-expand', parent, inspector, 'Open the scene in fullscreen, press Esc to exit');
+        }
+
+        // Action : refresh the whole panel
+        public action() {
+
+            var elem = document.body;
+
+            function requestFullScreen(element:HTMLElement) {
+                // Supports most browsers and their versions.
+                var requestMethod = element.requestFullscreen || element.webkitRequestFullScreen;
+                requestMethod.call(element);
+            }
+           
+            requestFullScreen(elem);
+        }
+    }
+}

+ 3 - 0
inspector/src/tools/Toolbar.ts

@@ -33,6 +33,9 @@
             if (!this._inspector.popupMode && !Helpers.IsBrowserEdge()) {
                 this._tools.push(new PopupTool(this._div, this._inspector));
             }
+            // FullScreen
+            this._tools.push(new FullscreenTool(this._div, this._inspector));
+
             // Pause schedule
             this._tools.push(new PauseScheduleTool(this._div, this._inspector));
             

+ 15 - 0
inspector/test/index.js

@@ -36,6 +36,21 @@ var Test = (function () {
         var scene = new BABYLON.Scene(this.engine);
         var canvas = scene.getEngine().getRenderingCanvas();
 
+        var camera = new BABYLON.FreeCamera("Camera", new BABYLON.Vector3(0, 0, 0), scene); 
+        
+        var camera2 = new BABYLON.ArcRotateCamera("Camera2", 0, 0, -0.1, new BABYLON.Vector3(0, 0, 0), scene);
+
+        var camera3 = new BABYLON.ArcRotateCamera("Camera3", 0, 0, -0.1, new BABYLON.Vector3(0, 0, 0), scene);
+
+        var camera4 = new BABYLON.ArcRotateCamera("Camera4", 0, 0, -0.1, new BABYLON.Vector3(0, 0, 0), scene);
+
+        var camera5 = new BABYLON.ArcRotateCamera("Camera5", 0, 0, -0.1, new BABYLON.Vector3(0, 0, 0), scene);
+
+        var camera6 = new BABYLON.ArcRotateCamera("Camera6", 0, 0, -0.1, new BABYLON.Vector3(0, 0, 0), scene);
+
+        scene.activeCamera = camera2;
+        
+        camera2.attachControl(canvas);
 
         var sceneRoot = new BABYLON.TransformNode("abstractmesh");
 

+ 8 - 8
loaders/src/glTF/1.0/babylon.glTFLoader.ts

@@ -1573,7 +1573,6 @@ module BABYLON.GLTF1 {
         public onMeshLoadedObservable = new Observable<AbstractMesh>();
         public onTextureLoadedObservable = new Observable<BaseTexture>();
         public onMaterialLoadedObservable = new Observable<Material>();
-        public onAnimationGroupLoadedObservable = new Observable<AnimationGroup>();
         public onCompleteObservable = new Observable<IGLTFLoader>();
         public onExtensionLoadedObservable = new Observable<IGLTFLoaderExtension>();
 
@@ -1582,7 +1581,7 @@ module BABYLON.GLTF1 {
         public dispose(): void {}
         // #endregion
 
-        private _importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string) => void): boolean {
+        private _importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string) => void): boolean {
             scene.useRightHandedSystem = true;
 
             GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, gltfRuntime => {
@@ -1632,26 +1631,27 @@ module BABYLON.GLTF1 {
                         postLoad(gltfRuntime);
 
                         if (!GLTFFileLoader.IncrementalLoading && onSuccess) {
-                            onSuccess(meshes, [], skeletons);
+                            onSuccess(meshes, skeletons);
                         }
                     });
                 }, onProgress);
 
                 if (GLTFFileLoader.IncrementalLoading && onSuccess) {
-                    onSuccess(meshes, [], skeletons);
+                    onSuccess(meshes, skeletons);
                 }
             }, onError);
 
             return true;
         }
 
-        public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{ meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[] }> {
+        public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{ meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[], animationGroups: AnimationGroup[] }> {
             return new Promise((resolve, reject) => {
-                this._importMeshAsync(meshesNames, scene, data, rootUrl, (meshes, particleSystems, skeletons) => {
+                this._importMeshAsync(meshesNames, scene, data, rootUrl, (meshes, skeletons) => {
                     resolve({
                         meshes: meshes,
-                        particleSystems: particleSystems,
-                        skeletons: skeletons
+                        particleSystems: [],
+                        skeletons: skeletons,
+                        animationGroups: []
                     });
                 }, onProgress, message => {
                     reject(new Error(message));

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


Деякі файли не було показано, через те що забагато файлів було змінено