diff --git a/index.html b/index.html index d000dc6..6776f9f 100644 --- a/index.html +++ b/index.html @@ -40,6 +40,7 @@ */ +
diff --git a/package-lock.json b/package-lock.json index 1d70bcc..609666c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,11 +20,14 @@ "@picovoice/eagle-web": "^1.0.0", "@picovoice/web-voice-processor": "^4.0.9", "@typed-mxgraph/typed-mxgraph": "^1.0.8", + "@types/dom-to-image": "^2.6.7", "@types/file-saver": "^2.0.6", "@types/node": "^18.14.0", "@types/react": "^18.2.72", "@types/react-dom": "^18.2.22", "axios": "^1.6.8", + "babylon-html": "0.0.1", + "dom-to-image-more": "^3.3.0", "earcut": "^2.2.4", "events": "^3.3.0", "file-saver": "^2.0.5", @@ -41,8 +44,9 @@ "uuid": "^9.0.1" }, "devDependencies": { + "@types/dom-to-image": "^2.6.7", "typescript": "^4.9.5", - "vite": "^5.2.6", + "vite": "^5.2.9", "vite-plugin-cp": "^1.0.0", "vitest": "^1.4.0" }, @@ -50,6 +54,20 @@ "node": ">=18.0.0" } }, + "../babylon-html": { + "version": "0.0.1", + "license": "MIT", + "dependencies": { + "@babylonjs/core": "^7.1.0", + "dom-to-image-more": "^3.3.0" + }, + "devDependencies": { + "@types/dom-to-image": "^2.6.7", + "ts-node": "^10.9.2", + "tsup": "^8.0.2", + "typescript": "^5.4.5" + } + }, "node_modules/@babylonjs/core": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-7.1.0.tgz", @@ -878,6 +896,12 @@ "resolved": "https://registry.npmjs.org/@typed-mxgraph/typed-mxgraph/-/typed-mxgraph-1.0.8.tgz", "integrity": "sha512-rzTbmD/XofRq0YZMY/BU9cjbCTw9q8rpIvWRhQO0DcgCx3+rpHTsVOk3pfuhcnUigUYNFkljmDkRuVjbl7zZoQ==" }, + "node_modules/@types/dom-to-image": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/@types/dom-to-image/-/dom-to-image-2.6.7.tgz", + "integrity": "sha512-me5VbCv+fcXozblWwG13krNBvuEOm6kA5xoa4RrjDJCNFOZSWR3/QLtOXimBHk1Fisq69Gx3JtOoXtg1N1tijg==", + "dev": true + }, "node_modules/@types/emscripten": { "version": "1.39.6", "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.6.tgz", @@ -1082,6 +1106,10 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/babylon-html": { + "resolved": "../babylon-html", + "link": true + }, "node_modules/babylonjs-gltf2interface": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-7.1.0.tgz", @@ -1320,6 +1348,11 @@ "node": ">=8" } }, + "node_modules/dom-to-image-more": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/dom-to-image-more/-/dom-to-image-more-3.3.0.tgz", + "integrity": "sha512-4k0oxVfQ4Nrv4/Iva6FpsXTAtPCp5JnZNO/n/hsuOpe3ANlMiK50URZDQKzJslthQD8k76z9vHS3usIzmJoFVw==" + }, "node_modules/double-ended-queue": { "version": "2.1.0-0", "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", @@ -2990,13 +3023,13 @@ } }, "node_modules/vite": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.6.tgz", - "integrity": "sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==", + "version": "5.2.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.9.tgz", + "integrity": "sha512-uOQWfuZBlc6Y3W/DTuQ1Sr+oIXWvqljLvS881SVmAj00d5RdgShLcuXWxseWPd4HXwiYBFW/vXHfKFeqj9uQnw==", "dev": true, "dependencies": { "esbuild": "^0.20.1", - "postcss": "^8.4.36", + "postcss": "^8.4.38", "rollup": "^4.13.0" }, "bin": { diff --git a/package.json b/package.json index 2cd7751..f8c1193 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "node": ">=18.0.0" }, "scripts": { - "dev": "cp ./node_modules/@babylonjs/havok/lib/esm/HavokPhysics.wasm ./node_modules/.vite/deps && vite", + "dev": "vite", "test": "vitest", "build": "vite build", "preview": "vite preview", @@ -16,7 +16,6 @@ "havok": "cp ./node_modules/@babylonjs/havok/lib/esm/HavokPhysics.wasm ./node_modules/.vite/deps" }, "dependencies": { - "axios": "^1.6.8", "@babylonjs/core": "^7.1.0", "@babylonjs/gui": "^7.1.0", "@babylonjs/havok": "1.3.1", @@ -25,33 +24,38 @@ "@babylonjs/materials": "^7.1.0", "@babylonjs/procedural-textures": "^7.1.0", "@babylonjs/serializers": "^7.1.0", - "events": "^3.3.0", - "@typed-mxgraph/typed-mxgraph": "^1.0.8", - "@types/node": "^18.14.0", - "earcut": "^2.2.4", - "file-saver": "^2.0.5", - "@types/file-saver": "^2.0.6", + "@picovoice/cobra-web": "^2.0.3", "@picovoice/eagle-web": "^1.0.0", "@picovoice/web-voice-processor": "^4.0.9", - "@picovoice/cobra-web": "^2.0.3", + "@typed-mxgraph/typed-mxgraph": "^1.0.8", + "@types/dom-to-image": "^2.6.7", + "@types/file-saver": "^2.0.6", + "@types/node": "^18.14.0", + "@types/react": "^18.2.72", + "@types/react-dom": "^18.2.22", + "axios": "^1.6.8", + "babylon-html": "0.0.1", + "dom-to-image-more": "^3.3.0", + "earcut": "^2.2.4", + "events": "^3.3.0", + "file-saver": "^2.0.5", "hls.js": "^1.1.4", "loglevel": "^1.9.1", "niceware": "^4.0.0", "pouchdb": "^8.0.1", "pouchdb-find": "^8.0.1", "query-string": "^8.1.0", - "recordrtc": "^5.6.0", "react-dom": "^18.2.0", + "recordrtc": "^5.6.0", "rfc4648": "^1.5.3", - "@types/react-dom": "^18.2.22", - "@types/react": "^18.2.72", "round": "^2.0.1", "uuid": "^9.0.1" }, "devDependencies": { + "@types/dom-to-image": "^2.6.7", "typescript": "^4.9.5", - "vite": "^5.2.6", - "vitest": "^1.4.0", - "vite-plugin-cp": "^1.0.0" + "vite": "^5.2.9", + "vite-plugin-cp": "^1.0.0", + "vitest": "^1.4.0" } } diff --git a/src/integration/pouchdbPersistenceManager.ts b/src/integration/pouchdbPersistenceManager.ts index a23bf3e..c9eb573 100644 --- a/src/integration/pouchdbPersistenceManager.ts +++ b/src/integration/pouchdbPersistenceManager.ts @@ -1,26 +1,21 @@ import PouchDB from 'pouchdb'; import {DiagramEntity, DiagramEventType} from "../diagram/types/diagramEntity"; import {Color3, Observable} from "@babylonjs/core"; -import {AppConfigType} from "../util/appConfigType"; -import {v4 as uuidv4} from 'uuid'; import axios from "axios"; import {DiagramManager} from "../diagram/diagramManager"; import log, {Logger} from "loglevel"; const logger: Logger = log.getLogger('PouchdbPersistenceManager'); export class PouchdbPersistenceManager { - configObserver: Observable = new Observable(); updateObserver: Observable = new Observable(); removeObserver: Observable = new Observable(); private db: PouchDB; private remote: PouchDB; - - private diagramListings: PouchDB; private user: string; constructor() { - this.diagramListings = new PouchDB("diagramListings"); + } public setDiagramManager(diagramManager: DiagramManager) { @@ -58,23 +53,6 @@ export class PouchdbPersistenceManager { }); } - private _currentDiagramId: string; - - public get currentDiagramId(): string { - return this._currentDiagramId; - } - - public set currentDiagramId(value: string) { - this._currentDiagramId = value; - try { - const listing = this.diagramListings.get(value); - } catch (err) { - this.diagramListings.put({_id: value, name: "New Diagram"}); - } - this.db = new PouchDB(value); - this.db.sync(this.remote, {live: true}); - } - public async add(entity: DiagramEntity) { if (!entity) { return; @@ -121,63 +99,26 @@ export class PouchdbPersistenceManager { return data; } - public async setConfig(config: AppConfigType, initial: boolean = false) { - if (!initial) { - localStorage.setItem('config', JSON.stringify(config)); - } else { - localStorage.setItem('config', JSON.stringify(config)); - } - } - - public getConfig(): AppConfigType { - return JSON.parse(localStorage.getItem('config')) as AppConfigType; - } - public async initialize() { try { let current = this.getPath(); - const configString = localStorage.getItem('config'); - const config = JSON.parse(configString) as AppConfigType; - if (!current && config.currentDiagramId) { - this.db = new PouchDB(config.currentDiagramId); - await this.beginSync(config.currentDiagramId); + if (current) { + this.db = new PouchDB(current); } else { - if (current) { - config.currentDiagramId = current; - } else { - config.currentDiagramId = uuidv4(); - } - this.db = new PouchDB(config.currentDiagramId); - await this.beginSync(config.currentDiagramId); - localStorage.setItem('config', JSON.stringify(config)); - } - this.configObserver.notifyObservers(config); - } catch (err) { - const defaultConfig = { - _id: '1', - demoCompleted: false, - gridSnap: 1, - rotateSnap: 0, - createSnap: 0, - turnSnap: 0, - flyMode: true, - currentDiagramId: 'public' - } - try { - await this.setConfig(defaultConfig, true); - } catch (err) { - logger.error(err); + current = 'public'; + this.db = new PouchDB(current); } - this.diagramListings.put({_id: defaultConfig.currentDiagramId, name: "New Diagram"}); - this.db = new PouchDB(defaultConfig.currentDiagramId); - await this.beginSync(defaultConfig.currentDiagramId); - this.configObserver.notifyObservers(defaultConfig); + await this.beginSync(current); + + } catch (err) { + logger.error(err); + logger.error('cannot initialize pouchdb for sync'); + return; } try { const all = await this.db.allDocs({include_docs: true}); - for (const entity of all.rows) { logger.debug(entity.doc); this.updateObserver.notifyObservers(entity.doc, 1); @@ -258,7 +199,6 @@ export class PouchdbPersistenceManager { } else { return; } - } const userEndpoint: string = import.meta.env.VITE_USER_ENDPOINT logger.debug(userEndpoint); diff --git a/src/util/appConfig.ts b/src/util/appConfig.ts index d301084..e8267bd 100644 --- a/src/util/appConfig.ts +++ b/src/util/appConfig.ts @@ -4,20 +4,31 @@ import {AppConfigType} from "./appConfigType"; export class AppConfig { public readonly onConfigChangedObservable = new Observable(); private _currentConfig: AppConfigType; + public readonly defaultConfig: AppConfigType = { + id: 1, + gridSnap: .1, + rotateSnap: 90, + createSnap: .1, + turnSnap: 22.5, + newRelicKey: null, + newRelicAccount: null, + physicsEnabled: false, + demoCompleted: false, + flyMode: true + } constructor() { - this._currentConfig = { - id: 1, - gridSnap: .1, - rotateSnap: 90, - createSnap: .1, - turnSnap: 22.5, - newRelicKey: null, - newRelicAccount: null, - physicsEnabled: false, - demoCompleted: false, - flyMode: true - }; + this._currentConfig = this.defaultConfig; + try { + const config = JSON.parse(localStorage.getItem('appConfig')); + if (config) { + this._currentConfig = config; + } else { + localStorage.setItem('appConfig', JSON.stringify(this._currentConfig)); + } + } catch (err) { + console.error(err); + } this.onConfigChangedObservable.add((config) => { this._currentConfig = config; }, -1); @@ -27,55 +38,49 @@ export class AppConfig { return this._currentConfig; } + public set current(config: AppConfigType) { + this._currentConfig = config; + localStorage.setItem('appConfig', JSON.stringify(this._currentConfig)); + this.onConfigChangedObservable.notifyObservers(this._currentConfig, -1); + } + public setRotateSnap(value: number) { this._currentConfig.rotateSnap = value; - this.onConfigChangedObservable.notifyObservers(this._currentConfig, 2); + this.save(); } public setFlyMode(value: boolean) { this._currentConfig.flyMode = value; - this.onConfigChangedObservable.notifyObservers(this._currentConfig, 2); + this.save(); } public setCreateSnap(value: number) { this._currentConfig.createSnap = value; - this.onConfigChangedObservable.notifyObservers(this._currentConfig, 2); + this.save(); } public setTurnSnap(value: number) { this._currentConfig.turnSnap = value; - this.onConfigChangedObservable.notifyObservers(this._currentConfig, 2); + this.save(); } public setGridSnap(value: number) { this._currentConfig.gridSnap = value; - this.onConfigChangedObservable.notifyObservers(this._currentConfig, 2); - } - - public set current(config: AppConfigType) { - this._currentConfig = config; - this.onConfigChangedObservable.notifyObservers(config, 2); - } - - public load(config: AppConfigType) { - this._currentConfig = config; - this.onConfigChangedObservable.notifyObservers(this._currentConfig, 1); - } - - public setPassphrase(passphrase: string) { - this._currentConfig.passphrase = passphrase; - this.onConfigChangedObservable.notifyObservers(this._currentConfig, 2); - + this.save(); } public setPhysicsEnabled(physicsEnabled: boolean) { this._currentConfig.physicsEnabled = physicsEnabled; - this.onConfigChangedObservable.notifyObservers(this._currentConfig, 2); - + this.save(); } public setDemoCompleted(demoCompleted: boolean) { this._currentConfig.demoCompleted = demoCompleted; - this.onConfigChangedObservable.notifyObservers(this._currentConfig, 2); + this.save(); + } + + private save() { + localStorage.setItem('appConfig', JSON.stringify(this._currentConfig)); + this.onConfigChangedObservable.notifyObservers(this._currentConfig, -1); } } \ No newline at end of file diff --git a/src/util/functions/groundMeshObserver.ts b/src/util/functions/groundMeshObserver.ts index a998072..376569f 100644 --- a/src/util/functions/groundMeshObserver.ts +++ b/src/util/functions/groundMeshObserver.ts @@ -75,7 +75,7 @@ export async function groundMeshObserver(ground: AbstractMesh, diagramManager.config.onConfigChangedObservable.add((config) => { rig.flyMode = config.flyMode; rig.turnSnap = config.turnSnap; - }); + }, -1, false, this); const config = new ConfigMenu(xr, diagramManager.controllers, diagramManager.config); const webController = new WebController(ground.getScene(), rig, diagramManager, diagramManager.controllers); diff --git a/src/util/functions/updateTextNode.ts b/src/util/functions/updateTextNode.ts index a8bd186..db8e625 100644 --- a/src/util/functions/updateTextNode.ts +++ b/src/util/functions/updateTextNode.ts @@ -1,14 +1,4 @@ -import { - AbstractMesh, - Color3, - DynamicTexture, - Material, - Mesh, - MeshBuilder, - Scene, - StandardMaterial, - Vector3 -} from "@babylonjs/core"; +import {AbstractMesh, Color3, DynamicTexture, Material, MeshBuilder, StandardMaterial} from "@babylonjs/core"; import log from "loglevel"; @@ -61,29 +51,26 @@ export function updateTextNode(mesh: AbstractMesh, text: string) { const mat = new StandardMaterial("mat", mesh.getScene()); mat.diffuseColor = Color3.Black(); mat.disableLighting = true; - mat.backFaceCulling = true; + mat.backFaceCulling = false; mat.emissiveTexture = dynamicTexture; mat.freeze(); - //mat.emissiveColor = Color3.White(); - //Create plane and set dynamic texture as material - //const plane = MeshBuilder.CreatePlane("text" + text, {width: planeWidth, height: height}, mesh.getScene()); const plane1 = createPlane(mat, mesh, text, planeWidth, height); - const plane2 = createPlane(mat, mesh, text, planeWidth, height); - plane2.rotation.y = Math.PI; + //const plane2 = createPlane(mat, mesh, text, planeWidth, height); + //plane2.rotation.y = Math.PI; } function createPlane(mat: Material, mesh: AbstractMesh, text: string, planeWidth: number, height: number): AbstractMesh { const plane = MeshBuilder.CreatePlane("text" + text, {width: planeWidth, height: height}, mesh.getScene()); const yOffset = mesh.getBoundingInfo().boundingSphere.maximum.y; - plane.parent = mesh; + plane.parent = mesh; plane.scaling.y = (1 / mesh.scaling.y); plane.scaling.x = (1 / mesh.scaling.x); plane.scaling.z = (1 / mesh.scaling.z); plane.material = mat; - //plane.billboardMode = Mesh.BILLBOARDMODE_ALL; plane.metadata = {exportable: true, label: true}; + if (mesh.metadata?.template == "#connection-template") { plane.billboardMode = AbstractMesh.BILLBOARDMODE_Y; plane.position.y = mesh.position.y + .1; @@ -91,22 +78,7 @@ function createPlane(mat: Material, mesh: AbstractMesh, text: string, planeWidth } else { plane.position.y = yOffset + (height * plane.scaling.y); } - //plane.addLODLevel(5, getDistantPlane(mesh.getScene(), plane.scaling, planeWidth, height)); plane.addLODLevel(3, null); return plane; } -let distantPlane = null; - -function getDistantPlane(scene: Scene, scaling: Vector3, planeWidth: number, planeHeight: number): Mesh { - //if (distantPlane == null) { - distantPlane = MeshBuilder.CreatePlane("distantPlane", {width: planeWidth, height: planeHeight}, scene); - distantPlane.scaling = scaling; - //distantPlane.scaling.y = distantPlane.scaling.y /4; - const material = new StandardMaterial("distantPlaneMaterial", scene); - material.emissiveColor = Color3.White() - material.freeze() - distantPlane.material = material; - // } - return distantPlane; -} diff --git a/src/vrApp.ts b/src/vrApp.ts index ee0db22..d990b9b 100644 --- a/src/vrApp.ts +++ b/src/vrApp.ts @@ -35,17 +35,6 @@ export class VrApp { const diagramManager = new DiagramManager(); const db = new PouchdbPersistenceManager(); db.setDiagramManager(diagramManager); - db.configObserver.add((newConfig) => { - if (!newConfig.demoCompleted) { - const main = document.querySelector('#main'); - } else { - const create = document.querySelector('#create'); - } - diagramManager.config.onConfigChangedObservable.notifyObservers(newConfig, 1); - }); - diagramManager.config.onConfigChangedObservable.add((newConfig) => { - db.setConfig(newConfig); - }, 2, false, this); await db.initialize(); const camera: FreeCamera = new FreeCamera("Main Camera", @@ -71,24 +60,8 @@ export class VrApp { }) } this.logger.info('keydown event listener added, use Ctrl+Shift+Alt+I to toggle debug layer'); - /* - - const textGen = new TextMeshGenerator(); - let y = .1; - for (let i = 0; i < 1000; i++) { - const text = textGen.generateCharMesh("hijklmnop Hello World"); - text.position.y = y; - text.position.z = -5; - text.rotation.y = Math.PI; - y+=.1; - } - */ - let i = 0; this.engine.runRenderLoop(() => { scene.render(); - if (i++ % 60 == 0) { - - } }); this.logger.info('Render loop started'); @@ -103,14 +76,11 @@ export class VrApp { this.engine = new Engine(canvas, true); } - //this.engine.setHardwareScalingLevel(1 / window.devicePixelRatio); + this.engine.setHardwareScalingLevel(1 / window.devicePixelRatio); - //window.onresize = () => { - // this.engine.resize(); - // } - /*window.setInterval(() => { - console.log(this.engine.performanceMonitor.instantaneousFPS.toFixed(2) + " fps"); - }, 1000);*/ + window.onresize = () => { + this.engine.resize(); + } const scene = new Scene(this.engine); scene.ambientColor = new Color3(.1, .1, .1); DefaultScene.Scene = scene;