Browse Source

More Control3D stuff
Associated with #4310

David Catuhe 7 years ago
parent
commit
3ff56041f6

+ 1 - 0
Tools/Gulp/config.json

@@ -1663,6 +1663,7 @@
                     "../../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/controls/control3D.ts",
                     "../../gui/src/3D/controls/container3D.ts",
                     "../../gui/src/3D/controls/button3D.ts"

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


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

@@ -973,6 +973,16 @@ declare module BABYLON.GUI {
         private _sceneDisposeObserver;
         private _utilityLayer;
         private _rootContainer;
+        private _pointerMoveObserver;
+        _lastPickedControl: Control3D;
+        /** @hidden */
+        _lastControlOver: {
+            [pointerId: number]: Control3D;
+        };
+        /** @hidden */
+        _lastControlDown: {
+            [pointerId: number]: Control3D;
+        };
         /** Gets the hosting scene */
         readonly scene: Scene;
         readonly utilityLayer: Nullable<UtilityLayerRenderer>;
@@ -981,6 +991,7 @@ declare module BABYLON.GUI {
          * @param scene
          */
         constructor(scene?: Scene);
+        private _doPicking(type, pointerEvent);
         /**
          * Gets the root container
          */
@@ -1012,6 +1023,14 @@ declare module BABYLON.GUI {
 
 
 declare module BABYLON.GUI {
+    class Vector3WithInfo extends Vector2 {
+        buttonIndex: number;
+        constructor(source: Vector3, buttonIndex?: number);
+    }
+}
+
+
+declare module BABYLON.GUI {
     /**
      * Class used as base class for controls
      */
@@ -1021,6 +1040,34 @@ declare module BABYLON.GUI {
         /** @hidden */
         _host: GUI3DManager;
         private _mesh;
+        private _downCount;
+        private _enterCount;
+        private _downPointerIds;
+        private _isVisible;
+        /**
+        * An event triggered when the pointer move over the control.
+        */
+        onPointerMoveObservable: Observable<Vector3>;
+        /**
+        * An event triggered when the pointer move out of the control.
+        */
+        onPointerOutObservable: Observable<Control3D>;
+        /**
+        * An event triggered when the pointer taps the control
+        */
+        onPointerDownObservable: Observable<Vector3WithInfo>;
+        /**
+        * An event triggered when pointer up
+        */
+        onPointerUpObservable: Observable<Vector3WithInfo>;
+        /**
+        * An event triggered when a control is clicked on
+        */
+        onPointerClickObservable: Observable<Vector3WithInfo>;
+        /**
+        * An event triggered when pointer enters the control
+        */
+        onPointerEnterObservable: Observable<Control3D>;
         /**
          * Gets or sets the parent container
          */
@@ -1052,6 +1099,8 @@ declare module BABYLON.GUI {
          * @returns null if behavior was not found else the requested behavior
          */
         getBehaviorByName(name: string): Nullable<Behavior<Control3D>>;
+        /** Gets or sets a boolean indicating if the control is visible */
+        isVisible: boolean;
         /**
          * Creates a new control
          * @param name defines the control name
@@ -1077,6 +1126,18 @@ declare module BABYLON.GUI {
          * @returns the attached mesh or null if none
          */
         protected _createMesh(scene: Scene): Nullable<Mesh>;
+        /** @hidden */
+        _onPointerMove(target: Control3D, coordinates: Vector3): void;
+        /** @hidden */
+        _onPointerEnter(target: Control3D): boolean;
+        /** @hidden */
+        _onPointerOut(target: Control3D): void;
+        /** @hidden */
+        _onPointerDown(target: Control3D, coordinates: Vector3, pointerId: number, buttonIndex: number): boolean;
+        /** @hidden */
+        _onPointerUp(target: Control3D, coordinates: Vector3, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
+        /** @hidden */
+        _processObservables(type: number, pickedPoint: Vector3, pointerId: number, buttonIndex: number): boolean;
         /**
          * Releases all associated resources
          */

+ 205 - 3
dist/preview release/gui/babylon.gui.js

@@ -5607,6 +5607,10 @@ var BABYLON;
              */
             function GUI3DManager(scene) {
                 var _this = this;
+                /** @hidden */
+                this._lastControlOver = {};
+                /** @hidden */
+                this._lastControlDown = {};
                 this._scene = scene || BABYLON.Engine.LastCreatedScene;
                 this._sceneDisposeObserver = this._scene.onDisposeObservable.add(function () {
                     _this._sceneDisposeObserver = null;
@@ -5616,6 +5620,22 @@ var BABYLON;
                 this._utilityLayer = new BABYLON.UtilityLayerRenderer(this._scene);
                 this._rootContainer = new GUI.Container3D("RootContainer");
                 this._rootContainer._host = this;
+                this._pointerMoveObserver = this._scene.onPrePointerObservable.add(function (pi, state) {
+                    var pointerEvent = (pi.event);
+                    if (_this._scene.isPointerCaptured(pointerEvent.pointerId)) {
+                        return;
+                    }
+                    if (pi.type !== BABYLON.PointerEventTypes.POINTERMOVE
+                        && pi.type !== BABYLON.PointerEventTypes.POINTERUP
+                        && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
+                        return;
+                    }
+                    var camera = _this._scene.cameraToUseForPointers || _this._scene.activeCamera;
+                    if (!camera) {
+                        return;
+                    }
+                    pi.skipOnPointerObservable = _this._doPicking(pi.type, pointerEvent);
+                });
             }
             Object.defineProperty(GUI3DManager.prototype, "scene", {
                 /** Gets the hosting scene */
@@ -5632,6 +5652,31 @@ var BABYLON;
                 enumerable: true,
                 configurable: true
             });
+            GUI3DManager.prototype._doPicking = function (type, pointerEvent) {
+                if (!this._utilityLayer) {
+                    return false;
+                }
+                var pointerId = pointerEvent.pointerId || 0;
+                var buttonIndex = pointerEvent.button;
+                var utilityScene = this._utilityLayer.utilityLayerScene;
+                var pickingInfo = utilityScene.pick(this._scene.pointerX, this._scene.pointerY);
+                if (!pickingInfo) {
+                    return false;
+                }
+                if (!pickingInfo.hit) {
+                    return false;
+                }
+                var control = (pickingInfo.pickedMesh.metadata);
+                if (!control._processObservables(type, pickingInfo.pickedPoint, pointerId, buttonIndex)) {
+                    if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
+                        if (this._lastControlOver[pointerId]) {
+                            this._lastControlOver[pointerId]._onPointerOut(this._lastControlOver[pointerId]);
+                        }
+                        delete this._lastControlOver[pointerId];
+                    }
+                }
+                return true;
+            };
             Object.defineProperty(GUI3DManager.prototype, "rootContainer", {
                 /**
                  * Gets the root container
@@ -5673,9 +5718,15 @@ var BABYLON;
              */
             GUI3DManager.prototype.dispose = function () {
                 this._rootContainer.dispose();
-                if (this._scene && this._sceneDisposeObserver) {
-                    this._scene.onDisposeObservable.remove(this._sceneDisposeObserver);
-                    this._sceneDisposeObserver = null;
+                if (this._scene) {
+                    if (this._pointerMoveObserver) {
+                        this._scene.onPrePointerObservable.remove(this._pointerMoveObserver);
+                        this._pointerMoveObserver = null;
+                    }
+                    if (this._sceneDisposeObserver) {
+                        this._scene.onDisposeObservable.remove(this._sceneDisposeObserver);
+                        this._sceneDisposeObserver = null;
+                    }
                 }
                 if (this._utilityLayer) {
                     this._utilityLayer.dispose();
@@ -5687,6 +5738,26 @@ var BABYLON;
     })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
 })(BABYLON || (BABYLON = {}));
 
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+var BABYLON;
+(function (BABYLON) {
+    var GUI;
+    (function (GUI) {
+        var Vector3WithInfo = /** @class */ (function (_super) {
+            __extends(Vector3WithInfo, _super);
+            function Vector3WithInfo(source, buttonIndex) {
+                if (buttonIndex === void 0) { buttonIndex = 0; }
+                var _this = _super.call(this, source.x, source.y) || this;
+                _this.buttonIndex = buttonIndex;
+                return _this;
+            }
+            return Vector3WithInfo;
+        }(BABYLON.Vector2));
+        GUI.Vector3WithInfo = Vector3WithInfo;
+    })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
+})(BABYLON || (BABYLON = {}));
+
 /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
 var BABYLON;
 (function (BABYLON) {
@@ -5704,6 +5775,34 @@ var BABYLON;
             /** Defines the control name */
             name) {
                 this.name = name;
+                this._downCount = 0;
+                this._enterCount = 0;
+                this._downPointerIds = {};
+                this._isVisible = true;
+                /**
+                * An event triggered when the pointer move over the control.
+                */
+                this.onPointerMoveObservable = new BABYLON.Observable();
+                /**
+                * 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
+                */
+                this.onPointerDownObservable = new BABYLON.Observable();
+                /**
+                * An event triggered when pointer up
+                */
+                this.onPointerUpObservable = new BABYLON.Observable();
+                /**
+                * An event triggered when a control is clicked on
+                */
+                this.onPointerClickObservable = new BABYLON.Observable();
+                /**
+                * An event triggered when pointer enters the control
+                */
+                this.onPointerEnterObservable = new BABYLON.Observable();
                 // Behaviors
                 this._behaviors = new Array();
             }
@@ -5774,6 +5873,23 @@ var BABYLON;
                 }
                 return null;
             };
+            Object.defineProperty(Control3D.prototype, "isVisible", {
+                /** Gets or sets a boolean indicating if the control is visible */
+                get: function () {
+                    return this._isVisible;
+                },
+                set: function (value) {
+                    if (this._isVisible === value) {
+                        return;
+                    }
+                    this._isVisible = value;
+                    if (this._mesh) {
+                        this._mesh.isVisible = value;
+                    }
+                },
+                enumerable: true,
+                configurable: true
+            });
             Object.defineProperty(Control3D.prototype, "typeName", {
                 /**
                  * Gets a string representing the class name
@@ -5795,6 +5911,8 @@ var BABYLON;
             Control3D.prototype.getAttachedMesh = function (scene) {
                 if (!this._mesh) {
                     this._mesh = this._createMesh(scene);
+                    this._mesh.isPickable = true;
+                    this._mesh.metadata = this; // Store the control on the metadata field in order to get it when picking
                 }
                 return this._mesh;
             };
@@ -5808,10 +5926,94 @@ var BABYLON;
                 // Do nothing by default
                 return null;
             };
+            // Pointers
+            /** @hidden */
+            Control3D.prototype._onPointerMove = function (target, coordinates) {
+                var canNotify = this.onPointerMoveObservable.notifyObservers(coordinates, -1, target, this);
+                if (canNotify && this.parent != null)
+                    this.parent._onPointerMove(target, coordinates);
+            };
+            /** @hidden */
+            Control3D.prototype._onPointerEnter = function (target) {
+                if (this._enterCount !== 0) {
+                    return false;
+                }
+                this._enterCount++;
+                var canNotify = this.onPointerEnterObservable.notifyObservers(this, -1, target, this);
+                if (canNotify && this.parent != null)
+                    this.parent._onPointerEnter(target);
+                return true;
+            };
+            /** @hidden */
+            Control3D.prototype._onPointerOut = function (target) {
+                this._enterCount = 0;
+                var canNotify = this.onPointerOutObservable.notifyObservers(this, -1, target, this);
+                if (canNotify && this.parent != null)
+                    this.parent._onPointerOut(target);
+            };
+            /** @hidden */
+            Control3D.prototype._onPointerDown = function (target, coordinates, pointerId, buttonIndex) {
+                if (this._downCount !== 0) {
+                    return false;
+                }
+                this._downCount++;
+                this._downPointerIds[pointerId] = true;
+                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);
+                return true;
+            };
+            /** @hidden */
+            Control3D.prototype._onPointerUp = function (target, coordinates, pointerId, buttonIndex, notifyClick) {
+                this._downCount = 0;
+                delete this._downPointerIds[pointerId];
+                var canNotifyClick = notifyClick;
+                if (notifyClick && this._enterCount > 0) {
+                    canNotifyClick = this.onPointerClickObservable.notifyObservers(new GUI.Vector3WithInfo(coordinates, buttonIndex), -1, target, this);
+                }
+                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);
+            };
+            /** @hidden */
+            Control3D.prototype._processObservables = function (type, pickedPoint, pointerId, buttonIndex) {
+                if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
+                    this._onPointerMove(this, pickedPoint);
+                    var previousControlOver = this._host._lastControlOver[pointerId];
+                    if (previousControlOver && previousControlOver !== this) {
+                        previousControlOver._onPointerOut(this);
+                    }
+                    if (previousControlOver !== this) {
+                        this._onPointerEnter(this);
+                    }
+                    this._host._lastControlOver[pointerId] = this;
+                    return true;
+                }
+                if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
+                    this._onPointerDown(this, pickedPoint, pointerId, buttonIndex);
+                    this._host._lastControlDown[pointerId] = this;
+                    this._host._lastPickedControl = this;
+                    return true;
+                }
+                if (type === BABYLON.PointerEventTypes.POINTERUP) {
+                    if (this._host._lastControlDown[pointerId]) {
+                        this._host._lastControlDown[pointerId]._onPointerUp(this, pickedPoint, pointerId, buttonIndex, true);
+                    }
+                    delete this._host._lastControlDown[pointerId];
+                    return true;
+                }
+                return false;
+            };
             /**
              * Releases all associated resources
              */
             Control3D.prototype.dispose = function () {
+                this.onPointerDownObservable.clear();
+                this.onPointerEnterObservable.clear();
+                this.onPointerMoveObservable.clear();
+                this.onPointerOutObservable.clear();
+                this.onPointerUpObservable.clear();
+                this.onPointerClickObservable.clear();
                 // Behaviors
                 for (var _i = 0, _a = this._behaviors; _i < _a.length; _i++) {
                     var behavior = _a[_i];

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


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

@@ -978,6 +978,16 @@ declare module BABYLON.GUI {
         private _sceneDisposeObserver;
         private _utilityLayer;
         private _rootContainer;
+        private _pointerMoveObserver;
+        _lastPickedControl: Control3D;
+        /** @hidden */
+        _lastControlOver: {
+            [pointerId: number]: Control3D;
+        };
+        /** @hidden */
+        _lastControlDown: {
+            [pointerId: number]: Control3D;
+        };
         /** Gets the hosting scene */
         readonly scene: Scene;
         readonly utilityLayer: Nullable<UtilityLayerRenderer>;
@@ -986,6 +996,7 @@ declare module BABYLON.GUI {
          * @param scene
          */
         constructor(scene?: Scene);
+        private _doPicking(type, pointerEvent);
         /**
          * Gets the root container
          */
@@ -1017,6 +1028,14 @@ declare module BABYLON.GUI {
 
 
 declare module BABYLON.GUI {
+    class Vector3WithInfo extends Vector2 {
+        buttonIndex: number;
+        constructor(source: Vector3, buttonIndex?: number);
+    }
+}
+
+
+declare module BABYLON.GUI {
     /**
      * Class used as base class for controls
      */
@@ -1026,6 +1045,34 @@ declare module BABYLON.GUI {
         /** @hidden */
         _host: GUI3DManager;
         private _mesh;
+        private _downCount;
+        private _enterCount;
+        private _downPointerIds;
+        private _isVisible;
+        /**
+        * An event triggered when the pointer move over the control.
+        */
+        onPointerMoveObservable: Observable<Vector3>;
+        /**
+        * An event triggered when the pointer move out of the control.
+        */
+        onPointerOutObservable: Observable<Control3D>;
+        /**
+        * An event triggered when the pointer taps the control
+        */
+        onPointerDownObservable: Observable<Vector3WithInfo>;
+        /**
+        * An event triggered when pointer up
+        */
+        onPointerUpObservable: Observable<Vector3WithInfo>;
+        /**
+        * An event triggered when a control is clicked on
+        */
+        onPointerClickObservable: Observable<Vector3WithInfo>;
+        /**
+        * An event triggered when pointer enters the control
+        */
+        onPointerEnterObservable: Observable<Control3D>;
         /**
          * Gets or sets the parent container
          */
@@ -1057,6 +1104,8 @@ declare module BABYLON.GUI {
          * @returns null if behavior was not found else the requested behavior
          */
         getBehaviorByName(name: string): Nullable<Behavior<Control3D>>;
+        /** Gets or sets a boolean indicating if the control is visible */
+        isVisible: boolean;
         /**
          * Creates a new control
          * @param name defines the control name
@@ -1082,6 +1131,18 @@ declare module BABYLON.GUI {
          * @returns the attached mesh or null if none
          */
         protected _createMesh(scene: Scene): Nullable<Mesh>;
+        /** @hidden */
+        _onPointerMove(target: Control3D, coordinates: Vector3): void;
+        /** @hidden */
+        _onPointerEnter(target: Control3D): boolean;
+        /** @hidden */
+        _onPointerOut(target: Control3D): void;
+        /** @hidden */
+        _onPointerDown(target: Control3D, coordinates: Vector3, pointerId: number, buttonIndex: number): boolean;
+        /** @hidden */
+        _onPointerUp(target: Control3D, coordinates: Vector3, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
+        /** @hidden */
+        _processObservables(type: number, pickedPoint: Vector3, pointerId: number, buttonIndex: number): boolean;
         /**
          * Releases all associated resources
          */

+ 162 - 1
gui/src/3D/controls/control3D.ts

@@ -8,6 +8,41 @@ module BABYLON.GUI {
         /** @hidden */
         public _host: GUI3DManager;
         private _mesh: Nullable<Mesh>;
+        private _downCount = 0;
+        private _enterCount = 0;
+        private _downPointerIds:{[id:number] : boolean} = {};
+        private _isVisible = true;
+        
+        /**
+        * 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>();
+       
 
         /**
          * Gets or sets the parent container
@@ -86,7 +121,23 @@ module BABYLON.GUI {
             }
 
             return null;
-        }        
+        }      
+        
+        /** Gets or sets a boolean indicating if the control is visible */
+        public get isVisible(): boolean {
+            return this._isVisible;
+        }
+
+        public set isVisible(value: boolean) {
+            if (this._isVisible === value) {
+                return;
+            }
+
+            this._isVisible = value;
+            if (this._mesh) {
+                this._mesh.isVisible = value;
+            }
+        }
 
         /**
          * Creates a new control
@@ -116,6 +167,8 @@ module BABYLON.GUI {
         public getAttachedMesh(scene: Scene): Nullable<Mesh> {
             if (!this._mesh) {
                 this._mesh = this._createMesh(scene);
+                this._mesh!.isPickable = true;
+                this._mesh!.metadata = this; // Store the control on the metadata field in order to get it when picking
             }
 
             return this._mesh;
@@ -132,10 +185,118 @@ module BABYLON.GUI {
             return null;
         }
 
+        // Pointers
+
+        /** @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);
+        }
+
+        /** @hidden */
+        public _onPointerEnter(target: Control3D): boolean {
+            if (this._enterCount !== 0) {
+                return false;
+            }
+
+            this._enterCount++;
+
+            var canNotify: boolean = this.onPointerEnterObservable.notifyObservers(this, -1, target, this);
+
+            if (canNotify && this.parent != null) this.parent._onPointerEnter(target);
+
+            return true;
+        }
+
+        /** @hidden */
+        public _onPointerOut(target: Control3D): void {
+            this._enterCount = 0;
+
+            var canNotify: boolean = this.onPointerOutObservable.notifyObservers(this, -1, target, this);
+
+            if (canNotify && this.parent != null) this.parent._onPointerOut(target);
+        }
+
+        /** @hidden */
+        public _onPointerDown(target: Control3D, coordinates: Vector3, pointerId:number, buttonIndex: number): boolean {
+            if (this._downCount !== 0) {
+                return false;
+            }
+
+            this._downCount++;
+
+            this._downPointerIds[pointerId] = true;
+
+            var canNotify: boolean = this.onPointerDownObservable.notifyObservers(new Vector3WithInfo(coordinates, buttonIndex), -1, target, this);
+
+            if (canNotify && this.parent != null) this.parent._onPointerDown(target, coordinates, pointerId, buttonIndex);
+
+            return true;
+        }
+
+        /** @hidden */
+        public _onPointerUp(target: Control3D, coordinates: Vector3, pointerId:number, buttonIndex: number, notifyClick: boolean): void {
+            this._downCount = 0;
+
+            delete this._downPointerIds[pointerId];
+
+            var canNotifyClick: boolean = notifyClick;
+			if (notifyClick && this._enterCount > 0) {
+				canNotifyClick = this.onPointerClickObservable.notifyObservers(new Vector3WithInfo(coordinates, buttonIndex), -1, target, this);
+			}
+			var canNotify: boolean = this.onPointerUpObservable.notifyObservers(new Vector3WithInfo(coordinates, buttonIndex), -1, target, this);
+
+            if (canNotify && this.parent != null) this.parent._onPointerUp(target, coordinates, pointerId, buttonIndex, canNotifyClick);
+        }  
+        
+        /** @hidden */
+        public _processObservables(type: number, pickedPoint: Vector3, pointerId:number, buttonIndex: number): boolean {
+            if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
+                this._onPointerMove(this, pickedPoint);
+
+                var previousControlOver = this._host._lastControlOver[pointerId];
+                if (previousControlOver && previousControlOver !== this) {
+                    previousControlOver._onPointerOut(this);
+                }
+
+                if (previousControlOver !== this) {
+                    this._onPointerEnter(this);
+                }
+
+                this._host._lastControlOver[pointerId] = this;
+                return true;
+            }
+
+            if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
+                this._onPointerDown(this, pickedPoint, pointerId, buttonIndex);
+                this._host._lastControlDown[pointerId] = this;
+                this._host._lastPickedControl = this;
+                return true;
+            }
+
+            if (type === BABYLON.PointerEventTypes.POINTERUP) {
+                if (this._host._lastControlDown[pointerId]) {
+                    this._host._lastControlDown[pointerId]._onPointerUp(this, pickedPoint, pointerId, buttonIndex, true);
+                }
+                delete this._host._lastControlDown[pointerId];
+                return true;
+            }
+
+            return false;
+        }        
+
         /**
          * Releases all associated resources
          */
         public dispose() {
+            this.onPointerDownObservable.clear();
+            this.onPointerEnterObservable.clear();
+            this.onPointerMoveObservable.clear();
+            this.onPointerOutObservable.clear();
+            this.onPointerUpObservable.clear();
+            this.onPointerClickObservable.clear();
+
             // Behaviors
             for (var behavior of this._behaviors) {
                 behavior.detach();

+ 71 - 3
gui/src/3D/gui3DManager.ts

@@ -9,6 +9,12 @@ module BABYLON.GUI {
         private _sceneDisposeObserver: Nullable<Observer<Scene>>;
         private _utilityLayer: Nullable<UtilityLayerRenderer>;
         private _rootContainer: Container3D;
+        private _pointerObserver: Nullable<Observer<PointerInfoPre>>;
+        public _lastPickedControl: Control3D;
+        /** @hidden */
+        public _lastControlOver: {[pointerId:number]: Control3D} = {};
+        /** @hidden */
+        public _lastControlDown: {[pointerId:number]: Control3D} = {};      
 
         /** Gets the hosting scene */
         public get scene(): Scene {
@@ -35,6 +41,62 @@ module BABYLON.GUI {
 
             this._rootContainer = new Container3D("RootContainer");
             this._rootContainer._host = this;
+            
+            this._pointerObserver = this._scene.onPrePointerObservable.add((pi, state) => {
+                let pointerEvent = <PointerEvent>(pi.event);
+                if (this._scene.isPointerCaptured(pointerEvent.pointerId)) {
+                    return;
+                }
+
+                if (pi.type !== BABYLON.PointerEventTypes.POINTERMOVE
+                    && pi.type !== BABYLON.PointerEventTypes.POINTERUP
+                    && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
+                    return;
+                }
+
+                let camera = this._scene.cameraToUseForPointers || this._scene.activeCamera;
+
+                if (!camera) {
+                    return;
+                }
+
+                pi.skipOnPointerObservable = this._doPicking(pi.type, pointerEvent)
+            });
+        }
+
+        private _doPicking(type: number, pointerEvent: PointerEvent): boolean {
+            if (!this._utilityLayer || this._utilityLayer.utilityLayerScene.activeCamera === null) {
+                return false;                
+            }
+
+            let pointerId = pointerEvent.pointerId || 0;
+            let buttonIndex = pointerEvent.button;
+            var utilityScene = this._utilityLayer.utilityLayerScene;
+
+            let pickingInfo = utilityScene.pick(this._scene.pointerX, this._scene.pointerY);
+            if (!pickingInfo || !pickingInfo.hit) {
+                var previousControlOver = this._lastControlOver[pointerId];
+                if (previousControlOver) {
+                    previousControlOver._onPointerOut(previousControlOver);
+                    delete this._lastControlOver[pointerId];
+                }                
+                return false;
+            }
+
+            let control = <Control3D>(pickingInfo.pickedMesh!.metadata);
+
+            if (!control._processObservables(type, pickingInfo.pickedPoint!, pointerId, buttonIndex)) {
+
+                if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
+                    if (this._lastControlOver[pointerId]) {
+                        this._lastControlOver[pointerId]._onPointerOut(this._lastControlOver[pointerId]);
+                    }
+
+                    delete this._lastControlOver[pointerId];
+                }
+            }
+
+            return true;
         }
 
         /**
@@ -79,9 +141,15 @@ module BABYLON.GUI {
         public dispose() {
             this._rootContainer.dispose();
 
-            if (this._scene && this._sceneDisposeObserver) {
-                this._scene.onDisposeObservable.remove(this._sceneDisposeObserver);
-                this._sceneDisposeObserver = null;
+            if (this._scene) {
+                if (this._pointerObserver) {
+                    this._scene.onPrePointerObservable.remove(this._pointerObserver);
+                    this._pointerObserver = null;
+                }
+                if (this._sceneDisposeObserver) {
+                    this._scene.onDisposeObservable.remove(this._sceneDisposeObserver);
+                    this._sceneDisposeObserver = null;
+                }                
             }
 
             if (this._utilityLayer) {

+ 9 - 0
gui/src/3D/vector3WithInfo.ts

@@ -0,0 +1,9 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON.GUI {
+    export class Vector3WithInfo extends Vector3 {        
+        public constructor(source: Vector3, public buttonIndex: number = 0) {
+            super(source.x, source.y, source.z);
+        }
+    }
+}