소스 검색

Merge remote-tracking branch 'upstream/master'

Cubees 8 년 전
부모
커밋
646d2158a4

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 2970 - 2967
dist/preview release/babylon.d.ts


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 33 - 33
dist/preview release/babylon.js


+ 20 - 15
dist/preview release/babylon.max.js

@@ -15501,7 +15501,7 @@ var BABYLON;
                 }
                 var canvas = _this._engine.getRenderingCanvas();
                 if (!_this.pointerMovePredicate) {
-                    _this.pointerMovePredicate = function (mesh) { return mesh.isPickable && mesh.isVisible && mesh.isReady() && (_this.constantlyUpdateMeshUnderPointer || (mesh.actionManager !== null && mesh.actionManager !== undefined)); };
+                    _this.pointerMovePredicate = function (mesh) { return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled() && (_this.constantlyUpdateMeshUnderPointer || (mesh.actionManager !== null && mesh.actionManager !== undefined)); };
                 }
                 // Meshes
                 var pickResult = _this.pick(_this._unTranslatedPointerX, _this._unTranslatedPointerY, _this.pointerMovePredicate, false, _this.cameraToUseForPointers);
@@ -15570,7 +15570,7 @@ var BABYLON;
                 _this._startingPointerTime = new Date().getTime();
                 if (!_this.pointerDownPredicate) {
                     _this.pointerDownPredicate = function (mesh) {
-                        return mesh.isPickable && mesh.isVisible && mesh.isReady();
+                        return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled();
                     };
                 }
                 // Meshes
@@ -15686,7 +15686,7 @@ var BABYLON;
                     }
                     if (!this.pointerUpPredicate) {
                         this.pointerUpPredicate = function (mesh) {
-                            return mesh.isPickable && mesh.isVisible && mesh.isReady();
+                            return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled();
                         };
                     }
                     // Meshes
@@ -21255,7 +21255,7 @@ var BABYLON;
             for (index = 0; index < meshes.length; index++) {
                 if (meshes[index]) {
                     meshes[index].computeWorldMatrix(true);
-                    otherVertexData = BABYLON.VertexData.ExtractFromMesh(meshes[index], false, true);
+                    otherVertexData = BABYLON.VertexData.ExtractFromMesh(meshes[index], true);
                     otherVertexData.transform(meshes[index].getWorldMatrix());
                     if (vertexData) {
                         vertexData.merge(otherVertexData);
@@ -41907,16 +41907,17 @@ var BABYLON;
             _this._lastUpdate = BABYLON.Tools.Now;
             return _this;
         }
+        VideoTexture.prototype.__setTextureReady = function () {
+            this._texture.isReady = true;
+        };
         VideoTexture.prototype._createTexture = function () {
-            var _this = this;
             this._texture = this.getScene().getEngine().createDynamicTexture(this.video.videoWidth, this.video.videoHeight, this._generateMipMaps, this._samplingMode);
             if (this._autoLaunch) {
                 this._autoLaunch = false;
                 this.video.play();
             }
-            this.video.addEventListener("playing", function () {
-                _this._texture.isReady = true;
-            });
+            this._setTextureReady = this.__setTextureReady.bind(this);
+            this.video.addEventListener("playing", this._setTextureReady);
         };
         VideoTexture.prototype.update = function () {
             var now = BABYLON.Tools.Now;
@@ -41927,6 +41928,10 @@ var BABYLON;
             this.getScene().getEngine().updateVideoTexture(this._texture, this.video, this._invertY);
             return true;
         };
+        VideoTexture.prototype.dispose = function () {
+            _super.prototype.dispose.call(this);
+            this.video.removeEventListener("playing", this._setTextureReady);
+        };
         VideoTexture.CreateFromWebCam = function (scene, onReady, constraints) {
             var video = document.createElement("video");
             var constraintsDeviceId;
@@ -55884,9 +55889,9 @@ var BABYLON;
             //For now pointDepth will not be used and will be automatically calculated.
             //Future reference - try and find the best place to add a reference to the pointDepth variable.
             var arraySize = pointDepth || ~~(Math.sqrt(pos.length / 3) - 1);
-            var dim = Math.min(object.getBoundingInfo().boundingBox.extendSize.x, object.getBoundingInfo().boundingBox.extendSize.z);
+            var dim = Math.min(object.getBoundingInfo().boundingBox.extendSizeWorld.x, object.getBoundingInfo().boundingBox.extendSizeWorld.z);
             var elementSize = dim * 2 / arraySize;
-            var minY = object.getBoundingInfo().boundingBox.extendSize.y;
+            var minY = object.getBoundingInfo().boundingBox.extendSizeWorld.y;
             for (var i = 0; i < pos.length; i = i + 3) {
                 var x = Math.round((pos[i + 0]) / elementSize + arraySize / 2);
                 var z = Math.round(((pos[i + 2]) / elementSize - arraySize / 2) * -1);
@@ -55956,15 +55961,15 @@ var BABYLON;
                 //rotation is back
                 mesh.rotationQuaternion = rotationQuaternion;
                 //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
-                var p = BABYLON.Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
+                var p = BABYLON.Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSizeWorld.x, 0, -mesh.getBoundingInfo().boundingBox.extendSizeWorld.z);
                 mesh.setPivotMatrix(p);
                 mesh.computeWorldMatrix(true);
                 //calculate the translation
-                var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
-                this._tmpPosition.copyFromFloats(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
+                var translation = mesh.getBoundingInfo().boundingBox.centerWorld.subtract(center).subtract(mesh.position).negate();
+                this._tmpPosition.copyFromFloats(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSizeWorld.y, translation.z);
                 //add it inverted to the delta 
-                this._tmpDeltaPosition.copyFrom(mesh.getBoundingInfo().boundingBox.center.subtract(c));
-                this._tmpDeltaPosition.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
+                this._tmpDeltaPosition.copyFrom(mesh.getBoundingInfo().boundingBox.centerWorld.subtract(c));
+                this._tmpDeltaPosition.y += mesh.getBoundingInfo().boundingBox.extendSizeWorld.y;
                 mesh.setPivotMatrix(oldPivot);
                 mesh.computeWorldMatrix(true);
             }

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 2970 - 2967
dist/preview release/babylon.module.d.ts


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 34 - 34
dist/preview release/babylon.worker.js


+ 95 - 8
dist/preview release/gui/babylon.gui.d.ts

@@ -5,12 +5,16 @@ declare module BABYLON.GUI {
         private _renderObserver;
         private _resizeObserver;
         private _pointerMoveObserver;
+        private _pointerObserver;
         private _background;
-        private _rootContainer;
+        _rootContainer: Container;
         _lastControlOver: Control;
         _lastControlDown: Control;
         _shouldBlockPointer: boolean;
-        _toDispose: IDisposable;
+        _layerToDispose: Layer;
+        _linkedControls: Control[];
+        private _isFullscreen;
+        private _fullscreenViewport;
         background: string;
         constructor(name: string, width: number, height: number, scene: Scene, generateMipMaps?: boolean, samplingMode?: number);
         markAsDirty(): void;
@@ -18,10 +22,11 @@ declare module BABYLON.GUI {
         removeControl(control: Control): AdvancedDynamicTexture;
         dispose(): void;
         private _onResize();
-        private _checkUpdate();
+        private _checkUpdate(camera);
         private _render();
         private _doPicking(x, y, type);
         attach(): void;
+        attachToMesh(mesh: AbstractMesh): void;
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number): AdvancedDynamicTexture;
         static CreateFullscreenUI(name: string, foreground: boolean, scene: Scene): AdvancedDynamicTexture;
     }
@@ -50,6 +55,7 @@ declare module BABYLON.GUI {
         determinant(): number;
         invertToRef(result: Matrix2D): Matrix2D;
         multiplyToRef(other: Matrix2D, result: Matrix2D): Matrix2D;
+        transformCoordinates(x: number, y: number, result: Vector2): Matrix2D;
         static Identity(): Matrix2D;
         static TranslationToRef(x: number, y: number, result: Matrix2D): void;
         static ScalingToRef(x: number, y: number, result: Matrix2D): void;
@@ -58,6 +64,9 @@ declare module BABYLON.GUI {
         private static _TempPostTranslationMatrix;
         private static _TempRotationMatrix;
         private static _TempScalingMatrix;
+        private static _TempCompose0;
+        private static _TempCompose1;
+        private static _TempCompose2;
         static ComposeToRef(tx: number, ty: number, angle: number, scaleX: number, scaleY: number, parentMatrix: Matrix2D, result: Matrix2D): void;
     }
 }
@@ -85,6 +94,7 @@ declare module BABYLON.GUI {
 declare module BABYLON.GUI {
     class Control {
         name: string;
+        private _alpha;
         private _zIndex;
         _root: Container;
         _host: AdvancedDynamicTexture;
@@ -101,8 +111,8 @@ declare module BABYLON.GUI {
             descent: number;
         };
         private _color;
-        private _horizontalAlignment;
-        private _verticalAlignment;
+        protected _horizontalAlignment: number;
+        protected _verticalAlignment: number;
         private _isDirty;
         private _cachedParentMeasure;
         private _marginLeft;
@@ -118,11 +128,15 @@ declare module BABYLON.GUI {
         private _transformCenterY;
         private _transformMatrix;
         private _invertTransformMatrix;
+        private _transformedPosition;
         private _isMatrixDirty;
         private _cachedOffsetX;
         private _cachedOffsetY;
+        _linkedMesh: AbstractMesh;
         isHitTestVisible: boolean;
         isPointerBlocker: boolean;
+        linkOffsetX: number;
+        linkOffsetY: number;
         /**
         * An event triggered when the pointer move over the control.
         * @type {BABYLON.Observable}
@@ -148,6 +162,12 @@ declare module BABYLON.GUI {
         * @type {BABYLON.Observable}
         */
         onPointerEnterObservable: Observable<Control>;
+        /**
+        * An event triggered when the control is marked as dirty
+        * @type {BABYLON.Observable}
+        */
+        onDirtyObservable: Observable<Control>;
+        alpha: number;
         scaleX: number;
         scaleY: number;
         rotation: number;
@@ -168,14 +188,19 @@ declare module BABYLON.GUI {
         marginBottom: string;
         left: string;
         top: string;
+        readonly centerX: number;
+        readonly centerY: number;
         constructor(name: string);
+        linkWithMesh(mesh: AbstractMesh): void;
+        _moveToProjectedPosition(projectedPosition: Vector3): void;
+        _markMatrixAsDirty(): void;
         protected _markAsDirty(): void;
         _link(root: Container, host: AdvancedDynamicTexture): void;
         protected _transform(context: CanvasRenderingContext2D): void;
         protected _applyStates(context: CanvasRenderingContext2D): void;
         protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _clip(context: CanvasRenderingContext2D): void;
-        protected _measure(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        _measure(): void;
         protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
@@ -213,12 +238,16 @@ declare module BABYLON.GUI {
 declare module BABYLON.GUI {
     class Container extends Control {
         name: string;
-        private _children;
+        protected _children: Control[];
         protected _measureForChildren: Measure;
+        protected _background: string;
+        background: string;
         constructor(name: string);
+        containsControl(control: Control): boolean;
         addControl(control: Control): Container;
         removeControl(control: Control): Container;
         _reOrderControl(control: Control): void;
+        _markMatrixAsDirty(): void;
         protected _localDraw(context: CanvasRenderingContext2D): void;
         _link(root: Container, host: AdvancedDynamicTexture): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
@@ -230,10 +259,20 @@ declare module BABYLON.GUI {
 
 /// <reference path="../../../dist/preview release/babylon.d.ts" />
 declare module BABYLON.GUI {
+    class StackPanel extends Container {
+        name: string;
+        private _isVertical;
+        isVertical: boolean;
+        constructor(name: string);
+        protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+    }
+}
+
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON.GUI {
     class Rectangle extends Container {
         name: string;
         private _thickness;
-        private _background;
         private _cornerRadius;
         thickness: number;
         cornerRadius: number;
@@ -248,6 +287,50 @@ declare module BABYLON.GUI {
 
 /// <reference path="../../../dist/preview release/babylon.d.ts" />
 declare module BABYLON.GUI {
+    class Ellipse extends Container {
+        name: string;
+        private _thickness;
+        thickness: number;
+        constructor(name: string);
+        protected _localDraw(context: CanvasRenderingContext2D): void;
+        protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        protected _clipForChildren(context: CanvasRenderingContext2D): void;
+    }
+}
+
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare var DOMImage: new (width?: number, height?: number) => HTMLImageElement;
+declare module BABYLON.GUI {
+    class Line extends Control {
+        name: string;
+        private _lineWidth;
+        private _background;
+        private _x1;
+        private _y1;
+        private _x2;
+        private _y2;
+        private _dash;
+        private _connectedControl;
+        private _connectedControlDirtyObserver;
+        dash: Array<number>;
+        connectedControl: Control;
+        x1: number;
+        y1: number;
+        x2: number;
+        y2: number;
+        lineWidth: number;
+        horizontalAlignment: number;
+        verticalAlignment: number;
+        constructor(name: string);
+        _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        _measure(): void;
+        protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        _moveToProjectedPosition(projectedPosition: Vector3): void;
+    }
+}
+
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON.GUI {
     class TextBlock extends Control {
         name: string;
         private _text;
@@ -295,6 +378,10 @@ declare module BABYLON.GUI {
 declare module BABYLON.GUI {
     class Button extends Rectangle {
         name: string;
+        pointerEnterAnimation: () => void;
+        pointerOutAnimation: () => void;
+        pointerDownAnimation: () => void;
+        pointerUpAnimation: () => void;
         constructor(name: string);
         _processPicking(x: number, y: number, type: number): boolean;
         protected _onPointerEnter(): void;

+ 542 - 42
dist/preview release/gui/babylon.gui.js

@@ -23,7 +23,10 @@ var BABYLON;
                 var _this = _super.call(this, name, { width: width, height: height }, scene, generateMipMaps, samplingMode, BABYLON.Engine.TEXTUREFORMAT_RGBA) || this;
                 _this._isDirty = false;
                 _this._rootContainer = new GUI.Container("root");
-                _this._renderObserver = _this.getScene().onBeforeRenderObservable.add(function () { return _this._checkUpdate(); });
+                _this._linkedControls = new Array();
+                _this._isFullscreen = false;
+                _this._fullscreenViewport = new BABYLON.Viewport(0, 0, 1, 1);
+                _this._renderObserver = _this.getScene().onBeforeCameraRenderObservable.add(function (camera) { return _this._checkUpdate(camera); });
                 _this._rootContainer._link(null, _this);
                 _this.hasAlpha = true;
                 if (!width || !height) {
@@ -58,16 +61,20 @@ var BABYLON;
                 return this;
             };
             AdvancedDynamicTexture.prototype.dispose = function () {
-                this.getScene().onBeforeRenderObservable.remove(this._renderObserver);
+                this.getScene().onBeforeCameraRenderObservable.remove(this._renderObserver);
                 if (this._resizeObserver) {
                     this.getScene().getEngine().onResizeObservable.remove(this._resizeObserver);
                 }
                 if (this._pointerMoveObserver) {
                     this.getScene().onPrePointerObservable.remove(this._pointerMoveObserver);
                 }
-                if (this._toDispose) {
-                    this._toDispose.dispose();
-                    this._toDispose = null;
+                if (this._pointerObserver) {
+                    this.getScene().onPointerObservable.remove(this._pointerObserver);
+                }
+                if (this._layerToDispose) {
+                    this._layerToDispose.texture = null;
+                    this._layerToDispose.dispose();
+                    this._layerToDispose = null;
                 }
                 _super.prototype.dispose.call(this);
             };
@@ -82,7 +89,19 @@ var BABYLON;
                     this.markAsDirty();
                 }
             };
-            AdvancedDynamicTexture.prototype._checkUpdate = function () {
+            AdvancedDynamicTexture.prototype._checkUpdate = function (camera) {
+                if (this._isFullscreen && this._linkedControls.length) {
+                    var scene = this.getScene();
+                    var engine = scene.getEngine();
+                    var globalViewport = this._fullscreenViewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight());
+                    for (var _i = 0, _a = this._linkedControls; _i < _a.length; _i++) {
+                        var control = _a[_i];
+                        var mesh = control._linkedMesh;
+                        var position = mesh.getBoundingInfo().boundingSphere.center;
+                        var projectedPosition = BABYLON.Vector3.Project(position, mesh.getWorldMatrix(), scene.getTransformMatrix(), globalViewport);
+                        control._moveToProjectedPosition(projectedPosition);
+                    }
+                }
                 if (!this._isDirty && !this._rootContainer.isDirty) {
                     return;
                 }
@@ -104,6 +123,7 @@ var BABYLON;
                     context.restore();
                 }
                 // Render
+                context.font = "18px Arial";
                 var measure = new GUI.Measure(0, 0, renderWidth, renderHeight);
                 this._rootContainer._draw(measure, context);
             };
@@ -128,7 +148,21 @@ var BABYLON;
                     }
                     _this._shouldBlockPointer = false;
                     _this._doPicking(scene.pointerX, scene.pointerY, pi.type);
-                    pi.skipOnPointerObservable = _this._shouldBlockPointer;
+                    pi.skipOnPointerObservable = _this._shouldBlockPointer && pi.type !== BABYLON.PointerEventTypes.POINTERUP;
+                });
+            };
+            AdvancedDynamicTexture.prototype.attachToMesh = function (mesh) {
+                var _this = this;
+                var scene = this.getScene();
+                this._pointerObserver = scene.onPointerObservable.add(function (pi, state) {
+                    if (pi.type !== BABYLON.PointerEventTypes.POINTERUP && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
+                        return;
+                    }
+                    if (pi.pickInfo.hit && pi.pickInfo.pickedMesh === mesh) {
+                        var uv = pi.pickInfo.getTextureCoordinates();
+                        var size = _this.getSize();
+                        _this._doPicking(uv.x * size.width, (1.0 - uv.y) * size.height, pi.type);
+                    }
                 });
             };
             // Statics
@@ -138,9 +172,12 @@ var BABYLON;
                 var result = new AdvancedDynamicTexture(mesh.name + " AdvancedDynamicTexture", width, height, mesh.getScene(), true, BABYLON.Texture.TRILINEAR_SAMPLINGMODE);
                 var material = new BABYLON.StandardMaterial("AdvancedDynamicTextureMaterial", mesh.getScene());
                 material.backFaceCulling = false;
+                material.diffuseColor = BABYLON.Color3.Black();
+                material.specularColor = BABYLON.Color3.Black();
                 material.emissiveTexture = result;
                 material.opacityTexture = result;
                 mesh.material = material;
+                result.attachToMesh(mesh);
                 return result;
             };
             AdvancedDynamicTexture.CreateFullscreenUI = function (name, foreground, scene) {
@@ -149,7 +186,8 @@ var BABYLON;
                 // Display
                 var layer = new BABYLON.Layer(name + "_layer", null, scene, !foreground);
                 layer.texture = result;
-                result._toDispose = layer;
+                result._layerToDispose = layer;
+                result._isFullscreen = true;
                 // Attach
                 result.attach();
                 return result;
@@ -271,6 +309,11 @@ var BABYLON;
                 result.m[5] = l4 * r1 + l5 * r3 + r5;
                 return this;
             };
+            Matrix2D.prototype.transformCoordinates = function (x, y, result) {
+                result.x = x * this.m[0] + y * this.m[2] + this.m[4];
+                result.y = x * this.m[1] + y * this.m[3] + this.m[5];
+                return this;
+            };
             // Statics
             Matrix2D.Identity = function () {
                 return new Matrix2D(1, 0, 0, 1, 0, 0);
@@ -291,6 +334,15 @@ var BABYLON;
                 Matrix2D.ScalingToRef(scaleX, scaleY, Matrix2D._TempScalingMatrix);
                 Matrix2D.RotationToRef(angle, Matrix2D._TempRotationMatrix);
                 Matrix2D.TranslationToRef(-tx, -ty, Matrix2D._TempPostTranslationMatrix);
+                Matrix2D._TempPreTranslationMatrix.multiplyToRef(Matrix2D._TempScalingMatrix, Matrix2D._TempCompose0);
+                Matrix2D._TempCompose0.multiplyToRef(Matrix2D._TempRotationMatrix, Matrix2D._TempCompose1);
+                if (parentMatrix) {
+                    Matrix2D._TempCompose1.multiplyToRef(Matrix2D._TempPostTranslationMatrix, Matrix2D._TempCompose2);
+                    Matrix2D._TempCompose2.multiplyToRef(parentMatrix, result);
+                }
+                else {
+                    Matrix2D._TempCompose1.multiplyToRef(Matrix2D._TempPostTranslationMatrix, result);
+                }
             };
             return Matrix2D;
         }());
@@ -298,6 +350,9 @@ var BABYLON;
         Matrix2D._TempPostTranslationMatrix = Matrix2D.Identity();
         Matrix2D._TempRotationMatrix = Matrix2D.Identity();
         Matrix2D._TempScalingMatrix = Matrix2D.Identity();
+        Matrix2D._TempCompose0 = Matrix2D.Identity();
+        Matrix2D._TempCompose1 = Matrix2D.Identity();
+        Matrix2D._TempCompose2 = Matrix2D.Identity();
         GUI.Matrix2D = Matrix2D;
     })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
 })(BABYLON || (BABYLON = {}));
@@ -406,9 +461,10 @@ var BABYLON;
             // Functions
             function Control(name) {
                 this.name = name;
+                this._alpha = 1;
                 this._zIndex = 0;
                 this._currentMeasure = GUI.Measure.Empty();
-                this._fontSize = 18;
+                this._fontFamily = "Arial";
                 this._width = new GUI.ValueAndUnit(1, GUI.ValueAndUnit.UNITMODE_PERCENTAGE, false);
                 this._height = new GUI.ValueAndUnit(1, GUI.ValueAndUnit.UNITMODE_PERCENTAGE, false);
                 this._horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
@@ -428,9 +484,12 @@ var BABYLON;
                 this._transformCenterY = 0.5;
                 this._transformMatrix = GUI.Matrix2D.Identity();
                 this._invertTransformMatrix = GUI.Matrix2D.Identity();
+                this._transformedPosition = BABYLON.Vector2.Zero();
                 this._isMatrixDirty = true;
                 this.isHitTestVisible = true;
                 this.isPointerBlocker = false;
+                this.linkOffsetX = 0;
+                this.linkOffsetY = 0;
                 // Properties
                 /**
                 * An event triggered when the pointer move over the control.
@@ -457,8 +516,26 @@ var BABYLON;
                 * @type {BABYLON.Observable}
                 */
                 this.onPointerEnterObservable = new BABYLON.Observable();
-                this.fontFamily = "Arial";
+                /**
+                * An event triggered when the control is marked as dirty
+                * @type {BABYLON.Observable}
+                */
+                this.onDirtyObservable = new BABYLON.Observable();
             }
+            Object.defineProperty(Control.prototype, "alpha", {
+                get: function () {
+                    return this._alpha;
+                },
+                set: function (value) {
+                    if (this._alpha === value) {
+                        return;
+                    }
+                    this._alpha = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
             Object.defineProperty(Control.prototype, "scaleX", {
                 get: function () {
                     return this._scaleX;
@@ -469,7 +546,7 @@ var BABYLON;
                     }
                     this._scaleX = value;
                     this._markAsDirty();
-                    this._isMatrixDirty = true;
+                    this._markMatrixAsDirty();
                 },
                 enumerable: true,
                 configurable: true
@@ -484,7 +561,7 @@ var BABYLON;
                     }
                     this._scaleY = value;
                     this._markAsDirty();
-                    this._isMatrixDirty = true;
+                    this._markMatrixAsDirty();
                 },
                 enumerable: true,
                 configurable: true
@@ -499,7 +576,7 @@ var BABYLON;
                     }
                     this._rotation = value;
                     this._markAsDirty();
-                    this._isMatrixDirty = true;
+                    this._markMatrixAsDirty();
                 },
                 enumerable: true,
                 configurable: true
@@ -514,7 +591,7 @@ var BABYLON;
                     }
                     this._transformCenterY = value;
                     this._markAsDirty();
-                    this._isMatrixDirty = true;
+                    this._markMatrixAsDirty();
                 },
                 enumerable: true,
                 configurable: true
@@ -529,7 +606,7 @@ var BABYLON;
                     }
                     this._transformCenterX = value;
                     this._markAsDirty();
-                    this._isMatrixDirty = true;
+                    this._markMatrixAsDirty();
                 },
                 enumerable: true,
                 configurable: true
@@ -643,7 +720,9 @@ var BABYLON;
                         return;
                     }
                     this._zIndex = value;
-                    this._root._reOrderControl(this);
+                    if (this._root) {
+                        this._root._reOrderControl(this);
+                    }
                 },
                 enumerable: true,
                 configurable: true
@@ -727,6 +806,41 @@ var BABYLON;
                 enumerable: true,
                 configurable: true
             });
+            Object.defineProperty(Control.prototype, "centerX", {
+                get: function () {
+                    return this._currentMeasure.left + this._currentMeasure.width / 2;
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Control.prototype, "centerY", {
+                get: function () {
+                    return this._currentMeasure.top + this._currentMeasure.height / 2;
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Control.prototype.linkWithMesh = function (mesh) {
+                if (!this._host || this._root !== this._host._rootContainer) {
+                    BABYLON.Tools.Error("Cannot link a control to a mesh if the control is not at root level");
+                    return;
+                }
+                if (this._host._linkedControls.indexOf(this) !== -1) {
+                    return;
+                }
+                this.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
+                this.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
+                this._linkedMesh = mesh;
+                this._host._linkedControls.push(this);
+            };
+            Control.prototype._moveToProjectedPosition = function (projectedPosition) {
+                this.left = ((projectedPosition.x + this.linkOffsetX) - this._currentMeasure.width / 2) + "px";
+                this.top = ((projectedPosition.y + this.linkOffsetY) - this._currentMeasure.height / 2) + "px";
+            };
+            Control.prototype._markMatrixAsDirty = function () {
+                this._isMatrixDirty = true;
+                this._markAsDirty();
+            };
             Control.prototype._markAsDirty = function () {
                 this._isDirty = true;
                 if (!this._host) {
@@ -739,25 +853,25 @@ var BABYLON;
                 this._host = host;
             };
             Control.prototype._transform = function (context) {
-                if (this._scaleX === 1 && this._scaleY === 1 && this._rotation === 0) {
+                if (!this._isMatrixDirty && this._scaleX === 1 && this._scaleY === 1 && this._rotation === 0) {
                     return;
                 }
-                // preTranslate
+                // postTranslate
                 var offsetX = this._currentMeasure.width * this._transformCenterX + this._currentMeasure.left;
                 var offsetY = this._currentMeasure.height * this._transformCenterY + this._currentMeasure.top;
                 context.translate(offsetX, offsetY);
-                // scale
-                context.scale(this._scaleX, this._scaleY);
                 // rotate
                 context.rotate(this._rotation);
-                // postTranslate
+                // scale
+                context.scale(this._scaleX, this._scaleY);
+                // preTranslate
                 context.translate(-offsetX, -offsetY);
                 // Need to update matrices?
                 if (this._isMatrixDirty || this._cachedOffsetX !== offsetX || this._cachedOffsetY !== offsetY) {
                     this._cachedOffsetX = offsetX;
                     this._cachedOffsetY = offsetY;
                     this._isMatrixDirty = false;
-                    GUI.Matrix2D.ComposeToRef(offsetX, offsetY, this._rotation, this._scaleX, this._scaleY, this._root ? this._root._transformMatrix : null, this._transformMatrix);
+                    GUI.Matrix2D.ComposeToRef(-offsetX, -offsetY, this._rotation, this._scaleX, this._scaleY, this._root ? this._root._transformMatrix : null, this._transformMatrix);
                     this._transformMatrix.invertToRef(this._invertTransformMatrix);
                 }
             };
@@ -768,11 +882,13 @@ var BABYLON;
                 if (this._color) {
                     context.fillStyle = this._color;
                 }
+                context.globalAlpha = this._alpha;
             };
             Control.prototype._processMeasures = function (parentMeasure, context) {
                 if (this._isDirty || !this._cachedParentMeasure.isEqualsTo(parentMeasure)) {
+                    this._isDirty = false;
                     this._currentMeasure.copyFrom(parentMeasure);
-                    this._measure(parentMeasure, context);
+                    this._measure();
                     this._computeAlignment(parentMeasure, context);
                     // Convert to int values
                     this._currentMeasure.left = this._currentMeasure.left | 0;
@@ -781,8 +897,10 @@ var BABYLON;
                     this._currentMeasure.height = this._currentMeasure.height | 0;
                     // Let children add more features
                     this._additionalProcessing(parentMeasure, context);
-                    this._isDirty = false;
                     this._cachedParentMeasure.copyFrom(parentMeasure);
+                    if (this.onDirtyObservable.hasObservers()) {
+                        this.onDirtyObservable.notifyObservers(this);
+                    }
                 }
                 // Transform
                 this._transform(context);
@@ -794,7 +912,7 @@ var BABYLON;
                 context.beginPath();
                 context.rect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
             };
-            Control.prototype._measure = function (parentMeasure, context) {
+            Control.prototype._measure = function () {
                 // Width / Height
                 if (this._width.isPixel) {
                     this._currentMeasure.width = this._width.value;
@@ -890,8 +1008,9 @@ var BABYLON;
             };
             Control.prototype.contains = function (x, y) {
                 // Invert transform
-                if (this._scaleX !== 1 || this._scaleY !== 1 || this.rotation !== 0) {
-                }
+                this._invertTransformMatrix.transformCoordinates(x, y, this._transformedPosition);
+                x = this._transformedPosition.x;
+                y = this._transformedPosition.y;
                 // Check
                 if (x < this._currentMeasure.left) {
                     return false;
@@ -911,6 +1030,9 @@ var BABYLON;
                 return true;
             };
             Control.prototype._processPicking = function (x, y, type) {
+                if (!this.isHitTestVisible) {
+                    return false;
+                }
                 if (!this.contains(x, y)) {
                     return false;
                 }
@@ -943,9 +1065,6 @@ var BABYLON;
                 }
             };
             Control.prototype._processObservables = function (type) {
-                if (!this.isHitTestVisible) {
-                    return false;
-                }
                 if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
                     this._onPointerMove();
                     var previousControlOver = this._host._lastControlOver;
@@ -964,11 +1083,10 @@ var BABYLON;
                     return true;
                 }
                 if (type === BABYLON.PointerEventTypes.POINTERUP) {
-                    this._onPointerUp();
-                    if (this._host._lastControlDown !== this) {
+                    if (this._host._lastControlDown) {
                         this._host._lastControlDown._onPointerUp();
-                        this._host._lastControlDown = null;
                     }
+                    this._host._lastControlDown = null;
                     return true;
                 }
                 return false;
@@ -1094,6 +1212,23 @@ var BABYLON;
                 _this._measureForChildren = GUI.Measure.Empty();
                 return _this;
             }
+            Object.defineProperty(Container.prototype, "background", {
+                get: function () {
+                    return this._background;
+                },
+                set: function (value) {
+                    if (this._background === value) {
+                        return;
+                    }
+                    this._background = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Container.prototype.containsControl = function (control) {
+                return this._children.indexOf(control) !== -1;
+            };
             Container.prototype.addControl = function (control) {
                 var index = this._children.indexOf(control);
                 if (index !== -1) {
@@ -1123,8 +1258,17 @@ var BABYLON;
                 this._children.push(control);
                 this._markAsDirty();
             };
+            Container.prototype._markMatrixAsDirty = function () {
+                _super.prototype._markMatrixAsDirty.call(this);
+                for (var index = 0; index < this._children.length; index++) {
+                    this._children[index]._markMatrixAsDirty();
+                }
+            };
             Container.prototype._localDraw = function (context) {
-                // Implemented by child to be injected inside main draw
+                if (this._background) {
+                    context.fillStyle = this._background;
+                    context.fillRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
+                }
             };
             Container.prototype._link = function (root, host) {
                 _super.prototype._link.call(this, root, host);
@@ -1188,6 +1332,76 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
+        var StackPanel = (function (_super) {
+            __extends(StackPanel, _super);
+            function StackPanel(name) {
+                var _this = _super.call(this, name) || this;
+                _this.name = name;
+                _this._isVertical = true;
+                return _this;
+            }
+            Object.defineProperty(StackPanel.prototype, "isVertical", {
+                get: function () {
+                    return this._isVertical;
+                },
+                set: function (value) {
+                    if (this._isVertical === value) {
+                        return;
+                    }
+                    this._isVertical = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            StackPanel.prototype._additionalProcessing = function (parentMeasure, context) {
+                var stack = 0;
+                for (var _i = 0, _a = this._children; _i < _a.length; _i++) {
+                    var child = _a[_i];
+                    child._currentMeasure.copyFrom(parentMeasure);
+                    child._measure();
+                    if (this._isVertical) {
+                        child.top = stack + "px";
+                        stack += child._currentMeasure.height;
+                        child.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
+                    }
+                    else {
+                        child.left = stack + "px";
+                        stack += child._currentMeasure.width;
+                        child.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
+                    }
+                }
+                if (this._isVertical) {
+                    this.height = stack + "px";
+                }
+                else {
+                    this.width = stack + "px";
+                }
+                _super.prototype._additionalProcessing.call(this, parentMeasure, context);
+            };
+            return StackPanel;
+        }(GUI.Container));
+        GUI.StackPanel = StackPanel;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=stackPanel.js.map
+
+/// <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) {
@@ -1324,11 +1538,279 @@ var BABYLON;
 (function (BABYLON) {
     var GUI;
     (function (GUI) {
+        var Ellipse = (function (_super) {
+            __extends(Ellipse, _super);
+            function Ellipse(name) {
+                var _this = _super.call(this, name) || this;
+                _this.name = name;
+                _this._thickness = 1;
+                return _this;
+            }
+            Object.defineProperty(Ellipse.prototype, "thickness", {
+                get: function () {
+                    return this._thickness;
+                },
+                set: function (value) {
+                    if (this._thickness === value) {
+                        return;
+                    }
+                    this._thickness = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Ellipse.prototype._localDraw = function (context) {
+                context.save();
+                context.beginPath();
+                context.ellipse(this._currentMeasure.left + this._currentMeasure.width / 2, this._currentMeasure.top + this._currentMeasure.height / 2, this._currentMeasure.width / 2 - this._thickness / 2, this._currentMeasure.height / 2 - this._thickness / 2, 0, 0, 2 * Math.PI);
+                context.closePath();
+                if (this._background) {
+                    context.fillStyle = this._background;
+                    context.fill();
+                }
+                if (this._thickness) {
+                    if (this.color) {
+                        context.strokeStyle = this.color;
+                    }
+                    context.lineWidth = this._thickness;
+                    context.stroke();
+                }
+                context.restore();
+            };
+            Ellipse.prototype._additionalProcessing = function (parentMeasure, context) {
+                _super.prototype._additionalProcessing.call(this, parentMeasure, context);
+                this._measureForChildren.width -= 2 * this._thickness;
+                this._measureForChildren.height -= 2 * this._thickness;
+                this._measureForChildren.left += this._thickness;
+                this._measureForChildren.top += this._thickness;
+            };
+            Ellipse.prototype._clipForChildren = function (context) {
+                context.beginPath();
+                context.ellipse(this._currentMeasure.left + this._currentMeasure.width / 2, this._currentMeasure.top + this._currentMeasure.height / 2, this._currentMeasure.width / 2, this._currentMeasure.height / 2, 0, 0, 2 * Math.PI);
+                context.clip();
+            };
+            return Ellipse;
+        }(GUI.Container));
+        GUI.Ellipse = Ellipse;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=ellipse.js.map
+
+/// <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 DOMImage = Image;
+var BABYLON;
+(function (BABYLON) {
+    var GUI;
+    (function (GUI) {
+        var Line = (function (_super) {
+            __extends(Line, _super);
+            function Line(name) {
+                var _this = _super.call(this, name) || this;
+                _this.name = name;
+                _this._lineWidth = 1;
+                _this._x1 = 0;
+                _this._y1 = 0;
+                _this._x2 = 0;
+                _this._y2 = 0;
+                _this._dash = new Array();
+                _this.isHitTestVisible = false;
+                _this._horizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
+                _this._verticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_TOP;
+                return _this;
+            }
+            Object.defineProperty(Line.prototype, "dash", {
+                get: function () {
+                    return this._dash;
+                },
+                set: function (value) {
+                    if (this._dash === value) {
+                        return;
+                    }
+                    this._dash = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Line.prototype, "connectedControl", {
+                get: function () {
+                    return this._connectedControl;
+                },
+                set: function (value) {
+                    var _this = this;
+                    if (this._connectedControl === value) {
+                        return;
+                    }
+                    if (this._connectedControlDirtyObserver && this._connectedControl) {
+                        this._connectedControl.onDirtyObservable.remove(this._connectedControlDirtyObserver);
+                        this._connectedControlDirtyObserver = null;
+                    }
+                    if (value) {
+                        this._connectedControlDirtyObserver = value.onDirtyObservable.add(function () { return _this._markAsDirty(); });
+                    }
+                    this._connectedControl = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Line.prototype, "x1", {
+                get: function () {
+                    return this._x1;
+                },
+                set: function (value) {
+                    if (this._x1 === value) {
+                        return;
+                    }
+                    this._x1 = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Line.prototype, "y1", {
+                get: function () {
+                    return this._y1;
+                },
+                set: function (value) {
+                    if (this._y1 === value) {
+                        return;
+                    }
+                    this._y1 = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Line.prototype, "x2", {
+                get: function () {
+                    if (this._connectedControl) {
+                        return this._connectedControl.centerX + this._x2;
+                    }
+                    return this._x2;
+                },
+                set: function (value) {
+                    if (this._x2 === value) {
+                        return;
+                    }
+                    this._x2 = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Line.prototype, "y2", {
+                get: function () {
+                    if (this._connectedControl) {
+                        return this._connectedControl.centerY + this._y2;
+                    }
+                    return this._y2;
+                },
+                set: function (value) {
+                    if (this._y2 === value) {
+                        return;
+                    }
+                    this._y2 = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Line.prototype, "lineWidth", {
+                get: function () {
+                    return this._lineWidth;
+                },
+                set: function (value) {
+                    if (this._lineWidth === value) {
+                        return;
+                    }
+                    this._lineWidth = value;
+                    this._markAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Line.prototype, "horizontalAlignment", {
+                set: function (value) {
+                    return;
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Object.defineProperty(Line.prototype, "verticalAlignment", {
+                set: function (value) {
+                    return;
+                },
+                enumerable: true,
+                configurable: true
+            });
+            Line.prototype._draw = function (parentMeasure, context) {
+                context.save();
+                this._applyStates(context);
+                _super.prototype._processMeasures.call(this, parentMeasure, context);
+                context.strokeStyle = this.color;
+                context.lineWidth = this._lineWidth;
+                context.setLineDash(this._dash);
+                context.beginPath();
+                context.moveTo(this._x1, this._y1);
+                context.lineTo(this.x2, this.y2);
+                context.stroke();
+                context.restore();
+            };
+            Line.prototype._measure = function () {
+                // Width / Height
+                this._currentMeasure.width = Math.abs(this._x1 - this.x2) + this._lineWidth;
+                this._currentMeasure.height = Math.abs(this._y1 - this.y2) + this._lineWidth;
+            };
+            Line.prototype._computeAlignment = function (parentMeasure, context) {
+                this._currentMeasure.left = Math.min(this._x1, this.x2) - this._lineWidth / 2;
+                this._currentMeasure.top = Math.min(this._y1, this.y2) - this._lineWidth / 2;
+            };
+            Line.prototype._moveToProjectedPosition = function (projectedPosition) {
+                this.x1 = projectedPosition.x + this.linkOffsetX;
+                this.y1 = projectedPosition.y + this.linkOffsetY;
+            };
+            return Line;
+        }(GUI.Control));
+        GUI.Line = Line;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=line.js.map
+
+/// <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 = "";
                 _this._textWrapping = false;
                 _this._textHorizontalAlignment = GUI.Control.HORIZONTAL_ALIGNMENT_CENTER;
                 _this._textVerticalAlignment = GUI.Control.VERTICAL_ALIGNMENT_CENTER;
@@ -1601,6 +2083,20 @@ var BABYLON;
                 _this.name = name;
                 _this.thickness = 1;
                 _this.isPointerBlocker = true;
+                _this.pointerEnterAnimation = function () {
+                    _this.alpha -= 0.1;
+                };
+                _this.pointerOutAnimation = function () {
+                    _this.alpha += 0.1;
+                };
+                _this.pointerDownAnimation = function () {
+                    _this.scaleX -= 0.05;
+                    _this.scaleY -= 0.05;
+                };
+                _this.pointerUpAnimation = function () {
+                    _this.scaleX += 0.05;
+                    _this.scaleY += 0.05;
+                };
                 return _this;
             }
             // While being a container, the button behaves like a control.
@@ -1612,23 +2108,27 @@ var BABYLON;
                 return true;
             };
             Button.prototype._onPointerEnter = function () {
-                this.scaleX += 0.01;
-                this.scaleY += 0.01;
+                if (this.pointerEnterAnimation) {
+                    this.pointerEnterAnimation();
+                }
                 _super.prototype._onPointerEnter.call(this);
             };
             Button.prototype._onPointerOut = function () {
-                this.scaleX -= 0.01;
-                this.scaleY -= 0.01;
+                if (this.pointerOutAnimation) {
+                    this.pointerOutAnimation();
+                }
                 _super.prototype._onPointerOut.call(this);
             };
             Button.prototype._onPointerDown = function () {
-                this.scaleX -= 0.05;
-                this.scaleY -= 0.05;
+                if (this.pointerDownAnimation) {
+                    this.pointerDownAnimation();
+                }
                 _super.prototype._onPointerDown.call(this);
             };
             Button.prototype._onPointerUp = function () {
-                this.scaleX += 0.05;
-                this.scaleY += 0.05;
+                if (this.pointerUpAnimation) {
+                    this.pointerUpAnimation();
+                }
                 _super.prototype._onPointerUp.call(this);
             };
             // Statics

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 2 - 1
dist/preview release/gui/babylon.gui.min.js


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

@@ -6,6 +6,7 @@
  - WebGL2 context support. WebGL2 is now used instead of WebGL 1 when available. [More info here](http://doc.babylonjs.com/overviews/webgl2) ([deltakosh](https://github.com/deltakosh))
  - Complete WebVR 1.1 support including controllers for HTC Vive and Occulus. [More info here](http://doc.babylonjs.com/overviews/webvr_camera) ([raanan](https://github.com/raananw))
  - Support for Morph Targets. [More info here](http://doc.babylonjs.com/tutorials/how_to_use_morphtargets) ([deltakosh](https://github.com/deltakosh))
+ - New Babylon.GUI to create user interface (comaptible with WebVR). [More info here](http://doc.babylonjs.com/overviews/Gui) ([deltakosh](https://github.com/deltakosh))
  - Added support for Exponential Shadow maps to replace Variance Shadow maps. [more info here](http://www.babylonjs-playground.com/debug.html#1CXNXC#3) - [Demo](http://www.babylonjs.com/Demos/AdvancedShadows/) - [Demo](http://www.babylonjs-playground.com/#1CXNXC#4) ([deltakosh](https://github.com/deltakosh))
  - Support for [Vertex Array Objects](https://www.opengl.org/registry/specs/ARB/vertex_array_object.txt) ([deltakosh](https://github.com/deltakosh))
  - Support for [Uniform Buffer Objects](https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.16) ([CraigFeldspar](https://github.com/CraigFeldspar))
@@ -19,7 +20,7 @@
  - All deprecated functions and properties were removed ([deltakosh](https://github.com/deltakosh))
  - New build system based on workloads. [More info here](http://doc.babylonjs.com/generals/how_to_start#custom-builds) ([deltakosh](https://github.com/deltakosh))
  - New `Cell Shading` material added into `Materials Library` [Demo](http://www.babylonjs.com/Demos/CellShading/) - ([Julien Moreau-Mathis](https://github.com/julien-moreau))
-
+ 
 ### Updates
 - Added `FIXED_EQUIRECTANGULAR_MIRRORED_MODE` mode for reflection texture. [Demo here](http://www.babylonjs-playground.com/#11GAIH#22) ([deltakosh](https://github.com/deltakosh))
 - Introduced `boundingBox.centerWorld` and `boundingBox.extendSizeWorld` ([deltakosh](https://github.com/deltakosh))

+ 3 - 14
gui/readme.md

@@ -1,16 +1,5 @@
 # Babylon.js GUI library
+The Babylon.js GUI library is an extension you can use to generate interactive user interface.
+It is build on top of the DynamicTexture.
 
-The Babylon.js GUI library is an extension you can use to generate interactive user interface on top of the DynamicTexture.
-
-## How to use it
-
-- unit mode (Default to percentage)
-
-## Features
-* Flixible containers and controls
-* Horizontal and vertical alignment
-* Proportional or pixel constant size modes
-* Text wrapping
-
-==> ideas
-* pick on mesh
+Documentation: http://doc.babylonjs.com/overviews/gui

+ 29 - 17
gui/src/advancedDynamicTexture.ts

@@ -6,14 +6,16 @@ module BABYLON.GUI {
         private _renderObserver: Observer<Camera>;
         private _resizeObserver: Observer<Engine>;
         private _pointerMoveObserver: Observer<PointerInfoPre>;
+        private _pointerObserver: Observer<PointerInfo>;
         private _background: string;
         public _rootContainer = new Container("root");
         public _lastControlOver: Control;
         public _lastControlDown: Control;
         public _shouldBlockPointer: boolean;
-        public _toDispose: IDisposable;
+        public _layerToDispose: Layer;
         public _linkedControls = new Array<Control>();
         private _isFullscreen = false;
+        private _fullscreenViewport = new Viewport(0, 0, 1, 1);
 
         public get background(): string {
             return this._background;
@@ -69,9 +71,14 @@ module BABYLON.GUI {
                 this.getScene().onPrePointerObservable.remove(this._pointerMoveObserver);
             }
 
-            if (this._toDispose) {
-                this._toDispose.dispose();
-                this._toDispose = null;
+            if (this._pointerObserver) {
+                this.getScene().onPointerObservable.remove(this._pointerObserver);
+            }
+
+            if (this._layerToDispose) {
+                this._layerToDispose.texture = null;
+                this._layerToDispose.dispose();
+                this._layerToDispose = null;
             }
 
             super.dispose();
@@ -94,8 +101,7 @@ module BABYLON.GUI {
             if (this._isFullscreen && this._linkedControls.length) {
                 var scene = this.getScene();
                 var engine = scene.getEngine();
-                var viewport = camera.viewport;
-                var globalViewport = viewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight());
+                var globalViewport = this._fullscreenViewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight());
 
                 for (var control of this._linkedControls) {
                     var mesh = control._linkedMesh;
@@ -166,6 +172,21 @@ module BABYLON.GUI {
             });
         }
 
+        public attachToMesh(mesh: AbstractMesh): void {
+            var scene = this.getScene();
+            this._pointerObserver = scene.onPointerObservable.add((pi, state) => {
+                if (pi.type !== BABYLON.PointerEventTypes.POINTERUP && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
+                    return;
+                }
+
+                if (pi.pickInfo.hit && pi.pickInfo.pickedMesh === mesh) {
+                    var uv = pi.pickInfo.getTextureCoordinates();
+                    var size = this.getSize();
+                    this._doPicking(uv.x * size.width, (1.0 - uv.y) * size.height, pi.type);
+                }
+            });
+        }
+
         // Statics
         public static CreateForMesh(mesh: AbstractMesh, width = 1024, height = 1024): AdvancedDynamicTexture {
             var result = new AdvancedDynamicTexture(mesh.name + " AdvancedDynamicTexture", width, height, mesh.getScene(), true, Texture.TRILINEAR_SAMPLINGMODE);
@@ -179,16 +200,7 @@ module BABYLON.GUI {
 
             mesh.material = material;
 
-            mesh.getScene().onPointerObservable.add(function(pi, state) {
-                if (pi.type !== BABYLON.PointerEventTypes.POINTERUP && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
-                    return;
-                }
-
-                if (pi.pickInfo.hit && pi.pickInfo.pickedMesh === mesh) {
-                    var uv = pi.pickInfo.getTextureCoordinates();
-                    result._doPicking(uv.x * width, (1.0 - uv.y) * height, pi.type);
-                }
-            });
+            result.attachToMesh(mesh);
 
             return result;
         }
@@ -200,7 +212,7 @@ module BABYLON.GUI {
             var layer = new BABYLON.Layer(name + "_layer", null, scene, !foreground);
             layer.texture = result;
 
-            result._toDispose = layer;
+            result._layerToDispose = layer;
             result._isFullscreen = true;
 
             // Attach

+ 36 - 7
gui/src/controls/button.ts

@@ -1,11 +1,34 @@
 /// <reference path="../../../dist/preview release/babylon.d.ts"/>
 
 module BABYLON.GUI {
-    export class Button extends Rectangle {      
+    export class Button extends Rectangle {    
+        public pointerEnterAnimation: () => void;
+        public pointerOutAnimation: () => void;
+        public pointerDownAnimation: () => void;
+        public pointerUpAnimation: () => void;
+
         constructor(public name: string) {
             super(name);
             this.thickness = 1;
             this.isPointerBlocker = true;
+
+            this.pointerEnterAnimation = () => {
+                this.alpha -= 0.1;
+            }
+
+            this.pointerOutAnimation = () => {
+                this.alpha += 0.1;
+            }    
+
+            this.pointerDownAnimation = () => {
+                this.scaleX -= 0.05;
+                this.scaleY -= 0.05;
+            }
+
+            this.pointerUpAnimation = () => {
+                this.scaleX += 0.05;
+                this.scaleY += 0.05;
+            }                      
         }
 
         // While being a container, the button behaves like a control.
@@ -20,25 +43,31 @@ module BABYLON.GUI {
         }
 
         protected _onPointerEnter(): void {
-            this.alpha -= 0.2;
+            if (this.pointerEnterAnimation) {
+                this.pointerEnterAnimation();
+            }
             super._onPointerEnter();
         }
 
         protected _onPointerOut(): void {
-            this.alpha += 0.2;
+            if (this.pointerOutAnimation) {
+                this.pointerOutAnimation();
+            }
             super._onPointerOut();
         }
 
         protected _onPointerDown(): void {
-            this.scaleX -= 0.05;
-            this.scaleY -= 0.05;
+            if (this.pointerDownAnimation) {
+                this.pointerDownAnimation();
+            }
 
             super._onPointerDown();
         }
 
         protected _onPointerUp (): void {
-            this.scaleX += 0.05;
-            this.scaleY += 0.05;
+            if (this.pointerUpAnimation) {
+                this.pointerUpAnimation();
+            }
 
             super._onPointerUp();
         }        

+ 19 - 2
gui/src/controls/container.ts

@@ -3,7 +3,21 @@
 module BABYLON.GUI {
     export class Container extends Control {
         protected _children = new Array<Control>();
-        protected _measureForChildren = Measure.Empty();     
+        protected _measureForChildren = Measure.Empty();  
+        protected _background: string;   
+
+        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);
@@ -62,7 +76,10 @@ module BABYLON.GUI {
         }
 
         protected _localDraw(context: CanvasRenderingContext2D): void {
-            // Implemented by child to be injected inside main draw
+            if (this._background) {
+                context.fillStyle = this._background;
+                context.fillRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
+            }
         }
 
         public _link(root: Container, host: AdvancedDynamicTexture): void {

+ 6 - 5
gui/src/controls/control.ts

@@ -374,6 +374,7 @@ module BABYLON.GUI {
 
         public _markMatrixAsDirty(): void {
             this._isMatrixDirty = true;
+            this._markAsDirty();
         }
 
         protected _markAsDirty(): void {            
@@ -395,18 +396,18 @@ module BABYLON.GUI {
                 return;
             }
 
-            // preTranslate
+            // postTranslate
             var offsetX = this._currentMeasure.width * this._transformCenterX + this._currentMeasure.left;
             var offsetY = this._currentMeasure.height * this._transformCenterY + this._currentMeasure.top;
             context.translate(offsetX, offsetY);
 
-            // scale
-            context.scale(this._scaleX, this._scaleY);
-
             // rotate
             context.rotate(this._rotation);
 
-            // postTranslate
+            // scale
+            context.scale(this._scaleX, this._scaleY);
+
+            // preTranslate
             context.translate(-offsetX, -offsetY);    
 
             // Need to update matrices?

+ 2 - 16
gui/src/controls/ellipse.ts

@@ -2,8 +2,7 @@
 
 module BABYLON.GUI {
     export class Ellipse extends Container {
-        private _thickness = 1;
-        private _background: string;          
+        private _thickness = 1;       
         
         public get thickness(): number {
             return this._thickness;
@@ -16,20 +15,7 @@ module BABYLON.GUI {
 
             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);

+ 16 - 6
gui/src/controls/line.ts

@@ -12,6 +12,7 @@ module BABYLON.GUI {
         private _y2 = 0;
         private _dash = new Array<number>();
         private _connectedControl: Control;
+        private _connectedControlDirtyObserver: Observer<Control>;
 
         public get dash(): Array<number> {
             return this._dash;
@@ -35,6 +36,15 @@ module BABYLON.GUI {
                 return;
             }
 
+            if (this._connectedControlDirtyObserver && this._connectedControl) {
+                this._connectedControl.onDirtyObservable.remove(this._connectedControlDirtyObserver);
+                this._connectedControlDirtyObserver = null;
+            }
+
+            if (value) {
+                this._connectedControlDirtyObserver = value.onDirtyObservable.add(() => this._markAsDirty());
+            }            
+
             this._connectedControl = value;
             this._markAsDirty();
         }              
@@ -67,7 +77,7 @@ module BABYLON.GUI {
 
         public get x2(): number {
             if (this._connectedControl) {
-                return this._connectedControl.centerX;
+                return this._connectedControl.centerX + this._x2;
             }
             return this._x2;
         }
@@ -83,7 +93,7 @@ module BABYLON.GUI {
 
         public get y2(): number {
             if (this._connectedControl) {
-                return this._connectedControl.centerY;
+                return this._connectedControl.centerY + this._y2;
             }
             return this._y2;
         }
@@ -147,13 +157,13 @@ module BABYLON.GUI {
 
         public _measure(): void {  
             // Width / Height
-            this._currentMeasure.width = Math.abs(this._x1 - this.x2);
-            this._currentMeasure.height = Math.abs(this._y1 - this.y2);
+            this._currentMeasure.width = Math.abs(this._x1 - this.x2) + this._lineWidth;
+            this._currentMeasure.height = Math.abs(this._y1 - this.y2) + this._lineWidth;
         }
 
         protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void {          
-            this._currentMeasure.left = Math.min(this._x1, this.x2);
-            this._currentMeasure.top = Math.min(this._y1, this.y2);            
+            this._currentMeasure.left = Math.min(this._x1, this.x2) - this._lineWidth / 2;
+            this._currentMeasure.top = Math.min(this._y1, this.y2) - this._lineWidth / 2;            
         }   
 
         public _moveToProjectedPosition(projectedPosition: Vector3): void {

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

@@ -3,7 +3,6 @@
 module BABYLON.GUI {
     export class Rectangle extends Container {
         private _thickness = 1;
-        private _background: string;
         private _cornerRadius = 0;
         
         public get thickness(): number {

+ 31 - 5
gui/src/controls/stackPanel.ts

@@ -2,22 +2,48 @@
 
 module BABYLON.GUI {
     export class StackPanel extends Container {
+        private _isVertical = true;
+
+        public get isVertical(): boolean {
+            return this._isVertical;
+        }
+
+        public set isVertical(value: boolean) {
+            if (this._isVertical === value) {
+                return;
+            }
+
+            this._isVertical = value;
+            this._markAsDirty();
+        }           
     
         constructor(public name: string) {
             super(name);
         }
 
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
-            var top = 0;
+            var stack = 0;
             for (var child of this._children) {
                 child._currentMeasure.copyFrom(parentMeasure);
                 child._measure();
-                child.top = top + "px";
-                top += child._currentMeasure.height;
-                child.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
+
+                if (this._isVertical) {
+                    child.top = stack + "px";
+                    stack += child._currentMeasure.height;
+                    child.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
+                } else {
+                    child.left = stack + "px";
+                    stack += child._currentMeasure.width;
+                    child.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
+
+                }
             }
 
-            this.height = top + "px";
+            if (this._isVertical) {
+                this.height = stack + "px";
+            } else {
+                this.width = stack + "px";
+            }
 
             super._additionalProcessing(parentMeasure, context);
         }    

+ 1 - 1
gui/src/controls/textBlock.ts

@@ -2,7 +2,7 @@
 
 module BABYLON.GUI {
     export class TextBlock extends Control {
-        private _text: string;
+        private _text = "";
         private _textY: number;
         private _textWrapping = false;
         private _textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;

+ 25 - 17
src/Materials/Textures/babylon.videoTexture.ts

@@ -4,8 +4,8 @@
 
         private _autoLaunch = true;
         private _lastUpdate: number;
-        private _generateMipMaps: boolean
-
+        private _generateMipMaps: boolean
+        private _setTextureReady: () => void;
         /**
          * Creates a video texture.
          * Sample : https://doc.babylonjs.com/tutorials/01._Advanced_Texturing
@@ -58,17 +58,20 @@
 
             this._lastUpdate = Tools.Now;
         }
-
-        private _createTexture(): void {
+
+        private __setTextureReady(): void {
+            this._texture.isReady = true;
+        }
+
+        private _createTexture(): void {
             this._texture = this.getScene().getEngine().createDynamicTexture(this.video.videoWidth, this.video.videoHeight, this._generateMipMaps, this._samplingMode);
 
             if (this._autoLaunch) {
                 this._autoLaunch = false;
                 this.video.play();
             }
-            this.video.addEventListener("playing", () => {
-                this._texture.isReady = true;
-            });
+            this._setTextureReady = this.__setTextureReady.bind(this);
+            this.video.addEventListener("playing", this._setTextureReady);
         }
 
         public update(): boolean {
@@ -81,20 +84,25 @@
             this._lastUpdate = now;
             this.getScene().getEngine().updateVideoTexture(this._texture, this.video, this._invertY);
             return true;
+        }
+
+        public dispose(): void {
+            super.dispose();
+            this.video.removeEventListener("playing", this._setTextureReady);
         }
 
-        public static CreateFromWebCam(scene: Scene, onReady: (videoTexture: VideoTexture) => void, constraints: { 
-                minWidth: number, 
-                maxWidth: number, 
-                minHeight: number, 
+        public static CreateFromWebCam(scene: Scene, onReady: (videoTexture: VideoTexture) => void, constraints: {
+                minWidth: number,
+                maxWidth: number,
+                minHeight: number,
                 maxHeight: number,
                 deviceId: string
             }): void {
             var video = document.createElement("video");
             var constraintsDeviceId;
             if (constraints && constraints.deviceId){
-                constraintsDeviceId = { 
-                    exact: constraints.deviceId                     
+                constraintsDeviceId = {
+                    exact: constraints.deviceId
                 }
             }
 
@@ -102,7 +110,7 @@
 		    window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
 
 		    if (navigator.getUserMedia) {
-			    navigator.getUserMedia({                     
+			    navigator.getUserMedia({
                     video: {
                         deviceId: constraintsDeviceId,
                         width: {
@@ -121,16 +129,16 @@
                     } else {
                         video.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
                     }
-                    
+
                     video.play();
 
                     if (onReady) {
                         onReady(new BABYLON.VideoTexture("video", video, scene, true, true));
                     }
 			    }, function (e) {
-                    Tools.Error(e.name); 
+                    Tools.Error(e.name);
                 });
             }
         }
     }
-}
+}

+ 7 - 7
src/Physics/Plugins/babylon.cannonJSPlugin.ts

@@ -272,11 +272,11 @@
             //Future reference - try and find the best place to add a reference to the pointDepth variable.
             var arraySize = pointDepth || ~~(Math.sqrt(pos.length / 3) - 1);
 
-            var dim = Math.min(object.getBoundingInfo().boundingBox.extendSize.x, object.getBoundingInfo().boundingBox.extendSize.z);
+            var dim = Math.min(object.getBoundingInfo().boundingBox.extendSizeWorld.x, object.getBoundingInfo().boundingBox.extendSizeWorld.z);
 
             var elementSize = dim * 2 / arraySize;
 
-            var minY = object.getBoundingInfo().boundingBox.extendSize.y;
+            var minY = object.getBoundingInfo().boundingBox.extendSizeWorld.y;
 
             for (var i = 0; i < pos.length; i = i + 3) {
                 var x = Math.round((pos[i + 0]) / elementSize + arraySize / 2);
@@ -367,17 +367,17 @@
                 mesh.rotationQuaternion = rotationQuaternion;
 
                 //calculate the new center using a pivot (since Cannon.js doesn't center height maps)
-                var p = Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSize.x, 0, -mesh.getBoundingInfo().boundingBox.extendSize.z);
+                var p = Matrix.Translation(mesh.getBoundingInfo().boundingBox.extendSizeWorld.x, 0, -mesh.getBoundingInfo().boundingBox.extendSizeWorld.z);
                 mesh.setPivotMatrix(p);
                 mesh.computeWorldMatrix(true);
 
                 //calculate the translation
-                var translation = mesh.getBoundingInfo().boundingBox.center.subtract(center).subtract(mesh.position).negate();
+                var translation = mesh.getBoundingInfo().boundingBox.centerWorld.subtract(center).subtract(mesh.position).negate();
 
-                this._tmpPosition.copyFromFloats(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSize.y, translation.z);
+                this._tmpPosition.copyFromFloats(translation.x, translation.y - mesh.getBoundingInfo().boundingBox.extendSizeWorld.y, translation.z);
                 //add it inverted to the delta 
-                this._tmpDeltaPosition.copyFrom(mesh.getBoundingInfo().boundingBox.center.subtract(c));
-                this._tmpDeltaPosition.y += mesh.getBoundingInfo().boundingBox.extendSize.y;
+                this._tmpDeltaPosition.copyFrom(mesh.getBoundingInfo().boundingBox.centerWorld.subtract(c));
+                this._tmpDeltaPosition.y += mesh.getBoundingInfo().boundingBox.extendSizeWorld.y;
 
                 mesh.setPivotMatrix(oldPivot);
                 mesh.computeWorldMatrix(true);

+ 3 - 3
src/babylon.scene.ts

@@ -1127,7 +1127,7 @@
                 var canvas = this._engine.getRenderingCanvas();
 
                 if (!this.pointerMovePredicate) {
-                    this.pointerMovePredicate = (mesh: AbstractMesh): boolean => mesh.isPickable && mesh.isVisible && mesh.isReady() && (this.constantlyUpdateMeshUnderPointer || (mesh.actionManager !== null && mesh.actionManager !== undefined));
+                    this.pointerMovePredicate = (mesh: AbstractMesh): boolean => mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled() && (this.constantlyUpdateMeshUnderPointer || (mesh.actionManager !== null && mesh.actionManager !== undefined));
                 }
 
                 // Meshes
@@ -1204,7 +1204,7 @@
 
                 if (!this.pointerDownPredicate) {
                     this.pointerDownPredicate = (mesh: AbstractMesh): boolean => {
-                        return mesh.isPickable && mesh.isVisible && mesh.isReady();
+                        return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled();
                     };
                 }
 
@@ -1334,7 +1334,7 @@
 
                     if (!this.pointerUpPredicate) {
                         this.pointerUpPredicate = (mesh: AbstractMesh): boolean => {
-                            return mesh.isPickable && mesh.isVisible && mesh.isReady();
+                            return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled();
                         };
                     }