Ver código fonte

Fluent - step 1
Associated with #4310

David Catuhe 7 anos atrás
pai
commit
c9615da935

+ 6 - 1
Tools/Gulp/config.json

@@ -1663,11 +1663,16 @@
                     "../../gui/src/2D/controls/virtualKeyboard.ts",
                     "../../gui/src/2D/controls/multiLine.ts",
                     "../../gui/src/3D/gui3DManager.ts",
-                    "../../gui/src/3D/Vector3WithInfo.ts",
+                    "../../gui/src/3D/materials/fluentMaterial.ts",
+                    "../../gui/src/3D/vector3WithInfo.ts",
                     "../../gui/src/3D/controls/control3D.ts",
                     "../../gui/src/3D/controls/container3D.ts",
                     "../../gui/src/3D/controls/button3D.ts"
                 ],
+                "shaderFiles": [
+                    "../../gui/src/3D/materials/shaders/fluent.vertex.fx",
+                    "../../gui/src/3D/materials/shaders/fluent.fragment.fx"
+                ],
                 "output": "babylon.gui.js",
                 "buildAsModule": true,
                 "moduleName": "babylonjs-gui",

Diferenças do arquivo suprimidas por serem muito extensas
+ 18239 - 18238
dist/preview release/babylon.d.ts


Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
dist/preview release/babylon.js


+ 4 - 2
dist/preview release/babylon.max.js

@@ -65113,9 +65113,11 @@ var BABYLON;
         /**
          * Updates the texture
          * @param invertY defines the direction for the Y axis (default is true - y increases downwards)
+         * @param premulAlpha defines if alpha is stored as premultiplied
          */
-        DynamicTexture.prototype.update = function (invertY) {
-            this._engine.updateDynamicTexture(this._texture, this._canvas, invertY === undefined ? true : invertY, undefined, this._format || undefined);
+        DynamicTexture.prototype.update = function (invertY, premulAlpha) {
+            if (premulAlpha === void 0) { premulAlpha = false; }
+            this._engine.updateDynamicTexture(this._texture, this._canvas, invertY === undefined ? true : invertY, premulAlpha, this._format || undefined);
         };
         /**
          * Draws text onto the texture

+ 4 - 2
dist/preview release/babylon.no-module.max.js

@@ -65080,9 +65080,11 @@ var BABYLON;
         /**
          * Updates the texture
          * @param invertY defines the direction for the Y axis (default is true - y increases downwards)
+         * @param premulAlpha defines if alpha is stored as premultiplied
          */
-        DynamicTexture.prototype.update = function (invertY) {
-            this._engine.updateDynamicTexture(this._texture, this._canvas, invertY === undefined ? true : invertY, undefined, this._format || undefined);
+        DynamicTexture.prototype.update = function (invertY, premulAlpha) {
+            if (premulAlpha === void 0) { premulAlpha = false; }
+            this._engine.updateDynamicTexture(this._texture, this._canvas, invertY === undefined ? true : invertY, premulAlpha, this._format || undefined);
         };
         /**
          * Draws text onto the texture

Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
dist/preview release/babylon.worker.js


+ 4 - 2
dist/preview release/es6.js

@@ -65080,9 +65080,11 @@ var BABYLON;
         /**
          * Updates the texture
          * @param invertY defines the direction for the Y axis (default is true - y increases downwards)
+         * @param premulAlpha defines if alpha is stored as premultiplied
          */
-        DynamicTexture.prototype.update = function (invertY) {
-            this._engine.updateDynamicTexture(this._texture, this._canvas, invertY === undefined ? true : invertY, undefined, this._format || undefined);
+        DynamicTexture.prototype.update = function (invertY, premulAlpha) {
+            if (premulAlpha === void 0) { premulAlpha = false; }
+            this._engine.updateDynamicTexture(this._texture, this._canvas, invertY === undefined ? true : invertY, premulAlpha, this._format || undefined);
         };
         /**
          * Draws text onto the texture

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

@@ -99,6 +99,10 @@ declare module BABYLON.GUI {
         private _focusedControl;
         private _blockNextFocusCheck;
         private _renderScale;
+        /**
+         * Gets or sets a boolean defining if alpha is stored as premultiplied
+         */
+        premulAlpha: boolean;
         renderScale: number;
         background: string;
         idealWidth: number;
@@ -1044,29 +1048,37 @@ declare module BABYLON.GUI {
         private _enterCount;
         private _downPointerIds;
         private _isVisible;
+        /** Callback used to start pointer enter animation */
+        pointerEnterAnimation: () => void;
+        /** Callback used to start pointer out animation */
+        pointerOutAnimation: () => void;
+        /** Callback used to start pointer down animation */
+        pointerDownAnimation: () => void;
+        /** Callback used to start pointer up animation */
+        pointerUpAnimation: () => void;
         /**
         * An event triggered when the pointer move over the control.
         */
         onPointerMoveObservable: Observable<Vector3>;
         /**
-        * An event triggered when the pointer move out of the control.
-        */
+         * An event triggered when the pointer move out of the control.
+         */
         onPointerOutObservable: Observable<Control3D>;
         /**
-        * An event triggered when the pointer taps the control
-        */
+         * An event triggered when the pointer taps the control
+         */
         onPointerDownObservable: Observable<Vector3WithInfo>;
         /**
-        * An event triggered when pointer up
-        */
+         * An event triggered when pointer up
+         */
         onPointerUpObservable: Observable<Vector3WithInfo>;
         /**
-        * An event triggered when a control is clicked on
-        */
+         * An event triggered when a control is clicked on
+         */
         onPointerClickObservable: Observable<Vector3WithInfo>;
         /**
-        * An event triggered when pointer enters the control
-        */
+         * An event triggered when pointer enters the control
+         */
         onPointerEnterObservable: Observable<Control3D>;
         /**
          * Gets or sets the parent container
@@ -1101,6 +1113,8 @@ declare module BABYLON.GUI {
         getBehaviorByName(name: string): Nullable<Behavior<Control3D>>;
         /** Gets or sets a boolean indicating if the control is visible */
         isVisible: boolean;
+        /** Gets or sets the control position */
+        position: Vector3;
         /**
          * Creates a new control
          * @param name defines the control name
@@ -1114,11 +1128,21 @@ declare module BABYLON.GUI {
         readonly typeName: string;
         protected _getTypeName(): string;
         /**
+         * Gets the mesh used to render this control
+         */
+        readonly mesh: Nullable<Mesh>;
+        /**
+         * Link the control as child of the given mesh
+         * @param mesh defines the mesh to link to. Use null to unlink the control
+         * @returns the current control
+         */
+        linkToMesh(mesh: Nullable<AbstractMesh>): Control3D;
+        /**
          * Get the attached mesh used to render the control
          * @param scene defines the scene where the mesh must be attached
          * @returns the attached mesh or null if none
          */
-        getAttachedMesh(scene: Scene): Nullable<Mesh>;
+        prepareMesh(scene: Scene): Nullable<Mesh>;
         /**
          * Mesh creation.
          * Can be overriden by children
@@ -1137,6 +1161,8 @@ declare module BABYLON.GUI {
         /** @hidden */
         _onPointerUp(target: Control3D, coordinates: Vector3, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
         /** @hidden */
+        forcePointerUp(pointerId?: Nullable<number>): void;
+        /** @hidden */
         _processObservables(type: number, pickedPoint: Vector3, pointerId: number, buttonIndex: number): boolean;
         /**
          * Releases all associated resources
@@ -1189,6 +1215,7 @@ declare module BABYLON.GUI {
      * Class used to create a button in 3D
      */
     class Button3D extends Control3D {
+        private _currentMaterial;
         /**
          * Creates a new button
          * @param name defines the control name

+ 126 - 16
dist/preview release/gui/babylon.gui.js

@@ -269,6 +269,10 @@ var BABYLON;
                 _this._renderAtIdealSize = false;
                 _this._blockNextFocusCheck = false;
                 _this._renderScale = 1;
+                /**
+                 * Gets or sets a boolean defining if alpha is stored as premultiplied
+                 */
+                _this.premulAlpha = false;
                 scene = _this.getScene();
                 if (!scene || !_this._texture) {
                     return _this;
@@ -578,7 +582,7 @@ var BABYLON;
                 }
                 this._isDirty = false;
                 this._render();
-                this.update();
+                this.update(false, this.premulAlpha);
             };
             AdvancedDynamicTexture.prototype._render = function () {
                 var textureSize = this.getSize();
@@ -5618,8 +5622,10 @@ var BABYLON;
                     _this.dispose();
                 });
                 this._utilityLayer = new BABYLON.UtilityLayerRenderer(this._scene);
+                // Root
                 this._rootContainer = new GUI.Container3D("RootContainer");
                 this._rootContainer._host = this;
+                // Events
                 this._pointerObserver = this._scene.onPrePointerObservable.add(function (pi, state) {
                     var pointerEvent = (pi.event);
                     if (_this._scene.isPointerCaptured(pointerEvent.pointerId)) {
@@ -5636,6 +5642,10 @@ var BABYLON;
                     }
                     pi.skipOnPointerObservable = _this._doPicking(pi.type, pointerEvent);
                 });
+                // Scene
+                this._utilityLayer.utilityLayerScene.autoClear = false;
+                this._utilityLayer.utilityLayerScene.autoClearDepthAndStencil = false;
+                new BABYLON.HemisphericLight("hemi", BABYLON.Vector3.Up(), this._utilityLayer.utilityLayerScene);
             }
             Object.defineProperty(GUI3DManager.prototype, "scene", {
                 /** Gets the hosting scene */
@@ -5653,7 +5663,7 @@ var BABYLON;
                 configurable: true
             });
             GUI3DManager.prototype._doPicking = function (type, pointerEvent) {
-                if (!this._utilityLayer || this._utilityLayer.utilityLayerScene.activeCamera === null) {
+                if (!this._utilityLayer || !this._utilityLayer.utilityLayerScene.activeCamera) {
                     return false;
                 }
                 var pointerId = pointerEvent.pointerId || 0;
@@ -5666,6 +5676,12 @@ var BABYLON;
                         previousControlOver._onPointerOut(previousControlOver);
                         delete this._lastControlOver[pointerId];
                     }
+                    if (type === BABYLON.PointerEventTypes.POINTERUP) {
+                        if (this._lastControlDown[pointerEvent.pointerId]) {
+                            this._lastControlDown[pointerEvent.pointerId].forcePointerUp();
+                            delete this._lastControlDown[pointerEvent.pointerId];
+                        }
+                    }
                     return false;
                 }
                 var control = (pickingInfo.pickedMesh.metadata);
@@ -5677,6 +5693,12 @@ var BABYLON;
                         delete this._lastControlOver[pointerId];
                     }
                 }
+                if (type === BABYLON.PointerEventTypes.POINTERUP) {
+                    if (this._lastControlDown[pointerEvent.pointerId]) {
+                        this._lastControlDown[pointerEvent.pointerId].forcePointerUp();
+                        delete this._lastControlDown[pointerEvent.pointerId];
+                    }
+                }
                 return true;
             };
             Object.defineProperty(GUI3DManager.prototype, "rootContainer", {
@@ -5786,24 +5808,24 @@ var BABYLON;
                 */
                 this.onPointerMoveObservable = new BABYLON.Observable();
                 /**
-                * An event triggered when the pointer move out of the control.
-                */
+                 * An event triggered when the pointer move out of the control.
+                 */
                 this.onPointerOutObservable = new BABYLON.Observable();
                 /**
-                * An event triggered when the pointer taps the control
-                */
+                 * An event triggered when the pointer taps the control
+                 */
                 this.onPointerDownObservable = new BABYLON.Observable();
                 /**
-                * An event triggered when pointer up
-                */
+                 * An event triggered when pointer up
+                 */
                 this.onPointerUpObservable = new BABYLON.Observable();
                 /**
-                * An event triggered when a control is clicked on
-                */
+                 * An event triggered when a control is clicked on
+                 */
                 this.onPointerClickObservable = new BABYLON.Observable();
                 /**
-                * An event triggered when pointer enters the control
-                */
+                 * An event triggered when pointer enters the control
+                 */
                 this.onPointerEnterObservable = new BABYLON.Observable();
                 // Behaviors
                 this._behaviors = new Array();
@@ -5892,6 +5914,22 @@ var BABYLON;
                 enumerable: true,
                 configurable: true
             });
+            Object.defineProperty(Control3D.prototype, "position", {
+                /** Gets or sets the control position */
+                get: function () {
+                    if (this._mesh) {
+                        return this._mesh.position;
+                    }
+                    return BABYLON.Vector3.Zero();
+                },
+                set: function (value) {
+                    if (this._mesh) {
+                        this._mesh.position = value;
+                    }
+                },
+                enumerable: true,
+                configurable: true
+            });
             Object.defineProperty(Control3D.prototype, "typeName", {
                 /**
                  * Gets a string representing the class name
@@ -5905,12 +5943,33 @@ var BABYLON;
             Control3D.prototype._getTypeName = function () {
                 return "Control3D";
             };
+            Object.defineProperty(Control3D.prototype, "mesh", {
+                /**
+                 * Gets the mesh used to render this control
+                 */
+                get: function () {
+                    return this._mesh;
+                },
+                enumerable: true,
+                configurable: true
+            });
+            /**
+             * Link the control as child of the given mesh
+             * @param mesh defines the mesh to link to. Use null to unlink the control
+             * @returns the current control
+             */
+            Control3D.prototype.linkToMesh = function (mesh) {
+                if (this._mesh) {
+                    this._mesh.parent = mesh;
+                }
+                return this;
+            };
             /**
              * Get the attached mesh used to render the control
              * @param scene defines the scene where the mesh must be attached
              * @returns the attached mesh or null if none
              */
-            Control3D.prototype.getAttachedMesh = function (scene) {
+            Control3D.prototype.prepareMesh = function (scene) {
                 if (!this._mesh) {
                     this._mesh = this._createMesh(scene);
                     this._mesh.isPickable = true;
@@ -5944,6 +6003,9 @@ var BABYLON;
                 var canNotify = this.onPointerEnterObservable.notifyObservers(this, -1, target, this);
                 if (canNotify && this.parent != null)
                     this.parent._onPointerEnter(target);
+                if (this.pointerEnterAnimation) {
+                    this.pointerEnterAnimation();
+                }
                 return true;
             };
             /** @hidden */
@@ -5952,6 +6014,9 @@ var BABYLON;
                 var canNotify = this.onPointerOutObservable.notifyObservers(this, -1, target, this);
                 if (canNotify && this.parent != null)
                     this.parent._onPointerOut(target);
+                if (this.pointerOutAnimation) {
+                    this.pointerOutAnimation();
+                }
             };
             /** @hidden */
             Control3D.prototype._onPointerDown = function (target, coordinates, pointerId, buttonIndex) {
@@ -5963,6 +6028,9 @@ var BABYLON;
                 var canNotify = this.onPointerDownObservable.notifyObservers(new GUI.Vector3WithInfo(coordinates, buttonIndex), -1, target, this);
                 if (canNotify && this.parent != null)
                     this.parent._onPointerDown(target, coordinates, pointerId, buttonIndex);
+                if (this.pointerDownAnimation) {
+                    this.pointerDownAnimation();
+                }
                 return true;
             };
             /** @hidden */
@@ -5976,6 +6044,21 @@ var BABYLON;
                 var canNotify = this.onPointerUpObservable.notifyObservers(new GUI.Vector3WithInfo(coordinates, buttonIndex), -1, target, this);
                 if (canNotify && this.parent != null)
                     this.parent._onPointerUp(target, coordinates, pointerId, buttonIndex, canNotifyClick);
+                if (this.pointerUpAnimation) {
+                    this.pointerUpAnimation();
+                }
+            };
+            /** @hidden */
+            Control3D.prototype.forcePointerUp = function (pointerId) {
+                if (pointerId === void 0) { pointerId = null; }
+                if (pointerId !== null) {
+                    this._onPointerUp(this, BABYLON.Vector3.Zero(), pointerId, 0, true);
+                }
+                else {
+                    for (var key in this._downPointerIds) {
+                        this._onPointerUp(this, BABYLON.Vector3.Zero(), +key, 0, true);
+                    }
+                }
             };
             /** @hidden */
             Control3D.prototype._processObservables = function (type, pickedPoint, pointerId, buttonIndex) {
@@ -6069,7 +6152,7 @@ var BABYLON;
                 control.parent = this;
                 control._host = this._host;
                 if (this._host.utilityLayer) {
-                    control.getAttachedMesh(this._host.utilityLayer.utilityLayerScene);
+                    control.prepareMesh(this._host.utilityLayer.utilityLayerScene);
                 }
                 return this;
             };
@@ -6122,18 +6205,45 @@ var BABYLON;
              * @param name defines the control name
              */
             function Button3D(name) {
-                return _super.call(this, name) || this;
+                var _this = _super.call(this, name) || this;
+                // Default animations
+                _this.pointerEnterAnimation = function () {
+                    if (!_this.mesh) {
+                        return;
+                    }
+                    _this._currentMaterial.emissiveColor = BABYLON.Color3.Red();
+                };
+                _this.pointerOutAnimation = function () {
+                    _this._currentMaterial.emissiveColor = BABYLON.Color3.Black();
+                };
+                _this.pointerDownAnimation = function () {
+                    if (!_this.mesh) {
+                        return;
+                    }
+                    _this.mesh.scaling.scaleInPlace(0.95);
+                };
+                _this.pointerUpAnimation = function () {
+                    if (!_this.mesh) {
+                        return;
+                    }
+                    _this.mesh.scaling.scaleInPlace(1.05);
+                };
+                return _this;
             }
             Button3D.prototype._getTypeName = function () {
                 return "Button3D";
             };
             // Mesh association
             Button3D.prototype._createMesh = function (scene) {
-                return BABYLON.MeshBuilder.CreateBox(this.name + "Mesh", {
+                var mesh = BABYLON.MeshBuilder.CreateBox(this.name + "Mesh", {
                     width: 1.0,
                     height: 1.0,
                     depth: 0.1
                 }, scene);
+                this._currentMaterial = new BABYLON.StandardMaterial(this.name + "Material", scene);
+                this._currentMaterial.specularColor = BABYLON.Color3.Black();
+                mesh.material = this._currentMaterial;
+                return mesh;
             };
             return Button3D;
         }(GUI.Control3D));

Diferenças do arquivo suprimidas por serem muito extensas
+ 4 - 4
dist/preview release/gui/babylon.gui.min.js


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

@@ -104,6 +104,10 @@ declare module BABYLON.GUI {
         private _focusedControl;
         private _blockNextFocusCheck;
         private _renderScale;
+        /**
+         * Gets or sets a boolean defining if alpha is stored as premultiplied
+         */
+        premulAlpha: boolean;
         renderScale: number;
         background: string;
         idealWidth: number;
@@ -1049,29 +1053,37 @@ declare module BABYLON.GUI {
         private _enterCount;
         private _downPointerIds;
         private _isVisible;
+        /** Callback used to start pointer enter animation */
+        pointerEnterAnimation: () => void;
+        /** Callback used to start pointer out animation */
+        pointerOutAnimation: () => void;
+        /** Callback used to start pointer down animation */
+        pointerDownAnimation: () => void;
+        /** Callback used to start pointer up animation */
+        pointerUpAnimation: () => void;
         /**
         * An event triggered when the pointer move over the control.
         */
         onPointerMoveObservable: Observable<Vector3>;
         /**
-        * An event triggered when the pointer move out of the control.
-        */
+         * An event triggered when the pointer move out of the control.
+         */
         onPointerOutObservable: Observable<Control3D>;
         /**
-        * An event triggered when the pointer taps the control
-        */
+         * An event triggered when the pointer taps the control
+         */
         onPointerDownObservable: Observable<Vector3WithInfo>;
         /**
-        * An event triggered when pointer up
-        */
+         * An event triggered when pointer up
+         */
         onPointerUpObservable: Observable<Vector3WithInfo>;
         /**
-        * An event triggered when a control is clicked on
-        */
+         * An event triggered when a control is clicked on
+         */
         onPointerClickObservable: Observable<Vector3WithInfo>;
         /**
-        * An event triggered when pointer enters the control
-        */
+         * An event triggered when pointer enters the control
+         */
         onPointerEnterObservable: Observable<Control3D>;
         /**
          * Gets or sets the parent container
@@ -1106,6 +1118,8 @@ declare module BABYLON.GUI {
         getBehaviorByName(name: string): Nullable<Behavior<Control3D>>;
         /** Gets or sets a boolean indicating if the control is visible */
         isVisible: boolean;
+        /** Gets or sets the control position */
+        position: Vector3;
         /**
          * Creates a new control
          * @param name defines the control name
@@ -1119,11 +1133,21 @@ declare module BABYLON.GUI {
         readonly typeName: string;
         protected _getTypeName(): string;
         /**
+         * Gets the mesh used to render this control
+         */
+        readonly mesh: Nullable<Mesh>;
+        /**
+         * Link the control as child of the given mesh
+         * @param mesh defines the mesh to link to. Use null to unlink the control
+         * @returns the current control
+         */
+        linkToMesh(mesh: Nullable<AbstractMesh>): Control3D;
+        /**
          * Get the attached mesh used to render the control
          * @param scene defines the scene where the mesh must be attached
          * @returns the attached mesh or null if none
          */
-        getAttachedMesh(scene: Scene): Nullable<Mesh>;
+        prepareMesh(scene: Scene): Nullable<Mesh>;
         /**
          * Mesh creation.
          * Can be overriden by children
@@ -1142,6 +1166,8 @@ declare module BABYLON.GUI {
         /** @hidden */
         _onPointerUp(target: Control3D, coordinates: Vector3, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
         /** @hidden */
+        forcePointerUp(pointerId?: Nullable<number>): void;
+        /** @hidden */
         _processObservables(type: number, pickedPoint: Vector3, pointerId: number, buttonIndex: number): boolean;
         /**
          * Releases all associated resources
@@ -1194,6 +1220,7 @@ declare module BABYLON.GUI {
      * Class used to create a button in 3D
      */
     class Button3D extends Control3D {
+        private _currentMaterial;
         /**
          * Creates a new button
          * @param name defines the control name

Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
dist/preview release/viewer/babylon.viewer.js


+ 4 - 2
dist/preview release/viewer/babylon.viewer.max.js

@@ -65201,9 +65201,11 @@ var BABYLON;
         /**
          * Updates the texture
          * @param invertY defines the direction for the Y axis (default is true - y increases downwards)
+         * @param premulAlpha defines if alpha is stored as premultiplied
          */
-        DynamicTexture.prototype.update = function (invertY) {
-            this._engine.updateDynamicTexture(this._texture, this._canvas, invertY === undefined ? true : invertY, undefined, this._format || undefined);
+        DynamicTexture.prototype.update = function (invertY, premulAlpha) {
+            if (premulAlpha === void 0) { premulAlpha = false; }
+            this._engine.updateDynamicTexture(this._texture, this._canvas, invertY === undefined ? true : invertY, premulAlpha, this._format || undefined);
         };
         /**
          * Draws text onto the texture

+ 6 - 1
gui/src/2D/advancedDynamicTexture.ts

@@ -34,6 +34,11 @@ module BABYLON.GUI {
         private _blockNextFocusCheck = false;
         private _renderScale = 1;
 
+        /**
+         * Gets or sets a boolean defining if alpha is stored as premultiplied
+         */
+        public premulAlpha = false;
+
         public get renderScale(): number {
             return this._renderScale;
         }
@@ -382,7 +387,7 @@ module BABYLON.GUI {
             this._isDirty = false;
 
             this._render();
-            this.update();
+            this.update(true, this.premulAlpha);
         }
 
         private _render(): void {

+ 74 - 4
gui/src/3D/controls/button3D.ts

@@ -5,13 +5,69 @@ module BABYLON.GUI {
      * Class used to create a button in 3D
      */
     export class Button3D extends Control3D {
-        
+        private _currentMaterial: FluentMaterial;
+        private _facadeTexture: AdvancedDynamicTexture;
+        private _content: Control;
+
         /**
          * Creates a new button
          * @param name defines the control name
          */
         constructor(name?: string) {
             super(name);
+
+            // Default animations
+
+            this.pointerEnterAnimation = () => {
+                if (!this.mesh) {
+                    return;
+                }
+               // this._currentMaterial.emissiveColor = Color3.Red();
+            }
+
+            this.pointerOutAnimation = () => {
+               // this._currentMaterial.emissiveColor = Color3.Black();
+            }    
+
+            this.pointerDownAnimation = () => {
+                if (!this.mesh) {
+                    return;
+                }
+
+                this.mesh.scaling.scaleInPlace(0.95);
+            }
+
+            this.pointerUpAnimation = () => {
+                if (!this.mesh) {
+                    return;
+                }
+
+                this.mesh.scaling.scaleInPlace(1.0 / 0.95);
+            }                     
+        }
+
+        /**
+         * Gets or sets the GUI 2D content used to display the button's facade
+         */
+        public get content(): Control {
+            return this._content;
+        }
+
+        public set content(value: Control) {
+            if (!this._host || !this._host.utilityLayer) {
+                return;
+            }
+
+            if (!this._facadeTexture) {
+                this._facadeTexture = new BABYLON.GUI.AdvancedDynamicTexture("Facade", 512, 512, this._host.utilityLayer.utilityLayerScene, true, BABYLON.Texture.TRILINEAR_SAMPLINGMODE);
+                this._facadeTexture.rootContainer.scaleX = 2;
+                this._facadeTexture.rootContainer.scaleY = 2;
+                this._facadeTexture.premulAlpha = true;
+            }
+            
+            this._facadeTexture.addControl(value);
+        
+            this._currentMaterial.emissiveTexture = this._facadeTexture;
         }
 
         protected _getTypeName(): string {
@@ -20,11 +76,25 @@ module BABYLON.GUI {
 
         // Mesh association
         protected _createMesh(scene: Scene): Mesh {
-            return MeshBuilder.CreateBox(this.name + "Mesh", {
+            var faceUV = new Array(6);
+
+            for (var i = 0; i < 6; i++) {
+                faceUV[i] = new BABYLON.Vector4(0, 0, 0, 0);
+            }
+            faceUV[1] = new BABYLON.Vector4(0, 0, 1, 1);
+
+            let mesh = MeshBuilder.CreateBox(this.name + "Mesh", {
                 width: 1.0, 
                 height: 1.0,
-                depth: 0.1
-            }, scene);            
+                depth: 0.1,
+                faceUV: faceUV
+            }, scene); 
+
+            this._currentMaterial = new FluentMaterial(this.name + "Material", scene);
+
+            mesh.material = this._currentMaterial;
+            
+            return mesh;
         }
     }
 }

+ 1 - 1
gui/src/3D/controls/container3D.ts

@@ -39,7 +39,7 @@ module BABYLON.GUI {
             control._host = this._host;
 
             if (this._host.utilityLayer) {
-                control.getAttachedMesh(this._host.utilityLayer.utilityLayerScene);
+                control.prepareMesh(this._host.utilityLayer.utilityLayerScene);
             }
 
             return this;

+ 105 - 42
gui/src/3D/controls/control3D.ts

@@ -12,39 +12,47 @@ module BABYLON.GUI {
         private _enterCount = 0;
         private _downPointerIds:{[id:number] : boolean} = {};
         private _isVisible = true;
-        
+
+        /** Callback used to start pointer enter animation */
+        public pointerEnterAnimation: () => void;
+        /** Callback used to start pointer out animation */
+        public pointerOutAnimation: () => void;
+        /** Callback used to start pointer down animation */
+        public pointerDownAnimation: () => void;
+        /** Callback used to start pointer up animation */
+        public pointerUpAnimation: () => void;
+
         /**
         * An event triggered when the pointer move over the control.
         */
-       public onPointerMoveObservable = new Observable<Vector3>();
-
-       /**
-       * An event triggered when the pointer move out of the control.
-       */
-       public onPointerOutObservable = new Observable<Control3D>();
-
-       /**
-       * An event triggered when the pointer taps the control
-       */
-       public onPointerDownObservable = new Observable<Vector3WithInfo>();
-
-       /**
-       * An event triggered when pointer up
-       */
-       public onPointerUpObservable = new Observable<Vector3WithInfo>();
-
-       /**
-       * An event triggered when a control is clicked on
-       */
-       public onPointerClickObservable = new Observable<Vector3WithInfo>();
-
-       /**
-       * An event triggered when pointer enters the control
-       */
-       public onPointerEnterObservable = new Observable<Control3D>();
-       
+        public onPointerMoveObservable = new Observable<Vector3>();
+
+        /**
+         * An event triggered when the pointer move out of the control.
+         */
+        public onPointerOutObservable = new Observable<Control3D>();
+
+        /**
+         * An event triggered when the pointer taps the control
+         */
+        public onPointerDownObservable = new Observable<Vector3WithInfo>();
+
+        /**
+         * An event triggered when pointer up
+         */
+        public onPointerUpObservable = new Observable<Vector3WithInfo>();
 
         /**
+         * An event triggered when a control is clicked on
+         */
+        public onPointerClickObservable = new Observable<Vector3WithInfo>();
+
+        /**
+         * An event triggered when pointer enters the control
+         */
+        public onPointerEnterObservable = new Observable<Control3D>();
+        
+        /**
          * Gets or sets the parent container
          */
         public parent: Nullable<Container3D>;
@@ -139,6 +147,21 @@ module BABYLON.GUI {
             }
         }
 
+        /** Gets or sets the control position */
+        public get position(): Vector3 {
+            if (this._mesh) {
+                return this._mesh.position;
+            }
+
+            return Vector3.Zero();
+        }
+
+        public set position(value: Vector3) {
+            if (this._mesh) {
+                this._mesh.position = value;
+            }            
+        }
+
         /**
          * Creates a new control
          * @param name defines the control name
@@ -160,11 +183,30 @@ module BABYLON.GUI {
         }
 
         /**
+         * Gets the mesh used to render this control
+         */
+        public get mesh(): Nullable<Mesh> {
+            return this._mesh;
+        }
+
+        /**
+         * Link the control as child of the given mesh
+         * @param mesh defines the mesh to link to. Use null to unlink the control
+         * @returns the current control
+         */
+        public linkToMesh(mesh: Nullable<AbstractMesh>): Control3D {
+            if (this._mesh) {
+                this._mesh.parent = mesh;
+            }
+            return this;
+        }    
+
+        /**
          * Get the attached mesh used to render the control
          * @param scene defines the scene where the mesh must be attached
          * @returns the attached mesh or null if none
          */        
-        public getAttachedMesh(scene: Scene): Nullable<Mesh> {
+        public prepareMesh(scene: Scene): Nullable<Mesh> {
             if (!this._mesh) {
                 this._mesh = this._createMesh(scene);
                 this._mesh!.isPickable = true;
@@ -189,9 +231,7 @@ module BABYLON.GUI {
 
         /** @hidden */
         public _onPointerMove(target: Control3D, coordinates: Vector3): void {
-            var canNotify: boolean = this.onPointerMoveObservable.notifyObservers(coordinates, -1, target, this);
-
-            if (canNotify && this.parent != null) this.parent._onPointerMove(target, coordinates);
+            this.onPointerMoveObservable.notifyObservers(coordinates, -1, target, this);
         }
 
         /** @hidden */
@@ -202,9 +242,11 @@ module BABYLON.GUI {
 
             this._enterCount++;
 
-            var canNotify: boolean = this.onPointerEnterObservable.notifyObservers(this, -1, target, this);
+            this.onPointerEnterObservable.notifyObservers(this, -1, target, this);
 
-            if (canNotify && this.parent != null) this.parent._onPointerEnter(target);
+            if (this.pointerEnterAnimation) {
+                this.pointerEnterAnimation();
+            }
 
             return true;
         }
@@ -213,9 +255,11 @@ module BABYLON.GUI {
         public _onPointerOut(target: Control3D): void {
             this._enterCount = 0;
 
-            var canNotify: boolean = this.onPointerOutObservable.notifyObservers(this, -1, target, this);
+            this.onPointerOutObservable.notifyObservers(this, -1, target, this);
 
-            if (canNotify && this.parent != null) this.parent._onPointerOut(target);
+            if (this.pointerOutAnimation) {
+                this.pointerOutAnimation();
+            }            
         }
 
         /** @hidden */
@@ -228,9 +272,11 @@ module BABYLON.GUI {
 
             this._downPointerIds[pointerId] = true;
 
-            var canNotify: boolean = this.onPointerDownObservable.notifyObservers(new Vector3WithInfo(coordinates, buttonIndex), -1, target, this);
+            this.onPointerDownObservable.notifyObservers(new Vector3WithInfo(coordinates, buttonIndex), -1, target, this);
 
-            if (canNotify && this.parent != null) this.parent._onPointerDown(target, coordinates, pointerId, buttonIndex);
+            if (this.pointerDownAnimation) {
+                this.pointerDownAnimation();
+            }                 
 
             return true;
         }
@@ -241,14 +287,26 @@ module BABYLON.GUI {
 
             delete this._downPointerIds[pointerId];
 
-            var canNotifyClick: boolean = notifyClick;
 			if (notifyClick && this._enterCount > 0) {
-				canNotifyClick = this.onPointerClickObservable.notifyObservers(new Vector3WithInfo(coordinates, buttonIndex), -1, target, this);
+				this.onPointerClickObservable.notifyObservers(new Vector3WithInfo(coordinates, buttonIndex), -1, target, this);
 			}
-			var canNotify: boolean = this.onPointerUpObservable.notifyObservers(new Vector3WithInfo(coordinates, buttonIndex), -1, target, this);
+			this.onPointerUpObservable.notifyObservers(new Vector3WithInfo(coordinates, buttonIndex), -1, target, this);            
 
-            if (canNotify && this.parent != null) this.parent._onPointerUp(target, coordinates, pointerId, buttonIndex, canNotifyClick);
+            if (this.pointerUpAnimation) {
+                this.pointerUpAnimation();
+            }          
         }  
+
+        /** @hidden */
+        public forcePointerUp(pointerId: Nullable<number> = null) {
+            if(pointerId !== null){
+                this._onPointerUp(this, Vector3.Zero(), pointerId, 0, true);
+            }else{
+                for(var key in this._downPointerIds){
+                    this._onPointerUp(this, Vector3.Zero(), +key as number, 0, true);
+                }
+            }
+        }
         
         /** @hidden */
         public _processObservables(type: number, pickedPoint: Vector3, pointerId:number, buttonIndex: number): boolean {
@@ -297,6 +355,11 @@ module BABYLON.GUI {
             this.onPointerUpObservable.clear();
             this.onPointerClickObservable.clear();
 
+            if (this._mesh) {
+                this._mesh.dispose(false, true);
+                this._mesh = null;
+            }
+
             // Behaviors
             for (var behavior of this._behaviors) {
                 behavior.detach();

+ 22 - 1
gui/src/3D/gui3DManager.ts

@@ -39,9 +39,11 @@ module BABYLON.GUI {
 
             this._utilityLayer = new UtilityLayerRenderer(this._scene);
 
+            // Root
             this._rootContainer = new Container3D("RootContainer");
             this._rootContainer._host = this;
             
+            // Events
             this._pointerObserver = this._scene.onPrePointerObservable.add((pi, state) => {
                 let pointerEvent = <PointerEvent>(pi.event);
                 if (this._scene.isPointerCaptured(pointerEvent.pointerId)) {
@@ -62,10 +64,15 @@ module BABYLON.GUI {
 
                 pi.skipOnPointerObservable = this._doPicking(pi.type, pointerEvent)
             });
+
+            // Scene
+            this._utilityLayer.utilityLayerScene.autoClear = false;
+            this._utilityLayer.utilityLayerScene.autoClearDepthAndStencil = false;
+            new BABYLON.HemisphericLight("hemi", Vector3.Up(), this._utilityLayer.utilityLayerScene);
         }
 
         private _doPicking(type: number, pointerEvent: PointerEvent): boolean {
-            if (!this._utilityLayer || this._utilityLayer.utilityLayerScene.activeCamera === null) {
+            if (!this._utilityLayer || !this._utilityLayer.utilityLayerScene.activeCamera) {
                 return false;                
             }
 
@@ -79,6 +86,13 @@ module BABYLON.GUI {
                 if (previousControlOver) {
                     previousControlOver._onPointerOut(previousControlOver);
                     delete this._lastControlOver[pointerId];
+                }               
+                
+                if (type === BABYLON.PointerEventTypes.POINTERUP) {
+                    if (this._lastControlDown[pointerEvent.pointerId]) {
+                        this._lastControlDown[pointerEvent.pointerId].forcePointerUp();
+                        delete this._lastControlDown[pointerEvent.pointerId];
+                    }
                 }                
                 return false;
             }
@@ -96,6 +110,13 @@ module BABYLON.GUI {
                 }
             }
 
+            if (type === BABYLON.PointerEventTypes.POINTERUP) {
+                if (this._lastControlDown[pointerEvent.pointerId]) {
+                    this._lastControlDown[pointerEvent.pointerId].forcePointerUp();
+                    delete this._lastControlDown[pointerEvent.pointerId];
+                }
+            }
+
             return true;
         }
 

+ 168 - 0
gui/src/3D/materials/fluentMaterial.ts

@@ -0,0 +1,168 @@
+/// <reference path="../../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.GUI {
+    /**
+     * Class used to render controls with fluent desgin
+     */
+    export class FluentMaterial extends PushMaterial {    
+        @serializeAsTexture("emissiveTexture")
+        private _emissiveTexture: BaseTexture;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public emissiveTexture: BaseTexture;
+
+        private _renderId: number;
+
+        constructor(name: string, scene: Scene) {
+            super(name, scene);
+        }
+
+        public needAlphaBlending(): boolean {
+            return false;
+        }
+
+        public needAlphaTesting(): boolean {
+            return false;
+        }
+
+        public getAlphaTestTexture(): Nullable<BaseTexture> {
+            return null;
+        } 
+        
+        public isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean {
+            if (this.isFrozen) {
+                if (this._wasPreviouslyReady && subMesh.effect) {
+                    return true;
+                }
+            }
+
+            var scene = this.getScene();
+
+            if (!this.checkReadyOnEveryCall && subMesh.effect) {
+                if (this._renderId === scene.getRenderId()) {
+                    return true;
+                }
+            }
+
+            var engine = scene.getEngine();
+
+            scene.resetCachedMaterial();
+
+            //Attributes
+            var attribs = [VertexBuffer.PositionKind];
+            attribs.push(VertexBuffer.NormalKind);
+            attribs.push(VertexBuffer.UVKind);
+
+            var shaderName = "fluent";
+
+            var uniforms = ["world", "viewProjection", "emissiveMatrix"];
+
+            var samplers = ["emissiveSampler"]
+            var uniformBuffers = new Array<string>();
+
+            MaterialHelper.PrepareUniformsAndSamplersList(<EffectCreationOptions>{
+                uniformsNames: uniforms,
+                uniformBuffersNames: uniformBuffers,
+                samplers: samplers,
+                defines: "",
+                maxSimultaneousLights: 4
+            });            
+
+            subMesh.setEffect(scene.getEngine().createEffect(shaderName,
+                <EffectCreationOptions>{
+                    attributes: attribs,
+                    uniformsNames: uniforms,
+                    uniformBuffersNames: uniformBuffers,
+                    samplers: samplers,
+                    defines: "",
+                    fallbacks: null,
+                    onCompiled: this.onCompiled,
+                    onError: this.onError,
+                    indexParameters: { maxSimultaneousLights: 4 }
+                }, engine));
+
+                if (!subMesh.effect || !subMesh.effect.isReady()) {
+                return false;
+            }
+
+            this._renderId = scene.getRenderId();
+            this._wasPreviouslyReady = true;
+
+            return true;
+        }
+
+        public bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void {
+            var scene = this.getScene();
+
+            var effect = subMesh.effect;
+            if (!effect) {
+                return;
+            }
+            this._activeEffect = effect;
+
+            // Matrices        
+            this.bindOnlyWorldMatrix(world);
+            this._activeEffect.setMatrix("viewProjection", scene.getTransformMatrix());
+
+
+            if (this._mustRebind(scene, effect)) {
+                // Textures        
+                if (this.emissiveTexture && StandardMaterial.DiffuseTextureEnabled) {
+                    this._activeEffect.setTexture("emissiveSampler", this.emissiveTexture);
+
+                    this._activeEffect.setMatrix("emissiveMatrix", this.emissiveTexture.getTextureMatrix());
+                }                
+            }
+
+            this._afterBind(mesh, this._activeEffect);
+        }    
+
+        public getActiveTextures(): BaseTexture[] {
+            var activeTextures = super.getActiveTextures();
+
+            if (this.emissiveTexture) {
+                activeTextures.push(this.emissiveTexture);
+            }
+
+            return activeTextures;
+        }        
+
+        public hasTexture(texture: BaseTexture): boolean {
+            if (super.hasTexture(texture)) {
+                return true;
+            }
+
+            if (this.emissiveTexture === texture) {
+                return true;
+            }
+
+            return false;
+        }        
+        
+        public dispose(forceDisposeEffect?: boolean): void {
+            if (this.emissiveTexture) {
+                this.emissiveTexture.dispose();
+            }
+
+            super.dispose(forceDisposeEffect);
+        }
+
+        public clone(name: string): FluentMaterial {
+            return SerializationHelper.Clone(() => new FluentMaterial(name, this.getScene()), this);
+        }
+
+        public serialize(): any {
+            var serializationObject = SerializationHelper.Serialize(this);
+            serializationObject.customType = "BABYLON.GUI.FluentMaterial";
+            return serializationObject;
+        }
+
+        public getClassName(): string {
+            return "FluentMaterial";
+        }
+
+        // Statics
+        public static Parse(source: any, scene: Scene, rootUrl: string): FluentMaterial {
+            return SerializationHelper.Parse(() => new FluentMaterial(source.name, scene), source, scene, rootUrl);
+        }
+    }
+}

+ 10 - 0
gui/src/3D/materials/shaders/fluent.fragment.fx

@@ -0,0 +1,10 @@
+precision highp float;
+
+varying vec2 vEmissiveUV;
+uniform sampler2D emissiveSampler;
+
+
+void main(void) {
+	vec3 emissiveColor = texture2D(emissiveSampler, vEmissiveUV).rgb;
+	gl_FragColor = vec4(emissiveColor, 1.0);
+}

+ 19 - 0
gui/src/3D/materials/shaders/fluent.vertex.fx

@@ -0,0 +1,19 @@
+precision highp float;
+
+// Attributes
+attribute vec3 position;
+attribute vec3 normal;
+attribute vec2 uv;
+
+// Uniforms
+uniform mat4 world;
+uniform mat4 viewProjection;
+uniform mat4 emissiveMatrix;
+
+varying vec2 vEmissiveUV;
+
+void main(void) {
+	vEmissiveUV = vec2(emissiveMatrix * vec4(uv, 1.0, 0.0));
+
+	gl_Position = viewProjection * world * vec4(position, 1.0);
+}

+ 3 - 2
src/Materials/Textures/babylon.dynamicTexture.ts

@@ -111,9 +111,10 @@
         /**
          * Updates the texture
          * @param invertY defines the direction for the Y axis (default is true - y increases downwards)
+         * @param premulAlpha defines if alpha is stored as premultiplied (default is false)
          */
-        public update(invertY?: boolean): void {
-            this._engine.updateDynamicTexture(this._texture, this._canvas, invertY === undefined ? true : invertY, undefined, this._format || undefined);
+        public update(invertY?: boolean, premulAlpha = false): void {
+            this._engine.updateDynamicTexture(this._texture, this._canvas, invertY === undefined ? true : invertY, premulAlpha, this._format || undefined);
         }
 
         /**