diff --git a/package-lock.json b/package-lock.json index 0aefad7..90157e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,14 +8,14 @@ "name": "immersive", "version": "0.0.1", "dependencies": { - "@babylonjs/core": "^6.21.3", - "@babylonjs/gui": "^6.21.3", - "@babylonjs/havok": "1.1.4", - "@babylonjs/inspector": "^6.21.3", - "@babylonjs/loaders": "^6.21.3", - "@babylonjs/materials": "^6.21.3", - "@babylonjs/procedural-textures": "^6.21.3", - "@babylonjs/serializers": "^6.21.3", + "@babylonjs/core": "^6.45.1", + "@babylonjs/gui": "^6.45.1", + "@babylonjs/havok": "1.3.1", + "@babylonjs/inspector": "^6.45.1", + "@babylonjs/loaders": "^6.45.1", + "@babylonjs/materials": "^6.45.1", + "@babylonjs/procedural-textures": "^6.45.1", + "@babylonjs/serializers": "^6.45.1", "@cloudflare/workers-types": "^4.20230821.0", "@netlify/functions": "^2.3.0", "@typed-mxgraph/typed-mxgraph": "^1.0.8", @@ -49,14 +49,14 @@ } }, "node_modules/@babylonjs/core": { - "version": "6.21.3", - "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-6.21.3.tgz", - "integrity": "sha512-j+UnhCSz3HldEWVHnxRHKGLqhWafju/WGqKaLXncbgo/Fkz48OoFbrec651jv1cBiNx82zdVa59c8VIK6FNSOw==" + "version": "6.45.1", + "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-6.45.1.tgz", + "integrity": "sha512-wkORoAqpnZb10bUhrI0vinE9IiW7+gSgH4U4Zp41wO4kSeV0mtJY+Q5Ez6/n9ad9sLykD2FD7650B+Qi5tTMSw==" }, "node_modules/@babylonjs/gui": { - "version": "6.21.3", - "resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-6.21.3.tgz", - "integrity": "sha512-bsh6GT/tvWIDua1vSg2n3GeMGWnkuW7j9Dpi6+NVRjaXYEKdtbsSuWwND8JVClSoYa23qosIeeNPCqRPB8pq3g==", + "version": "6.45.1", + "resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-6.45.1.tgz", + "integrity": "sha512-lev/3nprv4t8lu3kW1zdlH7VzlWh9dmyZ2PkzybmBI6nB48bswPm7cX2ppaFTkpY8Z904js9TOsrYQotMzsUiw==", "peerDependencies": { "@babylonjs/core": "^6.0.0" } @@ -74,17 +74,17 @@ } }, "node_modules/@babylonjs/havok": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@babylonjs/havok/-/havok-1.1.4.tgz", - "integrity": "sha512-mK/sgqv4LaI4BjoQgWYGxOBX45hVauZ8PopPkIUIB42DiVPgWkiCZbBQ9pL7r1tbLhThvV1RTokj4z5bVGBayw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@babylonjs/havok/-/havok-1.3.1.tgz", + "integrity": "sha512-ctaAQ2RN7hzE2vukGiA27//08YE4RNqH4RN26fCd8q0q7Qn+pXg4P61ZgakWYox/YS4VqHrB3ovZUDtPt2Scxg==", "dependencies": { "@types/emscripten": "^1.39.6" } }, "node_modules/@babylonjs/inspector": { - "version": "6.21.3", - "resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-6.21.3.tgz", - "integrity": "sha512-XJfqYVilSWEDLRy7IaSxkGNAs5U+SHsWBi9+eS49bFsP06fGjcbJjF2ZK1qY7DbMEThbwzwD6VypJtjKaoF9kw==", + "version": "6.45.1", + "resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-6.45.1.tgz", + "integrity": "sha512-4YhJLD2FrVXUFIU+ttBanhevVaCBVLaBxhPuwrxXxKWkuBulFOQz7GkvRT/CJwA3Ad9/66qwS5+vfRT99GLM/w==", "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.1.0", "@fortawesome/free-regular-svg-icons": "^6.0.0", @@ -102,34 +102,34 @@ } }, "node_modules/@babylonjs/loaders": { - "version": "6.21.3", - "resolved": "https://registry.npmjs.org/@babylonjs/loaders/-/loaders-6.21.3.tgz", - "integrity": "sha512-2GpMOEQFuih8O/l6IIyGd0i0gCYo6x8LPjD10FBFBVX2dSkazhWDaAQSS8HCZNY2Uennmy83ePzuTf5RvaKDaw==", + "version": "6.45.1", + "resolved": "https://registry.npmjs.org/@babylonjs/loaders/-/loaders-6.45.1.tgz", + "integrity": "sha512-a75JvRVxT3DROCrl5iigLEpI5/eR7Rh4wdsDzZNn7bv3sXB40Kbw8EL60W3jDBXPdGUqNVzqtrxJF/ec2udg/Q==", "peerDependencies": { "@babylonjs/core": "^6.0.0", "babylonjs-gltf2interface": "^6.0.0" } }, "node_modules/@babylonjs/materials": { - "version": "6.21.3", - "resolved": "https://registry.npmjs.org/@babylonjs/materials/-/materials-6.21.3.tgz", - "integrity": "sha512-oH/ZmiYKTJnvWzaZVNDPSjvekKK9C/eQZaiMcYiPTb39LHJw+bnIJS8NyvWjDLLn4cJ9XfEict69WqMb1XItVA==", + "version": "6.45.1", + "resolved": "https://registry.npmjs.org/@babylonjs/materials/-/materials-6.45.1.tgz", + "integrity": "sha512-v1jqgG0bfX+8Qezq4eDT2sSjpQYW+ocNU70dbJF0AYrhuhhgf0SpM28C7DAKi9GUOKjMvZrIBEbFmJ6AijLjcQ==", "peerDependencies": { "@babylonjs/core": "^6.0.0" } }, "node_modules/@babylonjs/procedural-textures": { - "version": "6.21.3", - "resolved": "https://registry.npmjs.org/@babylonjs/procedural-textures/-/procedural-textures-6.21.3.tgz", - "integrity": "sha512-S1KIMrrVubk06mxuVeLGH8YngUj1W0zhdYjp2tHP2a7gueARG8a2OhqLW4e0MwFxi7XnP9DuFyzmkK95XZMaKw==", + "version": "6.45.1", + "resolved": "https://registry.npmjs.org/@babylonjs/procedural-textures/-/procedural-textures-6.45.1.tgz", + "integrity": "sha512-QpLuPknYIvylfUscSqorkuXO4QSI49atQnScWN43ZpRzr+ecXWnxEaOyAmt7bbf93htshtIkUQdJhwx8w4fqrg==", "peerDependencies": { "@babylonjs/core": "^6.0.0" } }, "node_modules/@babylonjs/serializers": { - "version": "6.21.3", - "resolved": "https://registry.npmjs.org/@babylonjs/serializers/-/serializers-6.21.3.tgz", - "integrity": "sha512-E8jerSLDrDkwkNc8D9a9vmvPlNJiaXUl5m6cIUQ317oUk0/pT06NiM/N//HbyjM8ccnkaPUBkNBq4dxtPW/XSw==", + "version": "6.45.1", + "resolved": "https://registry.npmjs.org/@babylonjs/serializers/-/serializers-6.45.1.tgz", + "integrity": "sha512-iSPUdjZhQIbSyi21IFiFC/wm6Bj4zcH9NhsN9i+xqLTbO/Uho49cHU0ew39n0Xn+LRsGRMTJWQLTsp+TPvAvrw==", "peerDependencies": { "@babylonjs/core": "^6.0.0", "babylonjs-gltf2interface": "^6.0.0" diff --git a/package.json b/package.json index 2c8e12d..1f99733 100644 --- a/package.json +++ b/package.json @@ -16,14 +16,14 @@ }, "dependencies": { "axios": "^0.24.0", - "@babylonjs/core": "^6.21.3", - "@babylonjs/gui": "^6.21.3", - "@babylonjs/havok": "1.1.4", - "@babylonjs/inspector": "^6.21.3", - "@babylonjs/loaders": "^6.21.3", - "@babylonjs/materials": "^6.21.3", - "@babylonjs/procedural-textures": "^6.21.3", - "@babylonjs/serializers": "^6.21.3", + "@babylonjs/core": "^6.45.1", + "@babylonjs/gui": "^6.45.1", + "@babylonjs/havok": "1.3.1", + "@babylonjs/inspector": "^6.45.1", + "@babylonjs/loaders": "^6.45.1", + "@babylonjs/materials": "^6.45.1", + "@babylonjs/procedural-textures": "^6.45.1", + "@babylonjs/serializers": "^6.45.1", "@cloudflare/workers-types": "^4.20230821.0", "@netlify/functions": "^2.3.0", "events": "^3.3.0", diff --git a/src/controllers/base.ts b/src/controllers/base.ts index a25a680..0cc731d 100644 --- a/src/controllers/base.ts +++ b/src/controllers/base.ts @@ -143,7 +143,7 @@ export class Base { this.previousScaling = mesh?.scaling.clone(); this.previousPosition = mesh?.position.clone(); - if (("toolbox" != mesh?.parent?.parent?.id) || player) { + if (!mesh.metadata?.grabClone || player) { if (mesh.physicsBody) { const transformNode = setupTransformNode(mesh, this.controller.motionController.rootMesh); mesh.physicsBody.setMotionType(PhysicsMotionType.ANIMATED); @@ -155,6 +155,8 @@ export class Base { this.grabbedMesh = mesh; } else { 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.grabbedMesh = clone.newMesh; this.previousParentId = null; diff --git a/src/controllers/webController.ts b/src/controllers/webController.ts index 5326e32..b39c91c 100644 --- a/src/controllers/webController.ts +++ b/src/controllers/webController.ts @@ -51,9 +51,16 @@ export class WebController { } if (kbInfo.type == KeyboardEventTypes.KEYUP) { this.rig.turn(0); + this.rig.updown(0); } if (kbInfo.type == 1) { switch (kbInfo.event.key) { + case "W": + this.rig.updown(-this.speed); + break; + case "S": + this.rig.updown(this.speed); + break; case "ArrowUp": case "w": this.rig.forwardback(-this.speed); diff --git a/src/information/inputTextView.ts b/src/information/inputTextView.ts index fe5b0b2..33306a0 100644 --- a/src/information/inputTextView.ts +++ b/src/information/inputTextView.ts @@ -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 {AdvancedDynamicTexture, Control, InputText, VirtualKeyboard} from "@babylonjs/gui"; import {ControllerEventType, Controllers} from "../controllers/controllers"; @@ -37,8 +37,10 @@ export class InputTextView { public showVirtualKeyboard() { - + const inputBaseNode = new TransformNode("inputBase", 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 input = new InputText(); @@ -96,7 +98,7 @@ export class InputTextView { 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(); } diff --git a/src/menus/configMenu.ts b/src/menus/configMenu.ts index c627f6a..5907de3 100644 --- a/src/menus/configMenu.ts +++ b/src/menus/configMenu.ts @@ -1,5 +1,5 @@ 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 {ControllerEventType, Controllers} from "../controllers/controllers"; import {DiaSounds} from "../util/diaSounds"; @@ -9,6 +9,7 @@ import {setMenuPosition} from "../util/functions/setMenuPosition"; export class ConfigMenu extends AbstractMenu { private sounds: DiaSounds; private config: AppConfig; + private readonly baseTransform: TransformNode; private gridSnaps: Array<{ label: string, value: number }> = [ {label: "Off", value: 0}, {label: "0.01", value: 0.01}, @@ -22,11 +23,11 @@ export class ConfigMenu extends AbstractMenu { {label: "22.5", value: 22.5}, {label: "45", value: 45}, {label: "90", value: 90}, - ] constructor(scene: Scene, xr: WebXRDefaultExperience, controllers: Controllers, config: AppConfig) { super(scene, xr, controllers); + this.baseTransform = new TransformNode("configMenuBase", scene); this.config = config; this.sounds = new DiaSounds(scene); @@ -35,56 +36,72 @@ export class ConfigMenu extends AbstractMenu { 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)); } - - public toggle() { - if (this.handle) { - this.handle.mesh.dispose(false, true); - this.sounds.exit.play(); - this.handle = null; - return; - } - this.sounds.enter.play(); + private buildMenu() { const configPlane = MeshBuilder - .CreatePlane("gridSizePlane", + .CreatePlane("configMenuPlane", { width: .6, height: .3 }, 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); - - configTexture.background = "white"; + //configTexture.background = "#00ffff"; const columnPanel = new StackPanel('columns'); - columnPanel.fontSize = "48px"; columnPanel.isVertical = false; + + //columnPanel.width = 1; + columnPanel.fontSize = "48px"; + //columnPanel.background = "#ff0000"; + // configTexture.addControl(columnPanel); const selectionPanel1 = new SelectionPanel("selectionPanel1"); - selectionPanel1.width = .3; + selectionPanel1.width = "500px"; + //selectionPanel1.width = .3; columnPanel.addControl(selectionPanel1); this.buildGridSizeControl(selectionPanel1); this.buildCreateScaleControl(selectionPanel1); + const selectionPanel2 = new SelectionPanel("selectionPanel2"); - selectionPanel2.width = .3; + selectionPanel2.width = "500px"; + columnPanel.addControl(selectionPanel2); this.buildRotationSnapControl(selectionPanel2); this.buildTurnSnapControl(selectionPanel2); const selectionPanel3 = new SelectionPanel("selectionPanel3"); - selectionPanel3.width = .3; + selectionPanel3.width = "768px"; columnPanel.addControl(selectionPanel3); this.buildFlyModeControl(selectionPanel3); - configPlane.position.set(0, .2, 0); - setMenuPosition(this.handle.mesh, this.scene, new Vector3(.6, .4, 0)); + setMenuPosition(this.handle.mesh, this.scene, new Vector3(.6, .1, 0)); + this.baseTransform.parent.setEnabled(false); + } private adjustRadio(radio: RadioGroup | CheckboxGroup) { radio.groupPanel.height = "512px"; + radio.groupPanel.background = "#cccccc"; + radio.groupPanel.color = "#000000"; radio.groupPanel.fontSize = "64px"; radio.groupPanel.children[0].height = "70px"; radio.groupPanel.paddingLeft = "16px"; @@ -100,16 +117,15 @@ export class ConfigMenu extends AbstractMenu { private buildCreateScaleControl(selectionPanel: SelectionPanel): RadioGroup { const radio = new RadioGroup("Create Scale"); - selectionPanel.addGroup(radio); for (const [index, snap] of this.gridSnaps.entries()) { const selected = (this.config.current.createSnap == snap.value); + console.log(selected); radio.addRadio(snap.label, this.createVal.bind(this), selected); } this.adjustRadio(radio); return radio; } - private buildFlyModeControl(selectionPanel: SelectionPanel): CheckboxGroup { const checkbox = new CheckboxGroup("Fly Mode"); selectionPanel.addGroup(checkbox); @@ -117,7 +133,6 @@ export class ConfigMenu extends AbstractMenu { this.adjustRadio(checkbox); return checkbox; } - private buildRotationSnapControl(selectionPanel: SelectionPanel): RadioGroup { const radio = new RadioGroup("Rotation Snap"); selectionPanel.addGroup(radio); @@ -128,15 +143,11 @@ export class ConfigMenu extends AbstractMenu { this.adjustRadio(radio); return radio; } - private buildGridSizeControl(selectionPanel: SelectionPanel): RadioGroup { const radio = new RadioGroup("Grid Snap"); - selectionPanel.addGroup(radio); - for (const [index, snap] of this.gridSnaps.entries()) { const selected = (this.config.current.gridSnap == snap.value); - radio.addRadio(snap.label, this.gridVal.bind(this), selected); } this.adjustRadio(radio); diff --git a/src/menus/editMenu.ts b/src/menus/editMenu.ts index 8fab356..db58b24 100644 --- a/src/menus/editMenu.ts +++ b/src/menus/editMenu.ts @@ -168,20 +168,21 @@ export class EditMenu extends AbstractMenu { //this.scaleMenu = new ScaleMenu(this.scene, this.xr, this.controllers); this.sounds = new DiaSounds(scene); this.diagramManager = diagramManager; - this.gizmoManager = new GizmoManager(scene); + /*this.gizmoManager = new GizmoManager(scene); this.gizmoManager.boundingBoxGizmoEnabled = true; this.gizmoManager.gizmos.boundingBoxGizmo.scaleBoxSize = .020; this.gizmoManager.gizmos.boundingBoxGizmo.rotationSphereSize = .020; this.gizmoManager.gizmos.boundingBoxGizmo.scaleDragSpeed = 2; this.gizmoManager.clearGizmoOnEmptyPointerEvent = true; - this.gizmoManager.usePointerToAttachGizmos = false; + this.gizmoManager.usePointerToAttachGizmos = false;*/ this.manager = new GUI3DManager(this.scene); - const panel = new PlanePanel(); + const panel = new PlanePanel(); + panel.orientation = PlanePanel.FACEFORWARDREVERSED_ORIENTATION; panel.columns = 4; this.manager.addControl(panel); //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("Label", "label")); panel.addControl(this.makeButton("Copy", "copy")); @@ -218,7 +219,7 @@ export class EditMenu extends AbstractMenu { }); this.panel = panel; 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; } diff --git a/src/objects/handle.ts b/src/objects/handle.ts index 6d1fcff..fd08e85 100644 --- a/src/objects/handle.ts +++ b/src/objects/handle.ts @@ -17,6 +17,7 @@ export class Handle { handle.metadata = {handle: true}; if (this.transformNode) { this.transformNode.setParent(handle); + //this.transformNode.rotation.y = Math.PI; } this.mesh = handle; } @@ -30,9 +31,9 @@ function getHandleMesh(name: string, scene: Scene): InstancedMesh { return instance; } const handle = MeshBuilder.CreateCapsule("base-handle-mesh", { - radius: .05, + radius: .04, orientation: Vector3.Right(), - height: .4 + height: .3 }, scene); handle.setEnabled(false); handle.material = buildStandardMaterial('base-handle-material', scene, "#CCCCDD"); diff --git a/src/react/webApp.tsx b/src/react/webApp.tsx index 5739938..e7a02d9 100644 --- a/src/react/webApp.tsx +++ b/src/react/webApp.tsx @@ -57,8 +57,9 @@ function DiagramList({display, onClick}) { useEffect(() => { const listDb = async () => { const data = await indexedDB.databases(); + let i = 0; 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(); @@ -71,7 +72,7 @@ function DiagramList({display, onClick}) {
New
diff --git a/src/toolbox/functions/buildColor.ts b/src/toolbox/functions/buildColor.ts index 8a38bdc..00badae 100644 --- a/src/toolbox/functions/buildColor.ts +++ b/src/toolbox/functions/buildColor.ts @@ -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 {ToolType} from "../types/toolType"; import {buildTool} from "./buildTool"; -import {AdvancedDynamicTexture, ColorPicker} from "@babylonjs/gui"; -export function buildColor(color: Color3, scene: Scene, parent: TransformNode, index: number, - colorChangeObservable: Observable<{ oldColor: string, newColor: string }>) { - const width = 1; - const depth = .2; - //const material = new PBRMaterial("material-" + color.toHexString(), scene); +export function buildColor(color: Color3, scene: Scene, parent: TransformNode, index: number): Node { + const width = .1; + const depth = .1; + const height = .01; const material = new StandardMaterial("material-" + color.toHexString(), scene); material.diffuseColor = color; - material.roughness = 1; - material.specularPower = 1; - //material.emissiveColor = color; + material.ambientColor = color; - //const material = new StandardMaterial("material-" + color.toHexString(), scene); - //material.albedoColor = color; - //material.metallic = 1; - //material.bumpTexture = new MarbleProceduralTexture("marble", 1024, scene); - //material.bumpTexture.level = 5; - const mesh = MeshBuilder.CreateBox("toolbox-color-" + color.toHexString(), { + //material.emissiveColor = new Color3(.1,.1,.1); + //material.roughness = 1; + //material.specularPower = .0001; + + const colorBoxMesh = MeshBuilder.CreateBox("toolbox-color-" + color.toHexString(), { width: width, - height: .01, + height: height, depth: depth }, scene); - mesh.material = material; - mesh.position.z = index / 4; - mesh.parent = parent; - mesh.metadata = {tool: 'color'}; + colorBoxMesh.rotation.x = Math.PI / 2; + colorBoxMesh.material = material; + const rowLength = 8; + 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; + const tools = []; for (const tool of enumKeys(ToolType)) { - const newItem = buildTool(ToolType[tool], mesh); + const newItem = buildTool(ToolType[tool], colorBoxMesh, material); if (newItem) { + //buildColorPicker(scene, color, newItem, material, i, colorChangeObservable); newItem.position = new Vector3(calculatePosition(++i), .1, 0); + tools.push(newItem.id); } } - const colorPickerPlane = MeshBuilder - .CreatePlane("colorPickerPlane", - { - 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); - + colorBoxMesh.metadata.tools = tools; + return colorBoxMesh; } + + const GRID_SIZE = 5; function calculatePosition(i: number) { diff --git a/src/toolbox/functions/buildMesh.ts b/src/toolbox/functions/buildMesh.ts index 5b2428a..ec6d95e 100644 --- a/src/toolbox/functions/buildMesh.ts +++ b/src/toolbox/functions/buildMesh.ts @@ -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); 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); 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: return MeshBuilder.CreateCylinder(toolname, { @@ -19,7 +24,7 @@ export function buildMesh(type: ToolType, toolname: string, scene: Scene): Mesh subdivisions: 1, height: 1, diameterBottom: 1, - tessellation: 12 + tessellation: 24 }, scene); case ToolType.PLANE: diff --git a/src/toolbox/functions/buildTool.ts b/src/toolbox/functions/buildTool.ts index 7a6b54f..17c31ab 100644 --- a/src/toolbox/functions/buildTool.ts +++ b/src/toolbox/functions/buildTool.ts @@ -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 {buildMesh} from "./buildMesh"; const WIDGET_SIZE = .1; -export function buildTool(tool: ToolType, parent: AbstractMesh) { +export function buildTool(tool: ToolType, colorParent: AbstractMesh, material: Material) { let id = "ID"; - switch (parent.material.getClassName()) { - + switch (material.getClassName()) { case "StandardMaterial": - id = toolId(tool, (parent.material as StandardMaterial).diffuseColor); + id = toolId(tool, (material as StandardMaterial).diffuseColor); break; case "PBRMaterial": - id = toolId(tool, (parent.material as PBRMaterial).albedoColor); + id = toolId(tool, (material as PBRMaterial).albedoColor); break; default: 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) { return null; } - newItem.material = parent.material; + newItem.material = material; if (tool === ToolType.PLANE) { newItem.material.backFaceCulling = false; } newItem.scaling = new Vector3(WIDGET_SIZE, WIDGET_SIZE, WIDGET_SIZE); - newItem.parent = parent; - newItem.metadata = {template: tool, tool: true}; + newItem.parent = colorParent.parent; + newItem.metadata = {template: tool, tool: true, grabClone: true}; const instance = new InstancedMesh("instance-" + id, newItem); - instance.metadata = {template: tool, tool: true}; - instance.parent = parent; + instance.metadata = {template: tool, tool: true, grabClone: true}; + instance.parent = colorParent.parent; + instance.setEnabled(false); newItem.setEnabled(false); + /* newItem.onEnabledStateChangedObservable.add(() => { + instance.setEnabled(false); }); + + */ return instance; } diff --git a/src/toolbox/simpleToolbox.ts b/src/toolbox/simpleToolbox.ts deleted file mode 100644 index 4945904..0000000 --- a/src/toolbox/simpleToolbox.ts +++ /dev/null @@ -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); - } - } -} \ No newline at end of file diff --git a/src/toolbox/toolbox.ts b/src/toolbox/toolbox.ts index 2a7c429..a79fda0 100644 --- a/src/toolbox/toolbox.ts +++ b/src/toolbox/toolbox.ts @@ -1,49 +1,52 @@ -import {AssetContainer, Color3, Mesh, Observable, Scene, TransformNode, Vector3} from "@babylonjs/core"; - -import {Button3D, GUI3DManager, StackPanel3D, TextBlock} from "@babylonjs/gui"; -import {ControllerEventType, Controllers} from "../controllers/controllers"; +import {AxesViewer, Color3, Mesh, Node, Observable, Scene, TransformNode, Vector3} from "@babylonjs/core"; +import {GUI3DManager, StackPanel3D,} from "@babylonjs/gui"; import {setMenuPosition} from "../util/functions/setMenuPosition"; import {buildColor} from "./functions/buildColor"; - import log from "loglevel"; 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 { private readonly logger = log.getLogger('Toolbox'); private index = 0; + public readonly toolboxBaseNode: TransformNode; private readonly scene: Scene; - public readonly node: TransformNode; + private colorPicker: TransformNode; + private changing = false; private readonly manager: GUI3DManager; private readonly addPanel: StackPanel3D; - private readonly controllers: Controllers; - private readonly xObserver; public readonly colorChangeObservable: Observable<{ oldColor: string, newColor: string }> = new Observable<{ oldColor: string; newColor: string }>() private handle: Handle; - constructor(scene: Scene, controllers: Controllers) { + private axes: AxesViewer; + + constructor(scene: Scene) { this.scene = scene; - this.controllers = controllers; this.addPanel = new StackPanel3D(); this.manager = new GUI3DManager(scene); this.manager.addControl(this.addPanel); - this.node = new TransformNode("toolbox", this.scene); - this.handle = new Handle(this.node); - this.node.position.y = .1; - this.node.position.z = .2; - this.node.scaling = new Vector3(0.6, 0.6, 0.6); + this.toolboxBaseNode = new TransformNode("toolbox", this.scene); + this.handle = new Handle(this.toolboxBaseNode); + this.toolboxBaseNode.position.y = .2; + //this.toolboxBaseNode.position.z = .05; + /**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(); + } - if (!this.xObserver) { - this.xObserver = this.controllers.controllerObserver.add((evt) => { - if (evt.type == ControllerEventType.X_BUTTON) { - if (evt.value == 1) { - this.node.parent.setEnabled(!this.node.parent.isEnabled(false)); - setMenuPosition(this.node.parent as Mesh, this.scene, - Vector3.Zero()); - } - } - }); - } + public toggle() { + this.toolboxBaseNode.parent.setEnabled(!this.toolboxBaseNode.parent.isEnabled(false)); + setMenuPosition(this.toolboxBaseNode.parent as Mesh, this.scene, + Vector3.Zero()); } public updateToolbox(color: string) { @@ -51,7 +54,7 @@ export class Toolbox { if (this.scene.getMeshById("toolbox-color-" + color)) { return; } else { - buildColor(Color3.FromHexString(color), this.scene, this.node, this.index++, this.colorChangeObservable); + buildColor(Color3.FromHexString(color), this.scene, this.toolboxBaseNode, this.index++); } } else { this.logger.warn("updateToolbox called with no color"); @@ -59,38 +62,48 @@ export class Toolbox { } - private readonly objectObservable: Observable = new Observable(); + private nodePredicate = (node: Node) => { + return node.getClassName() == "InstancedMesh" && + node.isEnabled(false) == true + }; + 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 - this.node.parent.setEnabled(false); - setMenuPosition(this.node.parent as Mesh, this.scene, + let initial = true; + for (const c of colors) { + 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()); -// } } - -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; -} \ No newline at end of file diff --git a/src/util/customEnvironment.ts b/src/util/customEnvironment.ts index 8138566..451b468 100644 --- a/src/util/customEnvironment.ts +++ b/src/util/customEnvironment.ts @@ -33,9 +33,10 @@ export class CustomEnvironment { if (loading) { 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.intensity = .6; + light.diffuse = new Color3(1, 1, 1); + light.intensity = .8; const physics = new CustomPhysics(this.scene, config); physics diff --git a/src/util/functions/setMenuPosition.ts b/src/util/functions/setMenuPosition.ts index 2c1e37c..fb31125 100644 --- a/src/util/functions/setMenuPosition.ts +++ b/src/util/functions/setMenuPosition.ts @@ -36,30 +36,44 @@ export function setMenuPosition(node: TransformNode, scene: Scene, offset: Vecto */ if (scene.activeCamera) { - switch (scene.activeCamera.getClassName()) { - 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; - - } + setPosition(node, scene, offset); + } 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'); + +} \ No newline at end of file diff --git a/src/vrApp.ts b/src/vrApp.ts index 3d3d895..6e9f892 100644 --- a/src/vrApp.ts +++ b/src/vrApp.ts @@ -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 {DiagramManager} from "./diagram/diagramManager"; import {Toolbox} from "./toolbox/toolbox"; @@ -6,7 +6,7 @@ import log, {Logger} from "loglevel"; import {AppConfig} from "./util/appConfig"; import {GamepadManager} from "./controllers/gamepadManager"; import {CustomEnvironment} from "./util/customEnvironment"; -import {Controllers} from "./controllers/controllers"; +import {ControllerEventType, Controllers} from "./controllers/controllers"; import {Spinner} from "./util/spinner"; import {PouchdbPersistenceManager} from "./integration/pouchdbPersistenceManager"; import {addSceneInspector} from "./util/functions/sceneInspctor"; @@ -38,13 +38,21 @@ export class VrApp { } const scene = new Scene(this.engine); this.scene = scene; + this.scene.ambientColor = new Color3(.1, .1, .1); + const spinner = new Spinner(scene); spinner.show(); const config = new AppConfig(); 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 db = new PouchdbPersistenceManager(); db.setDiagramManager(diagramManager); db.configObserver.add((newConfig) => {