Updated menu system to be more consistent. Change toolbox to fixed colors;

This commit is contained in:
Michael Mainguy 2024-03-08 10:41:18 -06:00
parent 1413a0bda9
commit 73a850613d
17 changed files with 279 additions and 254 deletions

64
package-lock.json generated
View File

@ -8,14 +8,14 @@
"name": "immersive", "name": "immersive",
"version": "0.0.1", "version": "0.0.1",
"dependencies": { "dependencies": {
"@babylonjs/core": "^6.21.3", "@babylonjs/core": "^6.45.1",
"@babylonjs/gui": "^6.21.3", "@babylonjs/gui": "^6.45.1",
"@babylonjs/havok": "1.1.4", "@babylonjs/havok": "1.3.1",
"@babylonjs/inspector": "^6.21.3", "@babylonjs/inspector": "^6.45.1",
"@babylonjs/loaders": "^6.21.3", "@babylonjs/loaders": "^6.45.1",
"@babylonjs/materials": "^6.21.3", "@babylonjs/materials": "^6.45.1",
"@babylonjs/procedural-textures": "^6.21.3", "@babylonjs/procedural-textures": "^6.45.1",
"@babylonjs/serializers": "^6.21.3", "@babylonjs/serializers": "^6.45.1",
"@cloudflare/workers-types": "^4.20230821.0", "@cloudflare/workers-types": "^4.20230821.0",
"@netlify/functions": "^2.3.0", "@netlify/functions": "^2.3.0",
"@typed-mxgraph/typed-mxgraph": "^1.0.8", "@typed-mxgraph/typed-mxgraph": "^1.0.8",
@ -49,14 +49,14 @@
} }
}, },
"node_modules/@babylonjs/core": { "node_modules/@babylonjs/core": {
"version": "6.21.3", "version": "6.45.1",
"resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-6.21.3.tgz", "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-6.45.1.tgz",
"integrity": "sha512-j+UnhCSz3HldEWVHnxRHKGLqhWafju/WGqKaLXncbgo/Fkz48OoFbrec651jv1cBiNx82zdVa59c8VIK6FNSOw==" "integrity": "sha512-wkORoAqpnZb10bUhrI0vinE9IiW7+gSgH4U4Zp41wO4kSeV0mtJY+Q5Ez6/n9ad9sLykD2FD7650B+Qi5tTMSw=="
}, },
"node_modules/@babylonjs/gui": { "node_modules/@babylonjs/gui": {
"version": "6.21.3", "version": "6.45.1",
"resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-6.21.3.tgz", "resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-6.45.1.tgz",
"integrity": "sha512-bsh6GT/tvWIDua1vSg2n3GeMGWnkuW7j9Dpi6+NVRjaXYEKdtbsSuWwND8JVClSoYa23qosIeeNPCqRPB8pq3g==", "integrity": "sha512-lev/3nprv4t8lu3kW1zdlH7VzlWh9dmyZ2PkzybmBI6nB48bswPm7cX2ppaFTkpY8Z904js9TOsrYQotMzsUiw==",
"peerDependencies": { "peerDependencies": {
"@babylonjs/core": "^6.0.0" "@babylonjs/core": "^6.0.0"
} }
@ -74,17 +74,17 @@
} }
}, },
"node_modules/@babylonjs/havok": { "node_modules/@babylonjs/havok": {
"version": "1.1.4", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/@babylonjs/havok/-/havok-1.1.4.tgz", "resolved": "https://registry.npmjs.org/@babylonjs/havok/-/havok-1.3.1.tgz",
"integrity": "sha512-mK/sgqv4LaI4BjoQgWYGxOBX45hVauZ8PopPkIUIB42DiVPgWkiCZbBQ9pL7r1tbLhThvV1RTokj4z5bVGBayw==", "integrity": "sha512-ctaAQ2RN7hzE2vukGiA27//08YE4RNqH4RN26fCd8q0q7Qn+pXg4P61ZgakWYox/YS4VqHrB3ovZUDtPt2Scxg==",
"dependencies": { "dependencies": {
"@types/emscripten": "^1.39.6" "@types/emscripten": "^1.39.6"
} }
}, },
"node_modules/@babylonjs/inspector": { "node_modules/@babylonjs/inspector": {
"version": "6.21.3", "version": "6.45.1",
"resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-6.21.3.tgz", "resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-6.45.1.tgz",
"integrity": "sha512-XJfqYVilSWEDLRy7IaSxkGNAs5U+SHsWBi9+eS49bFsP06fGjcbJjF2ZK1qY7DbMEThbwzwD6VypJtjKaoF9kw==", "integrity": "sha512-4YhJLD2FrVXUFIU+ttBanhevVaCBVLaBxhPuwrxXxKWkuBulFOQz7GkvRT/CJwA3Ad9/66qwS5+vfRT99GLM/w==",
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.1.0", "@fortawesome/fontawesome-svg-core": "^6.1.0",
"@fortawesome/free-regular-svg-icons": "^6.0.0", "@fortawesome/free-regular-svg-icons": "^6.0.0",
@ -102,34 +102,34 @@
} }
}, },
"node_modules/@babylonjs/loaders": { "node_modules/@babylonjs/loaders": {
"version": "6.21.3", "version": "6.45.1",
"resolved": "https://registry.npmjs.org/@babylonjs/loaders/-/loaders-6.21.3.tgz", "resolved": "https://registry.npmjs.org/@babylonjs/loaders/-/loaders-6.45.1.tgz",
"integrity": "sha512-2GpMOEQFuih8O/l6IIyGd0i0gCYo6x8LPjD10FBFBVX2dSkazhWDaAQSS8HCZNY2Uennmy83ePzuTf5RvaKDaw==", "integrity": "sha512-a75JvRVxT3DROCrl5iigLEpI5/eR7Rh4wdsDzZNn7bv3sXB40Kbw8EL60W3jDBXPdGUqNVzqtrxJF/ec2udg/Q==",
"peerDependencies": { "peerDependencies": {
"@babylonjs/core": "^6.0.0", "@babylonjs/core": "^6.0.0",
"babylonjs-gltf2interface": "^6.0.0" "babylonjs-gltf2interface": "^6.0.0"
} }
}, },
"node_modules/@babylonjs/materials": { "node_modules/@babylonjs/materials": {
"version": "6.21.3", "version": "6.45.1",
"resolved": "https://registry.npmjs.org/@babylonjs/materials/-/materials-6.21.3.tgz", "resolved": "https://registry.npmjs.org/@babylonjs/materials/-/materials-6.45.1.tgz",
"integrity": "sha512-oH/ZmiYKTJnvWzaZVNDPSjvekKK9C/eQZaiMcYiPTb39LHJw+bnIJS8NyvWjDLLn4cJ9XfEict69WqMb1XItVA==", "integrity": "sha512-v1jqgG0bfX+8Qezq4eDT2sSjpQYW+ocNU70dbJF0AYrhuhhgf0SpM28C7DAKi9GUOKjMvZrIBEbFmJ6AijLjcQ==",
"peerDependencies": { "peerDependencies": {
"@babylonjs/core": "^6.0.0" "@babylonjs/core": "^6.0.0"
} }
}, },
"node_modules/@babylonjs/procedural-textures": { "node_modules/@babylonjs/procedural-textures": {
"version": "6.21.3", "version": "6.45.1",
"resolved": "https://registry.npmjs.org/@babylonjs/procedural-textures/-/procedural-textures-6.21.3.tgz", "resolved": "https://registry.npmjs.org/@babylonjs/procedural-textures/-/procedural-textures-6.45.1.tgz",
"integrity": "sha512-S1KIMrrVubk06mxuVeLGH8YngUj1W0zhdYjp2tHP2a7gueARG8a2OhqLW4e0MwFxi7XnP9DuFyzmkK95XZMaKw==", "integrity": "sha512-QpLuPknYIvylfUscSqorkuXO4QSI49atQnScWN43ZpRzr+ecXWnxEaOyAmt7bbf93htshtIkUQdJhwx8w4fqrg==",
"peerDependencies": { "peerDependencies": {
"@babylonjs/core": "^6.0.0" "@babylonjs/core": "^6.0.0"
} }
}, },
"node_modules/@babylonjs/serializers": { "node_modules/@babylonjs/serializers": {
"version": "6.21.3", "version": "6.45.1",
"resolved": "https://registry.npmjs.org/@babylonjs/serializers/-/serializers-6.21.3.tgz", "resolved": "https://registry.npmjs.org/@babylonjs/serializers/-/serializers-6.45.1.tgz",
"integrity": "sha512-E8jerSLDrDkwkNc8D9a9vmvPlNJiaXUl5m6cIUQ317oUk0/pT06NiM/N//HbyjM8ccnkaPUBkNBq4dxtPW/XSw==", "integrity": "sha512-iSPUdjZhQIbSyi21IFiFC/wm6Bj4zcH9NhsN9i+xqLTbO/Uho49cHU0ew39n0Xn+LRsGRMTJWQLTsp+TPvAvrw==",
"peerDependencies": { "peerDependencies": {
"@babylonjs/core": "^6.0.0", "@babylonjs/core": "^6.0.0",
"babylonjs-gltf2interface": "^6.0.0" "babylonjs-gltf2interface": "^6.0.0"

View File

@ -16,14 +16,14 @@
}, },
"dependencies": { "dependencies": {
"axios": "^0.24.0", "axios": "^0.24.0",
"@babylonjs/core": "^6.21.3", "@babylonjs/core": "^6.45.1",
"@babylonjs/gui": "^6.21.3", "@babylonjs/gui": "^6.45.1",
"@babylonjs/havok": "1.1.4", "@babylonjs/havok": "1.3.1",
"@babylonjs/inspector": "^6.21.3", "@babylonjs/inspector": "^6.45.1",
"@babylonjs/loaders": "^6.21.3", "@babylonjs/loaders": "^6.45.1",
"@babylonjs/materials": "^6.21.3", "@babylonjs/materials": "^6.45.1",
"@babylonjs/procedural-textures": "^6.21.3", "@babylonjs/procedural-textures": "^6.45.1",
"@babylonjs/serializers": "^6.21.3", "@babylonjs/serializers": "^6.45.1",
"@cloudflare/workers-types": "^4.20230821.0", "@cloudflare/workers-types": "^4.20230821.0",
"@netlify/functions": "^2.3.0", "@netlify/functions": "^2.3.0",
"events": "^3.3.0", "events": "^3.3.0",

View File

@ -143,7 +143,7 @@ export class Base {
this.previousScaling = mesh?.scaling.clone(); this.previousScaling = mesh?.scaling.clone();
this.previousPosition = mesh?.position.clone(); this.previousPosition = mesh?.position.clone();
if (("toolbox" != mesh?.parent?.parent?.id) || player) { if (!mesh.metadata?.grabClone || player) {
if (mesh.physicsBody) { if (mesh.physicsBody) {
const transformNode = setupTransformNode(mesh, this.controller.motionController.rootMesh); const transformNode = setupTransformNode(mesh, this.controller.motionController.rootMesh);
mesh.physicsBody.setMotionType(PhysicsMotionType.ANIMATED); mesh.physicsBody.setMotionType(PhysicsMotionType.ANIMATED);
@ -155,6 +155,8 @@ export class Base {
this.grabbedMesh = mesh; this.grabbedMesh = mesh;
} else { } else {
const clone = grabAndClone(this.diagramManager, mesh, this.controller.motionController.rootMesh); const clone = grabAndClone(this.diagramManager, mesh, this.controller.motionController.rootMesh);
clone.newMesh.metadata.grabClone = false;
clone.newMesh.metadata.tool = false;
this.grabbedMeshParentId = clone.transformNode.id; this.grabbedMeshParentId = clone.transformNode.id;
this.grabbedMesh = clone.newMesh; this.grabbedMesh = clone.newMesh;
this.previousParentId = null; this.previousParentId = null;

View File

@ -51,9 +51,16 @@ export class WebController {
} }
if (kbInfo.type == KeyboardEventTypes.KEYUP) { if (kbInfo.type == KeyboardEventTypes.KEYUP) {
this.rig.turn(0); this.rig.turn(0);
this.rig.updown(0);
} }
if (kbInfo.type == 1) { if (kbInfo.type == 1) {
switch (kbInfo.event.key) { switch (kbInfo.event.key) {
case "W":
this.rig.updown(-this.speed);
break;
case "S":
this.rig.updown(this.speed);
break;
case "ArrowUp": case "ArrowUp":
case "w": case "w":
this.rig.forwardback(-this.speed); this.rig.forwardback(-this.speed);

View File

@ -1,4 +1,4 @@
import {MeshBuilder, Observable, Scene, Vector3, WebXRDefaultExperience} from "@babylonjs/core"; import {MeshBuilder, Observable, Scene, TransformNode, Vector3, WebXRDefaultExperience} from "@babylonjs/core";
import log, {Logger} from "loglevel"; import log, {Logger} from "loglevel";
import {AdvancedDynamicTexture, Control, InputText, VirtualKeyboard} from "@babylonjs/gui"; import {AdvancedDynamicTexture, Control, InputText, VirtualKeyboard} from "@babylonjs/gui";
import {ControllerEventType, Controllers} from "../controllers/controllers"; import {ControllerEventType, Controllers} from "../controllers/controllers";
@ -37,8 +37,10 @@ export class InputTextView {
public showVirtualKeyboard() { public showVirtualKeyboard() {
const inputBaseNode = new TransformNode("inputBase", this.scene);
const inputMesh = MeshBuilder.CreatePlane("input", {width: 1, height: .5}, this.scene); const inputMesh = MeshBuilder.CreatePlane("input", {width: 1, height: .5}, this.scene);
inputMesh.parent = inputBaseNode;
inputMesh.rotation.y = Math.PI;
const advancedTexture = AdvancedDynamicTexture.CreateForMesh(inputMesh, 2048, 1024, false); const advancedTexture = AdvancedDynamicTexture.CreateForMesh(inputMesh, 2048, 1024, false);
const input = new InputText(); const input = new InputText();
@ -96,7 +98,7 @@ export class InputTextView {
this.sounds.exit.play(); this.sounds.exit.play();
} }
}); });
setMenuPosition(inputMesh, this.scene, new Vector3(0, .4, 0)); setMenuPosition(inputBaseNode, this.scene, new Vector3(0, .4, 0));
this.sounds.enter.play(); this.sounds.enter.play();
} }

View File

@ -1,5 +1,5 @@
import {AdvancedDynamicTexture, CheckboxGroup, RadioGroup, SelectionPanel, StackPanel} from "@babylonjs/gui"; import {AdvancedDynamicTexture, CheckboxGroup, RadioGroup, SelectionPanel, StackPanel} from "@babylonjs/gui";
import {MeshBuilder, Scene, Vector3, WebXRDefaultExperience} from "@babylonjs/core"; import {MeshBuilder, Scene, TransformNode, 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";
@ -9,6 +9,7 @@ import {setMenuPosition} from "../util/functions/setMenuPosition";
export class ConfigMenu extends AbstractMenu { export class ConfigMenu extends AbstractMenu {
private sounds: DiaSounds; private sounds: DiaSounds;
private config: AppConfig; private config: AppConfig;
private readonly baseTransform: TransformNode;
private gridSnaps: Array<{ label: string, value: number }> = [ private gridSnaps: Array<{ label: string, value: number }> = [
{label: "Off", value: 0}, {label: "Off", value: 0},
{label: "0.01", value: 0.01}, {label: "0.01", value: 0.01},
@ -22,11 +23,11 @@ export class ConfigMenu extends AbstractMenu {
{label: "22.5", value: 22.5}, {label: "22.5", value: 22.5},
{label: "45", value: 45}, {label: "45", value: 45},
{label: "90", value: 90}, {label: "90", value: 90},
] ]
constructor(scene: Scene, xr: WebXRDefaultExperience, controllers: Controllers, config: AppConfig) { constructor(scene: Scene, xr: WebXRDefaultExperience, controllers: Controllers, config: AppConfig) {
super(scene, xr, controllers); super(scene, xr, controllers);
this.baseTransform = new TransformNode("configMenuBase", scene);
this.config = config; this.config = config;
this.sounds = new DiaSounds(scene); this.sounds = new DiaSounds(scene);
@ -35,56 +36,72 @@ export class ConfigMenu extends AbstractMenu {
this.toggle(); this.toggle();
} }
}); });
this.buildMenu();
}
public toggle() {
if (this.baseTransform.parent.isEnabled()) {
this.sounds.exit.play();
this.baseTransform.parent.setEnabled(false);
} else {
this.sounds.enter.play();
this.baseTransform.parent.setEnabled(true);
}
setMenuPosition(this.handle.mesh, this.scene, new Vector3(.6, .1, 0));
} }
private buildMenu() {
public toggle() {
if (this.handle) {
this.handle.mesh.dispose(false, true);
this.sounds.exit.play();
this.handle = null;
return;
}
this.sounds.enter.play();
const configPlane = MeshBuilder const configPlane = MeshBuilder
.CreatePlane("gridSizePlane", .CreatePlane("configMenuPlane",
{ {
width: .6, width: .6,
height: .3 height: .3
}, this.scene); }, this.scene);
this.createHandle(configPlane); configPlane.rotation.y = Math.PI;
configPlane.setParent(this.baseTransform);
this.createHandle(this.baseTransform);
this.baseTransform.position.set(0, .2, 0);
const configTexture = AdvancedDynamicTexture.CreateForMesh(configPlane, 2048, 1024); const configTexture = AdvancedDynamicTexture.CreateForMesh(configPlane, 2048, 1024);
//configTexture.background = "#00ffff";
configTexture.background = "white";
const columnPanel = new StackPanel('columns'); const columnPanel = new StackPanel('columns');
columnPanel.fontSize = "48px";
columnPanel.isVertical = false; columnPanel.isVertical = false;
//columnPanel.width = 1;
columnPanel.fontSize = "48px";
//columnPanel.background = "#ff0000";
//
configTexture.addControl(columnPanel); configTexture.addControl(columnPanel);
const selectionPanel1 = new SelectionPanel("selectionPanel1"); const selectionPanel1 = new SelectionPanel("selectionPanel1");
selectionPanel1.width = .3; selectionPanel1.width = "500px";
//selectionPanel1.width = .3;
columnPanel.addControl(selectionPanel1); columnPanel.addControl(selectionPanel1);
this.buildGridSizeControl(selectionPanel1); this.buildGridSizeControl(selectionPanel1);
this.buildCreateScaleControl(selectionPanel1); this.buildCreateScaleControl(selectionPanel1);
const selectionPanel2 = new SelectionPanel("selectionPanel2"); const selectionPanel2 = new SelectionPanel("selectionPanel2");
selectionPanel2.width = .3; selectionPanel2.width = "500px";
columnPanel.addControl(selectionPanel2); columnPanel.addControl(selectionPanel2);
this.buildRotationSnapControl(selectionPanel2); this.buildRotationSnapControl(selectionPanel2);
this.buildTurnSnapControl(selectionPanel2); this.buildTurnSnapControl(selectionPanel2);
const selectionPanel3 = new SelectionPanel("selectionPanel3"); const selectionPanel3 = new SelectionPanel("selectionPanel3");
selectionPanel3.width = .3; selectionPanel3.width = "768px";
columnPanel.addControl(selectionPanel3); columnPanel.addControl(selectionPanel3);
this.buildFlyModeControl(selectionPanel3); this.buildFlyModeControl(selectionPanel3);
configPlane.position.set(0, .2, 0); setMenuPosition(this.handle.mesh, this.scene, new Vector3(.6, .1, 0));
setMenuPosition(this.handle.mesh, this.scene, new Vector3(.6, .4, 0)); this.baseTransform.parent.setEnabled(false);
} }
private adjustRadio(radio: RadioGroup | CheckboxGroup) { private adjustRadio(radio: RadioGroup | CheckboxGroup) {
radio.groupPanel.height = "512px"; radio.groupPanel.height = "512px";
radio.groupPanel.background = "#cccccc";
radio.groupPanel.color = "#000000";
radio.groupPanel.fontSize = "64px"; radio.groupPanel.fontSize = "64px";
radio.groupPanel.children[0].height = "70px"; radio.groupPanel.children[0].height = "70px";
radio.groupPanel.paddingLeft = "16px"; radio.groupPanel.paddingLeft = "16px";
@ -100,16 +117,15 @@ export class ConfigMenu extends AbstractMenu {
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);
console.log(selected);
radio.addRadio(snap.label, this.createVal.bind(this), selected); radio.addRadio(snap.label, this.createVal.bind(this), selected);
} }
this.adjustRadio(radio); this.adjustRadio(radio);
return radio; return radio;
} }
private buildFlyModeControl(selectionPanel: SelectionPanel): CheckboxGroup { private buildFlyModeControl(selectionPanel: SelectionPanel): CheckboxGroup {
const checkbox = new CheckboxGroup("Fly Mode"); const checkbox = new CheckboxGroup("Fly Mode");
selectionPanel.addGroup(checkbox); selectionPanel.addGroup(checkbox);
@ -117,7 +133,6 @@ export class ConfigMenu extends AbstractMenu {
this.adjustRadio(checkbox); this.adjustRadio(checkbox);
return checkbox; return checkbox;
} }
private buildRotationSnapControl(selectionPanel: SelectionPanel): RadioGroup { private buildRotationSnapControl(selectionPanel: SelectionPanel): RadioGroup {
const radio = new RadioGroup("Rotation Snap"); const radio = new RadioGroup("Rotation Snap");
selectionPanel.addGroup(radio); selectionPanel.addGroup(radio);
@ -128,15 +143,11 @@ export class ConfigMenu extends AbstractMenu {
this.adjustRadio(radio); this.adjustRadio(radio);
return radio; return radio;
} }
private buildGridSizeControl(selectionPanel: SelectionPanel): RadioGroup { private buildGridSizeControl(selectionPanel: SelectionPanel): RadioGroup {
const radio = new RadioGroup("Grid Snap"); const radio = new RadioGroup("Grid Snap");
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.gridSnap == snap.value); const selected = (this.config.current.gridSnap == snap.value);
radio.addRadio(snap.label, this.gridVal.bind(this), selected); radio.addRadio(snap.label, this.gridVal.bind(this), selected);
} }
this.adjustRadio(radio); this.adjustRadio(radio);

View File

@ -168,20 +168,21 @@ export class EditMenu extends AbstractMenu {
//this.scaleMenu = new ScaleMenu(this.scene, this.xr, this.controllers); //this.scaleMenu = new ScaleMenu(this.scene, this.xr, this.controllers);
this.sounds = new DiaSounds(scene); this.sounds = new DiaSounds(scene);
this.diagramManager = diagramManager; this.diagramManager = diagramManager;
this.gizmoManager = new GizmoManager(scene); /*this.gizmoManager = new GizmoManager(scene);
this.gizmoManager.boundingBoxGizmoEnabled = true; this.gizmoManager.boundingBoxGizmoEnabled = true;
this.gizmoManager.gizmos.boundingBoxGizmo.scaleBoxSize = .020; this.gizmoManager.gizmos.boundingBoxGizmo.scaleBoxSize = .020;
this.gizmoManager.gizmos.boundingBoxGizmo.rotationSphereSize = .020; this.gizmoManager.gizmos.boundingBoxGizmo.rotationSphereSize = .020;
this.gizmoManager.gizmos.boundingBoxGizmo.scaleDragSpeed = 2; this.gizmoManager.gizmos.boundingBoxGizmo.scaleDragSpeed = 2;
this.gizmoManager.clearGizmoOnEmptyPointerEvent = true; this.gizmoManager.clearGizmoOnEmptyPointerEvent = true;
this.gizmoManager.usePointerToAttachGizmos = false; this.gizmoManager.usePointerToAttachGizmos = false;*/
this.manager = new GUI3DManager(this.scene); this.manager = new GUI3DManager(this.scene);
const panel = new PlanePanel();
const panel = new PlanePanel();
panel.orientation = PlanePanel.FACEFORWARDREVERSED_ORIENTATION;
panel.columns = 4; panel.columns = 4;
this.manager.addControl(panel); this.manager.addControl(panel);
//panel.addControl(this.makeButton("Cameras", "camera")); //panel.addControl(this.makeButton("Cameras", "camera"));
panel.addControl(this.makeButton("Modify", "modify")); //panel.addControl(this.makeButton("Modify", "modify"));
panel.addControl(this.makeButton("Remove", "remove")); panel.addControl(this.makeButton("Remove", "remove"));
panel.addControl(this.makeButton("Label", "label")); panel.addControl(this.makeButton("Label", "label"));
panel.addControl(this.makeButton("Copy", "copy")); panel.addControl(this.makeButton("Copy", "copy"));
@ -218,7 +219,7 @@ export class EditMenu extends AbstractMenu {
}); });
this.panel = panel; this.panel = panel;
this.createHandle(this.manager.rootContainer.children[0].node); this.createHandle(this.manager.rootContainer.children[0].node);
this.manager.rootContainer.children[0].node.position.y = .2; this.manager.rootContainer.children[0].node.position.y = .15;
this.isVisible = false; this.isVisible = false;
} }

View File

@ -17,6 +17,7 @@ export class Handle {
handle.metadata = {handle: true}; handle.metadata = {handle: true};
if (this.transformNode) { if (this.transformNode) {
this.transformNode.setParent(handle); this.transformNode.setParent(handle);
//this.transformNode.rotation.y = Math.PI;
} }
this.mesh = handle; this.mesh = handle;
} }
@ -30,9 +31,9 @@ function getHandleMesh(name: string, scene: Scene): InstancedMesh {
return instance; return instance;
} }
const handle = MeshBuilder.CreateCapsule("base-handle-mesh", { const handle = MeshBuilder.CreateCapsule("base-handle-mesh", {
radius: .05, radius: .04,
orientation: Vector3.Right(), orientation: Vector3.Right(),
height: .4 height: .3
}, scene); }, scene);
handle.setEnabled(false); handle.setEnabled(false);
handle.material = buildStandardMaterial('base-handle-material', scene, "#CCCCDD"); handle.material = buildStandardMaterial('base-handle-material', scene, "#CCCCDD");

View File

@ -57,8 +57,9 @@ function DiagramList({display, onClick}) {
useEffect(() => { useEffect(() => {
const listDb = async () => { const listDb = async () => {
const data = await indexedDB.databases(); const data = await indexedDB.databases();
let i = 0;
setDbList(data.filter((item) => item.name.indexOf('_pouch_') > -1).map((item) => { setDbList(data.filter((item) => item.name.indexOf('_pouch_') > -1).map((item) => {
return {name: item.name.replace('_pouch_', '')} return {key: i++, name: item.name.replace('_pouch_', '')}
})); }));
}; };
listDb(); listDb();
@ -71,7 +72,7 @@ function DiagramList({display, onClick}) {
<div id="startCreate"><a href="#" id="startCreateLink" onClick={onClick}>New</a></div> <div id="startCreate"><a href="#" id="startCreateLink" onClick={onClick}>New</a></div>
<div id="diagramListContent"> <div id="diagramListContent">
<ul> <ul>
{dbList.map((item) => <li><a href={`/db/${item.name}`}>{item.name}</a></li>)} {dbList.map((item) => <li key={item.key}><a href={`/db/${item.name}`}>{item.name}</a></li>)}
</ul> </ul>
</div> </div>
</div> </div>

View File

@ -1,75 +1,50 @@
import {Color3, MeshBuilder, Observable, Scene, StandardMaterial, TransformNode, Vector3} from "@babylonjs/core"; import {Color3, MeshBuilder, Node, Scene, StandardMaterial, TransformNode, Vector3} from "@babylonjs/core";
import {enumKeys} from "../../util/functions/enumKeys"; import {enumKeys} from "../../util/functions/enumKeys";
import {ToolType} from "../types/toolType"; import {ToolType} from "../types/toolType";
import {buildTool} from "./buildTool"; import {buildTool} from "./buildTool";
import {AdvancedDynamicTexture, ColorPicker} from "@babylonjs/gui";
export function buildColor(color: Color3, scene: Scene, parent: TransformNode, index: number, export function buildColor(color: Color3, scene: Scene, parent: TransformNode, index: number): Node {
colorChangeObservable: Observable<{ oldColor: string, newColor: string }>) { const width = .1;
const width = 1; const depth = .1;
const depth = .2; const height = .01;
//const material = new PBRMaterial("material-" + color.toHexString(), scene);
const material = new StandardMaterial("material-" + color.toHexString(), scene); const material = new StandardMaterial("material-" + color.toHexString(), scene);
material.diffuseColor = color; material.diffuseColor = color;
material.roughness = 1; material.ambientColor = color;
material.specularPower = 1;
//material.emissiveColor = color;
//const material = new StandardMaterial("material-" + color.toHexString(), scene); //material.emissiveColor = new Color3(.1,.1,.1);
//material.albedoColor = color; //material.roughness = 1;
//material.metallic = 1; //material.specularPower = .0001;
//material.bumpTexture = new MarbleProceduralTexture("marble", 1024, scene);
//material.bumpTexture.level = 5; const colorBoxMesh = MeshBuilder.CreateBox("toolbox-color-" + color.toHexString(), {
const mesh = MeshBuilder.CreateBox("toolbox-color-" + color.toHexString(), {
width: width, width: width,
height: .01, height: height,
depth: depth depth: depth
}, scene); }, scene);
mesh.material = material; colorBoxMesh.rotation.x = Math.PI / 2;
mesh.position.z = index / 4; colorBoxMesh.material = material;
mesh.parent = parent; const rowLength = 8;
mesh.metadata = {tool: 'color'}; colorBoxMesh.position.x = -.45 + ((index % rowLength) / rowLength);
colorBoxMesh.position.y = -Math.floor(index / rowLength) * .1;
colorBoxMesh.parent = parent;
colorBoxMesh.metadata = {tool: 'color'};
let i = 0; let i = 0;
const tools = [];
for (const tool of enumKeys(ToolType)) { for (const tool of enumKeys(ToolType)) {
const newItem = buildTool(ToolType[tool], mesh); const newItem = buildTool(ToolType[tool], colorBoxMesh, material);
if (newItem) { if (newItem) {
//buildColorPicker(scene, color, newItem, material, i, colorChangeObservable);
newItem.position = new Vector3(calculatePosition(++i), .1, 0); newItem.position = new Vector3(calculatePosition(++i), .1, 0);
tools.push(newItem.id);
} }
} }
const colorPickerPlane = MeshBuilder colorBoxMesh.metadata.tools = tools;
.CreatePlane("colorPickerPlane", return colorBoxMesh;
{
width: .1,
height: .1
}, scene);
const colorPickerTexture = AdvancedDynamicTexture.CreateForMesh(colorPickerPlane, 1024, 1024);
colorPickerPlane.parent = mesh;
colorPickerPlane.position = new Vector3(calculatePosition(++i), .1, 0);
const colorPicker = new ColorPicker("color-picker");
colorPicker.scaleY = 5;
colorPicker.scaleX = 5;
colorPicker.value = color;
colorPicker.onValueChangedObservable.add((value) => {
const oldColor = material.diffuseColor.clone();
const newColor = value.clone();
material.diffuseColor = newColor;
const newColorHex = newColor.toHexString();
material.id = "material-" + newColorHex;
material.name = "material-" + newColorHex;
mesh.id = "toolbox-color-" + newColorHex;
mesh.name = "toolbox-color-" + newColorHex;
colorChangeObservable.notifyObservers({
oldColor: oldColor.toHexString(),
newColor: newColor.toHexString()
});
});
colorPickerTexture.addControl(colorPicker);
} }
const GRID_SIZE = 5; const GRID_SIZE = 5;
function calculatePosition(i: number) { function calculatePosition(i: number) {

View File

@ -7,11 +7,16 @@ export function buildMesh(type: ToolType, toolname: string, scene: Scene): Mesh
return MeshBuilder.CreateBox(toolname, {width: 1, height: 1, depth: 1}, scene); return MeshBuilder.CreateBox(toolname, {width: 1, height: 1, depth: 1}, scene);
case ToolType.SPHERE: case ToolType.SPHERE:
return MeshBuilder.CreateIcoSphere(toolname, {subdivisions: 5, radius: .5}, scene); return MeshBuilder.CreateIcoSphere(toolname, {subdivisions: 6, radius: .5, flat: false}, scene);
//return MeshBuilder.CreateSphere(toolname, {diameter: 1}, scene); //return MeshBuilder.CreateSphere(toolname, {diameter: 1}, scene);
case ToolType.CYLINDER: case ToolType.CYLINDER:
return MeshBuilder.CreateCylinder(toolname, {height: 1, diameter: 1, subdivisions: 1, tessellation: 12}, scene); return MeshBuilder.CreateCylinder(toolname, {
height: 1,
diameter: 1,
subdivisions: 1,
tessellation: 24
}, scene);
case ToolType.CONE: case ToolType.CONE:
return MeshBuilder.CreateCylinder(toolname, { return MeshBuilder.CreateCylinder(toolname, {
@ -19,7 +24,7 @@ export function buildMesh(type: ToolType, toolname: string, scene: Scene): Mesh
subdivisions: 1, subdivisions: 1,
height: 1, height: 1,
diameterBottom: 1, diameterBottom: 1,
tessellation: 12 tessellation: 24
}, scene); }, scene);
case ToolType.PLANE: case ToolType.PLANE:

View File

@ -1,44 +1,48 @@
import {AbstractMesh, Color3, InstancedMesh, PBRMaterial, StandardMaterial, Vector3} from "@babylonjs/core"; import {AbstractMesh, Color3, InstancedMesh, Material, PBRMaterial, StandardMaterial, Vector3} from "@babylonjs/core";
import {ToolType} from "../types/toolType"; import {ToolType} from "../types/toolType";
import {buildMesh} from "./buildMesh"; import {buildMesh} from "./buildMesh";
const WIDGET_SIZE = .1; const WIDGET_SIZE = .1;
export function buildTool(tool: ToolType, parent: AbstractMesh) { export function buildTool(tool: ToolType, colorParent: AbstractMesh, material: Material) {
let id = "ID"; let id = "ID";
switch (parent.material.getClassName()) { switch (material.getClassName()) {
case "StandardMaterial": case "StandardMaterial":
id = toolId(tool, (parent.material as StandardMaterial).diffuseColor); id = toolId(tool, (material as StandardMaterial).diffuseColor);
break; break;
case "PBRMaterial": case "PBRMaterial":
id = toolId(tool, (parent.material as PBRMaterial).albedoColor); id = toolId(tool, (material as PBRMaterial).albedoColor);
break; break;
default: default:
this.logger.warn("buildTool: parent.material is null"); this.logger.warn("buildTool: parent.material is null");
} }
const newItem = buildMesh(tool, `tool-${id}`, parent.getScene()); const newItem = buildMesh(tool, `tool-${id}`, colorParent.getScene());
if (!newItem) { if (!newItem) {
return null; return null;
} }
newItem.material = parent.material; newItem.material = material;
if (tool === ToolType.PLANE) { if (tool === ToolType.PLANE) {
newItem.material.backFaceCulling = false; newItem.material.backFaceCulling = false;
} }
newItem.scaling = new Vector3(WIDGET_SIZE, newItem.scaling = new Vector3(WIDGET_SIZE,
WIDGET_SIZE, WIDGET_SIZE,
WIDGET_SIZE); WIDGET_SIZE);
newItem.parent = parent; newItem.parent = colorParent.parent;
newItem.metadata = {template: tool, tool: true}; newItem.metadata = {template: tool, tool: true, grabClone: true};
const instance = new InstancedMesh("instance-" + id, newItem); const instance = new InstancedMesh("instance-" + id, newItem);
instance.metadata = {template: tool, tool: true}; instance.metadata = {template: tool, tool: true, grabClone: true};
instance.parent = parent; instance.parent = colorParent.parent;
instance.setEnabled(false);
newItem.setEnabled(false); newItem.setEnabled(false);
/*
newItem.onEnabledStateChangedObservable.add(() => { newItem.onEnabledStateChangedObservable.add(() => {
instance.setEnabled(false); instance.setEnabled(false);
}); });
*/
return instance; return instance;
} }

View File

@ -1,20 +0,0 @@
import {Color3, Scene, StandardMaterial, TransformNode} from "@babylonjs/core";
import {enumKeys} from "../util/functions/enumKeys";
import {ToolType} from "./types/toolType";
import {buildMesh} from "./functions/buildMesh";
export class SimpleToolbox {
private scene: Scene;
private transformNode: TransformNode;
constructor(scene: Scene) {
this.scene = scene;
this.transformNode = new TransformNode("SimpleToolbox", this.scene);
}
private buildBaseShapes(color: Color3) {
for (const tool of enumKeys(ToolType)) {
const mesh = buildMesh(ToolType[tool], id = toolId(tool, (parent.material as StandardMaterial).diffuseColor), this.transformNode);
}
}
}

View File

@ -1,49 +1,52 @@
import {AssetContainer, Color3, Mesh, Observable, Scene, TransformNode, Vector3} from "@babylonjs/core"; import {AxesViewer, Color3, Mesh, Node, Observable, Scene, TransformNode, Vector3} from "@babylonjs/core";
import {GUI3DManager, StackPanel3D,} from "@babylonjs/gui";
import {Button3D, GUI3DManager, StackPanel3D, TextBlock} from "@babylonjs/gui";
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 log from "loglevel"; import log from "loglevel";
import {Handle} from "../objects/handle"; import {Handle} from "../objects/handle";
const colors: string[] = [
"#222222", "#8b4513", "#006400", "#778899",
"#4b0082", "#ff0000", "#ffa500", "#ffff00",
"#00ff00", "#00ffff", "#0000ff", "#ff00ff",
"#1e90ff", "#98fb98", "#ffe4b5", "#ff69b4"
]
export class Toolbox { export class Toolbox {
private readonly logger = log.getLogger('Toolbox'); private readonly logger = log.getLogger('Toolbox');
private index = 0; private index = 0;
public readonly toolboxBaseNode: TransformNode;
private readonly scene: Scene; private readonly scene: Scene;
public readonly node: TransformNode; private colorPicker: TransformNode;
private changing = false;
private readonly manager: GUI3DManager; private readonly manager: GUI3DManager;
private readonly addPanel: StackPanel3D; private readonly addPanel: StackPanel3D;
private readonly controllers: Controllers;
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: Handle; private handle: Handle;
constructor(scene: Scene, controllers: Controllers) { private axes: AxesViewer;
constructor(scene: Scene) {
this.scene = scene; this.scene = scene;
this.controllers = controllers;
this.addPanel = new StackPanel3D(); this.addPanel = new StackPanel3D();
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.toolboxBaseNode = new TransformNode("toolbox", this.scene);
this.handle = new Handle(this.node); this.handle = new Handle(this.toolboxBaseNode);
this.node.position.y = .1; this.toolboxBaseNode.position.y = .2;
this.node.position.z = .2; //this.toolboxBaseNode.position.z = .05;
this.node.scaling = new Vector3(0.6, 0.6, 0.6); /**this.axes = new AxesViewer(this.scene);
this.axes.xAxis.parent = this.toolboxBaseNode;
this.axes.yAxis.parent = this.toolboxBaseNode;
this.axes.zAxis.parent = this.toolboxBaseNode;*/
this.toolboxBaseNode.scaling = new Vector3(0.6, 0.6, 0.6);
this.buildToolbox(); this.buildToolbox();
}
if (!this.xObserver) { public toggle() {
this.xObserver = this.controllers.controllerObserver.add((evt) => { this.toolboxBaseNode.parent.setEnabled(!this.toolboxBaseNode.parent.isEnabled(false));
if (evt.type == ControllerEventType.X_BUTTON) { setMenuPosition(this.toolboxBaseNode.parent as Mesh, this.scene,
if (evt.value == 1) { Vector3.Zero());
this.node.parent.setEnabled(!this.node.parent.isEnabled(false));
setMenuPosition(this.node.parent as Mesh, this.scene,
Vector3.Zero());
}
}
});
}
} }
public updateToolbox(color: string) { public updateToolbox(color: string) {
@ -51,7 +54,7 @@ export class Toolbox {
if (this.scene.getMeshById("toolbox-color-" + color)) { if (this.scene.getMeshById("toolbox-color-" + color)) {
return; return;
} else { } else {
buildColor(Color3.FromHexString(color), this.scene, this.node, this.index++, this.colorChangeObservable); buildColor(Color3.FromHexString(color), this.scene, this.toolboxBaseNode, this.index++);
} }
} else { } else {
this.logger.warn("updateToolbox called with no color"); this.logger.warn("updateToolbox called with no color");
@ -59,38 +62,48 @@ export class Toolbox {
} }
private readonly objectObservable: Observable<AssetContainer> = new Observable(); private nodePredicate = (node: Node) => {
return node.getClassName() == "InstancedMesh" &&
node.isEnabled(false) == true
};
private buildToolbox() { private buildToolbox() {
this.scene.onPointerObservable.add((pointerInfo) => {
if (pointerInfo.type == 1 && pointerInfo.pickInfo.pickedMesh?.metadata?.tool == 'color') {
if (this.changing) {
console.log('changing');
this.colorPicker.setEnabled(true);
return;
} else {
const active = pointerInfo.pickInfo.pickedMesh?.parent.getChildren(this.nodePredicate, true);
for (const node of active) {
node.setEnabled(false);
}
const nodes = pointerInfo.pickInfo.pickedMesh?.metadata?.tools;
if (nodes) {
for (const node of nodes) {
this.scene.getNodeById(node)?.setEnabled(true);
}
}
}
const color = "#7777FF"; }
buildColor(Color3.FromHexString(color), this.scene, this.node, this.index++, this.colorChangeObservable);
const addButton = createButton();
this.addPanel.node.parent = this.node.parent;
this.addPanel.addControl(addButton);
this.addPanel.node.scaling = new Vector3(.1, .1, .1);
this.addPanel.position = new Vector3(-.25, 0, 0);
//@TODO: move this somewhere else, just to prototype loading objects.
addButton.onPointerClickObservable.add(() => {
buildColor(Color3.Random(), this.scene, this.node, this.index++, this.colorChangeObservable);
}); });
//this.node.parent let initial = true;
this.node.parent.setEnabled(false); for (const c of colors) {
setMenuPosition(this.node.parent as Mesh, this.scene, const cnode = buildColor(Color3.FromHexString(c), this.scene, this.toolboxBaseNode, this.index++);
if (initial) {
initial = false;
for (const id of cnode.metadata.tools) {
this.scene.getNodeById(id)?.setEnabled(true);
}
}
}
this.toolboxBaseNode.parent.setEnabled(false);
setMenuPosition(this.toolboxBaseNode.parent as Mesh, this.scene,
Vector3.Zero()); Vector3.Zero());
//
} }
} }
function createButton(): Button3D {
const addButton = new Button3D("add-button");
const text = new TextBlock("add-button-text", "Add Color");
text.color = "white";
text.fontSize = "48px";
text.text = "Add Color";
addButton.content = text;
return addButton;
}

View File

@ -33,9 +33,10 @@ export class CustomEnvironment {
if (loading) { if (loading) {
loading.remove(); loading.remove();
} }
const light = new HemisphericLight("light1", new Vector3(.1, 1, 0), scene); const light = new HemisphericLight("light1", new Vector3(1, 2, 1), scene);
light.groundColor = new Color3(.1, .1, .1) light.groundColor = new Color3(.1, .1, .1)
light.intensity = .6; light.diffuse = new Color3(1, 1, 1);
light.intensity = .8;
const physics = new CustomPhysics(this.scene, config); const physics = new CustomPhysics(this.scene, config);
physics physics

View File

@ -36,30 +36,44 @@ export function setMenuPosition(node: TransformNode, scene: Scene, offset: Vecto
*/ */
if (scene.activeCamera) { if (scene.activeCamera) {
switch (scene.activeCamera.getClassName()) { setPosition(node, scene, offset);
case "WebXRCamera":
node.parent = null;
const front = getFrontPosition(.8, scene);
//front.y = scene.activeCamera.globalPosition.y;
node.position = front;
node.position.addInPlace(offset);
node.position.y -= .5;
node.lookAt(scene.activeCamera.globalPosition);
node.rotation.y = node.rotation.y + Math.PI;
break;
case "FreeCamera":
case "DeviceOrientationCamera":
case "ArcRotateCamera":
case "UniversalCamera":
node.parent = scene.activeCamera;
const width = scene.getEngine().getRenderWidth();
const height = scene.getEngine().getRenderHeight();
node.position.z = 2;
node.position.y = -.8;
break;
}
} else {
scene.onActiveCameraChanged.add((scene: Scene) => {
setPosition(node, scene, offset);
});
console.error("No active camera");
} }
} }
function setPosition(node: TransformNode, scene: Scene, offset: Vector3 = Vector3.Zero()) {
const platform = scene.getMeshByName("platform");
switch (scene.activeCamera.getClassName()) {
case "WebXRCamera":
//const oldParent = node.parent;
//console.log(oldParent.name);
node.setParent(null);
const front = getFrontPosition(1, scene);
const camPos = scene.activeCamera.globalPosition.clone();
node.position.x = front.x + offset.x;
node.position.z = front.z + offset.z;
node.position.y = 1.2 + offset.y;
node.lookAt(camPos);
node.setParent(platform);
break;
case "FreeCamera":
case "DeviceOrientationCamera":
case "ArcRotateCamera":
case "UniversalCamera":
node.parent = scene.activeCamera;
const width = scene.getEngine().getRenderWidth();
const height = scene.getEngine().getRenderHeight();
node.position.z = 2;
node.position.y = -.8 + offset.y;
node.position.x = offset.x;
break;
}
console.log('menu position set');
}

View File

@ -1,4 +1,4 @@
import {Engine, FreeCamera, Scene, Vector3} from "@babylonjs/core"; import {Color3, Engine, FreeCamera, Scene, Vector3} from "@babylonjs/core";
import '@babylonjs/loaders'; import '@babylonjs/loaders';
import {DiagramManager} from "./diagram/diagramManager"; import {DiagramManager} from "./diagram/diagramManager";
import {Toolbox} from "./toolbox/toolbox"; import {Toolbox} from "./toolbox/toolbox";
@ -6,7 +6,7 @@ import log, {Logger} from "loglevel";
import {AppConfig} from "./util/appConfig"; import {AppConfig} from "./util/appConfig";
import {GamepadManager} from "./controllers/gamepadManager"; import {GamepadManager} from "./controllers/gamepadManager";
import {CustomEnvironment} from "./util/customEnvironment"; import {CustomEnvironment} from "./util/customEnvironment";
import {Controllers} from "./controllers/controllers"; import {ControllerEventType, Controllers} from "./controllers/controllers";
import {Spinner} from "./util/spinner"; import {Spinner} from "./util/spinner";
import {PouchdbPersistenceManager} from "./integration/pouchdbPersistenceManager"; import {PouchdbPersistenceManager} from "./integration/pouchdbPersistenceManager";
import {addSceneInspector} from "./util/functions/sceneInspctor"; import {addSceneInspector} from "./util/functions/sceneInspctor";
@ -38,13 +38,21 @@ export class VrApp {
} }
const scene = new Scene(this.engine); const scene = new Scene(this.engine);
this.scene = scene; this.scene = scene;
this.scene.ambientColor = new Color3(.1, .1, .1);
const spinner = new Spinner(scene); const spinner = new Spinner(scene);
spinner.show(); spinner.show();
const config = new AppConfig(); const config = new AppConfig();
const controllers = new Controllers(); const controllers = new Controllers();
const toolbox = new Toolbox(scene, controllers); const toolbox = new Toolbox(scene);
controllers.controllerObserver.add((evt) => {
if (evt.type == ControllerEventType.X_BUTTON) {
if (evt.value == 1) {
toolbox.toggle();
}
}
})
const diagramManager = new DiagramManager(scene, controllers, toolbox, config); const diagramManager = new DiagramManager(scene, controllers, toolbox, config);
const db = new PouchdbPersistenceManager(); const db = new PouchdbPersistenceManager();
db.setDiagramManager(diagramManager); db.setDiagramManager(diagramManager);
db.configObserver.add((newConfig) => { db.configObserver.add((newConfig) => {