davrous 8 lat temu
rodzic
commit
f6152b74e0
55 zmienionych plików z 11630 dodań i 9967 usunięć
  1. 1 1
      Playground/css/index.css
  2. 1 1
      Playground/debug.html
  3. 1 1
      Playground/index-local.html
  4. 1 1
      Playground/index.html
  5. 1 1
      Playground/index2_5.html
  6. 0 0
      Playground/scenes/StanfordBunny.obj
  7. 1 1
      Playground/test.html
  8. 22 1
      Tools/Gulp/config.json
  9. 4735 4711
      dist/preview release/babylon.d.ts
  10. 38 38
      dist/preview release/babylon.js
  11. 242 87
      dist/preview release/babylon.max.js
  12. 4735 4711
      dist/preview release/babylon.module.d.ts
  13. 39 39
      dist/preview release/babylon.worker.js
  14. 11 11
      dist/preview release/canvas2D/babylon.canvas2d.min.js
  15. 5 0
      dist/preview release/gui/babylon.gui.d.ts
  16. 24 0
      dist/preview release/gui/babylon.gui.js
  17. 1 0
      dist/preview release/gui/babylon.gui.min.js
  18. 263 263
      dist/preview release/inspector/babylon.inspector.bundle.js
  19. 3 3
      dist/preview release/inspector/babylon.inspector.min.js
  20. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  21. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  22. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  23. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  24. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  25. 1 1
      dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js
  26. 1 1
      dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js
  27. 106 0
      gui/src/advancedDynamicTexture.js
  28. 107 0
      gui/src/advancedDynamicTexture.ts
  29. 76 0
      gui/src/controls/container.js
  30. 72 0
      gui/src/controls/container.ts
  31. 63 0
      gui/src/controls/contentControl.js
  32. 53 0
      gui/src/controls/contentControl.ts
  33. 220 0
      gui/src/controls/control.js
  34. 214 0
      gui/src/controls/control.ts
  35. 73 0
      gui/src/controls/rectangle.js
  36. 58 0
      gui/src/controls/rectangle.ts
  37. 84 0
      gui/src/controls/textBlock.js
  38. 76 0
      gui/src/controls/textBlock.ts
  39. 22 0
      gui/src/measure.js
  40. 13 0
      gui/src/measure.ts
  41. 7 0
      gui/src/tsconfig.json
  42. 36 19
      src/Animations/babylon.animation.ts
  43. 46 50
      src/Cameras/VR/babylon.webVRCamera.ts
  44. 44 0
      src/Cameras/babylon.camera.ts
  45. 1 1
      src/Layer/babylon.layer.ts
  46. 1 1
      src/Lights/babylon.hemisphericLight.ts
  47. 1 1
      src/Lights/babylon.light.ts
  48. 21 8
      src/Materials/Textures/babylon.dynamicTexture.ts
  49. 2 2
      src/Materials/babylon.pushMaterial.ts
  50. 2 1
      src/Materials/babylon.standardMaterial.ts
  51. 14 2
      src/Math/babylon.math.ts
  52. 1 1
      src/Rendering/babylon.boundingBoxRenderer.ts
  53. 20 0
      src/Tools/babylon.extendedGamepad.ts
  54. 53 1
      src/babylon.engine.ts
  55. 11 1
      src/babylon.scene.ts

+ 1 - 1
Playground/css/index.css

@@ -40,7 +40,7 @@ body {
 }
 .wrapper #jsEditor {
     padding-top:5px;
-    height: 100%;
+    height: calc(100% - 10px);
 }
 
 .wrapper #jsEditor.light {

+ 1 - 1
Playground/debug.html

@@ -150,7 +150,7 @@
             </div>
         </div>
         <div class="save-message" id="saveMessage">
-            This PG has no metadata. Click save to add them.
+            This PG has missing metadata. Click save to add them.
         </div>
     </div>
 

+ 1 - 1
Playground/index-local.html

@@ -116,7 +116,7 @@
             </div>
         </div>
         <div class="save-message" id="saveMessage">
-            This PG has no metadata. Click save to add them.
+            This PG has missing metadata. Click save to add them.
         </div>
     </div>
 

+ 1 - 1
Playground/index.html

@@ -149,7 +149,7 @@
             </div>
         </div>
         <div class="save-message" id="saveMessage">
-            This PG has no metadata. Click save to add them.
+            This PG has missing metadata. Click save to add them.
         </div>
     </div>
 

+ 1 - 1
Playground/index2_5.html

@@ -123,7 +123,7 @@
             </div>
         </div>
         <div class="save-message" id="saveMessage">
-            This PG has no metadata. Click save to add them.
+            This PG has missing metadata. Click save to add them.
         </div>
     </div>
 

Playground/Scenes/StanfordBunny.obj → Playground/scenes/StanfordBunny.obj


+ 1 - 1
Playground/test.html

@@ -51,5 +51,5 @@
     </div>
 </div>
 <div class="save-message" id="saveMessage">
-    This PG has no metadata. Click save to add them.
+    This PG has missing metadata. Click save to add them.
 </div>

+ 22 - 1
Tools/Gulp/config.json

@@ -883,7 +883,8 @@
         "proceduralTexturesLibrary",
         "loaders",
         "serializers",
-        "inspector"
+        "inspector",
+        "gui"
     ],
     "materialsLibrary": {
         "libraries": [
@@ -1210,6 +1211,26 @@
             "distOutputDirectory": "/serializers/"
         }
     },
+    "gui": {
+        "libraries": [
+            {
+                "files": [
+                    "../../gui/src/advancedDynamicTexture.ts",
+                    "../../gui/src/measure.ts",
+                    "../../gui/src/controls/control.ts",
+                    "../../gui/src/controls/contentControl.ts",
+                    "../../gui/src/controls/container.ts",
+                    "../../gui/src/controls/rectangle.ts",
+                    "../../gui/src/controls/textBlock.ts"
+                ],
+                "output": "babylon.gui.js"
+            }
+        ],
+        "build": {
+            "srcOutputDirectory": "../../gui/",
+            "distOutputDirectory": "/gui/"
+        }
+    },    
     "canvas2D": {
         "libraries": [
             {

Plik diff jest za duży
+ 4735 - 4711
dist/preview release/babylon.d.ts


Plik diff jest za duży
+ 38 - 38
dist/preview release/babylon.js


+ 242 - 87
dist/preview release/babylon.max.js

@@ -2661,6 +2661,19 @@ var __extends = (this && this.__extends) || (function () {
             result.z = (num3 * left.z) + (num2 * right.z);
             result.w = (num3 * left.w) + (num2 * right.w);
         };
+        Quaternion.Hermite = function (value1, tangent1, value2, tangent2, amount) {
+            var squared = amount * amount;
+            var cubed = amount * squared;
+            var part1 = ((2.0 * cubed) - (3.0 * squared)) + 1.0;
+            var part2 = (-2.0 * cubed) + (3.0 * squared);
+            var part3 = (cubed - (2.0 * squared)) + amount;
+            var part4 = cubed - squared;
+            var x = (((value1.x * part1) + (value2.x * part2)) + (tangent1.x * part3)) + (tangent2.x * part4);
+            var y = (((value1.y * part1) + (value2.y * part2)) + (tangent1.y * part3)) + (tangent2.y * part4);
+            var z = (((value1.z * part1) + (value2.z * part2)) + (tangent1.z * part3)) + (tangent2.z * part4);
+            var w = (((value1.w * part1) + (value2.w * part2)) + (tangent1.w * part3)) + (tangent2.w * part4);
+            return new Quaternion(x, y, z, w);
+        };
         return Quaternion;
     }());
     BABYLON.Quaternion = Quaternion;
@@ -7020,6 +7033,11 @@ var BABYLON;
             // To enable/disable IDB support and avoid XHR on .manifest
             this.enableOfflineSupport = BABYLON.Database;
             this.scenes = new Array();
+            // Observables
+            /**
+             * Observable event triggered each time the rendering canvas is resized
+             */
+            this.onResizeObservable = new BABYLON.Observable();
             this._windowIsBackground = false;
             this._webGLVersion = 1.0;
             this._badOS = false;
@@ -7908,6 +7926,9 @@ var BABYLON;
          * @param {number} height - the new canvas' height
          */
         Engine.prototype.setSize = function (width, height) {
+            if (this._renderingCanvas.width === width && this._renderingCanvas.height === height) {
+                return;
+            }
             this._renderingCanvas.width = width;
             this._renderingCanvas.height = height;
             for (var index = 0; index < this.scenes.length; index++) {
@@ -7917,8 +7938,49 @@ var BABYLON;
                     cam._currentRenderId = 0;
                 }
             }
+            if (this.onResizeObservable.hasObservers) {
+                this.onResizeObservable.notifyObservers(this);
+            }
         };
         //WebVR functions
+        Engine.prototype.isVRDevicePresent = function (callback) {
+            this.getVRDevice(null, function (device) {
+                callback(device !== null);
+            });
+        };
+        Engine.prototype.getVRDevice = function (name, callback) {
+            if (!this.vrDisplaysPromise) {
+                callback(null);
+                return;
+            }
+            this.vrDisplaysPromise.then(function (devices) {
+                if (devices.length > 0) {
+                    if (name) {
+                        var found = devices.some(function (device) {
+                            if (device.displayName === name) {
+                                callback(device);
+                                return true;
+                            }
+                            else {
+                                return false;
+                            }
+                        });
+                        if (!found) {
+                            BABYLON.Tools.Warn("Display " + name + " was not found. Using " + devices[0].displayName);
+                            callback(devices[0]);
+                        }
+                    }
+                    else {
+                        //choose the first one
+                        callback(devices[0]);
+                    }
+                }
+                else {
+                    BABYLON.Tools.Error("No WebVR devices found!");
+                    callback(null);
+                }
+            });
+        };
         Engine.prototype.initWebVR = function () {
             if (!this.vrDisplaysPromise) {
                 this._getVRDisplays();
@@ -12691,7 +12753,7 @@ var BABYLON;
             _this._excludedMeshesIds = new Array();
             _this._includedOnlyMeshesIds = new Array();
             _this.getScene().addLight(_this);
-            _this._uniformBuffer = new BABYLON.UniformBuffer(scene.getEngine());
+            _this._uniformBuffer = new BABYLON.UniformBuffer(_this.getScene().getEngine());
             _this._buildUniformLayout();
             _this.includedOnlyMeshes = new Array();
             _this.excludedMeshes = new Array();
@@ -13511,6 +13573,19 @@ var BABYLON;
             this.updateFrustumPlanes();
             return target.isCompletelyInFrustum(this._frustumPlanes);
         };
+        Camera.prototype.getForwardRay = function (length, transform, origin) {
+            if (length === void 0) { length = 100; }
+            if (!transform) {
+                transform = this.getWorldMatrix();
+            }
+            if (!origin) {
+                origin = this.position;
+            }
+            var forward = new BABYLON.Vector3(0, 0, 1);
+            var forwardWorld = BABYLON.Vector3.TransformNormal(forward, transform);
+            var direction = BABYLON.Vector3.Normalize(forwardWorld);
+            return new BABYLON.Ray(origin, direction, length);
+        };
         Camera.prototype.dispose = function () {
             // Animations
             this.getScene().stopAnimation(this);
@@ -13526,7 +13601,39 @@ var BABYLON;
             }
             _super.prototype.dispose.call(this);
         };
-        // ---- Camera rigs section ----
+        Object.defineProperty(Camera.prototype, "leftCamera", {
+            // ---- Camera rigs section ----
+            get: function () {
+                if (this._rigCameras.length < 1) {
+                    return undefined;
+                }
+                return this._rigCameras[0];
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Camera.prototype, "rightCamera", {
+            get: function () {
+                if (this._rigCameras.length < 2) {
+                    return undefined;
+                }
+                return this._rigCameras[1];
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Camera.prototype.getLeftTarget = function () {
+            if (this._rigCameras.length < 1) {
+                return undefined;
+            }
+            return this._rigCameras[0].getTarget();
+        };
+        Camera.prototype.getRightTarget = function () {
+            if (this._rigCameras.length < 2) {
+                return undefined;
+            }
+            return this._rigCameras[1].getTarget();
+        };
         Camera.prototype.setCameraRigMode = function (mode, rigParams) {
             while (this._rigCameras.length > 0) {
                 this._rigCameras.pop().dispose();
@@ -15052,6 +15159,13 @@ var BABYLON;
         Scene.prototype.getCachedEffect = function () {
             return this._cachedEffect;
         };
+        Scene.prototype.getCachedVisibility = function () {
+            return this._cachedVisibility;
+        };
+        Scene.prototype.isCachedMaterialValid = function (material, effect, visibility) {
+            if (visibility === void 0) { visibility = 0; }
+            return this._cachedEffect !== effect || this._cachedMaterial !== material || this._cachedVisibility !== visibility;
+        };
         Scene.prototype.getBoundingBoxRenderer = function () {
             if (!this._boundingBoxRenderer) {
                 this._boundingBoxRenderer = new BABYLON.BoundingBoxRenderer(this);
@@ -15682,6 +15796,7 @@ var BABYLON;
         Scene.prototype.resetCachedMaterial = function () {
             this._cachedMaterial = null;
             this._cachedEffect = null;
+            this._cachedVisibility = null;
         };
         Scene.prototype.registerBeforeRender = function (func) {
             this.onBeforeRenderObservable.add(func);
@@ -23649,8 +23764,9 @@ var BABYLON;
             _super.prototype._afterBind.call(this, mesh);
             this.getScene()._cachedEffect = effect;
         };
-        PushMaterial.prototype._mustRebind = function (scene, effect) {
-            return scene.getCachedEffect() !== effect || scene.getCachedMaterial() !== this;
+        PushMaterial.prototype._mustRebind = function (scene, effect, visibility) {
+            if (visibility === void 0) { visibility = 0; }
+            return scene.isCachedMaterialValid(this, effect, visibility);
         };
         PushMaterial.prototype.markAsDirty = function (flag) {
             if (flag & BABYLON.Material.TextureDirtyFlag) {
@@ -27707,7 +27823,7 @@ var BABYLON;
             this.bindOnlyWorldMatrix(world);
             // Bones
             BABYLON.MaterialHelper.BindBonesParameters(mesh, effect);
-            if (this._mustRebind(scene, effect)) {
+            if (this._mustRebind(scene, effect, mesh.visibility)) {
                 this._uniformBuffer.bindToEffect(effect, "Material");
                 this.bindViewProjection(effect);
                 if (!this._uniformBuffer.useUbo || !this.isFrozen || !this._uniformBuffer.isSync) {
@@ -31778,7 +31894,7 @@ var BABYLON;
         function HemisphericLight(name, direction, scene) {
             var _this = _super.call(this, name, scene) || this;
             _this.groundColor = new BABYLON.Color3(0.0, 0.0, 0.0);
-            _this.direction = direction;
+            _this.direction = direction || BABYLON.Vector3.Up();
             return _this;
         }
         HemisphericLight.prototype._buildUniformLayout = function () {
@@ -32610,12 +32726,21 @@ var BABYLON;
         Animation.prototype.quaternionInterpolateFunction = function (startValue, endValue, gradient) {
             return BABYLON.Quaternion.Slerp(startValue, endValue, gradient);
         };
+        Animation.prototype.quaternionInterpolateFunctionWithTangents = function (startValue, outTangent, endValue, inTangent, gradient) {
+            return BABYLON.Quaternion.Hermite(startValue, outTangent, endValue, inTangent, gradient);
+        };
         Animation.prototype.vector3InterpolateFunction = function (startValue, endValue, gradient) {
             return BABYLON.Vector3.Lerp(startValue, endValue, gradient);
         };
+        Animation.prototype.vector3InterpolateFunctionWithTangents = function (startValue, outTangent, endValue, inTangent, gradient) {
+            return BABYLON.Vector3.Hermite(startValue, outTangent, endValue, inTangent, gradient);
+        };
         Animation.prototype.vector2InterpolateFunction = function (startValue, endValue, gradient) {
             return BABYLON.Vector2.Lerp(startValue, endValue, gradient);
         };
+        Animation.prototype.vector2InterpolateFunctionWithTangents = function (startValue, outTangent, endValue, inTangent, gradient) {
+            return BABYLON.Vector2.Hermite(startValue, outTangent, endValue, inTangent, gradient);
+        };
         Animation.prototype.sizeInterpolateFunction = function (startValue, endValue, gradient) {
             return BABYLON.Size.Lerp(startValue, endValue, gradient);
         };
@@ -32657,18 +32782,21 @@ var BABYLON;
             }
             this.currentFrame = currentFrame;
             // Try to get a hash to find the right key
-            var startKey = Math.max(0, Math.min(this._keys.length - 1, Math.floor(this._keys.length * (currentFrame - this._keys[0].frame) / (this._keys[this._keys.length - 1].frame - this._keys[0].frame)) - 1));
-            if (this._keys[startKey].frame >= currentFrame) {
-                while (startKey - 1 >= 0 && this._keys[startKey].frame >= currentFrame) {
-                    startKey--;
-                }
-            }
-            for (var key = startKey; key < this._keys.length; key++) {
-                if (this._keys[key + 1].frame >= currentFrame) {
-                    var startValue = this._getKeyValue(this._keys[key].value);
-                    var endValue = this._getKeyValue(this._keys[key + 1].value);
+            var startKeyIndex = Math.max(0, Math.min(this._keys.length - 1, Math.floor(this._keys.length * (currentFrame - this._keys[0].frame) / (this._keys[this._keys.length - 1].frame - this._keys[0].frame)) - 1));
+            if (this._keys[startKeyIndex].frame >= currentFrame) {
+                while (startKeyIndex - 1 >= 0 && this._keys[startKeyIndex].frame >= currentFrame) {
+                    startKeyIndex--;
+                }
+            }
+            for (var key = startKeyIndex; key < this._keys.length; key++) {
+                var endKey = this._keys[key + 1];
+                if (endKey.frame >= currentFrame) {
+                    var startKey = this._keys[key];
+                    var startValue = this._getKeyValue(startKey.value);
+                    var endValue = this._getKeyValue(endKey.value);
+                    var useTangent = startKey.outTangent && endKey.inTangent;
                     // gradient : percent of currentFrame between the frame inf and the frame sup
-                    var gradient = (currentFrame - this._keys[key].frame) / (this._keys[key + 1].frame - this._keys[key].frame);
+                    var gradient = (currentFrame - startKey.frame) / (endKey.frame - startKey.frame);
                     // check for easingFunction and correction of gradient
                     if (this._easingFunction != null) {
                         gradient = this._easingFunction.ease(gradient);
@@ -32686,34 +32814,34 @@ var BABYLON;
                             break;
                         // Quaternion
                         case Animation.ANIMATIONTYPE_QUATERNION:
-                            var quaternion = null;
+                            var quaternion = useTangent ? this.quaternionInterpolateFunctionWithTangents(startValue, startKey.outTangent, endValue, endKey.inTangent, gradient) : this.quaternionInterpolateFunction(startValue, endValue, gradient);
                             switch (loopMode) {
                                 case Animation.ANIMATIONLOOPMODE_CYCLE:
                                 case Animation.ANIMATIONLOOPMODE_CONSTANT:
-                                    quaternion = this.quaternionInterpolateFunction(startValue, endValue, gradient);
-                                    break;
+                                    return quaternion;
                                 case Animation.ANIMATIONLOOPMODE_RELATIVE:
-                                    quaternion = this.quaternionInterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
-                                    break;
+                                    return quaternion.add(offsetValue.scale(repeatCount));
                             }
                             return quaternion;
                         // Vector3
                         case Animation.ANIMATIONTYPE_VECTOR3:
+                            var vec3Value = useTangent ? this.vector3InterpolateFunctionWithTangents(startValue, startKey.outTangent, endValue, endKey.inTangent, gradient) : this.vector3InterpolateFunction(startValue, endValue, gradient);
                             switch (loopMode) {
                                 case Animation.ANIMATIONLOOPMODE_CYCLE:
                                 case Animation.ANIMATIONLOOPMODE_CONSTANT:
-                                    return this.vector3InterpolateFunction(startValue, endValue, gradient);
+                                    return vec3Value;
                                 case Animation.ANIMATIONLOOPMODE_RELATIVE:
-                                    return this.vector3InterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
+                                    return vec3Value.add(offsetValue.scale(repeatCount));
                             }
                         // Vector2
                         case Animation.ANIMATIONTYPE_VECTOR2:
+                            var vec2Value = useTangent ? this.vector2InterpolateFunctionWithTangents(startValue, startKey.outTangent, endValue, endKey.inTangent, gradient) : this.vector2InterpolateFunction(startValue, endValue, gradient);
                             switch (loopMode) {
                                 case Animation.ANIMATIONLOOPMODE_CYCLE:
                                 case Animation.ANIMATIONLOOPMODE_CONSTANT:
-                                    return this.vector2InterpolateFunction(startValue, endValue, gradient);
+                                    return vec2Value;
                                 case Animation.ANIMATIONLOOPMODE_RELATIVE:
-                                    return this.vector2InterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
+                                    return vec2Value.add(offsetValue.scale(repeatCount));
                             }
                         // Size
                         case Animation.ANIMATIONTYPE_SIZE:
@@ -41531,20 +41659,21 @@ var BABYLON;
             if (format === void 0) { format = BABYLON.Engine.TEXTUREFORMAT_RGBA; }
             var _this = _super.call(this, null, scene, !generateMipMaps, undefined, samplingMode, undefined, undefined, undefined, undefined, format) || this;
             _this.name = name;
+            var engine = _this.getScene().getEngine();
             _this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
             _this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
             _this._generateMipMaps = generateMipMaps;
             if (options.getContext) {
                 _this._canvas = options;
-                _this._texture = scene.getEngine().createDynamicTexture(options.width, options.height, generateMipMaps, samplingMode);
+                _this._texture = engine.createDynamicTexture(options.width, options.height, generateMipMaps, samplingMode);
             }
             else {
                 _this._canvas = document.createElement("canvas");
                 if (options.width) {
-                    _this._texture = scene.getEngine().createDynamicTexture(options.width, options.height, generateMipMaps, samplingMode);
+                    _this._texture = engine.createDynamicTexture(options.width, options.height, generateMipMaps, samplingMode);
                 }
                 else {
-                    _this._texture = scene.getEngine().createDynamicTexture(options, options, generateMipMaps, samplingMode);
+                    _this._texture = engine.createDynamicTexture(options, options, generateMipMaps, samplingMode);
                 }
             }
             var textureSize = _this.getSize();
@@ -41560,15 +41689,24 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
-        DynamicTexture.prototype.scale = function (ratio) {
-            var textureSize = this.getSize();
-            textureSize.width *= ratio;
-            textureSize.height *= ratio;
+        DynamicTexture.prototype._recreate = function (textureSize) {
             this._canvas.width = textureSize.width;
             this._canvas.height = textureSize.height;
             this.releaseInternalTexture();
             this._texture = this.getScene().getEngine().createDynamicTexture(textureSize.width, textureSize.height, this._generateMipMaps, this._samplingMode);
         };
+        DynamicTexture.prototype.scale = function (ratio) {
+            var textureSize = this.getSize();
+            textureSize.width *= ratio;
+            textureSize.height *= ratio;
+            this._recreate(textureSize);
+        };
+        DynamicTexture.prototype.scaleTo = function (width, height) {
+            var textureSize = this.getSize();
+            textureSize.width = width;
+            textureSize.height = height;
+            this._recreate(textureSize);
+        };
         DynamicTexture.prototype.getContext = function () {
             return this._context;
         };
@@ -46087,6 +46225,25 @@ var BABYLON;
         PoseEnabledController.prototype.detachMesh = function () {
             this._mesh = undefined;
         };
+        Object.defineProperty(PoseEnabledController.prototype, "mesh", {
+            get: function () {
+                return this._mesh;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        PoseEnabledController.prototype.getForwardRay = function (length) {
+            if (length === void 0) { length = 100; }
+            if (!this.mesh) {
+                return new BABYLON.Ray(BABYLON.Vector3.Zero(), new BABYLON.Vector3(0, 0, 1), length);
+            }
+            var m = this.mesh.getWorldMatrix();
+            var origin = m.getTranslation();
+            var forward = new BABYLON.Vector3(0, 0, -1);
+            var forwardWorld = BABYLON.Vector3.TransformNormal(forward, m);
+            var direction = BABYLON.Vector3.Normalize(forwardWorld);
+            return new BABYLON.Ray(origin, direction, length);
+        };
         return PoseEnabledController;
     }(BABYLON.Gamepad));
     BABYLON.PoseEnabledController = PoseEnabledController;
@@ -57031,7 +57188,7 @@ var BABYLON;
             }
             this._colorShader = new BABYLON.ShaderMaterial("colorShader", this._scene, "color", {
                 attributes: [BABYLON.VertexBuffer.PositionKind],
-                uniforms: ["worldViewProjection", "color"]
+                uniforms: ["world", "viewProjection", "color"]
             });
             var engine = this._scene.getEngine();
             var boxdata = BABYLON.VertexData.CreateBox(1.0);
@@ -58906,51 +59063,26 @@ var BABYLON;
             }
             //enable VR
             _this.getEngine().initWebVR();
-            if (!_this.getEngine().vrDisplaysPromise) {
-                BABYLON.Tools.Error("WebVR is not enabled on your browser");
+            //check specs version
+            if (!window.VRFrameData) {
+                _this._specsVersion = 1.0;
+                _this._frameData = {};
             }
             else {
-                //check specs version
-                if (!window.VRFrameData) {
-                    _this._specsVersion = 1.0;
-                    _this._frameData = {};
-                }
-                else {
-                    _this._frameData = new VRFrameData();
-                }
-                _this.getEngine().vrDisplaysPromise.then(function (devices) {
-                    if (devices.length > 0) {
-                        _this._vrEnabled = true;
-                        if (_this.webVROptions.displayName) {
-                            var found = devices.some(function (device) {
-                                if (device.displayName === _this.webVROptions.displayName) {
-                                    _this._vrDevice = device;
-                                    return true;
-                                }
-                                else {
-                                    return false;
-                                }
-                            });
-                            if (!found) {
-                                _this._vrDevice = devices[0];
-                                BABYLON.Tools.Warn("Display " + _this.webVROptions.displayName + " was not found. Using " + _this._vrDevice.displayName);
-                            }
-                        }
-                        else {
-                            //choose the first one
-                            _this._vrDevice = devices[0];
-                        }
-                        //reset the rig parameters.
-                        _this.setCameraRigMode(BABYLON.Camera.RIG_MODE_WEBVR, { parentCamera: _this, vrDisplay: _this._vrDevice, frameData: _this._frameData, specs: _this._specsVersion });
-                        if (_this._attached) {
-                            _this.getEngine().enableVR(_this._vrDevice);
-                        }
-                    }
-                    else {
-                        BABYLON.Tools.Error("No WebVR devices found!");
-                    }
-                });
+                _this._frameData = new VRFrameData();
             }
+            _this.getEngine().getVRDevice(_this.webVROptions.displayName, function (device) {
+                if (!device) {
+                    return;
+                }
+                _this._vrEnabled = true;
+                _this._vrDevice = device;
+                //reset the rig parameters.
+                _this.setCameraRigMode(BABYLON.Camera.RIG_MODE_WEBVR, { parentCamera: _this, vrDisplay: _this._vrDevice, frameData: _this._frameData, specs: _this._specsVersion });
+                if (_this._attached) {
+                    _this.getEngine().enableVR(_this._vrDevice);
+                }
+            });
             // try to attach the controllers, if found.
             _this.initControllers();
             /**
@@ -58997,17 +59129,40 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
-        WebVRFreeCamera.prototype.getLeftCamera = function () {
-            return this._rigCameras[0];
-        };
-        WebVRFreeCamera.prototype.getRightCamera = function () {
-            return this._rigCameras[1];
-        };
-        WebVRFreeCamera.prototype.getLeftTarget = function () {
-            return this._rigCameras[0].getTarget();
+        WebVRFreeCamera.prototype.getControllerByName = function (name) {
+            for (var _i = 0, _a = this.controllers; _i < _a.length; _i++) {
+                var gp = _a[_i];
+                if (gp.hand === name) {
+                    return gp;
+                }
+            }
+            return undefined;
         };
-        WebVRFreeCamera.prototype.getRightTarget = function () {
-            return this._rigCameras[1].getTarget();
+        Object.defineProperty(WebVRFreeCamera.prototype, "leftController", {
+            get: function () {
+                if (!this._leftController) {
+                    this._leftController = this.getControllerByName("left");
+                }
+                return this._leftController;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        ;
+        Object.defineProperty(WebVRFreeCamera.prototype, "rightController", {
+            get: function () {
+                if (!this._rightController) {
+                    this._rightController = this.getControllerByName("right");
+                }
+                return this._rightController;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        ;
+        WebVRFreeCamera.prototype.getForwardRay = function (length) {
+            if (length === void 0) { length = 100; }
+            return _super.prototype.getForwardRay.call(this, length, this.leftCamera.getWorldMatrix(), this.position.add(this.devicePosition)); // Need the actual rendered camera
         };
         WebVRFreeCamera.prototype._checkInputs = function () {
             if (this._vrEnabled) {
@@ -63212,7 +63367,7 @@ var BABYLON;
             this.color = color === undefined ? new BABYLON.Color4(1, 1, 1, 1) : color;
             this._scene = scene || BABYLON.Engine.LastCreatedScene;
             this._scene.layers.push(this);
-            var engine = scene.getEngine();
+            var engine = this._scene.getEngine();
             // VBO
             var vertices = [];
             vertices.push(1, 1);

Plik diff jest za duży
+ 4735 - 4711
dist/preview release/babylon.module.d.ts


Plik diff jest za duży
+ 39 - 39
dist/preview release/babylon.worker.js


Plik diff jest za duży
+ 11 - 11
dist/preview release/canvas2D/babylon.canvas2d.min.js


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

@@ -0,0 +1,5 @@
+/// <reference path="../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class AdvancedDynamicTexture extends DynamicTexture {
+    }
+}

+ 24 - 0
dist/preview release/gui/babylon.gui.js

@@ -0,0 +1,24 @@
+/// <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 AdvancedDynamicTexture = (function (_super) {
+        __extends(AdvancedDynamicTexture, _super);
+        function AdvancedDynamicTexture() {
+            return _super !== null && _super.apply(this, arguments) || this;
+        }
+        return AdvancedDynamicTexture;
+    }(BABYLON.DynamicTexture));
+    BABYLON.AdvancedDynamicTexture = AdvancedDynamicTexture;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=advancedDynamicTexture.js.map

+ 1 - 0
dist/preview release/gui/babylon.gui.min.js

@@ -0,0 +1 @@
+var BABYLON;!(function(n){var t=(function(n){function t(){return null!==n&&n.apply(this,arguments)||this}return __extends(t,n),t})(n.DynamicTexture);n.AdvancedDynamicTexture=t})(BABYLON||(BABYLON={}));

Plik diff jest za duży
+ 263 - 263
dist/preview release/inspector/babylon.inspector.bundle.js


Plik diff jest za duży
+ 3 - 3
dist/preview release/inspector/babylon.inspector.min.js


Plik diff jest za duży
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


Plik diff jest za duży
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


Plik diff jest za duży
+ 2 - 2
dist/preview release/loaders/babylon.glTFFileLoader.min.js


Plik diff jest za duży
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


Plik diff jest za duży
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


Plik diff jest za duży
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js


Plik diff jest za duży
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js


+ 106 - 0
gui/src/advancedDynamicTexture.js

@@ -0,0 +1,106 @@
+/// <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 AdvancedDynamicTexture = (function (_super) {
+            __extends(AdvancedDynamicTexture, _super);
+            function AdvancedDynamicTexture(name, scene) {
+                var _this = _super.call(this, name, {}, scene, false, BABYLON.Texture.NEAREST_SAMPLINGMODE, BABYLON.Engine.TEXTUREFORMAT_RGBA) || this;
+                _this._dirty = false;
+                _this._rootContainer = new GUI.Container("root");
+                _this._resizeObserver = _this.getScene().getEngine().onResizeObservable.add(function () { return _this._onResize(); });
+                _this._renderObserver = _this.getScene().onBeforeRenderObservable.add(function () { return _this._checkUpdate(); });
+                _this._onResize();
+                return _this;
+            }
+            Object.defineProperty(AdvancedDynamicTexture.prototype, "background", {
+                get: function () {
+                    return this._background;
+                },
+                set: function (value) {
+                    if (this._background === value) {
+                        return;
+                    }
+                    this._background = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            AdvancedDynamicTexture.prototype.addControl = function (control) {
+                control._setRoot(this._rootContainer);
+                this._rootContainer.addControl(control);
+                return this;
+            };
+            AdvancedDynamicTexture.prototype.removeControl = function (control) {
+                this._rootContainer.removeControl(control);
+                return this;
+            };
+            AdvancedDynamicTexture.prototype.dispose = function () {
+                this.getScene().onBeforeRenderObservable.remove(this._renderObserver);
+                this.getScene().getEngine().onResizeObservable.remove(this._resizeObserver);
+                _super.prototype.dispose.call(this);
+            };
+            AdvancedDynamicTexture.prototype._onResize = function () {
+                // Check size
+                var engine = this.getScene().getEngine();
+                var textureSize = this.getSize();
+                var renderWidth = engine.getRenderWidth();
+                var renderHeight = engine.getRenderHeight();
+                if (textureSize.width !== renderWidth || textureSize.height !== renderHeight) {
+                    this.scaleTo(renderWidth, renderHeight);
+                }
+                // Update constant pixel resources            
+                var scaleX = renderWidth / 1000.0;
+                var scaleY = renderHeight / 1000.0;
+                this._rootContainer._rescale(scaleX, scaleY);
+                this._markAsDirty();
+            };
+            AdvancedDynamicTexture.prototype._markAsDirty = function () {
+                this._dirty = true;
+            };
+            AdvancedDynamicTexture.prototype._checkUpdate = function () {
+                if (!this._dirty) {
+                    return;
+                }
+                this._dirty = false;
+                this._render();
+                this.update();
+            };
+            AdvancedDynamicTexture.prototype._render = function () {
+                var engine = this.getScene().getEngine();
+                var renderWidth = engine.getRenderWidth();
+                var renderHeight = engine.getRenderHeight();
+                // Clear
+                var context = this.getContext();
+                if (this._background) {
+                    context.save();
+                    context.fillStyle = this._background;
+                    context.fillRect(0, 0, renderWidth, renderHeight);
+                    context.restore();
+                }
+                else {
+                    this.clear();
+                }
+                // Render
+                var measure = new GUI.Measure(0, 0, renderWidth, renderHeight);
+                this._rootContainer._draw(measure, context);
+            };
+            return AdvancedDynamicTexture;
+        }(BABYLON.DynamicTexture));
+        GUI.AdvancedDynamicTexture = AdvancedDynamicTexture;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=advancedDynamicTexture.js.map

+ 107 - 0
gui/src/advancedDynamicTexture.ts

@@ -0,0 +1,107 @@
+/// <reference path="../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.GUI {
+    export class AdvancedDynamicTexture extends DynamicTexture {
+        private _dirty = false;
+        private _renderObserver: Observer<Scene>;
+        private _resizeObserver: Observer<Engine>;
+        private _background: string;
+        private _rootContainer = new Container("root");
+
+        public get background(): string {
+            return this._background;
+        }
+
+        public set background(value: string) {
+            if (this._background === value) {
+                return;
+            }
+
+            this._background = value;
+            this._markAsDirty();
+        }
+        
+        constructor(name: string, scene: Scene) {
+            super(name, {}, scene, false, Texture.NEAREST_SAMPLINGMODE, Engine.TEXTUREFORMAT_RGBA);
+
+            this._resizeObserver = this.getScene().getEngine().onResizeObservable.add(() => this._onResize());
+            this._renderObserver = this.getScene().onBeforeRenderObservable.add(() => this._checkUpdate());
+
+            this._onResize();
+        }
+
+        public addControl(control: Control): AdvancedDynamicTexture {
+            control._setRoot(this._rootContainer);
+            this._rootContainer.addControl(control);
+
+            return this;
+        }
+
+        public removeControl(control: Control): AdvancedDynamicTexture {
+            this._rootContainer.removeControl(control);
+            return this;
+        }
+
+        public dispose() {
+            this.getScene().onBeforeRenderObservable.remove(this._renderObserver);
+            this.getScene().getEngine().onResizeObservable.remove(this._resizeObserver);
+
+            super.dispose();
+        }
+
+        private _onResize(): void {
+            // Check size
+            var engine = this.getScene().getEngine();
+            var textureSize = this.getSize();
+            var renderWidth = engine.getRenderWidth();
+            var renderHeight = engine.getRenderHeight();
+
+            if (textureSize.width !== renderWidth || textureSize.height !== renderHeight) {
+                this.scaleTo(renderWidth, renderHeight);
+            }
+
+            // Update constant pixel resources            
+            var scaleX = renderWidth / 1000.0;
+            var scaleY = renderHeight / 1000.0;
+
+            this._rootContainer._rescale(scaleX, scaleY);
+
+            this._markAsDirty();
+        }
+
+        public _markAsDirty() {
+            this._dirty = true;
+        }
+
+        private _checkUpdate(): void {
+            if (!this._dirty) {
+                return;
+            }
+            this._dirty = false;
+
+            this._render();
+            this.update();
+        }
+
+        private _render(): void {
+            var engine = this.getScene().getEngine();
+            var renderWidth = engine.getRenderWidth();
+            var renderHeight = engine.getRenderHeight();
+
+            // Clear
+            var context = this.getContext();
+            if (this._background) {
+                context.save();
+                context.fillStyle = this._background;
+                context.fillRect(0, 0, renderWidth, renderHeight);
+                context.restore();
+            } else {
+                this.clear();
+            }
+
+            // Render
+            var measure = new Measure(0, 0, renderWidth, renderHeight);
+            this._rootContainer._draw(measure, context);
+        }
+    }    
+}

+ 76 - 0
gui/src/controls/container.js

@@ -0,0 +1,76 @@
+/// <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 Container = (function (_super) {
+            __extends(Container, _super);
+            function Container(name) {
+                var _this = _super.call(this, name) || this;
+                _this.name = name;
+                _this._children = new Array();
+                return _this;
+            }
+            Container.prototype.addControl = function (control) {
+                var index = this._children.indexOf(control);
+                if (index !== -1) {
+                    return this;
+                }
+                control._setRoot(this);
+                this._reOrderControl(control);
+                this._markAsDirty();
+                return this;
+            };
+            Container.prototype.removeControl = function (control) {
+                var index = this._children.indexOf(control);
+                if (index !== -1) {
+                    this._children.splice(index, 1);
+                }
+                this._markAsDirty();
+                return this;
+            };
+            Container.prototype._reOrderControl = function (control) {
+                this.removeControl(control);
+                for (var index = 0; index < this._children.length; index++) {
+                    if (this._children[index].zIndex > control.zIndex) {
+                        this._children.splice(index, 0, control);
+                        return;
+                    }
+                }
+                this._children.push(control);
+                this._markAsDirty();
+            };
+            Container.prototype._draw = function (parentMeasure, context) {
+                this._currentMeasure = parentMeasure.copy();
+                context.save();
+                this.applyStates(context);
+                for (var _i = 0, _a = this._children; _i < _a.length; _i++) {
+                    var child = _a[_i];
+                    child._draw(this._currentMeasure, context);
+                }
+                context.restore();
+            };
+            Container.prototype._rescale = function (scaleX, scaleY) {
+                _super.prototype._rescale.call(this, scaleX, scaleY);
+                for (var _i = 0, _a = this._children; _i < _a.length; _i++) {
+                    var child = _a[_i];
+                    child._rescale(scaleX, scaleY);
+                }
+            };
+            return Container;
+        }(GUI.Control));
+        GUI.Container = Container;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=container.js.map

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

@@ -0,0 +1,72 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.GUI {
+    export class Container extends Control {
+        private _children = new Array<Control>();
+
+        constructor(public name: string) {
+            super(name);
+        }
+
+       public addControl(control: Control): Container {
+           var index = this._children.indexOf(control);
+
+            if (index !== -1) {
+                return this;
+            }
+            control._setRoot(this);
+
+            this._reOrderControl(control);
+
+            this._markAsDirty();
+            return this;
+        }
+
+        public removeControl(control: Control): Container {
+            var index = this._children.indexOf(control);
+
+            if (index !== -1) {
+                this._children.splice(index, 1);
+            }
+
+            this._markAsDirty();
+            return this;
+        }
+
+        public _reOrderControl(control: Control): void {
+            this.removeControl(control);
+
+            for (var index = 0; index < this._children.length; index++) {
+                if (this._children[index].zIndex > control.zIndex) {
+                    this._children.splice(index, 0, control);
+                    return;
+                }
+            }
+
+            this._children.push(control);
+
+            this._markAsDirty();
+        }
+
+        public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
+            this._currentMeasure = parentMeasure.copy();
+
+            context.save();
+            
+            this.applyStates(context);
+
+            for (var child of this._children) {
+                child._draw(this._currentMeasure, context);
+            }
+            context.restore();
+        }
+
+        public _rescale(scaleX: number, scaleY: number) {
+            super._rescale(scaleX, scaleY);
+
+            for (var child of this._children) {
+                child._rescale(scaleX, scaleY);
+            }
+        }
+    }    
+}

+ 63 - 0
gui/src/controls/contentControl.js

@@ -0,0 +1,63 @@
+/// <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 ContentControl = (function (_super) {
+            __extends(ContentControl, _super);
+            function ContentControl(name) {
+                var _this = _super.call(this, name) || this;
+                _this.name = name;
+                return _this;
+            }
+            Object.defineProperty(ContentControl.prototype, "child", {
+                get: function () {
+                    return this._child;
+                },
+                set: function (control) {
+                    if (this._child === control) {
+                        return;
+                    }
+                    this._child = control;
+                    control._setRoot(this._root);
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            ContentControl.prototype._localDraw = function (context) {
+                // Implemented by child to be injected inside main draw
+            };
+            ContentControl.prototype._draw = function (parentMeasure, context) {
+                this._currentMeasure = parentMeasure.copy();
+                context.save();
+                this.applyStates(context);
+                this._localDraw(context);
+                if (this._child) {
+                    this._child._draw(this._currentMeasure, context);
+                }
+                context.restore();
+            };
+            ContentControl.prototype._rescale = function (scaleX, scaleY) {
+                _super.prototype._rescale.call(this, scaleX, scaleY);
+                if (this._child) {
+                    this._child._rescale(scaleX, scaleY);
+                }
+            };
+            return ContentControl;
+        }(GUI.Control));
+        GUI.ContentControl = ContentControl;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=contentControl.js.map

+ 53 - 0
gui/src/controls/contentControl.ts

@@ -0,0 +1,53 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.GUI {
+    export class ContentControl extends Control {
+        private _child: Control;       
+
+        public get child(): Control {
+            return this._child;
+        }
+
+        public set child(control: Control) {
+            if (this._child === control) {
+                return;
+            }
+
+            this._child = control;
+            control._setRoot(this._root);
+
+            this._markAsDirty();
+        }
+
+        constructor(public name: string) {
+            super(name);
+        }
+
+        protected _localDraw(context: CanvasRenderingContext2D): void {
+            // Implemented by child to be injected inside main draw
+        }
+
+        public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
+            this._currentMeasure = parentMeasure.copy();
+
+            context.save();
+            
+            this.applyStates(context);
+
+            this._localDraw(context);
+
+            if (this._child) {
+                this._child._draw(this._currentMeasure, context);
+            }
+            context.restore();
+        }
+
+        public _rescale(scaleX: number, scaleY: number) {
+            super._rescale(scaleX, scaleY);
+
+            if (this._child) {
+                this._child._rescale(scaleX, scaleY);
+            }
+        }
+    }    
+}

+ 220 - 0
gui/src/controls/control.js

@@ -0,0 +1,220 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+var BABYLON;
+(function (BABYLON) {
+    var GUI;
+    (function (GUI) {
+        var Control = (function () {
+            function Control(name) {
+                this.name = name;
+                this._zIndex = 0;
+                this._fontSize = 18;
+                this._horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
+                this._verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
+                this.fontFamily = "Arial";
+            }
+            Object.defineProperty(Control.prototype, "horizontalAlignment", {
+                get: function () {
+                    return this._horizontalAlignment;
+                },
+                set: function (value) {
+                    if (this._horizontalAlignment === value) {
+                        return;
+                    }
+                    this._horizontalAlignment = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Control.prototype, "verticalAlignment", {
+                get: function () {
+                    return this._verticalAlignment;
+                },
+                set: function (value) {
+                    if (this._verticalAlignment === value) {
+                        return;
+                    }
+                    this._verticalAlignment = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Control.prototype, "fontFamily", {
+                get: function () {
+                    return this._fontFamily;
+                },
+                set: function (value) {
+                    if (this._fontFamily === value) {
+                        return;
+                    }
+                    this._fontFamily = value;
+                    this._prepareFont();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Control.prototype, "fontSize", {
+                get: function () {
+                    return this._fontSize;
+                },
+                set: function (value) {
+                    if (this._fontSize === value) {
+                        return;
+                    }
+                    this._fontSize = value;
+                    this._prepareFont();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Control.prototype, "color", {
+                get: function () {
+                    return this._color;
+                },
+                set: function (value) {
+                    if (this._color === value) {
+                        return;
+                    }
+                    this._color = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Control.prototype, "zIndex", {
+                get: function () {
+                    return this._zIndex;
+                },
+                set: function (value) {
+                    if (this.zIndex === value) {
+                        return;
+                    }
+                    this._zIndex = value;
+                    this._root._reOrderControl(this);
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Control.prototype._markAsDirty = function () {
+                if (!this._root) {
+                    return; // Not yet connected
+                }
+                this._root._markAsDirty();
+            };
+            Control.prototype._setRoot = function (root) {
+                this._root = root;
+            };
+            Control.prototype.applyStates = function (context) {
+                if (this._font) {
+                    context.font = this._font;
+                }
+                if (this._color) {
+                    context.fillStyle = this._color;
+                }
+            };
+            Control.prototype._draw = function (parentMeasure, context) {
+                this._currentMeasure = parentMeasure.copy();
+                // Do nothing
+            };
+            Control.prototype._rescale = function (scaleX, scaleY) {
+                this._scaleX = scaleX;
+                this._scaleY = scaleY;
+                this._prepareFont();
+            };
+            Control.prototype._prepareFont = function () {
+                if (!this._fontFamily) {
+                    return;
+                }
+                this._font = (this._fontSize * this._scaleX) + "px " + this._fontFamily;
+                this._fontOffset = Control._GetFontOffset(this._font);
+                this._markAsDirty();
+            };
+            Object.defineProperty(Control, "HORIZONTAL_ALIGNMENT_LEFT", {
+                get: function () {
+                    return Control._HORIZONTAL_ALIGNMENT_LEFT;
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Control, "HORIZONTAL_ALIGNMENT_RIGHT", {
+                get: function () {
+                    return Control._HORIZONTAL_ALIGNMENT_RIGHT;
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Control, "HORIZONTAL_ALIGNMENT_CENTER", {
+                get: function () {
+                    return Control._HORIZONTAL_ALIGNMENT_CENTER;
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Control, "VERTICAL_ALIGNMENT_TOP", {
+                get: function () {
+                    return Control._VERTICAL_ALIGNMENT_TOP;
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Control, "VERTICAL_ALIGNMENT_BOTTOM", {
+                get: function () {
+                    return Control._VERTICAL_ALIGNMENT_BOTTOM;
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Control, "VERTICAL_ALIGNMENT_CENTER", {
+                get: function () {
+                    return Control._VERTICAL_ALIGNMENT_CENTER;
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Control._GetFontOffset = function (font) {
+                if (Control._FontHeightSizes[font]) {
+                    return Control._FontHeightSizes[font];
+                }
+                var text = document.createElement("span");
+                text.innerHTML = "Hg";
+                text.style.font = font;
+                var block = document.createElement("div");
+                block.style.display = "inline-block";
+                block.style.width = "1px";
+                block.style.height = "0px";
+                block.style.verticalAlign = "bottom";
+                var div = document.createElement("div");
+                div.appendChild(text);
+                div.appendChild(block);
+                document.body.appendChild(div);
+                var fontAscent = 0;
+                var fontHeight = 0;
+                try {
+                    fontHeight = block.getBoundingClientRect().top - text.getBoundingClientRect().top;
+                    block.style.verticalAlign = "baseline";
+                    fontAscent = block.getBoundingClientRect().top - text.getBoundingClientRect().top;
+                }
+                finally {
+                    div.remove();
+                }
+                var result = { ascent: fontAscent, height: fontHeight, descent: fontHeight - fontAscent };
+                Control._FontHeightSizes[font] = result;
+                return result;
+            };
+            ;
+            return Control;
+        }());
+        // Statics
+        Control._HORIZONTAL_ALIGNMENT_LEFT = 0;
+        Control._HORIZONTAL_ALIGNMENT_RIGHT = 1;
+        Control._HORIZONTAL_ALIGNMENT_CENTER = 2;
+        Control._VERTICAL_ALIGNMENT_TOP = 0;
+        Control._VERTICAL_ALIGNMENT_BOTTOM = 1;
+        Control._VERTICAL_ALIGNMENT_CENTER = 2;
+        Control._FontHeightSizes = {};
+        GUI.Control = Control;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=control.js.map

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

@@ -0,0 +1,214 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.GUI {
+    export class Control {        
+        private _zIndex = 0;
+        public _root: Container;
+        public _currentMeasure: Measure;
+        private _scaleX: number;
+        private _scaleY: number;
+        private _fontFamily: string;
+        private _fontSize = 18;
+        private _font: string;
+        private _lastMeasuredFont: string;
+        protected _fontOffset: {ascent: number, height: number, descent: number};
+        private _color: string;
+        private _horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
+        private _verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
+        
+        public get horizontalAlignment(): number {
+            return this._horizontalAlignment;
+        }
+
+        public set horizontalAlignment(value: number) {
+            if (this._horizontalAlignment === value) {
+                return;
+            }
+
+            this._horizontalAlignment = value;
+            this._markAsDirty();
+        } 
+
+        public get verticalAlignment(): number {
+            return this._verticalAlignment;
+        }
+
+        public set verticalAlignment(value: number) {
+            if (this._verticalAlignment === value) {
+                return;
+            }
+
+            this._verticalAlignment = value;
+            this._markAsDirty();
+        } 
+
+        public get fontFamily(): string {
+            return this._fontFamily;
+        }
+
+        public set fontFamily(value: string) {
+            if (this._fontFamily === value) {
+                return;
+            }
+
+            this._fontFamily = value;
+            this._prepareFont();
+        }
+
+        public get fontSize(): number {
+            return this._fontSize;
+        }
+
+        public set fontSize(value: number) {
+            if (this._fontSize === value) {
+                return;
+            }
+
+            this._fontSize = value;
+            this._prepareFont();
+        }
+
+        public get color(): string {
+            return this._color;
+        }
+
+        public set color(value: string) {
+            if (this._color === value) {
+                return;
+            }
+
+            this._color = value;
+            this._markAsDirty();
+        }                       
+
+        public get zIndex(): number {
+            return this._zIndex;
+        }
+
+        public set zIndex(value: number) {
+            if (this.zIndex === value) {
+                return;
+            }
+
+            this._zIndex = value;
+            this._root._reOrderControl(this);
+        }
+
+        constructor(public name: string) {
+            this.fontFamily = "Arial";
+        }
+
+        protected _markAsDirty(): void {
+            if (!this._root) {
+                return; // Not yet connected
+            }
+            this._root._markAsDirty();
+        }
+
+        public _setRoot(root: Container): void {
+            this._root = root;
+        }
+
+        protected applyStates(context: CanvasRenderingContext2D): void {
+            if (this._font) {
+                context.font = this._font;
+            }
+
+            if (this._color) {
+                context.fillStyle = this._color;
+            }
+        }
+
+        public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
+            this._currentMeasure = parentMeasure.copy();
+            // Do nothing
+        }
+
+        public _rescale(scaleX: number, scaleY: number) {
+            this._scaleX = scaleX;
+            this._scaleY = scaleY;
+
+            this._prepareFont();
+        }
+
+        private _prepareFont() {
+            if (!this._fontFamily) {
+                return;
+            }
+            this._font = (this._fontSize * this._scaleX) + "px " + this._fontFamily;
+            this._fontOffset = Control._GetFontOffset(this._font);
+            this._markAsDirty();
+        }
+
+        // Statics
+        private static _HORIZONTAL_ALIGNMENT_LEFT = 0;
+        private static _HORIZONTAL_ALIGNMENT_RIGHT = 1;
+        private static _HORIZONTAL_ALIGNMENT_CENTER = 2;
+        private static _VERTICAL_ALIGNMENT_TOP = 0;
+        private static _VERTICAL_ALIGNMENT_BOTTOM = 1;
+        private static _VERTICAL_ALIGNMENT_CENTER = 2;
+
+        public static get HORIZONTAL_ALIGNMENT_LEFT(): number {
+            return Control._HORIZONTAL_ALIGNMENT_LEFT;
+        }
+
+        public static get HORIZONTAL_ALIGNMENT_RIGHT(): number {
+            return Control._HORIZONTAL_ALIGNMENT_RIGHT;
+        }
+
+        public static get HORIZONTAL_ALIGNMENT_CENTER(): number {
+            return Control._HORIZONTAL_ALIGNMENT_CENTER;
+        }
+
+        public static get VERTICAL_ALIGNMENT_TOP(): number {
+            return Control._VERTICAL_ALIGNMENT_TOP;
+        }
+
+        public static get VERTICAL_ALIGNMENT_BOTTOM(): number {
+            return Control._VERTICAL_ALIGNMENT_BOTTOM;
+        }
+
+        public static get VERTICAL_ALIGNMENT_CENTER(): number {
+            return Control._VERTICAL_ALIGNMENT_CENTER;
+        }
+
+        private static _FontHeightSizes = {};
+
+        public static _GetFontOffset(font: string): {ascent: number, height: number, descent: number} {
+
+            if (Control._FontHeightSizes[font]) {
+                return Control._FontHeightSizes[font];
+            }
+
+            var text = document.createElement("span");
+            text.innerHTML = "Hg";
+            text.style.font = font;
+
+            var block = document.createElement("div");
+            block.style.display = "inline-block";
+            block.style.width = "1px";
+            block.style.height = "0px";
+            block.style.verticalAlign = "bottom";
+
+            var div = document.createElement("div");
+            div.appendChild(text);
+            div.appendChild(block);
+
+            document.body.appendChild(div);
+
+            var fontAscent = 0;
+            var fontHeight = 0;
+            try {
+                fontHeight = block.getBoundingClientRect().top - text.getBoundingClientRect().top;
+                block.style.verticalAlign = "baseline";
+                fontAscent = block.getBoundingClientRect().top - text.getBoundingClientRect().top;
+            } finally {
+                div.remove();
+            }
+            var result = { ascent: fontAscent, height: fontHeight, descent: fontHeight - fontAscent };
+            Control._FontHeightSizes[font] = result;
+
+            return result;
+        };
+    }    
+}

+ 73 - 0
gui/src/controls/rectangle.js

@@ -0,0 +1,73 @@
+/// <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 Rectangle = (function (_super) {
+            __extends(Rectangle, _super);
+            function Rectangle(name) {
+                var _this = _super.call(this, name) || this;
+                _this.name = name;
+                _this._thickness = 1;
+                return _this;
+            }
+            Object.defineProperty(Rectangle.prototype, "thickness", {
+                get: function () {
+                    return this._thickness;
+                },
+                set: function (value) {
+                    if (this._thickness === value) {
+                        return;
+                    }
+                    this._thickness = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Rectangle.prototype, "background", {
+                get: function () {
+                    return this._background;
+                },
+                set: function (value) {
+                    if (this._background === value) {
+                        return;
+                    }
+                    this._background = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Rectangle.prototype._localDraw = function (context) {
+                context.save();
+                if (this._background) {
+                    context.fillStyle = this._background;
+                    context.fillRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
+                }
+                if (this._thickness) {
+                    if (this.color) {
+                        context.strokeStyle = this.color;
+                    }
+                    context.lineWidth = this._thickness;
+                    context.strokeRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
+                }
+                context.restore();
+            };
+            return Rectangle;
+        }(GUI.ContentControl));
+        GUI.Rectangle = Rectangle;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=rectangle.js.map

+ 58 - 0
gui/src/controls/rectangle.ts

@@ -0,0 +1,58 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.GUI {
+    export class Rectangle extends ContentControl {
+        private _thickness = 1;
+        private _background: string;
+        
+        public get thickness(): number {
+            return this._thickness;
+        }
+
+        public set thickness(value: number) {
+            if (this._thickness === value) {
+                return;
+            }
+
+            this._thickness = value;
+            this._markAsDirty();
+        }   
+
+       
+        public get background(): string {
+            return this._background;
+        }
+
+        public set background(value: string) {
+            if (this._background === value) {
+                return;
+            }
+
+            this._background = value;
+            this._markAsDirty();
+        }           
+     
+        constructor(public name: string) {
+            super(name);
+        }
+
+        protected _localDraw(context: CanvasRenderingContext2D): void {
+            context.save();
+
+            if (this._background) {
+                context.fillStyle = this._background;
+                context.fillRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
+            }
+
+            if (this._thickness) {
+                if (this.color) {
+                    context.strokeStyle = this.color;
+                }
+                context.lineWidth = this._thickness;
+                context.strokeRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
+            }
+        
+            context.restore();
+        }
+    }    
+}

+ 84 - 0
gui/src/controls/textBlock.js

@@ -0,0 +1,84 @@
+/// <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 TextBlock = (function (_super) {
+            __extends(TextBlock, _super);
+            function TextBlock(name, text) {
+                var _this = _super.call(this, name) || this;
+                _this.name = name;
+                _this.text = text;
+                return _this;
+            }
+            Object.defineProperty(TextBlock.prototype, "text", {
+                get: function () {
+                    return this._text;
+                },
+                set: function (value) {
+                    if (this._text === value) {
+                        return;
+                    }
+                    this._text = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            TextBlock.prototype._draw = function (parentMeasure, context) {
+                context.save();
+                this.applyStates(context);
+                this._prepare(parentMeasure, context);
+                context.fillText(this.text, this._currentMeasure.left, this._currentMeasure.top);
+                context.restore();
+            };
+            TextBlock.prototype._prepare = function (parentMeasure, context) {
+                var width = parentMeasure.width;
+                var height = parentMeasure.height;
+                var x = 0;
+                var y = 0;
+                var textSize = context.measureText(this.text);
+                switch (this.horizontalAlignment) {
+                    case GUI.Control.HORIZONTAL_ALIGNMENT_LEFT:
+                        x = 0;
+                        break;
+                    case GUI.Control.HORIZONTAL_ALIGNMENT_RIGHT:
+                        x = width - textSize.width;
+                        break;
+                    case GUI.Control.HORIZONTAL_ALIGNMENT_CENTER:
+                        x = (width - textSize.width) / 2;
+                        break;
+                }
+                if (!this._fontOffset) {
+                    this._fontOffset = GUI.Control._GetFontOffset(context.font);
+                }
+                switch (this.verticalAlignment) {
+                    case GUI.Control.VERTICAL_ALIGNMENT_TOP:
+                        y = this._fontOffset.ascent;
+                        break;
+                    case GUI.Control.VERTICAL_ALIGNMENT_BOTTOM:
+                        y = height - this._fontOffset.descent;
+                        break;
+                    case GUI.Control.VERTICAL_ALIGNMENT_CENTER:
+                        y = (height / 2) + (this._fontOffset.ascent - this._fontOffset.height / 2);
+                        break;
+                }
+                this._currentMeasure = new GUI.Measure(parentMeasure.left + x, parentMeasure.top + y, width, height);
+            };
+            return TextBlock;
+        }(GUI.Control));
+        GUI.TextBlock = TextBlock;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=textBlock.js.map

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

@@ -0,0 +1,76 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.GUI {
+    export class TextBlock extends Control {
+        private _text: string;
+
+        public get text(): string {
+            return this._text;
+        }
+
+        public set text(value: string) {
+            if (this._text === value) {
+                return;
+            }
+            this._text = value;
+            this._markAsDirty();
+        }
+
+        constructor(public name: string, text: string) {
+            super(name);
+
+            this.text = text;
+        }
+
+        public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
+            context.save();
+            
+            this.applyStates(context);
+
+            this._prepare(parentMeasure, context)
+
+            context.fillText(this.text, this._currentMeasure.left, this._currentMeasure.top);
+
+            context.restore();
+        }
+
+        private _prepare(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
+            var width = parentMeasure.width;
+            var height = parentMeasure.height;
+
+            var x = 0;
+            var y = 0;
+
+            var textSize = context.measureText(this.text);
+            switch (this.horizontalAlignment) {
+                case Control.HORIZONTAL_ALIGNMENT_LEFT:
+                    x = 0
+                    break;
+                case Control.HORIZONTAL_ALIGNMENT_RIGHT:
+                    x = width - textSize.width;
+                    break;
+                case Control.HORIZONTAL_ALIGNMENT_CENTER:
+                    x = (width - textSize.width) / 2;
+                    break;
+            }
+
+            if (!this._fontOffset) {
+                this._fontOffset = Control._GetFontOffset(context.font);
+            }
+
+            switch (this.verticalAlignment) {
+                case Control.VERTICAL_ALIGNMENT_TOP:
+                    y = this._fontOffset.ascent;
+                    break;
+                case Control.VERTICAL_ALIGNMENT_BOTTOM:
+                    y = height - this._fontOffset.descent;
+                    break;
+                case Control.VERTICAL_ALIGNMENT_CENTER:
+                    y = (height /2) + (this._fontOffset.ascent - this._fontOffset.height / 2);
+                    break;
+            }
+            
+            this._currentMeasure = new Measure(parentMeasure.left + x, parentMeasure.top + y, width, height);
+        }
+    }    
+}

+ 22 - 0
gui/src/measure.js

@@ -0,0 +1,22 @@
+/// <reference path="../../dist/preview release/babylon.d.ts"/>
+var BABYLON;
+(function (BABYLON) {
+    var GUI;
+    (function (GUI) {
+        var Measure = (function () {
+            function Measure(left, top, width, height) {
+                this.left = left;
+                this.top = top;
+                this.width = width;
+                this.height = height;
+            }
+            Measure.prototype.copy = function () {
+                return new Measure(this.left, this.top, this.width, this.height);
+            };
+            return Measure;
+        }());
+        GUI.Measure = Measure;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=measure.js.map

+ 13 - 0
gui/src/measure.ts

@@ -0,0 +1,13 @@
+/// <reference path="../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.GUI {
+    export class Measure {
+        public constructor(public left: number, public top: number, public width: number, public height: number) {
+
+        }
+
+        public copy(): Measure {
+            return new Measure(this.left, this.top,  this.width, this.height);
+        }
+    }    
+}

+ 7 - 0
gui/src/tsconfig.json

@@ -0,0 +1,7 @@
+{
+  "compilerOptions": {
+    "experimentalDecorators": true,
+    "module": "commonjs",
+    "target": "es5"
+  }
+}

+ 36 - 19
src/Animations/babylon.animation.ts

@@ -89,7 +89,7 @@
     }
 
     export class Animation {
-        private _keys: Array<{frame:number, value: any}>;
+        private _keys: Array<{frame:number, value: any, inTangent?: any, outTangent?: any}>;
         private _offsetsCache = {};
         private _highLimitsCache = {};
         private _stopped = false;
@@ -285,14 +285,26 @@
             return Quaternion.Slerp(startValue, endValue, gradient);
         }
 
+        public quaternionInterpolateFunctionWithTangents(startValue: Quaternion, outTangent: Quaternion, endValue: Quaternion, inTangent: Quaternion, gradient: number): Quaternion {
+            return Quaternion.Hermite(startValue, outTangent, endValue, inTangent, gradient);
+        }
+
         public vector3InterpolateFunction(startValue: Vector3, endValue: Vector3, gradient: number): Vector3 {
             return Vector3.Lerp(startValue, endValue, gradient);
         }
 
+        public vector3InterpolateFunctionWithTangents(startValue: Vector3, outTangent: Vector3, endValue: Vector3, inTangent: Vector3, gradient: number): Vector3 {
+            return Vector3.Hermite(startValue, outTangent, endValue, inTangent, gradient);
+        }
+
         public vector2InterpolateFunction(startValue: Vector2, endValue: Vector2, gradient: number): Vector2 {
             return Vector2.Lerp(startValue, endValue, gradient);
         }
 
+        public vector2InterpolateFunctionWithTangents(startValue: Vector2, outTangent: Vector2, endValue: Vector2, inTangent: Vector2, gradient: number): Vector2 {
+            return Vector2.Hermite(startValue, outTangent, endValue, inTangent, gradient);
+        }
+
         public sizeInterpolateFunction(startValue: Size, endValue: Size, gradient: number): Size {
             return Size.Lerp(startValue, endValue, gradient);
         }
@@ -347,22 +359,27 @@
             this.currentFrame = currentFrame;
 
             // Try to get a hash to find the right key
-            var startKey = Math.max(0, Math.min(this._keys.length - 1, Math.floor(this._keys.length * (currentFrame - this._keys[0].frame) / (this._keys[this._keys.length - 1].frame - this._keys[0].frame)) - 1));
+            var startKeyIndex = Math.max(0, Math.min(this._keys.length - 1, Math.floor(this._keys.length * (currentFrame - this._keys[0].frame) / (this._keys[this._keys.length - 1].frame - this._keys[0].frame)) - 1));
 
-            if (this._keys[startKey].frame >= currentFrame) {
-                while (startKey - 1 >= 0 && this._keys[startKey].frame >= currentFrame) {
-                    startKey--;
+            if (this._keys[startKeyIndex].frame >= currentFrame) {
+                while (startKeyIndex - 1 >= 0 && this._keys[startKeyIndex].frame >= currentFrame) {
+                    startKeyIndex--;
                 }
             }
 
-            for (var key = startKey; key < this._keys.length; key++) {
-                if (this._keys[key + 1].frame >= currentFrame) {
+            for (var key = startKeyIndex; key < this._keys.length; key++) {
+                var endKey = this._keys[key + 1];
+
+                if (endKey.frame >= currentFrame) {
+
+                    var startKey = this._keys[key];
+                    var startValue = this._getKeyValue(startKey.value);
+                    var endValue = this._getKeyValue(endKey.value);
 
-                    var startValue = this._getKeyValue(this._keys[key].value);
-                    var endValue = this._getKeyValue(this._keys[key + 1].value);
+                    var useTangent = startKey.outTangent && endKey.inTangent;
 
                     // gradient : percent of currentFrame between the frame inf and the frame sup
-                    var gradient = (currentFrame - this._keys[key].frame) / (this._keys[key + 1].frame - this._keys[key].frame);
+                    var gradient = (currentFrame - startKey.frame) / (endKey.frame - startKey.frame);
 
                     // check for easingFunction and correction of gradient
                     if (this._easingFunction != null) {
@@ -382,35 +399,35 @@
                             break;
                         // Quaternion
                         case Animation.ANIMATIONTYPE_QUATERNION:
-                            var quaternion = null;
+                            var quaternion = useTangent ? this.quaternionInterpolateFunctionWithTangents(startValue, startKey.outTangent, endValue, endKey.inTangent, gradient) : this.quaternionInterpolateFunction(startValue, endValue, gradient);
                             switch (loopMode) {
                                 case Animation.ANIMATIONLOOPMODE_CYCLE:
                                 case Animation.ANIMATIONLOOPMODE_CONSTANT:
-                                    quaternion = this.quaternionInterpolateFunction(startValue, endValue, gradient);
-                                    break;
+                                    return quaternion;
                                 case Animation.ANIMATIONLOOPMODE_RELATIVE:
-                                    quaternion = this.quaternionInterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
-                                    break;
+                                    return quaternion.add(offsetValue.scale(repeatCount));
                             }
 
                             return quaternion;
                         // Vector3
                         case Animation.ANIMATIONTYPE_VECTOR3:
+                            var vec3Value = useTangent ? this.vector3InterpolateFunctionWithTangents(startValue, startKey.outTangent, endValue, endKey.inTangent, gradient) : this.vector3InterpolateFunction(startValue, endValue, gradient);
                             switch (loopMode) {
                                 case Animation.ANIMATIONLOOPMODE_CYCLE:
                                 case Animation.ANIMATIONLOOPMODE_CONSTANT:
-                                    return this.vector3InterpolateFunction(startValue, endValue, gradient);
+                                    return vec3Value;
                                 case Animation.ANIMATIONLOOPMODE_RELATIVE:
-                                    return this.vector3InterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
+                                    return vec3Value.add(offsetValue.scale(repeatCount));
                             }
                         // Vector2
                         case Animation.ANIMATIONTYPE_VECTOR2:
+                            var vec2Value = useTangent ? this.vector2InterpolateFunctionWithTangents(startValue, startKey.outTangent, endValue, endKey.inTangent, gradient) : this.vector2InterpolateFunction(startValue, endValue, gradient);
                             switch (loopMode) {
                                 case Animation.ANIMATIONLOOPMODE_CYCLE:
                                 case Animation.ANIMATIONLOOPMODE_CONSTANT:
-                                    return this.vector2InterpolateFunction(startValue, endValue, gradient);
+                                    return vec2Value;
                                 case Animation.ANIMATIONLOOPMODE_RELATIVE:
-                                    return this.vector2InterpolateFunction(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
+                                    return vec2Value.add(offsetValue.scale(repeatCount));
                             }
                         // Size
                         case Animation.ANIMATIONTYPE_SIZE:

+ 46 - 50
src/Cameras/VR/babylon.webVRCamera.ts

@@ -96,50 +96,30 @@ module BABYLON {
             //enable VR
             this.getEngine().initWebVR();
 
-            if (!this.getEngine().vrDisplaysPromise) {
-                Tools.Error("WebVR is not enabled on your browser");
+            //check specs version
+            if (!window.VRFrameData) {
+                this._specsVersion = 1.0;
+                this._frameData = {
+                };
             } else {
-                //check specs version
-                if (!window.VRFrameData) {
-                    this._specsVersion = 1.0;
-                    this._frameData = {
-                    };
-                } else {
-                    this._frameData = new VRFrameData();
+                this._frameData = new VRFrameData();
+            }
+
+            this.getEngine().getVRDevice(this.webVROptions.displayName, device => {
+                if (!device) {
+                    return;
                 }
 
-                this.getEngine().vrDisplaysPromise.then((devices) => {
-                    if (devices.length > 0) {
-                        this._vrEnabled = true;
-                        if (this.webVROptions.displayName) {
-                            var found = devices.some(device => {
-                                if (device.displayName === this.webVROptions.displayName) {
-                                    this._vrDevice = device;
-                                    return true;
-                                } else {
-                                    return false;
-                                }
-                            });
-                            if (!found) {
-                                this._vrDevice = devices[0];
-                                Tools.Warn("Display " + this.webVROptions.displayName + " was not found. Using " + this._vrDevice.displayName);
-                            }
-                        } else {
-                            //choose the first one
-                            this._vrDevice = devices[0];
-                        }
+                this._vrEnabled = true;               
+                this._vrDevice = device;
 
-                        //reset the rig parameters.
-                        this.setCameraRigMode(Camera.RIG_MODE_WEBVR, { parentCamera: this, vrDisplay: this._vrDevice, frameData: this._frameData, specs: this._specsVersion });
+                //reset the rig parameters.
+                this.setCameraRigMode(Camera.RIG_MODE_WEBVR, { parentCamera: this, vrDisplay: this._vrDevice, frameData: this._frameData, specs: this._specsVersion });
 
-                        if (this._attached) {
-                            this.getEngine().enableVR(this._vrDevice)
-                        }
-                    } else {
-                        Tools.Error("No WebVR devices found!");
-                    }
-                });
-            }
+                if (this._attached) {
+                    this.getEngine().enableVR(this._vrDevice)
+                }
+            });                
 
             // try to attach the controllers, if found.
             this.initControllers();
@@ -186,21 +166,37 @@ module BABYLON {
             }
         }
 
-        public getLeftCamera() {
-            return (<FreeCamera>this._rigCameras[0]);
-        }
+        public getControllerByName(name: string): WebVRController {
+            for (var gp of this.controllers) {
+                if (gp.hand === name) {
+                    return gp;
+                }
+            }
 
-        public getRightCamera() {
-            return (<FreeCamera>this._rigCameras[1]);
+            return undefined;
         }
 
-        public getLeftTarget() {
-            return (<TargetCamera>this._rigCameras[0]).getTarget();
-        }
+        private _leftController: WebVRController;
+        public get leftController(): WebVRController {
+            if (!this._leftController) {
+                this._leftController = this.getControllerByName("left");
+            }
 
-        public getRightTarget() {
-            return (<TargetCamera>this._rigCameras[1]).getTarget();
-        }
+            return this._leftController;
+        };
+
+        private _rightController: WebVRController;
+        public get rightController(): WebVRController {
+            if (!this._rightController) {
+                this._rightController = this.getControllerByName("right");
+            }
+
+            return this._rightController;
+        };
+
+        public getForwardRay(length = 100): Ray {
+            return super.getForwardRay(length, this.leftCamera.getWorldMatrix(), this.position.add(this.devicePosition)); // Need the actual rendered camera
+        } 
 
         public _checkInputs(): void {
             if (this._vrEnabled) {

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

@@ -530,6 +530,22 @@
             return target.isCompletelyInFrustum(this._frustumPlanes);
         }
 
+        public getForwardRay(length = 100, transform: Matrix, origin: Vector3): Ray {
+            if (!transform) {
+                transform = this.getWorldMatrix();
+            }
+
+            if (!origin) {
+                origin = this.position;
+            }
+            var forward = new BABYLON.Vector3(0, 0, 1);
+            var forwardWorld = BABYLON.Vector3.TransformNormal(forward, transform);
+
+            var direction = BABYLON.Vector3.Normalize(forwardWorld);
+
+            return new Ray(origin, direction, length);
+        } 
+
         public dispose(): void {
             // Animations
             this.getScene().stopAnimation(this);
@@ -550,6 +566,34 @@
         }
 
         // ---- Camera rigs section ----
+        public get leftCamera(): FreeCamera {
+            if (this._rigCameras.length < 1) {
+                return undefined;
+            }
+            return (<FreeCamera>this._rigCameras[0]);
+        }
+
+        public get rightCamera(): FreeCamera {
+            if (this._rigCameras.length < 2) {
+                return undefined;
+            }            
+            return (<FreeCamera>this._rigCameras[1]);
+        }
+
+        public getLeftTarget(): Vector3 {
+            if (this._rigCameras.length < 1) {
+                return undefined;
+            }             
+            return (<TargetCamera>this._rigCameras[0]).getTarget();
+        }
+
+        public getRightTarget(): Vector3 {
+            if (this._rigCameras.length < 2) {
+                return undefined;
+            }             
+            return (<TargetCamera>this._rigCameras[1]).getTarget();
+        }
+
         public setCameraRigMode(mode: number, rigParams: any): void {
             while (this._rigCameras.length > 0) {
                 this._rigCameras.pop().dispose();

+ 1 - 1
src/Layer/babylon.layer.ts

@@ -67,7 +67,7 @@
             this._scene = scene || Engine.LastCreatedScene;
             this._scene.layers.push(this);
 
-            var engine = scene.getEngine();
+            var engine = this._scene.getEngine();
 
             // VBO
             var vertices = [];

+ 1 - 1
src/Lights/babylon.hemisphericLight.ts

@@ -16,7 +16,7 @@
          */
         constructor(name: string, direction: Vector3, scene: Scene) {
             super(name, scene);
-            this.direction = direction;
+            this.direction = direction || Vector3.Up();
         }
 
         protected _buildUniformLayout(): void {

+ 1 - 1
src/Lights/babylon.light.ts

@@ -145,7 +145,7 @@
         constructor(name: string, scene: Scene) {
             super(name, scene);
             this.getScene().addLight(this);
-            this._uniformBuffer = new UniformBuffer(scene.getEngine());
+            this._uniformBuffer = new UniformBuffer(this.getScene().getEngine());
             this._buildUniformLayout();
 
             this.includedOnlyMeshes = new Array<AbstractMesh>();

+ 21 - 8
src/Materials/Textures/babylon.dynamicTexture.ts

@@ -10,7 +10,7 @@ module BABYLON {
             super(null, scene, !generateMipMaps, undefined, samplingMode, undefined, undefined, undefined, undefined, format);
 
             this.name = name;
-
+            var engine = this.getScene().getEngine();
             this.wrapU = Texture.CLAMP_ADDRESSMODE;
             this.wrapV = Texture.CLAMP_ADDRESSMODE;
 
@@ -18,14 +18,14 @@ module BABYLON {
 
             if (options.getContext) {
                 this._canvas = options;
-                this._texture = scene.getEngine().createDynamicTexture(options.width, options.height, generateMipMaps, samplingMode);
+                this._texture = engine.createDynamicTexture(options.width, options.height, generateMipMaps, samplingMode);
             } else {
                 this._canvas = document.createElement("canvas");
 
                 if (options.width) {
-                    this._texture = scene.getEngine().createDynamicTexture(options.width, options.height, generateMipMaps, samplingMode);
+                    this._texture = engine.createDynamicTexture(options.width, options.height, generateMipMaps, samplingMode);
                 } else {
-                    this._texture = scene.getEngine().createDynamicTexture(options, options, generateMipMaps, samplingMode);
+                    this._texture = engine.createDynamicTexture(options, options, generateMipMaps, samplingMode);
                 }
             }
 
@@ -40,18 +40,31 @@ module BABYLON {
             return true;
         }
 
+        private _recreate(textureSize: ISize): void {
+            this._canvas.width = textureSize.width;
+            this._canvas.height = textureSize.height;
+
+            this.releaseInternalTexture();
+
+            this._texture = this.getScene().getEngine().createDynamicTexture(textureSize.width, textureSize.height, this._generateMipMaps, this._samplingMode);
+        }
+
         public scale(ratio: number): void {
             var textureSize = this.getSize();
 
             textureSize.width *= ratio;
             textureSize.height *= ratio;
 
-            this._canvas.width = textureSize.width;
-            this._canvas.height = textureSize.height;
+            this._recreate(textureSize);
+        }
 
-            this.releaseInternalTexture();
+        public scaleTo(width: number, height: number): void {
+            var textureSize = this.getSize();
 
-            this._texture = this.getScene().getEngine().createDynamicTexture(textureSize.width, textureSize.height, this._generateMipMaps, this._samplingMode);
+            textureSize.width  = width;
+            textureSize.height = height;
+
+            this._recreate(textureSize);
         }
 
         public getContext(): CanvasRenderingContext2D {

+ 2 - 2
src/Materials/babylon.pushMaterial.ts

@@ -41,8 +41,8 @@
             this.getScene()._cachedEffect = effect;
         }
 
-        protected _mustRebind(scene: Scene, effect: Effect) {
-            return scene.getCachedEffect() !== effect || scene.getCachedMaterial() !== this;
+        protected _mustRebind(scene: Scene, effect: Effect, visibility: number = 0) {
+            return scene.isCachedMaterialValid(this, effect, visibility);
         }
 
         public markAsDirty(flag: number): void {

+ 2 - 1
src/Materials/babylon.standardMaterial.ts

@@ -821,7 +821,7 @@ module BABYLON {
 
             // Bones
             MaterialHelper.BindBonesParameters(mesh, effect);
-            if (this._mustRebind(scene, effect)) {
+            if (this._mustRebind(scene, effect, mesh.visibility)) {
                 this._uniformBuffer.bindToEffect(effect, "Material");
                 
                 this.bindViewProjection(effect);
@@ -918,6 +918,7 @@ module BABYLON {
                         this._uniformBuffer.updateColor4("vSpecularColor", this.specularColor, this.specularPower);
                     }
                     this._uniformBuffer.updateColor3("vEmissiveColor", this.emissiveColor);
+
                     // Diffuse
                     this._uniformBuffer.updateColor4("vDiffuseColor", this.diffuseColor, this.alpha * mesh.visibility);
                 }

+ 14 - 2
src/Math/babylon.math.ts

@@ -2813,13 +2813,11 @@
         }
 
         public static Slerp(left: Quaternion, right: Quaternion, amount: number): Quaternion {
-
             var result = Quaternion.Identity();
 
             Quaternion.SlerpToRef(left, right, amount, result);
 
             return result;
-
         }
 
         public static SlerpToRef(left: Quaternion, right: Quaternion, amount: number, result: Quaternion): void {
@@ -2849,7 +2847,21 @@
             result.y = (num3 * left.y) + (num2 * right.y);
             result.z = (num3 * left.z) + (num2 * right.z);
             result.w = (num3 * left.w) + (num2 * right.w);
+        }
 
+        public static Hermite(value1: Quaternion, tangent1: Quaternion, value2: Quaternion, tangent2: Quaternion, amount: number): Quaternion {
+            var squared = amount * amount;
+            var cubed = amount * squared;
+            var part1 = ((2.0 * cubed) - (3.0 * squared)) + 1.0;
+            var part2 = (-2.0 * cubed) + (3.0 * squared);
+            var part3 = (cubed - (2.0 * squared)) + amount;
+            var part4 = cubed - squared;
+
+            var x = (((value1.x * part1) + (value2.x * part2)) + (tangent1.x * part3)) + (tangent2.x * part4);
+            var y = (((value1.y * part1) + (value2.y * part2)) + (tangent1.y * part3)) + (tangent2.y * part4);
+            var z = (((value1.z * part1) + (value2.z * part2)) + (tangent1.z * part3)) + (tangent2.z * part4);
+            var w = (((value1.w * part1) + (value2.w * part2)) + (tangent1.w * part3)) + (tangent2.w * part4);
+            return new Quaternion(x, y, z, w);
         }
     }
 

+ 1 - 1
src/Rendering/babylon.boundingBoxRenderer.ts

@@ -22,7 +22,7 @@
             this._colorShader = new ShaderMaterial("colorShader", this._scene, "color",
                 {
                     attributes: [VertexBuffer.PositionKind],
-                    uniforms: ["worldViewProjection", "color"]
+                    uniforms: ["world", "viewProjection", "color"]
                 });
 
 

+ 20 - 0
src/Tools/babylon.extendedGamepad.ts

@@ -121,6 +121,26 @@ module BABYLON {
         public detachMesh() {
             this._mesh = undefined;
         }
+
+        public get mesh(): AbstractMesh {
+            return this._mesh;
+        }
+
+        public getForwardRay(length = 100): Ray {
+            if (!this.mesh) {
+                return new Ray(Vector3.Zero(), new BABYLON.Vector3(0, 0, 1), length);
+            }
+
+            var m = this.mesh.getWorldMatrix();
+            var origin = m.getTranslation();
+
+            var forward = new BABYLON.Vector3(0, 0, -1);
+            var forwardWorld = BABYLON.Vector3.TransformNormal(forward, m);
+
+            var direction = BABYLON.Vector3.Normalize(forwardWorld);            
+
+            return new Ray(origin, direction, length);
+        } 
     }
 
     export interface GamepadButtonChanges {

+ 53 - 1
src/babylon.engine.ts

@@ -443,6 +443,13 @@
         public enableOfflineSupport = BABYLON.Database;
         public scenes = new Array<Scene>();
 
+        // Observables
+
+        /**
+         * Observable event triggered each time the rendering canvas is resized
+         */
+        public onResizeObservable = new Observable<Engine>();
+
         //WebVR 
 
         //The new WebVR uses promises.
@@ -1168,6 +1175,10 @@
          * @param {number} height - the new canvas' height
          */
         public setSize(width: number, height: number): void {
+            if (this._renderingCanvas.width === width && this._renderingCanvas.height === height) {
+                return;
+            }
+
             this._renderingCanvas.width = width;
             this._renderingCanvas.height = height;
 
@@ -1180,12 +1191,53 @@
                     cam._currentRenderId = 0;
                 }
             }
+
+            if (this.onResizeObservable.hasObservers) {
+                this.onResizeObservable.notifyObservers(this);
+            }
         }
 
 
         //WebVR functions
+        public isVRDevicePresent(callback: (result: boolean) => void) {
+            this.getVRDevice(null, (device) => {
+                callback(device !== null);
+            });
+        }
+
+        public getVRDevice(name: string, callback: (device) => void) {
+            if (!this.vrDisplaysPromise) {
+                callback(null);
+                return;
+            }
+
+            this.vrDisplaysPromise.then((devices) => {
+                if (devices.length > 0) {
+                    if (name) {
+                        var found = devices.some(device => {
+                            if (device.displayName === name) {
+                                callback(device);
+                                return true;
+                            } else {
+                                return false;
+                            }
+                        });
+                        if (!found) {
+                            Tools.Warn("Display " + name + " was not found. Using " + devices[0].displayName);
+                            callback(devices[0]);
+                        }
+                    } else {
+                        //choose the first one
+                        callback(devices[0]);
+                    }
+                } else {
+                    Tools.Error("No WebVR devices found!");
+                    callback(null);
+                }
+            });            
+        }
 
-        public initWebVR() {
+        public initWebVR(): void {
             if (!this.vrDisplaysPromise) {
                 this._getVRDisplays();
             }

+ 11 - 1
src/babylon.scene.ts

@@ -658,6 +658,7 @@
 
         public _cachedMaterial: Material;
         public _cachedEffect: Effect;
+        public _cachedVisibility: number;
 
         private _renderId = 0;
         private _executeWhenReadyTimeoutId = -1;
@@ -812,10 +813,18 @@
             return this._cachedMaterial;
         }
 
-         public getCachedEffect(): Effect {
+        public getCachedEffect(): Effect {
             return this._cachedEffect;
         }
 
+        public getCachedVisibility(): number {
+            return this._cachedVisibility;
+        }
+
+        public isCachedMaterialValid(material: Material, effect: Effect, visibility: number = 0) {
+            return this._cachedEffect !== effect || this._cachedMaterial !== material || this._cachedVisibility !== visibility;
+        }
+
         public getBoundingBoxRenderer(): BoundingBoxRenderer {
             if (!this._boundingBoxRenderer) {
                 this._boundingBoxRenderer = new BoundingBoxRenderer(this);
@@ -1508,6 +1517,7 @@
         public resetCachedMaterial(): void {
             this._cachedMaterial = null;
             this._cachedEffect = null;
+            this._cachedVisibility = null;
         }
 
         public registerBeforeRender(func: () => void): void {