Cleaned up circular dependencies. Added persistence manager.
This commit is contained in:
parent
8ab433e687
commit
afd8040108
@ -15,7 +15,7 @@
|
|||||||
align-content: center;
|
align-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
background: url("/loading-loading-forever.gif");
|
background: url("/spinner.gif");
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
32
package-lock.json
generated
32
package-lock.json
generated
@ -10,10 +10,10 @@
|
|||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@auth0/auth0-spa-js": "^2.0.8",
|
"@auth0/auth0-spa-js": "^2.0.8",
|
||||||
"@babylonjs/core": "^6.8.0",
|
"@babylonjs/core": "^6.12.3",
|
||||||
"@babylonjs/gui": "^6.9.0",
|
"@babylonjs/gui": "^6.12.3",
|
||||||
"@babylonjs/havok": "^1.0.1",
|
"@babylonjs/havok": "^1.1.0",
|
||||||
"@babylonjs/inspector": "^6.8.0",
|
"@babylonjs/inspector": "^6.12.3",
|
||||||
"@maptiler/client": "^1.5.0",
|
"@maptiler/client": "^1.5.0",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
@ -48,14 +48,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babylonjs/core": {
|
"node_modules/@babylonjs/core": {
|
||||||
"version": "6.8.0",
|
"version": "6.12.3",
|
||||||
"resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-6.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-6.12.3.tgz",
|
||||||
"integrity": "sha512-wTWj9TsnVGqfXt+tXKi7+SIWi4MzBMwIq+jcylRR1qzHTHFfMuKrRRLZJ5jQtpAhcDPI2TOuJ3/NOccPyawlgQ=="
|
"integrity": "sha512-p1di605M2Pa5+YiHbydGJ3PA4nUWSlmu79agL3mcsq7s8zC5VN/HaK1uNSicYI9LhVfPF6bDsVGHqCXxEkRsFQ=="
|
||||||
},
|
},
|
||||||
"node_modules/@babylonjs/gui": {
|
"node_modules/@babylonjs/gui": {
|
||||||
"version": "6.9.0",
|
"version": "6.12.3",
|
||||||
"resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-6.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-6.12.3.tgz",
|
||||||
"integrity": "sha512-RcVorxsj6n2EbwkBJYPBqF88Rybd3OHbx55runbMSehb9rKhc6d2QIiXTi7yI2oBNyuQBsDxx+ky58Rur2UXww==",
|
"integrity": "sha512-Yh9rVWwAymjy23g8dC5PMjeI2c71HWMZ6Lw2G0yjTZS9gf0st2A/OLsv/4ofK51u0fqvHZFBTfFTL5ZOFYNMow==",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@babylonjs/core": "^6.0.0"
|
"@babylonjs/core": "^6.0.0"
|
||||||
}
|
}
|
||||||
@ -73,17 +73,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babylonjs/havok": {
|
"node_modules/@babylonjs/havok": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babylonjs/havok/-/havok-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babylonjs/havok/-/havok-1.1.0.tgz",
|
||||||
"integrity": "sha512-J41CIAbL9WOQkPRdMADEVKDKZsU4iOlesBg0C/LP1GPxUncGVylLPkyyGPcQPLd6ifV9cZcnkEJrkiE8xVahTw==",
|
"integrity": "sha512-BNo2d+gfkoCbbEGYOVZgdPWG6NRdo5Tjvd9rpjMs0sWV/EaKQ6kL8hnJUn+HVZx4hdyKrTkq8ThTGFt/nTediA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/emscripten": "^1.39.6"
|
"@types/emscripten": "^1.39.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babylonjs/inspector": {
|
"node_modules/@babylonjs/inspector": {
|
||||||
"version": "6.8.0",
|
"version": "6.12.3",
|
||||||
"resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-6.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-6.12.3.tgz",
|
||||||
"integrity": "sha512-tu3nb0l7xSYXkTaKAnP7zBL34qR9J0op+NzOn4Y1C9RcY91yH3YfLTdoo4pFA0K5NaS99W0nAIjCcrS2BPBmMQ==",
|
"integrity": "sha512-REW+BF4LQhOK0cRRTVfSaOGnjh1LVE1lgwel7BBjjWeRcIjCVBimAprPY8rE0K+EAGMmPlxt9rDIpGoA0PUTqQ==",
|
||||||
"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",
|
||||||
|
|||||||
@ -12,10 +12,10 @@
|
|||||||
"postinstall": "cp ./node_modules/@babylonjs/havok/lib/esm/HavokPhysics.wasm ./node_modules/.vite/deps"
|
"postinstall": "cp ./node_modules/@babylonjs/havok/lib/esm/HavokPhysics.wasm ./node_modules/.vite/deps"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babylonjs/core": "^6.8.0",
|
"@babylonjs/core": "^6.12.3",
|
||||||
"@babylonjs/gui": "^6.9.0",
|
"@babylonjs/gui": "^6.12.3",
|
||||||
"@babylonjs/havok": "^1.0.1",
|
"@babylonjs/havok": "^1.1.0",
|
||||||
"@babylonjs/inspector": "^6.8.0",
|
"@babylonjs/inspector": "^6.12.3",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"@auth0/auth0-spa-js": "^2.0.8",
|
"@auth0/auth0-spa-js": "^2.0.8",
|
||||||
"ring-client-api": "^11.8.0",
|
"ring-client-api": "^11.8.0",
|
||||||
|
|||||||
BIN
public/spinner.gif
Normal file
BIN
public/spinner.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 630 KiB |
53
src/app.ts
53
src/app.ts
@ -19,15 +19,16 @@ import {
|
|||||||
///import {havokModule} from "./util/havok";
|
///import {havokModule} from "./util/havok";
|
||||||
import HavokPhysics from "@babylonjs/havok";
|
import HavokPhysics from "@babylonjs/havok";
|
||||||
import {Rigplatform} from "./controllers/rigplatform";
|
import {Rigplatform} from "./controllers/rigplatform";
|
||||||
|
|
||||||
import {DiagramManager} from "./diagram/diagramManager";
|
import {DiagramManager} from "./diagram/diagramManager";
|
||||||
|
|
||||||
|
|
||||||
class App {
|
export class App {
|
||||||
//preTasks = [havokModule];
|
//preTasks = [havokModule];
|
||||||
|
|
||||||
private token: string;
|
private token: string;
|
||||||
|
public static scene: Scene;
|
||||||
|
public static xr: WebXRDefaultExperience;
|
||||||
|
public static rig: Rigplatform;
|
||||||
constructor() {
|
constructor() {
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
canvas.style.width = "100%";
|
canvas.style.width = "100%";
|
||||||
@ -40,38 +41,46 @@ class App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async initialize(canvas) {
|
async initialize(canvas) {
|
||||||
|
if (App.xr) {
|
||||||
|
App.xr.dispose();
|
||||||
|
App.xr=null;
|
||||||
|
}
|
||||||
|
if (App.scene) {
|
||||||
|
App.scene.dispose();
|
||||||
|
App.scene = null;
|
||||||
|
}
|
||||||
|
if (DiagramManager.onDiagramEventObservable) {
|
||||||
|
DiagramManager.onDiagramEventObservable.clear();
|
||||||
|
DiagramManager.onDiagramEventObservable = null;
|
||||||
|
}
|
||||||
const engine = new Engine(canvas, true);
|
const engine = new Engine(canvas, true);
|
||||||
const scene = new Scene(engine);
|
const scene = new Scene(engine);
|
||||||
const diagramManager = new DiagramManager(scene);
|
|
||||||
|
App.scene = scene;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const havokInstance = await HavokPhysics();
|
const havokInstance = await HavokPhysics();
|
||||||
|
|
||||||
const havokPlugin = new HavokPlugin(true, havokInstance);
|
const havokPlugin = new HavokPlugin(true, havokInstance);
|
||||||
scene.enablePhysics(new Vector3(0, -9.8, 0), havokPlugin);
|
scene.enablePhysics(new Vector3(0, -9.8, 0), havokPlugin);
|
||||||
const camera: ArcRotateCamera = new ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 2, 2,
|
const camera: ArcRotateCamera = new ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 2, 2,
|
||||||
new Vector3(0, 1.6, 0), scene);
|
new Vector3(0, 1.6, 0), scene);
|
||||||
camera.attachControl(canvas, true);
|
camera.attachControl(canvas, true);
|
||||||
new HemisphericLight("light1", new Vector3(1, 1, 0), scene);
|
new HemisphericLight("light1", new Vector3(1, 1, 0), scene);
|
||||||
|
|
||||||
|
|
||||||
//const envTexture = new CubeTexture("/assets/textures/SpecularHDR.dds", scene);
|
|
||||||
//scene.createDefaultSkybox(envTexture, true, 1000);
|
|
||||||
|
|
||||||
const photoDome = new PhotoDome('sky',
|
const photoDome = new PhotoDome('sky',
|
||||||
'./outdoor_field.jpeg', {},
|
'./outdoor_field.jpeg', {},
|
||||||
scene);
|
scene);
|
||||||
|
|
||||||
const xr = await WebXRDefaultExperience.CreateAsync(scene, {
|
App.xr = await WebXRDefaultExperience.CreateAsync(scene, {
|
||||||
floorMeshes: [this.createGround(scene)],
|
floorMeshes: [this.createGround()],
|
||||||
disableTeleportation: true,
|
disableTeleportation: true,
|
||||||
optionalFeatures: true
|
optionalFeatures: true
|
||||||
|
|
||||||
});
|
});
|
||||||
const rig = new Rigplatform(scene, xr);
|
const diagramManager = new DiagramManager(App.scene, App.xr.baseExperience);
|
||||||
//const ring = new Cameras(scene, this.token);
|
App.rig = new Rigplatform(App.scene, App.xr);
|
||||||
//ring.getCameras().then(() => ring.createCameras());
|
|
||||||
//xr.teleportation.detach();
|
|
||||||
|
|
||||||
// hide/show the Inspector
|
|
||||||
window.addEventListener("keydown", (ev) => {
|
window.addEventListener("keydown", (ev) => {
|
||||||
// Shift+Ctrl+Alt+I
|
// Shift+Ctrl+Alt+I
|
||||||
if (ev.shiftKey && ev.ctrlKey && ev.altKey && ev.keyCode === 73) {
|
if (ev.shiftKey && ev.ctrlKey && ev.altKey && ev.keyCode === 73) {
|
||||||
@ -89,19 +98,19 @@ class App {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createGround(scene) {
|
createGround() {
|
||||||
const groundMaterial = new PBRMetallicRoughnessMaterial("groundMaterial", scene);
|
const groundMaterial = new PBRMetallicRoughnessMaterial("groundMaterial", App.scene);
|
||||||
const gText = new Texture("./grass1.jpeg", scene);
|
const gText = new Texture("./grass1.jpeg", App.scene);
|
||||||
gText.uScale = 40;
|
gText.uScale = 40;
|
||||||
gText.vScale = 40;
|
gText.vScale = 40;
|
||||||
groundMaterial.baseTexture = gText;
|
groundMaterial.baseTexture = gText;
|
||||||
groundMaterial.metallic = 0;
|
groundMaterial.metallic = 0;
|
||||||
groundMaterial.roughness = 1;
|
groundMaterial.roughness = 1;
|
||||||
|
|
||||||
const ground = MeshBuilder.CreateGround("ground", {width: 100, height: 100, subdivisions: 1}, scene);
|
const ground = MeshBuilder.CreateGround("ground", {width: 100, height: 100, subdivisions: 1}, App.scene);
|
||||||
|
|
||||||
ground.material = groundMaterial;
|
ground.material = groundMaterial;
|
||||||
const groundAggregate = new PhysicsAggregate(ground, PhysicsShapeType.BOX, {mass: 0}, scene);
|
new PhysicsAggregate(ground, PhysicsShapeType.BOX, {mass: 0}, App.scene);
|
||||||
return ground;
|
return ground;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
import {Vector3, WebXRInputSource} from "@babylonjs/core";
|
import {Vector3, WebXRInputSource} from "@babylonjs/core";
|
||||||
import {Rigplatform} from "./rigplatform";
|
|
||||||
|
|
||||||
export class Base {
|
export class Base {
|
||||||
static stickVector = Vector3.Zero();
|
static stickVector = Vector3.Zero();
|
||||||
protected controller: WebXRInputSource;
|
protected controller: WebXRInputSource;
|
||||||
protected rig: Rigplatform;
|
|
||||||
protected speedFactor = 4;
|
protected speedFactor = 4;
|
||||||
|
|
||||||
constructor(controller:
|
constructor(controller:
|
||||||
@ -22,8 +20,7 @@ export class Base {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
public mesh() {
|
||||||
setRig(rig: Rigplatform) {
|
return this.controller.grip;
|
||||||
this.rig = rig;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
20
src/controllers/controllers.ts
Normal file
20
src/controllers/controllers.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
import {AbstractMesh, Observable, TransformNode} from "@babylonjs/core";
|
||||||
|
|
||||||
|
export enum ControllerMovementMode {
|
||||||
|
ROTATE,
|
||||||
|
TRANSLATE
|
||||||
|
}
|
||||||
|
export class Controllers {
|
||||||
|
public static movable: TransformNode | AbstractMesh;
|
||||||
|
public static controllerObserver = new Observable();
|
||||||
|
public static movementMode: ControllerMovementMode = ControllerMovementMode.ROTATE;
|
||||||
|
public static toggleMovementMode() {
|
||||||
|
if (this.movementMode == ControllerMovementMode.ROTATE) {
|
||||||
|
this.movementMode = ControllerMovementMode.TRANSLATE;
|
||||||
|
} else {
|
||||||
|
this.movementMode = ControllerMovementMode.ROTATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,40 +1,65 @@
|
|||||||
import {Vector3, WebXRInputSource} from "@babylonjs/core";
|
import {Vector3, WebXRInputSource} from "@babylonjs/core";
|
||||||
import {Base} from "./base";
|
import {Base} from "./base";
|
||||||
|
import {Controllers} from "./controllers";
|
||||||
|
|
||||||
|
|
||||||
export class Left extends Base {
|
export class Left extends Base {
|
||||||
|
public static instance: Left;
|
||||||
|
|
||||||
constructor(controller:
|
constructor(controller:
|
||||||
WebXRInputSource) {
|
WebXRInputSource) {
|
||||||
super(controller);
|
super(controller);
|
||||||
|
|
||||||
|
Left.instance = this;
|
||||||
this.controller.onMotionControllerInitObservable.add((init) => {
|
this.controller.onMotionControllerInitObservable.add((init) => {
|
||||||
if (init.components['xr-standard-thumbstick']) {
|
if (init.components['xr-standard-thumbstick']) {
|
||||||
init.components['xr-standard-thumbstick']
|
init.components['xr-standard-thumbstick']
|
||||||
.onAxisValueChangedObservable.add((value) => {
|
.onAxisValueChangedObservable.add((value) => {
|
||||||
|
if (!Controllers.movable) {
|
||||||
|
this.moveRig(value);
|
||||||
|
} else {
|
||||||
|
this.moveMovable(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private moveMovable(value: { x: number, y: number }) {
|
||||||
if (Math.abs(value.x) > .1) {
|
if (Math.abs(value.x) > .1) {
|
||||||
this.rig.leftright(value.x * this.speedFactor);
|
Controllers.movable.position.x += .005 * Math.sign(value.x);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
if (Math.abs(value.y) > .1) {
|
||||||
|
Controllers.movable.position.y += -.005 * Math.sign(value.y);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private moveRig(value: { x: number, y: number }) {
|
||||||
|
if (Math.abs(value.x) > .1) {
|
||||||
|
Controllers.controllerObserver.notifyObservers({type: 'leftright', value: value.x * this.speedFactor});
|
||||||
Base.stickVector.x = 1;
|
Base.stickVector.x = 1;
|
||||||
} else {
|
} else {
|
||||||
Base.stickVector.x = 0;
|
Base.stickVector.x = 0;
|
||||||
}
|
}
|
||||||
if (Math.abs(value.y) > .1) {
|
if (Math.abs(value.y) > .1) {
|
||||||
this.rig.updown(value.y * this.speedFactor);
|
Controllers.controllerObserver.notifyObservers({type: 'updown', value: value.y * this.speedFactor});
|
||||||
Base.stickVector.y = 1;
|
Base.stickVector.y = 1;
|
||||||
} else {
|
} else {
|
||||||
Base.stickVector.y = 0;
|
Base.stickVector.y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Base.stickVector.equals(Vector3.Zero())) {
|
if (Base.stickVector.equals(Vector3.Zero())) {
|
||||||
this.rig.updown(0);
|
Controllers.controllerObserver.notifyObservers({type: 'leftright', value: 0});
|
||||||
this.rig.leftright(0)
|
Controllers.controllerObserver.notifyObservers({type: 'updown', value: 0});
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,17 +1,30 @@
|
|||||||
import {Base} from "./base";
|
import {Base} from "./base";
|
||||||
import {Vector3, WebXRInputSource} from "@babylonjs/core";
|
import {Angle, Observable, Vector3, WebXRControllerComponent, WebXRInputSource} from "@babylonjs/core";
|
||||||
import {Bmenu, BmenuState} from "../menus/bmenu";
|
import {Bmenu} from "../menus/bmenu";
|
||||||
import {DiagramEvent, DiagramEventType, DiagramManager} from "../diagram/diagramManager";
|
import {DiagramManager} from "../diagram/diagramManager";
|
||||||
|
import {ControllerMovementMode, Controllers} from "./controllers";
|
||||||
|
import {BmenuState} from "../menus/MenuState";
|
||||||
|
import {DiagramEvent, DiagramEventType} from "../diagram/diagramEntity";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export class Right extends Base {
|
export class Right extends Base {
|
||||||
private bmenu: Bmenu;
|
private bmenu: Bmenu;
|
||||||
|
public static instance: Right;
|
||||||
|
|
||||||
private down: boolean = false;
|
private down: boolean = false;
|
||||||
|
|
||||||
constructor(controller:
|
private initBButton(bbutton: WebXRControllerComponent) {
|
||||||
WebXRInputSource) {
|
if (bbutton) {
|
||||||
super(controller);
|
bbutton.onButtonStateChangedObservable.add((value) => {
|
||||||
this.controller.onMotionControllerInitObservable.add((init) => {
|
if (value.pressed) {
|
||||||
const trigger = init.components['xr-standard-trigger'];
|
this.bmenu.toggle(this.controller.grip);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private initTrigger(trigger: WebXRControllerComponent) {
|
||||||
if (trigger) {
|
if (trigger) {
|
||||||
trigger
|
trigger
|
||||||
.onButtonStateChangedObservable
|
.onButtonStateChangedObservable
|
||||||
@ -32,40 +45,116 @@ export class Right extends Base {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (init.components['b-button']) {
|
}
|
||||||
init.components['b-button'].onButtonStateChangedObservable.add((value) => {
|
|
||||||
|
private initAButton(abutton: WebXRControllerComponent) {
|
||||||
|
if (abutton) {
|
||||||
|
abutton.onButtonStateChangedObservable.add((value) => {
|
||||||
if (value.pressed) {
|
if (value.pressed) {
|
||||||
this.bmenu.toggle();
|
if (DiagramManager.currentMesh) {
|
||||||
|
if (Controllers.movable) {
|
||||||
|
Controllers.movable = null;
|
||||||
|
} else {
|
||||||
|
Controllers.movable = DiagramManager.currentMesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (init.components['xr-standard-thumbstick']) {
|
|
||||||
init.components['xr-standard-thumbstick']
|
|
||||||
.onAxisValueChangedObservable.add((value) => {
|
|
||||||
if (Math.abs(value.x) > .1) {
|
|
||||||
this.rig.turn(value.x);
|
|
||||||
} else {
|
|
||||||
this.rig.turn(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private initThumbstick(thumbstick: WebXRControllerComponent) {
|
||||||
|
if (thumbstick) {
|
||||||
|
thumbstick.onAxisValueChangedObservable.add((value) => {
|
||||||
|
if (!Controllers.movable) {
|
||||||
|
this.moveRig(value);
|
||||||
|
} else {
|
||||||
|
if (Controllers.movementMode == ControllerMovementMode.ROTATE) {
|
||||||
|
this.rotateMovable(value);
|
||||||
|
} else {
|
||||||
|
this.moveMovable(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
thumbstick.onButtonStateChangedObservable.add((value) => {
|
||||||
|
if (value.pressed) {
|
||||||
|
Controllers.toggleMovementMode();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private moveRig(value) {
|
||||||
|
if (Math.abs(value.x) > .1) {
|
||||||
|
Controllers.controllerObserver.notifyObservers({type: 'turn', value: value.x});
|
||||||
|
} else {
|
||||||
|
Controllers.controllerObserver.notifyObservers({type: 'turn', value: 0});
|
||||||
|
}
|
||||||
if (Math.abs(value.y) > .1) {
|
if (Math.abs(value.y) > .1) {
|
||||||
this.rig.forwardback(value.y * this.speedFactor);
|
Controllers.controllerObserver.notifyObservers({type: 'forwardback', value: value.y * this.speedFactor});
|
||||||
Base.stickVector.z = 1;
|
Base.stickVector.z = 1;
|
||||||
} else {
|
} else {
|
||||||
|
Controllers.controllerObserver.notifyObservers({type: 'forwardback', value: 0});
|
||||||
Base.stickVector.z = 0;
|
Base.stickVector.z = 0;
|
||||||
}
|
}
|
||||||
if (Base.stickVector.equals(Vector3.Zero())) {
|
if (Base.stickVector.equals(Vector3.Zero())) {
|
||||||
this.rig.forwardback(0);
|
Controllers.controllerObserver.notifyObservers({type: 'forwardback', value: 0});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constructor(controller:
|
||||||
|
WebXRInputSource) {
|
||||||
|
super(controller);
|
||||||
|
Right.instance = this;
|
||||||
|
this.controller.onMotionControllerInitObservable.add((init) => {
|
||||||
|
this.initTrigger(init.components['xr-standard-trigger']);
|
||||||
|
this.initBButton(init.components['b-button']);
|
||||||
|
this.initAButton(init.components['a-button']);
|
||||||
|
this.initThumbstick(init.components['xr-standard-thumbstick']);
|
||||||
|
this.initGrip(init.components['xr-standard-squeeze']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private initGrip(grip: WebXRControllerComponent) {
|
||||||
|
grip.onButtonStateChangedObservable.add((value) => {
|
||||||
|
if (value.value > .5) {
|
||||||
|
if (this.controller.pointer.collider.collidedMesh) {
|
||||||
|
console.log(this.controller.pointer.collider.collidedMesh.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
public setBMenu(menu: Bmenu) {
|
public setBMenu(menu: Bmenu) {
|
||||||
this.bmenu = menu;
|
this.bmenu = menu;
|
||||||
this.bmenu.setController(this.controller);
|
this.bmenu.setController(this.controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private rotateMovable(value: { x: number; y: number }) {
|
||||||
|
if (Math.abs(value.y) > .1) {
|
||||||
|
Controllers.movable.rotation.x +=
|
||||||
|
Angle.FromDegrees(Math.sign(value.y) * 1).radians();
|
||||||
|
Controllers.movable.rotation.x = this.fixRadians(Controllers.movable.rotation.x);
|
||||||
|
}
|
||||||
|
if (Math.abs(value.x) > .1) {
|
||||||
|
Controllers.movable.rotation.z +=
|
||||||
|
Angle.FromDegrees(Math.sign(value.x) * 1).radians();
|
||||||
|
Controllers.movable.rotation.z = this.fixRadians(Controllers.movable.rotation.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fixRadians(value: number) {
|
||||||
|
if (value > 2 * Math.PI) {
|
||||||
|
return value - 2 * Math.PI;
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private moveMovable(value: { x: number; y: number }) {
|
||||||
|
if (Math.abs(value.y) > .1) {
|
||||||
|
Controllers.movable.position.z += Math.sign(value.y) * -.005;
|
||||||
|
}
|
||||||
|
if (Math.abs(value.x) > .1) {
|
||||||
|
Controllers.movable.position.x += Math.sign(value.x) * .005;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -17,33 +17,36 @@ import {
|
|||||||
import {Right} from "./right";
|
import {Right} from "./right";
|
||||||
import {Left} from "./left";
|
import {Left} from "./left";
|
||||||
import {Bmenu} from "../menus/bmenu";
|
import {Bmenu} from "../menus/bmenu";
|
||||||
|
import {Hud} from "../information/hud";
|
||||||
|
import {Controllers} from "./controllers";
|
||||||
|
|
||||||
|
|
||||||
export class Rigplatform {
|
export class Rigplatform {
|
||||||
static LINEAR_VELOCITY = 4;
|
static LINEAR_VELOCITY = 4;
|
||||||
static ANGULAR_VELOCITY = 3;
|
static ANGULAR_VELOCITY = 3;
|
||||||
static x90 = Quaternion.RotationAxis(Vector3.Up(), 1.5708);
|
static x90 = Quaternion.RotationAxis(Vector3.Up(), 1.5708);
|
||||||
public bMenu: Bmenu;
|
public bMenu: Bmenu;
|
||||||
|
private scene: Scene;
|
||||||
|
public static instance: Rigplatform;
|
||||||
|
private static xr: WebXRDefaultExperience;
|
||||||
private yRotation: number = 0;
|
private yRotation: number = 0;
|
||||||
public right: Right;
|
|
||||||
public left: Left;
|
|
||||||
public body: PhysicsBody;
|
public body: PhysicsBody;
|
||||||
public rigMesh: Mesh;
|
public rigMesh: Mesh;
|
||||||
private camera: Camera;
|
private camera: Camera;
|
||||||
private scene: Scene;
|
|
||||||
private xr: WebXRDefaultExperience;
|
|
||||||
private turning: boolean = false;
|
private turning: boolean = false;
|
||||||
|
|
||||||
constructor(scene: Scene, xr: WebXRDefaultExperience) {
|
constructor(scene: Scene, xr: WebXRDefaultExperience) {
|
||||||
this.xr = xr;
|
|
||||||
this.bMenu = new Bmenu(scene, this.xr.baseExperience);
|
|
||||||
this.camera = scene.activeCamera;
|
|
||||||
|
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
|
Rigplatform.xr = xr;
|
||||||
|
Rigplatform.instance = this;
|
||||||
|
|
||||||
this.rigMesh = MeshBuilder.CreateCylinder("platform", {diameter: 1.5, height: .01}, scene);
|
this.bMenu = new Bmenu(scene, xr.baseExperience);
|
||||||
|
this.camera = scene.activeCamera;
|
||||||
for (const cam of this.scene.cameras) {
|
this.rigMesh = MeshBuilder.CreateBox("platform", {width: 2, height: .02, depth: 2}, scene);
|
||||||
|
const hud = new Hud(this.rigMesh, scene);
|
||||||
|
for (const cam of scene.cameras) {
|
||||||
cam.parent = this.rigMesh;
|
cam.parent = this.rigMesh;
|
||||||
|
cam.position = new Vector3(0, 1.6, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const myMaterial = new StandardMaterial("myMaterial", scene);
|
const myMaterial = new StandardMaterial("myMaterial", scene);
|
||||||
@ -55,31 +58,28 @@ export class Rigplatform {
|
|||||||
new PhysicsAggregate(
|
new PhysicsAggregate(
|
||||||
this.rigMesh,
|
this.rigMesh,
|
||||||
PhysicsShapeType.CYLINDER,
|
PhysicsShapeType.CYLINDER,
|
||||||
{friction: 1, center: Vector3.Zero(), radius: .5, mass: .1, restitution: .1},
|
{friction: 1, center: Vector3.Zero(), radius: .5, mass: 10, restitution: .01},
|
||||||
scene);
|
scene);
|
||||||
rigAggregate.body.setMotionType(PhysicsMotionType.ANIMATED);
|
rigAggregate.body.setMotionType(PhysicsMotionType.DYNAMIC);
|
||||||
rigAggregate.body.setGravityFactor(0);
|
rigAggregate.body.setGravityFactor(.001);
|
||||||
|
|
||||||
|
|
||||||
this.#fixRotation();
|
this.#fixRotation();
|
||||||
this.body = rigAggregate.body;
|
this.body = rigAggregate.body;
|
||||||
this.#setupKeyboard();
|
this.#setupKeyboard();
|
||||||
this.#initializeControllers();
|
this.#initializeControllers();
|
||||||
this.scene.onActiveCameraChanged.add((s) => {
|
scene.onActiveCameraChanged.add((s) => {
|
||||||
this.camera = s.activeCamera;
|
this.camera = s.activeCamera;
|
||||||
this.camera.parent = this.rigMesh;
|
this.camera.parent = this.rigMesh;
|
||||||
console.log('camera changed');
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public forwardback(val: number) {
|
public forwardback(val: number) {
|
||||||
const ray = this.camera.getForwardRay();
|
const ray = this.camera.getForwardRay();
|
||||||
|
|
||||||
this.body.setLinearVelocity(ray.direction.scale(val * -1));
|
this.body.setLinearVelocity(ray.direction.scale(val * -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public leftright(val: number) {
|
public leftright(val: number) {
|
||||||
|
|
||||||
|
|
||||||
const ray = this.camera.getForwardRay();
|
const ray = this.camera.getForwardRay();
|
||||||
const direction = ray.direction.applyRotationQuaternion(Rigplatform.x90).scale(val);
|
const direction = ray.direction.applyRotationQuaternion(Rigplatform.x90).scale(val);
|
||||||
this.body.setLinearVelocity(direction);
|
this.body.setLinearVelocity(direction);
|
||||||
@ -125,28 +125,46 @@ export class Rigplatform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#initializeControllers() {
|
#initializeControllers() {
|
||||||
this.xr.input.onControllerAddedObservable.add((source, state) => {
|
Rigplatform.xr.input.onControllerAddedObservable.add((source) => {
|
||||||
let controller;
|
let controller;
|
||||||
switch (source.inputSource.handedness) {
|
switch (source.inputSource.handedness) {
|
||||||
case "right":
|
case "right":
|
||||||
controller = new Right(source);
|
Right.instance = new Right(source);
|
||||||
this.right = controller;
|
Right.instance.setBMenu(this.bMenu);
|
||||||
controller.setBMenu(this.bMenu);
|
Controllers.controllerObserver.add((event: { type: string, value: number }) => {
|
||||||
|
switch (event.type) {
|
||||||
|
case "turn":
|
||||||
|
this.turn(event.value);
|
||||||
break;
|
break;
|
||||||
case "left":
|
case "forwardback":
|
||||||
controller = new Left(source);
|
this.forwardback(event.value);
|
||||||
this.left = controller;
|
break;
|
||||||
|
case "leftright":
|
||||||
|
this.leftright(event.value);
|
||||||
|
break;
|
||||||
|
case "updown":
|
||||||
|
this.updown(event.value);
|
||||||
|
break;
|
||||||
|
case "stop":
|
||||||
|
this.stop();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
this.xr.baseExperience.camera.position = new Vector3(0, 1.6, 0);
|
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "left":
|
||||||
|
Left.instance = new Left(source);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
Rigplatform.xr.baseExperience.camera.position = new Vector3(0, 1.6, 0);
|
||||||
if (controller) {
|
if (controller) {
|
||||||
controller.setRig(this);
|
controller.setRig(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(source);
|
|
||||||
console.log(state);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//create a method to set the camera to the rig
|
//create a method to set the camera to the rig
|
||||||
@ -181,7 +199,7 @@ export class Rigplatform {
|
|||||||
this.updown(1 * Rigplatform.LINEAR_VELOCITY);
|
this.updown(1 * Rigplatform.LINEAR_VELOCITY);
|
||||||
break;
|
break;
|
||||||
case " ":
|
case " ":
|
||||||
this.bMenu.toggle()
|
this.bMenu.toggle(this.rigMesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -197,6 +215,7 @@ export class Rigplatform {
|
|||||||
#fixRotation() {
|
#fixRotation() {
|
||||||
this.scene.registerBeforeRender(() => {
|
this.scene.registerBeforeRender(() => {
|
||||||
const q = this.rigMesh.rotationQuaternion;
|
const q = this.rigMesh.rotationQuaternion;
|
||||||
|
this.body.setAngularVelocity(Vector3.Zero());
|
||||||
const e = q.toEulerAngles();
|
const e = q.toEulerAngles();
|
||||||
e.y += this.yRotation;
|
e.y += this.yRotation;
|
||||||
q.copyFrom(Quaternion.FromEulerAngles(0, e.y, 0));
|
q.copyFrom(Quaternion.FromEulerAngles(0, e.y, 0));
|
||||||
|
|||||||
@ -1,2 +1,31 @@
|
|||||||
|
import {Vector3} from "@babylonjs/core";
|
||||||
|
import {BmenuState} from "../menus/MenuState";
|
||||||
|
export enum DiagramEventType {
|
||||||
|
ADD,
|
||||||
|
REMOVE,
|
||||||
|
MODIFY,
|
||||||
|
DROP,
|
||||||
|
DROPPED,
|
||||||
|
CLEAR,
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
export type DiagramEvent = {
|
||||||
|
type: DiagramEventType;
|
||||||
|
menustate?: BmenuState;
|
||||||
|
entity?: DiagramEntity;
|
||||||
|
|
||||||
|
}
|
||||||
|
export type DiagramEntity = {
|
||||||
|
color?: string;
|
||||||
|
id?: string;
|
||||||
|
last_seen?: Date;
|
||||||
|
position?: Vector3;
|
||||||
|
rotation?: Vector3;
|
||||||
|
template?: string;
|
||||||
|
text?: string;
|
||||||
|
scale?: Vector3;
|
||||||
|
parent?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,77 +1,70 @@
|
|||||||
import {AbstractMesh, Color3, Mesh, MeshBuilder, Observable, Scene, StandardMaterial, Vector3} from "@babylonjs/core";
|
import {
|
||||||
|
AbstractMesh,
|
||||||
|
Angle,
|
||||||
|
Color3,
|
||||||
|
Mesh,
|
||||||
|
MeshBuilder,
|
||||||
|
Observable, Scene,
|
||||||
|
StandardMaterial,
|
||||||
|
Vector3, WebXRExperienceHelper
|
||||||
|
} from "@babylonjs/core";
|
||||||
import {v4 as uuidv4} from 'uuid';
|
import {v4 as uuidv4} from 'uuid';
|
||||||
import {BmenuState} from "../menus/bmenu";
|
import {DiagramEntity, DiagramEvent, DiagramEventType} from "./diagramEntity";
|
||||||
|
import {PersistenceManager} from "./persistenceManager";
|
||||||
|
|
||||||
export enum DiagramEventType {
|
|
||||||
ADD,
|
|
||||||
REMOVE,
|
|
||||||
MODIFY,
|
|
||||||
DROP,
|
|
||||||
DROPPED,
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export type DiagramEvent = {
|
|
||||||
type: DiagramEventType;
|
|
||||||
menustate?: BmenuState;
|
|
||||||
entity?: DiagramEntity;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export type DiagramEntity = {
|
|
||||||
color?: string;
|
|
||||||
id?: string;
|
|
||||||
last_seen?: Date;
|
|
||||||
position?: Vector3;
|
|
||||||
rotation?: Vector3;
|
|
||||||
template?: string;
|
|
||||||
text?: string;
|
|
||||||
scale?: Vector3;
|
|
||||||
parent?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DiagramManager {
|
export class DiagramManager {
|
||||||
|
private persistenceManager: PersistenceManager = new PersistenceManager();
|
||||||
static onDiagramEventObservable = new Observable();
|
static onDiagramEventObservable = new Observable();
|
||||||
static leftController: Mesh;
|
private scene: Scene;
|
||||||
|
private xr: WebXRExperienceHelper;
|
||||||
static currentMesh: AbstractMesh;
|
static currentMesh: AbstractMesh;
|
||||||
static rightController: Mesh;
|
|
||||||
static state: BmenuState;
|
|
||||||
private readonly scene: Scene;
|
|
||||||
|
|
||||||
constructor(scene: Scene) {
|
constructor(scene: Scene, xr: WebXRExperienceHelper) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
|
this.xr = xr;
|
||||||
|
this.persistenceManager.updateObserver.add(this.#onRemoteEvent, -1, true, this);
|
||||||
|
this.persistenceManager.initialize();
|
||||||
|
if (!DiagramManager.onDiagramEventObservable) {
|
||||||
|
DiagramManager.onDiagramEventObservable = new Observable();
|
||||||
|
}
|
||||||
if (DiagramManager.onDiagramEventObservable.hasObservers()) {
|
if (DiagramManager.onDiagramEventObservable.hasObservers()) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
DiagramManager.onDiagramEventObservable.add(this.#onDiagramEvent, -1, true, this);
|
DiagramManager.onDiagramEventObservable.add(this.#onDiagramEvent, -1, true, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#onRemoteEvent(event: DiagramEntity) {
|
||||||
|
const mesh = this.#createMesh(event);
|
||||||
|
const material = new StandardMaterial("material-" + event.id, this.scene);
|
||||||
|
material.diffuseColor = Color3.FromHexString(event.color);
|
||||||
|
mesh.material = material;
|
||||||
|
}
|
||||||
|
|
||||||
#onDiagramEvent(event: DiagramEvent) {
|
#onDiagramEvent(event: DiagramEvent) {
|
||||||
console.log(event);
|
|
||||||
const entity = event.entity;
|
const entity = event.entity;
|
||||||
|
|
||||||
let mesh;
|
let mesh;
|
||||||
|
|
||||||
let material
|
let material
|
||||||
if (entity) {
|
if (entity) {
|
||||||
mesh = this.scene.getMeshByName(entity.id);
|
mesh = this.scene.getMeshByName(entity.id);
|
||||||
material = this.scene.getMaterialByName("material-" + entity.id);
|
if (mesh) {
|
||||||
if (!material) {
|
material = mesh.material;
|
||||||
material = new StandardMaterial("material-" + event.entity.id, this.scene);
|
|
||||||
material.ambientColor = Color3.FromHexString(event.entity.color.replace("#", ""));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
|
case DiagramEventType.CLEAR:
|
||||||
|
DiagramManager.currentMesh.dispose();
|
||||||
|
DiagramManager.currentMesh = null;
|
||||||
|
break;
|
||||||
case DiagramEventType.DROPPED:
|
case DiagramEventType.DROPPED:
|
||||||
break;
|
break;
|
||||||
case DiagramEventType.DROP:
|
case DiagramEventType.DROP:
|
||||||
if (DiagramManager.currentMesh) {
|
if (DiagramManager.currentMesh) {
|
||||||
const newMesh = DiagramManager.currentMesh.clone(DiagramManager.currentMesh.name = "id" + uuidv4(), DiagramManager.currentMesh.parent);
|
this.persistenceManager.add(DiagramManager.currentMesh);
|
||||||
|
const newName = uuidv4();
|
||||||
|
const newMesh = DiagramManager.currentMesh.clone("id"+newName, DiagramManager.currentMesh.parent);
|
||||||
|
const newMaterial = DiagramManager.currentMesh.material.clone("material"+newName);
|
||||||
|
newMesh.material=newMaterial;
|
||||||
DiagramManager.currentMesh.setParent(null);
|
DiagramManager.currentMesh.setParent(null);
|
||||||
DiagramManager.currentMesh = newMesh;
|
DiagramManager.currentMesh = newMesh;
|
||||||
DiagramManager.onDiagramEventObservable.notifyObservers({
|
DiagramManager.onDiagramEventObservable.notifyObservers({
|
||||||
@ -84,41 +77,48 @@ export class DiagramManager {
|
|||||||
if (DiagramManager.currentMesh) {
|
if (DiagramManager.currentMesh) {
|
||||||
DiagramManager.currentMesh.dispose();
|
DiagramManager.currentMesh.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mesh) {
|
if (mesh) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
mesh = this.#createMesh(entity);
|
mesh = this.#createMesh(entity);
|
||||||
|
if (!material) {
|
||||||
|
material = new StandardMaterial("material-" + event.entity.id, this.scene);
|
||||||
|
material.diffuseColor = Color3.FromHexString(event.entity.color);
|
||||||
|
mesh.material = material;
|
||||||
|
|
||||||
|
}
|
||||||
if (!mesh) {
|
if (!mesh) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
DiagramManager.currentMesh = mesh;
|
||||||
|
break;
|
||||||
case DiagramEventType.MODIFY:
|
case DiagramEventType.MODIFY:
|
||||||
if (!mesh) {
|
if (!mesh) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
const rotation = entity.rotation;
|
if (!material) {
|
||||||
const scale = entity.scale;
|
material = new StandardMaterial("material-" + event.entity.id, this.scene);
|
||||||
const position = entity.position;
|
material.diffuseColor = Color3.FromHexString(event.entity.color);
|
||||||
|
if (mesh) {
|
||||||
mesh.material = material;
|
mesh.material = material;
|
||||||
mesh.position = new Vector3(position.x, position.y, position.z);
|
}
|
||||||
mesh.rotation = new Vector3(rotation.x, rotation.y, rotation.z);
|
|
||||||
|
|
||||||
|
}
|
||||||
|
mesh.material = material;
|
||||||
|
mesh.position = entity.position;
|
||||||
|
mesh.rotation = entity.rotation;
|
||||||
if (entity.parent) {
|
if (entity.parent) {
|
||||||
mesh.parent = this.scene.getMeshByName(entity.parent);
|
mesh.parent = this.scene.getMeshByName(entity.parent);
|
||||||
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DiagramManager.currentMesh = mesh;
|
DiagramManager.currentMesh = mesh;
|
||||||
break;
|
break;
|
||||||
case DiagramEventType.REMOVE:
|
case DiagramEventType.REMOVE:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#createMesh(entity: DiagramEntity) {
|
#createMesh(entity: DiagramEntity) {
|
||||||
@ -130,28 +130,41 @@ export class DiagramManager {
|
|||||||
case "#box-template":
|
case "#box-template":
|
||||||
mesh = MeshBuilder.CreateBox(entity.id,
|
mesh = MeshBuilder.CreateBox(entity.id,
|
||||||
{
|
{
|
||||||
width: entity.scale.x,
|
width: 1,
|
||||||
height: entity.scale.y,
|
height: 1,
|
||||||
depth: entity.scale.z
|
depth: 1
|
||||||
}, this.scene);
|
}, this.scene);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "#sphere-template":
|
case "#sphere-template":
|
||||||
|
mesh = MeshBuilder.CreateSphere(entity.id, {diameter: 1}, this.scene);
|
||||||
mesh = MeshBuilder.CreateSphere(entity.id, {diameter: entity.scale.x}, this.scene);
|
|
||||||
break
|
break
|
||||||
case "#cylinder-template":
|
case "#cylinder-template":
|
||||||
mesh = MeshBuilder.CreateCylinder(entity.id, {
|
mesh = MeshBuilder.CreateCylinder(entity.id, {
|
||||||
diameter: entity.scale.x,
|
diameter: 1,
|
||||||
height: entity.scale.y
|
height: 1
|
||||||
}, this.scene);
|
}, this.scene);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
mesh = null;
|
mesh = null;
|
||||||
}
|
}
|
||||||
|
if (mesh) {
|
||||||
|
mesh.metadata = {template: entity.template};
|
||||||
|
|
||||||
|
if (entity.position) {
|
||||||
|
mesh.position = entity.position;
|
||||||
|
}
|
||||||
|
if (entity.rotation) {
|
||||||
|
mesh.rotation = entity.rotation;
|
||||||
|
}
|
||||||
|
if (entity.parent) {
|
||||||
|
mesh.parent = this.scene.getMeshByName(entity.parent);
|
||||||
|
}
|
||||||
|
if (entity.scale) {
|
||||||
|
mesh.scaling = entity.scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
48
src/diagram/persistenceManager.ts
Normal file
48
src/diagram/persistenceManager.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import {AbstractMesh, Mesh, Observable, StandardMaterial, Vector3} from "@babylonjs/core";
|
||||||
|
import {DiagramEntity} from "./diagramEntity";
|
||||||
|
|
||||||
|
export class PersistenceManager {
|
||||||
|
public updateObserver: Observable<DiagramEntity> = new Observable<DiagramEntity>();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public add(mesh: AbstractMesh) {
|
||||||
|
const entity = <any>{};
|
||||||
|
entity.id = mesh.id;
|
||||||
|
entity.position = mesh.position.toString();
|
||||||
|
entity.rotation = mesh.rotation.toString();
|
||||||
|
entity.last_seen = new Date().getDate();
|
||||||
|
entity.template = "default";
|
||||||
|
entity.text = "";
|
||||||
|
entity.scale = mesh.scaling.toString();
|
||||||
|
if (mesh.material) {
|
||||||
|
entity.color = (mesh.material as StandardMaterial).diffuseColor.toHexString();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public remove() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public modify() {
|
||||||
|
|
||||||
|
}
|
||||||
|
public initialize() {
|
||||||
|
const entity: DiagramEntity = <DiagramEntity>{};
|
||||||
|
entity.id = "test";
|
||||||
|
entity.position = new Vector3(0,2,-2);
|
||||||
|
entity.rotation = Vector3.Zero();
|
||||||
|
entity.last_seen = new Date();
|
||||||
|
entity.scale = Vector3.One();
|
||||||
|
entity.color = "#ff0000";
|
||||||
|
entity.text = "test";
|
||||||
|
entity.parent = null;
|
||||||
|
entity.template = "#box-template";
|
||||||
|
|
||||||
|
this.updateObserver.notifyObservers(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
56
src/information/hud.ts
Normal file
56
src/information/hud.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import {AbstractMesh, Color3, MeshBuilder, Scene, Vector3} from "@babylonjs/core";
|
||||||
|
import {AdvancedDynamicTexture, StackPanel, TextBlock} from "@babylonjs/gui";
|
||||||
|
import {Controllers} from "../controllers/controllers";
|
||||||
|
|
||||||
|
export class Hud {
|
||||||
|
private scene: Scene;
|
||||||
|
private parent: AbstractMesh;
|
||||||
|
private hudPlane: AbstractMesh;
|
||||||
|
constructor(parent: AbstractMesh, scene: Scene) {
|
||||||
|
this.scene = scene;
|
||||||
|
this.parent = parent;
|
||||||
|
this.hudPlane = MeshBuilder.CreatePlane("hudPlane", {width: 1, height: .5}, this.parent.getScene());
|
||||||
|
this.hudPlane.parent=this.parent.getScene().activeCamera
|
||||||
|
this.parent.getScene().onActiveCameraChanged.add((scene) => {
|
||||||
|
this.hudPlane.parent = scene.activeCamera;
|
||||||
|
});
|
||||||
|
this.hudPlane.position = new Vector3(.5, .75, 3);
|
||||||
|
|
||||||
|
this.hudPlane.outlineColor = Color3.FromHexString("#ffffff");
|
||||||
|
|
||||||
|
|
||||||
|
const textPosition = this.createTextBlock();
|
||||||
|
const textRotation = this.createTextBlock();
|
||||||
|
|
||||||
|
const hudTexture = AdvancedDynamicTexture.CreateForMesh(this.hudPlane, 1024, 512);
|
||||||
|
|
||||||
|
hudTexture.background = "black";
|
||||||
|
const stackPanel = new StackPanel();
|
||||||
|
hudTexture.addControl(stackPanel);
|
||||||
|
|
||||||
|
|
||||||
|
stackPanel.addControl(textPosition);
|
||||||
|
stackPanel.addControl(textRotation);
|
||||||
|
|
||||||
|
this.scene.onBeforeRenderObservable.add(() => {
|
||||||
|
if (Controllers.movable) {
|
||||||
|
textPosition.text = 'position: '+ this.formatVector3(Controllers.movable.position);
|
||||||
|
textRotation.text = 'rotation: '+ this.formatVector3(Controllers.movable.rotation);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
createTextBlock(): TextBlock {
|
||||||
|
const text = new TextBlock();
|
||||||
|
text.isHitTestVisible = false;
|
||||||
|
text.text = "";
|
||||||
|
text.height="20%";
|
||||||
|
text.resizeToFit=true;
|
||||||
|
|
||||||
|
text.color="white";
|
||||||
|
text.fontSize = 64;
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
private formatVector3(v: Vector3): string {
|
||||||
|
return `(${v.x.toFixed(2)},${v.y.toFixed(2)},${v.z.toFixed(2)})`;
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/menus/MenuState.ts
Normal file
6
src/menus/MenuState.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export enum BmenuState {
|
||||||
|
NONE,
|
||||||
|
ADDING, // Adding a new entity
|
||||||
|
DROPPING, // Dropping an entity
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,43 +1,36 @@
|
|||||||
import {
|
import {
|
||||||
AbstractMesh,
|
AbstractMesh,
|
||||||
Angle,
|
|
||||||
Color3,
|
Color3,
|
||||||
Scene,
|
Scene,
|
||||||
StandardMaterial,
|
StandardMaterial,
|
||||||
TransformNode,
|
|
||||||
Vector3,
|
Vector3,
|
||||||
WebXRExperienceHelper,
|
WebXRExperienceHelper,
|
||||||
WebXRInputSource
|
WebXRInputSource
|
||||||
} from "@babylonjs/core";
|
} from "@babylonjs/core";
|
||||||
import {GUI3DManager, HolographicButton, PlanePanel} from "@babylonjs/gui";
|
import {GUI3DManager, NearMenu, TouchHolographicButton} from "@babylonjs/gui";
|
||||||
import {DiagramEntity, DiagramEvent, DiagramEventType, DiagramManager} from "../diagram/diagramManager";
|
import {DiagramManager} from "../diagram/diagramManager";
|
||||||
|
import {BmenuState} from "./MenuState";
|
||||||
|
import {DiagramEntity, DiagramEvent, DiagramEventType} from "../diagram/diagramEntity";
|
||||||
|
|
||||||
export enum BmenuState {
|
|
||||||
NONE,
|
|
||||||
ADDING, // Adding a new entity
|
|
||||||
DROPPING, // Dropping an entity
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Bmenu {
|
export class Bmenu {
|
||||||
private readonly scene;
|
|
||||||
private state: BmenuState = BmenuState.NONE;
|
private state: BmenuState = BmenuState.NONE;
|
||||||
|
private manager: GUI3DManager;
|
||||||
|
private scene: Scene;
|
||||||
|
|
||||||
private xr;
|
|
||||||
private manager;
|
|
||||||
private panel;
|
|
||||||
private rightController: AbstractMesh;
|
private rightController: AbstractMesh;
|
||||||
|
private xr: WebXRExperienceHelper;
|
||||||
|
|
||||||
constructor(scene: Scene, xr: WebXRExperienceHelper) {
|
constructor(scene: Scene, xr: WebXRExperienceHelper) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.manager = new GUI3DManager(scene);
|
|
||||||
|
|
||||||
this.xr = xr;
|
this.xr = xr;
|
||||||
|
|
||||||
DiagramManager.onDiagramEventObservable.add((event: DiagramEvent) => {
|
DiagramManager.onDiagramEventObservable.add((event: DiagramEvent) => {
|
||||||
if (event.type === DiagramEventType.DROPPED) {
|
if (event.type === DiagramEventType.DROPPED) {
|
||||||
this.state = BmenuState.ADDING;
|
this.state = BmenuState.ADDING;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setController(controller: WebXRInputSource) {
|
setController(controller: WebXRInputSource) {
|
||||||
@ -45,7 +38,7 @@ export class Bmenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
makeButton(name: string, id: string) {
|
makeButton(name: string, id: string) {
|
||||||
const button = new HolographicButton(name);
|
const button = new TouchHolographicButton(name);
|
||||||
button.text = name;
|
button.text = name;
|
||||||
button.name = id;
|
button.name = id;
|
||||||
button.onPointerClickObservable.add(this.#clickhandler, -1, false, this);
|
button.onPointerClickObservable.add(this.#clickhandler, -1, false, this);
|
||||||
@ -59,72 +52,90 @@ export class Bmenu {
|
|||||||
public setState(state: BmenuState) {
|
public setState(state: BmenuState) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
}
|
}
|
||||||
|
toggle(mesh: AbstractMesh) {
|
||||||
toggle() {
|
console.log(mesh.name);
|
||||||
if (this.panel) {
|
if (this.manager) {
|
||||||
this.panel.dispose();
|
this.manager.dispose();
|
||||||
this.panel = null;
|
this.manager = null;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
const anchor = new TransformNode("bMenuAnchor");
|
this.manager = new GUI3DManager(this.scene);
|
||||||
anchor.rotation.y = Angle.FromDegrees(180).radians();
|
const panel = new NearMenu();
|
||||||
const cam = this.xr.camera.getFrontPosition(1);
|
|
||||||
cam.y = cam.y - .5;
|
|
||||||
anchor.position = cam;
|
|
||||||
const panel = new PlanePanel();
|
|
||||||
panel.margin = .06;
|
|
||||||
this.manager.addControl(panel);
|
this.manager.addControl(panel);
|
||||||
panel.linkToTransformNode(anchor);
|
const follower = panel.defaultBehavior.followBehavior;
|
||||||
panel.addControl(this.makeButton("Add Box", "addBox"));
|
follower.maxViewHorizontalDegrees = 45;
|
||||||
panel.addControl(this.makeButton("Add Sphere", "addSphere"));
|
follower.useFixedVerticalOffset = true;
|
||||||
panel.addControl(this.makeButton("Add Cylinder", "addCylinder"));
|
follower.fixedVerticalOffset = 1;
|
||||||
panel.addControl(this.makeButton("Done Adding", "doneAdding"));
|
follower.defaultDistance = 2;
|
||||||
for (const control of panel.children) {
|
follower.maximumDistance = 3;
|
||||||
control.scaling = new Vector3(.1, .1, .1);
|
follower.minimumDistance = 1;
|
||||||
}
|
|
||||||
this.panel = panel;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
panel.backPlateMargin = .01;
|
||||||
|
panel.scaling= new Vector3(.5, .5, .1);
|
||||||
|
panel.margin = .01;
|
||||||
|
//panel.scaling.x = .5;
|
||||||
|
//panel.scaling.y = .5;
|
||||||
|
//const camdir = panel.mesh.getDirection(this.xr.camera.globalPosition);
|
||||||
|
//panel.mesh.lookAt(this.xr.camera.globalPosition);
|
||||||
|
panel.addButton(this.makeButton("Add Box", "addBox"));
|
||||||
|
panel.addButton(this.makeButton("Add Sphere", "addSphere"));
|
||||||
|
panel.addButton(this.makeButton("Add Cylinder", "addCylinder"));
|
||||||
|
panel.addButton(this.makeButton("Done Adding", "doneAdding"));
|
||||||
|
this.manager.controlScaling = .5;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#clickhandler(_info, state) {
|
#clickhandler(_info, state) {
|
||||||
console.log(state.currentTarget.name);
|
console.log(state.currentTarget.name);
|
||||||
|
|
||||||
|
const id = this?.rightController?.id || null;
|
||||||
let entity: DiagramEntity = {
|
let entity: DiagramEntity = {
|
||||||
template: null,
|
template: null,
|
||||||
position: new Vector3(0, -.040, .13),
|
position: new Vector3(-.01, -.1, .14),
|
||||||
rotation: new Vector3(),
|
rotation: new Vector3(76.04, 0, 0),
|
||||||
scale: new Vector3(.1, .1, .1),
|
scale: new Vector3(.1, .1, .1),
|
||||||
color: "#CEE",
|
color: "#CC0000",
|
||||||
text: "test",
|
text: "test",
|
||||||
last_seen: new Date(),
|
last_seen: new Date(),
|
||||||
parent: this.rightController.id
|
parent: id
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (state.currentTarget.name) {
|
switch (state.currentTarget.name) {
|
||||||
case "addBox":
|
case "addBox":
|
||||||
entity.template = "#box-template";
|
entity.template = "#box-template";
|
||||||
|
this.state = BmenuState.ADDING;
|
||||||
break;
|
break;
|
||||||
case "addSphere":
|
case "addSphere":
|
||||||
entity.template = "#sphere-template";
|
entity.template = "#sphere-template";
|
||||||
|
this.state = BmenuState.ADDING;
|
||||||
break;
|
break;
|
||||||
case "addCylinder":
|
case "addCylinder":
|
||||||
entity.template = "#cylinder-template";
|
entity.template = "#cylinder-template";
|
||||||
|
this.state = BmenuState.ADDING;
|
||||||
break;
|
break;
|
||||||
case "doneAdding":
|
case "doneAdding":
|
||||||
this.state = BmenuState.NONE;
|
this.state = BmenuState.NONE;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.log("Unknown button");
|
console.log("Unknown button");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this.state === BmenuState.ADDING) {
|
||||||
const event: DiagramEvent = {
|
const event: DiagramEvent = {
|
||||||
type: DiagramEventType.ADD,
|
type: DiagramEventType.ADD,
|
||||||
entity: entity
|
entity: entity
|
||||||
}
|
}
|
||||||
this.state = BmenuState.ADDING;
|
|
||||||
DiagramManager.onDiagramEventObservable.notifyObservers(event);
|
DiagramManager.onDiagramEventObservable.notifyObservers(event);
|
||||||
|
} else {
|
||||||
|
const event: DiagramEvent = {
|
||||||
|
type: DiagramEventType.CLEAR
|
||||||
|
}
|
||||||
|
DiagramManager.onDiagramEventObservable.notifyObservers(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#createDefaultMaterial() {
|
#createDefaultMaterial() {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user