Added initial networkmanager component.

This commit is contained in:
Michael Mainguy 2023-08-02 13:10:44 -05:00
parent afba69042c
commit 0e2ced65e8
16 changed files with 288 additions and 248 deletions

76
package-lock.json generated
View File

@ -17,6 +17,7 @@
"dexie-observable": "^4.0.1-beta.13", "dexie-observable": "^4.0.1-beta.13",
"earcut": "^2.2.4", "earcut": "^2.2.4",
"loglevel": "^1.8.1", "loglevel": "^1.8.1",
"p2p-data-channel": "^1.10.7",
"query-string": "^8.1.0", "query-string": "^8.1.0",
"ring-client-api": "11.7.7", "ring-client-api": "11.7.7",
"round": "^2.0.1", "round": "^2.0.1",
@ -882,6 +883,14 @@
"url": "https://github.com/sindresorhus/is?sponsor=1" "url": "https://github.com/sindresorhus/is?sponsor=1"
} }
}, },
"node_modules/@swc/helpers": {
"version": "0.3.17",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.3.17.tgz",
"integrity": "sha512-tb7Iu+oZ+zWJZ3HJqwx8oNwSDIU440hmVMDPhpACWQWnrZHK99Bxs70gT1L2dnr5Hg50ZRWEFkQCAnOVVV0z1Q==",
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@szmarczak/http-timer": { "node_modules/@szmarczak/http-timer": {
"version": "4.0.6", "version": "4.0.6",
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
@ -1820,6 +1829,11 @@
"node": ">=0.8.0" "node": ">=0.8.0"
} }
}, },
"node_modules/eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
},
"node_modules/events": { "node_modules/events": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
@ -2961,6 +2975,15 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/p2p-data-channel": {
"version": "1.10.7",
"resolved": "https://registry.npmjs.org/p2p-data-channel/-/p2p-data-channel-1.10.7.tgz",
"integrity": "sha512-YPpmzm75hX773d2dB1KYYUhvEXBM5NlkWHALvudQOG3Xv8AGceJuNcGpAKxprMu/dY3WL7RgJuqM/EzZojlUcw==",
"dependencies": {
"peerjs": "^1.4.7",
"uuid": "^9.0.0"
}
},
"node_modules/parse-exponential": { "node_modules/parse-exponential": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/parse-exponential/-/parse-exponential-1.0.1.tgz", "resolved": "https://registry.npmjs.org/parse-exponential/-/parse-exponential-1.0.1.tgz",
@ -3011,6 +3034,29 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/peerjs": {
"version": "1.4.7",
"resolved": "https://registry.npmjs.org/peerjs/-/peerjs-1.4.7.tgz",
"integrity": "sha512-dWE2HIGvJO0Hm8lYHJiO/5OWl8xYtGcAuU08To1HMIfhh76ULzkCS3NIQO/PZm4noO1RhaGTkQaQ6sbAss6/Tg==",
"dependencies": {
"@swc/helpers": "^0.3.13",
"eventemitter3": "^4.0.7",
"peerjs-js-binarypack": "1.0.1",
"webrtc-adapter": "^7.7.1"
},
"engines": {
"node": ">= 10"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/peer"
}
},
"node_modules/peerjs-js-binarypack": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/peerjs-js-binarypack/-/peerjs-js-binarypack-1.0.1.tgz",
"integrity": "sha512-N6aeia3NhdpV7kiGxJV5xQiZZCVEEVjRz2T2C6UZQiBkHWHzUv/oWA4myQLcwBwO8LUoR1KWW5oStvwVesmfCg=="
},
"node_modules/pick-port": { "node_modules/pick-port": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/pick-port/-/pick-port-1.0.1.tgz", "resolved": "https://registry.npmjs.org/pick-port/-/pick-port-1.0.1.tgz",
@ -3343,6 +3389,18 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/rtcpeerconnection-shim": {
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.15.tgz",
"integrity": "sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==",
"dependencies": {
"sdp": "^2.6.0"
},
"engines": {
"node": ">=6.0.0",
"npm": ">=3.10.0"
}
},
"node_modules/run-async": { "node_modules/run-async": {
"version": "2.4.1", "version": "2.4.1",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
@ -3411,6 +3469,11 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
}, },
"node_modules/sdp": {
"version": "2.12.0",
"resolved": "https://registry.npmjs.org/sdp/-/sdp-2.12.0.tgz",
"integrity": "sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw=="
},
"node_modules/set-cookie-parser": { "node_modules/set-cookie-parser": {
"version": "2.6.0", "version": "2.6.0",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz",
@ -3927,6 +3990,19 @@
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
}, },
"node_modules/webrtc-adapter": {
"version": "7.7.1",
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-7.7.1.tgz",
"integrity": "sha512-TbrbBmiQBL9n0/5bvDdORc6ZfRY/Z7JnEj+EYOD1ghseZdpJ+nF2yx14k3LgQKc7JZnG7HAcL+zHnY25So9d7A==",
"dependencies": {
"rtcpeerconnection-shim": "^1.2.15",
"sdp": "^2.12.0"
},
"engines": {
"node": ">=6.0.0",
"npm": ">=3.10.0"
}
},
"node_modules/werift": { "node_modules/werift": {
"version": "0.18.2", "version": "0.18.2",
"resolved": "https://registry.npmjs.org/werift/-/werift-0.18.2.tgz", "resolved": "https://registry.npmjs.org/werift/-/werift-0.18.2.tgz",

View File

@ -23,7 +23,8 @@
"loglevel": "^1.8.1", "loglevel": "^1.8.1",
"round": "^2.0.1", "round": "^2.0.1",
"earcut": "^2.2.4", "earcut": "^2.2.4",
"uuid": "^9.0.0" "uuid": "^9.0.0",
"p2p-data-channel": "^1.10.7"
}, },
"devDependencies": { "devDependencies": {
"typescript": "^5.0.2", "typescript": "^5.0.2",

View File

@ -1,15 +1,12 @@
import "@babylonjs/core/Debug/debugLayer";
import "@babylonjs/inspector";
import { import {
ArcRotateCamera, ArcRotateCamera,
DualShockPad, DualShockPad,
Engine, Engine,
GroundMesh,
HavokPlugin, HavokPlugin,
HemisphericLight, HemisphericLight,
MeshBuilder, MeshBuilder,
PBRMetallicRoughnessMaterial, PBRMetallicRoughnessMaterial,
PhotoDome,
PhysicsAggregate, PhysicsAggregate,
PhysicsShapeType, PhysicsShapeType,
Scene, Scene,
@ -18,7 +15,6 @@ import {
WebXRDefaultExperience, WebXRDefaultExperience,
WebXRState WebXRState
} from "@babylonjs/core"; } from "@babylonjs/core";
///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";
@ -26,7 +22,6 @@ import {Toolbox} from "./toolbox/toolbox";
import {DualshockEventMapper} from "./util/dualshockEventMapper"; import {DualshockEventMapper} from "./util/dualshockEventMapper";
import log from "loglevel"; import log from "loglevel";
import {AppConfig} from "./util/appConfig"; import {AppConfig} from "./util/appConfig";
import {IndexdbPersistenceManager} from "./diagram/indexdbPersistenceManager";
import {DiaSounds} from "./util/diaSounds"; import {DiaSounds} from "./util/diaSounds";
export class App { export class App {
@ -35,7 +30,7 @@ export class App {
private scene: Scene; private scene: Scene;
private xr: WebXRDefaultExperience;
private rig: Rigplatform; private rig: Rigplatform;
constructor() { constructor() {
@ -51,13 +46,11 @@ export class App {
this.initialize(canvas).then(() => { this.initialize(canvas).then(() => {
log.debug('App', 'Scene Initialized'); log.debug('App', 'Scene Initialized');
}); });
} }
async initialize(canvas) { async initialize(canvas) {
if (this.xr) {
this.xr.dispose();
this.xr = null;
}
if (this.scene) { if (this.scene) {
this.scene.dispose(); this.scene.dispose();
this.scene = null; this.scene = null;
@ -81,13 +74,15 @@ export class App {
camera.radius = 0; camera.radius = 0;
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 photoDome = new PhotoDome('sky', import('@babylonjs/core').then((babylon) => {
'./outdoor_field2.jpeg', {}, new babylon.PhotoDome('sky',
scene); './outdoor_field2.jpeg', {},
scene);
});
const ground = this.createGround(); const ground = this.createGround();
this.xr = await WebXRDefaultExperience.CreateAsync(scene, { const xr = await WebXRDefaultExperience.CreateAsync(scene, {
floorMeshes: [ground], floorMeshes: [ground],
disableTeleportation: true, disableTeleportation: true,
outputCanvasOptions: { outputCanvasOptions: {
@ -102,10 +97,10 @@ export class App {
}); });
this.xr.baseExperience.onStateChangedObservable.add((state) => { xr.baseExperience.onStateChangedObservable.add((state) => {
if (state == WebXRState.IN_XR) { if (state == WebXRState.IN_XR) {
this.scene.audioEnabled = true; this.scene.audioEnabled = true;
this.xr.baseExperience.camera.position = new Vector3(0, 1.6, 0); xr.baseExperience.camera.position = new Vector3(0, 1.6, 0);
window.addEventListener(('pa-button-state-change'), (event: any) => { window.addEventListener(('pa-button-state-change'), (event: any) => {
if (event.detail) { if (event.detail) {
log.debug('App', event.detail); log.debug('App', event.detail);
@ -114,14 +109,17 @@ export class App {
} }
}); });
const persistenceManager = new IndexdbPersistenceManager("diagram"); const diagramManager = new DiagramManager(this.scene, xr.baseExperience);
const diagramManager = new DiagramManager(this.scene, this.xr.baseExperience); this.rig = new Rigplatform(this.scene, xr, diagramManager);
diagramManager.setPersistenceManager(persistenceManager); const toolbox = new Toolbox(scene, xr.baseExperience, diagramManager);
AppConfig.config.setPersistenceManager(persistenceManager);
import ('./diagram/indexdbPersistenceManager').then((module) => {
const persistenceManager = new module.IndexdbPersistenceManager("diagram");
diagramManager.setPersistenceManager(persistenceManager);
AppConfig.config.setPersistenceManager(persistenceManager);
persistenceManager.initialize();
});
this.rig = new Rigplatform(this.scene, this.xr, diagramManager);
const toolbox = new Toolbox(scene, this.xr.baseExperience, diagramManager);
this.scene.gamepadManager.onGamepadConnectedObservable.add((gamepad) => { this.scene.gamepadManager.onGamepadConnectedObservable.add((gamepad) => {
try { try {
@ -190,15 +188,19 @@ export class App {
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) {
if (scene.debugLayer.isVisible()) { import("@babylonjs/core/Debug/debugLayer").then(() => {
scene.debugLayer.hide(); import("@babylonjs/inspector").then(() => {
} else { if (scene.debugLayer.isVisible()) {
scene.debugLayer.show(); scene.debugLayer.hide();
} } else {
scene.debugLayer.show();
}
});
});
} }
}); });
this.logger.info('keydown event listener added, use Ctrl+Shift+Alt+I to toggle debug layer'); this.logger.info('keydown event listener added, use Ctrl+Shift+Alt+I to toggle debug layer');
persistenceManager.initialize();
engine.runRenderLoop(() => { engine.runRenderLoop(() => {
scene.render(); scene.render();
@ -215,7 +217,11 @@ export class App {
groundMaterial.metallic = 0; groundMaterial.metallic = 0;
groundMaterial.roughness = 1; groundMaterial.roughness = 1;
const ground = MeshBuilder.CreateGround("ground", {width: 100, height: 100, subdivisions: 1}, this.scene); const ground: GroundMesh = MeshBuilder.CreateGround("ground", {
width: 100,
height: 100,
subdivisions: 1
}, this.scene);
ground.material = groundMaterial; ground.material = groundMaterial;
new PhysicsAggregate(ground, PhysicsShapeType.BOX, {mass: 0}, this.scene); new PhysicsAggregate(ground, PhysicsShapeType.BOX, {mass: 0}, this.scene);

View File

@ -79,7 +79,6 @@ export class Base {
if (init.components['xr-standard-squeeze']) { if (init.components['xr-standard-squeeze']) {
this.initGrip(init.components['xr-standard-squeeze']) this.initGrip(init.components['xr-standard-squeeze'])
} }
;
}); });
Controllers.controllerObserver.add((event) => { Controllers.controllerObserver.add((event) => {
if (event.type == 'pulse') { if (event.type == 'pulse') {
@ -88,8 +87,7 @@ export class Base {
this.controller?.motionController?.pulse(.25, 30); this.controller?.motionController?.pulse(.25, 30);
} }
} }
}); })
} }
public disable() { public disable() {
@ -101,11 +99,6 @@ export class Base {
this.controller.motionController.rootMesh.setEnabled(true); this.controller.motionController.rootMesh.setEnabled(true);
this.controller.pointer.setEnabled(true); this.controller.pointer.setEnabled(true);
} }
private buildTransformNode() {
}
private setupTransformNode(mesh: TransformNode) { private setupTransformNode(mesh: TransformNode) {
const transformNode = new TransformNode("grabAnchor, this.scene"); const transformNode = new TransformNode("grabAnchor, this.scene");
transformNode.id = "grabAnchor"; transformNode.id = "grabAnchor";

View File

@ -12,7 +12,7 @@ import {
WebXRExperienceHelper WebXRExperienceHelper
} from "@babylonjs/core"; } from "@babylonjs/core";
import {DiagramEntity, DiagramEvent, DiagramEventType} from "./diagramEntity"; import {DiagramEntity, DiagramEvent, DiagramEventType} from "./diagramEntity";
import {IPersistenceManager} from "./persistenceManager"; import {IPersistenceManager} from "./iPersistenceManager";
import {MeshConverter} from "./meshConverter"; import {MeshConverter} from "./meshConverter";
import log from "loglevel"; import log from "loglevel";
import {Controllers} from "../controllers/controllers"; import {Controllers} from "../controllers/controllers";

View File

@ -17,6 +17,7 @@ export class DiagramShapePhysics {
if (mesh.physicsBody) { if (mesh.physicsBody) {
mesh.physicsBody.dispose(); mesh.physicsBody.dispose();
} }
let shapeType = PhysicsShapeType.BOX; let shapeType = PhysicsShapeType.BOX;
switch (mesh.metadata.template) { switch (mesh.metadata.template) {
case "#sphere-template": case "#sphere-template":
@ -30,8 +31,9 @@ export class DiagramShapePhysics {
break; break;
} }
let mass = mesh.scaling.x * mesh.scaling.y * mesh.scaling.z * 10;
const aggregate = new PhysicsAggregate(mesh, const aggregate = new PhysicsAggregate(mesh,
shapeType, {mass: 20, restitution: .02, friction: .9}, scene); shapeType, {mass: mass, restitution: .02, friction: .9}, scene);
aggregate.body.setCollisionCallbackEnabled(true); aggregate.body.setCollisionCallbackEnabled(true);
aggregate.body.getCollisionObservable().add((event, state) => { aggregate.body.getCollisionObservable().add((event, state) => {
if (event.distance > .001 && !DiaSounds.instance.low.isPlaying) { if (event.distance > .001 && !DiaSounds.instance.low.isPlaying) {

View File

@ -0,0 +1,50 @@
import {AbstractMesh, Color3, Observable} from "@babylonjs/core";
import {DiagramEntity} from "./diagramEntity";
import {AppConfigType} from "../util/appConfigType";
export enum DiagramListingEventType {
GET,
ADD,
REMOVE,
MODIFY
}
export type DiagramListingEvent = {
type: DiagramListingEventType;
listing: DiagramListing;
}
export type DiagramListing = {
type: DiagramListingEvent;
id: string;
name: string;
description?: string;
sharekey?: string;
}
export interface IPersistenceManager {
diagramListingObserver: Observable<DiagramListingEvent>;
addDiagram(diagram: DiagramListing);
removeDiagram(diagram: DiagramListing);
add(mesh: AbstractMesh);
remove(mesh: AbstractMesh);
modify(mesh: AbstractMesh);
initialize();
setConfig(config: AppConfigType);
modifyDiagram(diagram: DiagramListing);
updateObserver: Observable<DiagramEntity>;
configObserver: Observable<AppConfigType>;
changeColor(oldColor: Color3, newColor: Color3);
setCurrentDiagram(diagram: DiagramListing);
}

View File

@ -1,4 +1,4 @@
import {IPersistenceManager} from "./persistenceManager"; import {DiagramListing, DiagramListingEvent, DiagramListingEventType, IPersistenceManager} from "./iPersistenceManager";
import {AbstractMesh, Observable, Vector3} from "@babylonjs/core"; import {AbstractMesh, Observable, Vector3} from "@babylonjs/core";
import {DiagramEntity} from "./diagramEntity"; import {DiagramEntity} from "./diagramEntity";
import Dexie from "dexie"; import Dexie from "dexie";
@ -6,20 +6,25 @@ import {MeshConverter} from "./meshConverter";
import log from "loglevel"; import log from "loglevel";
import {AppConfigType} from "../util/appConfigType"; import {AppConfigType} from "../util/appConfigType";
export class IndexdbPersistenceManager implements IPersistenceManager { export class IndexdbPersistenceManager implements IPersistenceManager {
private readonly logger = log.getLogger('IndexdbPersistenceManager'); private readonly logger = log.getLogger('IndexdbPersistenceManager');
public readonly diagramListingObserver: Observable<DiagramListingEvent> = new Observable<DiagramListingEvent>();
public readonly updateObserver: Observable<DiagramEntity> = new Observable<DiagramEntity>(); public readonly updateObserver: Observable<DiagramEntity> = new Observable<DiagramEntity>();
public readonly configObserver: Observable<AppConfigType> = new Observable<AppConfigType>(); public readonly configObserver: Observable<AppConfigType> = new Observable<AppConfigType>();
private db: Dexie; private db: Dexie;
private currentDiagramId: string;
constructor(name: string) { constructor(name: string) {
this.db = new Dexie(name); this.db = new Dexie(name);
const version = 2; const version = 3;
this.db.version(version).stores({config: "id,gridSnap,rotateSnap,createSnap"}); this.db.version(version).stores({config: "id,gridSnap,rotateSnap,createSnap"});
this.db.version(version).stores({entities: "id,position,rotation,last_seen,template,text,scale,color"}); this.db.version(version).stores({entities: "id,diagramlistingid,position,rotation,last_seen,template,text,scale,color"});
this.db.version(version).stores({diagramlisting: "id,name,description,sharekey"});
this.logger.debug("IndexdbPersistenceManager constructed"); this.logger.debug("IndexdbPersistenceManager constructed");
}
public setCurrentDiagram(diagram: DiagramListing) {
this.currentDiagramId = diagram.id;
} }
public add(mesh: AbstractMesh) { public add(mesh: AbstractMesh) {
@ -31,10 +36,20 @@ export class IndexdbPersistenceManager implements IPersistenceManager {
entity.position = this.vectoxys(mesh.position); entity.position = this.vectoxys(mesh.position);
entity.rotation = this.vectoxys(mesh.rotation); entity.rotation = this.vectoxys(mesh.rotation);
entity.scale = this.vectoxys(mesh.scaling); entity.scale = this.vectoxys(mesh.scaling);
entity.diagramlistingid = this.currentDiagramId;
this.db["entities"].add(entity); this.db["entities"].add(entity);
this.logger.debug('add', mesh, entity); this.logger.debug('add', mesh, entity);
} }
public addDiagram(diagram: DiagramListing) {
this.db["diagramlisting"].add(diagram);
const event = {
type: DiagramListingEventType.ADD,
listing: diagram
}
this.diagramListingObserver.notifyObservers(event);
}
public remove(mesh: AbstractMesh) { public remove(mesh: AbstractMesh) {
if (!mesh) { if (!mesh) {
this.logger.error("Removing null mesh, early return"); this.logger.error("Removing null mesh, early return");
@ -50,6 +65,55 @@ export class IndexdbPersistenceManager implements IPersistenceManager {
this.configObserver.notifyObservers(config); this.configObserver.notifyObservers(config);
} }
public removeDiagram(diagram: DiagramListing) {
this.db["diagramlisting"].delete(diagram.id);
const event = {
type: DiagramListingEventType.REMOVE,
listing: diagram
}
this.diagramListingObserver.notifyObservers(event);
}
modifyDiagram(diagram: DiagramListing) {
this.db["diagramlisting"].update(diagram.id, diagram);
const event = {
type: DiagramListingEventType.MODIFY,
listing: diagram
}
this.diagramListingObserver.notifyObservers(event);
}
public async initialize() {
this.logger.info('initialize', this.db['entities'].length);
const configs = await this.db['config'].toArray();
const config = configs[0];
if (config) {
this.logger.debug('initialize config', config);
this.configObserver.notifyObservers(config);
if (config.currentDiagramId) {
this.logger.debug('initialize currentDiagramId', config.currentDiagramId);
const currentDiagram = await this.db['diagramlisting'].get(config.currentDiagramId);
if (currentDiagram) {
this.logger.debug('found currentDiagram', currentDiagram);
this.currentDiagramId = currentDiagram.id;
} else {
this.logger.error('could not find currentDiagram', config.currentDiagramId);
}
} else {
this.logger.warn('no currentDiagramId, using default');
}
}
this.getFilteredEntities().each((e) => {
e.position = this.xyztovec(e.position);
e.rotation = this.xyztovec(e.rotation);
e.scale = this.xyztovec(e.scale);
this.logger.debug('adding', e);
this.updateObserver.notifyObservers(e);
});
this.listDiagrams();
this.logger.info("initialize finished");
}
public modify(mesh) { public modify(mesh) {
if (!mesh) { if (!mesh) {
this.logger.error("Modifying null mesh, early return"); this.logger.error("Modifying null mesh, early return");
@ -67,21 +131,6 @@ export class IndexdbPersistenceManager implements IPersistenceManager {
this.logger.debug('modify', mesh, entity); this.logger.debug('modify', mesh, entity);
} }
public initialize() {
this.logger.info('initialize', this.db['entities'].length);
this.db['entities'].each((e) => {
e.position = this.xyztovec(e.position);
e.rotation = this.xyztovec(e.rotation);
e.scale = this.xyztovec(e.scale);
this.logger.debug('adding', e);
this.updateObserver.notifyObservers(e);
});
this.db['config'].each((c) => {
this.configObserver.notifyObservers(c);
});
this.logger.info("initialize finished");
}
public changeColor(oldColor, newColor) { public changeColor(oldColor, newColor) {
if (!oldColor) { if (!oldColor) {
if (!newColor) { if (!newColor) {
@ -92,7 +141,31 @@ export class IndexdbPersistenceManager implements IPersistenceManager {
return; return;
} }
this.logger.debug(`changeColor ${oldColor.toHexString()} to ${newColor.toHexString()}`); this.logger.debug(`changeColor ${oldColor.toHexString()} to ${newColor.toHexString()}`);
this.db['entities'].where('color').equals(oldColor.toHexString()).modify({color: newColor.toHexString()}); this.getFilteredEntities().filter((e) => e.color == oldColor.toHexString()).modify({color: newColor.toHexString()});
}
private listDiagrams() {
return this.db["diagramlisting"].toArray((diagrams) => {
this.logger.debug('listDiagrams', diagrams);
for (const diagram of diagrams) {
const event = {
type: DiagramListingEventType.GET,
listing: diagram
}
this.diagramListingObserver.notifyObservers(event);
}
});
}
private getFilteredEntities() {
return this.db['entities'].filter((e) => {
if (!this.currentDiagramId && !e.diagramlistingid) {
return true;
} else {
return e.diagramlistingid == this.currentDiagramId;
}
}
);
} }
private vectoxys(v: Vector3): { x, y, z } { private vectoxys(v: Vector3): { x, y, z } {

View File

@ -1,22 +0,0 @@
import {AbstractMesh, Color3, Observable} from "@babylonjs/core";
import {DiagramEntity} from "./diagramEntity";
import {AppConfigType} from "../util/appConfigType";
export interface IPersistenceManager {
add(mesh: AbstractMesh);
remove(mesh: AbstractMesh);
modify(mesh: AbstractMesh);
initialize();
setConfig(config: AppConfigType);
changeColor(oldColor: Color3, newColor: Color3)
updateObserver: Observable<DiagramEntity>;
configObserver: Observable<AppConfigType>;
}

View File

@ -1,5 +0,0 @@
class Database {
constructor() {
}
}

View File

@ -0,0 +1,20 @@
import {Observable} from "@babylonjs/core";
export enum NetworkMessageType {
DIAGRAM_EVENT = 'diagramEvent',
CONNECTION_EVENT = 'connectionEvent',
}
class NetworkMessage {
type: NetworkMessageType;
data: any;
}
export interface INetworkConnection {
onMessageObservable: Observable<NetworkMessage>;
connect(name: string, room: string);
disconnect();
}

View File

@ -0,0 +1,3 @@
export class PeerjsNetworkConnection {
}

View File

@ -1,57 +0,0 @@
import {
Angle,
Color3,
MeshBuilder,
Scene,
StandardMaterial,
Texture,
Vector3,
WebXRSessionManager
} from "@babylonjs/core";
import log from "loglevel";
export class Cameras {
private readonly scene: Scene;
private readonly logger = log.getLogger('bmenu');
private xrSession: WebXRSessionManager;
private startPosition = new Vector3(0, 0, 0);
constructor(scene: Scene, xrSession: WebXRSessionManager) {
this.scene = scene;
this.xrSession = xrSession;
}
public createCameras(position: Vector3) {
this.startPosition = position;
this.getCameras();
}
private getCameras() {
}
private async createCamera() {
const width = 1.6;
const height = .9
const plane = MeshBuilder.CreatePlane("plane", {width: width, height: height}, this.scene);
const materialPlane = new StandardMaterial("texturePlane", this.scene);
//const photo = []
//await cam.getSnapshot();
//const textureBlob = new Blob([photo], {type: 'image/jpeg'});
//const textureUrl = URL.createObjectURL(textureBlob);
materialPlane.diffuseTexture = new Texture("", this.scene);
materialPlane.specularColor = new Color3(0, 0, 0);
materialPlane.backFaceCulling = false;
plane.material = materialPlane;
plane.rotation.y = Angle.FromDegrees(180).radians();
plane.position.y = height / 2 + .2;
plane.position.z = -3;
plane.position.x = (width * 3) + this.startPosition.x;
this.startPosition.x += 3;
}
}

View File

@ -156,9 +156,9 @@ export class EditMenu {
private setCopying(mesh: AbstractMesh) { private setCopying(mesh: AbstractMesh) {
if (mesh) { if (mesh) {
const newMesh = this.diagramManager.createCopy(mesh); const newMesh = this.diagramManager.createCopy(mesh, true);
newMesh.setParent(null);
DiagramShapePhysics.applyPhysics(newMesh, this.scene); DiagramShapePhysics.applyPhysics(newMesh, this.scene);
newMesh.parent = null;
} }
this.logger.warn('copying not implemented', mesh); this.logger.warn('copying not implemented', mesh);
//@todo implement //@todo implement

View File

@ -1,28 +0,0 @@
import {AbstractMesh, MeshBuilder, Scene, WebXRExperienceHelper} from "@babylonjs/core";
import {
AdvancedDynamicTexture
} from "@babylonjs/gui";
export class Keyboard {
private readonly scene: Scene;
private mesh: AbstractMesh;
private panel: AbstractMesh;
private xr: WebXRExperienceHelper;
constructor(scene: Scene, xr: WebXRExperienceHelper, mesh: AbstractMesh ) {
this.scene = scene;
this.xr = xr;
this.mesh = mesh;
}
public async show() {
this.panel = MeshBuilder.CreatePlane("hudPlane", {width: 1, height: 1}, this.scene);
const inputTexture = AdvancedDynamicTexture.CreateForMesh(this.panel, 1024, 1024);
await inputTexture.parseFromURLAsync("./textInputTexture.json", false);
this.panel.position = this.xr.camera.getFrontPosition(3);
this.panel.position.y = this.panel.position.y + 2;
this.panel.lookAt(this.xr.camera.getFrontPosition(-1));
this.panel.rotation.y = this.panel.rotation.y + Math.PI;
}
}

View File

@ -1,72 +0,0 @@
import {AdvancedDynamicTexture, Button, Control, Slider, StackPanel} from "@babylonjs/gui";
import {Angle, Mesh} from "@babylonjs/core";
export class ObjectEditor {
private scene;
private editor: Mesh;
private mesh;
constructor(scene, mesh) {
this.scene = scene;
this.mesh = mesh;
this.edit();
}
public edit() {
this.editor = Mesh.CreatePlane("editor", 2, this.scene);
this.editor.position.z = -2;
this.editor.position.y = 2;
this.editor.rotation.y = Angle.FromDegrees(180).radians();
const texture = AdvancedDynamicTexture.CreateForMesh(this.editor);
const panel = new StackPanel();
panel.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_RIGHT;
panel.verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
panel.width = '100%';
panel.height = '100%';
texture.addControl(panel);
const x = this.createControl();
const y = this.createControl();
const z = this.createControl()
const myMesh = this.mesh;
z.value = myMesh.scaling.z;
z.onValueChangedObservable.add((value) => {
myMesh.scaling.z = value;
});
y.onValueChangedObservable.add((value) => {
myMesh.scaling.y = value;
});
y.value = myMesh.scaling.x;
x.onValueChangedObservable.add((value) => {
myMesh.scaling.x = value;
});
x.value = myMesh.scaling.x;
panel.addControl(x);
panel.addControl(y);
panel.addControl(z);
const button1 = Button.CreateSimpleButton("close-editor", "Close");
button1.height = '20px';
button1.background = "#FFF";
panel.addControl(button1);
button1.onPointerClickObservable.add(() => {
this.close();
}, -1, false, this);
}
createControl(): Slider {
const slider = new Slider();
slider.minimum = .1
slider.maximum = 10;
slider.height = '40px';
slider.step = .1
return slider;
}
close() {
this.editor.dispose();
this.mesh = null;
this.scene = null;
}
}