Fixed up menu system.

This commit is contained in:
Michael Mainguy 2023-08-25 13:26:19 -05:00
parent 16f9f7f92c
commit e43a9e9d41
7 changed files with 154 additions and 65 deletions

View File

@ -96,11 +96,13 @@ export class Base {
} }
public disable() { public disable() {
this.scene.preventDefaultOnPointerDown = true;
this.controller.motionController.rootMesh.setEnabled(false) this.controller.motionController.rootMesh.setEnabled(false)
this.controller.pointer.setEnabled(false); this.controller.pointer.setEnabled(false);
} }
public enable() { public enable() {
this.scene.preventDefaultOnPointerDown = false;
this.controller.motionController.rootMesh.setEnabled(true); this.controller.motionController.rootMesh.setEnabled(true);
this.controller.pointer.setEnabled(true) this.controller.pointer.setEnabled(true)
} }
@ -112,7 +114,7 @@ export class Base {
} }
const template = mesh?.metadata?.template; const template = mesh?.metadata?.template;
if (!template) { if (!template) {
if (mesh?.id == "handle") { if (mesh?.metadata?.handle == true) {
mesh && mesh.setParent(this.controller.motionController.rootMesh); mesh && mesh.setParent(this.controller.motionController.rootMesh);
this.grabbedMesh = mesh; this.grabbedMesh = mesh;
} else { } else {
@ -163,7 +165,7 @@ export class Base {
private toolboxHandleWasGrabbed(mesh: AbstractMesh): boolean { private toolboxHandleWasGrabbed(mesh: AbstractMesh): boolean {
if (!mesh?.metadata?.template if (!mesh?.metadata?.template
&& mesh?.id == "handle") { && mesh?.metadata?.handle == true) {
this.grabbedMesh = null; this.grabbedMesh = null;
this.previousParentId = null; this.previousParentId = null;
mesh.setParent(null); mesh.setParent(null);

View File

@ -1,7 +1,8 @@
import {Observable, Scene, WebXRDefaultExperience} from "@babylonjs/core"; import {MeshBuilder, Observable, Scene, Vector3, WebXRDefaultExperience} from "@babylonjs/core";
import log from "loglevel"; import log from "loglevel";
import {AdvancedDynamicTexture, InputText} from "@babylonjs/gui"; import {AdvancedDynamicTexture, Control, InputText, VirtualKeyboard} from "@babylonjs/gui";
import {ControllerEventType, Controllers} from "../controllers/controllers"; import {ControllerEventType, Controllers} from "../controllers/controllers";
import {setMenuPosition} from "../util/functions/setMenuPosition";
export type TextEvent = { export type TextEvent = {
text: string; text: string;
@ -15,33 +16,71 @@ export type InputTextViewOptions = {
export class InputTextView { export class InputTextView {
public readonly onTextObservable: Observable<TextEvent> = new Observable<TextEvent>(); public readonly onTextObservable: Observable<TextEvent> = new Observable<TextEvent>();
private readonly text: string; private readonly text: string = "";
private readonly scene: Scene; private readonly scene: Scene;
private readonly controllers: Controllers; private readonly controllers: Controllers;
private readonly xr: WebXRDefaultExperience; private readonly xr: WebXRDefaultExperience;
constructor(options: InputTextViewOptions) { constructor(text: string, xr: WebXRDefaultExperience, scene: Scene) {
if (options.text) { this.text = text ? text : "";
this.text = options.text; this.xr = xr;
} this.scene = scene;
if (options.xr) {
this.xr = options.xr;
}
if (options.scene) {
this.scene = options.scene;
}
if (options.controllers) {
this.controllers = options.controllers;
}
} }
public show() { public show() {
this.showVirtualKeyboard();
if ((this.xr as WebXRDefaultExperience).baseExperience?.sessionManager?.inXRSession) { /*if ((this.xr as WebXRDefaultExperience).baseExperience?.sessionManager?.inXRSession) {
this.showXr(); this.showXr();
} else { } else {
this.showWeb(); this.showWeb();
} }*/
}
public showVirtualKeyboard() {
const inputMesh = MeshBuilder.CreatePlane("input", {width: 1, height: .5}, this.scene);
const advancedTexture = AdvancedDynamicTexture.CreateForMesh(inputMesh, 2048, 1024, false);
const input = new InputText();
input.width = 0.5;
input.maxWidth = 0.5;
input.height = "64px";
input.text = this.text;
input.fontSize = "32px";
input.color = "white";
input.background = "black";
input.thickness = 3;
input.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
advancedTexture.addControl(input);
const keyboard = VirtualKeyboard.CreateDefaultLayout();
keyboard.scaleY = 2;
keyboard.scaleX = 2;
keyboard.transformCenterY = 0;
keyboard.transformCenterX = .5;
keyboard.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
keyboard.paddingTop = "70px"
keyboard.height = "768px";
keyboard.fontSizeInPixels = 24;
advancedTexture.addControl(keyboard);
keyboard.connect(input);
keyboard.isVisible = true;
keyboard.isEnabled = true;
keyboard.onKeyPressObservable.add((key) => {
if (key === '↵') {
this.onTextObservable.notifyObservers({text: input.text});
input.dispose();
keyboard.dispose();
advancedTexture.dispose();
inputMesh.dispose();
}
});
setMenuPosition(inputMesh, this.scene, new Vector3(0, .4, 0));
} }
public showWeb() { public showWeb() {
@ -59,6 +98,7 @@ export class InputTextView {
this.onTextObservable.notifyObservers({text: textInput.text}); this.onTextObservable.notifyObservers({text: textInput.text});
textInput.dispose(); textInput.dispose();
advancedTexture.dispose(); advancedTexture.dispose();
} }
}); });

View File

@ -1,14 +1,14 @@
import {AdvancedDynamicTexture, RadioGroup, SelectionPanel} from "@babylonjs/gui"; import {AdvancedDynamicTexture, RadioGroup, SelectionPanel, StackPanel} from "@babylonjs/gui";
import {AbstractMesh, MeshBuilder, Scene, WebXRDefaultExperience} from "@babylonjs/core"; import {MeshBuilder, Scene, Vector3, WebXRDefaultExperience} from "@babylonjs/core";
import {AppConfig} from "../util/appConfig"; import {AppConfig} from "../util/appConfig";
import {ControllerEventType, Controllers} from "../controllers/controllers"; import {ControllerEventType, Controllers} from "../controllers/controllers";
import {DiaSounds} from "../util/diaSounds"; import {DiaSounds} from "../util/diaSounds";
import {AbstractMenu} from "./abstractMenu"; import {AbstractMenu} from "./abstractMenu";
import {setMenuPosition} from "../util/functions/setMenuPosition"; import {setMenuPosition} from "../util/functions/setMenuPosition";
import {MenuHandle} from "./menuHandle";
export class ConfigMenu extends AbstractMenu { export class ConfigMenu extends AbstractMenu {
private sounds: DiaSounds; private sounds: DiaSounds;
private configPlane: AbstractMesh = null;
private yObserver; private yObserver;
private config: AppConfig; private config: AppConfig;
@ -42,44 +42,68 @@ export class ConfigMenu extends AbstractMenu {
} }
private handle: MenuHandle;
public toggle() { public toggle() {
if (this.configPlane) { if (this.handle) {
this.handle.mesh.dispose(false, true);
this.sounds.exit.play(); this.sounds.exit.play();
this.configPlane.dispose(); this.handle = null;
this.configPlane = null;
return; return;
} }
this.sounds.enter.play(); this.sounds.enter.play();
const width = .25; const configPlane = MeshBuilder
const height = .75;
const res = 256;
const heightPixels = Math.round((height / width) * res);
this.configPlane = MeshBuilder
.CreatePlane("gridSizePlane", .CreatePlane("gridSizePlane",
{ {
width: .25, width: .6,
height: .75 height: .3
}, this.scene); }, this.scene);
const configTexture = AdvancedDynamicTexture.CreateForMesh(this.configPlane, res, heightPixels); this.handle = new MenuHandle(configPlane);
configTexture.background = "white"; const configTexture = AdvancedDynamicTexture.CreateForMesh(configPlane, 2048, 1024);
const selectionPanel = new SelectionPanel("selectionPanel");
configTexture.addControl(selectionPanel)
this.buildGridSizeControl(selectionPanel);
this.buildCreateScaleControl(selectionPanel);
this.buildRotationSnapControl(selectionPanel);
this.buildTurnSnapControl(selectionPanel);
setMenuPosition(this.configPlane, this.scene); configTexture.background = "white";
const columnPanel = new StackPanel('columns');
columnPanel.fontSize = "48px";
columnPanel.isVertical = false;
configTexture.addControl(columnPanel);
const selectionPanel1 = new SelectionPanel("selectionPanel1");
selectionPanel1.width = .5;
columnPanel.addControl(selectionPanel1);
this.buildGridSizeControl(selectionPanel1);
this.buildCreateScaleControl(selectionPanel1);
const selectionPanel2 = new SelectionPanel("selectionPanel2");
selectionPanel2.width = .5;
columnPanel.addControl(selectionPanel2);
this.buildRotationSnapControl(selectionPanel2);
this.buildTurnSnapControl(selectionPanel2);
configPlane.position.set(0, .2, 0);
setMenuPosition(this.handle.mesh, this.scene, new Vector3(0, .4, 0));
}
private adjustRadio(radio: RadioGroup) {
radio.groupPanel.height = "512px";
radio.groupPanel.fontSize = "64px";
radio.groupPanel.children[0].height = "70px";
radio.groupPanel.paddingLeft = "16px";
radio.selectors.forEach((panel) => {
panel.children[0].height = "64px";
panel.children[0].width = "64px";
panel.children[1].paddingLeft = "32px";
panel.paddingTop = "16px";
panel.fontSize = "60px";
panel.adaptHeightToChildren = true;
});
} }
private buildCreateScaleControl(selectionPanel: SelectionPanel): RadioGroup { private buildCreateScaleControl(selectionPanel: SelectionPanel): RadioGroup {
const radio = new RadioGroup("Create Scale"); const radio = new RadioGroup("Create Scale");
selectionPanel.addGroup(radio);
selectionPanel.addGroup(radio);
for (const [index, snap] of this.gridSnaps.entries()) { for (const [index, snap] of this.gridSnaps.entries()) {
const selected = (this.config.current.createSnap == snap.value); const selected = (this.config.current.createSnap == snap.value);
radio.addRadio(snap.label, this.createVal.bind(this), selected); radio.addRadio(snap.label, this.createVal.bind(this), selected);
} }
this.adjustRadio(radio);
return radio; return radio;
} }
@ -90,6 +114,7 @@ export class ConfigMenu extends AbstractMenu {
const selected = (this.config.current.rotateSnap == snap.value); const selected = (this.config.current.rotateSnap == snap.value);
radio.addRadio(snap.label, this.rotateVal.bind(this), selected); radio.addRadio(snap.label, this.rotateVal.bind(this), selected);
} }
this.adjustRadio(radio);
return radio; return radio;
} }
@ -103,6 +128,7 @@ export class ConfigMenu extends AbstractMenu {
radio.addRadio(snap.label, this.gridVal.bind(this), selected); radio.addRadio(snap.label, this.gridVal.bind(this), selected);
} }
this.adjustRadio(radio);
return radio; return radio;
} }
@ -113,6 +139,7 @@ export class ConfigMenu extends AbstractMenu {
const selected = (this.config.current.turnSnap == snap.value); const selected = (this.config.current.turnSnap == snap.value);
radio.addRadio(snap.label, this.turnVal.bind(this), selected); radio.addRadio(snap.label, this.turnVal.bind(this), selected);
} }
this.adjustRadio(radio);
return radio; return radio;
} }

View File

@ -129,7 +129,7 @@ export class EditMenu extends AbstractMenu {
} else { } else {
this.sounds.enter.play(); this.sounds.enter.play();
setMenuPosition(this.manager.rootContainer.children[0].node, this.scene); setMenuPosition(this.manager.rootContainer.children[0].node, this.scene, new Vector3(0, .4, 0));
this.isVisible = true; this.isVisible = true;
} }
} }
@ -252,7 +252,7 @@ export class EditMenu extends AbstractMenu {
if (mesh?.metadata?.text) { if (mesh?.metadata?.text) {
text = mesh.metadata.text; text = mesh.metadata.text;
} }
const textInput = new InputTextView({xr: this.xr, text: text, controllers: this.controllers}); const textInput = new InputTextView(text, this.xr, this.scene);
textInput.show(); textInput.show();
textInput.onTextObservable.addOnce((value) => { textInput.onTextObservable.addOnce((value) => {
@ -264,7 +264,7 @@ export class EditMenu extends AbstractMenu {
} }
private showNewRelic() { private showNewRelic() {
const inputTextView = new InputTextView({xr: this.xr, scene: this.scene, text: "New Relic"}); const inputTextView = new InputTextView('test', this.xr, this.scene);
inputTextView.show(); inputTextView.show();
inputTextView.onTextObservable.addOnce((value) => { inputTextView.onTextObservable.addOnce((value) => {
const config = this.diagramManager.config.current; const config = this.diagramManager.config.current;

30
src/menus/menuHandle.ts Normal file
View File

@ -0,0 +1,30 @@
import {AbstractMesh, Color3, MeshBuilder, Scene, StandardMaterial, TransformNode, Vector3} from "@babylonjs/core";
export class MenuHandle {
public mesh: AbstractMesh;
private menuTransformNode: TransformNode;
constructor(mesh: TransformNode) {
this.menuTransformNode = mesh;
this.buildHandle(mesh.getScene());
}
private buildHandle(scene: Scene) {
const handle = MeshBuilder.CreateCapsule("handle", {
radius: .05,
orientation: Vector3.Right(),
height: .4
}, scene);
handle.id = "handle-" + this.menuTransformNode.id + "-mesh";
const handleMaterial = new StandardMaterial("handle-" + this.menuTransformNode.id, scene);
handleMaterial.diffuseColor = Color3.FromHexString("#EEEEFF");
handleMaterial.alpha = .8;
handle.material = handleMaterial;
handle.position = Vector3.Zero();
handle.metadata = {handle: true};
if (this.menuTransformNode) {
this.menuTransformNode.setParent(handle);
}
this.mesh = handle;
}
}

View File

@ -1,9 +1,10 @@
import {Color3, Mesh, MeshBuilder, Observable, Scene, StandardMaterial, TransformNode, Vector3} from "@babylonjs/core"; import {Color3, Mesh, Observable, Scene, TransformNode, Vector3} from "@babylonjs/core";
import {Button3D, GUI3DManager, StackPanel3D, TextBlock} from "@babylonjs/gui"; import {Button3D, GUI3DManager, StackPanel3D, TextBlock} from "@babylonjs/gui";
import {ControllerEventType, Controllers} from "../controllers/controllers"; import {ControllerEventType, Controllers} from "../controllers/controllers";
import {setMenuPosition} from "../util/functions/setMenuPosition"; import {setMenuPosition} from "../util/functions/setMenuPosition";
import {buildColor} from "./functions/buildColor"; import {buildColor} from "./functions/buildColor";
import {MenuHandle} from "../menus/menuHandle";
export class Toolbox { export class Toolbox {
private index = 0; private index = 0;
@ -15,7 +16,7 @@ export class Toolbox {
private readonly xObserver; private readonly xObserver;
public readonly colorChangeObservable: Observable<{ oldColor: string, newColor: string }> = public readonly colorChangeObservable: Observable<{ oldColor: string, newColor: string }> =
new Observable<{ oldColor: string; newColor: string }>() new Observable<{ oldColor: string; newColor: string }>()
private handle: MenuHandle;
constructor(scene: Scene, controllers: Controllers) { constructor(scene: Scene, controllers: Controllers) {
this.scene = scene; this.scene = scene;
this.controllers = controllers; this.controllers = controllers;
@ -23,20 +24,9 @@ export class Toolbox {
this.manager = new GUI3DManager(scene); this.manager = new GUI3DManager(scene);
this.manager.addControl(this.addPanel); this.manager.addControl(this.addPanel);
this.node = new TransformNode("toolbox", this.scene); this.node = new TransformNode("toolbox", this.scene);
const handle = MeshBuilder.CreateCapsule("handle", { this.handle = new MenuHandle(this.node);
radius: .05,
orientation: Vector3.Right(),
height: .4
}, this.scene);
handle.id = "handle";
const handleMaterial = new StandardMaterial("handle-material", this.scene);
handleMaterial.diffuseColor = Color3.FromHexString("#EEEEFF");
handleMaterial.alpha = .8;
handle.material = handleMaterial;
handle.position = Vector3.Zero();
this.node.parent = handle;
this.node.position.y = .1; this.node.position.y = .1;
this.node.position.z = .2;
this.node.scaling = new Vector3(0.6, 0.6, 0.6); this.node.scaling = new Vector3(0.6, 0.6, 0.6);
this.buildToolbox(); this.buildToolbox();

View File

@ -3,11 +3,11 @@ import {getFrontPosition} from "./getFrontPosition";
export function setMenuPosition(node: TransformNode, scene: Scene, offset: Vector3 = Vector3.Zero()) { export function setMenuPosition(node: TransformNode, scene: Scene, offset: Vector3 = Vector3.Zero()) {
const front = getFrontPosition(.8, scene); const front = getFrontPosition(.8, scene);
front.y = scene.activeCamera.globalPosition.y; //front.y = scene.activeCamera.globalPosition.y;
node.position = front; node.position = front;
node.position.addInPlace(offset); node.position.addInPlace(offset);
node.lookAt(scene.activeCamera.globalPosition);
node.rotation.y = node.rotation.y + Math.PI;
node.position.y -= .5; node.position.y -= .5;
node.lookAt(scene.activeCamera.globalPosition);
node.rotation.y = node.rotation.y + Math.PI;
} }