Simplified interactions, changed menu interactions for changing entities.

This commit is contained in:
Michael Mainguy 2024-04-12 13:33:52 -05:00
parent cabc38ce09
commit 159e687c19
8 changed files with 111 additions and 45 deletions

View File

@ -41,6 +41,7 @@ export class Base {
private logger: log.Logger; private logger: log.Logger;
private lastPosition: Vector3 = null; private lastPosition: Vector3 = null;
protected controllers: Controllers; protected controllers: Controllers;
private clickMenu: ClickMenu;
constructor(controller: WebXRInputSource, constructor(controller: WebXRInputSource,
scene: Scene, scene: Scene,
@ -262,9 +263,18 @@ export class Base {
private click() { private click() {
let mesh = this.xr.pointerSelection.getMeshUnderPointer(this.controller.uniqueId); let mesh = this.xr.pointerSelection.getMeshUnderPointer(this.controller.uniqueId);
if (pointable(mesh)) { if (pointable(mesh)) {
this.logger.debug("click on " + mesh.id); this.logger.debug("click on " + mesh.id);
const menu = new ClickMenu(mesh, this.diagramManager); if (this.clickMenu && !this.clickMenu.isDisposed) {
if (this.clickMenu.isConnecting) {
this.clickMenu.connect(mesh);
this.clickMenu = null;
}
} else {
this.clickMenu = new ClickMenu(mesh, this.diagramManager, this.controller.grip);
}
} else { } else {
this.logger.debug("click on nothing"); this.logger.debug("click on nothing");
} }

View File

@ -1,4 +1,4 @@
import {AbstractMesh, MeshBuilder, PointerInfo, Scene, TransformNode, Vector3} from "@babylonjs/core"; import {AbstractMesh, MeshBuilder, Scene, TransformNode, Vector3} from "@babylonjs/core";
import {v4 as uuidv4} from 'uuid'; import {v4 as uuidv4} from 'uuid';
import log, {Logger} from "loglevel"; import log, {Logger} from "loglevel";
import {buildStandardMaterial} from "../materials/functions/buildStandardMaterial"; import {buildStandardMaterial} from "../materials/functions/buildStandardMaterial";
@ -8,7 +8,7 @@ export class DiagramConnection {
private logger: Logger = log.getLogger('DiagramConnection'); private logger: Logger = log.getLogger('DiagramConnection');
private readonly id: string; private readonly id: string;
constructor(from: string, to: string, id: string, scene?: Scene, pointerInfo?: PointerInfo) { constructor(from: string, to: string, id: string, scene?: Scene, gripTransform?: TransformNode) {
this.logger.debug('buildConnection constructor'); this.logger.debug('buildConnection constructor');
if (id) { if (id) {
this.id = id; this.id = id;
@ -34,8 +34,8 @@ export class DiagramConnection {
to.ignoreNonUniformScaling = true; to.ignoreNonUniformScaling = true;
to.id = this.id + "_to"; to.id = this.id + "_to";
to.position = fromMesh.absolutePosition.clone(); to.position = fromMesh.absolutePosition.clone();
if (pointerInfo) { if (gripTransform) {
to.setParent(pointerInfo.pickInfo.gripTransform); to.setParent(gripTransform);
} }
this.toAnchor = to; this.toAnchor = to;
@ -105,7 +105,7 @@ export class DiagramConnection {
private buildConnection() { private buildConnection() {
this.logger.debug(`buildConnection from ${this._from} to ${this._to}`); this.logger.debug(`buildConnection from ${this._from} to ${this._to}`);
this._mesh = MeshBuilder.CreateCylinder(this.id + "_connection", {diameter: .02, height: 1}, this.scene); this._mesh = MeshBuilder.CreateCylinder(this.id + "_connection", {diameter: .02, height: 1}, this.scene);
this._mesh.material = buildStandardMaterial(this.id + "_material", this.scene, "#000000"); this._mesh.material = buildStandardMaterial(this.id + "_material", this.scene, "#FFFFFF");
this.transformNode = new TransformNode(this.id + "_transform", this.scene); this.transformNode = new TransformNode(this.id + "_transform", this.scene);
this.transformNode.metadata = {exportable: true}; this.transformNode.metadata = {exportable: true};
this._mesh.setParent(this.transformNode); this._mesh.setParent(this.transformNode);

View File

@ -66,6 +66,7 @@ export function diagramEventHandler(event: DiagramEvent,
if (physicsEnabled) { if (physicsEnabled) {
applyPhysics(sounds, mesh, scene); applyPhysics(sounds, mesh, scene);
} }
updateTextNode(mesh, entity.text);
break; break;
case DiagramEventType.REMOVE: case DiagramEventType.REMOVE:
if (mesh) { if (mesh) {

View File

@ -20,6 +20,7 @@ export class InputTextView {
private readonly handle: Handle; private readonly handle: Handle;
private inputText: InputText; private inputText: InputText;
private diagramMesh: AbstractMesh; private diagramMesh: AbstractMesh;
private keyboard: VirtualKeyboard;
constructor(scene: Scene, controllers: Controllers) { constructor(scene: Scene, controllers: Controllers) {
this.controllers = controllers; this.controllers = controllers;
@ -31,41 +32,49 @@ export class InputTextView {
} }
public show(mesh: AbstractMesh) { public show(mesh: AbstractMesh) {
this.inputText.text = mesh.metadata?.label || "";
this.handle.mesh.setEnabled(true); this.handle.mesh.setEnabled(true);
if (mesh.metadata?.label) {
this.inputText.text = mesh.metadata?.label;
}
this.diagramMesh = mesh; this.diagramMesh = mesh;
this.keyboard.isVisible = true;
this.inputText.focus();
console.log(mesh.metadata); console.log(mesh.metadata);
} }
public createKeyboard() { public createKeyboard() {
const platform = this.scene.getMeshById('platform'); const platform = this.scene.getMeshById('platform');
let position = new Vector3(0, 1.66, .5); const position = new Vector3(0, 1.66, .5);
let rotation = new Vector3(0, .9, 0); const rotation = new Vector3(.9, 0, 0);
const handle = this.handle; const handle = this.handle;
if (handle.mesh.position.x != 0 && handle.mesh.position.y != 0 && handle.mesh.position.z != 0) { /*if (handle.mesh.position.x != 0 && handle.mesh.position.y != 0 && handle.mesh.position.z != 0) {
position = handle.mesh.position; position = handle.mesh.position;
} }
if (handle.mesh.rotation.x != 0 && handle.mesh.rotation.y != 0 && handle.mesh.rotation.z != 0) { if (handle.mesh.rotation.x != 0 && handle.mesh.rotation.y != 0 && handle.mesh.rotation.z != 0) {
rotation = handle.mesh.rotation; rotation = handle.mesh.rotation;
} }*/
if (!platform) { if (!platform) {
this.scene.onNewMeshAddedObservable.add((mesh) => { this.scene.onNewMeshAddedObservable.add((mesh) => {
if (mesh.id == 'platform') { if (mesh.id == 'platform') {
this.logger.debug("platform added"); this.logger.debug("platform added");
handle.mesh.setParent(platform); handle.mesh.parent = mesh;
if (!handle.idStored) {
handle.mesh.position = position; handle.mesh.position = position;
handle.mesh.rotation = rotation; handle.mesh.rotation = rotation;
}
} }
}); }, -1, false, this, false);
} else { } else {
handle.mesh.parent = platform; handle.mesh.setParent(platform);
handle.mesh.position = position; if (!handle.idStored) {
handle.mesh.rotation = rotation; handle.mesh.position = position;
handle.mesh.rotation = rotation;
}
} }
//setMenuPosition(handle.mesh, this.scene, new Vector3(0, .4, 0)); //setMenuPosition(handle.mesh, this.scene, new Vector3(0, .4, 0));
const advancedTexture = AdvancedDynamicTexture.CreateForMesh(this.inputMesh, 2048, 1024, false); const advancedTexture = AdvancedDynamicTexture.CreateForMesh(this.inputMesh, 2048, 1024, false);
const input = new InputText(); const input = new InputText();
input.width = 0.5; input.width = 0.5;
input.maxWidth = 0.5; input.maxWidth = 0.5;
@ -110,11 +119,17 @@ export class InputTextView {
}); });
keyboard.onKeyPressObservable.add((key) => { keyboard.onKeyPressObservable.add((key) => {
if (key === '↵') { if (key === '↵') {
this.logger.error(this.inputText.text); if (this.inputText.text && this.inputText.text.length > 0) {
this.onTextObservable.notifyObservers({id: this.diagramMesh.id, text: this.inputText.text}); this.logger.error(this.inputText.text);
this.onTextObservable.notifyObservers({id: this.diagramMesh.id, text: this.inputText.text});
} else {
this.onTextObservable.notifyObservers({id: this.diagramMesh.id, text: null});
}
this.hide(); this.hide();
} }
}, -1, false, this, false); }, -1, false, this, false);
this.keyboard = keyboard;
this.handle.mesh.setEnabled(false); this.handle.mesh.setEnabled(false);
} }

View File

@ -3,6 +3,8 @@ import {AbstractMesh, TransformNode} from "@babylonjs/core";
import {DiagramEvent, DiagramEventType} from "../diagram/types/diagramEntity"; import {DiagramEvent, DiagramEventType} from "../diagram/types/diagramEntity";
import {toDiagramEntity} from "../diagram/functions/toDiagramEntity"; import {toDiagramEntity} from "../diagram/functions/toDiagramEntity";
import {DiagramManager} from "../diagram/diagramManager"; import {DiagramManager} from "../diagram/diagramManager";
import {DiagramConnection} from "../diagram/diagramConnection";
import {isDiagramEntity} from "../diagram/functions/isDiagramEntity";
export class ClickMenu { export class ClickMenu {
private static readonly sounds; private static readonly sounds;
@ -11,7 +13,10 @@ export class ClickMenu {
private readonly transform: TransformNode; private readonly transform: TransformNode;
private readonly diagramManager: DiagramManager; private readonly diagramManager: DiagramManager;
constructor(entity: AbstractMesh, diagramManager: DiagramManager) {
private connection: DiagramConnection = null;
constructor(entity: AbstractMesh, diagramManager: DiagramManager, grip: TransformNode) {
this.entity = entity; this.entity = entity;
this.diagramManager = diagramManager; this.diagramManager = diagramManager;
const scene = entity.getScene(); const scene = entity.getScene();
@ -29,17 +34,39 @@ export class ClickMenu {
manager.controlScaling = .1; manager.controlScaling = .1;
manager.addControl(panel); manager.addControl(panel);
panel.addControl(this.makeButton("Remove", "remove")); panel.addControl(this.makeButton("Remove", "remove", grip));
panel.addControl(this.makeButton("Label", "label")); panel.addControl(this.makeButton("Label", "label", grip));
panel.addControl(this.makeButton("Connect", "connect")); panel.addControl(this.makeButton("Connect", "connect", grip));
panel.addControl(this.makeButton("Close", "close")); panel.addControl(this.makeButton("Close", "close", grip));
panel.linkToTransformNode(transform); panel.linkToTransformNode(transform);
this.transform = transform; this.transform = transform;
this.manager = manager; this.manager = manager;
} }
private makeButton(name: string, id: string) { public get isConnecting() {
return this.connection != null;
}
public get isDisposed(): boolean {
return this.transform.isDisposed();
}
public connect(mesh: AbstractMesh) {
if (this.connection) {
if (mesh && isDiagramEntity(mesh)) {
this.connection.to = mesh.id;
this.diagramManager.onDiagramEventObservable.notifyObservers({
type: DiagramEventType.ADD,
entity: toDiagramEntity(this.connection.mesh)
}, -1);
this.connection = null;
this.dispose();
}
}
}
private makeButton(name: string, id: string, grip: TransformNode) {
const button = new Button3D(name); const button = new Button3D(name);
//button.scaling = new Vector3(.1, .1, .1); //button.scaling = new Vector3(.1, .1, .1);
button.name = id; button.name = id;
@ -66,7 +93,8 @@ export class ClickMenu {
this.diagramManager.editText(this.entity); this.diagramManager.editText(this.entity);
this.dispose(); this.dispose();
break; break;
case "connect":
this.createMeshConnection(this.entity, grip);
} }
@ -74,8 +102,13 @@ export class ClickMenu {
return button; return button;
} }
private createMeshConnection(mesh: AbstractMesh, grip: TransformNode) {
this.connection = new DiagramConnection(mesh.id, null, null, this.transform.getScene(), grip);
}
private dispose() { private dispose() {
this.manager.dispose(); this.manager.dispose();
this.transform.dispose(); this.transform.dispose();
} }
} }

View File

@ -147,7 +147,7 @@ export class EditMenu extends AbstractMenu {
}, -1); }, -1);
this.connection = null; this.connection = null;
} else { } else {
this.connection = new DiagramConnection(mesh.id, null, null, this.scene, pointerInfo); this.connection = new DiagramConnection(mesh.id, null, null, this.scene, pointerInfo.pickInfo.gripTransform);
} }
} }

View File

@ -4,12 +4,16 @@ import {buildStandardMaterial} from "../materials/functions/buildStandardMateria
export class Handle { export class Handle {
public mesh: AbstractMesh; public mesh: AbstractMesh;
private readonly transformNode: TransformNode; private readonly transformNode: TransformNode;
private _isStored: boolean = false;
constructor(mesh: TransformNode) { constructor(mesh: TransformNode) {
this.transformNode = mesh; this.transformNode = mesh;
this.buildHandle(); this.buildHandle();
} }
public get idStored() {
return this._isStored;
}
private buildHandle() { private buildHandle() {
const scene: Scene = this.transformNode.getScene(); const scene: Scene = this.transformNode.getScene();
const handle = getHandleMesh("handle-" + this.transformNode.id + "-mesh", scene); const handle = getHandleMesh("handle-" + this.transformNode.id + "-mesh", scene);
@ -22,6 +26,7 @@ export class Handle {
const locationdata = JSON.parse(stored); const locationdata = JSON.parse(stored);
handle.position = new Vector3(locationdata.position.x, locationdata.position.y, locationdata.position.z); handle.position = new Vector3(locationdata.position.x, locationdata.position.y, locationdata.position.z);
handle.rotation = new Vector3(locationdata.rotation.x, locationdata.rotation.y, locationdata.rotation.z); handle.rotation = new Vector3(locationdata.rotation.x, locationdata.rotation.y, locationdata.rotation.z);
this._isStored = true;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
handle.position = Vector3.Zero(); handle.position = Vector3.Zero();

View File

@ -93,38 +93,40 @@ export class Toolbox {
} }
} }
//this.toolboxBaseNode.parent.setEnabled(false); //this.toolboxBaseNode.parent.setEnabled(false);
let offset = new Vector3(-.50, 1.6, .38); const offset = new Vector3(-.50, 1.6, .38);
let rotation = new Vector3(.5, -.6, .18); const rotation = new Vector3(.5, -.6, .18);
if (this.toolboxBaseNode.parent) { if (this.toolboxBaseNode.parent) {
const platform = this.scene.getNodeById("platform"); const platform = this.scene.getNodeById("platform");
if (platform) { if (platform) {
const handle = this.handle; const handle = this.handle;
if (handle.mesh.position.x != 0 && handle.mesh.position.y != 0 && handle.mesh.position.z != 0) { handle.mesh.parent = platform;
/*if (handle.mesh.position.x != 0 && handle.mesh.position.y != 0 && handle.mesh.position.z != 0) {
offset = handle.mesh.position; offset = handle.mesh.position;
} }
if (handle.mesh.rotation.x != 0 && handle.mesh.rotation.y != 0 && handle.mesh.rotation.z != 0) { if (handle.mesh.rotation.x != 0 && handle.mesh.rotation.y != 0 && handle.mesh.rotation.z != 0) {
rotation = handle.mesh.rotation; rotation = handle.mesh.rotation;
}*/
//handle.mesh.parent = platform;
if (!handle.idStored) {
handle.mesh.position = offset;
handle.mesh.rotation = rotation;
} }
handle.mesh.parent = platform;
handle.mesh.position = offset;
handle.mesh.rotation = rotation;
} else { } else {
this.scene.onNewMeshAddedObservable.add((mesh: AbstractMesh) => { this.scene.onNewMeshAddedObservable.add((mesh: AbstractMesh) => {
if (mesh.id == "platform") { if (mesh && mesh.id == "platform") {
const handle = this.handle; const handle = this.handle;
if (handle.mesh.position.x != 0 && handle.mesh.position.y != 0 && handle.mesh.position.z != 0) {
offset = handle.mesh.position;
}
if (handle.mesh.rotation.x != 0 && handle.mesh.rotation.y != 0 && handle.mesh.rotation.z != 0) {
rotation = handle.mesh.rotation;
}
handle.mesh.parent = mesh; handle.mesh.parent = mesh;
handle.mesh.position = offset; if (!handle.idStored) {
handle.mesh.rotation = rotation; handle.mesh.position = offset;
handle.mesh.rotation = rotation;
}
//handle.mesh.parent = mesh;
} }
}); }, -1, false, this, false);
} }
} }