From 9d5cb0ab95fa2cb81d7957d0093fcb90795cfd7a Mon Sep 17 00:00:00 2001 From: Michael Mainguy Date: Thu, 27 Jul 2023 15:43:34 -0500 Subject: [PATCH] Added Initial Config Menu. --- src/app.ts | 2 +- src/controllers/base.ts | 19 +++++- src/controllers/controllers.ts | 6 +- src/controllers/left.ts | 29 +++++++- src/controllers/right.ts | 10 +-- src/controllers/rigplatform.ts | 8 +-- src/menus/amenu.ts | 11 --- src/menus/configMenu.ts | 68 +++++++++++++++++++ src/menus/{bmenu.ts => editMenu.ts} | 10 ++- src/toolbox/toolbox.ts | 28 ++++---- src/util/appConfig.ts | 19 ++++++ ...EventMapper.ts => dualshockEventMapper.ts} | 8 ++- src/util/myMenu.ts | 10 --- 13 files changed, 169 insertions(+), 59 deletions(-) delete mode 100644 src/menus/amenu.ts create mode 100644 src/menus/configMenu.ts rename src/menus/{bmenu.ts => editMenu.ts} (95%) create mode 100644 src/util/appConfig.ts rename src/util/{DualshockEventMapper.ts => dualshockEventMapper.ts} (92%) delete mode 100644 src/util/myMenu.ts diff --git a/src/app.ts b/src/app.ts index b9db21a..29afda5 100644 --- a/src/app.ts +++ b/src/app.ts @@ -23,7 +23,7 @@ import HavokPhysics from "@babylonjs/havok"; import {Rigplatform} from "./controllers/rigplatform"; import {DiagramManager} from "./diagram/diagramManager"; import {Toolbox} from "./toolbox/toolbox"; -import {DualshockEventMapper} from "./util/DualshockEventMapper"; +import {DualshockEventMapper} from "./util/dualshockEventMapper"; import log from "loglevel"; diff --git a/src/controllers/base.ts b/src/controllers/base.ts index 0c6dba7..1b92daf 100644 --- a/src/controllers/base.ts +++ b/src/controllers/base.ts @@ -24,6 +24,7 @@ export class Base { protected previousRotation: Vector3 = null; protected previousScaling: Vector3 = null; protected previousPosition: Vector3 = null; + protected readonly xr: WebXRDefaultExperience; constructor(controller: WebXRInputSource, scene: Scene, xr: WebXRDefaultExperience) { @@ -42,18 +43,30 @@ export class Base { this.initGrip(init.components['xr-standard-squeeze']); }); } + + public disable() { + this.controller.motionController.rootMesh.setEnabled(false); + this.controller.pointer.setEnabled(false); + } + + public enable() { + this.controller.motionController.rootMesh.setEnabled(true); + this.controller.pointer.setEnabled(true); + } + private createCopy(mesh: AbstractMesh) { if (!mesh.isAnInstance) { - return new InstancedMesh("new", (mesh as Mesh)); + return new InstancedMesh("new", (mesh as Mesh)); } else { - return new InstancedMesh("new", (mesh as InstancedMesh).sourceMesh); + return new InstancedMesh("new", (mesh as InstancedMesh).sourceMesh); } } + private initGrip(grip: WebXRControllerComponent) { grip.onButtonStateChangedObservable.add(() => { if (grip.changes.pressed) { - if (grip.pressed){ + if (grip.pressed) { let mesh = this.scene.meshUnderPointer; if (this.xr.pointerSelection.getMeshUnderPointer) { mesh = this.xr.pointerSelection.getMeshUnderPointer(this.controller.uniqueId); diff --git a/src/controllers/controllers.ts b/src/controllers/controllers.ts index 0bf2ced..9d3b455 100644 --- a/src/controllers/controllers.ts +++ b/src/controllers/controllers.ts @@ -1,7 +1,9 @@ import {AbstractMesh, Observable, TransformNode} from "@babylonjs/core"; +export type ControllerEventType = { + type: string +} export class Controllers { public static movable: TransformNode | AbstractMesh; - public static controllerObserver = new Observable(); - + public static controllerObserver: Observable = new Observable(); } \ No newline at end of file diff --git a/src/controllers/left.ts b/src/controllers/left.ts index 1e49eb7..d886479 100644 --- a/src/controllers/left.ts +++ b/src/controllers/left.ts @@ -1,17 +1,18 @@ -import {Scene, Vector3, WebXRDefaultExperience, WebXRInputSource} from "@babylonjs/core"; +import {Scene, Vector3, WebXRControllerComponent, WebXRDefaultExperience, WebXRInputSource} from "@babylonjs/core"; import {Base} from "./base"; import {Controllers} from "./controllers"; import log from "loglevel"; +import {ConfigMenu} from "../menus/configMenu"; export class Left extends Base { public static instance: Left; - + public configMenu: ConfigMenu; constructor(controller: WebXRInputSource, scene: Scene, xr: WebXRDefaultExperience) { super(controller, scene, xr); - + this.configMenu = new ConfigMenu(this.scene, xr.baseExperience); Left.instance = this; this.controller.onMotionControllerInitObservable.add((init) => { if (init.components['xr-standard-thumbstick']) { @@ -24,6 +25,8 @@ export class Left extends Base { this.moveMovable(value); } }); + this.initXButton(init.components['x-button']); + this.initYButton(init.components['y-button']); init.components['xr-standard-thumbstick'].onButtonStateChangedObservable.add((value) => { if (value.pressed) { log.trace('Left', 'thumbstick changed'); @@ -35,6 +38,26 @@ export class Left extends Base { } + private initXButton(xbutton: WebXRControllerComponent) { + if (xbutton) { + xbutton.onButtonStateChangedObservable.add((button) => { + if (button.pressed) { + Controllers.controllerObserver.notifyObservers({type: 'x-button', value: button.value}); + } + }); + } + } + + private initYButton(ybutton: WebXRControllerComponent) { + if (ybutton) { + ybutton.onButtonStateChangedObservable.add((button) => { + if (button.pressed) { + Controllers.controllerObserver.notifyObservers({type: 'y-button', value: button.value}); + } + }); + } + } + private moveMovable(value: { x: number, y: number }) { if (Math.abs(value.x) > .1) { Controllers.movable.position.x += .005 * Math.sign(value.x); diff --git a/src/controllers/right.ts b/src/controllers/right.ts index 8ae8ec4..898da04 100644 --- a/src/controllers/right.ts +++ b/src/controllers/right.ts @@ -1,11 +1,5 @@ import {Base} from "./base"; -import { - Scene, - Vector3, - WebXRControllerComponent, - WebXRDefaultExperience, - WebXRInputSource -} from "@babylonjs/core"; +import {Scene, Vector3, WebXRControllerComponent, WebXRDefaultExperience, WebXRInputSource} from "@babylonjs/core"; import {Controllers} from "./controllers"; import log from "loglevel"; @@ -22,8 +16,6 @@ export class Right extends Base { this.initAButton(init.components['a-button']); this.initThumbstick(init.components['xr-standard-thumbstick']); }); - - } private initBButton(bbutton: WebXRControllerComponent) { diff --git a/src/controllers/rigplatform.ts b/src/controllers/rigplatform.ts index 68f8fbb..d738625 100644 --- a/src/controllers/rigplatform.ts +++ b/src/controllers/rigplatform.ts @@ -16,16 +16,15 @@ import { } from "@babylonjs/core"; import {Right} from "./right"; import {Left} from "./left"; -import {Bmenu} from "../menus/bmenu"; +import {EditMenu} from "../menus/editMenu"; import {Controllers} from "./controllers"; import log from "loglevel"; - export class Rigplatform { private velocityIndex = 2; private readonly velocityArray = [0.01, 0.1, 1, 2, 5]; - public bMenu: Bmenu; + public bMenu: EditMenu; private readonly scene: Scene; public static instance: Rigplatform; private static xr: WebXRDefaultExperience; @@ -41,8 +40,9 @@ export class Rigplatform { this.scene = scene; Rigplatform.xr = xr; Rigplatform.instance = this; - this.bMenu = new Bmenu(scene, xr.baseExperience); + this.bMenu = new EditMenu(scene, xr.baseExperience); this.camera = scene.activeCamera; + this.rigMesh = MeshBuilder.CreateBox("platform", {width: 2, height: .02, depth: 2}, scene); for (const cam of scene.cameras) { cam.parent = this.rigMesh; diff --git a/src/menus/amenu.ts b/src/menus/amenu.ts deleted file mode 100644 index a1f7515..0000000 --- a/src/menus/amenu.ts +++ /dev/null @@ -1,11 +0,0 @@ -export class Amenu { - private visible = false; - - constructor() { - - } - - public toggle() { - this.visible = !this.visible; - } -} \ No newline at end of file diff --git a/src/menus/configMenu.ts b/src/menus/configMenu.ts new file mode 100644 index 0000000..a655563 --- /dev/null +++ b/src/menus/configMenu.ts @@ -0,0 +1,68 @@ +import {AdvancedDynamicTexture, RadioGroup, SelectionPanel} from "@babylonjs/gui"; +import {AbstractMesh, Angle, MeshBuilder, Scene, WebXRExperienceHelper} from "@babylonjs/core"; +import {CameraHelper} from "../util/cameraHelper"; +import log from "loglevel"; +import {AppConfig} from "../util/appConfig"; +import {Controllers} from "../controllers/controllers"; + +export class ConfigMenu { + private readonly scene: Scene; + private readonly xr: WebXRExperienceHelper; + private configPlane: AbstractMesh = null; + + constructor(scene: Scene, xr: WebXRExperienceHelper) { + this.scene = scene; + this.xr = xr; + Controllers.controllerObserver.add((event) => { + if (event.type == 'x-button') { + this.toggle(); + } + }); + } + + public toggle() { + if (this.configPlane) { + this.configPlane.dispose(); + this.configPlane = null; + return; + } + this.configPlane = MeshBuilder + .CreatePlane("gridSizePlane", + { + width: .25, + height: .5 + }, this.scene); + const configTexture = AdvancedDynamicTexture.CreateForMesh(this.configPlane, 256, 512); + configTexture.background = "white"; + const selectionPanel = new SelectionPanel("selectionPanel"); + selectionPanel.fontSize = "24px"; + selectionPanel.height = "100%"; + configTexture.addControl(selectionPanel) + const radio1 = new RadioGroup("Rotation Snap"); + radio1.addRadio("Off", this.rotateVal); + radio1.addRadio("22.5 degrees", this.rotateVal); + radio1.addRadio("45 degrees", this.rotateVal); + radio1.addRadio("90 degrees", this.rotateVal); + selectionPanel.addGroup(radio1); + const radio2 = new RadioGroup("Grid Snap"); + radio2.addRadio("Off", this.gridVal); + radio2.addRadio("1 cm", this.gridVal); + radio2.addRadio("10 cm", this.gridVal); + radio2.addRadio("25 cm", this.gridVal); + selectionPanel.addGroup(radio1); + selectionPanel.addGroup(radio2); + this.configPlane.position = CameraHelper.getFrontPosition(2, this.scene); + this.configPlane.rotation.y = Angle.FromDegrees(180).radians(); + } + + private rotateVal(value) { + AppConfig.config.rotateSnap = AppConfig.config.rotateSnapArray[value]; + log.debug("configMenu", "rotate Snap", value); + } + + private gridVal(value) { + AppConfig.config.gridSnap = AppConfig.config.gridSnapArray[value]; + log.debug("configMenu", "grid Snap", value); + } + +} \ No newline at end of file diff --git a/src/menus/bmenu.ts b/src/menus/editMenu.ts similarity index 95% rename from src/menus/bmenu.ts rename to src/menus/editMenu.ts index a955b1d..1730e32 100644 --- a/src/menus/bmenu.ts +++ b/src/menus/editMenu.ts @@ -14,8 +14,10 @@ import {DiagramEvent, DiagramEventType} from "../diagram/diagramEntity"; import {MeshConverter} from "../diagram/meshConverter"; import log from "loglevel"; import {InputTextView} from "../information/inputTextView"; +import {Right} from "../controllers/right"; +import {Left} from "../controllers/left"; -export class Bmenu { +export class EditMenu { private state: BmenuState = BmenuState.NONE; private manager: GUI3DManager; private readonly scene: Scene; @@ -102,6 +104,10 @@ export class Bmenu { } else { textInput.value = ""; } + if (this.xr.sessionManager.inXRSession) { + Right.instance.disable(); + Left.instance.disable(); + } textInput.focus(); if (navigator.userAgent.indexOf('Macintosh') > -1) { @@ -128,6 +134,8 @@ export class Bmenu { MeshConverter.updateTextNode(mesh, textInput.value); this.persist(mesh, textInput.value); this.cleanup(); + Right.instance.enable(); + Left.instance.enable(); }); } this.textInput = textInput; diff --git a/src/toolbox/toolbox.ts b/src/toolbox/toolbox.ts index 93d3e33..109adea 100644 --- a/src/toolbox/toolbox.ts +++ b/src/toolbox/toolbox.ts @@ -1,9 +1,13 @@ import { - AbstractMesh, Angle, - Color3, InstancedMesh, Mesh, + AbstractMesh, + Angle, + Color3, + InstancedMesh, + Mesh, MeshBuilder, Scene, - StandardMaterial, TransformNode, + StandardMaterial, + TransformNode, Vector3, WebXRExperienceHelper } from "@babylonjs/core"; @@ -80,8 +84,6 @@ export class Toolbox { this.addPanel.position = new Vector3(0, 0, .5); addButton.onPointerClickObservable.add(() => { this.buildColor(Color3.Random()); - - }); } @@ -106,14 +108,16 @@ export class Toolbox { newItem.position = new Vector3(this.calculatePosition(++i), .1, 0); } } - const myPlane = MeshBuilder + const colorPickerPlane = MeshBuilder .CreatePlane("myPlane", - {width: Toolbox.WIDGET_SIZE, - height: Toolbox.WIDGET_SIZE}, this.scene); - myPlane.parent=mesh; - myPlane.position= new Vector3(this.calculatePosition(++i), .1, 0); + { + width: Toolbox.WIDGET_SIZE, + height: Toolbox.WIDGET_SIZE + }, this.scene); + colorPickerPlane.parent = mesh; + colorPickerPlane.position = new Vector3(this.calculatePosition(++i), .1, 0); - const advancedTexture2 = AdvancedDynamicTexture.CreateForMesh(myPlane, 1024, 1024); + const colorPickerTexture = AdvancedDynamicTexture.CreateForMesh(colorPickerPlane, 1024, 1024); const colorPicker = new ColorPicker("color-picker"); colorPicker.scaleY = 5; colorPicker.scaleX = 5; @@ -134,7 +138,7 @@ export class Toolbox { ); }); - advancedTexture2.addControl(colorPicker); + colorPickerTexture.addControl(colorPicker); this.addPanel.position.z += .25; this.node.position.z -= .125; } diff --git a/src/util/appConfig.ts b/src/util/appConfig.ts new file mode 100644 index 0000000..bf22d71 --- /dev/null +++ b/src/util/appConfig.ts @@ -0,0 +1,19 @@ +export class AppConfig { + public gridSnap = 0; + public rotateSnap = 0; + public gridSnapArray = + [0, 0.1, 0.5, 1]; + public rotateSnapArray = + [0, 22.5, 45, 90] + + private static _config: AppConfig; + + public static get config() { + if (!AppConfig._config) { + AppConfig._config = new AppConfig(); + } + return AppConfig._config; + + } + +} \ No newline at end of file diff --git a/src/util/DualshockEventMapper.ts b/src/util/dualshockEventMapper.ts similarity index 92% rename from src/util/DualshockEventMapper.ts rename to src/util/dualshockEventMapper.ts index 3c7ab22..bcd38b8 100644 --- a/src/util/DualshockEventMapper.ts +++ b/src/util/dualshockEventMapper.ts @@ -1,5 +1,6 @@ import {DualShockButton} from "@babylonjs/core"; import log from "loglevel"; + type ButtonEvent = { objectName?: string, pressed: boolean, @@ -57,17 +58,18 @@ export class DualshockEventMapper { log.debug('DualshockEventMapper','D-Pad Up'); break; case 13: - log.debug('DualshockEventMapper','D-Pad Down'); + log.debug('DualshockEventMapper', 'D-Pad Down'); buttonEvent.objectName = "left-controller"; buttonEvent.buttonIndex = 3; break; case 14: - log.debug('DualshockEventMapper','D-Pad Left'); + log.debug('DualshockEventMapper', 'D-Pad Left'); + log.debug('DualshockEventMapper', 'D-Pad Left'); buttonEvent.objectName = "left-controller"; buttonEvent.buttonIndex = 4; break; case 15: - log.debug('DualshockEventMapper','D-Pad Right'); + log.debug('DualshockEventMapper', 'D-Pad Right'); break; case 10: log.debug('DualshockEventMapper','L3'); diff --git a/src/util/myMenu.ts b/src/util/myMenu.ts deleted file mode 100644 index ffd43ba..0000000 --- a/src/util/myMenu.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {PlanePanel} from "@babylonjs/gui"; - -export class MyMenu extends PlanePanel { - public arrangeChildren: boolean = true; - protected _arrangeChildren() { - if (this.arrangeChildren) { - super._arrangeChildren(); - } - } -} \ No newline at end of file