Added persistenceManager.ts

This commit is contained in:
Michael Mainguy 2023-07-19 15:41:48 -05:00
parent afd8040108
commit d32995c999
12 changed files with 181 additions and 93 deletions

24
package-lock.json generated
View File

@ -16,6 +16,9 @@
"@babylonjs/inspector": "^6.12.3",
"@maptiler/client": "^1.5.0",
"axios": "^1.4.0",
"dexie": "^3.2.4",
"dexie-observable": "^4.0.1-beta.13",
"earcut": "^2.2.4",
"express": "^4.18.2",
"express-http-proxy": "^1.6.3",
"google-static-maps-tile": "1.0.0",
@ -1759,6 +1762,22 @@
"node": ">=8"
}
},
"node_modules/dexie": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/dexie/-/dexie-3.2.4.tgz",
"integrity": "sha512-VKoTQRSv7+RnffpOJ3Dh6ozknBqzWw/F3iqMdsZg958R0AS8AnY9x9d1lbwENr0gzeGJHXKcGhAMRaqys6SxqA==",
"engines": {
"node": ">=6.0"
}
},
"node_modules/dexie-observable": {
"version": "4.0.1-beta.13",
"resolved": "https://registry.npmjs.org/dexie-observable/-/dexie-observable-4.0.1-beta.13.tgz",
"integrity": "sha512-axmgPk7yjoPwj+0DdQIE5s1MBXi+6XcIFIjBKdQAmSGpsLQSth/LHvMOQ3q3Wj6pwIE5hqIxg2GL75sVqQbhEw==",
"peerDependencies": {
"dexie": "^3.0.2 || ^4.0.1-alpha.5"
}
},
"node_modules/dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@ -1782,6 +1801,11 @@
"url": "https://github.com/motdotla/dotenv?sponsor=1"
}
},
"node_modules/earcut": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz",
"integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ=="
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",

View File

@ -21,10 +21,13 @@
"ring-client-api": "^11.8.0",
"@maptiler/client": "^1.5.0",
"axios": "^1.4.0",
"dexie": "^3.2.4",
"dexie-observable": "^4.0.1-beta.13",
"google-static-maps-tile": "1.0.0",
"query-string": "^8.1.0",
"vite-express": "^0.9.1",
"express-http-proxy": "^1.6.3",
"earcut": "^2.2.4",
"uuid": "^9.0.0"
},
"devDependencies": {

View File

@ -1,13 +1,18 @@
import {Vector3, WebXRInputSource} from "@babylonjs/core";
import {AbstractMesh, Scene, Vector3, WebXRInputSource} from "@babylonjs/core";
export class Base {
static stickVector = Vector3.Zero();
protected controller: WebXRInputSource;
protected speedFactor = 4;
protected readonly scene: Scene;
protected currentMesh: AbstractMesh = null;
constructor(controller:
WebXRInputSource) {
WebXRInputSource, scene: Scene) {
this.controller = controller;
this.scene= scene;
this.scene.registerAfterRender(() => {
this.currentMesh= this.scene.getPointerOverMesh();
});
this.controller.onMotionControllerInitObservable.add((init) => {
if (init.components['xr-standard-trigger']) {
init.components['xr-standard-trigger']

View File

@ -1,4 +1,4 @@
import {Vector3, WebXRInputSource} from "@babylonjs/core";
import {Scene, Vector3, WebXRInputSource} from "@babylonjs/core";
import {Base} from "./base";
import {Controllers} from "./controllers";
@ -7,8 +7,9 @@ export class Left extends Base {
public static instance: Left;
constructor(controller:
WebXRInputSource) {
super(controller);
WebXRInputSource, scene: Scene) {
super(controller, scene);
Left.instance = this;
this.controller.onMotionControllerInitObservable.add((init) => {

View File

@ -1,19 +1,30 @@
import {Base} from "./base";
import {Angle, Observable, Vector3, WebXRControllerComponent, WebXRInputSource} from "@babylonjs/core";
import {Angle, Scene, Vector3, WebXRControllerComponent, WebXRInputSource} from "@babylonjs/core";
import {Bmenu} from "../menus/bmenu";
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 {
private bmenu: Bmenu;
public static instance: Right;
private down: boolean = false;
constructor(controller:
WebXRInputSource, scene: Scene) {
super(controller, scene);
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 initBButton(bbutton: WebXRControllerComponent) {
if (bbutton) {
bbutton.onButtonStateChangedObservable.add((value) => {
@ -103,23 +114,16 @@ export class Right extends Base {
}
}
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);
if (this.currentMesh) {
this.currentMesh.setParent(this.controller.pointer);
}
} else {
if (this.currentMesh) {
this.currentMesh.setParent(null);
}
}
@ -133,12 +137,12 @@ export class Right extends Base {
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();
Angle.FromDegrees(Math.sign(value.y)).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();
Angle.FromDegrees(Math.sign(value.x)).radians();
Controllers.movable.rotation.z = this.fixRadians(Controllers.movable.rotation.z);
}
}

View File

@ -43,7 +43,7 @@ export class Rigplatform {
this.bMenu = new Bmenu(scene, xr.baseExperience);
this.camera = scene.activeCamera;
this.rigMesh = MeshBuilder.CreateBox("platform", {width: 2, height: .02, depth: 2}, scene);
const hud = new Hud(this.rigMesh, scene);
new Hud(this.rigMesh, scene);
for (const cam of scene.cameras) {
cam.parent = this.rigMesh;
cam.position = new Vector3(0, 1.6, 0);
@ -72,6 +72,7 @@ export class Rigplatform {
this.camera = s.activeCamera;
this.camera.parent = this.rigMesh;
});
}
public forwardback(val: number) {
@ -129,7 +130,7 @@ export class Rigplatform {
let controller;
switch (source.inputSource.handedness) {
case "right":
Right.instance = new Right(source);
Right.instance = new Right(source, this.scene);
Right.instance.setBMenu(this.bMenu);
Controllers.controllerObserver.add((event: { type: string, value: number }) => {
switch (event.type) {
@ -154,7 +155,7 @@ export class Rigplatform {
});
break;
case "left":
Left.instance = new Left(source);
Left.instance = new Left(source, this.scene);
break;
}
@ -175,13 +176,13 @@ export class Rigplatform {
window.addEventListener("keydown", (ev) => {
switch (ev.key) {
case "w":
this.forwardback(1 * Rigplatform.LINEAR_VELOCITY);
this.forwardback(Rigplatform.LINEAR_VELOCITY);
break;
case "s":
this.forwardback(-1 * Rigplatform.LINEAR_VELOCITY);
break;
case "a":
this.leftright(1 * Rigplatform.LINEAR_VELOCITY);
this.leftright(Rigplatform.LINEAR_VELOCITY);
break;
case "d":
this.leftright(-1 * Rigplatform.LINEAR_VELOCITY);
@ -190,13 +191,13 @@ export class Rigplatform {
this.turn(-1 * Rigplatform.ANGULAR_VELOCITY);
break;
case "e":
this.turn(1 * Rigplatform.ANGULAR_VELOCITY);
this.turn(Rigplatform.ANGULAR_VELOCITY);
break;
case "W":
this.updown(-1 * Rigplatform.LINEAR_VELOCITY);
break;
case "S":
this.updown(1 * Rigplatform.LINEAR_VELOCITY);
this.updown(Rigplatform.LINEAR_VELOCITY);
break;
case " ":
this.bMenu.toggle(this.rigMesh)

View File

@ -1,12 +1,12 @@
import {
AbstractMesh,
Angle,
Color3,
Color3, DynamicTexture,
Mesh,
MeshBuilder,
Observable, Scene,
Observable,
Scene,
StandardMaterial,
Vector3, WebXRExperienceHelper
WebXRExperienceHelper
} from "@babylonjs/core";
import {v4 as uuidv4} from 'uuid';
import {DiagramEntity, DiagramEvent, DiagramEventType} from "./diagramEntity";
@ -15,7 +15,7 @@ import {PersistenceManager} from "./persistenceManager";
export class DiagramManager {
private persistenceManager: PersistenceManager = new PersistenceManager();
static onDiagramEventObservable = new Observable();
private scene: Scene;
private readonly scene: Scene;
private xr: WebXRExperienceHelper;
static currentMesh: AbstractMesh;
@ -33,13 +33,18 @@ export class DiagramManager {
DiagramManager.onDiagramEventObservable.add(this.#onDiagramEvent, -1, true, this);
}
}
#onRemoteEvent(event: DiagramEntity) {
const mesh = this.#createMesh(event);
if (!mesh.material) {
const material = new StandardMaterial("material-" + event.id, this.scene);
material.diffuseColor = Color3.FromHexString(event.color);
mesh.material = material;
}
}
#onDiagramEvent(event: DiagramEvent) {
const entity = event.entity;
let mesh;
@ -53,8 +58,10 @@ export class DiagramManager {
switch (event.type) {
case DiagramEventType.CLEAR:
if (DiagramManager.currentMesh) {
DiagramManager.currentMesh.dispose();
DiagramManager.currentMesh = null;
}
break;
case DiagramEventType.DROPPED:
break;
@ -62,10 +69,11 @@ export class DiagramManager {
if (DiagramManager.currentMesh) {
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;
const newMesh = DiagramManager.currentMesh.clone("id" + newName, DiagramManager.currentMesh.parent);
newMesh.material = DiagramManager.currentMesh.material.clone("material" + newName);
DiagramManager.currentMesh.setParent(null);
//DiagramManager.currentMesh.billboardMode = Mesh.BILLBOARDMODE_Y;
DiagramManager.currentMesh = newMesh;
DiagramManager.onDiagramEventObservable.notifyObservers({
type: DiagramEventType.DROPPED,
@ -82,9 +90,6 @@ export class DiagramManager {
} else {
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) {
@ -98,11 +103,6 @@ export class DiagramManager {
} else {
if (!material) {
material = new StandardMaterial("material-" + event.entity.id, this.scene);
material.diffuseColor = Color3.FromHexString(event.entity.color);
if (mesh) {
mesh.material = material;
}
}
mesh.material = material;
@ -127,6 +127,42 @@ export class DiagramManager {
}
let mesh: Mesh;
switch (entity.template) {
case "#plane-template":
case "#text-template":
const material = new StandardMaterial("material-" + entity.id, this.scene);
material.backFaceCulling = false;
const font_size = 48;
const font = "bold 48px roboto";
const planeHeight=1;
const DTHeight = 1.5*font_size;
const ratio = planeHeight / DTHeight;
const text = 'This is some text to put on a plane';
const tempText = new DynamicTexture("dynamic texture", 64, this.scene);
const tempContext = tempText.getContext();
tempContext.font = font;
const DTWidth = tempContext.measureText(text).width;
const planeWidth = DTWidth * ratio;
const myDynamicTexture = new DynamicTexture("dynamic texture",
{width: DTWidth, height: DTHeight},
this.scene, false);
mesh= MeshBuilder.CreatePlane(entity.id, {
width: planeWidth,
height: planeHeight
}, this.scene);
myDynamicTexture.drawText('This is some short text',
null, null,
font, "#000000", "#FFFFFF",
true, true);
material.diffuseTexture = myDynamicTexture;
mesh.material = material;
break;
case "#box-template":
mesh = MeshBuilder.CreateBox(entity.id,
{
@ -150,7 +186,9 @@ export class DiagramManager {
}
if (mesh) {
mesh.metadata = {template: entity.template};
if (entity.text) {
mesh.metadata.text = entity.text;
}
if (entity.position) {
mesh.position = entity.position;
}
@ -163,6 +201,11 @@ export class DiagramManager {
if (entity.scale) {
mesh.scaling = entity.scale;
}
if (!mesh.material) {
const material = new StandardMaterial("material-" + entity.id, this.scene);
material.diffuseColor = Color3.FromHexString(entity.color);
mesh.material = material;
}
}
return mesh;

View File

@ -1,26 +1,32 @@
import {AbstractMesh, Mesh, Observable, StandardMaterial, Vector3} from "@babylonjs/core";
import {AbstractMesh, Observable, StandardMaterial, Vector3} from "@babylonjs/core";
import {DiagramEntity} from "./diagramEntity";
import Dexie from "dexie";
export class PersistenceManager {
public updateObserver: Observable<DiagramEntity> = new Observable<DiagramEntity>();
private db: Dexie = new Dexie("diagram");
constructor() {
this.db.version(1).stores({entities: "id,position,rotation,last_seen,template,text,scale,color"});
}
public add(mesh: AbstractMesh) {
const entity = <any>{};
entity.id = mesh.id;
entity.position = mesh.position.toString();
entity.rotation = mesh.rotation.toString();
entity.position = this.vectoxys(mesh.position);
entity.rotation = this.vectoxys(mesh.rotation);
entity.last_seen = new Date().getDate();
entity.template = "default";
entity.text = "";
entity.scale = mesh.scaling.toString();
entity.template = mesh?.metadata?.template;
entity.text = mesh?.metadata?.text;
entity.scale = this.vectoxys(mesh.scaling);
if (mesh.material) {
entity.color = (mesh.material as StandardMaterial).diffuseColor.toHexString();
}
console.log(entity);
this.db["entities"].add(entity);
}
private vectoxys(v: Vector3): {x, y ,z} {
return {x: v.x, y: v.y, z: v.z};
}
private xyztovec(xyz: {x, y, z}): Vector3 {
return new Vector3(xyz.x, xyz.y, xyz.z);
}
public remove() {
@ -30,19 +36,26 @@ export class PersistenceManager {
}
public initialize() {
this.db['entities'].each((e: DiagramEntity) => {
e.position = this.xyztovec(e.position);
e.rotation = this.xyztovec(e.rotation);
e.scale = this.xyztovec(e.scale);
console.log(e);
this.updateObserver.notifyObservers(e);
});
}
private dummyEntity(): DiagramEntity {
const entity: DiagramEntity = <DiagramEntity>{};
entity.id = "test";
entity.position = new Vector3(0,2,-2);
entity.position = new Vector3(0,2,-5);
entity.rotation = Vector3.Zero();
entity.last_seen = new Date();
entity.scale = Vector3.One();
entity.scale = new Vector3(.1,.1,.1);
entity.color = "#ff0000";
entity.text = "test";
entity.parent = null;
entity.template = "#box-template";
this.updateObserver.notifyObservers(entity);
entity.template = "#text-template";
return entity;
}
}

View File

@ -5,7 +5,7 @@ import {Controllers} from "../controllers/controllers";
export class Hud {
private scene: Scene;
private parent: AbstractMesh;
private hudPlane: AbstractMesh;
private readonly hudPlane: AbstractMesh;
constructor(parent: AbstractMesh, scene: Scene) {
this.scene = scene;
this.parent = parent;

View File

@ -1,8 +1,6 @@
import {
AbstractMesh,
Color3,
Scene,
StandardMaterial,
Vector3,
WebXRExperienceHelper,
WebXRInputSource
@ -16,7 +14,7 @@ import {DiagramEntity, DiagramEvent, DiagramEventType} from "../diagram/diagramE
export class Bmenu {
private state: BmenuState = BmenuState.NONE;
private manager: GUI3DManager;
private scene: Scene;
private readonly scene: Scene;
private rightController: AbstractMesh;
private xr: WebXRExperienceHelper;
@ -52,6 +50,7 @@ export class Bmenu {
public setState(state: BmenuState) {
this.state = state;
}
toggle(mesh: AbstractMesh) {
console.log(mesh.name);
if (this.manager) {
@ -70,7 +69,7 @@ export class Bmenu {
follower.minimumDistance = 1;
panel.backPlateMargin = .01;
panel.scaling= new Vector3(.5, .5, .1);
panel.scaling = new Vector3(.5, .5, .1);
panel.margin = .01;
//panel.scaling.x = .5;
//panel.scaling.y = .5;
@ -79,6 +78,7 @@ export class Bmenu {
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("Add Text", "addText"));
panel.addButton(this.makeButton("Done Adding", "doneAdding"));
this.manager.controlScaling = .5;
@ -91,11 +91,11 @@ export class Bmenu {
const id = this?.rightController?.id || null;
let entity: DiagramEntity = {
template: null,
position: new Vector3(-.01, -.1, .14),
position: new Vector3(-0.02, -.090, .13),
rotation: new Vector3(76.04, 0, 0),
scale: new Vector3(.1, .1, .1),
color: "#CC0000",
text: "test",
text: "text",
last_seen: new Date(),
parent: id
};
@ -113,6 +113,10 @@ export class Bmenu {
entity.template = "#cylinder-template";
this.state = BmenuState.ADDING;
break;
case "addText":
entity.template = "#text-template";
this.state = BmenuState.ADDING;
break;
case "doneAdding":
this.state = BmenuState.NONE;
@ -133,14 +137,5 @@ export class Bmenu {
}
DiagramManager.onDiagramEventObservable.notifyObservers(event);
}
}
#createDefaultMaterial() {
const myMaterial = new StandardMaterial("myMaterial", this.scene);
myMaterial.diffuseColor = Color3.FromHexString("#CEE");
return myMaterial;
}
}

View File

@ -4,12 +4,12 @@ export class RingCamera {
private ringApi: RingApi;
constructor() {
const ringApi = new RingApi({
this.ringApi = new RingApi({
refreshToken: process.env.RING_TOKEN,
cameraStatusPollingSeconds: 30,
debug: true
});
this.ringApi = ringApi;
}
public async getCameras() {

View File

@ -9,8 +9,8 @@ export class Mapt {
}
buildMapImage() {
const apiKey = '073I3Pfe4lzoSf8tNriR';
maptilerClient.config.apiKey = apiKey;
maptilerClient.config.apiKey = '073I3Pfe4lzoSf8tNriR';
const link = maptilerClient.staticMaps.centered(
[-88.8711198, 42.3370588],
@ -19,7 +19,6 @@ export class Mapt {
);
const plane = MeshBuilder.CreatePlane("plane", {width: 10, height: 10}, this.scene);
const materialPlane = new StandardMaterial("texturePlane", this.scene);
const zoom = 10;
const sphere = MeshBuilder.CreateSphere("cams", {diameter: .1}, this.scene);
sphere.position.y = 0.2;
sphere.position.z = -5;