浏览代码

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js

noalak 8 年之前
父节点
当前提交
5c63a8500e
共有 100 个文件被更改,包括 50401 次插入28443 次删除
  1. 2 0
      Playground/indexStable.html
  2. 0 158
      Playground/js/perf.js
  3. 0 77
      Playground/perf.html
  4. 21 11
      Tools/Gulp/config.json
  5. 1465 1384
      dist/preview release/babylon.d.ts
  6. 47 47
      dist/preview release/babylon.js
  7. 711 332
      dist/preview release/babylon.max.js
  8. 1465 1384
      dist/preview release/babylon.module.d.ts
  9. 47 47
      dist/preview release/babylon.worker.js
  10. 3660 3579
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  11. 51 37
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  12. 37756 17519
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  13. 3660 3579
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts
  14. 69 3
      dist/preview release/gui/babylon.gui.d.ts
  15. 378 14
      dist/preview release/gui/babylon.gui.js
  16. 3 3
      dist/preview release/gui/babylon.gui.min.js
  17. 69 3
      dist/preview release/gui/babylon.gui.module.d.ts
  18. 2 1
      dist/preview release/materialsLibrary/babylon.cellMaterial.js
  19. 1 1
      dist/preview release/materialsLibrary/babylon.cellMaterial.min.js
  20. 2 1
      dist/preview release/materialsLibrary/babylon.fireMaterial.js
  21. 1 1
      dist/preview release/materialsLibrary/babylon.fireMaterial.min.js
  22. 2 1
      dist/preview release/materialsLibrary/babylon.furMaterial.js
  23. 1 1
      dist/preview release/materialsLibrary/babylon.furMaterial.min.js
  24. 2 1
      dist/preview release/materialsLibrary/babylon.gradientMaterial.js
  25. 1 1
      dist/preview release/materialsLibrary/babylon.gradientMaterial.min.js
  26. 2 1
      dist/preview release/materialsLibrary/babylon.lavaMaterial.js
  27. 1 1
      dist/preview release/materialsLibrary/babylon.lavaMaterial.min.js
  28. 2 1
      dist/preview release/materialsLibrary/babylon.normalMaterial.js
  29. 1 1
      dist/preview release/materialsLibrary/babylon.normalMaterial.min.js
  30. 2 1
      dist/preview release/materialsLibrary/babylon.simpleMaterial.js
  31. 1 1
      dist/preview release/materialsLibrary/babylon.simpleMaterial.min.js
  32. 2 1
      dist/preview release/materialsLibrary/babylon.terrainMaterial.js
  33. 1 1
      dist/preview release/materialsLibrary/babylon.terrainMaterial.min.js
  34. 2 1
      dist/preview release/materialsLibrary/babylon.triPlanarMaterial.js
  35. 1 1
      dist/preview release/materialsLibrary/babylon.triPlanarMaterial.min.js
  36. 1 0
      dist/preview release/materialsLibrary/babylon.waterMaterial.js
  37. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  38. 6 3
      dist/preview release/what's new.md
  39. 58 7
      gui/src/advancedDynamicTexture.ts
  40. 10 0
      gui/src/controls/container.ts
  41. 11 0
      gui/src/controls/control.ts
  42. 216 11
      gui/src/controls/inputText.ts
  43. 136 0
      gui/src/controls/virtualKeyboard.ts
  44. 0 1
      loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts
  45. 48 48
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  46. 3 3
      loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts
  47. 5 4
      localDev/index.html
  48. 1 0
      materialsLibrary/src/cell/babylon.cellMaterial.ts
  49. 2 0
      materialsLibrary/src/cell/cell.fragment.fx
  50. 1 0
      materialsLibrary/src/fire/babylon.fireMaterial.ts
  51. 2 0
      materialsLibrary/src/fire/fire.fragment.fx
  52. 1 0
      materialsLibrary/src/fur/babylon.furMaterial.ts
  53. 2 0
      materialsLibrary/src/fur/fur.fragment.fx
  54. 1 0
      materialsLibrary/src/gradient/babylon.gradientMaterial.ts
  55. 2 0
      materialsLibrary/src/gradient/gradient.fragment.fx
  56. 1 0
      materialsLibrary/src/lava/babylon.lavaMaterial.ts
  57. 2 0
      materialsLibrary/src/lava/lava.fragment.fx
  58. 1 0
      materialsLibrary/src/normal/babylon.normalMaterial.ts
  59. 2 0
      materialsLibrary/src/normal/normal.fragment.fx
  60. 1 0
      materialsLibrary/src/simple/babylon.simpleMaterial.ts
  61. 2 0
      materialsLibrary/src/simple/simple.fragment.fx
  62. 1 0
      materialsLibrary/src/terrain/babylon.terrainMaterial.ts
  63. 2 0
      materialsLibrary/src/terrain/terrain.fragment.fx
  64. 1 0
      materialsLibrary/src/triPlanar/babylon.triPlanarMaterial.ts
  65. 2 0
      materialsLibrary/src/triPlanar/triplanar.fragment.fx
  66. 1 0
      materialsLibrary/src/water/babylon.waterMaterial.ts
  67. 3 2
      src/Animations/babylon.animation.ts
  68. 7 5
      src/Behaviors/Cameras/babylon.framingBehavior.ts
  69. 57 78
      src/Cameras/Inputs/babylon.arcRotateCameraKeyboardMoveInput.ts
  70. 39 8
      src/Cameras/Inputs/babylon.arcRotateCameraPointersInput.ts
  71. 28 28
      src/Cameras/Inputs/babylon.freeCameraKeyboardMoveInput.ts
  72. 11 3
      src/Cameras/VR/babylon.webVRCamera.ts
  73. 22 4
      src/Cameras/babylon.arcRotateCamera.ts
  74. 16 2
      src/Cameras/babylon.camera.ts
  75. 4 4
      src/Cameras/babylon.freeCamera.ts
  76. 2 2
      src/Cameras/babylon.targetCamera.ts
  77. 5 5
      src/Collisions/babylon.collisionCoordinator.ts
  78. 33 0
      src/Events/babylon.keyboardEvents.ts
  79. 69 0
      src/Events/babylon.pointerEvents.ts
  80. 11 1
      src/Layer/babylon.highlightlayer.ts
  81. 11 1
      src/Lights/Shadows/babylon.shadowGenerator.ts
  82. 1 0
      src/Materials/PBR/babylon.pbrBaseMaterial.ts
  83. 2 0
      src/Materials/Textures/babylon.mirrorTexture.ts
  84. 16 0
      src/Materials/Textures/babylon.multiRenderTarget.ts
  85. 1 1
      src/Materials/Textures/babylon.renderTargetTexture.ts
  86. 6 2
      src/Materials/babylon.effect.ts
  87. 3 0
      src/Materials/babylon.material.ts
  88. 5 0
      src/Materials/babylon.materialHelper.ts
  89. 20 0
      src/Materials/babylon.standardMaterial.ts
  90. 2 2
      src/Mesh/babylon.abstractMesh.ts
  91. 3 1
      src/PostProcess/RenderPipeline/Pipelines/babylon.defaultRenderingPipeline.ts
  92. 1 1
      src/PostProcess/RenderPipeline/Pipelines/babylon.ssao2RenderingPipeline.ts
  93. 2 3
      src/PostProcess/RenderPipeline/Pipelines/babylon.standardRenderingPipeline.ts
  94. 11 1
      src/PostProcess/babylon.postProcess.ts
  95. 9 1
      src/PostProcess/babylon.volumetricLightScatteringPostProcess.ts
  96. 1 1
      src/PostProcess/babylon.vrDistortionCorrectionPostProcess.ts
  97. 9 1
      src/Rendering/babylon.depthRenderer.ts
  98. 12 2
      src/Rendering/babylon.geometryBufferRenderer.ts
  99. 25 11
      src/Rendering/babylon.outlineRenderer.ts
  100. 0 0
      src/Rendering/babylon.renderingGroup.ts

+ 2 - 0
Playground/indexStable.html

@@ -45,6 +45,8 @@
     <script src="https://cdn.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
     <script src="https://cdn.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
     <script src="https://cdn.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
     <script src="https://cdn.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
 
 
+    <script src="https://cdn.babylonjs.com/gui/babylon.gui.min.js"></script>    
+
     <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
     <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>
     <link href="css/index.css" rel="stylesheet" />
     <link href="css/index.css" rel="stylesheet" />
 </head>
 </head>

+ 0 - 158
Playground/js/perf.js

@@ -1,158 +0,0 @@
-(function () {
-    var snippetUrl = "https://babylonjs-api2.azurewebsites.net/snippets";
-    var currentSnippetToken;
-    var engine;
-    var scripts;
-    var zipCode;
-    BABYLON.Engine.ShadersRepository = "/src/Shaders/";
-    var loadScript = function (scriptURL, title) {
-        var xhr = new XMLHttpRequest();
-
-        xhr.open('GET', scriptURL, true);
-
-        xhr.onreadystatechange = function () {
-            if (xhr.readyState === 4) {
-                if (xhr.status === 200) {
-                    blockEditorChange = true;
-                    console.log(xhr.responseText);
-                    jsEditor.setValue(xhr.responseText);
-                    jsEditor.setPosition({ lineNumber: 0, column: 0 });
-                    blockEditorChange = false;
-                    compileAndRun();
-
-                    document.getElementById("currentScript").innerHTML = title;
-
-                    currentSnippetToken = null;
-                }
-            }
-        };
-
-        xhr.send(null);
-    };
-
-    var showError = function(error) {
-        console.warn(error);
-    };
-
-    compileAndRun = function (code) {
-        try {
-
-            if (!BABYLON.Engine.isSupported()) {
-                showError("Your browser does not support WebGL");
-                return;
-            }
-
-            if (engine) {
-                engine.dispose();
-                engine = null;
-            }
-
-            var canvas = document.getElementById("renderCanvas");
-            engine = new BABYLON.Engine(canvas, true, {stencil: true});
-            engine.renderEvenInBackground = false;
-            BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault = true;
-
-            engine.runRenderLoop(function () {
-                if (engine.scenes.length === 0) {
-                    return;
-                }
-
-                if (canvas.width !== canvas.clientWidth) {
-                    engine.resize();
-                }
-
-                var scene = engine.scenes[0];
-
-                if (scene.activeCamera || scene.activeCameras.length > 0) {
-                    scene.render();
-                }
-            });
-
-            var scene;
-            if (code.indexOf("createScene") !== -1) { // createScene
-                eval(code);
-                scene = createScene();
-                if (!scene) {
-                    showError("createScene function must return a scene.");
-                    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;
-                }
-
-                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;
-                }
-
-                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);
-
-                zipCode = "var scene = new BABYLON.Scene(engine);\r\n\r\n" + code;
-            }
-
-        } catch (e) {
-            // showError(e.message);
-        }
-    };
-    window.addEventListener("resize", function () {
-        if (engine) {
-            engine.resize();
-        }
-    });
-
-    // UI
-
-    var cleanHash = function () {
-        var splits = decodeURIComponent(location.hash.substr(1)).split("#");
-
-        if (splits.length > 2) {
-            splits.splice(2, splits.length - 2);
-        }
-
-        location.hash = splits.join("#");
-    };
-
-    var checkHash = function () {
-        if (location.hash) {
-            cleanHash();
-
-            try {
-                var xmlHttp = new XMLHttpRequest();
-                xmlHttp.onreadystatechange = function () {
-                    if (xmlHttp.readyState === 4) {
-                        if (xmlHttp.status === 200) {
-                            var snippetCode = JSON.parse(JSON.parse(xmlHttp.responseText)[0].jsonPayload).code;
-                            compileAndRun(snippetCode);
-                        }
-                    }
-                };
-
-                var hash = location.hash.substr(1);
-                currentSnippetToken = hash.split("#")[0];
-                if(!hash.split("#")[1]) hash += "#0";
-
-                xmlHttp.open("GET", snippetUrl + "/" + hash.replace("#", "/"));
-                xmlHttp.send();
-            } catch (e) {
-
-            }
-        }
-    };
-
-    checkHash();
-
-})();

+ 0 - 77
Playground/perf.html

@@ -1,77 +0,0 @@
-<!DOCTYPE html>
-<html>
-
-<head>
-    <title>Babylon.js Playground</title>
-    <link rel="shortcut icon" href="https://www.babylonjs.com/img/favicon/favicon.ico">
-	<link rel="apple-touch-icon" sizes="57x57" href="https://www.babylonjs.com/img/favicon/apple-icon-57x57.png">
-	<link rel="apple-touch-icon" sizes="60x60" href="https://www.babylonjs.com/img/favicon/apple-icon-60x60.png">
-	<link rel="apple-touch-icon" sizes="72x72" href="https://www.babylonjs.com/img/favicon/apple-icon-72x72.png">
-	<link rel="apple-touch-icon" sizes="76x76" href="https://www.babylonjs.com/img/favicon/apple-icon-76x76.png">
-	<link rel="apple-touch-icon" sizes="114x114" href="https://www.babylonjs.com/img/favicon/apple-icon-114x114.png">
-	<link rel="apple-touch-icon" sizes="120x120" href="https://www.babylonjs.com/img/favicon/apple-icon-120x120.png">
-	<link rel="apple-touch-icon" sizes="144x144" href="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png">
-	<link rel="apple-touch-icon" sizes="152x152" href="https://www.babylonjs.com/img/favicon/apple-icon-152x152.png">
-	<link rel="apple-touch-icon" sizes="180x180" href="https://www.babylonjs.com/img/favicon/apple-icon-180x180.png">
-	<link rel="icon" type="image/png" sizes="192x192"  href="https://www.babylonjs.com/img/favicon/android-icon-192x192.png">
-	<link rel="icon" type="image/png" sizes="32x32" href="https://www.babylonjs.com/img/favicon/favicon-32x32.png">
-	<link rel="icon" type="image/png" sizes="96x96" href="https://www.babylonjs.com/img/favicon/favicon-96x96.png">
-	<link rel="icon" type="image/png" sizes="16x16" href="https://www.babylonjs.com/img/favicon/favicon-16x16.png">
-	<link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
-	<meta name="msapplication-TileColor" content="#ffffff">
-	<meta name="msapplication-TileImage" content="https://www.babylonjs.com/img/favicon/ms-icon-144x144.png">
-	<meta name="msapplication-config" content="https://www.babylonjs.com/img/favicon/browserconfig.xml">
-	<meta name="theme-color" content="#ffffff">
-
-    <script src="https://code.jquery.com/pep/0.4.2/pep.min.js"></script>
-    <!-- Babylon.js -->
-    <script src="https://preview.babylonjs.com/cannon.js"></script>
-    <script src="https://preview.babylonjs.com/Oimo.js"></script>
-    <script src="https://preview.babylonjs.com/babylon.js"></script>    
-    <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
-
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.fireMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.waterMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.lavaMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.normalMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.skyMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.triPlanarMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.terrainMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gradientMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.furMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.gridMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.shadowOnlyMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.customMaterial.min.js"></script>
-    <script src="https://preview.babylonjs.com/materialsLibrary/babylon.cellMaterial.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.brickProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.cloudProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.fireProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.grassProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.marbleProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.roadProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.starfieldProceduralTexture.min.js"></script>
-    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylon.woodProceduralTexture.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.asciiArtPostProcess.min.js"></script>
-    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylon.digitalRainPostProcess.min.js"></script>
-
-    <script src="https://preview.babylonjs.com/loaders/babylon.glTFFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.objFileLoader.js"></script>
-    <script src="https://preview.babylonjs.com/loaders/babylon.stlFileLoader.js"></script>
-
-    <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
-    
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/ClonerSystem/src/babylonx.cloner.js"></script>    
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/canvas2D/dist/preview%20release/babylon.canvas2d.min.js"></script>
-    <script src="https://rawgit.com/BabylonJS/Extensions/master/CompoundShader/src/babylonx.CompoundShader.js"></script>
-    <link href="frame.css" rel="stylesheet" />
-</head>
-
-<body>
-    <canvas touch-action="none" id="renderCanvas"></canvas>
-    <script src="https://code.jquery.com/jquery.js"></script>
-    <script src="/js/perf.js"></script>
-</body>
-
-</html>

+ 21 - 11
Tools/Gulp/config.json

@@ -27,16 +27,19 @@
         "minimal": ["standardMaterial", "freeCamera", "hemisphericLight"],
         "minimal": ["standardMaterial", "freeCamera", "hemisphericLight"],
         "minimalWithBuilder": ["meshBuilder", "standardMaterial", "freeCamera", "hemisphericLight"],
         "minimalWithBuilder": ["meshBuilder", "standardMaterial", "freeCamera", "hemisphericLight"],
         "minimalGLTFViewer": [
         "minimalGLTFViewer": [
-                "animations", "arcRotateCamera", "additionalTextures", "textureFormats",
-                "shadows", "pointLight", "directionalLight", "spotLight",
-                "multiMaterial", "pbrMaterial",
-                "meshBuilder", "layer",
-                "additionalPostProcess_blur", "additionalPostProcess_fxaa", "additionalPostProcess_highlights", 
-                "additionalPostProcess_imageProcessing", "colorCurves", "defaultRenderingPipeline", "imageProcessing",
-                "debug", "textureTools", "hdr",
-                "loader",
+                "standardMaterial", "pbrMaterial", "freeCamera", "arcRotateCamera", "hemisphericLight", 
+                "pointLight", "directionalLight", "spotLight", "animations", "actions", "sprites", "picking", "collisions",
+                "particles", "solidParticles", "additionalMeshes", "meshBuilder", "audio", "additionalTextures", "shadows",
+                "loader", "userData", "offline", "fresnel", "multiMaterial", "touchCamera", "procedural", "gamepad",
+                "additionalCameras", "postProcesses", "renderingPipeline", "additionalRenderingPipeline", "defaultRenderingPipeline",
+                "depthRenderer", "geometryBufferRenderer", "additionalPostProcesses",
+                "additionalPostProcess_blur", "additionalPostProcess_fxaa", "additionalPostProcess_imageProcessing",
+                "bones", "hdr", "polygonMesh", "csg", "lensFlares", "physics", "textureFormats", "debug", "morphTargets",
+                "colorCurves", "octrees", "simd", "vr", "virtualJoystick", "optimizations", "highlights", "assetsManager",
+                "mapTexture", "dynamicFloatArray",
+                "imageProcessing", "serialization", "probes", "layer", "textureTools", "cameraBehaviors",
                 "materialsLibrary/babylon.gridMaterial.js",
                 "materialsLibrary/babylon.gridMaterial.js",
-                "loaders/babylon.glTFFileLoader.js", "cameraBehaviors", "morphTargets"
+                "loaders/babylon.glTFFileLoader.js"
         ],
         ],
         "distributed": ["minimalGLTFViewer"]
         "distributed": ["minimalGLTFViewer"]
     },
     },
@@ -45,6 +48,8 @@
         "core" :
         "core" :
         {
         {
             "files":[
             "files":[
+                "../../src/Events/babylon.keyboardEvents.js",
+                "../../src/Events/babylon.pointerEvents.js",
                 "../../src/Math/babylon.math.js",
                 "../../src/Math/babylon.math.js",
                 "../../src/Math/babylon.math.scalar.js",
                 "../../src/Math/babylon.math.scalar.js",
                 "../../src/babylon.mixins.js",
                 "../../src/babylon.mixins.js",
@@ -82,6 +87,9 @@
                 "../../src/Mesh/babylon.geometry.js",
                 "../../src/Mesh/babylon.geometry.js",
                 "../../src/PostProcess/babylon.postProcessManager.js",
                 "../../src/PostProcess/babylon.postProcessManager.js",
                 "../../src/Tools/babylon.performanceMonitor.js"
                 "../../src/Tools/babylon.performanceMonitor.js"
+            ],
+            "shaderIncludes": [
+                "depthPrePass"
             ]
             ]
         },         
         },         
         "particles" : 
         "particles" : 
@@ -585,10 +593,11 @@
                 "geometry.fragment"
                 "geometry.fragment"
             ],
             ],
             "shaderIncludes": [
             "shaderIncludes": [
+                "mrtFragmentDeclaration",
                 "bones300Declaration",
                 "bones300Declaration",
                 "instances300Declaration",
                 "instances300Declaration",
                 "instancesVertex",
                 "instancesVertex",
-                "bonesVertex"
+                "bonesVertex"               
             ]
             ]
         },
         },
         "postProcesses" : 
         "postProcesses" : 
@@ -1439,7 +1448,8 @@
                     "../../gui/src/controls/image.ts",
                     "../../gui/src/controls/image.ts",
                     "../../gui/src/controls/button.ts",
                     "../../gui/src/controls/button.ts",
                     "../../gui/src/controls/colorPicker.ts",
                     "../../gui/src/controls/colorPicker.ts",
-                    "../../gui/src/controls/inputText.ts"
+                    "../../gui/src/controls/inputText.ts",
+                    "../../gui/src/controls/virtualKeyboard.ts"
                 ],
                 ],
                 "output": "babylon.gui.js",
                 "output": "babylon.gui.js",
                 "buildAsModule": "true",
                 "buildAsModule": "true",

文件差异内容过多而无法显示
+ 1465 - 1384
dist/preview release/babylon.d.ts


文件差异内容过多而无法显示
+ 47 - 47
dist/preview release/babylon.js


文件差异内容过多而无法显示
+ 711 - 332
dist/preview release/babylon.max.js


文件差异内容过多而无法显示
+ 1465 - 1384
dist/preview release/babylon.module.d.ts


文件差异内容过多而无法显示
+ 47 - 47
dist/preview release/babylon.worker.js


文件差异内容过多而无法显示
+ 3660 - 3579
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


文件差异内容过多而无法显示
+ 51 - 37
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


文件差异内容过多而无法显示
+ 37756 - 17519
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


文件差异内容过多而无法显示
+ 3660 - 3579
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts


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

@@ -1,14 +1,21 @@
 
 
 declare module BABYLON.GUI {
 declare module BABYLON.GUI {
+    interface IFocusableControl {
+        onFocus(): void;
+        onBlur(): void;
+        processKeyboard(evt: KeyboardEvent): void;
+    }
     class AdvancedDynamicTexture extends DynamicTexture {
     class AdvancedDynamicTexture extends DynamicTexture {
         private _isDirty;
         private _isDirty;
         private _renderObserver;
         private _renderObserver;
         private _resizeObserver;
         private _resizeObserver;
+        private _preKeyboardObserver;
         private _pointerMoveObserver;
         private _pointerMoveObserver;
         private _pointerObserver;
         private _pointerObserver;
-        private _canvasBlurObserver;
+        private _canvasPointerOutObserver;
         private _background;
         private _background;
         _rootContainer: Container;
         _rootContainer: Container;
+        _lastPickedControl: Control;
         _lastControlOver: Control;
         _lastControlOver: Control;
         _lastControlDown: Control;
         _lastControlDown: Control;
         _capturingControl: Control;
         _capturingControl: Control;
@@ -20,12 +27,14 @@ declare module BABYLON.GUI {
         private _idealWidth;
         private _idealWidth;
         private _idealHeight;
         private _idealHeight;
         private _renderAtIdealSize;
         private _renderAtIdealSize;
+        private _focusedControl;
         background: string;
         background: string;
         idealWidth: number;
         idealWidth: number;
         idealHeight: number;
         idealHeight: number;
         renderAtIdealSize: boolean;
         renderAtIdealSize: boolean;
         readonly layer: Layer;
         readonly layer: Layer;
         readonly rootContainer: Container;
         readonly rootContainer: Container;
+        focusedControl: IFocusableControl;
         constructor(name: string, width: number, height: number, scene: Scene, generateMipMaps?: boolean, samplingMode?: number);
         constructor(name: string, width: number, height: number, scene: Scene, generateMipMaps?: boolean, samplingMode?: number);
         executeOnAllControls(func: (control: Control) => void, container?: Container): void;
         executeOnAllControls(func: (control: Control) => void, container?: Container): void;
         markAsDirty(): void;
         markAsDirty(): void;
@@ -39,7 +48,7 @@ declare module BABYLON.GUI {
         private _doPicking(x, y, type);
         private _doPicking(x, y, type);
         attach(): void;
         attach(): void;
         attachToMesh(mesh: AbstractMesh, supportPointerMove?: boolean): void;
         attachToMesh(mesh: AbstractMesh, supportPointerMove?: boolean): void;
-        private _attachToOnBlur(scene);
+        private _attachToOnPointerOut(scene);
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean): AdvancedDynamicTexture;
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean): AdvancedDynamicTexture;
         static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Scene): AdvancedDynamicTexture;
         static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Scene): AdvancedDynamicTexture;
     }
     }
@@ -159,6 +168,7 @@ declare module BABYLON.GUI {
         private _doNotRender;
         private _doNotRender;
         isHitTestVisible: boolean;
         isHitTestVisible: boolean;
         isPointerBlocker: boolean;
         isPointerBlocker: boolean;
+        isFocusInvisible: boolean;
         protected _linkOffsetX: ValueAndUnit;
         protected _linkOffsetX: ValueAndUnit;
         protected _linkOffsetY: ValueAndUnit;
         protected _linkOffsetY: ValueAndUnit;
         readonly typeName: string;
         readonly typeName: string;
@@ -249,6 +259,7 @@ declare module BABYLON.GUI {
         forcePointerUp(): void;
         forcePointerUp(): void;
         _processObservables(type: number, x: number, y: number): boolean;
         _processObservables(type: number, x: number, y: number): boolean;
         private _prepareFont();
         private _prepareFont();
+        dispose(): void;
         private static _HORIZONTAL_ALIGNMENT_LEFT;
         private static _HORIZONTAL_ALIGNMENT_LEFT;
         private static _HORIZONTAL_ALIGNMENT_RIGHT;
         private static _HORIZONTAL_ALIGNMENT_RIGHT;
         private static _HORIZONTAL_ALIGNMENT_CENTER;
         private static _HORIZONTAL_ALIGNMENT_CENTER;
@@ -300,6 +311,7 @@ declare module BABYLON.GUI {
         _processPicking(x: number, y: number, type: number): boolean;
         _processPicking(x: number, y: number, type: number): boolean;
         protected _clipForChildren(context: CanvasRenderingContext2D): void;
         protected _clipForChildren(context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        dispose(): void;
     }
     }
 }
 }
 
 
@@ -584,22 +596,76 @@ declare module BABYLON.GUI {
 
 
 
 
 declare module BABYLON.GUI {
 declare module BABYLON.GUI {
-    class InputText extends Control {
+    class InputText extends Control implements IFocusableControl {
         name: string;
         name: string;
         private _text;
         private _text;
         private _background;
         private _background;
+        private _focusedBackground;
         private _thickness;
         private _thickness;
         private _margin;
         private _margin;
         private _autoStretchWidth;
         private _autoStretchWidth;
         private _maxWidth;
         private _maxWidth;
+        private _isFocused;
+        private _blinkTimeout;
+        private _blinkIsEven;
+        private _cursorOffset;
+        private _scrollLeft;
+        promptMessage: string;
+        onTextChangedObservable: Observable<InputText>;
+        onFocusObservable: Observable<InputText>;
+        onBlurObservable: Observable<InputText>;
         maxWidth: string | number;
         maxWidth: string | number;
         margin: string;
         margin: string;
         autoStretchWidth: boolean;
         autoStretchWidth: boolean;
         thickness: number;
         thickness: number;
+        focusedBackground: string;
         background: string;
         background: string;
         text: string;
         text: string;
         constructor(name?: string, text?: string);
         constructor(name?: string, text?: string);
+        onBlur(): void;
+        onFocus(): void;
         protected _getTypeName(): string;
         protected _getTypeName(): string;
+        processKey(keyCode: number, key?: string): void;
+        processKeyboard(evt: KeyboardEvent): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        protected _onPointerDown(coordinates: Vector2): boolean;
+        protected _onPointerUp(coordinates: Vector2): void;
+        dispose(): void;
+    }
+}
+
+
+declare module BABYLON.GUI {
+    class KeyPropertySet {
+        width?: string;
+        height?: string;
+        paddingLeft?: string;
+        paddingRight?: string;
+        paddingTop?: string;
+        paddingBottom?: string;
+        color?: string;
+        background?: string;
+    }
+    class VirtualKeyboard extends StackPanel {
+        onKeyPressObservable: Observable<string>;
+        defaultButtonWidth: string;
+        defaultButtonHeight: string;
+        defaultButtonPaddingLeft: string;
+        defaultButtonPaddingRight: string;
+        defaultButtonPaddingTop: string;
+        defaultButtonPaddingBottom: string;
+        defaultButtonColor: string;
+        defaultButtonBackground: string;
+        protected _getTypeName(): string;
+        private _createKey(key, propertySet?);
+        addKeysRow(keys: Array<string>, propertySets?: Array<KeyPropertySet>): void;
+        private _connectedInputText;
+        private _onFocusObserver;
+        private _onBlurObserver;
+        private _onKeyPressObserver;
+        readonly connectedInputText: InputText;
+        connect(input: InputText): void;
+        disconnect(): void;
+        static CreateDefaultLayout(): VirtualKeyboard;
     }
     }
 }
 }

+ 378 - 14
dist/preview release/gui/babylon.gui.js

@@ -30,6 +30,15 @@ var BABYLON;
                 _this._idealHeight = 0;
                 _this._idealHeight = 0;
                 _this._renderAtIdealSize = false;
                 _this._renderAtIdealSize = false;
                 _this._renderObserver = _this.getScene().onBeforeCameraRenderObservable.add(function (camera) { return _this._checkUpdate(camera); });
                 _this._renderObserver = _this.getScene().onBeforeCameraRenderObservable.add(function (camera) { return _this._checkUpdate(camera); });
+                _this._preKeyboardObserver = _this.getScene().onPreKeyboardObservable.add(function (info) {
+                    if (!_this._focusedControl) {
+                        return;
+                    }
+                    if (info.type === BABYLON.KeyboardEventTypes.KEYDOWN) {
+                        _this._focusedControl.processKeyboard(info.event);
+                    }
+                    info.skipOnPointerObservable = true;
+                });
                 _this._rootContainer._link(null, _this);
                 _this._rootContainer._link(null, _this);
                 _this.hasAlpha = true;
                 _this.hasAlpha = true;
                 if (!width || !height) {
                 if (!width || !height) {
@@ -111,6 +120,25 @@ var BABYLON;
                 enumerable: true,
                 enumerable: true,
                 configurable: true
                 configurable: true
             });
             });
+            Object.defineProperty(AdvancedDynamicTexture.prototype, "focusedControl", {
+                get: function () {
+                    return this._focusedControl;
+                },
+                set: function (control) {
+                    if (this._focusedControl === control) {
+                        return;
+                    }
+                    if (!this._focusedControl) {
+                        control.onFocus();
+                    }
+                    else {
+                        this._focusedControl.onBlur();
+                    }
+                    this._focusedControl = control;
+                },
+                enumerable: true,
+                configurable: true
+            });
             AdvancedDynamicTexture.prototype.executeOnAllControls = function (func, container) {
             AdvancedDynamicTexture.prototype.executeOnAllControls = function (func, container) {
                 if (!container) {
                 if (!container) {
                     container = this._rootContainer;
                     container = this._rootContainer;
@@ -146,14 +174,15 @@ var BABYLON;
                 if (this._pointerObserver) {
                 if (this._pointerObserver) {
                     this.getScene().onPointerObservable.remove(this._pointerObserver);
                     this.getScene().onPointerObservable.remove(this._pointerObserver);
                 }
                 }
-                if (this._canvasBlurObserver) {
-                    this.getScene().getEngine().onCanvasBlurObservable.remove(this._canvasBlurObserver);
+                if (this._canvasPointerOutObserver) {
+                    this.getScene().getEngine().onCanvasPointerOutObservable.remove(this._canvasPointerOutObserver);
                 }
                 }
                 if (this._layerToDispose) {
                 if (this._layerToDispose) {
                     this._layerToDispose.texture = null;
                     this._layerToDispose.texture = null;
                     this._layerToDispose.dispose();
                     this._layerToDispose.dispose();
                     this._layerToDispose = null;
                     this._layerToDispose = null;
                 }
                 }
+                this._rootContainer.dispose();
                 _super.prototype.dispose.call(this);
                 _super.prototype.dispose.call(this);
             };
             };
             AdvancedDynamicTexture.prototype._onResize = function () {
             AdvancedDynamicTexture.prototype._onResize = function () {
@@ -262,6 +291,15 @@ var BABYLON;
                         this._lastControlOver = null;
                         this._lastControlOver = null;
                     }
                     }
                 }
                 }
+                // Focus management
+                if (this._focusedControl) {
+                    if (this._focusedControl !== this._lastPickedControl) {
+                        if (this._lastPickedControl.isFocusInvisible) {
+                            return;
+                        }
+                        this.focusedControl = null;
+                    }
+                }
             };
             };
             AdvancedDynamicTexture.prototype.attach = function () {
             AdvancedDynamicTexture.prototype.attach = function () {
                 var _this = this;
                 var _this = this;
@@ -281,7 +319,7 @@ var BABYLON;
                     _this._doPicking(x, y, pi.type);
                     _this._doPicking(x, y, pi.type);
                     pi.skipOnPointerObservable = _this._shouldBlockPointer && pi.type !== BABYLON.PointerEventTypes.POINTERUP;
                     pi.skipOnPointerObservable = _this._shouldBlockPointer && pi.type !== BABYLON.PointerEventTypes.POINTERUP;
                 });
                 });
-                this._attachToOnBlur(scene);
+                this._attachToOnPointerOut(scene);
             };
             };
             AdvancedDynamicTexture.prototype.attachToMesh = function (mesh, supportPointerMove) {
             AdvancedDynamicTexture.prototype.attachToMesh = function (mesh, supportPointerMove) {
                 var _this = this;
                 var _this = this;
@@ -312,11 +350,11 @@ var BABYLON;
                     }
                     }
                 });
                 });
                 mesh.enablePointerMoveEvents = supportPointerMove;
                 mesh.enablePointerMoveEvents = supportPointerMove;
-                this._attachToOnBlur(scene);
+                this._attachToOnPointerOut(scene);
             };
             };
-            AdvancedDynamicTexture.prototype._attachToOnBlur = function (scene) {
+            AdvancedDynamicTexture.prototype._attachToOnPointerOut = function (scene) {
                 var _this = this;
                 var _this = this;
-                this._canvasBlurObserver = scene.getEngine().onCanvasBlurObservable.add(function () {
+                this._canvasPointerOutObserver = scene.getEngine().onCanvasPointerOutObservable.add(function () {
                     if (_this._lastControlOver) {
                     if (_this._lastControlOver) {
                         _this._lastControlOver._onPointerOut();
                         _this._lastControlOver._onPointerOut();
                     }
                     }
@@ -692,6 +730,7 @@ var BABYLON;
                 this._doNotRender = false;
                 this._doNotRender = false;
                 this.isHitTestVisible = true;
                 this.isHitTestVisible = true;
                 this.isPointerBlocker = false;
                 this.isPointerBlocker = false;
+                this.isFocusInvisible = false;
                 this._linkOffsetX = new GUI.ValueAndUnit(0);
                 this._linkOffsetX = new GUI.ValueAndUnit(0);
                 this._linkOffsetY = new GUI.ValueAndUnit(0);
                 this._linkOffsetY = new GUI.ValueAndUnit(0);
                 /**
                 /**
@@ -1429,6 +1468,7 @@ var BABYLON;
                 if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
                 if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
                     this._onPointerDown(this._dummyVector2);
                     this._onPointerDown(this._dummyVector2);
                     this._host._lastControlDown = this;
                     this._host._lastControlDown = this;
+                    this._host._lastPickedControl = this;
                     return true;
                     return true;
                 }
                 }
                 if (type === BABYLON.PointerEventTypes.POINTERUP) {
                 if (type === BABYLON.PointerEventTypes.POINTERUP) {
@@ -1447,6 +1487,14 @@ var BABYLON;
                 this._font = this._fontSize.getValue(this._host) + "px " + this._fontFamily;
                 this._font = this._fontSize.getValue(this._host) + "px " + this._fontFamily;
                 this._fontOffset = Control._GetFontOffset(this._font);
                 this._fontOffset = Control._GetFontOffset(this._font);
             };
             };
+            Control.prototype.dispose = function () {
+                this.onDirtyObservable.clear();
+                this.onPointerDownObservable.clear();
+                this.onPointerEnterObservable.clear();
+                this.onPointerMoveObservable.clear();
+                this.onPointerOutObservable.clear();
+                this.onPointerUpObservable.clear();
+            };
             Object.defineProperty(Control, "HORIZONTAL_ALIGNMENT_LEFT", {
             Object.defineProperty(Control, "HORIZONTAL_ALIGNMENT_LEFT", {
                 get: function () {
                 get: function () {
                     return Control._HORIZONTAL_ALIGNMENT_LEFT;
                     return Control._HORIZONTAL_ALIGNMENT_LEFT;
@@ -1646,6 +1694,7 @@ var BABYLON;
                     return this;
                     return this;
                 }
                 }
                 control._link(this, this._host);
                 control._link(this, this._host);
+                control._markAllAsDirty();
                 this._reOrderControl(control);
                 this._reOrderControl(control);
                 this._markAsDirty();
                 this._markAsDirty();
                 return this;
                 return this;
@@ -1735,6 +1784,13 @@ var BABYLON;
                 _super.prototype._additionalProcessing.call(this, parentMeasure, context);
                 _super.prototype._additionalProcessing.call(this, parentMeasure, context);
                 this._measureForChildren.copyFrom(this._currentMeasure);
                 this._measureForChildren.copyFrom(this._currentMeasure);
             };
             };
+            Container.prototype.dispose = function () {
+                _super.prototype.dispose.call(this);
+                for (var _i = 0, _a = this._children; _i < _a.length; _i++) {
+                    var control = _a[_i];
+                    control.dispose();
+                }
+            };
             return Container;
             return Container;
         }(GUI.Control));
         }(GUI.Control));
         GUI.Container = Container;
         GUI.Container = Container;
@@ -3719,10 +3775,18 @@ var BABYLON;
                 _this.name = name;
                 _this.name = name;
                 _this._text = "";
                 _this._text = "";
                 _this._background = "black";
                 _this._background = "black";
+                _this._focusedBackground = "black";
                 _this._thickness = 1;
                 _this._thickness = 1;
                 _this._margin = new GUI.ValueAndUnit(10, GUI.ValueAndUnit.UNITMODE_PIXEL);
                 _this._margin = new GUI.ValueAndUnit(10, GUI.ValueAndUnit.UNITMODE_PIXEL);
                 _this._autoStretchWidth = true;
                 _this._autoStretchWidth = true;
                 _this._maxWidth = new GUI.ValueAndUnit(1, GUI.ValueAndUnit.UNITMODE_PERCENTAGE, false);
                 _this._maxWidth = new GUI.ValueAndUnit(1, GUI.ValueAndUnit.UNITMODE_PERCENTAGE, false);
+                _this._isFocused = false;
+                _this._blinkIsEven = false;
+                _this._cursorOffset = 0;
+                _this.promptMessage = "Please enter text:";
+                _this.onTextChangedObservable = new BABYLON.Observable();
+                _this.onFocusObservable = new BABYLON.Observable();
+                _this.onBlurObservable = new BABYLON.Observable();
                 _this.text = text;
                 _this.text = text;
                 return _this;
                 return _this;
             }
             }
@@ -3784,6 +3848,20 @@ var BABYLON;
                 enumerable: true,
                 enumerable: true,
                 configurable: true
                 configurable: true
             });
             });
+            Object.defineProperty(InputText.prototype, "focusedBackground", {
+                get: function () {
+                    return this._focusedBackground;
+                },
+                set: function (value) {
+                    if (this._focusedBackground === value) {
+                        return;
+                    }
+                    this._focusedBackground = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
             Object.defineProperty(InputText.prototype, "background", {
             Object.defineProperty(InputText.prototype, "background", {
                 get: function () {
                 get: function () {
                     return this._background;
                     return this._background;
@@ -3808,33 +3886,178 @@ var BABYLON;
                     }
                     }
                     this._text = value;
                     this._text = value;
                     this._markAsDirty();
                     this._markAsDirty();
+                    this.onTextChangedObservable.notifyObservers(this);
                 },
                 },
                 enumerable: true,
                 enumerable: true,
                 configurable: true
                 configurable: true
             });
             });
+            InputText.prototype.onBlur = function () {
+                this._isFocused = false;
+                this._scrollLeft = null;
+                this._cursorOffset = 0;
+                clearTimeout(this._blinkTimeout);
+                this._markAsDirty();
+                this.onBlurObservable.notifyObservers(this);
+            };
+            InputText.prototype.onFocus = function () {
+                this._scrollLeft = null;
+                this._isFocused = true;
+                this._blinkIsEven = false;
+                this._cursorOffset = 0;
+                this._markAsDirty();
+                this.onFocusObservable.notifyObservers(this);
+                if (navigator.userAgent.indexOf("Mobile") !== -1) {
+                    this.text = prompt(this.promptMessage);
+                    this._host.focusedControl = null;
+                    return;
+                }
+            };
             InputText.prototype._getTypeName = function () {
             InputText.prototype._getTypeName = function () {
                 return "InputText";
                 return "InputText";
             };
             };
+            InputText.prototype.processKey = function (keyCode, key) {
+                // Specific cases
+                switch (keyCode) {
+                    case 8:// BACKSPACE
+                        if (this._text && this._text.length > 0) {
+                            if (this._cursorOffset === 0) {
+                                this.text = this._text.substr(0, this._text.length - 1);
+                            }
+                            else {
+                                var deletePosition = this._text.length - this._cursorOffset;
+                                if (deletePosition > 0) {
+                                    this.text = this._text.slice(0, deletePosition - 1) + this._text.slice(deletePosition);
+                                }
+                            }
+                        }
+                        return;
+                    case 46:// DELETE
+                        if (this._text && this._text.length > 0) {
+                            var deletePosition = this._text.length - this._cursorOffset;
+                            this.text = this._text.slice(0, deletePosition) + this._text.slice(deletePosition + 1);
+                            this._cursorOffset--;
+                        }
+                        return;
+                    case 13:// RETURN
+                        this._host.focusedControl = null;
+                        return;
+                    case 35:// END
+                        this._cursorOffset = 0;
+                        this._blinkIsEven = false;
+                        this._markAsDirty();
+                        return;
+                    case 36:// HOME
+                        this._cursorOffset = this._text.length;
+                        this._blinkIsEven = false;
+                        this._markAsDirty();
+                        return;
+                    case 37:// LEFT
+                        this._cursorOffset++;
+                        if (this._cursorOffset > this._text.length) {
+                            this._cursorOffset = this._text.length;
+                        }
+                        this._blinkIsEven = false;
+                        this._markAsDirty();
+                        return;
+                    case 39:// RIGHT
+                        this._cursorOffset--;
+                        if (this._cursorOffset < 0) {
+                            this._cursorOffset = 0;
+                        }
+                        this._blinkIsEven = false;
+                        this._markAsDirty();
+                        return;
+                }
+                // Printable characters
+                if ((keyCode === -1) ||
+                    (keyCode === 32) ||
+                    (keyCode > 47 && keyCode < 58) ||
+                    (keyCode > 64 && keyCode < 91) ||
+                    (keyCode > 185 && keyCode < 193) ||
+                    (keyCode > 218 && keyCode < 223) ||
+                    (keyCode > 95 && keyCode < 112)) {
+                    if (this._cursorOffset === 0) {
+                        this.text += key;
+                    }
+                    else {
+                        var insertPosition = this._text.length - this._cursorOffset;
+                        this.text = this._text.slice(0, insertPosition) + key + this._text.slice(insertPosition);
+                    }
+                }
+            };
+            InputText.prototype.processKeyboard = function (evt) {
+                this.processKey(evt.keyCode, evt.key);
+            };
             InputText.prototype._draw = function (parentMeasure, context) {
             InputText.prototype._draw = function (parentMeasure, context) {
+                var _this = this;
                 context.save();
                 context.save();
                 this._applyStates(context);
                 this._applyStates(context);
                 if (this._processMeasures(parentMeasure, context)) {
                 if (this._processMeasures(parentMeasure, context)) {
                     // Background
                     // Background
-                    if (this._background) {
+                    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.fillStyle = this._background;
                         context.fillRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
                         context.fillRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
                     }
                     }
+                    if (!this._fontOffset) {
+                        this._fontOffset = GUI.Control._GetFontOffset(context.font);
+                    }
                     // Text
                     // Text
-                    if (this._text) {
-                        if (this.color) {
-                            context.fillStyle = this.color;
+                    var clipTextLeft = this._currentMeasure.left + this._margin.getValueInPixel(this._host, parentMeasure.width);
+                    if (this.color) {
+                        context.fillStyle = this.color;
+                    }
+                    var textWidth = context.measureText(this._text).width;
+                    var marginWidth = this._margin.getValueInPixel(this._host, parentMeasure.width) * 2;
+                    if (this._autoStretchWidth) {
+                        this.width = Math.min(this._maxWidth.getValueInPixel(this._host, parentMeasure.width), textWidth + marginWidth) + "px";
+                    }
+                    var rootY = this._fontOffset.ascent + (this._currentMeasure.height - this._fontOffset.height) / 2;
+                    var availableWidth = this._width.getValueInPixel(this._host, parentMeasure.width) - marginWidth;
+                    context.save();
+                    context.beginPath();
+                    context.rect(clipTextLeft, this._currentMeasure.top + (this._currentMeasure.height - this._fontOffset.height) / 2, availableWidth + 2, this._currentMeasure.height);
+                    context.clip();
+                    if (this._isFocused && textWidth > availableWidth) {
+                        var textLeft = clipTextLeft - textWidth + availableWidth;
+                        if (!this._scrollLeft) {
+                            this._scrollLeft = textLeft;
                         }
                         }
-                        var rootY = this._fontOffset.ascent + (this._currentMeasure.height - this._fontOffset.height) / 2;
-                        context.fillText(this._text, this._currentMeasure.left + this._margin.getValueInPixel(this._host, parentMeasure.width), this._currentMeasure.top + rootY);
-                        if (this._autoStretchWidth) {
-                            this.width = Math.min(this._maxWidth.getValueInPixel(this._host, parentMeasure.width), context.measureText(this._text).width + this._margin.getValueInPixel(this._host, parentMeasure.width) * 2) + "px";
+                    }
+                    else {
+                        this._scrollLeft = clipTextLeft;
+                    }
+                    context.fillText(this._text, this._scrollLeft, this._currentMeasure.top + rootY);
+                    // Cursor
+                    if (this._isFocused) {
+                        if (!this._blinkIsEven) {
+                            var cursorOffsetText = this.text.substr(this._text.length - this._cursorOffset);
+                            var cursorOffsetWidth = context.measureText(cursorOffsetText).width;
+                            var cursorLeft = this._scrollLeft + textWidth - cursorOffsetWidth;
+                            if (cursorLeft < clipTextLeft) {
+                                this._scrollLeft += (clipTextLeft - cursorLeft);
+                                cursorLeft = clipTextLeft;
+                                this._markAsDirty();
+                            }
+                            else if (cursorLeft > clipTextLeft + availableWidth) {
+                                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);
                         }
                         }
+                        clearTimeout(this._blinkTimeout);
+                        this._blinkTimeout = setTimeout(function () {
+                            _this._blinkIsEven = !_this._blinkIsEven;
+                            _this._markAsDirty();
+                        }, 500);
                     }
                     }
+                    context.restore();
                     // Border
                     // Border
                     if (this._thickness) {
                     if (this._thickness) {
                         if (this.color) {
                         if (this.color) {
@@ -3846,8 +4069,149 @@ var BABYLON;
                 }
                 }
                 context.restore();
                 context.restore();
             };
             };
+            InputText.prototype._onPointerDown = function (coordinates) {
+                if (!_super.prototype._onPointerDown.call(this, coordinates)) {
+                    return false;
+                }
+                this._host.focusedControl = this;
+                return true;
+            };
+            InputText.prototype._onPointerUp = function (coordinates) {
+                _super.prototype._onPointerUp.call(this, coordinates);
+            };
+            InputText.prototype.dispose = function () {
+                _super.prototype.dispose.call(this);
+                this.onBlurObservable.clear();
+                this.onFocusObservable.clear();
+                this.onTextChangedObservable.clear();
+            };
             return InputText;
             return InputText;
         }(GUI.Control));
         }(GUI.Control));
         GUI.InputText = InputText;
         GUI.InputText = InputText;
     })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
     })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
 })(BABYLON || (BABYLON = {}));
 })(BABYLON || (BABYLON = {}));
+
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+var BABYLON;
+(function (BABYLON) {
+    var GUI;
+    (function (GUI) {
+        var KeyPropertySet = (function () {
+            function KeyPropertySet() {
+            }
+            return KeyPropertySet;
+        }());
+        GUI.KeyPropertySet = KeyPropertySet;
+        var VirtualKeyboard = (function (_super) {
+            __extends(VirtualKeyboard, _super);
+            function VirtualKeyboard() {
+                var _this = _super !== null && _super.apply(this, arguments) || this;
+                _this.onKeyPressObservable = new BABYLON.Observable();
+                _this.defaultButtonWidth = "40px";
+                _this.defaultButtonHeight = "40px";
+                _this.defaultButtonPaddingLeft = "2px";
+                _this.defaultButtonPaddingRight = "2px";
+                _this.defaultButtonPaddingTop = "2px";
+                _this.defaultButtonPaddingBottom = "2px";
+                _this.defaultButtonColor = "#DDD";
+                _this.defaultButtonBackground = "#070707";
+                return _this;
+            }
+            VirtualKeyboard.prototype._getTypeName = function () {
+                return "VirtualKeyboard";
+            };
+            VirtualKeyboard.prototype._createKey = function (key, propertySet) {
+                var _this = this;
+                var button = GUI.Button.CreateSimpleButton(key, key);
+                button.width = propertySet && propertySet.width ? propertySet.width : this.defaultButtonWidth;
+                button.height = propertySet && propertySet.height ? propertySet.height : this.defaultButtonHeight;
+                button.color = propertySet && propertySet.color ? propertySet.color : this.defaultButtonColor;
+                button.background = propertySet && propertySet.background ? propertySet.background : this.defaultButtonBackground;
+                button.paddingLeft = propertySet && propertySet.paddingLeft ? propertySet.paddingLeft : this.defaultButtonPaddingLeft;
+                button.paddingRight = propertySet && propertySet.paddingRight ? propertySet.paddingRight : this.defaultButtonPaddingRight;
+                button.paddingTop = propertySet && propertySet.paddingTop ? propertySet.paddingTop : this.defaultButtonPaddingTop;
+                button.paddingBottom = propertySet && propertySet.paddingBottom ? propertySet.paddingBottom : this.defaultButtonPaddingBottom;
+                button.thickness = 0;
+                button.isFocusInvisible = true;
+                button.onPointerUpObservable.add(function () {
+                    _this.onKeyPressObservable.notifyObservers(key);
+                });
+                return button;
+            };
+            VirtualKeyboard.prototype.addKeysRow = function (keys, propertySets) {
+                var panel = new GUI.StackPanel();
+                panel.isVertical = false;
+                panel.isFocusInvisible = true;
+                for (var i = 0; i < keys.length; i++) {
+                    var properties = null;
+                    if (propertySets && propertySets.length === keys.length) {
+                        properties = propertySets[i];
+                    }
+                    panel.addControl(this._createKey(keys[i], properties));
+                }
+                this.addControl(panel);
+            };
+            Object.defineProperty(VirtualKeyboard.prototype, "connectedInputText", {
+                get: function () {
+                    return this._connectedInputText;
+                },
+                enumerable: true,
+                configurable: true
+            });
+            VirtualKeyboard.prototype.connect = function (input) {
+                var _this = this;
+                this.isVisible = false;
+                this._connectedInputText = input;
+                // Events hooking
+                this._onFocusObserver = input.onFocusObservable.add(function () {
+                    _this.isVisible = true;
+                });
+                this._onBlurObserver = input.onBlurObservable.add(function () {
+                    _this.isVisible = false;
+                });
+                this._onKeyPressObserver = this.onKeyPressObservable.add(function (key) {
+                    switch (key) {
+                        case "\u2190":
+                            _this._connectedInputText.processKey(8);
+                            return;
+                        case "\u21B5":
+                            _this._connectedInputText.processKey(13);
+                            return;
+                    }
+                    _this._connectedInputText.processKey(-1, key);
+                });
+            };
+            VirtualKeyboard.prototype.disconnect = function () {
+                if (!this._connectedInputText) {
+                    return;
+                }
+                this._connectedInputText.onFocusObservable.remove(this._onFocusObserver);
+                this._connectedInputText.onBlurObservable.remove(this._onBlurObserver);
+                this.onKeyPressObservable.remove(this._onKeyPressObserver);
+                this._connectedInputText = null;
+            };
+            // Statics
+            VirtualKeyboard.CreateDefaultLayout = function () {
+                var returnValue = new VirtualKeyboard();
+                returnValue.addKeysRow(["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "\u2190"]);
+                returnValue.addKeysRow(["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"]);
+                returnValue.addKeysRow(["a", "s", "d", "f", "g", "h", "j", "k", "l", ";", "'", "\u21B5"]);
+                returnValue.addKeysRow(["z", "x", "c", "v", "b", "n", "m", ",", ".", "/"]);
+                returnValue.addKeysRow([" "], [{ width: "200px" }]);
+                return returnValue;
+            };
+            return VirtualKeyboard;
+        }(GUI.StackPanel));
+        GUI.VirtualKeyboard = VirtualKeyboard;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));

文件差异内容过多而无法显示
+ 3 - 3
dist/preview release/gui/babylon.gui.min.js


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

@@ -1,14 +1,21 @@
 /// <reference path="../../dist/preview release/babylon.d.ts" />
 /// <reference path="../../dist/preview release/babylon.d.ts" />
 declare module BABYLON.GUI {
 declare module BABYLON.GUI {
+    interface IFocusableControl {
+        onFocus(): void;
+        onBlur(): void;
+        processKeyboard(evt: KeyboardEvent): void;
+    }
     class AdvancedDynamicTexture extends DynamicTexture {
     class AdvancedDynamicTexture extends DynamicTexture {
         private _isDirty;
         private _isDirty;
         private _renderObserver;
         private _renderObserver;
         private _resizeObserver;
         private _resizeObserver;
+        private _preKeyboardObserver;
         private _pointerMoveObserver;
         private _pointerMoveObserver;
         private _pointerObserver;
         private _pointerObserver;
-        private _canvasBlurObserver;
+        private _canvasPointerOutObserver;
         private _background;
         private _background;
         _rootContainer: Container;
         _rootContainer: Container;
+        _lastPickedControl: Control;
         _lastControlOver: Control;
         _lastControlOver: Control;
         _lastControlDown: Control;
         _lastControlDown: Control;
         _capturingControl: Control;
         _capturingControl: Control;
@@ -20,12 +27,14 @@ declare module BABYLON.GUI {
         private _idealWidth;
         private _idealWidth;
         private _idealHeight;
         private _idealHeight;
         private _renderAtIdealSize;
         private _renderAtIdealSize;
+        private _focusedControl;
         background: string;
         background: string;
         idealWidth: number;
         idealWidth: number;
         idealHeight: number;
         idealHeight: number;
         renderAtIdealSize: boolean;
         renderAtIdealSize: boolean;
         readonly layer: Layer;
         readonly layer: Layer;
         readonly rootContainer: Container;
         readonly rootContainer: Container;
+        focusedControl: IFocusableControl;
         constructor(name: string, width: number, height: number, scene: Scene, generateMipMaps?: boolean, samplingMode?: number);
         constructor(name: string, width: number, height: number, scene: Scene, generateMipMaps?: boolean, samplingMode?: number);
         executeOnAllControls(func: (control: Control) => void, container?: Container): void;
         executeOnAllControls(func: (control: Control) => void, container?: Container): void;
         markAsDirty(): void;
         markAsDirty(): void;
@@ -39,7 +48,7 @@ declare module BABYLON.GUI {
         private _doPicking(x, y, type);
         private _doPicking(x, y, type);
         attach(): void;
         attach(): void;
         attachToMesh(mesh: AbstractMesh, supportPointerMove?: boolean): void;
         attachToMesh(mesh: AbstractMesh, supportPointerMove?: boolean): void;
-        private _attachToOnBlur(scene);
+        private _attachToOnPointerOut(scene);
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean): AdvancedDynamicTexture;
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean): AdvancedDynamicTexture;
         static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Scene): AdvancedDynamicTexture;
         static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Scene): AdvancedDynamicTexture;
     }
     }
@@ -159,6 +168,7 @@ declare module BABYLON.GUI {
         private _doNotRender;
         private _doNotRender;
         isHitTestVisible: boolean;
         isHitTestVisible: boolean;
         isPointerBlocker: boolean;
         isPointerBlocker: boolean;
+        isFocusInvisible: boolean;
         protected _linkOffsetX: ValueAndUnit;
         protected _linkOffsetX: ValueAndUnit;
         protected _linkOffsetY: ValueAndUnit;
         protected _linkOffsetY: ValueAndUnit;
         readonly typeName: string;
         readonly typeName: string;
@@ -249,6 +259,7 @@ declare module BABYLON.GUI {
         forcePointerUp(): void;
         forcePointerUp(): void;
         _processObservables(type: number, x: number, y: number): boolean;
         _processObservables(type: number, x: number, y: number): boolean;
         private _prepareFont();
         private _prepareFont();
+        dispose(): void;
         private static _HORIZONTAL_ALIGNMENT_LEFT;
         private static _HORIZONTAL_ALIGNMENT_LEFT;
         private static _HORIZONTAL_ALIGNMENT_RIGHT;
         private static _HORIZONTAL_ALIGNMENT_RIGHT;
         private static _HORIZONTAL_ALIGNMENT_CENTER;
         private static _HORIZONTAL_ALIGNMENT_CENTER;
@@ -300,6 +311,7 @@ declare module BABYLON.GUI {
         _processPicking(x: number, y: number, type: number): boolean;
         _processPicking(x: number, y: number, type: number): boolean;
         protected _clipForChildren(context: CanvasRenderingContext2D): void;
         protected _clipForChildren(context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        dispose(): void;
     }
     }
 }
 }
 
 
@@ -584,23 +596,77 @@ declare module BABYLON.GUI {
 
 
 /// <reference path="../../../dist/preview release/babylon.d.ts" />
 /// <reference path="../../../dist/preview release/babylon.d.ts" />
 declare module BABYLON.GUI {
 declare module BABYLON.GUI {
-    class InputText extends Control {
+    class InputText extends Control implements IFocusableControl {
         name: string;
         name: string;
         private _text;
         private _text;
         private _background;
         private _background;
+        private _focusedBackground;
         private _thickness;
         private _thickness;
         private _margin;
         private _margin;
         private _autoStretchWidth;
         private _autoStretchWidth;
         private _maxWidth;
         private _maxWidth;
+        private _isFocused;
+        private _blinkTimeout;
+        private _blinkIsEven;
+        private _cursorOffset;
+        private _scrollLeft;
+        promptMessage: string;
+        onTextChangedObservable: Observable<InputText>;
+        onFocusObservable: Observable<InputText>;
+        onBlurObservable: Observable<InputText>;
         maxWidth: string | number;
         maxWidth: string | number;
         margin: string;
         margin: string;
         autoStretchWidth: boolean;
         autoStretchWidth: boolean;
         thickness: number;
         thickness: number;
+        focusedBackground: string;
         background: string;
         background: string;
         text: string;
         text: string;
         constructor(name?: string, text?: string);
         constructor(name?: string, text?: string);
+        onBlur(): void;
+        onFocus(): void;
         protected _getTypeName(): string;
         protected _getTypeName(): string;
+        processKey(keyCode: number, key?: string): void;
+        processKeyboard(evt: KeyboardEvent): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        protected _onPointerDown(coordinates: Vector2): boolean;
+        protected _onPointerUp(coordinates: Vector2): void;
+        dispose(): void;
+    }
+}
+
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON.GUI {
+    class KeyPropertySet {
+        width?: string;
+        height?: string;
+        paddingLeft?: string;
+        paddingRight?: string;
+        paddingTop?: string;
+        paddingBottom?: string;
+        color?: string;
+        background?: string;
+    }
+    class VirtualKeyboard extends StackPanel {
+        onKeyPressObservable: Observable<string>;
+        defaultButtonWidth: string;
+        defaultButtonHeight: string;
+        defaultButtonPaddingLeft: string;
+        defaultButtonPaddingRight: string;
+        defaultButtonPaddingTop: string;
+        defaultButtonPaddingBottom: string;
+        defaultButtonColor: string;
+        defaultButtonBackground: string;
+        protected _getTypeName(): string;
+        private _createKey(key, propertySet?);
+        addKeysRow(keys: Array<string>, propertySets?: Array<KeyPropertySet>): void;
+        private _connectedInputText;
+        private _onFocusObserver;
+        private _onBlurObserver;
+        private _onKeyPressObserver;
+        readonly connectedInputText: InputText;
+        connect(input: InputText): void;
+        disconnect(): void;
+        static CreateDefaultLayout(): VirtualKeyboard;
     }
     }
 }
 }
 
 

文件差异内容过多而无法显示
+ 2 - 1
dist/preview release/materialsLibrary/babylon.cellMaterial.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/materialsLibrary/babylon.cellMaterial.min.js


文件差异内容过多而无法显示
+ 2 - 1
dist/preview release/materialsLibrary/babylon.fireMaterial.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/materialsLibrary/babylon.fireMaterial.min.js


文件差异内容过多而无法显示
+ 2 - 1
dist/preview release/materialsLibrary/babylon.furMaterial.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/materialsLibrary/babylon.furMaterial.min.js


文件差异内容过多而无法显示
+ 2 - 1
dist/preview release/materialsLibrary/babylon.gradientMaterial.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/materialsLibrary/babylon.gradientMaterial.min.js


文件差异内容过多而无法显示
+ 2 - 1
dist/preview release/materialsLibrary/babylon.lavaMaterial.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/materialsLibrary/babylon.lavaMaterial.min.js


文件差异内容过多而无法显示
+ 2 - 1
dist/preview release/materialsLibrary/babylon.normalMaterial.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/materialsLibrary/babylon.normalMaterial.min.js


文件差异内容过多而无法显示
+ 2 - 1
dist/preview release/materialsLibrary/babylon.simpleMaterial.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/materialsLibrary/babylon.simpleMaterial.min.js


文件差异内容过多而无法显示
+ 2 - 1
dist/preview release/materialsLibrary/babylon.terrainMaterial.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/materialsLibrary/babylon.terrainMaterial.min.js


文件差异内容过多而无法显示
+ 2 - 1
dist/preview release/materialsLibrary/babylon.triPlanarMaterial.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/materialsLibrary/babylon.triPlanarMaterial.min.js


+ 1 - 0
dist/preview release/materialsLibrary/babylon.waterMaterial.js

@@ -25,6 +25,7 @@ var BABYLON;
             _this.REFLECTION = false;
             _this.REFLECTION = false;
             _this.CLIPPLANE = false;
             _this.CLIPPLANE = false;
             _this.ALPHATEST = false;
             _this.ALPHATEST = false;
+            _this.DEPTHPREPASS = false;
             _this.POINTSIZE = false;
             _this.POINTSIZE = false;
             _this.FOG = false;
             _this.FOG = false;
             _this.NORMAL = false;
             _this.NORMAL = false;

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


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

@@ -1,15 +1,18 @@
 # 3.1.0:
 # 3.1.0:
 
 
 ## Major updates
 ## Major updates
-- Added support for webgl context lost and restored events. (Doc here)[http://doc.babylonjs.com/tutorials/optimizing_your_scene#handling-webgl-context-lost] ([deltakosh](https://github.com/deltakosh))
+- Added support for webgl context lost and restored events. [Doc here](http://doc.babylonjs.com/tutorials/optimizing_your_scene#handling-webgl-context-lost) ([deltakosh](https://github.com/deltakosh))
 - Added support for non-pow2 textures when in WebGL2 mode ([deltakosh](https://github.com/deltakosh))
 - Added support for non-pow2 textures when in WebGL2 mode ([deltakosh](https://github.com/deltakosh))
 - Engine can now be initialized with an existing webgl context ([deltakosh](https://github.com/deltakosh))
 - Engine can now be initialized with an existing webgl context ([deltakosh](https://github.com/deltakosh))
-- Introduced behaviors. (Doc here)[http://doc.babylonjs.com/overviews/behaviors] ([deltakosh](https://github.com/deltakosh))
-- Added support for WebGL Occlusion queries. (Doc here)[http://doc.babylonjs.com/overviews/occlusionquery] ([Ibraheem Osama](https://github.com/IbraheemOsama))
+- Introduced behaviors. [Doc here](http://doc.babylonjs.com/overviews/behaviors) ([deltakosh](https://github.com/deltakosh))
+- Added support for WebGL Occlusion queries. [Doc here](http://doc.babylonjs.com/overviews/occlusionquery) ([Ibraheem Osama](https://github.com/IbraheemOsama))
 - New behaviors for ArcRotateCamera:
 - New behaviors for ArcRotateCamera:
  - AutoRotation ([deltakosh](https://github.com/deltakosh))
  - AutoRotation ([deltakosh](https://github.com/deltakosh))
  - Framing ([deltakosh](https://github.com/deltakosh))
  - Framing ([deltakosh](https://github.com/deltakosh))
  - Bouncing ([deltakosh](https://github.com/deltakosh))
  - Bouncing ([deltakosh](https://github.com/deltakosh))
+- New InputText for Babylon.GUI. [Doc here](http://doc.babylonjs.com/overviews/gui#inputtext) ([deltakosh](https://github.com/deltakosh))
+- New VirtualKeyboard for Babylon.GUI. [Doc here](http://doc.babylonjs.com/overviews/gui#virtualkeyboard) ([deltakosh](https://github.com/deltakosh) / [adam](https://github.com/abow))
+- Added support for depth pre-pass rendering. [Doc here](http://doc.babylonjs.com/tutorials/transparency_and_how_meshes_are_rendered#depth-pre-pass-meshes) ([deltakosh](https://github.com/deltakosh))
 
 
 ## Updates
 ## Updates
 - New `camera.storeState()` and `camera.restoreState()` functions to store / restore cameras position / rotation / fov. (Doc here)[http://doc.babylonjs.com/tutorials/cameras#state] ([deltakosh](https://github.com/deltakosh))
 - New `camera.storeState()` and `camera.restoreState()` functions to store / restore cameras position / rotation / fov. (Doc here)[http://doc.babylonjs.com/tutorials/cameras#state] ([deltakosh](https://github.com/deltakosh))

+ 58 - 7
gui/src/advancedDynamicTexture.ts

@@ -1,15 +1,23 @@
 /// <reference path="../../dist/preview release/babylon.d.ts"/>
 /// <reference path="../../dist/preview release/babylon.d.ts"/>
 
 
 module BABYLON.GUI {
 module BABYLON.GUI {
+    export interface IFocusableControl {
+        onFocus(): void;
+        onBlur(): void;
+        processKeyboard(evt: KeyboardEvent): void;
+    }
+
     export class AdvancedDynamicTexture extends DynamicTexture {
     export class AdvancedDynamicTexture extends DynamicTexture {
         private _isDirty = false;
         private _isDirty = false;
         private _renderObserver: Observer<Camera>;
         private _renderObserver: Observer<Camera>;
         private _resizeObserver: Observer<Engine>;
         private _resizeObserver: Observer<Engine>;
+        private _preKeyboardObserver: Observer<KeyboardInfoPre>;
         private _pointerMoveObserver: Observer<PointerInfoPre>;
         private _pointerMoveObserver: Observer<PointerInfoPre>;
         private _pointerObserver: Observer<PointerInfo>;
         private _pointerObserver: Observer<PointerInfo>;
-        private _canvasBlurObserver: Observer<Engine>;
+        private _canvasPointerOutObserver: Observer<Engine>;
         private _background: string;
         private _background: string;
         public _rootContainer = new Container("root");
         public _rootContainer = new Container("root");
+        public _lastPickedControl: Control;
         public _lastControlOver: Control;
         public _lastControlOver: Control;
         public _lastControlDown: Control;
         public _lastControlDown: Control;
         public _capturingControl: Control;
         public _capturingControl: Control;
@@ -21,6 +29,7 @@ module BABYLON.GUI {
         private _idealWidth = 0;
         private _idealWidth = 0;
         private _idealHeight = 0;
         private _idealHeight = 0;
         private _renderAtIdealSize = false;
         private _renderAtIdealSize = false;
+        private _focusedControl: IFocusableControl;
 
 
         public get background(): string {
         public get background(): string {
             return this._background;
             return this._background;
@@ -83,11 +92,40 @@ module BABYLON.GUI {
         public get rootContainer(): Container {
         public get rootContainer(): Container {
             return this._rootContainer;
             return this._rootContainer;
         }
         }
+
+        public get focusedControl(): IFocusableControl {
+            return this._focusedControl;
+        }
+
+        public set focusedControl(control: IFocusableControl) {
+            if (this._focusedControl === control) {
+                return;
+            }
+
+            if (!this._focusedControl) {
+                control.onFocus();
+            } else {
+                this._focusedControl.onBlur();
+            }
+
+            this._focusedControl = control;
+        }
        
        
         constructor(name: string, width = 0, height = 0, scene: Scene, generateMipMaps = false, samplingMode = Texture.NEAREST_SAMPLINGMODE) {
         constructor(name: string, width = 0, height = 0, scene: Scene, generateMipMaps = false, samplingMode = Texture.NEAREST_SAMPLINGMODE) {
             super(name, {width: width, height: height}, scene, generateMipMaps, samplingMode, Engine.TEXTUREFORMAT_RGBA);
             super(name, {width: width, height: height}, scene, generateMipMaps, samplingMode, Engine.TEXTUREFORMAT_RGBA);
 
 
             this._renderObserver = this.getScene().onBeforeCameraRenderObservable.add((camera: Camera) => this._checkUpdate(camera));
             this._renderObserver = this.getScene().onBeforeCameraRenderObservable.add((camera: Camera) => this._checkUpdate(camera));
+            this._preKeyboardObserver = this.getScene().onPreKeyboardObservable.add(info => {
+                if (!this._focusedControl) {
+                    return;
+                }
+
+                if (info.type === KeyboardEventTypes.KEYDOWN) {
+                    this._focusedControl.processKeyboard(info.event);
+                }
+
+                info.skipOnPointerObservable = true;
+            });
 
 
             this._rootContainer._link(null, this);
             this._rootContainer._link(null, this);
 
 
@@ -145,8 +183,8 @@ module BABYLON.GUI {
                 this.getScene().onPointerObservable.remove(this._pointerObserver);
                 this.getScene().onPointerObservable.remove(this._pointerObserver);
             }
             }
 
 
-            if (this._canvasBlurObserver) {
-                this.getScene().getEngine().onCanvasBlurObservable.remove(this._canvasBlurObserver);
+            if (this._canvasPointerOutObserver) {
+                this.getScene().getEngine().onCanvasPointerOutObservable.remove(this._canvasPointerOutObserver);
             }
             }
 
 
             if (this._layerToDispose) {
             if (this._layerToDispose) {
@@ -155,6 +193,8 @@ module BABYLON.GUI {
                 this._layerToDispose = null;
                 this._layerToDispose = null;
             }
             }
 
 
+            this._rootContainer.dispose();
+
             super.dispose();
             super.dispose();
         }
         }
 
 
@@ -286,6 +326,17 @@ module BABYLON.GUI {
                     this._lastControlOver = null;
                     this._lastControlOver = null;
                 }
                 }
             }
             }
+
+            // Focus management
+            if (this._focusedControl) {
+                if (this._focusedControl !== (<any>this._lastPickedControl)) {
+                    if (this._lastPickedControl.isFocusInvisible) {
+                        return;
+                    }
+
+                    this.focusedControl = null;
+                }
+            }
         }
         }
 
 
         public attach(): void {
         public attach(): void {
@@ -309,7 +360,7 @@ module BABYLON.GUI {
                 pi.skipOnPointerObservable = this._shouldBlockPointer && pi.type !== BABYLON.PointerEventTypes.POINTERUP;
                 pi.skipOnPointerObservable = this._shouldBlockPointer && pi.type !== BABYLON.PointerEventTypes.POINTERUP;
             });
             });
 
 
-            this._attachToOnBlur(scene);
+            this._attachToOnPointerOut(scene);
         }
         }
 
 
         public attachToMesh(mesh: AbstractMesh, supportPointerMove = true): void {
         public attachToMesh(mesh: AbstractMesh, supportPointerMove = true): void {
@@ -339,11 +390,11 @@ module BABYLON.GUI {
             });
             });
 
 
             mesh.enablePointerMoveEvents = supportPointerMove;
             mesh.enablePointerMoveEvents = supportPointerMove;
-            this._attachToOnBlur(scene);
+            this._attachToOnPointerOut(scene);
         }
         }
 
 
-        private _attachToOnBlur(scene: Scene): void {
-            this._canvasBlurObserver = scene.getEngine().onCanvasBlurObservable.add(() => {
+        private _attachToOnPointerOut(scene: Scene): void {
+            this._canvasPointerOutObserver = scene.getEngine().onCanvasPointerOutObservable.add(() => {
                 if (this._lastControlOver) {
                 if (this._lastControlOver) {
                     this._lastControlOver._onPointerOut();
                     this._lastControlOver._onPointerOut();
                 }            
                 }            

+ 10 - 0
gui/src/controls/container.ts

@@ -63,6 +63,8 @@ module BABYLON.GUI {
             }
             }
             control._link(this, this._host);
             control._link(this, this._host);
 
 
+            control._markAllAsDirty();
+
             this._reOrderControl(control);
             this._reOrderControl(control);
 
 
             this._markAsDirty();
             this._markAsDirty();
@@ -176,5 +178,13 @@ module BABYLON.GUI {
 
 
             this._measureForChildren.copyFrom(this._currentMeasure);
             this._measureForChildren.copyFrom(this._currentMeasure);
         }
         }
+
+        public dispose() {
+            super.dispose();
+
+            for (var control of this._children) {
+                control.dispose();
+            }
+        }
     }    
     }    
 }
 }

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

@@ -47,6 +47,7 @@ module BABYLON.GUI {
 
 
         public isHitTestVisible = true;
         public isHitTestVisible = true;
         public isPointerBlocker = false;
         public isPointerBlocker = false;
+        public isFocusInvisible = false;
 
 
         protected _linkOffsetX = new ValueAndUnit(0);
         protected _linkOffsetX = new ValueAndUnit(0);
         protected _linkOffsetY = new ValueAndUnit(0);
         protected _linkOffsetY = new ValueAndUnit(0);
@@ -834,6 +835,7 @@ module BABYLON.GUI {
             if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
             if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
                 this._onPointerDown(this._dummyVector2);
                 this._onPointerDown(this._dummyVector2);
                 this._host._lastControlDown = this;
                 this._host._lastControlDown = this;
+                this._host._lastPickedControl = this;
                 return true;
                 return true;
             }
             }
 
 
@@ -858,6 +860,15 @@ module BABYLON.GUI {
             this._fontOffset = Control._GetFontOffset(this._font);
             this._fontOffset = Control._GetFontOffset(this._font);
         }
         }
 
 
+        public dispose() {
+            this.onDirtyObservable.clear();
+            this.onPointerDownObservable.clear();
+            this.onPointerEnterObservable.clear();
+            this.onPointerMoveObservable.clear();
+            this.onPointerOutObservable.clear();
+            this.onPointerUpObservable.clear();
+        }
+
         // Statics
         // Statics
         private static _HORIZONTAL_ALIGNMENT_LEFT = 0;
         private static _HORIZONTAL_ALIGNMENT_LEFT = 0;
         private static _HORIZONTAL_ALIGNMENT_RIGHT = 1;
         private static _HORIZONTAL_ALIGNMENT_RIGHT = 1;

+ 216 - 11
gui/src/controls/inputText.ts

@@ -1,13 +1,25 @@
 /// <reference path="../../../dist/preview release/babylon.d.ts"/>
 /// <reference path="../../../dist/preview release/babylon.d.ts"/>
 
 
 module BABYLON.GUI {
 module BABYLON.GUI {
-    export class InputText extends Control {
+    export class InputText extends Control implements IFocusableControl {
         private _text = "";
         private _text = "";
         private _background = "black";   
         private _background = "black";   
+        private _focusedBackground = "black";   
         private _thickness = 1;
         private _thickness = 1;
         private _margin = new ValueAndUnit(10, ValueAndUnit.UNITMODE_PIXEL);
         private _margin = new ValueAndUnit(10, ValueAndUnit.UNITMODE_PIXEL);
         private _autoStretchWidth = true;        
         private _autoStretchWidth = true;        
         private _maxWidth = new ValueAndUnit(1, ValueAndUnit.UNITMODE_PERCENTAGE, false);
         private _maxWidth = new ValueAndUnit(1, ValueAndUnit.UNITMODE_PERCENTAGE, false);
+        private _isFocused = false;
+        private _blinkTimeout: number;
+        private _blinkIsEven = false;
+        private _cursorOffset = 0;        
+        private _scrollLeft: number;
+
+        public promptMessage = "Please enter text:";
+
+        public onTextChangedObservable = new Observable<InputText>();
+        public onFocusObservable = new Observable<InputText>();
+        public onBlurObservable = new Observable<InputText>();
 
 
         public get maxWidth(): string | number {
         public get maxWidth(): string | number {
             return this._maxWidth.toString(this._host);
             return this._maxWidth.toString(this._host);
@@ -63,6 +75,19 @@ module BABYLON.GUI {
             this._markAsDirty();
             this._markAsDirty();
         }          
         }          
 
 
+        public get focusedBackground(): string {
+            return this._focusedBackground;
+        }
+
+        public set focusedBackground(value: string) {
+            if (this._focusedBackground === value) {
+                return;
+            }
+
+            this._focusedBackground = value;
+            this._markAsDirty();
+        }  
+
         public get background(): string {
         public get background(): string {
             return this._background;
             return this._background;
         }
         }
@@ -74,7 +99,7 @@ module BABYLON.GUI {
 
 
             this._background = value;
             this._background = value;
             this._markAsDirty();
             this._markAsDirty();
-        }  
+        }          
 
 
         public get text(): string {
         public get text(): string {
             return this._text;
             return this._text;
@@ -86,6 +111,8 @@ module BABYLON.GUI {
             }
             }
             this._text = value;
             this._text = value;
             this._markAsDirty();
             this._markAsDirty();
+
+            this.onTextChangedObservable.notifyObservers(this);
         }
         }
 
 
         constructor(public name?: string, text: string = "") {
         constructor(public name?: string, text: string = "") {
@@ -94,37 +121,193 @@ module BABYLON.GUI {
             this.text = text;
             this.text = text;
         }
         }
 
 
+        public onBlur(): void {
+            this._isFocused = false;
+            this._scrollLeft = null;
+            this._cursorOffset = 0;
+            clearTimeout(this._blinkTimeout);
+            this._markAsDirty();
+
+            this.onBlurObservable.notifyObservers(this);
+        }
+
+        public onFocus(): void {
+            this._scrollLeft = null;
+            this._isFocused = true;
+            this._blinkIsEven = false;
+            this._cursorOffset = 0;
+            this._markAsDirty();
+
+            this.onFocusObservable.notifyObservers(this);
+
+            if (navigator.userAgent.indexOf("Mobile") !== -1) {
+                this.text = prompt(this.promptMessage);
+                this._host.focusedControl = null;
+                return;
+            }
+        }
+
         protected _getTypeName(): string {
         protected _getTypeName(): string {
             return "InputText";
             return "InputText";
         }
         }
 
 
-       public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
+        public processKey(keyCode: number, key?: string) {
+            // Specific cases
+            switch (keyCode) {
+                case 8: // BACKSPACE
+                    if (this._text && this._text.length > 0) {
+                        if (this._cursorOffset === 0) {
+                            this.text = this._text.substr(0, this._text.length - 1);
+                        } else {
+                            let deletePosition = this._text.length - this._cursorOffset;
+                            if (deletePosition > 0) {
+                                this.text = this._text.slice(0, deletePosition - 1) + this._text.slice(deletePosition);
+                            }
+                        }
+                    }
+                    return;
+                case 46: // DELETE
+                    if (this._text && this._text.length > 0) {
+                        let deletePosition = this._text.length - this._cursorOffset;
+                        this.text = this._text.slice(0, deletePosition) + this._text.slice(deletePosition + 1);
+                        this._cursorOffset--;
+                    }
+                    return;                    
+                case 13: // RETURN
+                    this._host.focusedControl = null;
+                    return;
+                case 35: // END
+                    this._cursorOffset = 0;
+                    this._blinkIsEven = false;
+                    this._markAsDirty();                
+                    return;
+                case 36: // HOME
+                    this._cursorOffset = this._text.length;
+                    this._blinkIsEven = false;
+                    this._markAsDirty();                
+                return;
+                case 37: // LEFT
+                    this._cursorOffset++;
+                    if (this._cursorOffset > this._text.length) {
+                        this._cursorOffset = this._text.length;
+                    }
+                    this._blinkIsEven = false;
+                    this._markAsDirty();
+                    return;
+                case 39: // RIGHT
+                    this._cursorOffset--;
+                    if (this._cursorOffset < 0) {
+                        this._cursorOffset = 0;
+                    }
+                    this._blinkIsEven = false;
+                    this._markAsDirty();
+                    return;
+            }
+
+            // Printable characters
+            if (
+                (keyCode === -1) ||                     // Direct access
+                (keyCode === 32) ||                     // Space
+                (keyCode > 47 && keyCode < 58) ||       // Numbers
+                (keyCode > 64 && keyCode < 91) ||       // Letters
+                (keyCode > 185 && keyCode < 193) ||     // 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;
+
+                        this.text = this._text.slice(0, insertPosition) + key + this._text.slice(insertPosition);
+                    }
+                }
+        }
+
+        public processKeyboard(evt: KeyboardEvent): void {
+            this.processKey(evt.keyCode, evt.key);
+        }
+
+        public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
             context.save();
             context.save();
 
 
             this._applyStates(context);
             this._applyStates(context);
             if (this._processMeasures(parentMeasure, context)) {
             if (this._processMeasures(parentMeasure, context)) {
                 
                 
                 // Background
                 // Background
-                if (this._background) {
+                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.fillStyle = this._background;
 
 
                     context.fillRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
                     context.fillRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
                 }
                 }
 
 
+                if (!this._fontOffset) {
+                    this._fontOffset = Control._GetFontOffset(context.font);
+                }
+
                 // Text
                 // Text
-                if (this._text) {
-                    if (this.color) {
-                        context.fillStyle = this.color;
+                let clipTextLeft = this._currentMeasure.left + this._margin.getValueInPixel(this._host, parentMeasure.width);
+                if (this.color) {
+                    context.fillStyle = this.color;
+                }
+
+                let textWidth = context.measureText(this._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), textWidth + marginWidth) + "px";
+                }
+
+                let rootY = this._fontOffset.ascent + (this._currentMeasure.height - this._fontOffset.height) / 2;
+                let availableWidth = this._width.getValueInPixel(this._host, parentMeasure.width) - marginWidth;
+                context.save();
+                context.beginPath();
+                context.rect(clipTextLeft, this._currentMeasure.top + (this._currentMeasure.height - this._fontOffset.height) / 2, availableWidth + 2, this._currentMeasure.height);
+                context.clip();
+
+                if (this._isFocused && textWidth > availableWidth) {      
+                    let textLeft = clipTextLeft - textWidth + availableWidth;
+                    if (!this._scrollLeft) {
+                        this._scrollLeft = textLeft;
                     }
                     }
+                } else {
+                    this._scrollLeft = clipTextLeft;
+                }
 
 
-                    let rootY = this._fontOffset.ascent + (this._currentMeasure.height - this._fontOffset.height) / 2;
-                    context.fillText(this._text, this._currentMeasure.left + this._margin.getValueInPixel(this._host, parentMeasure.width), this._currentMeasure.top + rootY);
+                context.fillText(this._text, this._scrollLeft, this._currentMeasure.top + rootY);
 
 
-                    if (this._autoStretchWidth) {
-                        this.width = Math.min(this._maxWidth.getValueInPixel(this._host, parentMeasure.width), context.measureText(this._text).width + this._margin.getValueInPixel(this._host, parentMeasure.width) * 2) + "px";
+                // Cursor
+                if (this._isFocused) {         
+                    if (!this._blinkIsEven) {
+                        let cursorOffsetText = this.text.substr(this._text.length - this._cursorOffset);
+                        let cursorOffsetWidth = context.measureText(cursorOffsetText).width;   
+                        let cursorLeft = this._scrollLeft  + textWidth - cursorOffsetWidth;
+    
+                        if (cursorLeft < clipTextLeft) {
+                            this._scrollLeft += (clipTextLeft - cursorLeft);
+                            cursorLeft = clipTextLeft;
+                            this._markAsDirty();
+                        } else if (cursorLeft > clipTextLeft + availableWidth) {
+                            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);
                     }
                     }
+
+                    clearTimeout(this._blinkTimeout);
+                    this._blinkTimeout = setTimeout(() => {
+                        this._blinkIsEven = !this._blinkIsEven;
+                        this._markAsDirty();
+                    }, 500);
                 }
                 }
 
 
+                context.restore();
+
                 // Border
                 // Border
                 if (this._thickness) {
                 if (this._thickness) {
                     if (this.color) {
                     if (this.color) {
@@ -138,5 +321,27 @@ module BABYLON.GUI {
             }
             }
             context.restore();
             context.restore();
         }
         }
+
+        protected _onPointerDown(coordinates: Vector2): boolean {
+            if (!super._onPointerDown(coordinates)) {
+                return false;
+            }
+
+            this._host.focusedControl = this;
+
+            return true;
+        }
+
+        protected _onPointerUp(coordinates: Vector2): void {
+            super._onPointerUp(coordinates);
+        }  
+
+        public dispose() {
+            super.dispose();
+
+            this.onBlurObservable.clear();
+            this.onFocusObservable.clear();
+            this.onTextChangedObservable.clear();
+        }
     }
     }
 }
 }

+ 136 - 0
gui/src/controls/virtualKeyboard.ts

@@ -0,0 +1,136 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.GUI {
+
+    export class KeyPropertySet {
+        width?: string;
+        height?: string;
+        paddingLeft?: string;
+        paddingRight?: string;
+        paddingTop?: string;
+        paddingBottom?: string;
+        color?: string;
+        background?: string;
+    }
+
+    export class VirtualKeyboard extends StackPanel {
+        public onKeyPressObservable = new Observable<string>();
+
+        public defaultButtonWidth = "40px";
+        public defaultButtonHeight = "40px";
+
+        public defaultButtonPaddingLeft= "2px";
+        public defaultButtonPaddingRight = "2px";
+        public defaultButtonPaddingTop = "2px";
+        public defaultButtonPaddingBottom = "2px";    
+        
+        public defaultButtonColor = "#DDD";
+        public defaultButtonBackground = "#070707";    
+        
+        protected _getTypeName(): string {
+            return "VirtualKeyboard";
+        }
+
+        private _createKey(key: string, propertySet?: KeyPropertySet) {
+            var button = Button.CreateSimpleButton(key, key);
+            
+           
+            button.width = propertySet && propertySet.width ? propertySet.width : this.defaultButtonWidth;
+            button.height = propertySet && propertySet.height ? propertySet.height : this.defaultButtonHeight;
+            button.color = propertySet && propertySet.color ? propertySet.color : this.defaultButtonColor;
+            button.background = propertySet && propertySet.background ? propertySet.background : this.defaultButtonBackground;
+            button.paddingLeft = propertySet && propertySet.paddingLeft ? propertySet.paddingLeft : this.defaultButtonPaddingLeft;
+            button.paddingRight = propertySet && propertySet.paddingRight ? propertySet.paddingRight : this.defaultButtonPaddingRight;
+            button.paddingTop = propertySet && propertySet.paddingTop ? propertySet.paddingTop : this.defaultButtonPaddingTop;
+            button.paddingBottom = propertySet && propertySet.paddingBottom ? propertySet.paddingBottom : this.defaultButtonPaddingBottom;
+        
+            button.thickness = 0;
+            button.isFocusInvisible = true;
+        
+            button.onPointerUpObservable.add(() => {
+                this.onKeyPressObservable.notifyObservers(key);
+            });
+    
+            return button;
+        }
+
+        public addKeysRow(keys: Array<string>, propertySets?: Array<KeyPropertySet>): void {
+            let panel = new StackPanel();
+            panel.isVertical = false;
+            panel.isFocusInvisible = true;
+        
+            for(var i = 0; i < keys.length; i++) {
+                let properties = null;
+
+                if (propertySets && propertySets.length === keys.length) {
+                    properties = propertySets[i];
+                }
+
+                panel.addControl(this._createKey(keys[i], properties));
+            }
+        
+            this.addControl(panel);
+        }
+
+        private _connectedInputText: InputText;
+        private _onFocusObserver: Observer<InputText>;
+        private _onBlurObserver: Observer<InputText>;
+        private _onKeyPressObserver: Observer<string>;
+
+        public get connectedInputText(): InputText {
+            return this._connectedInputText;
+        }
+
+        public connect(input: InputText): void {
+            this.isVisible = false;
+            this._connectedInputText = input;
+            
+            // Events hooking
+            this._onFocusObserver = input.onFocusObservable.add(() => {
+                this.isVisible = true;
+            });
+    
+            this._onBlurObserver = input.onBlurObservable.add(() => {
+                this.isVisible = false;
+            });		
+
+            this._onKeyPressObserver = this.onKeyPressObservable.add((key) => {
+                switch (key) {
+                    case "\u2190":
+                        this._connectedInputText.processKey(8);
+                        return;
+                    case "\u21B5":
+                        this._connectedInputText.processKey(13);
+                        return;                        
+                }
+
+                this._connectedInputText.processKey(-1, key);
+            });
+        }
+
+        public disconnect(): void {
+            if (!this._connectedInputText) {
+                return;
+            }
+
+            this._connectedInputText.onFocusObservable.remove(this._onFocusObserver);
+            this._connectedInputText.onBlurObservable.remove(this._onBlurObserver);
+            this.onKeyPressObservable.remove(this._onKeyPressObserver);
+
+            this._connectedInputText = null;
+        }
+
+        // Statics
+        public static CreateDefaultLayout(): VirtualKeyboard {
+            let returnValue = new VirtualKeyboard();
+
+            returnValue.addKeysRow(["1", "2", "3", "4", "5", "6", "7", "8", "9", "0","\u2190"]);
+            returnValue.addKeysRow(["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"]);
+            returnValue.addKeysRow(["a", "s", "d", "f", "g", "h", "j", "k", "l",";","'","\u21B5"]);
+            returnValue.addKeysRow(["z", "x", "c", "v", "b", "n", "m", ",", ".", "/"]);
+            returnValue.addKeysRow([" "], [{ width: "200px"}]);
+        
+            return returnValue;
+        }
+    }
+}

+ 0 - 1
loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts

@@ -40,7 +40,6 @@ module BABYLON.GLTF2.Extensions {
 
 
             if (properties.diffuseTexture) {
             if (properties.diffuseTexture) {
                 babylonMaterial.albedoTexture = loader.loadTexture(properties.diffuseTexture);
                 babylonMaterial.albedoTexture = loader.loadTexture(properties.diffuseTexture);
-                loader.loadMaterialAlphaProperties(material);
             }
             }
 
 
             if (properties.specularGlossinessTexture) {
             if (properties.specularGlossinessTexture) {

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

@@ -12,7 +12,6 @@ module BABYLON.GLTF2 {
         private _errorCallback: (message: string) => void;
         private _errorCallback: (message: string) => void;
         private _renderReady: boolean = false;
         private _renderReady: boolean = false;
         private _disposed: boolean = false;
         private _disposed: boolean = false;
-        private _objectURLs: string[] = new Array<string>();
         private _blockPendingTracking: boolean = false;
         private _blockPendingTracking: boolean = false;
         private _nonBlockingData: Array<any>;
         private _nonBlockingData: Array<any>;
 
 
@@ -68,8 +67,13 @@ module BABYLON.GLTF2 {
             this._disposed = true;
             this._disposed = true;
 
 
             // Revoke object urls created during load
             // Revoke object urls created during load
-            this._objectURLs.forEach(url => URL.revokeObjectURL(url));
-            this._objectURLs.length = 0;
+            if (this._gltf.textures) {
+                this._gltf.textures.forEach(texture => {
+                    if (texture.url) {
+                        URL.revokeObjectURL(texture.url);
+                    }
+                });
+            }
 
 
             this._gltf = undefined;
             this._gltf = undefined;
             this._babylonScene = undefined;
             this._babylonScene = undefined;
@@ -158,7 +162,7 @@ module BABYLON.GLTF2 {
 
 
             var binaryBuffer: IGLTFBuffer;
             var binaryBuffer: IGLTFBuffer;
             var buffers = this._gltf.buffers;
             var buffers = this._gltf.buffers;
-            if (buffers.length > 0 && buffers[0].uri === undefined) {
+            if (buffers && buffers[0].uri === undefined) {
                 binaryBuffer = buffers[0];
                 binaryBuffer = buffers[0];
             }
             }
 
 
@@ -182,10 +186,12 @@ module BABYLON.GLTF2 {
             rootMesh.rotation.y = Math.PI;
             rootMesh.rotation.y = Math.PI;
 
 
             var nodes = this._gltf.nodes;
             var nodes = this._gltf.nodes;
-            for (var i = 0; i < nodes.length; i++) {
-                var mesh = nodes[i].babylonMesh;
-                if (mesh && !mesh.parent) {
-                    mesh.parent = rootMesh;
+            if (nodes) {
+                for (var i = 0; i < nodes.length; i++) {
+                    var mesh = nodes[i].babylonMesh;
+                    if (mesh && !mesh.parent) {
+                        mesh.parent = rootMesh;
+                    }
                 }
                 }
             }
             }
         }
         }
@@ -1131,6 +1137,8 @@ module BABYLON.GLTF2 {
                     Tools.Warn("Invalid alpha mode '" + material.alphaMode + "'");
                     Tools.Warn("Invalid alpha mode '" + material.alphaMode + "'");
                     break;
                     break;
             }
             }
+
+            babylonMaterial.alphaCutOff = material.alphaCutoff === undefined ? 0.5 : material.alphaCutoff;
         }
         }
 
 
         public loadTexture(textureInfo: IGLTFTextureInfo): Texture {
         public loadTexture(textureInfo: IGLTFTextureInfo): Texture {
@@ -1141,31 +1149,13 @@ module BABYLON.GLTF2 {
                 return null;
                 return null;
             }
             }
 
 
-            // check the cache first
-            var babylonTexture: Texture;
-            if (texture.babylonTextures) {
-                babylonTexture = texture.babylonTextures[texCoord];
-                if (!babylonTexture) {
-                    for (var i = 0; i < texture.babylonTextures.length; i++) {
-                        babylonTexture = texture.babylonTextures[i];
-                        if (babylonTexture) {
-                            babylonTexture = babylonTexture.clone();
-                            babylonTexture.coordinatesIndex = texCoord;
-                            break;
-                        }
-                    }
-                }
-
-                return babylonTexture;
-            }
-
             var source = this._gltf.images[texture.source];
             var source = this._gltf.images[texture.source];
             var sampler = (texture.sampler === undefined ? <IGLTFSampler>{} : this._gltf.samplers[texture.sampler]);
             var sampler = (texture.sampler === undefined ? <IGLTFSampler>{} : this._gltf.samplers[texture.sampler]);
             var noMipMaps = (sampler.minFilter === ETextureMinFilter.NEAREST || sampler.minFilter === ETextureMinFilter.LINEAR);
             var noMipMaps = (sampler.minFilter === ETextureMinFilter.NEAREST || sampler.minFilter === ETextureMinFilter.LINEAR);
             var samplingMode = GLTFUtils.GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
             var samplingMode = GLTFUtils.GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
 
 
             this.addPendingData(texture);
             this.addPendingData(texture);
-            babylonTexture = new Texture(null, this._babylonScene, noMipMaps, false, samplingMode, () => {
+            var babylonTexture = new Texture(null, this._babylonScene, noMipMaps, false, samplingMode, () => {
                 if (!this._disposed) {
                 if (!this._disposed) {
                     this.removePendingData(texture);
                     this.removePendingData(texture);
                 }
                 }
@@ -1176,27 +1166,41 @@ module BABYLON.GLTF2 {
                 }
                 }
             });
             });
 
 
-            var setTextureData = data => {
-                var url = URL.createObjectURL(new Blob([data], { type: source.mimeType }));
-                this._objectURLs.push(url);
-                babylonTexture.updateURL(url);
-            };
-
-            if (!source.uri) {
-                var bufferView = this._gltf.bufferViews[source.bufferView];
-                this._loadBufferViewAsync(bufferView, 0, bufferView.byteLength, 1, EComponentType.UNSIGNED_BYTE, setTextureData);
+            if (texture.url) {
+                babylonTexture.updateURL(texture.url);
             }
             }
-            else if (GLTFUtils.IsBase64(source.uri)) {
-                setTextureData(new Uint8Array(GLTFUtils.DecodeBase64(source.uri)));
+            else if (texture.dataReadyObservable) {
+                texture.dataReadyObservable.add(texture => {
+                    babylonTexture.updateURL(texture.url);
+                });
             }
             }
             else {
             else {
-                Tools.LoadFile(this._rootUrl + source.uri, setTextureData, event => {
-                    if (!this._disposed) {
-                        this._onProgress(event);
-                    }
-                }, this._babylonScene.database, true, request => {
-                    this._onError("Failed to load file '" + source.uri + "': " + request.status + " " + request.statusText);
+                texture.dataReadyObservable = new Observable<IGLTFTexture>();
+                texture.dataReadyObservable.add(texture => {
+                    babylonTexture.updateURL(texture.url);
                 });
                 });
+
+                var setTextureData = data => {
+                    texture.url = URL.createObjectURL(new Blob([data], { type: source.mimeType }));
+                    texture.dataReadyObservable.notifyObservers(texture);
+                };
+
+                if (!source.uri) {
+                    var bufferView = this._gltf.bufferViews[source.bufferView];
+                    this._loadBufferViewAsync(bufferView, 0, bufferView.byteLength, 1, EComponentType.UNSIGNED_BYTE, setTextureData);
+                }
+                else if (GLTFUtils.IsBase64(source.uri)) {
+                    setTextureData(new Uint8Array(GLTFUtils.DecodeBase64(source.uri)));
+                }
+                else {
+                    Tools.LoadFile(this._rootUrl + source.uri, setTextureData, event => {
+                        if (!this._disposed) {
+                            this._onProgress(event);
+                        }
+                    }, this._babylonScene.database, true, request => {
+                        this._onError("Failed to load file '" + source.uri + "': " + request.status + " " + request.statusText);
+                    });
+                }
             }
             }
 
 
             babylonTexture.coordinatesIndex = texCoord;
             babylonTexture.coordinatesIndex = texCoord;
@@ -1204,10 +1208,6 @@ module BABYLON.GLTF2 {
             babylonTexture.wrapV = GLTFUtils.GetTextureWrapMode(sampler.wrapT);
             babylonTexture.wrapV = GLTFUtils.GetTextureWrapMode(sampler.wrapT);
             babylonTexture.name = texture.name || "texture" + textureInfo.index;
             babylonTexture.name = texture.name || "texture" + textureInfo.index;
 
 
-            // Cache the texture
-            texture.babylonTextures = texture.babylonTextures || [];
-            texture.babylonTextures[texCoord] = babylonTexture;
-
             if (this._parent.onTextureLoaded) {
             if (this._parent.onTextureLoaded) {
                 this._parent.onTextureLoaded(babylonTexture);
                 this._parent.onTextureLoaded(babylonTexture);
             }
             }

+ 3 - 3
loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts

@@ -245,8 +245,9 @@ module BABYLON.GLTF2 {
         sampler?: number;
         sampler?: number;
         source: number;
         source: number;
 
 
-        // Runtime values (one per coordinate index)
-        babylonTextures?: Texture[];
+        // Runtime values
+        url?: string;
+        dataReadyObservable?: Observable<IGLTFTexture>;
     }
     }
 
 
     export interface IGLTFTextureInfo {
     export interface IGLTFTextureInfo {
@@ -263,7 +264,6 @@ module BABYLON.GLTF2 {
         cameras?: IGLTFCamera[];
         cameras?: IGLTFCamera[];
         extensionsUsed?: string[];
         extensionsUsed?: string[];
         extensionsRequired?: string[];
         extensionsRequired?: string[];
-        glExtensionsUsed?: string[];
         images?: IGLTFImage[];
         images?: IGLTFImage[];
         materials?: IGLTFMaterial[];
         materials?: IGLTFMaterial[];
         meshes?: IGLTFMesh[];
         meshes?: IGLTFMesh[];

+ 5 - 4
localDev/index.html

@@ -3,8 +3,9 @@
 <head>
 <head>
 	<title>Local Development</title>
 	<title>Local Development</title>
 	
 	
-    <script src="https://babylonjs.azurewebsites.net/cannon.js"></script>
-    <script src="https://babylonjs.azurewebsites.net/Oimo.js"></script>
+    <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="../assets/refs/dat.gui.min.js"></script>
 	<script src="../assets/refs/dat.gui.min.js"></script>
 	<script src="../tools/DevLoader/BabylonLoader.js"></script>
 	<script src="../tools/DevLoader/BabylonLoader.js"></script>
 	<script src="src/webgl-debug.js"></script>
 	<script src="src/webgl-debug.js"></script>
@@ -39,11 +40,11 @@
 </head>
 </head>
 <body>
 <body>
 	<div id="fps">0</div>
 	<div id="fps">0</div>
-	<canvas id="renderCanvas"></canvas>
+	<canvas id="renderCanvas" touch-action="none"></canvas>
 	
 	
 	<script>
 	<script>
 		var canvas = document.getElementById("renderCanvas");
 		var canvas = document.getElementById("renderCanvas");
-		// canvas = WebGLDebugUtils.makeLostContextSimulatingCanvas(canvas);
+	//	canvas = WebGLDebugUtils.makeLostContextSimulatingCanvas(canvas);
 		var divFps = document.getElementById("fps");
 		var divFps = document.getElementById("fps");
 
 
 		// Global to simulate PG.
 		// Global to simulate PG.

+ 1 - 0
materialsLibrary/src/cell/babylon.cellMaterial.ts

@@ -18,6 +18,7 @@ module BABYLON {
         public NDOTL = true;
         public NDOTL = true;
         public CUSTOMUSERLIGHTING = true;
         public CUSTOMUSERLIGHTING = true;
         public CELLBASIC = true;
         public CELLBASIC = true;
+        public DEPTHPREPASS = false;
         public USERIGHTHANDEDSYSTEM = false;
         public USERIGHTHANDEDSYSTEM = false;
 
 
         constructor() {
         constructor() {

+ 2 - 0
materialsLibrary/src/cell/cell.fragment.fx

@@ -107,6 +107,8 @@ void main(void)
 		discard;
 		discard;
 #endif
 #endif
 
 
+#include<depthPrePass>
+
 	baseColor.rgb *= vDiffuseInfos.y;
 	baseColor.rgb *= vDiffuseInfos.y;
 #endif
 #endif
 
 

+ 1 - 0
materialsLibrary/src/fire/babylon.fireMaterial.ts

@@ -6,6 +6,7 @@ module BABYLON {
         public DIFFUSE = false;
         public DIFFUSE = false;
         public CLIPPLANE = false;
         public CLIPPLANE = false;
         public ALPHATEST = false;
         public ALPHATEST = false;
+        public DEPTHPREPASS = false;
         public POINTSIZE = false;
         public POINTSIZE = false;
         public FOG = false;
         public FOG = false;
         public UV1 = false;
         public UV1 = false;

+ 2 - 0
materialsLibrary/src/fire/fire.fragment.fx

@@ -71,6 +71,8 @@ void main(void) {
 	if (opacityColor.r < 0.1)
 	if (opacityColor.r < 0.1)
 		discard;
 		discard;
 #endif
 #endif
+
+#include<depthPrePass>
 	
 	
 	baseColor = texture2D(diffuseSampler, perturbedBaseCoords.xy) * 2.0;
 	baseColor = texture2D(diffuseSampler, perturbedBaseCoords.xy) * 2.0;
 	baseColor *= opacityColor;
 	baseColor *= opacityColor;

+ 1 - 0
materialsLibrary/src/fur/babylon.furMaterial.ts

@@ -6,6 +6,7 @@ module BABYLON {
         public HEIGHTMAP = false;
         public HEIGHTMAP = false;
         public CLIPPLANE = false;
         public CLIPPLANE = false;
         public ALPHATEST = false;
         public ALPHATEST = false;
+        public DEPTHPREPASS = false;
         public POINTSIZE = false;
         public POINTSIZE = false;
         public FOG = false;
         public FOG = false;
         public NORMAL = false;
         public NORMAL = false;

+ 2 - 0
materialsLibrary/src/fur/fur.fragment.fx

@@ -70,6 +70,8 @@ void main(void) {
 		discard;
 		discard;
 #endif
 #endif
 
 
+#include<depthPrePass>
+
 	baseColor.rgb *= vDiffuseInfos.y;
 	baseColor.rgb *= vDiffuseInfos.y;
 #endif
 #endif
 
 

+ 1 - 0
materialsLibrary/src/gradient/babylon.gradientMaterial.ts

@@ -5,6 +5,7 @@ module BABYLON {
         public DIFFUSE = false;
         public DIFFUSE = false;
         public CLIPPLANE = false;
         public CLIPPLANE = false;
         public ALPHATEST = false;
         public ALPHATEST = false;
+        public DEPTHPREPASS = false;
         public POINTSIZE = false;
         public POINTSIZE = false;
         public FOG = false;
         public FOG = false;
         public LIGHT0 = false;
         public LIGHT0 = false;

+ 2 - 0
materialsLibrary/src/gradient/gradient.fragment.fx

@@ -68,6 +68,8 @@ void main(void) {
 		discard;
 		discard;
 #endif
 #endif
 
 
+#include<depthPrePass>
+
 #ifdef VERTEXCOLOR
 #ifdef VERTEXCOLOR
 	baseColor.rgb *= vColor.rgb;
 	baseColor.rgb *= vColor.rgb;
 #endif
 #endif

+ 1 - 0
materialsLibrary/src/lava/babylon.lavaMaterial.ts

@@ -5,6 +5,7 @@ module BABYLON {
         public DIFFUSE = false;
         public DIFFUSE = false;
         public CLIPPLANE = false;
         public CLIPPLANE = false;
         public ALPHATEST = false;
         public ALPHATEST = false;
+        public DEPTHPREPASS = false;
         public POINTSIZE = false;
         public POINTSIZE = false;
         public FOG = false;
         public FOG = false;
         public LIGHT0 = false;
         public LIGHT0 = false;

+ 2 - 0
materialsLibrary/src/lava/lava.fragment.fx

@@ -108,6 +108,8 @@ void main(void) {
 		discard;
 		discard;
 #endif
 #endif
 
 
+#include<depthPrePass>
+
 	baseColor.rgb *= vDiffuseInfos.y;
 	baseColor.rgb *= vDiffuseInfos.y;
 #endif
 #endif
 
 

+ 1 - 0
materialsLibrary/src/normal/babylon.normalMaterial.ts

@@ -5,6 +5,7 @@ module BABYLON {
         public DIFFUSE = false;
         public DIFFUSE = false;
         public CLIPPLANE = false;
         public CLIPPLANE = false;
         public ALPHATEST = false;
         public ALPHATEST = false;
+        public DEPTHPREPASS = false;
         public POINTSIZE = false;
         public POINTSIZE = false;
         public FOG = false;
         public FOG = false;
         public LIGHT0 = false;
         public LIGHT0 = false;

+ 2 - 0
materialsLibrary/src/normal/normal.fragment.fx

@@ -60,6 +60,8 @@ void main(void) {
 		discard;
 		discard;
 #endif
 #endif
 
 
+#include<depthPrePass>
+
 	baseColor.rgb *= vDiffuseInfos.y;
 	baseColor.rgb *= vDiffuseInfos.y;
 #endif
 #endif
 
 

+ 1 - 0
materialsLibrary/src/simple/babylon.simpleMaterial.ts

@@ -5,6 +5,7 @@ module BABYLON {
         public DIFFUSE = false;
         public DIFFUSE = false;
         public CLIPPLANE = false;
         public CLIPPLANE = false;
         public ALPHATEST = false;
         public ALPHATEST = false;
+        public DEPTHPREPASS = false;
         public POINTSIZE = false;
         public POINTSIZE = false;
         public FOG = false;
         public FOG = false;
         public NORMAL = false;
         public NORMAL = false;

+ 2 - 0
materialsLibrary/src/simple/simple.fragment.fx

@@ -56,6 +56,8 @@ void main(void) {
 		discard;
 		discard;
 #endif
 #endif
 
 
+#include<depthPrePass>
+
 	baseColor.rgb *= vDiffuseInfos.y;
 	baseColor.rgb *= vDiffuseInfos.y;
 #endif
 #endif
 
 

+ 1 - 0
materialsLibrary/src/terrain/babylon.terrainMaterial.ts

@@ -7,6 +7,7 @@ module BABYLON {
         public BUMP = false;
         public BUMP = false;
         public CLIPPLANE = false;
         public CLIPPLANE = false;
         public ALPHATEST = false;
         public ALPHATEST = false;
+        public DEPTHPREPASS = false;
         public POINTSIZE = false;
         public POINTSIZE = false;
         public FOG = false;
         public FOG = false;
         public SPECULARTERM = false;
         public SPECULARTERM = false;

+ 2 - 0
materialsLibrary/src/terrain/terrain.fragment.fx

@@ -137,6 +137,8 @@ void main(void) {
 		discard;
 		discard;
 #endif
 #endif
 
 
+#include<depthPrePass>
+
 	baseColor.rgb *= vTextureInfos.y;
 	baseColor.rgb *= vTextureInfos.y;
 	
 	
 	vec4 diffuse1Color = texture2D(diffuse1Sampler, vTextureUV * diffuse1Infos);
 	vec4 diffuse1Color = texture2D(diffuse1Sampler, vTextureUV * diffuse1Infos);

+ 1 - 0
materialsLibrary/src/triPlanar/babylon.triPlanarMaterial.ts

@@ -12,6 +12,7 @@ module BABYLON {
         
         
         public CLIPPLANE = false;
         public CLIPPLANE = false;
         public ALPHATEST = false;
         public ALPHATEST = false;
+        public DEPTHPREPASS = false;
         public POINTSIZE = false;
         public POINTSIZE = false;
         public FOG = false;
         public FOG = false;
         public SPECULARTERM = false;
         public SPECULARTERM = false;

+ 2 - 0
materialsLibrary/src/triPlanar/triplanar.fragment.fx

@@ -108,6 +108,8 @@ void main(void) {
 		discard;
 		discard;
 #endif
 #endif
 
 
+#include<depthPrePass>
+
 #ifdef VERTEXCOLOR
 #ifdef VERTEXCOLOR
 	baseColor.rgb *= vColor.rgb;
 	baseColor.rgb *= vColor.rgb;
 #endif
 #endif

+ 1 - 0
materialsLibrary/src/water/babylon.waterMaterial.ts

@@ -6,6 +6,7 @@ module BABYLON {
         public REFLECTION = false;
         public REFLECTION = false;
         public CLIPPLANE = false;
         public CLIPPLANE = false;
         public ALPHATEST = false;
         public ALPHATEST = false;
+        public DEPTHPREPASS = false;
         public POINTSIZE = false;
         public POINTSIZE = false;
         public FOG = false;
         public FOG = false;
         public NORMAL = false;
         public NORMAL = false;

+ 3 - 2
src/Animations/babylon.animation.ts

@@ -89,6 +89,8 @@
     }
     }
 
 
     export class Animation {
     export class Animation {
+        public static AllowMatricesInterpolation = false;
+
         private _keys: Array<{frame:number, value: any, inTangent?: any, outTangent?: any}>;
         private _keys: Array<{frame:number, value: any, inTangent?: any, outTangent?: any}>;
         private _offsetsCache = {};
         private _offsetsCache = {};
         private _highLimitsCache = {};
         private _highLimitsCache = {};
@@ -103,7 +105,6 @@
         public targetPropertyPath: string[];
         public targetPropertyPath: string[];
         public currentFrame: number;
         public currentFrame: number;
 
 
-        public allowMatricesInterpolation = false;
 
 
         public blendingSpeed = 0.01;
         public blendingSpeed = 0.01;
         private _originalBlendValue: any;
         private _originalBlendValue: any;
@@ -520,7 +521,7 @@
                             switch (loopMode) {
                             switch (loopMode) {
                                 case Animation.ANIMATIONLOOPMODE_CYCLE:
                                 case Animation.ANIMATIONLOOPMODE_CYCLE:
                                 case Animation.ANIMATIONLOOPMODE_CONSTANT:
                                 case Animation.ANIMATIONLOOPMODE_CONSTANT:
-                                    if (this.allowMatricesInterpolation) {
+                                    if (Animation.AllowMatricesInterpolation) {
                                         return this.matrixInterpolateFunction(startValue, endValue, gradient);
                                         return this.matrixInterpolateFunction(startValue, endValue, gradient);
                                     }
                                     }
                                 case Animation.ANIMATIONLOOPMODE_RELATIVE:
                                 case Animation.ANIMATIONLOOPMODE_RELATIVE:

+ 7 - 5
src/Behaviors/Cameras/babylon.framingBehavior.ts

@@ -205,12 +205,13 @@ module BABYLON {
 		 * @param radius Optional. If a cached radius position already exists, overrides default.
 		 * @param radius Optional. If a cached radius position already exists, overrides default.
 		 * @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top
 		 * @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top
 		 * @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
 		 * @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
+		 * @param onAnimationEnd Callback triggered at the end of the framing animation
 		 */
 		 */
-		public zoomOnMesh(mesh: AbstractMesh, focusOnOriginXZ: boolean = false): void {
+		public zoomOnMesh(mesh: AbstractMesh, focusOnOriginXZ: boolean = false, onAnimationEnd: () => void = null): void {
 			mesh.computeWorldMatrix(true);
 			mesh.computeWorldMatrix(true);
 
 
 			let boundingBox = mesh.getBoundingInfo().boundingBox;
 			let boundingBox = mesh.getBoundingInfo().boundingBox;
-			this.zoomOnBoundingInfo(boundingBox.minimumWorld, boundingBox.maximumWorld, focusOnOriginXZ);
+			this.zoomOnBoundingInfo(boundingBox.minimumWorld, boundingBox.maximumWorld, focusOnOriginXZ, onAnimationEnd);
 		}
 		}
 
 
 		/**
 		/**
@@ -219,8 +220,9 @@ module BABYLON {
 		 * @param radius Optional. If a cached radius position already exists, overrides default.
 		 * @param radius Optional. If a cached radius position already exists, overrides default.
 		 * @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top
 		 * @param framingPositionY Position on mesh to center camera focus where 0 corresponds bottom of its bounding box and 1, the top
 		 * @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
 		 * @param focusOnOriginXZ Determines if the camera should focus on 0 in the X and Z axis instead of the mesh
+		 * @param onAnimationEnd Callback triggered at the end of the framing animation
 		 */
 		 */
-		public zoomOnBoundingInfo(minimumWorld: Vector3, maximumWorld: Vector3, focusOnOriginXZ: boolean = false): void {
+		public zoomOnBoundingInfo(minimumWorld: Vector3, maximumWorld: Vector3, focusOnOriginXZ: boolean = false, onAnimationEnd: () => void = null): void {
 			let zoomTarget: BABYLON.Vector3;
 			let zoomTarget: BABYLON.Vector3;
 
 
 			// Find target by interpolating from bottom of bounding box in world-space to top via framingPositionY
 			// Find target by interpolating from bottom of bounding box in world-space to top via framingPositionY
@@ -265,8 +267,8 @@ module BABYLON {
 			}
 			}
 
 
 			this._animatables.push(Animation.TransitionTo("radius", radius, this._attachedCamera, this._attachedCamera.getScene(), 
 			this._animatables.push(Animation.TransitionTo("radius", radius, this._attachedCamera, this._attachedCamera.getScene(), 
-									60, this._radiusTransition, this._framingTime));															
-		}	
+				60, this._radiusTransition, this._framingTime, onAnimationEnd));
+		}
 		
 		
 		/**
 		/**
 		 * Calculates the lowest radius for the camera based on the bounding box of the mesh.
 		 * Calculates the lowest radius for the camera based on the bounding box of the mesh.

+ 57 - 78
src/Cameras/Inputs/babylon.arcRotateCameraKeyboardMoveInput.ts

@@ -2,11 +2,6 @@ module BABYLON {
     export class ArcRotateCameraKeyboardMoveInput implements ICameraInput<ArcRotateCamera> {
     export class ArcRotateCameraKeyboardMoveInput implements ICameraInput<ArcRotateCamera> {
         camera: ArcRotateCamera;
         camera: ArcRotateCamera;
         private _keys = [];
         private _keys = [];
-        private _onKeyDown: (e: KeyboardEvent) => any;
-        private _onKeyUp: (e: KeyboardEvent) => any;
-        private _onLostFocus: (e: FocusEvent) => any;
-        private _onFocus: () => void;
-        private _onBlur: () => void;
         
         
         @serialize()
         @serialize()
         public keysUp = [38];
         public keysUp = [38];
@@ -27,97 +22,81 @@ module BABYLON {
         public panningSensibility: number = 50.0;        
         public panningSensibility: number = 50.0;        
 
 
         private _ctrlPressed: boolean;
         private _ctrlPressed: boolean;
+        private _onCanvasBlurObserver: Observer<Engine>;
+        private _onKeyboardObserver: Observer<KeyboardInfo>;
+        private _engine: Engine;
+        private _scene: Scene;
 
 
         public attachControl(element: HTMLElement, noPreventDefault?: boolean) {
         public attachControl(element: HTMLElement, noPreventDefault?: boolean) {
-            element.tabIndex = 1;
-
-            this._onKeyDown = evt => {
-
-                this._ctrlPressed = evt.ctrlKey;
-
-                if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                    this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                    this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                    this.keysRight.indexOf(evt.keyCode) !== -1 ||
-                    this.keysReset.indexOf(evt.keyCode) !== -1) {
-                    var index = this._keys.indexOf(evt.keyCode);
+            if (this._onCanvasBlurObserver) {
+                return;
+            }
+            
+            this._scene = this.camera.getScene();
+            this._engine = this._scene.getEngine();
 
 
-                    if (index === -1) {
-                        this._keys.push(evt.keyCode);
-                    }
+            this._onCanvasBlurObserver = this._engine.onCanvasBlurObservable.add(()=>{
+                this._keys = [];
+            });
+
+            this._onKeyboardObserver = this._scene.onKeyboardObservable.add(info => {
+                let evt = info.event;
+
+                if (info.type === KeyboardEventTypes.KEYDOWN) {
+                    this._ctrlPressed = evt.ctrlKey;
+                    
+                    if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        this.keysRight.indexOf(evt.keyCode) !== -1 ||
+                        this.keysReset.indexOf(evt.keyCode) !== -1) {
+                        var index = this._keys.indexOf(evt.keyCode);
+
+                        if (index === -1) {
+                            this._keys.push(evt.keyCode);
+                        }
 
 
-                    if (evt.preventDefault) {
-                        if (!noPreventDefault) {
-                            evt.preventDefault();
+                        if (evt.preventDefault) {
+                            if (!noPreventDefault) {
+                                evt.preventDefault();
+                            }
                         }
                         }
                     }
                     }
-                }
-            };
-
-            this._onKeyUp = evt => {
-                
-                if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                    this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                    this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                    this.keysRight.indexOf(evt.keyCode) !== -1 ||
-                    this.keysReset.indexOf(evt.keyCode) !== -1) {
-                    var index = this._keys.indexOf(evt.keyCode);
-
-                    if (index >= 0) {
-                        this._keys.splice(index, 1);
-                    }
-
-                    if (evt.preventDefault) {
-                        if (!noPreventDefault) {
-                            evt.preventDefault();
+                } else {
+                    if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        this.keysRight.indexOf(evt.keyCode) !== -1 ||
+                        this.keysReset.indexOf(evt.keyCode) !== -1) {
+                        var index = this._keys.indexOf(evt.keyCode);
+    
+                        if (index >= 0) {
+                            this._keys.splice(index, 1);
+                        }
+    
+                        if (evt.preventDefault) {
+                            if (!noPreventDefault) {
+                                evt.preventDefault();
+                            }
                         }
                         }
                     }
                     }
                 }
                 }
-            };
-
-            this._onLostFocus = () => {
-                this._keys = [];
-            };
-
-            this._onFocus = () => {
-                element.addEventListener("keydown", this._onKeyDown, false);
-                element.addEventListener("keyup", this._onKeyUp, false);   
-            }
-
-            this._onBlur = () => {
-                element.removeEventListener("keydown", this._onKeyDown);
-                element.removeEventListener("keyup", this._onKeyUp);
-            }
-
-            element.addEventListener("focus", this._onFocus);
-            element.addEventListener("blur", this._onBlur);
-
-            Tools.RegisterTopRootEvents([
-                { name: "blur", handler: this._onLostFocus }
-            ]);
+            });    
         }
         }
 
 
         public detachControl(element: HTMLElement) {
         public detachControl(element: HTMLElement) {
-            if (element && this._onBlur) {
-                this._onBlur();
-                element.removeEventListener("focus", this._onFocus);
-                element.removeEventListener("blur", this._onBlur);
+            if (this._scene) {
+                this._scene.onKeyboardObservable.remove(this._onKeyboardObserver);
+                this._engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
+                this._onKeyboardObserver = null;
+                this._onCanvasBlurObserver = null;
             }
             }
 
 
-            Tools.UnregisterTopRootEvents([
-                { name: "blur", handler: this._onLostFocus }
-            ]);
-            
             this._keys = [];
             this._keys = [];
-            this._onKeyDown = null;
-            this._onKeyUp = null;
-            this._onLostFocus = null;
-            this._onBlur = null;
-            this._onFocus = null;
         }
         }
 
 
         public checkInputs() {
         public checkInputs() {
-            if (this._onKeyDown){
+            if (this._onKeyboardObserver){
                 var camera = this.camera;
                 var camera = this.camera;
 
 
                 for (var index = 0; index < this._keys.length; index++) {
                 for (var index = 0; index < this._keys.length; index++) {

+ 39 - 8
src/Cameras/Inputs/babylon.arcRotateCameraPointersInput.ts

@@ -19,6 +19,9 @@ module BABYLON {
         @serialize()
         @serialize()
         public panningSensibility: number = 50.0;
         public panningSensibility: number = 50.0;
 
 
+        @serialize()
+        public multiTouchPanning: boolean = true;
+
         private _isPanClick: boolean = false;
         private _isPanClick: boolean = false;
         public pinchInwards = true;
         public pinchInwards = true;
 
 
@@ -35,7 +38,9 @@ module BABYLON {
             var engine = this.camera.getEngine();
             var engine = this.camera.getEngine();
             var cacheSoloPointer: { x: number, y: number, pointerId: number, type: any }; // cache pointer object for better perf on camera rotation
             var cacheSoloPointer: { x: number, y: number, pointerId: number, type: any }; // cache pointer object for better perf on camera rotation
             var pointA: { x: number, y: number, pointerId: number, type: any }, pointB: { x: number, y: number, pointerId: number, type: any };
             var pointA: { x: number, y: number, pointerId: number, type: any }, pointB: { x: number, y: number, pointerId: number, type: any };
+            var previousPinchSquaredDistance = 0;
             var previousPinchDistance = 0;
             var previousPinchDistance = 0;
+            var previousMultiTouchPanPosition: { x: number, y: number, isPaning: boolean } = { x: 0, y:0, isPaning: false };
 
 
             this._pointerInput = (p, s) => {
             this._pointerInput = (p, s) => {
                 var evt = <PointerEvent>p.event;
                 var evt = <PointerEvent>p.event;
@@ -78,7 +83,9 @@ module BABYLON {
                     }
                     }
 
 
                     cacheSoloPointer = null;
                     cacheSoloPointer = null;
+                    previousPinchSquaredDistance = 0;
                     previousPinchDistance = 0;
                     previousPinchDistance = 0;
+                    previousMultiTouchPanPosition.isPaning = false;
 
 
                     //would be better to use pointers.remove(evt.pointerId) for multitouch gestures, 
                     //would be better to use pointers.remove(evt.pointerId) for multitouch gestures, 
                     //but emptying completly pointers collection is required to fix a bug on iPhone : 
                     //but emptying completly pointers collection is required to fix a bug on iPhone : 
@@ -97,8 +104,7 @@ module BABYLON {
                     // One button down
                     // One button down
                     if (pointA && pointB === undefined) {
                     if (pointA && pointB === undefined) {
                         if (this.panningSensibility !== 0 &&
                         if (this.panningSensibility !== 0 &&
-                            ((evt.ctrlKey && this.camera._useCtrlForPanning) ||
-                                (!this.camera._useCtrlForPanning && this._isPanClick))) {
+                            ((evt.ctrlKey && this.camera._useCtrlForPanning) || this._isPanClick)) {
                             this.camera.inertialPanningX += -(evt.clientX - cacheSoloPointer.x) / this.panningSensibility;
                             this.camera.inertialPanningX += -(evt.clientX - cacheSoloPointer.x) / this.panningSensibility;
                             this.camera.inertialPanningY += (evt.clientY - cacheSoloPointer.y) / this.panningSensibility;
                             this.camera.inertialPanningY += (evt.clientY - cacheSoloPointer.y) / this.panningSensibility;
                         } else {
                         } else {
@@ -112,7 +118,7 @@ module BABYLON {
                         cacheSoloPointer.y = evt.clientY;
                         cacheSoloPointer.y = evt.clientY;
                     }
                     }
 
 
-                    // Two buttons down: pinch
+                    // Two buttons down: pinch/pan
                     else if (pointA && pointB) {
                     else if (pointA && pointB) {
                         //if (noPreventDefault) { evt.preventDefault(); } //if pinch gesture, could be useful to force preventDefault to avoid html page scroll/zoom in some mobile browsers
                         //if (noPreventDefault) { evt.preventDefault(); } //if pinch gesture, could be useful to force preventDefault to avoid html page scroll/zoom in some mobile browsers
                         var ed = (pointA.pointerId === evt.pointerId) ? pointA : pointB;
                         var ed = (pointA.pointerId === evt.pointerId) ? pointA : pointB;
@@ -122,19 +128,42 @@ module BABYLON {
                         var distX = pointA.x - pointB.x;
                         var distX = pointA.x - pointB.x;
                         var distY = pointA.y - pointB.y;
                         var distY = pointA.y - pointB.y;
                         var pinchSquaredDistance = (distX * distX) + (distY * distY);
                         var pinchSquaredDistance = (distX * distX) + (distY * distY);
-                        if (previousPinchDistance === 0) {
-                            previousPinchDistance = pinchSquaredDistance;
+                        var pinchDistance = Math.sqrt(pinchSquaredDistance);
+                        if (previousPinchSquaredDistance === 0) {
+                            previousPinchSquaredDistance = pinchSquaredDistance;
+                            previousPinchDistance = pinchDistance;
                             return;
                             return;
                         }
                         }
 
 
-                        if (pinchSquaredDistance !== previousPinchDistance) {
+                        if (Math.abs(pinchDistance - previousPinchDistance) > this.camera.pinchToPanMaxDistance) {
                             this.camera
                             this.camera
-                                .inertialRadiusOffset += (pinchSquaredDistance - previousPinchDistance) /
+                                .inertialRadiusOffset += (pinchSquaredDistance - previousPinchSquaredDistance) /
                                 (this.pinchPrecision *
                                 (this.pinchPrecision *
                                     ((this.angularSensibilityX + this.angularSensibilityY) / 2) *
                                     ((this.angularSensibilityX + this.angularSensibilityY) / 2) *
                                     direction);
                                     direction);
-                            previousPinchDistance = pinchSquaredDistance;
+                            previousMultiTouchPanPosition.isPaning = false;
+                        }
+                        else {
+                            if (cacheSoloPointer.pointerId === ed.pointerId && this.panningSensibility !== 0 && this.multiTouchPanning) {
+                                if (!previousMultiTouchPanPosition.isPaning) {
+                                    previousMultiTouchPanPosition.isPaning = true;
+                                    previousMultiTouchPanPosition.x = ed.x;
+                                    previousMultiTouchPanPosition.y = ed.y;
+                                    return;
+                                }
+
+                                this.camera.inertialPanningX += -(ed.x - previousMultiTouchPanPosition.x) / this.panningSensibility;
+                                this.camera.inertialPanningY += (ed.y - previousMultiTouchPanPosition.y) / this.panningSensibility;
+                            }
                         }
                         }
+
+                        if (cacheSoloPointer.pointerId === evt.pointerId) {
+                            previousMultiTouchPanPosition.x = ed.x;
+                            previousMultiTouchPanPosition.y = ed.y;
+                        }
+
+                        previousPinchSquaredDistance = pinchSquaredDistance;
+                        previousPinchDistance = pinchDistance;
                     }
                     }
                 }
                 }
             }
             }
@@ -152,7 +181,9 @@ module BABYLON {
             this._onLostFocus = () => {
             this._onLostFocus = () => {
                 //this._keys = [];
                 //this._keys = [];
                 pointA = pointB = undefined;
                 pointA = pointB = undefined;
+                previousPinchSquaredDistance = 0;
                 previousPinchDistance = 0;
                 previousPinchDistance = 0;
+                previousMultiTouchPanPosition.isPaning = false;
                 cacheSoloPointer = null;
                 cacheSoloPointer = null;
             };
             };
 
 

+ 28 - 28
src/Cameras/Inputs/babylon.freeCameraKeyboardMoveInput.ts

@@ -2,8 +2,10 @@ module BABYLON {
     export class FreeCameraKeyboardMoveInput implements ICameraInput<FreeCamera> {
     export class FreeCameraKeyboardMoveInput implements ICameraInput<FreeCamera> {
         camera: FreeCamera;
         camera: FreeCamera;
         private _keys = [];
         private _keys = [];
-        private _onKeyDown: (e: KeyboardEvent) => any;
-        private _onKeyUp: (e: KeyboardEvent) => any;
+        private _onCanvasBlurObserver: Observer<Engine>;
+        private _onKeyboardObserver: Observer<KeyboardInfo>;
+        private _engine: Engine;
+        private _scene: Scene;        
 
 
         @serialize()
         @serialize()
         public keysUp = [38];
         public keysUp = [38];
@@ -18,10 +20,21 @@ module BABYLON {
         public keysRight = [39];
         public keysRight = [39];
 
 
         attachControl(element : HTMLElement, noPreventDefault?: boolean) {
         attachControl(element : HTMLElement, noPreventDefault?: boolean) {
-            if (!this._onKeyDown) {
-                element.tabIndex = 1;
+            if (this._onCanvasBlurObserver) {
+                return;
+            }
+
+            this._scene = this.camera.getScene();
+            this._engine = this._scene.getEngine();
+
+            this._onCanvasBlurObserver = this._engine.onCanvasBlurObservable.add(()=>{
+                this._keys = [];
+            });
 
 
-                this._onKeyDown = evt => {
+            this._onKeyboardObserver = this._scene.onKeyboardObservable.add(info => {
+                let evt = info.event;
+
+                if (info.type === KeyboardEventTypes.KEYDOWN) {
                     if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
                     if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
                         this.keysDown.indexOf(evt.keyCode) !== -1 ||
                         this.keysDown.indexOf(evt.keyCode) !== -1 ||
                         this.keysLeft.indexOf(evt.keyCode) !== -1 ||
                         this.keysLeft.indexOf(evt.keyCode) !== -1 ||
@@ -35,9 +48,7 @@ module BABYLON {
                             evt.preventDefault();
                             evt.preventDefault();
                         }
                         }
                     }
                     }
-                };
-
-                this._onKeyUp = evt => {
+                } else {
                     if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
                     if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
                         this.keysDown.indexOf(evt.keyCode) !== -1 ||
                         this.keysDown.indexOf(evt.keyCode) !== -1 ||
                         this.keysLeft.indexOf(evt.keyCode) !== -1 ||
                         this.keysLeft.indexOf(evt.keyCode) !== -1 ||
@@ -51,33 +62,22 @@ module BABYLON {
                             evt.preventDefault();
                             evt.preventDefault();
                         }
                         }
                     }
                     }
-                };
-
-                element.addEventListener("keydown", this._onKeyDown, false);
-                element.addEventListener("keyup", this._onKeyUp, false);
-
-                Tools.RegisterTopRootEvents([
-                    { name: "blur", handler: this._onLostFocus }
-                ]);
-            }
+                }
+            });     
         }
         }
 
 
         detachControl(element : HTMLElement) {
         detachControl(element : HTMLElement) {
-            if (this._onKeyDown) {
-                element.removeEventListener("keydown", this._onKeyDown);
-                element.removeEventListener("keyup", this._onKeyUp);
-
-                Tools.UnregisterTopRootEvents([
-                    { name: "blur", handler: this._onLostFocus }
-                ]);
-                this._keys = [];
-                this._onKeyDown = null;
-                this._onKeyUp = null;
+            if (this._scene) {
+                this._scene.onKeyboardObservable.remove(this._onKeyboardObserver);
+                this._engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
+                this._onKeyboardObserver = null;
+                this._onCanvasBlurObserver = null;
             }
             }
+            this._keys = [];
         }
         }
         
         
         public checkInputs() {
         public checkInputs() {
-            if (this._onKeyDown){
+            if (this._onKeyboardObserver){
                 var camera = this.camera;
                 var camera = this.camera;
                 // Keyboard
                 // Keyboard
                 for (var index = 0; index < this._keys.length; index++) {
                 for (var index = 0; index < this._keys.length; index++) {

+ 11 - 3
src/Cameras/VR/babylon.webVRCamera.ts

@@ -406,9 +406,17 @@ module BABYLON {
                                 if (!this._lightOnControllers) {
                                 if (!this._lightOnControllers) {
                                     this._lightOnControllers = new BABYLON.HemisphericLight("vrControllersLight", new BABYLON.Vector3(0, 1, 0), this.getScene());
                                     this._lightOnControllers = new BABYLON.HemisphericLight("vrControllersLight", new BABYLON.Vector3(0, 1, 0), this.getScene());
                                 }
                                 }
-                                loadedMesh.getChildren().forEach((mesh) => {
-                                    this._lightOnControllers.includedOnlyMeshes.push(<AbstractMesh>mesh);
-                                });
+                                let activateLightOnSubMeshes = function(mesh: AbstractMesh, light: HemisphericLight) {
+                                    let children = mesh.getChildren();
+                                    if (children.length !== 0) {
+                                        children.forEach((mesh) => {
+                                            light.includedOnlyMeshes.push(<AbstractMesh>mesh);
+                                            activateLightOnSubMeshes(<AbstractMesh>mesh, light);
+                                        });
+                                    }
+                                }
+                                this._lightOnControllers.includedOnlyMeshes.push(loadedMesh);
+                                activateLightOnSubMeshes(loadedMesh, this._lightOnControllers);
                             }
                             }
                         });
                         });
                     }
                     }

+ 22 - 4
src/Cameras/babylon.arcRotateCamera.ts

@@ -57,6 +57,15 @@ module BABYLON {
         public inertialPanningY: number = 0;
         public inertialPanningY: number = 0;
 
 
         @serialize()
         @serialize()
+        public pinchToPanMaxDistance: number = 2;
+
+        @serialize()
+        public panningDistanceLimit: number = null;
+
+        @serializeAsVector3()
+        public panningOriginTarget: Vector3 = Vector3.Zero();
+
+        @serialize()
         public panningInertia = 0.9;
         public panningInertia = 0.9;
 
 
         //-- begin properties for backward compatibility for inputs
         //-- begin properties for backward compatibility for inputs
@@ -365,8 +374,8 @@ module BABYLON {
         /**
         /**
          * Restored camera state. You must call storeState() first
          * Restored camera state. You must call storeState() first
          */
          */
-        public restoreState(): boolean {
-            if (!super.restoreState()) {
+        public _restoreStateValues(): boolean {
+            if (!super._restoreStateValues()) {
                 return false;
                 return false;
             }
             }
 
 
@@ -382,7 +391,7 @@ module BABYLON {
             this.inertialPanningY = 0;
             this.inertialPanningY = 0;
         
         
             return true;
             return true;
-        }             
+        }
 
 
         // Synchronized
         // Synchronized
         public _isSynchronizedViewMatrix(): boolean {
         public _isSynchronizedViewMatrix(): boolean {
@@ -467,7 +476,16 @@ module BABYLON {
                 }
                 }
 
 
                 if (!this._targetHost) {
                 if (!this._targetHost) {
-                    this._target.addInPlace(this._transformedDirection);
+                    if (this.panningDistanceLimit) {
+                        this._transformedDirection.addInPlace(this._target);
+                        var distanceSquared = Vector3.DistanceSquared(this._transformedDirection, this.panningOriginTarget);
+                        if (distanceSquared <= (this.panningDistanceLimit * this.panningDistanceLimit)) {
+                            this._target.copyFrom(this._transformedDirection);
+                        }
+                    }
+                    else {
+                        this._target.addInPlace(this._transformedDirection);
+                    }
                 }
                 }
 
 
                 this.inertialPanningX *= this.panningInertia;
                 this.inertialPanningX *= this.panningInertia;

+ 16 - 2
src/Cameras/babylon.camera.ts

@@ -127,6 +127,7 @@
         public onViewMatrixChangedObservable = new Observable<Camera>();
         public onViewMatrixChangedObservable = new Observable<Camera>();
         public onProjectionMatrixChangedObservable = new Observable<Camera>();
         public onProjectionMatrixChangedObservable = new Observable<Camera>();
         public onAfterCheckInputsObservable = new Observable<Camera>();
         public onAfterCheckInputsObservable = new Observable<Camera>();
+        public onRestoreStateObservable = new Observable<Camera>();
 
 
         // Cache
         // Cache
         private _computedViewMatrix = Matrix.Identity();
         private _computedViewMatrix = Matrix.Identity();
@@ -168,9 +169,9 @@
         }
         }
 
 
         /**
         /**
-         * Restored camera state. You must call storeState() first
+         * Restores the camera state values if it has been stored. You must call storeState() first
          */
          */
-        public restoreState(): boolean {
+        protected _restoreStateValues(): boolean {
             if (!this._stateStored) {
             if (!this._stateStored) {
                 return false;
                 return false;
             }
             }
@@ -180,6 +181,18 @@
             return true;
             return true;
         }
         }
 
 
+        /**
+         * Restored camera state. You must call storeState() first
+         */
+        public restoreState(): boolean {
+            if (this._restoreStateValues()) {
+                this.onRestoreStateObservable.notifyObservers(this);
+                return true;
+            }
+
+            return false;
+        }
+
         public getClassName(): string {
         public getClassName(): string {
             return "Camera";
             return "Camera";
         }
         }
@@ -577,6 +590,7 @@
             this.onViewMatrixChangedObservable.clear();
             this.onViewMatrixChangedObservable.clear();
             this.onProjectionMatrixChangedObservable.clear();
             this.onProjectionMatrixChangedObservable.clear();
             this.onAfterCheckInputsObservable.clear();
             this.onAfterCheckInputsObservable.clear();
+            this.onRestoreStateObservable.clear();
 
 
             // Inputs
             // Inputs
             if (this.inputs) {
             if (this.inputs) {

+ 4 - 4
src/Cameras/babylon.freeCamera.ts

@@ -114,7 +114,7 @@
             this._collisionMask = !isNaN(mask) ? mask : -1;
             this._collisionMask = !isNaN(mask) ? mask : -1;
         }
         }
 	 
 	 
-        public _collideWithWorld(direction: Vector3): void {
+        public _collideWithWorld(displacement: Vector3): void {
             var globalPosition: Vector3;
             var globalPosition: Vector3;
 
 
             if (this.parent) {
             if (this.parent) {
@@ -133,15 +133,15 @@
             this._collider.collisionMask = this._collisionMask;
             this._collider.collisionMask = this._collisionMask;
 		
 		
             //no need for clone, as long as gravity is not on.
             //no need for clone, as long as gravity is not on.
-            var actualDirection = direction;
+            var actualDisplacement = displacement;
 			
 			
             //add gravity to the direction to prevent the dual-collision checking
             //add gravity to the direction to prevent the dual-collision checking
             if (this.applyGravity) {
             if (this.applyGravity) {
                 //this prevents mending with cameraDirection, a global variable of the free camera class.
                 //this prevents mending with cameraDirection, a global variable of the free camera class.
-                actualDirection = direction.add(this.getScene().gravity);
+                actualDisplacement = displacement.add(this.getScene().gravity);
             }
             }
 
 
-            this.getScene().collisionCoordinator.getNewPosition(this._oldPosition, actualDirection, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
+            this.getScene().collisionCoordinator.getNewPosition(this._oldPosition, actualDisplacement, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
 
 
         }
         }
 
 

+ 2 - 2
src/Cameras/babylon.targetCamera.ts

@@ -79,8 +79,8 @@ module BABYLON {
         /**
         /**
          * Restored camera state. You must call storeState() first
          * Restored camera state. You must call storeState() first
          */
          */
-        public restoreState(): boolean {
-            if (!super.restoreState()) {
+        public _restoreStateValues(): boolean {
+            if (!super._restoreStateValues()) {
                 return false;
                 return false;
             }
             }
 
 

+ 5 - 5
src/Collisions/babylon.collisionCoordinator.ts

@@ -4,7 +4,7 @@ module BABYLON {
     export var CollisionWorker = "";
     export var CollisionWorker = "";
 
 
     export interface ICollisionCoordinator {
     export interface ICollisionCoordinator {
-        getNewPosition(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
+        getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
         init(scene: Scene): void;
         init(scene: Scene): void;
         destroy(): void;
         destroy(): void;
 
 
@@ -186,12 +186,12 @@ module BABYLON {
             }
             }
         }
         }
 
 
-        public getNewPosition(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void {
+        public getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void {
             if (!this._init) return;
             if (!this._init) return;
             if (this._collisionsCallbackArray[collisionIndex] || this._collisionsCallbackArray[collisionIndex + 100000]) return;
             if (this._collisionsCallbackArray[collisionIndex] || this._collisionsCallbackArray[collisionIndex + 100000]) return;
 
 
             position.divideToRef(collider.radius, this._scaledPosition);
             position.divideToRef(collider.radius, this._scaledPosition);
-            velocity.divideToRef(collider.radius, this._scaledVelocity);
+            displacement.divideToRef(collider.radius, this._scaledVelocity);
 
 
             this._collisionsCallbackArray[collisionIndex] = onNewPosition;
             this._collisionsCallbackArray[collisionIndex] = onNewPosition;
 
 
@@ -347,9 +347,9 @@ module BABYLON {
 
 
         private _finalPosition = Vector3.Zero();
         private _finalPosition = Vector3.Zero();
 
 
-        public getNewPosition(position: Vector3, velocity: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void {
+        public getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void {
             position.divideToRef(collider.radius, this._scaledPosition);
             position.divideToRef(collider.radius, this._scaledPosition);
-            velocity.divideToRef(collider.radius, this._scaledVelocity);
+            displacement.divideToRef(collider.radius, this._scaledVelocity);
             collider.collidedMesh = null;
             collider.collidedMesh = null;
             collider.retry = 0;
             collider.retry = 0;
             collider.initialVelocity = this._scaledVelocity;
             collider.initialVelocity = this._scaledVelocity;

+ 33 - 0
src/Events/babylon.keyboardEvents.ts

@@ -0,0 +1,33 @@
+module BABYLON {
+    
+    export class KeyboardEventTypes {
+        static _KEYDOWN = 0x01;
+        static _KEYUP = 0x02;
+
+        public static get KEYDOWN(): number {
+            return KeyboardEventTypes._KEYDOWN;
+        }
+
+        public static get KEYUP(): number {
+            return KeyboardEventTypes._KEYUP;
+        }
+    }
+
+    export class KeyboardInfo {
+        constructor(public type: number, public 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
+     */
+    export class KeyboardInfoPre extends KeyboardInfo {
+        constructor(type: number, event: KeyboardEvent) {
+            super(type, event);
+            this.skipOnPointerObservable = false;
+        }
+
+        public skipOnPointerObservable: boolean;
+    }   
+}

+ 69 - 0
src/Events/babylon.pointerEvents.ts

@@ -0,0 +1,69 @@
+module BABYLON {
+    export class PointerEventTypes {
+        static _POINTERDOWN = 0x01;
+        static _POINTERUP = 0x02;
+        static _POINTERMOVE = 0x04;
+        static _POINTERWHEEL = 0x08;
+        static _POINTERPICK = 0x10;
+        static _POINTERTAP = 0x20;
+        static _POINTERDOUBLETAP = 0x40;
+
+        public static get POINTERDOWN(): number {
+            return PointerEventTypes._POINTERDOWN;
+        }
+
+        public static get POINTERUP(): number {
+            return PointerEventTypes._POINTERUP;
+        }
+
+        public static get POINTERMOVE(): number {
+            return PointerEventTypes._POINTERMOVE;
+        }
+
+        public static get POINTERWHEEL(): number {
+            return PointerEventTypes._POINTERWHEEL;
+        }
+
+        public static get POINTERPICK(): number {
+            return PointerEventTypes._POINTERPICK;
+        }
+
+        public static get POINTERTAP(): number {
+            return PointerEventTypes._POINTERTAP;
+        }
+
+        public static get POINTERDOUBLETAP(): number {
+            return PointerEventTypes._POINTERDOUBLETAP;
+        }
+    }
+
+    export class PointerInfoBase {
+        constructor(public type: number, public 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
+     */
+    export class PointerInfoPre extends PointerInfoBase {
+        constructor(type: number, event: PointerEvent | MouseWheelEvent, localX, localY) {
+            super(type, event);
+            this.skipOnPointerObservable = false;
+            this.localPosition = new Vector2(localX, localY);
+        }
+
+        public localPosition: Vector2;
+        public 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.
+     */
+    export class PointerInfo extends PointerInfoBase {
+        constructor(type: number, event: PointerEvent | MouseWheelEvent, public pickInfo: PickingInfo) {
+            super(type, event);
+        }
+    }    
+}

+ 11 - 1
src/Layer/babylon.highlightlayer.ts

@@ -486,11 +486,21 @@ module BABYLON {
                 }
                 }
             };
             };
 
 
-            this._mainTexture.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>): void => {
+            this._mainTexture.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>): void => {
                 this.onBeforeRenderMainTextureObservable.notifyObservers(this);
                 this.onBeforeRenderMainTextureObservable.notifyObservers(this);
 
 
                 var index: number;
                 var index: number;
 
 
+                let engine = this._scene.getEngine();
+                
+                if (depthOnlySubMeshes.length) {
+                    engine.setColorWrite(false);            
+                    for (index = 0; index < depthOnlySubMeshes.length; index++) {
+                        renderSubMesh(depthOnlySubMeshes.data[index]);
+                    }
+                    engine.setColorWrite(true);
+                }                
+
                 for (index = 0; index < opaqueSubMeshes.length; index++) {
                 for (index = 0; index < opaqueSubMeshes.length; index++) {
                     renderSubMesh(opaqueSubMeshes.data[index]);
                     renderSubMesh(opaqueSubMeshes.data[index]);
                 }
                 }

+ 11 - 1
src/Lights/Shadows/babylon.shadowGenerator.ts

@@ -444,8 +444,18 @@
             }
             }
         }
         }
 
 
-        private _renderForShadowMap(opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>): void {
+        private _renderForShadowMap(opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>): void {
             var index: number;
             var index: number;
+            let engine = this._scene.getEngine();
+
+            if (depthOnlySubMeshes.length) {
+                engine.setColorWrite(false);            
+                for (index = 0; index < depthOnlySubMeshes.length; index++) {
+                    this._renderSubMeshForShadowMap(depthOnlySubMeshes.data[index]);
+                }
+                engine.setColorWrite(true);
+            }
+            
             for (index = 0; index < opaqueSubMeshes.length; index++) {
             for (index = 0; index < opaqueSubMeshes.length; index++) {
                 this._renderSubMeshForShadowMap(opaqueSubMeshes.data[index]);
                 this._renderSubMeshForShadowMap(opaqueSubMeshes.data[index]);
             }
             }

+ 1 - 0
src/Materials/PBR/babylon.pbrBaseMaterial.ts

@@ -20,6 +20,7 @@
         public OPACITYDIRECTUV = 0;
         public OPACITYDIRECTUV = 0;
         public OPACITYRGB = false;
         public OPACITYRGB = false;
         public ALPHATEST = false;
         public ALPHATEST = false;
+        public DEPTHPREPASS = false;
         public ALPHABLEND = false;
         public ALPHABLEND = false;
         public ALPHAFROMALBEDO = false;
         public ALPHAFROMALBEDO = false;
         public ALPHATESTVALUE = 0.5;
         public ALPHATESTVALUE = 0.5;

+ 2 - 0
src/Materials/Textures/babylon.mirrorTexture.ts

@@ -61,6 +61,8 @@ module BABYLON {
         constructor(name: string, size: any, scene: Scene, generateMipMaps?: boolean, type: number = Engine.TEXTURETYPE_UNSIGNED_INT, samplingMode = Texture.BILINEAR_SAMPLINGMODE, generateDepthBuffer = true) {
         constructor(name: string, size: any, scene: Scene, generateMipMaps?: boolean, type: number = Engine.TEXTURETYPE_UNSIGNED_INT, samplingMode = Texture.BILINEAR_SAMPLINGMODE, generateDepthBuffer = true) {
             super(name, size, scene, generateMipMaps, true, type, false, samplingMode, generateDepthBuffer);
             super(name, size, scene, generateMipMaps, true, type, false, samplingMode, generateDepthBuffer);
 
 
+            this.ignoreCameraViewport = true;
+
             this.onBeforeRenderObservable.add(() => {
             this.onBeforeRenderObservable.add(() => {
                 Matrix.ReflectionToRef(this.mirrorPlane, this._mirrorMatrix);
                 Matrix.ReflectionToRef(this.mirrorPlane, this._mirrorMatrix);
                 this._savedViewMatrix = scene.getViewMatrix();
                 this._savedViewMatrix = scene.getViewMatrix();

+ 16 - 0
src/Materials/Textures/babylon.multiRenderTarget.ts

@@ -29,6 +29,22 @@ module BABYLON {
             return this._textures[this._textures.length - 1];
             return this._textures[this._textures.length - 1];
         }
         }
 
 
+        public set wrapU (wrap: number) {
+            if (this._textures) {
+                for (var i = 0; i < this._textures.length; i++) {
+                    this._textures[i].wrapU = wrap;
+                }
+            }
+        }
+
+        public set wrapV (wrap: number) {
+            if (this._textures) {
+                for (var i = 0; i < this._textures.length; i++) {
+                    this._textures[i].wrapV = wrap;
+                }
+            }
+        }
+
         constructor(name: string, size: any, count: number, scene: Scene, options?: any) {
         constructor(name: string, size: any, count: number, scene: Scene, options?: any) {
             options = options || {};
             options = options || {};
 
 

+ 1 - 1
src/Materials/Textures/babylon.renderTargetTexture.ts

@@ -30,7 +30,7 @@
         public renderSprites = false;
         public renderSprites = false;
         public coordinatesMode = Texture.PROJECTION_MODE;
         public coordinatesMode = Texture.PROJECTION_MODE;
         public activeCamera: Camera;
         public activeCamera: Camera;
-        public customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, beforeTransparents?: () => void) => void;
+        public customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>, beforeTransparents?: () => void) => void;
         public useCameraPostProcesses: boolean;
         public useCameraPostProcesses: boolean;
         public ignoreCameraViewport: boolean = false;
         public ignoreCameraViewport: boolean = false;
 
 

+ 6 - 2
src/Materials/babylon.effect.ts

@@ -378,12 +378,15 @@
                 callback(preparedSourceCode.replace("#version 300 es", ""));
                 callback(preparedSourceCode.replace("#version 300 es", ""));
                 return;
                 return;
             }
             }
+
+            var hasDrawBuffersExtension = preparedSourceCode.search(/#extension.+GL_EXT_draw_buffers.+require/) !== -1;
             
             
             // Remove extensions 
             // Remove extensions 
             // #extension GL_OES_standard_derivatives : enable
             // #extension GL_OES_standard_derivatives : enable
             // #extension GL_EXT_shader_texture_lod : enable
             // #extension GL_EXT_shader_texture_lod : enable
             // #extension GL_EXT_frag_depth : enable
             // #extension GL_EXT_frag_depth : enable
-            var regex = /#extension.+(GL_OES_standard_derivatives|GL_EXT_shader_texture_lod|GL_EXT_frag_depth).+enable/g;
+            // #extension GL_EXT_draw_buffers : require
+            var regex = /#extension.+(GL_OES_standard_derivatives|GL_EXT_shader_texture_lod|GL_EXT_frag_depth|GL_EXT_draw_buffers).+(enable|require)/g;
             var result = preparedSourceCode.replace(regex, "");
             var result = preparedSourceCode.replace(regex, "");
 
 
             // Migrate to GLSL v300
             // Migrate to GLSL v300
@@ -398,7 +401,8 @@
                 result = result.replace(/textureCube\(/g, "texture(");
                 result = result.replace(/textureCube\(/g, "texture(");
                 result = result.replace(/gl_FragDepthEXT/g, "gl_FragDepth");
                 result = result.replace(/gl_FragDepthEXT/g, "gl_FragDepth");
                 result = result.replace(/gl_FragColor/g, "glFragColor");
                 result = result.replace(/gl_FragColor/g, "glFragColor");
-                result = result.replace(/void\s+?main\(/g, "out vec4 glFragColor;\nvoid main(");
+                result = result.replace(/gl_FragData/g, "glFragData");
+                result = result.replace(/void\s+?main\(/g, (hasDrawBuffersExtension ? "" : "out vec4 glFragColor;\n") + "void main(");
             }
             }
             
             
             callback(result);
             callback(result);

+ 3 - 0
src/Materials/babylon.material.ts

@@ -285,6 +285,9 @@
         public alphaMode = Engine.ALPHA_COMBINE;
         public alphaMode = Engine.ALPHA_COMBINE;
 
 
         @serialize()
         @serialize()
+        public needDepthPrePass = false;
+
+        @serialize()
         public disableDepthWrite = false;
         public disableDepthWrite = false;
 
 
         @serialize("fogEnabled")
         @serialize("fogEnabled")

+ 5 - 0
src/Materials/babylon.materialHelper.ts

@@ -46,6 +46,11 @@
                 changed = true;
                 changed = true;
             }
             }
 
 
+            if (defines["DEPTHPREPASS"] !== !engine.getColorWrite()) {
+                defines["DEPTHPREPASS"] = !defines["DEPTHPREPASS"];
+                changed = true;
+            }            
+
             if (defines["INSTANCES"] !== useInstances) {
             if (defines["INSTANCES"] !== useInstances) {
                 defines["INSTANCES"] = useInstances;
                 defines["INSTANCES"] = useInstances;
                 changed = true;
                 changed = true;

+ 20 - 0
src/Materials/babylon.standardMaterial.ts

@@ -21,6 +21,7 @@ module BABYLON {
         public SPECULAROVERALPHA = false;
         public SPECULAROVERALPHA = false;
         public CLIPPLANE = false;
         public CLIPPLANE = false;
         public ALPHATEST = false;
         public ALPHATEST = false;
+        public DEPTHPREPASS = false;
         public ALPHAFROMDIFFUSE = false;
         public ALPHAFROMDIFFUSE = false;
         public POINTSIZE = false;
         public POINTSIZE = false;
         public FOG = false;
         public FOG = false;
@@ -428,6 +429,25 @@ module BABYLON {
             this._imageProcessingConfiguration.colorGradingTexture = value;
             this._imageProcessingConfiguration.colorGradingTexture = value;
         }
         }
 
 
+        /**
+         * The color grading curves provide additional color adjustmnent that is applied after any color grading transform (3D LUT). 
+         * They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects.
+         * These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image; 
+         * corresponding to low luminance, medium luminance, and high luminance areas respectively.
+         */
+        public get cameraColorCurves(): ColorCurves {
+            return this._imageProcessingConfiguration.colorCurves;
+        }
+        /**
+         * The color grading curves provide additional color adjustmnent that is applied after any color grading transform (3D LUT). 
+         * They allow basic adjustment of saturation and small exposure adjustments, along with color filter tinting to provide white balance adjustment or more stylistic effects.
+         * These are similar to controls found in many professional imaging or colorist software. The global controls are applied to the entire image. For advanced tuning, extra controls are provided to adjust the shadow, midtone and highlight areas of the image; 
+         * corresponding to low luminance, medium luminance, and high luminance areas respectively.
+         */
+        public set cameraColorCurves(value: ColorCurves) {
+            this._imageProcessingConfiguration.colorCurves = value;
+        }        
+
         public customShaderNameResolve: (shaderName: string, uniforms: string[], uniformBuffers: string[], samplers: string[], defines: StandardMaterialDefines) => string;
         public customShaderNameResolve: (shaderName: string, uniforms: string[], uniformBuffers: string[], samplers: string[], defines: StandardMaterialDefines) => string;
 
 
         protected _renderTargets = new SmartArray<RenderTargetTexture>(16);
         protected _renderTargets = new SmartArray<RenderTargetTexture>(16);

+ 2 - 2
src/Mesh/babylon.abstractMesh.ts

@@ -1533,7 +1533,7 @@
             }
             }
         }
         }
 
 
-        public moveWithCollisions(direction: Vector3): AbstractMesh {
+        public moveWithCollisions(displacement: Vector3): AbstractMesh {
             var globalPosition = this.getAbsolutePosition();
             var globalPosition = this.getAbsolutePosition();
 
 
             globalPosition.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPositionForCollisions);
             globalPosition.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPositionForCollisions);
@@ -1545,7 +1545,7 @@
 
 
             this._collider.radius = this.ellipsoid;
             this._collider.radius = this.ellipsoid;
 
 
-            this.getScene().collisionCoordinator.getNewPosition(this._oldPositionForCollisions, direction, this._collider, 3, this, this._onCollisionPositionChange, this.uniqueId);
+            this.getScene().collisionCoordinator.getNewPosition(this._oldPositionForCollisions, displacement, this._collider, 3, this, this._onCollisionPositionChange, this.uniqueId);
             return this;
             return this;
         }
         }
 
 

+ 3 - 1
src/PostProcess/RenderPipeline/Pipelines/babylon.defaultRenderingPipeline.ts

@@ -223,8 +223,10 @@
                 this.imageProcessing = new BABYLON.ImageProcessingPostProcess("imageProcessing",  1.0, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);
                 this.imageProcessing = new BABYLON.ImageProcessingPostProcess("imageProcessing",  1.0, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);
                 if (this._hdr) {
                 if (this._hdr) {
                     this.addEffect(new PostProcessRenderEffect(engine, this.ImageProcessingPostProcessId, () => { return this.imageProcessing; }, true));
                     this.addEffect(new PostProcessRenderEffect(engine, this.ImageProcessingPostProcessId, () => { return this.imageProcessing; }, true));
+                } else {
+                    this._scene.imageProcessingConfiguration.applyByPostProcess = false;
                 }
                 }
-            }
+            } 
 
 
 			if (this.fxaaEnabled) {
 			if (this.fxaaEnabled) {
                 this.fxaa = new FxaaPostProcess("fxaa", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);
                 this.fxaa = new FxaaPostProcess("fxaa", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);

+ 1 - 1
src/PostProcess/RenderPipeline/Pipelines/babylon.ssao2RenderingPipeline.ts

@@ -120,7 +120,7 @@
         */
         */
         public static get IsSupported(): boolean {
         public static get IsSupported(): boolean {
             var engine = Engine.LastCreatedEngine;
             var engine = Engine.LastCreatedEngine;
-            return engine.webGLVersion > 1;
+            return engine.getCaps().drawBuffersExtension;
         }
         }
 
 
         private _scene: Scene;
         private _scene: Scene;

+ 2 - 3
src/PostProcess/RenderPipeline/Pipelines/babylon.standardRenderingPipeline.ts

@@ -726,9 +726,8 @@
         }
         }
 
 
         private _getDepthTexture(): Texture {
         private _getDepthTexture(): Texture {
-            var geometry = this._scene.enableGeometryBufferRenderer();
-            if (geometry) {
-                return geometry.getGBuffer().textures[0];
+            if (this._scene.getEngine().getCaps().drawBuffersExtension) {
+                return this._scene.enableGeometryBufferRenderer().getGBuffer().textures[0];
             }
             }
 
 
             return this._scene.enableDepthRenderer().getDepthMap();
             return this._scene.enableDepthRenderer().getDepthMap();

+ 11 - 1
src/PostProcess/babylon.postProcess.ts

@@ -20,6 +20,7 @@
         public scaleMode = Engine.SCALEMODE_FLOOR;
         public scaleMode = Engine.SCALEMODE_FLOOR;
         public alwaysForcePOT = false;
         public alwaysForcePOT = false;
         public samples = 1;
         public samples = 1;
+        public adaptScaleToCurrentViewport = false;
 
 
         private _camera: Camera;
         private _camera: Camera;
         private _scene: Scene;
         private _scene: Scene;
@@ -221,9 +222,18 @@
                 var requiredWidth = ((sourceTexture ? sourceTexture.width : this._engine.getRenderingCanvas().width) * <number>this._options) | 0;
                 var requiredWidth = ((sourceTexture ? sourceTexture.width : this._engine.getRenderingCanvas().width) * <number>this._options) | 0;
                 var requiredHeight = ((sourceTexture ? sourceTexture.height : this._engine.getRenderingCanvas().height) * <number>this._options) | 0;
                 var requiredHeight = ((sourceTexture ? sourceTexture.height : this._engine.getRenderingCanvas().height) * <number>this._options) | 0;
 
 
-                var desiredWidth = (<PostProcessOptions>this._options).width || requiredWidth;
+                var desiredWidth = ((<PostProcessOptions>this._options).width || requiredWidth);
                 var desiredHeight = (<PostProcessOptions>this._options).height || requiredHeight;
                 var desiredHeight = (<PostProcessOptions>this._options).height || requiredHeight;
 
 
+                if (this.adaptScaleToCurrentViewport) {
+                    let currentViewport = engine.currentViewport;
+
+                    if (currentViewport) {
+                        desiredWidth *= currentViewport.width;
+                        desiredHeight *= currentViewport.height;
+                    }
+                }
+
                 if (this.renderTargetSamplingMode === Texture.TRILINEAR_SAMPLINGMODE || this.alwaysForcePOT) {
                 if (this.renderTargetSamplingMode === Texture.TRILINEAR_SAMPLINGMODE || this.alwaysForcePOT) {
                     if (!(<PostProcessOptions>this._options).width) {
                     if (!(<PostProcessOptions>this._options).width) {
                         desiredWidth = engine.needPOTTextures ? Tools.GetExponentOfTwo(desiredWidth, maxSize, this.scaleMode) : desiredWidth;
                         desiredWidth = engine.needPOTTextures ? Tools.GetExponentOfTwo(desiredWidth, maxSize, this.scaleMode) : desiredWidth;

+ 9 - 1
src/PostProcess/babylon.volumetricLightScatteringPostProcess.ts

@@ -333,9 +333,17 @@
                 scene.clearColor = savedSceneClearColor;
                 scene.clearColor = savedSceneClearColor;
             });
             });
             
             
-            this._volumetricLightScatteringRTT.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>): void => {
+            this._volumetricLightScatteringRTT.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>): void => {
                 var engine = scene.getEngine();
                 var engine = scene.getEngine();
                 var index: number;
                 var index: number;
+                
+                if (depthOnlySubMeshes.length) {
+                    engine.setColorWrite(false);            
+                    for (index = 0; index < depthOnlySubMeshes.length; index++) {
+                        renderSubMesh(depthOnlySubMeshes.data[index]);
+                    }
+                    engine.setColorWrite(true);
+                }                   
 
 
                 for (index = 0; index < opaqueSubMeshes.length; index++) {
                 for (index = 0; index < opaqueSubMeshes.length; index++) {
                     renderSubMesh(opaqueSubMeshes.data[index]);
                     renderSubMesh(opaqueSubMeshes.data[index]);

+ 1 - 1
src/PostProcess/babylon.vrDistortionCorrectionPostProcess.ts

@@ -10,7 +10,6 @@
         private _scaleFactor: Vector2;
         private _scaleFactor: Vector2;
         private _lensCenter: Vector2;
         private _lensCenter: Vector2;
 
 
-        //ANY
         constructor(name: string, camera: Camera, isRightEye: boolean, vrMetrics: VRCameraMetrics) {
         constructor(name: string, camera: Camera, isRightEye: boolean, vrMetrics: VRCameraMetrics) {
             super(name, "vrDistortionCorrection", [
             super(name, "vrDistortionCorrection", [
                 'LensCenter',
                 'LensCenter',
@@ -23,6 +22,7 @@
             this._distortionFactors = vrMetrics.distortionK;
             this._distortionFactors = vrMetrics.distortionK;
             this._postProcessScaleFactor = vrMetrics.postProcessScaleFactor;
             this._postProcessScaleFactor = vrMetrics.postProcessScaleFactor;
             this._lensCenterOffset = vrMetrics.lensCenterOffset;
             this._lensCenterOffset = vrMetrics.lensCenterOffset;
+            this.adaptScaleToCurrentViewport = true;
 
 
             this.onSizeChangedObservable.add(() => {
             this.onSizeChangedObservable.add(() => {
                 this.aspectRatio = this.width * .5 / this.height;
                 this.aspectRatio = this.width * .5 / this.height;

+ 9 - 1
src/Rendering/babylon.depthRenderer.ts

@@ -73,9 +73,17 @@
                 }
                 }
             };
             };
 
 
-            this._depthMap.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>): void => {
+            this._depthMap.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>): void => {
                 var index;
                 var index;
 
 
+                if (depthOnlySubMeshes.length) {
+                    engine.setColorWrite(false);            
+                    for (index = 0; index < depthOnlySubMeshes.length; index++) {
+                        renderSubMesh(depthOnlySubMeshes.data[index]);
+                    }
+                    engine.setColorWrite(true);
+                }     
+
                 for (index = 0; index < opaqueSubMeshes.length; index++) {
                 for (index = 0; index < opaqueSubMeshes.length; index++) {
                     renderSubMesh(opaqueSubMeshes.data[index]);
                     renderSubMesh(opaqueSubMeshes.data[index]);
                 }
                 }

+ 12 - 2
src/Rendering/babylon.geometryBufferRenderer.ts

@@ -102,7 +102,9 @@ module BABYLON {
                 this._effect = this._scene.getEngine().createEffect("geometry",
                 this._effect = this._scene.getEngine().createEffect("geometry",
                     attribs,
                     attribs,
                     ["world", "mBones", "viewProjection", "diffuseMatrix", "view"],
                     ["world", "mBones", "viewProjection", "diffuseMatrix", "view"],
-                    ["diffuseSampler"], join);
+                    ["diffuseSampler"], join,
+                    null, null, null,
+                    { buffersCount: this._enablePosition ? 3 : 2 });
             }
             }
 
 
             return this._effect.isReady();
             return this._effect.isReady();
@@ -180,9 +182,17 @@ module BABYLON {
                 }
                 }
             };
             };
 
 
-            this._multiRenderTarget.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>): void => {
+            this._multiRenderTarget.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>): void => {
                 var index;
                 var index;
 
 
+                if (depthOnlySubMeshes.length) {
+                    engine.setColorWrite(false);            
+                    for (index = 0; index < depthOnlySubMeshes.length; index++) {
+                        renderSubMesh(depthOnlySubMeshes.data[index]);
+                    }
+                    engine.setColorWrite(true);
+                }                  
+
                 for (index = 0; index < opaqueSubMeshes.length; index++) {
                 for (index = 0; index < opaqueSubMeshes.length; index++) {
                     renderSubMesh(opaqueSubMeshes.data[index]);
                     renderSubMesh(opaqueSubMeshes.data[index]);
                 }
                 }

+ 25 - 11
src/Rendering/babylon.outlineRenderer.ts

@@ -24,6 +24,13 @@
             var material = subMesh.getMaterial();
             var material = subMesh.getMaterial();
 
 
             engine.enableEffect(this._effect);
             engine.enableEffect(this._effect);
+
+            // Logarithmic depth
+            if((<any> material).useLogarithmicDepth)
+            {
+                this._effect.setFloat("logarithmicDepthConstant", 2.0 / (Math.log(scene.activeCamera.maxZ + 1.0) / Math.LN2));
+            }
+
             this._effect.setFloat("offset", useOverlay ? 0 : mesh.outlineWidth);
             this._effect.setFloat("offset", useOverlay ? 0 : mesh.outlineWidth);
             this._effect.setColor4("color", useOverlay ? mesh.overlayColor : mesh.outlineColor, useOverlay ? mesh.overlayAlpha : material.alpha);
             this._effect.setColor4("color", useOverlay ? mesh.overlayColor : mesh.outlineColor, useOverlay ? mesh.overlayAlpha : material.alpha);
             this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
             this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
@@ -59,19 +66,26 @@
             var mesh = subMesh.getMesh();
             var mesh = subMesh.getMesh();
             var material = subMesh.getMaterial();
             var material = subMesh.getMaterial();
 
 
-            // Alpha test
-            if (material && material.needAlphaTesting()) {
-                defines.push("#define ALPHATEST");
-                if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
-                    attribs.push(VertexBuffer.UVKind);
-                    defines.push("#define UV1");
+            if (material) {
+                // Alpha test
+                if(material.needAlphaTesting())
+                {
+                    defines.push("#define ALPHATEST");
+                    if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
+                        attribs.push(VertexBuffer.UVKind);
+                        defines.push("#define UV1");
+                    }
+                    if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
+                        attribs.push(VertexBuffer.UV2Kind);
+                        defines.push("#define UV2");
+                    }
                 }
                 }
-                if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
-                    attribs.push(VertexBuffer.UV2Kind);
-                    defines.push("#define UV2");
+                //Logarithmic depth
+                if((<any> material).useLogarithmicDepth)
+                {
+                    defines.push("#define LOGARITHMICDEPTH");
                 }
                 }
             }
             }
-
             // Bones
             // Bones
             if (mesh.useBones && mesh.computeBonesUsingShaders) {
             if (mesh.useBones && mesh.computeBonesUsingShaders) {
                 attribs.push(VertexBuffer.MatricesIndicesKind);
                 attribs.push(VertexBuffer.MatricesIndicesKind);
@@ -101,7 +115,7 @@
                 this._cachedDefines = join;
                 this._cachedDefines = join;
                 this._effect = this._scene.getEngine().createEffect("outline",
                 this._effect = this._scene.getEngine().createEffect("outline",
                     attribs,
                     attribs,
-                    ["world", "mBones", "viewProjection", "diffuseMatrix", "offset", "color"],
+                    ["world", "mBones", "viewProjection", "diffuseMatrix", "offset", "color", "logarithmicDepthConstant"],
                     ["diffuseSampler"], join);
                     ["diffuseSampler"], join);
             }
             }
 
 

+ 0 - 0
src/Rendering/babylon.renderingGroup.ts


部分文件因为文件数量过多而无法显示