Browse Source

Merge master

David Catuhe 7 years ago
parent
commit
03960a5e8c
100 changed files with 10139 additions and 23310 deletions
  1. 891 736
      Playground/babylon.d.txt
  2. 57 46
      Playground/js/frame.js
  3. 55 47
      Playground/js/index.js
  4. 1 1
      Playground/js/pbt.js
  5. 23 5
      Tools/Gulp/config.json
  6. 16 4
      Tools/Gulp/gulpfile.js
  7. 14 6
      Tools/Gulp/package.json
  8. 4 0
      Tools/Publisher/index.js
  9. 97 0
      Viewer/assets/deepmerge.min.js
  10. 1 0
      Viewer/assets/es6-promise.min.js
  11. 29 0
      Viewer/assets/handlebars.min.js
  12. 1 0
      Viewer/assets/templates/default/loadingScreen.html
  13. 3 3
      Viewer/dist/basicExample.html
  14. 1897 500
      Viewer/dist/viewer.js
  15. 1 38
      Viewer/dist/viewer.min.js
  16. 6 9
      Viewer/package.json
  17. 1 0
      Viewer/src/configuration/configuration.ts
  18. 1 1
      Viewer/src/configuration/loader.ts
  19. 2 4
      Viewer/src/index.ts
  20. 1 1
      Viewer/src/templateManager.ts
  21. 1 1
      Viewer/src/util/promiseObservable.ts
  22. 59 13
      Viewer/src/viewer/defaultViewer.ts
  23. 2 0
      Viewer/src/viewer/viewerManager.ts
  24. 32 0
      Viewer/tsconfig-gulp.json
  25. 1 2
      Viewer/tsconfig.json
  26. 51 0
      Viewer/webpack.gulp.config.js
  27. 0 18033
      dist/babylon.module.d.ts
  28. 7 10
      dist/inspector/babylon.inspector.css
  29. 949 783
      dist/preview release/babylon.d.ts
  30. 49 48
      dist/preview release/babylon.js
  31. 1173 462
      dist/preview release/babylon.max.js
  32. 51 50
      dist/preview release/babylon.worker.js
  33. 382 270
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  34. 53 52
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  35. 1354 529
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  36. 4 3
      dist/preview release/gui/babylon.gui.d.ts
  37. 45 8
      dist/preview release/gui/babylon.gui.js
  38. 3 3
      dist/preview release/gui/babylon.gui.min.js
  39. 4 3
      dist/preview release/gui/babylon.gui.module.d.ts
  40. 1 1
      dist/preview release/gui/package.json
  41. 4 447
      dist/preview release/inspector/babylon.inspector.bundle.js
  42. 4 0
      dist/preview release/inspector/babylon.inspector.d.ts
  43. 18 3
      dist/preview release/inspector/babylon.inspector.js
  44. 4 4
      dist/preview release/inspector/babylon.inspector.min.js
  45. 1 1
      dist/preview release/inspector/package.json
  46. 58 6
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  47. 72 18
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  48. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  49. 64 16
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  50. 165 62
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  51. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  52. 64 16
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  53. 183 69
      dist/preview release/loaders/babylon.glTFFileLoader.js
  54. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  55. 183 69
      dist/preview release/loaders/babylonjs.loaders.js
  56. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  57. 64 16
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  58. 1 1
      dist/preview release/loaders/package.json
  59. 3 2
      dist/preview release/materialsLibrary/babylon.waterMaterial.d.ts
  60. 26 9
      dist/preview release/materialsLibrary/babylon.waterMaterial.js
  61. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  62. 26 9
      dist/preview release/materialsLibrary/babylonjs.materials.js
  63. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  64. 3 2
      dist/preview release/materialsLibrary/babylonjs.materials.module.d.ts
  65. 1 1
      dist/preview release/materialsLibrary/package.json
  66. 1 1
      dist/preview release/postProcessesLibrary/package.json
  67. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  68. 1 1
      dist/preview release/serializers/package.json
  69. 66 0
      dist/preview release/viewer/babylon.viewer.js
  70. 32 0
      dist/preview release/viewer/package.json
  71. 56 0
      dist/preview release/viewer/readme.md
  72. 1 0
      dist/preview release/what's new.md
  73. 2 0
      gui/src/advancedDynamicTexture.ts
  74. 133 133
      gui/src/controls/control.ts
  75. 16 1
      gui/src/controls/image.ts
  76. 71 52
      gui/src/controls/inputText.ts
  77. 39 35
      gui/src/controls/slider.ts
  78. 10 3
      inspector/src/details/PropertyLine.ts
  79. 8 0
      inspector/src/helpers/Helpers.ts
  80. 18 17
      inspector/test/index.js
  81. 7 3
      inspector/webpack.config.js
  82. 26 12
      loaders/src/glTF/1.0/babylon.glTFLoader.ts
  83. 110 52
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  84. 2 2
      loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts
  85. 1 2
      loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts
  86. 131 52
      loaders/src/glTF/README.md
  87. 88 14
      loaders/src/glTF/babylon.glTFFileLoader.ts
  88. 117 108
      localDev/index.html
  89. 42 17
      materialsLibrary/src/water/babylon.waterMaterial.ts
  90. 2 2
      package.json
  91. 14 8
      sandbox/index.js
  92. 1 1
      src/Audio/babylon.sound.ts
  93. 706 306
      src/Cameras/VR/babylon.vrExperienceHelper.ts
  94. 93 15
      src/Cameras/VR/babylon.webVRCamera.ts
  95. 4 0
      src/Cameras/babylon.camera.ts
  96. 14 17
      src/Cameras/babylon.targetCamera.ts
  97. 10 5
      src/Engine/babylon.engine.ts
  98. 27 15
      src/Gamepad/Controllers/babylon.poseEnabledController.ts
  99. 11 0
      src/Gamepad/Controllers/babylon.windowsMotionController.ts
  100. 0 0
      src/Gamepad/babylon.gamepadManager.ts

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


+ 57 - 46
Playground/js/frame.js

@@ -61,72 +61,83 @@
             }
 
             var canvas = document.getElementById("renderCanvas");
-            engine = new BABYLON.Engine(canvas, true, { stencil: true });
-            BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault = true;
-            engine.runRenderLoop(function () {
-                if (engine.scenes.length === 0) {
-                    return;
-                }
 
-                if (canvas.width !== canvas.clientWidth) {
-                    engine.resize();
-                }
+            var checkCamera = true;
+            var wrappedEval = false;
+            var createEngineFunction = "createDefaultEngine";
+            var createSceneFunction;
 
-                var scene = engine.scenes[0];
+            var createDefaultEngine = function () {
+                return new BABYLON.Engine(canvas, true, { stencil: true });
+            }
 
-                if (scene.activeCamera || scene.activeCameras.length > 0) {
-                    scene.render();
-                }
+            var scene;
 
-                if (fpsLabel) {
-                    fpsLabel.innerHTML = engine.getFps().toFixed() + " fps";
-                }
-            });
+            if (code.indexOf("createEngine") !== -1) {
+                createEngineFunction = "createEngine";
+            }
 
-            var scene;
             if (code.indexOf("delayCreateScene") !== -1) { // createScene
+                createSceneFunction = "delayCreateScene";
+                checkCamera = false;
+            } else if (code.indexOf("createScene") !== -1) { // createScene
+                createSceneFunction = "createScene";
+            } else if (code.indexOf("CreateScene") !== -1) { // CreateScene
+                createSceneFunction = "CreateScene";
+            } else if (code.indexOf("createscene") !== -1) { // createscene
+                createSceneFunction = "createscene";
+            }
+
+            if (!createSceneFunction) {
+                // just pasted code.
+                engine = createDefaultEngine();
+                scene = new BABYLON.Scene(engine);
+                eval("runScript = function(scene, canvas) {" + code + "}");
+                runScript(scene, canvas);
+
+                zipCode = "var scene = new BABYLON.Scene(engine);\r\n\r\n" + code;
+            } else {
+                //execute the code
                 eval(code);
-                scene = delayCreateScene();
-                if (!scene) {
-                    showError("delayCreateScene function must return a scene.", null);
+                //create engine
+                eval("engine = " + createEngineFunction + "()");
+                if (!engine) {
+                    showError("createEngine function must return an engine.", null);
                     return;
                 }
 
-                zipCode = code + "\r\n\r\nvar scene = createScene();";
-            } if (code.indexOf("createScene") !== -1) { // createScene
-                eval(code);
-                scene = createScene();
+                //create scene
+                eval("scene = " + createSceneFunction + "()");
+
                 if (!scene) {
-                    showError("createScene function must return a scene.");
+                    showError(createSceneFunction + " function must return a scene.", null);
                     return;
                 }
 
-                zipCode = code + "\r\n\r\nvar scene = createScene();";
-            } else if (code.indexOf("CreateScene") !== -1) { // CreateScene
-                eval(code);
-                scene = CreateScene();
-                if (!scene) {
-                    showError("CreateScene function must return a scene.");
+                // update the scene code for the zip file
+                zipCode = code + "\r\n\r\nvar scene = " + createSceneFunction + "()";
+            }
+
+            BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault = true;
+            engine.runRenderLoop(function () {
+                if (engine.scenes.length === 0) {
                     return;
                 }
 
-                zipCode = code + "\r\n\r\nvar scene = CreateScene();";
-            } else if (code.indexOf("createscene") !== -1) { // createscene
-                eval(code);
-                scene = createscene();
-                if (!scene) {
-                    showError("createscene function must return a scene.");
-                    return;
+                if (canvas.width !== canvas.clientWidth) {
+                    engine.resize();
                 }
 
-                zipCode = code + "\r\n\r\nvar scene = createscene();";
-            } else { // Direct code
-                scene = new BABYLON.Scene(engine);
-                eval("runScript = function(scene, canvas) {" + code + "}");
-                runScript(scene, canvas);
+                var scene = engine.scenes[0];
 
-                zipCode = "var scene = new BABYLON.Scene(engine);\r\n\r\n" + code;
-            }
+                if (scene.activeCamera || scene.activeCameras.length > 0) {
+                    scene.render();
+                }
+
+                if (fpsLabel) {
+                    fpsLabel.innerHTML = engine.getFps().toFixed() + " fps";
+                }
+            });
 
         } catch (e) {
             // showError(e.message);

+ 55 - 47
Playground/js/index.js

@@ -355,77 +355,85 @@
                 }
 
                 var canvas = document.getElementById("renderCanvas");
-                engine = new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true });
                 document.getElementById("errorZone").style.display = 'none';
                 document.getElementById("errorZone").innerHTML = "";
                 document.getElementById("statusBar").innerHTML = "Loading assets...Please wait";
                 var checkCamera = true;
+                var wrappedEval = false;
+                var createEngineFunction = "createDefaultEngine";
+                var createSceneFunction;
 
-                engine.runRenderLoop(function () {
-                    if (engine.scenes.length === 0) {
-                        return;
-                    }
-
-                    if (canvas.width !== canvas.clientWidth) {
-                        engine.resize();
-                    }
+                var code = jsEditor.getValue();
 
-                    var scene = engine.scenes[0];
+                var createDefaultEngine = function () {
+                    return new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true });
+                }
 
-                    if (scene.activeCamera || scene.activeCameras.length > 0) {
-                        scene.render();
-                    }
+                var scene;
 
-                    fpsLabel.style.right = document.body.clientWidth - (jsEditor.domElement.clientWidth + canvas.clientWidth) + "px";
-                    fpsLabel.innerHTML = engine.getFps().toFixed() + " fps";
-                });
+                if (code.indexOf("createEngine") !== -1) {
+                    createEngineFunction = "createEngine";
+                }
 
-                var code = jsEditor.getValue();
-                var scene;
                 if (code.indexOf("delayCreateScene") !== -1) { // createScene
-                    eval(code);
-                    scene = delayCreateScene();
+                    createSceneFunction = "delayCreateScene";
                     checkCamera = false;
-                    if (!scene) {
-                        showError("delayCreateScene function must return a scene.", null);
-                        return;
-                    }
-
-                    zipCode = code + "\r\n\r\nvar scene = createScene();";
                 } else if (code.indexOf("createScene") !== -1) { // createScene
+                    createSceneFunction = "createScene";
+                } else if (code.indexOf("CreateScene") !== -1) { // CreateScene
+                    createSceneFunction = "CreateScene";
+                } else if (code.indexOf("createscene") !== -1) { // createscene
+                    createSceneFunction = "createscene";
+                }
+
+                if (!createSceneFunction) {
+                    // just pasted code.
+                    engine = createDefaultEngine();
+                    scene = new BABYLON.Scene(engine);
+                    eval("runScript = function(scene, canvas) {" + code + "}");
+                    runScript(scene, canvas);
+
+                    zipCode = "var scene = new BABYLON.Scene(engine);\r\n\r\n" + code;
+                } else {
+                    //execute the code
                     eval(code);
-                    scene = createScene();
-                    if (!scene) {
-                        showError("createScene function must return a scene.", null);
+                    //create engine
+                    eval("engine = " + createEngineFunction + "()");
+                    if (!engine) {
+                        showError("createEngine function must return an engine.", null);
                         return;
                     }
 
-                    zipCode = code + "\r\n\r\nvar scene = createScene();";
-                } else if (code.indexOf("CreateScene") !== -1) { // CreateScene
-                    eval(code);
-                    scene = CreateScene();
+                    //create scene
+                    eval("scene = " + createSceneFunction + "()");
+
                     if (!scene) {
-                        showError("CreateScene function must return a scene.", null);
+                        showError(createSceneFunction + " function must return a scene.", null);
                         return;
                     }
 
-                    zipCode = code + "\r\n\r\nvar scene = CreateScene();";
-                } else if (code.indexOf("createscene") !== -1) { // createscene
-                    eval(code);
-                    scene = createscene();
-                    if (!scene) {
-                        showError("createscene function must return a scene.", null);
+                    // update the scene code for the zip file
+                    zipCode = code + "\r\n\r\nvar scene = " + createSceneFunction + "()";
+                }
+
+                engine.runRenderLoop(function () {
+                    if (engine.scenes.length === 0) {
                         return;
                     }
 
-                    zipCode = code + "\r\n\r\nvar scene = createscene();";
-                } else { // Direct code
-                    scene = new BABYLON.Scene(engine);
-                    eval("runScript = function(scene, canvas) {" + code + "}");
-                    runScript(scene, canvas);
+                    if (canvas.width !== canvas.clientWidth) {
+                        engine.resize();
+                    }
 
-                    zipCode = "var scene = new BABYLON.Scene(engine);\r\n\r\n" + code;
-                }
+                    var scene = engine.scenes[0];
+
+                    if (scene.activeCamera || scene.activeCameras.length > 0) {
+                        scene.render();
+                    }
+
+                    fpsLabel.style.right = document.body.clientWidth - (jsEditor.domElement.clientWidth + canvas.clientWidth) + "px";
+                    fpsLabel.innerHTML = engine.getFps().toFixed() + " fps";
+                });
 
                 if (engine.scenes.length === 0) {
                     showError("You must at least create a scene.", null);

+ 1 - 1
Playground/js/pbt.js

@@ -417,7 +417,7 @@ var PBT = function() {
             parent.addControl(header);  
 
             button.onValueChangedObservable.add(function(value) {
-                header.text = "Y-rotation: " + onValueChange(value) + " " + unit;
+                header.text = text + onValueChange(value) + " " + unit;
                 func(value);
             });
             parent.addControl(button);

+ 23 - 5
Tools/Gulp/config.json

@@ -931,7 +931,8 @@
                 "../../src/Physics/Plugins/babylon.oimoJSPlugin.js"
             ],
             "dependUpon": [
-                "core"
+                "core",
+                "picking"
             ]
         },
         "textureFormats": {
@@ -1178,7 +1179,8 @@
         "loaders",
         "serializers",
         "inspector",
-        "gui"
+        "gui",
+        "viewer"
     ],
     "materialsLibrary": {
         "libraries": [
@@ -1566,12 +1568,12 @@
                     "../../gui/src/controls/ellipse.ts",
                     "../../gui/src/controls/line.ts",
                     "../../gui/src/controls/slider.ts",
-                    "../../gui/src/controls/checkBox.ts",
+                    "../../gui/src/controls/checkbox.ts",
                     "../../gui/src/controls/radioButton.ts",
                     "../../gui/src/controls/textBlock.ts",
                     "../../gui/src/controls/image.ts",
                     "../../gui/src/controls/button.ts",
-                    "../../gui/src/controls/colorPicker.ts",
+                    "../../gui/src/controls/colorpicker.ts",
                     "../../gui/src/controls/inputText.ts",
                     "../../gui/src/controls/virtualKeyboard.ts"
                 ],
@@ -1661,5 +1663,21 @@
             "srcOutputDirectory": "../../inspector/",
             "distOutputDirectory": "/inspector/"
         }
+    },
+    "viewer": {
+        "libraries": [
+            {
+                "files": [],
+                "noBundleInName": true,
+                "output": "babylon.viewer.js",
+                "webpack": "../../Viewer/webpack.gulp.config.js",
+                "bundle": "true",
+                "moduleDeclaration": "BabylonViewer"
+            }
+        ],
+        "build": {
+            "srcOutputDirectory": "../../Viewer/",
+            "distOutputDirectory": "/viewer/"
+        }
     }
-}
+}

+ 16 - 4
Tools/Gulp/gulpfile.js

@@ -49,7 +49,8 @@ var tsConfig = {
     noImplicitThis: true,
     noUnusedLocals: true,
     strictNullChecks: true,
-    strictFunctionTypes: true
+    strictFunctionTypes: true,
+    types: []
 };
 var tsProject = typescript.createProject(tsConfig);
 
@@ -64,7 +65,8 @@ var externalTsConfig = {
     noImplicitReturns: true,
     noImplicitThis: true,
     noUnusedLocals: true,
-    strictNullChecks: true
+    strictNullChecks: true,
+    types: []
 };
 
 var minimist = require("minimist");
@@ -224,7 +226,14 @@ gulp.task("build", ["shaders"], function () {
 /*
 * Compiles all typescript files and creating a js and a declaration file.
 */
+var alreadyCompiled = false;
+var forceCompile = false;
 gulp.task("typescript-compile", function () {
+    if (!forceCompile && alreadyCompiled) {
+        return;
+    }
+    alreadyCompiled = true;
+
     var tsResult = gulp.src(config.typescript)
         .pipe(sourcemaps.init())
         .pipe(tsProject());
@@ -398,9 +407,11 @@ var buildExternalLibrary = function (library, settings, watch) {
 
         if (library.webpack) {
             return waitAll.on("end", function () {
-                webpack(require(library.webpack))
-                    .pipe(rename(library.output.replace(".js", ".bundle.js")))
+                return webpack(require(library.webpack))
+                    .pipe(rename(library.output.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
                     .pipe(addModuleExports(library.moduleDeclaration, false, false, true))
+                    .pipe(uglify())
+                    .pipe(optimisejs())
                     .pipe(gulp.dest(outputDirectory))
             });
         }
@@ -473,6 +484,7 @@ gulp.task("typescript-all", function (cb) {
  * Watch ts files and fire repective tasks.
  */
 gulp.task("watch", [], function () {
+    forceCompile = true;
     var interval = 1000;
     var tasks = [gulp.watch(config.typescript, { interval: interval }, ["typescript-compile"])];
 

+ 14 - 6
Tools/Gulp/package.json

@@ -9,9 +9,13 @@
     "readme": "https://github.com/BabylonJS/Babylon.js/edit/master/readme.md",
     "license": "(Apache-2.0)",
     "devDependencies": {
+        "@types/node": "^8.0.53",
+        "base64-image-loader": "^1.2.0",
         "css-loader": "^0.25.0",
+        "deepmerge": "^2.0.1",
         "del": "2.2.2",
-        "exports-loader": "^0.6.3",
+        "es6-promise": "^4.1.1",
+        "exports-loader": "^0.6.4",
         "gulp": "^3.8.11",
         "gulp-changed-in-place": "2.0.3",
         "gulp-clean-ts-extends": "~0.1.1",
@@ -24,20 +28,24 @@
         "gulp-replace": "~0.5.3",
         "gulp-sass": "3.1.0",
         "gulp-sourcemaps": "~1.9.1",
-        "gulp-typescript": "^3.2.2",
+        "gulp-typescript": "^3.2.3",
         "gulp-uglify": "^2.1.2",
         "gulp-util": "~3.0.4",
         "gulp-webserver": "^0.9.1",
-        "imports-loader": "^0.7.0",
+        "handlebars": "^4.0.11",
+        "html-loader": "^0.5.1",
+        "imports-loader": "^0.7.1",
+        "json-loader": "^0.5.7",
         "merge2": "~0.3.5",
         "minimist": "^1.2.0",
         "run-sequence": "~1.1.0",
-        "style-loader": "^0.13.1",
+        "style-loader": "^0.13.2",
         "through2": "~0.6.5",
+        "ts-loader": "^2.3.7",
         "typescript": "~2.6.1",
-        "webpack-stream": "^3.2.0"
+        "webpack-stream": "^4.0.0"
     },
     "scripts": {
         "install": "npm --prefix ../../Playground/ install ../../Playground/ && gulp typescript-compile && gulp typescript-libraries && gulp deployLocalDev"
     }
-}
+}

+ 4 - 0
Tools/Publisher/index.js

@@ -39,6 +39,10 @@ let packages = [
     {
         name: 'inspector',
         path: basePath + '/inspector/'
+    },
+    {
+        name: 'viewer',
+        path: basePath + '/viewer/'
     }
 ];
 

+ 97 - 0
Viewer/assets/deepmerge.min.js

@@ -0,0 +1,97 @@
+(function (global, factory) {
+	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+	typeof define === 'function' && define.amd ? define(factory) :
+	(global.deepmerge = factory());
+}(this, (function () { 'use strict';
+
+var isMergeableObject = function isMergeableObject(value) {
+	return isNonNullObject(value)
+		&& !isSpecial(value)
+};
+
+function isNonNullObject(value) {
+	return !!value && typeof value === 'object'
+}
+
+function isSpecial(value) {
+	var stringValue = Object.prototype.toString.call(value);
+
+	return stringValue === '[object RegExp]'
+		|| stringValue === '[object Date]'
+		|| isReactElement(value)
+}
+
+// see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25
+var canUseSymbol = typeof Symbol === 'function' && Symbol.for;
+var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7;
+
+function isReactElement(value) {
+	return value.$$typeof === REACT_ELEMENT_TYPE
+}
+
+function emptyTarget(val) {
+	return Array.isArray(val) ? [] : {}
+}
+
+function cloneUnlessOtherwiseSpecified(value, optionsArgument) {
+	var clone = !optionsArgument || optionsArgument.clone !== false;
+
+	return (clone && isMergeableObject(value))
+		? deepmerge(emptyTarget(value), value, optionsArgument)
+		: value
+}
+
+function defaultArrayMerge(target, source, optionsArgument) {
+	return target.concat(source).map(function(element) {
+		return cloneUnlessOtherwiseSpecified(element, optionsArgument)
+	})
+}
+
+function mergeObject(target, source, optionsArgument) {
+	var destination = {};
+	if (isMergeableObject(target)) {
+		Object.keys(target).forEach(function(key) {
+			destination[key] = cloneUnlessOtherwiseSpecified(target[key], optionsArgument);
+		});
+	}
+	Object.keys(source).forEach(function(key) {
+		if (!isMergeableObject(source[key]) || !target[key]) {
+			destination[key] = cloneUnlessOtherwiseSpecified(source[key], optionsArgument);
+		} else {
+			destination[key] = deepmerge(target[key], source[key], optionsArgument);
+		}
+	});
+	return destination
+}
+
+function deepmerge(target, source, optionsArgument) {
+	var sourceIsArray = Array.isArray(source);
+	var targetIsArray = Array.isArray(target);
+	var options = optionsArgument || { arrayMerge: defaultArrayMerge };
+	var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray;
+
+	if (!sourceAndTargetTypesMatch) {
+		return cloneUnlessOtherwiseSpecified(source, optionsArgument)
+	} else if (sourceIsArray) {
+		var arrayMerge = options.arrayMerge || defaultArrayMerge;
+		return arrayMerge(target, source, optionsArgument)
+	} else {
+		return mergeObject(target, source, optionsArgument)
+	}
+}
+
+deepmerge.all = function deepmergeAll(array, optionsArgument) {
+	if (!Array.isArray(array)) {
+		throw new Error('first argument should be an array')
+	}
+
+	return array.reduce(function(prev, next) {
+		return deepmerge(prev, next, optionsArgument)
+	}, {})
+};
+
+var deepmerge_1 = deepmerge;
+
+return deepmerge_1;
+
+})));

File diff suppressed because it is too large
+ 1 - 0
Viewer/assets/es6-promise.min.js


File diff suppressed because it is too large
+ 29 - 0
Viewer/assets/handlebars.min.js


+ 1 - 0
Viewer/assets/templates/default/loadingScreen.html

@@ -3,6 +3,7 @@
 
     loading-screen {
         position: absolute;
+        left: 0;
         z-index: 100;
         opacity: 1;
         pointer-events: none;

+ 3 - 3
Viewer/dist/basicExample.html

@@ -17,8 +17,8 @@
     </head>
 
     <body>
-        <babylon model.title="Amazing Rabbit" model.subtitle="BabylonJS" model.thumbnail="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png"
-            model.url="https://playground.babylonjs.com/scenes/Rabbit.babylon" camera.behaviors.auto-rotate="0" templates.nav-bar.params.disable-on-fullscreen="true"></babylon>
+        <babylon model.title="Damaged Helmet" model.subtitle="BabylonJS" model.thumbnail="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png"
+            model.url="https://www.babylonjs.com/Assets/DamagedHelmet/glTF/DamagedHelmet.gltf" camera.behaviors.auto-rotate="0" templates.nav-bar.params.disable-on-fullscreen="true"></babylon>
         <script src="viewer.js"></script>
         <script>
             // The following lines are redundant. 
@@ -31,4 +31,4 @@
         </script>
     </body>
 
-</html>
+</html>

File diff suppressed because it is too large
+ 1897 - 500
Viewer/dist/viewer.js


File diff suppressed because it is too large
+ 1 - 38
Viewer/dist/viewer.min.js


+ 6 - 9
Viewer/package.json

@@ -23,22 +23,19 @@
     },
     "homepage": "https://github.com/BabylonJS/Babylon.js#readme",
     "devDependencies": {
-        "@types/node": "^8.0.52",
+        "@types/node": "^8.0.53",
         "base64-image-loader": "^1.2.0",
         "html-loader": "^0.5.1",
         "json-loader": "^0.5.7",
         "ts-loader": "^2.3.7",
-        "typescript": "^2.6.1",
-        "uglifyjs-webpack-plugin": "^1.0.1",
+        "typescript": "^2.6.2",
+        "uglifyjs-webpack-plugin": "^1.1.1",
         "webpack": "^3.8.1",
-        "webpack-dev-server": "^2.9.4"
+        "webpack-dev-server": "^2.9.5"
     },
     "dependencies": {
-        "babylonjs": "^3.1.0-beta3",
-        "babylonjs-loaders": "^3.1.0-beta3",
-        "babylonjs-materials": "^3.1.0-beta3",
-        "babylonjs-post-process": "^3.1.0-beta3",
-        "babylonjs-procedural-textures": "^3.1.0-beta3",
+        "babylonjs": "^3.1.0-beta6",
+        "babylonjs-loaders": "^3.1.0-beta6",
         "deepmerge": "^2.0.1",
         "es6-promise": "^4.1.1",
         "handlebars": "^4.0.11"

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

@@ -98,6 +98,7 @@ export interface ViewerConfiguration {
         size?: number;
         receiveShadows?: boolean;
         shadowOnly?: boolean;
+        mirror?: boolean;
         material?: {
             [propName: string]: any;
         }

+ 1 - 1
Viewer/src/configuration/loader.ts

@@ -2,7 +2,7 @@ import { mapperManager } from './mappers';
 import { ViewerConfiguration } from './configuration';
 import { getConfigurationType } from './types';
 
-import deepmerge from 'deepmerge';
+import * as deepmerge from '../../assets/deepmerge.min.js';
 
 export class ConfigurationLoader {
 

+ 2 - 4
Viewer/src/index.ts

@@ -13,17 +13,15 @@ import { AbstractViewer } from './viewer/viewer';
 // load babylon and needed modules.
 import 'babylonjs';
 import 'babylonjs-loaders';
-import 'babylonjs-materials';
 import '../assets/pep.min';
 
 import { InitTags } from './initializer';
 
 // promise polyfill, if needed!
-global.Promise = Promise || require('es6-promise').Promise;
+global.Promise = typeof Promise === 'undefined' ? require('es6-promise').Promise : Promise;
 
 export let disableInit: boolean = false;
-
-setTimeout(() => {
+document.addEventListener("DOMContentLoaded", function (event) {
     if (disableInit) return;
     InitTags();
 });

+ 1 - 1
Viewer/src/templateManager.ts

@@ -143,7 +143,7 @@ export class TemplateManager {
 }
 
 
-import * as Handlebars from 'handlebars/dist/handlebars.min.js';
+import * as Handlebars from '../assets/handlebars.min.js';
 // register a new helper. modified https://stackoverflow.com/questions/9838925/is-there-any-method-to-iterate-a-map-with-handlebars-js
 Handlebars.registerHelper('eachInMap', function (map, block) {
     var out = '';

+ 1 - 1
Viewer/src/util/promiseObservable.ts

@@ -1,4 +1,4 @@
-import { Observable, Nullable, Observer } from "babylonjs";
+import { Observable } from 'babylonjs';
 
 export class PromiseObservable<T> extends Observable<T> {
 

+ 59 - 13
Viewer/src/viewer/defaultViewer.ts

@@ -1,13 +1,11 @@
+
+
 import { ViewerConfiguration } from './../configuration/configuration';
 import { Template } from './../templateManager';
 import { AbstractViewer } from './viewer';
-import { Observable, ShadowLight, CubeTexture, BouncingBehavior, FramingBehavior, Behavior, Light, Engine, Scene, AutoRotationBehavior, AbstractMesh, Quaternion, StandardMaterial, ShadowOnlyMaterial, ArcRotateCamera, ImageProcessingConfiguration, Color3, Vector3, SceneLoader, Mesh, HemisphericLight } from 'babylonjs';
+import { MirrorTexture, Plane, ShadowGenerator, Texture, BackgroundMaterial, Observable, ShadowLight, CubeTexture, BouncingBehavior, FramingBehavior, Behavior, Light, Engine, Scene, AutoRotationBehavior, AbstractMesh, Quaternion, StandardMaterial, ArcRotateCamera, ImageProcessingConfiguration, Color3, Vector3, SceneLoader, Mesh, HemisphericLight } from 'babylonjs';
 import { CameraBehavior } from '../interfaces';
 
-// A small hack for the inspector. to be removed!
-import * as BABYLON from 'babylonjs';
-window['BABYLON'] = BABYLON;
-
 export class DefaultViewer extends AbstractViewer {
 
     public camera: ArcRotateCamera;
@@ -107,7 +105,7 @@ export class DefaultViewer extends AbstractViewer {
                                     let requestFullScreen = viewerElement.requestFullscreen || viewerElement.webkitRequestFullscreen || (<any>viewerElement).msRequestFullscreen || (<any>viewerElement).mozRequestFullScreen;
                                     requestFullScreen.call(viewerElement);
                                 } else {
-                                    let exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen || (<any>document).msExitFullscreen || document.mozCancelFullScreen
+                                    let exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen || (<any>document).msExitFullscreen || (<any>document).mozCancelFullScreen
                                     exitFullscreen.call(document);
                                 }
 
@@ -158,7 +156,7 @@ export class DefaultViewer extends AbstractViewer {
         this.setupCamera(meshes);
         this.setupLights(meshes);
 
-        return this.initEnvironment();
+        return this.initEnvironment(meshes);
     }
 
     private setModelMetaData() {
@@ -190,7 +188,7 @@ export class DefaultViewer extends AbstractViewer {
 
     }
 
-    public initEnvironment(): Promise<Scene> {
+    public initEnvironment(focusMeshes: Array<AbstractMesh> = []): Promise<Scene> {
         if (this.configuration.skybox) {
             // Define a general environment textue
             let texture;
@@ -215,25 +213,73 @@ export class DefaultViewer extends AbstractViewer {
                 }
 
                 this.extendClassWithConfig(box, this.configuration.skybox);
+
+                box && focusMeshes.push(box);
             }
         }
 
         if (this.configuration.ground) {
             let groundConfig = (typeof this.configuration.ground === 'boolean') ? {} : this.configuration.ground;
 
-            var ground = Mesh.CreateGround('ground', groundConfig.size || 1000, groundConfig.size || 1000, 8, this.scene);
+            let groundSize = groundConfig.size || (this.configuration.skybox && this.configuration.skybox.scale) || 3000;
+
+            let ground = Mesh.CreatePlane("BackgroundPlane", groundSize, this.scene);
+            let backgroundMaterial = new BackgroundMaterial('groundmat', this.scene);
+            ground.rotation.x = Math.PI / 2; // Face up by default.
+            ground.receiveShadows = groundConfig.receiveShadows || false;
+
+            // default values
+            backgroundMaterial.alpha = 0.9;
+            backgroundMaterial.alphaMode = Engine.ALPHA_PREMULTIPLIED_PORTERDUFF;
+            backgroundMaterial.shadowLevel = 0.5;
+            backgroundMaterial.primaryLevel = 1;
+            backgroundMaterial.primaryColor = new Color3(0.2, 0.2, 0.3).toLinearSpace().scale(3);
+            backgroundMaterial.secondaryLevel = 0;
+            backgroundMaterial.tertiaryLevel = 0;
+            backgroundMaterial.useRGBColor = false;
+            backgroundMaterial.enableNoise = true;
+
+            // if config provided, extend the default values
+            if (groundConfig.material) {
+                this.extendClassWithConfig(ground, ground.material);
+            }
+
+            ground.material = backgroundMaterial;
             if (this.configuration.ground === true || groundConfig.shadowOnly) {
-                ground.material = new ShadowOnlyMaterial('groundmat', this.scene);
+                // shadow only:
+                ground.receiveShadows = true;
+                const diffuseTexture = new Texture("https://assets.babylonjs.com/environments/backgroundGround.png", this.scene);
+                diffuseTexture.gammaSpace = false;
+                diffuseTexture.hasAlpha = true;
+                backgroundMaterial.diffuseTexture = diffuseTexture;
+            } else if (groundConfig.mirror) {
+                var mirror = new MirrorTexture("mirror", 512, this.scene);
+                mirror.mirrorPlane = new Plane(0, -1, 0, 0);
+                mirror.renderList = mirror.renderList || [];
+                focusMeshes.length && focusMeshes.forEach(m => {
+                    m && mirror.renderList && mirror.renderList.push(m);
+                });
+
+                backgroundMaterial.reflectionTexture = mirror;
             } else {
-                ground.material = new StandardMaterial('groundmat', this.scene);
+                if (groundConfig.material) {
+                    if (groundConfig.material.diffuseTexture) {
+                        const diffuseTexture = new Texture(groundConfig.material.diffuseTexture, this.scene);
+                        backgroundMaterial.diffuseTexture = diffuseTexture;
+                    }
+                }
+                // ground.material = new StandardMaterial('groundmat', this.scene);
             }
             //default configuration
             if (this.configuration.ground === true) {
                 ground.receiveShadows = true;
-                ground.material.alpha = 0.4;
+                if (ground.material)
+                    ground.material.alpha = 0.4;
             }
 
 
+
+
             this.extendClassWithConfig(ground, groundConfig);
         }
 
@@ -354,7 +400,7 @@ export class DefaultViewer extends AbstractViewer {
                 //position. Some lights don't support shadows
                 if (light instanceof ShadowLight) {
                     if (lightConfig.shadowEnabled) {
-                        var shadowGenerator = new BABYLON.ShadowGenerator(512, light);
+                        var shadowGenerator = new ShadowGenerator(512, light);
                         this.extendClassWithConfig(shadowGenerator, lightConfig.shadowConfig || {});
                         // add the focues meshes to the shadow list
                         let shadownMap = shadowGenerator.getShadowMap();

+ 2 - 0
Viewer/src/viewer/viewerManager.ts

@@ -1,3 +1,5 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
 import { Observable } from 'babylonjs';
 import { AbstractViewer } from './viewer';
 

+ 32 - 0
Viewer/tsconfig-gulp.json

@@ -0,0 +1,32 @@
+{
+    "compilerOptions": {
+        "target": "es5",
+        "module": "commonjs",
+        "noResolve": false,
+        "noImplicitAny": false, //mainly due to usage of external libs without typings.
+        "strictNullChecks": true,
+        "removeComments": true,
+        "preserveConstEnums": true,
+        "sourceMap": false,
+        "experimentalDecorators": true,
+        "isolatedModules": false,
+        "declaration": false,
+        "lib": [
+            "dom",
+            "es2015.promise",
+            "es5"
+        ],
+        "types": [
+            "node"
+        ],
+        "baseUrl": ".",
+        "paths": {
+            "babylonjs": [
+                "../dist/preview release/babylon.max.js"
+            ],
+            "babylonjs-loaders": [
+                "../dist/preview release/loaders/babylonjs.loaders.js"
+            ]
+        }
+    }
+}

+ 1 - 2
Viewer/tsconfig.json

@@ -20,8 +20,7 @@
         "types": [
             "node",
             "babylonjs",
-            "babylonjs-loaders",
-            "babylonjs-materials"
+            "babylonjs-loaders"
         ]
     }
 }

+ 51 - 0
Viewer/webpack.gulp.config.js

@@ -0,0 +1,51 @@
+module.exports = {
+    //context: __dirname,
+    entry: [
+        __dirname + '/src/index.ts'
+    ]
+    ,
+    output: {
+        libraryTarget: 'var',
+        library: 'BabylonViewer',
+        umdNamedDefine: true
+    },
+    externals: {
+        cannon: true,
+        vertx: true
+    },
+    resolve: {
+        extensions: ['.ts', '.js'],
+        alias: {
+            "babylonjs": __dirname + '/../dist/preview release/babylon.max.js',
+            "babylonjs-materials": __dirname + '/../dist/preview release/materialsLibrary/babylonjs.materials.js',
+            "babylonjs-loaders": __dirname + '/../dist/preview release/loaders/babylonjs.loaders.js',
+            "es6-promise": __dirname + '/assets/es6-promise.min.js',
+            "deepmerge": __dirname + '/assets/deepmerge.min.js',
+        }
+    },
+    module: {
+        loaders: [{
+            test: /\.tsx?$/,
+            use: {
+                loader: 'ts-loader',
+                options: {
+                    configFile: 'tsconfig-gulp.json'
+                }
+            },
+            exclude: /node_modules/
+        },
+        {
+            test: /\.(html)$/,
+            use: {
+                loader: 'html-loader',
+                options: {
+                    minimize: true
+                }
+            }
+        },
+        {
+            test: /\.(jpe?g|png|ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
+            use: 'base64-image-loader?limit=1000&name=[name].[ext]'
+        }]
+    }
+}

File diff suppressed because it is too large
+ 0 - 18033
dist/babylon.module.d.ts


+ 7 - 10
dist/inspector/babylon.inspector.css

@@ -1,22 +1,19 @@
 @import url(https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css);
 @import url(https://fonts.googleapis.com/css?family=Inconsolata);
-
-@import url(https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css);
-@import url(https://fonts.googleapis.com/css?family=Inconsolata);
 .insp-wrapper {
   user-select: none;
   display: flex;
   font-size: 0.9em;
   font-family: "Inconsolata", sans-serif;
   background-color: #242424;
-  /**
- * A tool contained in the tree panel (available for each item of the tree)
+  /**
+ * A tool contained in the tree panel (available for each item of the tree)
  */
-  /**
- * The toolbar contains : 
- * - a refresh tool - refresh the whole panel
- * - a popup tool - Open the inspector in a new panel
- * ...
+  /**
+ * The toolbar contains : 
+ * - a refresh tool - refresh the whole panel
+ * - a popup tool - Open the inspector in a new panel
+ * ...
  */ }
   .insp-wrapper .gutter {
     background-color: #2c2c2c; }

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


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


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


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


+ 382 - 270
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts

@@ -3763,6 +3763,131 @@ declare module BABYLON {
     }
 }
 
+declare module BABYLON {
+    class BoundingBox implements ICullable {
+        minimum: Vector3;
+        maximum: Vector3;
+        vectors: Vector3[];
+        center: Vector3;
+        centerWorld: Vector3;
+        extendSize: Vector3;
+        extendSizeWorld: Vector3;
+        directions: Vector3[];
+        vectorsWorld: Vector3[];
+        minimumWorld: Vector3;
+        maximumWorld: Vector3;
+        private _worldMatrix;
+        constructor(minimum: Vector3, maximum: Vector3);
+        getWorldMatrix(): Matrix;
+        setWorldMatrix(matrix: Matrix): BoundingBox;
+        _update(world: Matrix): void;
+        isInFrustum(frustumPlanes: Plane[]): boolean;
+        isCompletelyInFrustum(frustumPlanes: Plane[]): boolean;
+        intersectsPoint(point: Vector3): boolean;
+        intersectsSphere(sphere: BoundingSphere): boolean;
+        intersectsMinMax(min: Vector3, max: Vector3): boolean;
+        static Intersects(box0: BoundingBox, box1: BoundingBox): boolean;
+        static IntersectsSphere(minPoint: Vector3, maxPoint: Vector3, sphereCenter: Vector3, sphereRadius: number): boolean;
+        static IsCompletelyInFrustum(boundingVectors: Vector3[], frustumPlanes: Plane[]): boolean;
+        static IsInFrustum(boundingVectors: Vector3[], frustumPlanes: Plane[]): boolean;
+    }
+}
+
+declare module BABYLON {
+    interface ICullable {
+        isInFrustum(frustumPlanes: Plane[]): boolean;
+        isCompletelyInFrustum(frustumPlanes: Plane[]): boolean;
+    }
+    class BoundingInfo implements ICullable {
+        minimum: Vector3;
+        maximum: Vector3;
+        boundingBox: BoundingBox;
+        boundingSphere: BoundingSphere;
+        private _isLocked;
+        constructor(minimum: Vector3, maximum: Vector3);
+        isLocked: boolean;
+        update(world: Matrix): void;
+        /**
+         * Recreate the bounding info to be centered around a specific point given a specific extend.
+         * @param center New center of the bounding info
+         * @param extend New extend of the bounding info
+         */
+        centerOn(center: Vector3, extend: Vector3): BoundingInfo;
+        isInFrustum(frustumPlanes: Plane[]): boolean;
+        /**
+         * Gets the world distance between the min and max points of the bounding box
+         */
+        readonly diagonalLength: number;
+        isCompletelyInFrustum(frustumPlanes: Plane[]): boolean;
+        _checkCollision(collider: Collider): boolean;
+        intersectsPoint(point: Vector3): boolean;
+        intersects(boundingInfo: BoundingInfo, precise: boolean): boolean;
+    }
+}
+
+declare module BABYLON {
+    class BoundingSphere {
+        minimum: Vector3;
+        maximum: Vector3;
+        center: Vector3;
+        radius: number;
+        centerWorld: Vector3;
+        radiusWorld: number;
+        private _tempRadiusVector;
+        constructor(minimum: Vector3, maximum: Vector3);
+        _update(world: Matrix): void;
+        isInFrustum(frustumPlanes: Plane[]): boolean;
+        intersectsPoint(point: Vector3): boolean;
+        static Intersects(sphere0: BoundingSphere, sphere1: BoundingSphere): boolean;
+    }
+}
+
+declare module BABYLON {
+    class Ray {
+        origin: Vector3;
+        direction: Vector3;
+        length: number;
+        private _edge1;
+        private _edge2;
+        private _pvec;
+        private _tvec;
+        private _qvec;
+        private _tmpRay;
+        constructor(origin: Vector3, direction: Vector3, length?: number);
+        intersectsBoxMinMax(minimum: Vector3, maximum: Vector3): boolean;
+        intersectsBox(box: BoundingBox): boolean;
+        intersectsSphere(sphere: BoundingSphere): boolean;
+        intersectsTriangle(vertex0: Vector3, vertex1: Vector3, vertex2: Vector3): Nullable<IntersectionInfo>;
+        intersectsPlane(plane: Plane): Nullable<number>;
+        intersectsMesh(mesh: AbstractMesh, fastCheck?: boolean): PickingInfo;
+        intersectsMeshes(meshes: Array<AbstractMesh>, fastCheck?: boolean, results?: Array<PickingInfo>): Array<PickingInfo>;
+        private _comparePickingInfo(pickingInfoA, pickingInfoB);
+        private static smallnum;
+        private static rayl;
+        /**
+         * Intersection test between the ray and a given segment whithin a given tolerance (threshold)
+         * @param sega the first point of the segment to test the intersection against
+         * @param segb the second point of the segment to test the intersection against
+         * @param threshold the tolerance margin, if the ray doesn't intersect the segment but is close to the given threshold, the intersection is successful
+         * @return the distance from the ray origin to the intersection point if there's intersection, or -1 if there's no intersection
+         */
+        intersectionSegment(sega: Vector3, segb: Vector3, threshold: number): number;
+        update(x: number, y: number, viewportWidth: number, viewportHeight: number, world: Matrix, view: Matrix, projection: Matrix): Ray;
+        static Zero(): Ray;
+        static CreateNew(x: number, y: number, viewportWidth: number, viewportHeight: number, world: Matrix, view: Matrix, projection: Matrix): Ray;
+        /**
+        * Function will create a new transformed ray starting from origin and ending at the end point. Ray's length will be set, and ray will be
+        * transformed to the given world matrix.
+        * @param origin The origin point
+        * @param end The end point
+        * @param world a matrix to transform the ray to. Default is the identity matrix.
+        */
+        static CreateNewFromTo(origin: Vector3, end: Vector3, world?: Matrix): Ray;
+        static Transform(ray: Ray, matrix: Matrix): Ray;
+        static TransformToRef(ray: Ray, matrix: Matrix, result: Ray): void;
+    }
+}
+
 declare module BABYLON.Debug {
     class AxesViewer {
         private _xline;
@@ -3893,131 +4018,6 @@ declare module BABYLON.Debug {
 }
 
 declare module BABYLON {
-    class BoundingBox implements ICullable {
-        minimum: Vector3;
-        maximum: Vector3;
-        vectors: Vector3[];
-        center: Vector3;
-        centerWorld: Vector3;
-        extendSize: Vector3;
-        extendSizeWorld: Vector3;
-        directions: Vector3[];
-        vectorsWorld: Vector3[];
-        minimumWorld: Vector3;
-        maximumWorld: Vector3;
-        private _worldMatrix;
-        constructor(minimum: Vector3, maximum: Vector3);
-        getWorldMatrix(): Matrix;
-        setWorldMatrix(matrix: Matrix): BoundingBox;
-        _update(world: Matrix): void;
-        isInFrustum(frustumPlanes: Plane[]): boolean;
-        isCompletelyInFrustum(frustumPlanes: Plane[]): boolean;
-        intersectsPoint(point: Vector3): boolean;
-        intersectsSphere(sphere: BoundingSphere): boolean;
-        intersectsMinMax(min: Vector3, max: Vector3): boolean;
-        static Intersects(box0: BoundingBox, box1: BoundingBox): boolean;
-        static IntersectsSphere(minPoint: Vector3, maxPoint: Vector3, sphereCenter: Vector3, sphereRadius: number): boolean;
-        static IsCompletelyInFrustum(boundingVectors: Vector3[], frustumPlanes: Plane[]): boolean;
-        static IsInFrustum(boundingVectors: Vector3[], frustumPlanes: Plane[]): boolean;
-    }
-}
-
-declare module BABYLON {
-    interface ICullable {
-        isInFrustum(frustumPlanes: Plane[]): boolean;
-        isCompletelyInFrustum(frustumPlanes: Plane[]): boolean;
-    }
-    class BoundingInfo implements ICullable {
-        minimum: Vector3;
-        maximum: Vector3;
-        boundingBox: BoundingBox;
-        boundingSphere: BoundingSphere;
-        private _isLocked;
-        constructor(minimum: Vector3, maximum: Vector3);
-        isLocked: boolean;
-        update(world: Matrix): void;
-        /**
-         * Recreate the bounding info to be centered around a specific point given a specific extend.
-         * @param center New center of the bounding info
-         * @param extend New extend of the bounding info
-         */
-        centerOn(center: Vector3, extend: Vector3): BoundingInfo;
-        isInFrustum(frustumPlanes: Plane[]): boolean;
-        /**
-         * Gets the world distance between the min and max points of the bounding box
-         */
-        readonly diagonalLength: number;
-        isCompletelyInFrustum(frustumPlanes: Plane[]): boolean;
-        _checkCollision(collider: Collider): boolean;
-        intersectsPoint(point: Vector3): boolean;
-        intersects(boundingInfo: BoundingInfo, precise: boolean): boolean;
-    }
-}
-
-declare module BABYLON {
-    class BoundingSphere {
-        minimum: Vector3;
-        maximum: Vector3;
-        center: Vector3;
-        radius: number;
-        centerWorld: Vector3;
-        radiusWorld: number;
-        private _tempRadiusVector;
-        constructor(minimum: Vector3, maximum: Vector3);
-        _update(world: Matrix): void;
-        isInFrustum(frustumPlanes: Plane[]): boolean;
-        intersectsPoint(point: Vector3): boolean;
-        static Intersects(sphere0: BoundingSphere, sphere1: BoundingSphere): boolean;
-    }
-}
-
-declare module BABYLON {
-    class Ray {
-        origin: Vector3;
-        direction: Vector3;
-        length: number;
-        private _edge1;
-        private _edge2;
-        private _pvec;
-        private _tvec;
-        private _qvec;
-        private _tmpRay;
-        constructor(origin: Vector3, direction: Vector3, length?: number);
-        intersectsBoxMinMax(minimum: Vector3, maximum: Vector3): boolean;
-        intersectsBox(box: BoundingBox): boolean;
-        intersectsSphere(sphere: BoundingSphere): boolean;
-        intersectsTriangle(vertex0: Vector3, vertex1: Vector3, vertex2: Vector3): Nullable<IntersectionInfo>;
-        intersectsPlane(plane: Plane): Nullable<number>;
-        intersectsMesh(mesh: AbstractMesh, fastCheck?: boolean): PickingInfo;
-        intersectsMeshes(meshes: Array<AbstractMesh>, fastCheck?: boolean, results?: Array<PickingInfo>): Array<PickingInfo>;
-        private _comparePickingInfo(pickingInfoA, pickingInfoB);
-        private static smallnum;
-        private static rayl;
-        /**
-         * Intersection test between the ray and a given segment whithin a given tolerance (threshold)
-         * @param sega the first point of the segment to test the intersection against
-         * @param segb the second point of the segment to test the intersection against
-         * @param threshold the tolerance margin, if the ray doesn't intersect the segment but is close to the given threshold, the intersection is successful
-         * @return the distance from the ray origin to the intersection point if there's intersection, or -1 if there's no intersection
-         */
-        intersectionSegment(sega: Vector3, segb: Vector3, threshold: number): number;
-        update(x: number, y: number, viewportWidth: number, viewportHeight: number, world: Matrix, view: Matrix, projection: Matrix): Ray;
-        static Zero(): Ray;
-        static CreateNew(x: number, y: number, viewportWidth: number, viewportHeight: number, world: Matrix, view: Matrix, projection: Matrix): Ray;
-        /**
-        * Function will create a new transformed ray starting from origin and ending at the end point. Ray's length will be set, and ray will be
-        * transformed to the given world matrix.
-        * @param origin The origin point
-        * @param end The end point
-        * @param world a matrix to transform the ray to. Default is the identity matrix.
-        */
-        static CreateNewFromTo(origin: Vector3, end: Vector3, world?: Matrix): Ray;
-        static Transform(ray: Ray, matrix: Matrix): Ray;
-        static TransformToRef(ray: Ray, matrix: Matrix, result: Ray): void;
-    }
-}
-
-declare module BABYLON {
     class InstancingAttributeInfo {
         /**
          * Index/offset of the attribute in the vertex shader
@@ -4320,11 +4320,10 @@ declare module BABYLON {
         protected _alphaState: Internals._AlphaState;
         protected _alphaMode: number;
         private _internalTexturesCache;
-        protected _activeChannel: number;
+        protected _activeTextureChannel: number;
         protected _boundTexturesCache: {
             [key: string]: Nullable<InternalTexture>;
         };
-        protected _boundTexturesOrder: InternalTexture[];
         protected _currentEffect: Nullable<Effect>;
         protected _currentProgram: Nullable<WebGLProgram>;
         private _compiledEffects;
@@ -4354,7 +4353,6 @@ declare module BABYLON {
         private _emptyCubeTexture;
         private _emptyTexture3D;
         private _frameHandler;
-        private _nextFreeTextureSlot;
         private _texturesSupported;
         private _textureFormatInUse;
         readonly texturesSupported: Array<string>;
@@ -4626,8 +4624,8 @@ declare module BABYLON {
         createTexture(urlArg: Nullable<string>, noMipmap: boolean, invertY: boolean, scene: Nullable<Scene>, samplingMode?: number, onLoad?: Nullable<() => void>, onError?: Nullable<(message: string, exception: any) => void>, buffer?: Nullable<ArrayBuffer | HTMLImageElement>, fallBack?: Nullable<InternalTexture>, format?: Nullable<number>): InternalTexture;
         private _rescaleTexture(source, destination, scene, internalFormat, onComplete);
         private _getInternalFormat(format);
-        updateRawTexture(texture: Nullable<InternalTexture>, data: Nullable<ArrayBufferView>, format: number, invertY: boolean, compression?: Nullable<string>): void;
-        createRawTexture(data: Nullable<ArrayBufferView>, width: number, height: number, format: number, generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression?: Nullable<string>): InternalTexture;
+        updateRawTexture(texture: Nullable<InternalTexture>, data: Nullable<ArrayBufferView>, format: number, invertY: boolean, compression?: Nullable<string>, type?: number): void;
+        createRawTexture(data: Nullable<ArrayBufferView>, width: number, height: number, format: number, generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression?: Nullable<string>, type?: number): InternalTexture;
         createDynamicTexture(width: number, height: number, generateMipMaps: boolean, samplingMode: number): InternalTexture;
         updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void;
         updateDynamicTexture(texture: Nullable<InternalTexture>, canvas: HTMLCanvasElement, invertY: boolean, premulAlpha?: boolean, format?: number): void;
@@ -4656,17 +4654,13 @@ declare module BABYLON {
         _releaseFramebufferObjects(texture: InternalTexture): void;
         _releaseTexture(texture: InternalTexture): void;
         private setProgram(program);
-        private _boundUniforms;
         bindSamplers(effect: Effect): void;
-        private _activateTextureChannel(channel);
-        private _removeDesignatedSlot(internalTexture);
+        private activateTextureChannel(textureChannel);
         _bindTextureDirectly(target: number, texture: Nullable<InternalTexture>): void;
         _bindTexture(channel: number, texture: Nullable<InternalTexture>): void;
         setTextureFromPostProcess(channel: number, postProcess: Nullable<PostProcess>): void;
         unbindAllTextures(): void;
         setTexture(channel: number, uniform: Nullable<WebGLUniformLocation>, texture: Nullable<BaseTexture>): void;
-        private _getCorrectTextureChannel(channel, internalTexture);
-        private _bindSamplerUniformToChannel(sourceSlot, destination);
         private _setTexture(channel, texture);
         setTextureArray(channel: number, uniform: Nullable<WebGLUniformLocation>, textures: BaseTexture[]): void;
         _setAnisotropicLevel(key: number, texture: BaseTexture): void;
@@ -4871,6 +4865,69 @@ declare var WebGLVertexArrayObject: {
 };
 
 declare module BABYLON {
+    class KeyboardEventTypes {
+        static _KEYDOWN: number;
+        static _KEYUP: number;
+        static readonly KEYDOWN: number;
+        static readonly KEYUP: number;
+    }
+    class KeyboardInfo {
+        type: number;
+        event: KeyboardEvent;
+        constructor(type: number, event: KeyboardEvent);
+    }
+    /**
+     * This class is used to store keyboard related info for the onPreKeyboardObservable event.
+     * Set the skipOnKeyboardObservable property to true if you want the engine to stop any process after this event is triggered, even not calling onKeyboardObservable
+     */
+    class KeyboardInfoPre extends KeyboardInfo {
+        constructor(type: number, event: KeyboardEvent);
+        skipOnPointerObservable: boolean;
+    }
+}
+
+declare module BABYLON {
+    class PointerEventTypes {
+        static _POINTERDOWN: number;
+        static _POINTERUP: number;
+        static _POINTERMOVE: number;
+        static _POINTERWHEEL: number;
+        static _POINTERPICK: number;
+        static _POINTERTAP: number;
+        static _POINTERDOUBLETAP: number;
+        static readonly POINTERDOWN: number;
+        static readonly POINTERUP: number;
+        static readonly POINTERMOVE: number;
+        static readonly POINTERWHEEL: number;
+        static readonly POINTERPICK: number;
+        static readonly POINTERTAP: number;
+        static readonly POINTERDOUBLETAP: number;
+    }
+    class PointerInfoBase {
+        type: number;
+        event: PointerEvent | MouseWheelEvent;
+        constructor(type: number, event: PointerEvent | MouseWheelEvent);
+    }
+    /**
+     * This class is used to store pointer related info for the onPrePointerObservable event.
+     * Set the skipOnPointerObservable property to true if you want the engine to stop any process after this event is triggered, even not calling onPointerObservable
+     */
+    class PointerInfoPre extends PointerInfoBase {
+        constructor(type: number, event: PointerEvent | MouseWheelEvent, localX: number, localY: number);
+        localPosition: Vector2;
+        skipOnPointerObservable: boolean;
+    }
+    /**
+     * This type contains all the data related to a pointer event in Babylon.js.
+     * The event member is an instance of PointerEvent for all types except PointerWheel and is of type MouseWheelEvent when type equals PointerWheel. The different event types can be found in the PointerEventTypes class.
+     */
+    class PointerInfo extends PointerInfoBase {
+        pickInfo: Nullable<PickingInfo>;
+        constructor(type: number, event: PointerEvent | MouseWheelEvent, pickInfo: Nullable<PickingInfo>);
+    }
+}
+
+declare module BABYLON {
     class StickValues {
         x: number;
         y: number;
@@ -4925,23 +4982,24 @@ declare module BABYLON {
 
 declare module BABYLON {
     class GamepadManager {
+        private _scene;
         private _babylonGamepads;
         private _oneGamepadConnected;
-        private _isMonitoring;
+        _isMonitoring: boolean;
         private _gamepadEventSupported;
         private _gamepadSupport;
         onGamepadConnectedObservable: Observable<Gamepad>;
         onGamepadDisconnectedObservable: Observable<Gamepad>;
         private _onGamepadConnectedEvent;
         private _onGamepadDisconnectedEvent;
-        constructor();
+        constructor(_scene?: Scene | undefined);
         readonly gamepads: Gamepad[];
         getGamepadByType(type?: number): Nullable<Gamepad>;
         dispose(): void;
         private _addNewGamepad(gamepad);
         private _startMonitoringGamepads();
         private _stopMonitoringGamepads();
-        private _checkGamepadsStatus();
+        _checkGamepadsStatus(): void;
         private _updateGamepadObjects();
     }
 }
@@ -5313,69 +5371,6 @@ declare namespace BABYLON {
 }
 
 declare module BABYLON {
-    class KeyboardEventTypes {
-        static _KEYDOWN: number;
-        static _KEYUP: number;
-        static readonly KEYDOWN: number;
-        static readonly KEYUP: number;
-    }
-    class KeyboardInfo {
-        type: number;
-        event: KeyboardEvent;
-        constructor(type: number, event: KeyboardEvent);
-    }
-    /**
-     * This class is used to store keyboard related info for the onPreKeyboardObservable event.
-     * Set the skipOnKeyboardObservable property to true if you want the engine to stop any process after this event is triggered, even not calling onKeyboardObservable
-     */
-    class KeyboardInfoPre extends KeyboardInfo {
-        constructor(type: number, event: KeyboardEvent);
-        skipOnPointerObservable: boolean;
-    }
-}
-
-declare module BABYLON {
-    class PointerEventTypes {
-        static _POINTERDOWN: number;
-        static _POINTERUP: number;
-        static _POINTERMOVE: number;
-        static _POINTERWHEEL: number;
-        static _POINTERPICK: number;
-        static _POINTERTAP: number;
-        static _POINTERDOUBLETAP: number;
-        static readonly POINTERDOWN: number;
-        static readonly POINTERUP: number;
-        static readonly POINTERMOVE: number;
-        static readonly POINTERWHEEL: number;
-        static readonly POINTERPICK: number;
-        static readonly POINTERTAP: number;
-        static readonly POINTERDOUBLETAP: number;
-    }
-    class PointerInfoBase {
-        type: number;
-        event: PointerEvent | MouseWheelEvent;
-        constructor(type: number, event: PointerEvent | MouseWheelEvent);
-    }
-    /**
-     * This class is used to store pointer related info for the onPrePointerObservable event.
-     * Set the skipOnPointerObservable property to true if you want the engine to stop any process after this event is triggered, even not calling onPointerObservable
-     */
-    class PointerInfoPre extends PointerInfoBase {
-        constructor(type: number, event: PointerEvent | MouseWheelEvent, localX: number, localY: number);
-        localPosition: Vector2;
-        skipOnPointerObservable: boolean;
-    }
-    /**
-     * This type contains all the data related to a pointer event in Babylon.js.
-     * The event member is an instance of PointerEvent for all types except PointerWheel and is of type MouseWheelEvent when type equals PointerWheel. The different event types can be found in the PointerEventTypes class.
-     */
-    class PointerInfo extends PointerInfoBase {
-        pickInfo: Nullable<PickingInfo>;
-        constructor(type: number, event: PointerEvent | MouseWheelEvent, pickInfo: Nullable<PickingInfo>);
-    }
-}
-
-declare module BABYLON {
     /**
      * This class can be used to get instrumentation data from a Babylon engine
      */
@@ -8726,9 +8721,21 @@ declare module BABYLON {
         /**
          * Normalize the current Vector3.
          * Returns the updated Vector3.
+         * /!\ In place operation.
          */
         normalize(): Vector3;
         /**
+         * Normalize the current Vector3 to a new vector.
+         * @returns the new Vector3.
+         */
+        normalizeToNew(): Vector3;
+        /**
+         * Normalize the current Vector3 to the reference.
+         * @param the reference to update.
+         * @returns the updated Vector3.
+         */
+        normalizeToRef(reference: Vector3): Vector3;
+        /**
          * Returns a new Vector3 copied from the current Vector3.
          */
         clone(): Vector3;
@@ -11519,6 +11526,8 @@ declare module BABYLON {
          * Returns the Mesh.
          */
         refreshBoundingInfo(): Mesh;
+        _refreshBoundingInfo(applySkeleton: boolean): Mesh;
+        private _getPositionData(applySkeleton);
         _createGlobalSubMesh(force: boolean): Nullable<SubMesh>;
         subdivide(count: number): void;
         /**
@@ -13489,6 +13498,15 @@ declare module BABYLON {
          */
         locallyTranslate(vector3: Vector3): TransformNode;
         private static _lookAtVectorCache;
+        /**
+         * Orients a mesh towards a target point. Mesh must be drawn facing user.
+         * @param targetPoint the position (must be in same space as current mesh) to look at
+         * @param yawCor optional yaw (y-axis) correction in radians
+         * @param pitchCor optional pitch (x-axis) correction in radians
+         * @param rollCor optional roll (z-axis) correction in radians
+         * @param space the choosen space of the target
+         * @returns the TransformNode.
+         */
         lookAt(targetPoint: Vector3, yawCor?: number, pitchCor?: number, rollCor?: number, space?: Space): TransformNode;
         /**
           * Returns a new Vector3 what is the localAxis, expressed in the mesh local space, rotated like the mesh.
@@ -14439,10 +14457,17 @@ declare module BABYLON {
     /**
      * The strenght of the force in correspondence to the distance of the affected object
      */
-    enum PhysicsRadialImpulseFallof {
+    enum PhysicsRadialImpulseFalloff {
         Constant = 0,
         Linear = 1,
     }
+    /**
+     * The strenght of the force in correspondence to the distance of the affected object
+     */
+    enum PhysicsUpdraftMode {
+        Center = 0,
+        Perpendicular = 1,
+    }
     class PhysicsHelper {
         private _scene;
         private _physicsEngine;
@@ -14451,33 +14476,41 @@ declare module BABYLON {
          * @param {Vector3} origin the origin of the explosion
          * @param {number} radius the explosion radius
          * @param {number} strength the explosion strength
-         * @param {PhysicsRadialImpulseFallof} falloff possible options: Constant & Linear. Defaults to Constant
+         * @param {PhysicsRadialImpulseFalloff} falloff possible options: Constant & Linear. Defaults to Constant
          */
-        applyRadialExplosionImpulse(origin: Vector3, radius: number, strength: number, falloff?: PhysicsRadialImpulseFallof): Nullable<PhysicsRadialExplosionEvent>;
+        applyRadialExplosionImpulse(origin: Vector3, radius: number, strength: number, falloff?: PhysicsRadialImpulseFalloff): Nullable<PhysicsRadialExplosionEvent>;
         /**
          * @param {Vector3} origin the origin of the explosion
          * @param {number} radius the explosion radius
          * @param {number} strength the explosion strength
-         * @param {PhysicsRadialImpulseFallof} falloff possible options: Constant & Linear. Defaults to Constant
+         * @param {PhysicsRadialImpulseFalloff} falloff possible options: Constant & Linear. Defaults to Constant
          */
-        applyRadialExplosionForce(origin: Vector3, radius: number, strength: number, falloff?: PhysicsRadialImpulseFallof): Nullable<PhysicsRadialExplosionEvent>;
+        applyRadialExplosionForce(origin: Vector3, radius: number, strength: number, falloff?: PhysicsRadialImpulseFalloff): Nullable<PhysicsRadialExplosionEvent>;
         /**
          * @param {Vector3} origin the origin of the explosion
          * @param {number} radius the explosion radius
          * @param {number} strength the explosion strength
-         * @param {PhysicsRadialImpulseFallof} falloff possible options: Constant & Linear. Defaults to Constant
+         * @param {PhysicsRadialImpulseFalloff} falloff possible options: Constant & Linear. Defaults to Constant
+         */
+        gravitationalField(origin: Vector3, radius: number, strength: number, falloff?: PhysicsRadialImpulseFalloff): Nullable<PhysicsGravitationalFieldEvent>;
+        /**
+         * @param {Vector3} origin the origin of the updraft
+         * @param {number} radius the radius of the updraft
+         * @param {number} strength the strength of the updraft
+         * @param {number} height the height of the updraft
          */
-        gravitationalField(origin: Vector3, radius: number, strength: number, falloff?: PhysicsRadialImpulseFallof): Nullable<PhysicsGravitationalFieldEvent>;
+        updraft(origin: Vector3, radius: number, strength: number, height: number, updraftMode: PhysicsUpdraftMode): Nullable<PhysicsUpdraftEvent>;
     }
     /***** Radial explosion *****/
     class PhysicsRadialExplosionEvent {
         private _scene;
-        private _radialSphere;
+        private _sphere;
+        private _sphereOptions;
         private _rays;
         private _dataFetched;
         constructor(scene: Scene);
         /**
-         * Returns the data related to the radial explosion event (radialSphere & rays).
+         * Returns the data related to the radial explosion event (sphere & rays).
          * @returns {PhysicsRadialExplosionEventData}
          */
         getData(): PhysicsRadialExplosionEventData;
@@ -14487,26 +14520,18 @@ declare module BABYLON {
          * @param {Vector3} origin the origin of the explosion
          * @param {number} radius the explosion radius
          * @param {number} strength the explosion strength
-         * @param {PhysicsRadialImpulseFallof} falloff possible options: Constant & Linear
+         * @param {PhysicsRadialImpulseFalloff} falloff possible options: Constant & Linear
          * @returns {Nullable<PhysicsForceAndContactPoint>}
          */
-        getImpostorForceAndContactPoint(impostor: PhysicsImpostor, origin: Vector3, radius: number, strength: number, falloff: PhysicsRadialImpulseFallof): Nullable<PhysicsForceAndContactPoint>;
+        getImpostorForceAndContactPoint(impostor: PhysicsImpostor, origin: Vector3, radius: number, strength: number, falloff: PhysicsRadialImpulseFalloff): Nullable<PhysicsForceAndContactPoint>;
         /**
-         * Disposes the radialSphere.
+         * Disposes the sphere.
          * @param {bolean} force
          */
         dispose(force?: boolean): void;
         /*** Helpers ***/
-        private _prepareRadialSphere();
-        private _intersectsWithRadialSphere(impostor, origin, radius);
-    }
-    interface PhysicsRadialExplosionEventData {
-        radialSphere: Mesh;
-        rays: Array<Ray>;
-    }
-    interface PhysicsForceAndContactPoint {
-        force: Vector3;
-        contactPoint: Vector3;
+        private _prepareSphere();
+        private _intersectsWithSphere(impostor, origin, radius);
     }
     /***** Gravitational Field *****/
     class PhysicsGravitationalFieldEvent {
@@ -14517,11 +14542,11 @@ declare module BABYLON {
         private _strength;
         private _falloff;
         private _tickCallback;
-        private _radialSphere;
+        private _sphere;
         private _dataFetched;
-        constructor(physicsHelper: PhysicsHelper, scene: Scene, origin: Vector3, radius: number, strength: number, falloff?: PhysicsRadialImpulseFallof);
+        constructor(physicsHelper: PhysicsHelper, scene: Scene, origin: Vector3, radius: number, strength: number, falloff?: PhysicsRadialImpulseFalloff);
         /**
-         * Returns the data related to the gravitational field event (radialSphere).
+         * Returns the data related to the gravitational field event (sphere).
          * @returns {PhysicsGravitationalFieldEventData}
          */
         getData(): PhysicsGravitationalFieldEventData;
@@ -14534,14 +14559,66 @@ declare module BABYLON {
          */
         disable(): void;
         /**
-         * Disposes the radialSphere.
+         * Disposes the sphere.
          * @param {bolean} force
          */
         dispose(force?: boolean): void;
         private _tick();
     }
     interface PhysicsGravitationalFieldEventData {
-        radialSphere: Mesh;
+        sphere: Mesh;
+    }
+    /***** Updraft *****/
+    class PhysicsUpdraftEvent {
+        private _physicsEngine;
+        private _scene;
+        private _origin;
+        private _originTop;
+        private _originDirection;
+        private _radius;
+        private _strength;
+        private _height;
+        private _updraftMode;
+        private _tickCallback;
+        private _cylinder;
+        private _cylinderPosition;
+        private _dataFetched;
+        constructor(physicsEngine: PhysicsEngine, scene: Scene, origin: Vector3, radius: number, strength: number, height: number, updraftMode: PhysicsUpdraftMode);
+        /**
+         * Returns the data related to the updraft event (cylinder).
+         * @returns {PhysicsGravitationalFieldEventData}
+         */
+        getData(): PhysicsUpdraftEventData;
+        /**
+         * Enables the updraft.
+         */
+        enable(): void;
+        /**
+         * Disables the cortex.
+         */
+        disable(): void;
+        /**
+         * Disposes the sphere.
+         * @param {bolean} force
+         */
+        dispose(force?: boolean): void;
+        private getImpostorForceAndContactPoint(impostor);
+        private _tick();
+        /*** Helpers ***/
+        private _prepareCylinder();
+        private _intersectsWithCylinder(impostor);
+    }
+    /***** Data interfaces *****/
+    interface PhysicsRadialExplosionEventData {
+        sphere: Mesh;
+        rays: Array<Ray>;
+    }
+    interface PhysicsForceAndContactPoint {
+        force: Vector3;
+        contactPoint: Vector3;
+    }
+    interface PhysicsUpdraftEventData {
+        cylinder: Mesh;
     }
 }
 
@@ -14863,36 +14940,6 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
-    class ReflectionProbe {
-        name: string;
-        private _scene;
-        private _renderTargetTexture;
-        private _projectionMatrix;
-        private _viewMatrix;
-        private _target;
-        private _add;
-        private _attachedMesh;
-        invertYAxis: boolean;
-        position: Vector3;
-        constructor(name: string, size: number, scene: Scene, generateMipMaps?: boolean);
-        samples: number;
-        refreshRate: number;
-        getScene(): Scene;
-        readonly cubeTexture: RenderTargetTexture;
-        readonly renderList: Nullable<AbstractMesh[]>;
-        attachToMesh(mesh: AbstractMesh): void;
-        /**
-         * Specifies whether or not the stencil and depth buffer are cleared between two rendering groups.
-         *
-         * @param renderingGroupId The rendering group id corresponding to its index
-         * @param autoClearDepthStencil Automatically clears depth and stencil between groups if true.
-         */
-        setRenderingAutoClearDepthStencil(renderingGroupId: number, autoClearDepthStencil: boolean): void;
-        dispose(): void;
-    }
-}
-
-declare module BABYLON {
     class AnaglyphPostProcess extends PostProcess {
         private _passedProcess;
         constructor(name: string, options: number | PostProcessOptions, rigCameras: Camera[], samplingMode?: number, engine?: Engine, reusable?: boolean);
@@ -15420,6 +15467,36 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
+    class ReflectionProbe {
+        name: string;
+        private _scene;
+        private _renderTargetTexture;
+        private _projectionMatrix;
+        private _viewMatrix;
+        private _target;
+        private _add;
+        private _attachedMesh;
+        invertYAxis: boolean;
+        position: Vector3;
+        constructor(name: string, size: number, scene: Scene, generateMipMaps?: boolean);
+        samples: number;
+        refreshRate: number;
+        getScene(): Scene;
+        readonly cubeTexture: RenderTargetTexture;
+        readonly renderList: Nullable<AbstractMesh[]>;
+        attachToMesh(mesh: AbstractMesh): void;
+        /**
+         * Specifies whether or not the stencil and depth buffer are cleared between two rendering groups.
+         *
+         * @param renderingGroupId The rendering group id corresponding to its index
+         * @param autoClearDepthStencil Automatically clears depth and stencil between groups if true.
+         */
+        setRenderingAutoClearDepthStencil(renderingGroupId: number, autoClearDepthStencil: boolean): void;
+        dispose(): void;
+    }
+}
+
+declare module BABYLON {
     class BoundingBoxRenderer {
         frontColor: Color3;
         backColor: Color3;
@@ -17569,9 +17646,10 @@ declare module BABYLON {
         private _onVRDisplayChanged;
         private _onVRRequestPresentStart;
         private _onVRRequestPresentComplete;
-        onEnteringVR: () => void;
-        onExitingVR: () => void;
-        onControllerMeshLoaded: (controller: WebVRController) => void;
+        onEnteringVR: Observable<{}>;
+        onExitingVR: Observable<{}>;
+        onControllerMeshLoaded: Observable<WebVRController>;
+        private _rayLength;
         private _useCustomVRButton;
         private _teleportationRequested;
         private _teleportationEnabledOnLeftController;
@@ -17591,9 +17669,27 @@ declare module BABYLON {
         private _teleportationBorderColor;
         private _rotationAngle;
         private _haloCenter;
-        private _rayHelper;
         private _gazeTracker;
+        private _padSensibilityUp;
+        private _padSensibilityDown;
+        private _leftLaserPointer;
+        private _rightLaserPointer;
+        private _currentMeshSelected;
+        onNewMeshSelected: Observable<AbstractMesh>;
+        private _circleEase;
+        private _raySelectionPredicate;
+        /**
+         * To be optionaly changed by user to define custom ray selection
+         */
+        raySelectionPredicate: (mesh: AbstractMesh) => boolean;
+        /**
+         * To be optionaly changed by user to define custom selection logic (after ray selection)
+         */
         meshSelectionPredicate: (mesh: AbstractMesh) => boolean;
+        private _currentHit;
+        private _pointerDownOnMeshAsked;
+        private _isActionableMesh;
+        private _defaultHeight;
         readonly deviceOrientationCamera: DeviceOrientationCamera;
         readonly currentVRCamera: FreeCamera;
         readonly webVRCamera: WebVRFreeCamera;
@@ -17623,9 +17719,12 @@ declare module BABYLON {
         private _displayTeleportationCircle();
         private _hideTeleportationCircle();
         private _rotateCamera(right);
-        private _moveTeleportationSelectorTo(coordinates);
+        private _moveTeleportationSelectorTo(hit);
+        private _workingVector;
         private _teleportCamera();
         private _castRayAndSelectObject();
+        changeLaserColor(color: Color3): void;
+        changeGazeColor(color: Color3): void;
         dispose(): void;
         getClassName(): string;
     }
@@ -17666,6 +17765,8 @@ declare module BABYLON {
         defaultLightingOnControllers?: boolean;
         useCustomVRButton?: boolean;
         customVRButton?: HTMLButtonElement;
+        rayLength?: number;
+        defaultHeight?: number;
     }
     class WebVRFreeCamera extends FreeCamera implements PoseControlled {
         private webVROptions;
@@ -18621,10 +18722,15 @@ declare module BABYLON {
         protected _forceAlphaTest: boolean;
         /**
          * A fresnel is applied to the alpha of the model to ensure grazing angles edges are not alpha tested.
-         * And/Or occlude the blended part.
+         * And/Or occlude the blended part. (alpha is converted to gamma to compute the fresnel)
          */
         protected _useAlphaFresnel: boolean;
         /**
+         * A fresnel is applied to the alpha of the model to ensure grazing angles edges are not alpha tested.
+         * And/Or occlude the blended part. (alpha stays linear to compute the fresnel)
+         */
+        protected _useLinearAlphaFresnel: boolean;
+        /**
          * The transparency mode of the material.
          */
         protected _transparencyMode: Nullable<number>;
@@ -18768,10 +18874,13 @@ declare module BABYLON.Internals {
          * If sets to true and backfaceCulling is false, normals will be flipped on the backside.
          */
         doubleSided: boolean;
+        lightmapTexture: BaseTexture;
+        useLightmapAsShadowmap: boolean;
         /**
          * Return the active textures of the material.
          */
         getActiveTextures(): BaseTexture[];
+        hasTexture(texture: BaseTexture): boolean;
         /**
          * Instantiates a new PBRMaterial instance.
          *
@@ -19002,11 +19111,16 @@ declare module BABYLON {
         twoSidedLighting: boolean;
         /**
          * A fresnel is applied to the alpha of the model to ensure grazing angles edges are not alpha tested.
-         * And/Or occlude the blended part.
+         * And/Or occlude the blended part. (alpha is converted to gamma to compute the fresnel)
          */
         useAlphaFresnel: boolean;
         /**
          * A fresnel is applied to the alpha of the model to ensure grazing angles edges are not alpha tested.
+         * And/Or occlude the blended part. (alpha stays linear to compute the fresnel)
+         */
+        useLinearAlphaFresnel: boolean;
+        /**
+         * A fresnel is applied to the alpha of the model to ensure grazing angles edges are not alpha tested.
          * And/Or occlude the blended part.
          */
         environmentBRDFTexture: Nullable<BaseTexture>;
@@ -19526,8 +19640,6 @@ declare module BABYLON {
         baseHeight: number;
         baseDepth: number;
         invertY: boolean;
-        _initialSlot: number;
-        _designatedSlot: number;
         _dataSource: number;
         _buffer: Nullable<ArrayBuffer | HTMLImageElement>;
         _bufferView: Nullable<ArrayBufferView>;
@@ -19634,13 +19746,13 @@ declare module BABYLON {
     class RawTexture extends Texture {
         format: number;
         private _engine;
-        constructor(data: ArrayBufferView, width: number, height: number, format: number, scene: Scene, generateMipMaps?: boolean, invertY?: boolean, samplingMode?: number);
+        constructor(data: ArrayBufferView, width: number, height: number, format: number, scene: Scene, generateMipMaps?: boolean, invertY?: boolean, samplingMode?: number, type?: number);
         update(data: ArrayBufferView): void;
         static CreateLuminanceTexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps?: boolean, invertY?: boolean, samplingMode?: number): RawTexture;
         static CreateLuminanceAlphaTexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps?: boolean, invertY?: boolean, samplingMode?: number): RawTexture;
         static CreateAlphaTexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps?: boolean, invertY?: boolean, samplingMode?: number): RawTexture;
-        static CreateRGBTexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps?: boolean, invertY?: boolean, samplingMode?: number): RawTexture;
-        static CreateRGBATexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps?: boolean, invertY?: boolean, samplingMode?: number): RawTexture;
+        static CreateRGBTexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps?: boolean, invertY?: boolean, samplingMode?: number, type?: number): RawTexture;
+        static CreateRGBATexture(data: ArrayBufferView, width: number, height: number, scene: Scene, generateMipMaps?: boolean, invertY?: boolean, samplingMode?: number, type?: number): RawTexture;
     }
 }
 

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


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


+ 4 - 3
dist/preview release/gui/babylon.gui.d.ts

@@ -165,8 +165,8 @@ declare module BABYLON.GUI {
         private _transformCenterX;
         private _transformCenterY;
         private _transformMatrix;
-        private _invertTransformMatrix;
-        private _transformedPosition;
+        protected _invertTransformMatrix: Matrix2D;
+        protected _transformedPosition: Vector2;
         private _isMatrixDirty;
         private _cachedOffsetX;
         private _cachedOffsetY;
@@ -456,7 +456,7 @@ declare module BABYLON.GUI {
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         private _pointerIsDown;
-        private _updateValueFromPointer(x);
+        private _updateValueFromPointer(x, y);
         _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: Vector2): void;
         _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
@@ -678,6 +678,7 @@ declare module BABYLON.GUI {
         placeholderColor: string;
         placeholderText: string;
         text: string;
+        width: string | number;
         constructor(name?: string | undefined, text?: string);
         onBlur(): void;
         onFocus(): void;

+ 45 - 8
dist/preview release/gui/babylon.gui.js

@@ -304,6 +304,8 @@ var BABYLON;
                             continue;
                         }
                         control.notRenderable = false;
+                        // Account for RenderScale.
+                        projectedPosition.scaleInPlace(this.renderScale);
                         control._moveToProjectedPosition(projectedPosition);
                     }
                 }
@@ -1368,7 +1370,7 @@ var BABYLON;
                 this.notRenderable = false;
             };
             Control.prototype.linkWithMesh = function (mesh) {
-                if (!this._host || this._root !== this._host._rootContainer) {
+                if (!this._host || this._root && this._root !== this._host._rootContainer) {
                     BABYLON.Tools.Error("Cannot link a control to a mesh if the control is not at root level");
                     return;
                 }
@@ -2775,10 +2777,10 @@ var BABYLON;
                         context.shadowOffsetY = this.shadowOffsetY;
                     }
                     if (this._thumbWidth.isPixel) {
-                        effectiveThumbWidth = Math.min(this._thumbWidth.getValue(this._host), this._currentMeasure.height);
+                        effectiveThumbWidth = Math.min(this._thumbWidth.getValue(this._host), this._currentMeasure.width);
                     }
                     else {
-                        effectiveThumbWidth = this._currentMeasure.height * this._thumbWidth.getValue(this._host);
+                        effectiveThumbWidth = this._currentMeasure.width * this._thumbWidth.getValue(this._host);
                     }
                     if (this._barOffset.isPixel) {
                         effectiveBarOffset = Math.min(this._barOffset.getValue(this._host), this._currentMeasure.height);
@@ -2831,7 +2833,11 @@ var BABYLON;
                 }
                 context.restore();
             };
-            Slider.prototype._updateValueFromPointer = function (x) {
+            Slider.prototype._updateValueFromPointer = function (x, y) {
+                if (this.rotation != 0) {
+                    this._invertTransformMatrix.transformCoordinates(x, y, this._transformedPosition);
+                    x = this._transformedPosition.x;
+                }
                 this.value = this._minimum + ((x - this._currentMeasure.left) / this._currentMeasure.width) * (this._maximum - this._minimum);
             };
             Slider.prototype._onPointerDown = function (target, coordinates, buttonIndex) {
@@ -2839,13 +2845,13 @@ var BABYLON;
                     return false;
                 }
                 this._pointerIsDown = true;
-                this._updateValueFromPointer(coordinates.x);
+                this._updateValueFromPointer(coordinates.x, coordinates.y);
                 this._host._capturingControl = this;
                 return true;
             };
             Slider.prototype._onPointerMove = function (target, coordinates) {
                 if (this._pointerIsDown) {
-                    this._updateValueFromPointer(coordinates.x);
+                    this._updateValueFromPointer(coordinates.x, coordinates.y);
                 }
                 _super.prototype._onPointerMove.call(this, target, coordinates);
             };
@@ -2987,7 +2993,7 @@ var BABYLON;
     })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
 })(BABYLON || (BABYLON = {}));
 
-//# sourceMappingURL=checkBox.js.map
+//# sourceMappingURL=checkbox.js.map
 
 /// <reference path="../../../dist/preview release/babylon.d.ts"/>
 
@@ -3505,7 +3511,7 @@ var BABYLON;
                         _this._onImageLoaded();
                     };
                     if (value) {
-                        this._domImage.crossOrigin = "anonymous";
+                        BABYLON.Tools.SetCorsBehavior(value, this._domImage);
                         this._domImage.src = value;
                     }
                 },
@@ -3517,7 +3523,11 @@ var BABYLON;
                     return this._cellWidth;
                 },
                 set: function (value) {
+                    if (this._cellWidth === value) {
+                        return;
+                    }
                     this._cellWidth = value;
+                    this._markAsDirty();
                 },
                 enumerable: true,
                 configurable: true
@@ -3527,7 +3537,11 @@ var BABYLON;
                     return this._cellHeight;
                 },
                 set: function (value) {
+                    if (this._cellHeight === value) {
+                        return;
+                    }
                     this._cellHeight = value;
+                    this._markAsDirty();
                 },
                 enumerable: true,
                 configurable: true
@@ -3537,7 +3551,11 @@ var BABYLON;
                     return this._cellId;
                 },
                 set: function (value) {
+                    if (this._cellId === value) {
+                        return;
+                    }
                     this._cellId = value;
+                    this._markAsDirty();
                 },
                 enumerable: true,
                 configurable: true
@@ -4311,6 +4329,22 @@ var BABYLON;
                 enumerable: true,
                 configurable: true
             });
+            Object.defineProperty(InputText.prototype, "width", {
+                get: function () {
+                    return this._width.toString(this._host);
+                },
+                set: function (value) {
+                    if (this._width.toString(this._host) === value) {
+                        return;
+                    }
+                    if (this._width.fromString(value)) {
+                        this._markAsDirty();
+                    }
+                    this.autoStretchWidth = false;
+                },
+                enumerable: true,
+                configurable: true
+            });
             InputText.prototype.onBlur = function () {
                 this._isFocused = false;
                 this._scrollLeft = null;
@@ -4341,6 +4375,9 @@ var BABYLON;
             InputText.prototype.processKey = function (keyCode, key) {
                 // Specific cases
                 switch (keyCode) {
+                    case 32://SPACE
+                        key = " "; //ie11 key for space is "Spacebar" 
+                        break;
                     case 8:// BACKSPACE
                         if (this._text && this._text.length > 0) {
                             if (this._cursorOffset === 0) {

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


+ 4 - 3
dist/preview release/gui/babylon.gui.module.d.ts

@@ -170,8 +170,8 @@ declare module BABYLON.GUI {
         private _transformCenterX;
         private _transformCenterY;
         private _transformMatrix;
-        private _invertTransformMatrix;
-        private _transformedPosition;
+        protected _invertTransformMatrix: Matrix2D;
+        protected _transformedPosition: Vector2;
         private _isMatrixDirty;
         private _cachedOffsetX;
         private _cachedOffsetY;
@@ -461,7 +461,7 @@ declare module BABYLON.GUI {
         protected _getTypeName(): string;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         private _pointerIsDown;
-        private _updateValueFromPointer(x);
+        private _updateValueFromPointer(x, y);
         _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: Vector2): void;
         _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void;
@@ -683,6 +683,7 @@ declare module BABYLON.GUI {
         placeholderColor: string;
         placeholderText: string;
         text: string;
+        width: string | number;
         constructor(name?: string | undefined, text?: string);
         onBlur(): void;
         onFocus(): void;

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

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

File diff suppressed because it is too large
+ 4 - 447
dist/preview release/inspector/babylon.inspector.bundle.js


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

@@ -721,6 +721,10 @@ declare module INSPECTOR {
          */
         static IsBrowserEdge(): boolean;
         /**
+         * Returns true if the user browser is IE.
+         */
+        static IsBrowserIE(): boolean;
+        /**
          * Returns the name of the type of the given object, where the name
          * is in PROPERTIES constant.
          * Returns 'Undefined' if no type exists for this object

+ 18 - 3
dist/preview release/inspector/babylon.inspector.js

@@ -1562,8 +1562,9 @@ var INSPECTOR;
         PropertyLine.prototype._createElements = function () {
             // Colors
             if (this.type == 'Color3' || this.type == 'Color4') {
-                this._elements.push(new INSPECTOR.ColorPickerElement(this.value, this));
-                //this._elements.push(new ColorElement(this.value));
+                if (!INSPECTOR.Helpers.IsBrowserIE()) {
+                    this._elements.push(new INSPECTOR.ColorPickerElement(this.value, this));
+                }
             }
             // Texture
             if (this.type == 'Texture') {
@@ -1699,7 +1700,13 @@ var INSPECTOR;
                     var objToDetail = this.value;
                     // Display all properties that are not functions
                     var propToDisplay = INSPECTOR.Helpers.GetAllLinesPropertiesAsString(objToDetail);
-                    propToDisplay.sort().reverse();
+                    // special case for color3
+                    if ((propToDisplay.indexOf('r') && propToDisplay.indexOf('g') && propToDisplay.indexOf('b')) == 0) {
+                        propToDisplay.sort();
+                    }
+                    else {
+                        propToDisplay.sort().reverse();
+                    }
                     for (var _b = 0, propToDisplay_1 = propToDisplay; _b < propToDisplay_1.length; _b++) {
                         var prop = propToDisplay_1[_b];
                         var infos = new INSPECTOR.Property(prop, this._property.value);
@@ -2253,6 +2260,14 @@ var INSPECTOR;
             return regexp.test(navigator.userAgent);
         };
         /**
+         * Returns true if the user browser is IE.
+         */
+        Helpers.IsBrowserIE = function () {
+            //Detect if we are running on a faulty buggy OS.
+            var regexp = /Trident.*rv\:11\./;
+            return regexp.test(navigator.userAgent);
+        };
+        /**
          * Returns the name of the type of the given object, where the name
          * is in PROPERTIES constant.
          * Returns 'Undefined' if no type exists for this object

File diff suppressed because it is too large
+ 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.1.0-beta5",
+    "version": "3.1.0-rc-0",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -1,9 +1,28 @@
 
 declare module BABYLON {
     enum GLTFLoaderCoordinateSystemMode {
+        /**
+         * Automatically convert the glTF right-handed data to the appropriate system based on the current coordinate system mode of the scene.
+         */
         AUTO = 0,
-        PASS_THROUGH = 1,
-        FORCE_RIGHT_HANDED = 2,
+        /**
+         * Sets the useRightHandedSystem flag on the scene.
+         */
+        FORCE_RIGHT_HANDED = 1,
+    }
+    enum GLTFLoaderAnimationStartMode {
+        /**
+         * No animation will start.
+         */
+        NONE = 0,
+        /**
+         * The first animation will start.
+         */
+        FIRST = 1,
+        /**
+         * All animations will start.
+         */
+        ALL = 2,
     }
     interface IGLTFLoaderData {
         json: Object;
@@ -16,25 +35,58 @@ declare module BABYLON {
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
+        /**
+         * Raised when the asset has been parsed.
+         * The data.json property stores the glTF JSON.
+         * The data.bin property stores the BIN chunk from a glTF binary or null if the input is not a glTF binary.
+         */
         onParsed: (data: IGLTFLoaderData) => void;
-        static HomogeneousCoordinates: boolean;
         static IncrementalLoading: boolean;
+        static HomogeneousCoordinates: boolean;
+        /**
+         * The coordinate system mode (AUTO, FORCE_RIGHT_HANDED).
+         */
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
+        /**
+         * The animation start mode (NONE, FIRST, ALL).
+         */
+        animationStartMode: GLTFLoaderAnimationStartMode;
+        /**
+         * Set to true to compile materials before raising the success callback.
+         */
         compileMaterials: boolean;
-        compileShadowGenerators: boolean;
+        /**
+         * Set to true to also compile materials with clip planes.
+         */
         useClipPlane: boolean;
+        /**
+         * Set to true to compile shadow generators before raising the success callback.
+         */
+        compileShadowGenerators: boolean;
+        /**
+         * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
+         */
         onMeshLoaded: (mesh: AbstractMesh) => void;
+        /**
+         * Raised when the loader creates a texture after parsing the glTF properties of the texture.
+         */
         onTextureLoaded: (texture: BaseTexture) => void;
+        /**
+         * Raised when the loader creates a material after parsing the glTF properties of the material.
+         */
         onMaterialLoaded: (material: Material) => void;
         /**
-         * Raised when the asset is completely loaded, just before the loader is disposed.
+         * 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 just after onSuccess.
+         * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          */
         onComplete: () => void;
         private _loader;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
+        /**
+         * Disposes the loader, releases resources during load, and cancels any outstanding requests.
+         */
         dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;

+ 72 - 18
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -3,27 +3,63 @@ var BABYLON;
 (function (BABYLON) {
     var GLTFLoaderCoordinateSystemMode;
     (function (GLTFLoaderCoordinateSystemMode) {
-        // Automatically convert the glTF right-handed data to the appropriate system based on the current coordinate system mode of the scene (scene.useRightHandedSystem).
-        // NOTE: When scene.useRightHandedSystem is false, an additional transform will be added to the root to transform the data from right-handed to left-handed.
+        /**
+         * Automatically convert the glTF right-handed data to the appropriate system based on the current coordinate system mode of the scene.
+         */
         GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["AUTO"] = 0] = "AUTO";
-        // The glTF right-handed data is not transformed in any form and is loaded directly.
-        GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["PASS_THROUGH"] = 1] = "PASS_THROUGH";
-        // Sets the useRightHandedSystem flag on the scene.
-        GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["FORCE_RIGHT_HANDED"] = 2] = "FORCE_RIGHT_HANDED";
+        /**
+         * Sets the useRightHandedSystem flag on the scene.
+         */
+        GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["FORCE_RIGHT_HANDED"] = 1] = "FORCE_RIGHT_HANDED";
     })(GLTFLoaderCoordinateSystemMode = BABYLON.GLTFLoaderCoordinateSystemMode || (BABYLON.GLTFLoaderCoordinateSystemMode = {}));
+    var GLTFLoaderAnimationStartMode;
+    (function (GLTFLoaderAnimationStartMode) {
+        /**
+         * No animation will start.
+         */
+        GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["NONE"] = 0] = "NONE";
+        /**
+         * The first animation will start.
+         */
+        GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["FIRST"] = 1] = "FIRST";
+        /**
+         * All animations will start.
+         */
+        GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["ALL"] = 2] = "ALL";
+    })(GLTFLoaderAnimationStartMode = BABYLON.GLTFLoaderAnimationStartMode || (BABYLON.GLTFLoaderAnimationStartMode = {}));
     var GLTFFileLoader = /** @class */ (function () {
         function GLTFFileLoader() {
-            // V2 options
+            // #endregion
+            // #region V2 options
+            /**
+             * The coordinate system mode (AUTO, FORCE_RIGHT_HANDED).
+             */
             this.coordinateSystemMode = GLTFLoaderCoordinateSystemMode.AUTO;
+            /**
+             * The animation start mode (NONE, FIRST, ALL).
+             */
+            this.animationStartMode = GLTFLoaderAnimationStartMode.FIRST;
+            /**
+             * Set to true to compile materials before raising the success callback.
+             */
             this.compileMaterials = false;
-            this.compileShadowGenerators = false;
+            /**
+             * Set to true to also compile materials with clip planes.
+             */
             this.useClipPlane = false;
+            /**
+             * Set to true to compile shadow generators before raising the success callback.
+             */
+            this.compileShadowGenerators = false;
             this.name = "gltf";
             this.extensions = {
                 ".gltf": { isBinary: false },
                 ".glb": { isBinary: true }
             };
         }
+        /**
+         * Disposes the loader, releases resources during load, and cancels any outstanding requests.
+         */
         GLTFFileLoader.prototype.dispose = function () {
             if (this._loader) {
                 this._loader.dispose();
@@ -181,7 +217,13 @@ var BABYLON;
             };
         };
         GLTFFileLoader._parseVersion = function (version) {
-            var match = (version + "").match(/^(\d+)\.(\d+)$/);
+            if (version === "1.0" || version === "1.0.1") {
+                return {
+                    major: 1,
+                    minor: 0
+                };
+            }
+            var match = (version + "").match(/^(\d+)\.(\d+)/);
             if (!match) {
                 return null;
             }
@@ -209,9 +251,10 @@ var BABYLON;
             }
             return result;
         };
-        // V1 options
-        GLTFFileLoader.HomogeneousCoordinates = false;
+        // #endregion
+        // #region V1 options
         GLTFFileLoader.IncrementalLoading = true;
+        GLTFFileLoader.HomogeneousCoordinates = false;
         return GLTFFileLoader;
     }());
     BABYLON.GLTFFileLoader = GLTFFileLoader;
@@ -824,10 +867,7 @@ var BABYLON;
             if (!node.babylonNode) {
                 return newMesh;
             }
-            var multiMat = new BABYLON.MultiMaterial("multimat" + id, gltfRuntime.scene);
-            if (!newMesh.material) {
-                newMesh.material = multiMat;
-            }
+            var subMaterials = [];
             var vertexData = new BABYLON.VertexData();
             var geometry = new BABYLON.Geometry(id, gltfRuntime.scene, vertexData, false, newMesh);
             var verticesStarts = new Array();
@@ -915,13 +955,27 @@ var BABYLON;
                     }
                     vertexData.merge(tempVertexData);
                     // Sub material
-                    var material = gltfRuntime.scene.getMaterialByID(primitive.material);
-                    multiMat.subMaterials.push(material === null ? GLTF1.GLTFUtils.GetDefaultMaterial(gltfRuntime.scene) : material);
+                    var material_1 = gltfRuntime.scene.getMaterialByID(primitive.material);
+                    subMaterials.push(material_1 === null ? GLTF1.GLTFUtils.GetDefaultMaterial(gltfRuntime.scene) : material_1);
                     // Update vertices start and index start
                     verticesStarts.push(verticesStarts.length === 0 ? 0 : verticesStarts[verticesStarts.length - 1] + verticesCounts[verticesCounts.length - 2]);
                     indexStarts.push(indexStarts.length === 0 ? 0 : indexStarts[indexStarts.length - 1] + indexCounts[indexCounts.length - 2]);
                 }
             }
+            var material;
+            if (subMaterials.length > 1) {
+                material = new BABYLON.MultiMaterial("multimat" + id, gltfRuntime.scene);
+                material.subMaterials = subMaterials;
+            }
+            else {
+                material = new BABYLON.StandardMaterial("multimat" + id, gltfRuntime.scene);
+            }
+            if (subMaterials.length === 1) {
+                material = subMaterials[0];
+            }
+            if (!newMesh.material) {
+                newMesh.material = material;
+            }
             // Apply geometry
             geometry.setAllVerticesData(vertexData, false);
             newMesh.computeWorldMatrix(true);
@@ -992,7 +1046,7 @@ var BABYLON;
                     var skin = gltfRuntime.skins[node.skin];
                     var newMesh = importMesh(gltfRuntime, node, node.meshes, id, node.babylonNode);
                     newMesh.skeleton = gltfRuntime.scene.getLastSkeletonByID(node.skin);
-                    if (newMesh.skeleton === null && skin.babylonSkeleton) {
+                    if (newMesh.skeleton === null) {
                         newMesh.skeleton = importSkeleton(gltfRuntime, skin, newMesh, skin.babylonSkeleton, node.skin);
                         if (!skin.babylonSkeleton) {
                             skin.babylonSkeleton = newMesh.skeleton;

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


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

@@ -1,9 +1,28 @@
 
 declare module BABYLON {
     enum GLTFLoaderCoordinateSystemMode {
+        /**
+         * Automatically convert the glTF right-handed data to the appropriate system based on the current coordinate system mode of the scene.
+         */
         AUTO = 0,
-        PASS_THROUGH = 1,
-        FORCE_RIGHT_HANDED = 2,
+        /**
+         * Sets the useRightHandedSystem flag on the scene.
+         */
+        FORCE_RIGHT_HANDED = 1,
+    }
+    enum GLTFLoaderAnimationStartMode {
+        /**
+         * No animation will start.
+         */
+        NONE = 0,
+        /**
+         * The first animation will start.
+         */
+        FIRST = 1,
+        /**
+         * All animations will start.
+         */
+        ALL = 2,
     }
     interface IGLTFLoaderData {
         json: Object;
@@ -16,25 +35,58 @@ declare module BABYLON {
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
+        /**
+         * Raised when the asset has been parsed.
+         * The data.json property stores the glTF JSON.
+         * The data.bin property stores the BIN chunk from a glTF binary or null if the input is not a glTF binary.
+         */
         onParsed: (data: IGLTFLoaderData) => void;
-        static HomogeneousCoordinates: boolean;
         static IncrementalLoading: boolean;
+        static HomogeneousCoordinates: boolean;
+        /**
+         * The coordinate system mode (AUTO, FORCE_RIGHT_HANDED).
+         */
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
+        /**
+         * The animation start mode (NONE, FIRST, ALL).
+         */
+        animationStartMode: GLTFLoaderAnimationStartMode;
+        /**
+         * Set to true to compile materials before raising the success callback.
+         */
         compileMaterials: boolean;
-        compileShadowGenerators: boolean;
+        /**
+         * Set to true to also compile materials with clip planes.
+         */
         useClipPlane: boolean;
+        /**
+         * Set to true to compile shadow generators before raising the success callback.
+         */
+        compileShadowGenerators: boolean;
+        /**
+         * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
+         */
         onMeshLoaded: (mesh: AbstractMesh) => void;
+        /**
+         * Raised when the loader creates a texture after parsing the glTF properties of the texture.
+         */
         onTextureLoaded: (texture: BaseTexture) => void;
+        /**
+         * Raised when the loader creates a material after parsing the glTF properties of the material.
+         */
         onMaterialLoaded: (material: Material) => void;
         /**
-         * Raised when the asset is completely loaded, just before the loader is disposed.
+         * 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 just after onSuccess.
+         * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          */
         onComplete: () => void;
         private _loader;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
+        /**
+         * Disposes the loader, releases resources during load, and cancels any outstanding requests.
+         */
         dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
@@ -245,11 +297,8 @@ declare module BABYLON.GLTF2 {
         translation?: number[];
         weights?: number[];
         index: number;
-        parent?: IGLTFNode;
+        parent: IGLTFNode;
         babylonMesh: Mesh;
-        babylonBones?: {
-            [skin: number]: Bone;
-        };
         babylonAnimationTargets?: Node[];
     }
     interface IGLTFSampler extends IGLTFChildRootProperty {
@@ -339,7 +388,6 @@ declare module BABYLON.GLTF2 {
         private _loadData(data);
         private _getMeshes();
         private _getSkeletons();
-        private _getAnimationTargets();
         private _startAnimations();
         private _loadDefaultScene(nodeNames);
         private _loadScene(context, scene, nodeNames);
@@ -364,13 +412,13 @@ declare module BABYLON.GLTF2 {
         private _loadAllMorphTargetVertexDataAsync(context, node, mesh, onSuccess);
         private _loadMorphTargetVertexDataAsync(context, vertexData, attributes, onSuccess);
         private _loadTransform(node);
-        private _loadSkin(context, skin);
+        private _loadSkinAsync(context, skin, onSuccess);
         private _createBone(node, skin, parent, localMatrix, baseMatrix, index);
         private _loadBones(context, skin, inverseBindMatrixData);
         private _loadBone(node, skin, inverseBindMatrixData, babylonBones);
         private _getNodeMatrix(node);
-        private _traverseNodes(context, indices, action, parentNode?);
-        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: Nullable<IGLTFNode>) => boolean, parentNode?: Nullable<IGLTFNode>): void;
+        private _traverseNodes(context, indices, action, parentNode);
+        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): void;
         private _loadAnimations();
         private _loadAnimation(context, animation);
         private _loadAnimationChannel(animation, channelContext, channel, samplerContext, sampler);
@@ -429,12 +477,12 @@ declare module BABYLON.GLTF2 {
     abstract class GLTFLoaderExtension {
         enabled: boolean;
         readonly abstract name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: Nullable<IGLTFNode>): boolean;
+        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
         protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
         protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean;
         static _Extensions: GLTFLoaderExtension[];
-        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: Nullable<IGLTFNode>): boolean;
+        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
         static LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
         static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private static _ApplyExtensions(action);

+ 165 - 62
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -3,27 +3,63 @@ var BABYLON;
 (function (BABYLON) {
     var GLTFLoaderCoordinateSystemMode;
     (function (GLTFLoaderCoordinateSystemMode) {
-        // Automatically convert the glTF right-handed data to the appropriate system based on the current coordinate system mode of the scene (scene.useRightHandedSystem).
-        // NOTE: When scene.useRightHandedSystem is false, an additional transform will be added to the root to transform the data from right-handed to left-handed.
+        /**
+         * Automatically convert the glTF right-handed data to the appropriate system based on the current coordinate system mode of the scene.
+         */
         GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["AUTO"] = 0] = "AUTO";
-        // The glTF right-handed data is not transformed in any form and is loaded directly.
-        GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["PASS_THROUGH"] = 1] = "PASS_THROUGH";
-        // Sets the useRightHandedSystem flag on the scene.
-        GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["FORCE_RIGHT_HANDED"] = 2] = "FORCE_RIGHT_HANDED";
+        /**
+         * Sets the useRightHandedSystem flag on the scene.
+         */
+        GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["FORCE_RIGHT_HANDED"] = 1] = "FORCE_RIGHT_HANDED";
     })(GLTFLoaderCoordinateSystemMode = BABYLON.GLTFLoaderCoordinateSystemMode || (BABYLON.GLTFLoaderCoordinateSystemMode = {}));
+    var GLTFLoaderAnimationStartMode;
+    (function (GLTFLoaderAnimationStartMode) {
+        /**
+         * No animation will start.
+         */
+        GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["NONE"] = 0] = "NONE";
+        /**
+         * The first animation will start.
+         */
+        GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["FIRST"] = 1] = "FIRST";
+        /**
+         * All animations will start.
+         */
+        GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["ALL"] = 2] = "ALL";
+    })(GLTFLoaderAnimationStartMode = BABYLON.GLTFLoaderAnimationStartMode || (BABYLON.GLTFLoaderAnimationStartMode = {}));
     var GLTFFileLoader = /** @class */ (function () {
         function GLTFFileLoader() {
-            // V2 options
+            // #endregion
+            // #region V2 options
+            /**
+             * The coordinate system mode (AUTO, FORCE_RIGHT_HANDED).
+             */
             this.coordinateSystemMode = GLTFLoaderCoordinateSystemMode.AUTO;
+            /**
+             * The animation start mode (NONE, FIRST, ALL).
+             */
+            this.animationStartMode = GLTFLoaderAnimationStartMode.FIRST;
+            /**
+             * Set to true to compile materials before raising the success callback.
+             */
             this.compileMaterials = false;
-            this.compileShadowGenerators = false;
+            /**
+             * Set to true to also compile materials with clip planes.
+             */
             this.useClipPlane = false;
+            /**
+             * Set to true to compile shadow generators before raising the success callback.
+             */
+            this.compileShadowGenerators = false;
             this.name = "gltf";
             this.extensions = {
                 ".gltf": { isBinary: false },
                 ".glb": { isBinary: true }
             };
         }
+        /**
+         * Disposes the loader, releases resources during load, and cancels any outstanding requests.
+         */
         GLTFFileLoader.prototype.dispose = function () {
             if (this._loader) {
                 this._loader.dispose();
@@ -181,7 +217,13 @@ var BABYLON;
             };
         };
         GLTFFileLoader._parseVersion = function (version) {
-            var match = (version + "").match(/^(\d+)\.(\d+)$/);
+            if (version === "1.0" || version === "1.0.1") {
+                return {
+                    major: 1,
+                    minor: 0
+                };
+            }
+            var match = (version + "").match(/^(\d+)\.(\d+)/);
             if (!match) {
                 return null;
             }
@@ -209,9 +251,10 @@ var BABYLON;
             }
             return result;
         };
-        // V1 options
-        GLTFFileLoader.HomogeneousCoordinates = false;
+        // #endregion
+        // #region V1 options
         GLTFFileLoader.IncrementalLoading = true;
+        GLTFFileLoader.HomogeneousCoordinates = false;
         return GLTFFileLoader;
     }());
     BABYLON.GLTFFileLoader = GLTFFileLoader;
@@ -501,21 +544,38 @@ var BABYLON;
                 }
                 return skeletons;
             };
-            GLTFLoader.prototype._getAnimationTargets = function () {
-                var targets = new Array();
+            GLTFLoader.prototype._startAnimations = function () {
                 var animations = this._gltf.animations;
-                if (animations) {
-                    for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
-                        var animation = animations_1[_i];
-                        targets.push.apply(targets, animation.targets);
-                    }
+                if (!animations) {
+                    return;
                 }
-                return targets;
-            };
-            GLTFLoader.prototype._startAnimations = function () {
-                for (var _i = 0, _a = this._getAnimationTargets(); _i < _a.length; _i++) {
-                    var target = _a[_i];
-                    this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
+                switch (this._parent.animationStartMode) {
+                    case BABYLON.GLTFLoaderAnimationStartMode.NONE: {
+                        // do nothing
+                        break;
+                    }
+                    case BABYLON.GLTFLoaderAnimationStartMode.FIRST: {
+                        var animation = animations[0];
+                        for (var _i = 0, _a = animation.targets; _i < _a.length; _i++) {
+                            var target = _a[_i];
+                            this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
+                        }
+                        break;
+                    }
+                    case BABYLON.GLTFLoaderAnimationStartMode.ALL: {
+                        for (var _b = 0, animations_1 = animations; _b < animations_1.length; _b++) {
+                            var animation = animations_1[_b];
+                            for (var _c = 0, _d = animation.targets; _c < _d.length; _c++) {
+                                var target = _d[_c];
+                                this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
+                            }
+                        }
+                        break;
+                    }
+                    default: {
+                        BABYLON.Tools.Error("Invalid animation start mode " + this._parent.animationStartMode);
+                        return;
+                    }
                 }
             };
             GLTFLoader.prototype._loadDefaultScene = function (nodeNames) {
@@ -526,19 +586,17 @@ var BABYLON;
                 this._loadScene("#/scenes/" + scene.index, scene, nodeNames);
             };
             GLTFLoader.prototype._loadScene = function (context, scene, nodeNames) {
+                var _this = this;
                 this._rootNode = { babylonMesh: new BABYLON.Mesh("__root__", this._babylonScene) };
                 switch (this._parent.coordinateSystemMode) {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO: {
                         if (!this._babylonScene.useRightHandedSystem) {
-                            this._rootNode.babylonMesh.rotation = new BABYLON.Vector3(0, Math.PI, 0);
-                            this._rootNode.babylonMesh.scaling = new BABYLON.Vector3(1, 1, -1);
+                            this._rootNode.rotation = [0, 1, 0, 0];
+                            this._rootNode.scale = [1, 1, -1];
+                            this._loadTransform(this._rootNode);
                         }
                         break;
                     }
-                    case BABYLON.GLTFLoaderCoordinateSystemMode.PASS_THROUGH: {
-                        // do nothing
-                        break;
-                    }
                     case BABYLON.GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED: {
                         this._babylonScene.useRightHandedSystem = true;
                         break;
@@ -564,6 +622,7 @@ var BABYLON;
                     this._traverseNodes(context, nodeIndices, function (node) {
                         if (nodeNames.indexOf(node.name) !== -1) {
                             filteredNodeIndices_1.push(node.index);
+                            node.parent = _this._rootNode;
                             return false;
                         }
                         return true;
@@ -595,15 +654,22 @@ var BABYLON;
                     }
                     this._loadMesh("#/meshes/" + node.mesh, node, mesh);
                 }
-                node.babylonMesh.parent = node.parent ? node.parent.babylonMesh : null;
+                node.babylonMesh.parent = node.parent.babylonMesh;
                 node.babylonAnimationTargets = node.babylonAnimationTargets || [];
                 node.babylonAnimationTargets.push(node.babylonMesh);
                 if (node.skin != null) {
-                    var skin = GLTFLoader._GetProperty(this._gltf.skins, node.skin);
-                    if (!skin) {
+                    var skin_1 = GLTFLoader._GetProperty(this._gltf.skins, node.skin);
+                    if (!skin_1) {
                         throw new Error(context + ": Failed to find skin " + node.skin);
                     }
-                    node.babylonMesh.skeleton = this._loadSkin("#/skins/" + node.skin, skin);
+                    this._loadSkinAsync("#/skins/" + node.skin, skin_1, function () {
+                        node.babylonMesh.skeleton = skin_1.babylonSkeleton;
+                        node.babylonMesh._refreshBoundingInfo(true);
+                    });
+                    node.babylonMesh.parent = this._rootNode.babylonMesh;
+                    node.babylonMesh.position = BABYLON.Vector3.Zero();
+                    node.babylonMesh.rotationQuaternion = BABYLON.Quaternion.Identity();
+                    node.babylonMesh.scaling = BABYLON.Vector3.One();
                 }
                 if (node.camera != null) {
                     // TODO: handle cameras
@@ -652,32 +718,52 @@ var BABYLON;
                     }
                     ;
                 });
-                var multiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, this._babylonScene);
-                node.babylonMesh.material = multiMaterial;
-                var subMaterials = multiMaterial.subMaterials;
-                var _loop_1 = function (index) {
-                    var primitive = primitives[index];
+                if (primitives.length === 1) {
+                    var primitive = primitives[0];
                     if (primitive.material == null) {
-                        subMaterials[index] = this_1._getDefaultMaterial();
+                        node.babylonMesh.material = this._getDefaultMaterial();
                     }
                     else {
-                        var material = GLTFLoader._GetProperty(this_1._gltf.materials, primitive.material);
+                        var material = GLTFLoader._GetProperty(this._gltf.materials, primitive.material);
                         if (!material) {
                             throw new Error(context + ": Failed to find material " + primitive.material);
                         }
-                        this_1._loadMaterial("#/materials/" + material.index, material, function (babylonMaterial, isNew) {
+                        this._loadMaterial("#/materials/" + material.index, material, function (babylonMaterial, isNew) {
                             if (isNew && _this._parent.onMaterialLoaded) {
                                 _this._parent.onMaterialLoaded(babylonMaterial);
                             }
-                            subMaterials[index] = babylonMaterial;
+                            node.babylonMesh.material = babylonMaterial;
                         });
                     }
-                };
-                var this_1 = this;
-                for (var index = 0; index < primitives.length; index++) {
-                    _loop_1(index);
                 }
-                ;
+                else {
+                    var multiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, this._babylonScene);
+                    node.babylonMesh.material = multiMaterial;
+                    var subMaterials_1 = multiMaterial.subMaterials;
+                    var _loop_1 = function (index) {
+                        var primitive = primitives[index];
+                        if (primitive.material == null) {
+                            subMaterials_1[index] = this_1._getDefaultMaterial();
+                        }
+                        else {
+                            var material = GLTFLoader._GetProperty(this_1._gltf.materials, primitive.material);
+                            if (!material) {
+                                throw new Error(context + ": Failed to find material " + primitive.material);
+                            }
+                            this_1._loadMaterial("#/materials/" + material.index, material, function (babylonMaterial, isNew) {
+                                if (isNew && _this._parent.onMaterialLoaded) {
+                                    _this._parent.onMaterialLoaded(babylonMaterial);
+                                }
+                                subMaterials_1[index] = babylonMaterial;
+                            });
+                        }
+                    };
+                    var this_1 = this;
+                    for (var index = 0; index < primitives.length; index++) {
+                        _loop_1(index);
+                    }
+                    ;
+                }
             };
             GLTFLoader.prototype._loadAllVertexDataAsync = function (context, mesh, onSuccess) {
                 var primitives = mesh.primitives;
@@ -997,12 +1083,17 @@ var BABYLON;
                 node.babylonMesh.rotationQuaternion = rotation;
                 node.babylonMesh.scaling = scaling;
             };
-            GLTFLoader.prototype._loadSkin = function (context, skin) {
+            GLTFLoader.prototype._loadSkinAsync = function (context, skin, onSuccess) {
                 var _this = this;
+                if (skin.babylonSkeleton) {
+                    onSuccess();
+                    return;
+                }
                 var skeletonId = "skeleton" + skin.index;
                 skin.babylonSkeleton = new BABYLON.Skeleton(skin.name || skeletonId, skeletonId, this._babylonScene);
                 if (skin.inverseBindMatrices == null) {
                     this._loadBones(context, skin, null);
+                    onSuccess();
                 }
                 else {
                     var accessor = GLTFLoader._GetProperty(this._gltf.accessors, skin.inverseBindMatrices);
@@ -1011,14 +1102,12 @@ var BABYLON;
                     }
                     this._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
                         _this._loadBones(context, skin, data);
+                        onSuccess();
                     });
                 }
-                return skin.babylonSkeleton;
             };
             GLTFLoader.prototype._createBone = function (node, skin, parent, localMatrix, baseMatrix, index) {
                 var babylonBone = new BABYLON.Bone(node.name || "bone" + node.index, skin.babylonSkeleton, parent, localMatrix, null, baseMatrix, index);
-                node.babylonBones = node.babylonBones || {};
-                node.babylonBones[skin.index] = babylonBone;
                 node.babylonAnimationTargets = node.babylonAnimationTargets || [];
                 node.babylonAnimationTargets.push(babylonBone);
                 return babylonBone;
@@ -1046,7 +1135,7 @@ var BABYLON;
                     baseMatrix.invertToRef(baseMatrix);
                 }
                 var babylonParentBone = null;
-                if (node.index !== skin.skeleton && node.parent && node.parent !== this._rootNode) {
+                if (node.parent !== this._rootNode) {
                     babylonParentBone = this._loadBone(node.parent, skin, inverseBindMatrixData, babylonBones);
                     baseMatrix.multiplyToRef(babylonParentBone.getInvertedAbsoluteTransform(), baseMatrix);
                 }
@@ -1060,7 +1149,6 @@ var BABYLON;
                     BABYLON.Matrix.Compose(node.scale ? BABYLON.Vector3.FromArray(node.scale) : BABYLON.Vector3.One(), node.rotation ? BABYLON.Quaternion.FromArray(node.rotation) : BABYLON.Quaternion.Identity(), node.translation ? BABYLON.Vector3.FromArray(node.translation) : BABYLON.Vector3.Zero());
             };
             GLTFLoader.prototype._traverseNodes = function (context, indices, action, parentNode) {
-                if (parentNode === void 0) { parentNode = null; }
                 for (var _i = 0, indices_1 = indices; _i < indices_1.length; _i++) {
                     var index = indices_1[_i];
                     var node = GLTFLoader._GetProperty(this._gltf.nodes, index);
@@ -1071,7 +1159,6 @@ var BABYLON;
                 }
             };
             GLTFLoader.prototype._traverseNode = function (context, node, action, parentNode) {
-                if (parentNode === void 0) { parentNode = null; }
                 if (GLTF2.GLTFLoaderExtension.TraverseNode(this, context, node, action, parentNode)) {
                     return;
                 }
@@ -1206,9 +1293,19 @@ var BABYLON;
                         }
                     }
                     ;
-                    var keys = new Array(inputData.length);
-                    for (var frameIndex = 0; frameIndex < inputData.length; frameIndex++) {
-                        keys[frameIndex] = getNextKey(frameIndex);
+                    var keys;
+                    if (inputData.length === 1) {
+                        var key = getNextKey(0);
+                        keys = [
+                            { frame: key.frame, value: key.value },
+                            { frame: key.frame + 1, value: key.value }
+                        ];
+                    }
+                    else {
+                        keys = new Array(inputData.length);
+                        for (var frameIndex = 0; frameIndex < inputData.length; frameIndex++) {
+                            keys[frameIndex] = getNextKey(frameIndex);
+                        }
                     }
                     if (targetPath === "influence") {
                         var morphTargetManager = targetNode.babylonMesh.morphTargetManager;
@@ -1750,10 +1847,6 @@ var BABYLON;
             };
             GLTFLoader.prototype._compileMaterialAsync = function (babylonMaterial, babylonMesh, onSuccess) {
                 var _this = this;
-                if (!this._parent.compileMaterials) {
-                    onSuccess();
-                    return;
-                }
                 if (this._parent.useClipPlane) {
                     babylonMaterial.forceCompilation(babylonMesh, function () {
                         babylonMaterial.forceCompilation(babylonMesh, function () {
@@ -1784,6 +1877,9 @@ var BABYLON;
                             }
                         }
                     }
+                    else if (mesh.material) {
+                        remaining++;
+                    }
                 }
                 if (remaining === 0) {
                     onSuccess();
@@ -1803,6 +1899,13 @@ var BABYLON;
                             }
                         }
                     }
+                    else if (mesh.material) {
+                        this._compileMaterialAsync(mesh.material, mesh, function () {
+                            if (--remaining === 0) {
+                                onSuccess();
+                            }
+                        });
+                    }
                 }
             };
             GLTFLoader.prototype._compileShadowGeneratorsAsync = function (onSuccess) {

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


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

@@ -1,9 +1,28 @@
 
 declare module BABYLON {
     enum GLTFLoaderCoordinateSystemMode {
+        /**
+         * Automatically convert the glTF right-handed data to the appropriate system based on the current coordinate system mode of the scene.
+         */
         AUTO = 0,
-        PASS_THROUGH = 1,
-        FORCE_RIGHT_HANDED = 2,
+        /**
+         * Sets the useRightHandedSystem flag on the scene.
+         */
+        FORCE_RIGHT_HANDED = 1,
+    }
+    enum GLTFLoaderAnimationStartMode {
+        /**
+         * No animation will start.
+         */
+        NONE = 0,
+        /**
+         * The first animation will start.
+         */
+        FIRST = 1,
+        /**
+         * All animations will start.
+         */
+        ALL = 2,
     }
     interface IGLTFLoaderData {
         json: Object;
@@ -16,25 +35,58 @@ declare module BABYLON {
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
+        /**
+         * Raised when the asset has been parsed.
+         * The data.json property stores the glTF JSON.
+         * The data.bin property stores the BIN chunk from a glTF binary or null if the input is not a glTF binary.
+         */
         onParsed: (data: IGLTFLoaderData) => void;
-        static HomogeneousCoordinates: boolean;
         static IncrementalLoading: boolean;
+        static HomogeneousCoordinates: boolean;
+        /**
+         * The coordinate system mode (AUTO, FORCE_RIGHT_HANDED).
+         */
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
+        /**
+         * The animation start mode (NONE, FIRST, ALL).
+         */
+        animationStartMode: GLTFLoaderAnimationStartMode;
+        /**
+         * Set to true to compile materials before raising the success callback.
+         */
         compileMaterials: boolean;
-        compileShadowGenerators: boolean;
+        /**
+         * Set to true to also compile materials with clip planes.
+         */
         useClipPlane: boolean;
+        /**
+         * Set to true to compile shadow generators before raising the success callback.
+         */
+        compileShadowGenerators: boolean;
+        /**
+         * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
+         */
         onMeshLoaded: (mesh: AbstractMesh) => void;
+        /**
+         * Raised when the loader creates a texture after parsing the glTF properties of the texture.
+         */
         onTextureLoaded: (texture: BaseTexture) => void;
+        /**
+         * Raised when the loader creates a material after parsing the glTF properties of the material.
+         */
         onMaterialLoaded: (material: Material) => void;
         /**
-         * Raised when the asset is completely loaded, just before the loader is disposed.
+         * 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 just after onSuccess.
+         * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          */
         onComplete: () => void;
         private _loader;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
+        /**
+         * Disposes the loader, releases resources during load, and cancels any outstanding requests.
+         */
         dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
@@ -792,11 +844,8 @@ declare module BABYLON.GLTF2 {
         translation?: number[];
         weights?: number[];
         index: number;
-        parent?: IGLTFNode;
+        parent: IGLTFNode;
         babylonMesh: Mesh;
-        babylonBones?: {
-            [skin: number]: Bone;
-        };
         babylonAnimationTargets?: Node[];
     }
     interface IGLTFSampler extends IGLTFChildRootProperty {
@@ -886,7 +935,6 @@ declare module BABYLON.GLTF2 {
         private _loadData(data);
         private _getMeshes();
         private _getSkeletons();
-        private _getAnimationTargets();
         private _startAnimations();
         private _loadDefaultScene(nodeNames);
         private _loadScene(context, scene, nodeNames);
@@ -911,13 +959,13 @@ declare module BABYLON.GLTF2 {
         private _loadAllMorphTargetVertexDataAsync(context, node, mesh, onSuccess);
         private _loadMorphTargetVertexDataAsync(context, vertexData, attributes, onSuccess);
         private _loadTransform(node);
-        private _loadSkin(context, skin);
+        private _loadSkinAsync(context, skin, onSuccess);
         private _createBone(node, skin, parent, localMatrix, baseMatrix, index);
         private _loadBones(context, skin, inverseBindMatrixData);
         private _loadBone(node, skin, inverseBindMatrixData, babylonBones);
         private _getNodeMatrix(node);
-        private _traverseNodes(context, indices, action, parentNode?);
-        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: Nullable<IGLTFNode>) => boolean, parentNode?: Nullable<IGLTFNode>): void;
+        private _traverseNodes(context, indices, action, parentNode);
+        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): void;
         private _loadAnimations();
         private _loadAnimation(context, animation);
         private _loadAnimationChannel(animation, channelContext, channel, samplerContext, sampler);
@@ -976,12 +1024,12 @@ declare module BABYLON.GLTF2 {
     abstract class GLTFLoaderExtension {
         enabled: boolean;
         readonly abstract name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: Nullable<IGLTFNode>): boolean;
+        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
         protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
         protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean;
         static _Extensions: GLTFLoaderExtension[];
-        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: Nullable<IGLTFNode>): boolean;
+        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
         static LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
         static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private static _ApplyExtensions(action);

+ 183 - 69
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -3,27 +3,63 @@ var BABYLON;
 (function (BABYLON) {
     var GLTFLoaderCoordinateSystemMode;
     (function (GLTFLoaderCoordinateSystemMode) {
-        // Automatically convert the glTF right-handed data to the appropriate system based on the current coordinate system mode of the scene (scene.useRightHandedSystem).
-        // NOTE: When scene.useRightHandedSystem is false, an additional transform will be added to the root to transform the data from right-handed to left-handed.
+        /**
+         * Automatically convert the glTF right-handed data to the appropriate system based on the current coordinate system mode of the scene.
+         */
         GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["AUTO"] = 0] = "AUTO";
-        // The glTF right-handed data is not transformed in any form and is loaded directly.
-        GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["PASS_THROUGH"] = 1] = "PASS_THROUGH";
-        // Sets the useRightHandedSystem flag on the scene.
-        GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["FORCE_RIGHT_HANDED"] = 2] = "FORCE_RIGHT_HANDED";
+        /**
+         * Sets the useRightHandedSystem flag on the scene.
+         */
+        GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["FORCE_RIGHT_HANDED"] = 1] = "FORCE_RIGHT_HANDED";
     })(GLTFLoaderCoordinateSystemMode = BABYLON.GLTFLoaderCoordinateSystemMode || (BABYLON.GLTFLoaderCoordinateSystemMode = {}));
+    var GLTFLoaderAnimationStartMode;
+    (function (GLTFLoaderAnimationStartMode) {
+        /**
+         * No animation will start.
+         */
+        GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["NONE"] = 0] = "NONE";
+        /**
+         * The first animation will start.
+         */
+        GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["FIRST"] = 1] = "FIRST";
+        /**
+         * All animations will start.
+         */
+        GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["ALL"] = 2] = "ALL";
+    })(GLTFLoaderAnimationStartMode = BABYLON.GLTFLoaderAnimationStartMode || (BABYLON.GLTFLoaderAnimationStartMode = {}));
     var GLTFFileLoader = /** @class */ (function () {
         function GLTFFileLoader() {
-            // V2 options
+            // #endregion
+            // #region V2 options
+            /**
+             * The coordinate system mode (AUTO, FORCE_RIGHT_HANDED).
+             */
             this.coordinateSystemMode = GLTFLoaderCoordinateSystemMode.AUTO;
+            /**
+             * The animation start mode (NONE, FIRST, ALL).
+             */
+            this.animationStartMode = GLTFLoaderAnimationStartMode.FIRST;
+            /**
+             * Set to true to compile materials before raising the success callback.
+             */
             this.compileMaterials = false;
-            this.compileShadowGenerators = false;
+            /**
+             * Set to true to also compile materials with clip planes.
+             */
             this.useClipPlane = false;
+            /**
+             * Set to true to compile shadow generators before raising the success callback.
+             */
+            this.compileShadowGenerators = false;
             this.name = "gltf";
             this.extensions = {
                 ".gltf": { isBinary: false },
                 ".glb": { isBinary: true }
             };
         }
+        /**
+         * Disposes the loader, releases resources during load, and cancels any outstanding requests.
+         */
         GLTFFileLoader.prototype.dispose = function () {
             if (this._loader) {
                 this._loader.dispose();
@@ -181,7 +217,13 @@ var BABYLON;
             };
         };
         GLTFFileLoader._parseVersion = function (version) {
-            var match = (version + "").match(/^(\d+)\.(\d+)$/);
+            if (version === "1.0" || version === "1.0.1") {
+                return {
+                    major: 1,
+                    minor: 0
+                };
+            }
+            var match = (version + "").match(/^(\d+)\.(\d+)/);
             if (!match) {
                 return null;
             }
@@ -209,9 +251,10 @@ var BABYLON;
             }
             return result;
         };
-        // V1 options
-        GLTFFileLoader.HomogeneousCoordinates = false;
+        // #endregion
+        // #region V1 options
         GLTFFileLoader.IncrementalLoading = true;
+        GLTFFileLoader.HomogeneousCoordinates = false;
         return GLTFFileLoader;
     }());
     BABYLON.GLTFFileLoader = GLTFFileLoader;
@@ -824,10 +867,7 @@ var BABYLON;
             if (!node.babylonNode) {
                 return newMesh;
             }
-            var multiMat = new BABYLON.MultiMaterial("multimat" + id, gltfRuntime.scene);
-            if (!newMesh.material) {
-                newMesh.material = multiMat;
-            }
+            var subMaterials = [];
             var vertexData = new BABYLON.VertexData();
             var geometry = new BABYLON.Geometry(id, gltfRuntime.scene, vertexData, false, newMesh);
             var verticesStarts = new Array();
@@ -915,13 +955,27 @@ var BABYLON;
                     }
                     vertexData.merge(tempVertexData);
                     // Sub material
-                    var material = gltfRuntime.scene.getMaterialByID(primitive.material);
-                    multiMat.subMaterials.push(material === null ? GLTF1.GLTFUtils.GetDefaultMaterial(gltfRuntime.scene) : material);
+                    var material_1 = gltfRuntime.scene.getMaterialByID(primitive.material);
+                    subMaterials.push(material_1 === null ? GLTF1.GLTFUtils.GetDefaultMaterial(gltfRuntime.scene) : material_1);
                     // Update vertices start and index start
                     verticesStarts.push(verticesStarts.length === 0 ? 0 : verticesStarts[verticesStarts.length - 1] + verticesCounts[verticesCounts.length - 2]);
                     indexStarts.push(indexStarts.length === 0 ? 0 : indexStarts[indexStarts.length - 1] + indexCounts[indexCounts.length - 2]);
                 }
             }
+            var material;
+            if (subMaterials.length > 1) {
+                material = new BABYLON.MultiMaterial("multimat" + id, gltfRuntime.scene);
+                material.subMaterials = subMaterials;
+            }
+            else {
+                material = new BABYLON.StandardMaterial("multimat" + id, gltfRuntime.scene);
+            }
+            if (subMaterials.length === 1) {
+                material = subMaterials[0];
+            }
+            if (!newMesh.material) {
+                newMesh.material = material;
+            }
             // Apply geometry
             geometry.setAllVerticesData(vertexData, false);
             newMesh.computeWorldMatrix(true);
@@ -992,7 +1046,7 @@ var BABYLON;
                     var skin = gltfRuntime.skins[node.skin];
                     var newMesh = importMesh(gltfRuntime, node, node.meshes, id, node.babylonNode);
                     newMesh.skeleton = gltfRuntime.scene.getLastSkeletonByID(node.skin);
-                    if (newMesh.skeleton === null && skin.babylonSkeleton) {
+                    if (newMesh.skeleton === null) {
                         newMesh.skeleton = importSkeleton(gltfRuntime, skin, newMesh, skin.babylonSkeleton, node.skin);
                         if (!skin.babylonSkeleton) {
                             skin.babylonSkeleton = newMesh.skeleton;
@@ -2646,21 +2700,38 @@ var BABYLON;
                 }
                 return skeletons;
             };
-            GLTFLoader.prototype._getAnimationTargets = function () {
-                var targets = new Array();
+            GLTFLoader.prototype._startAnimations = function () {
                 var animations = this._gltf.animations;
-                if (animations) {
-                    for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
-                        var animation = animations_1[_i];
-                        targets.push.apply(targets, animation.targets);
-                    }
+                if (!animations) {
+                    return;
                 }
-                return targets;
-            };
-            GLTFLoader.prototype._startAnimations = function () {
-                for (var _i = 0, _a = this._getAnimationTargets(); _i < _a.length; _i++) {
-                    var target = _a[_i];
-                    this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
+                switch (this._parent.animationStartMode) {
+                    case BABYLON.GLTFLoaderAnimationStartMode.NONE: {
+                        // do nothing
+                        break;
+                    }
+                    case BABYLON.GLTFLoaderAnimationStartMode.FIRST: {
+                        var animation = animations[0];
+                        for (var _i = 0, _a = animation.targets; _i < _a.length; _i++) {
+                            var target = _a[_i];
+                            this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
+                        }
+                        break;
+                    }
+                    case BABYLON.GLTFLoaderAnimationStartMode.ALL: {
+                        for (var _b = 0, animations_1 = animations; _b < animations_1.length; _b++) {
+                            var animation = animations_1[_b];
+                            for (var _c = 0, _d = animation.targets; _c < _d.length; _c++) {
+                                var target = _d[_c];
+                                this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
+                            }
+                        }
+                        break;
+                    }
+                    default: {
+                        BABYLON.Tools.Error("Invalid animation start mode " + this._parent.animationStartMode);
+                        return;
+                    }
                 }
             };
             GLTFLoader.prototype._loadDefaultScene = function (nodeNames) {
@@ -2671,19 +2742,17 @@ var BABYLON;
                 this._loadScene("#/scenes/" + scene.index, scene, nodeNames);
             };
             GLTFLoader.prototype._loadScene = function (context, scene, nodeNames) {
+                var _this = this;
                 this._rootNode = { babylonMesh: new BABYLON.Mesh("__root__", this._babylonScene) };
                 switch (this._parent.coordinateSystemMode) {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO: {
                         if (!this._babylonScene.useRightHandedSystem) {
-                            this._rootNode.babylonMesh.rotation = new BABYLON.Vector3(0, Math.PI, 0);
-                            this._rootNode.babylonMesh.scaling = new BABYLON.Vector3(1, 1, -1);
+                            this._rootNode.rotation = [0, 1, 0, 0];
+                            this._rootNode.scale = [1, 1, -1];
+                            this._loadTransform(this._rootNode);
                         }
                         break;
                     }
-                    case BABYLON.GLTFLoaderCoordinateSystemMode.PASS_THROUGH: {
-                        // do nothing
-                        break;
-                    }
                     case BABYLON.GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED: {
                         this._babylonScene.useRightHandedSystem = true;
                         break;
@@ -2709,6 +2778,7 @@ var BABYLON;
                     this._traverseNodes(context, nodeIndices, function (node) {
                         if (nodeNames.indexOf(node.name) !== -1) {
                             filteredNodeIndices_1.push(node.index);
+                            node.parent = _this._rootNode;
                             return false;
                         }
                         return true;
@@ -2740,15 +2810,22 @@ var BABYLON;
                     }
                     this._loadMesh("#/meshes/" + node.mesh, node, mesh);
                 }
-                node.babylonMesh.parent = node.parent ? node.parent.babylonMesh : null;
+                node.babylonMesh.parent = node.parent.babylonMesh;
                 node.babylonAnimationTargets = node.babylonAnimationTargets || [];
                 node.babylonAnimationTargets.push(node.babylonMesh);
                 if (node.skin != null) {
-                    var skin = GLTFLoader._GetProperty(this._gltf.skins, node.skin);
-                    if (!skin) {
+                    var skin_1 = GLTFLoader._GetProperty(this._gltf.skins, node.skin);
+                    if (!skin_1) {
                         throw new Error(context + ": Failed to find skin " + node.skin);
                     }
-                    node.babylonMesh.skeleton = this._loadSkin("#/skins/" + node.skin, skin);
+                    this._loadSkinAsync("#/skins/" + node.skin, skin_1, function () {
+                        node.babylonMesh.skeleton = skin_1.babylonSkeleton;
+                        node.babylonMesh._refreshBoundingInfo(true);
+                    });
+                    node.babylonMesh.parent = this._rootNode.babylonMesh;
+                    node.babylonMesh.position = BABYLON.Vector3.Zero();
+                    node.babylonMesh.rotationQuaternion = BABYLON.Quaternion.Identity();
+                    node.babylonMesh.scaling = BABYLON.Vector3.One();
                 }
                 if (node.camera != null) {
                     // TODO: handle cameras
@@ -2797,32 +2874,52 @@ var BABYLON;
                     }
                     ;
                 });
-                var multiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, this._babylonScene);
-                node.babylonMesh.material = multiMaterial;
-                var subMaterials = multiMaterial.subMaterials;
-                var _loop_1 = function (index) {
-                    var primitive = primitives[index];
+                if (primitives.length === 1) {
+                    var primitive = primitives[0];
                     if (primitive.material == null) {
-                        subMaterials[index] = this_1._getDefaultMaterial();
+                        node.babylonMesh.material = this._getDefaultMaterial();
                     }
                     else {
-                        var material = GLTFLoader._GetProperty(this_1._gltf.materials, primitive.material);
+                        var material = GLTFLoader._GetProperty(this._gltf.materials, primitive.material);
                         if (!material) {
                             throw new Error(context + ": Failed to find material " + primitive.material);
                         }
-                        this_1._loadMaterial("#/materials/" + material.index, material, function (babylonMaterial, isNew) {
+                        this._loadMaterial("#/materials/" + material.index, material, function (babylonMaterial, isNew) {
                             if (isNew && _this._parent.onMaterialLoaded) {
                                 _this._parent.onMaterialLoaded(babylonMaterial);
                             }
-                            subMaterials[index] = babylonMaterial;
+                            node.babylonMesh.material = babylonMaterial;
                         });
                     }
-                };
-                var this_1 = this;
-                for (var index = 0; index < primitives.length; index++) {
-                    _loop_1(index);
                 }
-                ;
+                else {
+                    var multiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, this._babylonScene);
+                    node.babylonMesh.material = multiMaterial;
+                    var subMaterials_1 = multiMaterial.subMaterials;
+                    var _loop_1 = function (index) {
+                        var primitive = primitives[index];
+                        if (primitive.material == null) {
+                            subMaterials_1[index] = this_1._getDefaultMaterial();
+                        }
+                        else {
+                            var material = GLTFLoader._GetProperty(this_1._gltf.materials, primitive.material);
+                            if (!material) {
+                                throw new Error(context + ": Failed to find material " + primitive.material);
+                            }
+                            this_1._loadMaterial("#/materials/" + material.index, material, function (babylonMaterial, isNew) {
+                                if (isNew && _this._parent.onMaterialLoaded) {
+                                    _this._parent.onMaterialLoaded(babylonMaterial);
+                                }
+                                subMaterials_1[index] = babylonMaterial;
+                            });
+                        }
+                    };
+                    var this_1 = this;
+                    for (var index = 0; index < primitives.length; index++) {
+                        _loop_1(index);
+                    }
+                    ;
+                }
             };
             GLTFLoader.prototype._loadAllVertexDataAsync = function (context, mesh, onSuccess) {
                 var primitives = mesh.primitives;
@@ -3142,12 +3239,17 @@ var BABYLON;
                 node.babylonMesh.rotationQuaternion = rotation;
                 node.babylonMesh.scaling = scaling;
             };
-            GLTFLoader.prototype._loadSkin = function (context, skin) {
+            GLTFLoader.prototype._loadSkinAsync = function (context, skin, onSuccess) {
                 var _this = this;
+                if (skin.babylonSkeleton) {
+                    onSuccess();
+                    return;
+                }
                 var skeletonId = "skeleton" + skin.index;
                 skin.babylonSkeleton = new BABYLON.Skeleton(skin.name || skeletonId, skeletonId, this._babylonScene);
                 if (skin.inverseBindMatrices == null) {
                     this._loadBones(context, skin, null);
+                    onSuccess();
                 }
                 else {
                     var accessor = GLTFLoader._GetProperty(this._gltf.accessors, skin.inverseBindMatrices);
@@ -3156,14 +3258,12 @@ var BABYLON;
                     }
                     this._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
                         _this._loadBones(context, skin, data);
+                        onSuccess();
                     });
                 }
-                return skin.babylonSkeleton;
             };
             GLTFLoader.prototype._createBone = function (node, skin, parent, localMatrix, baseMatrix, index) {
                 var babylonBone = new BABYLON.Bone(node.name || "bone" + node.index, skin.babylonSkeleton, parent, localMatrix, null, baseMatrix, index);
-                node.babylonBones = node.babylonBones || {};
-                node.babylonBones[skin.index] = babylonBone;
                 node.babylonAnimationTargets = node.babylonAnimationTargets || [];
                 node.babylonAnimationTargets.push(babylonBone);
                 return babylonBone;
@@ -3191,7 +3291,7 @@ var BABYLON;
                     baseMatrix.invertToRef(baseMatrix);
                 }
                 var babylonParentBone = null;
-                if (node.index !== skin.skeleton && node.parent && node.parent !== this._rootNode) {
+                if (node.parent !== this._rootNode) {
                     babylonParentBone = this._loadBone(node.parent, skin, inverseBindMatrixData, babylonBones);
                     baseMatrix.multiplyToRef(babylonParentBone.getInvertedAbsoluteTransform(), baseMatrix);
                 }
@@ -3205,7 +3305,6 @@ var BABYLON;
                     BABYLON.Matrix.Compose(node.scale ? BABYLON.Vector3.FromArray(node.scale) : BABYLON.Vector3.One(), node.rotation ? BABYLON.Quaternion.FromArray(node.rotation) : BABYLON.Quaternion.Identity(), node.translation ? BABYLON.Vector3.FromArray(node.translation) : BABYLON.Vector3.Zero());
             };
             GLTFLoader.prototype._traverseNodes = function (context, indices, action, parentNode) {
-                if (parentNode === void 0) { parentNode = null; }
                 for (var _i = 0, indices_1 = indices; _i < indices_1.length; _i++) {
                     var index = indices_1[_i];
                     var node = GLTFLoader._GetProperty(this._gltf.nodes, index);
@@ -3216,7 +3315,6 @@ var BABYLON;
                 }
             };
             GLTFLoader.prototype._traverseNode = function (context, node, action, parentNode) {
-                if (parentNode === void 0) { parentNode = null; }
                 if (GLTF2.GLTFLoaderExtension.TraverseNode(this, context, node, action, parentNode)) {
                     return;
                 }
@@ -3351,9 +3449,19 @@ var BABYLON;
                         }
                     }
                     ;
-                    var keys = new Array(inputData.length);
-                    for (var frameIndex = 0; frameIndex < inputData.length; frameIndex++) {
-                        keys[frameIndex] = getNextKey(frameIndex);
+                    var keys;
+                    if (inputData.length === 1) {
+                        var key = getNextKey(0);
+                        keys = [
+                            { frame: key.frame, value: key.value },
+                            { frame: key.frame + 1, value: key.value }
+                        ];
+                    }
+                    else {
+                        keys = new Array(inputData.length);
+                        for (var frameIndex = 0; frameIndex < inputData.length; frameIndex++) {
+                            keys[frameIndex] = getNextKey(frameIndex);
+                        }
                     }
                     if (targetPath === "influence") {
                         var morphTargetManager = targetNode.babylonMesh.morphTargetManager;
@@ -3895,10 +4003,6 @@ var BABYLON;
             };
             GLTFLoader.prototype._compileMaterialAsync = function (babylonMaterial, babylonMesh, onSuccess) {
                 var _this = this;
-                if (!this._parent.compileMaterials) {
-                    onSuccess();
-                    return;
-                }
                 if (this._parent.useClipPlane) {
                     babylonMaterial.forceCompilation(babylonMesh, function () {
                         babylonMaterial.forceCompilation(babylonMesh, function () {
@@ -3929,6 +4033,9 @@ var BABYLON;
                             }
                         }
                     }
+                    else if (mesh.material) {
+                        remaining++;
+                    }
                 }
                 if (remaining === 0) {
                     onSuccess();
@@ -3948,6 +4055,13 @@ var BABYLON;
                             }
                         }
                     }
+                    else if (mesh.material) {
+                        this._compileMaterialAsync(mesh.material, mesh, function () {
+                            if (--remaining === 0) {
+                                onSuccess();
+                            }
+                        });
+                    }
                 }
             };
             GLTFLoader.prototype._compileShadowGeneratorsAsync = function (onSuccess) {

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


+ 183 - 69
dist/preview release/loaders/babylonjs.loaders.js

@@ -977,27 +977,63 @@ var BABYLON;
 (function (BABYLON) {
     var GLTFLoaderCoordinateSystemMode;
     (function (GLTFLoaderCoordinateSystemMode) {
-        // Automatically convert the glTF right-handed data to the appropriate system based on the current coordinate system mode of the scene (scene.useRightHandedSystem).
-        // NOTE: When scene.useRightHandedSystem is false, an additional transform will be added to the root to transform the data from right-handed to left-handed.
+        /**
+         * Automatically convert the glTF right-handed data to the appropriate system based on the current coordinate system mode of the scene.
+         */
         GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["AUTO"] = 0] = "AUTO";
-        // The glTF right-handed data is not transformed in any form and is loaded directly.
-        GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["PASS_THROUGH"] = 1] = "PASS_THROUGH";
-        // Sets the useRightHandedSystem flag on the scene.
-        GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["FORCE_RIGHT_HANDED"] = 2] = "FORCE_RIGHT_HANDED";
+        /**
+         * Sets the useRightHandedSystem flag on the scene.
+         */
+        GLTFLoaderCoordinateSystemMode[GLTFLoaderCoordinateSystemMode["FORCE_RIGHT_HANDED"] = 1] = "FORCE_RIGHT_HANDED";
     })(GLTFLoaderCoordinateSystemMode = BABYLON.GLTFLoaderCoordinateSystemMode || (BABYLON.GLTFLoaderCoordinateSystemMode = {}));
+    var GLTFLoaderAnimationStartMode;
+    (function (GLTFLoaderAnimationStartMode) {
+        /**
+         * No animation will start.
+         */
+        GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["NONE"] = 0] = "NONE";
+        /**
+         * The first animation will start.
+         */
+        GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["FIRST"] = 1] = "FIRST";
+        /**
+         * All animations will start.
+         */
+        GLTFLoaderAnimationStartMode[GLTFLoaderAnimationStartMode["ALL"] = 2] = "ALL";
+    })(GLTFLoaderAnimationStartMode = BABYLON.GLTFLoaderAnimationStartMode || (BABYLON.GLTFLoaderAnimationStartMode = {}));
     var GLTFFileLoader = /** @class */ (function () {
         function GLTFFileLoader() {
-            // V2 options
+            // #endregion
+            // #region V2 options
+            /**
+             * The coordinate system mode (AUTO, FORCE_RIGHT_HANDED).
+             */
             this.coordinateSystemMode = GLTFLoaderCoordinateSystemMode.AUTO;
+            /**
+             * The animation start mode (NONE, FIRST, ALL).
+             */
+            this.animationStartMode = GLTFLoaderAnimationStartMode.FIRST;
+            /**
+             * Set to true to compile materials before raising the success callback.
+             */
             this.compileMaterials = false;
-            this.compileShadowGenerators = false;
+            /**
+             * Set to true to also compile materials with clip planes.
+             */
             this.useClipPlane = false;
+            /**
+             * Set to true to compile shadow generators before raising the success callback.
+             */
+            this.compileShadowGenerators = false;
             this.name = "gltf";
             this.extensions = {
                 ".gltf": { isBinary: false },
                 ".glb": { isBinary: true }
             };
         }
+        /**
+         * Disposes the loader, releases resources during load, and cancels any outstanding requests.
+         */
         GLTFFileLoader.prototype.dispose = function () {
             if (this._loader) {
                 this._loader.dispose();
@@ -1155,7 +1191,13 @@ var BABYLON;
             };
         };
         GLTFFileLoader._parseVersion = function (version) {
-            var match = (version + "").match(/^(\d+)\.(\d+)$/);
+            if (version === "1.0" || version === "1.0.1") {
+                return {
+                    major: 1,
+                    minor: 0
+                };
+            }
+            var match = (version + "").match(/^(\d+)\.(\d+)/);
             if (!match) {
                 return null;
             }
@@ -1183,9 +1225,10 @@ var BABYLON;
             }
             return result;
         };
-        // V1 options
-        GLTFFileLoader.HomogeneousCoordinates = false;
+        // #endregion
+        // #region V1 options
         GLTFFileLoader.IncrementalLoading = true;
+        GLTFFileLoader.HomogeneousCoordinates = false;
         return GLTFFileLoader;
     }());
     BABYLON.GLTFFileLoader = GLTFFileLoader;
@@ -1798,10 +1841,7 @@ var BABYLON;
             if (!node.babylonNode) {
                 return newMesh;
             }
-            var multiMat = new BABYLON.MultiMaterial("multimat" + id, gltfRuntime.scene);
-            if (!newMesh.material) {
-                newMesh.material = multiMat;
-            }
+            var subMaterials = [];
             var vertexData = new BABYLON.VertexData();
             var geometry = new BABYLON.Geometry(id, gltfRuntime.scene, vertexData, false, newMesh);
             var verticesStarts = new Array();
@@ -1889,13 +1929,27 @@ var BABYLON;
                     }
                     vertexData.merge(tempVertexData);
                     // Sub material
-                    var material = gltfRuntime.scene.getMaterialByID(primitive.material);
-                    multiMat.subMaterials.push(material === null ? GLTF1.GLTFUtils.GetDefaultMaterial(gltfRuntime.scene) : material);
+                    var material_1 = gltfRuntime.scene.getMaterialByID(primitive.material);
+                    subMaterials.push(material_1 === null ? GLTF1.GLTFUtils.GetDefaultMaterial(gltfRuntime.scene) : material_1);
                     // Update vertices start and index start
                     verticesStarts.push(verticesStarts.length === 0 ? 0 : verticesStarts[verticesStarts.length - 1] + verticesCounts[verticesCounts.length - 2]);
                     indexStarts.push(indexStarts.length === 0 ? 0 : indexStarts[indexStarts.length - 1] + indexCounts[indexCounts.length - 2]);
                 }
             }
+            var material;
+            if (subMaterials.length > 1) {
+                material = new BABYLON.MultiMaterial("multimat" + id, gltfRuntime.scene);
+                material.subMaterials = subMaterials;
+            }
+            else {
+                material = new BABYLON.StandardMaterial("multimat" + id, gltfRuntime.scene);
+            }
+            if (subMaterials.length === 1) {
+                material = subMaterials[0];
+            }
+            if (!newMesh.material) {
+                newMesh.material = material;
+            }
             // Apply geometry
             geometry.setAllVerticesData(vertexData, false);
             newMesh.computeWorldMatrix(true);
@@ -1966,7 +2020,7 @@ var BABYLON;
                     var skin = gltfRuntime.skins[node.skin];
                     var newMesh = importMesh(gltfRuntime, node, node.meshes, id, node.babylonNode);
                     newMesh.skeleton = gltfRuntime.scene.getLastSkeletonByID(node.skin);
-                    if (newMesh.skeleton === null && skin.babylonSkeleton) {
+                    if (newMesh.skeleton === null) {
                         newMesh.skeleton = importSkeleton(gltfRuntime, skin, newMesh, skin.babylonSkeleton, node.skin);
                         if (!skin.babylonSkeleton) {
                             skin.babylonSkeleton = newMesh.skeleton;
@@ -3602,21 +3656,38 @@ var BABYLON;
                 }
                 return skeletons;
             };
-            GLTFLoader.prototype._getAnimationTargets = function () {
-                var targets = new Array();
+            GLTFLoader.prototype._startAnimations = function () {
                 var animations = this._gltf.animations;
-                if (animations) {
-                    for (var _i = 0, animations_1 = animations; _i < animations_1.length; _i++) {
-                        var animation = animations_1[_i];
-                        targets.push.apply(targets, animation.targets);
-                    }
+                if (!animations) {
+                    return;
                 }
-                return targets;
-            };
-            GLTFLoader.prototype._startAnimations = function () {
-                for (var _i = 0, _a = this._getAnimationTargets(); _i < _a.length; _i++) {
-                    var target = _a[_i];
-                    this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
+                switch (this._parent.animationStartMode) {
+                    case BABYLON.GLTFLoaderAnimationStartMode.NONE: {
+                        // do nothing
+                        break;
+                    }
+                    case BABYLON.GLTFLoaderAnimationStartMode.FIRST: {
+                        var animation = animations[0];
+                        for (var _i = 0, _a = animation.targets; _i < _a.length; _i++) {
+                            var target = _a[_i];
+                            this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
+                        }
+                        break;
+                    }
+                    case BABYLON.GLTFLoaderAnimationStartMode.ALL: {
+                        for (var _b = 0, animations_1 = animations; _b < animations_1.length; _b++) {
+                            var animation = animations_1[_b];
+                            for (var _c = 0, _d = animation.targets; _c < _d.length; _c++) {
+                                var target = _d[_c];
+                                this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
+                            }
+                        }
+                        break;
+                    }
+                    default: {
+                        BABYLON.Tools.Error("Invalid animation start mode " + this._parent.animationStartMode);
+                        return;
+                    }
                 }
             };
             GLTFLoader.prototype._loadDefaultScene = function (nodeNames) {
@@ -3627,19 +3698,17 @@ var BABYLON;
                 this._loadScene("#/scenes/" + scene.index, scene, nodeNames);
             };
             GLTFLoader.prototype._loadScene = function (context, scene, nodeNames) {
+                var _this = this;
                 this._rootNode = { babylonMesh: new BABYLON.Mesh("__root__", this._babylonScene) };
                 switch (this._parent.coordinateSystemMode) {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO: {
                         if (!this._babylonScene.useRightHandedSystem) {
-                            this._rootNode.babylonMesh.rotation = new BABYLON.Vector3(0, Math.PI, 0);
-                            this._rootNode.babylonMesh.scaling = new BABYLON.Vector3(1, 1, -1);
+                            this._rootNode.rotation = [0, 1, 0, 0];
+                            this._rootNode.scale = [1, 1, -1];
+                            this._loadTransform(this._rootNode);
                         }
                         break;
                     }
-                    case BABYLON.GLTFLoaderCoordinateSystemMode.PASS_THROUGH: {
-                        // do nothing
-                        break;
-                    }
                     case BABYLON.GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED: {
                         this._babylonScene.useRightHandedSystem = true;
                         break;
@@ -3665,6 +3734,7 @@ var BABYLON;
                     this._traverseNodes(context, nodeIndices, function (node) {
                         if (nodeNames.indexOf(node.name) !== -1) {
                             filteredNodeIndices_1.push(node.index);
+                            node.parent = _this._rootNode;
                             return false;
                         }
                         return true;
@@ -3696,15 +3766,22 @@ var BABYLON;
                     }
                     this._loadMesh("#/meshes/" + node.mesh, node, mesh);
                 }
-                node.babylonMesh.parent = node.parent ? node.parent.babylonMesh : null;
+                node.babylonMesh.parent = node.parent.babylonMesh;
                 node.babylonAnimationTargets = node.babylonAnimationTargets || [];
                 node.babylonAnimationTargets.push(node.babylonMesh);
                 if (node.skin != null) {
-                    var skin = GLTFLoader._GetProperty(this._gltf.skins, node.skin);
-                    if (!skin) {
+                    var skin_1 = GLTFLoader._GetProperty(this._gltf.skins, node.skin);
+                    if (!skin_1) {
                         throw new Error(context + ": Failed to find skin " + node.skin);
                     }
-                    node.babylonMesh.skeleton = this._loadSkin("#/skins/" + node.skin, skin);
+                    this._loadSkinAsync("#/skins/" + node.skin, skin_1, function () {
+                        node.babylonMesh.skeleton = skin_1.babylonSkeleton;
+                        node.babylonMesh._refreshBoundingInfo(true);
+                    });
+                    node.babylonMesh.parent = this._rootNode.babylonMesh;
+                    node.babylonMesh.position = BABYLON.Vector3.Zero();
+                    node.babylonMesh.rotationQuaternion = BABYLON.Quaternion.Identity();
+                    node.babylonMesh.scaling = BABYLON.Vector3.One();
                 }
                 if (node.camera != null) {
                     // TODO: handle cameras
@@ -3753,32 +3830,52 @@ var BABYLON;
                     }
                     ;
                 });
-                var multiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, this._babylonScene);
-                node.babylonMesh.material = multiMaterial;
-                var subMaterials = multiMaterial.subMaterials;
-                var _loop_1 = function (index) {
-                    var primitive = primitives[index];
+                if (primitives.length === 1) {
+                    var primitive = primitives[0];
                     if (primitive.material == null) {
-                        subMaterials[index] = this_1._getDefaultMaterial();
+                        node.babylonMesh.material = this._getDefaultMaterial();
                     }
                     else {
-                        var material = GLTFLoader._GetProperty(this_1._gltf.materials, primitive.material);
+                        var material = GLTFLoader._GetProperty(this._gltf.materials, primitive.material);
                         if (!material) {
                             throw new Error(context + ": Failed to find material " + primitive.material);
                         }
-                        this_1._loadMaterial("#/materials/" + material.index, material, function (babylonMaterial, isNew) {
+                        this._loadMaterial("#/materials/" + material.index, material, function (babylonMaterial, isNew) {
                             if (isNew && _this._parent.onMaterialLoaded) {
                                 _this._parent.onMaterialLoaded(babylonMaterial);
                             }
-                            subMaterials[index] = babylonMaterial;
+                            node.babylonMesh.material = babylonMaterial;
                         });
                     }
-                };
-                var this_1 = this;
-                for (var index = 0; index < primitives.length; index++) {
-                    _loop_1(index);
                 }
-                ;
+                else {
+                    var multiMaterial = new BABYLON.MultiMaterial(node.babylonMesh.name, this._babylonScene);
+                    node.babylonMesh.material = multiMaterial;
+                    var subMaterials_1 = multiMaterial.subMaterials;
+                    var _loop_1 = function (index) {
+                        var primitive = primitives[index];
+                        if (primitive.material == null) {
+                            subMaterials_1[index] = this_1._getDefaultMaterial();
+                        }
+                        else {
+                            var material = GLTFLoader._GetProperty(this_1._gltf.materials, primitive.material);
+                            if (!material) {
+                                throw new Error(context + ": Failed to find material " + primitive.material);
+                            }
+                            this_1._loadMaterial("#/materials/" + material.index, material, function (babylonMaterial, isNew) {
+                                if (isNew && _this._parent.onMaterialLoaded) {
+                                    _this._parent.onMaterialLoaded(babylonMaterial);
+                                }
+                                subMaterials_1[index] = babylonMaterial;
+                            });
+                        }
+                    };
+                    var this_1 = this;
+                    for (var index = 0; index < primitives.length; index++) {
+                        _loop_1(index);
+                    }
+                    ;
+                }
             };
             GLTFLoader.prototype._loadAllVertexDataAsync = function (context, mesh, onSuccess) {
                 var primitives = mesh.primitives;
@@ -4098,12 +4195,17 @@ var BABYLON;
                 node.babylonMesh.rotationQuaternion = rotation;
                 node.babylonMesh.scaling = scaling;
             };
-            GLTFLoader.prototype._loadSkin = function (context, skin) {
+            GLTFLoader.prototype._loadSkinAsync = function (context, skin, onSuccess) {
                 var _this = this;
+                if (skin.babylonSkeleton) {
+                    onSuccess();
+                    return;
+                }
                 var skeletonId = "skeleton" + skin.index;
                 skin.babylonSkeleton = new BABYLON.Skeleton(skin.name || skeletonId, skeletonId, this._babylonScene);
                 if (skin.inverseBindMatrices == null) {
                     this._loadBones(context, skin, null);
+                    onSuccess();
                 }
                 else {
                     var accessor = GLTFLoader._GetProperty(this._gltf.accessors, skin.inverseBindMatrices);
@@ -4112,14 +4214,12 @@ var BABYLON;
                     }
                     this._loadAccessorAsync("#/accessors/" + accessor.index, accessor, function (data) {
                         _this._loadBones(context, skin, data);
+                        onSuccess();
                     });
                 }
-                return skin.babylonSkeleton;
             };
             GLTFLoader.prototype._createBone = function (node, skin, parent, localMatrix, baseMatrix, index) {
                 var babylonBone = new BABYLON.Bone(node.name || "bone" + node.index, skin.babylonSkeleton, parent, localMatrix, null, baseMatrix, index);
-                node.babylonBones = node.babylonBones || {};
-                node.babylonBones[skin.index] = babylonBone;
                 node.babylonAnimationTargets = node.babylonAnimationTargets || [];
                 node.babylonAnimationTargets.push(babylonBone);
                 return babylonBone;
@@ -4147,7 +4247,7 @@ var BABYLON;
                     baseMatrix.invertToRef(baseMatrix);
                 }
                 var babylonParentBone = null;
-                if (node.index !== skin.skeleton && node.parent && node.parent !== this._rootNode) {
+                if (node.parent !== this._rootNode) {
                     babylonParentBone = this._loadBone(node.parent, skin, inverseBindMatrixData, babylonBones);
                     baseMatrix.multiplyToRef(babylonParentBone.getInvertedAbsoluteTransform(), baseMatrix);
                 }
@@ -4161,7 +4261,6 @@ var BABYLON;
                     BABYLON.Matrix.Compose(node.scale ? BABYLON.Vector3.FromArray(node.scale) : BABYLON.Vector3.One(), node.rotation ? BABYLON.Quaternion.FromArray(node.rotation) : BABYLON.Quaternion.Identity(), node.translation ? BABYLON.Vector3.FromArray(node.translation) : BABYLON.Vector3.Zero());
             };
             GLTFLoader.prototype._traverseNodes = function (context, indices, action, parentNode) {
-                if (parentNode === void 0) { parentNode = null; }
                 for (var _i = 0, indices_1 = indices; _i < indices_1.length; _i++) {
                     var index = indices_1[_i];
                     var node = GLTFLoader._GetProperty(this._gltf.nodes, index);
@@ -4172,7 +4271,6 @@ var BABYLON;
                 }
             };
             GLTFLoader.prototype._traverseNode = function (context, node, action, parentNode) {
-                if (parentNode === void 0) { parentNode = null; }
                 if (GLTF2.GLTFLoaderExtension.TraverseNode(this, context, node, action, parentNode)) {
                     return;
                 }
@@ -4307,9 +4405,19 @@ var BABYLON;
                         }
                     }
                     ;
-                    var keys = new Array(inputData.length);
-                    for (var frameIndex = 0; frameIndex < inputData.length; frameIndex++) {
-                        keys[frameIndex] = getNextKey(frameIndex);
+                    var keys;
+                    if (inputData.length === 1) {
+                        var key = getNextKey(0);
+                        keys = [
+                            { frame: key.frame, value: key.value },
+                            { frame: key.frame + 1, value: key.value }
+                        ];
+                    }
+                    else {
+                        keys = new Array(inputData.length);
+                        for (var frameIndex = 0; frameIndex < inputData.length; frameIndex++) {
+                            keys[frameIndex] = getNextKey(frameIndex);
+                        }
                     }
                     if (targetPath === "influence") {
                         var morphTargetManager = targetNode.babylonMesh.morphTargetManager;
@@ -4851,10 +4959,6 @@ var BABYLON;
             };
             GLTFLoader.prototype._compileMaterialAsync = function (babylonMaterial, babylonMesh, onSuccess) {
                 var _this = this;
-                if (!this._parent.compileMaterials) {
-                    onSuccess();
-                    return;
-                }
                 if (this._parent.useClipPlane) {
                     babylonMaterial.forceCompilation(babylonMesh, function () {
                         babylonMaterial.forceCompilation(babylonMesh, function () {
@@ -4885,6 +4989,9 @@ var BABYLON;
                             }
                         }
                     }
+                    else if (mesh.material) {
+                        remaining++;
+                    }
                 }
                 if (remaining === 0) {
                     onSuccess();
@@ -4904,6 +5011,13 @@ var BABYLON;
                             }
                         }
                     }
+                    else if (mesh.material) {
+                        this._compileMaterialAsync(mesh.material, mesh, function () {
+                            if (--remaining === 0) {
+                                onSuccess();
+                            }
+                        });
+                    }
                 }
             };
             GLTFLoader.prototype._compileShadowGeneratorsAsync = function (onSuccess) {

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


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

@@ -99,9 +99,28 @@ declare module BABYLON {
 
 declare module BABYLON {
     enum GLTFLoaderCoordinateSystemMode {
+        /**
+         * Automatically convert the glTF right-handed data to the appropriate system based on the current coordinate system mode of the scene.
+         */
         AUTO = 0,
-        PASS_THROUGH = 1,
-        FORCE_RIGHT_HANDED = 2,
+        /**
+         * Sets the useRightHandedSystem flag on the scene.
+         */
+        FORCE_RIGHT_HANDED = 1,
+    }
+    enum GLTFLoaderAnimationStartMode {
+        /**
+         * No animation will start.
+         */
+        NONE = 0,
+        /**
+         * The first animation will start.
+         */
+        FIRST = 1,
+        /**
+         * All animations will start.
+         */
+        ALL = 2,
     }
     interface IGLTFLoaderData {
         json: Object;
@@ -114,25 +133,58 @@ declare module BABYLON {
     class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
+        /**
+         * Raised when the asset has been parsed.
+         * The data.json property stores the glTF JSON.
+         * The data.bin property stores the BIN chunk from a glTF binary or null if the input is not a glTF binary.
+         */
         onParsed: (data: IGLTFLoaderData) => void;
-        static HomogeneousCoordinates: boolean;
         static IncrementalLoading: boolean;
+        static HomogeneousCoordinates: boolean;
+        /**
+         * The coordinate system mode (AUTO, FORCE_RIGHT_HANDED).
+         */
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
+        /**
+         * The animation start mode (NONE, FIRST, ALL).
+         */
+        animationStartMode: GLTFLoaderAnimationStartMode;
+        /**
+         * Set to true to compile materials before raising the success callback.
+         */
         compileMaterials: boolean;
-        compileShadowGenerators: boolean;
+        /**
+         * Set to true to also compile materials with clip planes.
+         */
         useClipPlane: boolean;
+        /**
+         * Set to true to compile shadow generators before raising the success callback.
+         */
+        compileShadowGenerators: boolean;
+        /**
+         * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
+         */
         onMeshLoaded: (mesh: AbstractMesh) => void;
+        /**
+         * Raised when the loader creates a texture after parsing the glTF properties of the texture.
+         */
         onTextureLoaded: (texture: BaseTexture) => void;
+        /**
+         * Raised when the loader creates a material after parsing the glTF properties of the material.
+         */
         onMaterialLoaded: (material: Material) => void;
         /**
-         * Raised when the asset is completely loaded, just before the loader is disposed.
+         * 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 just after onSuccess.
+         * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          */
         onComplete: () => void;
         private _loader;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
+        /**
+         * Disposes the loader, releases resources during load, and cancels any outstanding requests.
+         */
         dispose(): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
@@ -890,11 +942,8 @@ declare module BABYLON.GLTF2 {
         translation?: number[];
         weights?: number[];
         index: number;
-        parent?: IGLTFNode;
+        parent: IGLTFNode;
         babylonMesh: Mesh;
-        babylonBones?: {
-            [skin: number]: Bone;
-        };
         babylonAnimationTargets?: Node[];
     }
     interface IGLTFSampler extends IGLTFChildRootProperty {
@@ -984,7 +1033,6 @@ declare module BABYLON.GLTF2 {
         private _loadData(data);
         private _getMeshes();
         private _getSkeletons();
-        private _getAnimationTargets();
         private _startAnimations();
         private _loadDefaultScene(nodeNames);
         private _loadScene(context, scene, nodeNames);
@@ -1009,13 +1057,13 @@ declare module BABYLON.GLTF2 {
         private _loadAllMorphTargetVertexDataAsync(context, node, mesh, onSuccess);
         private _loadMorphTargetVertexDataAsync(context, vertexData, attributes, onSuccess);
         private _loadTransform(node);
-        private _loadSkin(context, skin);
+        private _loadSkinAsync(context, skin, onSuccess);
         private _createBone(node, skin, parent, localMatrix, baseMatrix, index);
         private _loadBones(context, skin, inverseBindMatrixData);
         private _loadBone(node, skin, inverseBindMatrixData, babylonBones);
         private _getNodeMatrix(node);
-        private _traverseNodes(context, indices, action, parentNode?);
-        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: Nullable<IGLTFNode>) => boolean, parentNode?: Nullable<IGLTFNode>): void;
+        private _traverseNodes(context, indices, action, parentNode);
+        _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): void;
         private _loadAnimations();
         private _loadAnimation(context, animation);
         private _loadAnimationChannel(animation, channelContext, channel, samplerContext, sampler);
@@ -1074,12 +1122,12 @@ declare module BABYLON.GLTF2 {
     abstract class GLTFLoaderExtension {
         enabled: boolean;
         readonly abstract name: string;
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: Nullable<IGLTFNode>): boolean;
+        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
         protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
         protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean;
         static _Extensions: GLTFLoaderExtension[];
-        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: Nullable<IGLTFNode>): boolean;
+        static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean;
         static LoadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean;
         static LoadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private static _ApplyExtensions(action);

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

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

+ 3 - 2
dist/preview release/materialsLibrary/babylon.waterMaterial.d.ts

@@ -75,13 +75,14 @@ declare module BABYLON {
         private _lastDeltaTime;
         private _renderId;
         private _useLogarithmicDepth;
+        private _waitingRenderList;
         /**
         * Constructor
         */
         constructor(name: string, scene: Scene, renderTargetSize?: Vector2);
         useLogarithmicDepth: boolean;
-        readonly refractionTexture: RenderTargetTexture;
-        readonly reflectionTexture: RenderTargetTexture;
+        readonly refractionTexture: Nullable<RenderTargetTexture>;
+        readonly reflectionTexture: Nullable<RenderTargetTexture>;
         addToRenderList(node: any): void;
         enableRenderTargets(enable: boolean): void;
         getRenderList(): Nullable<AbstractMesh[]>;

+ 26 - 9
dist/preview release/materialsLibrary/babylon.waterMaterial.js

@@ -158,24 +158,28 @@ var BABYLON;
         });
         // Methods
         WaterMaterial.prototype.addToRenderList = function (node) {
-            if (this._refractionRTT.renderList) {
+            if (this._refractionRTT && this._refractionRTT.renderList) {
                 this._refractionRTT.renderList.push(node);
             }
-            if (this._reflectionRTT.renderList) {
+            if (this._reflectionRTT && this._reflectionRTT.renderList) {
                 this._reflectionRTT.renderList.push(node);
             }
         };
         WaterMaterial.prototype.enableRenderTargets = function (enable) {
             var refreshRate = enable ? 1 : 0;
-            this._refractionRTT.refreshRate = refreshRate;
-            this._reflectionRTT.refreshRate = refreshRate;
+            if (this._refractionRTT) {
+                this._refractionRTT.refreshRate = refreshRate;
+            }
+            if (this._reflectionRTT) {
+                this._reflectionRTT.refreshRate = refreshRate;
+            }
         };
         WaterMaterial.prototype.getRenderList = function () {
-            return this._refractionRTT.renderList;
+            return this._refractionRTT ? this._refractionRTT.renderList : [];
         };
         Object.defineProperty(WaterMaterial.prototype, "renderTargetsEnabled", {
             get: function () {
-                return !(this._refractionRTT.refreshRate === 0);
+                return !(this._refractionRTT && this._refractionRTT.refreshRate === 0);
             },
             enumerable: true,
             configurable: true
@@ -241,7 +245,14 @@ var BABYLON;
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, true, this._maxSimultaneousLights, this._disableLighting);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
+            // Configure this
             this._mesh = mesh;
+            if (this._waitingRenderList) {
+                for (var i = 0; i < this._waitingRenderList.length; i++) {
+                    this.addToRenderList(scene.getNodeByID(this._waitingRenderList[i]));
+                }
+                this._waitingRenderList = null;
+            }
             // Get correct effect      
             if (defines.isDirty) {
                 defines.markAsProcessed();
@@ -508,8 +519,12 @@ var BABYLON;
         WaterMaterial.prototype.serialize = function () {
             var serializationObject = BABYLON.SerializationHelper.Serialize(this);
             serializationObject.customType = "BABYLON.WaterMaterial";
-            serializationObject.reflectionTexture.isRenderTarget = true;
-            serializationObject.refractionTexture.isRenderTarget = true;
+            serializationObject.renderList = [];
+            if (this._refractionRTT && this._refractionRTT.renderList) {
+                for (var i = 0; i < this._refractionRTT.renderList.length; i++) {
+                    serializationObject.renderList.push(this._refractionRTT.renderList[i].id);
+                }
+            }
             return serializationObject;
         };
         WaterMaterial.prototype.getClassName = function () {
@@ -517,7 +532,9 @@ var BABYLON;
         };
         // Statics
         WaterMaterial.Parse = function (source, scene, rootUrl) {
-            return BABYLON.SerializationHelper.Parse(function () { return new WaterMaterial(source.name, scene); }, source, scene, rootUrl);
+            var mat = BABYLON.SerializationHelper.Parse(function () { return new WaterMaterial(source.name, scene); }, source, scene, rootUrl);
+            mat._waitingRenderList = source.renderList;
+            return mat;
         };
         WaterMaterial.CreateDefaultMesh = function (name, scene) {
             var mesh = BABYLON.Mesh.CreateGround(name, 512, 512, 32, scene, false);

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


+ 26 - 9
dist/preview release/materialsLibrary/babylonjs.materials.js

@@ -1572,24 +1572,28 @@ var BABYLON;
         });
         // Methods
         WaterMaterial.prototype.addToRenderList = function (node) {
-            if (this._refractionRTT.renderList) {
+            if (this._refractionRTT && this._refractionRTT.renderList) {
                 this._refractionRTT.renderList.push(node);
             }
-            if (this._reflectionRTT.renderList) {
+            if (this._reflectionRTT && this._reflectionRTT.renderList) {
                 this._reflectionRTT.renderList.push(node);
             }
         };
         WaterMaterial.prototype.enableRenderTargets = function (enable) {
             var refreshRate = enable ? 1 : 0;
-            this._refractionRTT.refreshRate = refreshRate;
-            this._reflectionRTT.refreshRate = refreshRate;
+            if (this._refractionRTT) {
+                this._refractionRTT.refreshRate = refreshRate;
+            }
+            if (this._reflectionRTT) {
+                this._reflectionRTT.refreshRate = refreshRate;
+            }
         };
         WaterMaterial.prototype.getRenderList = function () {
-            return this._refractionRTT.renderList;
+            return this._refractionRTT ? this._refractionRTT.renderList : [];
         };
         Object.defineProperty(WaterMaterial.prototype, "renderTargetsEnabled", {
             get: function () {
-                return !(this._refractionRTT.refreshRate === 0);
+                return !(this._refractionRTT && this._refractionRTT.refreshRate === 0);
             },
             enumerable: true,
             configurable: true
@@ -1655,7 +1659,14 @@ var BABYLON;
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, true, this._maxSimultaneousLights, this._disableLighting);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
+            // Configure this
             this._mesh = mesh;
+            if (this._waitingRenderList) {
+                for (var i = 0; i < this._waitingRenderList.length; i++) {
+                    this.addToRenderList(scene.getNodeByID(this._waitingRenderList[i]));
+                }
+                this._waitingRenderList = null;
+            }
             // Get correct effect      
             if (defines.isDirty) {
                 defines.markAsProcessed();
@@ -1922,8 +1933,12 @@ var BABYLON;
         WaterMaterial.prototype.serialize = function () {
             var serializationObject = BABYLON.SerializationHelper.Serialize(this);
             serializationObject.customType = "BABYLON.WaterMaterial";
-            serializationObject.reflectionTexture.isRenderTarget = true;
-            serializationObject.refractionTexture.isRenderTarget = true;
+            serializationObject.renderList = [];
+            if (this._refractionRTT && this._refractionRTT.renderList) {
+                for (var i = 0; i < this._refractionRTT.renderList.length; i++) {
+                    serializationObject.renderList.push(this._refractionRTT.renderList[i].id);
+                }
+            }
             return serializationObject;
         };
         WaterMaterial.prototype.getClassName = function () {
@@ -1931,7 +1946,9 @@ var BABYLON;
         };
         // Statics
         WaterMaterial.Parse = function (source, scene, rootUrl) {
-            return BABYLON.SerializationHelper.Parse(function () { return new WaterMaterial(source.name, scene); }, source, scene, rootUrl);
+            var mat = BABYLON.SerializationHelper.Parse(function () { return new WaterMaterial(source.name, scene); }, source, scene, rootUrl);
+            mat._waitingRenderList = source.renderList;
+            return mat;
         };
         WaterMaterial.CreateDefaultMesh = function (name, scene) {
             var mesh = BABYLON.Mesh.CreateGround(name, 512, 512, 32, scene, false);

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylonjs.materials.min.js


+ 3 - 2
dist/preview release/materialsLibrary/babylonjs.materials.module.d.ts

@@ -220,13 +220,14 @@ declare module BABYLON {
         private _lastDeltaTime;
         private _renderId;
         private _useLogarithmicDepth;
+        private _waitingRenderList;
         /**
         * Constructor
         */
         constructor(name: string, scene: Scene, renderTargetSize?: Vector2);
         useLogarithmicDepth: boolean;
-        readonly refractionTexture: RenderTargetTexture;
-        readonly reflectionTexture: RenderTargetTexture;
+        readonly refractionTexture: Nullable<RenderTargetTexture>;
+        readonly reflectionTexture: Nullable<RenderTargetTexture>;
         addToRenderList(node: any): void;
         enableRenderTargets(enable: boolean): void;
         getRenderList(): Nullable<AbstractMesh[]>;

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

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

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

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

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

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

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

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

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


+ 32 - 0
dist/preview release/viewer/package.json

@@ -0,0 +1,32 @@
+{
+    "author": {
+        "name": "Raanan Weber"
+    },
+    "name": "babylonjs-viewer",
+    "description": "A simple-to-use viewer based on BabylonJS to display 3D elements natively",
+    "version": "3.1.0-rc-0",
+    "repository": {
+        "type": "git",
+        "url": "https://github.com/BabylonJS/Babylon.js.git"
+    },
+    "main": "babylon.viewer.js",
+    "files": [
+        "babylon.viewer.js",
+        "readme.md",
+        "package.json"
+    ],
+    "keywords": [
+        "3D",
+        "javascript",
+        "html5",
+        "webgl",
+        "viewer"
+    ],
+    "license": "Apache-2.0",
+    "peerDependencies": {
+        "babylonjs": ">=3.1.0-alpha"
+    },
+    "engines": {
+        "node": "*"
+    }
+}

+ 56 - 0
dist/preview release/viewer/readme.md

@@ -0,0 +1,56 @@
+Babylon.js Viewer
+=====================
+
+Babylon's viewer is a wrapper around Babylon, that automatically initializes the needed components in order to display a loaded model. It is easy to use, and require no coding at all.
+
+The viewer automatically interacts with the DOM, searching for HTML elements named `babylon`. It will then automatically read the configuration from the DOM element and will create a scene for it.
+
+for basic and advanced usage instructions please read the doc at https://doc.babylonjs.com/extensions/the_babylon_viewer
+
+The source code can be found at https://github.com/BabylonJS/Babylon.js/tree/master/Viewer
+
+# Basic usage
+
+to create a simple viewer add the following code to your HTML>
+
+```HTML
+<babylon model="https://playground.babylonjs.com/scenes/Rabbit.babylon"></babylon>
+<script src="https://viewer.babylonjs.com/viewer.min.js"></script>
+```
+
+Make sure to size the babylon HTML tag. For example:
+
+```css
+babylon {
+    max-width: 800px;
+    max-height: 500px;
+    width: 100%;
+    height: 600px;
+}
+```
+
+# Installation instructions
+
+## CDN
+
+Compiled js files (minified) are offered on our public CDN here:
+
+* https://viewer.babylonjs.com/serializers/viewer.min.js
+
+## NPM
+
+To install using npm :
+
+```
+npm install --save babylonjs-viewer
+```
+
+Afterwards it can be imported to the project using:
+
+```
+import from 'babylonjs-viewer';
+```
+
+This will enable the BabylonViewer namespace.
+
+Using webpack to package your project will use the minified js file.

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

@@ -1,6 +1,7 @@
 # 3.1.0:
 
 ## Major updates
+- Added VRExperienceHelper to create WebVR experience with 2 lines of code. [Doc here](http://doc.babylonjs.com/how_to/webvr_helper) ([davrous](https://github.com/davrous), [TrevorDev](https://github.com/TrevorDev))
 - Viewer (TODO)
 - Added BackgroundMaterial [Doc here](https://doc.babylonjs.com/how_to/backgroundmaterial)
 - Added EnvironmentHelper [Doc here](https://doc.babylonjs.com/babylon101/environment#skybox-and-ground)

+ 2 - 0
gui/src/advancedDynamicTexture.ts

@@ -327,6 +327,8 @@ module BABYLON.GUI {
                         continue;
                     }
                     control.notRenderable = false;
+                    // Account for RenderScale.
+                    projectedPosition.scaleInPlace(this.renderScale);
                     control._moveToProjectedPosition(projectedPosition);
                 }
             }

+ 133 - 133
gui/src/controls/control.ts

@@ -1,9 +1,9 @@
 /// <reference path="../../../dist/preview release/babylon.d.ts"/>
 
 module BABYLON.GUI {
-    export class Control {       
-        private _alpha = 1; 
-        private _alphaSet = false; 
+    export class Control {
+        private _alpha = 1;
+        private _alphaSet = false;
         private _zIndex = 0;
         public _root: Nullable<Container>;
         public _host: AdvancedDynamicTexture;
@@ -15,7 +15,7 @@ module BABYLON.GUI {
         private _font: string;
         public _width = new ValueAndUnit(1, ValueAndUnit.UNITMODE_PERCENTAGE, false);
         public _height = new ValueAndUnit(1, ValueAndUnit.UNITMODE_PERCENTAGE, false);
-        protected _fontOffset: {ascent: number, height: number, descent: number};
+        protected _fontOffset: { ascent: number, height: number, descent: number };
         private _color = "";
         protected _horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
         protected _verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
@@ -24,7 +24,7 @@ module BABYLON.GUI {
         private _paddingLeft = new ValueAndUnit(0);
         private _paddingRight = new ValueAndUnit(0);
         private _paddingTop = new ValueAndUnit(0);
-        private _paddingBottom = new ValueAndUnit(0);        
+        private _paddingBottom = new ValueAndUnit(0);
         public _left = new ValueAndUnit(0);
         public _top = new ValueAndUnit(0);
         private _scaleX = 1.0;
@@ -33,8 +33,8 @@ module BABYLON.GUI {
         private _transformCenterX = 0.5;
         private _transformCenterY = 0.5;
         private _transformMatrix = Matrix2D.Identity();
-        private _invertTransformMatrix = Matrix2D.Identity();
-        private _transformedPosition = Vector2.Zero();
+        protected _invertTransformMatrix = Matrix2D.Identity();
+        protected _transformedPosition = Vector2.Zero();
         private _isMatrixDirty = true;
         private _cachedOffsetX: number;
         private _cachedOffsetY: number;
@@ -49,15 +49,15 @@ module BABYLON.GUI {
         public isHitTestVisible = true;
         public isPointerBlocker = false;
         public isFocusInvisible = false;
- 
+
         public shadowOffsetX = 0;
         public shadowOffsetY = 0;
         public shadowBlur = 0;
-        public shadowColor = '#000'; 
+        public shadowColor = '#000';
 
         protected _linkOffsetX = new ValueAndUnit(0);
         protected _linkOffsetY = new ValueAndUnit(0);
-        
+
         // Properties
 
         public get typeName(): string {
@@ -74,37 +74,37 @@ module BABYLON.GUI {
         * An event triggered when the pointer move out of the control.
         * @type {BABYLON.Observable}
         */
-        public onPointerOutObservable = new Observable<Control>();        
+        public onPointerOutObservable = new Observable<Control>();
 
         /**
         * An event triggered when the pointer taps the control
         * @type {BABYLON.Observable}
         */
-        public onPointerDownObservable = new Observable<Vector2WithInfo>();     
+        public onPointerDownObservable = new Observable<Vector2WithInfo>();
 
         /**
         * An event triggered when pointer up
         * @type {BABYLON.Observable}
         */
-        public onPointerUpObservable = new Observable<Vector2WithInfo>();     
+        public onPointerUpObservable = new Observable<Vector2WithInfo>();
 
         /**
         * An event triggered when pointer enters the control
         * @type {BABYLON.Observable}
         */
-        public onPointerEnterObservable = new Observable<Control>();    
+        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>();    
+        public onDirtyObservable = new Observable<Control>();
+
+        /**
+       * An event triggered after the control is drawn
+       * @type {BABYLON.Observable}
+       */
+        public onAfterDrawObservable = new Observable<Control>();
 
         public get alpha(): number {
             return this._alpha;
@@ -117,7 +117,7 @@ module BABYLON.GUI {
             this._alphaSet = true;
             this._alpha = value;
             this._markAsDirty();
-        }                 
+        }
 
         public get scaleX(): number {
             return this._scaleX;
@@ -131,7 +131,7 @@ module BABYLON.GUI {
             this._scaleX = value;
             this._markAsDirty();
             this._markMatrixAsDirty();
-        }     
+        }
 
         public get scaleY(): number {
             return this._scaleY;
@@ -145,7 +145,7 @@ module BABYLON.GUI {
             this._scaleY = value;
             this._markAsDirty();
             this._markMatrixAsDirty();
-        }  
+        }
 
         public get rotation(): number {
             return this._rotation;
@@ -159,7 +159,7 @@ module BABYLON.GUI {
             this._rotation = value;
             this._markAsDirty();
             this._markMatrixAsDirty();
-        }    
+        }
 
         public get transformCenterY(): number {
             return this._transformCenterY;
@@ -173,7 +173,7 @@ module BABYLON.GUI {
             this._transformCenterY = value;
             this._markAsDirty();
             this._markMatrixAsDirty();
-        }     
+        }
 
         public get transformCenterX(): number {
             return this._transformCenterX;
@@ -187,7 +187,7 @@ module BABYLON.GUI {
             this._transformCenterX = value;
             this._markAsDirty();
             this._markMatrixAsDirty();
-        }    
+        }
 
         public get horizontalAlignment(): number {
             return this._horizontalAlignment;
@@ -200,7 +200,7 @@ module BABYLON.GUI {
 
             this._horizontalAlignment = value;
             this._markAsDirty();
-        } 
+        }
 
         public get verticalAlignment(): number {
             return this._verticalAlignment;
@@ -213,17 +213,17 @@ module BABYLON.GUI {
 
             this._verticalAlignment = value;
             this._markAsDirty();
-        } 
+        }
 
         public get width(): string | number {
             return this._width.toString(this._host);
         }
 
-        public get widthInPixels(): number  {
+        public get widthInPixels(): number {
             return this._width.getValueInPixel(this._host, this._cachedParentMeasure.width);
         }
 
-        public set width(value: string | number ) {
+        public set width(value: string | number) {
             if (this._width.toString(this._host) === value) {
                 return;
             }
@@ -233,15 +233,15 @@ module BABYLON.GUI {
             }
         }
 
-        public get height(): string | number  {
+        public get height(): string | number {
             return this._height.toString(this._host);
         }
 
-        public get heightInPixels(): number  {
+        public get heightInPixels(): number {
             return this._height.getValueInPixel(this._host, this._cachedParentMeasure.height);
         }
 
-        public set height(value: string | number ) {
+        public set height(value: string | number) {
             if (this._height.toString(this._host) === value) {
                 return;
             }
@@ -249,7 +249,7 @@ module BABYLON.GUI {
             if (this._height.fromString(value)) {
                 this._markAsDirty();
             }
-        }   
+        }
 
         public get fontFamily(): string {
             return this._fontFamily;
@@ -275,17 +275,17 @@ module BABYLON.GUI {
 
             this._fontStyle = value;
             this._fontSet = true;
-        }     
-        
-        public get fontSizeInPixels(): number  {
+        }
+
+        public get fontSizeInPixels(): number {
             return this._fontSize.getValueInPixel(this._host, 100);
         }
 
-        public get fontSize(): string | number  {
+        public get fontSize(): string | number {
             return this._fontSize.toString(this._host);
         }
 
-        public set fontSize(value: string | number ) {
+        public set fontSize(value: string | number) {
             if (this._fontSize.toString(this._host) === value) {
                 return;
             }
@@ -307,7 +307,7 @@ module BABYLON.GUI {
 
             this._color = value;
             this._markAsDirty();
-        }                       
+        }
 
         public get zIndex(): number {
             return this._zIndex;
@@ -354,126 +354,126 @@ module BABYLON.GUI {
         public get isDirty(): boolean {
             return this._isDirty;
         }
-        
-        public get paddingLeft(): string | number  {
+
+        public get paddingLeft(): string | number {
             return this._paddingLeft.toString(this._host);
         }
 
-        public get paddingLeftInPixels(): number  {
+        public get paddingLeftInPixels(): number {
             return this._paddingLeft.getValueInPixel(this._host, this._cachedParentMeasure.width);
-        }             
+        }
 
-        public set paddingLeft(value: string | number ) {
+        public set paddingLeft(value: string | number) {
             if (this._paddingLeft.fromString(value)) {
                 this._markAsDirty();
             }
-        }    
+        }
 
-        public get paddingRight(): string | number  {
+        public get paddingRight(): string | number {
             return this._paddingRight.toString(this._host);
         }
 
-        public get paddingRightInPixels(): number  {
+        public get paddingRightInPixels(): number {
             return this._paddingRight.getValueInPixel(this._host, this._cachedParentMeasure.width);
-        }         
+        }
 
-        public set paddingRight(value: string | number ) {
+        public set paddingRight(value: string | number) {
             if (this._paddingRight.fromString(value)) {
                 this._markAsDirty();
             }
         }
 
-        public get paddingTop(): string | number  {
+        public get paddingTop(): string | number {
             return this._paddingTop.toString(this._host);
         }
 
-        public get paddingTopInPixels(): number  {
+        public get paddingTopInPixels(): number {
             return this._paddingTop.getValueInPixel(this._host, this._cachedParentMeasure.height);
-        }         
+        }
 
-        public set paddingTop(value: string | number ) {
+        public set paddingTop(value: string | number) {
             if (this._paddingTop.fromString(value)) {
                 this._markAsDirty();
             }
         }
 
-        public get paddingBottom(): string | number  {
+        public get paddingBottom(): string | number {
             return this._paddingBottom.toString(this._host);
         }
 
-        public get paddingBottomInPixels(): number  {
+        public get paddingBottomInPixels(): number {
             return this._paddingBottom.getValueInPixel(this._host, this._cachedParentMeasure.height);
-        }                 
+        }
 
-        public set paddingBottom(value: string | number ) {
+        public set paddingBottom(value: string | number) {
             if (this._paddingBottom.fromString(value)) {
                 this._markAsDirty();
             }
-        }     
+        }
 
-        public get left(): string | number  {
+        public get left(): string | number {
             return this._left.toString(this._host);
         }
 
-        public get leftInPixels(): number  {
+        public get leftInPixels(): number {
             return this._left.getValueInPixel(this._host, this._cachedParentMeasure.width);
-        }          
+        }
 
-        public set left(value: string | number ) {
+        public set left(value: string | number) {
             if (this._left.fromString(value)) {
                 this._markAsDirty();
             }
-        }  
+        }
 
-        public get top(): string | number  {
+        public get top(): string | number {
             return this._top.toString(this._host);
         }
 
-        public get topInPixels(): number  {
+        public get topInPixels(): number {
             return this._top.getValueInPixel(this._host, this._cachedParentMeasure.height);
-        }        
+        }
 
-        public set top(value: string | number ) {
+        public set top(value: string | number) {
             if (this._top.fromString(value)) {
                 this._markAsDirty();
             }
-        }     
+        }
 
-        public get linkOffsetX(): string | number  {
+        public get linkOffsetX(): string | number {
             return this._linkOffsetX.toString(this._host);
         }
 
-        public get linkOffsetXInPixels(): number  {
+        public get linkOffsetXInPixels(): number {
             return this._linkOffsetX.getValueInPixel(this._host, this._cachedParentMeasure.width);
-        }        
+        }
 
-        public set linkOffsetX(value: string | number ) {
+        public set linkOffsetX(value: string | number) {
             if (this._linkOffsetX.fromString(value)) {
                 this._markAsDirty();
             }
-        }      
+        }
 
-        public get linkOffsetY(): string | number  {
+        public get linkOffsetY(): string | number {
             return this._linkOffsetY.toString(this._host);
         }
 
-        public get linkOffsetYInPixels(): number  {
+        public get linkOffsetYInPixels(): number {
             return this._linkOffsetY.getValueInPixel(this._host, this._cachedParentMeasure.height);
-        }        
+        }
 
-        public set linkOffsetY(value: string | number ) {
+        public set linkOffsetY(value: string | number) {
             if (this._linkOffsetY.fromString(value)) {
                 this._markAsDirty();
             }
-        }                
+        }
 
         public get centerX(): number {
             return this._currentMeasure.left + this._currentMeasure.width / 2;
-        }       
+        }
 
         public get centerY(): number {
             return this._currentMeasure.top + this._currentMeasure.height / 2;
-        }                   
+        }
 
         // Functions
         constructor(public name?: string) {
@@ -505,13 +505,13 @@ module BABYLON.GUI {
 
             return result;
         }
-        
+
         public moveToVector3(position: Vector3, scene: Scene): void {
             if (!this._host || this._root !== this._host._rootContainer) {
                 Tools.Error("Cannot move a control to a vector3 if the control is not at root level");
                 return;
             }
-            
+
             this.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
             this.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
 
@@ -528,7 +528,7 @@ module BABYLON.GUI {
         }
 
         public linkWithMesh(mesh: Nullable<AbstractMesh>): void {
-            if (!this._host || this._root !== this._host._rootContainer) {
+            if (!this._host || this._root && this._root !== this._host._rootContainer) {
                 Tools.Error("Cannot link a control to a mesh if the control is not at root level");
                 return;
             }
@@ -561,7 +561,7 @@ module BABYLON.GUI {
             this._markAsDirty();
         }
 
-        public _markAsDirty(): void {            
+        public _markAsDirty(): void {
             this._isDirty = true;
 
             if (!this._host) {
@@ -584,7 +584,7 @@ module BABYLON.GUI {
         }
 
         protected _transform(context: CanvasRenderingContext2D): void {
-            if (!this._isMatrixDirty && this._scaleX === 1 && this._scaleY ===1 && this._rotation === 0) {
+            if (!this._isMatrixDirty && this._scaleX === 1 && this._scaleY === 1 && this._rotation === 0) {
                 return;
             }
 
@@ -600,7 +600,7 @@ module BABYLON.GUI {
             context.scale(this._scaleX, this._scaleY);
 
             // preTranslate
-            context.translate(-offsetX, -offsetY);    
+            context.translate(-offsetX, -offsetY);
 
             // Need to update matrices?
             if (this._isMatrixDirty || this._cachedOffsetX !== offsetX || this._cachedOffsetY !== offsetY) {
@@ -633,7 +633,7 @@ module BABYLON.GUI {
             }
         }
 
-        protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): boolean {     
+        protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): boolean {
             if (this._isDirty || !this._cachedParentMeasure.isEqualsTo(parentMeasure)) {
                 this._isDirty = false;
                 this._currentMeasure.copyFrom(parentMeasure);
@@ -657,8 +657,8 @@ module BABYLON.GUI {
 
                 if (this.onDirtyObservable.hasObservers()) {
                     this.onDirtyObservable.notifyObservers(this);
-                }                
-            }     
+                }
+            }
 
             if (this._currentMeasure.left > parentMeasure.left + parentMeasure.width) {
                 return false;
@@ -677,8 +677,8 @@ module BABYLON.GUI {
             }
 
             // Transform
-            this._transform(context); 
-                        
+            this._transform(context);
+
             // Clip
             this._clip(context);
             context.clip();
@@ -686,40 +686,40 @@ module BABYLON.GUI {
             return true;
         }
 
-        protected _clip( context: CanvasRenderingContext2D) {
+        protected _clip(context: CanvasRenderingContext2D) {
             context.beginPath();
-            
-            if(this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY){
+
+            if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
                 var shadowOffsetX = this.shadowOffsetX;
                 var shadowOffsetY = this.shadowOffsetY;
                 var shadowBlur = this.shadowBlur;
-                
-                var leftShadowOffset = Math.min(Math.min(shadowOffsetX, 0) - shadowBlur*2, 0);
-                var rightShadowOffset = Math.max(Math.max(shadowOffsetX, 0) + shadowBlur*2, 0);
-                var topShadowOffset = Math.min(Math.min(shadowOffsetY, 0) - shadowBlur*2, 0);
-                var bottomShadowOffset = Math.max(Math.max(shadowOffsetY, 0) + shadowBlur*2, 0);
-
-                context.rect(this._currentMeasure.left + leftShadowOffset, 
-                            this._currentMeasure.top + topShadowOffset, 
-                            this._currentMeasure.width + rightShadowOffset - leftShadowOffset, 
-                            this._currentMeasure.height + bottomShadowOffset - topShadowOffset);
+
+                var leftShadowOffset = Math.min(Math.min(shadowOffsetX, 0) - shadowBlur * 2, 0);
+                var rightShadowOffset = Math.max(Math.max(shadowOffsetX, 0) + shadowBlur * 2, 0);
+                var topShadowOffset = Math.min(Math.min(shadowOffsetY, 0) - shadowBlur * 2, 0);
+                var bottomShadowOffset = Math.max(Math.max(shadowOffsetY, 0) + shadowBlur * 2, 0);
+
+                context.rect(this._currentMeasure.left + leftShadowOffset,
+                    this._currentMeasure.top + topShadowOffset,
+                    this._currentMeasure.width + rightShadowOffset - leftShadowOffset,
+                    this._currentMeasure.height + bottomShadowOffset - topShadowOffset);
             } else {
-                context.rect(this._currentMeasure.left ,this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
+                context.rect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
             }
         }
 
-        public _measure(): void {  
+        public _measure(): void {
             // Width / Height
             if (this._width.isPixel) {
                 this._currentMeasure.width = this._width.getValue(this._host);
             } else {
-                this._currentMeasure.width *= this._width.getValue(this._host); 
+                this._currentMeasure.width *= this._width.getValue(this._host);
             }
 
             if (this._height.isPixel) {
                 this._currentMeasure.height = this._height.getValue(this._host);
             } else {
-                this._currentMeasure.height *= this._height.getValue(this._host); 
+                this._currentMeasure.height *= this._height.getValue(this._host);
             }
         }
 
@@ -757,7 +757,7 @@ module BABYLON.GUI {
                     y = (parentHeight - height) / 2;
                     break;
             }
-            
+
             if (this._paddingLeft.isPixel) {
                 this._currentMeasure.left += this._paddingLeft.getValue(this._host);
                 this._currentMeasure.width -= this._paddingLeft.getValue(this._host);
@@ -784,7 +784,7 @@ module BABYLON.GUI {
                 this._currentMeasure.height -= this._paddingBottom.getValue(this._host);
             } else {
                 this._currentMeasure.height -= parentHeight * this._paddingBottom.getValue(this._host);
-            }            
+            }
 
             if (this._left.isPixel) {
                 this._currentMeasure.left += this._left.getValue(this._host);
@@ -799,12 +799,12 @@ module BABYLON.GUI {
             }
 
             this._currentMeasure.left += x;
-            this._currentMeasure.top += y;            
+            this._currentMeasure.top += y;
         }
 
         protected _preMeasure(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
             // Do nothing
-        }        
+        }
 
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
             // Do nothing
@@ -814,7 +814,7 @@ module BABYLON.GUI {
             // Do nothing
         }
 
-        public contains(x: number, y: number) : boolean {
+        public contains(x: number, y: number): boolean {
             // Invert transform
             this._invertTransformMatrix.transformCoordinates(x, y, this._transformedPosition);
 
@@ -836,7 +836,7 @@ module BABYLON.GUI {
 
             if (y > this._currentMeasure.top + this._currentMeasure.height) {
                 return false;
-            } 
+            }
 
             if (this.isPointerBlocker) {
                 this._host._shouldBlockPointer = true;
@@ -902,9 +902,9 @@ module BABYLON.GUI {
 
         public _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void {
             this._downCount = 0;
-            
+
             var canNotify: boolean = this.onPointerUpObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
-            
+
             if (canNotify && this.parent != null) this.parent._onPointerUp(target, coordinates, buttonIndex);
         }
 
@@ -919,7 +919,7 @@ module BABYLON.GUI {
 
                 var previousControlOver = this._host._lastControlOver;
                 if (previousControlOver && previousControlOver !== this) {
-                    previousControlOver._onPointerOut(this);                
+                    previousControlOver._onPointerOut(this);
                 }
 
                 if (previousControlOver !== this) {
@@ -944,7 +944,7 @@ module BABYLON.GUI {
                 this._host._lastControlDown = null;
                 return true;
             }
-        
+
             return false;
         }
 
@@ -954,7 +954,7 @@ module BABYLON.GUI {
             }
 
             this._font = this._fontStyle + " " + this._fontSize.getValue(this._host) + "px " + this._fontFamily;
-        
+
             this._fontOffset = Control._GetFontOffset(this._font);
         }
 
@@ -982,7 +982,7 @@ module BABYLON.GUI {
         private static _HORIZONTAL_ALIGNMENT_LEFT = 0;
         private static _HORIZONTAL_ALIGNMENT_RIGHT = 1;
         private static _HORIZONTAL_ALIGNMENT_CENTER = 2;
-        
+
         private static _VERTICAL_ALIGNMENT_TOP = 0;
         private static _VERTICAL_ALIGNMENT_BOTTOM = 1;
         private static _VERTICAL_ALIGNMENT_CENTER = 2;
@@ -1011,9 +1011,9 @@ module BABYLON.GUI {
             return Control._VERTICAL_ALIGNMENT_CENTER;
         }
 
-        private static _FontHeightSizes: {[key: string]: {ascent: number, height: number, descent: number}} = {};
+        private static _FontHeightSizes: { [key: string]: { ascent: number, height: number, descent: number } } = {};
 
-        public static _GetFontOffset(font: string): {ascent: number, height: number, descent: number} {
+        public static _GetFontOffset(font: string): { ascent: number, height: number, descent: number } {
 
             if (Control._FontHeightSizes[font]) {
                 return Control._FontHeightSizes[font];
@@ -1051,10 +1051,10 @@ module BABYLON.GUI {
         };
 
         public static AddHeader(control: Control, text: string, size: string | number, options: { isHorizontal: boolean, controlFirst: boolean }): StackPanel {
-            let panel = new BABYLON.GUI.StackPanel("panel");        
+            let panel = new BABYLON.GUI.StackPanel("panel");
             let isHorizontal = options ? options.isHorizontal : true;
             let controlFirst = options ? options.controlFirst : true;
-            
+
             panel.isVertical = !isHorizontal;
 
             let header = new BABYLON.GUI.TextBlock("header");
@@ -1068,14 +1068,14 @@ module BABYLON.GUI {
 
             if (controlFirst) {
                 panel.addControl(control);
-                panel.addControl(header); 
+                panel.addControl(header);
                 header.paddingLeft = "5px";
             } else {
-                panel.addControl(header); 
+                panel.addControl(header);
                 panel.addControl(control);
                 header.paddingRight = "5px";
             }
-            
+
             header.shadowBlur = control.shadowBlur;
             header.shadowColor = control.shadowColor;
             header.shadowOffsetX = control.shadowOffsetX;
@@ -1084,7 +1084,7 @@ module BABYLON.GUI {
             return panel;
         }
 
-        protected static drawEllipse(x:number, y:number, width:number, height:number, context:CanvasRenderingContext2D):void{
+        protected static drawEllipse(x: number, y: number, width: number, height: number, context: CanvasRenderingContext2D): void {
             context.translate(x, y);
             context.scale(width, height);
 
@@ -1092,8 +1092,8 @@ module BABYLON.GUI {
             context.arc(0, 0, 1, 0, 2 * Math.PI);
             context.closePath();
 
-            context.scale(1/width, 1/height);
-            context.translate(-x, -y);            
+            context.scale(1 / width, 1 / height);
+            context.translate(-x, -y);
         }
-    }    
+    }
 }

+ 16 - 1
gui/src/controls/image.ts

@@ -150,7 +150,7 @@ module BABYLON.GUI {
                 this._onImageLoaded();
             }
             if (value) {
-                this._domImage.crossOrigin = "anonymous";
+                Tools.SetCorsBehavior(value, this._domImage);
                 this._domImage.src = value;
             }
         }
@@ -159,21 +159,36 @@ module BABYLON.GUI {
             return this._cellWidth;
         }
         set cellWidth(value: number) {
+            if(this._cellWidth === value){
+                return;
+            }
+            
             this._cellWidth = value;
+            this._markAsDirty();
         }
 
         get cellHeight(): number {
             return this._cellHeight;
         }
         set cellHeight(value: number) {
+            if(this._cellHeight === value){
+                return;
+            }
+            
             this._cellHeight = value;
+            this._markAsDirty();
         }
 
         get cellId(): number {
             return this._cellId;
         }
         set cellId(value: number) {
+            if (this._cellId === value) {
+                 return;
+             }
+            
             this._cellId = value;
+            this._markAsDirty();
         }
 
         constructor(public name?: string, url: Nullable<string> = null) {

+ 71 - 52
gui/src/controls/inputText.ts

@@ -4,21 +4,21 @@ module BABYLON.GUI {
     export class InputText extends Control implements IFocusableControl {
         private _text = "";
         private _placeholderText = "";
-        private _background = "#222222";   
-        private _focusedBackground = "#000000";   
-        private _placeholderColor = "gray";   
+        private _background = "#222222";
+        private _focusedBackground = "#000000";
+        private _placeholderColor = "gray";
         private _thickness = 1;
         private _margin = new ValueAndUnit(10, ValueAndUnit.UNITMODE_PIXEL);
-        private _autoStretchWidth = true;        
+        private _autoStretchWidth = true;
         private _maxWidth = new ValueAndUnit(1, ValueAndUnit.UNITMODE_PERCENTAGE, false);
         private _isFocused = false;
         private _blinkTimeout: number;
         private _blinkIsEven = false;
-        private _cursorOffset = 0;        
+        private _cursorOffset = 0;
         private _scrollLeft: Nullable<number>;
         private _textWidth: number;
         private _clickedCoordinate: Nullable<number>;
-        
+
         public promptMessage = "Please enter text:";
 
         public onTextChangedObservable = new Observable<InputText>();
@@ -29,11 +29,11 @@ module BABYLON.GUI {
             return this._maxWidth.toString(this._host);
         }
 
-        public get maxWidthInPixels(): number  {
+        public get maxWidthInPixels(): number {
             return this._maxWidth.getValueInPixel(this._host, this._cachedParentMeasure.width);
-        }             
+        }
 
-        public set maxWidth(value: string | number ) {
+        public set maxWidth(value: string | number) {
             if (this._maxWidth.toString(this._host) === value) {
                 return;
             }
@@ -41,15 +41,15 @@ module BABYLON.GUI {
             if (this._maxWidth.fromString(value)) {
                 this._markAsDirty();
             }
-        }        
+        }
 
         public get margin(): string {
             return this._margin.toString(this._host);
         }
 
-        public get marginInPixels(): number  {
+        public get marginInPixels(): number {
             return this._margin.getValueInPixel(this._host, this._cachedParentMeasure.width);
-        }            
+        }
 
         public set margin(value: string) {
             if (this._margin.toString(this._host) === value) {
@@ -59,8 +59,8 @@ module BABYLON.GUI {
             if (this._margin.fromString(value)) {
                 this._markAsDirty();
             }
-        }   
-        
+        }
+
         public get autoStretchWidth(): boolean {
             return this._autoStretchWidth;
         }
@@ -72,8 +72,8 @@ module BABYLON.GUI {
 
             this._autoStretchWidth = value;
             this._markAsDirty();
-        }           
-        
+        }
+
         public get thickness(): number {
             return this._thickness;
         }
@@ -85,7 +85,7 @@ module BABYLON.GUI {
 
             this._thickness = value;
             this._markAsDirty();
-        }          
+        }
 
         public get focusedBackground(): string {
             return this._focusedBackground;
@@ -98,7 +98,7 @@ module BABYLON.GUI {
 
             this._focusedBackground = value;
             this._markAsDirty();
-        }  
+        }
 
         public get background(): string {
             return this._background;
@@ -111,7 +111,7 @@ module BABYLON.GUI {
 
             this._background = value;
             this._markAsDirty();
-        }  
+        }
 
         public get placeholderColor(): string {
             return this._placeholderColor;
@@ -124,8 +124,8 @@ module BABYLON.GUI {
 
             this._placeholderColor = value;
             this._markAsDirty();
-        }          
-        
+        }
+
         public get placeholderText(): string {
             return this._placeholderText;
         }
@@ -136,7 +136,7 @@ module BABYLON.GUI {
             }
             this._placeholderText = value;
             this._markAsDirty();
-        }        
+        }
 
         public get text(): string {
             return this._text;
@@ -152,6 +152,22 @@ module BABYLON.GUI {
             this.onTextChangedObservable.notifyObservers(this);
         }
 
+        public get width(): string | number {
+            return this._width.toString(this._host);
+        }
+
+        public set width(value: string | number) {
+            if (this._width.toString(this._host) === value) {
+                return;
+            }
+
+            if (this._width.fromString(value)) {
+                this._markAsDirty();
+            }
+
+            this.autoStretchWidth = false;
+        }
+
         constructor(public name?: string, text: string = "") {
             super(name);
 
@@ -195,6 +211,9 @@ module BABYLON.GUI {
         public processKey(keyCode: number, key?: string) {
             // Specific cases
             switch (keyCode) {
+                case 32: //SPACE
+                    key = " "; //ie11 key for space is "Spacebar" 
+                    break;
                 case 8: // BACKSPACE
                     if (this._text && this._text.length > 0) {
                         if (this._cursorOffset === 0) {
@@ -213,20 +232,20 @@ module BABYLON.GUI {
                         this.text = this._text.slice(0, deletePosition) + this._text.slice(deletePosition + 1);
                         this._cursorOffset--;
                     }
-                    return;                    
+                    return;
                 case 13: // RETURN
                     this._host.focusedControl = null;
                     return;
                 case 35: // END
                     this._cursorOffset = 0;
                     this._blinkIsEven = false;
-                    this._markAsDirty();                
+                    this._markAsDirty();
                     return;
                 case 36: // HOME
                     this._cursorOffset = this._text.length;
                     this._blinkIsEven = false;
-                    this._markAsDirty();                
-                return;
+                    this._markAsDirty();
+                    return;
                 case 37: // LEFT
                     this._cursorOffset++;
                     if (this._cursorOffset > this._text.length) {
@@ -252,16 +271,16 @@ module BABYLON.GUI {
                 (keyCode > 47 && keyCode < 58) ||       // Numbers
                 (keyCode > 64 && keyCode < 91) ||       // Letters
                 (keyCode > 185 && keyCode < 193) ||     // Special characters
-                (keyCode > 218  && keyCode < 223) ||    // Special characters
+                (keyCode > 218 && keyCode < 223) ||    // Special characters
                 (keyCode > 95 && keyCode < 112)) {      // Numpad
-                    if (this._cursorOffset === 0) {
-                        this.text += key;
-                    } else {
-                        let insertPosition = this._text.length - this._cursorOffset;
+                if (this._cursorOffset === 0) {
+                    this.text += key;
+                } else {
+                    let insertPosition = this._text.length - this._cursorOffset;
 
-                        this.text = this._text.slice(0, insertPosition) + key + this._text.slice(insertPosition);
-                    }
+                    this.text = this._text.slice(0, insertPosition) + key + this._text.slice(insertPosition);
                 }
+            }
         }
 
         public processKeyboard(evt: KeyboardEvent): void {
@@ -273,8 +292,8 @@ module BABYLON.GUI {
 
             this._applyStates(context);
             if (this._processMeasures(parentMeasure, context)) {
-                
-                if(this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY){
+
+                if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
                     context.shadowColor = this.shadowColor;
                     context.shadowBlur = this.shadowBlur;
                     context.shadowOffsetX = this.shadowOffsetX;
@@ -285,16 +304,16 @@ module BABYLON.GUI {
                 if (this._isFocused) {
                     if (this._focusedBackground) {
                         context.fillStyle = this._focusedBackground;
-    
+
                         context.fillRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
-                    }                        
+                    }
                 } else if (this._background) {
                     context.fillStyle = this._background;
 
                     context.fillRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
                 }
-                
-                if(this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY){
+
+                if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
                     context.shadowBlur = 0;
                     context.shadowOffsetX = 0;
                     context.shadowOffsetY = 0;
@@ -312,7 +331,7 @@ module BABYLON.GUI {
 
                 let text = this._text;
 
-                if (!this._isFocused && !this._text && this._placeholderText) {  
+                if (!this._isFocused && !this._text && this._placeholderText) {
                     text = this._placeholderText;
 
                     if (this._placeholderColor) {
@@ -320,7 +339,7 @@ module BABYLON.GUI {
                     }
                 }
 
-                this._textWidth = context.measureText(text).width;   
+                this._textWidth = context.measureText(text).width;
                 let marginWidth = this._margin.getValueInPixel(this._host, parentMeasure.width) * 2;
                 if (this._autoStretchWidth) {
                     this.width = Math.min(this._maxWidth.getValueInPixel(this._host, parentMeasure.width), this._textWidth + marginWidth) + "px";
@@ -333,7 +352,7 @@ module BABYLON.GUI {
                 context.rect(clipTextLeft, this._currentMeasure.top + (this._currentMeasure.height - this._fontOffset.height) / 2, availableWidth + 2, this._currentMeasure.height);
                 context.clip();
 
-                if (this._isFocused && this._textWidth > availableWidth) {      
+                if (this._isFocused && this._textWidth > availableWidth) {
                     let textLeft = clipTextLeft - this._textWidth + availableWidth;
                     if (!this._scrollLeft) {
                         this._scrollLeft = textLeft;
@@ -345,7 +364,7 @@ module BABYLON.GUI {
                 context.fillText(text, this._scrollLeft, this._currentMeasure.top + rootY);
 
                 // Cursor
-                if (this._isFocused) {         
+                if (this._isFocused) {
 
                     // Need to move cursor
                     if (this._clickedCoordinate) {
@@ -361,7 +380,7 @@ module BABYLON.GUI {
                             this._cursorOffset++;
                             currentSize = context.measureText(text.substr(text.length - this._cursorOffset, this._cursorOffset)).width;
 
-                        } while(currentSize < absoluteCursorPosition);
+                        } while (currentSize < absoluteCursorPosition);
 
                         // Find closest move
                         if (Math.abs(absoluteCursorPosition - currentSize) > previousDist) {
@@ -375,18 +394,18 @@ module BABYLON.GUI {
                     // Render cursor
                     if (!this._blinkIsEven) {
                         let cursorOffsetText = this.text.substr(this._text.length - this._cursorOffset);
-                        let cursorOffsetWidth = context.measureText(cursorOffsetText).width;   
-                        let cursorLeft = this._scrollLeft  + this._textWidth - cursorOffsetWidth;
-    
+                        let cursorOffsetWidth = context.measureText(cursorOffsetText).width;
+                        let cursorLeft = this._scrollLeft + this._textWidth - cursorOffsetWidth;
+
                         if (cursorLeft < clipTextLeft) {
                             this._scrollLeft += (clipTextLeft - cursorLeft);
                             cursorLeft = clipTextLeft;
                             this._markAsDirty();
                         } else if (cursorLeft > clipTextLeft + availableWidth) {
-                            this._scrollLeft += (clipTextLeft  + availableWidth - cursorLeft);
+                            this._scrollLeft += (clipTextLeft + availableWidth - cursorLeft);
                             cursorLeft = clipTextLeft + availableWidth;
                             this._markAsDirty();
-                        }                   
+                        }
                         context.fillRect(cursorLeft, this._currentMeasure.top + (this._currentMeasure.height - this._fontOffset.height) / 2, 2, this._fontOffset.height);
                     }
 
@@ -406,8 +425,8 @@ module BABYLON.GUI {
                     }
                     context.lineWidth = this._thickness;
 
-                    context.strokeRect(this._currentMeasure.left + this._thickness / 2, this._currentMeasure.top + this._thickness / 2, 
-                                        this._currentMeasure.width - this._thickness, this._currentMeasure.height - this._thickness);
+                    context.strokeRect(this._currentMeasure.left + this._thickness / 2, this._currentMeasure.top + this._thickness / 2,
+                        this._currentMeasure.width - this._thickness, this._currentMeasure.height - this._thickness);
                 }
             }
             context.restore();
@@ -432,7 +451,7 @@ module BABYLON.GUI {
 
         public _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void {
             super._onPointerUp(target, coordinates, buttonIndex);
-        }  
+        }
 
         public dispose() {
             super.dispose();

+ 39 - 35
gui/src/controls/slider.ts

@@ -3,10 +3,10 @@
 module BABYLON.GUI {
     export class Slider extends Control {
         private _thumbWidth = new ValueAndUnit(30, ValueAndUnit.UNITMODE_PIXEL, false);
-        private _minimum = 0; 
+        private _minimum = 0;
         private _maximum = 100;
         private _value = 50;
-        private _background = "black";   
+        private _background = "black";
         private _borderColor = "white";
         private _barOffset = new ValueAndUnit(5, ValueAndUnit.UNITMODE_PIXEL, false);
         private _isThumbCircle = false;
@@ -24,7 +24,7 @@ module BABYLON.GUI {
 
             this._borderColor = value;
             this._markAsDirty();
-        }  
+        }
 
         public get background(): string {
             return this._background;
@@ -37,17 +37,17 @@ module BABYLON.GUI {
 
             this._background = value;
             this._markAsDirty();
-        }     
+        }
 
-        public get barOffset(): string | number  {
+        public get barOffset(): string | number {
             return this._barOffset.toString(this._host);
         }
 
-        public get barOffsetInPixels(): number  {
+        public get barOffsetInPixels(): number {
             return this._barOffset.getValueInPixel(this._host, this._cachedParentMeasure.width);
-        }            
+        }
 
-        public set barOffset(value: string | number ) {
+        public set barOffset(value: string | number) {
             if (this._barOffset.toString(this._host) === value) {
                 return;
             }
@@ -55,17 +55,17 @@ module BABYLON.GUI {
             if (this._barOffset.fromString(value)) {
                 this._markAsDirty();
             }
-        }      
+        }
 
-        public get thumbWidth(): string | number  {
+        public get thumbWidth(): string | number {
             return this._thumbWidth.toString(this._host);
         }
 
-        public get thumbWidthInPixels(): number  {
+        public get thumbWidthInPixels(): number {
             return this._thumbWidth.getValueInPixel(this._host, this._cachedParentMeasure.width);
-        }          
+        }
 
-        public set thumbWidth(value: string | number ) {
+        public set thumbWidth(value: string | number) {
             if (this._thumbWidth.toString(this._host) === value) {
                 return;
             }
@@ -73,7 +73,7 @@ module BABYLON.GUI {
             if (this._thumbWidth.fromString(value)) {
                 this._markAsDirty();
             }
-        }              
+        }
 
         public get minimum(): number {
             return this._minimum;
@@ -88,7 +88,7 @@ module BABYLON.GUI {
             this._markAsDirty();
 
             this.value = Math.max(Math.min(this.value, this._maximum), this._minimum);
-        }         
+        }
 
         public get maximum(): number {
             return this._maximum;
@@ -103,7 +103,7 @@ module BABYLON.GUI {
             this._markAsDirty();
 
             this.value = Math.max(Math.min(this.value, this._maximum), this._minimum);
-        }     
+        }
 
         public get value(): number {
             return this._value;
@@ -119,7 +119,7 @@ module BABYLON.GUI {
             this._markAsDirty();
 
             this.onValueChangedObservable.notifyObservers(this._value);
-        }                             
+        }
 
         public get isThumbCircle(): boolean {
             return this._isThumbCircle;
@@ -142,7 +142,7 @@ module BABYLON.GUI {
 
         protected _getTypeName(): string {
             return "Slider";
-        }              
+        }
 
         public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
             context.save();
@@ -153,7 +153,7 @@ module BABYLON.GUI {
                 var effectiveThumbWidth;
                 var effectiveBarOffset;
 
-                if(this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY){
+                if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
                     context.shadowColor = this.shadowColor;
                     context.shadowBlur = this.shadowBlur;
                     context.shadowOffsetX = this.shadowOffsetX;
@@ -161,16 +161,16 @@ module BABYLON.GUI {
                 }
 
                 if (this._thumbWidth.isPixel) {
-                    effectiveThumbWidth = Math.min(this._thumbWidth.getValue(this._host), this._currentMeasure.height);
+                    effectiveThumbWidth = Math.min(this._thumbWidth.getValue(this._host), this._currentMeasure.width);
                 } else {
-                    effectiveThumbWidth = this._currentMeasure.height * this._thumbWidth.getValue(this._host); 
+                    effectiveThumbWidth = this._currentMeasure.width * this._thumbWidth.getValue(this._host);
                 }
 
                 if (this._barOffset.isPixel) {
                     effectiveBarOffset = Math.min(this._barOffset.getValue(this._host), this._currentMeasure.height);
                 } else {
-                    effectiveBarOffset = this._currentMeasure.height * this._barOffset.getValue(this._host); 
-                }                
+                    effectiveBarOffset = this._currentMeasure.height * this._barOffset.getValue(this._host);
+                }
 
 
                 var left = this._currentMeasure.left + effectiveThumbWidth / 2;
@@ -181,7 +181,7 @@ module BABYLON.GUI {
                 context.fillStyle = this._background;
                 context.fillRect(left, this._currentMeasure.top + effectiveBarOffset, width, this._currentMeasure.height - effectiveBarOffset * 2);
 
-                if(this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY){
+                if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
                     context.shadowBlur = 0;
                     context.shadowOffsetX = 0;
                     context.shadowOffsetY = 0;
@@ -190,7 +190,7 @@ module BABYLON.GUI {
                 context.fillStyle = this.color;
                 context.fillRect(left, this._currentMeasure.top + effectiveBarOffset, thumbPosition, this._currentMeasure.height - effectiveBarOffset * 2);
 
-                if(this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY){
+                if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
                     context.shadowColor = this.shadowColor;
                     context.shadowBlur = this.shadowBlur;
                     context.shadowOffsetX = this.shadowOffsetX;
@@ -203,7 +203,7 @@ module BABYLON.GUI {
                     context.arc(left + thumbPosition, this._currentMeasure.top + this._currentMeasure.height / 2, effectiveThumbWidth / 2, 0, 2 * Math.PI);
                     context.fill();
 
-                    if(this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY){
+                    if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
                         context.shadowBlur = 0;
                         context.shadowOffsetX = 0;
                         context.shadowOffsetY = 0;
@@ -214,8 +214,8 @@ module BABYLON.GUI {
                 }
                 else {
                     context.fillRect(left + thumbPosition - effectiveThumbWidth / 2, this._currentMeasure.top, effectiveThumbWidth, this._currentMeasure.height);
-                    
-                    if(this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY){
+
+                    if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
                         context.shadowBlur = 0;
                         context.shadowOffsetX = 0;
                         context.shadowOffsetY = 0;
@@ -231,7 +231,11 @@ module BABYLON.GUI {
         // Events
         private _pointerIsDown = false;
 
-        private _updateValueFromPointer(x: number): void {
+        private _updateValueFromPointer(x: number, y: number): void {
+            if (this.rotation != 0) {
+                this._invertTransformMatrix.transformCoordinates(x, y, this._transformedPosition);
+                x = this._transformedPosition.x;
+            }
             this.value = this._minimum + ((x - this._currentMeasure.left) / this._currentMeasure.width) * (this._maximum - this._minimum);
         }
 
@@ -242,7 +246,7 @@ module BABYLON.GUI {
 
             this._pointerIsDown = true;
 
-            this._updateValueFromPointer(coordinates.x);
+            this._updateValueFromPointer(coordinates.x, coordinates.y);
             this._host._capturingControl = this;
 
             return true;
@@ -250,17 +254,17 @@ module BABYLON.GUI {
 
         public _onPointerMove(target: Control, coordinates: Vector2): void {
             if (this._pointerIsDown) {
-                this._updateValueFromPointer(coordinates.x);
+                this._updateValueFromPointer(coordinates.x, coordinates.y);
             }
 
             super._onPointerMove(target, coordinates);
         }
 
-        public _onPointerUp (target: Control, coordinates: Vector2, buttonIndex: number): void {
+        public _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void {
             this._pointerIsDown = false;
-            
+
             this._host._capturingControl = null;
             super._onPointerUp(target, coordinates, buttonIndex);
-        }         
-    }    
+        }
+    }
 }

+ 10 - 3
inspector/src/details/PropertyLine.ts

@@ -252,8 +252,9 @@ module INSPECTOR {
         private _createElements() {
             // Colors
             if (this.type == 'Color3' || this.type == 'Color4') {
-                this._elements.push(new ColorPickerElement(this.value, this));
-                //this._elements.push(new ColorElement(this.value));
+                if (!Helpers.IsBrowserIE()) {
+                    this._elements.push(new ColorPickerElement(this.value, this));
+                }
             }
             // Texture
             if (this.type == 'Texture') {
@@ -388,7 +389,13 @@ module INSPECTOR {
                     let objToDetail = this.value;
                     // Display all properties that are not functions
                     let propToDisplay = Helpers.GetAllLinesPropertiesAsString(objToDetail);
-                    propToDisplay.sort().reverse();
+
+                    // special case for color3
+                    if ((propToDisplay.indexOf('r') && propToDisplay.indexOf('g') && propToDisplay.indexOf('b')) == 0) {
+                        propToDisplay.sort();
+                    } else {
+                        propToDisplay.sort().reverse();
+                    }
 
                     for (let prop of propToDisplay) {
                         let infos = new Property(prop, this._property.value);

+ 8 - 0
inspector/src/helpers/Helpers.ts

@@ -51,6 +51,14 @@ module INSPECTOR {
             var regexp = /Edge/
             return regexp.test(navigator.userAgent);
         }
+        /**
+         * Returns true if the user browser is IE.
+         */
+        public static IsBrowserIE(): boolean {
+            //Detect if we are running on a faulty buggy OS.
+            var regexp = /Trident.*rv\:11\./
+            return regexp.test(navigator.userAgent);
+        }
 
         /** 
          * Returns the name of the type of the given object, where the name 

+ 18 - 17
inspector/test/index.js

@@ -5,7 +5,7 @@ var Test = (function () {
         var _this = this;
         var canvas = document.getElementById(canvasId);
         this.engine = new BABYLON.Engine(canvas, true);
-        BABYLONDEVTOOLS.Loader.debugShortcut(this.engine);
+        // BABYLONDEVTOOLS.Loader.debugShortcut(this.engine);
         this.scene = null;
         window.addEventListener("resize", function () {
             _this.engine.resize();
@@ -15,17 +15,17 @@ var Test = (function () {
     Test.prototype._run = function () {
         var _this = this;
         this._initScene();
-        this.scene.debugLayer.show({
-            popup: false,
-            parentElement: document.getElementById('inspector'),
-            newColors: {
-                backgroundColor: '#eee',
-                backgroundColorLighter: '#fff',
-                backgroundColorLighter2: '#fff',
-                backgroundColorLighter3: '#fff',
-                color: '#333'
-            }
-        });
+        // this.scene.debugLayer.show({
+        //     popup: false,
+        //     parentElement: document.getElementById('inspector'),
+        //     newColors: {
+        //         backgroundColor: '#eee',
+        //         backgroundColorLighter: '#fff',
+        //         backgroundColorLighter2: '#fff',
+        //         backgroundColorLighter3: '#fff',
+        //         color: '#333'
+        //     }
+        // });
         this.scene.executeWhenReady(function () {
             _this.engine.runRenderLoop(function () {
                 _this.scene.render();
@@ -51,7 +51,7 @@ var Test = (function () {
         let p = sceneRoot;
         for (let i = 0; i < num; i++) {
             // Our built-in 'sphere' shape. Params: name, subdivs, size, scene
-            let sphere = BABYLON.Mesh.CreateSphere(`sphere${i}`, 16, 2, scene);
+            let sphere = BABYLON.Mesh.CreateSphere('sphere' + i, 16, 2, scene);
 
             // Move the sphere upward 1/2 its height        
             sphere.position.y = 0.2;
@@ -62,13 +62,14 @@ var Test = (function () {
         }
 
         let t = 0;
-        scene.registerBeforeRender(() => {
-            ground.rotation.y += 0.01;
-            ground.position.y = Math.cos(t += 0.01);
-        });
+        // scene.registerBeforeRender(() => {
+        //     ground.rotation.y += 0.01;
+        //     ground.position.y = Math.cos(t += 0.01);
+        // });
 
         scene.createDefaultCameraOrLight(true);
         scene.activeCamera.attachControl(canvas);
+        scene.debugLayer.show();
 
         this.scene = scene;
     };

+ 7 - 3
inspector/webpack.config.js

@@ -1,7 +1,7 @@
 module.exports = {
     entry: [
         "../../dist/preview release/inspector/babylon.inspector.css",
-        "../../dist/preview release/inspector/babylon.inspector.min.js"
+        "../../dist/preview release/inspector/babylon.inspector.js"
     ],
     output: {
         libraryTarget: "var",
@@ -15,8 +15,12 @@ module.exports = {
     },
     module: {
         loaders: [
-            { test: /\.css$/, loader: "style!css" },
-            { test: /babylon.inspector.min.js$/, loader: "imports?Split=split!exports?INSPECTOR" }
+            { test: /\.css$/, use: ['style-loader', 'css-loader'] },
+            {
+                test: /babylon.inspector.js/, use: [
+                    "imports-loader?Split=split", "exports-loader?INSPECTOR"]
+
+            }
         ]
     }
 }

+ 26 - 12
loaders/src/glTF/1.0/babylon.glTFLoader.ts

@@ -445,7 +445,7 @@ module BABYLON.GLTF1 {
     /**
     * Imports a skeleton
     */
-    var importSkeleton = (gltfRuntime: IGLTFRuntime, skins: IGLTFSkins, mesh: Mesh, newSkeleton: Skeleton, id: string): Skeleton => {
+    var importSkeleton = (gltfRuntime: IGLTFRuntime, skins: IGLTFSkins, mesh: Mesh, newSkeleton: Skeleton | undefined, id: string): Skeleton => {
 
         if (!newSkeleton) {
             newSkeleton = new Skeleton(skins.name || "", "", gltfRuntime.scene);
@@ -581,11 +581,8 @@ module BABYLON.GLTF1 {
         if (!node.babylonNode) {
             return newMesh;
         }
-        var multiMat = new MultiMaterial("multimat" + id, gltfRuntime.scene);
 
-        if (!newMesh.material) {
-            newMesh.material = multiMat;
-        }
+        const subMaterials : Material[] = [];
 
         var vertexData = new VertexData();
         var geometry = new Geometry(id, gltfRuntime.scene, vertexData, false, newMesh);
@@ -690,14 +687,31 @@ module BABYLON.GLTF1 {
                 vertexData.merge(tempVertexData);
 
                 // Sub material
-                var material = gltfRuntime.scene.getMaterialByID(primitive.material);
-                multiMat.subMaterials.push(material === null ? GLTFUtils.GetDefaultMaterial(gltfRuntime.scene) : material);
+                let material = gltfRuntime.scene.getMaterialByID(primitive.material);
+
+                subMaterials.push(material === null ? GLTFUtils.GetDefaultMaterial(gltfRuntime.scene) : material);
 
                 // Update vertices start and index start
                 verticesStarts.push(verticesStarts.length === 0 ? 0 : verticesStarts[verticesStarts.length - 1] + verticesCounts[verticesCounts.length - 2]);
                 indexStarts.push(indexStarts.length === 0 ? 0 : indexStarts[indexStarts.length - 1] + indexCounts[indexCounts.length - 2]);
             }
         }
+        let material : StandardMaterial | MultiMaterial;
+        if (subMaterials.length > 1) {
+            material = new MultiMaterial("multimat" + id, gltfRuntime.scene);
+            (material as MultiMaterial).subMaterials = subMaterials;
+        }
+        else {
+            material = new StandardMaterial("multimat" + id, gltfRuntime.scene);
+        }
+
+        if (subMaterials.length === 1) {
+            material = (subMaterials[0] as StandardMaterial);
+        }
+
+        if (!newMesh.material) {
+            newMesh.material = material;
+        }
 
         // Apply geometry
         geometry.setAllVerticesData(vertexData, false);
@@ -785,7 +799,7 @@ module BABYLON.GLTF1 {
                 var newMesh = importMesh(gltfRuntime, node, node.meshes, id, <Mesh>node.babylonNode);
                 newMesh.skeleton = gltfRuntime.scene.getLastSkeletonByID(node.skin);
 
-                if (newMesh.skeleton === null && skin.babylonSkeleton) {
+                if (newMesh.skeleton === null) {
                     newMesh.skeleton = importSkeleton(gltfRuntime, skin, newMesh, skin.babylonSkeleton, node.skin);
 
                     if (!skin.babylonSkeleton) {
@@ -892,10 +906,10 @@ module BABYLON.GLTF1 {
                         persCamera.minZ = perspectiveCamera.znear;
                     }
 
-                    lastNode = persCamera;
-                }
-            }
-        }
+                     lastNode = persCamera;
+                 }
+             }
+         }
 
         // Empty node
         if (!node.jointName) {

+ 110 - 52
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -85,7 +85,7 @@ module BABYLON.GLTF2 {
 
         // IE 11 Compatibility.
         private static _progressEventFactory: (name: string, data: IProgressEventData) => ProgressEvent;
-        
+
         private static _createProgressEventByConstructor(name: string, data: IProgressEventData): ProgressEvent {
             return new ProgressEvent(name, data);
         }
@@ -272,22 +272,36 @@ module BABYLON.GLTF2 {
             return skeletons;
         }
 
-        private _getAnimationTargets(): any[] {
-            const targets = new Array();
-
+        private _startAnimations(): void {
             const animations = this._gltf.animations;
-            if (animations) {
-                for (const animation of animations) {
-                    targets.push(...animation.targets);
-                }
+            if (!animations) {
+                return;
             }
 
-            return targets;
-        }
-
-        private _startAnimations(): void {
-            for (const target of this._getAnimationTargets()) { 
-                this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
+            switch (this._parent.animationStartMode) {
+                case GLTFLoaderAnimationStartMode.NONE: {
+                    // do nothing
+                    break;
+                }
+                case GLTFLoaderAnimationStartMode.FIRST: {
+                    const animation = animations[0];
+                    for (const target of animation.targets) {
+                        this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
+                    }
+                    break;
+                }
+                case GLTFLoaderAnimationStartMode.ALL: {
+                    for (const animation of animations) {
+                        for (const target of animation.targets) {
+                            this._babylonScene.beginAnimation(target, 0, Number.MAX_VALUE, true);
+                        }
+                    }
+                    break;
+                }
+                default: {
+                    Tools.Error("Invalid animation start mode " + this._parent.animationStartMode);
+                    return;
+                }
             }
         }
 
@@ -306,15 +320,12 @@ module BABYLON.GLTF2 {
             switch (this._parent.coordinateSystemMode) {
                 case GLTFLoaderCoordinateSystemMode.AUTO: {
                     if (!this._babylonScene.useRightHandedSystem) {
-                        this._rootNode.babylonMesh.rotation = new Vector3(0, Math.PI, 0);
-                        this._rootNode.babylonMesh.scaling = new Vector3(1, 1, -1);
+                        this._rootNode.rotation = [0, 1, 0, 0];
+                        this._rootNode.scale = [1, 1, -1];
+                        this._loadTransform(this._rootNode);
                     }
                     break;
                 }
-                case GLTFLoaderCoordinateSystemMode.PASS_THROUGH: {
-                    // do nothing
-                    break;
-                }
                 case GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED: {
                     this._babylonScene.useRightHandedSystem = true;
                     break;
@@ -345,6 +356,7 @@ module BABYLON.GLTF2 {
                 this._traverseNodes(context, nodeIndices, node => {
                     if (nodeNames.indexOf(node.name) !== -1) {
                         filteredNodeIndices.push(node.index);
+                        node.parent = this._rootNode;
                         return false;
                     }
 
@@ -386,7 +398,7 @@ module BABYLON.GLTF2 {
                 this._loadMesh("#/meshes/" + node.mesh, node, mesh);
             }
 
-            node.babylonMesh.parent = node.parent ? node.parent.babylonMesh : null;
+            node.babylonMesh.parent = node.parent.babylonMesh;
 
             node.babylonAnimationTargets = node.babylonAnimationTargets || [];
             node.babylonAnimationTargets.push(node.babylonMesh);
@@ -397,7 +409,15 @@ module BABYLON.GLTF2 {
                     throw new Error(context + ": Failed to find skin " + node.skin);
                 }
 
-                node.babylonMesh.skeleton = this._loadSkin("#/skins/" + node.skin, skin);
+                this._loadSkinAsync("#/skins/" + node.skin, skin, () => {
+                    node.babylonMesh.skeleton = skin.babylonSkeleton;
+                    node.babylonMesh._refreshBoundingInfo(true);
+                });
+
+                node.babylonMesh.parent = this._rootNode.babylonMesh;
+                node.babylonMesh.position = Vector3.Zero();
+                node.babylonMesh.rotationQuaternion = Quaternion.Identity();
+                node.babylonMesh.scaling = Vector3.One();
             }
 
             if (node.camera != null) {
@@ -454,14 +474,10 @@ module BABYLON.GLTF2 {
                 };
             });
 
-            const multiMaterial = new MultiMaterial(node.babylonMesh.name, this._babylonScene);
-            node.babylonMesh.material = multiMaterial;
-            const subMaterials = multiMaterial.subMaterials;
-            for (let index = 0; index < primitives.length; index++) {
-                const primitive = primitives[index];
-
+            if (primitives.length === 1) {
+                const primitive = primitives[0];
                 if (primitive.material == null) {
-                    subMaterials[index] = this._getDefaultMaterial();
+                    node.babylonMesh.material = this._getDefaultMaterial();
                 }
                 else {
                     const material = GLTFLoader._GetProperty(this._gltf.materials, primitive.material);
@@ -473,11 +489,36 @@ module BABYLON.GLTF2 {
                         if (isNew && this._parent.onMaterialLoaded) {
                             this._parent.onMaterialLoaded(babylonMaterial);
                         }
-
-                        subMaterials[index] = babylonMaterial;
+                        node.babylonMesh.material = babylonMaterial;
                     });
                 }
-            };
+            }
+            else {
+                const multiMaterial = new MultiMaterial(node.babylonMesh.name, this._babylonScene);
+                node.babylonMesh.material = multiMaterial;
+                const subMaterials = multiMaterial.subMaterials;
+                for (let index = 0; index < primitives.length; index++) {
+                    const primitive = primitives[index];
+
+                    if (primitive.material == null) {
+                        subMaterials[index] = this._getDefaultMaterial();
+                    }
+                    else {
+                        const material = GLTFLoader._GetProperty(this._gltf.materials, primitive.material);
+                        if (!material) {
+                            throw new Error(context + ": Failed to find material " + primitive.material);
+                        }
+
+                        this._loadMaterial("#/materials/" + material.index, material, (babylonMaterial, isNew) => {
+                            if (isNew && this._parent.onMaterialLoaded) {
+                                this._parent.onMaterialLoaded(babylonMaterial);
+                            }
+
+                            subMaterials[index] = babylonMaterial;
+                        });
+                    }
+                };
+            }
         }
 
         private _loadAllVertexDataAsync(context: string, mesh: IGLTFMesh, onSuccess: () => void): void {
@@ -765,7 +806,7 @@ module BABYLON.GLTF2 {
                             // Tangent data for morph targets is stored as xyz delta.
                             // The vertexData.tangent is stored as xyzw.
                             // So we need to skip every fourth vertexData.tangent.
-                            for (let i = 0, j = 0; i < values.length; i++, j++) {
+                            for (let i = 0, j = 0; i < values.length; i++ , j++) {
                                 values[i] += vertexData.tangents![j];
                                 if ((i + 1) % 3 == 0) {
                                     j++;
@@ -807,12 +848,18 @@ module BABYLON.GLTF2 {
             node.babylonMesh.scaling = scaling;
         }
 
-        private _loadSkin(context: string, skin: IGLTFSkin): Skeleton {
+        private _loadSkinAsync(context: string, skin: IGLTFSkin, onSuccess: () => void): void {
+            if (skin.babylonSkeleton) {
+                onSuccess();
+                return;
+            }
+
             const skeletonId = "skeleton" + skin.index;
             skin.babylonSkeleton = new Skeleton(skin.name || skeletonId, skeletonId, this._babylonScene);
 
             if (skin.inverseBindMatrices == null) {
                 this._loadBones(context, skin, null);
+                onSuccess();
             }
             else {
                 const accessor = GLTFLoader._GetProperty(this._gltf.accessors, skin.inverseBindMatrices);
@@ -822,18 +869,14 @@ module BABYLON.GLTF2 {
 
                 this._loadAccessorAsync("#/accessors/" + accessor.index, accessor, data => {
                     this._loadBones(context, skin, <Float32Array>data);
+                    onSuccess();
                 });
             }
-
-            return skin.babylonSkeleton;
         }
 
         private _createBone(node: IGLTFNode, skin: IGLTFSkin, parent: Nullable<Bone>, localMatrix: Matrix, baseMatrix: Matrix, index: number): Bone {
             const babylonBone = new Bone(node.name || "bone" + node.index, skin.babylonSkeleton, parent, localMatrix, null, baseMatrix, index);
 
-            node.babylonBones = node.babylonBones || {};
-            node.babylonBones[skin.index] = babylonBone;
-
             node.babylonAnimationTargets = node.babylonAnimationTargets || [];
             node.babylonAnimationTargets.push(babylonBone);
 
@@ -867,7 +910,7 @@ module BABYLON.GLTF2 {
             }
 
             let babylonParentBone: Nullable<Bone> = null;
-            if (node.index !== skin.skeleton && node.parent && node.parent !== this._rootNode) {
+            if (node.parent !== this._rootNode) {
                 babylonParentBone = this._loadBone(node.parent, skin, inverseBindMatrixData, babylonBones);
                 baseMatrix.multiplyToRef(babylonParentBone.getInvertedAbsoluteTransform(), baseMatrix);
             }
@@ -886,7 +929,7 @@ module BABYLON.GLTF2 {
                     node.translation ? Vector3.FromArray(node.translation) : Vector3.Zero());
         }
 
-        private _traverseNodes(context: string, indices: number[], action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: Nullable<IGLTFNode> = null): void {
+        private _traverseNodes(context: string, indices: number[], action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): void {
             for (const index of indices) {
                 const node = GLTFLoader._GetProperty(this._gltf.nodes, index);
                 if (!node) {
@@ -897,7 +940,7 @@ module BABYLON.GLTF2 {
             }
         }
 
-        public _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: Nullable<IGLTFNode>) => boolean, parentNode: Nullable<IGLTFNode> = null): void {
+        public _traverseNode(context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): void {
             if (GLTFLoaderExtension.TraverseNode(this, context, node, action, parentNode)) {
                 return;
             }
@@ -1049,9 +1092,19 @@ module BABYLON.GLTF2 {
                     }
                 };
 
-                const keys = new Array(inputData.length);
-                for (let frameIndex = 0; frameIndex < inputData.length; frameIndex++) {
-                    keys[frameIndex] = getNextKey(frameIndex);
+                let keys: Array<any>;
+                if (inputData.length === 1) {
+                    let key = getNextKey(0);
+                    keys = [
+                        { frame: key.frame, value: key.value },
+                        { frame: key.frame + 1, value: key.value }
+                    ];
+                }
+                else {
+                    keys = new Array(inputData.length);
+                    for (let frameIndex = 0; frameIndex < inputData.length; frameIndex++) {
+                        keys[frameIndex] = getNextKey(frameIndex);
+                    }
                 }
 
                 if (targetPath === "influence") {
@@ -1296,7 +1349,7 @@ module BABYLON.GLTF2 {
             this._loaderTrackers.push(tracker);
 
             this._addLoaderPendingData(tracker);
-            
+
             action();
 
             this._removeLoaderPendingData(tracker);
@@ -1600,7 +1653,7 @@ module BABYLON.GLTF2 {
             }
         }
 
-        private static _AssignIndices(array?: Array<{index: number}>): void {
+        private static _AssignIndices(array?: Array<{ index: number }>): void {
             if (array) {
                 for (let index = 0; index < array.length; index++) {
                     array[index].index = index;
@@ -1682,11 +1735,6 @@ module BABYLON.GLTF2 {
         }
 
         private _compileMaterialAsync(babylonMaterial: Material, babylonMesh: AbstractMesh, onSuccess: () => void): void {
-            if (!this._parent.compileMaterials) {
-                onSuccess();
-                return;
-            }
-
             if (this._parent.useClipPlane) {
                 babylonMaterial.forceCompilation(babylonMesh, () => {
                     babylonMaterial.forceCompilation(babylonMesh, () => {
@@ -1718,6 +1766,9 @@ module BABYLON.GLTF2 {
                         }
                     }
                 }
+                else if (mesh.material) {
+                    remaining++;
+                }
             }
 
             if (remaining === 0) {
@@ -1737,6 +1788,13 @@ module BABYLON.GLTF2 {
                         }
                     }
                 }
+                else if (mesh.material) {
+                    this._compileMaterialAsync(mesh.material, mesh, () => {
+                        if (--remaining === 0) {
+                            onSuccess();
+                        }
+                    })
+                }
             }
         }
 

+ 2 - 2
loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts

@@ -6,7 +6,7 @@ module BABYLON.GLTF2 {
 
         public abstract get name(): string;
 
-        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: Nullable<IGLTFNode>): boolean { return false; }
+        protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean { return false; }
 
         protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean { return false; }
 
@@ -39,7 +39,7 @@ module BABYLON.GLTF2 {
 
         public static _Extensions: GLTFLoaderExtension[] = [];
 
-        public static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: Nullable<IGLTFNode>): boolean {
+        public static TraverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean {
             return this._ApplyExtensions(extension => extension._traverseNode(loader, context, node, action, parentNode));
         }
 

+ 1 - 2
loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts

@@ -232,9 +232,8 @@ module BABYLON.GLTF2 {
 
         // Runtime values
         index: number;
-        parent?: IGLTFNode;
+        parent: IGLTFNode;
         babylonMesh: Mesh;
-        babylonBones?: { [skin: number]: Bone };
         babylonAnimationTargets?: Node[];
     }
 

+ 131 - 52
loaders/src/glTF/README.md

@@ -1,17 +1,16 @@
 # Babylon.js glTF File Loader
 
-# Usage
 The glTF file loader is a SceneLoader plugin.
 
-[glTF2 Playground example](http://www.babylonjs-playground.com/#6MZV8R)
+[Simple Playground Example](http://www.babylonjs-playground.com/#2IK4U7)
 
-## Step 1 - Include the glTF File Loader
+## Setup
 
 **Full Version**
 
 This loader supports both glTF 1.0 and 2.0 and will use the correct loader based on the glTF version string.
 
-```
+```HTML
 <script src="babylon.js"></script>
 <script src="babylon.glTFFileLoader.js"></script>
 ```
@@ -20,7 +19,7 @@ This loader supports both glTF 1.0 and 2.0 and will use the correct loader based
 
 This loader supports only glTF 1.0 and will fail to load glTF 2.0.
 
-```
+```HTML
 <script src="babylon.js"></script>
 <script src="babylon.glTF1FileLoader.js"></script>
 ```
@@ -29,75 +28,155 @@ This loader supports only glTF 1.0 and will fail to load glTF 2.0.
 
 This loader supports only glTF 2.0 and will fail to load glTF 1.0.
 
-```
+```HTML
 <script src="babylon.js"></script>
 <script src="babylon.glTF2FileLoader.js"></script>
 ```
 
-## Step 2 - Call the Scene Loader
+## Loading the Scene
+The Load function loads a glTF asset into a new scene.
+```JavaScript
+BABYLON.SceneLoader.Load("./", "duck.gltf", engine, function (scene) {
+    // do something with the scene
+});
 ```
-BABYLON.SceneLoader.Load("./", "duck.gltf", engine, function (scene) { 
-   // do somethings with the scene
+
+The Append function appends a glTF file to an existing scene.
+```JavaScript
+BABYLON.SceneLoader.Append("./", "duck.gltf", scene, function (scene) {
+    // do something with the scene
 });
 ```
 
-You can also call the ImportMesh function and import specific meshes
+The ImportMesh function imports specific meshes from a glTF asset to an existing scene and returns the imported meshes and skeletons.
+```JavaScript
+// The first parameter can be set to null to load all meshes and skeletons
+BABYLON.SceneLoader.ImportMesh(["myMesh1", "myMesh2"], "./", "duck.gltf", scene, function (meshes, particleSystems, skeletons) {
+    // do something with the meshes and skeletons
+    // particleSystems are always null for glTF assets
+});
 ```
-// meshesNames can be set to "null" to load all meshes and skeletons
-BABYLON.SceneLoader.ImportMesh(["myMesh1", "myMesh2", "..."], "./", "duck.gltf", scene, function (meshes, particleSystems, skeletons) { 
-   // do somethings with the meshes, particleSystems (not handled in glTF files) and skeletons
+
+## Advanced
+
+The SceneLoader returns the glTF loader instance to enable setting properties per instance.
+
+```JavaScript
+var loader = BABYLON.SceneLoader.Load("./", "duck.gltf", engine, function (scene) {
+    // do something with the scene
 });
+
+// do something with the loader
+// loader.<option1> = <...>
+// loader.<option2> = <...>
+// loader.dispose();
 ```
 
-You can also append a glTF file to a scene. When using `SceneLoader.Append`, configure the scene to use right handed system by setting the property `useRightHandedSystem` to true. 
+#### onParsed
+Raised when the asset has been parsed. The `data.json` property stores the glTF JSON. The `data.bin` property stores the BIN chunk from a glTF binary or null if the input is not a glTF binary.
 
+```JavaScript
+loader.onParsed = function (data) {
+    // do something with the data
+};
 ```
-// glTF Files use right handed system 
-scene.useRightHandedSystem = true;
 
-// Append sample glTF model to scene
-BABYLON.SceneLoader.Append("https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/BoomBox/glTF/", "BoomBox.gltf", scene, function (scene) {
-}, null, function (scene) {
-    alert("error");
-});
+### Version 1 Only
+
+#### IncrementalLoading
+Set this property to false to disable incremental loading which delays the loader from calling the success callback until after loading the meshes and shaders. Textures always loads asynchronously. For example, the success callback can compute the bounding information of the loaded meshes when incremental loading is disabled. Defaults to true.
+
+```JavaScript
+BABYLON.GLTFFileLoader.IncrementalLoading = false;
+```
+
+#### HomogeneousCoordinates
+Set this property to true in order to work with homogeneous coordinates, available with some converters and exporters. Defaults to false.
+
+```JavaScript
+BABYLON.GLTFFileLoader.HomogeneousCoordinates = true;
+```
+
+### Version 2 Only
+
+#### coordinateSystemMode
+The coordinate system mode (AUTO, FORCE_RIGHT_HANDED). Defaults to AUTO.
+
+```JavaScript
+loader.coordinateSystemMode = BABYLON.GLTFLoaderCoordinateSystemMode.FORCE_RIGHT_HANDED;
 ```
 
-## Step 3 (V1 Only) - Optionally Specify Flags
+#### animationStartMode
+The animation start mode (NONE, FIRST, ALL). Defaults to FIRST.
 
-If you want to disable incremental loading, you can set the property `IncrementalLoading` to false.
-Then, you'll be able to be called back with all geometries and shaders loaded. Textures are always loaded asynchronously. For example, you can retrieve the real bounding infos of a mesh loaded when incremental loading is disabled.
+```JavaScript
+loader.animationStartMode = BABYLON.GLTFLoaderAnimationStartMode.NONE;
 ```
-BABYLON.GLTFFileLoader.IncrementalLoading = false; // true by default
+
+#### compileMaterials
+Set to true to compile materials before raising the success callback. Defaults to false.
+
+```JavaScript
+loader.compileMaterials = true;
+```
+
+#### useClipPlane
+Set to true to also compile materials with clip planes. Defaults to false.
+
+```JavaScript
+loader.useClipPlane = true;
 ```
 
-In order to work with homogeneous coordinates (that can be available with some converters and exporters):
+#### compileShadowGenerators
+Set to true to compile shadow generators before raising the success callback. Defaults to false.
+
+```JavaScript
+loader.compileShadowGenerators = true;
 ```
-BABYLON.GLTFFileLoader.HomogeneousCoordinates = true; // false by default
+
+#### onMeshLoaded
+Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
+
+```JavaScript
+loader.onMeshLoaded = function (mesh) {
+    // do something with the mesh
+};
 ```
 
-# Supported Features
-* Load scenes (SceneLoader.Load and SceneLoader.Append)
-* Support of ImportMesh function
-* Import geometries
-    * From binary files
-    * From base64 buffers
-* Import lights (V1 only)
-* Import cameras
-* Import and set custom shaders (V1 only)
-    * Automatically bind attributes
-    * Automatically bind matrices
-    * Set uniforms
-* Import and set animations
-* Skinning (BETA, sometimes wrong on tricky models)
-    * Skeletons
-    * Hardware skinning (shaders support)
-    * Bones import
-* Handle dummy nodes (empty nodes)
-* PBR materials (V2 only)
+#### onTextureLoaded
+Raised when the loader creates a texture 
+after parsing the glTF properties of the texture.
 
-# Future Improvements
-* Test on more geometries
-* Test on more animated models
-* Test on more skinned models
-* Improve shaders support (V1 only) (glitches with samplers can appear in particular configurations)
-* Add support for morph targets (V2 only)
+```JavaScript
+loader.onTextureLoaded = function (texture) {
+    // do something with the texture
+};
+```
+
+#### onMaterialLoaded
+Raised when the loader creates a material after parsing the glTF properties of the material.
+
+```JavaScript
+loader.onMaterialLoaded = function (material) {
+    // do something with the material
+};
+```
+
+#### onComplete
+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.
+
+```JavaScript
+loader.onComplete = function () {
+    // do something when loading is complete
+};
+```
+
+#### dispose
+Disposes the loader, releases resources during load, and cancels any outstanding requests.
+
+```JavaScript
+// Cancel loading of the current glTF asset.
+loader.dispose();
+```

+ 88 - 14
loaders/src/glTF/babylon.glTFFileLoader.ts

@@ -2,17 +2,34 @@
 
 module BABYLON {
     export enum GLTFLoaderCoordinateSystemMode {
-        // Automatically convert the glTF right-handed data to the appropriate system based on the current coordinate system mode of the scene (scene.useRightHandedSystem).
-        // NOTE: When scene.useRightHandedSystem is false, an additional transform will be added to the root to transform the data from right-handed to left-handed.
+        /**
+         * Automatically convert the glTF right-handed data to the appropriate system based on the current coordinate system mode of the scene.
+         */
         AUTO,
 
-        // The glTF right-handed data is not transformed in any form and is loaded directly.
-        PASS_THROUGH,
-
-        // Sets the useRightHandedSystem flag on the scene.
+        /**
+         * Sets the useRightHandedSystem flag on the scene.
+         */
         FORCE_RIGHT_HANDED,
     }
 
+    export enum GLTFLoaderAnimationStartMode {
+        /**
+         * No animation will start.
+         */
+        NONE,
+
+        /**
+         * The first animation will start.
+         */
+        FIRST,
+
+        /**
+         * All animations will start.
+         */
+        ALL,
+    }
+
     export interface IGLTFLoaderData {
         json: Object;
         bin: Nullable<ArrayBufferView>;
@@ -27,29 +44,76 @@ module BABYLON {
         public static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
         public static CreateGLTFLoaderV2: (parent: GLTFFileLoader) => IGLTFLoader;
 
-        // Common options
+        // #region Common options
+
+        /**
+         * Raised when the asset has been parsed.
+         * The data.json property stores the glTF JSON.
+         * The data.bin property stores the BIN chunk from a glTF binary or null if the input is not a glTF binary.
+         */
         public onParsed: (data: IGLTFLoaderData) => void;
 
-        // V1 options
-        public static HomogeneousCoordinates = false;
+        // #endregion
+
+        // #region V1 options
+
         public static IncrementalLoading = true;
 
-        // V2 options
+        public static HomogeneousCoordinates = false;
+
+        // #endregion
+
+        // #region V2 options
+
+        /**
+         * The coordinate system mode (AUTO, FORCE_RIGHT_HANDED).
+         */
         public coordinateSystemMode = GLTFLoaderCoordinateSystemMode.AUTO;
+
+        /**
+         * The animation start mode (NONE, FIRST, ALL).
+         */
+        public animationStartMode = GLTFLoaderAnimationStartMode.FIRST;
+
+        /**
+         * Set to true to compile materials before raising the success callback.
+         */
         public compileMaterials = false;
-        public compileShadowGenerators = false;
+
+        /**
+         * Set to true to also compile materials with clip planes.
+         */
         public useClipPlane = false;
+
+        /**
+         * Set to true to compile shadow generators before raising the success callback.
+         */
+        public compileShadowGenerators = false;
+
+        /**
+         * Raised when the loader creates a mesh after parsing the glTF properties of the mesh.
+         */
         public onMeshLoaded: (mesh: AbstractMesh) => void;
+
+        /**
+         * Raised when the loader creates a texture after parsing the glTF properties of the texture.
+         */
         public onTextureLoaded: (texture: BaseTexture) => void;
+
+        /**
+         * Raised when the loader creates a material after parsing the glTF properties of the material.
+         */
         public onMaterialLoaded: (material: Material) => void;
 
         /**
-         * Raised when the asset is completely loaded, just before the loader is disposed.
+         * 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 just after onSuccess.
+         * For assets without LODs, raised when the model is complete, immediately after onSuccess.
          */
         public onComplete: () => void;
 
+        // #endregion
+
         private _loader: IGLTFLoader;
 
         public name = "gltf";
@@ -59,6 +123,9 @@ module BABYLON {
             ".glb": { isBinary: true }
         };
 
+        /**
+         * Disposes the loader, releases resources during load, and cancels any outstanding requests.
+         */
         public dispose(): void {
             if (this._loader) {
                 this._loader.dispose();
@@ -253,7 +320,14 @@ module BABYLON {
         }
 
         private static _parseVersion(version: string): Nullable<{ major: number, minor: number }> {
-            const match = (version + "").match(/^(\d+)\.(\d+)$/);
+            if (version === "1.0" || version === "1.0.1") {
+                return {
+                    major: 1,
+                    minor: 0
+                };
+            }
+
+            const match = (version + "").match(/^(\d+)\.(\d+)/);
             if (!match) {
                 return null;
             }

+ 117 - 108
localDev/index.html

@@ -1,111 +1,120 @@
 <!DOCTYPE html>
 <html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-	<title>Local Development</title>
-	
-    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-	<script src="https://preview.babylonjs.com/cannon.js"></script>
-	<script src="https://preview.babylonjs.com/Oimo.js"></script>
-	<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
-	<script src="../tools/DevLoader/BabylonLoader.js"></script>
-	<script src="src/webgl-debug.js"></script>
-
-	<style>
-		html, body {
-			width: 100%;
-			height: 100%;
-			padding: 0;
-			margin: 0;
-			overflow: hidden;
-		}
-
-		#renderCanvas {
-			width: 100%;
-			height: 100%;
-		}
-
-		#fps {
-			position: absolute;
-			background-color: black;
-			border: 2px solid red;
-			text-align: center;
-			font-size: 16px;
-			color: white;
-			top: 15px;
-			right: 10px;
-			width: 60px;
-			height: 20px;
-		}
-	</style>
-</head>
-<body>
-	<div id="fps">0</div>
-	<canvas id="renderCanvas" touch-action="none"></canvas>
-	
-	<script>
-		var canvas = document.getElementById("renderCanvas");
-	//	canvas = WebGLDebugUtils.makeLostContextSimulatingCanvas(canvas);
-		var divFps = document.getElementById("fps");
-
-		// Global to simulate PG.
-		var engine = null;
-
-		// Allow querystring to navigate easily in debug in local samples.
-		var indexjs = 'src/index';
-		var sampleSearch = /sample=([0-9]+)/i;
-		var matches = null;
-		if ((matches = sampleSearch.exec(window.location)) !== null) {			
-			indexjs += '.';
-			indexjs += matches[1];
-		}
-		indexjs += '.js';
-
-		// Load the scripts + map file to allow vscode debug.
-		BABYLONDEVTOOLS.Loader
-			.require(indexjs)
-			.load(function() {
-				if (BABYLON.Engine.isSupported()) {
-					engine = new BABYLON.Engine(canvas, true, { stencil: true, disableWebGL2Support: false });
-					BABYLONDEVTOOLS.Loader.debugShortcut(engine);
-
-					// call the scene creation from the js.
-					if (typeof delayCreateScene !== "undefined") {
-						var scene = delayCreateScene();
-
-						if (scene) {
-							// Register a render loop to repeatedly render the scene
-
-							engine.runRenderLoop(function () {
-								if (scene.activeCamera) {
-									scene.render();
-								}
-								divFps.innerHTML = engine.getFps().toFixed() + " fps";
-							});
-						}
-					}
-					else {
-						var scene = createScene();
-
-						if (scene) {
-							// Register a render loop to repeatedly render the scene
-
-							engine.runRenderLoop(function () {
-								scene.render();
-								divFps.innerHTML = engine.getFps().toFixed() + " fps";
-							});
-						}
-					}
-
-					// Resize
-					window.addEventListener("resize", function () {
-						engine.resize();
-					});
-					
-				}
-				else {
-					alert('BabylonJS is not supported.')
-				}
-			});
-	</script>
-</body>
+
+    <head>
+        <title>Local Development</title>
+
+        <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
+        <script src="https://preview.babylonjs.com/cannon.js"></script>
+        <script src="https://preview.babylonjs.com/Oimo.js"></script>
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
+        <script src="../Tools/DevLoader/BabylonLoader.js"></script>
+        <script src="src/webgl-debug.js"></script>
+
+        <style>
+            html,
+            body {
+                width: 100%;
+                height: 100%;
+                padding: 0;
+                margin: 0;
+                overflow: hidden;
+            }
+
+            #renderCanvas {
+                width: 100%;
+                height: 100%;
+            }
+
+            #fps {
+                position: absolute;
+                background-color: black;
+                border: 2px solid red;
+                text-align: center;
+                font-size: 16px;
+                color: white;
+                top: 15px;
+                right: 10px;
+                width: 60px;
+                height: 20px;
+            }
+        </style>
+    </head>
+
+    <body>
+        <div id="fps">0</div>
+        <canvas id="renderCanvas" touch-action="none"></canvas>
+
+        <script>
+            var canvas = document.getElementById("renderCanvas");
+            //	canvas = WebGLDebugUtils.makeLostContextSimulatingCanvas(canvas);
+            var divFps = document.getElementById("fps");
+
+            // Global to simulate PG.
+            var engine = null;
+
+            // Allow querystring to navigate easily in debug in local samples.
+            var indexjs = 'src/index';
+            var sampleSearch = /sample=([0-9]+)/i;
+            var matches = null;
+            if ((matches = sampleSearch.exec(window.location)) !== null) {
+                indexjs += '.';
+                indexjs += matches[1];
+            }
+            indexjs += '.js';
+
+            // Load the scripts + map file to allow vscode debug.
+            BABYLONDEVTOOLS.Loader
+                .require(indexjs)
+                .load(function () {
+                    if (BABYLON.Engine.isSupported()) {
+                        if (typeof createEngine !== "undefined") {
+                            engine = createEngine();
+                        } else {
+                            engine = new BABYLON.Engine(canvas, true, { stencil: true, disableWebGL2Support: false, preserveDrawingBuffer: true });
+                        }
+
+                        BABYLONDEVTOOLS.Loader.debugShortcut(engine);
+
+                        // call the scene creation from the js.
+                        if (typeof delayCreateScene !== "undefined") {
+                            var scene = delayCreateScene();
+
+                            if (scene) {
+                                // Register a render loop to repeatedly render the scene
+
+                                engine.runRenderLoop(function () {
+                                    if (scene.activeCamera) {
+                                        scene.render();
+                                    }
+                                    divFps.innerHTML = engine.getFps().toFixed() + " fps";
+                                });
+                            }
+                        }
+                        else {
+                            var scene = createScene();
+
+                            if (scene) {
+                                // Register a render loop to repeatedly render the scene
+
+                                engine.runRenderLoop(function () {
+                                    scene.render();
+                                    divFps.innerHTML = engine.getFps().toFixed() + " fps";
+                                });
+                            }
+                        }
+
+                        // Resize
+                        window.addEventListener("resize", function () {
+                            engine.resize();
+                        });
+
+                    }
+                    else {
+                        alert('BabylonJS is not supported.')
+                    }
+                });
+        </script>
+    </body>
+
 </html>

+ 42 - 17
materialsLibrary/src/water/babylon.waterMaterial.ts

@@ -140,8 +140,8 @@ module BABYLON {
 		*/
         private _mesh: Nullable<AbstractMesh> = null;
 
-        private _refractionRTT: RenderTargetTexture;
-        private _reflectionRTT: RenderTargetTexture;
+        private _refractionRTT: Nullable<RenderTargetTexture>;
+        private _reflectionRTT: Nullable<RenderTargetTexture>;
 
         private _reflectionTransform: Matrix = Matrix.Zero();
         private _lastTime: number = 0;
@@ -151,6 +151,8 @@ module BABYLON {
 
         private _useLogarithmicDepth: boolean;
 
+        private _waitingRenderList: Nullable<string[]>;
+
         /**
 		* Constructor
 		*/
@@ -162,8 +164,8 @@ module BABYLON {
             // Create render targets
             this.getRenderTargetTextures = (): SmartArray<RenderTargetTexture> => {
                 this._renderTargets.reset();
-                this._renderTargets.push(this._reflectionRTT);
-                this._renderTargets.push(this._refractionRTT);
+                this._renderTargets.push(<RenderTargetTexture> this._reflectionRTT);
+                this._renderTargets.push(<RenderTargetTexture> this._refractionRTT);
 
                 return this._renderTargets;
             }
@@ -181,21 +183,21 @@ module BABYLON {
         }
 
         // Get / Set
-        public get refractionTexture(): RenderTargetTexture {
+        public get refractionTexture(): Nullable<RenderTargetTexture> {
             return this._refractionRTT;
         }
 
-        public get reflectionTexture(): RenderTargetTexture {
+        public get reflectionTexture(): Nullable<RenderTargetTexture> {
             return this._reflectionRTT;
         }
 
         // Methods
         public addToRenderList(node: any): void {
-            if (this._refractionRTT.renderList) {
+            if (this._refractionRTT && this._refractionRTT.renderList) {
                 this._refractionRTT.renderList.push(node);
             }
 
-            if (this._reflectionRTT.renderList) {
+            if (this._reflectionRTT && this._reflectionRTT.renderList) {
                 this._reflectionRTT.renderList.push(node);
             }
         }
@@ -203,16 +205,21 @@ module BABYLON {
         public enableRenderTargets(enable: boolean): void {
             var refreshRate = enable ? 1 : 0;
 
-            this._refractionRTT.refreshRate = refreshRate;
-            this._reflectionRTT.refreshRate = refreshRate;
+            if (this._refractionRTT) {
+                this._refractionRTT.refreshRate = refreshRate;
+            }
+
+            if (this._reflectionRTT) {
+                this._reflectionRTT.refreshRate = refreshRate;
+            }
         }
 
         public getRenderList(): Nullable<AbstractMesh[]> {
-            return this._refractionRTT.renderList;
+            return this._refractionRTT ? this._refractionRTT.renderList : [];
         }
 
         public get renderTargetsEnabled(): boolean {
-            return !(this._refractionRTT.refreshRate === 0);
+            return !(this._refractionRTT && this._refractionRTT.refreshRate === 0);
         }
 
         public needAlphaBlending(): boolean {
@@ -292,8 +299,17 @@ module BABYLON {
             // Attribs
             MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
 
+            // Configure this
             this._mesh = mesh;
 
+            if (this._waitingRenderList) {
+                for (var i = 0; i < this._waitingRenderList.length; i++) {
+                    this.addToRenderList(scene.getNodeByID(this._waitingRenderList[i]));
+                }
+
+                this._waitingRenderList = null;
+            }
+
             // Get correct effect      
             if (defines.isDirty) {
                 defines.markAsProcessed();
@@ -598,12 +614,12 @@ module BABYLON {
                 this.bumpTexture.dispose();
             }
 
-            var index = this.getScene().customRenderTargets.indexOf(this._refractionRTT);
+            var index = this.getScene().customRenderTargets.indexOf(<RenderTargetTexture> this._refractionRTT);
             if (index != -1) {
                 this.getScene().customRenderTargets.splice(index, 1);
             }
             index = -1;
-            index = this.getScene().customRenderTargets.indexOf(this._reflectionRTT);
+            index = this.getScene().customRenderTargets.indexOf(<RenderTargetTexture> this._reflectionRTT);
             if (index != -1) {
                 this.getScene().customRenderTargets.splice(index, 1);
             }
@@ -625,8 +641,14 @@ module BABYLON {
         public serialize(): any {
             var serializationObject = SerializationHelper.Serialize(this);
             serializationObject.customType = "BABYLON.WaterMaterial";
-            serializationObject.reflectionTexture.isRenderTarget = true;
-            serializationObject.refractionTexture.isRenderTarget = true;
+            
+            serializationObject.renderList = [];
+            if (this._refractionRTT && this._refractionRTT.renderList) {
+                for (var i = 0; i < this._refractionRTT.renderList.length; i++) {
+                    serializationObject.renderList.push(this._refractionRTT.renderList[i].id);
+                }
+            }
+
             return serializationObject;
         }
 
@@ -636,7 +658,10 @@ module BABYLON {
 
         // Statics
         public static Parse(source: any, scene: Scene, rootUrl: string): WaterMaterial {
-            return SerializationHelper.Parse(() => new WaterMaterial(source.name, scene), source, scene, rootUrl);
+            var mat = SerializationHelper.Parse(() => new WaterMaterial(source.name, scene), source, scene, rootUrl);
+            mat._waitingRenderList = source.renderList;
+
+            return mat;
         }
 
         public static CreateDefaultMesh(name: string, scene: Scene): Mesh {

+ 2 - 2
package.json

@@ -8,7 +8,7 @@
     ],
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "3.1.0-beta5",
+    "version": "3.1.0-rc-0",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -67,4 +67,4 @@
     "readmeFilename": "README.md",
     "_id": "babylonjs@3.1.0-alpha2",
     "_from": "babylonjs@"
-}
+}

+ 14 - 8
sandbox/index.js

@@ -1,4 +1,5 @@
 /// <reference path="../dist/preview release/babylon.d.ts" />
+/// <reference path="../dist/preview release/loaders/babylon.glTFFileLoader.d.ts" />
 
 if (BABYLON.Engine.isSupported()) {
     var canvas = document.getElementById("renderCanvas");
@@ -21,7 +22,7 @@ if (BABYLON.Engine.isSupported()) {
     var currentPluginName;
     var toExecuteAfterSceneCreation;
 
-    canvas.addEventListener("contextmenu", function(evt) {
+    canvas.addEventListener("contextmenu", function (evt) {
         evt.preventDefault();
     }, false);
 
@@ -32,14 +33,14 @@ if (BABYLON.Engine.isSupported()) {
     if (!currentHelpCounter) currentHelpCounter = 0;
 
     // Setting up some GLTF values
-    BABYLON.SceneLoader.OnPluginActivatedObservable.add(function(plugin) {
+    BABYLON.GLTFFileLoader.IncrementalLoading = false;
+    BABYLON.SceneLoader.OnPluginActivatedObservable.add(function (plugin) {
         currentPluginName = plugin.name;
 
-        if (plugin.name !== "gltf") {
-            return;
+        if (plugin.name === "gltf" && plugin instanceof BABYLON.GLTFFileLoader) {
+            plugin.animationStartMode = BABYLON.GLTFLoaderAnimationStartMode.ALL;
+            plugin.compileMaterials = true;
         }
-
-        plugin.compileMaterials = true;
     });
 
     // Resize
@@ -71,6 +72,11 @@ if (BABYLON.Engine.isSupported()) {
         // Fix for IE, otherwise it will change the default filter for files selection after first use
         htmlInput.value = "";
 
+        // removing glTF created camera
+        if (currentScene.activeCamera && currentPluginName === "gltf") {
+            currentScene.activeCamera.dispose();
+            currentScene.activeCamera = null;
+        }
         // Attach camera to canvas inputs
         if (!currentScene.activeCamera || currentScene.lights.length === 0) {
             currentScene.createDefaultCameraOrLight(true);
@@ -94,7 +100,7 @@ if (BABYLON.Engine.isSupported()) {
             currentScene.activeCamera.pinchDeltaPercentage = 0.01;
         }
 
-        currentScene.activeCamera.attachControl(canvas); 
+        currentScene.activeCamera.attachControl(canvas);
 
         // Environment
         if (currentPluginName === "gltf") {
@@ -230,7 +236,7 @@ if (BABYLON.Engine.isSupported()) {
     }
 }
 
-function sizeScene () {
+function sizeScene() {
     let divInspWrapper = document.getElementsByClassName('insp-wrapper')[0];
     if (divInspWrapper) {
         let divFooter = document.getElementsByClassName('footer')[0];

+ 1 - 1
src/Audio/babylon.sound.ts

@@ -136,7 +136,7 @@ module BABYLON {
                                         this._htmlAudioElement = new Audio(url);
                                         this._htmlAudioElement.controls = false;
                                         this._htmlAudioElement.loop = this.loop;
-                                        this._htmlAudioElement.crossOrigin = "anonymous";
+                                        Tools.SetCorsBehavior(url, this._htmlAudioElement);
                                         this._htmlAudioElement.preload = "auto";
                                         this._htmlAudioElement.addEventListener("canplaythrough", () => {
                                             this._isReadyToPlay = true;

File diff suppressed because it is too large
+ 706 - 306
src/Cameras/VR/babylon.vrExperienceHelper.ts


+ 93 - 15
src/Cameras/VR/babylon.webVRCamera.ts

@@ -37,6 +37,8 @@ module BABYLON {
         defaultLightingOnControllers?: boolean; // creating a default HemiLight only on controllers
         useCustomVRButton?: boolean; // if you don't want to use the default VR button of the helper
         customVRButton?: HTMLButtonElement; //if you'd like to provide your own button to the VRHelper
+        rayLength?: number; // to change the length of the ray for gaze/controllers.
+        defaultHeight?: number; // to change the default offset from the ground to account for user's height
     }
 
     export class WebVRFreeCamera extends FreeCamera implements PoseControlled {
@@ -50,10 +52,19 @@ module BABYLON {
 
         protected _descendants: Array<Node> = [];
 
+        // Represents device position and rotation in room space. Should only be used to help calculate babylon space values
+        private _deviceRoomPosition = Vector3.Zero();
+        private _deviceRoomRotationQuaternion = Quaternion.Identity(); 
+
+        // Represents device position and rotation in babylon space
         public devicePosition = Vector3.Zero();
-        public deviceRotationQuaternion: Quaternion;
+        public deviceRotationQuaternion = Quaternion.Identity();        
+
         public deviceScaleFactor: number = 1;
 
+        private _deviceToWorld = Matrix.Identity();
+        private _worldToDevice = Matrix.Identity();
+
         public controllers: Array<WebVRController> = [];
         public onControllersAttachedObservable = new Observable<Array<WebVRController>>();
         public onControllerMeshLoadedObservable = new Observable<WebVRController>();
@@ -64,7 +75,11 @@ module BABYLON {
 
         constructor(name: string, position: Vector3, scene: Scene, private webVROptions: WebVROptions = {}) {
             super(name, position, scene);
-
+            this._cache.position = Vector3.Zero();
+            if(webVROptions.defaultHeight){
+                this.position.y = webVROptions.defaultHeight;
+            }
+            
             this.minZ = 0.1;
 
             //legacy support - the compensation boolean was removed.
@@ -84,7 +99,6 @@ module BABYLON {
             }
 
             this.rotationQuaternion = new Quaternion();
-            this.deviceRotationQuaternion = new Quaternion();
 
             if (this.webVROptions && this.webVROptions.positionScale) {
                 this.deviceScaleFactor = this.webVROptions.positionScale;
@@ -179,9 +193,12 @@ module BABYLON {
             return this._rightController;
         };
 
+
+        
         public getForwardRay(length = 100): Ray {
             if (this.leftCamera) {
-                return super.getForwardRay(length, this.leftCamera.getWorldMatrix(), this.position.add(this.devicePosition)); // Need the actual rendered camera
+                // Use left eye to avoid computation to compute center on every call
+                return super.getForwardRay(length, this.leftCamera.getWorldMatrix(), this.leftCamera.globalPosition); // Need the actual rendered camera
             }
             else {
                 return super.getForwardRay(length);
@@ -201,16 +218,16 @@ module BABYLON {
         updateFromDevice(poseData: DevicePose) {
             if (poseData && poseData.orientation) {
                 this.rawPose = poseData;
-                this.deviceRotationQuaternion.copyFromFloats(poseData.orientation[0], poseData.orientation[1], -poseData.orientation[2], -poseData.orientation[3]);
+                this._deviceRoomRotationQuaternion.copyFromFloats(poseData.orientation[0], poseData.orientation[1], -poseData.orientation[2], -poseData.orientation[3]);
 
                 if (this.getScene().useRightHandedSystem) {
-                    this.deviceRotationQuaternion.z *= -1;
-                    this.deviceRotationQuaternion.w *= -1;
+                    this._deviceRoomRotationQuaternion.z *= -1;
+                    this._deviceRoomRotationQuaternion.w *= -1;
                 }
                 if (this.webVROptions.trackPosition && this.rawPose.position) {
-                    this.devicePosition.copyFromFloats(this.rawPose.position[0], this.rawPose.position[1], -this.rawPose.position[2]);
+                    this._deviceRoomPosition.copyFromFloats(this.rawPose.position[0], this.rawPose.position[1], -this.rawPose.position[2]);
                     if (this.getScene().useRightHandedSystem) {
-                        this.devicePosition.z *= -1;
+                        this._deviceRoomPosition.z *= -1;
                     }
                 }
             }
@@ -260,11 +277,60 @@ module BABYLON {
         public _updateRigCameras() {
             var camLeft = <TargetCamera>this._rigCameras[0];
             var camRight = <TargetCamera>this._rigCameras[1];
-            camLeft.rotationQuaternion.copyFrom(this.deviceRotationQuaternion);
-            camRight.rotationQuaternion.copyFrom(this.deviceRotationQuaternion);
+            camLeft.rotationQuaternion.copyFrom(this._deviceRoomRotationQuaternion);
+            camRight.rotationQuaternion.copyFrom(this._deviceRoomRotationQuaternion);
 
-            camLeft.position.copyFrom(this.devicePosition);
-            camRight.position.copyFrom(this.devicePosition);
+            camLeft.position.copyFrom(this._deviceRoomPosition);
+            camRight.position.copyFrom(this._deviceRoomPosition);
+        }
+
+        private _workingVector = Vector3.Zero();
+        private _oneVector = Vector3.One();
+        private _workingMatrix = Matrix.Identity();
+        public _updateCache(ignoreParentClass?: boolean): void {
+            if(!this.rotationQuaternion.equals(this._cache.rotationQuaternion) || !this.position.equals(this._cache.position)){
+                // Set working vector to the device position in room space rotated by the new rotation
+                this.rotationQuaternion.toRotationMatrix(this._workingMatrix);
+                Vector3.TransformCoordinatesToRef(this._deviceRoomPosition, this._workingMatrix, this._workingVector);
+
+                // Subtract this vector from the current device position in world to get the translation for the device world matrix
+                this.devicePosition.subtractToRef(this._workingVector, this._workingVector)
+                Matrix.ComposeToRef(this._oneVector, this.rotationQuaternion, this._workingVector, this._deviceToWorld);             
+                
+                // Add translation from anchor position
+                this._deviceToWorld.getTranslationToRef(this._workingVector)
+                this._workingVector.addInPlace(this.position);
+                this._workingVector.subtractInPlace(this._cache.position)
+                this._deviceToWorld.setTranslation(this._workingVector)
+
+                // Set an inverted matrix to be used when updating the camera
+                this._deviceToWorld.invertToRef(this._worldToDevice)
+                
+                // Update the gamepad to ensure the mesh is updated on the same frame as camera
+                this.controllers.forEach((controller)=>{
+                    controller._deviceToWorld = this._deviceToWorld;
+                    controller.update();
+                })
+                this.update();
+            }
+
+            if (!ignoreParentClass) {
+                super._updateCache();
+            }
+        }
+        public update() {
+            // Get current device position in babylon world
+            Vector3.TransformCoordinatesToRef(this._deviceRoomPosition, this._deviceToWorld, this.devicePosition);
+            
+            // Get current device rotation in babylon world
+            Matrix.FromQuaternionToRef(this._deviceRoomRotationQuaternion, this._workingMatrix);
+            this._deviceToWorld.multiplyToRef(this._workingMatrix, this._workingMatrix);
+            Quaternion.FromRotationMatrixToRef(this._workingMatrix, this.deviceRotationQuaternion);
+
+            super.update();
+        }
+        public _getViewMatrix(): Matrix {
+            return Matrix.Identity();
         }
 
         /**
@@ -304,7 +370,8 @@ module BABYLON {
 
                 this._webvrViewMatrix.invert();
             }
-
+            
+            parentCamera._worldToDevice.multiplyToRef(this._webvrViewMatrix, this._webvrViewMatrix);
             return this._webvrViewMatrix;
         }
 
@@ -342,13 +409,24 @@ module BABYLON {
                     if (webVrController.defaultModel) {
                         webVrController.defaultModel.setEnabled(false);
                     }
+
+                    if(webVrController.hand === "right"){
+                        this._rightController = null;
+                    }
+                    if(webVrController.hand === "left"){
+                        this._rightController = null;
+                    }
+                    const controllerIndex = this.controllers.indexOf(webVrController);
+                    if (controllerIndex !== -1) {
+                        this.controllers.splice(controllerIndex, 1);
+                    }
                 }
             });
 
             this._onGamepadConnectedObserver = manager.onGamepadConnectedObservable.add((gamepad) => {
                 if (gamepad.type === BABYLON.Gamepad.POSE_ENABLED) {
                     let webVrController: WebVRController = <WebVRController>gamepad;
-
+                    webVrController._deviceToWorld = this._deviceToWorld;
                     if (this.webVROptions.controllerMeshes) {
                         if (webVrController.defaultModel) {
                             webVrController.defaultModel.setEnabled(true);

+ 4 - 0
src/Cameras/babylon.camera.ts

@@ -907,6 +907,10 @@
             }
         }
 
+        public computeWorldMatrix(): Matrix {
+            return this.getWorldMatrix();
+        }
+
         public static Parse(parsedCamera: any, scene: Scene): Camera {
             var type = parsedCamera.type;
             var construct = Camera.GetConstructorFromName(type, parsedCamera.name, scene, parsedCamera.interaxial_distance, parsedCamera.isStereoscopicSideBySide);

+ 14 - 17
src/Cameras/babylon.targetCamera.ts

@@ -25,7 +25,7 @@
         private _rigCamTransformMatrix: Matrix;
 
         public _referencePoint = new Vector3(0, 0, 1);
-        private _defaultUpVector = new Vector3(0, 1, 0);
+        private _currentUpVector = new Vector3(0, 1, 0);
         public _transformedReferencePoint = Vector3.Zero();
         public _lookAtTemp = Matrix.Zero();
         public _tempMatrix = Matrix.Zero();
@@ -148,7 +148,7 @@
         public setTarget(target: Vector3): void {
             this.upVector.normalize();
 
-            Matrix.LookAtLHToRef(this.position, target, this._defaultUpVector, this._camMatrix);
+            Matrix.LookAtLHToRef(this.position, target, this.upVector, this._camMatrix);
             this._camMatrix.invert();
 
             this.rotation.x = Math.atan(this._camMatrix.m[6] / this._camMatrix.m[10]);
@@ -271,31 +271,28 @@
             } else {
                 Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
             }
+
             //update the up vector!
-            BABYLON.Vector3.TransformNormalToRef(this._defaultUpVector, this._cameraRotationMatrix, this.upVector);
+            BABYLON.Vector3.TransformNormalToRef(this.upVector, this._cameraRotationMatrix, this._currentUpVector);
         }
 
         public _getViewMatrix(): Matrix {
-            if (!this.lockedTarget) {
-                // Compute
-                this._updateCameraRotationMatrix();
+            if (this.lockedTarget) {
+                this.setTarget(this._getLockedTargetPosition()!);
+            }
 
-                Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
+            // Compute
+            this._updateCameraRotationMatrix();
 
-                // Computing target and final matrix
-                this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
-            } else {
-                let targetPosition = this._getLockedTargetPosition();
+            Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
 
-                if (targetPosition) {
-                    this._currentTarget.copyFrom(targetPosition);
-                }
-            }
+            // Computing target and final matrix
+            this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
 
             if (this.getScene().useRightHandedSystem) {
-                Matrix.LookAtRHToRef(this.position, this._currentTarget, this.upVector, this._viewMatrix);
+                Matrix.LookAtRHToRef(this.position, this._currentTarget, this._currentUpVector, this._viewMatrix);
             } else {
-                Matrix.LookAtLHToRef(this.position, this._currentTarget, this.upVector, this._viewMatrix);
+                Matrix.LookAtLHToRef(this.position, this._currentTarget, this._currentUpVector, this._viewMatrix);
             }
 
             return this._viewMatrix;

+ 10 - 5
src/Engine/babylon.engine.ts

@@ -298,6 +298,7 @@
         deterministicLockstep?: boolean;
         lockstepMaxSteps?: number;
         doNotHandleContextLost?: boolean;
+        constantAnimationDeltaTime?: number;
     }
 
     export interface IDisplayChangedEventArgs {
@@ -563,7 +564,7 @@
         }
 
         public static get Version(): string {
-            return "3.1-beta-6";
+            return "3.1-rc-0";
         }
 
         // Updatable statics so stick with vars here
@@ -3225,18 +3226,21 @@
             return internalFormat;
         }
 
-        public updateRawTexture(texture: Nullable<InternalTexture>, data: Nullable<ArrayBufferView>, format: number, invertY: boolean, compression: Nullable<string> = null): void {
+        public updateRawTexture(texture: Nullable<InternalTexture>, data: Nullable<ArrayBufferView>, format: number, invertY: boolean, compression: Nullable<string> = null, type = Engine.TEXTURETYPE_UNSIGNED_INT): void {
             if (!texture) {
                 return;
             }
 
             var internalFormat = this._getInternalFormat(format);
+            var internalSizedFomat = this._getRGBABufferInternalSizedFormat(type);
+            var textureType = this._getWebGLTextureType(type);
             this._bindTextureDirectly(this._gl.TEXTURE_2D, texture);
             this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, invertY === undefined ? 1 : (invertY ? 1 : 0));
 
             if (!this._doNotHandleContextLost) {
                 texture._bufferView = data;
                 texture.format = format;
+                texture.type = type;
                 texture.invertY = invertY;
                 texture._compression = compression;
             }
@@ -3248,7 +3252,7 @@
             if (compression && data) {
                 this._gl.compressedTexImage2D(this._gl.TEXTURE_2D, 0, (<any>this.getCaps().s3tc)[compression], texture.width, texture.height, 0, data);
             } else {
-                this._gl.texImage2D(this._gl.TEXTURE_2D, 0, internalFormat, texture.width, texture.height, 0, internalFormat, this._gl.UNSIGNED_BYTE, data);
+                this._gl.texImage2D(this._gl.TEXTURE_2D, 0, internalSizedFomat, texture.width, texture.height, 0, internalFormat, textureType, data);
             }
 
             if (texture.generateMipMaps) {
@@ -3259,7 +3263,7 @@
             texture.isReady = true;
         }
 
-        public createRawTexture(data: Nullable<ArrayBufferView>, width: number, height: number, format: number, generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression: Nullable<string> = null): InternalTexture {
+        public createRawTexture(data: Nullable<ArrayBufferView>, width: number, height: number, format: number, generateMipMaps: boolean, invertY: boolean, samplingMode: number, compression: Nullable<string> = null, type: number = BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT): InternalTexture {
             var texture = new InternalTexture(this, InternalTexture.DATASOURCE_RAW);
             texture.baseWidth = width;
             texture.baseHeight = height;
@@ -3270,12 +3274,13 @@
             texture.samplingMode = samplingMode;
             texture.invertY = invertY;
             texture._compression = compression;
+            texture.type = type;
 
             if (!this._doNotHandleContextLost) {
                 texture._bufferView = data;
             }
 
-            this.updateRawTexture(texture, data, format, invertY, compression);
+            this.updateRawTexture(texture, data, format, invertY, compression, type);
             this._bindTextureDirectly(this._gl.TEXTURE_2D, texture);
 
             // Filters

+ 27 - 15
src/Gamepad/Controllers/babylon.poseEnabledController.ts

@@ -41,8 +41,14 @@ module BABYLON {
     }
 
     export class PoseEnabledController extends Gamepad implements PoseControlled {
-        devicePosition: Vector3;
-        deviceRotationQuaternion: Quaternion;
+        // Represents device position and rotation in room space. Should only be used to help calculate babylon space values
+        private _deviceRoomPosition = Vector3.Zero();
+        private _deviceRoomRotationQuaternion = new Quaternion();
+
+        // Represents device position and rotation in babylon space
+        public devicePosition = Vector3.Zero();
+        public deviceRotationQuaternion = new Quaternion();
+
         deviceScaleFactor: number = 1;
 
         public position: Vector3;
@@ -59,29 +65,35 @@ module BABYLON {
 
         private _leftHandSystemQuaternion: Quaternion = new Quaternion();
         
+        public _deviceToWorld = Matrix.Identity();
+
         constructor(browserGamepad: any) {
             super(browserGamepad.id, browserGamepad.index, browserGamepad);
             this.type = Gamepad.POSE_ENABLED;
             this.controllerType = PoseEnabledControllerType.GENERIC;
             this.position = Vector3.Zero();
             this.rotationQuaternion = new Quaternion();
-            this.devicePosition = Vector3.Zero();
-            this.deviceRotationQuaternion = new Quaternion();
 
             this._calculatedPosition = Vector3.Zero();
             this._calculatedRotation = new Quaternion();
             Quaternion.RotationYawPitchRollToRef(Math.PI, 0, 0, this._leftHandSystemQuaternion);
         }
 
+        private _workingMatrix = Matrix.Identity();
         public update() {
             super.update();
             var pose: GamepadPose = this.browserGamepad.pose;
             this.updateFromDevice(pose);
-            
+
+            Vector3.TransformCoordinatesToRef(this._calculatedPosition, this._deviceToWorld, this.devicePosition)
+            this._deviceToWorld.getRotationMatrixToRef(this._workingMatrix);
+            Quaternion.FromRotationMatrixToRef(this._workingMatrix, this.deviceRotationQuaternion);
+
             if (this._mesh) {
-                this._mesh.position.copyFrom(this._calculatedPosition);
+                this._mesh.position.copyFrom(this.devicePosition);
+
                 if (this._mesh.rotationQuaternion) {
-                    this._mesh.rotationQuaternion.copyFrom(this._calculatedRotation);
+                    this._mesh.rotationQuaternion.copyFrom(this.deviceRotationQuaternion.multiplyInPlace(this._calculatedRotation));
                 }
             }
         }
@@ -90,29 +102,29 @@ module BABYLON {
             if (poseData) {
                 this.rawPose = poseData;
                 if (poseData.position) {
-                    this.devicePosition.copyFromFloats(poseData.position[0], poseData.position[1], -poseData.position[2]);
+                    this._deviceRoomPosition.copyFromFloats(poseData.position[0], poseData.position[1], -poseData.position[2]);
                     if (this._mesh && this._mesh.getScene().useRightHandedSystem) {
-                        this.devicePosition.z *= -1;
+                        this._deviceRoomPosition.z *= -1;
                     }
 
-                    this.devicePosition.scaleToRef(this.deviceScaleFactor, this._calculatedPosition);
+                    this._deviceRoomPosition.scaleToRef(this.deviceScaleFactor, this._calculatedPosition);
                     this._calculatedPosition.addInPlace(this.position);
 
                 }
                 let pose = this.rawPose;
                 if (poseData.orientation && pose.orientation) {
-                    this.deviceRotationQuaternion.copyFromFloats(pose.orientation[0], pose.orientation[1], -pose.orientation[2], -pose.orientation[3]);
+                    this._deviceRoomRotationQuaternion.copyFromFloats(pose.orientation[0], pose.orientation[1], -pose.orientation[2], -pose.orientation[3]);
                     if (this._mesh) {
                         if (this._mesh.getScene().useRightHandedSystem) {
-                            this.deviceRotationQuaternion.z *= -1;
-                            this.deviceRotationQuaternion.w *= -1;
+                            this._deviceRoomRotationQuaternion.z *= -1;
+                            this._deviceRoomRotationQuaternion.w *= -1;
                         } else {
-                            this.deviceRotationQuaternion.multiplyToRef(this._leftHandSystemQuaternion, this.deviceRotationQuaternion);
+                            this._deviceRoomRotationQuaternion.multiplyToRef(this._leftHandSystemQuaternion, this._deviceRoomRotationQuaternion);
                         }
                     }
 
                     // if the camera is set, rotate to the camera's rotation
-                    this.deviceRotationQuaternion.multiplyToRef(this.rotationQuaternion, this._calculatedRotation);
+                    this._deviceRoomRotationQuaternion.multiplyToRef(this.rotationQuaternion, this._calculatedRotation);
                 }
             }
         }

+ 11 - 0
src/Gamepad/Controllers/babylon.windowsMotionController.ts

@@ -66,6 +66,8 @@ module BABYLON {
         };
 
         public onTrackpadChangedObservable = new Observable<ExtendedGamepadButton>();
+        public onTrackpadValuesChangedObservable = new Observable<StickValues>();
+        public trackpad: StickValues = { x: 0, y: 0 };
 
         constructor(vrGamepad: any) {
             super(vrGamepad);
@@ -92,6 +94,10 @@ module BABYLON {
         public get onTouchpadButtonStateChangedObservable(): Observable<ExtendedGamepadButton> {
             return this.onTrackpadChangedObservable;
         }
+
+        public get onTouchpadValuesChangedObservable(): Observable<StickValues> {
+            return this.onTrackpadValuesChangedObservable;
+        }
         
         /**
          * Called once per frame by the engine.
@@ -102,6 +108,11 @@ module BABYLON {
             // Only need to animate axes if there is a loaded mesh
             if (this._loadedMeshInfo) {
                 if (this.browserGamepad.axes) {
+                    if(this.browserGamepad.axes[2] != this.trackpad.x || this.browserGamepad.axes[3] != this.trackpad.y){
+                        this.trackpad.x = this.browserGamepad["axes"][2];
+                        this.trackpad.y = this.browserGamepad["axes"][3];
+                        this.onTrackpadValuesChangedObservable.notifyObservers(this.trackpad);
+                    }
                     for (let axis = 0; axis < this._mapping.axisMeshNames.length; axis++) {
                         this.lerpAxisTransform(axis, this.browserGamepad.axes[axis]);
                     }

+ 0 - 0
src/Gamepad/babylon.gamepadManager.ts


Some files were not shown because too many files changed in this diff