Browse Source

Mouse wheel for FreeCamera: Better layout of user toggles.

duncan law 4 years ago
parent
commit
72b5d2d53f

+ 35 - 20
src/Cameras/Inputs/BaseCameraMouseWheelInput.ts

@@ -43,7 +43,9 @@ export abstract class BaseCameraMouseWheelInput implements ICameraInput<Camera>
     /**
     /**
      * Attach the input controls to a specific dom element to get the input from.
      * Attach the input controls to a specific dom element to get the input from.
      * @param element Defines the element the controls should be listened from
      * @param element Defines the element the controls should be listened from
-     * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
+     * @param noPreventDefault Defines whether event caught by the controls
+     *   should call preventdefault().
+     *   (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
      */
      */
     public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
     public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
         this._wheel = (pointer, _) => {
         this._wheel = (pointer, _) => {
@@ -52,38 +54,39 @@ export abstract class BaseCameraMouseWheelInput implements ICameraInput<Camera>
 
 
             const event = <MouseWheelEvent>pointer.event;
             const event = <MouseWheelEvent>pointer.event;
 
 
-            // Chrome, Safari: event.deltaY
-            // IE: event.wheelDelta
-            // Firefox: event.detail (inverted)
-            //const wheelDelta = Math.max(-1, Math.min(1,
-            //    (event.deltaY || (<any>event).wheelDelta || -event.detail)));
-
-            const platformScale = 
+            const platformScale =
                 event.deltaMode === WheelEvent.DOM_DELTA_LINE ? this._ffMultiplier : 1;
                 event.deltaMode === WheelEvent.DOM_DELTA_LINE ? this._ffMultiplier : 1;
 
 
-            if(event.deltaY !== undefined ) {
+            if (event.deltaY !== undefined) {
                 // Most recent browsers versions have delta properties.
                 // Most recent browsers versions have delta properties.
                 // Firefox >= v17  (Has WebGL >= v4)
                 // Firefox >= v17  (Has WebGL >= v4)
                 // Chrome >=  v31  (Has WebGL >= v8)
                 // Chrome >=  v31  (Has WebGL >= v8)
                 // Edge >=    v12  (Has WebGl >= v12)
                 // Edge >=    v12  (Has WebGl >= v12)
                 // https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent
                 // https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent
-                this._wheelDeltaX += this.wheelPrecisionX * platformScale * event.deltaX;
-                this._wheelDeltaY -= this.wheelPrecisionY * platformScale * event.deltaY;
-                this._wheelDeltaZ += this.wheelPrecisionZ * platformScale * event.deltaZ;
-            } else if((<any>event).wheelDeltaY !== undefined ) {
+                this._wheelDeltaX +=
+                    this.wheelPrecisionX * platformScale * event.deltaX / this._normalize;
+                this._wheelDeltaY -=
+                    this.wheelPrecisionY * platformScale * event.deltaY / this._normalize;
+                this._wheelDeltaZ +=
+                    this.wheelPrecisionZ * platformScale * event.deltaZ / this._normalize;
+            } else if ((<any>event).wheelDeltaY !== undefined) {
                 // Unsure whether these catch anything more. Documentation
                 // Unsure whether these catch anything more. Documentation
                 // online is contradictory.
                 // online is contradictory.
                 this._wheelDeltaX +=
                 this._wheelDeltaX +=
-                    this.wheelPrecisionX * platformScale * (<any>event).wheelDeltaX;
+                    this.wheelPrecisionX * platformScale * 
+                    (<any>event).wheelDeltaX / this._normalize;
                 this._wheelDeltaY -=
                 this._wheelDeltaY -=
-                    this.wheelPrecisionY * platformScale * (<any>event).wheelDeltaY;
+                    this.wheelPrecisionY * platformScale *
+                    (<any>event).wheelDeltaY / this._normalize;
                 this._wheelDeltaZ +=
                 this._wheelDeltaZ +=
-                    this.wheelPrecisionZ * platformScale * (<any>event).wheelDeltaZ;
-            } else if((<any>event).wheelDelta) {
+                    this.wheelPrecisionZ * platformScale *
+                    (<any>event).wheelDeltaZ / this._normalize;
+            } else if ((<any>event).wheelDelta) {
                 // IE >= v9   (Has WebGL >= v11)
                 // IE >= v9   (Has WebGL >= v11)
                 // Maybe others?
                 // Maybe others?
-                this._wheelDeltaY -= this.wheelPrecisionY * (<any>event).wheelDelta;
-            } else if(event.detail) {
+                this._wheelDeltaY -=
+                    this.wheelPrecisionY * (<any>event).wheelDelta / this._normalize;
+            } else if (event.detail) {
                 // Firefox < v17  (Has WebGL >= v4)
                 // Firefox < v17  (Has WebGL >= v4)
                 // TODO How should we scale this?
                 // TODO How should we scale this?
                 // Since it's Firefox, it's probably the same as
                 // Since it's Firefox, it's probably the same as
@@ -91,6 +94,11 @@ export abstract class BaseCameraMouseWheelInput implements ICameraInput<Camera>
                 // ie: we can presume it needs scaled to match per-pixel.
                 // ie: we can presume it needs scaled to match per-pixel.
                 this._wheelDeltaY +=
                 this._wheelDeltaY +=
                     this.wheelPrecisionY * this._ffMultiplier * event.detail;
                     this.wheelPrecisionY * this._ffMultiplier * event.detail;
+                if ( "axis" in event && 
+                      (<any>event).axis === (<any>event).HORIZONTAL_AXIS ) {
+                    this._wheelDeltaX = this._wheelDeltaY;
+                    this._wheelDeltaY = 0;
+                }
             }
             }
 
 
             if (event.preventDefault) {
             if (event.preventDefault) {
@@ -151,7 +159,7 @@ export abstract class BaseCameraMouseWheelInput implements ICameraInput<Camera>
      */
      */
     protected _wheelDeltaZ: number = 0;
     protected _wheelDeltaZ: number = 0;
 
 
-    /*
+    /**
      * Firefox uses a different scheme to report scroll distances to other
      * Firefox uses a different scheme to report scroll distances to other
      * browsers. Rather than use complicated methods to calculate the exact
      * browsers. Rather than use complicated methods to calculate the exact
      * multiple we need to apply, let's just cheat and use a constant.
      * multiple we need to apply, let's just cheat and use a constant.
@@ -159,4 +167,11 @@ export abstract class BaseCameraMouseWheelInput implements ICameraInput<Camera>
      * https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line
      * https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line
      */
      */
     private readonly _ffMultiplier = 12;
     private readonly _ffMultiplier = 12;
+
+    /**
+     * Different event attributes for wheel data fall into a few set ranges.
+     * Some relevant but dated date here:
+     * https://stackoverflow.com/questions/5527601/normalizing-mousewheel-speed-across-browsers
+     */
+    private readonly _normalize = 120;
 }
 }

+ 49 - 238
src/Cameras/Inputs/freeCameraMouseWheelInput.ts

@@ -6,29 +6,6 @@ import { BaseCameraMouseWheelInput } from "../../Cameras/Inputs/BaseCameraMouseW
 import { Matrix, Vector3 } from "../../Maths/math.vector";
 import { Matrix, Vector3 } from "../../Maths/math.vector";
 
 
 /**
 /**
- * Defines Mouse wheel axis. A typical laptop trackpad emulates a mouse wheel in
- * X and Y axis. Many modern browsers permit X, Y and Z.
- */
-export enum FreeCameraMouseWheelAxis {
-    /**
-     * No mouse wheel set.
-     */
-    NONE,
-    /**
-     * Mouse wheel X axis is set.
-     */
-    X,
-    /**
-     * Mouse wheel Y axis is set.
-     */
-    Y,
-    /**
-     * Mouse wheel Z axis is set.
-     */
-    Z
-}
-
-/**
  * A user configurable callback to be called on mouse wheel movement.
  * A user configurable callback to be called on mouse wheel movement.
  */
  */
 export interface FreeCameraMouseWheelCustomCallback {
 export interface FreeCameraMouseWheelCustomCallback {
@@ -46,15 +23,7 @@ export interface FreeCameraMouseWheelCustomCallback {
  * @see https://doc.babylonjs.com/how_to/customizing_camera_inputs
  * @see https://doc.babylonjs.com/how_to/customizing_camera_inputs
  */
  */
 export class FreeCameraMouseWheelInput extends BaseCameraMouseWheelInput {
 export class FreeCameraMouseWheelInput extends BaseCameraMouseWheelInput {
-    /**
-     * Manage the mouse scroll wheel input to control the movement of a free camera.
-     * @see https://doc.babylonjs.com/how_to/customizing_camera_inputs
-     */
-    constructor() {
-        super();
-        this._setAllAxis();
-    }
-
+    
     /**
     /**
      * Defines the camera the input is attached to.
      * Defines the camera the input is attached to.
      */
      */
@@ -68,204 +37,90 @@ export class FreeCameraMouseWheelInput extends BaseCameraMouseWheelInput {
         return "FreeCameraMouseWheelInput";
         return "FreeCameraMouseWheelInput";
     }
     }
 
 
-    /**
-     * Log error messages if basic misconfiguration has occurred.
-     */
-    public warningEnable: boolean = true;
-
-    private _cameraMoveX: FreeCameraMouseWheelAxis = FreeCameraMouseWheelAxis.X;
-
-    /**
-     * Get which mouse wheel axis moves along camera's X axis (if any).
-     * @returns the currently configured mouse wheel axis.
-     */
-    @serialize()
-    public get cameraMoveX(): FreeCameraMouseWheelAxis {
-        return this._cameraMoveX;
-    }
-
-    /**
-     * Set which mouse wheel axis moves along camera's X axis (if any).
-     * @param axis is the desired mouse wheel axis.
-     */
-    public set cameraMoveX(axis: FreeCameraMouseWheelAxis) {
-        this._cameraMoveX = axis;
-        this._setAllAxis();
-        this._sanityCheck();
-    }
-
-    private _cameraMoveY: FreeCameraMouseWheelAxis = FreeCameraMouseWheelAxis.NONE;
-
-    /**
-     * Get which mouse wheel axis moves along camera's Y axis (if any).
-     * @returns the currently configured mouse wheel axis.
-     */
-    @serialize()
-    public get cameraMoveY(): FreeCameraMouseWheelAxis {
-        return this._cameraMoveY;
-    }
-
-    /**
-     * Set which mouse wheel axis moves along camera's Y axis (if any).
-     * @param axis is the desired mouse wheel axis.
-     */
-    public set cameraMoveY(axis: FreeCameraMouseWheelAxis) {
-        this._cameraMoveY = axis;
-        this._setAllAxis();
-        this._sanityCheck();
-    }
-
-    private _cameraMoveZ: FreeCameraMouseWheelAxis = FreeCameraMouseWheelAxis.Y;
-
-    /**
-     * Get which mouse wheel axis moves along camera's X axis (if any).
-     * @returns the currently configured mouse wheel axis.
-     */
-    @serialize()
-    public get cameraMoveZ(): FreeCameraMouseWheelAxis {
-        return this._cameraMoveZ;
-    }
-
-    /**
-     * Set which mouse wheel axis moves along camera's Z axis (if any).
-     * @param axis is the desired mouse wheel axis.
-     */
-    public set cameraMoveZ(axis: FreeCameraMouseWheelAxis) {
-        this._cameraMoveZ = axis;
-        this._setAllAxis();
-        this._sanityCheck();
-    }
-
-    private _cameraWorldPosX: FreeCameraMouseWheelAxis = FreeCameraMouseWheelAxis.NONE;
+    private _moveRelative = Vector3.Zero();
+    private _rotateRelative = Vector3.Zero();
+    private _moveScene = Vector3.Zero();
 
 
-    /**
-     * Get which mouse wheel axis moves the camera along the scene's X axis (if any).
-     * @returns the currently configured mouse wheel axis.
-     */
-    @serialize()
-    public get cameraWorldPosX(): FreeCameraMouseWheelAxis {
-        return this._cameraWorldPosX;
-    }
+    private _wheelXAction: Nullable<Vector3> = this._moveRelative;
+    private _wheelXActionProperty: Nullable<number> = 0;
+    private _wheelYAction: Nullable<Vector3> = this._moveRelative;
+    private _wheelYActionProperty: Nullable<number> = 2;
+    private _wheelZAction: Nullable<Vector3> = null;
+    private _wheelZActionProperty: Nullable<number> = null;
 
 
-    /**
-     * Set which mouse wheel axis moves the camera along the scene's X axis (if any).
-     * @param axis is the desired mouse wheel axis.
-     */
-    public set cameraWorldPosX(axis: FreeCameraMouseWheelAxis) {
-        this._cameraWorldPosX = axis;
-        this._setAllAxis();
-        this._sanityCheck();
-    }
-
-    private _cameraWorldPosY: FreeCameraMouseWheelAxis = FreeCameraMouseWheelAxis.NONE;
-
-    /**
-     * Get which mouse wheel axis moves the camera along the scene's Y axis (if any).
-     * @returns the currently configured mouse wheel axis.
-     */
-    @serialize()
-    public get cameraWorldPosY(): FreeCameraMouseWheelAxis {
-        return this._cameraWorldPosY;
-    }
-
-    /**
-     * Set which mouse wheel axis moves the camera along the scene's Y axis (if any).
-     * @param axis is the desired mouse wheel axis.
-     */
-    public set cameraWorldPosY(axis: FreeCameraMouseWheelAxis) {
-        this._cameraWorldPosY = axis;
-        this._setAllAxis();
-        this._sanityCheck();
-    }
-
-
-    private _cameraWorldPosZ: FreeCameraMouseWheelAxis = FreeCameraMouseWheelAxis.NONE;
-
-    /**
-     * Get which mouse wheel axis moves the camera along the scene's Z axis (if any).
-     * @returns the currently configured mouse wheel axis.
-     */
-    @serialize()
-    public get cameraWorldPosZ(): FreeCameraMouseWheelAxis {
-        return this._cameraWorldPosZ;
-    }
+    private _updateCamera(
+        value: number, action: Nullable<Vector3>, property: Nullable<number>): void {
+            if(value === 0) {
+                // Wheel has not moved.
+                return;
+            }
+            if(action === null || property === null) {
+                // Wheel axis not configured.
+                return;
+            }
 
 
-    /**
-     * Set which mouse wheel axis moves the camera along the scene's Z axis (if any).
-     * @param axis is the desired mouse wheel axis.
-     */
-    public set cameraWorldPosZ(axis: FreeCameraMouseWheelAxis) {
-        this._cameraWorldPosZ = axis;
-        this._setAllAxis();
-        this._sanityCheck();
+            switch(property) {
+                case 0:
+                    action.set(value, 0, 0);
+                    break;
+                case 1:
+                    action.set(0, value, 0);
+                    break;
+                case 2:
+                    action.set(0, 0, value);
+                    break;
+                default:
+                    console.warn("Invalid value");
+            }
     }
     }
 
 
     /**
     /**
-     * Set user configurable callback to be called on mouse wheel movement
-     * to be used whenever the default functionality of this class does not
+     * A user configurable callback to be called on mouse wheel movement.
+     * To be used whenever the default functionality of this class does not
      * change the required camera parameter by default.
      * change the required camera parameter by default.
-     * @param customCallback is a callback function which if set will get called
-     * whenever the mouse wheel value(s) change.
      */
      */
     @serialize()
     @serialize()
     public customCallback: Nullable<FreeCameraMouseWheelCustomCallback> = null;
     public customCallback: Nullable<FreeCameraMouseWheelCustomCallback> = null;
 
 
-    private _cameraUpdate = Vector3.Zero();
-    private _worldUpdate = Vector3.Zero();
-
     /**
     /**
      * Called for each rendered frame.
      * Called for each rendered frame.
      */
      */
     public checkInputs(): void {
     public checkInputs(): void {
-        if(this._wheelDeltaX === 0 &&
+        if (this._wheelDeltaX === 0 &&
                 this._wheelDeltaY === 0 &&
                 this._wheelDeltaY === 0 &&
                 this._wheelDeltaZ == 0) {
                 this._wheelDeltaZ == 0) {
             return;
             return;
         }
         }
 
 
-        this._cameraUpdate.setAll(0);
-        this._worldUpdate.setAll(0);
+        this._moveRelative.setAll(0);
+        this._rotateRelative.setAll(0);
+        this._moveScene.setAll(0);
 
 
-        // Iterate over all camera properties we might want to update.
-        this._allAxis.forEach((axis) => {
-            const [wheelAxis, updater, component] = axis;
-
-            if(this._wheelDeltaX !== 0 && wheelAxis === FreeCameraMouseWheelAxis.X) {
-                updater.set(component == "x" ? this._wheelDeltaX/100 : 0,
-                            component == "y" ? this._wheelDeltaX/100 : 0,
-                            component == "z" ? this._wheelDeltaX/100 : 0);
-            }
-            if(this._wheelDeltaY !== 0 && wheelAxis === FreeCameraMouseWheelAxis.Y) {
-                updater.set(component == "x" ? this._wheelDeltaY/100 : 0,
-                            component == "y" ? this._wheelDeltaY/100 : 0,
-                            component == "z" ? this._wheelDeltaY/100 : 0);
-            }
-            if(this._wheelDeltaZ !== 0 && wheelAxis === FreeCameraMouseWheelAxis.Z) {
-                updater.set(component == "x" ? this._wheelDeltaZ/100 : 0,
-                            component == "y" ? this._wheelDeltaZ/100 : 0,
-                            component == "z" ? this._wheelDeltaZ/100 : 0);
-            }
-        });
+        this._updateCamera(this._wheelDeltaX, this._wheelXAction, this._wheelXActionProperty);
+        this._updateCamera(this._wheelDeltaY, this._wheelYAction, this._wheelYActionProperty);
+        this._updateCamera(this._wheelDeltaZ, this._wheelZAction, this._wheelZActionProperty);
 
 
         if (this.camera.getScene().useRightHandedSystem) {
         if (this.camera.getScene().useRightHandedSystem) {
             // TODO: Does this need done for worldUpdate too?
             // TODO: Does this need done for worldUpdate too?
-            this._cameraUpdate.z *= -1;
+            this._moveRelative.z *= -1;
         }
         }
 
 
         // Convert updates relative to camera to world position update.
         // Convert updates relative to camera to world position update.
         const cameraTransformMatrix = Matrix.Zero();
         const cameraTransformMatrix = Matrix.Zero();
         this.camera.getViewMatrix().invertToRef(cameraTransformMatrix);
         this.camera.getViewMatrix().invertToRef(cameraTransformMatrix);
-        
+
         const transformedDirection = Vector3.Zero();
         const transformedDirection = Vector3.Zero();
         Vector3.TransformNormalToRef(
         Vector3.TransformNormalToRef(
-            this._cameraUpdate, cameraTransformMatrix, transformedDirection);
+            this._moveRelative, cameraTransformMatrix, transformedDirection);
 
 
         // Apply updates to camera position.
         // Apply updates to camera position.
+        this.camera.cameraRotation.x += this._rotateRelative.x / 200;
+        this.camera.cameraRotation.y += this._rotateRelative.y / 200;
         this.camera.cameraDirection.addInPlace(transformedDirection);
         this.camera.cameraDirection.addInPlace(transformedDirection);
-        this.camera.cameraDirection.addInPlace(this._worldUpdate);
+        this.camera.cameraDirection.addInPlace(this._moveScene);
 
 
         // Do the user defined customCallback if set.
         // Do the user defined customCallback if set.
-        if(this.customCallback !== null) {
+        if (this.customCallback !== null) {
             this.customCallback(
             this.customCallback(
                 this.camera, this._wheelDeltaX, this._wheelDeltaY, this._wheelDeltaZ);
                 this.camera, this._wheelDeltaX, this._wheelDeltaY, this._wheelDeltaZ);
         }
         }
@@ -275,50 +130,6 @@ export class FreeCameraMouseWheelInput extends BaseCameraMouseWheelInput {
         this._wheelDeltaY = 0;
         this._wheelDeltaY = 0;
         this._wheelDeltaZ = 0;
         this._wheelDeltaZ = 0;
     }
     }
-    
-    /**
-     * Gather all user configurable axis into one collection so we can itterate
-     * over them later.
-     */
-    private _allAxis: [FreeCameraMouseWheelAxis, Vector3, string][];
-    private _setAllAxis(): void {
-        this._allAxis = [
-            [this._cameraMoveX, this._cameraUpdate, "x"],
-            [this._cameraMoveY, this._cameraUpdate, "y"],
-            [this._cameraMoveZ, this._cameraUpdate, "z"],
-            [this._cameraWorldPosX, this._worldUpdate, "x"],
-            [this._cameraWorldPosY, this._worldUpdate, "y"],
-            [this._cameraWorldPosZ, this._worldUpdate, "z"] ];
-    }
-
-    /**
-     * Display a warning on console if there are obvious misconfiguration.
-     * Eg: A single mouse wheel axis controlling multiple camera attributes.
-     */
-    private _sanityCheck(): void {
-        if(!this.warningEnable) {
-            return;
-        }
-        const labels: {[id: number]: string} = {1: "X", 2: "Y", 3: "Z"};
-        
-        const configuredCount: [number, number, number, number] = [0, 0, 0, 0];
-        this._allAxis.forEach((axis) => {
-            const wheelAxis = axis[0];
-
-            configuredCount[wheelAxis] += 1;
-        });
-
-        // Warn of misconfiguration.
-        for(let axis = FreeCameraMouseWheelAxis.X;
-            axis <= FreeCameraMouseWheelAxis.Z; 
-            axis += 1) {
-                if(configuredCount[axis] > 1) {
-                    console.warn(
-                        `Touch pad ${labels[axis]} axis assigned to ` +
-                        `${configuredCount[axis]} tasks. (Only 1 will have any effect.)`);
-                }
-        }
-    }
 }
 }
 
 
 (<any>CameraInputTypes)["FreeCameraMouseWheelInput"] = FreeCameraMouseWheelInput;
 (<any>CameraInputTypes)["FreeCameraMouseWheelInput"] = FreeCameraMouseWheelInput;